| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- """fq → fgd:计算并期变更指令(纯函数,不写库)"""
- from __future__ import annotations
- from decimal import Decimal
- from typing import Any, Dict, Iterable, List, Mapping
- from app.services.protocol_transfer_status import schedule_paid_and_arrears
- def _dec(v: Any) -> Decimal:
- if v is None or v == "":
- return Decimal("0")
- return Decimal(str(v))
- def _status(row: Mapping[str, Any], *keys: str) -> str:
- for k in keys:
- if k in row and row[k] is not None:
- return str(row[k]).strip()
- return ""
- def plan_fq_to_fgd_merge(
- *,
- schedules: Iterable[Mapping[str, Any]],
- transfers: Iterable[Mapping[str, Any]],
- ) -> Dict[str, Any]:
- sch_list = [
- s
- for s in schedules
- if _status(s, "scheduleStatus", "schedule_status") != "void"
- and not s.get("_deleted")
- ]
- sch_list.sort(key=lambda s: int(s.get("scheduleNo") or s.get("schedule_no") or 0))
- tr_list = list(transfers or [])
- by_sch: Dict[str, List[Mapping[str, Any]]] = {}
- for t in tr_list:
- sid = str(t.get("scheduleId") or t.get("schedule_id") or "")
- by_sch.setdefault(sid, []).append(t)
- def _arrears(s: Mapping[str, Any]) -> Decimal:
- sid = str(s.get("id") or "")
- confirmed = [
- _dec(t.get("transferAmount", t.get("transfer_amount")))
- for t in by_sch.get(sid, [])
- if _status(t, "payStatus", "pay_status") == "yjf"
- ]
- _paid, arr = schedule_paid_and_arrears(
- due=s.get("dueAmount", s.get("due_amount")),
- confirmed_transfers=confirmed,
- )
- arr_d = _dec(arr)
- return arr_d if arr_d > 0 else Decimal("0")
- target = None
- for s in sch_list:
- if _arrears(s) > 0:
- target = s
- break
- if target is None:
- for s in sch_list:
- if _status(s, "scheduleStatus", "schedule_status") != "cleared":
- target = s
- break
- if target is None:
- raise ValueError("没有可合并的未清期次")
- target_no = int(target.get("scheduleNo") or target.get("schedule_no") or 0)
- later = [
- s
- for s in sch_list
- if int(s.get("scheduleNo") or s.get("schedule_no") or 0) > target_no
- ]
- for s in later:
- sid = str(s.get("id") or "")
- if any(
- _status(t, "payStatus", "pay_status") == "yjf" for t in by_sch.get(sid, [])
- ):
- raise ValueError("后续期已有已确认转账,无法合并为分改趸")
- remain = sum((_arrears(s) for s in sch_list), Decimal("0"))
- tid = str(target.get("id") or "")
- target_confirmed = sum(
- (
- _dec(t.get("transferAmount", t.get("transfer_amount")))
- for t in by_sch.get(tid, [])
- if _status(t, "payStatus", "pay_status") == "yjf"
- ),
- Decimal("0"),
- )
- new_due = target_confirmed + remain
- soft_ids = [str(s.get("id") or "") for s in later if str(s.get("id") or "")]
- soft_set = set(soft_ids)
- kept = [s for s in sch_list if str(s.get("id") or "") not in soft_set]
- return {
- "targetScheduleId": tid,
- "newDueAmount": new_due,
- "softDeleteScheduleIds": soft_ids,
- "newInstallmentCount": len(kept),
- }
|