166 lines
5.6 KiB
Python
166 lines
5.6 KiB
Python
import logging
|
|
from odoo import fields
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
def get_ar_aging(env, params):
|
|
today = fields.Date.today()
|
|
domain = [
|
|
('account_id.account_type', '=', 'asset_receivable'),
|
|
('parent_state', '=', 'posted'),
|
|
('reconciled', '=', False),
|
|
('company_id', '=', env.company.id),
|
|
]
|
|
amls = env['account.move.line'].search(domain)
|
|
|
|
buckets = {'current': 0, '1_30': 0, '31_60': 0, '61_90': 0, '90_plus': 0}
|
|
for aml in amls:
|
|
if not aml.date_maturity or aml.date_maturity >= today:
|
|
buckets['current'] += aml.amount_residual
|
|
else:
|
|
days = (today - aml.date_maturity).days
|
|
if days <= 30:
|
|
buckets['1_30'] += aml.amount_residual
|
|
elif days <= 60:
|
|
buckets['31_60'] += aml.amount_residual
|
|
elif days <= 90:
|
|
buckets['61_90'] += aml.amount_residual
|
|
else:
|
|
buckets['90_plus'] += aml.amount_residual
|
|
|
|
return {
|
|
'total': sum(buckets.values()),
|
|
'buckets': buckets,
|
|
'line_count': len(amls),
|
|
}
|
|
|
|
|
|
def get_overdue_invoices(env, params):
|
|
today = fields.Date.today()
|
|
days_overdue = int(params.get('min_days_overdue', 1))
|
|
from datetime import timedelta
|
|
cutoff = today - timedelta(days=days_overdue)
|
|
invoices = env['account.move'].search([
|
|
('move_type', '=', 'out_invoice'),
|
|
('state', '=', 'posted'),
|
|
('payment_state', 'in', ('not_paid', 'partial')),
|
|
('invoice_date_due', '<', cutoff),
|
|
('company_id', '=', env.company.id),
|
|
], order='invoice_date_due asc', limit=int(params.get('limit', 50)))
|
|
return {
|
|
'count': len(invoices),
|
|
'invoices': [{
|
|
'id': inv.id,
|
|
'name': inv.name,
|
|
'partner': inv.partner_id.name if inv.partner_id else '',
|
|
'email': inv.partner_id.email or '' if inv.partner_id else '',
|
|
'phone': inv.partner_id.phone or '' if inv.partner_id else '',
|
|
'amount_total': inv.amount_total,
|
|
'amount_residual': inv.amount_residual,
|
|
'date_due': str(inv.invoice_date_due),
|
|
'days_overdue': (today - inv.invoice_date_due).days,
|
|
} for inv in invoices],
|
|
}
|
|
|
|
|
|
def get_partner_balance(env, params):
|
|
partner_id = int(params['partner_id'])
|
|
partner = env['res.partner'].browse(partner_id)
|
|
if not partner.exists():
|
|
return {'error': 'Partner not found'}
|
|
amls = env['account.move.line'].search([
|
|
('partner_id', '=', partner_id),
|
|
('account_id.account_type', '=', 'asset_receivable'),
|
|
('parent_state', '=', 'posted'),
|
|
('reconciled', '=', False),
|
|
('company_id', '=', env.company.id),
|
|
])
|
|
return {
|
|
'partner': partner.name,
|
|
'balance': sum(aml.amount_residual for aml in amls),
|
|
'open_items': [{
|
|
'id': aml.id,
|
|
'ref': aml.ref or aml.move_id.name,
|
|
'date': str(aml.date),
|
|
'amount_residual': aml.amount_residual,
|
|
'date_maturity': str(aml.date_maturity) if aml.date_maturity else '',
|
|
} for aml in amls],
|
|
}
|
|
|
|
|
|
def send_followup(env, params):
|
|
partner_id = int(params['partner_id'])
|
|
partner = env['res.partner'].browse(partner_id)
|
|
if not partner.exists():
|
|
return {'error': 'Partner not found'}
|
|
options = {
|
|
'partner_id': partner_id,
|
|
'email': params.get('send_email', False),
|
|
'print': params.get('print_letter', False),
|
|
'sms': False,
|
|
}
|
|
if params.get('email_subject'):
|
|
options['email_subject'] = params['email_subject']
|
|
if params.get('body'):
|
|
options['body'] = params['body']
|
|
result = partner.execute_followup(options)
|
|
return {'status': 'sent', 'partner': partner.name, 'result': str(result) if result else 'done'}
|
|
|
|
|
|
def get_followup_report(env, params):
|
|
partner_id = int(params['partner_id'])
|
|
partner = env['res.partner'].browse(partner_id)
|
|
if not partner.exists():
|
|
return {'error': 'Partner not found'}
|
|
try:
|
|
report = env['account.followup.report']
|
|
html = report._get_followup_report_html(partner)
|
|
return {'partner': partner.name, 'html': html}
|
|
except Exception as e:
|
|
return {'error': str(e)}
|
|
|
|
|
|
def reconcile_payment_to_invoice(env, params):
|
|
move_line_ids = [int(x) for x in params['move_line_ids']]
|
|
amls = env['account.move.line'].browse(move_line_ids)
|
|
if len(amls) < 2:
|
|
return {'error': 'Need at least 2 journal items to reconcile'}
|
|
amls.reconcile()
|
|
return {
|
|
'status': 'reconciled',
|
|
'move_line_ids': move_line_ids,
|
|
}
|
|
|
|
|
|
def get_unmatched_payments(env, params):
|
|
domain = [
|
|
('account_id.account_type', '=', 'asset_receivable'),
|
|
('parent_state', '=', 'posted'),
|
|
('reconciled', '=', False),
|
|
('move_id.payment_id', '!=', False),
|
|
('company_id', '=', env.company.id),
|
|
]
|
|
amls = env['account.move.line'].search(domain, order='date desc')
|
|
return {
|
|
'count': len(amls),
|
|
'payments': [{
|
|
'id': aml.id,
|
|
'date': str(aml.date),
|
|
'ref': aml.ref or aml.move_id.name,
|
|
'partner': aml.partner_id.name if aml.partner_id else '',
|
|
'amount': abs(aml.amount_residual),
|
|
} for aml in amls[:50]],
|
|
}
|
|
|
|
|
|
TOOLS = {
|
|
'get_ar_aging': get_ar_aging,
|
|
'get_overdue_invoices': get_overdue_invoices,
|
|
'get_partner_balance': get_partner_balance,
|
|
'send_followup': send_followup,
|
|
'get_followup_report': get_followup_report,
|
|
'reconcile_payment_to_invoice': reconcile_payment_to_invoice,
|
|
'get_unmatched_payments': get_unmatched_payments,
|
|
}
|