diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/controller/InboundPlanController.java b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/controller/InboundPlanController.java index 20ebe6d42..8662f4e9e 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/controller/InboundPlanController.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/controller/InboundPlanController.java @@ -7,9 +7,10 @@ import com.baiyue.lastleg.inboundplan.dto.ConvertInboundPlanRequest; import com.baiyue.lastleg.inboundplan.dto.BatchFbaAppointmentRequest; import com.baiyue.lastleg.inboundplan.dto.FbaAppointmentResponse; import com.baiyue.lastleg.inboundplan.dto.InboundPlanResponse; +import com.baiyue.lastleg.inboundplan.dto.InboundPlanListResponse; import com.baiyue.lastleg.inboundplan.dto.InboundPlanRequests; -import com.baiyue.lastleg.inboundplan.dto.InboundPlanSummary; import com.baiyue.lastleg.inboundplan.dto.SupplementPalletRequest; +import com.baiyue.lastleg.inboundplan.dto.UpdateFbaAppointmentRequest; import com.baiyue.lastleg.inboundplan.service.InboundFbaAppointmentService; import com.baiyue.lastleg.inboundplan.service.InboundPlanService; import com.baiyue.lastleg.security.OverseasPermissions; @@ -25,24 +26,26 @@ import org.springframework.web.server.ResponseStatusException; @RestController @RequestMapping("/api/platform/v1/last-leg/inbound-plans") -@Tag(name = "Tail-leg inbound plans") +@Tag(name = "尾程入仓计划") public class InboundPlanController { @Resource private InboundPlanService service; @Resource private InboundFbaAppointmentService appointmentService; + /** 按入仓计划明细分页查询可预约的入库订单行。 */ @GetMapping @PreAuthorize("hasAuthority('" + OverseasPermissions.INBOUND_ORDER_LIST + "')") - @Operation(summary = "Page inbound plans without PDA, internal-event or outbound workflow fields", description = "Required authority: " + OverseasPermissions.INBOUND_ORDER_LIST) - public ApiResponse> page( + @Operation(summary = "分页查询入库订单", description = "Required authority: " + OverseasPermissions.INBOUND_ORDER_LIST) + public ApiResponse> page( @AuthenticationPrincipal AuthenticatedUser user, - @RequestParam(required = false) String customerId, + @RequestParam String customerId, @Valid InboundPlanRequests.Query query) { return ApiResponse.success(service.page(scope(user, customerId), query)); } @PostMapping("/convert") @PreAuthorize("hasAuthority('" + OverseasPermissions.INBOUND_ORDER_CREATE + "')") - @Operation(summary = "Convert one inbound order to one inbound plan", description = "Required authority: " + OverseasPermissions.INBOUND_ORDER_CREATE) + /** 将入仓单转换为入仓计划。 */ + @Operation(summary = "入仓单转入仓计划", description = "Required authority: " + OverseasPermissions.INBOUND_ORDER_CREATE) public ApiResponse convert(@AuthenticationPrincipal AuthenticatedUser user, @Valid @RequestBody ConvertInboundPlanRequest request) { return ApiResponse.success(service.convert(scope(user, request.customerId()), request.orderId())); @@ -50,7 +53,8 @@ public class InboundPlanController { @GetMapping("/{planNo}") @PreAuthorize("hasAuthority('" + OverseasPermissions.INBOUND_ORDER_LIST + "')") - @Operation(summary = "Get an inbound plan with lines, pallets and allocations", description = "Required authority: " + OverseasPermissions.INBOUND_ORDER_LIST) + /** 查询入仓计划及其明细、托盘和分配信息。 */ + @Operation(summary = "查询入仓计划详情", description = "Required authority: " + OverseasPermissions.INBOUND_ORDER_LIST) public ApiResponse detail(@AuthenticationPrincipal AuthenticatedUser user, @PathVariable String planNo, @RequestParam(required = false) String customerId) { @@ -59,7 +63,8 @@ public class InboundPlanController { @PostMapping("/{planNo}/pallets/supplement") @PreAuthorize("hasAuthority('" + OverseasPermissions.INBOUND_ORDER_EDIT + "')") - @Operation(summary = "Add one printable supplemental pallet for a plan destination warehouse", description = "Required authority: " + OverseasPermissions.INBOUND_ORDER_EDIT) + /** 为计划目标仓新增一个可打印的补充托盘。 */ + @Operation(summary = "新增补充托盘", description = "Required authority: " + OverseasPermissions.INBOUND_ORDER_EDIT) public ApiResponse supplementPallet(@AuthenticationPrincipal AuthenticatedUser user, @PathVariable String planNo, @Valid @RequestBody SupplementPalletRequest request) { @@ -68,7 +73,8 @@ public class InboundPlanController { @PostMapping("/fba-appointments/batch") @PreAuthorize("hasAuthority('" + OverseasPermissions.INBOUND_ORDER_EDIT + "')") - @Operation(summary = "Create one FBA appointment for selected inbound lines", description = "Required authority: " + OverseasPermissions.INBOUND_ORDER_EDIT) + /** 为选中的入仓明细创建 FBA 预约。 */ + @Operation(summary = "创建 FBA 预约", description = "Required authority: " + OverseasPermissions.INBOUND_ORDER_EDIT) public ApiResponse batchFbaAppointment( @AuthenticationPrincipal AuthenticatedUser user, @Valid @RequestBody BatchFbaAppointmentRequest request) { @@ -79,7 +85,8 @@ public class InboundPlanController { @GetMapping("/fba-appointments/{appointmentNo}") @PreAuthorize("hasAuthority('" + OverseasPermissions.INBOUND_ORDER_LIST + "')") - @Operation(summary = "Get an FBA appointment and its selected inbound lines", description = "Required authority: " + OverseasPermissions.INBOUND_ORDER_LIST) + /** 查询 FBA 预约及其选中的入仓明细。 */ + @Operation(summary = "查询 FBA 预约详情", description = "Required authority: " + OverseasPermissions.INBOUND_ORDER_LIST) public ApiResponse fbaAppointmentDetail( @AuthenticationPrincipal AuthenticatedUser user, @PathVariable String appointmentNo, @@ -87,6 +94,17 @@ public class InboundPlanController { return ApiResponse.success(appointmentService.detail(scope(user, customerId), appointmentNo)); } + @PutMapping("/fba-appointments/{appointmentNo}") + @PreAuthorize("hasAuthority('" + OverseasPermissions.INBOUND_ORDER_EDIT + "')") + @Operation(summary = "编辑 FBA 预约", description = "Required authority: " + OverseasPermissions.INBOUND_ORDER_EDIT) + public ApiResponse updateFbaAppointment( + @AuthenticationPrincipal AuthenticatedUser user, + @PathVariable String appointmentNo, + @Valid @RequestBody UpdateFbaAppointmentRequest request) { + return ApiResponse.success(appointmentService.update(scope(user, request.customerId()), + appointmentNo, request)); + } + private String scope(AuthenticatedUser user, String requestedCustomer) { if (user == null || user.tenantId() == null) { throw new ResponseStatusException(HttpStatus.UNAUTHORIZED); diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/dto/BatchFbaAppointmentRequest.java b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/dto/BatchFbaAppointmentRequest.java index 1572cb552..7547e0bc3 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/dto/BatchFbaAppointmentRequest.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/dto/BatchFbaAppointmentRequest.java @@ -13,6 +13,7 @@ public record BatchFbaAppointmentRequest( @NotEmpty @Size(max = 500) List<@NotNull Long> lineIds, @NotBlank @Size(max = 64) String appointmentNo, @NotNull LocalDateTime appointmentAt, + @NotNull LocalDateTime expectedLoadingAt, @NotBlank @Size(max = 32) String appointmentStatus, @Size(max = 1000) String appointmentRemark ) { diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/dto/FbaAppointmentResponse.java b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/dto/FbaAppointmentResponse.java index acf32635b..4c6c31d8d 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/dto/FbaAppointmentResponse.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/dto/FbaAppointmentResponse.java @@ -8,6 +8,7 @@ public record FbaAppointmentResponse( String customerId, String appointmentNo, LocalDateTime appointmentAt, + LocalDateTime expectedLoadingAt, String appointmentStatus, String appointmentRemark, String fbaWarehouseCode, diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/dto/InboundPlanListResponse.java b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/dto/InboundPlanListResponse.java new file mode 100644 index 000000000..5a4e1c6a5 --- /dev/null +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/dto/InboundPlanListResponse.java @@ -0,0 +1,30 @@ +package com.baiyue.lastleg.inboundplan.dto; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +public record InboundPlanListResponse( + Long lineId, + Long planId, + String planNo, + String customerId, + Long orderId, + String inboundCode, + String orderType, + String warehouseId, + String warehouseCode, + String warehouseName, + String fbaWarehouseCode, + String customerName, + Integer packageCount, + BigDecimal volumeCbm, + Integer palletCount, + String status, + String appointmentNo, + String appointmentStatus, + LocalDateTime appointmentAt, + LocalDateTime expectedLoadingAt, + String dispatchStatus, + LocalDateTime createdAt +) { +} diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/dto/InboundPlanRequests.java b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/dto/InboundPlanRequests.java index b7a4a5d11..ae1024497 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/dto/InboundPlanRequests.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/dto/InboundPlanRequests.java @@ -2,6 +2,7 @@ package com.baiyue.lastleg.inboundplan.dto; import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Pattern; import java.time.LocalDateTime; @@ -17,8 +18,12 @@ public final class InboundPlanRequests { String status, String overseasWarehouseId, String destinationWarehouseCode, + String warehouse, String fbaWarehouseCode, + @Pattern(regexp = "UNAPPOINTED|PENDING|SUCCESS|FAILED|CANCELLED") String appointmentStatus, + @Pattern(regexp = "UNSCHEDULED|SCHEDULED") + String dispatchStatus, LocalDateTime createdFrom, LocalDateTime createdTo ) { diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/dto/UpdateFbaAppointmentRequest.java b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/dto/UpdateFbaAppointmentRequest.java new file mode 100644 index 000000000..6f7076fe5 --- /dev/null +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/dto/UpdateFbaAppointmentRequest.java @@ -0,0 +1,16 @@ +package com.baiyue.lastleg.inboundplan.dto; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +import java.time.LocalDateTime; + +public record UpdateFbaAppointmentRequest( + String customerId, + @NotNull LocalDateTime appointmentAt, + @NotNull LocalDateTime expectedLoadingAt, + @NotBlank @Size(max = 32) String appointmentStatus, + @Size(max = 1000) String appointmentRemark +) { +} diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/entity/InboundFbaAppointment.java b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/entity/InboundFbaAppointment.java index 20f34801b..fc075215b 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/entity/InboundFbaAppointment.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/entity/InboundFbaAppointment.java @@ -15,6 +15,7 @@ public class InboundFbaAppointment { private String customerId; private String appointmentNo; private LocalDateTime appointmentAt; + private LocalDateTime expectedLoadingAt; private String appointmentStatus; private String appointmentRemark; private String fbaWarehouseCode; diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/mapper/InboundPlanQueryMapper.java b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/mapper/InboundPlanQueryMapper.java new file mode 100644 index 000000000..3b811de71 --- /dev/null +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/mapper/InboundPlanQueryMapper.java @@ -0,0 +1,55 @@ +package com.baiyue.lastleg.inboundplan.mapper; + +import com.baiyue.lastleg.inboundplan.dto.InboundPlanListResponse; +import com.baiyue.lastleg.inboundplan.dto.InboundPlanRequests; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +@Mapper +public interface InboundPlanQueryMapper { + String FROM_AND_FILTER = " FROM ll_inbound_plan_line l" + + " JOIN ll_inbound_plan p ON p.id=l.plan_id AND p.customer_id=#{customerId}" + + " JOIN ll_order o ON o.id=l.order_id AND o.customer_id=#{customerId}" + + " LEFT JOIN ll_inbound_fba_appointment_item ai ON ai.line_id=l.id" + + " AND ai.id=(SELECT ai2.id FROM ll_inbound_fba_appointment_item ai2" + + " JOIN ll_inbound_fba_appointment a2 ON a2.id=ai2.appointment_id" + + " WHERE ai2.line_id=l.id AND a2.customer_id=#{customerId}" + + " ORDER BY a2.created_at DESC,ai2.id DESC LIMIT 1)" + + " LEFT JOIN ll_inbound_fba_appointment a ON a.id=ai.appointment_id AND a.customer_id=#{customerId}" + + " WHERE 1=1" + + " AND p.plan_no LIKE CONCAT('%',#{q.planNo},'%')" + + " AND l.inbound_code LIKE CONCAT('%',#{q.inboundCode},'%')" + + " AND p.status=#{q.status}" + + " AND l.destination_warehouse_id=#{q.overseasWarehouseId}" + + " AND l.destination_warehouse_code=#{q.destinationWarehouseCode}" + + " AND (l.destination_warehouse_id LIKE CONCAT('%',#{q.warehouse},'%') OR l.destination_warehouse_code LIKE CONCAT('%',#{q.warehouse},'%') OR l.destination_warehouse_name LIKE CONCAT('%',#{q.warehouse},'%'))" + + " AND l.fba_warehouse_code LIKE CONCAT('%',#{q.fbaWarehouseCode},'%')" + + " AND ai.id IS NULL" + + " AND a.appointment_status=#{q.appointmentStatus}" + + " AND EXISTS (SELECT 1 FROM ll_dispatch_item di WHERE di.customer_id=#{customerId} AND di.order_id=l.order_id)" + + " AND NOT EXISTS (SELECT 1 FROM ll_dispatch_item di WHERE di.customer_id=#{customerId} AND di.order_id=l.order_id)" + + " AND p.created_at >=#{q.createdFrom}" + + " AND p.created_at <=#{q.createdTo}"; + + @Select("") + List rows(@Param("customerId") String customerId, + @Param("q") InboundPlanRequests.Query query, + @Param("offset") long offset, + @Param("limit") long limit); + + @Select("") + long count(@Param("customerId") String customerId, @Param("q") InboundPlanRequests.Query query); +} diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/service/InboundFbaAppointmentService.java b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/service/InboundFbaAppointmentService.java index 6045f4a46..b06b8a05a 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/service/InboundFbaAppointmentService.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/service/InboundFbaAppointmentService.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.IdWorker; import com.baiyue.lastleg.inboundplan.dto.BatchFbaAppointmentRequest; import com.baiyue.lastleg.inboundplan.dto.FbaAppointmentResponse; +import com.baiyue.lastleg.inboundplan.dto.UpdateFbaAppointmentRequest; import com.baiyue.lastleg.inboundplan.entity.InboundFbaAppointment; import com.baiyue.lastleg.inboundplan.entity.InboundFbaAppointmentItem; import com.baiyue.lastleg.inboundplan.mapper.InboundFbaAppointmentItemMapper; @@ -44,7 +45,7 @@ public class InboundFbaAppointmentService { InboundFbaAppointment existing = find(customerId, appointmentNo); if (existing != null) { - return verifyReplay(existing, lineIds, request.appointmentAt(), status, remark); + return verifyReplay(existing, lineIds, request.appointmentAt(), request.expectedLoadingAt(), status, remark); } List lines = queryMapper.lockLines(customerId, lineIds); @@ -57,7 +58,7 @@ public class InboundFbaAppointmentService { // The row locks serialize concurrent submissions selecting the same inbound lines. existing = find(customerId, appointmentNo); if (existing != null) { - return verifyReplay(existing, lineIds, request.appointmentAt(), status, remark); + return verifyReplay(existing, lineIds, request.appointmentAt(), request.expectedLoadingAt(), status, remark); } LocalDateTime now = LocalDateTime.now(); @@ -66,6 +67,7 @@ public class InboundFbaAppointmentService { appointment.setCustomerId(customerId); appointment.setAppointmentNo(appointmentNo); appointment.setAppointmentAt(request.appointmentAt()); + appointment.setExpectedLoadingAt(request.expectedLoadingAt()); appointment.setAppointmentStatus(status); appointment.setAppointmentRemark(remark); appointment.setFbaWarehouseCode(fbaWarehouseCode); @@ -78,7 +80,7 @@ public class InboundFbaAppointmentService { } catch (DuplicateKeyException exception) { InboundFbaAppointment concurrent = find(customerId, appointmentNo); if (concurrent != null) { - return verifyReplay(concurrent, lineIds, request.appointmentAt(), status, remark); + return verifyReplay(concurrent, lineIds, request.appointmentAt(), request.expectedLoadingAt(), status, remark); } throw exception; } @@ -108,12 +110,31 @@ public class InboundFbaAppointmentService { return response(appointment, items(appointment.getId())); } + @Transactional + public FbaAppointmentResponse update(String customerId, String appointmentNo, + UpdateFbaAppointmentRequest request) { + InboundFbaAppointment appointment = find(customerId, + requiredTrimmed(appointmentNo, "Appointment number is required")); + if (appointment == null) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "FBA appointment not found"); + } + appointment.setAppointmentAt(request.appointmentAt()); + appointment.setExpectedLoadingAt(request.expectedLoadingAt()); + appointment.setAppointmentStatus(normalizeStatus(request.appointmentStatus())); + appointment.setAppointmentRemark(trimToNull(request.appointmentRemark())); + appointment.setUpdatedAt(LocalDateTime.now()); + appointmentMapper.updateById(appointment); + return response(appointment, items(appointment.getId())); + } + private FbaAppointmentResponse verifyReplay(InboundFbaAppointment existing, List requestedLineIds, - LocalDateTime appointmentAt, String status, String remark) { + LocalDateTime appointmentAt, LocalDateTime expectedLoadingAt, + String status, String remark) { List existingItems = items(existing.getId()); Set existingLineIds = existingItems.stream() .map(InboundFbaAppointmentItem::getLineId).collect(java.util.stream.Collectors.toSet()); if (!Objects.equals(existing.getAppointmentAt(), appointmentAt) + || !Objects.equals(existing.getExpectedLoadingAt(), expectedLoadingAt) || !Objects.equals(existing.getAppointmentStatus(), status) || !Objects.equals(existing.getAppointmentRemark(), remark) || existingLineIds.size() != requestedLineIds.size() @@ -149,7 +170,8 @@ public class InboundFbaAppointmentService { private FbaAppointmentResponse response(InboundFbaAppointment appointment, List items) { return new FbaAppointmentResponse(appointment.getId(), appointment.getCustomerId(), - appointment.getAppointmentNo(), appointment.getAppointmentAt(), appointment.getAppointmentStatus(), + appointment.getAppointmentNo(), appointment.getAppointmentAt(), appointment.getExpectedLoadingAt(), + appointment.getAppointmentStatus(), appointment.getAppointmentRemark(), appointment.getFbaWarehouseCode(), appointment.getSelectedCount(), appointment.getCreatedBy(), appointment.getCreatedAt(), appointment.getUpdatedAt(), items.stream().map(item -> new FbaAppointmentResponse.Item(item.getId(), item.getPlanId(), diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/service/InboundPlanService.java b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/service/InboundPlanService.java index ac12ebc30..5b9753a88 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/service/InboundPlanService.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/service/InboundPlanService.java @@ -3,9 +3,9 @@ package com.baiyue.lastleg.inboundplan.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.IdWorker; import com.baiyue.common.core.api.PageResult; +import com.baiyue.lastleg.inboundplan.dto.InboundPlanListResponse; import com.baiyue.lastleg.inboundplan.dto.InboundPlanRequests; import com.baiyue.lastleg.inboundplan.dto.InboundPlanResponse; -import com.baiyue.lastleg.inboundplan.dto.InboundPlanSummary; import com.baiyue.lastleg.inboundplan.dto.SupplementPalletRequest; import com.baiyue.lastleg.inboundplan.entity.InboundPlan; import com.baiyue.lastleg.inboundplan.entity.InboundPlanLine; @@ -16,6 +16,7 @@ import com.baiyue.lastleg.inboundplan.mapper.InboundPlanMapper; import com.baiyue.lastleg.inboundplan.mapper.InboundPlanOrderMapper; import com.baiyue.lastleg.inboundplan.mapper.InboundPlanPalletAllocationMapper; import com.baiyue.lastleg.inboundplan.mapper.InboundPlanPalletMapper; +import com.baiyue.lastleg.inboundplan.mapper.InboundPlanQueryMapper; import com.baiyue.lastleg.inboundplan.model.SourceOrderSnapshot; import jakarta.annotation.Resource; import org.springframework.http.HttpStatus; @@ -38,16 +39,18 @@ public class InboundPlanService { @Resource private InboundPlanPalletMapper palletMapper; @Resource private InboundPlanPalletAllocationMapper allocationMapper; @Resource private InboundPlanOrderMapper orderMapper; + @Resource private InboundPlanQueryMapper queryMapper; @Transactional(readOnly = true) - public PageResult page(String customerId, InboundPlanRequests.Query query) { + public PageResult page(String customerId, InboundPlanRequests.Query query) { if (query.createdFrom() != null && query.createdTo() != null && query.createdFrom().isAfter(query.createdTo())) { - throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "createdFrom must not be after createdTo"); + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, + "createdFrom must not be after createdTo"); } - long total = planMapper.countRows(customerId, query); - List records = total == 0 ? List.of() - : planMapper.pageRows(customerId, query, Math.multiplyExact(query.page() - 1, query.size()), query.size()); + long total = queryMapper.count(customerId, query); + List records = total == 0 ? List.of() : queryMapper.rows( + customerId, query, (query.page() - 1) * query.size(), query.size()); long pages = total == 0 ? 0 : (total + query.size() - 1) / query.size(); return new PageResult<>(records, query.page(), query.size(), total, pages); } diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/inventory/query/dto/InventoryLedgerView.java b/lastleg-service/src/main/java/com/baiyue/lastleg/inventory/query/dto/InventoryLedgerView.java index 00b602cbc..7f60e2f0b 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/inventory/query/dto/InventoryLedgerView.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/inventory/query/dto/InventoryLedgerView.java @@ -13,6 +13,7 @@ public record InventoryLedgerView( String palletNo, String batchNo, String warehouseLocationCode, + String skuCode, String businessType, String businessOrderNo, String outboundOrderNo, diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/inventory/query/dto/InventoryQueryRequests.java b/lastleg-service/src/main/java/com/baiyue/lastleg/inventory/query/dto/InventoryQueryRequests.java index 9ad5e9847..1ab5b2fed 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/inventory/query/dto/InventoryQueryRequests.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/inventory/query/dto/InventoryQueryRequests.java @@ -21,6 +21,8 @@ public final class InventoryQueryRequests { String businessOrderNo, String skuCode, String productName, + String batchNo, + String warehouseLocationCode, String inventoryStatus ) { public BalanceQuery { @@ -44,6 +46,8 @@ public final class InventoryQueryRequests { String outboundOrderNo, String palletNo, String batchNo, + String skuCode, + String warehouseLocationCode, LocalDateTime occurredFrom, LocalDateTime occurredTo ) { diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/inventory/query/mapper/InventoryQueryMapper.java b/lastleg-service/src/main/java/com/baiyue/lastleg/inventory/query/mapper/InventoryQueryMapper.java index 6625112d8..f40923089 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/inventory/query/mapper/InventoryQueryMapper.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/inventory/query/mapper/InventoryQueryMapper.java @@ -21,6 +21,8 @@ public interface InventoryQueryMapper { " AND EXISTS (SELECT 1 FROM ll_inventory_ledger l WHERE l.balance_id=ll_inventory_balance.id AND l.customer_id=#{customerId} AND l.business_order_no LIKE CONCAT('%',#{q.businessOrderNo},'%'))" + " AND sku_code LIKE CONCAT('%',#{q.skuCode},'%')" + " AND (product_name_zh LIKE CONCAT('%',#{q.productName},'%') OR product_name_en LIKE CONCAT('%',#{q.productName},'%'))" + + " AND EXISTS (SELECT 1 FROM ll_inventory_position p WHERE p.balance_id=ll_inventory_balance.id AND p.customer_id=#{customerId} AND p.batch_no LIKE CONCAT('%',#{q.batchNo},'%'))" + + " AND EXISTS (SELECT 1 FROM ll_inventory_position p WHERE p.balance_id=ll_inventory_balance.id AND p.customer_id=#{customerId} AND p.warehouse_location_code LIKE CONCAT('%',#{q.warehouseLocationCode},'%'))" + "" + " AND available_packages > 0" + " AND hold_packages > 0" + @@ -41,6 +43,8 @@ public interface InventoryQueryMapper { " AND EXISTS (SELECT 1 FROM ll_inventory_ledger l WHERE l.balance_id=b.id AND l.customer_id=#{customerId} AND l.business_order_no LIKE CONCAT('%',#{q.businessOrderNo},'%'))" + " AND b.sku_code LIKE CONCAT('%',#{q.skuCode},'%')" + " AND (b.product_name_zh LIKE CONCAT('%',#{q.productName},'%') OR b.product_name_en LIKE CONCAT('%',#{q.productName},'%'))" + + " AND EXISTS (SELECT 1 FROM ll_inventory_position p2 WHERE p2.balance_id=b.id AND p2.customer_id=#{customerId} AND p2.batch_no LIKE CONCAT('%',#{q.batchNo},'%'))" + + " AND EXISTS (SELECT 1 FROM ll_inventory_position p2 WHERE p2.balance_id=b.id AND p2.customer_id=#{customerId} AND p2.warehouse_location_code LIKE CONCAT('%',#{q.warehouseLocationCode},'%'))" + "" + " AND b.available_packages > 0" + " AND b.hold_packages > 0" + @@ -83,6 +87,8 @@ public interface InventoryQueryMapper { @Select("