feat: gate overseas receiving and harden phase4 workflows
This commit is contained in:
+53
@@ -0,0 +1,53 @@
|
||||
package com.baiyue.lastleg.pda.warehouse.controller;
|
||||
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.common.security.AuthenticatedUser;
|
||||
import com.baiyue.lastleg.pda.security.PdaWarehouseIdentity;
|
||||
import com.baiyue.lastleg.pda.warehouse.dto.PdaWarehouseRequests;
|
||||
import com.baiyue.lastleg.pda.warehouse.dto.PdaWarehouseResponses;
|
||||
import com.baiyue.lastleg.pda.warehouse.service.PdaWarehouseService;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/pda/v1/last-leg")
|
||||
@PreAuthorize("hasAuthority('lastleg:pda:operate') and hasAuthority('ROLE_WAREHOUSE_PICKER')")
|
||||
public class PdaWarehouseController {
|
||||
@Resource private PdaWarehouseService service;
|
||||
|
||||
@PostMapping("/inventory/resolve")
|
||||
public ApiResponse<PdaWarehouseResponses.InventoryScan> inventory(@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@Valid @RequestBody PdaWarehouseRequests.Scan request) {
|
||||
PdaWarehouseIdentity identity = PdaWarehouseIdentity.require(user);
|
||||
return ApiResponse.success(service.inventory(identity.overseasWarehouseId(), request));
|
||||
}
|
||||
|
||||
@PostMapping("/locations/resolve")
|
||||
public ApiResponse<PdaWarehouseResponses.Location> location(@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@Valid @RequestBody PdaWarehouseRequests.Scan request) {
|
||||
PdaWarehouseIdentity identity = PdaWarehouseIdentity.require(user);
|
||||
return ApiResponse.success(service.location(identity.overseasWarehouseId(), request));
|
||||
}
|
||||
|
||||
@PostMapping("/pallets/resolve")
|
||||
public ApiResponse<PdaWarehouseResponses.Pallet> pallet(@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@Valid @RequestBody PdaWarehouseRequests.Scan request) {
|
||||
PdaWarehouseIdentity identity = PdaWarehouseIdentity.require(user);
|
||||
return ApiResponse.success(service.pallet(identity.overseasWarehouseId(), request));
|
||||
}
|
||||
|
||||
@GetMapping("/operations")
|
||||
public ApiResponse<PageResult<PdaWarehouseResponses.Operation>> operations(
|
||||
@AuthenticationPrincipal AuthenticatedUser user, @Valid PdaWarehouseRequests.HistoryQuery query) {
|
||||
PdaWarehouseIdentity identity = PdaWarehouseIdentity.require(user);
|
||||
return ApiResponse.success(service.history(identity.overseasWarehouseId(), identity.operatorKey(), query));
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -11,7 +11,7 @@ import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface PdaWarehouseMapper extends BaseMapper<PdaOperationHistory> {
|
||||
String INVENTORY_SELECT = "SELECT b.customer_id,b.customer_name,b.id balance_id,p.id position_id," +
|
||||
String INVENTORY_SELECT = "SELECT DISTINCT b.customer_id,b.customer_name,b.id balance_id,p.id position_id," +
|
||||
"COALESCE(NULLIF(r.sku_code,''),b.sku_code) sku_code," +
|
||||
"COALESCE(NULLIF(r.product_name_zh,''),b.product_name_zh) product_name_zh," +
|
||||
"COALESCE(NULLIF(r.product_name_en,''),b.product_name_en) product_name_en,b.inbound_code," +
|
||||
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
package com.baiyue.lastleg.pda.warehouse.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.lastleg.inboundplan.pda.gateway.WarehouseResourceGateway;
|
||||
import com.baiyue.lastleg.pda.warehouse.dto.PdaWarehouseRequests;
|
||||
import com.baiyue.lastleg.pda.warehouse.dto.PdaWarehouseResponses;
|
||||
import com.baiyue.lastleg.pda.warehouse.entity.PdaOperationHistory;
|
||||
import com.baiyue.lastleg.pda.warehouse.mapper.PdaWarehouseMapper;
|
||||
import com.baiyue.lastleg.pda.warehouse.model.PdaInventoryProjection;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class PdaWarehouseService {
|
||||
@Resource private PdaWarehouseMapper mapper;
|
||||
@Resource private WarehouseResourceGateway warehouse;
|
||||
|
||||
public PdaWarehouseResponses.InventoryScan inventory(long warehouseId, PdaWarehouseRequests.Scan request) {
|
||||
String code = code(request.code());
|
||||
List<PdaWarehouseResponses.InventoryItem> items = items(mapper.scanInventory(String.valueOf(warehouseId), code));
|
||||
if (items.isEmpty()) throw notFound("Inventory code was not found in the bound warehouse");
|
||||
return new PdaWarehouseResponses.InventoryScan(code, items);
|
||||
}
|
||||
|
||||
public PdaWarehouseResponses.Location location(long warehouseId, PdaWarehouseRequests.Scan request) {
|
||||
WarehouseResourceGateway.WarehouseLocationReference location = warehouse.resolveLocation(warehouseId,
|
||||
code(request.code()));
|
||||
List<PdaWarehouseResponses.InventoryItem> inventory = items(mapper.inventoryByLocation(
|
||||
String.valueOf(warehouseId), location.locationId(), location.locationCode(), "__NO_CARTON__"));
|
||||
long packages = inventory.stream().mapToLong(this::packages).sum();
|
||||
int positions = (int) inventory.stream().map(PdaWarehouseResponses.InventoryItem::positionId).distinct().count();
|
||||
return new PdaWarehouseResponses.Location(location.locationId(), location.locationCode(),
|
||||
location.locationType(), location.maxLoadKg(), location.status(), packages, positions);
|
||||
}
|
||||
|
||||
public PdaWarehouseResponses.Pallet pallet(long warehouseId, PdaWarehouseRequests.Scan request) {
|
||||
WarehouseResourceGateway.WarehousePalletReference pallet = warehouse.resolvePallet(code(request.code()));
|
||||
if (pallet.warehouseId() != warehouseId) throw conflict("Pallet belongs to another overseas warehouse");
|
||||
WarehouseResourceGateway.WarehouseLocationReference location = warehouse.resolveLocation(warehouseId,
|
||||
pallet.locationId());
|
||||
List<PdaWarehouseResponses.InventoryItem> inventory = items(mapper.inventoryByPallet(
|
||||
String.valueOf(warehouseId), pallet.palletId(), "__NO_CARTON__"));
|
||||
long packages = inventory.stream().mapToLong(this::packages).sum();
|
||||
int positions = (int) inventory.stream().map(PdaWarehouseResponses.InventoryItem::positionId).distinct().count();
|
||||
return new PdaWarehouseResponses.Pallet(pallet.palletId(), pallet.palletNo(), pallet.status(), pallet.version(),
|
||||
location.locationId(), location.locationCode(), packages, positions, inventory);
|
||||
}
|
||||
|
||||
public PageResult<PdaWarehouseResponses.Operation> history(long warehouseId, String operatorKey,
|
||||
PdaWarehouseRequests.HistoryQuery query) {
|
||||
long offset = (query.page() - 1) * query.size();
|
||||
List<PdaWarehouseResponses.Operation> rows = mapper.history(warehouseId, operatorKey,
|
||||
trim(query.operationType()), offset, query.size());
|
||||
long total = mapper.countHistory(warehouseId, operatorKey, trim(query.operationType()));
|
||||
return new PageResult<>(rows, query.page(), query.size(), total,
|
||||
total == 0 ? 0 : (total + query.size() - 1) / query.size());
|
||||
}
|
||||
|
||||
public void record(long warehouseId, String customerId, String operatorKey, String operationType,
|
||||
String businessKey, String status, String idempotencyKey, String requestHash, String summary) {
|
||||
PdaOperationHistory history = new PdaOperationHistory();
|
||||
history.setId(IdWorker.getId()); history.setOverseasWarehouseId(warehouseId);
|
||||
history.setCustomerId(trim(customerId)); history.setOperatorKey(operatorKey);
|
||||
history.setOperationType(operationType); history.setBusinessKey(businessKey); history.setStatus(status);
|
||||
history.setIdempotencyKey(trim(idempotencyKey)); history.setRequestHash(trim(requestHash));
|
||||
history.setSummary(trim(summary)); history.setOccurredAt(LocalDateTime.now()); history.setCreatedAt(history.getOccurredAt());
|
||||
mapper.insert(history);
|
||||
}
|
||||
|
||||
private List<PdaWarehouseResponses.InventoryItem> items(List<PdaInventoryProjection> values) {
|
||||
LinkedHashMap<String, PdaWarehouseResponses.InventoryItem> result = new LinkedHashMap<>();
|
||||
for (PdaInventoryProjection value : values) {
|
||||
String key = value.getPositionId() + ":" + text(value.getSkuCode()) + ":" + text(value.getCartonMark());
|
||||
result.putIfAbsent(key, new PdaWarehouseResponses.InventoryItem(value.getCustomerId(), value.getCustomerName(),
|
||||
number(value.getBalanceId()), number(value.getPositionId()), value.getSkuCode(),
|
||||
first(value.getProductNameZh(), value.getProductNameEn()), value.getInboundCode(), value.getCartonMark(),
|
||||
number(value.getPalletId()), value.getPalletCode(), value.getLocationId(), value.getLocationCode(),
|
||||
number(value.getAvailablePackages()), number(value.getHoldPackages()), number(value.getReceivingPackages()),
|
||||
value.getStatus(), number(value.getVersion())));
|
||||
}
|
||||
return List.copyOf(result.values());
|
||||
}
|
||||
|
||||
private long packages(PdaWarehouseResponses.InventoryItem value) {
|
||||
return value.availablePackages() + value.holdPackages() + value.receivingPackages();
|
||||
}
|
||||
private static String code(String value) { String result = trim(value); if (result == null) throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Scan code is required"); return result; }
|
||||
private static String trim(String value) { return value == null || value.isBlank() ? null : value.trim(); }
|
||||
private static String text(String value) { return value == null ? "" : value; }
|
||||
private static String first(String first, String second) { String value = trim(first); return value == null ? trim(second) : value; }
|
||||
private static long number(Long value) { return value == null ? 0 : value; }
|
||||
private static ResponseStatusException notFound(String message) { return new ResponseStatusException(HttpStatus.NOT_FOUND, message); }
|
||||
private static ResponseStatusException conflict(String message) { return new ResponseStatusException(HttpStatus.CONFLICT, message); }
|
||||
}
|
||||
Reference in New Issue
Block a user