feat(berths): normalize mooring numbers to canonical form
Sweep CRM mooring numbers from the legacy hyphen+padded form ("A-01")
to the canonical bare form ("A1") used by NocoDB, the public website,
the per-berth PDFs, and the Documenso EOI templates. Drift was
introduced by the original load-berths-to-port-nimara.ts seed; this
gates the Phase 3 public-website cutover where /berths/A1 URLs would
404 against a CRM still storing "A-01".
- 0024 data migration: idempotent regexp_replace + post-update sanity
check that surfaces any non-conforming rows for manual triage.
- Invert normalizeLegacyMooring in dedup/migration-apply: it now
canonicalizes ("D-32" -> "D32") instead of legacy-izing.
- Update tiptap-to-pdfme example tokens, EOI fixture moorings, and
smoke-test seed moorings.
- Refresh seed-data/berths.json to canonical form; drop the now-
redundant legacyMooringNumber field.
- Delete scripts/load-berths-to-port-nimara.ts (superseded in 0c).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -37,22 +37,18 @@ import type {
|
||||
const SOURCE_SYSTEM = 'nocodb_interests';
|
||||
|
||||
/**
|
||||
* Convert a legacy bare mooring string like "D32" / "A1" / "E18" to the
|
||||
* dashed/padded form "D-32" / "A-01" / "E-18" used by the new berths
|
||||
* schema. If the input doesn't match the bare pattern, returns it
|
||||
* unchanged so a literal lookup can still hit (handles the case where
|
||||
* the legacy data already has the dashed form).
|
||||
*
|
||||
* Multi-mooring strings ("A3, D30") return the original string -
|
||||
* those need human review and we don't want to silently pick one half.
|
||||
* Canonicalize a mooring string to the unified form ("A1", "D32", "E18")
|
||||
* used by the new berths schema after the Phase 0 mooring-number sweep.
|
||||
* Accepts inputs in any of the historical forms - bare ("D32"), dashed
|
||||
* ("D-32"), or dashed-padded ("D-032") - and returns the canonical bare
|
||||
* form. Inputs that don't match (multi-mooring strings like "A3, D30",
|
||||
* non-numeric suffixes like "B-LEG") are returned unchanged so a literal
|
||||
* lookup can still hit and the caller can flag the row for review.
|
||||
*/
|
||||
function normalizeLegacyMooring(raw: string): string {
|
||||
// Bare letter+digits, e.g. "D32"
|
||||
const m = /^([A-E])(\d{1,3})$/i.exec(raw.trim());
|
||||
const m = /^([A-Z]+)-?0*(\d+)$/i.exec(raw.trim());
|
||||
if (!m) return raw;
|
||||
const letter = m[1]!.toUpperCase();
|
||||
const num = parseInt(m[2]!, 10);
|
||||
return `${letter}-${num.toString().padStart(2, '0')}`;
|
||||
return `${m[1]!.toUpperCase()}${parseInt(m[2]!, 10)}`;
|
||||
}
|
||||
|
||||
export interface ApplyResult {
|
||||
@@ -254,10 +250,9 @@ async function applyInterest(
|
||||
if (planned.berthMooringNumber) {
|
||||
berthId =
|
||||
mooringToBerthId.get(planned.berthMooringNumber) ??
|
||||
// The legacy NocoDB Interests table uses bare mooring strings like
|
||||
// "D32", "B16", whereas the new berths schema (mirroring the NocoDB
|
||||
// Berths snapshot) uses zero-padded "D-32", "B-16". Try the dashed
|
||||
// form as a fallback so legacy references resolve correctly.
|
||||
// Legacy NocoDB Interests rows recorded mooring strings inconsistently
|
||||
// ("D32", "D-32", "D-032"). The new berths schema stores the canonical
|
||||
// bare form ("D32") - canonicalize the lookup key as a fallback.
|
||||
mooringToBerthId.get(normalizeLegacyMooring(planned.berthMooringNumber)) ??
|
||||
null;
|
||||
if (!berthId) {
|
||||
|
||||
Reference in New Issue
Block a user