fix(order): align FBA submit and fee confirmation
This commit is contained in:
@@ -7,6 +7,7 @@ public record UnifiedInboundSummary(
|
||||
InboundOrderSummary inbound,
|
||||
String mainStatus,
|
||||
String nextAction,
|
||||
Boolean customerFeeConfirmationRequired,
|
||||
PreloadSummary preload,
|
||||
LoadingSummary loading,
|
||||
DeliverySummary delivery
|
||||
|
||||
@@ -22,7 +22,9 @@ import com.baiyue.firstleg.mapper.ContainerTierPricingMapper;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/** FBA 计费仓储;平台基础资料列表可跨企业读取,其他业务操作强制带租户条件。 */
|
||||
@Repository
|
||||
@@ -250,6 +252,24 @@ public class FbaPricingRepository {
|
||||
.orderByDesc(InboundFeeEntity::getFeeVersion).last("LIMIT 1"));
|
||||
}
|
||||
|
||||
public Map<Long, Boolean> customerFeeConfirmationRequiredMap(
|
||||
Long tenantId, Map<Long, Long> tenantByInbound) {
|
||||
if (tenantByInbound == null || tenantByInbound.isEmpty()) return Map.of();
|
||||
var query = new LambdaQueryWrapper<InboundFeeEntity>()
|
||||
.in(InboundFeeEntity::getInboundId, tenantByInbound.keySet());
|
||||
if (tenantId != null) query.eq(InboundFeeEntity::getTenantId, tenantId);
|
||||
query.orderByDesc(InboundFeeEntity::getFeeVersion)
|
||||
.orderByDesc(InboundFeeEntity::getId);
|
||||
Map<Long, Boolean> result = new LinkedHashMap<>();
|
||||
for (InboundFeeEntity fee : fees.selectList(query)) {
|
||||
Long expectedTenantId = tenantByInbound.get(fee.getInboundId());
|
||||
if (expectedTenantId == null || !expectedTenantId.equals(fee.getTenantId())) continue;
|
||||
result.putIfAbsent(fee.getInboundId(),
|
||||
"SENT".equals(fee.getFeeStatus()) && fee.getCustomerConfirmedAt() == null);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public InboundFeeEntity findLatestFeeForUpdate(long tenantId, long inboundId) {
|
||||
return fees.selectOne(new LambdaQueryWrapper<InboundFeeEntity>()
|
||||
.eq(InboundFeeEntity::getTenantId, tenantId)
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.baiyue.firstleg.dto.UnifiedInboundSummary;
|
||||
import com.baiyue.firstleg.entity.InboundOrderEntity;
|
||||
import com.baiyue.firstleg.dto.CurrentContainerTransport;
|
||||
import com.baiyue.firstleg.loading.entity.CabinetLoadingEvidenceEntity;
|
||||
import com.baiyue.firstleg.repository.FbaPricingRepository;
|
||||
import com.baiyue.firstleg.repository.InboundOrderRepository;
|
||||
import com.baiyue.firstleg.repository.UnifiedInboundReadRepository;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
@@ -32,6 +33,7 @@ public class UnifiedInboundQueryService {
|
||||
private static final Set<String> REVIEW_STATUSES = Set.of("UNRECORDED", "PENDING", "APPROVED", "REJECTED");
|
||||
|
||||
@Resource private InboundOrderRepository inbounds;
|
||||
@Resource private FbaPricingRepository pricing;
|
||||
@Resource private UnifiedInboundReadRepository operations;
|
||||
@Resource private ObjectMapper json;
|
||||
|
||||
@@ -79,8 +81,10 @@ public class UnifiedInboundQueryService {
|
||||
}
|
||||
CurrentContainerTransport transport = includePhaseThree
|
||||
? operations.findTransport(tenantId, inbound.getId()) : null;
|
||||
boolean customerFeeConfirmationRequired = pricing.customerFeeConfirmationRequiredMap(
|
||||
tenantId, Map.of(inbound.getId(), inbound.getTenantId())).getOrDefault(inbound.getId(), false);
|
||||
return new UnifiedInboundDetail(summary(inbound, detail, preload, pick, evidence, deliveryAt,
|
||||
transport, null, null), timeline);
|
||||
transport, null, null, customerFeeConfirmationRequired), timeline);
|
||||
}
|
||||
|
||||
private List<UnifiedInboundSummary> summaries(List<InboundOrderEntity> records) {
|
||||
@@ -99,10 +103,12 @@ public class UnifiedInboundQueryService {
|
||||
records.forEach(inbound -> applyConfirmedPalletCount(inbound, confirmedPalletCounts));
|
||||
var locationCodes = inbounds.locationCodesMap(null, owners);
|
||||
var pickups = inbounds.pickupMap(null, owners);
|
||||
var customerFeeConfirmations = pricing.customerFeeConfirmationRequiredMap(null, owners);
|
||||
return records.stream().map(inbound -> summary(inbound, null, preloads.get(inbound.getId()),
|
||||
picks.get(inbound.getId()), evidences.getOrDefault(inbound.getId(), List.of()),
|
||||
deliveries.get(inbound.getId()) == null ? null : deliveries.get(inbound.getId()).getOccurredAt(),
|
||||
transports.get(inbound.getId()), locationCodes.get(inbound.getId()), pickups.get(inbound.getId()))).toList();
|
||||
transports.get(inbound.getId()), locationCodes.get(inbound.getId()), pickups.get(inbound.getId()),
|
||||
customerFeeConfirmations.getOrDefault(inbound.getId(), false))).toList();
|
||||
}
|
||||
|
||||
private static void applyConfirmedPalletCount(InboundOrderEntity inbound,
|
||||
@@ -118,7 +124,8 @@ public class UnifiedInboundQueryService {
|
||||
com.baiyue.firstleg.loading.entity.InboundLoadingPickTaskEntity pick,
|
||||
List<CabinetLoadingEvidenceEntity> evidence, LocalDateTime deliveryAt,
|
||||
CurrentContainerTransport transport, String locationCodes,
|
||||
com.baiyue.firstleg.entity.InboundPickupSnapshotEntity pickup) {
|
||||
com.baiyue.firstleg.entity.InboundPickupSnapshotEntity pickup,
|
||||
boolean customerFeeConfirmationRequired) {
|
||||
String mainStatus = mainStatus(inbound.getProcessStatus());
|
||||
List<CabinetLoadingEvidenceEntity> activeEvidence = evidence.stream()
|
||||
.filter(item -> item.getStatus() == null || "ACTIVE".equals(item.getStatus())).toList();
|
||||
@@ -143,6 +150,7 @@ public class UnifiedInboundQueryService {
|
||||
locationCodes == null && baseSummary != null ? baseSummary.locationCodes() : locationCodes);
|
||||
return new UnifiedInboundSummary(inboundSummary, mainStatus,
|
||||
nextAction(mainStatus, inbound.getProcessStatus(), preload == null ? null : preload.getStatus()),
|
||||
customerFeeConfirmationRequired,
|
||||
preloadSummary, loadingSummary, deliverySummary);
|
||||
}
|
||||
|
||||
|
||||
@@ -1573,6 +1573,7 @@ components:
|
||||
inbound: {$ref: '#/components/schemas/UnifiedInboundOrderSummary'}
|
||||
mainStatus: {$ref: '#/components/schemas/UnifiedMainStatus'}
|
||||
nextAction: {type: string, nullable: true}
|
||||
customerFeeConfirmationRequired: {type: boolean, description: 最新费用已发送给客户且尚未由客户确认}
|
||||
preload: {$ref: '#/components/schemas/UnifiedPreloadSummary'}
|
||||
loading: {$ref: '#/components/schemas/UnifiedLoadingSummary'}
|
||||
delivery: {$ref: '#/components/schemas/UnifiedDeliverySummary'}
|
||||
|
||||
+27
@@ -10,6 +10,7 @@ import com.baiyue.firstleg.entity.CustomerChargeRuleEntity;
|
||||
import com.baiyue.firstleg.entity.CarrierFbaRateEntity;
|
||||
import com.baiyue.firstleg.entity.InboundPricingIdempotencyEntity;
|
||||
import com.baiyue.firstleg.entity.InboundPricingEntity;
|
||||
import com.baiyue.firstleg.entity.InboundFeeEntity;
|
||||
import com.baiyue.firstleg.mapper.CarrierFbaRateMapper;
|
||||
import com.baiyue.firstleg.mapper.CustomerChargeRuleMapper;
|
||||
import com.baiyue.firstleg.mapper.ContainerTierPricingMapper;
|
||||
@@ -30,6 +31,7 @@ import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
@@ -58,6 +60,8 @@ class FbaPricingRepositoryRuleListTest {
|
||||
CarrierFbaRateEntity.class);
|
||||
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new Configuration(), "test"),
|
||||
InboundPricingEntity.class);
|
||||
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new Configuration(), "test"),
|
||||
InboundFeeEntity.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -204,6 +208,29 @@ class FbaPricingRepositoryRuleListTest {
|
||||
.contains("List.of(\"FEE_CONFIRMING\", \"WAIT_PALLET\", \"WAIT_SPLIT\", \"LOADING\", \"LOADED\", \"DELIVERED\")");
|
||||
}
|
||||
|
||||
@Test
|
||||
void customerFeeConfirmationIsRequiredOnlyForLatestUnconfirmedSentFee() {
|
||||
InboundFeeEntity waiting = new InboundFeeEntity();
|
||||
waiting.setId(12L);
|
||||
waiting.setTenantId(10001L);
|
||||
waiting.setInboundId(88L);
|
||||
waiting.setFeeVersion(2);
|
||||
waiting.setFeeStatus("SENT");
|
||||
InboundFeeEntity confirmed = new InboundFeeEntity();
|
||||
confirmed.setId(22L);
|
||||
confirmed.setTenantId(10001L);
|
||||
confirmed.setInboundId(99L);
|
||||
confirmed.setFeeVersion(1);
|
||||
confirmed.setFeeStatus("SENT");
|
||||
confirmed.setCustomerConfirmedAt(java.time.LocalDateTime.now());
|
||||
when(fees.selectList(org.mockito.ArgumentMatchers.any())).thenReturn(List.of(waiting, confirmed));
|
||||
|
||||
assertThat(repository.customerFeeConfirmationRequiredMap(
|
||||
10001L, Map.of(88L, 10001L, 99L, 10001L)))
|
||||
.containsEntry(88L, true)
|
||||
.containsEntry(99L, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
void dropshipInitialPricingPreservesWaitingForPalletization() {
|
||||
when(pricing.update(org.mockito.ArgumentMatchers.isNull(), org.mockito.ArgumentMatchers.any()))
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.baiyue.firstleg.dto.InboundOrderDetail;
|
||||
import com.baiyue.firstleg.dto.UnifiedInboundDetail;
|
||||
import com.baiyue.firstleg.dto.UnifiedInboundQuery;
|
||||
import com.baiyue.firstleg.entity.InboundOrderEntity;
|
||||
import com.baiyue.firstleg.repository.FbaPricingRepository;
|
||||
import com.baiyue.firstleg.repository.InboundOrderRepository;
|
||||
import com.baiyue.firstleg.repository.UnifiedInboundReadRepository;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -91,9 +92,11 @@ class UnifiedInboundQueryServiceTest {
|
||||
void phaseTwoDetailDoesNotQueryPhaseThreeTables(String processStatus) {
|
||||
InboundOrderRepository inbounds = mock(InboundOrderRepository.class);
|
||||
UnifiedInboundReadRepository operations = mock(UnifiedInboundReadRepository.class);
|
||||
FbaPricingRepository pricing = mock(FbaPricingRepository.class);
|
||||
UnifiedInboundQueryService service = new UnifiedInboundQueryService();
|
||||
ReflectionTestUtils.setField(service, "inbounds", inbounds);
|
||||
ReflectionTestUtils.setField(service, "operations", operations);
|
||||
ReflectionTestUtils.setField(service, "pricing", pricing);
|
||||
|
||||
InboundOrderEntity inbound = new InboundOrderEntity();
|
||||
inbound.setId(88L);
|
||||
@@ -103,10 +106,13 @@ class UnifiedInboundQueryServiceTest {
|
||||
InboundOrderDetail detail = new InboundOrderDetail(null, null, null, null, null, List.of());
|
||||
when(inbounds.findByOrderId(10001L, 99L)).thenReturn(inbound);
|
||||
when(inbounds.detail(10001L, inbound)).thenReturn(detail);
|
||||
when(pricing.customerFeeConfirmationRequiredMap(10001L, Map.of(88L, 10001L)))
|
||||
.thenReturn(Map.of(88L, true));
|
||||
|
||||
UnifiedInboundDetail result = service.detail(10001L, 99L);
|
||||
|
||||
assertThat(result).isNotNull();
|
||||
assertThat(result.summary().customerFeeConfirmationRequired()).isTrue();
|
||||
verifyNoInteractions(operations);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user