feat(configurator): "PO Pending" escape hatch for customers who send PO later

Customer feedback: some customers don't send their PO with the
initial order — they send it days or weeks later. The system was
blocking SO confirmation without a PO, which forced the shop to
either wait on paperwork or ask a manager for a formal override.

New estimator-level path: a "PO Pending" boolean on sale.order +
an optional "PO Expected By" date.

  * Confirm without a PO# / PO document when PO Pending is ticked.
  * action_confirm skips the hard error if po_pending OR po_override
    is set (keeps the existing manager-override path too).
  * On confirm with PO Pending, the system schedules a chase
    activity for po_expected_date (or +3 days if blank), assigned
    via mail.activity so it shows up in the sales user's activity
    list. Chatter note logged so audit is obvious.
  * Direct-order wizard: po_number and po_attachment_file become
    optional. Ticking "PO Pending" in the wizard is the trade-in;
    a help note under the toggle explains the chase behaviour.
  * Once the PO arrives, user fills in the PO# / uploads the doc,
    and turns PO Pending off — existing downstream flow resumes.

Difference from x_fc_po_override (kept):
  * PO Override = manager waiver, permanent ("handshake deal").
  * PO Pending = estimator flag, time-boxed ("customer will send it
    by Friday").

fusion_plating_configurator → 19.0.14.0.0
fusion_plating_invoicing    → 19.0.3.0.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-04-23 10:08:00 -04:00
parent 2d3ee03f86
commit 8142bd229a
7 changed files with 131 additions and 21 deletions

View File

@@ -28,6 +28,25 @@ class SaleOrder(models.Model):
x_fc_po_override = fields.Boolean(string='PO Override',
help='Manager override — proceed without formal PO (handshake deal).')
x_fc_po_override_reason = fields.Text(string='Override Reason')
# Estimator-level "PO is coming later" flag. Unlike PO Override
# (permanent, manager-only), this one is time-boxed: the order
# confirms with no PO yet, but a chase activity is scheduled for
# po_expected_date so sales chases the customer for the paperwork.
x_fc_po_pending = fields.Boolean(
string='PO Pending',
tracking=True,
help='Customer will provide the PO later. Confirms the order '
'without a PO number, schedules a chase activity, and '
'shows a "PO Pending" ribbon on the form. Toggle off once '
'the real PO arrives and you\'ve entered it below.',
)
x_fc_po_expected_date = fields.Date(
string='PO Expected By',
tracking=True,
help='Date the customer promised to send the PO. A follow-up '
'activity is scheduled for this date when the order is '
'confirmed with PO Pending set.',
)
x_fc_invoice_strategy = fields.Selection(
[('deposit', 'Deposit'), ('progress', 'Progress Billing'),
('net_terms', 'Net Terms'), ('cod_prepay', 'COD / Prepay')],