77 lines
3.1 KiB
Python
77 lines
3.1 KiB
Python
# Step 8 — Jane creates the invoice for the completed SO and posts it.
|
|
# Test:
|
|
# A) SO has invoice_status = 'to invoice' after delivery
|
|
# B) Jane creates the invoice
|
|
# C) Invoice draft has correct lines, taxes, payment terms
|
|
# D) Jane posts → invoice posted, account moves balanced
|
|
# E) Notification fires (best-effort)
|
|
|
|
so = env['sale.order'].browse(423)
|
|
print(f'[Jane] Looking at SO {so.name}')
|
|
print(f' state: {so.state}')
|
|
print(f' invoice_status: {so.invoice_status}')
|
|
print(f' amount_total: {so.amount_total} {so.currency_id.symbol}')
|
|
print(f' payment_term_id: {so.payment_term_id.name if so.payment_term_id else None}')
|
|
print(f' x_fc_invoice_strategy: {so.x_fc_invoice_strategy}')
|
|
print(f' partner.account hold? {getattr(so.partner_id, "x_fc_account_hold", False)}')
|
|
|
|
# What's already invoiced?
|
|
existing = env['account.move'].search([
|
|
('invoice_origin', '=', so.name),
|
|
])
|
|
print(f' Existing invoices for this SO: {len(existing)}')
|
|
for inv in existing:
|
|
print(f' {inv.name}: state={inv.state}, type={inv.move_type}, amount={inv.amount_total}')
|
|
|
|
# Path A: create invoices.
|
|
print()
|
|
print('[Jane] Clicks "Create Invoice"')
|
|
if so.invoice_status == 'to invoice':
|
|
try:
|
|
result = so._create_invoices()
|
|
new_invs = env['account.move'].search([
|
|
('invoice_origin', '=', so.name), ('id', 'not in', existing.ids),
|
|
])
|
|
print(f' Created {len(new_invs)} new invoice(s)')
|
|
for inv in new_invs:
|
|
print(f' {inv.name}: state={inv.state}, lines={len(inv.invoice_line_ids)}')
|
|
for ln in inv.invoice_line_ids:
|
|
print(f' - {ln.name[:50]}: qty={ln.quantity}, price={ln.price_unit}, subtotal={ln.price_subtotal}')
|
|
except Exception as e:
|
|
print(f' ❌ {e}')
|
|
else:
|
|
print(f' Skipped — invoice_status={so.invoice_status} (nothing to invoice)')
|
|
new_invs = env['account.move'].browse()
|
|
|
|
# Path B: post.
|
|
if new_invs:
|
|
inv = new_invs[0]
|
|
print()
|
|
print(f'[Jane] Posting invoice {inv.name}:')
|
|
try:
|
|
inv.action_post()
|
|
print(f' ✓ state={inv.state}')
|
|
print(f' payment_state={inv.payment_state}')
|
|
except Exception as e:
|
|
print(f' ❌ {e}')
|
|
|
|
# Verify the SO progress: invoice_status should now show 'invoiced'
|
|
print()
|
|
print(f'[Jane] After posting:')
|
|
print(f' SO invoice_status: {so.invoice_status}')
|
|
print(f' Outstanding receivables on partner: {sum(env["account.move"].search([("partner_id", "=", so.partner_id.id), ("move_type", "=", "out_invoice"), ("state", "=", "posted"), ("payment_state", "in", ("not_paid", "partial"))]).mapped("amount_residual"))}')
|
|
|
|
# Notification check.
|
|
print()
|
|
print(f'[Jane] Notification logs for this SO/invoice:')
|
|
NotifLog = env['fp.notification.log'] if 'fp.notification.log' in env else None
|
|
if NotifLog and new_invs:
|
|
logs = NotifLog.search([('source_record_id', 'in', new_invs.ids)])
|
|
print(f' {len(logs)} notification log(s)')
|
|
for lg in logs:
|
|
print(f' {lg.trigger_event} → {lg.partner_id.name if lg.partner_id else "(no partner)"} sent_at={lg.sent_at if "sent_at" in lg._fields else "?"}')
|
|
|
|
env.cr.commit()
|
|
print()
|
|
print('== Step 8 complete ==')
|