feat(jobs): mirror delivery_method/ship_via/invoice_strategy on fp.job

Tier 3 of the SO->fp.job persistence audit. Three logistics/billing
fields surface on fp.job as related read-only (not stored) mirrors:

- x_fc_delivery_method - Local Delivery / Shipping Partner / Customer
  Pickup. Cargo classification used by logistics planning.
- x_fc_ship_via - Carrier name (UPS, FedEx, customer pickup, etc.).
- x_fc_invoice_strategy - Deposit / Progress / Net Terms / COD-Prepay.
  Read by the invoicing module's hooks; mirroring on the WO is for
  manager visibility only.

These were intentionally chosen as related (not stored persisted)
because the SO is the authoritative source - the existing downstream
code (delivery + invoicing modules) already reads them off SO directly.
A stored copy would risk drift. Related auto-follows SO updates.

Same three fields also mirrored on sale.order.line as stored related
for per-line list visibility.

Closes the SO->fp.job persistence audit. All 10 operational fields
identified now flow through to the WO (7 stored + populated at confirm,
3 related read-only).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-05-12 08:39:12 -04:00
parent 15eac309ee
commit cba9a6da6b
6 changed files with 45 additions and 3 deletions

View File

@@ -23,6 +23,26 @@ _logger = logging.getLogger(__name__)
class FpJob(models.Model):
_inherit = 'fp.job'
# ---- Tier 3 mirrors from sale.order -----------------------------
# Related (not stored) — pure display mirrors. Values may change on
# the SO after job confirm (e.g. customer changes carrier preference)
# and the WO should reflect the latest; related auto-follows.
x_fc_delivery_method = fields.Selection(
related='sale_order_id.x_fc_delivery_method',
string='Delivery Method',
readonly=True,
)
x_fc_ship_via = fields.Char(
related='sale_order_id.x_fc_ship_via',
string='Ship Via',
readonly=True,
)
x_fc_invoice_strategy = fields.Selection(
related='sale_order_id.x_fc_invoice_strategy',
string='Invoice Strategy',
readonly=True,
)
part_catalog_id = fields.Many2one(
'fp.part.catalog',
string='Part',