Five new boolean flags on res.partner applied to CHILD contacts:
x_fc_receives_certs, _qc, _quotes_so, _invoices, and _is_global_contact.
Single resolver helper res.partner._fp_resolve_notification_recipients
(stream, delivery_location=None) walks location contacts first then
company contacts, returning emails for contacts that opted into the
stream (or flagged themselves global). Falls back to partner.email
when no contact opts in so existing customers keep their exact
pre-Sub-6 routing.
fp.notification.template._dispatch now maps each trigger event to a
stream (so_confirmed→quotes_so, invoice_posted→invoices, shipped→
certs, etc.) and overrides the mail_template's email_to with the
resolved list. fp.delivery passes its delivery_address_id so the
shipped/CoC email routes through location-scoped contacts when they
exist.
Partner form gets a new "Communication Routing" tab on child contact
forms with the 5 flags (hides the per-stream checkboxes when
Global Contact is on, since it overrides them).
fusion_plating_certificates → 19.0.4.0.0 (adds the flag fields)
fusion_plating_notifications → 19.0.5.0.0 (+depends certificates)
Smoke on entech: 11/11 assertions pass including per-stream routing,
delivery-location scoping, zero-flag fallback, email-less skip,
unknown-stream + global behaviour, and case-insensitive dedup.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two user-reported bugs on S00056 (and visible on any SO/invoice):
Bug 1: Cancelling the Send dialog still sends the email.
action_quotation_send is a button handler that returns a
compose-dialog action synchronously. Our override was calling
_dispatch('quote_sent', ...) AFTER super(), which immediately
sends the email via template.send_mail() before the user ever
sees the dialog. Clicking Cancel at that point only dismisses
the already-sent email's compose window.
Fix: removed the _dispatch call entirely from action_quotation_send.
The Send button IS the manual-send path; Odoo's compose dialog
(pre-populated with our FP: Quotation Sent template thanks to
_find_mail_template) handles the send-or-cancel choice correctly.
If an auto-quote-sent notification is ever wanted, it should be
wired from a cron that scans SOs that just transitioned
draft -> sent, not from the button handler. Noted in a code
comment.
Bug 2: Two copies of the same PDF attached to every email.
The mail.template records now carry report_template_ids (set by
the post_init hook from the previous refactor) which Odoo uses to
auto-attach PDFs on send_mail(). But the fp.notification.template
records ALSO had attach_quotation / attach_sale_order / attach_invoice
flags set, which cause _collect_attachments() to render the same
PDF a second time and pass it in email_values.
Fix: turned those three flags off in the XML data file. Other
flags (attach_coc, attach_bol, attach_receipt, attach_thickness_report,
attach_packing_list, attach_pod) stay on — those are genuinely
different documents, not dupes.
Because the records are noupdate="1", updated the post_init_hook
to also backfill the flag changes onto existing DB rows so
production instances get cleaned up on -u, not just fresh installs.
Smoke:
attach_quotation=False attach_sale_order=False attach_invoice=False on all three records
1 report per template (no dupes)
action_quotation_send no longer contains _dispatch("quote_sent", ...)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three reported PDF bugs from the customer-facing email package:
1. Invoice body was empty — Odoo 19 sets display_type='product' on
regular invoice/SO lines (was empty string in 18.0). Both
report_fp_invoice.xml and report_fp_sale.xml only matched
`not line.display_type`, so every product line was skipped.
Fixed both portrait + landscape variants to also match
display_type == 'product'.
2. CoC PDF was a bare 30 KB header — _fp_generate_cert_pdf was
rendering action_report_coc, which is bound to portal_job and
has minimal content. Rewrote to use the rich fp.certificate-bound
report (action_report_coc_en / action_report_coc_fr based on
cert.partner_id.lang) and slugged the filename to
CoC-<Customer>-<CertName>.pdf so the email attachment reads
nicely instead of CERT-00123.pdf.
3. Thickness cert was an exact duplicate of the CoC — the CoC
template already embeds thickness readings. Skip thickness cert
creation entirely when the customer also wants CoC; only create
a standalone thickness cert when the customer opted out of CoC.
Also: dispatcher in fp_notification_template now prefers
portal_job.coc_attachment_id (the rich one we just generated) and
falls back to rendering action_report_coc_en against fp.certificate
by partner.lang — never the bare portal-job report.
Versions bumped: bridge_mrp 19.0.6.0.0, notifications 19.0.4.0.0,
reports 19.0.4.0.0.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>
Bug review fixes (found by code review + live QWeb error):
- report_fp_sale.xml: product_uom → product_uom_id (Odoo 19 renamed;
was raising KeyError during PDF render, blocking all sale-order prints)
- mrp_production.button_mark_done: add idempotency guard on delivery
auto-create (was duplicating on every re-close)
- fp.certificate._compute_batch_ids: use empty recordset instead of
False for Many2many computed fields
- fp_notification_template._collect_attachments: collapse attach_quotation
+ attach_sale_order into a single render so email doesn't double-attach
the same PDF
- fp.operator.certification: SQL unique on computed state was unreliable;
added explicit `revoked` boolean, made state pure-compute, replaced
SQL constraint with @api.constrains that checks active-only uniqueness;
has_active_cert now reads revoked + expires_date directly (no stale
stored state between nightly recomputes)
Two missing invoice strategies implemented + 1 pre-existing deposit bug fix:
- Progress Billing: new x_fc_progress_initial_percent field on sale.order;
_create_progress_initial_invoice bills the configured % on SO confirm
via down-payment wizard, _create_final_balance_invoice bills the
remainder on delivery
- Net Terms: no invoice on confirm; full invoice auto-created when
fusion.plating.delivery.action_mark_delivered fires
- Fix for deposit (pre-existing, silent): sale.advance.payment.inv
reads active_ids at wizard-create time, not on create_invoices();
context was being set on the wrong call, so every deposit attempt
raised "Expected singleton" and message-posted to chatter instead
of actually invoicing
- New fusion_plating_invoicing/models/fp_delivery.py hooks
action_mark_delivered to dispatch final invoice for progress/net_terms
- fp.direct.order.wizard + SO form surface the progress_initial_percent
field (conditional on strategy)
Report styling cleanup:
- Hide DISCOUNT column from sale + invoice landscape reports unless at
least one line has a non-zero discount; colspan auto-adjusts
- Replace hardcoded #0066a1 in all reports with company.primary_color
driven by doc.company_id → company → user.company_id fallback chain,
with #1d1f1e as ultimate fallback; new .fp-header-primary class
exposes the colour for inline section headers (CARGO DESCRIPTION,
PAYMENT DETAILS, OPERATOR SIGN-OFF, etc.) so they retint with the
company theme without template edits
Certificate of Conformance — formal ENTECH-style rebuild:
- New res.company fields: x_fc_owner_user_id (default signer, sig from
hr.employee.signature), x_fc_coc_signature_override (manual upload),
x_fc_{nadcap,as9100,cgp}_logo + _active toggles for accreditation
badges
- New res.config.settings section "Fusion Plating" exposing the above
as configurable blocks; manager-only menu under Configuration →
Fusion Plating Settings
- New fp.certificate fields: nc_quantity, customer_job_no,
contact_partner_id (child contact for Name / Email / Phone block)
- New report_coc_en + report_coc_fr templates (primary): custom header
(company contact | accreditations | company logo), bilingual labels
per variant, customer info block with customer logo, 3-column cert
info table, 6-column line-item table (Part # | Process | Customer
PO | Shipped | NC Qty | Customer Job No.), signature image + bordered
certification statement, footer "Fusion Plating by Nexa Systems"
- Legacy report_coc + report_coc_portrait kept for existing portal-job
bindings (no behaviour change)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>