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

124 lines
4.7 KiB
Python

import logging
import re
_logger = logging.getLogger('poynt_match')
SL = env['poynt.settlement.line'].sudo()
Partner = env['res.partner'].sudo()
Invoice = env['account.move'].sudo()
lines = SL.search([('state', '=', 'fetched'), ('action', '=', 'SALE')])
print(f'Unmatched SALE lines: {len(lines)}', flush=True)
matched_by_name = 0
matched_by_amount = 0
no_match = 0
for sl in lines:
name = (sl.card_holder_name or '').strip()
amount = sl.amount
txn_date = sl.transaction_date.date() if sl.transaction_date else None
partner = None
# --- Strategy 1: Match by cardholder name ---
if name and name != '/':
# Parse LASTNAME/FIRSTNAME or FIRSTNAME LASTNAME
if '/' in name:
parts = name.split('/')
last_name = parts[0].strip().title()
first_name = parts[1].strip().title() if len(parts) > 1 else ''
else:
parts = name.split()
first_name = parts[0].title() if parts else ''
last_name = parts[-1].title() if len(parts) > 1 else ''
if last_name and first_name:
# Exact match: "Lastname, Firstname" or "Firstname Lastname"
candidates = Partner.search([
('customer_rank', '>', 0),
'|',
('name', 'ilike', f'{last_name}, {first_name}'),
('name', 'ilike', f'{first_name} {last_name}'),
], limit=5)
# If still ambiguous (>1), try to narrow by matching amount to open invoices
if len(candidates) == 1:
partner = candidates[0]
elif len(candidates) > 1:
# Pick the one with an open invoice matching the amount
for c in candidates:
inv = Invoice.search([
('partner_id', '=', c.id),
('move_type', '=', 'out_invoice'),
('payment_state', 'in', ('not_paid', 'partial')),
('amount_residual', '>=', amount - 1),
('amount_residual', '<=', amount + 1),
], limit=1)
if inv:
partner = c
break
if not partner:
partner = candidates[0] # Take first if no invoice match
# --- Strategy 2: Match by amount against open invoices (if no name match) ---
if not partner and txn_date and amount > 50:
# Look for open invoices with matching amount within ±30 days
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 - __import__('datetime').timedelta(days=60))),
('invoice_date', '<=', str(txn_date + __import__('datetime').timedelta(days=5))),
], limit=3)
if len(invs) == 1:
partner = invs[0].partner_id
sl.invoice_id = invs[0].id
# --- Write match ---
if partner:
vals = {'partner_id': partner.id, 'state': 'matched'}
if name and name != '/':
vals['match_method'] = 'cardholder_name'
matched_by_name += 1
else:
vals['match_method'] = 'invoice_amount'
matched_by_amount += 1
# Also try to find matching invoice if not already set
if not sl.invoice_id and txn_date:
inv = Invoice.search([
('partner_id', '=', partner.id),
('move_type', '=', 'out_invoice'),
('payment_state', 'in', ('not_paid', 'partial')),
('amount_residual', '>=', amount - 1),
('amount_residual', '<=', amount + 1),
], limit=1)
if inv:
vals['invoice_id'] = inv.id
sl.write(vals)
else:
no_match += 1
if (matched_by_name + matched_by_amount + no_match) % 100 == 0:
env.cr.commit()
env.cr.commit()
total_matched = matched_by_name + matched_by_amount
print(f'\nRESULTS:', flush=True)
print(f' Matched by name: {matched_by_name}', flush=True)
print(f' Matched by invoice amount: {matched_by_amount}', flush=True)
print(f' No match: {no_match}', flush=True)
print(f' Total matched: {total_matched}/{len(lines)} ({round(100*total_matched/len(lines),1) if lines else 0}%)', flush=True)
# Summary
all_lines = SL.search([])
print(f'\nOVERALL:', flush=True)
print(f' Total lines: {len(all_lines)}', flush=True)
print(f' Matched: {SL.search_count([("state", "=", "matched")])}', flush=True)
print(f' With invoice: {SL.search_count([("invoice_id", "!=", False)])}', flush=True)
print(f' Fetched (unmatched): {SL.search_count([("state", "=", "fetched")])}', flush=True)