eims integration master test complete

This commit is contained in:
Hagernesh
2026-08-12 14:08:28 +00:00
parent 8d53dc17ce
commit 2d4da8110b
38 changed files with 2270 additions and 173 deletions

View File

@@ -0,0 +1,33 @@
import { MigrationInterface, QueryRunner } from "typeorm";
/**
* `eims_irn varchar(64)` was sized for a guess; the real value MoR returns is longer. Confirmed
* live 2026-08-12 — a genuine `POST /v1/register` acceptance came back as
* `test-aeedcbf496f0b63bb035ba3ca1dc674e3c81c980cafeb1c5038421999a23a215` (69 chars: a `test-`
* prefix + a 64-hex-char body), which overflowed the column and threw *after* MoR had already
* accepted the document — `settleSuccess` never committed, leaving the invoice stuck `SUBMITTING`
* and the system-wide reservation stuck in-flight with no block/alert (see
* `EimsInvoiceRegistrationService` for the accompanying code fix).
*
* Widened to `text` rather than a new fixed length: MoR has never documented an IRN format or
* length, and a `test-` prefix on a *production* endpoint suggests this may not even be MoR's
* real production shape — guessing another fixed bound risks the exact same failure again.
*/
export class WidenEimsIrn3450000000000 implements MigrationInterface {
name = "WidenEimsIrn3450000000000";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE freight.invoices
ALTER COLUMN eims_irn TYPE text
`);
}
/** Only safe if nothing stored so far exceeds 64 chars — true only until this migration ran. */
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE freight.invoices
ALTER COLUMN eims_irn TYPE varchar(64)
`);
}
}

View File

@@ -0,0 +1,20 @@
import { MigrationInterface, QueryRunner } from "typeorm";
/** `DocumentDetails`/register-response field `signedQR`, persisted alongside `eims_irn`. */
export class AddEimsSignedQr3460000000000 implements MigrationInterface {
name = "AddEimsSignedQr3460000000000";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE freight.invoices
ADD COLUMN IF NOT EXISTS eims_signed_qr text
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE freight.invoices
DROP COLUMN IF EXISTS eims_signed_qr
`);
}
}

View File

@@ -0,0 +1,26 @@
import { MigrationInterface, QueryRunner } from "typeorm";
/** Columns for `POST /v1/cancel` — see `EimsCancellationService`. */
export class EimsCancellation3470000000000 implements MigrationInterface {
name = "EimsCancellation3470000000000";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE freight.invoices
ADD COLUMN IF NOT EXISTS eims_cancelled_at timestamptz,
ADD COLUMN IF NOT EXISTS eims_cancellation_date varchar(64),
ADD COLUMN IF NOT EXISTS eims_cancellation_reason_code varchar(8),
ADD COLUMN IF NOT EXISTS eims_cancellation_remark text
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE freight.invoices
DROP COLUMN IF EXISTS eims_cancelled_at,
DROP COLUMN IF EXISTS eims_cancellation_date,
DROP COLUMN IF EXISTS eims_cancellation_reason_code,
DROP COLUMN IF EXISTS eims_cancellation_remark
`);
}
}

View File

@@ -0,0 +1,24 @@
import { MigrationInterface, QueryRunner } from "typeorm";
/**
* Same bug as `3450000000000-WidenEimsIrn`, same fix: `previous_irn` stores a real MoR IRN too
* (fed into the next registration's `ReferenceDetails.PreviousIrn`) and would overflow the same
* varchar(64) on the next successful registration.
*/
export class WidenPreviousIrn3480000000000 implements MigrationInterface {
name = "WidenPreviousIrn3480000000000";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE freight.eims_system_state
ALTER COLUMN previous_irn TYPE text
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE freight.eims_system_state
ALTER COLUMN previous_irn TYPE varchar(64)
`);
}
}

View File

@@ -0,0 +1,34 @@
import { MigrationInterface, QueryRunner } from "typeorm";
/** `freight.eims_receipts` — see `EimsReceipt` entity. */
export class EimsReceipts3490000000000 implements MigrationInterface {
name = "EimsReceipts3490000000000";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
CREATE TABLE IF NOT EXISTS freight.eims_receipts (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
invoice_id uuid NOT NULL REFERENCES freight.invoices(id),
kind varchar(16) NOT NULL,
status varchar(20) NOT NULL DEFAULT 'NOT_SUBMITTED',
receipt_number varchar(64) NOT NULL,
rrn text,
qr text,
ack_status varchar(8),
submitted_at timestamptz,
last_error jsonb,
request jsonb,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),
deleted_at timestamptz
)
`);
await queryRunner.query(`
CREATE INDEX IF NOT EXISTS idx_eims_receipts_invoice_id ON freight.eims_receipts (invoice_id)
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP TABLE IF EXISTS freight.eims_receipts`);
}
}