Files
Odoo-Modules/fusion_plating/fusion_plating_invoicing/models/res_partner.py
gsinghpal 8c76a16366 chore(plating): de-dash shipped code + intake-neutral customer emails
Replace em-dashes and en-dashes with hyphens across 789 shipped source
files (py/xml/js/scss) so the delivered module reads as human-written;
em-dashes had become a recognizable AI-generated tell. Internal .md dev
notes are excluded. The WO-sticker mojibake strippers keep their dash
search targets (now written — / –). No logic changes: comments
and display strings only; validated with py_compile + lxml parse.

Rewrite the 7 customer notification emails to be intake-neutral
(ship-in / drop-off / pickup) and repair-aware, and fix the Shipped
email documents line (packing slip vs bill of lading; certificate only
when issued). Subjects use a hyphen separator.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 00:16:19 -04:00

87 lines
3.9 KiB
Python

# -*- coding: utf-8 -*-
# Copyright 2026 Nexa Systems Inc.
# License OPL-1 (Odoo Proprietary License v1.0)
# Part of the Fusion Plating product family.
from odoo import api, fields, models
class ResPartner(models.Model):
_inherit = 'res.partner'
# ===== Account hold (existing) ============================================
x_fc_account_hold = fields.Boolean(
string='Account Hold', tracking=True,
help='When active, blocks SO confirmation, invoicing, and shipping.',
)
@api.model
def _fp_user_can_override_account_hold(self):
"""True when the current user is allowed to override an account hold.
Plating Manager OR Plating Administrator qualifies. Administrator
is checked explicitly (in addition to the implied chain) because
Odoo's ``implied_ids`` cascade does NOT reliably propagate to
existing users on module upgrade - admin (uid 1) typically lands
in Administrator only, with no Manager membership. Without this
defensive check, the highest-privileged user can't bypass holds.
See CLAUDE.md "Implied group cascade" rule.
"""
user = self.env.user
# Phase G: fixed audit-finding-11 - old code referenced
# 'fusion_plating.group_fusion_plating_administrator', an xmlid
# that never existed, so the gate always returned False. Replaced
# with group_fp_manager which transitively implies Owner via
# implied_ids in Phase A's diamond hierarchy.
return user.has_group('fusion_plating.group_fp_manager')
x_fc_account_hold_reason = fields.Text(string='Hold Reason')
x_fc_account_hold_date = fields.Datetime(
string='Hold Date', help='When the hold was placed.',
)
x_fc_account_hold_by_id = fields.Many2one(
'res.users', string='Hold Placed By',
)
# ===== Plating Defaults (cascade onto every new SO for this customer) =====
# The estimator sets these once on the customer record; they pre-fill
# invoice strategy, delivery method, and deadlines on every new SO so
# repeat customers don't need re-typing the same values each order.
# Tax type lives on `property_account_position_id` (Odoo native fiscal
# position) and payment terms on `property_payment_term_id` - both are
# surfaced on the same Plating Defaults tab in the partner form.
x_fc_default_invoice_strategy = fields.Selection(
[('deposit', 'Deposit'),
('progress', 'Progress Billing'),
('net_terms', 'Net Terms'),
('cod_prepay', 'COD / Prepay')],
string='Default Invoice Strategy',
help='Pre-fills the SO invoice strategy when this customer is selected. '
'The estimator can still override per order.',
)
x_fc_default_deposit_percent = fields.Float(
string='Default Deposit %',
help='Used when invoice strategy is "Deposit". e.g. 50.0 for 50%.',
)
x_fc_default_delivery_method = fields.Selection(
[('local_delivery', 'Local Delivery'),
('shipping_partner', 'Shipping Partner'),
('customer_pickup', 'Customer Pickup')],
string='Default Delivery Method',
help='Pre-fills the SO delivery method when this customer is selected.',
)
# Lead-time defaults are expressed as offsets FROM the SO's planned-start
# date so they track real production schedules, not just "today + N".
# If planned_start is unset on the SO, the cascade falls back to today.
x_fc_default_internal_deadline_days = fields.Integer(
string='Internal Deadline (+ days from start)',
help='Pre-fills SO internal deadline as planned_start_date + this '
'many days. e.g. 5 means "ship five days after we start".',
)
x_fc_default_customer_deadline_days = fields.Integer(
string='Customer Deadline (+ days from start)',
help='Pre-fills the customer-facing commitment date as '
'planned_start_date + this many days.',
)