diff --git a/fusion_plating/fusion_plating_configurator/models/sale_order.py b/fusion_plating/fusion_plating_configurator/models/sale_order.py
index 15b83dfe..d4428a1a 100644
--- a/fusion_plating/fusion_plating_configurator/models/sale_order.py
+++ b/fusion_plating/fusion_plating_configurator/models/sale_order.py
@@ -70,6 +70,18 @@ class SaleOrder(models.Model):
x_fc_internal_deadline = fields.Date(
string='Internal Deadline', tracking=True,
)
+ x_fc_is_blanket_order = fields.Boolean(
+ string='Is Blanket Sales Order',
+ help='Blanket orders release parts in quantities over time, '
+ 'often with a negotiated price and a fixed expiry.',
+ tracking=True,
+ )
+ x_fc_block_partial_shipments = fields.Boolean(
+ string='Block Partial Shipments',
+ help='If set, the order must ship all-or-nothing. '
+ 'Partial pickings are blocked.',
+ tracking=True,
+ )
@api.onchange('upload_rfq_file')
def _onchange_upload_rfq_file(self):
diff --git a/fusion_plating/fusion_plating_configurator/models/sale_order_line.py b/fusion_plating/fusion_plating_configurator/models/sale_order_line.py
index 4c3e533a..408663c6 100644
--- a/fusion_plating/fusion_plating_configurator/models/sale_order_line.py
+++ b/fusion_plating/fusion_plating_configurator/models/sale_order_line.py
@@ -20,3 +20,8 @@ class SaleOrderLine(models.Model):
)
x_fc_part_deadline = fields.Date(string='Part Deadline')
x_fc_rush_order = fields.Boolean(string='Rush')
+ x_fc_wo_group_tag = fields.Char(
+ string='Work Order Group',
+ help='Lines sharing a tag (e.g. "WO#1") will be batched into one '
+ 'manufacturing order when bridge_mrp generates MOs.',
+ )
diff --git a/fusion_plating/fusion_plating_configurator/views/sale_order_views.xml b/fusion_plating/fusion_plating_configurator/views/sale_order_views.xml
index 289c6229..4802b3e5 100644
--- a/fusion_plating/fusion_plating_configurator/views/sale_order_views.xml
+++ b/fusion_plating/fusion_plating_configurator/views/sale_order_views.xml
@@ -89,6 +89,8 @@
+
+
@@ -98,6 +100,7 @@
+
diff --git a/fusion_plating/fusion_plating_configurator/wizard/fp_direct_order_line.py b/fusion_plating/fusion_plating_configurator/wizard/fp_direct_order_line.py
index 324cf7a8..d5e8017a 100644
--- a/fusion_plating/fusion_plating_configurator/wizard/fp_direct_order_line.py
+++ b/fusion_plating/fusion_plating_configurator/wizard/fp_direct_order_line.py
@@ -79,6 +79,11 @@ class FpDirectOrderLine(models.TransientModel):
help='Per-line deadline. Defaults to SO customer deadline if blank.',
)
rush_order = fields.Boolean(string='Rush')
+ wo_group_tag = fields.Char(
+ string='WO Group',
+ help='Free-text tag. Lines sharing a tag (e.g. "WO#1", "WO#2") '
+ 'will be batched into one manufacturing order.',
+ )
# ---- Description ----
description_template_id = fields.Many2one(
@@ -91,12 +96,28 @@ class FpDirectOrderLine(models.TransientModel):
'Edit freely — your changes override the template.',
)
+ # ---- Missing info per line ----
+ is_missing_info = fields.Boolean(
+ string='Missing Info',
+ compute='_compute_is_missing_info',
+ )
+
# ---- Computes ----
@api.depends('quantity', 'unit_price')
def _compute_line_subtotal(self):
for rec in self:
rec.line_subtotal = (rec.quantity or 0) * (rec.unit_price or 0.0)
+ @api.depends('part_catalog_id', 'coating_config_id', 'unit_price', 'quantity')
+ def _compute_is_missing_info(self):
+ for rec in self:
+ rec.is_missing_info = not (
+ rec.part_catalog_id
+ and rec.coating_config_id
+ and rec.unit_price
+ and rec.quantity
+ )
+
# ---- Onchange ----
@api.onchange('coating_config_id', 'quantity', 'part_catalog_id')
def _onchange_lookup_price(self):
diff --git a/fusion_plating/fusion_plating_configurator/wizard/fp_direct_order_wizard.py b/fusion_plating/fusion_plating_configurator/wizard/fp_direct_order_wizard.py
index 9f923464..11b67c4a 100644
--- a/fusion_plating/fusion_plating_configurator/wizard/fp_direct_order_wizard.py
+++ b/fusion_plating/fusion_plating_configurator/wizard/fp_direct_order_wizard.py
@@ -45,6 +45,16 @@ class FpDirectOrderWizard(models.TransientModel):
internal_deadline = fields.Date(string='Internal Deadline')
customer_deadline = fields.Date(string='Customer Deadline')
+ # ---- Order flags (Phase B) ----
+ is_blanket_order = fields.Boolean(
+ string='Blanket Sales Order',
+ help='Blanket orders release parts in quantities over time.',
+ )
+ block_partial_shipments = fields.Boolean(
+ string='Block Partial Shipments',
+ help='Ship all-or-nothing; partial pickings are blocked.',
+ )
+
# ---- PO (required — that's what makes this a "direct" order) ----
po_number = fields.Char(string='Customer PO #', required=True)
po_attachment_file = fields.Binary(string='PO Document', required=True)
@@ -184,6 +194,8 @@ class FpDirectOrderWizard(models.TransientModel):
'x_fc_deposit_percent': self.deposit_percent,
'x_fc_progress_initial_percent': self.progress_initial_percent,
'x_fc_delivery_method': self.delivery_method,
+ 'x_fc_is_blanket_order': self.is_blanket_order,
+ 'x_fc_block_partial_shipments': self.block_partial_shipments,
'origin': 'Direct Order',
'note': self.notes or False,
'order_line': [],
@@ -213,6 +225,7 @@ class FpDirectOrderWizard(models.TransientModel):
'x_fc_treatment_ids': [(6, 0, line.treatment_ids.ids)],
'x_fc_part_deadline': line.part_deadline,
'x_fc_rush_order': line.rush_order,
+ 'x_fc_wo_group_tag': line.wo_group_tag or False,
}))
# 5. Create + confirm
diff --git a/fusion_plating/fusion_plating_configurator/wizard/fp_direct_order_wizard_views.xml b/fusion_plating/fusion_plating_configurator/wizard/fp_direct_order_wizard_views.xml
index 01c7f7ae..8602aeb4 100644
--- a/fusion_plating/fusion_plating_configurator/wizard/fp_direct_order_wizard_views.xml
+++ b/fusion_plating/fusion_plating_configurator/wizard/fp_direct_order_wizard_views.xml
@@ -45,6 +45,8 @@
+
+
@@ -69,7 +71,9 @@
-
+
+
+
@@ -115,6 +120,7 @@
options="{'currency_field': 'currency_id'}"/>
+