rehan953 commited on
Commit
853f781
·
verified ·
1 Parent(s): c9ed81b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +69 -19
app.py CHANGED
@@ -32,6 +32,10 @@ Primary goals for reconcile rate:
32
  Date|Description|Amount table (common when Deposits (continued) is absent from OCR), split after a
33
  leading ITM DEPOSIT run when the next row matches generic electronic-debit patterns (POS purchase,
34
  ATM withdrawal, etc.). Safe no-op when there is no ITM prefix or no such debit row after it.
 
 
 
 
35
  - Post-pass: dedupe 3-col Date|Description|Amount tables when one is a duplicate fragment
36
  (later subset of earlier, earlier subset of later, or identical row sets)
37
  - Fix 18: adjacent DA3 tables — if the last K data rows of table N match the first K rows of table N+1
@@ -2926,6 +2930,28 @@ def _is_strong_ucb_electronic_debit_row(grid, r: int) -> bool:
2926
  return False
2927
 
2928
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2929
  def _ucb_split_grid_electronic_credits_debits_after_itm_prefix(grid):
2930
  """
2931
  Fix 17b: one fused DA3 table under Electronic Credits (+ optional empty EC/ED headings) where OCR
@@ -2952,7 +2978,9 @@ def _ucb_split_grid_electronic_credits_debits_after_itm_prefix(grid):
2952
  return g_ec, g_ed
2953
 
2954
 
2955
- def _try_split_ucb_ec_ed_from_fused_table_html(lead_before_ec: str, table_html: str):
 
 
2956
  try:
2957
  p = TableGridParser()
2958
  p.feed(table_html)
@@ -2960,22 +2988,42 @@ def _try_split_ucb_ec_ed_from_fused_table_html(lead_before_ec: str, table_html:
2960
  except Exception:
2961
  return None
2962
  pair = _ucb_split_grid_electronic_credits_debits_after_itm_prefix(grid)
2963
- if not pair:
2964
- return None
2965
- g_ec, g_ed = pair
2966
- sect = '<div align="center">\n\n{title}\n\n</div>\n\n'
2967
- parts = []
2968
- if lead_before_ec and lead_before_ec.strip():
2969
- parts.append(lead_before_ec.rstrip())
2970
- parts.extend(
2971
- [
2972
- sect.format(title="Electronic Credits"),
2973
- _grid_to_html(g_ec),
2974
- sect.format(title="Electronic Debits"),
2975
- _grid_to_html(g_ed),
2976
- ]
2977
- )
2978
- return "\n\n".join(parts)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2979
 
2980
 
2981
  # Optional empty centered banner only; EC/ED title divs are re-emitted after a successful split
@@ -2983,7 +3031,7 @@ def _try_split_ucb_ec_ed_from_fused_table_html(lead_before_ec: str, table_html:
2983
  _UCB_EC_ED_SINGLE_FUSED_TABLE = re.compile(
2984
  r'(?P<lead>(?:<div\s+align=["\']center["\']\s*>\s*</div>\s*)?)'
2985
  r'<div\s+align=["\']center["\']\s*>\s*Electronic\s+Credits\s*</div>\s*'
2986
- r'(?:<div\s+align=["\']center["\']\s*>\s*Electronic\s+Debits\s*</div>\s*)?'
2987
  r'(?P<table><table[^>]*>.*?</table>)',
2988
  re.DOTALL | re.IGNORECASE,
2989
  )
@@ -2997,8 +3045,10 @@ def _split_ucb_fused_ec_ed_headings_single_table_html(text: str) -> str:
2997
 
2998
  def _repl(m):
2999
  lead = m.group("lead")
 
3000
  table_html = m.group("table")
3001
- new = _try_split_ucb_ec_ed_from_fused_table_html(lead, table_html)
 
3002
  return new if new is not None else m.group(0)
3003
 
3004
  return _UCB_EC_ED_SINGLE_FUSED_TABLE.sub(_repl, text)
 
32
  Date|Description|Amount table (common when Deposits (continued) is absent from OCR), split after a
33
  leading ITM DEPOSIT run when the next row matches generic electronic-debit patterns (POS purchase,
34
  ATM withdrawal, etc.). Safe no-op when there is no ITM prefix or no such debit row after it.
35
+ - Fix 17c: When Electronic Debits appears *before* the table but every data row is credit-side (no strong
36
+ debit pattern) and at least one ITM DEPOSIT row exists, OCR stacked headings wrong — emit
37
+ Electronic Credits, then the table, then Electronic Debits (section continues below). Safe no-op
38
+ if the Debits heading was not before the table or any row looks like a card/ATM debit.
39
  - Post-pass: dedupe 3-col Date|Description|Amount tables when one is a duplicate fragment
40
  (later subset of earlier, earlier subset of later, or identical row sets)
41
  - Fix 18: adjacent DA3 tables — if the last K data rows of table N match the first K rows of table N+1
 
2930
  return False
2931
 
2932
 
2933
+ def _ucb_has_itm_deposit_data_row(grid) -> bool:
2934
+ for r in range(1, len(grid)):
2935
+ if _is_itm_deposit_row_ucb(grid, r):
2936
+ return True
2937
+ return False
2938
+
2939
+
2940
+ def _ucb_table_credits_only_no_strong_debits(grid) -> bool:
2941
+ """True if DA3 table has real data rows but none match strong electronic-debit patterns."""
2942
+ if not grid or len(grid) < 2 or not _is_da3_header(grid):
2943
+ return False
2944
+ has_data = False
2945
+ for r in range(1, len(grid)):
2946
+ row_txt = _row_text_full_ucb(grid, r).strip()
2947
+ if not row_txt:
2948
+ continue
2949
+ has_data = True
2950
+ if _is_strong_ucb_electronic_debit_row(grid, r):
2951
+ return False
2952
+ return bool(has_data and _ucb_has_itm_deposit_data_row(grid))
2953
+
2954
+
2955
  def _ucb_split_grid_electronic_credits_debits_after_itm_prefix(grid):
2956
  """
