fix overseas return inventory flow
This commit is contained in:
@@ -24,7 +24,7 @@ import java.util.stream.Collectors;
|
||||
public class SecurityEventOutboxService {
|
||||
private static final List<String> OVERSEAS_AUTHORITY_PREFIXES = List.of(
|
||||
"platform:overseas-warehouse:", "platform:overseas-business:",
|
||||
"platform:overseas-master-data:", "merchant:warehouse:",
|
||||
"platform:overseas-master-data:", "merchant:warehouse:", "merchant:overseas-warehouse:",
|
||||
"merchant:cross-border:", "platform:finance:", "lastleg:");
|
||||
@Resource private JdbcTemplate jdbc;
|
||||
@Resource private ObjectMapper objectMapper;
|
||||
|
||||
@@ -84,7 +84,7 @@ class SecurityEventOutboxServiceTest {
|
||||
.thenReturn(List.of("PLATFORM_ADMIN"));
|
||||
when(authorizationQueries.findPermissionsByIdentity(101L, 0L, "ADMIN"))
|
||||
.thenReturn(List.of("platform:overseas-warehouse:orders:view", "platform:iam:users:view",
|
||||
"lastleg:orders:view"));
|
||||
"merchant:overseas-warehouse:return-inventory:list", "lastleg:orders:view"));
|
||||
|
||||
service.permissionChanged(101L, 0L, "ADMIN", "ROLE_CHANGED");
|
||||
|
||||
@@ -96,7 +96,8 @@ class SecurityEventOutboxServiceTest {
|
||||
envelope.payload(), IamSecurityEventsV1.PermissionVersionChanged.class);
|
||||
assertThat(payload.roles()).containsExactly("PLATFORM_ADMIN");
|
||||
assertThat(payload.authorities()).containsExactlyInAnyOrder(
|
||||
"platform:overseas-warehouse:orders:view", "lastleg:orders:view");
|
||||
"platform:overseas-warehouse:orders:view",
|
||||
"merchant:overseas-warehouse:return-inventory:list", "lastleg:orders:view");
|
||||
assertThat(payload.authorities()).doesNotContain("platform:iam:users:view");
|
||||
}
|
||||
}
|
||||
|
||||
+7
@@ -6,6 +6,7 @@ import org.apache.ibatis.annotations.Insert;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -20,6 +21,12 @@ public interface ReturnInventoryBalanceMapper extends BaseMapper<ReturnInventory
|
||||
@Param("totalQuantity") long totalQuantity, @Param("availableQuantity") long availableQuantity,
|
||||
@Param("cartons") long cartons);
|
||||
|
||||
@Update("UPDATE ll_return_inventory_balance SET carton_quantity=carton_quantity+#{cartons},updated_at=NOW(3) " +
|
||||
"WHERE customer_id=#{customerId} AND overseas_warehouse_id=#{warehouseId} AND sku_code=#{skuCode} " +
|
||||
"AND carton_quantity+#{cartons}>=0")
|
||||
int adjustCartonQuantity(@Param("customerId") String customerId, @Param("warehouseId") String warehouseId,
|
||||
@Param("skuCode") String skuCode, @Param("cartons") long cartons);
|
||||
|
||||
@Select("<script>SELECT COUNT(*) FROM ll_return_inventory_balance WHERE customer_id=#{customerId} " +
|
||||
"<if test='warehouseId != null and warehouseId != \"\"'>AND overseas_warehouse_id=#{warehouseId} </if>" +
|
||||
"<if test='skuCode != null and skuCode != \"\"'>AND sku_code LIKE CONCAT('%',#{skuCode},'%') </if></script>")
|
||||
|
||||
+5
-3
@@ -65,7 +65,8 @@ public class ReturnInventoryService {
|
||||
long total = lines.stream().mapToLong(ReceiptLine::quantity).sum();
|
||||
ReturnInventoryCarton carton = new ReturnInventoryCarton();
|
||||
carton.setId(cartonId); carton.setCustomerId(order.getCustomerId()); carton.setOverseasWarehouseId(order.getOverseasWarehouseId());
|
||||
carton.setSourceReceiptId(receipt.getId()); carton.setSourceBatchNo(receipt.getReceiptBatchNo()); carton.setCartonMark(cartonMark);
|
||||
carton.setSourceReceiptId(receipt.getId()); carton.setSourceBatchNo(receipt.getReceiptBatchNo());
|
||||
carton.setSourceReturnNo(order.getReturnNo()); carton.setCartonMark(cartonMark);
|
||||
carton.setStatus(AVAILABLE); carton.setSkuTypes(lines.size()); carton.setTotalQuantity(total); carton.setCreatedAt(now); carton.setUpdatedAt(now);
|
||||
cartons.insert(carton);
|
||||
for (ReceiptLine line : lines) {
|
||||
@@ -264,8 +265,9 @@ public class ReturnInventoryService {
|
||||
// A SKU's carton count is the number of available physical cartons containing it:
|
||||
// remove fully emptied source cartons, then add the one merged target carton.
|
||||
long cartonDelta = 1L - emptiedBySku.getOrDefault(entry.getKey(), 0);
|
||||
balances.adjust(IdWorker.getId(), customerId, target.getOverseasWarehouseId(), entry.getKey(), productNames.get(entry.getKey()), 0,
|
||||
-entry.getValue(), cartonDelta);
|
||||
if (balances.adjustCartonQuantity(customerId, target.getOverseasWarehouseId(), entry.getKey(), cartonDelta) != 1) {
|
||||
throw new IllegalStateException("退货合箱库存箱数更新失败: " + entry.getKey());
|
||||
}
|
||||
}
|
||||
operation.setResultCartonId(targetId); operation.setUpdatedAt(now); operations.updateById(operation);
|
||||
return new ReturnInventoryResponses.MergeResult(target.getCartonMark(), requested.keySet().iterator().next(), total, label(target));
|
||||
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
package com.baiyue.lastleg.returnreceipt.service;
|
||||
|
||||
import com.baiyue.lastleg.pda.security.PdaWarehouseIdentity;
|
||||
import com.baiyue.lastleg.returnreceipt.dto.ReturnInventoryRequests;
|
||||
import com.baiyue.lastleg.returnreceipt.entity.ReturnInventoryCarton;
|
||||
import com.baiyue.lastleg.returnreceipt.entity.ReturnInventoryCartonItem;
|
||||
import com.baiyue.lastleg.returnreceipt.entity.ReturnOrder;
|
||||
import com.baiyue.lastleg.returnreceipt.entity.ReturnReceipt;
|
||||
import com.baiyue.lastleg.returnreceipt.mapper.ReturnInventoryBalanceMapper;
|
||||
import com.baiyue.lastleg.returnreceipt.mapper.ReturnInventoryCartonItemMapper;
|
||||
import com.baiyue.lastleg.returnreceipt.mapper.ReturnInventoryCartonMapper;
|
||||
import com.baiyue.lastleg.returnreceipt.mapper.ReturnInventoryMovementMapper;
|
||||
import com.baiyue.lastleg.returnreceipt.mapper.ReturnInventoryOperationMapper;
|
||||
import com.baiyue.lastleg.returnreceipt.mapper.ReturnInventoryQueryMapper;
|
||||
import com.baiyue.lastleg.returnreceipt.mapper.ReturnOrderMapper;
|
||||
import com.baiyue.lastleg.returnreceipt.mapper.ReturnReceiptMapper;
|
||||
import com.baiyue.lastleg.service.LastlegOrderNoGenerator;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class ReturnInventoryServiceTest {
|
||||
@Mock ReturnInventoryCartonMapper cartons;
|
||||
@Mock ReturnInventoryCartonItemMapper cartonItems;
|
||||
@Mock ReturnInventoryBalanceMapper balances;
|
||||
@Mock ReturnInventoryOperationMapper operations;
|
||||
@Mock ReturnInventoryQueryMapper queries;
|
||||
@Mock ReturnInventoryMovementMapper movements;
|
||||
@Mock LastlegOrderNoGenerator numbers;
|
||||
@Mock ReturnOrderMapper orders;
|
||||
@Mock ReturnReceiptMapper receipts;
|
||||
private ReturnInventoryService service;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
service = new ReturnInventoryService();
|
||||
ReflectionTestUtils.setField(service, "cartons", cartons);
|
||||
ReflectionTestUtils.setField(service, "cartonItems", cartonItems);
|
||||
ReflectionTestUtils.setField(service, "balances", balances);
|
||||
ReflectionTestUtils.setField(service, "operations", operations);
|
||||
ReflectionTestUtils.setField(service, "queries", queries);
|
||||
ReflectionTestUtils.setField(service, "movements", movements);
|
||||
ReflectionTestUtils.setField(service, "numbers", numbers);
|
||||
ReflectionTestUtils.setField(service, "orders", orders);
|
||||
ReflectionTestUtils.setField(service, "receiptMapper", receipts);
|
||||
}
|
||||
|
||||
@Test
|
||||
void receiptCartonKeepsTheSourceReturnNumber() {
|
||||
ReturnOrder order = completedOrder();
|
||||
ReturnReceipt receipt = new ReturnReceipt();
|
||||
receipt.setId(21L);
|
||||
receipt.setReceiptBatchNo("RB-1");
|
||||
when(numbers.next(anyString(), anyString(), anyLong())).thenReturn("RC-1");
|
||||
|
||||
service.createReceiptCarton(order, receipt, null,
|
||||
List.of(new ReturnInventoryService.ReceiptLine("SKU-A", "商品A", 2)));
|
||||
|
||||
ArgumentCaptor<ReturnInventoryCarton> captor = ArgumentCaptor.forClass(ReturnInventoryCarton.class);
|
||||
verify(cartons).insert(captor.capture());
|
||||
assertThat(captor.getValue().getSourceReturnNo()).isEqualTo("RT-1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void mergeMovesItemsBetweenCartonsWithoutReducingAvailableQuantity() {
|
||||
ReturnOrder order = completedOrder();
|
||||
ReturnReceipt receipt = new ReturnReceipt();
|
||||
receipt.setId(21L);
|
||||
ReturnInventoryCarton source = new ReturnInventoryCarton();
|
||||
source.setId(31L);
|
||||
source.setCustomerId("10001");
|
||||
source.setOverseasWarehouseId("42");
|
||||
source.setCartonMark("RC-SOURCE");
|
||||
source.setStatus(ReturnInventoryService.AVAILABLE);
|
||||
source.setSkuTypes(2);
|
||||
source.setTotalQuantity(4L);
|
||||
ReturnInventoryCartonItem skuA = item(41L, "SKU-A", 2L);
|
||||
ReturnInventoryCartonItem skuB = item(42L, "SKU-B", 2L);
|
||||
|
||||
when(orders.findByNos("42", List.of("RT-1"))).thenReturn(List.of(order));
|
||||
when(receipts.listOrder(11L)).thenReturn(List.of(receipt));
|
||||
when(cartons.findReceipt(21L)).thenReturn(source);
|
||||
when(cartons.lockMark("RC-SOURCE")).thenReturn(source);
|
||||
when(cartonItems.listCarton(31L)).thenReturn(List.of(skuA, skuB));
|
||||
when(numbers.next(anyString(), anyString(), anyLong())).thenReturn("RC-MERGED");
|
||||
when(balances.adjustCartonQuantity(anyString(), anyString(), anyString(), anyLong())).thenReturn(1);
|
||||
|
||||
service.merge(new PdaWarehouseIdentity("operator-1", "操作员", 42L),
|
||||
new ReturnInventoryRequests.Merge(List.of("RT-1"), List.of(
|
||||
new ReturnInventoryRequests.ValidItem("SKU-A", 1),
|
||||
new ReturnInventoryRequests.ValidItem("SKU-B", 1)),
|
||||
BigDecimal.ONE, BigDecimal.ONE, BigDecimal.ONE, BigDecimal.ONE, "merge-key"));
|
||||
|
||||
verify(balances).adjustCartonQuantity("10001", "42", "SKU-A", 1L);
|
||||
verify(balances).adjustCartonQuantity("10001", "42", "SKU-B", 1L);
|
||||
assertThat(source.getTotalQuantity()).isEqualTo(2L);
|
||||
assertThat(source.getStatus()).isEqualTo(ReturnInventoryService.AVAILABLE);
|
||||
}
|
||||
|
||||
private ReturnOrder completedOrder() {
|
||||
ReturnOrder order = new ReturnOrder();
|
||||
order.setId(11L);
|
||||
order.setCustomerId("10001");
|
||||
order.setReturnNo("RT-1");
|
||||
order.setOverseasWarehouseId("42");
|
||||
order.setStatus("COMPLETED");
|
||||
return order;
|
||||
}
|
||||
|
||||
private ReturnInventoryCartonItem item(long id, String sku, long quantity) {
|
||||
ReturnInventoryCartonItem item = new ReturnInventoryCartonItem();
|
||||
item.setId(id);
|
||||
item.setCartonId(31L);
|
||||
item.setCustomerId("10001");
|
||||
item.setSkuCode(sku);
|
||||
item.setProductNameZh(sku);
|
||||
item.setQuantity(quantity);
|
||||
return item;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user