mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 07:38:10 +00:00
add company stamp upload functionality for contract signing
- Introduced StampUpload component for uploading company stamp images. - Integrated stamp upload in contract signing modal, supporting PNG and JPG formats. - Implemented validation for file type and size (max 5 MB). - Added visual feedback for drag-and-drop functionality. - Updated contract-related pages to handle duplicate contract alerts and pricing notices. - Enhanced contract expiry management with a nightly sweep service. - Added unit tests for new features and updated existing tests for contract handling.
This commit is contained in:
@@ -30,6 +30,28 @@ import {
|
||||
} from './batch-window.util';
|
||||
import { type BookingWindowConfig } from './booking-window.config';
|
||||
|
||||
/**
|
||||
* The most urgent document-review deadline that still has un-accepted booking
|
||||
* requests behind it. Backoffice counts down to it and warns staff, because
|
||||
* everything still pending when the phase ends is expired automatically.
|
||||
*/
|
||||
export interface DocReviewAlert {
|
||||
/** A schedule of the route-day group under review (deep-link target). */
|
||||
scheduleId: string;
|
||||
originYardId: string;
|
||||
destinationYardId: string;
|
||||
/** EAT booking day of the group, YYYY-MM-DD. */
|
||||
day: string;
|
||||
/** IMPORT (the usual) or DOMESTIC — both run a review phase; export does not. */
|
||||
tradeDirection: string;
|
||||
/** ISO deadline the review phase ends at. */
|
||||
docReviewEndsAt: string;
|
||||
/** Full length of the review phase — the client warns past its halfway mark. */
|
||||
docReviewMinutes: number;
|
||||
/** Requests neither accepted nor rejected — they expire at the deadline. */
|
||||
pendingCount: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Drives the one-booking-day window cycle for IMPORT schedules and the FCFS
|
||||
* booking window for EXPORT schedules. All state lives in DB timestamps on the
|
||||
@@ -130,6 +152,65 @@ export class BookingWindowService implements OnModuleInit {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The route-day currently in document review whose deadline is nearest and
|
||||
* which still has un-accepted requests. Null when nothing is under review or
|
||||
* every request has been decided — the backoffice header shows nothing then.
|
||||
*
|
||||
* One card, one deadline, one count: route-days are checked in deadline order
|
||||
* and the first with pending work wins, so the number always belongs to the
|
||||
* clock beside it.
|
||||
*/
|
||||
async getDocReviewAlert(): Promise<DocReviewAlert | null> {
|
||||
const reviewing = (
|
||||
await this.trainSchedulesRepository.findAll({
|
||||
where: [
|
||||
{ status: TrainScheduleStatusEnum.Draft },
|
||||
{ status: TrainScheduleStatusEnum.Scheduled },
|
||||
],
|
||||
})
|
||||
)
|
||||
.filter(
|
||||
(s) =>
|
||||
s.windowPhase === 'DOC_REVIEW' &&
|
||||
s.docReviewCompletedAt == null &&
|
||||
s.docReviewEndsAt != null &&
|
||||
s.scheduledDepartureDate != null,
|
||||
)
|
||||
.sort((a, b) => a.docReviewEndsAt!.getTime() - b.docReviewEndsAt!.getTime());
|
||||
if (reviewing.length === 0) return null;
|
||||
|
||||
const liveCfg = await this.trainSchedulingService.getWindowConfig();
|
||||
const seen = new Set<string>();
|
||||
for (const schedule of reviewing) {
|
||||
const group = {
|
||||
originYardId: schedule.originStationId,
|
||||
destinationYardId: schedule.destinationStationId,
|
||||
day: eatDay(schedule.scheduledDepartureDate),
|
||||
};
|
||||
// Sibling trains share one review phase for the route-day pool — count it once.
|
||||
const key = `${group.originYardId}|${group.destinationYardId}|${group.day}`;
|
||||
if (seen.has(key)) continue;
|
||||
seen.add(key);
|
||||
|
||||
const pendingCount =
|
||||
await this.bookingBatchService.countUnacceptedForRouteDay(group);
|
||||
if (pendingCount === 0) continue;
|
||||
|
||||
return {
|
||||
scheduleId: schedule.id,
|
||||
...group,
|
||||
// Carried so the backoffice list opens on the same direction the
|
||||
// at-risk requests belong to (import corridor, or a domestic day).
|
||||
tradeDirection: schedule.direction ?? 'IMPORT',
|
||||
docReviewEndsAt: schedule.docReviewEndsAt!.toISOString(),
|
||||
docReviewMinutes: effectiveWindowConfig(schedule, liveCfg).docReviewMinutes,
|
||||
pendingCount,
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Staff finished document review early — start the batch/payment phase now. */
|
||||
async completeDocReview(scheduleId: string): Promise<TrainSchedule> {
|
||||
const schedule = await this.trainSchedulesRepository.findById(scheduleId);
|
||||
|
||||
Reference in New Issue
Block a user