mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-08 10:08:21 +00:00
- Implemented method in to allow customers to request an extension for expired contracts. - Added component in for users to initiate extension requests. - Updated to include logic for handling extension requests for expired contracts. - Enhanced to display extension request options and status. - Created migration to add and columns to the contracts table. - Added unit tests for contract extension request and handling in . - Defined DTOs for request and extension in . - Updated types in to include new fields related to contract extensions.
100 lines
4.4 KiB
TypeScript
100 lines
4.4 KiB
TypeScript
import { MigrationInterface, QueryRunner } from 'typeorm';
|
|
|
|
/**
|
|
* Customer-requested validity extension of an EXPIRED contract.
|
|
*
|
|
* Flow: the customer asks from the portal (`extension_requested_at` is stamped,
|
|
* the reason lands in contract_review_notes as EXTENSION_REQUESTED), then staff
|
|
* add days on the backoffice detail page and the contract returns to the status
|
|
* it held before it lapsed. Both expiry paths (nightly sweep + lazy flip on
|
|
* read) now stash that status in `status_before_expiry`, mirroring
|
|
* `status_before_suspension`; rows expired before this column existed fall
|
|
* back to the kind's resting status on extension.
|
|
*
|
|
* Also seeds `edr_freight_app:contracts:extend`. `FreightPositionsSeeder`
|
|
* resolves every registry key against `iam.permissions` at boot and throws on
|
|
* a missing row, so the catalog row must exist wherever the registry ships.
|
|
* The grant is copied from whoever already holds `contracts:suspend` — the
|
|
* registry places both keys on the same desk (marketing), and the position
|
|
* seeder only re-syncs presets when SEED_EDR_ORG is set.
|
|
*/
|
|
export class ContractExtensionRequest3920000000000 implements MigrationInterface {
|
|
name = 'ContractExtensionRequest3920000000000';
|
|
|
|
private static readonly KEY = 'edr_freight_app:contracts:extend';
|
|
private static readonly ID = 'a3000001-0001-4000-8000-00000000001d';
|
|
private static readonly SIBLING_KEY = 'edr_freight_app:contracts:suspend';
|
|
|
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
await queryRunner.query(`
|
|
ALTER TABLE freight.contracts
|
|
ADD COLUMN IF NOT EXISTS extension_requested_at timestamptz NULL
|
|
`);
|
|
await queryRunner.query(`
|
|
ALTER TABLE freight.contracts
|
|
ADD COLUMN IF NOT EXISTS status_before_expiry varchar(40) NULL
|
|
`);
|
|
|
|
await queryRunner.query(
|
|
`INSERT INTO iam.permissions (id, key, name, application_id)
|
|
SELECT $2::uuid,
|
|
$1::varchar,
|
|
'{"am": "Extend an expired contract", "en": "Extend an expired contract"}'::jsonb,
|
|
a.id
|
|
FROM iam.application a
|
|
WHERE a.key = 'edr_freight_app'
|
|
AND NOT EXISTS (SELECT 1 FROM iam.permissions p WHERE p.key = $1::varchar)`,
|
|
[ContractExtensionRequest3920000000000.KEY, ContractExtensionRequest3920000000000.ID],
|
|
);
|
|
|
|
// Grant wherever suspend is already granted (positions and roles alike).
|
|
await queryRunner.query(
|
|
`INSERT INTO iam.position_permissions (position_id, permission_id)
|
|
SELECT pp.position_id, np.id
|
|
FROM iam.position_permissions pp
|
|
JOIN iam.permissions sp ON sp.id = pp.permission_id AND sp.key = $2::varchar
|
|
JOIN iam.permissions np ON np.key = $1::varchar
|
|
WHERE NOT EXISTS (
|
|
SELECT 1 FROM iam.position_permissions x
|
|
WHERE x.position_id = pp.position_id AND x.permission_id = np.id
|
|
)`,
|
|
[ContractExtensionRequest3920000000000.KEY, ContractExtensionRequest3920000000000.SIBLING_KEY],
|
|
);
|
|
await queryRunner.query(
|
|
`INSERT INTO iam.role_permissions (role_id, permission_id)
|
|
SELECT rp.role_id, np.id
|
|
FROM iam.role_permissions rp
|
|
JOIN iam.permissions sp ON sp.id = rp.permission_id AND sp.key = $2::varchar
|
|
JOIN iam.permissions np ON np.key = $1::varchar
|
|
WHERE NOT EXISTS (
|
|
SELECT 1 FROM iam.role_permissions x
|
|
WHERE x.role_id = rp.role_id AND x.permission_id = np.id
|
|
)`,
|
|
[ContractExtensionRequest3920000000000.KEY, ContractExtensionRequest3920000000000.SIBLING_KEY],
|
|
);
|
|
}
|
|
|
|
/** Grants go first, or the delete trips the permission foreign keys. */
|
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
await queryRunner.query(
|
|
`DELETE FROM iam.position_permissions
|
|
WHERE permission_id IN (SELECT id FROM iam.permissions WHERE key = $1)`,
|
|
[ContractExtensionRequest3920000000000.KEY],
|
|
);
|
|
await queryRunner.query(
|
|
`DELETE FROM iam.role_permissions
|
|
WHERE permission_id IN (SELECT id FROM iam.permissions WHERE key = $1)`,
|
|
[ContractExtensionRequest3920000000000.KEY],
|
|
);
|
|
await queryRunner.query(`DELETE FROM iam.permissions WHERE key = $1`, [
|
|
ContractExtensionRequest3920000000000.KEY,
|
|
]);
|
|
await queryRunner.query(
|
|
`ALTER TABLE freight.contracts DROP COLUMN IF EXISTS status_before_expiry`,
|
|
);
|
|
await queryRunner.query(
|
|
`ALTER TABLE freight.contracts DROP COLUMN IF EXISTS extension_requested_at`,
|
|
);
|
|
}
|
|
}
|