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:
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2026 Nexa Systems Inc. — License OPL-1
|
||||
"""Plan task P3.1 — /fp/landing/kanban endpoint."""
|
||||
# Copyright 2026 Nexa Systems Inc. - License OPL-1
|
||||
"""Plan task P3.1 - /fp/landing/kanban endpoint."""
|
||||
import json
|
||||
|
||||
from odoo.tests.common import HttpCase, tagged
|
||||
|
||||
@@ -156,7 +156,7 @@ class TestSetPinViaResetToken(TransactionCase):
|
||||
# Verify the hash matches
|
||||
self.assertTrue(self.user.verify_tablet_pin('1234'))
|
||||
# Token still valid (single-use happens at set_pin endpoint
|
||||
# call site — model-level _sign / _verify is stateless)
|
||||
# call site - model-level _sign / _verify is stateless)
|
||||
uid = Reset._verify_reset_token(token)
|
||||
self.assertEqual(uid, self.user.id)
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
"""Tests for the tablet lock-screen payload helpers.
|
||||
|
||||
Covers the 3 module-level helpers added in 2026-05-24 redesign:
|
||||
- _initials_from(name) — letter-mark fallback for missing logo/photo
|
||||
- _avatar_gradient_for(uid) — deterministic per-user color gradient
|
||||
- _lock_company_payload(env) — company name + tagline + logo URL block
|
||||
- _initials_from(name) - letter-mark fallback for missing logo/photo
|
||||
- _avatar_gradient_for(uid) - deterministic per-user color gradient
|
||||
- _lock_company_payload(env) - company name + tagline + logo URL block
|
||||
|
||||
End-to-end test of the /fp/tablet/tiles endpoint payload shape:
|
||||
just verifies the helper output ends up in the response.
|
||||
@@ -52,7 +52,7 @@ class TestAvatarGradientFor(TransactionCase):
|
||||
)
|
||||
|
||||
def test_modulo_distribution(self):
|
||||
# Wrapping wraps cleanly — id 0 and id len(gradients) match
|
||||
# Wrapping wraps cleanly - id 0 and id len(gradients) match
|
||||
n = len(_AVATAR_GRADIENTS)
|
||||
self.assertEqual(_avatar_gradient_for(0), _avatar_gradient_for(n))
|
||||
self.assertEqual(_avatar_gradient_for(3), _avatar_gradient_for(n + 3))
|
||||
@@ -84,7 +84,7 @@ class TestLockCompanyPayload(TransactionCase):
|
||||
# brittle here because res.company.report_header is an HTML field in
|
||||
# Odoo 19: setting a plain string can come back wrapped in <p> tags
|
||||
# after sanitization. The helper's responsibility is just "use the
|
||||
# field's value when present, else fall back" — covered by
|
||||
# field's value when present, else fall back" - covered by
|
||||
# test_tagline_default_when_empty_report_header above.
|
||||
|
||||
def test_initials_match_company_name(self):
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2026 Nexa Systems Inc. — License OPL-1
|
||||
"""Phase 6 — Tablet PIN gate tests."""
|
||||
# Copyright 2026 Nexa Systems Inc. - License OPL-1
|
||||
"""Phase 6 - Tablet PIN gate tests."""
|
||||
import json
|
||||
|
||||
from odoo.tests.common import HttpCase, TransactionCase, tagged
|
||||
|
||||
|
||||
def _rpc(case, url, **params):
|
||||
"""Helper for HTTP/JSON-RPC tests — wraps Odoo's url_open."""
|
||||
"""Helper for HTTP/JSON-RPC tests - wraps Odoo's url_open."""
|
||||
res = case.url_open(
|
||||
url,
|
||||
data=json.dumps({'jsonrpc': '2.0', 'params': params}),
|
||||
@@ -18,7 +18,7 @@ def _rpc(case, url, **params):
|
||||
|
||||
@tagged('-at_install', 'post_install', 'fp_shopfloor', 'fp_tablet_pin')
|
||||
class TestTabletPinHash(TransactionCase):
|
||||
"""P6.1.1 — model fields + hash helpers + set/verify/clear methods."""
|
||||
"""P6.1.1 - model fields + hash helpers + set/verify/clear methods."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
@@ -32,7 +32,7 @@ class TestTabletPinHash(TransactionCase):
|
||||
stored = self.user.sudo().x_fc_tablet_pin_hash
|
||||
self.assertTrue(stored)
|
||||
self.assertIn('$', stored, 'hash must include salt separator')
|
||||
# Hash is non-deterministic — setting same PIN twice gives different stored values
|
||||
# Hash is non-deterministic - setting same PIN twice gives different stored values
|
||||
self.user.sudo().set_tablet_pin('1234')
|
||||
self.assertNotEqual(stored, self.user.sudo().x_fc_tablet_pin_hash)
|
||||
|
||||
@@ -66,7 +66,7 @@ class TestTabletPinHash(TransactionCase):
|
||||
|
||||
@tagged('-at_install', 'post_install', 'fp_shopfloor', 'fp_tablet_pin')
|
||||
class TestTabletSetPin(HttpCase):
|
||||
"""P6.1.2 — /fp/tablet/set_pin endpoint."""
|
||||
"""P6.1.2 - /fp/tablet/set_pin endpoint."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
@@ -79,13 +79,13 @@ class TestTabletSetPin(HttpCase):
|
||||
def test_set_pin_change_requires_old(self):
|
||||
admin = self.env.ref('base.user_admin')
|
||||
admin.set_tablet_pin('1234')
|
||||
# Change without old — rejected
|
||||
# Change without old - rejected
|
||||
res = _rpc(self, '/fp/tablet/set_pin', new_pin='5678')
|
||||
self.assertFalse(res['ok'])
|
||||
# Change with wrong old — rejected
|
||||
# Change with wrong old - rejected
|
||||
res = _rpc(self, '/fp/tablet/set_pin', old_pin='9999', new_pin='5678')
|
||||
self.assertFalse(res['ok'])
|
||||
# Change with correct old — accepted
|
||||
# Change with correct old - accepted
|
||||
res = _rpc(self, '/fp/tablet/set_pin', old_pin='1234', new_pin='5678')
|
||||
self.assertTrue(res['ok'])
|
||||
|
||||
@@ -97,7 +97,7 @@ class TestTabletSetPin(HttpCase):
|
||||
|
||||
@tagged('-at_install', 'post_install', 'fp_shopfloor', 'fp_tablet_pin')
|
||||
class TestTabletResetPinFor(HttpCase):
|
||||
"""P6.1.2 — /fp/tablet/reset_pin_for endpoint."""
|
||||
"""P6.1.2 - /fp/tablet/reset_pin_for endpoint."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
@@ -128,7 +128,7 @@ class TestTabletResetPinFor(HttpCase):
|
||||
|
||||
@tagged('-at_install', 'post_install', 'fp_shopfloor', 'fp_tablet_pin')
|
||||
class TestTabletTiles(HttpCase):
|
||||
"""P6.1.4 — /fp/tablet/tiles endpoint."""
|
||||
"""P6.1.4 - /fp/tablet/tiles endpoint."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
@@ -63,7 +63,7 @@ class TestTabletPinAuthManager(TransactionCase):
|
||||
|
||||
def test_other_credential_types_pass_through_to_super(self):
|
||||
# Standard password credential should still work normally.
|
||||
# We don't test the exact result here — just that our override
|
||||
# We don't test the exact result here - just that our override
|
||||
# doesn't intercept it.
|
||||
# AccessDenied is expected because we provide no password.
|
||||
# Key check: it's not OUR AccessDenied (which fires when type
|
||||
@@ -75,6 +75,6 @@ class TestTabletPinAuthManager(TransactionCase):
|
||||
{},
|
||||
)
|
||||
except AccessDenied:
|
||||
pass # expected — wrong password
|
||||
pass # expected - wrong password
|
||||
except Exception as e:
|
||||
self.fail(f'Standard password path broken: {e}')
|
||||
|
||||
@@ -19,7 +19,7 @@ class TestUnlockLockSessionEndpoints(HttpCase):
|
||||
self.tech.sudo().set_tablet_pin('1234')
|
||||
# Make sure the kiosk password is set so lock_session can re-auth.
|
||||
ICP = self.env['ir.config_parameter'].sudo()
|
||||
# Always override — HttpCase rolls back per test, so we never persist
|
||||
# Always override - HttpCase rolls back per test, so we never persist
|
||||
# the test password. Was previously gated on "if not get_param(...)"
|
||||
# which broke against entech where the post-migrate hook already
|
||||
# generated a random kiosk password.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2026 Nexa Systems Inc. — License OPL-1
|
||||
# Copyright 2026 Nexa Systems Inc. - License OPL-1
|
||||
"""HTTP tests for /fp/workspace/* endpoints."""
|
||||
import base64
|
||||
import json
|
||||
|
||||
Reference in New Issue
Block a user