Commit f93bad282f4985695244a111cbbcb13c5e6c5d1f

Authored by YunaiV
1 parent 33f654b7

✨ ERP:初始化 receipt 收款单的逻辑 30%

Showing 22 changed files with 1092 additions and 11 deletions
yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java
... ... @@ -72,6 +72,9 @@ ErrorCode PURCHASE_ORDER_ITEM_RETURN_FAIL_IN_EXCEED = new ErrorCode(1_030_101_00
72 72 ErrorCode SALE_OUT_APPROVE_FAIL = new ErrorCode(1_020_202_003, "审核失败,只有未审核的出库单才能审核");
73 73 ErrorCode SALE_OUT_NO_EXISTS = new ErrorCode(1_020_202_004, "生成出库单失败,请重新提交");
74 74 ErrorCode SALE_OUT_UPDATE_FAIL_APPROVE = new ErrorCode(1_020_202_005, "销售出库单({})已审核,无法修改");
  75 + ErrorCode SALE_OUT_NOT_APPROVE = new ErrorCode(1_020_202_006, "销售出库单未审核,无法操作");
  76 + ErrorCode SALE_OUT_FAIL_RECEIPT_PRICE_EXCEED = new ErrorCode(1_020_202_007, "收款金额({})超过销售出库单总金额({})");
  77 + ErrorCode SALE_OUT_PROCESS_FAIL_EXISTS_RECEIPT = new ErrorCode(1_020_202_008, "反审核失败,已存在对应的收款单");
75 78  
76 79 // ========== ERP 销售退货(1-030-203-000) ==========
77 80 ErrorCode SALE_RETURN_NOT_EXISTS = new ErrorCode(1_020_203_000, "销售退货单不存在");
... ... @@ -80,6 +83,9 @@ ErrorCode PURCHASE_ORDER_ITEM_RETURN_FAIL_IN_EXCEED = new ErrorCode(1_030_101_00
80 83 ErrorCode SALE_RETURN_APPROVE_FAIL = new ErrorCode(1_020_203_003, "审核失败,只有未审核的退货单才能审核");
81 84 ErrorCode SALE_RETURN_NO_EXISTS = new ErrorCode(1_020_203_004, "生成退货单失败,请重新提交");
82 85 ErrorCode SALE_RETURN_UPDATE_FAIL_APPROVE = new ErrorCode(1_020_203_005, "销售退货单({})已审核,无法修改");
  86 + ErrorCode SALE_RETURN_NOT_APPROVE = new ErrorCode(1_020_203_006, "销售退货单未审核,无法操作");
  87 + ErrorCode SALE_RETURN_FAIL_REFUND_PRICE_EXCEED = new ErrorCode(1_020_203_007, "退款金额({})超过销售退货单总金额({})");
  88 + ErrorCode SALE_RETURN_PROCESS_FAIL_EXISTS_REFUND = new ErrorCode(1_020_203_008, "反审核失败,已存在对应的退款单");
83 89  
84 90 // ========== ERP 仓库 1-030-400-000 ==========
85 91 ErrorCode WAREHOUSE_NOT_EXISTS = new ErrorCode(1_030_400_000, "仓库不存在");
... ... @@ -151,4 +157,12 @@ ErrorCode PURCHASE_ORDER_ITEM_RETURN_FAIL_IN_EXCEED = new ErrorCode(1_030_101_00
151 157 ErrorCode FINANCE_PAYMENT_NO_EXISTS = new ErrorCode(1_030_601_004, "生成付款单号失败,请重新提交");
152 158 ErrorCode FINANCE_PAYMENT_UPDATE_FAIL_APPROVE = new ErrorCode(1_030_601_005, "付款单({})已审核,无法修改");
153 159  
  160 + // ========== ERP 收款单 1-030-602-000 ==========
  161 + ErrorCode FINANCE_RECEIPT_NOT_EXISTS = new ErrorCode(1_030_602_000, "收款单不存在");
  162 + ErrorCode FINANCE_RECEIPT_DELETE_FAIL_APPROVE = new ErrorCode(1_030_602_001, "收款单({})已审核,无法删除");
  163 + ErrorCode FINANCE_RECEIPT_PROCESS_FAIL = new ErrorCode(1_030_602_002, "反审核失败,只有已审核的收款单才能反审核");
  164 + ErrorCode FINANCE_RECEIPT_APPROVE_FAIL = new ErrorCode(1_030_602_003, "审核失败,只有未审核的收款单才能审核");
  165 + ErrorCode FINANCE_RECEIPT_NO_EXISTS = new ErrorCode(1_030_602_004, "生成收款单号失败,请重新提交");
  166 + ErrorCode FINANCE_RECEIPT_UPDATE_FAIL_APPROVE = new ErrorCode(1_030_602_005, "收款单({})已审核,无法修改");
  167 +
154 168 }
... ...
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/ErpFinanceReceiptController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.erp.controller.admin.finance;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  7 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
  8 +import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
  9 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  10 +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
  11 +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
  12 +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.receipt.ErpFinanceReceiptPageReqVO;
  13 +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.receipt.ErpFinanceReceiptRespVO;
  14 +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.receipt.ErpFinanceReceiptSaveReqVO;
  15 +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpAccountDO;
  16 +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinanceReceiptDO;
  17 +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinanceReceiptItemDO;
  18 +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpCustomerDO;
  19 +import cn.iocoder.yudao.module.erp.service.finance.ErpAccountService;
  20 +import cn.iocoder.yudao.module.erp.service.finance.ErpFinanceReceiptService;
  21 +import cn.iocoder.yudao.module.erp.service.sale.ErpCustomerService;
  22 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
  23 +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
  24 +import io.swagger.v3.oas.annotations.Operation;
  25 +import io.swagger.v3.oas.annotations.Parameter;
  26 +import io.swagger.v3.oas.annotations.tags.Tag;
  27 +import jakarta.annotation.Resource;
  28 +import jakarta.servlet.http.HttpServletResponse;
  29 +import jakarta.validation.Valid;
  30 +import org.springframework.security.access.prepost.PreAuthorize;
  31 +import org.springframework.validation.annotation.Validated;
  32 +import org.springframework.web.bind.annotation.*;
  33 +
  34 +import java.io.IOException;
  35 +import java.util.List;
  36 +import java.util.Map;
  37 +import java.util.stream.Stream;
  38 +
  39 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  40 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
  41 +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
  42 +
  43 +@Tag(name = "管理后台 - ERP 收款单")
  44 +@RestController
  45 +@RequestMapping("/erp/finance-receipt")
  46 +@Validated
  47 +public class ErpFinanceReceiptController {
  48 +
  49 + @Resource
  50 + private ErpFinanceReceiptService financeReceiptService;
  51 + @Resource
  52 + private ErpCustomerService customerService;
  53 + @Resource
  54 + private ErpAccountService accountService;
  55 +
  56 + @Resource
  57 + private AdminUserApi adminUserApi;
  58 +
  59 + @PostMapping("/create")
  60 + @Operation(summary = "创建收款单")
  61 + @PreAuthorize("@ss.hasPermission('erp:finance-receipt:create')")
  62 + public CommonResult<Long> createFinanceReceipt(@Valid @RequestBody ErpFinanceReceiptSaveReqVO createReqVO) {
  63 + return success(financeReceiptService.createFinanceReceipt(createReqVO));
  64 + }
  65 +
  66 + @PutMapping("/update")
  67 + @Operation(summary = "更新收款单")
  68 + @PreAuthorize("@ss.hasPermission('erp:finance-receipt:update')")
  69 + public CommonResult<Boolean> updateFinanceReceipt(@Valid @RequestBody ErpFinanceReceiptSaveReqVO updateReqVO) {
  70 + financeReceiptService.updateFinanceReceipt(updateReqVO);
  71 + return success(true);
  72 + }
  73 +
  74 + @PutMapping("/update-status")
  75 + @Operation(summary = "更新收款单的状态")
  76 + @PreAuthorize("@ss.hasPermission('erp:finance-receipt:update-status')")
  77 + public CommonResult<Boolean> updateFinanceReceiptStatus(@RequestParam("id") Long id,
  78 + @RequestParam("status") Integer status) {
  79 + financeReceiptService.updateFinanceReceiptStatus(id, status);
  80 + return success(true);
  81 + }
  82 +
  83 + @DeleteMapping("/delete")
  84 + @Operation(summary = "删除收款单")
  85 + @Parameter(name = "ids", description = "编号数组", required = true)
  86 + @PreAuthorize("@ss.hasPermission('erp:finance-receipt:delete')")
  87 + public CommonResult<Boolean> deleteFinanceReceipt(@RequestParam("ids") List<Long> ids) {
  88 + financeReceiptService.deleteFinanceReceipt(ids);
  89 + return success(true);
  90 + }
  91 +
  92 + @GetMapping("/get")
  93 + @Operation(summary = "获得收款单")
  94 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  95 + @PreAuthorize("@ss.hasPermission('erp:finance-receipt:query')")
  96 + public CommonResult<ErpFinanceReceiptRespVO> getFinanceReceipt(@RequestParam("id") Long id) {
  97 + ErpFinanceReceiptDO receipt = financeReceiptService.getFinanceReceipt(id);
  98 + if (receipt == null) {
  99 + return success(null);
  100 + }
  101 + List<ErpFinanceReceiptItemDO> receiptItemList = financeReceiptService.getFinanceReceiptItemListByReceiptId(id);
  102 + return success(BeanUtils.toBean(receipt, ErpFinanceReceiptRespVO.class, financeReceiptVO ->
  103 + financeReceiptVO.setItems(BeanUtils.toBean(receiptItemList, ErpFinanceReceiptRespVO.Item.class))));
  104 + }
  105 +
  106 + @GetMapping("/page")
  107 + @Operation(summary = "获得收款单分页")
  108 + @PreAuthorize("@ss.hasPermission('erp:finance-receipt:query')")
  109 + public CommonResult<PageResult<ErpFinanceReceiptRespVO>> getFinanceReceiptPage(@Valid ErpFinanceReceiptPageReqVO pageReqVO) {
  110 + PageResult<ErpFinanceReceiptDO> pageResult = financeReceiptService.getFinanceReceiptPage(pageReqVO);
  111 + return success(buildFinanceReceiptVOPageResult(pageResult));
  112 + }
  113 +
  114 + @GetMapping("/export-excel")
  115 + @Operation(summary = "导出收款单 Excel")
  116 + @PreAuthorize("@ss.hasPermission('erp:finance-receipt:export')")
  117 + @OperateLog(type = EXPORT)
  118 + public void exportFinanceReceiptExcel(@Valid ErpFinanceReceiptPageReqVO pageReqVO,
  119 + HttpServletResponse response) throws IOException {
  120 + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
  121 + List<ErpFinanceReceiptRespVO> list = buildFinanceReceiptVOPageResult(financeReceiptService.getFinanceReceiptPage(pageReqVO)).getList();
  122 + // 导出 Excel
  123 + ExcelUtils.write(response, "收款单.xls", "数据", ErpFinanceReceiptRespVO.class, list);
  124 + }
  125 +
  126 + private PageResult<ErpFinanceReceiptRespVO> buildFinanceReceiptVOPageResult(PageResult<ErpFinanceReceiptDO> pageResult) {
  127 + if (CollUtil.isEmpty(pageResult.getList())) {
  128 + return PageResult.empty(pageResult.getTotal());
  129 + }
  130 + // 1.1 收款项
  131 + List<ErpFinanceReceiptItemDO> receiptItemList = financeReceiptService.getFinanceReceiptItemListByReceiptIds(
  132 + convertSet(pageResult.getList(), ErpFinanceReceiptDO::getId));
  133 + Map<Long, List<ErpFinanceReceiptItemDO>> financeReceiptItemMap = convertMultiMap(receiptItemList, ErpFinanceReceiptItemDO::getReceiptId);
  134 + // 1.2 客户信息
  135 + Map<Long, ErpCustomerDO> customerMap = customerService.getCustomerMap(
  136 + convertSet(pageResult.getList(), ErpFinanceReceiptDO::getCustomerId));
  137 + // 1.3 结算账户信息
  138 + Map<Long, ErpAccountDO> accountMap = accountService.getAccountMap(
  139 + convertSet(pageResult.getList(), ErpFinanceReceiptDO::getAccountId));
  140 + // 1.4 管理员信息
  141 + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(pageResult.getList(),
  142 + contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getFinanceUserId())));
  143 + // 2. 开始拼接
  144 + return BeanUtils.toBean(pageResult, ErpFinanceReceiptRespVO.class, receipt -> {
  145 + receipt.setItems(BeanUtils.toBean(financeReceiptItemMap.get(receipt.getId()), ErpFinanceReceiptRespVO.Item.class));
  146 + MapUtils.findAndThen(customerMap, receipt.getCustomerId(), customer -> receipt.setCustomerName(customer.getName()));
  147 + MapUtils.findAndThen(accountMap, receipt.getAccountId(), account -> receipt.setAccountName(account.getName()));
  148 + MapUtils.findAndThen(userMap, Long.parseLong(receipt.getCreator()), user -> receipt.setCreatorName(user.getNickname()));
  149 + MapUtils.findAndThen(userMap, receipt.getFinanceUserId(), user -> receipt.setFinanceUserName(user.getNickname()));
  150 + });
  151 + }
  152 +
  153 +}
