Enhance vehicle transport functionality in FalukantService and update UI components

- Modified the createTransport method in FalukantService to support optional vehicleIds, allowing for more flexible vehicle selection.
- Implemented logic to ensure that either specific vehicleIds or a vehicleTypeId must be provided, improving error handling for vehicle availability.
- Updated the BranchView component to include new UI elements for sending vehicles, including buttons for sending single or multiple vehicles of the same type.
- Added a modal dialog for selecting target branches when sending vehicles, enhancing user experience and streamlining transport operations.
- Updated German localization files to include new translations related to vehicle actions and transport functionalities.
This commit is contained in:
Torsten Schulz (local)
2025-12-05 12:49:37 +01:00
parent 085b851925
commit 5ad27a87e5
3 changed files with 355 additions and 29 deletions

View File

@@ -728,7 +728,7 @@ class FalukantService extends BaseService {
};
}
async createTransport(hashedUserId, { branchId, vehicleTypeId, productId, quantity, targetBranchId }) {
async createTransport(hashedUserId, { branchId, vehicleTypeId, vehicleIds, productId, quantity, targetBranchId }) {
const user = await getFalukantUserOrFail(hashedUserId);
const sourceBranch = await Branch.findOne({
@@ -754,9 +754,89 @@ class FalukantService extends BaseService {
const targetRegionId = targetBranch.regionId;
const now = new Date();
const type = await VehicleType.findByPk(vehicleTypeId);
if (!type) {
throw new Error('Vehicle type not found');
let type;
let freeVehicles = [];
// Wenn spezifische vehicleIds übergeben wurden, diese verwenden
if (vehicleIds && Array.isArray(vehicleIds) && vehicleIds.length > 0) {
const vehicles = await Vehicle.findAll({
where: {
id: { [Op.in]: vehicleIds },
falukantUserId: user.id,
regionId: sourceRegionId,
availableFrom: { [Op.lte]: now },
},
include: [
{
model: Transport,
as: 'transports',
required: false,
attributes: ['id'],
},
{
model: VehicleType,
as: 'type',
required: true,
},
],
});
freeVehicles = vehicles.filter((v) => {
const t = v.transports || [];
return t.length === 0;
});
if (freeVehicles.length === 0) {
throw new PreconditionError('noVehiclesAvailable');
}
// Alle Fahrzeuge müssen denselben Typ haben
const vehicleTypeIds = [...new Set(freeVehicles.map(v => v.vehicleTypeId))];
if (vehicleTypeIds.length !== 1) {
throw new Error('All vehicles must be of the same type');
}
type = await VehicleType.findByPk(vehicleTypeIds[0]);
if (!type) {
throw new Error('Vehicle type not found');
}
} else {
// Standard-Verhalten: Alle freien Fahrzeuge dieses Typs verwenden
if (!vehicleTypeId) {
throw new Error('Either vehicleTypeId or vehicleIds must be provided');
}
type = await VehicleType.findByPk(vehicleTypeId);
if (!type) {
throw new Error('Vehicle type not found');
}
// Freie Fahrzeuge dieses Typs in der Quell-Region
const vehicles = await Vehicle.findAll({
where: {
falukantUserId: user.id,
regionId: sourceRegionId,
vehicleTypeId,
availableFrom: { [Op.lte]: now },
},
include: [
{
model: Transport,
as: 'transports',
required: false,
attributes: ['id'],
},
],
});
freeVehicles = vehicles.filter((v) => {
const t = v.transports || [];
return t.length === 0;
});
}
if (!freeVehicles.length) {
throw new PreconditionError('noVehiclesAvailable');
}
const route = await computeShortestRoute(type.transportMode, sourceRegionId, targetRegionId);
@@ -764,29 +844,6 @@ class FalukantService extends BaseService {
throw new PreconditionError('noRoute');
}
// Freie Fahrzeuge dieses Typs in der Quell-Region
const vehicles = await Vehicle.findAll({
where: {
falukantUserId: user.id,
regionId: sourceRegionId,
vehicleTypeId,
availableFrom: { [Op.lte]: now },
},
include: [
{
model: Transport,
as: 'transports',
required: false,
attributes: ['id'],
},
],
});
const freeVehicles = vehicles.filter((v) => {
const t = v.transports || [];
return t.length === 0;
});
if (!freeVehicles.length) {
throw new PreconditionError('noVehiclesAvailable');
}