diff --git a/pom.xml b/pom.xml index 6d6d03c..a4a721f 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ com.imyeyu.timiserverapi TimiServerAPI - 1.0.44 + 1.0.45 jar TimiServerAPI imyeyu.com API diff --git a/src/main/java/com/imyeyu/api/modules/gao/service/GaoOrderPaymentService.java b/src/main/java/com/imyeyu/api/modules/gao/service/GaoOrderPaymentService.java index e291449..43a8758 100644 --- a/src/main/java/com/imyeyu/api/modules/gao/service/GaoOrderPaymentService.java +++ b/src/main/java/com/imyeyu/api/modules/gao/service/GaoOrderPaymentService.java @@ -16,6 +16,9 @@ public interface GaoOrderPaymentService { /// 登记收款 GaoFundRecord receive(GaoOrderPaymentReceiveRequest request); + /// 登记已收款并直接核销 + GaoFundRecord receiveAndVerify(GaoOrderPaymentReceiveRequest request); + /// 核销收款 GaoFundRecord verify(String fundRecordId); diff --git a/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoOrderPaymentServiceImplement.java b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoOrderPaymentServiceImplement.java index 4629573..70df61c 100644 --- a/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoOrderPaymentServiceImplement.java +++ b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoOrderPaymentServiceImplement.java @@ -49,10 +49,17 @@ public class GaoOrderPaymentServiceImplement implements GaoOrderPaymentService { @Transactional(TimiServerDBConfig.ROLLBACKER) @Override public GaoFundRecord receive(GaoOrderPaymentReceiveRequest request) { - return receiveInternal(request); + return receiveInternal(request, false); } - private GaoFundRecord receiveInternal(GaoOrderPaymentReceiveRequest request) { + @OperationAudit(AuditOperation.GAO_SALES_ORDER_PAYMENT_RECEIVE) + @Transactional(TimiServerDBConfig.ROLLBACKER) + @Override + public GaoFundRecord receiveAndVerify(GaoOrderPaymentReceiveRequest request) { + return receiveInternal(request, true); + } + + private GaoFundRecord receiveInternal(GaoOrderPaymentReceiveRequest request, boolean verified) { TimiException.required(request, "not found order payment request"); TimiException.required(request.getSalesOrderId(), "not found salesOrderId"); TimiException.required(request.getAmount(), "收款金额不能为空"); @@ -62,7 +69,7 @@ public class GaoOrderPaymentServiceImplement implements GaoOrderPaymentService { GaoFundRecord existing = fundRecordService.getByRequestNo(order.getStoreId(), requestNo); if (existing != null) { verifySameReceive(existing, order, request); - return existing; + return verified && existing.getStatus() == GaoFundRecord.Status.PENDING ? verify(existing.getId()) : existing; } TimiException.requiredTrue(order.getStatus() != GaoSalesOrder.Status.CANCELLED, "已取消订单不能收款"); TimiException.requiredTrue(order.getRefundStatus() != GaoSalesOrder.RefundStatus.REFUNDED, "已完成退款订单不能收款"); @@ -71,9 +78,27 @@ public class GaoOrderPaymentServiceImplement implements GaoOrderPaymentService { TimiException.requiredTrue(pending + paid + request.getAmount() <= safe(order.getSaleAmount()), "累计收款不能超过成交价"); TimiException.requiredTrue(hasPhoto(request.getAttachmentList()), "收款必须上传照片"); GaoFundRecord record = newRecord(order, GaoFundRecord.OperationType.RECEIVE, requestNo, request.getAmount(), request.getOccurredAt(), request.getRemark()); - record.setStatus(GaoFundRecord.Status.PENDING); + record.setStatus(verified ? GaoFundRecord.Status.VERIFIED : GaoFundRecord.Status.PENDING); + String verifierUserId = verified ? userLoginService.getRequireLoginUserId() : null; + Long verifiedAt = verified ? Time.now() : null; + if (verified) { + record.setVerifierUserId(verifierUserId); + record.setVerifiedAt(verifiedAt); + } fundRecordService.createByOrderPayment(record); - order.setPendingPaidAmount(pending + request.getAmount()); + if (!verified) { + order.setPendingPaidAmount(pending + request.getAmount()); + } else { + Long paidAtBefore = order.getPaidAt(); + order.setPaidAmount(paid + request.getAmount()); + orderService.recomputePaymentStatus(order); + orderService.updatePayment(order); + if (paidAtBefore == null && order.getPaidAt() != null) { + pointTriggerService.onSalesOrderPaid(order); + } + attachmentService.updateByBizId(Attachment.BizType.GAO_FUND_RECORD, record.getId(), request.getAttachmentList()); + return record; + } orderService.recomputePaymentStatus(order); orderService.updatePayment(order); attachmentService.updateByBizId(Attachment.BizType.GAO_FUND_RECORD, record.getId(), request.getAttachmentList()); diff --git a/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoOrderStraightThroughServiceImplement.java b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoOrderStraightThroughServiceImplement.java index 2e53cc5..dd7b30d 100644 --- a/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoOrderStraightThroughServiceImplement.java +++ b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoOrderStraightThroughServiceImplement.java @@ -43,29 +43,39 @@ public class GaoOrderStraightThroughServiceImplement implements GaoOrderStraight if (straightThrough == null) { return; } + boolean paymentVerified = Boolean.TRUE.equals(straightThrough.getPaymentVerified()); boolean receiveFullPayment = Boolean.TRUE.equals(straightThrough.getReceiveFullPayment()); boolean fulfillAll = Boolean.TRUE.equals(straightThrough.getFulfillAll()); - if (!receiveFullPayment && !fulfillAll) { + Long paymentAmount = paymentVerified ? straightThrough.getPaymentAmount() : order.getSaleAmount(); + if (!paymentVerified && !receiveFullPayment && !fulfillAll) { return; } TimiException.required(order, "not found sales order"); TimiException.required(order.getId(), "not found salesOrderId"); - TimiException.requiredTrue(!fulfillAll || receiveFullPayment || order.getSaleAmount() == 0, - "全部履约直通必须同时直接全额收款"); - checkPermissions(order.getOrderType(), receiveFullPayment, fulfillAll); + TimiException.requiredTrue(!(paymentVerified && receiveFullPayment), "已核销收款和已全额收款和核销不能同时启用"); + if (paymentVerified) { + TimiException.required(paymentAmount, "已核销收款金额不能为空"); + TimiException.requiredTrue(0 < paymentAmount && paymentAmount <= safe(order.getSaleAmount()), "已核销收款金额不能超过订单金额"); + } + TimiException.requiredTrue(!fulfillAll || receiveFullPayment || order.getSaleAmount() == 0 + || (paymentVerified && paymentAmount.equals(order.getSaleAmount())), + "全部履约直通必须同时完成收款核销"); + checkPermissions(order.getOrderType(), paymentVerified || receiveFullPayment, fulfillAll); if (receiveFullPayment) { settle(order, straightThrough); + } else if (paymentVerified) { + verifyReceivedPayment(order, straightThrough, paymentAmount); } if (fulfillAll) { fulfill(order, straightThrough); } } - private void checkPermissions(GaoSalesOrder.OrderType orderType, boolean receiveFullPayment, boolean fulfillAll) { + private void checkPermissions(GaoSalesOrder.OrderType orderType, boolean paymentCompleted, boolean fulfillAll) { List permissionCodeList = new ArrayList<>(); permissionCodeList.add(orderType == GaoSalesOrder.OrderType.PACKAGE ? GaoPermissionCode.CUSTOMER_PACKAGE_CREATE.getValue() : GaoPermissionCode.SALES_ORDER_CREATE.getValue()); - if (receiveFullPayment) { + if (paymentCompleted) { permissionCodeList.add(GaoPermissionCode.FUND_RECEIVE_CREATE.getValue()); permissionCodeList.add(GaoPermissionCode.FUND_RECEIVE_VERIFY.getValue()); } @@ -95,6 +105,18 @@ public class GaoOrderStraightThroughServiceImplement implements GaoOrderStraight TimiException.requiredTrue(record.getStatus() == GaoFundRecord.Status.VERIFIED, "直通收款记录不是已核销状态"); } + private void verifyReceivedPayment(GaoSalesOrder order, GaoOrderStraightThroughRequest straightThrough, Long paymentAmount) { + GaoOrderPaymentReceiveRequest paymentRequest = new GaoOrderPaymentReceiveRequest(); + paymentRequest.setSalesOrderId(order.getId()); + paymentRequest.setRequestNo("ORDER-%s-VERIFIED-PAY".formatted(order.getId())); + paymentRequest.setAmount(paymentAmount); + paymentRequest.setOccurredAt(TimiJava.defaultIfNull(straightThrough.getPaymentOccurredAt(), order.getPurchasedAt())); + paymentRequest.setAttachmentList(straightThrough.getPaymentAttachmentList()); + paymentRequest.setRemark(TimiJava.defaultIfEmpty(straightThrough.getPaymentRemark(), "随订单创建直接核销已有收款")); + GaoFundRecord record = paymentService.receiveAndVerify(paymentRequest); + TimiException.requiredTrue(record.getStatus() == GaoFundRecord.Status.VERIFIED, "直通收款记录不是已核销状态"); + } + private void fulfill(GaoSalesOrder order, GaoOrderStraightThroughRequest straightThrough) { List orderItemList = order.getItemList(); TimiException.requiredTrue(orderItemList != null && !orderItemList.isEmpty(), "销售订单没有可履约明细"); @@ -126,4 +148,8 @@ public class GaoOrderStraightThroughServiceImplement implements GaoOrderStraight request.setFulfillmentId(fulfillmentId); return request; } + + private long safe(Long value) { + return value == null ? 0L : value; + } } diff --git a/src/main/java/com/imyeyu/api/modules/gao/vo/GaoOrderStraightThroughRequest.java b/src/main/java/com/imyeyu/api/modules/gao/vo/GaoOrderStraightThroughRequest.java index 6632167..e1d6d86 100644 --- a/src/main/java/com/imyeyu/api/modules/gao/vo/GaoOrderStraightThroughRequest.java +++ b/src/main/java/com/imyeyu/api/modules/gao/vo/GaoOrderStraightThroughRequest.java @@ -12,6 +12,12 @@ import java.util.List; @Data public class GaoOrderStraightThroughRequest { + /// true 为已有收款并直接核销 + private Boolean paymentVerified; + + /// 已核销收款金额,单位分 + private Long paymentAmount; + /// true 为直接全额收款并核销 private Boolean receiveFullPayment;