mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-01 17:03:27 +00:00
add dispute functionality for contract duty and implement collection dates
This commit is contained in:
@@ -7449,8 +7449,8 @@ export class TrainSchedulingService {
|
||||
|
||||
// Target: a slot of this train set, or an empty consist-only wagon of the
|
||||
// built train (physical wagon with no slot row yet).
|
||||
const targetSlot = slots.find((w) => w.id === dto.targetWagonId) ?? null;
|
||||
const consistWagon = targetSlot
|
||||
const slotById = slots.find((w) => w.id === dto.targetWagonId) ?? null;
|
||||
const wagonForTarget = slotById
|
||||
? null
|
||||
: schedule.trainSet?.trainId
|
||||
? await this.dataSource.getRepository(Wagon).findOne({
|
||||
@@ -7458,10 +7458,22 @@ export class TrainSchedulingService {
|
||||
relations: { wagonType: true },
|
||||
})
|
||||
: null;
|
||||
if (!targetSlot && !consistWagon) {
|
||||
if (!slotById && !wagonForTarget) {
|
||||
throw new NotFoundException('Target wagon is not part of this schedule');
|
||||
}
|
||||
// A physical wagon holds at most one slot. When the caller addressed the
|
||||
// wagon directly but a slot is already pinned to it, move into that slot
|
||||
// rather than minting a second one on the same wagon.
|
||||
const targetSlot =
|
||||
slotById ??
|
||||
(wagonForTarget
|
||||
? (slots.find((w) => w.physicalWagonId === wagonForTarget.id) ?? null)
|
||||
: null);
|
||||
const consistWagon = targetSlot ? null : wagonForTarget;
|
||||
const targetAllocs = targetSlot ? await loadAllocations(targetSlot.id) : [];
|
||||
if (targetSlot && targetSlot.id === source.id) {
|
||||
return this.getTrainScheduleById(scheduleId);
|
||||
}
|
||||
|
||||
const loadTypesOf = (allocs: WagonBookingAllocation[]) => [
|
||||
...new Set(allocs.map((a) => (a.loadType ?? 'CONTAINER').toUpperCase())),
|
||||
@@ -7525,19 +7537,6 @@ export class TrainSchedulingService {
|
||||
const slotRepo = manager.getRepository(TrainSetWagon);
|
||||
const allocs = manager.getRepository(WagonBookingAllocation);
|
||||
|
||||
// Empty consist wagon: repin the loaded slot onto that physical wagon.
|
||||
// Allocations and load fields stay put; only the wagon identity changes.
|
||||
if (consistWagon) {
|
||||
await slotRepo.update(source.id, {
|
||||
physicalWagonId: consistWagon.id,
|
||||
wagonTypeId: consistWagon.wagonTypeId,
|
||||
capacityTons: roundTons(Number(consistWagon.wagonType?.capacityTons ?? source.capacityTons)),
|
||||
lengthMeters: roundTons(Number(consistWagon.wagonType?.lengthMeters ?? source.lengthMeters)),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const target = targetSlot as TrainSetWagon;
|
||||
// Load-coupled slot fields travel with the load; wagon identity stays.
|
||||
const loadFieldsOf = (slot: TrainSetWagon) => ({
|
||||
assignedWeightTons: slot.assignedWeightTons,
|
||||
@@ -7552,6 +7551,47 @@ export class TrainSchedulingService {
|
||||
alightYardId: null,
|
||||
};
|
||||
const sourceLoadFields = loadFieldsOf(source);
|
||||
|
||||
// Empty consist wagon with no slot row yet: give it one, then move the
|
||||
// load into it. Repinning the SOURCE slot onto that wagon would have been
|
||||
// fewer writes, but it renames the wagons instead of moving the load —
|
||||
// the loaded slot becomes wagon B and B's identity pops out as an empty
|
||||
// wagon where A used to be. Staff read that as the train re-ordering
|
||||
// itself. A wagon must never change place because a container moved.
|
||||
if (consistWagon) {
|
||||
const { maxSequenceNo } = (await slotRepo
|
||||
.createQueryBuilder('slot')
|
||||
.select('COALESCE(MAX(slot.sequence_no), 0)', 'maxSequenceNo')
|
||||
.where('slot.train_set_id = :trainSetId', { trainSetId: source.trainSetId })
|
||||
.getRawOne<{ maxSequenceNo: string | number }>()) ?? { maxSequenceNo: 0 };
|
||||
|
||||
const created = await slotRepo.save(
|
||||
slotRepo.create({
|
||||
trainSetId: source.trainSetId,
|
||||
wagonTypeId: consistWagon.wagonTypeId,
|
||||
physicalWagonId: consistWagon.id,
|
||||
// Plan-order key only — the consist is drawn in the train's coupling
|
||||
// order (wagons.sequence_number), so appending here moves nothing.
|
||||
// It just has to clear the (train_set_id, sequence_no) unique index.
|
||||
sequenceNo: Number(maxSequenceNo) + 1,
|
||||
capacityTons: roundTons(
|
||||
Number(consistWagon.wagonType?.capacityTons ?? source.capacityTons),
|
||||
),
|
||||
lengthMeters: roundTons(
|
||||
Number(consistWagon.wagonType?.lengthMeters ?? source.lengthMeters),
|
||||
),
|
||||
...sourceLoadFields,
|
||||
}),
|
||||
);
|
||||
|
||||
for (const alloc of sourceAllocs) {
|
||||
await allocs.update(alloc.id, { trainSetWagonId: created.id });
|
||||
}
|
||||
await slotRepo.update(source.id, emptyLoadFields);
|
||||
return;
|
||||
}
|
||||
|
||||
const target = targetSlot as TrainSetWagon;
|
||||
const targetLoadFields = targetAllocs.length ? loadFieldsOf(target) : emptyLoadFields;
|
||||
|
||||
for (const alloc of sourceAllocs) {
|
||||
|
||||
Reference in New Issue
Block a user