src/orders/ingestion/allocation/allocation-rules.service.ts
Methods |
|
constructor(prisma: PrismaService)
|
||||||
|
Parameters :
|
| Async findAll | ||||||
findAll(organizationId: string)
|
||||||
|
Parameters :
Returns :
unknown
|
| Async getActiveRule | ||||||
getActiveRule(organizationId: string)
|
||||||
|
Get the active rule for the org, or return defaults
Parameters :
Returns :
unknown
|
| Async remove | ||||||
remove(id: string)
|
||||||
|
Parameters :
Returns :
unknown
|
| Async resetToDefault | ||||||
resetToDefault(organizationId: string)
|
||||||
|
Parameters :
Returns :
unknown
|
| Async upsert | |||||||||
upsert(organizationId: string, data: unknown)
|
|||||||||
|
Parameters :
Returns :
unknown
|
import { Injectable, NotFoundException, Logger } from '@nestjs/common';
import { PrismaService } from '../../../prisma/prisma.service';
const DEFAULT_RULE = {
name: 'Default Allocation Rule',
description: 'Zone permits, route balancing, capacity matching, load balancing, idle time preference',
isDefault: true,
isActive: true,
priority: 0,
zonePermitWeight: 50,
zonePermitPenalty: 30,
routeBalanceBonus: 30,
routeBalancePenalty: 20,
capacityOverPenalty: 500,
loadBalanceFactor: 0.5,
batchPenalty: 10,
availableBonus: 20,
idleTimeMaxBonus: 20,
maxOrdersPerTruck: 3,
onlyAvailableVehicles: true,
respectZonePermits: true,
enableRouteBalancing: true,
};
@Injectable()
export class AllocationRulesService {
private readonly logger = new Logger(AllocationRulesService.name);
constructor(private readonly prisma: PrismaService) {}
/** Get the active rule for the org, or return defaults */
async getActiveRule(organizationId: string) {
const rule = await this.prisma.allocationRule.findFirst({
where: { organizationId, isActive: true },
orderBy: { priority: 'desc' },
});
if (rule) return rule;
// Return virtual default (not persisted until user modifies)
return { id: null, organizationId, ...DEFAULT_RULE };
}
async findAll(organizationId: string) {
const rules = await this.prisma.allocationRule.findMany({
where: { organizationId },
orderBy: { priority: 'desc' },
});
if (rules.length === 0) {
return [{ id: null, organizationId, ...DEFAULT_RULE }];
}
return rules;
}
async upsert(organizationId: string, data: Partial<typeof DEFAULT_RULE> & { id?: string | null }) {
const { id, ...rest } = data;
if (id) {
// Update existing
const rule = await this.prisma.allocationRule.findUnique({ where: { id } });
if (!rule) throw new NotFoundException('Allocation rule not found');
return this.prisma.allocationRule.update({ where: { id }, data: rest });
}
// Create — if this is the first rule, make it active + default
const existing = await this.prisma.allocationRule.findFirst({
where: { organizationId },
});
return this.prisma.allocationRule.create({
data: {
organizationId,
isDefault: !existing,
isActive: true,
...rest,
name: rest.name || 'Custom Allocation Rule',
},
});
}
async remove(id: string) {
const rule = await this.prisma.allocationRule.findUnique({ where: { id } });
if (!rule) throw new NotFoundException('Allocation rule not found');
if (rule.isDefault) {
// Can't delete default — just deactivate
return this.prisma.allocationRule.update({ where: { id }, data: { isActive: false } });
}
await this.prisma.allocationRule.delete({ where: { id } });
return { deleted: true };
}
async resetToDefault(organizationId: string) {
// Delete all custom rules and create a fresh default
await this.prisma.allocationRule.deleteMany({ where: { organizationId } });
return this.prisma.allocationRule.create({
data: { organizationId, ...DEFAULT_RULE },
});
}
}