{"record":{"id":"913f12653d363520","repo":"YunaiV/yudao-cloud","slug":"error-913f12","errorCode":null,"errorMessage":"业务类型不正确：{}","messagePattern":"业务类型不正确：(.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":500,"severity":"error","filePath":"yudao-module-erp/yudao-module-erp-server/src/main/java/cn/iocoder/yudao/module/erp/service/finance/ErpFinanceReceiptServiceImpl.java","lineNumber":172,"sourceCode":"        if (updateCount == 0) {\n            throw exception(approve ? FINANCE_RECEIPT_APPROVE_FAIL : FINANCE_RECEIPT_PROCESS_FAIL);\n        }\n    }\n\n    private List<ErpFinanceReceiptItemDO> validateFinanceReceiptItems(\n            Long customerId,\n            List<ErpFinanceReceiptSaveReqVO.Item> list) {\n        return convertList(list, o -> BeanUtils.toBean(o, ErpFinanceReceiptItemDO.class, item -> {\n            if (ObjectUtil.equal(item.getBizType(), ErpBizTypeEnum.SALE_OUT.getType())) {\n                ErpSaleOutDO saleOut = saleOutService.validateSaleOut(item.getBizId());\n                Assert.equals(saleOut.getCustomerId(), customerId, \"客户必须相同\");\n                item.setTotalPrice(saleOut.getTotalPrice()).setBizNo(saleOut.getNo());\n            } else if (ObjectUtil.equal(item.getBizType(), ErpBizTypeEnum.SALE_RETURN.getType())) {\n                ErpSaleReturnDO saleReturn = saleReturnService.validateSaleReturn(item.getBizId());\n                Assert.equals(saleReturn.getCustomerId(), customerId, \"客户必须相同\");\n                item.setTotalPrice(saleReturn.getTotalPrice().negate()).setBizNo(saleReturn.getNo());\n            } else {\n                throw new IllegalArgumentException(\"业务类型不正确：\" + item.getBizType());\n            }\n        }));\n    }\n\n    private void updateFinanceReceiptItemList(Long id, List<ErpFinanceReceiptItemDO> newList) {\n        // 第一步，对比新老数据，获得添加、修改、删除的列表\n        List<ErpFinanceReceiptItemDO> oldList = financeReceiptItemMapper.selectListByReceiptId(id);\n        List<List<ErpFinanceReceiptItemDO>> diffList = diffList(oldList, newList, // id 不同，就认为是不同的记录\n                (oldVal, newVal) -> oldVal.getId().equals(newVal.getId()));\n\n        // 第二步，批量添加、修改、删除\n        if (CollUtil.isNotEmpty(diffList.get(0))) {\n            diffList.get(0).forEach(o -> o.setReceiptId(id));\n            financeReceiptItemMapper.insertBatch(diffList.get(0));\n        }\n        if (CollUtil.isNotEmpty(diffList.get(1))) {\n            financeReceiptItemMapper.updateBatch(diffList.get(1));\n        }","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/YunaiV/yudao-cloud/blob/477be9dd49ab7223a972a6abdff0684d6423dec3/yudao-module-erp/yudao-module-erp-server/src/main/java/cn/iocoder/yudao/module/erp/service/finance/ErpFinanceReceiptServiceImpl.java#L154-L190","documentation":"Mirror of the payment case: ErpFinanceReceiptServiceImpl throws IllegalArgumentException when a receipt (收款单) item's bizType is neither SALE_OUT (销售出库) nor SALE_RETURN (销售退货). Valid items are enriched from the validated sale document's totalPrice (negated for returns) and the customerId must equal the header customer via Assert.","triggerScenarios":"POST/PUT of a finance receipt whose items[] include bizType PURCHASE_IN/PURCHASE_RETURN — purchase documents belong to payments; bizType null/0 from an incomplete form; caller swapping payment and receipt payloads.","commonSituations":"Shared item-picker component emitting purchase types on the receipt screen; import scripts mapping doc kinds to the wrong finance type; guessing bizType numbering instead of ErpBizTypeEnum.","solutions":["Use only ErpBizTypeEnum.SALE_OUT or SALE_RETURN as bizType in receipt items","Use the finance payment (付款单) API for purchase-side documents (PURCHASE_IN / PURCHASE_RETURN)","Validate bizType per item in the frontend before submit"],"exampleFix":"// before: purchase doc in a receipt\n{\"customerId\":1,\"items\":[{\"bizType\":1,\"bizId\":201}]} // PURCHASE_IN -> throws\n\n// after\n{\"customerId\":1,\"items\":[{\"bizType\":3,\"bizId\":201}]} // SALE_OUT; purchase docs go to /erp/finance-payment","handlingStrategy":"validation","validationCode":"for (var item : reqVO.getItems()) {\n    Integer t = item.getBizType();\n    if (!Objects.equals(t, ErpBizTypeEnum.SALE_OUT.getType())\n     && !Objects.equals(t, ErpBizTypeEnum.SALE_RETURN.getType())) {\n        throw new IllegalArgumentException(\"收款单明细 bizType 必须为 销售出库/销售退货\");\n    }\n}","typeGuard":"boolean isReceiptBizType(Integer bizType) {\n    return Objects.equals(bizType, ErpBizTypeEnum.SALE_OUT.getType())\n        || Objects.equals(bizType, ErpBizTypeEnum.SALE_RETURN.getType());\n}","tryCatchPattern":null,"preventionTips":["Restrict the receipt form's document picker to sale out / sale return","Add a bean-validation rule on the items field for bizType membership","Keep receipt and payment item DTOs separate so they cannot be swapped"],"tags":["erp","finance","receipt","biz-type","validation"],"backgroundTag":null,"analyzedSha":"477be9dd49ab7223a972a6abdff0684d6423dec3","analyzedAt":"2026-08-14T13:35:31.121Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}