Files
Odoo-Modules/match_poynt_v2.py
gsinghpal c66bdf5089 changes
2026-04-03 15:45:18 -04:00

136 lines
4.9 KiB
Python

import logging
from datetime import timedelta
SL = env['poynt.settlement.line'].sudo()
Invoice = env['account.move'].sudo()
# Reset name-matched ones that don't have invoices — they might be wrong
bad_name_matches = SL.search([
('state', '=', 'matched'),
('match_method', '=', 'cardholder_name'),
('invoice_id', '=', False),
])
if bad_name_matches:
bad_name_matches.write({'state': 'fetched', 'partner_id': False, 'match_method': False})
print(f'Reset {len(bad_name_matches)} name-only matches without invoices', flush=True)
env.cr.commit()
lines = SL.search([('state', '=', 'fetched'), ('action', '=', 'SALE')])
print(f'Unmatched SALE lines to process: {len(lines)}', flush=True)
matched_invoice = 0
matched_card_history = 0
no_match = 0
# --- Build card history: which card_last4 has paid for which partner before? ---
# From already-matched lines
card_partner_map = {}
matched_lines = SL.search([('state', '=', 'matched'), ('partner_id', '!=', False)])
for ml in matched_lines:
if ml.card_last4:
key = (ml.card_brand, ml.card_last4)
card_partner_map.setdefault(key, set()).add(ml.partner_id.id)
# Also from payment.transaction (Odoo-processed payments with card tokens)
env.cr.execute("""
SELECT pt.payment_method_code, pt.provider_reference, pt.partner_id,
tok.provider_ref
FROM payment_transaction pt
LEFT JOIN payment_token tok ON pt.token_id = tok.id
WHERE pt.provider_code = 'poynt' AND pt.state = 'done' AND pt.partner_id IS NOT NULL
""")
for row in env.cr.fetchall():
pass # Token data doesn't reliably have last4
print(f'Card history: {len(card_partner_map)} unique cards mapped to partners', flush=True)
for sl in lines:
amount = sl.amount
txn_date = sl.transaction_date.date() if sl.transaction_date else None
if not txn_date:
no_match += 1
continue
partner = None
invoice = None
# --- Strategy 1: Match by exact amount against open invoices ---
if amount > 20:
invs = Invoice.search([
('move_type', '=', 'out_invoice'),
('payment_state', 'in', ('not_paid', 'partial')),
('amount_residual', '>=', amount - 0.50),
('amount_residual', '<=', amount + 0.50),
('invoice_date', '>=', str(txn_date - timedelta(days=90))),
('invoice_date', '<=', str(txn_date + timedelta(days=5))),
], limit=5)
if len(invs) == 1:
# Unique match — confident
partner = invs[0].partner_id
invoice = invs[0]
elif len(invs) > 1:
# Multiple invoices with same amount — try card history to pick one
card_key = (sl.card_brand, sl.card_last4)
known_partners = card_partner_map.get(card_key, set())
for inv in invs:
if inv.partner_id.id in known_partners:
partner = inv.partner_id
invoice = inv
break
# --- Strategy 2: Card history (same card paid before for same partner) ---
if not partner and sl.card_last4:
card_key = (sl.card_brand, sl.card_last4)
known_partners = card_partner_map.get(card_key, set())
if len(known_partners) == 1:
pid = list(known_partners)[0]
# Check if this partner has any open invoice close to this amount
invs = Invoice.search([
('partner_id', '=', pid),
('move_type', '=', 'out_invoice'),
('payment_state', 'in', ('not_paid', 'partial')),
('amount_residual', '>=', amount - 5),
('amount_residual', '<=', amount + 5),
], limit=1)
if invs:
partner = invs[0].partner_id
invoice = invs[0]
matched_card_history += 1
if partner:
vals = {
'partner_id': partner.id,
'state': 'matched',
'match_method': 'invoice_amount' if invoice else 'card_history',
}
if invoice:
vals['invoice_id'] = invoice.id
matched_invoice += 1
sl.write(vals)
# Update card history
if sl.card_last4:
card_key = (sl.card_brand, sl.card_last4)
card_partner_map.setdefault(card_key, set()).add(partner.id)
else:
no_match += 1
if (matched_invoice + matched_card_history + no_match) % 100 == 0:
env.cr.commit()
env.cr.commit()
print(f'\nRESULTS:', flush=True)
print(f' Matched by invoice amount: {matched_invoice}', flush=True)
print(f' Matched by card history: {matched_card_history}', flush=True)
print(f' No match: {no_match}', flush=True)
# Final stats
print(f'\nFINAL STATE:', flush=True)
for state in ['matched', 'fetched']:
cnt = SL.search_count([('state', '=', state)])
print(f' {state}: {cnt}', flush=True)
inv_cnt = SL.search_count([('invoice_id', '!=', False)])
print(f' With invoice linked: {inv_cnt}', flush=True)