提交
This commit is contained in:
+10
@@ -47,6 +47,16 @@ public class ProcurementWorkflowController {
|
||||
public ApiResponse<Workflow> dispatch(@AuthenticationPrincipal AuthenticatedUser user,@RequestParam String customerId,@PathVariable String orderNo,@PathVariable long batchId,@Valid @RequestBody Command request) {
|
||||
return ApiResponse.success(service.dispatch(customerId,orderNo,batchId,platform(user,customerId),request));
|
||||
}
|
||||
@PutMapping("/{orderNo}/outbounds/{batchId}")
|
||||
@PreAuthorize("hasAuthority('"+OverseasPermissions.PURCHASE_SHIP_CUSTOMER+"')")
|
||||
public ApiResponse<Workflow> editOutbound(@AuthenticationPrincipal AuthenticatedUser user,@RequestParam String customerId,@PathVariable String orderNo,@PathVariable long batchId,@Valid @RequestBody OutboundEdit request) {
|
||||
return ApiResponse.success(service.editOutbound(customerId,orderNo,batchId,platform(user,customerId),request));
|
||||
}
|
||||
@PostMapping("/{orderNo}/outbounds/{batchId}/cancel")
|
||||
@PreAuthorize("hasAuthority('"+OverseasPermissions.PURCHASE_SHIP_CUSTOMER+"')")
|
||||
public ApiResponse<Workflow> cancelOutbound(@AuthenticationPrincipal AuthenticatedUser user,@RequestParam String customerId,@PathVariable String orderNo,@PathVariable long batchId,@Valid @RequestBody Command request) {
|
||||
return ApiResponse.success(service.cancelOutbound(customerId,orderNo,batchId,platform(user,customerId),request));
|
||||
}
|
||||
/** 上传签收凭证并完成本批出库。 */
|
||||
@PostMapping("/{orderNo}/outbounds/{batchId}/complete")
|
||||
@PreAuthorize("hasAuthority('"+OverseasPermissions.PURCHASE_SHIP_CUSTOMER+"')")
|
||||
|
||||
+2
@@ -12,6 +12,8 @@ public final class ProcurementWorkflowDtos {
|
||||
@Positive long quantity,@NotEmpty @Size(max=20) List<@Positive Long> fileIds) { }
|
||||
public record Outbound(@Min(0) long version,@NotBlank @Size(max=128) String idempotencyKey,
|
||||
@Positive long quantity,@NotBlank @Size(max=255) String trackingNo) { }
|
||||
public record OutboundEdit(@Min(0) long version,@NotBlank @Size(max=128) String idempotencyKey,
|
||||
@Positive long quantity,@NotBlank @Size(max=255) String trackingNo) { }
|
||||
public record Completion(@Min(0) long version,@NotBlank @Size(max=128) String idempotencyKey,
|
||||
@NotEmpty @Size(max=20) List<@Positive Long> fileIds) { }
|
||||
public record ReceiptRow(Long id,long quantity,List<Long> fileIds,LocalDateTime receivedAt) { }
|
||||
|
||||
+3
@@ -28,4 +28,7 @@ public interface ProcurementWorkflowMapper {
|
||||
/** 派送和签收均要求批次属于已锁定订单。 */
|
||||
@Update("UPDATE ll_procurement_workflow_outbound SET status=#{status},file_ids=#{files},completed_at=#{completedAt} WHERE id=#{id} AND order_id=#{orderId}")
|
||||
void updateOutbound(@Param("id") long id,@Param("orderId") long orderId,@Param("status") String status,@Param("files") String files,@Param("completedAt") java.time.LocalDateTime completedAt);
|
||||
/** 修改尚未开始派送的批次。 */
|
||||
@Update("UPDATE ll_procurement_workflow_outbound SET quantity=#{quantity},tracking_no=#{tracking} WHERE id=#{id} AND order_id=#{orderId} AND status='IN_TRANSIT'")
|
||||
void editOutbound(@Param("id") long id,@Param("orderId") long orderId,@Param("quantity") long quantity,@Param("tracking") String tracking);
|
||||
}
|
||||
|
||||
+1
@@ -31,6 +31,7 @@ public class ProcurementWorkflowRepository {
|
||||
public void outbound(long id,long orderId,String no,long quantity,String tracking,String operator) { facts.outbound(id,orderId,no,quantity,tracking,operator); }
|
||||
/** 更新出库批次。 */
|
||||
public void outbound(long id,long orderId,String status,String files,java.time.LocalDateTime completedAt) { facts.updateOutbound(id,orderId,status,files,completedAt); }
|
||||
public void editOutbound(long id,long orderId,long quantity,String tracking) { facts.editOutbound(id,orderId,quantity,tracking); }
|
||||
/** 文件仅按当前订单及客户返回,不能引用其他采购单文件。 */
|
||||
public List<OverseasProcurementFile> files(OverseasProcurementOrder order) {
|
||||
return files.selectList(new LambdaQueryWrapper<OverseasProcurementFile>().eq(OverseasProcurementFile::getOrderId,order.getId()).eq(OverseasProcurementFile::getCustomerId,order.getCustomerId()));
|
||||
|
||||
+26
-1
@@ -91,6 +91,31 @@ public class ProcurementWorkflowService {
|
||||
return snapshot(order);
|
||||
}
|
||||
|
||||
/** 运输中批次允许调整数量和物流单号,开始派送后立即冻结。 */
|
||||
@Transactional
|
||||
public Workflow editOutbound(String customer,String no,long batchId,String operator,OutboundEdit request) {
|
||||
var order=order(customer,no,true);String action="EDIT_OUTBOUND:"+batchId;
|
||||
if(replay(order,request.idempotencyKey(),action,request)) return snapshot(order);
|
||||
version(order,request.version());var batch=batch(order,batchId);
|
||||
if(!"IN_TRANSIT".equals(batch.status())) throw conflict("开始派送后不能修改出库单");
|
||||
var current=snapshot(order); long available=current.availableQuantity()+batch.quantity();
|
||||
if(request.quantity()<=0 || request.quantity()>available) throw conflict("出库数量超过采购可用库存");
|
||||
if(request.trackingNo()==null || request.trackingNo().isBlank() || request.trackingNo().length()>255) throw bad("请填写物流跟踪号");
|
||||
repository.editOutbound(batchId,order.getId(),request.quantity(),request.trackingNo().trim());
|
||||
finish(order,operator,request.idempotencyKey(),action,request); return snapshot(order);
|
||||
}
|
||||
|
||||
/** 运输中批次允许取消;已开始派送的批次不可取消。 */
|
||||
@Transactional
|
||||
public Workflow cancelOutbound(String customer,String no,long batchId,String operator,Command request) {
|
||||
var order=order(customer,no,true);String action="CANCEL_OUTBOUND:"+batchId;
|
||||
if(replay(order,request.idempotencyKey(),action,request)) return snapshot(order);
|
||||
version(order,request.version());var batch=batch(order,batchId);
|
||||
if(!"IN_TRANSIT".equals(batch.status())) throw conflict("开始派送后不能取消出库单");
|
||||
repository.outbound(batchId,order.getId(),"CANCELLED","[]",null); refreshStatus(order);
|
||||
finish(order,operator,request.idempotencyKey(),action,request); return snapshot(order);
|
||||
}
|
||||
|
||||
/** 签收凭证关联到本批次;同事务完成批次并扣除采购库存,重试不重复扣减。 */
|
||||
@Transactional
|
||||
public Workflow complete(String customer,String no,long batchId,String operator,Completion request) {
|
||||
@@ -124,7 +149,7 @@ public class ProcurementWorkflowService {
|
||||
var outbounds=repository.outbounds(order.getId()).stream().map(r->new OutboundRow(number(r,"id"),text(r,"outbound_no"),number(r,"quantity"),text(r,"tracking_no"),text(r,"status"),ids(r.get("file_ids")),date(r.get("created_at")),date(r.get("completed_at")))).toList();
|
||||
long received=receipts.stream().mapToLong(ReceiptRow::quantity).sum();
|
||||
long completed=outbounds.stream().filter(b->"COMPLETED".equals(b.status())).mapToLong(OutboundRow::quantity).sum();
|
||||
long reserved=outbounds.stream().filter(b->!"COMPLETED".equals(b.status())).mapToLong(OutboundRow::quantity).sum();
|
||||
long reserved=outbounds.stream().filter(b->!Set.of("COMPLETED","CANCELLED").contains(b.status())).mapToLong(OutboundRow::quantity).sum();
|
||||
Set<Long> visible=new HashSet<>();receipts.forEach(r->visible.addAll(r.fileIds()));outbounds.forEach(b->visible.addAll(b.fileIds()));
|
||||
var files=visible.isEmpty()?List.<FileInfo>of():repository.files(order).stream().filter(f->visible.contains(f.getFileId())).map(f->new FileInfo(f.getFileId(),f.getFileName(),f.getContentType())).toList();
|
||||
return new Workflow(order.getOrderNo(),order.getVersion(),order.getStatus(),received,received-completed,reserved,received-completed-reserved,receipts,outbounds,files);
|
||||
|
||||
@@ -101,6 +101,36 @@ paths:
|
||||
description: 未认证
|
||||
'403':
|
||||
description: 身份或操作权限不允许
|
||||
/api/platform/v1/last-leg/overseas-procurements/{orderNo}/outbounds/{batchId}:
|
||||
put:
|
||||
summary: 修改尚未开始派送的出库单
|
||||
description: 仅 IN_TRANSIT 批次可修改数量和物流跟踪号;开始派送后拒绝修改。
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/OrderNo'
|
||||
- $ref: '#/components/parameters/CustomerId'
|
||||
- $ref: '#/components/parameters/BatchId'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/OutboundCommand' }
|
||||
responses:
|
||||
'200': { $ref: '#/components/responses/WorkflowResponse' }
|
||||
/api/platform/v1/last-leg/overseas-procurements/{orderNo}/outbounds/{batchId}/cancel:
|
||||
post:
|
||||
summary: 取消尚未开始派送的出库单
|
||||
description: 仅 IN_TRANSIT 批次可取消;取消后释放采购库存占用,开始派送后拒绝取消。
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/OrderNo'
|
||||
- $ref: '#/components/parameters/CustomerId'
|
||||
- $ref: '#/components/parameters/BatchId'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/Command' }
|
||||
responses:
|
||||
'200': { $ref: '#/components/responses/WorkflowResponse' }
|
||||
/api/platform/v1/last-leg/overseas-procurements/{orderNo}/outbounds/{batchId}/complete:
|
||||
post:
|
||||
summary: 上传凭证并完成本批出库
|
||||
|
||||
Reference in New Issue
Block a user