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>
This commit is contained in:
gsinghpal
2026-06-05 00:16:19 -04:00
parent c9eb61ee0c
commit 8c76a16366
789 changed files with 4692 additions and 4692 deletions

View File

@@ -116,7 +116,7 @@ class FpCustomerPortal(CustomerPortal):
return partner.commercial_partner_id
# ==========================================================================
# Sidebar items + active-state resolution
# Sidebar - items + active-state resolution
# ==========================================================================
# Sidebar item structure: list of dicts with `type` = 'item' | 'section_label'.
# Items have label / url / icon / key. Key matches either a page_name set by
@@ -150,7 +150,7 @@ class FpCustomerPortal(CustomerPortal):
'fp_account_summary': 'fp_account_summary',
}
_FP_URL_PREFIX_TO_SIDEBAR_KEY = [
# Order matters first match wins, so list longer prefixes first.
# Order matters - first match wins, so list longer prefixes first.
('/my/orders', 'odoo_orders'),
('/my/quotes', 'odoo_orders'), # /my/quotes is also sale_portal
('/my/invoices', 'fp_account_summary'),
@@ -194,7 +194,7 @@ class FpCustomerPortal(CustomerPortal):
partner = request.env.user.partner_id
commercial = partner.commercial_partner_id
values['fp_partner_display_name'] = commercial.name or partner.name
# Internal staff (share=False) get the clean employee experience no
# Internal staff (share=False) get the clean employee experience - no
# customer sidebar. Customers (share=True / portal users) keep it.
values['fp_show_customer_sidebar'] = bool(request.env.user.share)
return values
@@ -204,7 +204,7 @@ class FpCustomerPortal(CustomerPortal):
# funnel through this helper. It sets up chatter/pager but doesn't
# touch _prepare_portal_layout_values, so our sidebar context wouldn't
# otherwise reach those templates. Inject our keys conservatively via
# setdefault never overwrite anything the page already set.
# setdefault - never overwrite anything the page already set.
values = super()._get_page_view_values(
document, access_token, values, session_history, no_breadcrumbs, **kwargs,
)
@@ -219,7 +219,7 @@ class FpCustomerPortal(CustomerPortal):
# ==========================================================================
# 5 customer-facing stages aligned with the dashboard stepper.
# Each entry: (label, timestamp_field_name_on_fp_portal_job).
# Inspected and Plating share `in_progress_started_at` when state moves
# Inspected and Plating share `in_progress_started_at` - when state moves
# away from 'received' it means inspection finished and plating started.
_FP_STAGES = [
('Received', 'received_at'),
@@ -255,7 +255,7 @@ class FpCustomerPortal(CustomerPortal):
Records created post-hook never hit the interpolation branch.
"""
state_idx = self._FP_STATE_TO_STEP_IDX.get(job.state, 0)
# Baseline datetime for interpolation prefer the precise received_at
# Baseline datetime for interpolation - prefer the precise received_at
# but fall through to received_date (Date) converted to midnight.
baseline = job.received_at
if not baseline and job.received_date:
@@ -321,7 +321,7 @@ class FpCustomerPortal(CustomerPortal):
of {label, sub, url, icon_class, icon, pending}.
"""
# 5 fixed groups in display order. Indices used in the appends below
# if you reorder, update every groups[N] reference.
# - if you reorder, update every groups[N] reference.
# 0 = from_you, 1 = specs, 2 = work_order, 3 = quality, 4 = shipping
groups = [
{'key': 'from_you', 'label': 'From You', 'docs': []},
@@ -331,7 +331,7 @@ class FpCustomerPortal(CustomerPortal):
{'key': 'shipping', 'label': 'Shipping', 'docs': []},
]
# FROM YOU surface the Sales Order Confirmation via the fp.job
# FROM YOU - surface the Sales Order Confirmation via the fp.job
# link added by fusion_plating_jobs (job.x_fc_job_id.sale_order_id).
# When no SO is linked, fall back to the placeholder so customers
# know where to upload their PO + drawings.
@@ -381,7 +381,7 @@ class FpCustomerPortal(CustomerPortal):
'icon': '📄',
})
# SPECIFICATIONS (idx 1) V1: placeholder (V2 will pull customer spec)
# SPECIFICATIONS (idx 1) - V1: placeholder (V2 will pull customer spec)
groups[1]['docs'].append({
'label': 'Customer Specification',
'sub': 'Will appear when EN Plating links the spec',
@@ -389,7 +389,7 @@ class FpCustomerPortal(CustomerPortal):
'icon': '📋',
})
# WORK ORDER (idx 2) EN Plating WO Detail PDF via
# WORK ORDER (idx 2) - EN Plating WO Detail PDF via
# fusion_plating_jobs.report_fp_job_wo_detail_template. Requires a
# linked backend fp.job; placeholder otherwise.
if backend_job:
@@ -408,7 +408,7 @@ class FpCustomerPortal(CustomerPortal):
'icon': '🛠',
})
# QUALITY (idx 3) CoC from coc_attachment_id (the legacy direct field)
# QUALITY (idx 3) - CoC from coc_attachment_id (the legacy direct field)
if job.coc_attachment_id:
groups[3]['docs'].append({
'label': 'Certificate of Conformance',
@@ -428,7 +428,7 @@ class FpCustomerPortal(CustomerPortal):
'icon': '📑',
})
# SHIPPING (idx 4) packing list + tracking. Two separate
# SHIPPING (idx 4) - packing list + tracking. Two separate
# docs so each can be pending/ready independently. Previously
# combined into one entry; that broke when tracking_ref landed
# before the packing slip (KeyError 'url').
@@ -480,7 +480,7 @@ class FpCustomerPortal(CustomerPortal):
return '%.1f MB' % (size / (1024 * 1024))
# ==========================================================================
# Account Summary (Sub-A IA) invoices + credits + statements
# Account Summary (Sub-A IA) - invoices + credits + statements
# ==========================================================================
_FP_ACCOUNT_SUMMARY_TABS = [
('invoices', 'Invoices', 'out_invoice'),
@@ -516,18 +516,18 @@ class FpCustomerPortal(CustomerPortal):
search, sort, page):
"""Return {records, total, pager_offset} for one tab+filter combination.
tab 'invoices' | 'credit_memos' | 'statements'
filter_state 'open' | 'closed' | 'all'
search substring matched against name OR ref (case-insensitive)
sort key from _FP_ACCOUNT_SUMMARY_SORTS
page 1-indexed
tab - 'invoices' | 'credit_memos' | 'statements'
filter_state - 'open' | 'closed' | 'all'
search - substring matched against name OR ref (case-insensitive)
sort - key from _FP_ACCOUNT_SUMMARY_SORTS
page - 1-indexed
Uses commercial_partner.env so this helper works both in HTTP
context and in unit tests without requiring request to be active.
"""
env = commercial_partner.env
if tab == 'statements':
# V1 placeholder Statements is a 'coming soon' tab.
# V1 placeholder - Statements is a 'coming soon' tab.
return {'records': env['account.move'].browse(), 'total': 0,
'offset': 0}
@@ -621,7 +621,7 @@ class FpCustomerPortal(CustomerPortal):
)
def home(self, **kw):
# Internal staff don't belong on the customer dashboard. Send them to
# the employee clock portal but only when fusion_clock is installed
# the employee clock portal - but only when fusion_clock is installed
# (x_fclk_enable_clock proves it) AND the user actually has an employee
# record, otherwise /my/clock -> /my would bounce into a redirect loop.
user = request.env.user
@@ -851,7 +851,7 @@ class FpCustomerPortal(CustomerPortal):
methods=['GET'],
)
def portal_new_quote_request(self, **kw):
"""GET legacy entry point, redirected to the configurator wizard."""
"""GET - legacy entry point, redirected to the configurator wizard."""
return request.redirect('/my/configurator/new')
# ==========================================================================
@@ -1285,7 +1285,7 @@ class FpCustomerPortal(CustomerPortal):
type='http', auth='user', website=True,
)
def portal_my_purchase_orders(self, **kw):
"""Legacy URL redirected to Odoo default /my/orders (Sub-A IA)."""
"""Legacy URL - redirected to Odoo default /my/orders (Sub-A IA)."""
return request.redirect('/my/orders')
# ==========================================================================
@@ -1296,7 +1296,7 @@ class FpCustomerPortal(CustomerPortal):
type='http', auth='user', website=True,
)
def portal_my_fp_invoices(self, **kw):
"""Legacy URL redirected to /my/account_summary (Sub-A IA)."""
"""Legacy URL - redirected to /my/account_summary (Sub-A IA)."""
return request.redirect('/my/account_summary')
# ==========================================================================