B-44: 返修——余额目录视觉、八列事件表、抽屉键盘与审核三项决定
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -832,9 +832,106 @@ def event_payload(
|
||||
if int(event["payer_company_id"]) == int(viewer_company_id)
|
||||
else event["payer_company_name"]
|
||||
)
|
||||
item.update(_event_line_display(connection, event, viewer_company_id))
|
||||
return item
|
||||
|
||||
|
||||
_REPAY_MARKERS = ("还款", "归还借款", "归还往来款")
|
||||
|
||||
|
||||
def bank_short_name(name: str | None) -> str:
|
||||
text = str(name or "").strip()
|
||||
if text.startswith("中国"):
|
||||
text = text[2:]
|
||||
if text.endswith("银行"):
|
||||
text = text[:-2]
|
||||
return text or "银行"
|
||||
|
||||
|
||||
def _account_chip(visibility: str, bank_name: str | None, account: str | None) -> dict[str, object]:
|
||||
if visibility == "missing":
|
||||
return {"visibility": "missing", "label": None}
|
||||
if visibility == "masked":
|
||||
return {"visibility": "masked", "label": "按对方授权不可见"}
|
||||
number = str(account or "")
|
||||
tail = number[-4:] if number else ""
|
||||
short = bank_short_name(bank_name)
|
||||
label = f"{short} {tail}".strip() if tail else short
|
||||
return {"visibility": "visible", "label": label}
|
||||
|
||||
|
||||
def _event_line_display(
|
||||
connection: sqlite3.Connection,
|
||||
event: sqlite3.Row,
|
||||
viewer_company_id: int | None,
|
||||
) -> dict[str, object]:
|
||||
"""Account chips, summary and repayment flag for the event table."""
|
||||
missing = _account_chip("missing", None, None)
|
||||
payer_chip, payee_chip = missing, missing
|
||||
summary = None
|
||||
texts: list[str] = []
|
||||
sides = _event_source_sides(connection, event["ledger_event_id"])
|
||||
for side in sides:
|
||||
company_id = side["company_id"]
|
||||
own = viewer_company_id is None or int(company_id) == int(viewer_company_id)
|
||||
visibility = "visible" if own else "masked"
|
||||
chip = _account_chip(visibility, side.get("bank_name"), side.get("own_account"))
|
||||
if int(company_id) == int(event["payer_company_id"]):
|
||||
payer_chip = chip
|
||||
elif int(company_id) == int(event["payee_company_id"]):
|
||||
payee_chip = chip
|
||||
if own or viewer_company_id is None:
|
||||
if side.get("summary"):
|
||||
texts.append(str(side["summary"]))
|
||||
if side.get("reason"):
|
||||
texts.append(str(side["reason"]))
|
||||
if texts:
|
||||
summary = texts[0]
|
||||
blob = " ".join(texts)
|
||||
is_repayment = any(marker in blob for marker in _REPAY_MARKERS)
|
||||
return {
|
||||
"payer_account": payer_chip,
|
||||
"payee_account": payee_chip,
|
||||
"summary": summary,
|
||||
"is_repayment": is_repayment,
|
||||
}
|
||||
|
||||
|
||||
def _event_source_sides(
|
||||
connection: sqlite3.Connection, ledger_event_id: int
|
||||
) -> list[dict[str, object]]:
|
||||
rows = connection.execute(
|
||||
"""
|
||||
SELECT b.company_id AS company_id, s.bank_name AS bank_name,
|
||||
r.own_account AS own_account, r.summary AS summary,
|
||||
r.purpose AS purpose, NULL AS reason
|
||||
FROM ledger_event_bank_sources bs
|
||||
JOIN current_transfer_decisions cur ON cur.event_id = bs.bank_event_id
|
||||
JOIN transfer_decision_observations o ON o.decision_id = cur.decision_id
|
||||
JOIN source_rows r ON r.id = o.source_row_id
|
||||
JOIN sheet_batches s ON s.id = r.sheet_batch_id
|
||||
JOIN import_batches b ON b.id = s.import_batch_id
|
||||
WHERE bs.ledger_event_id = ?
|
||||
""",
|
||||
(ledger_event_id,),
|
||||
).fetchall()
|
||||
if rows:
|
||||
return [_row(row) for row in rows]
|
||||
manuals = connection.execute(
|
||||
"""
|
||||
SELECT m.company_id AS company_id, ba.bank_name AS bank_name,
|
||||
ba.account_number AS own_account, m.summary AS summary,
|
||||
NULL AS purpose, m.reason AS reason
|
||||
FROM ledger_event_manual_sources ms
|
||||
JOIN manual_records m ON m.id = ms.manual_record_id
|
||||
LEFT JOIN bank_accounts ba ON ba.id = m.bank_account_id
|
||||
WHERE ms.ledger_event_id = ?
|
||||
""",
|
||||
(ledger_event_id,),
|
||||
).fetchall()
|
||||
return [_row(row) for row in manuals]
|
||||
|
||||
|
||||
_DETAIL_SELECT = """
|
||||
SELECT p.ledger_event_id, p.id AS ledger_revision_id, p.effective_at, p.amount,
|
||||
p.amount_scale, p.currency, p.payer_company_id, p.payee_company_id,
|
||||
@@ -939,7 +1036,7 @@ def subject_review_queue(
|
||||
SELECT r.ledger_event_id, r.effective_at, r.amount, r.currency,
|
||||
r.payer_company_id, r.payee_company_id,
|
||||
cpayer.name AS payer_company_name, cpayee.name AS payee_company_name,
|
||||
r.id AS revision_id
|
||||
r.id AS revision_id, r.evidence_json AS evidence_json
|
||||
FROM current_ledger_event_revisions cur
|
||||
JOIN ledger_event_revisions r ON r.id = cur.revision_id
|
||||
JOIN companies cpayer ON cpayer.id = r.payer_company_id
|
||||
@@ -957,6 +1054,9 @@ def subject_review_queue(
|
||||
cursor_date, cursor_id = None, None
|
||||
filtered = []
|
||||
for row in rows:
|
||||
evidence = json.loads(row["evidence_json"] or "{}") if row["evidence_json"] else {}
|
||||
if evidence.get("admin_disposition") == "exception":
|
||||
continue
|
||||
if cursor_date is not None:
|
||||
if row["effective_at"] > cursor_date or (
|
||||
row["effective_at"] == cursor_date and row["ledger_event_id"] >= cursor_id
|
||||
@@ -982,6 +1082,7 @@ def subject_review_queue(
|
||||
""",
|
||||
(row["ledger_event_id"],),
|
||||
).fetchall()
|
||||
display = _event_line_display(connection, row, None)
|
||||
items.append(
|
||||
{
|
||||
"ledger_event_id": row["ledger_event_id"],
|
||||
@@ -993,6 +1094,8 @@ def subject_review_queue(
|
||||
"payer_company_name": row["payer_company_name"],
|
||||
"payee_company_id": row["payee_company_id"],
|
||||
"payee_company_name": row["payee_company_name"],
|
||||
"summary": display.get("summary"),
|
||||
"is_repayment": display.get("is_repayment"),
|
||||
"suggestions": [
|
||||
{
|
||||
"suggested_perspective_company_id": sug["suggested_perspective_company_id"],
|
||||
|
||||
Reference in New Issue
Block a user