mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 14:08:11 +00:00
72 lines
2.9 KiB
TypeScript
72 lines
2.9 KiB
TypeScript
import { MigrationInterface, QueryRunner } from "typeorm";
|
|
|
|
/**
|
|
* Extend `freight.invoices` into the billing record of record for every source
|
|
* (booking, demurrage, warehouse fees, …) so warehouse fee invoices can be
|
|
* centralized onto it instead of the parallel `warehouse_fee_invoices` table.
|
|
*
|
|
* Adds money tracking that supports partial payment (`subtotal/tax/paid/balance`),
|
|
* a `paid_at` stamp, a `payments` jsonb ledger, and the `ISSUED` / `PARTIALLY_PAID`
|
|
* statuses the warehouse flow uses.
|
|
*
|
|
* Matches billing/entities/invoice.entity.ts. All columns are additive with
|
|
* defaults, so existing booking/demurrage rows are unaffected.
|
|
*/
|
|
export class ExtendInvoicesForPartialPayment1828000000000
|
|
implements MigrationInterface
|
|
{
|
|
name = "ExtendInvoicesForPartialPayment1828000000000";
|
|
|
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
// New statuses. ADD VALUE is non-transactional-value-safe on PG 12+ as long
|
|
// as the value is not referenced in the same transaction (it is not here).
|
|
await queryRunner.query(
|
|
`ALTER TYPE freight.invoices_status_enum ADD VALUE IF NOT EXISTS 'ISSUED' BEFORE 'PENDING';`,
|
|
);
|
|
await queryRunner.query(
|
|
`ALTER TYPE freight.invoices_status_enum ADD VALUE IF NOT EXISTS 'PARTIALLY_PAID' BEFORE 'PAID';`,
|
|
);
|
|
|
|
await queryRunner.query(`
|
|
ALTER TABLE freight.invoices
|
|
ADD COLUMN IF NOT EXISTS subtotal_amount numeric(14, 2) NOT NULL DEFAULT 0,
|
|
ADD COLUMN IF NOT EXISTS tax_amount numeric(14, 2) NOT NULL DEFAULT 0,
|
|
ADD COLUMN IF NOT EXISTS paid_amount numeric(14, 2) NOT NULL DEFAULT 0,
|
|
ADD COLUMN IF NOT EXISTS balance_amount numeric(14, 2) NOT NULL DEFAULT 0,
|
|
ADD COLUMN IF NOT EXISTS paid_at timestamptz,
|
|
ADD COLUMN IF NOT EXISTS payments jsonb NOT NULL DEFAULT '[]';
|
|
`);
|
|
|
|
// Backfill existing rows: subtotal mirrors the total (no tax was modeled),
|
|
// the outstanding balance is the full total for unpaid invoices.
|
|
await queryRunner.query(`
|
|
UPDATE freight.invoices
|
|
SET subtotal_amount = total_amount,
|
|
balance_amount = total_amount;
|
|
`);
|
|
|
|
// Already-settled invoices: fully paid, zero balance, stamped from updated_at.
|
|
await queryRunner.query(`
|
|
UPDATE freight.invoices
|
|
SET paid_amount = total_amount,
|
|
balance_amount = 0,
|
|
paid_at = updated_at
|
|
WHERE status = 'PAID';
|
|
`);
|
|
}
|
|
|
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
await queryRunner.query(`
|
|
ALTER TABLE freight.invoices
|
|
DROP COLUMN IF EXISTS payments,
|
|
DROP COLUMN IF EXISTS paid_at,
|
|
DROP COLUMN IF EXISTS balance_amount,
|
|
DROP COLUMN IF EXISTS paid_amount,
|
|
DROP COLUMN IF EXISTS tax_amount,
|
|
DROP COLUMN IF EXISTS subtotal_amount;
|
|
`);
|
|
// Postgres cannot drop individual enum values; ISSUED / PARTIALLY_PAID are
|
|
// left on freight.invoices_status_enum (harmless, unused after down).
|
|
}
|
|
}
|