208 lines
5.1 KiB
TypeScript
208 lines
5.1 KiB
TypeScript
/**
|
|
* Fleet Service
|
|
* Mecánicas Diesel - ERP Suite
|
|
*
|
|
* Business logic for fleet management.
|
|
*/
|
|
|
|
import { Repository, DataSource } from 'typeorm';
|
|
import { Fleet } from '../entities/fleet.entity';
|
|
import { Vehicle, VehicleStatus } from '../entities/vehicle.entity';
|
|
|
|
// DTOs
|
|
export interface CreateFleetDto {
|
|
name: string;
|
|
code?: string;
|
|
contactName?: string;
|
|
contactPhone?: string;
|
|
contactEmail?: string;
|
|
discountLaborPct?: number;
|
|
discountPartsPct?: number;
|
|
creditDays?: number;
|
|
creditLimit?: number;
|
|
notes?: string;
|
|
}
|
|
|
|
export interface UpdateFleetDto {
|
|
name?: string;
|
|
code?: string;
|
|
contactName?: string;
|
|
contactPhone?: string;
|
|
contactEmail?: string;
|
|
discountLaborPct?: number;
|
|
discountPartsPct?: number;
|
|
creditDays?: number;
|
|
creditLimit?: number;
|
|
notes?: string;
|
|
isActive?: boolean;
|
|
}
|
|
|
|
export class FleetService {
|
|
private fleetRepository: Repository<Fleet>;
|
|
private vehicleRepository: Repository<Vehicle>;
|
|
|
|
constructor(dataSource: DataSource) {
|
|
this.fleetRepository = dataSource.getRepository(Fleet);
|
|
this.vehicleRepository = dataSource.getRepository(Vehicle);
|
|
}
|
|
|
|
/**
|
|
* Create a new fleet
|
|
*/
|
|
async create(tenantId: string, dto: CreateFleetDto): Promise<Fleet> {
|
|
const fleet = this.fleetRepository.create({
|
|
tenantId,
|
|
name: dto.name,
|
|
code: dto.code,
|
|
contactName: dto.contactName,
|
|
contactPhone: dto.contactPhone,
|
|
contactEmail: dto.contactEmail,
|
|
discountLaborPct: dto.discountLaborPct || 0,
|
|
discountPartsPct: dto.discountPartsPct || 0,
|
|
creditDays: dto.creditDays || 0,
|
|
creditLimit: dto.creditLimit || 0,
|
|
notes: dto.notes,
|
|
isActive: true,
|
|
vehicleCount: 0,
|
|
});
|
|
|
|
return this.fleetRepository.save(fleet);
|
|
}
|
|
|
|
/**
|
|
* Find fleet by ID
|
|
*/
|
|
async findById(tenantId: string, id: string): Promise<Fleet | null> {
|
|
return this.fleetRepository.findOne({
|
|
where: { id, tenantId },
|
|
});
|
|
}
|
|
|
|
/**
|
|
* List fleets
|
|
*/
|
|
async findAll(
|
|
tenantId: string,
|
|
pagination = { page: 1, limit: 20 }
|
|
) {
|
|
const queryBuilder = this.fleetRepository.createQueryBuilder('fleet')
|
|
.where('fleet.tenant_id = :tenantId', { tenantId });
|
|
|
|
const skip = (pagination.page - 1) * pagination.limit;
|
|
|
|
const [data, total] = await queryBuilder
|
|
.orderBy('fleet.name', 'ASC')
|
|
.skip(skip)
|
|
.take(pagination.limit)
|
|
.getManyAndCount();
|
|
|
|
return {
|
|
data,
|
|
total,
|
|
page: pagination.page,
|
|
limit: pagination.limit,
|
|
totalPages: Math.ceil(total / pagination.limit),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Update fleet
|
|
*/
|
|
async update(tenantId: string, id: string, dto: UpdateFleetDto): Promise<Fleet | null> {
|
|
const fleet = await this.findById(tenantId, id);
|
|
if (!fleet) return null;
|
|
|
|
Object.assign(fleet, dto);
|
|
return this.fleetRepository.save(fleet);
|
|
}
|
|
|
|
/**
|
|
* Deactivate fleet
|
|
*/
|
|
async deactivate(tenantId: string, id: string): Promise<boolean> {
|
|
const fleet = await this.findById(tenantId, id);
|
|
if (!fleet) return false;
|
|
|
|
fleet.isActive = false;
|
|
await this.fleetRepository.save(fleet);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get fleet with vehicle count
|
|
*/
|
|
async getFleetWithStats(tenantId: string, id: string): Promise<{
|
|
fleet: Fleet;
|
|
vehicleCount: number;
|
|
activeVehicles: number;
|
|
} | null> {
|
|
const fleet = await this.findById(tenantId, id);
|
|
if (!fleet) return null;
|
|
|
|
const [vehicleCount, activeVehicles] = await Promise.all([
|
|
this.vehicleRepository.count({ where: { tenantId, fleetId: id } }),
|
|
this.vehicleRepository.count({ where: { tenantId, fleetId: id, status: VehicleStatus.ACTIVE } }),
|
|
]);
|
|
|
|
return {
|
|
fleet,
|
|
vehicleCount,
|
|
activeVehicles,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get active fleets
|
|
*/
|
|
async findActive(tenantId: string): Promise<Fleet[]> {
|
|
return this.fleetRepository.find({
|
|
where: { tenantId, isActive: true },
|
|
order: { name: 'ASC' },
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Add vehicle to fleet
|
|
*/
|
|
async addVehicle(tenantId: string, fleetId: string, vehicleId: string): Promise<boolean> {
|
|
const fleet = await this.findById(tenantId, fleetId);
|
|
if (!fleet) return false;
|
|
|
|
const vehicle = await this.vehicleRepository.findOne({
|
|
where: { id: vehicleId, tenantId },
|
|
});
|
|
if (!vehicle) return false;
|
|
|
|
vehicle.fleetId = fleetId;
|
|
await this.vehicleRepository.save(vehicle);
|
|
|
|
// Update vehicle count
|
|
fleet.vehicleCount = await this.vehicleRepository.count({ where: { tenantId, fleetId } });
|
|
await this.fleetRepository.save(fleet);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Remove vehicle from fleet
|
|
*/
|
|
async removeVehicle(tenantId: string, fleetId: string, vehicleId: string): Promise<boolean> {
|
|
const vehicle = await this.vehicleRepository.findOne({
|
|
where: { id: vehicleId, tenantId, fleetId },
|
|
});
|
|
if (!vehicle) return false;
|
|
|
|
const fleet = await this.findById(tenantId, fleetId);
|
|
if (!fleet) return false;
|
|
|
|
vehicle.fleetId = undefined;
|
|
await this.vehicleRepository.save(vehicle);
|
|
|
|
// Update vehicle count
|
|
fleet.vehicleCount = await this.vehicleRepository.count({ where: { tenantId, fleetId } });
|
|
await this.fleetRepository.save(fleet);
|
|
|
|
return true;
|
|
}
|
|
}
|