... ...
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/payment/ErpFinancePaymentPageReqVO.java
... ... @@ -17,7 +17,7 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
17 17 @ToString(callSuper = true)
18 18 public class ErpFinancePaymentPageReqVO extends PageParam {
19 19  
20   - @Schema(description = "采购单编号", example = "XS001")
  20 + @Schema(description = "付款单编号", example = "XS001")
21 21 private String no;
22 22  
23 23 @Schema(description = "付款时间")
... ...
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/payment/ErpFinancePaymentRespVO.java
... ... @@ -79,10 +79,10 @@ public class ErpFinancePaymentRespVO {
79 79 @Schema(description = "业务单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756")
80 80 private String bizNo;
81 81  
82   - @Schema(description = "应付欠款,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000")
  82 + @Schema(description = "应付金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000")
83 83 private BigDecimal totalPrice;
84 84  
85   - @Schema(description = "已付欠款,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000")
  85 + @Schema(description = "已付金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000")
86 86 private BigDecimal paidPrice;
87 87  
88 88 @Schema(description = "本次付款,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000")
... ...
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/payment/ErpFinancePaymentSaveReqVO.java
... ... @@ -58,8 +58,8 @@ public class ErpFinancePaymentSaveReqVO {
58 58 @NotNull(message = "业务编号不能为空")
59 59 private Long bizId;
60 60  
61   - @Schema(description = "已付欠款,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000")
62   - @NotNull(message = "已付欠款不能为空")
  61 + @Schema(description = "已付金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000")
  62 + @NotNull(message = "已付金额不能为空")
63 63 private BigDecimal paidPrice;
64 64  
65 65 @Schema(description = "本次付款,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000")
... ...
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/receipt/ErpFinanceReceiptPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.erp.controller.admin.finance.vo.receipt;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +import org.springframework.format.annotation.DateTimeFormat;
  9 +
  10 +import java.time.LocalDateTime;
  11 +
  12 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  13 +
  14 +@Schema(description = "管理后台 - ERP 收款单分页 Request VO")
  15 +@Data
  16 +@EqualsAndHashCode(callSuper = true)
  17 +@ToString(callSuper = true)
  18 +public class ErpFinanceReceiptPageReqVO extends PageParam {
  19 +
  20 + @Schema(description = "收款单编号", example = "XS001")
  21 + private String no;
  22 +
  23 + @Schema(description = "收款时间")
  24 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  25 + private LocalDateTime[] receiptTime;
  26 +
  27 + @Schema(description = "客户编号", example = "1724")
  28 + private Long customerId;
  29 +
  30 + @Schema(description = "创建者", example = "666")
  31 + private String creator;
  32 +
  33 + @Schema(description = "财务人员编号", example = "888")
  34 + private String financeUserId;
  35 +
  36 + @Schema(description = "收款账户编号", example = "31189")
  37 + private Long accountId;
  38 +
  39 + @Schema(description = "收款状态", example = "2")
  40 + private Integer status;
  41 +
  42 + @Schema(description = "备注", example = "你猜")
  43 + private String remark;
  44 +
  45 + @Schema(description = "业务编号", example = "123")
  46 + private String bizNo;
  47 +
  48 +}
0 49 \ No newline at end of file
... ...
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/receipt/ErpFinanceReceiptRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.erp.controller.admin.finance.vo.receipt;
  2 +
  3 +import com.alibaba.excel.annotation.ExcelProperty;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import jakarta.validation.constraints.NotNull;
  6 +import lombok.Data;
  7 +
  8 +import java.math.BigDecimal;
  9 +import java.time.LocalDateTime;
  10 +import java.util.List;
  11 +
  12 +@Schema(description = "管理后台 - ERP 收款单 Response VO")
  13 +@Data
  14 +public class ErpFinanceReceiptRespVO {
  15 +
  16 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23752")
  17 + private Long id;
  18 +
  19 + @Schema(description = "收款单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "FKD888")
  20 + private String no;
  21 +
  22 + @Schema(description = "收款状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  23 + private Integer status;
  24 +
  25 + @Schema(description = "收款时间", requiredMode = Schema.RequiredMode.REQUIRED)
  26 + private LocalDateTime receiptTime;
  27 +
  28 + @Schema(description = "财务人员编号", example = "19690")
  29 + private Long financeUserId;
  30 + @Schema(description = "财务人员名称", example = "张三")
  31 + private String financeUserName;
  32 +
  33 + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "29399")
  34 + private Long customerId;
  35 + @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小番茄公司")
  36 + private String customerName;
  37 +
  38 + @Schema(description = "收款账户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28989")
  39 + private Long accountId;
  40 + @Schema(description = "收款账户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三")
  41 + private String accountName;
  42 +
  43 + @Schema(description = "合计价格,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "13832")
  44 + private BigDecimal totalPrice;
  45 +
  46 + @Schema(description = "优惠金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "11600")
  47 + private BigDecimal discountPrice;
  48 +
  49 + @Schema(description = "实际价格,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000")
  50 + private BigDecimal receiptPrice;
  51 +
  52 + @Schema(description = "备注", example = "你猜")
  53 + private String remark;
  54 +
  55 + @Schema(description = "创建人", example = "芋道")
  56 + private String creator;
  57 + @Schema(description = "创建人名称", example = "芋道")
  58 + private String creatorName;
  59 +
  60 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  61 + @ExcelProperty("创建时间")
  62 + private LocalDateTime createTime;
  63 +
  64 + @Schema(description = "收款项列表", requiredMode = Schema.RequiredMode.REQUIRED)
  65 + private List<Item> items;
  66 +
  67 + @Data
  68 + public static class Item {
  69 +
  70 + @Schema(description = "收款项编号", example = "11756")
  71 + private Long id;
  72 +
  73 + @Schema(description = "业务类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  74 + private Integer bizType;
  75 +
  76 + @Schema(description = "业务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756")
  77 + private Long bizId;
  78 +
  79 + @Schema(description = "业务单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756")
  80 + private String bizNo;
  81 +
  82 + @Schema(description = "应收金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000")
  83 + private BigDecimal totalPrice;
  84 +
  85 + @Schema(description = "已收金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000")
  86 + private BigDecimal receiptedPrice;
  87 +
  88 + @Schema(description = "本次收款,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000")
  89 + @NotNull(message = "本次收款不能为空")
  90 + private BigDecimal receiptPrice;
  91 +
  92 + @Schema(description = "备注", example = "随便")
  93 + private String remark;
  94 +
  95 + }
  96 +
  97 +}
0 98 \ No newline at end of file
... ...
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/receipt/ErpFinanceReceiptSaveReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.erp.controller.admin.finance.vo.receipt;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import jakarta.validation.Valid;
  5 +import jakarta.validation.constraints.NotEmpty;
  6 +import jakarta.validation.constraints.NotNull;
  7 +import lombok.Data;
  8 +
  9 +import java.math.BigDecimal;
  10 +import java.time.LocalDateTime;
  11 +import java.util.List;
  12 +
  13 +@Schema(description = "管理后台 - ERP 收款单新增/修改 Request VO")
  14 +@Data
  15 +public class ErpFinanceReceiptSaveReqVO {
  16 +
  17 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23752")
  18 + private Long id;
  19 +
  20 + @Schema(description = "收款时间", requiredMode = Schema.RequiredMode.REQUIRED)
  21 + @NotNull(message = "收款时间不能为空")
  22 + private LocalDateTime receiptTime;
  23 +
  24 + @Schema(description = "财务人员编号", example = "19690")
  25 + private Long financeUserId;
  26 +
  27 + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "29399")
  28 + @NotNull(message = "客户编号不能为空")
  29 + private Long customerId;
  30 +
  31 + @Schema(description = "收款账户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28989")
  32 + @NotNull(message = "收款账户编号不能为空")
  33 + private Long accountId;
  34 +
  35 + @Schema(description = "优惠金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "11600")
  36 + @NotNull(message = "优惠金额不能为空")
  37 + private BigDecimal discountPrice;
  38 +
  39 + @Schema(description = "备注", example = "你猜")
  40 + private String remark;
  41 +
  42 + @Schema(description = "收款项列表", requiredMode = Schema.RequiredMode.REQUIRED)
  43 + @NotEmpty(message = "收款项列表不能为空")
  44 + @Valid
  45 + private List<Item> items;
  46 +
  47 + @Data
  48 + public static class Item {
  49 +
  50 + @Schema(description = "收款项编号", example = "11756")
  51 + private Long id;
  52 +
  53 + @Schema(description = "业务类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  54 + @NotNull(message = "业务类型不能为空")
  55 + private Integer bizType;
  56 +
  57 + @Schema(description = "业务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756")
  58 + @NotNull(message = "业务编号不能为空")
  59 + private Long bizId;
  60 +
  61 + @Schema(description = "已收金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000")
  62 + @NotNull(message = "已收金额不能为空")
  63 + private BigDecimal receiptedPrice;
  64 +
  65 + @Schema(description = "本次收款,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000")
  66 + @NotNull(message = "本次收款不能为空")
  67 + private BigDecimal receiptPrice;
  68 +
  69 + @Schema(description = "备注", example = "随便")
  70 + private String remark;
  71 +
  72 + }
  73 +
  74 +}
0 75 \ No newline at end of file
... ...
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/finance/ErpFinancePaymentItemDO.java
... ... @@ -56,11 +56,11 @@ public class ErpFinancePaymentItemDO extends BaseDO {
56 56 private String bizNo;
57 57  
58 58 /**
59   - * 应付欠款,单位:分
  59 + * 应付金额,单位:分
60 60 */
61 61 private BigDecimal totalPrice;
62 62 /**
63   - * 已付欠款,单位:分
  63 + * 已付金额,单位:分
64 64 */
65 65 private BigDecimal paidPrice;
66 66 /**
... ...
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/finance/ErpFinanceReceiptDO.java
1 1 package cn.iocoder.yudao.module.erp.dal.dataobject.finance;
2 2  
3   -public class ErpFinanceReceiptDO {
4   -}
  3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpCustomerDO;
  5 +import com.baomidou.mybatisplus.annotation.KeySequence;
  6 +import com.baomidou.mybatisplus.annotation.TableId;
  7 +import com.baomidou.mybatisplus.annotation.TableName;
  8 +import lombok.*;
  9 +
  10 +import java.math.BigDecimal;
  11 +import java.time.LocalDateTime;
  12 +
  13 +/**
  14 + * ERP 收款单 DO
  15 + *
  16 + * @author 芋道源码
  17 + */
  18 +@TableName("erp_finance_receipt")
  19 +@KeySequence("erp_finance_receipt_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  20 +@Data
  21 +@EqualsAndHashCode(callSuper = true)
  22 +@ToString(callSuper = true)
  23 +@Builder
  24 +@NoArgsConstructor
  25 +@AllArgsConstructor
  26 +public class ErpFinanceReceiptDO extends BaseDO {
  27 +
  28 + /**
  29 + * 编号
  30 + */
  31 + @TableId
  32 + private Long id;
  33 + /**
  34 + * 收款单号
  35 + */
  36 + private String no;
  37 + /**
  38 + * 收款状态
  39 + *
  40 + * 枚举 {@link cn.iocoder.yudao.module.erp.enums.ErpAuditStatus}
  41 + */
  42 + private Integer status;
  43 + /**
  44 + * 收款时间
  45 + */
  46 + private LocalDateTime receiptTime;
  47 + /**
  48 + * 财务人员编号
  49 + *
  50 + * 关联 AdminUserDO 的 id 字段
  51 + */
  52 + private Long financeUserId;
  53 + /**
  54 + * 客户编号
  55 + *
  56 + * 关联 {@link ErpCustomerDO#getId()}
  57 + */
  58 + private Long customerId;
  59 + /**
  60 + * 收款账户编号
  61 + *
  62 + * 关联 {@link ErpAccountDO#getId()}
  63 + */
  64 + private Long accountId;
  65 +
  66 + /**
  67 + * 合计价格,单位:元
  68 + */
  69 + private BigDecimal totalPrice;
  70 + /**
  71 + * 优惠金额,单位:元
  72 + */
  73 + private BigDecimal discountPrice;
  74 + /**
  75 + * 实付金额,单位:分
  76 + *
  77 + * receiptPrice = totalPrice - discountPrice
  78 + */
  79 + private BigDecimal receiptPrice;
  80 +
  81 + /**
  82 + * 备注
  83 + */
  84 + private String remark;
  85 +
  86 +}
5 87 \ No newline at end of file
... ...
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/finance/ErpFinanceReceiptItemDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.erp.dal.dataobject.finance;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutDO;
  5 +import com.baomidou.mybatisplus.annotation.KeySequence;
  6 +import com.baomidou.mybatisplus.annotation.TableId;
  7 +import com.baomidou.mybatisplus.annotation.TableName;
  8 +import lombok.*;
  9 +
  10 +import java.math.BigDecimal;
  11 +
  12 +/**
  13 + * ERP 收款项 DO
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@TableName("erp_finance_payment_item")
  18 +@KeySequence("erp_finance_payment_item_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  19 +@Data
  20 +@EqualsAndHashCode(callSuper = true)
  21 +@ToString(callSuper = true)
  22 +@Builder
  23 +@NoArgsConstructor
  24 +@AllArgsConstructor
  25 +public class ErpFinanceReceiptItemDO extends BaseDO {
  26 +
  27 + /**
  28 + * 入库项编号
  29 + */
  30 + @TableId
  31 + private Long id;
  32 + /**
  33 + * 收款单编号
  34 + *
  35 + * 关联 {@link ErpFinanceReceiptDO#getId()}
  36 + */
  37 + private Long receiptId;
  38 +
  39 + /**
  40 + * 业务类型
  41 + *
  42 + * 枚举 {@link cn.iocoder.yudao.module.erp.enums.common.ErpBizTypeEnum} 的销售出库、退货
  43 + */
  44 + private Integer bizType;
  45 + /**
  46 + * 业务编号
  47 + *
  48 + * 例如说:{@link ErpSaleOutDO#getId()}
  49 + */
  50 + private Long bizId;
  51 + /**
  52 + * 业务单号
  53 + *
  54 + * 例如说:{@link ErpSaleOutDO#getNo()}
  55 + */
  56 + private String bizNo;
  57 +
  58 + /**
  59 + * 应收金额,单位:分
  60 + */
  61 + private BigDecimal totalPrice;
  62 + /**
  63 + * 已收金额,单位:分
  64 + */
  65 + private BigDecimal receiptedPrice;
  66 + /**
  67 + * 本次收款,单位:分
  68 + */
  69 + private BigDecimal receiptPrice;
  70 + /**
  71 + * 备注
  72 + */
  73 + private String remark;
  74 +
  75 +}
0 76 \ No newline at end of file
... ...
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpFinanceReceiptItemMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.erp.dal.mysql.finance;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.map.MapUtil;
  5 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  6 +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinanceReceiptItemDO;
  7 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  8 +import org.apache.ibatis.annotations.Mapper;
  9 +
  10 +import java.math.BigDecimal;
  11 +import java.util.Collection;
  12 +import java.util.List;
  13 +import java.util.Map;
  14 +
  15 +/**
  16 + * ERP 收款单项 Mapper
  17 + *
  18 + * @author 芋道源码
  19 + */
  20 +@Mapper
  21 +public interface ErpFinanceReceiptItemMapper extends BaseMapperX<ErpFinanceReceiptItemDO> {
  22 +
  23 + default List<ErpFinanceReceiptItemDO> selectListByReceiptId(Long receiptId) {
  24 + return selectList(ErpFinanceReceiptItemDO::getReceiptId, receiptId);
  25 + }
  26 +
  27 + default List<ErpFinanceReceiptItemDO> selectListByReceiptIds(Collection<Long> receiptIds) {
  28 + return selectList(ErpFinanceReceiptItemDO::getReceiptId, receiptIds);
  29 + }
  30 +
  31 + default BigDecimal selectReceiptPriceSumByBizIdAndBizType(Long bizId, Integer bizType) {
  32 + // SQL sum 查询
  33 + List<Map<String, Object>> result = selectMaps(new QueryWrapper<ErpFinanceReceiptItemDO>()
  34 + .select("SUM(receipt_price) AS receiptPriceSum")
  35 + .eq("biz_id", bizId)
  36 + .eq("biz_type", bizType));
  37 + // 获得数量
  38 + if (CollUtil.isEmpty(result)) {
  39 + return BigDecimal.ZERO;
  40 + }
  41 + return BigDecimal.valueOf(MapUtil.getDouble(result.get(0), "receiptPriceSum", 0D));
  42 + }
  43 +
  44 +}
0 45 \ No newline at end of file
... ...
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpFinanceReceiptMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.erp.dal.mysql.finance;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  5 +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX;
  6 +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.receipt.ErpFinanceReceiptPageReqVO;
  7 +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinanceReceiptDO;
  8 +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinanceReceiptItemDO;
  9 +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
  10 +import org.apache.ibatis.annotations.Mapper;
  11 +
  12 +/**
  13 + * ERP 收款单 Mapper
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Mapper
  18 +public interface ErpFinanceReceiptMapper extends BaseMapperX<ErpFinanceReceiptDO> {
  19 +
  20 + default PageResult<ErpFinanceReceiptDO> selectPage(ErpFinanceReceiptPageReqVO reqVO) {
  21 + MPJLambdaWrapperX<ErpFinanceReceiptDO> query = new MPJLambdaWrapperX<ErpFinanceReceiptDO>()
  22 + .likeIfPresent(ErpFinanceReceiptDO::getNo, reqVO.getNo())
  23 + .betweenIfPresent(ErpFinanceReceiptDO::getReceiptTime, reqVO.getReceiptTime())
  24 + .eqIfPresent(ErpFinanceReceiptDO::getCustomerId, reqVO.getCustomerId())
  25 + .eqIfPresent(ErpFinanceReceiptDO::getCreator, reqVO.getCreator())
  26 + .eqIfPresent(ErpFinanceReceiptDO::getFinanceUserId, reqVO.getFinanceUserId())
  27 + .eqIfPresent(ErpFinanceReceiptDO::getAccountId, reqVO.getAccountId())
  28 + .eqIfPresent(ErpFinanceReceiptDO::getStatus, reqVO.getStatus())
  29 + .likeIfPresent(ErpFinanceReceiptDO::getRemark, reqVO.getRemark())
  30 + .orderByDesc(ErpFinanceReceiptDO::getId);
  31 + if (reqVO.getBizNo() != null) {
  32 + query.leftJoin(ErpFinanceReceiptItemDO.class, ErpFinanceReceiptItemDO::getReceiptId, ErpFinanceReceiptDO::getId)
  33 + .eq(reqVO.getBizNo() != null, ErpFinanceReceiptItemDO::getBizNo, reqVO.getBizNo())
  34 + .groupBy(ErpFinanceReceiptDO::getId); // 避免 1 对多查询,产生相同的 1
  35 + }
  36 + return selectJoinPage(reqVO, ErpFinanceReceiptDO.class, query);
  37 + }
  38 +
  39 + default int updateByIdAndStatus(Long id, Integer status, ErpFinanceReceiptDO updateObj) {
  40 + return update(updateObj, new LambdaUpdateWrapper<ErpFinanceReceiptDO>()
  41 + .eq(ErpFinanceReceiptDO::getId, id).eq(ErpFinanceReceiptDO::getStatus, status));
  42 + }
  43 +
  44 + default ErpFinanceReceiptDO selectByNo(String no) {
  45 + return selectOne(ErpFinanceReceiptDO::getNo, no);
  46 + }
  47 +
  48 +}
0 49 \ No newline at end of file
... ...
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java
... ... @@ -68,6 +68,10 @@ public class ErpNoRedisDAO {
68 68 * 付款单 {@link cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinancePaymentDO}
69 69 */
70 70 public static final String FINANCE_PAYMENT_NO_PREFIX = "FKD";
  71 + /**
  72 + * 收款单 {@link cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinanceReceiptDO}
  73 + */
  74 + public static final String FINANCE_RECEIPT_NO_PREFIX = "SKD";
71 75  
72 76 @Resource
73 77 private StringRedisTemplate stringRedisTemplate;
... ...
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/finance/ErpFinanceReceiptService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.erp.service.finance;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.receipt.ErpFinanceReceiptPageReqVO;
  5 +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.receipt.ErpFinanceReceiptSaveReqVO;
  6 +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinanceReceiptDO;
  7 +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinanceReceiptItemDO;
  8 +import jakarta.validation.Valid;
  9 +
  10 +import java.util.Collection;
  11 +import java.util.List;
  12 +
  13 +/**
  14 + * ERP 收款单 Service 接口
  15 + *
  16 + * @author 芋道源码
  17 + */
  18 +public interface ErpFinanceReceiptService {
  19 +
  20 + /**
  21 + * 创建收款单
  22 + *
  23 + * @param createReqVO 创建信息
  24 + * @return 编号
  25 + */
  26 + Long createFinanceReceipt(@Valid ErpFinanceReceiptSaveReqVO createReqVO);
  27 +
  28 + /**
  29 + * 更新收款单
  30 + *
  31 + * @param updateReqVO 更新信息
  32 + */
  33 + void updateFinanceReceipt(@Valid ErpFinanceReceiptSaveReqVO updateReqVO);
  34 +
  35 + /**
  36 + * 更新收款单的状态
  37 + *
  38 + * @param id 编号
  39 + * @param status 状态
  40 + */
  41 + void updateFinanceReceiptStatus(Long id, Integer status);
  42 +
  43 + /**
  44 + * 删除收款单
  45 + *
  46 + * @param ids 编号数组
  47 + */
  48 + void deleteFinanceReceipt(List<Long> ids);
  49 +
  50 + /**
  51 + * 获得收款单
  52 + *
  53 + * @param id 编号
  54 + * @return 收款单
  55 + */
  56 + ErpFinanceReceiptDO getFinanceReceipt(Long id);
  57 +
  58 + /**
  59 + * 获得收款单分页
  60 + *
  61 + * @param pageReqVO 分页查询
  62 + * @return 收款单分页
  63 + */
  64 + PageResult<ErpFinanceReceiptDO> getFinanceReceiptPage(ErpFinanceReceiptPageReqVO pageReqVO);
  65 +
  66 + // ==================== 收款单项 ====================
  67 +
  68 + /**
  69 + * 获得收款单项列表
  70 + *
  71 + * @param receiptId 收款单编号
  72 + * @return 收款单项列表
  73 + */
  74 + List<ErpFinanceReceiptItemDO> getFinanceReceiptItemListByReceiptId(Long receiptId);
  75 +
  76 + /**
  77 + * 获得收款单项 List
  78 + *
  79 + * @param receiptIds 收款单编号数组
  80 + * @return 收款单项 List
  81 + */
  82 + List<ErpFinanceReceiptItemDO> getFinanceReceiptItemListByReceiptIds(Collection<Long> receiptIds);
  83 +
  84 +}
0 85 \ No newline at end of file
... ...
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/finance/ErpFinanceReceiptServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.erp.service.finance;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.lang.Assert;
  5 +import cn.hutool.core.util.ObjectUtil;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  7 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  8 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  9 +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.receipt.ErpFinanceReceiptPageReqVO;
  10 +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.receipt.ErpFinanceReceiptSaveReqVO;
  11 +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinanceReceiptDO;
  12 +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinanceReceiptItemDO;
  13 +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutDO;
  14 +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleReturnDO;
  15 +import cn.iocoder.yudao.module.erp.dal.mysql.finance.ErpFinanceReceiptItemMapper;
  16 +import cn.iocoder.yudao.module.erp.dal.mysql.finance.ErpFinanceReceiptMapper;
  17 +import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO;
  18 +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus;
  19 +import cn.iocoder.yudao.module.erp.enums.common.ErpBizTypeEnum;
  20 +import cn.iocoder.yudao.module.erp.service.sale.ErpCustomerService;
  21 +import cn.iocoder.yudao.module.erp.service.sale.ErpSaleOutService;
  22 +import cn.iocoder.yudao.module.erp.service.sale.ErpSaleReturnService;
  23 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
  24 +import jakarta.annotation.Resource;
  25 +import org.springframework.stereotype.Service;
  26 +import org.springframework.transaction.annotation.Transactional;
  27 +import org.springframework.validation.annotation.Validated;
  28 +
  29 +import java.math.BigDecimal;
  30 +import java.util.Collection;
  31 +import java.util.Collections;
  32 +import java.util.List;
  33 +
  34 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  35 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
  36 +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*;
  37 +
  38 +// TODO 芋艿:记录操作日志
  39 +
  40 +/**
  41 + * ERP 收款单 Service 实现类
  42 + *
  43 + * @author 芋道源码
  44 + */
  45 +@Service
  46 +@Validated
  47 +public class ErpFinanceReceiptServiceImpl implements ErpFinanceReceiptService {
  48 +
  49 + @Resource
  50 + private ErpFinanceReceiptMapper financeReceiptMapper;
  51 + @Resource
  52 + private ErpFinanceReceiptItemMapper financeReceiptItemMapper;
  53 +
  54 + @Resource
  55 + private ErpNoRedisDAO noRedisDAO;
  56 +
  57 + @Resource
  58 + private ErpCustomerService customerService;
  59 + @Resource
  60 + private ErpAccountService accountService;
  61 + @Resource
  62 + private ErpSaleOutService saleOutService;
  63 + @Resource
  64 + private ErpSaleReturnService saleReturnService;
  65 +
  66 + @Resource
  67 + private AdminUserApi adminUserApi;
  68 +
  69 + @Override
  70 + @Transactional(rollbackFor = Exception.class)
  71 + public Long createFinanceReceipt(ErpFinanceReceiptSaveReqVO createReqVO) {
  72 + // 1.1 校验订单项的有效性
  73 + List<ErpFinanceReceiptItemDO> receiptItems = validateFinanceReceiptItems(
  74 + createReqVO.getCustomerId(), createReqVO.getItems());
  75 + // 1.2 校验客户
  76 + customerService.validateCustomer(createReqVO.getCustomerId());
  77 + // 1.3 校验结算账户
  78 + if (createReqVO.getAccountId() != null) {
  79 + accountService.validateAccount(createReqVO.getAccountId());
  80 + }
  81 + // 1.4 校验财务人员
  82 + if (createReqVO.getFinanceUserId() != null) {
  83 + adminUserApi.validateUser(createReqVO.getFinanceUserId());
  84 + }
  85 + // 1.5 生成收款单号,并校验唯一性
  86 + String no = noRedisDAO.generate(ErpNoRedisDAO.FINANCE_RECEIPT_NO_PREFIX);
  87 + if (financeReceiptMapper.selectByNo(no) != null) {
  88 + throw exception(FINANCE_RECEIPT_NO_EXISTS);
  89 + }
  90 +
  91 + // 2.1 插入收款单
  92 + ErpFinanceReceiptDO receipt = BeanUtils.toBean(createReqVO, ErpFinanceReceiptDO.class, in -> in
  93 + .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus()));
  94 + calculateTotalPrice(receipt, receiptItems);
  95 + financeReceiptMapper.insert(receipt);
  96 + // 2.2 插入收款单项
  97 + receiptItems.forEach(o -> o.setReceiptId(receipt.getId()));
  98 + financeReceiptItemMapper.insertBatch(receiptItems);
  99 + return receipt.getId();
  100 + }
  101 +
  102 + @Override
  103 + @Transactional(rollbackFor = Exception.class)
  104 + public void updateFinanceReceipt(ErpFinanceReceiptSaveReqVO updateReqVO) {
  105 + // 1.1 校验存在
  106 + ErpFinanceReceiptDO receipt = validateFinanceReceiptExists(updateReqVO.getId());
  107 + if (ErpAuditStatus.APPROVE.getStatus().equals(receipt.getStatus())) {
  108 + throw exception(FINANCE_RECEIPT_UPDATE_FAIL_APPROVE, receipt.getNo());
  109 + }
  110 + // 1.2 校验客户
  111 + customerService.validateCustomer(updateReqVO.getCustomerId());
  112 + // 1.3 校验结算账户
  113 + if (updateReqVO.getAccountId() != null) {
  114 + accountService.validateAccount(updateReqVO.getAccountId());
  115 + }
  116 + // 1.4 校验财务人员
  117 + if (updateReqVO.getFinanceUserId() != null) {
  118 + adminUserApi.validateUser(updateReqVO.getFinanceUserId());
  119 + }
  120 + // 1.5 校验收款单项的有效性
  121 + List<ErpFinanceReceiptItemDO> receiptItems = validateFinanceReceiptItems(
  122 + updateReqVO.getCustomerId(), updateReqVO.getItems());
  123 +
  124 + // 2.1 更新收款单
  125 + ErpFinanceReceiptDO updateObj = BeanUtils.toBean(updateReqVO, ErpFinanceReceiptDO.class);
  126 + calculateTotalPrice(updateObj, receiptItems);
  127 + financeReceiptMapper.updateById(updateObj);
  128 + // 2.2 更新收款单项
  129 + updateFinanceReceiptItemList(updateReqVO.getId(), receiptItems);
  130 +
  131 + // 3. 更新销售出库、退货的收款金额情况
  132 + updateSalePrice(receiptItems);
  133 + }
  134 +
  135 + private void calculateTotalPrice(ErpFinanceReceiptDO receipt, List<ErpFinanceReceiptItemDO> receiptItems) {
  136 + receipt.setTotalPrice(getSumValue(receiptItems, ErpFinanceReceiptItemDO::getReceiptPrice, BigDecimal::add, BigDecimal.ZERO));
  137 + receipt.setReceiptPrice(receipt.getTotalPrice().subtract(receipt.getDiscountPrice()));
  138 + }
  139 +
  140 + @Override
  141 + @Transactional(rollbackFor = Exception.class)
  142 + public void updateFinanceReceiptStatus(Long id, Integer status) {
  143 + boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status);
  144 + // 1.1 校验存在
  145 + ErpFinanceReceiptDO receipt = validateFinanceReceiptExists(id);
  146 + // 1.2 校验状态
  147 + if (receipt.getStatus().equals(status)) {
  148 + throw exception(approve ? FINANCE_RECEIPT_APPROVE_FAIL : FINANCE_RECEIPT_PROCESS_FAIL);
  149 + }
  150 +
  151 + // 2. 更新状态
  152 + int updateCount = financeReceiptMapper.updateByIdAndStatus(id, receipt.getStatus(),
  153 + new ErpFinanceReceiptDO().setStatus(status));
  154 + if (updateCount == 0) {
  155 + throw exception(approve ? FINANCE_RECEIPT_APPROVE_FAIL : FINANCE_RECEIPT_PROCESS_FAIL);
  156 + }
  157 + }
  158 +
  159 + private List<ErpFinanceReceiptItemDO> validateFinanceReceiptItems(
  160 + Long customerId,
  161 + List<ErpFinanceReceiptSaveReqVO.Item> list) {
  162 + return convertList(list, o -> BeanUtils.toBean(o, ErpFinanceReceiptItemDO.class, item -> {
  163 + if (ObjectUtil.equal(item.getBizType(), ErpBizTypeEnum.SALE_OUT.getType())) {
  164 + ErpSaleOutDO saleOut = saleOutService.validateSaleOut(item.getBizId());
  165 + Assert.equals(saleOut.getCustomerId(), customerId, "客户必须相同");
  166 + item.setTotalPrice(saleOut.getTotalPrice()).setBizNo(saleOut.getNo());
  167 + } else if (ObjectUtil.equal(item.getBizType(), ErpBizTypeEnum.SALE_RETURN.getType())) {
  168 + ErpSaleReturnDO saleReturn = saleReturnService.validateSaleReturn(item.getBizId());
  169 + Assert.equals(saleReturn.getCustomerId(), customerId, "客户必须相同");
  170 + item.setTotalPrice(saleReturn.getTotalPrice().negate()).setBizNo(saleReturn.getNo());
  171 + } else {
  172 + throw new IllegalArgumentException("业务类型不正确:" + item.getBizType());
  173 + }
  174 + }));
  175 + }
  176 +
  177 + private void updateFinanceReceiptItemList(Long id, List<ErpFinanceReceiptItemDO> newList) {
  178 + // 第一步,对比新老数据,获得添加、修改、删除的列表
  179 + List<ErpFinanceReceiptItemDO> oldList = financeReceiptItemMapper.selectListByReceiptId(id);
  180 + List<List<ErpFinanceReceiptItemDO>> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录
  181 + (oldVal, newVal) -> oldVal.getId().equals(newVal.getId()));
  182 +
  183 + // 第二步,批量添加、修改、删除
  184 + if (CollUtil.isNotEmpty(diffList.get(0))) {
  185 + diffList.get(0).forEach(o -> o.setReceiptId(id));
  186 + financeReceiptItemMapper.insertBatch(diffList.get(0));
  187 + }
  188 + if (CollUtil.isNotEmpty(diffList.get(1))) {
  189 + financeReceiptItemMapper.updateBatch(diffList.get(1));
  190 + }
  191 + if (CollUtil.isNotEmpty(diffList.get(2))) {
  192 + financeReceiptItemMapper.deleteBatchIds(convertList(diffList.get(2), ErpFinanceReceiptItemDO::getId));
  193 + }
  194 +
  195 + // 第三步,更新销售出库、退货的收款金额情况
  196 + updateSalePrice(CollectionUtils.newArrayList(diffList));
  197 + }
  198 +
  199 + private void updateSalePrice(List<ErpFinanceReceiptItemDO> receiptItems) {
  200 + receiptItems.forEach(receiptItem -> {
  201 + BigDecimal totalReceiptPrice = financeReceiptItemMapper.selectReceiptPriceSumByBizIdAndBizType(
  202 + receiptItem.getBizId(), receiptItem.getBizType());
  203 + if (ErpBizTypeEnum.SALE_OUT.getType().equals(receiptItem.getBizType())) {
  204 + saleOutService.updateSaleInReceiptPrice(receiptItem.getBizId(), totalReceiptPrice);
  205 + } else if (ErpBizTypeEnum.SALE_RETURN.getType().equals(receiptItem.getBizType())) {
  206 + saleReturnService.updateSaleReturnRefundPrice(receiptItem.getBizId(), totalReceiptPrice.negate());
  207 + } else {
  208 + throw new IllegalArgumentException("业务类型不正确:" + receiptItem.getBizType());
  209 + }
  210 + });
  211 + }
  212 +
  213 + @Override
  214 + @Transactional(rollbackFor = Exception.class)
  215 + public void deleteFinanceReceipt(List<Long> ids) {
  216 + // 1. 校验不处于已审批
  217 + List<ErpFinanceReceiptDO> receipts = financeReceiptMapper.selectBatchIds(ids);
  218 + if (CollUtil.isEmpty(receipts)) {
  219 + return;
  220 + }
  221 + receipts.forEach(receipt -> {
  222 + if (ErpAuditStatus.APPROVE.getStatus().equals(receipt.getStatus())) {
  223 + throw exception(FINANCE_RECEIPT_DELETE_FAIL_APPROVE, receipt.getNo());
  224 + }
  225 + });
  226 +
  227 + // 2. 遍历删除,并记录操作日志
  228 + receipts.forEach(receipt -> {
  229 + // 2.1 删除收款单
  230 + financeReceiptMapper.deleteById(receipt.getId());
  231 + // 2.2 删除收款单项
  232 + List<ErpFinanceReceiptItemDO> receiptItems = financeReceiptItemMapper.selectListByReceiptId(receipt.getId());
  233 + financeReceiptItemMapper.deleteBatchIds(convertSet(receiptItems, ErpFinanceReceiptItemDO::getId));
  234 +
  235 + // 2.3 更新销售出库、退货的收款金额情况
  236 + updateSalePrice(receiptItems);
  237 + });
  238 + }
  239 +
  240 + private ErpFinanceReceiptDO validateFinanceReceiptExists(Long id) {
  241 + ErpFinanceReceiptDO receipt = financeReceiptMapper.selectById(id);
  242 + if (receipt == null) {
  243 + throw exception(FINANCE_RECEIPT_NOT_EXISTS);
  244 + }
  245 + return receipt;
  246 + }
  247 +
  248 + @Override
  249 + public ErpFinanceReceiptDO getFinanceReceipt(Long id) {
  250 + return financeReceiptMapper.selectById(id);
  251 + }
  252 +
  253 + @Override
  254 + public PageResult<ErpFinanceReceiptDO> getFinanceReceiptPage(ErpFinanceReceiptPageReqVO pageReqVO) {
  255 + return financeReceiptMapper.selectPage(pageReqVO);
  256 + }
  257 +
  258 + // ==================== 收款单项 ====================
  259 +
  260 + @Override
  261 + public List<ErpFinanceReceiptItemDO> getFinanceReceiptItemListByReceiptId(Long receiptId) {
  262 + return financeReceiptItemMapper.selectListByReceiptId(receiptId);
  263 + }
  264 +
  265 + @Override
  266 + public List<ErpFinanceReceiptItemDO> getFinanceReceiptItemListByReceiptIds(Collection<Long> receiptIds) {
  267 + if (CollUtil.isEmpty(receiptIds)) {
  268 + return Collections.emptyList();
  269 + }
  270 + return financeReceiptItemMapper.selectListByReceiptIds(receiptIds);
  271 + }
  272 +
  273 +}
0 274 \ No newline at end of file
... ...
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseInServiceImpl.java
... ... @@ -194,7 +194,7 @@ public class ErpPurchaseInServiceImpl implements ErpPurchaseInService {
194 194 return;
195 195 }
196 196 if (paymentPrice.compareTo(purchaseIn.getTotalPrice()) > 0) {
197   - throw exception(PURCHASE_IN_FAIL_PAYMENT_PRICE_EXCEED, purchaseIn.getTotalPrice(), paymentPrice);
  197 + throw exception(PURCHASE_IN_FAIL_PAYMENT_PRICE_EXCEED, paymentPrice, purchaseIn.getTotalPrice());
198 198 }
199 199 purchaseInMapper.updateById(new ErpPurchaseInDO().setId(id).setPaymentPrice(paymentPrice));
200 200 }
... ...
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseReturnServiceImpl.java
... ... @@ -190,7 +190,7 @@ public class ErpPurchaseReturnServiceImpl implements ErpPurchaseReturnService {
190 190 return;
191 191 }
192 192 if (refundPrice.compareTo(purchaseReturn.getTotalPrice()) > 0) {
193   - throw exception(PURCHASE_RETURN_FAIL_REFUND_PRICE_EXCEED, purchaseReturn.getTotalPrice(), refundPrice);
  193 + throw exception(PURCHASE_RETURN_FAIL_REFUND_PRICE_EXCEED, refundPrice, purchaseReturn.getTotalPrice());
194 194 }
195 195 purchaseReturnMapper.updateById(new ErpPurchaseReturnDO().setId(id).setRefundPrice(refundPrice));
196 196 }
... ...
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOutService.java
... ... @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutDO;
7 7 import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutItemDO;
8 8 import jakarta.validation.Valid;
9 9  
  10 +import java.math.BigDecimal;
10 11 import java.util.Collection;
11 12 import java.util.List;
12 13  
... ... @@ -41,6 +42,14 @@ public interface ErpSaleOutService {
41 42 void updateSaleOutStatus(Long id, Integer status);
42 43  
43 44 /**
  45 + * 更新销售出库的收款金额
  46 + *
  47 + * @param id 编号
  48 + * @param receiptPrice 收款金额
  49 + */
  50 + void updateSaleInReceiptPrice(Long id, BigDecimal receiptPrice);
  51 +
  52 + /**
44 53 * 删除销售出库
45 54 *
46 55 * @param ids 编号数组
... ... @@ -56,6 +65,14 @@ public interface ErpSaleOutService {
56 65 ErpSaleOutDO getSaleOut(Long id);
57 66  
58 67 /**
  68 + * 校验销售出库,已经审核通过
  69 + *
  70 + * @param id 编号
  71 + * @return 销售出库
  72 + */
  73 + ErpSaleOutDO validateSaleOut(Long id);
  74 +
  75 + /**
59 76 * 获得销售出库分页
60 77 *
61 78 * @param pageReqVO 分页查询
... ... @@ -81,4 +98,5 @@ public interface ErpSaleOutService {
81 98 */
82 99 List<ErpSaleOutItemDO> getSaleOutItemListByOutIds(Collection<Long> outIds);
83 100  
  101 +
84 102 }
85 103 \ No newline at end of file
... ...
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOutServiceImpl.java
... ... @@ -171,6 +171,10 @@ public class ErpSaleOutServiceImpl implements ErpSaleOutService {
171 171 if (saleOut.getStatus().equals(status)) {
172 172 throw exception(approve ? SALE_OUT_APPROVE_FAIL : SALE_OUT_PROCESS_FAIL);
173 173 }
  174 + // 1.3 校验已退款
  175 + if (approve && saleOut.getReceiptPrice().compareTo(BigDecimal.ZERO) > 0) {
  176 + throw exception(SALE_OUT_PROCESS_FAIL_EXISTS_RECEIPT);
  177 + }
174 178  
175 179 // 2. 更新状态
176 180 int updateCount = saleOutMapper.updateByIdAndStatus(id, saleOut.getStatus(),
... ... @@ -191,6 +195,18 @@ public class ErpSaleOutServiceImpl implements ErpSaleOutService {
191 195 });
192 196 }
193 197  
  198 + @Override
  199 + public void updateSaleInReceiptPrice(Long id, BigDecimal receiptPrice) {
  200 + ErpSaleOutDO saleOut = saleOutMapper.selectById(id);
  201 + if (saleOut.getReceiptPrice().equals(receiptPrice)) {
  202 + return;
  203 + }
  204 + if (receiptPrice.compareTo(saleOut.getTotalPrice()) > 0) {
  205 + throw exception(SALE_OUT_FAIL_RECEIPT_PRICE_EXCEED, receiptPrice, saleOut.getTotalPrice());
  206 + }
  207 + saleOutMapper.updateById(new ErpSaleOutDO().setId(id).setReceiptPrice(receiptPrice));
  208 + }
  209 +
194 210 private List<ErpSaleOutItemDO> validateSaleOutItems(List<ErpSaleOutSaveReqVO.Item> list) {
195 211 // 1. 校验产品存在
196 212 List<ErpProductDO> productList = productService.validProductList(
... ... @@ -269,6 +285,15 @@ public class ErpSaleOutServiceImpl implements ErpSaleOutService {
269 285 }
270 286  
271 287 @Override
  288 + public ErpSaleOutDO validateSaleOut(Long id) {
  289 + ErpSaleOutDO saleOut = validateSaleOut(id);
  290 + if (ObjectUtil.notEqual(saleOut.getStatus(), ErpAuditStatus.APPROVE.getStatus())) {
  291 + throw exception(SALE_OUT_NOT_APPROVE);
  292 + }
  293 + return saleOut;
  294 + }
  295 +
  296 + @Override
272 297 public PageResult<ErpSaleOutDO> getSaleOutPage(ErpSaleOutPageReqVO pageReqVO) {
273 298 return saleOutMapper.selectPage(pageReqVO);
274 299 }
... ...
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleReturnService.java
... ... @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleReturnDO;
7 7 import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleReturnItemDO;
8 8 import jakarta.validation.Valid;
9 9  
  10 +import java.math.BigDecimal;
10 11 import java.util.Collection;
11 12 import java.util.List;
12 13  
... ... @@ -41,6 +42,14 @@ public interface ErpSaleReturnService {
41 42 void updateSaleReturnStatus(Long id, Integer status);
42 43  
43 44 /**
  45 + * 更新销售退货的退款金额
  46 + *
  47 + * @param id 编号
  48 + * @param refundPrice 退款金额
  49 + */
  50 + void updateSaleReturnRefundPrice(Long id, BigDecimal refundPrice);
  51 +
  52 + /**
44 53 * 删除销售退货
45 54 *
46 55 * @param ids 编号数组
... ... @@ -56,6 +65,14 @@ public interface ErpSaleReturnService {
56 65 ErpSaleReturnDO getSaleReturn(Long id);
57 66  
58 67 /**
  68 + * 校验销售退货,已经审核通过
  69 + *
  70 + * @param id 编号
  71 + * @return 销售退货
  72 + */
  73 + ErpSaleReturnDO validateSaleReturn(Long id);
  74 +
  75 + /**
59 76 * 获得销售退货分页
60 77 *
61 78 * @param pageReqVO 分页查询
... ...
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleReturnServiceImpl.java
... ... @@ -171,6 +171,10 @@ public class ErpSaleReturnServiceImpl implements ErpSaleReturnService {
171 171 if (saleReturn.getStatus().equals(status)) {
172 172 throw exception(approve ? SALE_RETURN_APPROVE_FAIL : SALE_RETURN_PROCESS_FAIL);
173 173 }
  174 + // 1.3 校验已退款
  175 + if (approve && saleReturn.getRefundPrice().compareTo(BigDecimal.ZERO) > 0) {
  176 + throw exception(SALE_RETURN_PROCESS_FAIL_EXISTS_REFUND);
  177 + }
174 178  
175 179 // 2. 更新状态
176 180 int updateCount = saleReturnMapper.updateByIdAndStatus(id, saleReturn.getStatus(),
... ... @@ -191,6 +195,18 @@ public class ErpSaleReturnServiceImpl implements ErpSaleReturnService {
191 195 });
192 196 }
193 197  
  198 + @Override
  199 + public void updateSaleReturnRefundPrice(Long id, BigDecimal refundPrice) {
  200 + ErpSaleReturnDO saleReturn = saleReturnMapper.selectById(id);
  201 + if (saleReturn.getRefundPrice().equals(refundPrice)) {
  202 + return;
  203 + }
  204 + if (refundPrice.compareTo(saleReturn.getTotalPrice()) > 0) {
  205 + throw exception(SALE_RETURN_FAIL_REFUND_PRICE_EXCEED, refundPrice, saleReturn.getTotalPrice());
  206 + }
  207 + saleReturnMapper.updateById(new ErpSaleReturnDO().setId(id).setRefundPrice(refundPrice));
  208 + }
  209 +
194 210 private List<ErpSaleReturnItemDO> validateSaleReturnItems(List<ErpSaleReturnSaveReqVO.Item> list) {
195 211 // 1. 校验产品存在
196 212 List<ErpProductDO> productList = productService.validProductList(
... ... @@ -269,6 +285,15 @@ public class ErpSaleReturnServiceImpl implements ErpSaleReturnService {
269 285 }
270 286  
271 287 @Override
  288 + public ErpSaleReturnDO validateSaleReturn(Long id) {
  289 + ErpSaleReturnDO saleReturn = validateSaleReturnExists(id);
  290 + if (ObjectUtil.notEqual(saleReturn.getStatus(), ErpAuditStatus.APPROVE.getStatus())) {
  291 + throw exception(SALE_RETURN_NOT_APPROVE);
  292 + }
  293 + return saleReturn;
  294 + }
  295 +
  296 + @Override
272 297 public PageResult<ErpSaleReturnDO> getSaleReturnPage(ErpSaleReturnPageReqVO pageReqVO) {
273 298 return saleReturnMapper.selectPage(pageReqVO);
274 299 }
... ...