1
0
Fork 0
mirror of https://github.com/s-frick/effigenix.git synced 2026-03-28 13:59:36 +01:00

feat(scanner): Mobile Scanner App mit echten Produktionsaufträgen

Scanner-App  Tauri v2 Android App mit
Login, Barcode-Scanner, Consume/Move/Book-Flows und Aufgabenliste.

TasksPage lädt echte RELEASED/IN_PROGRESS Produktionsaufträge via API,
Consume-Flow nutzt den konkreten Auftrag für korrekte Rezept-Skalierung
statt blind den ersten IN_PROGRESS-Auftrag zu nehmen.

Backend: FindStockByBatchId Use Case + REST-Endpoint für Stock-Lookup
per Chargennummer.
This commit is contained in:
Sebastian Frick 2026-03-20 13:58:54 +01:00
parent 72979c9537
commit bf09e3b747
93 changed files with 8977 additions and 60 deletions

View file

@ -0,0 +1,28 @@
package de.effigenix.application.inventory;
import de.effigenix.domain.inventory.Stock;
import de.effigenix.domain.inventory.StockError;
import de.effigenix.domain.inventory.StockRepository;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result;
import java.util.List;
public class FindStockByBatchId {
private final StockRepository stockRepository;
public FindStockByBatchId(StockRepository stockRepository) {
this.stockRepository = stockRepository;
}
public Result<StockError, List<Stock>> execute(String batchId) {
if (batchId == null || batchId.isBlank()) {
return Result.failure(new StockError.InvalidBatchReference("Batch ID must not be blank"));
}
return switch (stockRepository.findAllByBatchId(batchId)) {
case Result.Failure(var err) -> Result.failure(new StockError.RepositoryFailure(err.message()));
case Result.Success(var stocks) -> Result.success(stocks);
};
}
}

View file

@ -14,6 +14,7 @@ import de.effigenix.application.inventory.BookProductionOutput;
import de.effigenix.application.inventory.ConfirmReservation;
import de.effigenix.application.inventory.RecordStockMovement;
import de.effigenix.application.inventory.ActivateStorageLocation;
import de.effigenix.application.inventory.FindStockByBatchId;
import de.effigenix.application.inventory.AddStockBatch;
import de.effigenix.application.inventory.BlockStockBatch;
import de.effigenix.application.inventory.CheckStockExpiry;
@ -99,6 +100,11 @@ public class InventoryUseCaseConfiguration {
return new ListStocks(stockRepository);
}
@Bean
public FindStockByBatchId findStockByBatchId(StockRepository stockRepository) {
return new FindStockByBatchId(stockRepository);
}
@Bean
public AddStockBatch addStockBatch(StockRepository stockRepository, UnitOfWork unitOfWork) {
return new AddStockBatch(stockRepository, unitOfWork);

View file

@ -264,6 +264,24 @@ public class JdbcStockRepository implements StockRepository {
}
}
@Override
public Result<RepositoryError, List<Stock>> findAllByBatchId(String batchId) {
try {
var stocks = jdbc.sql("""
SELECT DISTINCT s.* FROM stocks s
JOIN stock_batches b ON b.stock_id = s.id
WHERE b.batch_id = :batchId
""")
.param("batchId", batchId)
.query(this::mapStockRow)
.list();
return Result.success(loadChildrenForAll(stocks));
} catch (Exception e) {
logger.trace("Database error in findAllByBatchId", e);
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
}
}
@Override
public Result<RepositoryError, Void> save(Stock stock) {
try {

View file

@ -1,5 +1,6 @@
package de.effigenix.infrastructure.inventory.web.controller;
import de.effigenix.application.inventory.FindStockByBatchId;
import de.effigenix.application.inventory.AddStockBatch;
import de.effigenix.application.inventory.BlockStockBatch;
import de.effigenix.application.inventory.ConfirmReservation;
@ -63,6 +64,7 @@ public class StockController {
private final GetStock getStock;
private final ListStocks listStocks;
private final ListStocksBelowMinimum listStocksBelowMinimum;
private final FindStockByBatchId findStockByBatchId;
private final AddStockBatch addStockBatch;
private final RemoveStockBatch removeStockBatch;
private final BlockStockBatch blockStockBatch;
@ -72,7 +74,7 @@ public class StockController {
private final ConfirmReservation confirmReservation;
public StockController(CreateStock createStock, UpdateStock updateStock, GetStock getStock, ListStocks listStocks,
ListStocksBelowMinimum listStocksBelowMinimum,
ListStocksBelowMinimum listStocksBelowMinimum, FindStockByBatchId findStockByBatchId,
AddStockBatch addStockBatch, RemoveStockBatch removeStockBatch,
BlockStockBatch blockStockBatch, UnblockStockBatch unblockStockBatch,
ReserveStock reserveStock, ReleaseReservation releaseReservation,
@ -82,6 +84,7 @@ public class StockController {
this.getStock = getStock;
this.listStocks = listStocks;
this.listStocksBelowMinimum = listStocksBelowMinimum;
this.findStockByBatchId = findStockByBatchId;
this.addStockBatch = addStockBatch;
this.removeStockBatch = removeStockBatch;
this.blockStockBatch = blockStockBatch;
@ -109,6 +112,20 @@ public class StockController {
};
}
@GetMapping("/by-batch/{batchId}")
@PreAuthorize("hasAuthority('STOCK_READ')")
public ResponseEntity<List<StockResponse>> findByBatchId(@PathVariable String batchId) {
return switch (findStockByBatchId.execute(batchId)) {
case Result.Failure(var err) -> throw new StockDomainErrorException(err);
case Result.Success(var stocks) -> {
var responses = stocks.stream()
.map(StockResponse::from)
.toList();
yield ResponseEntity.ok(responses);
}
};
}
// NOTE: Must be declared before /{id} to avoid Spring matching "below-minimum" as path variable
@GetMapping("/below-minimum")
@PreAuthorize("hasAuthority('STOCK_READ')")

View file

@ -79,7 +79,7 @@ public class SecurityConfig {
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(allowedOrigins);
configuration.setAllowedOriginPatterns(List.of("*"));
configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(List.of("Authorization", "Content-Type"));
configuration.setAllowCredentials(true);

View file

@ -54,7 +54,7 @@ logging:
# CORS Configuration
effigenix:
cors:
allowed-origins: ${CORS_ALLOWED_ORIGINS:http://localhost:3000}
allowed-origins: ${CORS_ALLOWED_ORIGINS:http://localhost:3000,http://localhost:1420,tauri://localhost}
inventory:
expiry-check-cron: "0 0 6 * * *"

View file

@ -153,5 +153,6 @@ class ListStocksBelowMinimumTest {
@Override public Result<RepositoryError, List<Stock>> findAllWithExpiryRelevantBatches(LocalDate referenceDate) { return Result.success(List.of()); }
@Override public Result<RepositoryError, List<Stock>> findAllByBatchId(String batchId) { return Result.success(List.of()); }
@Override public Result<RepositoryError, Void> save(Stock stock) { return Result.success(null); }
@Override public Result<RepositoryError, List<Stock>> findAllByBatchId(String batchId) { return Result.success(List.of()); }
}
}