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:
@@ -9,7 +9,7 @@ from odoo import _, api, fields, models
|
||||
class FpPortalJob(models.Model):
|
||||
"""Lightweight portal-facing view of a production job.
|
||||
|
||||
This is intentionally a simple, decoupled model — it does NOT replace any
|
||||
This is intentionally a simple, decoupled model - it does NOT replace any
|
||||
real job/MO model from process packs (e.g. fusion_plating_process_en).
|
||||
Instead, the shop populates this once per job (manually or via a small
|
||||
sync rule from the real job) so the customer sees a clean, sanitised
|
||||
@@ -19,7 +19,7 @@ class FpPortalJob(models.Model):
|
||||
optional CoC + packing list attachments, and a tracking reference.
|
||||
"""
|
||||
_name = 'fusion.plating.portal.job'
|
||||
_description = 'Fusion Plating — Portal Job'
|
||||
_description = 'Fusion Plating - Portal Job'
|
||||
_inherit = ['portal.mixin', 'mail.thread']
|
||||
_order = 'received_date desc, id desc'
|
||||
|
||||
@@ -249,7 +249,7 @@ class FpPortalJob(models.Model):
|
||||
def walk(node, depth):
|
||||
for child in node.child_ids.sorted('sequence'):
|
||||
if not child.customer_visible:
|
||||
# Hidden node — and its sub-tree is also hidden,
|
||||
# Hidden node - and its sub-tree is also hidden,
|
||||
# because if you're skipping the parent the kids
|
||||
# never make sense in isolation.
|
||||
continue
|
||||
@@ -264,14 +264,14 @@ class FpPortalJob(models.Model):
|
||||
return result
|
||||
|
||||
# ==========================================================================
|
||||
# State recompute — single source of truth derived from upstream models
|
||||
# State recompute - single source of truth derived from upstream models
|
||||
# ==========================================================================
|
||||
# The portal state should ALWAYS reflect the real shop-floor state of the
|
||||
# linked fp.job(s), the outbound shipment(s), and the customer invoice.
|
||||
# Earlier paths wrote state directly from each event hook (tracking number
|
||||
# arrived → 'shipped'; invoice posted → 'complete') which drifted out of
|
||||
# sync the moment any of those events fired before the job was actually
|
||||
# done — e.g. a FedEx label booked early would promote portal state to
|
||||
# done - e.g. a FedEx label booked early would promote portal state to
|
||||
# 'shipped' even though the WO was still in 'confirmed'. The helper below
|
||||
# is the new single source of truth; the hooks now delegate to it.
|
||||
def _fp_recompute_portal_state(self):
|
||||
@@ -284,7 +284,7 @@ class FpPortalJob(models.Model):
|
||||
for portal in self:
|
||||
jobs = Job.sudo().search([('portal_job_id', '=', portal.id)])
|
||||
if not jobs:
|
||||
# No linked job — leave manual edits alone.
|
||||
# No linked job - leave manual edits alone.
|
||||
continue
|
||||
|
||||
all_done = all(j.state == 'done' for j in jobs)
|
||||
@@ -312,7 +312,7 @@ class FpPortalJob(models.Model):
|
||||
elif ship.status == 'shipped':
|
||||
ship_in_transit = True
|
||||
|
||||
# Invoice signal — any posted customer invoice on the SO.
|
||||
# Invoice signal - any posted customer invoice on the SO.
|
||||
invoiced = False
|
||||
for j in jobs:
|
||||
so = j.sale_order_id
|
||||
|
||||
@@ -13,14 +13,14 @@ class FpQuoteRequest(models.Model):
|
||||
|
||||
The RFQ is the entry point for new business through the customer portal.
|
||||
A customer fills out the public form (logged in), uploads any drawings,
|
||||
and submits — the record lands in the shop's backend in state ``new``.
|
||||
and submits - the record lands in the shop's backend in state ``new``.
|
||||
|
||||
The shop reviews, prices, and either quotes (``quoted``), declines, or
|
||||
lets the request expire. The portal mixin gives each request a stable
|
||||
access token URL so quote PDFs can be linked from chatter.
|
||||
"""
|
||||
_name = 'fusion.plating.quote.request'
|
||||
_description = 'Fusion Plating — Quote Request'
|
||||
_description = 'Fusion Plating - Quote Request'
|
||||
_inherit = ['portal.mixin', 'mail.thread', 'mail.activity.mixin']
|
||||
_order = 'create_date desc, id desc'
|
||||
|
||||
@@ -139,7 +139,7 @@ class FpQuoteRequest(models.Model):
|
||||
)
|
||||
notes_internal = fields.Html(
|
||||
string='Internal Notes',
|
||||
help='Visible to shop users only — never shown on the customer portal.',
|
||||
help='Visible to shop users only - never shown on the customer portal.',
|
||||
)
|
||||
|
||||
company_id = fields.Many2one(
|
||||
|
||||
@@ -13,7 +13,7 @@ class FpQuoteRequestLine(models.Model):
|
||||
part number, quantity, description, and file attachments.
|
||||
"""
|
||||
_name = 'fusion.plating.quote.request.line'
|
||||
_description = 'Fusion Plating — Quote Request Line'
|
||||
_description = 'Fusion Plating - Quote Request Line'
|
||||
_order = 'sequence, id'
|
||||
|
||||
request_id = fields.Many2one(
|
||||
|
||||
Reference in New Issue
Block a user