2957
  Fix 17b: one fused DA3 table under Electronic Credits (+ optional empty EC/ED headings) where OCR
 
2978
  return g_ec, g_ed
2979
 
2980
 
2981
+ def _try_split_ucb_ec_ed_from_fused_table_html(
2982
+ lead_before_ec: str, table_html: str, had_ed_heading_immediately_before_table: bool
2983
+ ):
2984
  try:
2985
  p = TableGridParser()
2986
  p.feed(table_html)
 
2988
  except Exception:
2989
  return None
2990
  pair = _ucb_split_grid_electronic_credits_debits_after_itm_prefix(grid)
2991
+ if pair:
2992
+ g_ec, g_ed = pair
2993
+ sect = '<div align="center">\n\n{title}\n\n</div>\n\n'
2994
+ parts = []
2995
+ if lead_before_ec and lead_before_ec.strip():
2996
+ parts.append(lead_before_ec.rstrip())
2997
+ parts.extend(
2998
+ [
2999
+ sect.format(title="Electronic Credits"),
3000
+ _grid_to_html(g_ec),
3001
+ sect.format(title="Electronic Debits"),
3002
+ _grid_to_html(g_ed),
3003
+ ]
3004
+ )
3005
+ return "\n\n".join(parts)
3006
+
3007
+ # Fix 17c: headings stacked as EC / ED / table but rows are all credits (e.g. ITM-only) —
3008
+ # put the table under Electronic Credits, then leave Electronic Debits for continuation.
3009
+ if (
3010
+ had_ed_heading_immediately_before_table
3011
+ and _ucb_table_credits_only_no_strong_debits(grid)
3012
+ ):
3013
+ sect = '<div align="center">\n\n{title}\n\n</div>\n\n'
3014
+ parts = []
3015
+ if lead_before_ec and lead_before_ec.strip():
3016
+ parts.append(lead_before_ec.rstrip())
3017
+ parts.extend(
3018
+ [
3019
+ sect.format(title="Electronic Credits"),
3020
+ _grid_to_html(grid),
3021
+ sect.format(title="Electronic Debits"),
3022
+ ]
3023
+ )
3024
+ return "\n\n".join(parts)
3025
+
3026
+ return None
3027
 
3028
 
3029
  # Optional empty centered banner only; EC/ED title divs are re-emitted after a successful split
 
3031
  _UCB_EC_ED_SINGLE_FUSED_TABLE = re.compile(
3032
  r'(?P<lead>(?:<div\s+align=["\']center["\']\s*>\s*</div>\s*)?)'
3033
  r'<div\s+align=["\']center["\']\s*>\s*Electronic\s+Credits\s*</div>\s*'
3034
+ r'(?P<ed_before>(?:<div\s+align=["\']center["\']\s*>\s*Electronic\s+Debits\s*</div>\s*)?)'
3035
  r'(?P<table><table[^>]*>.*?</table>)',
3036
  re.DOTALL | re.IGNORECASE,
3037
  )
 
3045
 
3046
  def _repl(m):
3047
  lead = m.group("lead")
3048
+ ed_before = m.group("ed_before") or ""
3049
  table_html = m.group("table")
3050
+ had_ed = bool(ed_before.strip())
3051
+ new = _try_split_ucb_ec_ed_from_fused_table_html(lead, table_html, had_ed)
3052
  return new if new is not None else m.group(0)
3053
 
3054
  return _UCB_EC_ED_SINGLE_FUSED_TABLE.sub(_repl, text)