Files
edr-platform/apps/edr-freight-api/src/modules/warehouses/warehouse-inspection.service.ts
2026-06-17 21:45:22 +00:00

117 lines
4.8 KiB
TypeScript

import { Injectable, NotFoundException } from '@nestjs/common';
import { DataSource } from 'typeorm';
import { FilesService } from '../files/files.service';
import { CreateInspectionReportDto } from './dto/create-inspection-report.dto';
import { UpdateInspectionReportDto } from './dto/update-inspection-report.dto';
import { WarehouseInspectionReport } from './entities/warehouse-inspection-report.entity';
import { WarehouseInventory } from './entities/warehouse-inventory.entity';
import { WarehouseInspectionRepository } from './warehouse-inspection.repository';
const INSPECTION_RESOURCE = 'warehouse-inspection-report';
@Injectable()
export class WarehouseInspectionService {
constructor(
private readonly dataSource: DataSource,
private readonly inspectionRepository: WarehouseInspectionRepository,
private readonly filesService: FilesService,
) {}
/** Create an inspection report for an inventory item and sync its inspectionStatus. */
async create(inventoryId: string, dto: CreateInspectionReportDto): Promise<WarehouseInspectionReport> {
const inventoryRepo = this.dataSource.getRepository(WarehouseInventory);
const inventory = await inventoryRepo.findOne({ where: { id: inventoryId } });
if (!inventory) {
throw new NotFoundException(`Inventory item ${inventoryId} not found`);
}
const expected = dto.expectedWeight ?? null;
const actual = dto.actualWeight ?? null;
const weightLoss = expected !== null && actual !== null ? Math.max(0, expected - actual) : null;
const report = await this.inspectionRepository.create({
inventoryId,
bookingId: inventory.bookingId ?? null,
reportType: dto.reportType,
inspectionStatus: dto.inspectionStatus,
hasDamage: dto.hasDamage ?? false,
damageDescription: dto.damageDescription ?? null,
hasWeightLoss: dto.hasWeightLoss ?? false,
expectedWeight: expected,
actualWeight: actual,
weightLoss,
weightLossUnit: weightLoss !== null ? 'kg' : null,
hasMissingItems: dto.hasMissingItems ?? false,
missingItemsDescription: dto.missingItemsDescription ?? null,
remarks: dto.remarks ?? null,
inspectedById: dto.inspectedById ?? null,
inspectedAt: new Date(),
});
// Mirror the latest outcome onto the inventory item so loading rules can read it.
await inventoryRepo.update(inventoryId, {
inspectionStatus: dto.inspectionStatus,
inspectedAt: new Date(),
});
return report;
}
async findByInventory(inventoryId: string): Promise<WarehouseInspectionReport[]> {
return this.inspectionRepository.findAll({
where: { inventoryId },
order: { createdAt: 'DESC' },
});
}
async findById(id: string): Promise<WarehouseInspectionReport> {
const report = await this.inspectionRepository.findById(id);
if (!report) {
throw new NotFoundException(`Inspection report ${id} not found`);
}
return report;
}
async update(id: string, dto: UpdateInspectionReportDto): Promise<WarehouseInspectionReport> {
const report = await this.findById(id);
const expected = dto.expectedWeight ?? report.expectedWeight ?? null;
const actual = dto.actualWeight ?? report.actualWeight ?? null;
const weightLoss = expected !== null && actual !== null ? Math.max(0, expected - actual) : report.weightLoss ?? null;
await this.inspectionRepository.update(id, {
...(dto.reportType ? { reportType: dto.reportType } : {}),
...(dto.inspectionStatus ? { inspectionStatus: dto.inspectionStatus } : {}),
...(dto.hasDamage !== undefined ? { hasDamage: dto.hasDamage } : {}),
...(dto.damageDescription !== undefined ? { damageDescription: dto.damageDescription } : {}),
...(dto.hasWeightLoss !== undefined ? { hasWeightLoss: dto.hasWeightLoss } : {}),
expectedWeight: expected,
actualWeight: actual,
weightLoss,
...(dto.hasMissingItems !== undefined ? { hasMissingItems: dto.hasMissingItems } : {}),
...(dto.missingItemsDescription !== undefined ? { missingItemsDescription: dto.missingItemsDescription } : {}),
...(dto.remarks !== undefined ? { remarks: dto.remarks } : {}),
});
if (dto.inspectionStatus) {
await this.dataSource
.getRepository(WarehouseInventory)
.update(report.inventoryId, { inspectionStatus: dto.inspectionStatus });
}
return this.findById(id);
}
/** Attach uploaded images/documents to a report, reusing the shared Files (MinIO) module. */
async addAttachments(reportId: string, files: Express.Multer.File[]) {
await this.findById(reportId);
if (!files?.length) return [];
return this.filesService.uploadMany(reportId, INSPECTION_RESOURCE, files);
}
listAttachments(reportId: string) {
return this.filesService.findByResource(reportId, INSPECTION_RESOURCE);
}
}