counterparty 0.1.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- counterparty/__init__.py +29 -0
- counterparty/extraction/__init__.py +0 -0
- counterparty/extraction/clean.py +124 -0
- counterparty/extraction/extract_payer_payee.py +160 -0
- counterparty/extraction/infer_counterparty.py +17 -0
- counterparty/key_engine/__init__.py +0 -0
- counterparty/key_engine/canonical_keys.json +326 -0
- counterparty/key_engine/key_detector.py +335 -0
- counterparty/key_engine/keys.py +332 -0
- counterparty/parsers/LAT_AM/LAT_AM_Entry.py +91 -0
- counterparty/parsers/LAT_AM/__init__.py +0 -0
- counterparty/parsers/LAT_AM/pattern1.py +169 -0
- counterparty/parsers/LAT_AM/pattern10.py +76 -0
- counterparty/parsers/LAT_AM/pattern11.py +76 -0
- counterparty/parsers/LAT_AM/pattern12.py +99 -0
- counterparty/parsers/LAT_AM/pattern2.py +102 -0
- counterparty/parsers/LAT_AM/pattern3.py +75 -0
- counterparty/parsers/LAT_AM/pattern4.py +128 -0
- counterparty/parsers/LAT_AM/pattern5.py +54 -0
- counterparty/parsers/LAT_AM/pattern6.py +141 -0
- counterparty/parsers/LAT_AM/pattern7.py +116 -0
- counterparty/parsers/LAT_AM/pattern8.py +134 -0
- counterparty/parsers/LAT_AM/pattern9.py +86 -0
- counterparty/parsers/__init__.py +0 -0
- counterparty/parsers/ach/__init__.py +0 -0
- counterparty/parsers/ach/ach_parser.py +190 -0
- counterparty/parsers/avidpay/__init__.py +0 -0
- counterparty/parsers/avidpay/avidp_check_parser.py +82 -0
- counterparty/parsers/avidpay/avidp_gen_parser.py +59 -0
- counterparty/parsers/directdebit/__init__.py +0 -0
- counterparty/parsers/directdebit/directdeb.py +80 -0
- counterparty/parsers/disbursement/__init__.py +0 -0
- counterparty/parsers/disbursement/disb_parser.py +72 -0
- counterparty/parsers/fundsTransfer/__init__.py +0 -0
- counterparty/parsers/fundsTransfer/fundsTrans_parser.py +80 -0
- counterparty/parsers/generic/__init__.py +0 -0
- counterparty/parsers/generic/all_parser.py +91 -0
- counterparty/parsers/merchref/__init__.py +0 -0
- counterparty/parsers/merchref/merch_ref_parser.py +47 -0
- counterparty/parsers/misc/__init__.py +0 -0
- counterparty/parsers/misc/cardp.py +61 -0
- counterparty/parsers/misc/invo.py +78 -0
- counterparty/parsers/misc/webt.py +55 -0
- counterparty/parsers/paypal/__init__.py +0 -0
- counterparty/parsers/paypal/paypal.py +118 -0
- counterparty/parsers/processor_eft/__init__.py +0 -0
- counterparty/parsers/processor_eft/peft.py +110 -0
- counterparty/parsers/remittance/__init__.py +0 -0
- counterparty/parsers/remittance/remi.py +79 -0
- counterparty/parsers/swift/__init__.py +0 -0
- counterparty/parsers/swift/swift_parser.py +97 -0
- counterparty/parsers/vendorpay/__init__.py +0 -0
- counterparty/parsers/vendorpay/vp_parser.py +54 -0
- counterparty/parsers/vendorpymt/__init__.py +0 -0
- counterparty/parsers/vendorpymt/vpymt_parser.py +132 -0
- counterparty/parsers/wire/__init__.py +0 -0
- counterparty/parsers/wire/wire_parser.py +137 -0
- counterparty/route.py +116 -0
- counterparty/routines.py +72 -0
- counterparty/util.py +40 -0
- counterparty-0.1.6.dist-info/METADATA +9 -0
- counterparty-0.1.6.dist-info/RECORD +64 -0
- counterparty-0.1.6.dist-info/WHEEL +5 -0
- counterparty-0.1.6.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
# 1. NORMALIZATION (shared)
|
|
4
|
+
def normalize_narrative(line: str) -> str:
|
|
5
|
+
if not line:
|
|
6
|
+
return ""
|
|
7
|
+
line = line.strip(",")
|
|
8
|
+
line = re.sub(r"\s+", " ", line)
|
|
9
|
+
return line.strip().upper()
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# 2. IDENTIFICATION REGEX
|
|
14
|
+
VENDOR_PAY_RECOGNISE_RE = re.compile(
|
|
15
|
+
r"\bVENDOR\s+PAY\b.*\b\d+\b$"
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def is_vendor_pay_narrative(line: str) -> bool:
|
|
20
|
+
norm = normalize_narrative(line)
|
|
21
|
+
if not norm:
|
|
22
|
+
return False
|
|
23
|
+
return bool(VENDOR_PAY_RECOGNISE_RE.search(norm))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
# 3. PARSING REGEX
|
|
28
|
+
VENDOR_PAY_PARSE_RE = re.compile(
|
|
29
|
+
r"""
|
|
30
|
+
^
|
|
31
|
+
(?P<CTPTY_NAME>.+?)\s+
|
|
32
|
+
VENDOR\s+PAY\s+
|
|
33
|
+
(?P<MANAGER_NAME>.+?)\s+
|
|
34
|
+
(?P<VENDOR_PAY_ID>\d+)
|
|
35
|
+
$
|
|
36
|
+
""",
|
|
37
|
+
re.VERBOSE
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def parse_vendor_pay_narrative(line: str) -> dict:
|
|
42
|
+
norm = normalize_narrative(line)
|
|
43
|
+
|
|
44
|
+
match = VENDOR_PAY_PARSE_RE.search(norm)
|
|
45
|
+
if not match:
|
|
46
|
+
return {}
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
"RAW": line,
|
|
50
|
+
"ENTITY": match.group("CTPTY_NAME"),
|
|
51
|
+
"TRANS_TYPE": "VENDOR_PAY",
|
|
52
|
+
"MANAGER_NAME": match.group("MANAGER_NAME"),
|
|
53
|
+
"VENDOR_PAY_ID": match.group("VENDOR_PAY_ID"),
|
|
54
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
def normalize_narrative(line: str) -> str:
|
|
4
|
+
if not line:
|
|
5
|
+
return ""
|
|
6
|
+
line = line.lstrip(",")
|
|
7
|
+
line = re.sub(r"[,\s]+$", "", line)
|
|
8
|
+
line = re.sub(r"\s+", " ", line)
|
|
9
|
+
return line.strip().upper()
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
VENDORPYMT_RMR_RE = re.compile(
|
|
13
|
+
r"VENDORPYMT\s*RMR\*IV\*.+\*\*\d",
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
VENDORPYMT_REMIT_RECOGNISE_RE = re.compile(
|
|
17
|
+
r"VENDORPYMT.*RMR\*IV\*"
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def is_vendor_payment_rmr(line: str) -> bool:
|
|
23
|
+
return bool(VENDORPYMT_RMR_RE.search(normalize_narrative(line)))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def is_vendor_payment_remittance(line: str) -> bool:
|
|
27
|
+
norm = normalize_narrative(line)
|
|
28
|
+
if not norm:
|
|
29
|
+
return False
|
|
30
|
+
|
|
31
|
+
# exclude invoice+amount version (handled elsewhere)
|
|
32
|
+
if "**" in norm:
|
|
33
|
+
return False
|
|
34
|
+
|
|
35
|
+
return bool(VENDORPYMT_REMIT_RECOGNISE_RE.search(norm))
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# PARSER REGEX
|
|
40
|
+
VENDORPYMT_RMR_PARSE_RE = re.compile(
|
|
41
|
+
r"""
|
|
42
|
+
^
|
|
43
|
+
(?P<COUNTERPARTY_NAME>.+?)
|
|
44
|
+
[\s\-]*
|
|
45
|
+
VENDORPYMT\s*RMR(?:\*IV\*)
|
|
46
|
+
(?P<INVOICE_NO>(?:[A-Z0-9]+\s?)+)
|
|
47
|
+
\*\*
|
|
48
|
+
(?P<AMOUNT>(?:\d+\s+)?\d+(?:\.\d{2})?)
|
|
49
|
+
""",
|
|
50
|
+
re.VERBOSE
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
VENDORPYMT_REMIT_PARSE_RE = re.compile(
|
|
56
|
+
r"""
|
|
57
|
+
^
|
|
58
|
+
(?P<COUNTERPARTY_NAME>.+?)
|
|
59
|
+
\s+VENDORPYMT\b
|
|
60
|
+
\s*
|
|
61
|
+
(?P<META_BLOCK>.*?)
|
|
62
|
+
\s*
|
|
63
|
+
RMR\*IV\*
|
|
64
|
+
(?P<REMIT_BLOCK>.+)
|
|
65
|
+
$
|
|
66
|
+
""",
|
|
67
|
+
re.VERBOSE
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
INVOICE_RE = re.compile(r"RMR(?:\*IV\*|IV)([A-Z0-9]+)")
|
|
73
|
+
AMOUNT_RE = re.compile(r"\*\*\s*([\d ]+(?:\.\d{2})?)")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
# PARSER
|
|
77
|
+
def parse_vendor_payment_rmr(line: str) -> dict:
|
|
78
|
+
norm = normalize_narrative(line).rstrip("\\")
|
|
79
|
+
m = VENDORPYMT_RMR_PARSE_RE.search(norm)
|
|
80
|
+
if not m:
|
|
81
|
+
return {
|
|
82
|
+
"RAW": line,
|
|
83
|
+
"META": norm,
|
|
84
|
+
"ERROR": "VENDORPYMT_RMR_PARSE_FAILED"
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
raw_amt = m.group("AMOUNT").replace(" ", "")
|
|
88
|
+
if "." not in raw_amt and len(raw_amt) > 2:
|
|
89
|
+
amt = f"{int(raw_amt[:-2])}.{raw_amt[-2:]}"
|
|
90
|
+
else:
|
|
91
|
+
amt = raw_amt
|
|
92
|
+
|
|
93
|
+
invoice_ids = m.group("INVOICE_NO").split()
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
"RAW": line,
|
|
97
|
+
"ENTITY": m.group("COUNTERPARTY_NAME").rstrip("- "),
|
|
98
|
+
"TRANS_TYPE": "VENDOR_PAYMENT_RMR",
|
|
99
|
+
"INVOICE_NO": invoice_ids,
|
|
100
|
+
"AMOUNT": amt,
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def parse_vendor_payment_remittance(line: str) -> dict:
|
|
106
|
+
norm = normalize_narrative(line)
|
|
107
|
+
|
|
108
|
+
m = VENDORPYMT_REMIT_PARSE_RE.search(norm)
|
|
109
|
+
if not m:
|
|
110
|
+
return {
|
|
111
|
+
"RAW": line,
|
|
112
|
+
"META": norm,
|
|
113
|
+
"ERROR": "VENDORPYMT_REMIT_PARSE_FAILED"
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
remit_block = m.group("REMIT_BLOCK")
|
|
117
|
+
|
|
118
|
+
remit_ids = re.findall(r"\b\d{4,}\b", remit_block)
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
"RAW": line,
|
|
122
|
+
"ENTITY": m.group("COUNTERPARTY_NAME").strip(),
|
|
123
|
+
"TRANS_TYPE": "VENDOR_PAYMENT_REMITTANCE",
|
|
124
|
+
"VENDOR_META": m.group("META_BLOCK").strip(),
|
|
125
|
+
"REMITTANCE_IDS": remit_ids,
|
|
126
|
+
"RAW_REMIT_BLOCK": remit_block
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
if __name__=='__main__':
|
|
132
|
+
pass
|
|
File without changes
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from counterparty.key_engine.keys import KEYS, INLINE_KEYS
|
|
3
|
+
from counterparty.util import norm
|
|
4
|
+
|
|
5
|
+
KEYS = sorted(set(KEYS), key=len, reverse=True)
|
|
6
|
+
INLINE_KEYS = sorted(INLINE_KEYS, key=len, reverse=True)
|
|
7
|
+
ALLOWED = {' ', ':', '=', '/', '\\', '_', ',', '-'}
|
|
8
|
+
|
|
9
|
+
WIRE_TOKENS = [
|
|
10
|
+
("WIRE TRANSFER", 3),
|
|
11
|
+
("FEDWIRE", 3),
|
|
12
|
+
("SWIFT", 2),
|
|
13
|
+
("BIC", 2),
|
|
14
|
+
("IBAN", 2),
|
|
15
|
+
("ABA", 2),
|
|
16
|
+
("RTN", 2),
|
|
17
|
+
("IMAD", 2),
|
|
18
|
+
("OMAD", 2),
|
|
19
|
+
("FWT", 2),
|
|
20
|
+
("WIRE", 1),
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
WIRE_RE_PARTS = [(re.compile(re.escape(k), re.I), w) for k, w in WIRE_TOKENS]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def is_wire(text: str) -> bool:
|
|
27
|
+
if not text:
|
|
28
|
+
return False
|
|
29
|
+
|
|
30
|
+
t = norm(text)
|
|
31
|
+
|
|
32
|
+
structural_hits = 0
|
|
33
|
+
|
|
34
|
+
if re.search(r'\bBIC\b|BIC:', t): structural_hits += 2
|
|
35
|
+
if re.search(r'\bABA\b|ABA:', t): structural_hits += 2
|
|
36
|
+
if re.search(r'\bIBAN\b|IBAN:', t): structural_hits += 2
|
|
37
|
+
if re.search(r'\bBNK ID\b|\bBANK ID\b', t): structural_hits += 2
|
|
38
|
+
if re.search(r'\bINSTG BNK\b|\bINSTD BNK\b', t): structural_hits += 2
|
|
39
|
+
|
|
40
|
+
if re.search(r'/[A-Z]{1,4}/[A-Z]{1,4}/', text):
|
|
41
|
+
structural_hits += 2
|
|
42
|
+
|
|
43
|
+
keyword_hits = 0
|
|
44
|
+
if "WIRE TRANSFER" in t: keyword_hits += 1
|
|
45
|
+
elif "WIRE" in t: keyword_hits += 0.5
|
|
46
|
+
|
|
47
|
+
return structural_hits >= 2 and (structural_hits + keyword_hits) >= 3
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def is_standalone(text, i, k_len):
|
|
52
|
+
before = text[i - 1] if i > 0 else ' '
|
|
53
|
+
after = text[i + k_len] if i + k_len < len(text) else ' '
|
|
54
|
+
return before in ALLOWED and after in ALLOWED
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def find_keys(text, key_list):
|
|
58
|
+
found = {}
|
|
59
|
+
reserved = []
|
|
60
|
+
|
|
61
|
+
for k in key_list:
|
|
62
|
+
k_len = len(k)
|
|
63
|
+
for i in range(len(text) - k_len + 1):
|
|
64
|
+
|
|
65
|
+
if text[i:i + k_len] != k:
|
|
66
|
+
continue
|
|
67
|
+
|
|
68
|
+
if not is_standalone(text, i, k_len):
|
|
69
|
+
continue
|
|
70
|
+
|
|
71
|
+
if any(s <= i < e for s, e in reserved):
|
|
72
|
+
continue
|
|
73
|
+
|
|
74
|
+
found[i] = k
|
|
75
|
+
reserved.append((i, i + k_len))
|
|
76
|
+
|
|
77
|
+
return dict(sorted(found.items()))
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def split_inline_keys(text: str):
|
|
81
|
+
marks = find_keys(text, INLINE_KEYS)
|
|
82
|
+
if not marks:
|
|
83
|
+
return text.strip()
|
|
84
|
+
|
|
85
|
+
idx = [0] + list(marks.keys()) + [len(text)]
|
|
86
|
+
out = {}
|
|
87
|
+
out["value"] = text[:idx[1]].strip()
|
|
88
|
+
|
|
89
|
+
for i in range(1, len(idx) - 1):
|
|
90
|
+
start, end = idx[i], idx[i + 1]
|
|
91
|
+
k = marks[start]
|
|
92
|
+
z = start + len(k)
|
|
93
|
+
while z < len(text) and not text[z].isalnum():
|
|
94
|
+
z += 1
|
|
95
|
+
out[k] = text[z:end].strip()
|
|
96
|
+
|
|
97
|
+
return out
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def wire_parser_v1(narr: str):
|
|
101
|
+
marks = find_keys(narr, KEYS)
|
|
102
|
+
idx = [0] + list(marks.keys()) + [len(narr)]
|
|
103
|
+
out = {}
|
|
104
|
+
out["META"] = narr[:idx[1]].strip()
|
|
105
|
+
|
|
106
|
+
for i in range(1, len(idx) - 1):
|
|
107
|
+
start, end = idx[i], idx[i + 1]
|
|
108
|
+
k = marks[start]
|
|
109
|
+
z = start + len(k)
|
|
110
|
+
|
|
111
|
+
while z < len(narr) and not narr[z].isalnum():
|
|
112
|
+
z += 1
|
|
113
|
+
|
|
114
|
+
out[k] = narr[z:end].strip()
|
|
115
|
+
|
|
116
|
+
return out
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def wire_parser_v2(v1_output: dict):
|
|
120
|
+
out = {}
|
|
121
|
+
for k, v in v1_output.items():
|
|
122
|
+
if 'WIRE' in k or 'SRC' in k:
|
|
123
|
+
out[k] = v
|
|
124
|
+
elif isinstance(v, str):
|
|
125
|
+
out[k] = split_inline_keys(v)
|
|
126
|
+
else:
|
|
127
|
+
out[k] = v
|
|
128
|
+
return out
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def wire_parser(narr: str):
|
|
132
|
+
v1 = wire_parser_v1(narr)
|
|
133
|
+
v2 = wire_parser_v2(v1)
|
|
134
|
+
return {
|
|
135
|
+
"RAW": narr,
|
|
136
|
+
**v2
|
|
137
|
+
}
|
counterparty/route.py
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# routes to respective parsers
|
|
2
|
+
|
|
3
|
+
from counterparty.parsers.disbursement.disb_parser import parse_disbursement_narrative,is_disbursement_narrative
|
|
4
|
+
from counterparty.parsers.fundsTransfer.fundsTrans_parser import parse_funds_transfer_frmdep,is_funds_transfer_frmdep
|
|
5
|
+
from counterparty.parsers.vendorpay.vp_parser import parse_vendor_pay_narrative,is_vendor_pay_narrative
|
|
6
|
+
from counterparty.parsers.vendorpymt.vpymt_parser import parse_vendor_payment_rmr, parse_vendor_payment_remittance,is_vendor_payment_remittance,is_vendor_payment_rmr
|
|
7
|
+
from counterparty.parsers.avidpay.avidp_check_parser import parse_avidpay_check,is_avidpay_check
|
|
8
|
+
from counterparty.parsers.avidpay.avidp_gen_parser import parse_avidpay_generic,is_avidpay_generic
|
|
9
|
+
from counterparty.parsers.misc.cardp import parse_card_payment,is_card_payment
|
|
10
|
+
from counterparty.parsers.misc.invo import parse_invoice_reference,is_invoice_reference
|
|
11
|
+
from counterparty.parsers.misc.webt import parse_web_transfer,is_web_transfer
|
|
12
|
+
from counterparty.parsers.remittance.remi import parse_remittance_advice,is_remittance_advice
|
|
13
|
+
from counterparty.parsers.merchref.merch_ref_parser import parse_merchant_reference,is_merchant_reference
|
|
14
|
+
from counterparty.parsers.paypal.paypal import parse_paypal,classify_paypal
|
|
15
|
+
from counterparty.parsers.processor_eft.peft import parse_processor_eft,is_processor_eft
|
|
16
|
+
from counterparty.parsers.directdebit.directdeb import parse_direct_debit,is_direct_debit
|
|
17
|
+
from counterparty.parsers.LAT_AM.LAT_AM_Entry import LATAM_parse,is_LATAM
|
|
18
|
+
|
|
19
|
+
from counterparty.parsers.wire.wire_parser import wire_parser,is_wire
|
|
20
|
+
from counterparty.parsers.ach.ach_parser import ach_parser,is_ach
|
|
21
|
+
from counterparty.parsers.swift.swift_parser import swift_parser,is_swift
|
|
22
|
+
|
|
23
|
+
from counterparty.parsers.generic.all_parser import all_parser
|
|
24
|
+
|
|
25
|
+
from counterparty.key_engine.key_detector import KeyDetector
|
|
26
|
+
from counterparty.routines import routine1
|
|
27
|
+
from counterparty.util import normalize_spaces
|
|
28
|
+
|
|
29
|
+
key_detector = KeyDetector()
|
|
30
|
+
|
|
31
|
+
def route_to_parser(narr: str):
|
|
32
|
+
|
|
33
|
+
# I call key detector to fix keys before delimiter based parsing
|
|
34
|
+
rewritten_narr, hitl = key_detector.rewrite(normalize_spaces(narr))
|
|
35
|
+
|
|
36
|
+
# if a new key is found.
|
|
37
|
+
if hitl: routine1(hitl)
|
|
38
|
+
|
|
39
|
+
if is_wire(narr):
|
|
40
|
+
res = wire_parser(rewritten_narr)
|
|
41
|
+
res["RAW"] = narr
|
|
42
|
+
return res, "wire"
|
|
43
|
+
|
|
44
|
+
if is_ach(narr):
|
|
45
|
+
res = ach_parser(rewritten_narr)
|
|
46
|
+
res["RAW"] = narr
|
|
47
|
+
return res, "ach"
|
|
48
|
+
|
|
49
|
+
if is_swift(narr):
|
|
50
|
+
res = swift_parser(rewritten_narr)
|
|
51
|
+
res["RAW"] = narr
|
|
52
|
+
return res, "swift"
|
|
53
|
+
|
|
54
|
+
# LATAM
|
|
55
|
+
if is_LATAM(narr) is not None:
|
|
56
|
+
return LATAM_parse(narr), "LATAM"
|
|
57
|
+
|
|
58
|
+
# Paypal
|
|
59
|
+
if classify_paypal(narr) is not None:
|
|
60
|
+
return parse_paypal(narr), "PAYPAL"
|
|
61
|
+
|
|
62
|
+
# Disbursement
|
|
63
|
+
if is_disbursement_narrative(narr):
|
|
64
|
+
return parse_disbursement_narrative(narr), "disbursement"
|
|
65
|
+
|
|
66
|
+
# Funds transfer
|
|
67
|
+
if is_funds_transfer_frmdep(narr):
|
|
68
|
+
return parse_funds_transfer_frmdep(narr), "fundstr"
|
|
69
|
+
|
|
70
|
+
# Vendor payments
|
|
71
|
+
if is_vendor_payment_remittance(narr):
|
|
72
|
+
return parse_vendor_payment_remittance(narr), "vpay_remit"
|
|
73
|
+
|
|
74
|
+
if is_vendor_payment_rmr(narr):
|
|
75
|
+
return parse_vendor_payment_rmr(narr), "vpymt"
|
|
76
|
+
|
|
77
|
+
if is_vendor_pay_narrative(narr):
|
|
78
|
+
return parse_vendor_pay_narrative(narr), "vpay"
|
|
79
|
+
|
|
80
|
+
# AvidPay
|
|
81
|
+
if is_avidpay_check(narr):
|
|
82
|
+
return parse_avidpay_check(narr), "avp_check"
|
|
83
|
+
|
|
84
|
+
if is_avidpay_generic(narr):
|
|
85
|
+
return parse_avidpay_generic(narr), "avp_gen"
|
|
86
|
+
|
|
87
|
+
# Card
|
|
88
|
+
if is_card_payment(narr):
|
|
89
|
+
return parse_card_payment(narr), "card"
|
|
90
|
+
|
|
91
|
+
# Invoice / Web
|
|
92
|
+
if is_invoice_reference(narr):
|
|
93
|
+
return parse_invoice_reference(narr), "invo"
|
|
94
|
+
|
|
95
|
+
if is_web_transfer(narr):
|
|
96
|
+
return parse_web_transfer(narr), "webt"
|
|
97
|
+
|
|
98
|
+
# Processor / EFT
|
|
99
|
+
if is_processor_eft(narr):
|
|
100
|
+
return parse_processor_eft(narr), "peft"
|
|
101
|
+
|
|
102
|
+
# Remittance / Merchant
|
|
103
|
+
if is_remittance_advice(narr):
|
|
104
|
+
return parse_remittance_advice(narr), "remi"
|
|
105
|
+
|
|
106
|
+
if is_merchant_reference(narr):
|
|
107
|
+
return parse_merchant_reference(narr), "merch"
|
|
108
|
+
|
|
109
|
+
# Direct Debit
|
|
110
|
+
if is_direct_debit(narr):
|
|
111
|
+
return parse_direct_debit(narr), "ddbt"
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
res = all_parser(rewritten_narr)
|
|
115
|
+
res["RAW"] = narr
|
|
116
|
+
return res, "generic"
|
counterparty/routines.py
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
def routine1(data):
|
|
5
|
+
# print("NEW KEY-VALUE PAIRS DETECTED.")
|
|
6
|
+
# print(f"ADD THEM TO THE LIST")
|
|
7
|
+
# for k in data[1]:
|
|
8
|
+
# print(f"{k} : {data[1][k]}")
|
|
9
|
+
# print()
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def routine2(key, value, inline=False):
|
|
14
|
+
key = key.strip().lower()
|
|
15
|
+
value = value.strip()
|
|
16
|
+
if not key or not value:
|
|
17
|
+
return
|
|
18
|
+
|
|
19
|
+
value_up = value.upper()
|
|
20
|
+
|
|
21
|
+
base = Path(__file__).resolve().parent
|
|
22
|
+
gamma = base.parent
|
|
23
|
+
|
|
24
|
+
# canonical_keys.json
|
|
25
|
+
canon_path = gamma / "key_engine" / "canonical_keys.json"
|
|
26
|
+
with open(canon_path, "r", encoding="utf-8") as f:
|
|
27
|
+
canon = json.load(f)
|
|
28
|
+
|
|
29
|
+
canon.setdefault(key, [])
|
|
30
|
+
if value.lower() not in canon[key]:
|
|
31
|
+
canon[key].append(value.lower())
|
|
32
|
+
with open(canon_path, "w", encoding="utf-8") as f:
|
|
33
|
+
json.dump(canon, f, indent=2)
|
|
34
|
+
|
|
35
|
+
all_path = gamma / "key_engine" / "keys.py"
|
|
36
|
+
add_to_keys(all_path, value_up, inline)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def add_to_keys(path, value, inline):
|
|
41
|
+
text = path.read_text(encoding="utf-8")
|
|
42
|
+
name = "INLINE_KEYS" if inline else "KEYS"
|
|
43
|
+
|
|
44
|
+
start = text.find(f"{name} = [")
|
|
45
|
+
if start == -1:
|
|
46
|
+
raise RuntimeError(f"{name} not found in {path}")
|
|
47
|
+
|
|
48
|
+
l = text.find("[", start)
|
|
49
|
+
r = text.find("]", l)
|
|
50
|
+
if l == -1 or r == -1:
|
|
51
|
+
raise RuntimeError(f"Broken {name} list in {path}")
|
|
52
|
+
|
|
53
|
+
body = text[l + 1:r]
|
|
54
|
+
items = []
|
|
55
|
+
|
|
56
|
+
for x in body.split(","):
|
|
57
|
+
x = x.strip().strip('"').strip("'")
|
|
58
|
+
if x:
|
|
59
|
+
items.append(x)
|
|
60
|
+
|
|
61
|
+
if value not in items:
|
|
62
|
+
items.append(value)
|
|
63
|
+
|
|
64
|
+
items = sorted(set(items), key=lambda x: (-len(x), x))
|
|
65
|
+
|
|
66
|
+
new_list = f"{name} = [\n"
|
|
67
|
+
for x in items:
|
|
68
|
+
new_list += f' "{x}",\n'
|
|
69
|
+
new_list += "]"
|
|
70
|
+
|
|
71
|
+
text = text[:start] + new_list + text[r + 1:]
|
|
72
|
+
path.write_text(text, encoding="utf-8")
|
counterparty/util.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from typing import Optional, Dict, Any
|
|
3
|
+
import unicodedata
|
|
4
|
+
|
|
5
|
+
# this is used in extract payer/payee logic
|
|
6
|
+
def norm2(v):
|
|
7
|
+
if v is None: return None
|
|
8
|
+
if isinstance(v, dict): v = v.get("value") or v.get("name")
|
|
9
|
+
s = str(v).strip()
|
|
10
|
+
s = unicodedata.normalize("NFKD", s)
|
|
11
|
+
s = s.encode("ascii", "ignore").decode("ascii")
|
|
12
|
+
s = re.sub(r"\s+", " ", s)
|
|
13
|
+
return s if s else None
|
|
14
|
+
|
|
15
|
+
# This one is for aliasing.
|
|
16
|
+
def normalize(text: str) -> str:
|
|
17
|
+
if not text: return ""
|
|
18
|
+
text = unicodedata.normalize("NFKD", text)
|
|
19
|
+
text = text.encode("ASCII", "ignore").decode("ASCII")
|
|
20
|
+
text = text.upper()
|
|
21
|
+
text = re.sub(r"[.,/\\]+", " ", text)
|
|
22
|
+
text = re.sub(r"\s+", " ", text)
|
|
23
|
+
return text.strip()
|
|
24
|
+
|
|
25
|
+
# This one is for wire/ach/swift detection
|
|
26
|
+
def norm(text: Optional[str]) -> str:
|
|
27
|
+
if not text: return ""
|
|
28
|
+
text = re.sub(r"^[,|]+", "", text)
|
|
29
|
+
text = re.sub(r"[\\|,]+$", "", text)
|
|
30
|
+
text = re.sub(r"\s+", " ", text)
|
|
31
|
+
return text.strip().upper()
|
|
32
|
+
|
|
33
|
+
# This one is when i want to run key_detector
|
|
34
|
+
def normalize_spaces(text: str) -> str:
|
|
35
|
+
text = text.replace('.','')
|
|
36
|
+
text = text.replace(',',' ')
|
|
37
|
+
# add space BEFORE and AFTER delimiter if missing
|
|
38
|
+
text = re.sub(r"(?<!\s)([:,=;#])", r" \1", text)
|
|
39
|
+
text = re.sub(r"([:,=;#])(?!\s)", r"\1 ", text)
|
|
40
|
+
return " ".join(text.split())
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
counterparty/__init__.py,sha256=LfM7ucTBfJhqumdJOT5411VdVG_RpHYvRoA0rvMNkwI,809
|
|
2
|
+
counterparty/route.py,sha256=Al8fLE0l3ITd-s5TMNR3SPp4bNKKfnH0vRmcnAtYzv0,4300
|
|
3
|
+
counterparty/routines.py,sha256=ELA34Pb36RIgzf7A5MRjcnLKCIZTSWQU09RHQPWs8qE,1915
|
|
4
|
+
counterparty/util.py,sha256=3_Zkcoef9U3qxsP38DANDLTj0khQFICRnHWUpOQIkKI,1319
|
|
5
|
+
counterparty/extraction/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
counterparty/extraction/clean.py,sha256=etNHWosQMM3REi1T6Cap0EZtGvAjxR0F74HWxLj3GoQ,3586
|
|
7
|
+
counterparty/extraction/extract_payer_payee.py,sha256=G92jLvNvLycU2Z9Ub24Rz5CzVXKATuGZaphYbOJlpjM,5296
|
|
8
|
+
counterparty/extraction/infer_counterparty.py,sha256=TmVuiJ0yUHuQUIdQEck9ikrSbp47gJpfu-vq414gGv4,411
|
|
9
|
+
counterparty/key_engine/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
+
counterparty/key_engine/canonical_keys.json,sha256=mNQYbLmAwEFq3C5PwkHS3uMKYiBPLVcPpMm4D9HIAlg,5277
|
|
11
|
+
counterparty/key_engine/key_detector.py,sha256=uVbHRTa5gr-_UZ0eFWOGgjXrRjWtNz_XLVF_g4AV9CA,9592
|
|
12
|
+
counterparty/key_engine/keys.py,sha256=ID42R1lh2h_1NajZI0qouokudcPbhz1QeHLXc4JvGyw,6143
|
|
13
|
+
counterparty/parsers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
+
counterparty/parsers/LAT_AM/LAT_AM_Entry.py,sha256=ObjjlKDdwzGaiboSFdqTlxDaiPvxNsxPMJe-G6hIofE,2728
|
|
15
|
+
counterparty/parsers/LAT_AM/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
+
counterparty/parsers/LAT_AM/pattern1.py,sha256=yPCotFTNThl6MhJjauCzwnaS_gUOP7-JJp5UHwa9KHo,3968
|
|
17
|
+
counterparty/parsers/LAT_AM/pattern10.py,sha256=eivRBqSdMrmkgmPX0qvqzG5l4bP6TQps_3bhCQm3gA0,1658
|
|
18
|
+
counterparty/parsers/LAT_AM/pattern11.py,sha256=2UsgNGLxZbEG9VzcfYpXdshwwuqbgP6q24Sq05ysnwI,1516
|
|
19
|
+
counterparty/parsers/LAT_AM/pattern12.py,sha256=fQY1sgBi0RfpwcU2dLMED9I8HLdRPmHm3Yih9VmnPlg,2432
|
|
20
|
+
counterparty/parsers/LAT_AM/pattern2.py,sha256=pmBh06VQ0rh-FI1KFpDEW3_jTqHqtifxjQ4vDl9RSvA,2651
|
|
21
|
+
counterparty/parsers/LAT_AM/pattern3.py,sha256=hHBiUxQ98uOMuC9UHnNobsPg8QN_ylwqSf4GaY521EY,1702
|
|
22
|
+
counterparty/parsers/LAT_AM/pattern4.py,sha256=A_idcKDZSX93mydQJNSzn-ONODZu1pxUINQTUen_Pwg,3401
|
|
23
|
+
counterparty/parsers/LAT_AM/pattern5.py,sha256=C8jc32oga6VDfO_xy9B6A44ZNa4FBXFaaId51DJ4pXo,1106
|
|
24
|
+
counterparty/parsers/LAT_AM/pattern6.py,sha256=xl1vo4mhbjAYSINVGLQf_ZkPRh4-q_Uzhtx1o0eiHro,3535
|
|
25
|
+
counterparty/parsers/LAT_AM/pattern7.py,sha256=MZrQb4ZbmwxDc2Xlt1SV-de9aXqbN_duvBqxWgXn9ww,2783
|
|
26
|
+
counterparty/parsers/LAT_AM/pattern8.py,sha256=Ci9-O_AmzMxToAM8SE2_4FePwOXcvT-K3f3Mqd78sRg,3273
|
|
27
|
+
counterparty/parsers/LAT_AM/pattern9.py,sha256=NOTLM_TdmANXGW77-668iLfesijoHarR62-z2BE92uA,2113
|
|
28
|
+
counterparty/parsers/ach/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
29
|
+
counterparty/parsers/ach/ach_parser.py,sha256=pA6JJw12ry8Hi8Hs7CM2Fsxdv53HLgXe4WFWvtBfbbs,4409
|
|
30
|
+
counterparty/parsers/avidpay/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
31
|
+
counterparty/parsers/avidpay/avidp_check_parser.py,sha256=7usYY7jU4CiaKrS8FGaWhZN2Ls-cmkU3uT7PD9J581g,1825
|
|
32
|
+
counterparty/parsers/avidpay/avidp_gen_parser.py,sha256=jkXviSVukB0SPX-OxQcsAWhfxpgRH7HrQ_zkVJXqLQ4,1435
|
|
33
|
+
counterparty/parsers/directdebit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
34
|
+
counterparty/parsers/directdebit/directdeb.py,sha256=DxSnukw9421LN_-4oZmxsUmfqxxeh0E8ckqPs0F3ORw,1654
|
|
35
|
+
counterparty/parsers/disbursement/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
36
|
+
counterparty/parsers/disbursement/disb_parser.py,sha256=xwY4ORQfVZpiyGTjd5r7LYJf8oekqfdFQvU4X22Fdc4,1438
|
|
37
|
+
counterparty/parsers/fundsTransfer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
38
|
+
counterparty/parsers/fundsTransfer/fundsTrans_parser.py,sha256=gFv8bdd9CUdvW0bXJdJamnOfSuvmk8PEUfX_se3CqJ4,1838
|
|
39
|
+
counterparty/parsers/generic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
40
|
+
counterparty/parsers/generic/all_parser.py,sha256=s_mBBJ7x1wOLD9E_IoQ5F9msjbTVSnXr771XZbbrLPc,2272
|
|
41
|
+
counterparty/parsers/merchref/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
42
|
+
counterparty/parsers/merchref/merch_ref_parser.py,sha256=INn6QwjNp4CbSOqejuJhLawYj1Zkn207vwKSeY6dsFA,1022
|
|
43
|
+
counterparty/parsers/misc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
44
|
+
counterparty/parsers/misc/cardp.py,sha256=_cmKZRWqg2Sjay0rkoe1iTZkHuUulSKc5KHPn2nYf9U,1384
|
|
45
|
+
counterparty/parsers/misc/invo.py,sha256=R3UJSPuDusrT_auFvWdgLBISyLj78DqJjwfWQIrt-0M,2066
|
|
46
|
+
counterparty/parsers/misc/webt.py,sha256=YWX7tpWLlQ-wkArS4ihhiRUeEQRh1H843XrtCG5eFig,1259
|
|
47
|
+
counterparty/parsers/paypal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
48
|
+
counterparty/parsers/paypal/paypal.py,sha256=G_ex6MrIE1QiyUDlXiWXfHU3_uVhEihJ3vdJVNrDoB4,2454
|
|
49
|
+
counterparty/parsers/processor_eft/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
50
|
+
counterparty/parsers/processor_eft/peft.py,sha256=LiQ3rJWQ_9BJWCUJELXXdnQDScifu3060pZuEk10lsk,2686
|
|
51
|
+
counterparty/parsers/remittance/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
52
|
+
counterparty/parsers/remittance/remi.py,sha256=tgoJhLLcLWxRmzrkEsyYoMjBCvhFilpg1vs07EdLJ_U,1898
|
|
53
|
+
counterparty/parsers/swift/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
54
|
+
counterparty/parsers/swift/swift_parser.py,sha256=szNX55hNIWn82dNwLEnUmvwYq7uw7na7xupYfYyGzSs,2596
|
|
55
|
+
counterparty/parsers/vendorpay/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
56
|
+
counterparty/parsers/vendorpay/vp_parser.py,sha256=uVS5c7K0yMfuDqDYtAt2DZG8WJVHeZ1FoFtXq-Xcs5o,1157
|
|
57
|
+
counterparty/parsers/vendorpymt/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
58
|
+
counterparty/parsers/vendorpymt/vpymt_parser.py,sha256=2ZTzhQXUwBo5iud1IiHYLewPm6PTpu5EBRetV9ctXH8,2953
|
|
59
|
+
counterparty/parsers/wire/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
60
|
+
counterparty/parsers/wire/wire_parser.py,sha256=iy1hwB0yztpYZ0uHKI9daISZgq3kqRQR8C9ZB-18R3w,3412
|
|
61
|
+
counterparty-0.1.6.dist-info/METADATA,sha256=-lcL8pr2To_hxp71eEesdC3TcH0xZoAnnW2R3-_JN3I,246
|
|
62
|
+
counterparty-0.1.6.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
63
|
+
counterparty-0.1.6.dist-info/top_level.txt,sha256=4GalgZH-igUEpExaDNOZUNUANXkbQRu3MnRc8Mcczoc,13
|
|
64
|
+
counterparty-0.1.6.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
counterparty
|