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:
@@ -33,8 +33,8 @@ export const USERS = {
|
||||
async function signUpUser(email: string, password: string, name: string) {
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Origin': BASE,
|
||||
'Referer': `${BASE}/`,
|
||||
Origin: BASE,
|
||||
Referer: `${BASE}/`,
|
||||
};
|
||||
|
||||
const res = await fetch(`${BASE}/api/auth/sign-up/email`, {
|
||||
@@ -95,11 +95,7 @@ setup('seed test database', async () => {
|
||||
);
|
||||
console.log(` ✓ sales_agent created: ${agentId}`);
|
||||
|
||||
const viewerId = await signUpUser(
|
||||
USERS.viewer.email,
|
||||
USERS.viewer.password,
|
||||
USERS.viewer.name,
|
||||
);
|
||||
const viewerId = await signUpUser(USERS.viewer.email, USERS.viewer.password, USERS.viewer.name);
|
||||
console.log(` ✓ viewer created: ${viewerId}`);
|
||||
|
||||
// 2. Get portId and roleIds from seed data
|
||||
@@ -158,17 +154,17 @@ setup('seed test database', async () => {
|
||||
console.log('🔧 Seeding berths...');
|
||||
await runSQL(`
|
||||
INSERT INTO berths (id, port_id, mooring_number, area, status, length_ft, width_ft, price, tenure_type)
|
||||
SELECT gen_random_uuid()::text, p.id, 'A-001', 'Marina A', 'available', '60', '20', '150000', 'permanent'
|
||||
SELECT gen_random_uuid()::text, p.id, 'A1', 'Marina A', 'available', '60', '20', '150000', 'permanent'
|
||||
FROM ports p WHERE p.slug = 'port-nimara'
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
INSERT INTO berths (id, port_id, mooring_number, area, status, length_ft, width_ft, price, tenure_type)
|
||||
SELECT gen_random_uuid()::text, p.id, 'A-002', 'Marina A', 'available', '80', '25', '250000', 'permanent'
|
||||
SELECT gen_random_uuid()::text, p.id, 'A2', 'Marina A', 'available', '80', '25', '250000', 'permanent'
|
||||
FROM ports p WHERE p.slug = 'port-nimara'
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
INSERT INTO berths (id, port_id, mooring_number, area, status, length_ft, width_ft, price, tenure_type)
|
||||
SELECT gen_random_uuid()::text, p.id, 'B-001', 'Marina B', 'under_offer', '45', '15', '95000', 'fixed_term'
|
||||
SELECT gen_random_uuid()::text, p.id, 'B1', 'Marina B', 'under_offer', '45', '15', '95000', 'fixed_term'
|
||||
FROM ports p WHERE p.slug = 'port-nimara'
|
||||
ON CONFLICT DO NOTHING;
|
||||
`);
|
||||
|
||||
@@ -291,7 +291,7 @@ describe('resolveTemplate — company-owned yacht', () => {
|
||||
});
|
||||
const berth = await makeBerth({
|
||||
portId: port.id,
|
||||
overrides: { mooringNumber: 'B-7' },
|
||||
overrides: { mooringNumber: 'B7' },
|
||||
});
|
||||
const [interest] = await db
|
||||
.insert(interestsTable)
|
||||
|
||||
@@ -62,7 +62,7 @@ function makeContext(overrides: Partial<EoiContext> = {}): EoiContext {
|
||||
company: null,
|
||||
owner: { type: 'client', name: 'Alice Smith' },
|
||||
berth: {
|
||||
mooringNumber: 'A-12',
|
||||
mooringNumber: 'A12',
|
||||
area: 'North',
|
||||
lengthFt: '50',
|
||||
price: '1000',
|
||||
@@ -93,7 +93,7 @@ describe('fillEoiFormFields', () => {
|
||||
expect(form.getTextField('Length').getText()).toBe('45');
|
||||
expect(form.getTextField('Width').getText()).toBe('14');
|
||||
expect(form.getTextField('Draft').getText()).toBe('6');
|
||||
expect(form.getTextField('Berth Number').getText()).toBe('A-12');
|
||||
expect(form.getTextField('Berth Number').getText()).toBe('A12');
|
||||
|
||||
expect(form.getCheckBox('Purchase').isChecked()).toBe(true);
|
||||
expect(form.getCheckBox('Lease_10').isChecked()).toBe(false);
|
||||
|
||||
@@ -27,7 +27,7 @@ function makeContext(overrides?: Partial<EoiContext>): EoiContext {
|
||||
company: null,
|
||||
owner: { type: 'client', name: 'Alice Smith' },
|
||||
berth: {
|
||||
mooringNumber: 'A-12',
|
||||
mooringNumber: 'A12',
|
||||
area: 'North Dock',
|
||||
lengthFt: '50',
|
||||
price: '1200',
|
||||
@@ -77,7 +77,7 @@ describe('buildDocumensoPayload', () => {
|
||||
Length: '45',
|
||||
Width: '14',
|
||||
Draft: '6',
|
||||
'Berth Number': 'A-12',
|
||||
'Berth Number': 'A12',
|
||||
Lease_10: false,
|
||||
Purchase: true,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user