feat: close overseas wallet and pallet cost flow

This commit is contained in:
2026-09-05 22:26:25 +08:00
parent f62283fb7f
commit 5fbd2bbd04
69 changed files with 1598 additions and 53 deletions
@@ -50,6 +50,14 @@ public class PlatformPalletController {
return ApiResponse.success(service.page(0L, query));
}
@GetMapping("/summary")
@PreAuthorize("hasAuthority('platform:pallet:list')")
public ApiResponse<PalletRequests.Summary> summary(@AuthenticationPrincipal AuthenticatedUser user,
@RequestParam(required = false) @Min(0) Long tenantId, @Valid @ParameterObject PalletRequests.PageQuery query) {
requirePlatform(user); requirePlatformScope(tenantId);
return ApiResponse.success(service.summary(0L, query));
}
@GetMapping("/{id}")
@PreAuthorize("hasAuthority('platform:pallet:list')")
@Operation(summary = "查询托盘详情")
@@ -75,6 +75,8 @@ public final class PalletRequests {
) {
}
public record Summary(long totalCount, long idleCount, long occupiedCount) { }
@Schema(name = "InternalPalletSnapshot", description = "内部只读托盘主数据快照;不包含动态资源状态")
public record Snapshot(
@Schema(description = "托盘ID") long palletId,
@@ -9,6 +9,7 @@ import com.baiyue.warehouse.entity.PalletEntity;
import com.baiyue.warehouse.repository.PalletRepository;
import com.baiyue.warehouse.repository.WarehouseRepository;
import jakarta.annotation.Resource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -18,6 +19,7 @@ import java.util.List;
/** 托盘主数据应用服务。 */
@Service
public class PalletApplicationService {
@Resource private JdbcTemplate jdbc;
private static final int CODE_INSERT_ATTEMPTS = 5;
@Resource
@@ -31,6 +33,19 @@ public class PalletApplicationService {
source.page(), source.size(), source.total(), source.pages());
}
public PalletRequests.Summary summary(long tenantId, PalletRequests.PageQuery query) {
StringBuilder where = new StringBuilder("p.tenant_id=? AND p.deleted=0");
java.util.List<Object> args = new java.util.ArrayList<>(); args.add(tenantId);
if (query.warehouseId() != null) { where.append(" AND p.warehouse_id=?"); args.add(query.warehouseId()); }
if (org.springframework.util.StringUtils.hasText(query.palletCode())) { where.append(" AND p.pallet_code LIKE ?"); args.add("%" + query.palletCode().trim() + "%"); }
if (org.springframework.util.StringUtils.hasText(query.palletType())) { where.append(" AND p.pallet_type=?"); args.add(query.palletType().trim()); }
String active = "EXISTS (SELECT 1 FROM wh_location_reservation r WHERE r.tenant_id=p.tenant_id AND r.warehouse_id=p.warehouse_id AND r.pallet_id=p.id AND r.reservation_status='RESERVED') OR EXISTS (SELECT 1 FROM wh_location_occupancy o WHERE o.tenant_id=p.tenant_id AND o.warehouse_id=p.warehouse_id AND o.pallet_id=p.id AND o.occupancy_status='OCCUPIED')";
java.util.Map<String,Object> row = jdbc.queryForMap("SELECT COUNT(*) total_count,SUM(CASE WHEN " + active + " THEN 1 ELSE 0 END) occupied_count FROM wh_pallet p WHERE " + where, args.toArray());
long total = ((Number) row.get("total_count")).longValue();
long occupied = row.get("occupied_count") == null ? 0 : ((Number) row.get("occupied_count")).longValue();
return new PalletRequests.Summary(total, total - occupied, occupied);
}
public PalletRequests.View detail(long tenantId, long warehouseId, long id) {
return view(owned(tenantId, warehouseId, id));
}
@@ -11,6 +11,7 @@ import org.junit.jupiter.api.Test;
import jakarta.annotation.Resource;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import org.springframework.jdbc.core.JdbcTemplate;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
@@ -24,8 +25,18 @@ import java.util.List;
class PalletApplicationServiceTest {
@MockBean private PalletRepository repository;
@MockBean private WarehouseRepository warehouseRepository;
@MockBean private JdbcTemplate jdbcTemplate;
@Resource private PalletApplicationService service;
@Test
void summarizesIdleAndOccupiedPallets() {
PalletRequests.PageQuery query = new PalletRequests.PageQuery(1, 20, 20L, "PLT", "木托盘");
when(jdbcTemplate.queryForMap(org.mockito.ArgumentMatchers.anyString(), org.mockito.ArgumentMatchers.any(Object[].class)))
.thenReturn(java.util.Map.of("total_count", 7L, "occupied_count", 3L));
org.assertj.core.api.Assertions.assertThat(service.summary(0, query))
.extracting("totalCount", "idleCount", "occupiedCount").containsExactly(7L, 4L, 3L);
}
@Test
void shouldHandleCase01() {
PalletEntity entity = pallet();