mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 19:58:11 +00:00
Merge branch 'freight/feature/first_mile_invoice' of github.com:Tria-plc/edr-platform into freight/feature/first_mile_invoice
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
/**
|
||||
* Split the mixed vehicle status into two fields:
|
||||
* - status: operational state (ACTIVE, MAINTENANCE, RETIRED, OUT_OF_SERVICE)
|
||||
* - availability: assignment state (FREE, BUSY)
|
||||
*
|
||||
* Existing FREE/BUSY statuses are moved to availability and the status is
|
||||
* normalized back to ACTIVE.
|
||||
*/
|
||||
export class SeparateVehicleAvailability1890000000000 implements MigrationInterface {
|
||||
name = "SeparateVehicleAvailability1890000000000";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`
|
||||
ALTER TABLE freight.vehicles
|
||||
ADD COLUMN IF NOT EXISTS availability varchar DEFAULT 'FREE'
|
||||
`);
|
||||
await queryRunner.query(`
|
||||
UPDATE freight.vehicles SET availability = 'BUSY' WHERE status = 'BUSY'
|
||||
`);
|
||||
await queryRunner.query(`
|
||||
UPDATE freight.vehicles SET availability = 'FREE' WHERE availability IS NULL
|
||||
`);
|
||||
await queryRunner.query(`
|
||||
UPDATE freight.vehicles SET status = 'ACTIVE' WHERE status IN ('FREE', 'BUSY')
|
||||
`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
// Fold availability back into status before dropping the column
|
||||
await queryRunner.query(`
|
||||
UPDATE freight.vehicles SET status = availability
|
||||
WHERE status = 'ACTIVE' AND availability IN ('FREE', 'BUSY')
|
||||
`);
|
||||
await queryRunner.query(`
|
||||
ALTER TABLE freight.vehicles DROP COLUMN IF EXISTS availability
|
||||
`);
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import { BookingsRepository } from '../bookings/bookings.repository';
|
||||
import { DriversService } from '../drivers/drivers.service';
|
||||
import { SmsClientService } from '../notifications/sms-client.service';
|
||||
import { VehiclesService } from '../vehicles/vehicles.service';
|
||||
import { VehicleStatus } from '../vehicles/entities/vehicle.entity';
|
||||
import { VehicleAvailability } from '../vehicles/entities/vehicle.entity';
|
||||
import { CreateFirstMileDto } from './dto/create-first-mile.dto';
|
||||
import { UpdateFirstMileDto } from './dto/update-first-mile.dto';
|
||||
import { FirstMile, FirstMileStatus } from './entities/first-mile.entity';
|
||||
@@ -193,7 +193,7 @@ export class FirstMileService {
|
||||
});
|
||||
|
||||
if (dto.vehicleId) {
|
||||
await this.vehiclesService.setStatus(dto.vehicleId, VehicleStatus.BUSY);
|
||||
await this.vehiclesService.setAvailability(dto.vehicleId, VehicleAvailability.BUSY);
|
||||
}
|
||||
|
||||
return record;
|
||||
@@ -245,7 +245,7 @@ export class FirstMileService {
|
||||
// Keep vehicle statuses in sync: new vehicle goes BUSY, replaced one goes back to FREE
|
||||
if (dto.vehicleId !== undefined && dto.vehicleId !== existing.vehicleId) {
|
||||
if (dto.vehicleId) {
|
||||
await this.vehiclesService.setStatus(dto.vehicleId, VehicleStatus.BUSY);
|
||||
await this.vehiclesService.setAvailability(dto.vehicleId, VehicleAvailability.BUSY);
|
||||
}
|
||||
if (existing.vehicleId) {
|
||||
await this.vehiclesService.releaseIfUnused([existing.vehicleId]);
|
||||
@@ -373,7 +373,7 @@ export class FirstMileService {
|
||||
|
||||
const vehicleIds = new Set(allocations.map((a) => a.vehicleId));
|
||||
await Promise.all(
|
||||
[...vehicleIds].map((vehicleId) => this.vehiclesService.setStatus(vehicleId, VehicleStatus.BUSY)),
|
||||
[...vehicleIds].map((vehicleId) => this.vehiclesService.setAvailability(vehicleId, VehicleAvailability.BUSY)),
|
||||
);
|
||||
await this.vehiclesService.releaseIfUnused(
|
||||
previousVehicleIds.filter((id) => !vehicleIds.has(id)),
|
||||
|
||||
@@ -5,7 +5,7 @@ import { BookingsRepository } from '../bookings/bookings.repository';
|
||||
import { DriversService } from '../drivers/drivers.service';
|
||||
import { SmsClientService } from '../notifications/sms-client.service';
|
||||
import { VehiclesService } from '../vehicles/vehicles.service';
|
||||
import { VehicleStatus } from '../vehicles/entities/vehicle.entity';
|
||||
import { VehicleAvailability } from '../vehicles/entities/vehicle.entity';
|
||||
import { CreateLastMileDto } from './dto/create-last-mile.dto';
|
||||
import { UpdateLastMileDto } from './dto/update-last-mile.dto';
|
||||
import { LastMile, LastMileStatus } from './entities/last-mile.entity';
|
||||
@@ -144,7 +144,7 @@ export class LastMileService {
|
||||
});
|
||||
|
||||
if (dto.vehicleId) {
|
||||
await this.vehiclesService.setStatus(dto.vehicleId, VehicleStatus.BUSY);
|
||||
await this.vehiclesService.setAvailability(dto.vehicleId, VehicleAvailability.BUSY);
|
||||
}
|
||||
|
||||
return record;
|
||||
@@ -184,7 +184,7 @@ export class LastMileService {
|
||||
// Keep vehicle statuses in sync: new vehicle goes BUSY, replaced one goes back to FREE
|
||||
if (dto.vehicleId !== undefined && dto.vehicleId !== existing.vehicleId) {
|
||||
if (dto.vehicleId) {
|
||||
await this.vehiclesService.setStatus(dto.vehicleId, VehicleStatus.BUSY);
|
||||
await this.vehiclesService.setAvailability(dto.vehicleId, VehicleAvailability.BUSY);
|
||||
}
|
||||
if (existing.vehicleId) {
|
||||
await this.vehiclesService.releaseIfUnused([existing.vehicleId]);
|
||||
@@ -302,7 +302,7 @@ export class LastMileService {
|
||||
|
||||
const vehicleIds = new Set(allocations.map((a) => a.vehicleId));
|
||||
await Promise.all(
|
||||
[...vehicleIds].map((vehicleId) => this.vehiclesService.setStatus(vehicleId, VehicleStatus.BUSY)),
|
||||
[...vehicleIds].map((vehicleId) => this.vehiclesService.setAvailability(vehicleId, VehicleAvailability.BUSY)),
|
||||
);
|
||||
await this.vehiclesService.releaseIfUnused(
|
||||
previousVehicleIds.filter((id) => !vehicleIds.has(id)),
|
||||
|
||||
@@ -20,13 +20,16 @@ export enum FuelType {
|
||||
|
||||
export enum VehicleStatus {
|
||||
ACTIVE = 'ACTIVE',
|
||||
FREE = 'FREE',
|
||||
BUSY = 'BUSY',
|
||||
MAINTENANCE = 'MAINTENANCE',
|
||||
RETIRED = 'RETIRED',
|
||||
OUT_OF_SERVICE = 'OUT_OF_SERVICE',
|
||||
}
|
||||
|
||||
export enum VehicleAvailability {
|
||||
FREE = 'FREE',
|
||||
BUSY = 'BUSY',
|
||||
}
|
||||
|
||||
@Entity({ name: 'vehicles', schema: 'freight' })
|
||||
export class Vehicle extends BaseEntity {
|
||||
@Column({ name: 'plate_number', unique: true, nullable: true })
|
||||
@@ -56,6 +59,9 @@ export class Vehicle extends BaseEntity {
|
||||
@Column({ name: 'status', type: 'varchar', default: VehicleStatus.ACTIVE, nullable: true })
|
||||
status?: VehicleStatus;
|
||||
|
||||
@Column({ name: 'availability', type: 'varchar', default: VehicleAvailability.FREE, nullable: true })
|
||||
availability?: VehicleAvailability;
|
||||
|
||||
@Column({ type: 'text', nullable: true })
|
||||
description?: string | null;
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ export class VehiclesController {
|
||||
findAll(
|
||||
@Query('search') search?: string,
|
||||
@Query('status') status?: string,
|
||||
@Query('availability') availability?: string,
|
||||
@Query('page') page?: string,
|
||||
@Query('limit') limit?: string,
|
||||
@Query('sortBy') sortBy?: string,
|
||||
@@ -42,6 +43,7 @@ export class VehiclesController {
|
||||
return this.vehiclesService.findAll({
|
||||
search,
|
||||
status: status as any,
|
||||
availability: availability as any,
|
||||
page: page ? parseInt(page) : undefined,
|
||||
limit: limit ? parseInt(limit) : undefined,
|
||||
sortBy,
|
||||
|
||||
@@ -3,7 +3,7 @@ import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Not, Repository } from 'typeorm';
|
||||
import { CreateVehicleDto } from './dto/create-vehicle.dto';
|
||||
import { UpdateVehicleDto } from './dto/update-vehicle.dto';
|
||||
import { Vehicle, VehicleStatus } from './entities/vehicle.entity';
|
||||
import { Vehicle, VehicleAvailability, VehicleStatus } from './entities/vehicle.entity';
|
||||
import { FirstMile, FirstMileStatus } from '../first-mile/entities/first-mile.entity';
|
||||
import { FirstMileContainerAllocation } from '../first-mile/entities/first-mile-container-allocation.entity';
|
||||
import { LastMile, LastMileStatus } from '../last-mile/entities/last-mile.entity';
|
||||
@@ -39,6 +39,7 @@ export class VehiclesService {
|
||||
async findAll(query: {
|
||||
search?: string;
|
||||
status?: VehicleStatus | string;
|
||||
availability?: VehicleAvailability | string;
|
||||
page?: number;
|
||||
limit?: number;
|
||||
sortBy?: string;
|
||||
@@ -57,6 +58,10 @@ export class VehiclesService {
|
||||
qb = qb.andWhere('v.status = :status', { status: query.status });
|
||||
}
|
||||
|
||||
if (query.availability) {
|
||||
qb = qb.andWhere('v.availability = :availability', { availability: query.availability });
|
||||
}
|
||||
|
||||
const sortBy = ['plateNumber', 'status', 'year', 'createdAt'].includes(
|
||||
query.sortBy ?? '',
|
||||
)
|
||||
@@ -95,8 +100,8 @@ export class VehiclesService {
|
||||
return this.vehicleRepo.save(vehicle);
|
||||
}
|
||||
|
||||
async setStatus(id: string, status: VehicleStatus): Promise<void> {
|
||||
await this.vehicleRepo.update(id, { status });
|
||||
async setAvailability(id: string, availability: VehicleAvailability): Promise<void> {
|
||||
await this.vehicleRepo.update(id, { availability });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,7 +136,7 @@ export class VehiclesService {
|
||||
.getCount(),
|
||||
]);
|
||||
if (fmRecords + lmRecords + fmAllocations + lmAllocations === 0) {
|
||||
await this.setStatus(vehicleId, VehicleStatus.FREE);
|
||||
await this.setAvailability(vehicleId, VehicleAvailability.FREE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user