add permissions and fix issues

This commit is contained in:
Marshal
2026-07-23 20:24:20 +00:00
parent 40f16f3cec
commit 668b5e1c9d
40 changed files with 18634 additions and 342 deletions

View File

@@ -26,6 +26,24 @@
-- missing production migration.
DROP INDEX IF EXISTS freight.uq_one_active_booking_per_one_time_contract;
-- 0b. Schema drift guard: CUSTOMS_CLEARANCE / WITH_RETURN rates became
-- route-scoped in migrations 2820 + 2830, but an e2e image built before them
-- still carries the old CK_rates_yard_scope (yards allowed only for ALWAYS
-- BULK/CONTAINER/INTERCITY rows). Re-state the post-2830 shape — a no-op on an
-- up-to-date image, and what lets the customs-clearance lane rates below load.
ALTER TABLE freight.rates DROP CONSTRAINT IF EXISTS "CK_rates_yard_scope";
ALTER TABLE freight.rates
ADD CONSTRAINT "CK_rates_yard_scope" CHECK (
deleted_at IS NOT NULL
OR status = 'SUPERSEDED'
OR CASE
WHEN ("trigger" = 'ALWAYS' AND applies_to IN ('BULK', 'CONTAINER', 'INTERCITY'))
OR "trigger" IN ('CUSTOMS_CLEARANCE', 'WITH_RETURN')
THEN origin_yard_id IS NOT NULL AND destination_yard_id IS NOT NULL
ELSE origin_yard_id IS NULL AND destination_yard_id IS NULL
END
);
-- 1a. Extra Ethiopian mid-corridor yard.
INSERT INTO freight.yards (id, code, label, country, is_active, display_order)
SELECT gen_random_uuid(), 'E2E_AWASH', 'E2E Awash Yard', 'Ethiopia', true, 50
@@ -124,7 +142,7 @@ FROM (
JOIN freight.yards y ON y.id = w2.current_yard_id AND y.code = 'DJIB_PORT'
WHERE w2.train_id IS NULL AND w2.deleted_at IS NULL
ORDER BY w2.wagon_number ASC
LIMIT 120
LIMIT 200
) pick
WHERE w.id = pick.id;
@@ -158,22 +176,35 @@ WHERE NOT EXISTS (SELECT 1 FROM freight.locomotives l WHERE l.code = v.code);
INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, current_yard_id)
SELECT gen_random_uuid(), 'ECW' || lpad(g::text, 4, '0'), wt.id,
(SELECT id FROM freight.yards
WHERE code = CASE WHEN g <= 80 THEN 'KALITY' ELSE 'DIRE_DAWA' END)
FROM generate_series(1, 100) AS g
WHERE code = CASE WHEN g <= 120 THEN 'KALITY' ELSE 'DIRE_DAWA' END)
FROM generate_series(1, 160) AS g
JOIN freight.wagon_types wt ON wt.code = 'CW4'
WHERE NOT EXISTS (
SELECT 1 FROM freight.wagons w WHERE w.wagon_number = 'ECW' || lpad(g::text, 4, '0')
);
-- 5b3. Ledger-day rolling stock: wheat may also ride PW2 box wagons, and the
-- GRAIN train is a BUILT Train-Builder consist — 37 PW2 wagons coupled at
-- KALITY behind two dedicated locos. A built train's physical wagon count IS
-- its schedule capacity (37), immune to the loco-length slot recompute.
-- 5b3. Ledger-day rolling stock: GRAINS ride PW2 box wagons on a BUILT
-- Train-Builder consist — 37 PW2 wagons coupled at KALITY behind two dedicated
-- locos. A built train's physical wagon count IS its schedule capacity (37),
-- immune to the loco-length slot recompute.
--
-- GRAINS gets PW2 (17.066 m), WHEAT gets CW4 (13.976 m) below — kept on SEPARATE
-- cargo types on purpose. `dimsFor`/`needFor` size a bulk booking off its cargo
-- type's FIRST wagon type, so a cargo carrying two wagon-lengths sizes
-- inconsistently on loco-pair export trains (one booking as CW4, another as PW2)
-- and the length budget never matches the 54-wagon CW4 board the export specs
-- expect. One cargo → one wagon length keeps that math deterministic.
DELETE FROM freight.cargo_type_wagon_types x
USING freight.cargo_types ct, freight.wagon_types wt
WHERE x.cargo_type_id = ct.id AND x.wagon_type_id = wt.id
AND ((ct.code = 'E2E_IMP_WHEAT' AND wt.code = 'PW2')
OR (ct.code = 'E2E_IMP_GRAINS' AND wt.code = 'CW4'));
INSERT INTO freight.cargo_type_wagon_types (cargo_type_id, wagon_type_id)
SELECT ct.id, wt.id
FROM freight.cargo_types ct
JOIN freight.wagon_types wt ON wt.code = 'PW2'
WHERE ct.code IN ('E2E_IMP_GRAINS', 'E2E_IMP_WHEAT')
WHERE ct.code = 'E2E_IMP_GRAINS'
AND NOT EXISTS (
SELECT 1 FROM freight.cargo_type_wagon_types x
WHERE x.cargo_type_id = ct.id AND x.wagon_type_id = wt.id
@@ -182,7 +213,8 @@ WHERE ct.code IN ('E2E_IMP_GRAINS', 'E2E_IMP_WHEAT')
INSERT INTO freight.locomotives
(id, code, max_pull_weight_tons, max_train_length_meters, current_yard_id)
SELECT gen_random_uuid(), v.code, 9000, 760, y.id
FROM (VALUES ('LOCO-LED-1'), ('LOCO-LED-2')) AS v(code)
FROM (VALUES ('LOCO-LED-1'), ('LOCO-LED-2'), ('LOCO-LED-3'), ('LOCO-LED-4'),
('LOCO-LED-5'), ('LOCO-LED-6')) AS v(code)
JOIN freight.yards y ON y.code = 'KALITY'
WHERE NOT EXISTS (SELECT 1 FROM freight.locomotives l WHERE l.code = v.code);
@@ -269,7 +301,7 @@ INSERT INTO freight.cargo_type_wagon_types (cargo_type_id, wagon_type_id)
SELECT ct.id, wt.id
FROM freight.cargo_types ct
JOIN freight.wagon_types wt ON wt.code = 'CW4'
WHERE ct.code IN ('E2E_IMP_GRAINS', 'E2E_IMP_WHEAT')
WHERE ct.code = 'E2E_IMP_WHEAT'
AND NOT EXISTS (
SELECT 1 FROM freight.cargo_type_wagon_types x
WHERE x.cargo_type_id = ct.id AND x.wagon_type_id = wt.id
@@ -289,7 +321,7 @@ WHERE wt.id = w.wagon_type_id AND wt.code = 'CW4'
-- Re-park the export CW4 pocket every seed (the mint above is insert-guarded).
UPDATE freight.wagons w
SET current_yard_id = (SELECT id FROM freight.yards
WHERE code = CASE WHEN substring(w.wagon_number FROM 4)::int <= 80
WHERE code = CASE WHEN substring(w.wagon_number FROM 4)::int <= 120
THEN 'KALITY' ELSE 'DIRE_DAWA' END)
FROM freight.wagon_types wt
WHERE wt.id = w.wagon_type_id AND wt.code = 'CW4'
@@ -357,3 +389,62 @@ WHERE NOT EXISTS (
AND r.origin_yard_id = a.id AND r.destination_yard_id = b.id
AND r.deleted_at IS NULL
);
-- 7b. Customs clearance service fees — billed on the booking invoice together
-- with the freight. Sold per direction + route + cargo kind: container fees
-- per container type (one row per active 20/40ft type so whichever type the
-- server resolves for a size always matches), bulk fees per commodity.
-- Without these, every customs booking hard-blocks at pricing.
INSERT INTO freight.rates
(id, rate_type, applies_to, trigger, currency, rate_value, rate_unit, status,
trade_direction, container_type_id, origin_yard_id, destination_yard_id,
proposed_by_staff_id)
SELECT gen_random_uuid(), 'CUSTOMS_CLEARANCE', 'OTHER', 'CUSTOMS_CLEARANCE',
'USD', 50, 'PER_CONTAINER', 'LIVE', v.direction, ct.id, a.id, b.id, u.id
FROM (VALUES
('IMPORT', 'DJIB_PORT', 'KALITY'),
('IMPORT', 'DJIB_PORT', 'MOJO'),
('IMPORT', 'NAGAD', 'KALITY'),
('IMPORT', 'NAGAD', 'MOJO'),
('EXPORT', 'KALITY', 'DJIB_PORT'),
('EXPORT', 'MOJO', 'DJIB_PORT'),
('EXPORT', 'DIRE_DAWA', 'DJIB_PORT')
) AS v(direction, from_code, to_code)
JOIN freight.yards a ON a.code = v.from_code
JOIN freight.yards b ON b.code = v.to_code
JOIN freight.container_types ct ON ct.size_ft IN (20, 40) AND ct.is_active
JOIN iam.users u ON u.email = 'operation@edr.local'
WHERE NOT EXISTS (
SELECT 1 FROM freight.rates r
WHERE r.rate_type = 'CUSTOMS_CLEARANCE'
AND r.container_type_id = ct.id
AND r.origin_yard_id = a.id AND r.destination_yard_id = b.id
AND r.deleted_at IS NULL
);
INSERT INTO freight.rates
(id, rate_type, applies_to, trigger, currency, rate_value, rate_unit, status,
trade_direction, cargo_type_id, origin_yard_id, destination_yard_id,
proposed_by_staff_id)
SELECT gen_random_uuid(), 'CUSTOMS_CLEARANCE', 'OTHER', 'CUSTOMS_CLEARANCE',
'USD', 2, 'PER_TON', 'LIVE', v.direction, cgt.id, a.id, b.id, u.id
FROM (VALUES
('IMPORT', 'DJIB_PORT', 'KALITY'),
('IMPORT', 'DJIB_PORT', 'MOJO'),
('IMPORT', 'NAGAD', 'KALITY'),
('IMPORT', 'NAGAD', 'MOJO'),
('EXPORT', 'KALITY', 'DJIB_PORT'),
('EXPORT', 'MOJO', 'DJIB_PORT'),
('EXPORT', 'DIRE_DAWA', 'DJIB_PORT')
) AS v(direction, from_code, to_code)
JOIN freight.yards a ON a.code = v.from_code
JOIN freight.yards b ON b.code = v.to_code
JOIN freight.cargo_types cgt ON cgt.code = 'E2E_IMP_WHEAT'
JOIN iam.users u ON u.email = 'operation@edr.local'
WHERE NOT EXISTS (
SELECT 1 FROM freight.rates r
WHERE r.rate_type = 'CUSTOMS_CLEARANCE'
AND r.cargo_type_id = cgt.id
AND r.origin_yard_id = a.id AND r.destination_yard_id = b.id
AND r.deleted_at IS NULL
);