Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -52,6 +52,9 @@ Primary goals for reconcile rate:
|
|
| 52 |
table first and a *second* DA3 table whose rows start with ITM DEPOSIT (credits) plus duplicate
|
| 53 |
debits. Reorder to Credits + ITM table + Electronic Debits + merged debits; drop dup keys from the
|
| 54 |
second table against the first; merge remaining orphan rows into the debits table.
|
|
|
|
|
|
|
|
|
|
| 55 |
- Fix 17e: Repeat EC/ED fused + 17d passes until stable (handles chained replacements). Centered section titles
|
| 56 |
match both align=\"center\" and style=\"text-align:center\" on divs.
|
| 57 |
- Post-pass: dedupe 3-col Date|Description|Amount tables when one is a duplicate fragment
|
|
@@ -2998,6 +3001,45 @@ def _ucb_html_table_body_looks_itm_credits_only(table_html: str) -> bool:
|
|
| 2998 |
return True
|
| 2999 |
|
| 3000 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3001 |
def _ucb_split_grid_electronic_credits_debits_after_itm_prefix(grid):
|
| 3002 |
"""
|
| 3003 |
Fix 17b: one fused DA3 table under Electronic Credits (+ optional empty EC/ED headings) where OCR
|
|
@@ -3036,18 +3078,16 @@ def _try_split_ucb_ec_ed_from_fused_table_html(
|
|
| 3036 |
pair = _ucb_split_grid_electronic_credits_debits_after_itm_prefix(grid)
|
| 3037 |
if pair:
|
| 3038 |
g_ec, g_ed = pair
|
|
|
|
| 3039 |
sect = '<div align="center">\n\n{title}\n\n</div>\n\n'
|
| 3040 |
parts = []
|
| 3041 |
if lead_before_ec and lead_before_ec.strip():
|
| 3042 |
parts.append(lead_before_ec.rstrip())
|
| 3043 |
-
parts.
|
| 3044 |
-
|
| 3045 |
-
|
| 3046 |
-
|
| 3047 |
-
|
| 3048 |
-
_grid_to_html(g_ed),
|
| 3049 |
-
]
|
| 3050 |
-
)
|
| 3051 |
return "\n\n".join(parts)
|
| 3052 |
|
| 3053 |
# Fix 17c: headings stacked as EC / ED / table but rows are all credits (e.g. ITM-only) —
|
|
|
|
| 52 |
table first and a *second* DA3 table whose rows start with ITM DEPOSIT (credits) plus duplicate
|
| 53 |
debits. Reorder to Credits + ITM table + Electronic Debits + merged debits; drop dup keys from the
|
| 54 |
second table against the first; merge remaining orphan rows into the debits table.
|
| 55 |
+
- Fix 17i: After Fix 17b splits ITM prefix from debits, OCR often leaves *credit* rows (POS Return, DDA
|
| 56 |
+
Transfer IN, Apple Cash INST R / CUPERTINO) at the *end* of the debits table — move that contiguous
|
| 57 |
+
tail from Electronic Debits back to Electronic Credits (same statement layout as the PDF).
|
| 58 |
- Fix 17e: Repeat EC/ED fused + 17d passes until stable (handles chained replacements). Centered section titles
|
| 59 |
match both align=\"center\" and style=\"text-align:center\" on divs.
|
| 60 |
- Post-pass: dedupe 3-col Date|Description|Amount tables when one is a duplicate fragment
|
|
|
|
| 3001 |
return True
|
| 3002 |
|
| 3003 |
|
| 3004 |
+
def _is_ucb_electronic_credit_row_after_split(grid, r: int) -> bool:
|
| 3005 |
+
"""
|
| 3006 |
+
Rows that belong under Electronic Credits but often land at the end of the debits table after OCR
|
| 3007 |
+
(Fix 17i). Must not match outgoing debits (POS purchase, Acct Fund SENT, etc.).
|
| 3008 |
+
"""
|
| 3009 |
+
if not grid or r < 1 or r >= len(grid):
|
| 3010 |
+
return False
|
| 3011 |
+
if _is_strong_ucb_electronic_debit_row(grid, r):
|
| 3012 |
+
return False
|
| 3013 |
+
t = _row_text_full_ucb(grid, r)
|
| 3014 |
+
if "pos return" in t:
|
| 3015 |
+
return True
|
| 3016 |
+
if "dda transfer" in t and "in" in t:
|
| 3017 |
+
return True
|
| 3018 |
+
if "acct fund" in t and ("inst r" in t or "cupertino" in t):
|
| 3019 |
+
return True
|
| 3020 |
+
return False
|
| 3021 |
+
|
| 3022 |
+
|
| 3023 |
+
def _ucb_move_trailing_credit_rows_from_ed_to_ec(g_ec, g_ed):
|
| 3024 |
+
"""Fix 17i: contiguous tail of credit-like rows at bottom of g_ed -> append to g_ec."""
|
| 3025 |
+
if not g_ec or not g_ed or len(g_ed) < 2 or not _is_da3_header(g_ec) or not _is_da3_header(g_ed):
|
| 3026 |
+
return g_ec, g_ed
|
| 3027 |
+
i = len(g_ed) - 1
|
| 3028 |
+
while i >= 1 and _is_ucb_electronic_credit_row_after_split(g_ed, i):
|
| 3029 |
+
i -= 1
|
| 3030 |
+
tail_start = i + 1
|
| 3031 |
+
if tail_start >= len(g_ed):
|
| 3032 |
+
return g_ec, g_ed
|
| 3033 |
+
credit_tail = [list(g_ed[r]) for r in range(tail_start, len(g_ed))]
|
| 3034 |
+
g_ed_new = [list(g_ed[0])] + [list(g_ed[r]) for r in range(1, tail_start)]
|
| 3035 |
+
g_ec_new = [list(g_ec[0])] + [list(r) for r in g_ec[1:]] + credit_tail
|
| 3036 |
+
max_c = max(len(r) for r in g_ec_new + g_ed_new)
|
| 3037 |
+
for row in g_ec_new + g_ed_new:
|
| 3038 |
+
while len(row) < max_c:
|
| 3039 |
+
row.append("")
|
| 3040 |
+
return g_ec_new, g_ed_new
|
| 3041 |
+
|
| 3042 |
+
|
| 3043 |
def _ucb_split_grid_electronic_credits_debits_after_itm_prefix(grid):
|
| 3044 |
"""
|
| 3045 |
Fix 17b: one fused DA3 table under Electronic Credits (+ optional empty EC/ED headings) where OCR
|
|
|
|
| 3078 |
pair = _ucb_split_grid_electronic_credits_debits_after_itm_prefix(grid)
|
| 3079 |
if pair:
|
| 3080 |
g_ec, g_ed = pair
|
| 3081 |
+
g_ec, g_ed = _ucb_move_trailing_credit_rows_from_ed_to_ec(g_ec, g_ed)
|
| 3082 |
sect = '<div align="center">\n\n{title}\n\n</div>\n\n'
|
| 3083 |
parts = []
|
| 3084 |
if lead_before_ec and lead_before_ec.strip():
|
| 3085 |
parts.append(lead_before_ec.rstrip())
|
| 3086 |
+
parts.append(sect.format(title="Electronic Credits"))
|
| 3087 |
+
parts.append(_grid_to_html(g_ec))
|
| 3088 |
+
if len(g_ed) > 1:
|
| 3089 |
+
parts.append(sect.format(title="Electronic Debits"))
|
| 3090 |
+
parts.append(_grid_to_html(g_ed))
|
|
|
|
|
|
|
|
|
|
| 3091 |
return "\n\n".join(parts)
|
| 3092 |
|
| 3093 |
# Fix 17c: headings stacked as EC / ED / table but rows are all credits (e.g. ITM-only) —
|