From fadc301d41c9fa600fd8c99e4c59fcfcf022ba60 Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Mon, 8 Dec 2025 08:36:21 +0100 Subject: [PATCH] Add bulk vehicle repair functionality in Falukant module - Implemented a new repairAllVehicles method in FalukantService to handle the repair of multiple vehicles at once, including cost calculation and precondition checks. - Updated FalukantController to expose the repairAllVehicles endpoint, allowing users to initiate bulk repairs via the API. - Enhanced FalukantRouter to include a new route for bulk vehicle repairs. - Modified BranchView component to add UI elements for repairing all vehicles, including a dialog for confirmation and displaying repair details. - Updated German localization files to include translations related to bulk vehicle repair actions, improving user experience for German-speaking users. --- backend/controllers/falukantController.js | 4 + backend/routers/falukantRouter.js | 1 + backend/services/falukantService.js | 102 ++++++++++++++ frontend/src/i18n/locales/de/falukant.json | 11 ++ frontend/src/views/falukant/BranchView.vue | 155 +++++++++++++++++++-- 5 files changed, 263 insertions(+), 10 deletions(-) diff --git a/backend/controllers/falukantController.js b/backend/controllers/falukantController.js index 4e1261d..0572543 100644 --- a/backend/controllers/falukantController.js +++ b/backend/controllers/falukantController.js @@ -221,6 +221,10 @@ class FalukantController { (userId, req) => this.service.repairVehicle(userId, req.params.vehicleId), { successStatus: 200 } ); + this.repairAllVehicles = this._wrapWithUser( + (userId, req) => this.service.repairAllVehicles(userId, req.body.vehicleIds), + { successStatus: 200 } + ); } diff --git a/backend/routers/falukantRouter.js b/backend/routers/falukantRouter.js index f348d46..9f998b9 100644 --- a/backend/routers/falukantRouter.js +++ b/backend/routers/falukantRouter.js @@ -76,6 +76,7 @@ router.get('/vehicles/types', falukantController.getVehicleTypes); router.post('/vehicles', falukantController.buyVehicles); router.get('/vehicles', falukantController.getVehicles); router.post('/vehicles/:vehicleId/repair', falukantController.repairVehicle); +router.post('/vehicles/repair-all', falukantController.repairAllVehicles); router.post('/transports', falukantController.createTransport); router.get('/transports/route', falukantController.getTransportRoute); router.get('/transports/branch/:branchId', falukantController.getBranchTransports); diff --git a/backend/services/falukantService.js b/backend/services/falukantService.js index 8b7bc39..d20d45e 100644 --- a/backend/services/falukantService.js +++ b/backend/services/falukantService.js @@ -1212,6 +1212,108 @@ class FalukantService extends BaseService { }; } + async repairAllVehicles(hashedUserId, vehicleIds) { + const user = await getFalukantUserOrFail(hashedUserId); + const now = new Date(); + + if (!vehicleIds || !Array.isArray(vehicleIds) || vehicleIds.length === 0) { + throw new Error('Keine Fahrzeuge zum Reparieren angegeben'); + } + + // Alle Fahrzeuge laden + const vehicles = await Vehicle.findAll({ + where: { + id: { [Op.in]: vehicleIds }, + falukantUserId: user.id, + }, + include: [ + { + model: VehicleType, + as: 'type', + required: true, + }, + { + model: Transport, + as: 'transports', + required: false, + attributes: ['id'], + }, + ], + }); + + if (vehicles.length !== vehicleIds.length) { + throw new Error('Nicht alle angegebenen Fahrzeuge gefunden oder gehören nicht dem Benutzer'); + } + + // Prüfe alle Fahrzeuge + const repairableVehicles = []; + let totalCost = 0; + + for (const vehicle of vehicles) { + // Prüfen, ob Fahrzeug in Benutzung ist + const hasActiveTransport = Array.isArray(vehicle.transports) && vehicle.transports.length > 0; + const isBuilding = vehicle.availableFrom && new Date(vehicle.availableFrom).getTime() > now.getTime(); + + if (hasActiveTransport || isBuilding) { + continue; // Überspringe Fahrzeuge in Benutzung + } + + // Prüfen, ob Reparatur nötig ist (Zustand < 100) + if (vehicle.condition >= 100) { + continue; // Überspringe bereits perfekte Fahrzeuge + } + + // Kosten berechnen: Baupreis * 0.8 * (100 - zustand) / 100 + const baseCost = vehicle.type.cost; + const repairCost = Math.round(baseCost * 0.8 * (100 - vehicle.condition) / 100); + totalCost += repairCost; + repairableVehicles.push({ vehicle, repairCost }); + } + + if (repairableVehicles.length === 0) { + throw new PreconditionError('noVehiclesToRepair'); + } + + // 10% Rabatt für Reparatur aller Fahrzeuge + const discountedCost = Math.round(totalCost * 0.9); + + if (user.money < discountedCost) { + throw new PreconditionError('insufficientFunds'); + } + + // Alle Reparaturen in einer Transaktion durchführen + await sequelize.transaction(async (tx) => { + // Geld abziehen + const moneyResult = await updateFalukantUserMoney( + user.id, + -discountedCost, + 'repair_all_vehicles', + user.id + ); + if (!moneyResult.success) { + throw new Error('Failed to update money'); + } + + // Alle Fahrzeuge reparieren + for (const { vehicle, repairCost } of repairableVehicles) { + const buildTimeMinutes = vehicle.type.buildTimeMinutes || 0; + const buildMs = buildTimeMinutes * 60 * 1000; + const availableFrom = new Date(now.getTime() + buildMs); + + await vehicle.update({ + condition: 100, + availableFrom: availableFrom, + }, { transaction: tx }); + } + }); + + return { + success: true, + repairedCount: repairableVehicles.length, + totalCost: discountedCost, + }; + } + async createStock(hashedUserId, branchId, stockData) { const u = await getFalukantUserOrFail(hashedUserId); const b = await getBranchOrFail(u.id, branchId); diff --git a/frontend/src/i18n/locales/de/falukant.json b/frontend/src/i18n/locales/de/falukant.json index c93c37c..bfe7e11 100644 --- a/frontend/src/i18n/locales/de/falukant.json +++ b/frontend/src/i18n/locales/de/falukant.json @@ -28,6 +28,9 @@ "notify_election_created": "Es wurde eine neue Wahl ausgeschrieben.", "production": { "overproduction": "Überproduktion: Deine Produktion liegt {value}% über dem Bedarf." + }, + "transport": { + "waiting": "Transport wartet" } }, "health": { @@ -319,8 +322,16 @@ "cancel": "Abbrechen", "close": "Schließen", "repair": "Reparieren", + "repairWithCost": "Reparieren (Kosten: {cost})", "repairTooltip": "Fahrzeug reparieren", "repairVehicleTitle": "Fahrzeug reparieren", + "repairAll": "Alle reparieren ({count} Fahrzeuge, Kosten: {cost})", + "repairAllTitle": "Alle Fahrzeuge reparieren", + "repairAllDescription": "Möchtest du alle {count} Fahrzeuge reparieren? Gesamtkosten: {cost}", + "repairAllDiscount": "Hinweis: Bei Reparatur aller Fahrzeuge erhältst du 10% Rabatt.", + "repairAllConfirm": "Alle reparieren", + "repairAllSuccess": "Alle Fahrzeuge werden repariert!", + "repairAllError": "Fehler beim Reparieren der Fahrzeuge.", "repairVehicleType": "Fahrzeugtyp", "repairCurrentCondition": "Aktueller Zustand", "repairCost": "Reparaturkosten", diff --git a/frontend/src/views/falukant/BranchView.vue b/frontend/src/views/falukant/BranchView.vue index 68992e8..89a3c57 100644 --- a/frontend/src/views/falukant/BranchView.vue +++ b/frontend/src/views/falukant/BranchView.vue @@ -68,9 +68,18 @@

{{ $t('falukant.branch.transport.placeholder') }}

- +
+ + +
@@ -122,7 +131,7 @@ :title="$t('falukant.branch.transport.repairTooltip')" class="repair-button" > - {{ $t('falukant.branch.transport.repair') }} + {{ $t('falukant.branch.transport.repairWithCost', { cost: formatMoney(calculateRepairCost(v)) }) }} @@ -194,6 +203,32 @@ + + +