{"record":{"id":"6c2e425415eb9255","repo":"YunaiV/yudao-cloud","slug":"error-6c2e42","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/ErpFinancePaymentServiceImpl.java","lineNumber":172,"sourceCode":"        if (updateCount == 0) {\n            throw exception(approve ? FINANCE_PAYMENT_APPROVE_FAIL : FINANCE_PAYMENT_PROCESS_FAIL);\n        }\n    }\n\n    private List<ErpFinancePaymentItemDO> validateFinancePaymentItems(\n            Long supplierId,\n            List<ErpFinancePaymentSaveReqVO.Item> list) {\n        return convertList(list, o -> BeanUtils.toBean(o, ErpFinancePaymentItemDO.class, item -> {\n            if (ObjectUtil.equal(item.getBizType(), ErpBizTypeEnum.PURCHASE_IN.getType())) {\n                ErpPurchaseInDO purchaseIn = purchaseInService.validatePurchaseIn(item.getBizId());\n                Assert.equals(purchaseIn.getSupplierId(), supplierId, \"供应商必须相同\");\n                item.setTotalPrice(purchaseIn.getTotalPrice()).setBizNo(purchaseIn.getNo());\n            } else if (ObjectUtil.equal(item.getBizType(), ErpBizTypeEnum.PURCHASE_RETURN.getType())) {\n                ErpPurchaseReturnDO purchaseReturn = purchaseReturnService.validatePurchaseReturn(item.getBizId());\n                Assert.equals(purchaseReturn.getSupplierId(), supplierId, \"供应商必须相同\");\n                item.setTotalPrice(purchaseReturn.getTotalPrice().negate()).setBizNo(purchaseReturn.getNo());\n            } else {\n                throw new IllegalArgumentException(\"业务类型不正确：\" + item.getBizType());\n            }\n        }));\n    }\n\n    private void updateFinancePaymentItemList(Long id, List<ErpFinancePaymentItemDO> newList) {\n        // 第一步，对比新老数据，获得添加、修改、删除的列表\n        List<ErpFinancePaymentItemDO> oldList = financePaymentItemMapper.selectListByPaymentId(id);\n        List<List<ErpFinancePaymentItemDO>> 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.setPaymentId(id));\n            financePaymentItemMapper.insertBatch(diffList.get(0));\n        }\n        if (CollUtil.isNotEmpty(diffList.get(1))) {\n            financePaymentItemMapper.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/ErpFinancePaymentServiceImpl.java#L154-L190","documentation":"While building payment (付款单) item DOs, ErpFinancePaymentServiceImpl throws IllegalArgumentException when an item's bizType is neither PURCHASE_IN (采购入库) nor PURCHASE_RETURN (采购退货). A payment slip can only settle those two purchase-side document types; each valid item is enriched with the source document's totalPrice and no via validate + an Assert that the supplierId matches the header supplier.","triggerScenarios":"POST/PUT of a finance payment whose items[] contain bizType like SALE_OUT (3) or SALE_RETURN — sale documents belong to receipts, not payments; bizType null or 0 from a partially filled frontend form; API caller mixing up receipt and payment item payloads.","commonSituations":"Frontend form reusing one item-picker component for both payment and receipt screens; import scripts mapping ERP document kinds to the wrong finance type; client guessing bizType numbering instead of using ErpBizTypeEnum.","solutions":["Use only ErpBizTypeEnum.PURCHASE_IN or PURCHASE_RETURN as bizType in payment items","Use the finance receipt (收款单) API for sale-side documents (SALE_OUT / SALE_RETURN)","Validate each item's bizType and bizId in the frontend before submit"],"exampleFix":"// before: sale doc in a payment\n{\"supplierId\":1,\"items\":[{\"bizType\":3,\"bizId\":101}]} // SALE_OUT -> throws\n\n// after\n{\"supplierId\":1,\"items\":[{\"bizType\":1,\"bizId\":101}]} // PURCHASE_IN; sale docs go to /erp/finance-receipt","handlingStrategy":"validation","validationCode":"for (var item : reqVO.getItems()) {\n    Integer t = item.getBizType();\n    if (!Objects.equals(t, ErpBizTypeEnum.PURCHASE_IN.getType())\n     && !Objects.equals(t, ErpBizTypeEnum.PURCHASE_RETURN.getType())) {\n        throw new IllegalArgumentException(\"付款单明细 bizType 必须为 采购入库/采购退货\");\n    }\n}","typeGuard":"boolean isPaymentBizType(Integer bizType) {\n    return Objects.equals(bizType, ErpBizTypeEnum.PURCHASE_IN.getType())\n        || Objects.equals(bizType, ErpBizTypeEnum.PURCHASE_RETURN.getType());\n}","tryCatchPattern":null,"preventionTips":["Restrict the payment form's document picker to purchase in / purchase return","Centralize the bizType check in the SaveReqVO validator (@AssertTrue on items)","Document the receipt-vs-payment type split in your API docs"],"tags":["erp","finance","payment","biz-type","validation"],"backgroundTag":null,"analyzedSha":"477be9dd49ab7223a972a6abdff0684d6423dec3","analyzedAt":"2026-08-14T13:35:31.121Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}