feat(certificates): per-customer document preferences (CHUNK 1/4)

Customers can now pick which shipping-time documents they actually want
instead of the shop remembering it per account. Four booleans on
res.partner (only shown on companies, not contacts):

  x_fc_send_coc              (default True)  Certificate of Conformance
  x_fc_send_thickness_report (default True)  Thickness readings
  x_fc_send_packing_slip     (default True)  Packing slip PDF
  x_fc_send_bol              (default False) Bill of Lading

Surfaced in a "Plating Documents" page on the customer form.

Two downstream gates:

1. fp.notification.template._collect_attachments() now reads the flags
   when attaching CoC / thickness / packing / BoL PDFs to the shipping
   confirmation email. Flags missing on the partner (e.g. legacy
   customers) fall back to the original defaults so nothing regresses.

2. mrp.production.button_mark_done() only auto-creates the quality
   documents the customer wants. A customer that unchecks both CoC and
   thickness gets zero certs auto-generated — shop can still create
   them manually if needed.

Note: today a standalone thickness-only report template doesn't exist,
so when a customer asks for thickness only (CoC off, thickness on) the
dispatcher still attaches the CoC PDF (which carries thickness data)
but with CoC creation gated off. A dedicated thickness-only template
is a follow-up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-04-17 19:54:54 -04:00
parent f94be9dfa9
commit 28dd7fdd76
6 changed files with 178 additions and 29 deletions

View File

@@ -495,32 +495,54 @@ class MrpProduction(models.Model):
'state': 'draft',
})
# Auto-create draft Certificate of Conformance
# Auto-create draft quality documents — which ones are created
# is driven by the customer's preferences on res.partner
# (x_fc_send_coc, x_fc_send_thickness_report). A customer that
# never wants paperwork gets zero certs auto-generated.
if Certificate is not None:
# Skip if a CoC already exists for this MO
existing = Certificate.search(
[('production_id', '=', mo.id), ('certificate_type', '=', 'coc')],
limit=1,
)
if not existing:
coating = so.x_fc_coating_config_id if (
so and 'x_fc_coating_config_id' in so._fields
) else False
cert_vals = {
'certificate_type': 'coc',
'partner_id': job.partner_id.id,
'production_id': mo.id,
'portal_job_id': job.id,
'sale_order_id': so.id if so else False,
'quantity_shipped': int(mo.product_qty),
'po_number': so.x_fc_po_number if (
so and 'x_fc_po_number' in so._fields
) else False,
'entech_wo_number': mo.name,
'spec_reference': coating.spec_reference if coating else False,
'process_description': coating.name if coating else False,
'part_number': mo.product_id.default_code or '',
'state': 'draft',
}
Certificate.create(cert_vals)
customer = job.partner_id
want_coc = True # default for customers that predate the flag
want_thickness = True
if 'x_fc_send_coc' in customer._fields:
want_coc = bool(customer.x_fc_send_coc)
if 'x_fc_send_thickness_report' in customer._fields:
want_thickness = bool(customer.x_fc_send_thickness_report)
coating = so.x_fc_coating_config_id if (
so and 'x_fc_coating_config_id' in so._fields
) else False
base_vals = {
'partner_id': customer.id,
'production_id': mo.id,
'portal_job_id': job.id,
'sale_order_id': so.id if so else False,
'quantity_shipped': int(mo.product_qty),
'po_number': so.x_fc_po_number if (
so and 'x_fc_po_number' in so._fields
) else False,
'entech_wo_number': mo.name,
'spec_reference': coating.spec_reference if coating else False,
'process_description': coating.name if coating else False,
'part_number': mo.product_id.default_code or '',
'state': 'draft',
}
if want_coc:
existing = Certificate.search(
[('production_id', '=', mo.id),
('certificate_type', '=', 'coc')], limit=1,
)
if not existing:
Certificate.create({**base_vals, 'certificate_type': 'coc'})
if want_thickness:
existing = Certificate.search(
[('production_id', '=', mo.id),
('certificate_type', '=', 'thickness_report')], limit=1,
)
if not existing:
Certificate.create({
**base_vals,
'certificate_type': 'thickness_report',
})
return res