费用提交
This commit is contained in:
-12
@@ -5,7 +5,6 @@ import com.baiyue.lastleg.procurement.dto.ProcurementWorkflowDtos.*;
|
||||
import com.baiyue.lastleg.procurement.entity.OverseasProcurementOrder;
|
||||
import com.baiyue.lastleg.procurement.repository.ProcurementWorkflowRepository;
|
||||
import com.baiyue.lastleg.service.LastlegDocumentNumberGenerator;
|
||||
import com.baiyue.lastleg.financefee.service.OverseasFeeSourceService;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -23,7 +22,6 @@ public class ProcurementWorkflowService {
|
||||
private final ProcurementWorkflowRepository repository;
|
||||
private final LastlegDocumentNumberGenerator numbers;
|
||||
private final ObjectMapper json;
|
||||
private final OverseasFeeSourceService fees;
|
||||
|
||||
/** 客户和平台共享实际批次事实,按客户及单号读取。 */
|
||||
@Transactional(readOnly=true)
|
||||
@@ -73,7 +71,6 @@ public class ProcurementWorkflowService {
|
||||
var order=order(customer,no,true);
|
||||
if(replay(order,request.idempotencyKey(),"OUTBOUND",request)) return snapshot(order);
|
||||
version(order,request.version());state(order,"CONFIRMED","IN_TRANSIT","DELIVERING");
|
||||
requireReviewedFees(order);
|
||||
if(request.quantity()<=0 || request.quantity()>snapshot(order).availableQuantity()) throw conflict("出库数量超过采购可用库存");
|
||||
if(request.trackingNo()==null || request.trackingNo().isBlank() || request.trackingNo().length()>255) throw bad("请填写物流跟踪号");
|
||||
repository.outbound(IdWorker.getId(),order.getId(),numbers.next("CK"),request.quantity(),request.trackingNo().trim(),operator);
|
||||
@@ -82,15 +79,6 @@ public class ProcurementWorkflowService {
|
||||
return snapshot(order);
|
||||
}
|
||||
|
||||
/** 本单有效应收须先添加并全部审核通过,作废费用不能替代费用明细。 */
|
||||
private void requireReviewedFees(OverseasProcurementOrder order) {
|
||||
var current=fees.listForBusiness(order.getCustomerId(),"OVERSEAS_PROCUREMENT",order.getId()).stream()
|
||||
.filter(f->"RECEIVABLE".equals(f.getDirection()) && !"VOIDED".equals(f.getSourceStatus())).toList();
|
||||
if(current.isEmpty()) throw conflict("请先添加费用明细并审核通过后再出库");
|
||||
if(current.stream().anyMatch(f->!"ACTIVE".equals(f.getSourceStatus()) || !"APPROVED".equals(f.getReviewStatus())))
|
||||
throw conflict("费用明细尚未全部审核通过,请先完成费用审核后再出库");
|
||||
}
|
||||
|
||||
/** 按具体出库批次推进到派送中。 */
|
||||
@Transactional
|
||||
public Workflow dispatch(String customer,String no,long batchId,String operator,Command request) {
|
||||
|
||||
@@ -63,7 +63,7 @@ paths:
|
||||
/api/platform/v1/last-leg/overseas-procurements/{orderNo}/outbounds:
|
||||
post:
|
||||
summary: 从采购库存创建出库单
|
||||
description: 权限 platform:overseas-business:purchase:ship-customer;仅平台主体,必须指定目标客户 customerId。仅 CONFIRMED、IN_TRANSIT 或 DELIVERING;数量不得超过 availableQuantity,物流跟踪号必填。必须存在本采购单未作废应收费用且全部有效并审核通过;缺少费用、待审核或驳回时拒绝出库。创建后占用数量增加,不实际扣库存。
|
||||
description: 权限 platform:overseas-business:purchase:ship-customer;仅平台主体,必须指定目标客户 customerId。仅 CONFIRMED、IN_TRANSIT 或 DELIVERING;数量不得超过 availableQuantity,物流跟踪号必填。费用明细缺失或尚未审核仅作提示,不阻止创建出库单。创建后占用数量增加,不实际扣库存。
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/OrderNo'
|
||||
- $ref: '#/components/parameters/CustomerId'
|
||||
|
||||
+3
-28
@@ -7,8 +7,6 @@ import com.baiyue.lastleg.procurement.entity.*;
|
||||
import com.baiyue.lastleg.procurement.mapper.*;
|
||||
import com.baiyue.lastleg.procurement.repository.ProcurementWorkflowRepository;
|
||||
import com.baiyue.lastleg.service.LastlegDocumentNumberGenerator;
|
||||
import com.baiyue.lastleg.financefee.service.OverseasFeeSourceService;
|
||||
import com.baiyue.lastleg.financefee.entity.OverseasFeeSource;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.*;
|
||||
import org.mybatis.spring.SqlSessionTemplate;
|
||||
@@ -33,7 +31,6 @@ class ProcurementWorkflowPersistenceTest {
|
||||
OverseasProcurementFileMapper files;
|
||||
OverseasProcurementStatusHistoryMapper histories;
|
||||
ProcurementWorkflowRepository repository;
|
||||
OverseasFeeSourceService fees;
|
||||
|
||||
@BeforeEach void setup() throws Exception {
|
||||
var ds=new DriverManagerDataSource("jdbc:h2:mem:"+UUID.randomUUID()+";MODE=MySQL;DATABASE_TO_LOWER=TRUE;DB_CLOSE_DELAY=-1","sa","");
|
||||
@@ -49,9 +46,7 @@ class ProcurementWorkflowPersistenceTest {
|
||||
histories=session.getMapper(OverseasProcurementStatusHistoryMapper.class);
|
||||
repository=new ProcurementWorkflowRepository(session.getMapper(ProcurementWorkflowMapper.class),orders,files);
|
||||
var numbers=mock(LastlegDocumentNumberGenerator.class);var sequence=new AtomicInteger();when(numbers.next("CK")).thenAnswer(i->"CK-"+sequence.incrementAndGet());
|
||||
fees=mock(OverseasFeeSourceService.class);
|
||||
when(fees.listForBusiness("9","OVERSEAS_PROCUREMENT",11L)).thenReturn(List.of(fee("ACTIVE","APPROVED")));
|
||||
service=new ProcurementWorkflowService(repository,numbers,new ObjectMapper().findAndRegisterModules(),fees);
|
||||
service=new ProcurementWorkflowService(repository,numbers,new ObjectMapper().findAndRegisterModules());
|
||||
var order=new OverseasProcurementOrder();order.setId(11L);order.setCustomerId("9");order.setOrderNo("CG-1");order.setProductName("采购商品");order.setPurchaseCategory("");order.setPurchaseQuantity(10L);order.setCurrency("USD");order.setStatus("RECEIVING");order.setVersion(0L);order.setInboundQuantity(0L);order.setContactName("buyer");order.setContactPhone("123456789");order.setIdempotencyKey("create");order.setRequestHash("0".repeat(64));orders.insert(order);
|
||||
file(101L,11L,"9","image/jpeg");file(102L,11L,"9","application/pdf");file(103L,12L,"10","image/jpeg");file(104L,11L,"9","image/png");
|
||||
}
|
||||
@@ -131,34 +126,14 @@ class ProcurementWorkflowPersistenceTest {
|
||||
assertThat(service.read("9","CG-1").stockQuantity()).isEqualTo(10);
|
||||
}
|
||||
|
||||
@Test void outboundRequiresCurrentReviewedReceivablesAndRejectedAttemptsLeaveNoInventoryChanges() {
|
||||
@Test void outboundDoesNotRequireFeeDetailsOrApproval() {
|
||||
tx.execute(s->service.receive("9","CG-1","7",new Receipt(0,"r",10,List.of(101L))));
|
||||
tx.execute(s->service.requestConfirmation("9","CG-1","7",new Command(1,"ask")));
|
||||
tx.execute(s->service.confirm("9","CG-1","8",new Command(2,"ok")));
|
||||
var request=new Outbound(3,"out",3,"TRACK");
|
||||
for(var rows:List.of(List.<OverseasFeeSource>of(),List.of(fee("VOIDED","APPROVED")))) {
|
||||
when(fees.listForBusiness("9","OVERSEAS_PROCUREMENT",11L)).thenReturn(rows);
|
||||
assertThatThrownBy(()->tx.execute(s->service.outbound("9","CG-1","7",request))).hasMessageContaining("请先添加费用明细");
|
||||
}
|
||||
var payable=fee("ACTIVE","APPROVED");payable.setDirection("PAYABLE");
|
||||
when(fees.listForBusiness("9","OVERSEAS_PROCUREMENT",11L)).thenReturn(List.of(payable));
|
||||
assertThatThrownBy(()->tx.execute(s->service.outbound("9","CG-1","7",request))).hasMessageContaining("请先添加费用明细");
|
||||
for(String review:List.of("PENDING","REJECTED")) {
|
||||
when(fees.listForBusiness("9","OVERSEAS_PROCUREMENT",11L)).thenReturn(List.of(fee("ACTIVE","APPROVED"),fee("ACTIVE",review)));
|
||||
assertThatThrownBy(()->tx.execute(s->service.outbound("9","CG-1","7",request))).hasMessageContaining("尚未全部审核通过");
|
||||
}
|
||||
assertThat(service.read("9","CG-1").version()).isEqualTo(3);
|
||||
assertThat(service.read("9","CG-1").reservedQuantity()).isZero();
|
||||
assertThat(service.read("9","CG-1").outbounds()).isEmpty();
|
||||
when(fees.listForBusiness("9","OVERSEAS_PROCUREMENT",11L)).thenReturn(List.of(fee("ACTIVE","APPROVED"),fee("VOIDED","REJECTED")));
|
||||
var result=tx.execute(s->service.outbound("9","CG-1","7",request));
|
||||
assertThat(result.reservedQuantity()).isEqualTo(3);
|
||||
when(fees.listForBusiness("9","OVERSEAS_PROCUREMENT",11L)).thenReturn(List.of());
|
||||
assertThat(tx.execute(s->service.outbound("9","CG-1","7",request)).version()).isEqualTo(4);
|
||||
}
|
||||
|
||||
private OverseasFeeSource fee(String status,String review) {
|
||||
var fee=new OverseasFeeSource();fee.setDirection("RECEIVABLE");fee.setSourceStatus(status);fee.setReviewStatus(review);return fee;
|
||||
assertThat(result.outbounds()).hasSize(1);
|
||||
}
|
||||
|
||||
private void file(long id,long orderId,String customer,String type) {
|
||||
|
||||
Reference in New Issue
Block a user