feat(certificates): multiple Default CoC Contacts per customer (M2o -> M2m)
res.partner.x_fc_default_coc_contact_id (single Many2one) becomes x_fc_default_coc_contact_ids (self-referential Many2many 'Default CoC Contacts') so a customer can list several contacts who need the CoC. - res.partner: M2m field (rel fp_default_coc_contact_rel) + many2many_tags. - Cert: contact_partner_id (primary addressee printed on the cert) is set to the FIRST CoC contact at job creation + lazy-filled at issue. - Send: action_send_to_customer pre-fills the email composer with ALL the customer's CoC contacts (primary + the rest), falling back to the company. - fp.job cert-default resolution + the action_issue gate wording updated. - Migration 19.0.10.2.0: copies each partner's old single value into the new M2m, then drops the orphaned column. Deployed + verified on entech: migration copied 2 existing values, old column dropped, field is M2m, send pre-fills all contacts. entech-only part_line_ids / multi-part resolver preserved. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -521,10 +521,12 @@ class FpCertificate(models.Model):
|
||||
# effect retroactively at issue time.
|
||||
if (not rec.contact_partner_id
|
||||
and rec.partner_id
|
||||
and 'x_fc_default_coc_contact_id' in rec.partner_id._fields
|
||||
and rec.partner_id.x_fc_default_coc_contact_id):
|
||||
and 'x_fc_default_coc_contact_ids' in rec.partner_id._fields
|
||||
and rec.partner_id.x_fc_default_coc_contact_ids):
|
||||
# Primary = first of the customer's CoC contacts; the rest
|
||||
# are CC'd at send (action_send_to_customer).
|
||||
rec.contact_partner_id = (
|
||||
rec.partner_id.x_fc_default_coc_contact_id
|
||||
rec.partner_id.x_fc_default_coc_contact_ids[:1]
|
||||
)
|
||||
# Lazy-fill the signer from the LIVE company owner (Settings
|
||||
# "Certificate Owner") when no per-cert / per-spec signer was
|
||||
@@ -578,13 +580,13 @@ class FpCertificate(models.Model):
|
||||
'(Settings > Fusion Plating).'
|
||||
) % {'name': rec.name or rec.display_name})
|
||||
# Customer contact — the named recipient printed on the
|
||||
# cert and emailed when it ships. Auto-filled from
|
||||
# partner.x_fc_default_coc_contact_id when set.
|
||||
# cert and emailed when it ships. Auto-filled from the FIRST
|
||||
# of partner.x_fc_default_coc_contact_ids when set.
|
||||
if not rec.contact_partner_id:
|
||||
raise UserError(_(
|
||||
'Cannot issue certificate "%(name)s" — Customer '
|
||||
'Contact is not set.\n\nPick the recipient contact, '
|
||||
'or configure a Default CoC Contact on customer '
|
||||
'or configure Default CoC Contacts on customer '
|
||||
'"%(cust)s".'
|
||||
) % {
|
||||
'name': rec.name or rec.display_name,
|
||||
@@ -1114,11 +1116,21 @@ class FpCertificate(models.Model):
|
||||
"""Open email composer with the certificate PDF attached."""
|
||||
self.ensure_one()
|
||||
template = self.env.ref('mail.email_compose_message_wizard_form', raise_if_not_found=False)
|
||||
# CoC goes to ALL the customer's CoC contacts (the cert's primary
|
||||
# contact + the rest of partner.x_fc_default_coc_contact_ids),
|
||||
# falling back to the company. Every contact who needs the cert is
|
||||
# pre-filled on the composer.
|
||||
recipients = self.contact_partner_id
|
||||
if (self.partner_id
|
||||
and 'x_fc_default_coc_contact_ids' in self.partner_id._fields):
|
||||
recipients |= self.partner_id.x_fc_default_coc_contact_ids
|
||||
partner_ids = recipients.ids or (
|
||||
[self.partner_id.id] if self.partner_id else [])
|
||||
ctx = {
|
||||
'default_model': 'fp.certificate',
|
||||
'default_res_ids': self.ids,
|
||||
'default_composition_mode': 'comment',
|
||||
'default_partner_ids': [self.partner_id.id] if self.partner_id else [],
|
||||
'default_partner_ids': partner_ids,
|
||||
}
|
||||
if self.attachment_id:
|
||||
ctx['default_attachment_ids'] = [self.attachment_id.id]
|
||||
|
||||
Reference in New Issue
Block a user