From eb090572c610b40d8fa7f092b24369ad8fef43e8 Mon Sep 17 00:00:00 2001 From: "hello@lv" <2256334253@qq.com> Date: Tue, 26 Mar 2024 23:09:59 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BB=93=E5=BA=93=E4=BA=8C=E6=9C=9F?= =?UTF-8?q?=EF=BC=8C=E5=87=BA=E5=85=A5=E5=BA=93=E5=8D=95=E6=89=93=E5=8D=B0?= =?UTF-8?q?=E9=A2=84=E8=A7=88=EF=BC=8C=E4=BA=A7=E5=93=81=E8=8C=83=E5=9B=B4?= =?UTF-8?q?=EF=BC=8C=E8=AE=A1=E4=BB=B7=E6=95=B0=E9=87=8F=EF=BC=8C=E6=8D=A2?= =?UTF-8?q?=E7=AE=97=E6=95=B0=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-on: https://git.daoyoucloud.com/daoyoucloud/tachycode/pulls/503 Co-authored-by: hello@lv <2256334253@qq.com> Co-committed-by: hello@lv <2256334253@qq.com> --- .../plugins/@hera/plugin-core/package.json | 4 +- .../plugins/@hera/plugin-rental/package.json | 4 +- .../custom-components/RecordItemCount.tsx | 12 +- .../RecordItemValuationQuantity.tsx | 55 +++- .../custom-components/RecordProductScope.tsx | 127 ++++++-- .../plugin-rental/src/client/hooks/index.tsx | 24 ++ .../pdf-documents/records-documentV2.tsx | 306 ++++++------------ .../src/server/services/record-pdf-service.ts | 132 ++++---- .../src/server/sqls/pdf_record.sql | 13 - 9 files changed, 362 insertions(+), 315 deletions(-) diff --git a/packages/plugins/@hera/plugin-core/package.json b/packages/plugins/@hera/plugin-core/package.json index e53750b03..63afe9bb4 100644 --- a/packages/plugins/@hera/plugin-core/package.json +++ b/packages/plugins/@hera/plugin-core/package.json @@ -1,6 +1,6 @@ { "name": "@hera/plugin-core", - "version": "1.6.1", + "version": "1.6.2", "displayName": "Hera platform", "displayName.zh-CN": "赫拉平台", "description": "Hera platform as nocobase plugin.", @@ -35,4 +35,4 @@ "keywords": [ "System management" ] -} +} \ No newline at end of file diff --git a/packages/plugins/@hera/plugin-rental/package.json b/packages/plugins/@hera/plugin-rental/package.json index 8834b36c1..9a6be2d06 100644 --- a/packages/plugins/@hera/plugin-rental/package.json +++ b/packages/plugins/@hera/plugin-rental/package.json @@ -1,6 +1,6 @@ { "name": "@hera/plugin-rental", - "version": "1.6.2", + "version": "1.6.3", "main": "dist/server/index.js", "displayName": "professional construction materials rental system - customized based on hera", "displayName.zh-CN": "专业建材租赁系统 - 基于赫拉定制", @@ -27,4 +27,4 @@ "keywords": [ "System management" ] -} +} \ No newline at end of file diff --git a/packages/plugins/@hera/plugin-rental/src/client/custom-components/RecordItemCount.tsx b/packages/plugins/@hera/plugin-rental/src/client/custom-components/RecordItemCount.tsx index c9eaa2d7c..d6d26d7a4 100644 --- a/packages/plugins/@hera/plugin-rental/src/client/custom-components/RecordItemCount.tsx +++ b/packages/plugins/@hera/plugin-rental/src/client/custom-components/RecordItemCount.tsx @@ -7,6 +7,8 @@ import { Spin } from 'antd'; import { useCachedRequest } from '../hooks'; export const RecordItemCount = observer((props) => { + const form = useForm(); + const field = useField(); const param = { resource: 'product_category', action: 'list', @@ -15,19 +17,17 @@ export const RecordItemCount = observer((props) => { }, }; const { loading, data } = useCachedRequest(param); - const form = useForm(); - const field = useField(); if (!data && loading) { return ; } - const item = form.getValuesIn(field.path.slice(0, -2).entire); - if (item?.product && item?.count && data) { - const category = data.data.find((category) => category.id === item.product.category_id); + if (item?.product && item?.count) { + const category = data.data?.find((category) => category.id === item?.product.category_id); if (!category) return; const value = category.convertible ? (item.product.ratio || 0) * item.count : item.count; - const unit = category.convertible ? category.conversion_unit : category.unit; + const unit = category.convertible ? category.conversion_unit : category.unit || ''; + return {formatQuantity(value, 2) + unit}; } return - ; diff --git a/packages/plugins/@hera/plugin-rental/src/client/custom-components/RecordItemValuationQuantity.tsx b/packages/plugins/@hera/plugin-rental/src/client/custom-components/RecordItemValuationQuantity.tsx index 1a381fef3..5b8113589 100644 --- a/packages/plugins/@hera/plugin-rental/src/client/custom-components/RecordItemValuationQuantity.tsx +++ b/packages/plugins/@hera/plugin-rental/src/client/custom-components/RecordItemValuationQuantity.tsx @@ -4,7 +4,7 @@ import { observer, useField, useForm } from '@formily/react'; import _ from 'lodash'; import { ConversionLogics, RecordCategory } from '../../utils/constants'; import { formatQuantity } from '../../utils/currencyUtils'; -import { useCachedRequest, useLeaseItems } from '../hooks'; +import { useCachedRequest, useLeaseItems, useProductFeeItems } from '../hooks'; // 计价数量 export const RecordItemValuationQuantity = observer((props) => { @@ -33,6 +33,9 @@ export const RecordItemValuationQuantity = observer((props) => { const { data: leaseItems } = useLeaseItems(contractPlanId); const { data: inLeaseItems } = useLeaseItems(inContractPlanId); const { data: outLeaseItems } = useLeaseItems(outContractPlanId); + const { data: ProductFeeItems } = useProductFeeItems(contractPlanId); + const { data: inProductFeeItems } = useProductFeeItems(inContractPlanId); + const { data: outProductFeeItems } = useProductFeeItems(outContractPlanId); const item = form.getValuesIn(field.path.slice(0, -2).entire); if (item?.product && item?.count) { @@ -50,7 +53,13 @@ export const RecordItemValuationQuantity = observer((props) => { (product) => product.id - 99999 === item.product?.category_id || product.id === item.product?.id, ), ); - const count = subtotal(rule, item, productCategory, reqWeightRules); + const feeRule = ProductFeeItems.data.find((feeItem) => feeItem.fee_product_id === item.product?.id); + let count; + if (!rule && feeRule) { + count = subtotal(feeRule, item, productCategory, reqWeightRules, 'fee'); + } else { + count = subtotal(rule, item, productCategory, reqWeightRules); + } count && result.push({ label: '合同', value: count }); } // 采购 @@ -78,12 +87,22 @@ export const RecordItemValuationQuantity = observer((props) => { const count = subtotal(rule, item, productCategory, reqWeightRules); count && result.push({ label: '报价', value: count }); } + const leaseRule = inLeaseItems.data.find((leaseItem) => leaseItem.products.find( (product) => product.id - 99999 === item.product?.category_id || product.id === item.product?.id, ), ); - const count = subtotal(leaseRule, item, productCategory, reqWeightRules); + const feeRule = inProductFeeItems.data.find( + (feeItem) => + feeItem.fee_product_id === item.product?.id || item.product?.category_id === feeItem.fee_product.category_id, + ); + let count; + if (!leaseRule && feeRule) { + count = subtotal(feeRule, item, productCategory, reqWeightRules, 'fee'); + } else { + count = subtotal(leaseRule, item, productCategory, reqWeightRules); + } count && result.push({ label: '入库合同', value: count }); } // 租赁直发 @@ -93,14 +112,32 @@ export const RecordItemValuationQuantity = observer((props) => { (product) => product.id - 99999 === item.product?.category_id || product.id === item.product?.id, ), ); - const count_out = subtotal(contractPlain_out, item, productCategory, reqWeightRules); + const contractPlain_out_fee = outProductFeeItems.data.find( + (feeItem) => + feeItem.fee_product_id === item.product?.id || item.product?.category_id === feeItem.fee_product.category_id, + ); + let count_out; + if (!contractPlain_out && contractPlain_out_fee) { + count_out = subtotal(contractPlain_out_fee, item, productCategory, reqWeightRules, 'fee'); + } else { + count_out = subtotal(contractPlain_out, item, productCategory, reqWeightRules); + } count_out && result.push({ label: '出库合同', value: count_out }); const contractPlain_in = inLeaseItems.data.find((leaseItem) => leaseItem.products.find( (product) => product.id - 99999 === item.product?.category_id || product.id === item.product?.id, ), ); - const count_in = subtotal(contractPlain_in, item, productCategory, reqWeightRules); + const contractPlain_in_fee = outProductFeeItems.data.find( + (feeItem) => + feeItem.fee_product_id === item.product?.id || item.product?.category_id === feeItem.fee_product.category_id, + ); + let count_in; + if (!contractPlain_in && contractPlain_in_fee) { + count_in = subtotal(contractPlain_in_fee, item, productCategory, reqWeightRules, 'fee'); + } else { + count_in = subtotal(contractPlain_in, item, productCategory, reqWeightRules); + } count_in && result.push({ label: '入库合同', value: count_in }); } } @@ -119,17 +156,17 @@ RecordItemValuationQuantity.displayName = 'RecordItemValuationQuantity'; RecordItemValuationQuantity.__componentType = CustomComponentType.CUSTOM_FIELD; RecordItemValuationQuantity.__componentLabel = '记录单 - 明细 - 计价数量'; -const subtotal = (rule: any, itemData: any, productCategory: any, reqWeightRules: any) => { +const subtotal = (rule: any, itemData: any, productCategory: any, reqWeightRules: any, item?: any) => { let count: number; let unit: string; if (rule?.conversion_logic_id === ConversionLogics.Keep) { count = itemData.count; - unit = productCategory.unit; + unit = item ? rule.unit : productCategory.unit; } else if (rule?.conversion_logic_id === ConversionLogics.Product) { count = productCategory.convertible ? itemData.count * itemData.product.ratio : itemData.count; - unit = productCategory.convertible ? productCategory.conversion_unit : productCategory.unit; + unit = item ? rule.unit : productCategory.convertible ? productCategory.conversion_unit : productCategory.unit; } else if (rule?.conversion_logic_id === ConversionLogics.ProductWeight) { - count = (itemData.count * itemData.product.weight) / 1000; + count = item ? itemData.count : (itemData.count * itemData.product.weight) / 1000; unit = '吨'; } else if (rule?.conversion_logic_id === ConversionLogics.ActualWeight) { count = 0; diff --git a/packages/plugins/@hera/plugin-rental/src/client/custom-components/RecordProductScope.tsx b/packages/plugins/@hera/plugin-rental/src/client/custom-components/RecordProductScope.tsx index a98678600..5bce1d6d7 100644 --- a/packages/plugins/@hera/plugin-rental/src/client/custom-components/RecordProductScope.tsx +++ b/packages/plugins/@hera/plugin-rental/src/client/custom-components/RecordProductScope.tsx @@ -4,7 +4,7 @@ import React from 'react'; import { observer, useForm } from '@formily/react'; import { RecordCategory } from '../../utils/constants'; import { CustomComponentType, CustomFC } from '@hera/plugin-core/client'; -import { useCachedRequest, useLeaseItems } from '../hooks'; +import { useCachedRequest, useLeaseItems, useProductFeeItems } from '../hooks'; import { useDeepCompareEffect } from 'ahooks'; export const RecordProductScope = observer(() => { @@ -15,36 +15,75 @@ export const RecordProductScope = observer(() => { let required = { price: false, contract: false, inContract: false, outContract: false }; const { data, loading } = useCachedRequest({ - resource: 'product_category', + resource: 'product', action: 'list', params: { pageSize: 99999, }, }); const { data: leaseItems, loading: leaseItemsLoading } = useLeaseItems(contractPlanId); + const { data: feeseItems, loading: feeItemsLoading } = useProductFeeItems(contractPlanId); const { data: inLeaseItems, loading: inLeaseItemsLoading } = useLeaseItems(inContractPlanId); + const { data: inFeeseItems, loading: inFeeItemsLoading } = useProductFeeItems(inContractPlanId); const { data: outLeaseItems, loading: outLeaseItemsLoading } = useLeaseItems(outContractPlanId); + const { data: outFeeseItems, loading: outFeeItemsLoading } = useProductFeeItems(outContractPlanId); - const contractProducts = - leaseItems?.data.reduce((acc, current) => { - acc.push(...current.products.map((item) => ({ id: item.category_id }))); - return acc; - }, []) ?? []; + /** + * 合同费用数据格式trans + */ + const transFee = (fee: any[]) => { + if (fee) { + const feeData = fee.map((fee) => { + const data = { + ...fee, + }; + data.products = [data.fee_product]; + return data; + }); + return feeData || []; + } else { + return []; + } + }; - const inContractProducts = - inLeaseItems?.data.reduce((acc, current) => { - acc.push(...current.products.map((item) => ({ id: item.category_id }))); - return acc; - }, []) ?? []; - - const outContractProducts = - outLeaseItems?.data.reduce((acc, current) => { - acc.push(...current.products.map((item) => ({ id: item.category_id }))); - return acc; - }, []) ?? []; + /** + * 生成合同产品/费用的id或category_id数据 + */ + const contractLeaseFee = (leaseData, feeData) => { + const data = + [...leaseData, ...transFee(feeData)].reduce((acc, current) => { + acc.push( + ...current.products.map((item) => { + if (item.id < 99999) { + return { id: item.id }; + } else { + return { category_id: item.id - 99999 }; + } + }), + ); + return acc; + }, []) ?? []; + return data; + }; + const contractProducts = contractLeaseFee(leaseItems?.data || [], feeseItems?.data); + const inContractProducts = contractLeaseFee(inLeaseItems?.data || [], inFeeseItems?.data); + const inContractFee = contractLeaseFee([], inFeeseItems?.data); + const outContractProducts = contractLeaseFee(outLeaseItems?.data || [], outFeeseItems?.data); const priceProducts = - form.values.price_items?.filter((item) => item.product).map((item) => ({ id: item.product.category_id })) ?? []; + form.values.price_items + ?.filter((item) => item.product) + .map((item) => { + if (item.product.id > 99999) { + return { + category_id: item.product.category_id, + }; + } else { + return { + id: item.product.id, + }; + } + }) ?? []; switch (form.values.category) { case RecordCategory.lease: @@ -53,10 +92,10 @@ export const RecordProductScope = observer(() => { case RecordCategory.purchase: required = { price: true, contract: false, inContract: false, outContract: false }; break; - case RecordCategory.lease2lease: // 出库合同,入库合同的产品范围交集 + case RecordCategory.lease2lease: required = { price: false, contract: false, inContract: true, outContract: true }; break; - case RecordCategory.purchase2lease: // 报价,入库合同的产品范围交集 + case RecordCategory.purchase2lease: // 报价,入库合同的产品范围交集, 加入入库合同的费用数据 required = { price: true, contract: false, inContract: true, outContract: false }; break; case RecordCategory.inventory: @@ -69,24 +108,56 @@ export const RecordProductScope = observer(() => { let result = data?.data ?? []; if (required.inContract && required.outContract) { // 租赁直发单 - const intersection = _.intersectionBy(inContractProducts, outContractProducts, 'id'); - result = _.intersectionBy(result, intersection, 'id'); + const intersection = [ + _.intersectionBy(inContractProducts, outContractProducts, 'id'), + _.intersectionBy(inContractProducts, outContractProducts, 'category_id'), + ].flat(); + const data = intersectionByMultiple(result, intersection, 'category_id'); + result = [_.intersectionBy(result, intersection, 'id'), data].flat(); } else if (required.price && required.inContract) { - const intersection = _.intersectionBy(inContractProducts, priceProducts, 'id'); - result = _.intersectionBy(result, intersection, 'id'); + const intersection = [ + _.intersectionBy(inContractProducts, priceProducts, 'id'), + _.intersectionBy(inContractProducts, priceProducts, 'category_id'), + ].flat(); + intersection.push(...inContractFee); + const data = intersectionByMultiple(result, intersection, 'category_id'); + result = [_.intersectionBy(result, intersection, 'id'), data].flat(); } else if (required.price) { - result = _.intersectionBy(result, priceProducts, 'id'); + const data = intersectionByMultiple(result, priceProducts, 'category_id'); + result = [_.intersectionBy(result, priceProducts, 'id'), data].flat(); } else if (required.contract) { - result = _.intersectionBy(result, contractProducts, 'id'); + const data = intersectionByMultiple(result, contractProducts, 'category_id'); + result = [_.intersectionBy(result, contractProducts, 'id'), data].flat(); } useDeepCompareEffect(() => { form.setValues({ product_scope: result, }); }, [result, form]); - return loading || leaseItemsLoading || inLeaseItemsLoading || outLeaseItemsLoading ? : <>; + return loading || + leaseItemsLoading || + inLeaseItemsLoading || + outLeaseItemsLoading || + feeItemsLoading || + inFeeItemsLoading || + outFeeItemsLoading ? ( + + ) : ( + <> + ); }) as CustomFC; RecordProductScope.displayName = 'RecordProductScope'; RecordProductScope.__componentType = CustomComponentType.CUSTOM_ASSOCIATED_FIELD; RecordProductScope.__componentLabel = '记录单 - 产品范围'; + +const intersectionByMultiple = (arr1, arr2, propName) => { + const result = []; + arr1.forEach((item) => { + const index = arr2.findIndex((i) => i[propName] === item[propName]); + if (index !== -1) { + result.push(item); + } + }); + return result; +}; diff --git a/packages/plugins/@hera/plugin-rental/src/client/hooks/index.tsx b/packages/plugins/@hera/plugin-rental/src/client/hooks/index.tsx index eb74ca756..2d7b738c7 100644 --- a/packages/plugins/@hera/plugin-rental/src/client/hooks/index.tsx +++ b/packages/plugins/@hera/plugin-rental/src/client/hooks/index.tsx @@ -30,6 +30,30 @@ export const useLeaseItems = (planId) => { return { data, loading }; }; +export const useProductFeeItems = (planId) => { + const feeParams = { + resource: 'contract_plan_fee_items', + action: 'list', + params: { + appends: ['fee_product'], + filter: { + contract_plan_id: planId, + }, + pageSize: 99999, + }, + }; + + const { data, loading, run } = useCachedRequest(feeParams, { + manual: true, + }); + useEffect(() => { + if (planId) { + run(); + } + }, [planId]); + return { data, loading }; +}; + export const useFeeItems = (categoryId, planId) => { const { data, loading, run } = useCachedRequest( { diff --git a/packages/plugins/@hera/plugin-rental/src/server/pdf-documents/records-documentV2.tsx b/packages/plugins/@hera/plugin-rental/src/server/pdf-documents/records-documentV2.tsx index 247d0e9d6..346cb9886 100644 --- a/packages/plugins/@hera/plugin-rental/src/server/pdf-documents/records-documentV2.tsx +++ b/packages/plugins/@hera/plugin-rental/src/server/pdf-documents/records-documentV2.tsx @@ -133,6 +133,7 @@ const styles = StyleSheet.create({ marginLeft: '-1px', borderTop: '1px solid black', marginTop: '-1px', + borderBottom: '1px solid black', }, tableCellLast: { flex: 1, @@ -302,6 +303,81 @@ const PreviewDocument = ({ dobuleRecord.push(result); } } + const renderRecord = (data, isDouble) => { + const columns = isDouble ? ['left_', 'right_'] : ['']; + const page = data.map((item, index) => ( + + {columns.map((column, columnIndex) => ( + + {item[column + 'name']} + + {!item[column + 'count'] ? '' : formatQuantity(item[column + 'count'], 2) + item[column + 'unit']} + + + {!item[column + 'total'] + ? '' + : formatQuantity(item[column + 'total'], 2) + item[column + 'conversion_unit']} + + + {item[column + 'isExcluded'] + ? '不计入合同 ' + (item[column + 'comment'] || '') + : item[column + 'comment'] || ''} + + + ))} + + )); + let addCol = <>; + if (detail.category === RecordCategory.purchase) { + const allprice = getAllPrice(); + addCol = ( + + {columns.map((column, columnIndex) => ( + + + {column === 'left_' ? '' : '总金额'} + {column === 'left_' ? '' : allprice} + + + ))} + + ); + } + + return detail.category === RecordCategory.purchase ? ( + <> + {page} + {addCol} + + ) : ( + page + ); + }; + + const renderPrice = (data, isDouble) => { + const columns = isDouble ? ['left_', 'right_'] : ['']; + return data.map((item, index) => ( + + {columns.map((column, columnIndex) => ( + + {item[column + 'name']} + + {formatQuantity(item[column + 'unit_price'], 2) + '元/' + item[column + 'unit']} + + + {formatQuantity(item[column + 'count'], 2)} + {item[column + 'unit']} + + {formatCurrency(item[column + 'all_price'], 2)} + + {item[column + 'comment'] || ''} + + + ))} + + )); + }; + return ( @@ -365,216 +441,44 @@ const PreviewDocument = ({ 车号:{car} )} - {/* 单列定价 */} - {!isDouble && detail.category === RecordCategory.purchase && ( + {/* 定价 */} + {detail.category === RecordCategory.purchase && ( 物料名称及规格 单价 数量 金额 - 备注 + 备注 + {isDouble && ( + <> + 物料名称及规格 + 单价 + 数量 + 金额 + 备注 + + )} )} - {!isDouble && - detail.category === RecordCategory.purchase && - priceRule.length && - priceRule.map((item) => ( - - {item.name} - - {item?.unit_price && formatQuantity(item.unit_price, 2) + '元/' + item.unit} - - - {formatQuantity(item.count, 2)} - {item.unit} - - {formatCurrency(item.all_price, 2)} - {item.comment || ''} - - ))} - {/* 双列定价 */} - {isDouble && detail.category === RecordCategory.purchase && ( - - 物料名称及规格 - 单价 - 数量 - 金额 - 备注 - 物料名称及规格 - 单价 - 数量 - 金额 - 备注 - - )} - {isDouble && - detail.category === RecordCategory.purchase && - priceRule.length && - dobulePriceRule.map((item) => ( - - {item.left_name} - - {item?.left_unit_price && formatQuantity(item.left_unit_price, 2) + '元/' + item.left_unit} - - - {formatQuantity(item.left_count, 2)} - {item.left_unit} - - {formatCurrency(item.left_all_price, 2)} - {item.left_comment || ''} - {item.right_name} - - {item?.right_unit_price && formatQuantity(item.right_unit_price, 2) + '元/' + item.right_unit} - - - {item.right_count && formatQuantity(item.right_count)} - {item.right_unit} - - - {item.right_all_price && formatCurrency(item.right_all_price, 2)} - - {item.right_comment || ''} - - ))} + {detail.category === RecordCategory.purchase && + renderPrice(isDouble ? dobulePriceRule : priceRule, isDouble)} {/* ============================================================两表分割================================================================================= */} {/* 单列租金及费用 */} - {!isDouble && ( - - 物料名称及规格 - 数量 - 小计 - - 备注 - - - )} - {!isDouble && - record.map((item) => ( - - {item.name} - - {!item.count || item.isFee ? '' : formatQuantity(item.count, 2) + item.unit} - - - {(printSetup === PrintSetup.Display && !item.product_id && !item.isTotal) || - (printSetup === PrintSetup.Manual && !item.product_id && !item.isTotal) - ? '' - : item.total - ? formatQuantity(item.total, 2) - : ''} - {item.isFee && !item.product_id // 判断未无产品关联费用 - ? printSetup === PrintSetup.DisplayAndPrice && item.total - ? '元' - : '' - : item.conversion_unit} - - - {item.isExcluded ? '不计入合同 ' + (item.comment || '') : item.comment || ''} - - - ))} - {!isDouble && detail.category === RecordCategory.purchase && ( - - - 总金额 - {getAllPrice()} - - - )} - {/* 双列租及费用 */} - {isDouble && ( - - 物料名称及规格 - 数量 - 小计 - - 备注 - - 物料名称及规格 - 数量 - 小计 - - 备注 - - - )} - {isDouble && - dobuleRecord.map((item) => ( - - {item.left_name} - - {!item.left_count || item.left_isFee ? '' : formatQuantity(item.left_count, 2) + item.left_unit} - - - {(printSetup === PrintSetup.Display && !item.left_product_id && !item.left_isTotal) || - (printSetup === PrintSetup.Manual && !item.left_product_id && !item.left_isTotal) - ? '' - : item.left_total - ? formatQuantity(item.left_total, 2) - : ''} - {item.left_isFee && !item.left_product_id // 判断未无产品关联费用 - ? printSetup === PrintSetup.DisplayAndPrice && item.left_total - ? '元' - : '' // 不记录合同不需要单位 - : item.left_conversion_unit} - - - {item.left_isExcluded ? '不计入合同 ' + (item.left_comment || '') : item.left_comment || ''} - - {item.right_name} - - {!item.right_count || item.right_isFee ? '' : formatQuantity(item.right_count, 2) + item.right_unit} - - - {(printSetup === PrintSetup.Display && !item.right_product_id && !item.right_isTotal) || - (printSetup === PrintSetup.Manual && !item.right_product_id && !item.right_isTotal) - ? '' - : item.right_total - ? formatQuantity(item.right_total, 2) - : ''} - {item.right_isFee && !item.right_product_id // 判断未无产品关联费用 - ? printSetup === PrintSetup.DisplayAndPrice && item.right_total - ? '元' - : '' // 不记录合同不需要单位 - : item.right_conversion_unit} - - - {item.right_name && item.right_isExcluded - ? '不计入合同 ' + (item.right_comment || '') - : item.right_comment || ''} - - - ))} - {isDouble && detail.category === RecordCategory.purchase && ( - - - - - - - 总金额 - {getAllPrice()} - - - )} + + 物料名称及规格 + 数量 + 小计 + 备注 + {isDouble && ( + <> + 物料名称及规格 + 数量 + 小计 + 备注 + + )} + + {renderRecord(isDouble ? dobuleRecord : record, isDouble)} diff --git a/packages/plugins/@hera/plugin-rental/src/server/services/record-pdf-service.ts b/packages/plugins/@hera/plugin-rental/src/server/services/record-pdf-service.ts index 43bee34d2..c5be9c782 100644 --- a/packages/plugins/@hera/plugin-rental/src/server/services/record-pdf-service.ts +++ b/packages/plugins/@hera/plugin-rental/src/server/services/record-pdf-service.ts @@ -1,11 +1,14 @@ import { ConversionLogics, RecordCategory, RulesNumber, SourcesType, countCource } from '../../utils/constants'; import { renderItV2 } from '../pdf-documents/records-documentV2'; -import { Service } from '@nocobase/utils'; +import { Db, Service } from '@nocobase/utils'; import { RecordPdfOptions } from '../../interfaces/options'; import { PrintSetup } from '../../utils/system'; +import Database from '@nocobase/database'; @Service() export class RecordPdfService { + @Db() + private db: Database; async transformPdfV2(recordData: any, lease_data: any, fee_data: any, options: RecordPdfOptions) { const { isDouble, printSetup } = options; @@ -79,7 +82,7 @@ export class RecordPdfService { make_price = setData; } - // 计算租金数据 + // !产品 const leaseData = lease_data .map((lease) => { const data = { @@ -117,8 +120,7 @@ export class RecordPdfService { }) .sort((a, b) => a.category_id - b.category_id); - // 计算费用数据,包括有产品关联跟无产品关联 - // 关联产品的赔偿(人工录入/全部) + // !产品赔偿 const product_fee = printSetup === PrintSetup.Manual ? fee_data.filter((item) => item.product_id && item.count_source === SourcesType.staff) @@ -148,68 +150,109 @@ export class RecordPdfService { category_id: item.product_category_id, }; if (item.conversion_logic_id === ConversionLogics.Keep) { - data['count'] = data.count1; + data['total'] = data.count1; } else if (item.conversion_logic_id === ConversionLogics.Product) { - if (item.convertible) data['count'] = data.count1 * item.product_ratio; - else data['count'] = data.count1; + if (item.convertible) data['total'] = data.count1 * item.product_ratio; + else data['total'] = data.count1; } else if (item.conversion_logic_id === ConversionLogics.ProductWeight) { - data['count'] = data.count1 * item.product_weight; + data['total'] = data.count1 * item.product_weight; } else if (item.conversion_logic_id === ConversionLogics.ActualWeight) { - data['count'] = item.actual_weight || item.record_weight; + data['total'] = item.actual_weight || item.record_weight; } else { if (item.weight_rules?.conversion_logic_id === ConversionLogics.Keep) { - data['count'] = data.count1 * item.weight_rules.weight; + data['total'] = data.count1 * item.weight_rules.weight; } else if (item.weight_rules?.conversion_logic_id === ConversionLogics.Product) { - data['count'] = data.count1 * item.weight_rules.weight * item.product_ratio; + data['total'] = data.count1 * item.weight_rules.weight * item.product_ratio; } } - // 如果 printSetup === PrintSetup.DisplayAndPrice 要计算费用产生的价格 + data['conversion_unit'] = item.unit; if (printSetup === PrintSetup.DisplayAndPrice) { - data['total'] = data['count'] * item.unit_price; + data['count'] = data['total']; + data['total'] = data['total'] * item.unit_price; data['conversion_unit'] = '元'; } return data; }); - // 无关联产品赔偿, 人工录取的情况直接为空,因为excludedFee已经处理,正常情况取非手动录入情况数据,excludedFee已经处理 + // !无关联赔偿 item中 + let manualData = []; + const noProductFee = fee_data.filter((item) => !item.product_id && item.count_source === SourcesType.staff); + if (noProductFee.length) { + const itemFee = await this.db.sequelize.query(` + select ri.product_id, ri.count, p.category_id, ri.comment + from records r + left join record_items ri on ri.record_id = r.id and ri.product_id in (${noProductFee.map((item) => item.fee_product_id).join(',')}) + join product p on p.id = ri.product_id + where r.id = ${recordData.id} + `); + const result: any = itemFee[0]; + manualData = result.map((item) => { + const feeRule = noProductFee.find((f) => f.fee_product_id === item.product_id); + if (!feeRule) return; + const data = { + name: feeRule.custom_name || feeRule.label, + unit: feeRule.unit, + conversion_unit: feeRule.unit, + comment: item.comment || '', + }; + if (feeRule.conversion_logic_id === ConversionLogics.Keep) { + data['total'] = item.count; + } else if (feeRule.conversion_logic_id === ConversionLogics.Product) { + data['total'] = feeRule.convertible ? item.count * feeRule.product_ratio : item.count; + } else if (feeRule.conversion_logic_id === ConversionLogics.ProductWeight) { + data['total'] = item.count * feeRule.weight; + } else if (feeRule.conversion_logic_id === ConversionLogics.ActualWeight) { + data['total'] = feeRule.record_weight; + } else { + const weight_rule = item.weight_rules.find( + (l) => l.product_id === item.product_id || l.product - RulesNumber === item.category_id, + ); + if (weight_rule && weight_rule.conversion_logic_id === ConversionLogics.Keep) { + return item.count * weight_rule.weight; + } else if (weight_rule && weight_rule.conversion_logic_id === ConversionLogics.Product) { + return item.count * feeRule.product_ratio * weight_rule.weight; + } + } + if (printSetup === PrintSetup.DisplayAndPrice) { + data['count'] = data['total']; + data['total'] = data['total'] * feeRule.unit_price; + data['conversion_unit'] = '元'; + } + return data; + }); + } + // !无关联赔偿,出入库量 const fee = printSetup === PrintSetup.Manual ? [] : fee_data.filter((item) => !item.product_id && item.count_source !== SourcesType.staff); const no_product_fee = fee .map((item) => { - // 购销/暂存/盘点无费用信息 if ( recordData.category === RecordCategory.purchase || recordData.category === RecordCategory.staging || recordData.category === RecordCategory.inventory - ) + ) { return; - if (item.count_source === countCource.artificial) { - const data = recordData.record_fee_items?.find((hava) => hava.product?.id === item.fee_product_id); - if (!data) return; } if (item.record_movement === '-1' && item.count_source === SourcesType.inbound) return; if (item.record_movement === '1' && item.count_source === SourcesType.outbound) return; const data = { isFee: true, name: item.custom_name || item.label, - unit: '', - conversion_unit: item.unit, + unit: item.unit, comment: '', }; - if (item.conversion_logic_id === ConversionLogics.Keep) { - data['count'] = lease_data.reduce((a, b) => a + b.count, 0); + data['total'] = lease_data.reduce((a, b) => a + b.count, 0); } else if (item.conversion_logic_id === ConversionLogics.Product) { - data['count'] = lease_data.reduce((a, b) => a + (item.convertible ? b.count * b.ratio : b.count), 0); + data['total'] = lease_data.reduce((a, b) => a + (item.convertible ? b.count * b.ratio : b.count), 0); } else if (item.conversion_logic_id === ConversionLogics.ProductWeight) { - data['count'] = lease_data.reduce((a, b) => a + b.count * b.weight, 0) / 1000; + data['total'] = lease_data.reduce((a, b) => a + b.count * b.weight, 0) / 1000; } else if (item.conversion_logic_id === ConversionLogics.ActualWeight) { - data['count'] = item.record_weight; + data['total'] = item.record_weight; } else { if (item.weight_rules?.length) { - // 计算有误,需要检查 - data['count'] = lease_data.reduce((a, b) => { + data['total'] = lease_data.reduce((a, b) => { const weight_rule = item.weight_rules.find( (l) => l.product_id === b.product_id || l.product - RulesNumber === b.category_id, ); @@ -221,34 +264,15 @@ export class RecordPdfService { }, 0); } } - // 如果 printSetup === PrintSetup.DisplayAndPrice 要计算费用产生的价格 + data['conversion_unit'] = '吨'; if (printSetup === PrintSetup.DisplayAndPrice) { - data['total'] = data['count'] * item.unit_price; + data['count'] = data['total']; + data['total'] = data['total'] * item.unit_price; + data['conversion_unit'] = '元'; } return data; }) - .filter((item) => item && item.count); - // 注意把手动录入的加入 - const manualData = recordData.record_fee_items; - // 因为以往逻辑是根据规则查询,这个订单中数据智能单独查询 - const excludedFee = - manualData - ?.map((item) => { - const data = { - isFee: true, - name: item.product.custom_name || item.product.label, - comment: '', - count: item.count, - isExcluded: item.is_excluded, - }; - const feeRule = fee_data.find((fee) => fee.fee_product_id === item.product_id); - if (feeRule) { - data['total'] = feeRule.unit_price * item.count; - data['unit'] = ''; - } - return data; - }) - .filter(Boolean) || []; + .filter((item) => item && item.total); const product_fees = transFormProductFee.filter(Boolean); // 内容(租金+费用) @@ -280,10 +304,10 @@ export class RecordPdfService { product_correlation.push(itemB); } }); - const recordPdfData = [...product_correlation, ...no_product_fee, ...excludedFee]; + const recordPdfData = [...product_correlation, ...manualData, ...no_product_fee].filter(Boolean); return await renderItV2({ detail: recordData, - record: recordPdfData, // 租金+费用,无关联费用 + record: recordPdfData, priceRule: make_price, isDouble, printSetup, diff --git a/packages/plugins/@hera/plugin-rental/src/server/sqls/pdf_record.sql b/packages/plugins/@hera/plugin-rental/src/server/sqls/pdf_record.sql index 301ca47e1..891ce6a5b 100644 --- a/packages/plugins/@hera/plugin-rental/src/server/sqls/pdf_record.sql +++ b/packages/plugins/@hera/plugin-rental/src/server/sqls/pdf_record.sql @@ -99,19 +99,6 @@ SELECT WHERE r.id = rv.record_id ) AS vehicles, - ( - SELECT - JSONB_AGG( - TO_JSONB( - JSONB_SET(TO_JSONB(rfi), '{product}', TO_JSONB(p)) - ) - ) - FROM - record_fee_items rfi - JOIN product p ON p.id = rfi.product_id - WHERE - rfi.record_id = r.id - ) AS record_fee_items, -- 查询分组实际重量 ( SELECT