feat: 仓库二期,出入库单打印预览,产品范围,计价数量,换算数量
Reviewed-on: daoyoucloud/tachycode#503 Co-authored-by: hello@lv <2256334253@qq.com> Co-committed-by: hello@lv <2256334253@qq.com>
This commit is contained in:
parent
6251551ded
commit
eb090572c6
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
@ -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<any>(param);
|
||||
const form = useForm();
|
||||
const field = useField();
|
||||
|
||||
if (!data && loading) {
|
||||
return <Spin />;
|
||||
}
|
||||
|
||||
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 <span>{formatQuantity(value, 2) + unit}</span>;
|
||||
}
|
||||
return <span> - </span>;
|
||||
|
@ -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;
|
||||
|
@ -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<any>({
|
||||
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 ? <Spin /> : <></>;
|
||||
return loading ||
|
||||
leaseItemsLoading ||
|
||||
inLeaseItemsLoading ||
|
||||
outLeaseItemsLoading ||
|
||||
feeItemsLoading ||
|
||||
inFeeItemsLoading ||
|
||||
outFeeItemsLoading ? (
|
||||
<Spin />
|
||||
) : (
|
||||
<></>
|
||||
);
|
||||
}) 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;
|
||||
};
|
||||
|
@ -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<any>(feeParams, {
|
||||
manual: true,
|
||||
});
|
||||
useEffect(() => {
|
||||
if (planId) {
|
||||
run();
|
||||
}
|
||||
}, [planId]);
|
||||
return { data, loading };
|
||||
};
|
||||
|
||||
export const useFeeItems = (categoryId, planId) => {
|
||||
const { data, loading, run } = useCachedRequest<any>(
|
||||
{
|
||||
|
@ -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) => (
|
||||
<View key={index} style={styles.tableContent}>
|
||||
{columns.map((column, columnIndex) => (
|
||||
<React.Fragment key={columnIndex}>
|
||||
<Text style={styles.tableCell2}>{item[column + 'name']}</Text>
|
||||
<Text style={styles.tableCell}>
|
||||
{!item[column + 'count'] ? '' : formatQuantity(item[column + 'count'], 2) + item[column + 'unit']}
|
||||
</Text>
|
||||
<Text style={styles.tableCell}>
|
||||
{!item[column + 'total']
|
||||
? ''
|
||||
: formatQuantity(item[column + 'total'], 2) + item[column + 'conversion_unit']}
|
||||
</Text>
|
||||
<Text style={!isDouble || column === 'right_' ? styles.tableCellLast : styles.tableCell}>
|
||||
{item[column + 'isExcluded']
|
||||
? '不计入合同 ' + (item[column + 'comment'] || '')
|
||||
: item[column + 'comment'] || ''}
|
||||
</Text>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</View>
|
||||
));
|
||||
let addCol = <></>;
|
||||
if (detail.category === RecordCategory.purchase) {
|
||||
const allprice = getAllPrice();
|
||||
addCol = (
|
||||
<View style={styles.tableContent}>
|
||||
{columns.map((column, columnIndex) => (
|
||||
<React.Fragment key={columnIndex}>
|
||||
<Text style={styles.tableCell2}></Text>
|
||||
<Text style={styles.tableCell}>{column === 'left_' ? '' : '总金额'}</Text>
|
||||
<Text style={styles.tableCell}>{column === 'left_' ? '' : allprice}</Text>
|
||||
<Text style={!isDouble || column === 'right_' ? styles.tableCellLast : styles.tableCell}></Text>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return detail.category === RecordCategory.purchase ? (
|
||||
<>
|
||||
{page}
|
||||
{addCol}
|
||||
</>
|
||||
) : (
|
||||
page
|
||||
);
|
||||
};
|
||||
|
||||
const renderPrice = (data, isDouble) => {
|
||||
const columns = isDouble ? ['left_', 'right_'] : [''];
|
||||
return data.map((item, index) => (
|
||||
<View key={index} style={styles.tableContent}>
|
||||
{columns.map((column, columnIndex) => (
|
||||
<React.Fragment key={columnIndex}>
|
||||
<Text style={styles.tableCell2}>{item[column + 'name']}</Text>
|
||||
<Text style={styles.tableCell}>
|
||||
{formatQuantity(item[column + 'unit_price'], 2) + '元/' + item[column + 'unit']}
|
||||
</Text>
|
||||
<Text style={styles.tableCell}>
|
||||
{formatQuantity(item[column + 'count'], 2)}
|
||||
{item[column + 'unit']}
|
||||
</Text>
|
||||
<Text style={styles.tableCell}>{formatCurrency(item[column + 'all_price'], 2)}</Text>
|
||||
<Text style={!isDouble || column === 'right_' ? styles.tableCellLast : styles.tableCell}>
|
||||
{item[column + 'comment'] || ''}
|
||||
</Text>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</View>
|
||||
));
|
||||
};
|
||||
|
||||
return (
|
||||
<Document>
|
||||
<Page size="A4" style={{ ...styles.page, marginTop: detail.margingTop }}>
|
||||
@ -365,216 +441,44 @@ const PreviewDocument = ({
|
||||
<Text style={styles.headerLeftRight}>车号:{car}</Text>
|
||||
</View>
|
||||
)}
|
||||
{/* 单列定价 */}
|
||||
{!isDouble && detail.category === RecordCategory.purchase && (
|
||||
{/* 定价 */}
|
||||
{detail.category === RecordCategory.purchase && (
|
||||
<View style={styles.tableContentTitle}>
|
||||
<Text style={styles.tableCellLargeTitle}>物料名称及规格</Text>
|
||||
<Text style={styles.tableCellTitle}>单价</Text>
|
||||
<Text style={styles.tableCellTitle}>数量</Text>
|
||||
<Text style={styles.tableCellTitle}>金额</Text>
|
||||
<Text style={styles.tableCellTitleLast}>备注</Text>
|
||||
<Text style={!isDouble ? styles.tableCellTitleLast : styles.tableCellTitle}>备注</Text>
|
||||
{isDouble && (
|
||||
<>
|
||||
<Text style={styles.tableCellLargeTitle}>物料名称及规格</Text>
|
||||
<Text style={styles.tableCellTitle}>单价</Text>
|
||||
<Text style={styles.tableCellTitle}>数量</Text>
|
||||
<Text style={styles.tableCellTitle}>金额</Text>
|
||||
<Text style={styles.tableCellTitleLast}>备注</Text>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
{!isDouble &&
|
||||
detail.category === RecordCategory.purchase &&
|
||||
priceRule.length &&
|
||||
priceRule.map((item) => (
|
||||
<View key={'key'} style={styles.tableContent}>
|
||||
<Text style={styles.tableCell2}>{item.name}</Text>
|
||||
<Text style={styles.tableCell}>
|
||||
{item?.unit_price && formatQuantity(item.unit_price, 2) + '元/' + item.unit}
|
||||
</Text>
|
||||
<Text style={styles.tableCell}>
|
||||
{formatQuantity(item.count, 2)}
|
||||
{item.unit}
|
||||
</Text>
|
||||
<Text style={styles.tableCell}>{formatCurrency(item.all_price, 2)}</Text>
|
||||
<Text style={styles.tableCellLast}>{item.comment || ''}</Text>
|
||||
</View>
|
||||
))}
|
||||
{/* 双列定价 */}
|
||||
{isDouble && detail.category === RecordCategory.purchase && (
|
||||
<View style={styles.tableContentTitle}>
|
||||
<Text style={styles.tableCellLargeTitle}>物料名称及规格</Text>
|
||||
<Text style={styles.tableCellTitle}>单价</Text>
|
||||
<Text style={styles.tableCellTitle}>数量</Text>
|
||||
<Text style={styles.tableCellTitle}>金额</Text>
|
||||
<Text style={styles.tableCellTitle}>备注</Text>
|
||||
<Text style={styles.tableCellLargeTitle}>物料名称及规格</Text>
|
||||
<Text style={styles.tableCellTitle}>单价</Text>
|
||||
<Text style={styles.tableCellTitle}>数量</Text>
|
||||
<Text style={styles.tableCellTitle}>金额</Text>
|
||||
<Text style={styles.tableCellTitleLast}>备注</Text>
|
||||
</View>
|
||||
)}
|
||||
{isDouble &&
|
||||
detail.category === RecordCategory.purchase &&
|
||||
priceRule.length &&
|
||||
dobulePriceRule.map((item) => (
|
||||
<View key={'key'} style={styles.tableContent}>
|
||||
<Text style={styles.tableCell2}>{item.left_name}</Text>
|
||||
<Text style={styles.tableCell}>
|
||||
{item?.left_unit_price && formatQuantity(item.left_unit_price, 2) + '元/' + item.left_unit}
|
||||
</Text>
|
||||
<Text style={styles.tableCell}>
|
||||
{formatQuantity(item.left_count, 2)}
|
||||
{item.left_unit}
|
||||
</Text>
|
||||
<Text style={styles.tableCell}>{formatCurrency(item.left_all_price, 2)}</Text>
|
||||
<Text style={styles.tableCell}>{item.left_comment || ''}</Text>
|
||||
<Text style={styles.tableCell2}>{item.right_name}</Text>
|
||||
<Text style={styles.tableCell}>
|
||||
{item?.right_unit_price && formatQuantity(item.right_unit_price, 2) + '元/' + item.right_unit}
|
||||
</Text>
|
||||
<Text style={styles.tableCell}>
|
||||
{item.right_count && formatQuantity(item.right_count)}
|
||||
{item.right_unit}
|
||||
</Text>
|
||||
<Text style={styles.tableCell}>
|
||||
{item.right_all_price && formatCurrency(item.right_all_price, 2)}
|
||||
</Text>
|
||||
<Text style={styles.tableCellLast}>{item.right_comment || ''}</Text>
|
||||
</View>
|
||||
))}
|
||||
{detail.category === RecordCategory.purchase &&
|
||||
renderPrice(isDouble ? dobulePriceRule : priceRule, isDouble)}
|
||||
{/* ============================================================两表分割================================================================================= */}
|
||||
{/* 单列租金及费用 */}
|
||||
{!isDouble && (
|
||||
<View style={styles.tableContentTitle}>
|
||||
<Text style={styles.tableCellLargeTitle}>物料名称及规格</Text>
|
||||
<Text style={styles.tableCellTitle}>数量</Text>
|
||||
<Text style={styles.tableCellTitle}>小计</Text>
|
||||
<Text
|
||||
style={
|
||||
detail.category === RecordCategory.purchase ? styles.tableCell2TitleLast : styles.tableCellTitleLast
|
||||
}
|
||||
>
|
||||
备注
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
{!isDouble &&
|
||||
record.map((item) => (
|
||||
<View key={'key'} style={styles.tableContent}>
|
||||
<Text style={styles.tableCell2}>{item.name}</Text>
|
||||
<Text style={styles.tableCell}>
|
||||
{!item.count || item.isFee ? '' : formatQuantity(item.count, 2) + item.unit}
|
||||
</Text>
|
||||
<Text style={styles.tableCell}>
|
||||
{(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}
|
||||
</Text>
|
||||
<Text
|
||||
style={detail.category === RecordCategory.purchase ? styles.tableCell2Last : styles.tableCellLast}
|
||||
>
|
||||
{item.isExcluded ? '不计入合同 ' + (item.comment || '') : item.comment || ''}
|
||||
</Text>
|
||||
</View>
|
||||
))}
|
||||
{!isDouble && detail.category === RecordCategory.purchase && (
|
||||
<View key={'key'} style={styles.tableContent}>
|
||||
<Text style={styles.tableCell2}></Text>
|
||||
<Text style={styles.tableCell}>总金额</Text>
|
||||
<Text style={styles.tableCell}>{getAllPrice()}</Text>
|
||||
<Text
|
||||
style={detail.category === RecordCategory.purchase ? styles.tableCell2Last : styles.tableCellLast}
|
||||
></Text>
|
||||
</View>
|
||||
)}
|
||||
{/* 双列租及费用 */}
|
||||
{isDouble && (
|
||||
<View style={styles.tableContentTitle}>
|
||||
<Text style={styles.tableCellLargeTitle}>物料名称及规格</Text>
|
||||
<Text style={styles.tableCellTitle}>数量</Text>
|
||||
<Text style={styles.tableCellTitle}>小计</Text>
|
||||
<Text
|
||||
style={detail.category === RecordCategory.purchase ? styles.tableCell2Title : styles.tableCellTitle}
|
||||
>
|
||||
备注
|
||||
</Text>
|
||||
<Text style={styles.tableCellLargeTitle}>物料名称及规格</Text>
|
||||
<Text style={styles.tableCellTitle}>数量</Text>
|
||||
<Text style={styles.tableCellTitle}>小计</Text>
|
||||
<Text
|
||||
style={
|
||||
detail.category === RecordCategory.purchase ? styles.tableCell2TitleLast : styles.tableCellTitleLast
|
||||
}
|
||||
>
|
||||
备注
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
{isDouble &&
|
||||
dobuleRecord.map((item) => (
|
||||
<View key={'key'} style={styles.tableContent}>
|
||||
<Text style={styles.tableCell2}>{item.left_name}</Text>
|
||||
<Text style={styles.tableCell}>
|
||||
{!item.left_count || item.left_isFee ? '' : formatQuantity(item.left_count, 2) + item.left_unit}
|
||||
</Text>
|
||||
<Text style={styles.tableCell}>
|
||||
{(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}
|
||||
</Text>
|
||||
<Text style={detail.category === RecordCategory.purchase ? styles.tableCell2 : styles.tableCell}>
|
||||
{item.left_isExcluded ? '不计入合同 ' + (item.left_comment || '') : item.left_comment || ''}
|
||||
</Text>
|
||||
<Text style={styles.tableCell2}>{item.right_name}</Text>
|
||||
<Text style={styles.tableCell}>
|
||||
{!item.right_count || item.right_isFee ? '' : formatQuantity(item.right_count, 2) + item.right_unit}
|
||||
</Text>
|
||||
<Text style={styles.tableCell}>
|
||||
{(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}
|
||||
</Text>
|
||||
<Text
|
||||
style={detail.category === RecordCategory.purchase ? styles.tableCell2Last : styles.tableCellLast}
|
||||
>
|
||||
{item.right_name && item.right_isExcluded
|
||||
? '不计入合同 ' + (item.right_comment || '')
|
||||
: item.right_comment || ''}
|
||||
</Text>
|
||||
</View>
|
||||
))}
|
||||
{isDouble && detail.category === RecordCategory.purchase && (
|
||||
<View key={'key'} style={styles.tableContent}>
|
||||
<Text style={styles.tableCell2}></Text>
|
||||
<Text style={styles.tableCell}></Text>
|
||||
<Text style={styles.tableCell}></Text>
|
||||
<Text style={detail.category === RecordCategory.purchase ? styles.tableCell2 : styles.tableCell}></Text>
|
||||
<Text style={styles.tableCell2}></Text>
|
||||
<Text style={styles.tableCell}>总金额</Text>
|
||||
<Text style={styles.tableCell}>{getAllPrice()}</Text>
|
||||
<Text
|
||||
style={detail.category === RecordCategory.purchase ? styles.tableCell2Last : styles.tableCellLast}
|
||||
></Text>
|
||||
</View>
|
||||
)}
|
||||
<View style={styles.tableContentTitle}>
|
||||
<Text style={styles.tableCellLargeTitle}>物料名称及规格</Text>
|
||||
<Text style={styles.tableCellTitle}>数量</Text>
|
||||
<Text style={styles.tableCellTitle}>小计</Text>
|
||||
<Text style={!isDouble ? styles.tableCellTitleLast : styles.tableCellTitle}>备注</Text>
|
||||
{isDouble && (
|
||||
<>
|
||||
<Text style={styles.tableCellLargeTitle}>物料名称及规格</Text>
|
||||
<Text style={styles.tableCellTitle}>数量</Text>
|
||||
<Text style={styles.tableCellTitle}>小计</Text>
|
||||
<Text style={styles.tableCellTitleLast}>备注</Text>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
{renderRecord(isDouble ? dobuleRecord : record, isDouble)}
|
||||
<View style={styles.tableFooter}>
|
||||
<View style={styles.tableFooterQr}>
|
||||
<Image src={imageUrl} />
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user