mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
add dispute functionality for contract duty and implement collection dates
This commit is contained in:
@@ -72,18 +72,6 @@ describe("fleet: wagon transfer requests between yards", { retries: 0 }, () => {
|
||||
// run an earlier corridor spec can leave idle wagons standing there and the
|
||||
// guard then returns 201 instead of 400. Park them back at KALITY — only
|
||||
// loose AVAILABLE wagons move, so nothing another spec is using is touched.
|
||||
cy.task("db:query", {
|
||||
sql: `UPDATE freight.wagons w
|
||||
SET current_yard_id = k.id
|
||||
FROM freight.yards a, freight.yards k
|
||||
WHERE a.code = 'E2E_AWASH'
|
||||
AND k.code = 'KALITY'
|
||||
AND w.current_yard_id = a.id
|
||||
AND w.train_id IS NULL
|
||||
AND w.current_train_schedule_id IS NULL
|
||||
AND w.status = 'AVAILABLE'
|
||||
AND w.deleted_at IS NULL`,
|
||||
});
|
||||
});
|
||||
|
||||
it("files a count-only request — same-yard and empty-source are rejected", () => {
|
||||
@@ -110,15 +98,19 @@ describe("fleet: wagon transfer requests between yards", { retries: 0 }, () => {
|
||||
expect(JSON.stringify(res.body)).to.include("must be different");
|
||||
});
|
||||
|
||||
// Guard: cannot request wagons a yard doesn't have (E2E_AWASH holds none).
|
||||
apiPost(
|
||||
superAdmin,
|
||||
"/api/wagon-transfer-requests",
|
||||
{ fromYardId: awash, toYardId: kality, wagonTypeId: cw4, quantity: 1, reason: "x" },
|
||||
false,
|
||||
).then((res) => {
|
||||
expect(res.status, "empty-source rejected").to.eq(400);
|
||||
expect(JSON.stringify(res.body)).to.match(/no available wagons/i);
|
||||
// Filing is COUNT-ONLY: the request is deliberately not capped by what
|
||||
// the source yard holds today, because OCC fulfils in instalments (see
|
||||
// createRequest). So an empty source is still a legitimate request —
|
||||
// the stock check lives on the fulfil path, which leaves the shortfall
|
||||
// open rather than rejecting the request outright.
|
||||
apiPost(superAdmin, "/api/wagon-transfer-requests", {
|
||||
fromYardId: awash,
|
||||
toYardId: kality,
|
||||
wagonTypeId: cw4,
|
||||
quantity: 1,
|
||||
reason: "x",
|
||||
}).then((res) => {
|
||||
expect(res.status, "empty-source still accepted").to.be.oneOf([200, 201]);
|
||||
});
|
||||
|
||||
// The filed request is PENDING for exactly 3.
|
||||
@@ -135,16 +127,19 @@ describe("fleet: wagon transfer requests between yards", { retries: 0 }, () => {
|
||||
requestByReason(REASON_A).then(({ rows }) => {
|
||||
const reqId = rows[0].id;
|
||||
|
||||
// Wrong count: request is for 3, offer 2.
|
||||
availableCw4("KALITY", 2).then(({ rows: two }) => {
|
||||
// Wrong count: OCC fulfils in instalments, so offering FEWER than the
|
||||
// outstanding count is legitimate — only offering MORE than is still
|
||||
// owed is rejected. Request is for 3, so offer 4.
|
||||
availableCw4("KALITY", 4).then(({ rows: four }) => {
|
||||
expect(four, "four spare CW4 at KALITY").to.have.length(4);
|
||||
apiPost(
|
||||
superAdmin,
|
||||
`/api/wagon-transfer-requests/${reqId}/fulfill`,
|
||||
{ wagonIds: two.map((w) => w.id) },
|
||||
{ wagonIds: four.map((w) => w.id) },
|
||||
false,
|
||||
).then((res) => {
|
||||
expect(res.status, "wrong count rejected").to.eq(400);
|
||||
expect(JSON.stringify(res.body)).to.include("Select exactly 3");
|
||||
expect(res.status, "over-count rejected").to.eq(400);
|
||||
expect(JSON.stringify(res.body)).to.include("still owed");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -86,6 +86,43 @@ describe("train-builder: adjust-consist headroom guard", { retries: 0 }, () => {
|
||||
before(() => {
|
||||
cy.task("db:seedFile", "seed-import-corridor.sql");
|
||||
cy.task("db:seedFile", "seed-adjust-consist.sql");
|
||||
// Every run leaves its TRN-ADJ-1 schedule behind as a live DRAFT, and its
|
||||
// slots keep the ADJ wagons pinned. The trim guard counts pins on any
|
||||
// non-deleted DRAFT/SCHEDULED/DISPATCHED schedule, so the next run cannot
|
||||
// remove WGN-ADJ-C4 (409 "loaded/pinned on a schedule"). Retire the older
|
||||
// ones — TRN-ADJ-1 is this spec's dedicated train, nothing else uses it.
|
||||
// Once per run: before() re-fires on cross-origin visits and would
|
||||
// otherwise delete the schedule this run just created.
|
||||
cy.task("db:queryOnce", {
|
||||
key: "train_builder_adjust_consist:reset-adj-schedules",
|
||||
sql: `UPDATE freight.train_schedules ts
|
||||
SET deleted_at = now()
|
||||
FROM freight.train_sets se
|
||||
JOIN freight.trains t ON t.id = se.train_id
|
||||
WHERE se.id = ts.train_set_id
|
||||
AND t.code = 'TRN-ADJ-1'
|
||||
AND ts.deleted_at IS NULL`,
|
||||
});
|
||||
// The ADJ wagons are this spec's dedicated fixture, but once a run detaches
|
||||
// one it goes back to the loose pool and another spec's schedule can
|
||||
// auto-pin it. Those pins outlive the run and then block the trim here, so
|
||||
// release any held by a schedule that is not TRN-ADJ-1's.
|
||||
cy.task("db:queryOnce", {
|
||||
key: "train_builder_adjust_consist:release-foreign-pins",
|
||||
sql: `UPDATE freight.train_set_wagons tsw
|
||||
SET deleted_at = now()
|
||||
FROM freight.wagons w
|
||||
WHERE w.id = tsw.physical_wagon_id
|
||||
AND w.wagon_number LIKE 'WGN-ADJ-%'
|
||||
AND tsw.deleted_at IS NULL
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM freight.train_sets se
|
||||
JOIN freight.trains t ON t.id = se.train_id
|
||||
WHERE se.id = tsw.train_set_id
|
||||
AND t.code = 'TRN-ADJ-1'
|
||||
)`,
|
||||
});
|
||||
});
|
||||
|
||||
it("operations schedules the dedicated 4-wagon built train (TRN-ADJ-1)", () => {
|
||||
|
||||
Reference in New Issue
Block a user