mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 04:08:11 +00:00
feat: implement wagon transfer management modals and page
- Add TransferFulfillModal for fulfilling wagon transfer requests. - Create TransferRequestFormModal for filing new wagon transfer requests. - Introduce TransferCloseShortModal for closing requests that cannot be fully fulfilled. - Develop WagonTransfersPage to manage and display wagon transfer requests. - Implement utility functions for handling wagon transfer request data and UI components. - Enhance UI with Mantine components for better user experience.
This commit is contained in:
@@ -5,7 +5,7 @@ import {
|
||||
BadRequestException,
|
||||
ForbiddenException,
|
||||
} from "@nestjs/common";
|
||||
import { DataSource } from "typeorm";
|
||||
import { DataSource, EntityManager } from "typeorm";
|
||||
import { CompaniesRepository } from "./companies.repository";
|
||||
import { CompanyProfileRepository } from "./company-profile.repository";
|
||||
import { CompanyChangeRequestRepository } from "./company-change-request.repository";
|
||||
@@ -1111,9 +1111,11 @@ export class CompaniesService {
|
||||
}
|
||||
|
||||
// Anything other than approval has no document gate and no concurrency
|
||||
// hazard — apply it directly.
|
||||
// hazard — no row lock, just the write.
|
||||
if (status !== ProfileStatus.Active) {
|
||||
return this.applyProfileStatus(existing, status, note, reviewerId);
|
||||
return this.dataSource.transaction((manager) =>
|
||||
this.applyProfileStatus(manager, existing, status, note, reviewerId),
|
||||
);
|
||||
}
|
||||
|
||||
// Approving over an outstanding document correction would silently accept the
|
||||
@@ -1149,7 +1151,7 @@ export class CompaniesService {
|
||||
);
|
||||
}
|
||||
|
||||
return this.applyProfileStatus(existing, status, note, reviewerId);
|
||||
return this.applyProfileStatus(manager, existing, status, note, reviewerId);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1160,11 +1162,21 @@ export class CompaniesService {
|
||||
* transaction while every other status skips that overhead.
|
||||
*/
|
||||
private async applyProfileStatus(
|
||||
manager: EntityManager,
|
||||
existing: CompanyProfile,
|
||||
status: ProfileStatus,
|
||||
note?: string,
|
||||
reviewerId?: string,
|
||||
): Promise<CompanyProfile> {
|
||||
// Every write below goes through `manager`. The approval path holds a
|
||||
// pessimistic_write lock on the company row, and the injected repositories
|
||||
// are bound to the DataSource's default pool — writing the same row through
|
||||
// one of them would block on a lock this very transaction holds, hanging the
|
||||
// request until the statement timed out. That deadlocked the first approval
|
||||
// of any customer: the profile went Active on its own connection while the
|
||||
// company stayed Pending and the caller never got a response.
|
||||
const profileRepo = manager.getRepository(CompanyProfile);
|
||||
const companyRepo = manager.getRepository(Company);
|
||||
// A reference number is only minted the first time a profile is approved
|
||||
// (status → Active). Pending/unapproved profiles carry no reference.
|
||||
const patch: Partial<CompanyProfile> = { status };
|
||||
@@ -1190,7 +1202,8 @@ export class CompaniesService {
|
||||
patch.reviewedAt = new Date();
|
||||
}
|
||||
|
||||
const updated = await this.companyProfilesRepo.update(existing.id, patch);
|
||||
await profileRepo.update(existing.id, patch);
|
||||
const updated = await profileRepo.findOne({ where: { id: existing.id } });
|
||||
if (!updated)
|
||||
throw new NotFoundException(`Company profile ${existing.id} not found`);
|
||||
|
||||
@@ -1208,7 +1221,9 @@ export class CompaniesService {
|
||||
: "approved"
|
||||
: null;
|
||||
if (change) {
|
||||
const company = await this.companiesRepo.findById(updated.companyId);
|
||||
const company = await companyRepo.findOne({
|
||||
where: { id: updated.companyId },
|
||||
});
|
||||
if (company) {
|
||||
this.companyNotifier.profileStatusChanged(
|
||||
company,
|
||||
@@ -1222,7 +1237,7 @@ export class CompaniesService {
|
||||
status === ProfileStatus.Active &&
|
||||
company.status === CompanyStatus.Pending
|
||||
) {
|
||||
await this.companiesRepo.update(updated.companyId, {
|
||||
await companyRepo.update(updated.companyId, {
|
||||
status: CompanyStatus.Active,
|
||||
});
|
||||
this.companyNotifier.companyApproved(company);
|
||||
|
||||
Reference in New Issue
Block a user