parent
b762282578
commit
0602743922
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@hera/plugin-rental",
|
||||
"displayName": "professional construction materials rental system - customized based on hera",
|
||||
"version": "1.7.41",
|
||||
"version": "1.7.42",
|
||||
"description": "Offering a standardized leasing management system, encompassing comprehensive administration from materials to contracts to labor personnel, while providing a robust financial management mechanism, and real-time monitoring of the operational capacity of the leasing system.",
|
||||
"keywords": [
|
||||
"System management"
|
||||
|
@ -3,10 +3,10 @@ import _ from 'lodash';
|
||||
import { CustomComponentType, CustomFunctionComponent } from '@hera/plugin-core/client';
|
||||
import { useField, useFieldSchema, useForm } from '@tachybase/schema';
|
||||
import { FormPath } from '@tachybase/schema';
|
||||
import { useCollection, useRequest } from '@tachybase/client';
|
||||
import { useRequest } from '@tachybase/client';
|
||||
import { Descriptions, Spin } from 'antd';
|
||||
import { formatQuantity } from '../../utils/currencyUtils';
|
||||
import { useProducts } from '../hooks';
|
||||
|
||||
export const RecordDetails: CustomFunctionComponent = () => {
|
||||
const form = useForm();
|
||||
const fieldSchema = useFieldSchema();
|
||||
@ -14,116 +14,103 @@ export const RecordDetails: CustomFunctionComponent = () => {
|
||||
const path: any = field.path.entire;
|
||||
const fieldPath = path?.replace(`.${fieldSchema.name}`, '');
|
||||
const itemPath = FormPath.parse('.', fieldPath).toString();
|
||||
const collection = useCollection();
|
||||
const record_id =
|
||||
collection.template === 'view' ? form.getValuesIn(itemPath).record_id : form.getValuesIn(itemPath).id;
|
||||
const reqRecordItems = useRequest<any>({
|
||||
resource: 'record_items',
|
||||
action: 'list',
|
||||
params: {
|
||||
appends: ['new_product'],
|
||||
appends: ['product', 'product.category'],
|
||||
filter: {
|
||||
record_id,
|
||||
record_id: form.getValuesIn(itemPath).id,
|
||||
},
|
||||
pageSize: 999,
|
||||
},
|
||||
});
|
||||
const { data: products } = useProducts();
|
||||
const reqRecordItemFeeItems = useRequest<any>({
|
||||
resource: 'record_contract',
|
||||
resource: 'record_item_fee_items',
|
||||
action: 'list',
|
||||
params: {
|
||||
appends: ['fees'],
|
||||
appends: ['product', 'record_item', 'record_item.product'],
|
||||
filter: {
|
||||
record_id: { $eq: record_id },
|
||||
record_item: {
|
||||
record_id: form.getValuesIn(itemPath).id,
|
||||
},
|
||||
},
|
||||
pageSize: 999,
|
||||
},
|
||||
});
|
||||
|
||||
const feeItems = {};
|
||||
const productItem = {};
|
||||
let feeItems = null;
|
||||
// 根据关联产品名称来合并赔偿
|
||||
if (reqRecordItemFeeItems.data && products) {
|
||||
reqRecordItemFeeItems.data.data?.forEach((contract, index) => {
|
||||
if (!contract.fees.length) return;
|
||||
const movement = contract.movement === '-1' ? '出库合同' : '入库合同';
|
||||
const contractfee = {};
|
||||
contract.fees.forEach((value) => {
|
||||
if (!value.new_product_id) return;
|
||||
const productItem = products.find((product) => product.id === value.new_product_id);
|
||||
const categoryProductItem = products.find((product) => product.id === productItem.parentId);
|
||||
const item = products.find((product) => product.id === value.new_fee_product_id);
|
||||
const categoryItem = products.find((product) => product.id === item.parentId);
|
||||
if (!productItem && !item && !categoryItem) return;
|
||||
const key = categoryProductItem?.id || value.new_product_id;
|
||||
const label = categoryItem.name ? `${categoryItem.name}[${item.name}]` : item.name;
|
||||
if (!Object.keys(contractfee).includes(key)) {
|
||||
contractfee[key] = {};
|
||||
if (reqRecordItemFeeItems.data) {
|
||||
feeItems = reqRecordItemFeeItems.data.data?.reduce((prev, current) => {
|
||||
if (current.record_item.product) {
|
||||
const key = current.record_item.product.name;
|
||||
if (!(key in prev)) {
|
||||
prev[key] = {};
|
||||
}
|
||||
if (!Object.keys(contractfee).includes(categoryItem.id)) {
|
||||
contractfee[key][categoryItem.id] = {
|
||||
productId: key,
|
||||
label,
|
||||
if (!current.product) {
|
||||
return prev;
|
||||
}
|
||||
if (!(current.product.label in prev[key])) {
|
||||
prev[key][current.product.label] = {
|
||||
id: current.product.id,
|
||||
label: current.product.label,
|
||||
count: 0,
|
||||
};
|
||||
}
|
||||
contractfee[key][categoryItem.id].count += value.count;
|
||||
});
|
||||
feeItems[movement + (index + 1)] = contractfee;
|
||||
});
|
||||
prev[key][current.product.label].count += current.count;
|
||||
}
|
||||
return prev;
|
||||
}, {});
|
||||
}
|
||||
const items = [];
|
||||
const productItem = {};
|
||||
if (reqRecordItems.data) {
|
||||
reqRecordItems.data.data?.forEach((item) => {
|
||||
if (!item.new_product_id) return;
|
||||
const categoryItem = products.find((value) => value.id === item.new_product.parentId);
|
||||
const key = categoryItem?.id || item.new_product.id;
|
||||
const count = categoryItem?.convertible ? item.count * item.new_product.ratio : item.count;
|
||||
const unit = categoryItem?.convertible ? categoryItem?.conversion_unit ?? '' : categoryItem?.unit ?? '';
|
||||
|
||||
const weight = item.count * item.new_product.weight;
|
||||
if (reqRecordItems.data && feeItems) {
|
||||
reqRecordItems.data.data?.forEach((item) => {
|
||||
if (!item.product) return;
|
||||
const key = item.product.name;
|
||||
const count = item.product.category.convertible ? item.count * item.product.ratio : item.count;
|
||||
const unit = item.product.category.convertible
|
||||
? item.product.category.conversion_unit
|
||||
: item.product.category.unit;
|
||||
|
||||
const weight = item.count * item.product.weight;
|
||||
if (productItem[key]) {
|
||||
productItem[key].count += count;
|
||||
productItem[key].weight += weight;
|
||||
} else {
|
||||
productItem[key] = {
|
||||
key,
|
||||
label: categoryItem?.name || item.new_product.name,
|
||||
key: item.product.category_id,
|
||||
label: item.product.name,
|
||||
sort: item.product.category.sort,
|
||||
unit,
|
||||
count,
|
||||
weight: weight,
|
||||
weight: formatQuantity(weight, 2) + 'KG',
|
||||
};
|
||||
}
|
||||
});
|
||||
for (const key in productItem) {
|
||||
productItem[key]['children'] = formatQuantity(productItem[key].count, 2) + productItem[key].unit;
|
||||
productItem[key]['span'] = 1;
|
||||
items.push(productItem[key]);
|
||||
productItem[key].children = formatQuantity(productItem[key].count, 2) + productItem[key].unit;
|
||||
productItem[key].span = 1;
|
||||
items.push({
|
||||
label: '理论重量',
|
||||
children: formatQuantity(productItem[key].weight, 2) + 'KG',
|
||||
children: [productItem[key].weight],
|
||||
});
|
||||
if (Object.keys(feeItems).length) {
|
||||
for (const fee in feeItems) {
|
||||
const children = {};
|
||||
children['movement'] = fee;
|
||||
const feeItem = feeItems[fee][key];
|
||||
if (!feeItem || !Object.keys(feeItem).length) {
|
||||
items.push({
|
||||
label: '维修赔偿',
|
||||
children: [''],
|
||||
});
|
||||
} else {
|
||||
children['label'] = Object.values(feeItem).reduce((pev, curr) => {
|
||||
return pev + `${curr['label']}:${curr['count']}`;
|
||||
}, '');
|
||||
items.push({
|
||||
label: '维修赔偿',
|
||||
children: `${children['movement']} : ${children['label']}`,
|
||||
});
|
||||
|
||||
if (key in feeItems) {
|
||||
productItem[key].span = 1;
|
||||
const children = [];
|
||||
for (const feeKey in feeItems[key]) {
|
||||
if (children.length > 0) {
|
||||
children.push(<br />);
|
||||
}
|
||||
children.push(feeItems[key][feeKey].label + ' ' + formatQuantity(feeItems[key][feeKey].count, 2));
|
||||
}
|
||||
items.push({
|
||||
label: '维修赔偿',
|
||||
children,
|
||||
});
|
||||
} else {
|
||||
items.push({
|
||||
label: '维修赔偿',
|
||||
@ -132,7 +119,7 @@ export const RecordDetails: CustomFunctionComponent = () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
items.sort((a, b) => a.key - b.key);
|
||||
items.sort((a, b) => a.sort - b.sort);
|
||||
if (reqRecordItems.loading || reqRecordItemFeeItems.loading) {
|
||||
return <Spin />;
|
||||
}
|
||||
|
@ -1,170 +1,213 @@
|
||||
import { observer } from '@tachybase/schema';
|
||||
import { onFieldInit, onFieldValueChange } from '@tachybase/schema';
|
||||
import { useField, useForm, useFormEffects } from '@tachybase/schema';
|
||||
import { CustomComponentType, CustomFC, CustomFunctionComponent } from '@hera/plugin-core/client';
|
||||
import { CustomComponentType, CustomFunctionComponent } from '@hera/plugin-core/client';
|
||||
import { useRequest } from '@tachybase/client';
|
||||
import _ from 'lodash';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { ConversionLogics, Movement, countCource } from '../../utils/constants';
|
||||
import { formatQuantity } from '../../utils/currencyUtils';
|
||||
import { useCachedRequest, useFeeItems, useProductFeeItems, useProducts } from '../hooks';
|
||||
import { useDeepCompareEffect } from 'ahooks';
|
||||
|
||||
export const RecordFeeConvertedAmount = observer((props) => {
|
||||
const form = useForm();
|
||||
const field = useField();
|
||||
const contractsItem = form.getValuesIn(field.path.slice(0, 2).entire);
|
||||
const date = form.getValuesIn('date');
|
||||
const formFeeItem = form.getValuesIn(field.path.slice(0, -2).entire);
|
||||
const contractPlanId = [contractsItem.contract?.id].filter(Boolean);
|
||||
const { data: products } = useProducts();
|
||||
const { data: feeItems } = useFeeItems(contractPlanId, date);
|
||||
const { data: productFeeRuleItems } = useProductFeeItems(contractPlanId, date);
|
||||
const reqWeightRules = useCachedRequest<any>({
|
||||
resource: 'weight_rules',
|
||||
export const RecordFeeConvertedAmount: CustomFunctionComponent = () => {
|
||||
// 查数据,查里面的费用关联的数据
|
||||
const contractPlans = useRequest<any>({
|
||||
resource: 'contract_plans',
|
||||
action: 'list',
|
||||
params: {
|
||||
appends: [
|
||||
'lease_items',
|
||||
'lease_items.products',
|
||||
'lease_items.fee_items',
|
||||
'lease_items.fee_items.conversion_logic',
|
||||
'lease_items.fee_items.conversion_logic.weight_items',
|
||||
'fee_items',
|
||||
'fee_items.conversion_logic',
|
||||
'fee_items.conversion_logic.weight_items',
|
||||
],
|
||||
pageSize: 99999,
|
||||
},
|
||||
});
|
||||
const productCategory = useRequest<any>({
|
||||
resource: 'product_category',
|
||||
action: 'list',
|
||||
params: {
|
||||
pageSize: 99999,
|
||||
},
|
||||
});
|
||||
const result = {};
|
||||
if (
|
||||
contractsItem.contract?.id &&
|
||||
products &&
|
||||
formFeeItem.new_product?.id &&
|
||||
formFeeItem.new_fee_product?.id &&
|
||||
formFeeItem.count &&
|
||||
Object.keys(productFeeRuleItems).length
|
||||
) {
|
||||
const productItem = products.find((value) => value.id === formFeeItem.new_product.id);
|
||||
const categoryItem = products.find((value) => value.id === productItem.parentId);
|
||||
const feeProductItem = products.find((value) => value.id === formFeeItem.new_fee_product.id);
|
||||
const productFeeItem = productFeeRuleItems[contractsItem.contract.id].find((contractItem) =>
|
||||
productItem?.['parentScopeId'].includes(contractItem.new_products_id),
|
||||
);
|
||||
const feeItem = productFeeItem?.fee_items?.find((value) =>
|
||||
feeProductItem?.['parentScopeId'].includes(value.new_fee_products_id),
|
||||
);
|
||||
const calc = { unit: categoryItem.unit, count: 0 };
|
||||
if (feeItem.count_source === countCource.artificial) {
|
||||
const { count, unit } = feeCalc(
|
||||
feeItem,
|
||||
productItem,
|
||||
formFeeItem.count,
|
||||
categoryItem,
|
||||
form.values,
|
||||
reqWeightRules?.data?.data,
|
||||
);
|
||||
|
||||
calc.unit = unit;
|
||||
calc.count = count;
|
||||
} else if (
|
||||
((feeItem.count_source === countCource.outProduct || feeItem.count_source === countCource.outItem) &&
|
||||
contractsItem.movement === '-1') ||
|
||||
((feeItem.count_source === countCource.enterProduct || feeItem.count_source === countCource.enterItem) &&
|
||||
contractsItem.movement === '1') ||
|
||||
feeItem.count_source === countCource.product ||
|
||||
feeItem.count_source === countCource.item
|
||||
) {
|
||||
const item = form.values.items.find((value) => value.new_product.id === formFeeItem.new_product.id);
|
||||
const { count, unit } = feeCalc(
|
||||
feeItem,
|
||||
productItem,
|
||||
item.count,
|
||||
categoryItem,
|
||||
form.values,
|
||||
reqWeightRules?.data?.data,
|
||||
);
|
||||
calc.unit = unit;
|
||||
calc.count = count;
|
||||
const [result, setResult] = useState('-');
|
||||
const [items, setItems] = useState([]);
|
||||
const [feeItems, setFeeItems] = useState([]);
|
||||
const [recordWeight, setWeight] = useState(0);
|
||||
const form = useForm();
|
||||
const field = useField();
|
||||
const recordData = {
|
||||
items: items,
|
||||
record_fee_items: feeItems,
|
||||
};
|
||||
const calcCount = () => {
|
||||
const path = field.path.entire as string;
|
||||
const newPath = path.replace('.converted_count.RecordFeeConvertedAmount', '');
|
||||
const pathArray: any = newPath.split('.');
|
||||
let target: any = recordData;
|
||||
for (let i = 0; i < pathArray.length; i++) {
|
||||
if (!isNaN(pathArray[i])) {
|
||||
pathArray[i] = parseInt(pathArray[i]);
|
||||
}
|
||||
target = target[pathArray[i]];
|
||||
}
|
||||
result['unit'] = calc.unit;
|
||||
result['count'] = calc.count;
|
||||
} else if (
|
||||
contractsItem.contract?.id &&
|
||||
products &&
|
||||
!formFeeItem.new_product?.id &&
|
||||
formFeeItem.new_fee_product?.id &&
|
||||
formFeeItem.count &&
|
||||
Object.keys(feeItems).length
|
||||
) {
|
||||
const feeItem = products.find((value) => value.id === formFeeItem.new_fee_product.id);
|
||||
const ruleItem = feeItems[contractsItem.contract.id]?.find((value) =>
|
||||
feeItem?.['parentScopeId'].includes(value.new_fee_products_id),
|
||||
);
|
||||
const calc = { unit: ruleItem.unit, count: 0 };
|
||||
if (
|
||||
ruleItem.count_source === countCource.artificial ||
|
||||
ruleItem.conversion_logic_id === ConversionLogics.ActualWeight
|
||||
) {
|
||||
calc.count = formFeeItem.count;
|
||||
if (ruleItem.conversion_logic_id === ConversionLogics.ActualWeight) calc.unit = '吨';
|
||||
} else if (
|
||||
((ruleItem.count_source === countCource.outProduct || ruleItem.count_source === countCource.outItem) &&
|
||||
contractsItem.movement === '-1') ||
|
||||
((ruleItem.count_source === countCource.enterProduct || ruleItem.count_source === countCource.enterItem) &&
|
||||
contractsItem.movement === '1') ||
|
||||
ruleItem.count_source === countCource.product ||
|
||||
ruleItem.count_source === countCource.item
|
||||
) {
|
||||
calc.count = [...form.values.items].reduce((prv, curr) => {
|
||||
if (!curr.new_product?.id) return prv + 0;
|
||||
const productItem = products.find((value) => value.id === curr.new_product.id);
|
||||
const categoryItem = products.find((value) => value.id === productItem.parentId);
|
||||
const { count, unit } = feeCalc(
|
||||
ruleItem,
|
||||
productItem,
|
||||
curr.count,
|
||||
categoryItem,
|
||||
form.values,
|
||||
reqWeightRules?.data?.data,
|
||||
let calcValue = 0;
|
||||
let feeRule;
|
||||
if (form.values.contract_plan) {
|
||||
const recordPlaid = contractPlans.data.data.find(
|
||||
(item) =>
|
||||
item.id === form.values.contract_plan.id ||
|
||||
(item.contract_id === form.values.contract_id &&
|
||||
item.start_date <= form.values.date &&
|
||||
item.end_date >= form.values.date),
|
||||
);
|
||||
const feeData = target;
|
||||
if (pathArray.length > 2) {
|
||||
// 关联产品费用
|
||||
const itemData = items[pathArray[1]];
|
||||
const productData = itemData?.product;
|
||||
// 租金规则
|
||||
const leaseRule = recordPlaid.lease_items.find((rule) =>
|
||||
rule.products.find(
|
||||
(product) => product.id - 99999 === productData.category_id || product.id === productData.id,
|
||||
),
|
||||
);
|
||||
return prv + count;
|
||||
}, 0);
|
||||
// 租金规则中的费用规则
|
||||
feeRule = leaseRule.fee_items.find((fee) => fee.fee_product_id === feeData.product?.id);
|
||||
if (!feeRule || !feeRule.conversion_logic_id || !feeRule.count_source) return;
|
||||
if (feeRule.count_source === countCource.artificial) {
|
||||
// 手工录入
|
||||
calcValue = feeData.count || 0;
|
||||
} else if (
|
||||
(feeRule.count_source === countCource.outProduct && form.values.movement === Movement.out) ||
|
||||
(feeRule.count_source === countCource.enterProduct && form.values.movement === Movement.in) ||
|
||||
feeRule.count_source === countCource.product
|
||||
) {
|
||||
// 出库量, 入库量, 出入库量
|
||||
calcValue = itemData.count || 0;
|
||||
}
|
||||
const category = productCategory.data.data.find((item) => item.id === productData.category_id);
|
||||
if (
|
||||
feeRule.conversion_logic_id === ConversionLogics.Keep ||
|
||||
feeRule.conversion_logic_id === ConversionLogics.ActualWeight
|
||||
) {
|
||||
// 不必处理
|
||||
} else if (feeRule.conversion_logic_id === ConversionLogics.Product) {
|
||||
calcValue = category.convertible ? calcValue * productData.ratio : calcValue;
|
||||
} else if (feeRule.conversion_logic_id === ConversionLogics.ProductWeight) {
|
||||
calcValue = calcValue * productData.weight;
|
||||
} else {
|
||||
const weightItem = feeRule.conversion_logic?.weight_items.find(
|
||||
(item) => item.product_id - 99999 === category.id || item.product_id === productData.id,
|
||||
);
|
||||
if (!weightItem) return;
|
||||
if (weightItem.conversion_logic_id === ConversionLogics.Keep) {
|
||||
calcValue = calcValue * weightItem.weight;
|
||||
} else if (weightItem.conversion_logic_id === ConversionLogics.Product) {
|
||||
calcValue = category.convertible
|
||||
? calcValue * productData.ratio * weightItem.weight
|
||||
: calcValue * weightItem.weight;
|
||||
}
|
||||
}
|
||||
if (!productData) return;
|
||||
// 定位组件所在的费用数据位置
|
||||
} else {
|
||||
feeRule = recordPlaid.fee_items.find((fee) => fee.fee_product_id === feeData.product?.id);
|
||||
if (!feeRule) return;
|
||||
let count;
|
||||
const category = productCategory.data.data.find((item) => item.id === feeData.product?.category_id);
|
||||
// 人工录入
|
||||
if (feeRule.count_source === countCource.artificial) {
|
||||
count = feeData.count;
|
||||
if (feeRule.conversion_logic_id === ConversionLogics.Keep) {
|
||||
calcValue = count;
|
||||
} else if (feeRule.conversion_logic_id === ConversionLogics.Product) {
|
||||
calcValue = category.convertible ? count * feeData.product?.ratio : count;
|
||||
} else if (feeRule.conversion_logic_id === ConversionLogics.ProductWeight) {
|
||||
calcValue = count * (feeData.product?.weight || 1);
|
||||
} else if (feeRule.conversion_logic_id === ConversionLogics.ActualWeight) {
|
||||
calcValue = form.values?.weight;
|
||||
} else {
|
||||
const weightItem = feeRule.conversion_logic?.weight_items.find((item) => {
|
||||
item.product_id - 99999 === category.id || item.product_id === feeData.product.id;
|
||||
});
|
||||
if (!weightItem) return;
|
||||
if (weightItem.conversion_logic_id === ConversionLogics.Keep) {
|
||||
calcValue = count * weightItem.weight;
|
||||
} else if (weightItem.conversion_logic_id === ConversionLogics.Product) {
|
||||
calcValue = category.convertible
|
||||
? count * feeData.product.ratio * weightItem.weight
|
||||
: count * weightItem.weight;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 出库/入库/出入库量
|
||||
// 出库单,但是规则不是出库产品量
|
||||
if (form.values.movement === Movement.out && feeRule.count_source === countCource.enterProduct) return;
|
||||
// 入库单,但是规则不是入库产品量
|
||||
if (form.values.movement === Movement.in && feeRule.count_source === countCource.outProduct) return;
|
||||
count = feeData.count;
|
||||
if (feeRule.conversion_logic_id === ConversionLogics.Keep) {
|
||||
calcValue = count;
|
||||
} else if (feeRule.conversion_logic_id === ConversionLogics.Product) {
|
||||
calcValue = category.convertible ? count * feeData.product.ratio : count;
|
||||
} else if (feeRule.conversion_logic_id === ConversionLogics.ProductWeight) {
|
||||
calcValue = count * (feeData.product.weight || 1);
|
||||
} else if (feeRule.conversion_logic_id === ConversionLogics.ActualWeight) {
|
||||
calcValue = form.values.weight;
|
||||
} else {
|
||||
let val = 0;
|
||||
items.forEach((item) => {
|
||||
const weightItem = feeRule.conversion_logic?.weight_items.find(
|
||||
(fee) => item.product?.id === fee.product_id - 99999 || item.product?.id === fee.product_id,
|
||||
);
|
||||
if (!weightItem) return;
|
||||
if (weightItem.conversion_logic_id === ConversionLogics.Keep) {
|
||||
val += item.count * weightItem.weight;
|
||||
} else if (weightItem.conversion_logic_id === ConversionLogics.Product) {
|
||||
val += category.convertible
|
||||
? item.count * feeData.product?.ratio * weightItem.weight
|
||||
: item.count * weightItem.weight;
|
||||
}
|
||||
});
|
||||
calcValue = val / 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result['unit'] = calc.unit;
|
||||
result['count'] = calc.count;
|
||||
}
|
||||
useDeepCompareEffect(() => {
|
||||
form.setValuesIn(field.path.entire, result);
|
||||
}, [formFeeItem, result]);
|
||||
return <span>{`${result['count'] || 0}${result['unit'] || ''}`}</span>;
|
||||
}) as CustomFC;
|
||||
setResult(formatQuantity(calcValue, 2) + (feeRule ? feeRule.unit : ''));
|
||||
};
|
||||
useFormEffects(() => {
|
||||
onFieldInit('items.*', () => {
|
||||
setItems(_.cloneDeep(form.values.items));
|
||||
});
|
||||
onFieldValueChange('items.*', () => {
|
||||
setItems(_.cloneDeep(form.values.items));
|
||||
});
|
||||
onFieldInit('record_fee_items.*', () => {
|
||||
setFeeItems(_.cloneDeep(form.values.record_fee_items));
|
||||
});
|
||||
onFieldValueChange('record_fee_items.*', () => {
|
||||
setFeeItems(_.cloneDeep(form.values.record_fee_items));
|
||||
});
|
||||
onFieldInit('weight', () => {
|
||||
setWeight(_.cloneDeep(form.values.weight));
|
||||
});
|
||||
onFieldValueChange('weight', () => {
|
||||
setWeight(_.cloneDeep(form.values.weight));
|
||||
});
|
||||
});
|
||||
useEffect(() => {
|
||||
if (!contractPlans.loading && !productCategory.loading) {
|
||||
calcCount();
|
||||
}
|
||||
}, [items, contractPlans, productCategory, feeItems, recordWeight]);
|
||||
return <span>{result}</span>;
|
||||
};
|
||||
|
||||
RecordFeeConvertedAmount.displayName = 'RecordFeeConvertedAmount';
|
||||
RecordFeeConvertedAmount.__componentType = CustomComponentType.CUSTOM_FIELD;
|
||||
RecordFeeConvertedAmount.__componentLabel = '费用 - 换算数量';
|
||||
|
||||
const feeCalc = (rule, item, itemCount, category, form, weightRule) => {
|
||||
const calc = { count: 0, unit: '' };
|
||||
if (rule.conversion_logic_id === ConversionLogics.Keep) {
|
||||
calc.count = itemCount;
|
||||
calc.unit = category.unit;
|
||||
} else if (rule.conversion_logic_id === ConversionLogics.Product) {
|
||||
calc.count = category.convertible ? item.ratio * itemCount : itemCount;
|
||||
calc.unit = category.convertible ? category.conversion_unit : category.unit;
|
||||
} else if (rule.conversion_logic_id === ConversionLogics.ActualWeight) {
|
||||
const groupWeight =
|
||||
form.group_weight_items?.find((value) => value.new_products?.id === category.id) || form.weight || 0;
|
||||
calc.count = groupWeight;
|
||||
calc.unit = '吨';
|
||||
} else if (rule.conversion_logic_id === ConversionLogics.ProductWeight) {
|
||||
calc.count = (itemCount * item.weight) / 1000;
|
||||
calc.unit = '吨';
|
||||
} else {
|
||||
const weightRuleItem = weightRule?.find(
|
||||
(weightItem) => weightItem.logic_id === rule.conversion_logic_id && weightItem.new_product_id === item.id,
|
||||
);
|
||||
if (weightRuleItem) {
|
||||
if (weightRuleItem.conversion_logic_id === ConversionLogics.Keep) {
|
||||
calc.count = (itemCount * weightRuleItem.weight) / 1000;
|
||||
calc.unit = '吨';
|
||||
} else if (weightRuleItem.conversion_logic_id === ConversionLogics.Product) {
|
||||
calc.count = category.convertible
|
||||
? (itemCount * item.ratio * weightRuleItem.weight) / 1000
|
||||
: (itemCount * weightRuleItem.weight) / 1000;
|
||||
calc.unit = '吨';
|
||||
}
|
||||
}
|
||||
}
|
||||
return calc;
|
||||
};
|
||||
|
@ -1,64 +1,69 @@
|
||||
import _ from 'lodash';
|
||||
import { Spin } from 'antd';
|
||||
import React, { useEffect } from 'react';
|
||||
import React from 'react';
|
||||
import { observer, useField, useFieldSchema, useForm } from '@tachybase/schema';
|
||||
import { CustomComponentType, CustomFC } from '@hera/plugin-core/client';
|
||||
import { useCachedRequest, useFeeItems, useProductFeeItems, useProducts } from '../hooks';
|
||||
import { useFeeItems } from '../hooks';
|
||||
import { useDeepCompareEffect } from 'ahooks';
|
||||
|
||||
export const RecordFeeScope = observer(() => {
|
||||
const form = useForm();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const field = useField();
|
||||
const contractsItem = form.getValuesIn(field.path.slice(0, 2).entire);
|
||||
const date = form.getValuesIn('date');
|
||||
const productsItem = form.getValuesIn(field.path.slice(0, -2).entire);
|
||||
const contractPlanId = [contractsItem.contract?.id].filter(Boolean);
|
||||
const { data: products } = useProducts();
|
||||
const { data: feeItems } = useFeeItems(contractPlanId, date);
|
||||
const { data: productFeeItems } = useProductFeeItems(contractPlanId, date);
|
||||
const result = [];
|
||||
const feeScope = { scopeItem: {} };
|
||||
if (contractsItem.contract?.id && products && productsItem.new_product?.id && Object.values(productFeeItems).length) {
|
||||
const productItem = products.find((value) => value.id === productsItem.new_product.id);
|
||||
const productFeeItem = productFeeItems[contractsItem.contract?.id]?.find((contractItem) =>
|
||||
productItem?.['parentScopeId'].includes(contractItem.new_products_id),
|
||||
const path: any = field.path.entire;
|
||||
const fieldPath = path?.replace(`.${fieldSchema.name}`, '');
|
||||
const item = form.getValuesIn(field.path.slice(0, -2).entire);
|
||||
let _loading = false;
|
||||
let contractLoading = false;
|
||||
const data = {
|
||||
data: [],
|
||||
};
|
||||
if (form.values.record_category === '1' || form.values.record_category === '0') {
|
||||
let _in = [],
|
||||
_out = [];
|
||||
const { data: inData, loading: inLoading } = useFeeItems(
|
||||
item.product?.category_id,
|
||||
form.values.in_contract_plan?.id,
|
||||
);
|
||||
productFeeItem?.fee_items.forEach((feeItem) => {
|
||||
const item = products.find((value) => value.id === feeItem.new_fee_products_id);
|
||||
if (!item) return;
|
||||
feeScope.scopeItem = isExist(feeScope.scopeItem, item);
|
||||
});
|
||||
result.push(...Object.values(feeScope.scopeItem));
|
||||
} else if (contractsItem.contract?.id && products && Object.values(feeItems).length) {
|
||||
feeItems[contractsItem.contract.id]?.forEach((feeItem) => {
|
||||
const item = products.find((value) => value.id === feeItem.new_fee_products_id);
|
||||
if (!item) return;
|
||||
feeScope.scopeItem = isExist(feeScope.scopeItem, item);
|
||||
});
|
||||
result.push(...Object.values(feeScope.scopeItem));
|
||||
_in = inData?.data || [];
|
||||
contractLoading = contractLoading || inLoading;
|
||||
if (form.values.record_category === '1') {
|
||||
const { data: outData, loading: outLoading } = useFeeItems(
|
||||
item.product?.category_id,
|
||||
form.values.out_contract_plan?.id,
|
||||
);
|
||||
_out = outData?.data || [];
|
||||
contractLoading = contractLoading || outLoading;
|
||||
}
|
||||
data.data = [..._in, ..._out];
|
||||
} else {
|
||||
const { data: origin, loading } = useFeeItems(item.product?.category_id, form.values.contract_plan?.id);
|
||||
data.data = origin?.data;
|
||||
_loading = _loading || loading;
|
||||
}
|
||||
let result = [];
|
||||
if (data.data?.length > 0) {
|
||||
const items = data.data as {
|
||||
products: { category_id: Number }[];
|
||||
fee_items: { fee_product_id: Number }[];
|
||||
}[];
|
||||
result = items.reduce((acc, current) => {
|
||||
acc.push(...current.fee_items.map((item) => ({ id: item.fee_product_id })));
|
||||
return acc;
|
||||
}, []);
|
||||
}
|
||||
useDeepCompareEffect(() => {
|
||||
form.setValuesIn(field.path.slice(0, -1).entire, result);
|
||||
}, [result, form]);
|
||||
return !contractsItem ? <Spin /> : <></>;
|
||||
form.setValuesIn(fieldPath, result);
|
||||
}, [result, form, fieldPath]);
|
||||
|
||||
return ((form.values.record_category === '1' || form.values.record_category === '0') && contractLoading) ||
|
||||
_loading ? (
|
||||
<Spin />
|
||||
) : (
|
||||
<></>
|
||||
);
|
||||
}) as CustomFC;
|
||||
|
||||
RecordFeeScope.displayName = 'RecordFeeScope';
|
||||
RecordFeeScope.__componentType = CustomComponentType.CUSTOM_ASSOCIATED_FIELD;
|
||||
RecordFeeScope.__componentLabel = '记录单 - 费用范围';
|
||||
|
||||
const isExist = (feeItemScope, item) => {
|
||||
if (!Object.keys(feeItemScope).length) feeItemScope[item.id] = item;
|
||||
const isParent = Object.values(feeItemScope)?.find(
|
||||
(value) => value['parentScopeId'].includes(item.id) && item.id !== value['id'],
|
||||
);
|
||||
const isChildren = Object.values(feeItemScope)?.find(
|
||||
(value) => item['parentScopeId'].includes(value['id']) && item.id !== value['id'],
|
||||
);
|
||||
if (isParent) return feeItemScope;
|
||||
if (isChildren) {
|
||||
delete feeItemScope[isChildren['id']];
|
||||
}
|
||||
feeItemScope[item.id] = item;
|
||||
return feeItemScope;
|
||||
};
|
||||
|
@ -4,21 +4,30 @@ import { observer, useField, useForm } from '@tachybase/schema';
|
||||
import _ from 'lodash';
|
||||
import { formatQuantity } from '../../utils/currencyUtils';
|
||||
import { Spin } from 'antd';
|
||||
import { useCachedRequest, useProducts } from '../hooks';
|
||||
import { useCachedRequest } from '../hooks';
|
||||
|
||||
export const RecordItemCount = observer((props) => {
|
||||
const form = useForm();
|
||||
const field = useField();
|
||||
const { data } = useProducts();
|
||||
if (!data) {
|
||||
const param = {
|
||||
resource: 'product_category',
|
||||
action: 'list',
|
||||
params: {
|
||||
pageSize: 99999,
|
||||
},
|
||||
};
|
||||
const { loading, data } = useCachedRequest<any>(param);
|
||||
|
||||
if (!data && loading) {
|
||||
return <Spin />;
|
||||
}
|
||||
const item = form.getValuesIn(field.path.slice(0, -2).entire);
|
||||
if (item?.new_product && item?.count) {
|
||||
const category = data.find((category) => category.id === item?.new_product.parentId);
|
||||
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.new_product.ratio || 0) * item.count : item.count;
|
||||
const value = category.convertible ? (item.product.ratio || 0) * item.count : item.count;
|
||||
const unit = category.convertible ? category.conversion_unit : category.unit || '';
|
||||
|
||||
return <span>{formatQuantity(value, 2) + unit}</span>;
|
||||
}
|
||||
return <span> - </span>;
|
||||
|
@ -2,24 +2,27 @@ import React from 'react';
|
||||
import { CustomComponentType, CustomFC } from '@hera/plugin-core/client';
|
||||
import { observer, useField, useForm } from '@tachybase/schema';
|
||||
import _ from 'lodash';
|
||||
import { ConversionLogics } from '../../utils/constants';
|
||||
import { ConversionLogics, RecordCategory } from '../../utils/constants';
|
||||
import { formatQuantity } from '../../utils/currencyUtils';
|
||||
import { useCachedRequest, useLeaseItems, useProducts } from '../hooks';
|
||||
import { useCachedRequest, useLeaseItems, useProductFeeItems } from '../hooks';
|
||||
|
||||
// 计价数量
|
||||
export const RecordItemValuationQuantity = observer((props) => {
|
||||
const form = useForm();
|
||||
const field = useField();
|
||||
const contractPlanId = form
|
||||
.getValuesIn('new_contracts')
|
||||
?.map((value) => {
|
||||
return value.contract?.id;
|
||||
})
|
||||
.filter(Boolean);
|
||||
const contractPlan = form.getValuesIn('new_contracts');
|
||||
const date = form.getValuesIn('date');
|
||||
const contractPlanId = form.getValuesIn('contract_plan')?.id;
|
||||
const inContractPlanId = form.getValuesIn('in_contract_plan')?.id;
|
||||
const outContractPlanId = form.getValuesIn('out_contract_plan')?.id;
|
||||
const priceItems = form.getValuesIn('price_items');
|
||||
const result = [];
|
||||
const { data: reqProduct } = useProducts();
|
||||
const reqProduct = useCachedRequest<any>({
|
||||
resource: 'product',
|
||||
action: 'list',
|
||||
params: {
|
||||
appends: ['category'],
|
||||
pageSize: 99999,
|
||||
},
|
||||
});
|
||||
const reqWeightRules = useCachedRequest<any>({
|
||||
resource: 'weight_rules',
|
||||
action: 'list',
|
||||
@ -27,25 +30,116 @@ export const RecordItemValuationQuantity = observer((props) => {
|
||||
pageSize: 99999,
|
||||
},
|
||||
});
|
||||
const { data: leaseItems } = useLeaseItems(contractPlanId, date);
|
||||
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?.new_product && item?.count && Object.keys(leaseItems).length) {
|
||||
if (item?.product && item?.count) {
|
||||
// 关联产品
|
||||
if (!reqProduct) {
|
||||
if (!reqProduct.data) {
|
||||
return;
|
||||
}
|
||||
const productCategory = reqProduct.find((value) => value.id === item.new_product.parentId);
|
||||
contractPlan.forEach((contractPlanItem, index) => {
|
||||
if (!contractPlanItem.contract) return;
|
||||
const rule = leaseItems[contractPlanItem.contract.id]?.find((product) => {
|
||||
return selParentId(reqProduct, item.new_product, product.new_products_id);
|
||||
});
|
||||
const count = subtotal(rule, item, productCategory, reqWeightRules);
|
||||
const movement = contractPlanItem.movement === '-1' ? '出库' : '入库';
|
||||
count && result.push({ label: movement + '合同' + (index + 1), value: count });
|
||||
});
|
||||
const productCategory = reqProduct.data.data?.find(
|
||||
(product) => product.category_id === item.product?.category_id,
|
||||
)?.category;
|
||||
// 合同
|
||||
if (form.values.category === RecordCategory.lease && leaseItems) {
|
||||
const rule = leaseItems.data.find((leaseItem) =>
|
||||
leaseItem.products.find(
|
||||
(product) => product.id - 99999 === item.product?.category_id || product.id === item.product?.id,
|
||||
),
|
||||
);
|
||||
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 });
|
||||
}
|
||||
// 采购
|
||||
if (form.values.category === RecordCategory.purchase && priceItems) {
|
||||
const rule = priceItems?.find(
|
||||
(rule) => rule.product?.category_id === item.product?.category_id || rule.product?.id === item.product?.id,
|
||||
);
|
||||
if (rule) {
|
||||
rule.conversion_logic_id = rule.conversion_logic?.id;
|
||||
const count = subtotal(rule, item, productCategory, reqWeightRules);
|
||||
count && result.push({ label: '报价', value: count });
|
||||
}
|
||||
}
|
||||
// 暂存或结存
|
||||
if (form.values.category === RecordCategory.inventory || form.values.category === RecordCategory.staging) {
|
||||
result.push([{ label: '', value: '-' }]);
|
||||
}
|
||||
// 采购直发
|
||||
if (form.values.category === RecordCategory.purchase2lease && priceItems && inLeaseItems) {
|
||||
const rule = priceItems?.find(
|
||||
(rule) => rule.product?.category_id === item.product?.category_id || rule.product?.id === item.product?.id,
|
||||
);
|
||||
if (rule) {
|
||||
rule.conversion_logic_id = rule.conversion_logic.id;
|
||||
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 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 });
|
||||
}
|
||||
// 租赁直发
|
||||
if (form.values.category === RecordCategory.lease2lease && inLeaseItems && outLeaseItems) {
|
||||
const contractPlain_out = outLeaseItems.data.find((leaseItem) =>
|
||||
leaseItem.products.find(
|
||||
(product) => product.id - 99999 === item.product?.category_id || product.id === item.product?.id,
|
||||
),
|
||||
);
|
||||
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 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 });
|
||||
}
|
||||
}
|
||||
return (
|
||||
<>
|
||||
@ -62,17 +156,21 @@ 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.new_product.ratio : itemData.count;
|
||||
unit = productCategory.convertible ? productCategory.conversion_unit || '' : productCategory.unit || '';
|
||||
count = productCategory.convertible ? itemData.count * itemData.product.ratio : itemData.count;
|
||||
unit = item
|
||||
? rule.unit || ''
|
||||
: productCategory.convertible
|
||||
? productCategory.conversion_unit || ''
|
||||
: productCategory.unit || '';
|
||||
} else if (rule?.conversion_logic_id === ConversionLogics.ProductWeight) {
|
||||
count = (itemData.count * itemData.weight) / 1000;
|
||||
count = item ? itemData.count : (itemData.count * itemData.product.weight) / 1000;
|
||||
unit = '吨';
|
||||
} else if (rule?.conversion_logic_id === ConversionLogics.ActualWeight) {
|
||||
count = 0;
|
||||
@ -80,29 +178,23 @@ const subtotal = (rule: any, itemData: any, productCategory: any, reqWeightRules
|
||||
} else {
|
||||
// 查询重量规则
|
||||
const weightRule = reqWeightRules?.data?.data?.find(
|
||||
(weightItem) =>
|
||||
weightItem.logic_id === rule?.conversion_logic_id && weightItem.new_product_id === itemData.new_product.id,
|
||||
(weight_item) =>
|
||||
weight_item.logic_id === rule?.conversion_logic_id &&
|
||||
(weight_item.product_id === itemData.product?.id ||
|
||||
weight_item.product_id === itemData.product?.category_id + 99999),
|
||||
);
|
||||
if (weightRule?.conversion_logic_id === ConversionLogics.Keep) {
|
||||
count = ((itemData.count || 0) * weightRule.weight) / 1000;
|
||||
if (!weightRule) return;
|
||||
if (weightRule.conversion_logic_id === ConversionLogics.Keep) {
|
||||
count = item ? (itemData.count || 0) * weightRule.weight : ((itemData.count || 0) * weightRule.weight) / 1000;
|
||||
unit = '吨';
|
||||
} else if (weightRule?.conversion_logic_id === ConversionLogics.Product) {
|
||||
const sacl = productCategory.convertible ? itemData.ratio : 1;
|
||||
count = ((itemData.count || 0) * sacl * weightRule.weight) / 1000;
|
||||
} else if (weightRule.conversion_logic_id === ConversionLogics.Product) {
|
||||
const sacl = productCategory.convertible ? itemData.product.ratio : 1;
|
||||
count = item
|
||||
? (itemData.count || 0) * sacl * weightRule.weight
|
||||
: ((itemData.count || 0) * sacl * weightRule.weight) / 1000;
|
||||
unit = '吨';
|
||||
}
|
||||
}
|
||||
const res = count > 0 ? formatQuantity(count, 2) + unit : '-';
|
||||
return res;
|
||||
};
|
||||
|
||||
const selParentId = (products, item, priceItemsId) => {
|
||||
if (item.id === priceItemsId || item?.parentId === priceItemsId) {
|
||||
return item;
|
||||
} else if (item.parentId) {
|
||||
const productItem = products.find((value) => value.id === item.parentId);
|
||||
return selParentId(products, productItem, priceItemsId);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
@ -8,10 +8,10 @@ export const RecordItemWeight = observer((props) => {
|
||||
const form = useForm();
|
||||
const field = useField();
|
||||
const item = form.getValuesIn(field.path.slice(0, -2).entire);
|
||||
if (item?.new_product && item?.count) {
|
||||
const value = ((item.new_product.weight || 0) * item.count) / 1000;
|
||||
if (item?.product && item?.count) {
|
||||
const value = ((item.product.weight || 0) * item.count) / 1000;
|
||||
if (value) {
|
||||
return <span>{formatQuantity(value, 3) + '吨'}</span>;
|
||||
return <span>{formatQuantity(value, 2) + '吨'}</span>;
|
||||
}
|
||||
}
|
||||
return <span> - </span>;
|
||||
|
@ -4,71 +4,160 @@ import React from 'react';
|
||||
import { observer, useForm } from '@tachybase/schema';
|
||||
import { RecordCategory } from '../../utils/constants';
|
||||
import { CustomComponentType, CustomFC } from '@hera/plugin-core/client';
|
||||
import { useCachedRequest, useLeaseItems, useProducts } from '../hooks';
|
||||
import { useCachedRequest, useLeaseItems, useProductFeeItems } from '../hooks';
|
||||
import { useDeepCompareEffect } from 'ahooks';
|
||||
|
||||
export const RecordProductScope = observer(() => {
|
||||
const form = useForm();
|
||||
const contractPlanId = form
|
||||
.getValuesIn('new_contracts')
|
||||
?.map((value) => {
|
||||
return value.contract?.id;
|
||||
})
|
||||
.filter(Boolean);
|
||||
const contractPlan = form.getValuesIn('new_contracts');
|
||||
const date = form.getValuesIn('date');
|
||||
const { data: products } = useProducts();
|
||||
const { data: leaseItems } = useLeaseItems(contractPlanId, date);
|
||||
const result = [];
|
||||
if (contractPlanId?.length && products && Object.keys(leaseItems).length) {
|
||||
const leaseItem = {};
|
||||
contractPlan.forEach((contractPlanItem) => {
|
||||
leaseItems[contractPlanItem.contract?.id]?.forEach((contractItem) => {
|
||||
if (!contractItem.new_products?.id) return;
|
||||
const item = products.find((value) => value.id === contractItem.new_products.id);
|
||||
const isParent = Object.values(leaseItem).find(
|
||||
(value) => value['parentScopeId'].includes(item.id) && item.id !== value['id'],
|
||||
);
|
||||
const isChildren = Object.values(leaseItem).find(
|
||||
(value) => item['parentScopeId'].includes(value['id']) && item.id !== value['id'],
|
||||
);
|
||||
if (isParent) return;
|
||||
if (isChildren) {
|
||||
delete leaseItem[isChildren['id']];
|
||||
leaseItem[item.id] = item;
|
||||
} else {
|
||||
leaseItem[item.id] = item;
|
||||
}
|
||||
const contractPlanId = form.getValuesIn('contract_plan')?.id;
|
||||
const inContractPlanId = form.getValuesIn('in_contract_plan')?.id;
|
||||
const outContractPlanId = form.getValuesIn('out_contract_plan')?.id;
|
||||
|
||||
let required = { price: false, contract: false, inContract: false, outContract: false };
|
||||
const { data, loading } = useCachedRequest<any>({
|
||||
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);
|
||||
|
||||
/**
|
||||
* 合同费用数据格式trans
|
||||
*/
|
||||
const transFee = (fee: any[]) => {
|
||||
if (fee) {
|
||||
const feeData = fee.map((fee) => {
|
||||
const data = {
|
||||
...fee,
|
||||
};
|
||||
data.products = [data.fee_product];
|
||||
return data;
|
||||
});
|
||||
});
|
||||
result.push(...Object.values(leaseItem));
|
||||
} else if (!contractPlanId?.length && products) {
|
||||
const leaseItem = {};
|
||||
products.forEach((item) => {
|
||||
const isParent = Object.values(leaseItem).find(
|
||||
(value) => value['parentScopeId'].includes(item.id) && item.id !== value['id'],
|
||||
);
|
||||
const isChildren = Object.values(leaseItem).find(
|
||||
(value) => item['parentScopeId'].includes(value['id']) && item.id !== value['id'],
|
||||
);
|
||||
if (isParent) return;
|
||||
if (isChildren) {
|
||||
delete leaseItem[isChildren['id']];
|
||||
leaseItem[item.id] = item;
|
||||
} else {
|
||||
leaseItem[item.id] = item;
|
||||
}
|
||||
});
|
||||
result.push(...Object.values(leaseItem));
|
||||
return feeData || [];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 生成合同产品/费用的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) => {
|
||||
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:
|
||||
required = { price: false, contract: true, inContract: false, outContract: false };
|
||||
break;
|
||||
case RecordCategory.purchase:
|
||||
required = { price: true, contract: false, inContract: false, outContract: false };
|
||||
break;
|
||||
case RecordCategory.lease2lease:
|
||||
required = { price: false, contract: false, inContract: true, outContract: true };
|
||||
break;
|
||||
case RecordCategory.purchase2lease: // 报价,入库合同的产品范围交集, 加入入库合同的费用数据
|
||||
required = { price: true, contract: false, inContract: true, outContract: false };
|
||||
break;
|
||||
case RecordCategory.inventory:
|
||||
case RecordCategory.staging:
|
||||
required = { price: false, contract: false, inContract: false, outContract: false };
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
let result = data?.data ?? [];
|
||||
if (required.inContract && required.outContract) {
|
||||
// 租赁直发单
|
||||
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'),
|
||||
_.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) {
|
||||
const data = intersectionByMultiple(result, priceProducts, 'category_id');
|
||||
result = [_.intersectionBy(result, priceProducts, 'id'), data].flat();
|
||||
} else if (required.contract) {
|
||||
const data = intersectionByMultiple(result, contractProducts, 'category_id');
|
||||
result = [_.intersectionBy(result, contractProducts, 'id'), data].flat();
|
||||
}
|
||||
useDeepCompareEffect(() => {
|
||||
form.setValues({
|
||||
product_scope: result,
|
||||
});
|
||||
}, [result, form]);
|
||||
return !Object.keys(leaseItems).length && !products ? <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;
|
||||
};
|
||||
|
@ -1,22 +1,21 @@
|
||||
import { observer, useForm } from '@tachybase/schema';
|
||||
import { ConversionLogics } from '../../utils/constants';
|
||||
import { ConversionLogics, RecordCategory } from '../../utils/constants';
|
||||
import { Descriptions, Tabs } from 'antd';
|
||||
import { CustomComponentType, CustomFC } from '@hera/plugin-core/client';
|
||||
import { CustomComponentType, CustomFC, CustomFunctionComponent } from '@hera/plugin-core/client';
|
||||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
import { formatCurrency, formatQuantity } from '../../utils/currencyUtils';
|
||||
import { useCachedRequest, useLeaseItems, useProducts } from '../hooks';
|
||||
import { useCachedRequest, useLeaseItems, useProductFeeItems } from '../hooks';
|
||||
import { RecordItems } from '../../interfaces/records';
|
||||
const cache = [];
|
||||
export const RecordSummary = observer((): any => {
|
||||
cache.length = 0;
|
||||
const form = useForm();
|
||||
const contractPlanId = form
|
||||
.getValuesIn('new_contracts')
|
||||
?.map((value) => {
|
||||
return value.contract?.id;
|
||||
})
|
||||
.filter(Boolean);
|
||||
const contractPlan = form.getValuesIn('new_contracts');
|
||||
const date = form.getValuesIn('date');
|
||||
const resultForm = form.values;
|
||||
const contractPlanId = form.values.contract_plan?.id;
|
||||
const inContractPlanId = form.values.in_contract_plan?.id;
|
||||
const outContractPlanId = form.values.out_contract_plan?.id;
|
||||
|
||||
const leaseData = form.values.price_items;
|
||||
const reqWeightRules = useCachedRequest<any>({
|
||||
resource: 'weight_rules',
|
||||
action: 'list',
|
||||
@ -24,75 +23,136 @@ export const RecordSummary = observer((): any => {
|
||||
pageSize: 99999,
|
||||
},
|
||||
});
|
||||
const { data: products } = useProducts();
|
||||
const reqProduct = useCachedRequest<any>({
|
||||
resource: 'product',
|
||||
action: 'list',
|
||||
params: {
|
||||
appends: ['category'],
|
||||
pageSize: 99999,
|
||||
},
|
||||
});
|
||||
//合同方案
|
||||
const { data: leaseItems } = useLeaseItems(contractPlanId, date);
|
||||
const { data: leaseItems } = useLeaseItems(contractPlanId);
|
||||
const { data: inLeaseItems } = useLeaseItems(inContractPlanId);
|
||||
const { data: outLeaseItems } = useLeaseItems(outContractPlanId);
|
||||
|
||||
if (!products) {
|
||||
if (!reqProduct.data) {
|
||||
return '';
|
||||
}
|
||||
const allPrice = {
|
||||
name: '总金额',
|
||||
total: 0,
|
||||
unit: '',
|
||||
};
|
||||
const weight = {
|
||||
name: '理论重量',
|
||||
total: 0,
|
||||
unit: '吨',
|
||||
};
|
||||
const priceWeight = {
|
||||
name: '理论重量',
|
||||
total: 0,
|
||||
unit: '吨',
|
||||
};
|
||||
const contractWeight = {
|
||||
name: '理论重量',
|
||||
total: 0,
|
||||
unit: '吨',
|
||||
};
|
||||
const outContractWeight = {
|
||||
name: '理论重量',
|
||||
total: 0,
|
||||
unit: '吨',
|
||||
};
|
||||
// 订单分组实际重量
|
||||
const recordData = form.values;
|
||||
// 基础小结
|
||||
const summaryProduct = {};
|
||||
// 合同小结/入库合同小结
|
||||
const contractSummary = {};
|
||||
// 出库合同小结
|
||||
const outContractSummary = {};
|
||||
// 报价小结
|
||||
const quoteSummary = {};
|
||||
form.values.items?.forEach((item) => {
|
||||
const productCategory = reqProduct.data.data?.find(
|
||||
(product) => product.category_id === item.product?.category_id,
|
||||
)?.category;
|
||||
if (!(JSON.stringify(productCategory?.attr) === `["6"]`)) {
|
||||
if (!item.product || !item.count) return;
|
||||
const element = _.cloneDeep(item);
|
||||
// 获取产品的分类数据信息
|
||||
if (!productCategory) return;
|
||||
element.product.category = productCategory;
|
||||
// 基础小结
|
||||
const { calc } = summary(element, null, null);
|
||||
weight.total += calc.weight / 1000;
|
||||
calcProductCount(summaryProduct, calc, productCategory);
|
||||
// 合同小结(租赁出入库单/租赁直发单)
|
||||
|
||||
const resultItems = {};
|
||||
if (form.values.items?.length && contractPlan?.length) {
|
||||
form.values.items.forEach((item) => {
|
||||
if (!item?.new_product_id && !item?.count) return;
|
||||
const productItem = products.find((value) => value.id === item.new_product.id);
|
||||
const productCategory = products?.find((value) => value.id === item.new_product.parentId);
|
||||
resultItems['basis'] = basisItem(productCategory, item, productItem, resultItems['basis']);
|
||||
contractPlan.forEach((contractPlanItem, index) => {
|
||||
if (!contractPlanItem.contract) return;
|
||||
const movement = contractPlanItem.movement === '-1' ? '出库' : '入库';
|
||||
const record_category = contractPlanItem.contract.record_category;
|
||||
const rule = leaseItems[contractPlanItem.contract.id]?.find((value) =>
|
||||
productItem?.parentScopeId.includes(value.new_products_id),
|
||||
);
|
||||
resultItems[movement + index] = ruleItem(
|
||||
record_category,
|
||||
movement,
|
||||
index + 1,
|
||||
rule,
|
||||
resultForm,
|
||||
productCategory,
|
||||
item,
|
||||
productItem,
|
||||
resultItems[movement + index],
|
||||
reqWeightRules,
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const trans: any[] = Object.values(resultItems)
|
||||
.map((item) => {
|
||||
let price = 0;
|
||||
let weight = 0;
|
||||
const valueItem = Object.values(item['value']).map((resultValue) => {
|
||||
price += resultValue['price'] ?? 0;
|
||||
weight += resultValue['weight'] ?? 0;
|
||||
return {
|
||||
key: resultValue['label'],
|
||||
label: resultValue['label'],
|
||||
children: formatQuantity(resultValue['count'], 3) + resultValue['unit'],
|
||||
};
|
||||
});
|
||||
valueItem.unshift({
|
||||
key: '理论重量',
|
||||
label: '理论重量',
|
||||
children: formatQuantity(weight, 3) + '吨',
|
||||
});
|
||||
if (item['record_category'] === '1') {
|
||||
valueItem.push({
|
||||
key: '总金额',
|
||||
label: '总金额',
|
||||
children: formatCurrency(price, 3),
|
||||
});
|
||||
if (form.values.category === RecordCategory.lease || form.values.category === RecordCategory.lease2lease) {
|
||||
if (form.values.category === RecordCategory.lease && !leaseItems) return;
|
||||
if (form.values.category === RecordCategory.lease2lease && !inLeaseItems) return;
|
||||
const in_contract = form.values.category === RecordCategory.lease ? leaseItems.data : inLeaseItems.data;
|
||||
const { ruleCalc } = summary(element, in_contract, reqWeightRules, recordData);
|
||||
contractWeight.total += ruleCalc.weight / 1000;
|
||||
calcProductCount(contractSummary, ruleCalc, productCategory);
|
||||
if (form.values.category === RecordCategory.lease2lease && outLeaseItems) {
|
||||
// 还需要生成出库合同小结
|
||||
const out_contract = outLeaseItems.data;
|
||||
const { ruleCalc } = summary(element, out_contract, reqWeightRules, recordData);
|
||||
outContractWeight.total += ruleCalc.weight / 1000;
|
||||
calcProductCount(outContractSummary, ruleCalc, productCategory);
|
||||
}
|
||||
}
|
||||
// 采购出入库/采购直发小结
|
||||
if (form.values.category === RecordCategory.purchase || form.values.category === RecordCategory.purchase2lease) {
|
||||
const priceRules = leaseData?.map((rule) => {
|
||||
return {
|
||||
conversion_logic_id: rule.conversion_logic.id,
|
||||
products: rule.product,
|
||||
unit_price: rule.unit_price,
|
||||
};
|
||||
});
|
||||
const { ruleCalc } = summary(element, priceRules, reqWeightRules, recordData);
|
||||
priceWeight.total += ruleCalc.weight / 1000;
|
||||
allPrice.total += ruleCalc.price;
|
||||
calcProductCount(quoteSummary, ruleCalc, productCategory);
|
||||
if (form.values.category === RecordCategory.purchase2lease && inLeaseItems) {
|
||||
const in_contract = inLeaseItems.data;
|
||||
const { ruleCalc } = summary(element, in_contract, null, recordData);
|
||||
contractWeight.total += ruleCalc.weight / 1000;
|
||||
calcProductCount(contractSummary, ruleCalc, productCategory);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
summaryProduct['0'] = weight;
|
||||
contractSummary['0'] = contractWeight;
|
||||
outContractSummary['0'] = outContractWeight;
|
||||
quoteSummary['0'] = priceWeight;
|
||||
quoteSummary['999'] = allPrice;
|
||||
|
||||
const resultItems = [
|
||||
{ label: '基础', value: transDescriptions(Object.values(summaryProduct)) },
|
||||
{ label: '报价', value: transDescriptions(Object.values(quoteSummary)) },
|
||||
{ label: '出库合同', value: transDescriptions(Object.values(outContractSummary)) },
|
||||
{
|
||||
label: form.values.category === RecordCategory.lease ? '合同' : '入库合同',
|
||||
value: transDescriptions(Object.values(contractSummary)),
|
||||
},
|
||||
];
|
||||
|
||||
const trans: any[] = resultItems
|
||||
.map((item) => {
|
||||
if (item.value.length) {
|
||||
const data = {
|
||||
label: item.label,
|
||||
key: item.label,
|
||||
children: <Descriptions items={item.value} />,
|
||||
};
|
||||
return data;
|
||||
}
|
||||
const data = {
|
||||
label: item['label'],
|
||||
key: item['label'],
|
||||
children: <Descriptions items={valueItem} />,
|
||||
};
|
||||
return data;
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
@ -116,144 +176,125 @@ RecordSummary.__componentType = CustomComponentType.CUSTOM_FORM_ITEM;
|
||||
RecordSummary.__componentLabel = '记录单 - 小结';
|
||||
|
||||
/** 计算小结
|
||||
* @param event RecordItem 订单项,record_item
|
||||
*/
|
||||
const summary = (rule, itemCount, category, item, ruleWeight) => {
|
||||
const summary = (event: RecordItems, rules: any[], ruleWeight: any, recordData = null) => {
|
||||
// 1. 没有规则直接默认产品表换算逻辑
|
||||
const calc = {
|
||||
name: '',
|
||||
count: 0,
|
||||
weight: 0,
|
||||
unit: '',
|
||||
};
|
||||
const ruleCalc = {
|
||||
name: '',
|
||||
count: 0,
|
||||
weight: 0,
|
||||
unit: '',
|
||||
price: 0,
|
||||
};
|
||||
calc.name = category.name;
|
||||
const convertible = category.convertible;
|
||||
if (rule.conversion_logic_id === ConversionLogics.Keep) {
|
||||
calc.count = itemCount;
|
||||
calc.unit = category.unit;
|
||||
} else if (rule.conversion_logic_id === ConversionLogics.Product) {
|
||||
calc.count = convertible ? itemCount * item.ratio : itemCount;
|
||||
calc.unit = convertible ? category.conversion_unit : category.unit;
|
||||
} else if (rule.conversion_logic_id === ConversionLogics.ProductWeight) {
|
||||
calc.count = (itemCount * item.weight) / 1000;
|
||||
calc.unit = '吨';
|
||||
const category = event.product.category;
|
||||
const convertiblen = category.convertible;
|
||||
if (!rules) {
|
||||
const count = convertiblen ? event.count * event.product.ratio : event.count;
|
||||
const unit = convertiblen ? category.conversion_unit : category.unit;
|
||||
calc.name = category.name;
|
||||
calc.count = count;
|
||||
calc.unit = unit;
|
||||
calc.weight = event.product.weight * event.count;
|
||||
} else {
|
||||
const weightRule = ruleWeight?.find(
|
||||
(weightItem) => weightItem.logic_id === rule.conversion_logic_id && weightItem.new_product_id === item.id,
|
||||
// 2. 存在规则(实际重量情况不计算)
|
||||
const plain = rules.find((item) =>
|
||||
// 处理报价跟合同不同数据结构问题 [].flat()
|
||||
[item.products]
|
||||
.flat()
|
||||
.find((product) => product?.id - 99999 === event.product.category_id || product?.id === event.product.id),
|
||||
);
|
||||
if (weightRule) {
|
||||
if (weightRule.conversion_logic_id === ConversionLogics.Keep) {
|
||||
calc.count = (itemCount * weightRule.weight) / 1000;
|
||||
calc.unit = '吨';
|
||||
} else if (weightRule.conversion_logic_id === ConversionLogics.Product) {
|
||||
calc.count = convertible
|
||||
? (itemCount * item.ratio * weightRule.weight) / 1000
|
||||
: (itemCount * weightRule.weight) / 1000;
|
||||
calc.unit = '吨';
|
||||
if (!plain) return { ruleCalc };
|
||||
ruleCalc.name = category.name;
|
||||
if (plain.conversion_logic_id === ConversionLogics.Keep) {
|
||||
ruleCalc.count = event.count;
|
||||
ruleCalc.unit = category.unit;
|
||||
} else if (plain.conversion_logic_id === ConversionLogics.Product) {
|
||||
const count = convertiblen ? event.count * event.product.ratio : event.count;
|
||||
const unit = convertiblen ? category.conversion_unit : category.unit;
|
||||
ruleCalc.count = count;
|
||||
ruleCalc.unit = unit;
|
||||
} else if (plain.conversion_logic_id === ConversionLogics.ProductWeight) {
|
||||
ruleCalc.count = (event.count * event.product.weight) / 1000;
|
||||
ruleCalc.unit = '吨';
|
||||
} else if (plain.conversion_logic_id === ConversionLogics.ActualWeight) {
|
||||
const cacheData = cache.find(
|
||||
(c) => c.id === plain.conversion_logic_id && c.category_id === event.product.category_id,
|
||||
);
|
||||
if (!cacheData) {
|
||||
const weight =
|
||||
recordData?.group_weight_items?.find((g) =>
|
||||
g.product_categories?.find((pc) => pc.id === event.product?.category_id),
|
||||
)?.weight || recordData?.weight;
|
||||
cache.push({
|
||||
id: plain.conversion_logic_id,
|
||||
category_id: event.product?.category_id,
|
||||
weight: weight,
|
||||
});
|
||||
ruleCalc.count = weight;
|
||||
ruleCalc.unit = '吨';
|
||||
}
|
||||
// 合同理论重量,换算逻辑是重量表取重量表换算后的值(重量)
|
||||
calc.weight = calc.count;
|
||||
calc.price = calc.count * rule.unit_price;
|
||||
} else {
|
||||
const weightRule = ruleWeight.data?.data?.find(
|
||||
(item) =>
|
||||
(item.product_id === event.product.id || item.product_id - 99999 === event.product.category_id) &&
|
||||
item.logic_id === plain.conversion_logic_id,
|
||||
);
|
||||
if (weightRule) {
|
||||
if (weightRule.conversion_logic_id === ConversionLogics.Keep) {
|
||||
ruleCalc.count = (event.count * weightRule.weight) / 1000;
|
||||
ruleCalc.unit = '吨';
|
||||
} else if (weightRule.conversion_logic_id === ConversionLogics.Product) {
|
||||
ruleCalc.count = convertiblen
|
||||
? (event.count * event.product.ratio * weightRule.weight) / 1000
|
||||
: (event.count * weightRule.weight) / 1000;
|
||||
ruleCalc.unit = '吨';
|
||||
}
|
||||
// 合同理论重量,换算逻辑是重量表取重量表换算后的值(重量)
|
||||
ruleCalc.weight = ruleCalc.count * 1000;
|
||||
ruleCalc.price = ruleCalc.count * plain.unit_price;
|
||||
}
|
||||
}
|
||||
// 合同理论重量,非重量表规则都是取产品重量
|
||||
if (plain.conversion_logic_id <= 4) {
|
||||
ruleCalc.price = ruleCalc.count * plain.unit_price;
|
||||
ruleCalc.weight = event.product.weight * event.count;
|
||||
}
|
||||
}
|
||||
// 合同理论重量,非重量表规则都是取产品重量
|
||||
if (rule.conversion_logic_id <= 4) {
|
||||
calc.weight = (item.weight * itemCount) / 1000;
|
||||
calc.price = rule.unit_price * calc.count;
|
||||
}
|
||||
return calc;
|
||||
|
||||
return { calc, ruleCalc };
|
||||
};
|
||||
|
||||
const basisItem = (productCategory, item, productItem, basis) => {
|
||||
const calc = {
|
||||
count: 0,
|
||||
unit: '',
|
||||
label: '',
|
||||
weight: 0,
|
||||
};
|
||||
|
||||
calc.count = productCategory?.convertible ? item.count * productItem.ratio : item.count;
|
||||
calc.weight = (item.count * productItem.weight) / 1000;
|
||||
calc.unit = productCategory.convertible ? productCategory.conversion_unit : productCategory.unit;
|
||||
calc.label = productCategory.name;
|
||||
if (!basis) {
|
||||
basis = {
|
||||
label: '基础',
|
||||
value: {},
|
||||
};
|
||||
}
|
||||
const basisProduct = basis.value[productCategory.id];
|
||||
if (basisProduct) {
|
||||
basisProduct.count += calc.count;
|
||||
basisProduct.weight += calc.weight;
|
||||
/**
|
||||
* 产品数量汇总方法
|
||||
*/
|
||||
const calcProductCount = (summary: any, calc: any, category: any) => {
|
||||
if (summary[category.id]) {
|
||||
summary[category.id].total += calc.count;
|
||||
} else {
|
||||
basis.value[productCategory.id] = { label: calc.label, count: calc.count, unit: calc.unit, weight: calc.weight };
|
||||
}
|
||||
return basis;
|
||||
};
|
||||
|
||||
const ruleItem = (
|
||||
record_category,
|
||||
movement,
|
||||
index,
|
||||
rule,
|
||||
resultForm,
|
||||
productCategory,
|
||||
item,
|
||||
productItem,
|
||||
contract,
|
||||
reqWeightRules,
|
||||
) => {
|
||||
const calc = {
|
||||
count: 0,
|
||||
unit: '',
|
||||
label: '',
|
||||
weight: 0,
|
||||
price: 0,
|
||||
};
|
||||
if (!contract) {
|
||||
contract = {
|
||||
label: movement + '合同' + index,
|
||||
record_category,
|
||||
value: {},
|
||||
};
|
||||
}
|
||||
if (!rule) return contract;
|
||||
if (rule.conversion_logic_id === ConversionLogics.ActualWeight) {
|
||||
const groupWeight =
|
||||
resultForm.group_weight_items?.find((value) => value.new_products?.id === productCategory.id) ||
|
||||
resultForm.weight;
|
||||
calc.label = productCategory.name;
|
||||
calc.count = groupWeight ?? 0;
|
||||
calc.unit = '吨';
|
||||
calc.price = calc.count * rule.unit_price;
|
||||
calc.weight = (item.count * productItem.weight) / 1000;
|
||||
} else {
|
||||
const {
|
||||
name: ruleName,
|
||||
count: ruleCount,
|
||||
weight: ruleWeight,
|
||||
unit: ruleUnit,
|
||||
price: rulePrice,
|
||||
} = summary(rule, item.count, productCategory, productItem, reqWeightRules?.data?.data);
|
||||
calc.weight = ruleWeight;
|
||||
calc.price = rulePrice;
|
||||
calc.label = ruleName;
|
||||
calc.count = ruleCount;
|
||||
calc.unit = ruleUnit;
|
||||
}
|
||||
const product = contract.value[productCategory.id];
|
||||
if (product) {
|
||||
product.count += calc.count;
|
||||
product.price += calc.price;
|
||||
product.weight += calc.weight;
|
||||
} else {
|
||||
contract.value[productCategory.id] = {
|
||||
label: calc.label,
|
||||
count: calc.count,
|
||||
summary[category.id] = {
|
||||
name: calc.name,
|
||||
total: calc.count,
|
||||
unit: calc.unit,
|
||||
price: calc.price,
|
||||
weight: calc.weight,
|
||||
};
|
||||
}
|
||||
return contract;
|
||||
};
|
||||
|
||||
const transDescriptions = (data) => {
|
||||
const values = data.map((item: any, index) => {
|
||||
if (item.total) {
|
||||
return {
|
||||
key: item.name,
|
||||
label: item.name,
|
||||
children: item.name === '总金额' ? formatCurrency(item.total, 2) : formatQuantity(item.total, 3) + item.unit,
|
||||
};
|
||||
}
|
||||
});
|
||||
return values.filter(Boolean);
|
||||
};
|
||||
|
@ -32,7 +32,6 @@ export const RecordTotalPrice: CustomFunctionComponent = () => {
|
||||
const [products, setProducts] = useState([]);
|
||||
const [groupWeight, setGroupWeight] = useState([]);
|
||||
const [recordWeight, setRecordWeight] = useState(0);
|
||||
return;
|
||||
// 总金额计算方法
|
||||
const computeTotalPrice = () => {
|
||||
if (!leaseData) return;
|
||||
|
@ -1,177 +1,90 @@
|
||||
import { useAPIClient, useRequest } from '@tachybase/client';
|
||||
import dayjs from 'dayjs';
|
||||
import { useRequest } from '@tachybase/client';
|
||||
import { stringify } from 'flatted';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
export function useCachedRequest<P>(params: {}, options = {}) {
|
||||
const cacheKey = stringify(params);
|
||||
return useRequest<P>(params, { cacheKey, ...options });
|
||||
}
|
||||
|
||||
export const useLeaseItems = (planId, date) => {
|
||||
const [data, setData] = useState({});
|
||||
const api = useAPIClient();
|
||||
const day = date || new Date();
|
||||
const nowDay = dayjs(day).startOf('day').add(-1, 'minute');
|
||||
if (typeof planId !== 'object') return { data };
|
||||
planId?.forEach((value) => {
|
||||
if (!value) return;
|
||||
if (!data[value]) {
|
||||
api
|
||||
.request({
|
||||
resource: 'contract_plan_lease_items',
|
||||
action: 'list',
|
||||
params: {
|
||||
appends: ['new_products'],
|
||||
filter: {
|
||||
effect_contracts: {
|
||||
start_date: { $dateBefore: nowDay },
|
||||
end_date: { $dateAfter: nowDay },
|
||||
contract_id: {
|
||||
$eq: value,
|
||||
},
|
||||
},
|
||||
},
|
||||
pageSize: 99999,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
const result = { ...data };
|
||||
result[value] = res.data?.data;
|
||||
setData(result);
|
||||
})
|
||||
.catch(() => {
|
||||
return;
|
||||
});
|
||||
}
|
||||
});
|
||||
return { data };
|
||||
};
|
||||
|
||||
export const useFeeItems = (planId, date) => {
|
||||
const [data, setData] = useState({});
|
||||
const api = useAPIClient();
|
||||
const day = date || new Date();
|
||||
const nowDay = dayjs(day).startOf('day').add(-1, 'minute');
|
||||
if (typeof planId !== 'object') return { data };
|
||||
planId?.forEach((value) => {
|
||||
if (!value) return;
|
||||
if (!data[value]) {
|
||||
api
|
||||
.request({
|
||||
resource: 'contract_plan_fee_items',
|
||||
action: 'list',
|
||||
params: {
|
||||
appends: ['new_fee_products'],
|
||||
filter: {
|
||||
effect_contracts: {
|
||||
start_date: { $dateBefore: nowDay },
|
||||
end_date: { $dateAfter: nowDay },
|
||||
contract_id: {
|
||||
$eq: value,
|
||||
},
|
||||
},
|
||||
},
|
||||
pageSize: 99999,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
const result = { ...data };
|
||||
result[value] = res.data?.data;
|
||||
setData(result);
|
||||
})
|
||||
.catch(() => {
|
||||
return;
|
||||
});
|
||||
}
|
||||
});
|
||||
return { data };
|
||||
};
|
||||
|
||||
export const useProductFeeItems = (planId, date) => {
|
||||
const [data, setData] = useState({});
|
||||
const api = useAPIClient();
|
||||
const day = date || new Date();
|
||||
const nowDay = dayjs(day).startOf('day').add(-1, 'minute');
|
||||
if (typeof planId !== 'object') return { data };
|
||||
planId?.forEach((value) => {
|
||||
if (!value) return;
|
||||
if (!data[value]) {
|
||||
api
|
||||
.request({
|
||||
resource: 'contract_plan_lease_items',
|
||||
action: 'list',
|
||||
params: {
|
||||
appends: ['fee_items', 'new_products'],
|
||||
filter: {
|
||||
effect_contracts: {
|
||||
start_date: { $dateBefore: nowDay },
|
||||
end_date: { $dateAfter: nowDay },
|
||||
contract_id: {
|
||||
$eq: value,
|
||||
},
|
||||
},
|
||||
},
|
||||
pageSize: 99999,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
const result = { ...data };
|
||||
result[value] = res.data?.data;
|
||||
setData(result);
|
||||
})
|
||||
.catch(() => {
|
||||
return;
|
||||
});
|
||||
}
|
||||
});
|
||||
return { data };
|
||||
};
|
||||
|
||||
export const useProducts = () => {
|
||||
const { data } = useCachedRequest<any>({
|
||||
resource: 'products',
|
||||
export const useLeaseItems = (planId) => {
|
||||
const params = {
|
||||
resource: 'contract_plan_lease_items',
|
||||
action: 'list',
|
||||
params: {
|
||||
appends: ['products'],
|
||||
filter: {
|
||||
contract_plan_id: planId,
|
||||
},
|
||||
pageSize: 99999,
|
||||
},
|
||||
};
|
||||
const { data, loading, run } = useCachedRequest<any>(params, {
|
||||
manual: true,
|
||||
});
|
||||
if (data?.data) {
|
||||
data.data.forEach((value) => {
|
||||
value['parentScopeId'] = selParentId(data.data, value, []);
|
||||
});
|
||||
}
|
||||
return { data: data?.data };
|
||||
};
|
||||
|
||||
export const useCompany = (appends, id) => {
|
||||
const { data, loading, run } = useCachedRequest<any>(
|
||||
{
|
||||
resource: 'contracts',
|
||||
action: 'list',
|
||||
params: {
|
||||
filter: { id: { $eq: id } },
|
||||
appends,
|
||||
},
|
||||
},
|
||||
{ manual: true },
|
||||
);
|
||||
useEffect(() => {
|
||||
if (id) {
|
||||
if (planId) {
|
||||
run();
|
||||
}
|
||||
}, [id]);
|
||||
}, [planId]);
|
||||
return { data, loading };
|
||||
};
|
||||
|
||||
const selParentId = (products, item, scopeId) => {
|
||||
scopeId.push(item.id);
|
||||
if (!item.parentId) {
|
||||
return scopeId;
|
||||
}
|
||||
const items = products.find((value) => value.id === item.parentId);
|
||||
if (!items) {
|
||||
return scopeId;
|
||||
}
|
||||
return selParentId(products, items, scopeId);
|
||||
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>(
|
||||
{
|
||||
resource: 'contract_plan_lease_items',
|
||||
action: 'list',
|
||||
params: {
|
||||
appends: ['fee_items', 'products'],
|
||||
filter: {
|
||||
$and: [
|
||||
{
|
||||
contract_plan_id: planId,
|
||||
},
|
||||
{
|
||||
products: {
|
||||
category_id: categoryId ?? -1,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
pageSize: 99999,
|
||||
},
|
||||
},
|
||||
{
|
||||
manual: true,
|
||||
},
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (planId && categoryId) {
|
||||
run();
|
||||
}
|
||||
}, [planId, categoryId]);
|
||||
return { data, loading };
|
||||
};
|
||||
|
@ -2,11 +2,6 @@ import { useRecord } from '@tachybase/client';
|
||||
import React, { createContext, useContext, useMemo, useState } from 'react';
|
||||
import { SettlementStyleContext } from '../schema-initializer/actions/SettlementStyleSwitchActionInitializer';
|
||||
|
||||
export const PdfPaperSwitchingContext = createContext({
|
||||
paper: null,
|
||||
setPaper: null,
|
||||
});
|
||||
|
||||
export const PdfIsDoubleContext = createContext({
|
||||
isDouble: null,
|
||||
setIsDouble: null,
|
||||
@ -22,61 +17,27 @@ export const PdfMargingTopContext = createContext({
|
||||
setMargingTop: null,
|
||||
});
|
||||
|
||||
// 页面缩放
|
||||
export const FontSizeContext = createContext({
|
||||
size: null,
|
||||
setSize: null,
|
||||
});
|
||||
|
||||
// 注释
|
||||
export const AnnotateContext = createContext({
|
||||
annotate: null,
|
||||
setAnnotate: null,
|
||||
});
|
||||
|
||||
export const PdfIsDoubleProvider = (props) => {
|
||||
const [isDouble, setIsDouble] = useState(false);
|
||||
const [settingType, setSettingLoad] = useState(false);
|
||||
const [margingTop, setMargingTop] = useState(0);
|
||||
const [paper, setPaper] = useState('A4');
|
||||
const [size, setSize] = useState('9');
|
||||
const [annotate, setAnnotate] = useState(false);
|
||||
return (
|
||||
<AnnotateContext.Provider value={{ annotate, setAnnotate }}>
|
||||
<PdfPaperSwitchingContext.Provider value={{ paper, setPaper }}>
|
||||
<PdfMargingTopContext.Provider value={{ margingTop, setMargingTop }}>
|
||||
<PdfIsDoubleContext.Provider value={{ isDouble, setIsDouble }}>
|
||||
<PdfIsLoadContext.Provider value={{ settingType, setSettingLoad }}>
|
||||
<FontSizeContext.Provider value={{ size, setSize }}>{props.children}</FontSizeContext.Provider>
|
||||
</PdfIsLoadContext.Provider>
|
||||
</PdfIsDoubleContext.Provider>
|
||||
</PdfMargingTopContext.Provider>
|
||||
</PdfPaperSwitchingContext.Provider>
|
||||
</AnnotateContext.Provider>
|
||||
<PdfMargingTopContext.Provider value={{ margingTop, setMargingTop }}>
|
||||
<PdfIsDoubleContext.Provider value={{ isDouble, setIsDouble }}>
|
||||
<PdfIsLoadContext.Provider value={{ settingType, setSettingLoad }}>{props.children}</PdfIsLoadContext.Provider>
|
||||
</PdfIsDoubleContext.Provider>
|
||||
</PdfMargingTopContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useRecordPdfPath = () => {
|
||||
const record = useRecord();
|
||||
let recordId = record.id || record.record_id;
|
||||
let stockId;
|
||||
if (record.__collectionName === 'contracts' && record.__parent) {
|
||||
// 查看页面,中间表id
|
||||
recordId = record.__parent.id;
|
||||
}
|
||||
if (record.__collectionName === 'record_stock') {
|
||||
stockId = record.id;
|
||||
}
|
||||
const { isDouble } = useContext(PdfIsDoubleContext);
|
||||
const { settingType } = useContext(PdfIsLoadContext);
|
||||
const { margingTop } = useContext(PdfMargingTopContext);
|
||||
const { paper } = useContext(PdfPaperSwitchingContext);
|
||||
const { size } = useContext(FontSizeContext);
|
||||
const { annotate } = useContext(AnnotateContext);
|
||||
const path = useMemo(
|
||||
() =>
|
||||
`/records:pdf?recordId=${recordId}&stockId=${stockId}&isDouble=${isDouble}&settingType=${settingType}&margingTop=${margingTop}&paper=${paper}&font=${size}&annotate=${annotate}`,
|
||||
[recordId, isDouble, settingType, margingTop, paper, size, annotate, stockId],
|
||||
() => `/records:pdf?recordId=${record.id}&isDouble=${isDouble}&settingType=${settingType}&margingTop=${margingTop}`,
|
||||
[record.id, isDouble, settingType, margingTop],
|
||||
);
|
||||
return path;
|
||||
};
|
||||
|
@ -49,16 +49,6 @@ import {
|
||||
PrintSetupMargingTop,
|
||||
} from './schema-initializer/actions/RecordPrintSetupMargingTopInitializer';
|
||||
import { UnusedRecordsBlockHelper } from './schema-initializer/blocks/UnusedRecordsBlockInitializer';
|
||||
|
||||
import { PaperSwitching, PaperSwitchingInitializer } from './schema-initializer/actions/paperSwitching';
|
||||
import {
|
||||
RecordPrintAnnotateActionInitializer,
|
||||
Annotate,
|
||||
} from './schema-initializer/actions/RecordPrintAnnotateActionInitializer';
|
||||
import { PrintFontSize, PrintFontSizeInitializer } from './schema-initializer/actions/RecordPrintFontSizeInitializer';
|
||||
import { MovementFieldInterface } from './interfaces/movement';
|
||||
import { Movement } from './schema-components/Movement';
|
||||
import { MovementStatus } from './custom-components/MovementStatus';
|
||||
export class PluginRentalClient extends Plugin {
|
||||
locale: Locale;
|
||||
async afterAdd() {}
|
||||
@ -94,44 +84,26 @@ export class PluginRentalClient extends Plugin {
|
||||
type: 'item',
|
||||
title: '{{t("Column switch")}}',
|
||||
component: 'ColumnSwitchActionInitializer',
|
||||
// useVisible() {
|
||||
// const collection = useCollection();
|
||||
// const name = collection['options']['name'];
|
||||
// return name === 'records';
|
||||
// },
|
||||
useVisible() {
|
||||
const collection = useCollection();
|
||||
const name = collection['options']['name'];
|
||||
return name === 'records';
|
||||
},
|
||||
});
|
||||
this.app.schemaInitializerManager.addItem('PDFViewActionInitializer', 'enbaleActions.paperSwitching', {
|
||||
type: 'item',
|
||||
title: '{{t("paper switching")}}',
|
||||
component: 'PaperSwitchingInitializer',
|
||||
});
|
||||
this.app.schemaInitializerManager.addItem('PDFViewActionInitializer', 'enbaleActions.paperSwitching', {
|
||||
type: 'item',
|
||||
title: '{{t("font size")}}',
|
||||
component: 'PrintFontSizeInitializer',
|
||||
});
|
||||
|
||||
this.app.schemaInitializerManager.addItem('PDFViewActionInitializer', 'enbaleActions.recordPrintSetup', {
|
||||
type: 'item',
|
||||
title: '{{t("Record print setup")}}',
|
||||
component: 'RecordPrintSetupActionInitializer',
|
||||
});
|
||||
|
||||
this.app.schemaInitializerManager.addItem('PDFViewActionInitializer', 'enbaleActions.recordPrintAnnotate', {
|
||||
type: 'item',
|
||||
title: '{{t("Record print annotate")}}',
|
||||
component: 'RecordPrintAnnotateActionInitializer',
|
||||
});
|
||||
|
||||
this.app.schemaInitializerManager.addItem('PDFViewActionInitializer', 'enbaleActions.recordPrintMargingTop', {
|
||||
type: 'item',
|
||||
title: '{{t("Record print margingtop")}}',
|
||||
component: 'RecordPrintSetupMargingTopInitializer',
|
||||
// useVisible() {
|
||||
// const collection = useCollection();
|
||||
// const name = collection['options']['name'];
|
||||
// return name === 'records' || name === 'waybills';
|
||||
// },
|
||||
useVisible() {
|
||||
const collection = useCollection();
|
||||
const name = collection['options']['name'];
|
||||
return name === 'records' || name === 'waybills';
|
||||
},
|
||||
});
|
||||
this.app.schemaInitializerManager.addItem('PDFViewActionInitializer', 'enbaleActions.settlementExcelExport', {
|
||||
type: 'item',
|
||||
@ -185,16 +157,9 @@ export class PluginRentalClient extends Plugin {
|
||||
// You can get and modify the app instance here
|
||||
async load() {
|
||||
this.locale = new Locale(this.app);
|
||||
this.app.dataSourceManager.addFieldInterfaceGroups({
|
||||
bussiness: {
|
||||
label: 'Bussiness',
|
||||
},
|
||||
});
|
||||
this.app.dataSourceManager.addFieldInterfaces([MovementFieldInterface]);
|
||||
this.app.addComponents({
|
||||
RecordFeeConvertedAmount,
|
||||
ReadFeeConvertedAmount,
|
||||
Movement,
|
||||
RecordFeeScope,
|
||||
RecordItemValuationQuantity,
|
||||
RecordItemWeight,
|
||||
@ -212,12 +177,6 @@ export class PluginRentalClient extends Plugin {
|
||||
PDFViewerCountablePrintActionInitializer,
|
||||
ColumnSwitchActionInitializer,
|
||||
ColumnSwitchAction,
|
||||
PaperSwitching,
|
||||
PrintFontSize,
|
||||
Annotate,
|
||||
RecordPrintAnnotateActionInitializer,
|
||||
PaperSwitchingInitializer,
|
||||
PrintFontSizeInitializer,
|
||||
SettlementExcelExportActionInitializer,
|
||||
SettlementStyleProvider,
|
||||
SettlementStyleSwitchActionInitializer,
|
||||
@ -226,7 +185,6 @@ export class PluginRentalClient extends Plugin {
|
||||
RecordPrintSetupMargingTopInitializer,
|
||||
PrintSetup,
|
||||
PrintSetupMargingTop,
|
||||
MovementStatus,
|
||||
});
|
||||
this.app.addScopes({
|
||||
useAddToChecklistActionProps,
|
||||
|
@ -2,7 +2,7 @@ import React, { useContext, useEffect, useState } from 'react';
|
||||
import { ActionInitializer } from '@tachybase/client';
|
||||
import { Radio, RadioChangeEvent } from 'antd';
|
||||
import { useRequest } from '@tachybase/client';
|
||||
import { PdfIsLoadContext, ScaleContext } from '../../hooks/usePdfPath';
|
||||
import { PdfIsLoadContext } from '../../hooks/usePdfPath';
|
||||
export const PrintSetup = (props) => {
|
||||
const [value, setValue] = useState('');
|
||||
const settingsData = useRequest<any>({
|
||||
|
@ -56,8 +56,8 @@ export const excelDataHandle = (excelData) => {
|
||||
*/
|
||||
const nameRows = [
|
||||
{
|
||||
companyName: { name: '承租单位:', value: `${contracts.party_b?.name ?? ''}` },
|
||||
companyName1: { name: '合同编号:', value: `${contracts.number ?? ''}` },
|
||||
companyName: { name: '承租单位:', value: `${contracts.project?.company?.name ?? ''}` },
|
||||
companyName1: { name: '合同编号:', value: `${contracts.project?.code ?? ''}` },
|
||||
rowId: '3',
|
||||
},
|
||||
{
|
||||
@ -78,7 +78,7 @@ export const excelDataHandle = (excelData) => {
|
||||
name: '项目联系人:',
|
||||
value: `${contracts?.project.contacts.map((contact) => contact.name + ' ' + contact.phone).join(' ')}`,
|
||||
},
|
||||
endData: { name: '制表人:', value: `${contracts.operator.nickname}` },
|
||||
endData: { name: '经办人:', value: `${contracts.operator.nickname}` },
|
||||
rowId: '6',
|
||||
},
|
||||
];
|
||||
@ -148,7 +148,7 @@ export const excelDataHandle = (excelData) => {
|
||||
parseFloat(calc.n_compensate.toFixed(2)),
|
||||
parseFloat(calc.h_compensate.toFixed(2)),
|
||||
parseFloat(calc.loadfreight.toFixed(2)),
|
||||
parseFloat(calc.other ? calc.other.toFixed(2) : 0),
|
||||
parseFloat(calc.other.toFixed(2)),
|
||||
formatPercent(calc.tax, 2),
|
||||
parseFloat(calc.current_expenses.toFixed(2)),
|
||||
parseFloat(calc.accumulate.toFixed(2)),
|
||||
@ -170,34 +170,30 @@ export const excelDataHandle = (excelData) => {
|
||||
columns: [
|
||||
{
|
||||
name: '物料名称',
|
||||
key: 'name1',
|
||||
},
|
||||
{
|
||||
name: ' ',
|
||||
key: '',
|
||||
},
|
||||
{
|
||||
name: '费用类别',
|
||||
key: 'name2',
|
||||
},
|
||||
{
|
||||
name: '单位',
|
||||
key: 'name3',
|
||||
},
|
||||
{
|
||||
name: '订单数量',
|
||||
key: 'name4',
|
||||
},
|
||||
{
|
||||
name: '出入库数量',
|
||||
key: 'name5',
|
||||
},
|
||||
{
|
||||
name: '租赁单价',
|
||||
key: 'name',
|
||||
},
|
||||
{
|
||||
name: ' ',
|
||||
key: ' ',
|
||||
},
|
||||
{
|
||||
name: '费用类别',
|
||||
key: 'name',
|
||||
},
|
||||
{
|
||||
name: '单位',
|
||||
key: 'name',
|
||||
},
|
||||
{
|
||||
name: '订单数量',
|
||||
key: 'name',
|
||||
},
|
||||
{
|
||||
name: '出入库数量',
|
||||
key: 'name',
|
||||
},
|
||||
{
|
||||
name: '租赁单价',
|
||||
key: 'name',
|
||||
},
|
||||
{
|
||||
@ -210,7 +206,7 @@ export const excelDataHandle = (excelData) => {
|
||||
},
|
||||
{
|
||||
name: ' ',
|
||||
key: '',
|
||||
key: ' ',
|
||||
},
|
||||
],
|
||||
rows: [],
|
||||
@ -225,7 +221,6 @@ export const excelDataHandle = (excelData) => {
|
||||
parseFloat(value.item_count?.toFixed(2) || 0),
|
||||
parseFloat(value.count.toFixed(2)),
|
||||
parseFloat(value.unit_price.toFixed(5)),
|
||||
'',
|
||||
value.days,
|
||||
parseFloat(value.amount.toFixed(2)),
|
||||
'',
|
||||
@ -258,10 +253,6 @@ export const excelDataHandle = (excelData) => {
|
||||
name: '物质名称',
|
||||
key: 'name',
|
||||
},
|
||||
{
|
||||
name: ' ',
|
||||
key: '',
|
||||
},
|
||||
{
|
||||
name: '费用类别',
|
||||
key: 'name',
|
||||
@ -300,7 +291,6 @@ export const excelDataHandle = (excelData) => {
|
||||
converDate(value.date, 'YYYY-MM-DD'),
|
||||
value.movement === '-1' ? '出库' : value.movement === '1' ? '入库' : '出入库',
|
||||
value.name,
|
||||
'',
|
||||
category,
|
||||
value.unit_name,
|
||||
parseFloat(value.item_count?.toFixed(2) || 0),
|
||||
@ -365,10 +355,6 @@ export const excelDataHandle = (excelData) => {
|
||||
name: ' ',
|
||||
key: ' ',
|
||||
},
|
||||
{
|
||||
name: ' ',
|
||||
key: ' ',
|
||||
},
|
||||
],
|
||||
rows: [],
|
||||
};
|
||||
@ -384,7 +370,6 @@ export const excelDataHandle = (excelData) => {
|
||||
item.notes,
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
]);
|
||||
});
|
||||
|
||||
@ -428,7 +413,7 @@ export const excelDataHandle = (excelData) => {
|
||||
},
|
||||
{
|
||||
name: ' ',
|
||||
key: '',
|
||||
key: ' ',
|
||||
},
|
||||
{
|
||||
name: '单位',
|
||||
@ -442,10 +427,6 @@ export const excelDataHandle = (excelData) => {
|
||||
name: '结存数量',
|
||||
key: 'name5',
|
||||
},
|
||||
{
|
||||
name: ' ',
|
||||
key: '',
|
||||
},
|
||||
],
|
||||
rows: [],
|
||||
};
|
||||
@ -464,7 +445,6 @@ export const excelDataHandle = (excelData) => {
|
||||
calc.summary[countNum]?.unit_name ?? '',
|
||||
calc.summary[countNum] ? parseFloat(calc.summary[countNum]?.item_count?.toFixed(2) || 0) : '',
|
||||
calc.summary[countNum] ? parseFloat(calc.summary[countNum]?.count.toFixed(2)) : '',
|
||||
'',
|
||||
]);
|
||||
}
|
||||
});
|
||||
@ -478,25 +458,17 @@ export const excelDataHandle = (excelData) => {
|
||||
|
||||
const footRows = [
|
||||
{
|
||||
companyName: { name: `承租单位:${contracts.party_b?.name ?? ''}` },
|
||||
companyName1: { name: `出租单位:${contracts.first_party?.name ?? PromptText.noContractedCompany}` },
|
||||
companyName: { name: '制表人:' },
|
||||
companyName1: { name: '审核人:' },
|
||||
companyName2: { name: '验收人:' },
|
||||
rowId: notesRow + 2,
|
||||
},
|
||||
{
|
||||
companyName: { name: '承租单位项目经理:' },
|
||||
companyName1: { name: '出租单位审核人:' },
|
||||
companyName1: { name: '材料负责人:' },
|
||||
companyName2: { name: '出租单位代表人:' },
|
||||
rowId: notesRow + 4,
|
||||
},
|
||||
{
|
||||
companyName: { name: '承租单位材料负责人:' },
|
||||
companyName1: { name: '出租单位对账人:' },
|
||||
rowId: notesRow + 6,
|
||||
},
|
||||
{
|
||||
companyName: { name: '签署日期:' },
|
||||
companyName1: { name: '签署日期:' },
|
||||
rowId: notesRow + 8,
|
||||
},
|
||||
];
|
||||
return {
|
||||
table1,
|
||||
@ -520,7 +492,7 @@ export const excelDataHandle = (excelData) => {
|
||||
|
||||
const excelAddTable = (tablerow, tableHeaderText, ws, table) => {
|
||||
ws.getCell(`A${tablerow - 1}`).value = tableHeaderText;
|
||||
ws.mergeCells(`A${tablerow - 1}:K${tablerow - 1}`);
|
||||
ws.mergeCells(`A${tablerow - 1}:J${tablerow - 1}`);
|
||||
ws.getCell(`A${tablerow - 1}`).alignment = { horizontal: 'center' };
|
||||
ws.getCell(`A${tablerow - 1}`).border = {
|
||||
top: { style: 'thin' },
|
||||
@ -574,7 +546,7 @@ export const ExportToExcel = async (data) => {
|
||||
value.height = 20;
|
||||
});
|
||||
//设置表格边框
|
||||
const cols = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K'];
|
||||
const cols = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'];
|
||||
const CellBorder = (row) => {
|
||||
cols.forEach((value) => {
|
||||
if (value === 'A' && row === `${notesRow}`) {
|
||||
@ -600,7 +572,9 @@ export const ExportToExcel = async (data) => {
|
||||
});
|
||||
};
|
||||
//设置表格表头
|
||||
ws.getCell('A1').value = `${contracts.first_party?.name ?? `${PromptText.noContractedCompany}`} 对账单`;
|
||||
ws.getCell('A1').value = `${
|
||||
contracts.project?.associated_company?.name ?? `${PromptText.noContractedCompany}`
|
||||
} 对账单`;
|
||||
ws.mergeCells('A1:J1');
|
||||
ws.getCell('A1').alignment = { vertical: 'middle', horizontal: 'center' };
|
||||
ws.getCell('A1').font = {
|
||||
@ -610,19 +584,19 @@ export const ExportToExcel = async (data) => {
|
||||
row.height = 30;
|
||||
//设置第一行内容
|
||||
ws.getCell('A2').value = '客户各项费用明细';
|
||||
ws.mergeCells('A2:K2');
|
||||
ws.mergeCells('A2:J2');
|
||||
ws.getCell('A2').alignment = { horizontal: 'center' };
|
||||
//设置表格上层合同信息
|
||||
nameRows.forEach((value) => {
|
||||
ws.getCell(`A${value?.rowId}`).value = value[Object.keys(value)[0]].name + value[Object.keys(value)[0]].value;
|
||||
ws.mergeCells(`A${value?.rowId}:F${value?.rowId}`);
|
||||
ws.getCell(`G${value?.rowId}`).value = value[Object.keys(value)[1]].name + value[Object.keys(value)[1]].value;
|
||||
ws.mergeCells(`G${value?.rowId}:K${value?.rowId}`);
|
||||
ws.mergeCells(`G${value?.rowId}:J${value?.rowId}`);
|
||||
});
|
||||
|
||||
//本期汇总
|
||||
ws.getCell(`A${table1Row - 1}`).value = '本期汇总';
|
||||
ws.mergeCells(`A${table1Row - 1}:K${table1Row - 1}`);
|
||||
ws.mergeCells(`A${table1Row - 1}:J${table1Row - 1}`);
|
||||
ws.getCell(`A${table1Row - 1}`).alignment = { horizontal: 'center' };
|
||||
ws.getCell(`A${table1Row - 1}`).border = {
|
||||
bottom: { style: 'thin' },
|
||||
@ -642,8 +616,7 @@ export const ExportToExcel = async (data) => {
|
||||
const rows24 = ws.getRows(table2Row, calc.history ? calc.history?.length + 1 : 1);
|
||||
rows24.forEach((value) => {
|
||||
ws.mergeCells(`A${value['_number']}:B${value['_number']}`);
|
||||
ws.mergeCells(`G${value['_number']}:H${value['_number']}`);
|
||||
ws.mergeCells(`J${value['_number']}:K${value['_number']}`);
|
||||
ws.mergeCells(`I${value['_number']}:J${value['_number']}`);
|
||||
if (value['_number'] !== table2Row) {
|
||||
const row25 = ws.getRow(value['_number']);
|
||||
row25.alignment = { horizontal: 'right' };
|
||||
@ -658,7 +631,6 @@ export const ExportToExcel = async (data) => {
|
||||
excelAddTable(table3Row, '本期明细', ws, table3);
|
||||
const rows37 = ws.getRows(table3Row, calc.list ? calc.list?.length + 1 : 1);
|
||||
rows37.forEach((value) => {
|
||||
ws.mergeCells(`C${value['_number']}:D${value['_number']}`);
|
||||
if (value['_number'] !== table3Row) {
|
||||
const row38 = ws.getRow(value['_number']);
|
||||
row38.alignment = { horizontal: 'right' };
|
||||
@ -673,7 +645,7 @@ export const ExportToExcel = async (data) => {
|
||||
ws.mergeCells(`A${value['_number']}:B${value['_number']}`);
|
||||
ws.mergeCells(`C${value['_number']}:D${value['_number']}`);
|
||||
ws.mergeCells(`F${value['_number']}:G${value['_number']}`);
|
||||
ws.mergeCells(`H${value['_number']}:K${value['_number']}`);
|
||||
ws.mergeCells(`H${value['_number']}:J${value['_number']}`);
|
||||
if (value['_number'] !== table4row) {
|
||||
const row38 = ws.getRow(value['_number']);
|
||||
row38.alignment = { horizontal: 'right' };
|
||||
@ -695,7 +667,6 @@ export const ExportToExcel = async (data) => {
|
||||
rows1?.forEach((value) => {
|
||||
ws.mergeCells(`A${value['_number']}:B${value['_number']}`);
|
||||
ws.mergeCells(`F${value['_number']}:G${value['_number']}`);
|
||||
ws.mergeCells(`J${value['_number']}:K${value['_number']}`);
|
||||
if (value['_number'] !== table5Row) {
|
||||
const row38 = ws.getRow(value['_number']);
|
||||
row38.alignment = { horizontal: 'right' };
|
||||
@ -714,8 +685,9 @@ export const ExportToExcel = async (data) => {
|
||||
'承租单位收到租费单结算明细15日内未提异议即视为确认。请签字盖章后邮寄一份至' +
|
||||
contracts.project?.associated_company.address;
|
||||
ws.getCell(`F${notesRow}`).value = `
|
||||
备注:${contracts.project?.comment ?? ''}`;
|
||||
ws.mergeCells(`F${notesRow}:K${notesRow}`);
|
||||
备注:${contracts.project?.comment ?? ''}
|
||||
出租单位:${contracts.project?.associated_company?.name ?? PromptText.noContractedCompany}`;
|
||||
ws.mergeCells(`F${notesRow}:J${notesRow}`);
|
||||
const url = 'http://985.so/bpw6g';
|
||||
const imageUrl = await QRCode.toDataURL(url);
|
||||
const imageId1 = workBook.addImage({
|
||||
@ -732,9 +704,11 @@ export const ExportToExcel = async (data) => {
|
||||
//设置底部签名区域
|
||||
footRows.forEach((value) => {
|
||||
ws.getCell(`A${value?.rowId}`).value = value[Object.keys(value)[0]].name;
|
||||
ws.mergeCells(`A${value?.rowId}:E${value?.rowId}`);
|
||||
ws.getCell(`F${value?.rowId}`).value = value[Object.keys(value)[1]].name;
|
||||
ws.mergeCells(`F${value?.rowId}:K${value?.rowId}`);
|
||||
ws.mergeCells(`A${value?.rowId}:C${value?.rowId}`);
|
||||
ws.getCell(`D${value?.rowId}`).value = value[Object.keys(value)[1]].name;
|
||||
ws.mergeCells(`D${value?.rowId}:G${value?.rowId}`);
|
||||
ws.getCell(`H${value?.rowId}`).value = value[Object.keys(value)[2]].name;
|
||||
ws.mergeCells(`H${value?.rowId}:J${value?.rowId}`);
|
||||
});
|
||||
|
||||
const buffer = await workBook.xlsx.writeBuffer();
|
||||
|
@ -1,6 +1,4 @@
|
||||
export interface RecordPdfOptions {
|
||||
isDouble: number;
|
||||
printSetup: String;
|
||||
margingTop: number;
|
||||
paper: string;
|
||||
}
|
||||
|
@ -1,34 +1,22 @@
|
||||
import { Record } from './record';
|
||||
|
||||
export interface Waybill {
|
||||
record_number: string;
|
||||
weight_or_amount: number;
|
||||
off_date: Date;
|
||||
arrival_date: Date;
|
||||
unit_price: number;
|
||||
side_information: string;
|
||||
driver: any;
|
||||
carrier: any;
|
||||
consignee_contact: any;
|
||||
in_stock: any;
|
||||
shipper_contact: any;
|
||||
out_stock: any;
|
||||
payee_account: any;
|
||||
payer: any;
|
||||
pay_date: Date;
|
||||
additional_cost: number;
|
||||
products: any[];
|
||||
payer_company: string;
|
||||
payer_name: string;
|
||||
payee_account_name: string;
|
||||
payee_account_bank: string;
|
||||
payee_account_number: string;
|
||||
shipper_company: string;
|
||||
shipper_name: string;
|
||||
shipper_contact_phone: string;
|
||||
shipper_address: string;
|
||||
consignee_company: string;
|
||||
consignee_contact_phone: string;
|
||||
consignee_address: string;
|
||||
consignee_name: string;
|
||||
unit_price: number;
|
||||
weight_or_amount: number;
|
||||
arrival_date: Date;
|
||||
off_date: Date;
|
||||
pdfExplain: string;
|
||||
record: Record;
|
||||
comment: string;
|
||||
shipper_contact: string;
|
||||
carrier: string;
|
||||
driver: string;
|
||||
driver_idcard: string;
|
||||
vehicles: string;
|
||||
driver_phone: string;
|
||||
side_information: string;
|
||||
consignee_contact: string;
|
||||
}
|
||||
|
@ -42,54 +42,46 @@ export class RecordPreviewController {
|
||||
const query = {
|
||||
where: where || {},
|
||||
attributes: [
|
||||
[sequelize.fn('sum', sequelize.col('record.items.count')), 'count'],
|
||||
[sequelize.col('record.items.new_product_id'), 'new_product_id'],
|
||||
[sequelize.col('view_records_contracts.movement'), 'movement'],
|
||||
[sequelize.fn('sum', sequelize.col('items.count')), 'count'],
|
||||
[sequelize.col('items.product_id'), 'product_id'],
|
||||
[sequelize.col('records.movement'), 'movement'],
|
||||
],
|
||||
include: [
|
||||
{
|
||||
association: 'record',
|
||||
association: 'items',
|
||||
attributes: [],
|
||||
include: [
|
||||
{
|
||||
association: 'items',
|
||||
attributes: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
...parsedFilterInclude,
|
||||
],
|
||||
group: [sequelize.col('record.items.new_product_id'), sequelize.col('view_records_contracts.movement')],
|
||||
group: [sequelize.col('items.product_id'), sequelize.col('records.movement')],
|
||||
order: [],
|
||||
subQuery: false,
|
||||
raw: true,
|
||||
} as any;
|
||||
const records = await ctx.db.getModel('view_records_contracts').findAll(query);
|
||||
const records = await ctx.db.getModel('records').findAll(query);
|
||||
if (records) {
|
||||
const allProducts = await ctx.db.getRepository('products').find();
|
||||
const allProducts = await ctx.db.getRepository('product').find({ appends: ['category'] });
|
||||
if (!allProducts) return;
|
||||
const items = {} as { [key: string]: { name: string; out: number; in: number; total: number } };
|
||||
const items = {} as { [key: string]: { name: string; sort: number; out: number; in: number; total: number } };
|
||||
records.forEach((item) => {
|
||||
const product = allProducts.find((p) => p.id === item?.new_product_id);
|
||||
const product = allProducts.find((p) => p.id === item?.product_id);
|
||||
if (!product) return;
|
||||
const parent = allProducts.find((p) => p.id === product.parentId);
|
||||
const name = parent?.name || product.name;
|
||||
if (!items[name]) {
|
||||
items[name] = {
|
||||
name: name,
|
||||
if (!items[product.name]) {
|
||||
items[product.name] = {
|
||||
name: product.name,
|
||||
sort: product.category.sort,
|
||||
out: 0,
|
||||
in: 0,
|
||||
total: 0,
|
||||
};
|
||||
}
|
||||
// 根据产品找父级产品的分类
|
||||
const count = parent?.convertible || product.convertible ? item.count * product.ratio : item.count;
|
||||
const count = product.category.convertible ? item.count * product.ratio : item.count;
|
||||
if (item.movement === Movement.in) {
|
||||
items[name].in += count;
|
||||
items[name].total += count;
|
||||
items[product.name].in += count;
|
||||
items[product.name].total += count;
|
||||
} else {
|
||||
items[name].out += count;
|
||||
items[name].total -= count;
|
||||
items[product.name].out += count;
|
||||
items[product.name].total -= count;
|
||||
}
|
||||
});
|
||||
const result = {
|
||||
@ -105,7 +97,7 @@ export class RecordPreviewController {
|
||||
@Action('allweight')
|
||||
async groupWeight(ctx: Context) {
|
||||
const { filter } = ctx.action.params.values;
|
||||
const collectionName = 'view_records_contracts';
|
||||
const collectionName = 'records';
|
||||
const collection = ctx.db.getCollection(collectionName);
|
||||
const fields = collection.fields;
|
||||
const filterParser = new FilterParser(filter, {
|
||||
@ -123,22 +115,16 @@ export class RecordPreviewController {
|
||||
const query = {
|
||||
where: where || {},
|
||||
attributes: [
|
||||
[sequelize.fn('sum', sequelize.col('record.weight')), 'weight'],
|
||||
[sequelize.col('view_records_contracts.movement'), 'movement'],
|
||||
],
|
||||
group: [sequelize.col('view_records_contracts.movement')],
|
||||
include: [
|
||||
{
|
||||
association: 'record',
|
||||
attributes: [],
|
||||
},
|
||||
...parsedFilterInclude,
|
||||
[sequelize.fn('sum', sequelize.col('records.weight')), 'weight'],
|
||||
[sequelize.col('records.movement'), 'movement'],
|
||||
],
|
||||
group: [sequelize.col('records.movement')],
|
||||
include: [...parsedFilterInclude],
|
||||
order: [],
|
||||
subQuery: false,
|
||||
raw: true,
|
||||
} as any;
|
||||
const records = await ctx.db.getModel('view_records_contracts').findAll(query);
|
||||
const records = await ctx.db.getModel('records').findAll(query);
|
||||
const inNum = records.find((item) => item.movement === Movement.in)?.weight ?? 0;
|
||||
const outNum = records.find((item) => item.movement === Movement.out)?.weight ?? 0;
|
||||
const data = {
|
||||
@ -150,7 +136,7 @@ export class RecordPreviewController {
|
||||
@Action('allprice')
|
||||
async groupPrice(ctx: Context) {
|
||||
const { filter } = ctx.action.params.values;
|
||||
const collectionName = 'view_records_contracts';
|
||||
const collectionName = 'records';
|
||||
const collection = ctx.db.getCollection(collectionName);
|
||||
const fields = collection.fields;
|
||||
const filterParser = new FilterParser(filter, {
|
||||
@ -168,22 +154,17 @@ export class RecordPreviewController {
|
||||
const query = {
|
||||
where: where || {},
|
||||
attributes: [
|
||||
[sequelize.fn('sum', sequelize.col('record.all_price')), 'all_price'],
|
||||
[sequelize.col('view_records_contracts.movement'), 'movement'],
|
||||
],
|
||||
group: [sequelize.col('view_records_contracts.movement')],
|
||||
include: [
|
||||
{
|
||||
association: 'record',
|
||||
attributes: [],
|
||||
},
|
||||
...parsedFilterInclude,
|
||||
[sequelize.fn('sum', sequelize.col('records.all_price')), 'all_price'],
|
||||
[sequelize.col('records.movement'), 'movement'],
|
||||
],
|
||||
group: [sequelize.col('records.movement')],
|
||||
include: [...parsedFilterInclude],
|
||||
order: [],
|
||||
subQuery: false,
|
||||
raw: true,
|
||||
} as any;
|
||||
const records = await ctx.db.getModel('view_records_contracts').findAll(query);
|
||||
const records = await ctx.db.getModel('records').findAll(query);
|
||||
|
||||
const inNum = records.find((item) => item.movement === Movement.in)?.all_price ?? 0;
|
||||
const outNum = records.find((item) => item.movement === Movement.out)?.all_price ?? 0;
|
||||
const data = {
|
||||
@ -195,270 +176,70 @@ export class RecordPreviewController {
|
||||
|
||||
@Action('pdf')
|
||||
async printPreview(ctx: Context) {
|
||||
// 中间表id,盘点单id,单双列展示,人工/全部/带金额,距上边距,纸张,字体,注解
|
||||
const {
|
||||
params: { recordId: id, stockId, isDouble, settingType, margingTop, paper, font, annotate },
|
||||
params: { recordId, isDouble, settingType, margingTop },
|
||||
} = ctx.action;
|
||||
|
||||
// #region 样式参数
|
||||
let pdfTop: number;
|
||||
if (Number(margingTop)) {
|
||||
pdfTop = Number(margingTop);
|
||||
} else {
|
||||
const currentUser = await ctx.db.getRepository('users').findOne({ filter: { id: ctx.state.currentUser.id } });
|
||||
pdfTop = Number(currentUser?.pdf_top_margin);
|
||||
}
|
||||
const isAnnotate = annotate === 'true' ? true : false;
|
||||
// 拉侧面文字说明
|
||||
const pdfExplain = await ctx.db.getRepository('basic_configuration').find();
|
||||
// 租金数据
|
||||
const leaseData = await ctx.db.sequelize.query(this.sqlLoader.sqlFiles['pdf_record_lease'], {
|
||||
replacements: {
|
||||
recordId,
|
||||
},
|
||||
type: QueryTypes.SELECT,
|
||||
});
|
||||
// 记录单数据
|
||||
const records = await ctx.db.sequelize.query(this.sqlLoader.sqlFiles['pdf_record'], {
|
||||
replacements: {
|
||||
recordId,
|
||||
},
|
||||
type: QueryTypes.SELECT,
|
||||
});
|
||||
const record = records[0] as any;
|
||||
// 拉标题
|
||||
const systemSetting = await this.systemSetting.get();
|
||||
record.systemTitle = systemSetting?.title || '异常数据,请联系相关负责人!';
|
||||
const userID = record.createdById || record.updatedById;
|
||||
const user = await ctx.db.getRepository('users').findOne({ filter: { id: userID } });
|
||||
record.nickname = user?.nickname || '';
|
||||
record.userPhone = user?.phone || '';
|
||||
record.pdfExplain = pdfExplain[0]?.out_of_storage_explain;
|
||||
if (Number(margingTop)) {
|
||||
record.margingTop = Number(margingTop);
|
||||
} else {
|
||||
// 查询当前用户信息
|
||||
const currentUser = await ctx.db.getRepository('users').findOne({ filter: { id: ctx.state.currentUser.id } });
|
||||
record.margingTop = Number(currentUser?.pdf_top_margin) || 0;
|
||||
}
|
||||
|
||||
const double = isDouble === '0' || isDouble === '1' ? isDouble : pdfExplain[0].record_columns;
|
||||
// 费用数据
|
||||
const feeData = await ctx.db.sequelize.query(this.sqlLoader.sqlFiles['pdf_record_fee'], {
|
||||
replacements: {
|
||||
recordId,
|
||||
},
|
||||
type: QueryTypes.SELECT,
|
||||
});
|
||||
// 订单打印选项
|
||||
const printSetup =
|
||||
settingType === '0' || settingType === '1' || settingType === '2'
|
||||
? settingType
|
||||
: pdfExplain[0]?.record_print_setup;
|
||||
// #endregion 样式参数
|
||||
const double = isDouble === '0' || isDouble === '1' ? isDouble : pdfExplain[0].record_columns;
|
||||
|
||||
// #region 查询视图前执行更新视图,用来确定所有产品的相关父级id
|
||||
const products_view = this.sqlLoader.sqlFiles['products_search_rule_special'];
|
||||
await ctx.db.sequelize.query(products_view);
|
||||
// #endregion
|
||||
|
||||
// 1.盘点单 只需要 leaseData
|
||||
// 2.租赁/购销单 需要 leaseData、leaseFeeData、noLeaseProductFeeData、noRuleexcluded
|
||||
// 3.暂存单 只需要 leaseData
|
||||
let leaseData = [];
|
||||
let leaseFeeData = [];
|
||||
let noLeaseProductFeeData = [];
|
||||
let noRuleexcluded = [];
|
||||
let contracts = {};
|
||||
let intermediate: any;
|
||||
let baseRecord: any;
|
||||
if (stockId !== 'undefined') {
|
||||
// 盘点单
|
||||
leaseData = await ctx.db.sequelize.query(
|
||||
`
|
||||
select
|
||||
p.id AS products_id,
|
||||
p2.id AS "parentId",
|
||||
ri."comment",
|
||||
p2.name AS "parentName",
|
||||
p2.name || '[' || p.name || ']' AS "name",
|
||||
p2.unit,
|
||||
p2.convertible,
|
||||
p2.conversion_unit,
|
||||
p.weight AS products_weight,
|
||||
p.ratio AS products_ratio,
|
||||
ri.count,
|
||||
2 as conversion_logic_id
|
||||
from record_stock rs
|
||||
join record_items ri on ri.stock_id = rs.id
|
||||
join products p on p.id = ri.new_product_id
|
||||
left join products p2 on p2.id = p."parentId"
|
||||
where rs.id = :stockId`,
|
||||
{
|
||||
replacements: {
|
||||
stockId,
|
||||
},
|
||||
type: QueryTypes.SELECT,
|
||||
},
|
||||
);
|
||||
const record_stock = await ctx.db
|
||||
.getRepository('record_stock')
|
||||
.findOne({ where: { id: stockId }, appends: ['project'] });
|
||||
const userID = record_stock.createdById || record_stock.updatedById || 6; // 记得将盘点用户信息补全
|
||||
const user = await ctx.db.getRepository('users').findOne({ filter: { id: userID } });
|
||||
baseRecord = {
|
||||
number: record_stock.id, // 记得生成单号替换
|
||||
date: record_stock.date,
|
||||
pdfExplain: pdfExplain[0]?.out_of_storage_explain,
|
||||
nickname: user.nickname,
|
||||
userPhone: user.phone,
|
||||
systemName: pdfExplain[0]?.name,
|
||||
plate: record_stock.project.name,
|
||||
};
|
||||
} else {
|
||||
// 租赁/购销/暂存单
|
||||
// 判断是外部视图查看还是表单中间表查看
|
||||
let model = 'record_contract';
|
||||
let isStock = false;
|
||||
if (id.split('_').length > 1) {
|
||||
// 视图的情况
|
||||
model = 'view_records_contracts';
|
||||
}
|
||||
intermediate = await ctx.db.getRepository(model).findOne({ filter: { id } }); // 中间表/出入库视图
|
||||
const recordId = intermediate.record_id; // 订单id
|
||||
const contractId = intermediate.contract_id; // 合同id
|
||||
let intermediateId = intermediate.id; // 中间表id
|
||||
|
||||
if (id.split('_').length > 1) {
|
||||
// 视图的情况
|
||||
intermediateId = parseInt(id.split('_')[1]);
|
||||
}
|
||||
baseRecord = await ctx.db.getRepository('records').findOne({
|
||||
filter: { id: recordId },
|
||||
appends: [
|
||||
'vehicles',
|
||||
'in_stock',
|
||||
'in_stock.company',
|
||||
'in_stock.contacts',
|
||||
'out_stock',
|
||||
'out_stock.company',
|
||||
'out_stock.contacts',
|
||||
],
|
||||
});
|
||||
let number;
|
||||
if (intermediate.number) {
|
||||
// 视图查看
|
||||
number = intermediate.number;
|
||||
} else if (!intermediate.number && model === 'record_contract') {
|
||||
const view = await ctx.db
|
||||
.getRepository('view_records_contracts')
|
||||
.findOne({ filter: { rc_id: intermediateId } });
|
||||
number = view.number;
|
||||
}
|
||||
baseRecord.number = number || baseRecord.number;
|
||||
// 3.拼接订单的pdf基础数据, 用户信息
|
||||
const userID = baseRecord.createdById || baseRecord.updatedById;
|
||||
const user = await ctx.db.getRepository('users').findOne({ filter: { id: userID } });
|
||||
baseRecord.nickname = user?.nickname || '';
|
||||
baseRecord.userPhone = user?.phone || '';
|
||||
// 侧面栏提示信息
|
||||
baseRecord.pdfExplain = pdfExplain[0]?.out_of_storage_explain;
|
||||
baseRecord.systemName = pdfExplain[0]?.name;
|
||||
|
||||
isStock = intermediate.record_category === '3'; // 判断是否为暂存单
|
||||
if (isStock) {
|
||||
contracts['record_category'] = '3';
|
||||
const company = await ctx.db.getRepository('company').findOne({
|
||||
filter: {
|
||||
id: intermediate.company_id,
|
||||
},
|
||||
appends: ['projects'],
|
||||
});
|
||||
contracts['first_party'] = company;
|
||||
const movement = company.projects.find((item) => item.id === baseRecord.in_stock_id) ? '1' : '-1';
|
||||
contracts['movement'] = movement;
|
||||
// 暂存单只需要leaseDate
|
||||
leaseData = await ctx.db.sequelize.query(
|
||||
`
|
||||
select
|
||||
p.id AS products_id,
|
||||
p2.id AS "parentId",
|
||||
ri."comment",
|
||||
p2.name AS "parentName",
|
||||
p2.name || '[' || p.name || ']' AS "name",
|
||||
p2.unit,
|
||||
p2.convertible,
|
||||
p2.conversion_unit,
|
||||
p.weight AS products_weight,
|
||||
p.ratio AS products_ratio,
|
||||
ri.count,
|
||||
2 as conversion_logic_id
|
||||
from records r
|
||||
join record_items ri on ri.record_id = r.id
|
||||
join products p on p.id = ri.new_product_id
|
||||
left join products p2 on p2.id = p."parentId"
|
||||
where r.id = :recordId`,
|
||||
{
|
||||
replacements: {
|
||||
recordId,
|
||||
},
|
||||
type: QueryTypes.SELECT,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
contracts = await ctx.db.getRepository('contracts').findOne({
|
||||
filter: {
|
||||
id: intermediate.contract_id,
|
||||
},
|
||||
appends: ['first_party', 'first_party.projects', 'party_b', 'party_b.projects'],
|
||||
});
|
||||
contracts['movement'] = intermediate.movement;
|
||||
// 租赁/购销
|
||||
leaseData = await ctx.db.sequelize.query(this.sqlLoader.sqlFiles['pdf_record_product_item'], {
|
||||
replacements: {
|
||||
recordId,
|
||||
contractId,
|
||||
},
|
||||
type: QueryTypes.SELECT,
|
||||
});
|
||||
// 租金产品赔偿
|
||||
leaseFeeData = await ctx.db.sequelize.query(this.sqlLoader.sqlFiles['pdf_record_product_fee_item'], {
|
||||
replacements: {
|
||||
intermediateId: parseInt(intermediateId),
|
||||
},
|
||||
type: QueryTypes.SELECT,
|
||||
});
|
||||
|
||||
// 无关联数据
|
||||
noLeaseProductFeeData = await ctx.db.sequelize.query(this.sqlLoader.sqlFiles['pdf_record_no_porduct_fees'], {
|
||||
replacements: {
|
||||
recordId,
|
||||
contractId,
|
||||
},
|
||||
type: QueryTypes.SELECT,
|
||||
});
|
||||
|
||||
// 比如运费按照出入库量,但是录单存在排除的情况,特殊处理
|
||||
noRuleexcluded = await ctx.db.sequelize.query(
|
||||
`
|
||||
select
|
||||
rfin.count ,
|
||||
rfin."comment" ,
|
||||
rfin.new_fee_product_id,
|
||||
p2.name || '[' || p.name || ']' as fee_name,
|
||||
p.custom_name,
|
||||
rfin.is_excluded
|
||||
from record_contract rc
|
||||
join record_fee_items_new rfin on rfin.record_contract_id = rc.id and rfin.is_excluded is true and rfin.new_product_id is null
|
||||
join products p on p.id = rfin.new_fee_product_id
|
||||
left join products p2 on p."parentId" = p2.id
|
||||
where rc.id = :intermediateId
|
||||
`,
|
||||
{
|
||||
replacements: {
|
||||
intermediateId: parseInt(intermediateId),
|
||||
},
|
||||
type: QueryTypes.SELECT,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// #endregion
|
||||
const cache = ctx.app.cacheManager.getCache('@hera/plugin-rental') as Cache;
|
||||
const key = stringify({
|
||||
intermediate,
|
||||
baseRecord,
|
||||
leaseData,
|
||||
leaseFeeData,
|
||||
noLeaseProductFeeData,
|
||||
noRuleexcluded,
|
||||
contracts,
|
||||
settings: { isDouble: double, printSetup, margingTop: pdfTop, paper, font, isAnnotate },
|
||||
});
|
||||
const key = stringify({ record, leaseData, feeData, settings: { isDouble: double, printSetup } });
|
||||
|
||||
const result = await cache.get(key);
|
||||
if (result) {
|
||||
if (Buffer.isBuffer(result)) {
|
||||
ctx.body = result;
|
||||
} else {
|
||||
//@ts-ignore
|
||||
ctx.body = Buffer.from(result.data);
|
||||
}
|
||||
} else {
|
||||
const buf = await getStream.buffer(
|
||||
//@ts-ignore
|
||||
await this.recordPdfService.transformPdfV2(
|
||||
intermediate,
|
||||
baseRecord,
|
||||
leaseData,
|
||||
leaseFeeData,
|
||||
noLeaseProductFeeData,
|
||||
noRuleexcluded,
|
||||
contracts,
|
||||
{ isDouble: double, printSetup, margingTop: pdfTop, paper, font, isAnnotate },
|
||||
),
|
||||
// @ts-ignore
|
||||
await this.recordPdfService.transformPdfV2(record, leaseData, feeData, { isDouble: double, printSetup }),
|
||||
);
|
||||
ctx.body = buf;
|
||||
await cache.set(key, buf);
|
||||
|
@ -7,7 +7,6 @@ import { QueryTypes } from 'sequelize';
|
||||
import { Cache } from '@tachybase/cache';
|
||||
import getStream from 'get-stream';
|
||||
import { stringify } from 'flatted';
|
||||
import { SettlementProductsService } from '../services/settlement-products-service';
|
||||
|
||||
@Controller('settlements')
|
||||
export class SettlementController {
|
||||
@ -20,78 +19,23 @@ export class SettlementController {
|
||||
@Inject(() => SettlementService)
|
||||
private settlmentService: SettlementService;
|
||||
|
||||
@Inject(() => SettlementProductsService)
|
||||
private SettlementProductsService: SettlementProductsService;
|
||||
|
||||
@Action('calculate')
|
||||
async updateOrderDetails(ctx: Context) {
|
||||
const {
|
||||
params: { settlementsId },
|
||||
} = ctx.action;
|
||||
const products_view = this.sqlLoader.sqlFiles['products_search_rule_special'];
|
||||
await ctx.db.sequelize.query(products_view);
|
||||
const leaseSql = this.sqlLoader.sqlFiles['settlement_calc_products'];
|
||||
const feeSql = this.sqlLoader.sqlFiles['settlement_calc_fee_products'];
|
||||
const feeNoProductSql = this.sqlLoader.sqlFiles['settlement_calc_fee_no_products'];
|
||||
const recordFeeSql = this.sqlLoader.sqlFiles['settlement_calc_record_fee_products'];
|
||||
const settlementLeaseData = await ctx.db.sequelize.query(leaseSql, {
|
||||
|
||||
const SQL = this.sqlLoader.sqlFiles['settlement_calc'];
|
||||
const settlement = await ctx.db.sequelize.query(SQL, {
|
||||
logging: console.log,
|
||||
raw: true,
|
||||
plain: true,
|
||||
replacements: {
|
||||
settlementsId,
|
||||
},
|
||||
type: QueryTypes.SELECT,
|
||||
});
|
||||
const settlementFeeData = await ctx.db.sequelize.query(feeSql, {
|
||||
replacements: {
|
||||
settlementsId,
|
||||
},
|
||||
type: QueryTypes.SELECT,
|
||||
});
|
||||
const settlementFeeNoProductData: any = await ctx.db.sequelize.query(feeNoProductSql, {
|
||||
replacements: {
|
||||
settlementsId,
|
||||
},
|
||||
type: QueryTypes.SELECT,
|
||||
});
|
||||
const settlement = await ctx.db.getRepository('settlements').findOne({
|
||||
where: {
|
||||
id: settlementsId,
|
||||
},
|
||||
fields: ['start_date', 'end_date'],
|
||||
});
|
||||
const settlementRecordFee: any = await ctx.db.sequelize.query(recordFeeSql, {
|
||||
replacements: {
|
||||
settlementsId,
|
||||
},
|
||||
type: QueryTypes.SELECT,
|
||||
});
|
||||
for (const item of settlementFeeNoProductData) {
|
||||
if (item.conversion_logic_id > 4) {
|
||||
const weightRules = await ctx.db.getRepository('weight_rules').find({
|
||||
where: {
|
||||
logic_id: item.conversion_logic_id,
|
||||
},
|
||||
appends: ['new_product'],
|
||||
});
|
||||
item['weightRules'] = weightRules;
|
||||
} else {
|
||||
item['weightRules'] = null;
|
||||
}
|
||||
}
|
||||
const settlementAddItems = await ctx.db.getRepository('settlement_add_items').findOne({
|
||||
where: {
|
||||
add_id: settlementsId,
|
||||
},
|
||||
});
|
||||
const settlementAbout = {
|
||||
settlementLeaseData,
|
||||
settlementFeeData,
|
||||
settlementFeeNoProductData,
|
||||
settlementRecordFee,
|
||||
settlementAddItems,
|
||||
start_date: settlement.start_date,
|
||||
end_date: settlement.end_date,
|
||||
};
|
||||
await this.SettlementProductsService.calculate(settlementAbout as any, settlementsId);
|
||||
await this.settlmentService.calculate(settlement as any, settlementsId);
|
||||
}
|
||||
|
||||
@Action('pdf')
|
||||
|
@ -20,20 +20,12 @@ export class WaybillsController {
|
||||
ctx.body = await renderWaybill(null);
|
||||
return;
|
||||
}
|
||||
const products = await ctx.db.sequelize.query(this.sqlLoader.sqlFiles['waybills_products'], {
|
||||
replacements: {
|
||||
recordId: recordId,
|
||||
},
|
||||
type: QueryTypes.SELECT,
|
||||
});
|
||||
const waybills = await ctx.db.sequelize.query(this.sqlLoader.sqlFiles['pdf_waybills'], {
|
||||
replacements: {
|
||||
recordId: recordId,
|
||||
},
|
||||
type: QueryTypes.SELECT,
|
||||
});
|
||||
const data = waybills[0];
|
||||
data['products'] = products;
|
||||
const settings = {};
|
||||
if (Number(margingTop)) {
|
||||
settings['margingTop'] = Number(margingTop);
|
||||
@ -41,7 +33,7 @@ export class WaybillsController {
|
||||
const currentUser = await ctx.db.getRepository('users').findOne({ filter: { id: ctx.state.currentUser.id } });
|
||||
settings['margingTop'] = Number(currentUser?.pdf_top_margin) || 0;
|
||||
}
|
||||
ctx.body = await renderWaybill(data as Waybill, settings);
|
||||
ctx.body = await renderWaybill(waybills[0] as Waybill, settings);
|
||||
}
|
||||
|
||||
@Action('group')
|
||||
|
@ -8,8 +8,8 @@ export default class extends Migration {
|
||||
console.log('开始执行脚本:record_category_script');
|
||||
const result: any = await this.app.db.sequelize.query(`
|
||||
UPDATE records
|
||||
SET record_category =
|
||||
CASE
|
||||
SET record_category =
|
||||
CASE
|
||||
WHEN category = '1' AND movement = '1' THEN '2'
|
||||
WHEN category = '1' AND movement = '-1' THEN '3'
|
||||
WHEN category = '0' AND movement = '1' THEN '4'
|
||||
|
@ -1,10 +1,197 @@
|
||||
import React from 'react';
|
||||
import { Document, Page, Text, View, StyleSheet, Image, renderToStream } from '@hera/plugin-core';
|
||||
import * as QRCode from 'qrcode';
|
||||
import { RecordCategory } from '../../utils/constants';
|
||||
import { formatCurrency, formatQuantity } from '../../utils/currencyUtils';
|
||||
import { dayjs } from '@tachybase/utils';
|
||||
import { RecordPdfOptions } from '../../interfaces/options';
|
||||
|
||||
import { PrintSetup } from '../../utils/system';
|
||||
const fontSizes = {
|
||||
title: '13px',
|
||||
subTitle: '11px',
|
||||
main: '9px',
|
||||
side: '8px',
|
||||
};
|
||||
const styles = StyleSheet.create({
|
||||
page: {
|
||||
flexDirection: 'column',
|
||||
backgroundColor: '#FFF',
|
||||
fontFamily: 'source-han-sans',
|
||||
padding: '12px',
|
||||
},
|
||||
title: {
|
||||
textAlign: 'center',
|
||||
fontSize: fontSizes.title,
|
||||
},
|
||||
subTitle: {
|
||||
textAlign: 'center',
|
||||
fontSize: fontSizes.subTitle,
|
||||
},
|
||||
content: {
|
||||
flexDirection: 'row',
|
||||
marginLeft: '10pt',
|
||||
marginRight: '10pt',
|
||||
},
|
||||
main: {
|
||||
flex: 1,
|
||||
},
|
||||
side: {
|
||||
width: '11px',
|
||||
fontSize: fontSizes.side,
|
||||
paddingLeft: '2px',
|
||||
},
|
||||
tableHeader: {
|
||||
fontSize: fontSizes.main,
|
||||
flexDirection: 'row',
|
||||
},
|
||||
headerLeft: {
|
||||
width: '205px',
|
||||
},
|
||||
headerMiddle: {
|
||||
flex: 1,
|
||||
},
|
||||
headerLeftLeft: {
|
||||
flex: 2,
|
||||
},
|
||||
headerLeftRight: {
|
||||
flex: 1,
|
||||
},
|
||||
headerRight: {
|
||||
width: '205px',
|
||||
},
|
||||
tableContentTitle: {
|
||||
fontSize: fontSizes.main,
|
||||
flexDirection: 'row',
|
||||
},
|
||||
tableCellLargeTitle: {
|
||||
flex: 2,
|
||||
textAlign: 'center',
|
||||
borderLeft: '1px solid black',
|
||||
marginLeft: '-1px',
|
||||
borderTop: '1px solid black',
|
||||
marginTop: '-1px',
|
||||
},
|
||||
tableCellTitle: {
|
||||
flex: 1,
|
||||
textAlign: 'center',
|
||||
borderLeft: '1px solid black',
|
||||
marginLeft: '-1px',
|
||||
borderTop: '1px solid black',
|
||||
marginTop: '-1px',
|
||||
},
|
||||
tableCell2Title: {
|
||||
flex: 2,
|
||||
textAlign: 'center',
|
||||
borderLeft: '1px solid black',
|
||||
marginLeft: '-1px',
|
||||
borderTop: '1px solid black',
|
||||
marginTop: '-1px',
|
||||
},
|
||||
tableCellTitleLast: {
|
||||
flex: 1,
|
||||
textAlign: 'center',
|
||||
borderLeft: '1px solid black',
|
||||
marginLeft: '-1px',
|
||||
borderTop: '1px solid black',
|
||||
marginTop: '-1px',
|
||||
borderRight: '1px solid black',
|
||||
marginRight: '-1px',
|
||||
},
|
||||
tableCell2TitleLast: {
|
||||
flex: 2,
|
||||
textAlign: 'center',
|
||||
borderLeft: '1px solid black',
|
||||
marginLeft: '-1px',
|
||||
borderTop: '1px solid black',
|
||||
marginTop: '-1px',
|
||||
borderRight: '1px solid black',
|
||||
marginRight: '-1px',
|
||||
},
|
||||
tableContent: {
|
||||
fontSize: fontSizes.main,
|
||||
flexDirection: 'row',
|
||||
},
|
||||
tableCell: {
|
||||
flex: 1,
|
||||
textAlign: 'right',
|
||||
borderLeft: '1px solid black',
|
||||
marginLeft: '-1px',
|
||||
borderTop: '1px solid black',
|
||||
marginTop: '-1px',
|
||||
borderBottom: '1px solid black',
|
||||
},
|
||||
tableCellNoLeft: {
|
||||
flex: 1,
|
||||
textAlign: 'right',
|
||||
borderTop: '1px solid black',
|
||||
marginTop: '-1px',
|
||||
borderBottom: '1px solid black',
|
||||
},
|
||||
tableCell2: {
|
||||
flex: 2,
|
||||
textAlign: 'right',
|
||||
borderLeft: '1px solid black',
|
||||
marginLeft: '-1px',
|
||||
borderTop: '1px solid black',
|
||||
marginTop: '-1px',
|
||||
borderBottom: '1px solid black',
|
||||
},
|
||||
tableCellLast: {
|
||||
flex: 1,
|
||||
textAlign: 'right',
|
||||
borderLeft: '1px solid black',
|
||||
marginLeft: '-1px',
|
||||
borderTop: '1px solid black',
|
||||
marginTop: '-1px',
|
||||
borderRight: '1px solid black',
|
||||
marginRight: '-1px',
|
||||
borderBottom: '1px solid black',
|
||||
},
|
||||
tableCell2Last: {
|
||||
flex: 2,
|
||||
textAlign: 'right',
|
||||
borderLeft: '1px solid black',
|
||||
marginLeft: '-1px',
|
||||
borderTop: '1px solid black',
|
||||
marginTop: '-1px',
|
||||
borderRight: '1px solid black',
|
||||
marginRight: '-1px',
|
||||
borderBottom: '1px solid black',
|
||||
},
|
||||
tableFooter: {
|
||||
flexDirection: 'row',
|
||||
},
|
||||
tableFooterQr: {
|
||||
width: '50px',
|
||||
marginLeft: '-50px',
|
||||
transform: 'translate(50px, 0)',
|
||||
},
|
||||
tableFooterLeft: {
|
||||
flex: 1,
|
||||
fontSize: fontSizes.main,
|
||||
borderLeft: '1px solid black',
|
||||
paddingLeft: '50px',
|
||||
marginLeft: '-1px',
|
||||
borderTop: '1px solid black',
|
||||
marginTop: '-1px',
|
||||
borderBottom: '1px solid black',
|
||||
marginBottom: '-1px',
|
||||
},
|
||||
tableFooterRight: {
|
||||
flex: 1,
|
||||
fontSize: fontSizes.main,
|
||||
border: '1px solid black',
|
||||
paddingRight: '50px',
|
||||
margin: '-1px',
|
||||
},
|
||||
sign: {
|
||||
marginTop: '0px',
|
||||
flexDirection: 'row',
|
||||
},
|
||||
signPart: {
|
||||
flex: 1,
|
||||
fontSize: fontSizes.main,
|
||||
},
|
||||
});
|
||||
/**
|
||||
*
|
||||
* @param isDouble 0为单列,1为双列
|
||||
@ -15,223 +202,67 @@ const PreviewDocument = ({
|
||||
detail,
|
||||
record,
|
||||
priceRule,
|
||||
options,
|
||||
isDouble,
|
||||
printSetup,
|
||||
}: {
|
||||
imageUrl: string;
|
||||
detail: any;
|
||||
record: any[];
|
||||
priceRule: any[];
|
||||
options: any; // RecordPdfOptions;
|
||||
isDouble: Number;
|
||||
printSetup: String;
|
||||
}) => {
|
||||
const fontSizes = {
|
||||
title: '13px',
|
||||
subTitle: '11px',
|
||||
main: `${options.font || 9}px`,
|
||||
side: '8px',
|
||||
};
|
||||
const styles = StyleSheet.create({
|
||||
page: {
|
||||
flexDirection: 'column',
|
||||
backgroundColor: '#FFF',
|
||||
fontFamily: 'source-han-sans',
|
||||
padding: '12px',
|
||||
},
|
||||
title: {
|
||||
textAlign: 'center',
|
||||
fontSize: fontSizes.title,
|
||||
},
|
||||
subTitle: {
|
||||
textAlign: 'center',
|
||||
fontSize: fontSizes.subTitle,
|
||||
},
|
||||
content: {
|
||||
flexDirection: 'row',
|
||||
marginLeft: '10pt',
|
||||
marginRight: '10pt',
|
||||
},
|
||||
main: {
|
||||
flex: 1,
|
||||
},
|
||||
side: {
|
||||
width: '11px',
|
||||
fontSize: fontSizes.side,
|
||||
paddingLeft: '2px',
|
||||
},
|
||||
tableHeader: {
|
||||
fontSize: fontSizes.main,
|
||||
flexDirection: 'row',
|
||||
},
|
||||
headerLeft: {
|
||||
width: '205px',
|
||||
},
|
||||
headerMiddle: {
|
||||
flex: 1,
|
||||
},
|
||||
headerLeftLeft: {
|
||||
flex: 2,
|
||||
},
|
||||
headerLeftRight: {
|
||||
flex: 1,
|
||||
},
|
||||
headerRight: {
|
||||
width: '205px',
|
||||
},
|
||||
tableContentTitle: {
|
||||
fontSize: fontSizes.main,
|
||||
flexDirection: 'row',
|
||||
},
|
||||
tableCellLargeTitle: {
|
||||
flex: 2,
|
||||
textAlign: 'center',
|
||||
borderLeft: '1px solid black',
|
||||
marginLeft: '-1px',
|
||||
borderTop: '1px solid black',
|
||||
marginTop: '-1px',
|
||||
},
|
||||
tableCellTitle: {
|
||||
flex: 1,
|
||||
textAlign: 'center',
|
||||
borderLeft: '1px solid black',
|
||||
marginLeft: '-1px',
|
||||
borderTop: '1px solid black',
|
||||
marginTop: '-1px',
|
||||
},
|
||||
tableCell2Title: {
|
||||
flex: 2,
|
||||
textAlign: 'center',
|
||||
borderLeft: '1px solid black',
|
||||
marginLeft: '-1px',
|
||||
borderTop: '1px solid black',
|
||||
marginTop: '-1px',
|
||||
},
|
||||
tableCellTitleLast: {
|
||||
flex: 1,
|
||||
textAlign: 'center',
|
||||
borderLeft: '1px solid black',
|
||||
marginLeft: '-1px',
|
||||
borderTop: '1px solid black',
|
||||
marginTop: '-1px',
|
||||
borderRight: '1px solid black',
|
||||
marginRight: '-1px',
|
||||
},
|
||||
tableCell2TitleLast: {
|
||||
flex: 2,
|
||||
textAlign: 'center',
|
||||
borderLeft: '1px solid black',
|
||||
marginLeft: '-1px',
|
||||
borderTop: '1px solid black',
|
||||
marginTop: '-1px',
|
||||
borderRight: '1px solid black',
|
||||
marginRight: '-1px',
|
||||
},
|
||||
tableContent: {
|
||||
fontSize: fontSizes.main,
|
||||
flexDirection: 'row',
|
||||
},
|
||||
tableCell: {
|
||||
flex: 1,
|
||||
textAlign: 'right',
|
||||
borderLeft: '1px solid black',
|
||||
marginLeft: '-1px',
|
||||
borderTop: '1px solid black',
|
||||
marginTop: '-1px',
|
||||
borderBottom: '1px solid black',
|
||||
},
|
||||
tableCellNoLeft: {
|
||||
flex: 1,
|
||||
textAlign: 'right',
|
||||
borderTop: '1px solid black',
|
||||
marginTop: '-1px',
|
||||
borderBottom: '1px solid black',
|
||||
},
|
||||
tableCell2: {
|
||||
flex: 2,
|
||||
textAlign: 'right',
|
||||
borderLeft: '1px solid black',
|
||||
marginLeft: '-1px',
|
||||
borderTop: '1px solid black',
|
||||
marginTop: '-1px',
|
||||
borderBottom: '1px solid black',
|
||||
},
|
||||
tableCellLast: {
|
||||
flex: 1,
|
||||
textAlign: 'right',
|
||||
borderLeft: '1px solid black',
|
||||
marginLeft: '-1px',
|
||||
borderTop: '1px solid black',
|
||||
marginTop: '-1px',
|
||||
borderRight: '1px solid black',
|
||||
marginRight: '-1px',
|
||||
borderBottom: '1px solid black',
|
||||
},
|
||||
tableCell2Last: {
|
||||
flex: 2,
|
||||
textAlign: 'right',
|
||||
borderLeft: '1px solid black',
|
||||
marginLeft: '-1px',
|
||||
borderTop: '1px solid black',
|
||||
marginTop: '-1px',
|
||||
borderRight: '1px solid black',
|
||||
marginRight: '-1px',
|
||||
borderBottom: '1px solid black',
|
||||
},
|
||||
tableFooter: {
|
||||
flexDirection: 'row',
|
||||
},
|
||||
tableFooterQr: {
|
||||
width: '50px',
|
||||
marginLeft: '-50px',
|
||||
transform: 'translate(50px, 0)',
|
||||
},
|
||||
tableFooterLeft: {
|
||||
flex: 1,
|
||||
fontSize: fontSizes.main,
|
||||
borderLeft: '1px solid black',
|
||||
paddingLeft: '50px',
|
||||
marginLeft: '-1px',
|
||||
borderTop: '1px solid black',
|
||||
marginTop: '-1px',
|
||||
borderBottom: '1px solid black',
|
||||
marginBottom: '-1px',
|
||||
},
|
||||
tableFooterRight: {
|
||||
flex: 1,
|
||||
fontSize: fontSizes.main,
|
||||
border: '1px solid black',
|
||||
paddingRight: '50px',
|
||||
margin: '-1px',
|
||||
},
|
||||
sign: {
|
||||
marginTop: '0px',
|
||||
flexDirection: 'row',
|
||||
},
|
||||
signPart: {
|
||||
flex: 1,
|
||||
fontSize: fontSizes.main,
|
||||
},
|
||||
});
|
||||
const annotate = options.isAnnotate;
|
||||
if (annotate) {
|
||||
let commentIndex = 1;
|
||||
record.forEach((item) => {
|
||||
if (item.comment) {
|
||||
item.commentIndex = commentIndex;
|
||||
commentIndex++;
|
||||
isDouble = Number(isDouble);
|
||||
const date = detail.date;
|
||||
const number = detail.number;
|
||||
const origin = detail.original_number;
|
||||
const singlePlayer = detail.nickname + ' ' + detail?.userPhone;
|
||||
const car = detail.vehicles ? detail.vehicles.map((item) => item?.number).join(' ') : '';
|
||||
const outOfStorage = detail.movement > 0 ? '入库' : '出库';
|
||||
const getTitle = () => {
|
||||
let name;
|
||||
if (detail.category === RecordCategory.lease) {
|
||||
name = detail.contract?.project?.associated_company?.name ?? detail.systemTitle;
|
||||
} else {
|
||||
if (outOfStorage === '入库') {
|
||||
name = detail.in_stock?.name ?? detail.systemTitle;
|
||||
} else {
|
||||
name = detail.out_stock?.name ?? detail.systemTitle;
|
||||
}
|
||||
});
|
||||
}
|
||||
const paper = options.paper;
|
||||
const isDouble = Number(options.isDouble);
|
||||
const explain = !detail.record_category
|
||||
? `盘点单用于清算仓库盈亏盈余。`
|
||||
: `如供需双方未签正式合同,本${
|
||||
detail.record_category
|
||||
}${detail.movement}单经供需双方代表签字确认后, 将作为合同及发生业务往来的有效凭证,如已签合同,则成为该合同的组成部分。${
|
||||
detail.movement === '入库' ? '出库方' : '采购方'
|
||||
}须核对 以上产品规格、数量确认后可签字认可。`;
|
||||
}
|
||||
return name;
|
||||
};
|
||||
const recordsName = getTitle();
|
||||
const outOfStorageAddress = (type) => {
|
||||
// 此type用于展示出入类型
|
||||
if (type === 1) {
|
||||
// 返回出库
|
||||
return detail.out_stock.name;
|
||||
} else {
|
||||
// 确定入库
|
||||
return detail.in_stock.name;
|
||||
}
|
||||
};
|
||||
const projectPhone = detail.contract?.project?.contacts
|
||||
?.map((item) => (item.name || '') + (item.phone || ''))
|
||||
.join(' ');
|
||||
const recordType = {
|
||||
'0': '租赁',
|
||||
'1': '购销',
|
||||
'2': '暂存',
|
||||
'3': '盘点',
|
||||
};
|
||||
const explain =
|
||||
detail.category === RecordCategory.inventory
|
||||
? `盘点单用于清算仓库盈亏盈余。`
|
||||
: `如供需双方未签正式合同,本${
|
||||
recordType[detail.category]
|
||||
}${outOfStorage}单经供需双方代表签字确认后, 将作为合同及发生业务往来的有效凭证,如已签合同,则成为该合同的组成部分。${
|
||||
outOfStorage === '入库' ? '出库方' : '采购方'
|
||||
}须核对 以上产品规格、数量确认后可签字认可。`;
|
||||
const getAllPrice = () => {
|
||||
let price = 0;
|
||||
if (detail.record_category === '购销' && priceRule.filter(Boolean).length) {
|
||||
if (detail.category === RecordCategory.purchase && priceRule.filter(Boolean).length) {
|
||||
priceRule.forEach((element) => {
|
||||
price += element.all_price;
|
||||
});
|
||||
@ -239,7 +270,7 @@ const PreviewDocument = ({
|
||||
return formatCurrency(price, 2);
|
||||
};
|
||||
const dobulePriceRule = [];
|
||||
if (isDouble && detail.record_category === '购销' && priceRule.filter(Boolean).length) {
|
||||
if (isDouble && detail.category === RecordCategory.purchase && priceRule.filter(Boolean).length) {
|
||||
// 双列展示
|
||||
const leftData = priceRule.slice(0, Math.ceil(priceRule.length / 2));
|
||||
const rightData = priceRule.slice(Math.ceil(priceRule.length / 2));
|
||||
@ -278,40 +309,26 @@ const PreviewDocument = ({
|
||||
<View key={index} style={styles.tableContent}>
|
||||
{columns.map((column, columnIndex) => (
|
||||
<React.Fragment key={columnIndex}>
|
||||
<Text style={styles.tableCell2}>
|
||||
{annotate && item[column + 'commentIndex']
|
||||
? item[column + 'commentIndex'] + '……' + item[column + 'name']
|
||||
: item[column + 'name']}
|
||||
</Text>
|
||||
<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={
|
||||
annotate
|
||||
? !isDouble || column === 'right_'
|
||||
? styles.tableCellLast
|
||||
: styles.tableCell
|
||||
: styles.tableCell
|
||||
}
|
||||
>
|
||||
<Text style={styles.tableCell}>
|
||||
{!item[column + 'total']
|
||||
? ''
|
||||
: formatQuantity(item[column + 'total'], 2) + item[column + 'conversion_unit']}
|
||||
</Text>
|
||||
{!annotate && (
|
||||
<Text style={!isDouble || column === 'right_' ? styles.tableCellLast : styles.tableCell}>
|
||||
{item[column + 'isExcluded']
|
||||
? '不计入合同 ' + (item[column + 'comment'] || '')
|
||||
: item[column + 'comment'] || ''}
|
||||
</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.record_category === '购销') {
|
||||
if (detail.category === RecordCategory.purchase) {
|
||||
const allprice = getAllPrice();
|
||||
addCol = (
|
||||
<View style={styles.tableContent}>
|
||||
@ -319,27 +336,15 @@ const PreviewDocument = ({
|
||||
<React.Fragment key={columnIndex}>
|
||||
<Text style={styles.tableCell2}></Text>
|
||||
<Text style={styles.tableCell}>{column === 'left_' ? '' : '总金额'}</Text>
|
||||
<Text
|
||||
style={
|
||||
annotate
|
||||
? !isDouble || column === 'right_'
|
||||
? styles.tableCellLast
|
||||
: styles.tableCell
|
||||
: styles.tableCell
|
||||
}
|
||||
>
|
||||
{column === 'left_' ? '' : allprice}
|
||||
</Text>
|
||||
{!annotate && (
|
||||
<Text style={!isDouble || column === 'right_' ? styles.tableCellLast : styles.tableCell}></Text>
|
||||
)}
|
||||
<Text style={styles.tableCell}>{column === 'left_' ? '' : allprice}</Text>
|
||||
<Text style={!isDouble || column === 'right_' ? styles.tableCellLast : styles.tableCell}></Text>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return detail.record_category === '购销' ? (
|
||||
return detail.category === RecordCategory.purchase ? (
|
||||
<>
|
||||
{page}
|
||||
{addCol}
|
||||
@ -376,83 +381,71 @@ const PreviewDocument = ({
|
||||
));
|
||||
};
|
||||
|
||||
const projectPhone = detail.record_party_b?.contacts?.map((item) => (item.name || '') + (item.phone || '')).join(' ');
|
||||
const car = detail.vehicles ? detail.vehicles.map((item) => item?.number).join(' ') : '';
|
||||
return (
|
||||
<Document>
|
||||
<Page size={paper || 'A4'} style={{ ...styles.page, marginTop: options.margingTop }}>
|
||||
{' '}
|
||||
{/**transform: `scale(${trans})` */}
|
||||
<Text style={styles.title}>
|
||||
{!detail.record_category
|
||||
? detail.plate
|
||||
: detail.contract_first_party?.name || detail.systemName || '异常数据,请联系相关负责人!'}
|
||||
</Text>
|
||||
<Text style={styles.subTitle}>{detail.contract_first_party ? detail.movement : '盘点'}单</Text>
|
||||
<Page size="A4" style={{ ...styles.page, marginTop: detail.margingTop }}>
|
||||
<Text style={styles.title}>{recordsName}</Text>
|
||||
<Text style={styles.subTitle}>{detail.category === RecordCategory.inventory ? '盘点' : outOfStorage}单</Text>
|
||||
<View style={styles.content}>
|
||||
<View style={styles.main}>
|
||||
{detail.record_category === '租赁' && (
|
||||
<View>
|
||||
<View style={styles.tableHeader}>
|
||||
<Text style={styles.headerLeftLeft}>承租单位:{detail.record_party_b.company.name || ''}</Text>
|
||||
<Text style={styles.headerLeftRight}>
|
||||
日期:{detail.record_date && dayjs(detail.record_date).format('YYYY-MM-DD')}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.tableHeader}>
|
||||
<Text style={styles.headerLeftLeft}>项目名称:{detail.record_party_b.name || ''}</Text>
|
||||
<Text style={styles.headerLeftRight}>流水号:{detail.record_number}</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.tableHeader}>
|
||||
<Text style={styles.headerLeftLeft}>项目地址:{detail.record_party_b.address}</Text>
|
||||
<Text style={styles.headerLeftRight}>原始单号:{detail.record_origin}</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.tableHeader}>
|
||||
<Text style={styles.headerLeftLeft}>项目联系人:{projectPhone}</Text>
|
||||
<Text style={styles.headerLeftRight}>车号:{car}</Text>
|
||||
</View>
|
||||
{/* 第一行 */}
|
||||
<View style={styles.tableHeader}>
|
||||
{detail.category === RecordCategory.purchase && (
|
||||
<Text style={styles.headerLeft}>销售单位:{outOfStorageAddress(1)}</Text>
|
||||
)}
|
||||
{detail.category === RecordCategory.staging && (
|
||||
<Text style={styles.headerLeft}>出库方:{outOfStorageAddress(1)}</Text>
|
||||
)}
|
||||
{detail.category === RecordCategory.inventory && (
|
||||
<Text style={styles.headerLeft}>盘点单位:{detail.in_stock?.name}</Text>
|
||||
)}
|
||||
{detail.category !== RecordCategory.lease && (
|
||||
<Text style={styles.headerMiddle}>日期:{date && dayjs(date).format('YYYY-MM-DD')}</Text>
|
||||
)}
|
||||
{detail.category !== RecordCategory.lease && <Text style={styles.headerRight}>流水号:{number}</Text>}
|
||||
</View>
|
||||
{/* 第二行 */}
|
||||
<View style={styles.tableHeader}>
|
||||
{detail.category === RecordCategory.purchase && (
|
||||
<Text style={styles.headerLeft}>采购单位:{outOfStorageAddress(0)}</Text>
|
||||
)}
|
||||
{detail.category === RecordCategory.staging && (
|
||||
<Text style={styles.headerLeft}>入库方:{outOfStorageAddress(0)}</Text>
|
||||
)}
|
||||
{detail.category !== RecordCategory.inventory && detail.category !== RecordCategory.lease && (
|
||||
<Text style={styles.headerMiddle}>车号:{car}</Text>
|
||||
)}
|
||||
{detail.category !== RecordCategory.inventory && detail.category !== RecordCategory.lease && (
|
||||
<Text style={styles.headerRight}>原始单号:{origin}</Text>
|
||||
)}
|
||||
</View>
|
||||
{/* 租赁 */}
|
||||
{detail.category === RecordCategory.lease && (
|
||||
<View style={styles.tableHeader}>
|
||||
<Text style={styles.headerLeftLeft}>承租单位:{detail.contract?.project?.company?.name || ''}</Text>
|
||||
<Text style={styles.headerLeftRight}>日期:{date && dayjs(date).format('YYYY-MM-DD')}</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{(detail.record_category === '购销' || detail.record_category === '暂存') && (
|
||||
<View>
|
||||
<View style={styles.tableHeader}>
|
||||
<Text style={styles.headerLeftLeft}>
|
||||
{detail.record_category === '暂存' ? '出库方:' : '销售单位:'}
|
||||
{detail.record_party_b?.company?.name || ''} {detail.record_party_b.name || ''}
|
||||
</Text>
|
||||
<Text style={styles.headerMiddle}>
|
||||
日期:{detail.record_date && dayjs(detail.record_date).format('YYYY-MM-DD')}
|
||||
</Text>
|
||||
<Text style={styles.headerLeftRight}>流水号:{detail.record_number}</Text>
|
||||
</View>
|
||||
<View style={styles.tableHeader}>
|
||||
<Text style={styles.headerLeftLeft}>
|
||||
{detail.record_category === '暂存' ? '入库方:' : '采购单位:'}
|
||||
{detail.record_party_a.name || ''}
|
||||
</Text>
|
||||
<Text style={styles.headerMiddle}>车号:{car}</Text>
|
||||
<Text style={styles.headerLeftRight}>原始单号:{detail.record_origin}</Text>
|
||||
</View>
|
||||
{detail.category === RecordCategory.lease && (
|
||||
<View style={styles.tableHeader}>
|
||||
<Text style={styles.headerLeftLeft}>项目名称:{detail.contract?.project?.name || ''}</Text>
|
||||
<Text style={styles.headerLeftRight}>流水号:{number}</Text>
|
||||
</View>
|
||||
)}
|
||||
{!detail.record_category && (
|
||||
<View>
|
||||
<View style={styles.tableHeader}>
|
||||
<Text style={styles.headerLeftLeft}>盘点单位:{detail.plate || ''}</Text>
|
||||
<Text style={styles.headerMiddle}>
|
||||
日期:{detail.record_date && dayjs(detail.record_date).format('YYYY-MM-DD')}
|
||||
</Text>
|
||||
<Text style={styles.headerLeftRight}>流水号:{detail.record_number}</Text>
|
||||
</View>
|
||||
{detail.category === RecordCategory.lease && (
|
||||
<View style={styles.tableHeader}>
|
||||
<Text style={styles.headerLeftLeft}>项目地址:{detail.contract?.project?.address}</Text>
|
||||
<Text style={styles.headerLeftRight}>原始单号:{origin}</Text>
|
||||
</View>
|
||||
)}
|
||||
{detail.category === RecordCategory.lease && (
|
||||
<View style={styles.tableHeader}>
|
||||
<Text style={styles.headerLeftLeft}>项目联系人:{projectPhone}</Text>
|
||||
<Text style={styles.headerLeftRight}>车号:{car}</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{/* 定价 */}
|
||||
{detail.record_category === '购销' && (
|
||||
{detail.category === RecordCategory.purchase && (
|
||||
<View style={styles.tableContentTitle}>
|
||||
<Text style={styles.tableCellLargeTitle}>物料名称及规格</Text>
|
||||
<Text style={styles.tableCellTitle}>单价</Text>
|
||||
@ -470,20 +463,21 @@ const PreviewDocument = ({
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
{detail.record_category === '购销' && renderPrice(isDouble ? dobulePriceRule : priceRule, isDouble)}
|
||||
{detail.category === RecordCategory.purchase &&
|
||||
renderPrice(isDouble ? dobulePriceRule : priceRule, isDouble)}
|
||||
{/* ============================================================两表分割================================================================================= */}
|
||||
{/* 单列租金及费用 */}
|
||||
<View style={styles.tableContentTitle}>
|
||||
<Text style={styles.tableCellLargeTitle}>物料名称及规格</Text>
|
||||
<Text style={styles.tableCellTitle}>数量</Text>
|
||||
<Text style={styles.tableCellTitle}>小计</Text>
|
||||
{!annotate && <Text style={!isDouble ? styles.tableCellTitleLast : styles.tableCellTitle}>备注</Text>}
|
||||
<Text style={!isDouble ? styles.tableCellTitleLast : styles.tableCellTitle}>备注</Text>
|
||||
{isDouble && (
|
||||
<>
|
||||
<Text style={styles.tableCellLargeTitle}>物料名称及规格</Text>
|
||||
<Text style={styles.tableCellTitle}>数量</Text>
|
||||
<Text style={annotate ? styles.tableCellTitleLast : styles.tableCellTitle}>小计</Text>
|
||||
{!annotate && <Text style={styles.tableCellTitleLast}>备注</Text>}
|
||||
<Text style={styles.tableCellTitle}>小计</Text>
|
||||
<Text style={styles.tableCellTitleLast}>备注</Text>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
@ -501,21 +495,14 @@ const PreviewDocument = ({
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.sign}>
|
||||
<Text style={styles.signPart}>制表人:{detail.nickname + ' ' + detail?.userPhone}</Text>
|
||||
{detail.record_category === '租赁' && <Text style={styles.signPart}>出租单位(签名):</Text>}
|
||||
{detail.record_category === '租赁' && <Text style={styles.signPart}>租借单位(签名):</Text>}
|
||||
{detail.record_category === '购销' && <Text style={styles.signPart}>采购单位(签名):</Text>}
|
||||
{detail.record_category === '购销' && <Text style={styles.signPart}>购入单位(签名):</Text>}
|
||||
{!detail.record_category && <Text style={styles.signPart}>盘点仓库(签名):</Text>}
|
||||
<Text style={styles.signPart}>制表人:{singlePlayer}</Text>
|
||||
{detail.category === RecordCategory.lease && <Text style={styles.signPart}>出租单位(签名):</Text>}
|
||||
{detail.category === RecordCategory.lease && <Text style={styles.signPart}>租借单位(签名):</Text>}
|
||||
{detail.category === RecordCategory.purchase && <Text style={styles.signPart}>采购单位(签名):</Text>}
|
||||
{detail.category === RecordCategory.purchase && <Text style={styles.signPart}>购入单位(签名):</Text>}
|
||||
{detail.category === RecordCategory.staging && <Text style={styles.signPart}>暂存仓库(签名):</Text>}
|
||||
{detail.category === RecordCategory.inventory && <Text style={styles.signPart}>盘点仓库(签名):</Text>}
|
||||
</View>
|
||||
{record.map((item) => (
|
||||
<>
|
||||
<View style={{ marginTop: '10px' }}></View>
|
||||
<View style={styles.tableContent}>
|
||||
{annotate && item.commentIndex && <Text style={{}}>{item.commentIndex + ':' + item.comment}</Text>}
|
||||
</View>
|
||||
</>
|
||||
))}
|
||||
</View>
|
||||
<View style={styles.side}>
|
||||
<Text>{detail.pdfExplain}</Text>
|
||||
@ -525,7 +512,13 @@ const PreviewDocument = ({
|
||||
</Document>
|
||||
);
|
||||
};
|
||||
export const renderItV2 = async (rent: { detail: any; record: any[]; priceRule: any[]; options: any }) => {
|
||||
export const renderItV2 = async (rent: {
|
||||
detail: any;
|
||||
record: any[];
|
||||
priceRule: any[];
|
||||
isDouble: Number;
|
||||
printSetup: String;
|
||||
}) => {
|
||||
const url = 'https://shcx.daoyoucloud.com/admin';
|
||||
const imageUrl = await QRCode.toDataURL(url);
|
||||
return await renderToStream(<PreviewDocument imageUrl={imageUrl} {...rent} />);
|
||||
|
@ -222,7 +222,7 @@ const PreviewDocument = ({
|
||||
<Document>
|
||||
<Page size="A4" style={styles.page}>
|
||||
<Text style={styles.title}>
|
||||
{contracts.first_party?.name ?? `${PromptText.noContractedCompany}`}
|
||||
{contracts.project?.associated_company?.name ?? `${PromptText.noContractedCompany}`}
|
||||
对账单
|
||||
</Text>
|
||||
<Text style={styles.subTitle}>客户各项费用明细</Text>
|
||||
@ -231,7 +231,7 @@ const PreviewDocument = ({
|
||||
<View style={styles.tableHeader}>
|
||||
<Text style={styles.headerLeft}>
|
||||
承租单位:
|
||||
{contracts.party_b?.name}
|
||||
{contracts?.project?.company?.name}
|
||||
</Text>
|
||||
<Text style={styles.headerRight}>
|
||||
合同编号:
|
||||
@ -259,7 +259,7 @@ const PreviewDocument = ({
|
||||
项目联系人:
|
||||
{contracts.project?.contacts.map((contact) => contact.name + ' ' + contact.phone).join(' ')}
|
||||
</Text>
|
||||
<Text style={styles.headerRight}>制表人:{contracts.operator.nickname}</Text>
|
||||
<Text style={styles.headerRight}>经办人:{contracts.operator.nickname}</Text>
|
||||
</view>
|
||||
<View style={styles.spacing} />
|
||||
<View style={styles.tableContentTitle}>
|
||||
@ -412,23 +412,21 @@ const PreviewDocument = ({
|
||||
</View>
|
||||
<View style={styles.tableFooterRight}>
|
||||
<Text>备注:{contracts.project?.comment}</Text>
|
||||
<Text>
|
||||
出租单位:
|
||||
{contracts.project?.associated_company?.name ?? `${PromptText.noContractedCompany}`}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.sign}>
|
||||
<Text style={styles.signPart}>承租单位:{contracts.party_b?.name} </Text>
|
||||
<Text style={styles.signPart}>出租单位:{contracts.first_party?.name}</Text>
|
||||
<Text style={styles.signPart}>制表人: </Text>
|
||||
<Text style={styles.signPart}>审核人:</Text>
|
||||
<Text style={styles.signPart}>验收:</Text>
|
||||
</View>
|
||||
<View style={styles.sign}>
|
||||
<Text style={styles.signPart}>承租单位项目经理:</Text>
|
||||
<Text style={styles.signPart}>出租单位审核人: </Text>
|
||||
</View>
|
||||
<View style={styles.sign}>
|
||||
<Text style={styles.signPart}>承租单位材料负责人:</Text>
|
||||
<Text style={styles.signPart}>出租对账人: </Text>
|
||||
</View>
|
||||
<View style={styles.sign}>
|
||||
<Text style={styles.signPart}>签署日期:</Text>
|
||||
<Text style={styles.signPart}>签署日期: </Text>
|
||||
<Text style={styles.signPart}>材料负责人: </Text>
|
||||
<Text style={styles.signPart}>出租单位代表人:</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Document, Page, Text, View, StyleSheet, renderToStream } from '@hera/plugin-core';
|
||||
import { formatQuantity } from '../../utils/currencyUtils';
|
||||
import { formatCurrency, formatQuantity } from '../../utils/currencyUtils';
|
||||
import { converDate } from '../../utils/daysUtils';
|
||||
import { Waybill } from '../../interfaces/waybill';
|
||||
|
||||
@ -193,20 +193,23 @@ const PreviewDocument = ({ waybill, settings }: { waybill: Waybill; settings: an
|
||||
);
|
||||
}
|
||||
// 单号
|
||||
const recordNumber = waybill.record_number;
|
||||
const items = waybill.products
|
||||
? waybill.products.map((item) => {
|
||||
const convertible = item.convertible;
|
||||
const data = {
|
||||
name: item.products_name,
|
||||
count: item.count,
|
||||
unit: item.unit,
|
||||
conversion_unit: convertible ? item.conversion_unit : item.unit,
|
||||
total: formatQuantity(item.total, 2),
|
||||
};
|
||||
return data;
|
||||
})
|
||||
: [];
|
||||
const recordNumber = waybill.record.number;
|
||||
const items = (
|
||||
waybill.record.items
|
||||
? waybill.record.items.map((item) => {
|
||||
const convertible = item.product.category.convertible;
|
||||
const data = {
|
||||
name: item.product.name + '/' + item.product.spec,
|
||||
count: item.count,
|
||||
unit: item.product.category.unit,
|
||||
conversion_unit: convertible ? item.product.category.conversion_unit : item.product.category.unit,
|
||||
sort: item.product.category.sort * 100000 + item.product.sort,
|
||||
total: formatQuantity(convertible ? item.count * item.product.ratio : item.count, 2),
|
||||
};
|
||||
return data;
|
||||
})
|
||||
: []
|
||||
).sort((a, b) => a.sort - b.sort);
|
||||
|
||||
const chunkedArray = Array.from({ length: Math.ceil(items.length / 3) }, (_, i) => {
|
||||
const chunk = items.slice(i * 3, i * 3 + 3);
|
||||
@ -341,15 +344,15 @@ const PreviewDocument = ({ waybill, settings }: { waybill: Waybill; settings: an
|
||||
</View>
|
||||
<View style={{ ...styles.tableCell, flex: '2', paddingRight: '1px' }}>
|
||||
<Text style={styles.textPadding}>
|
||||
{waybill.payer_company} {waybill.payer_name}
|
||||
{waybill.payer?.company?.name} {waybill.payer?.name}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.tableCell}>
|
||||
<Text style={styles.textPadding}>{waybill.payee_account_name}</Text>
|
||||
<Text style={styles.textPadding}>{waybill.payee_account?.name}</Text>
|
||||
</View>
|
||||
<View style={{ ...styles.tableCellLast, flex: '2', paddingRight: '1px' }}>
|
||||
<Text style={styles.textPadding}>
|
||||
{waybill.payee_account_bank} {waybill.payee_account_number}
|
||||
{waybill.payee_account?.bank} {waybill.payee_account?.number}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
@ -365,14 +368,14 @@ const PreviewDocument = ({ waybill, settings }: { waybill: Waybill; settings: an
|
||||
<Text style={styles.tableCellTitle}>发货方单位</Text>
|
||||
<View style={{ ...styles.tableCell3, borderBottom: '1px solid black' }}>
|
||||
<Text style={styles.textPadding}>
|
||||
{waybill.shipper_company} {waybill.shipper_name}
|
||||
{waybill.out_stock?.company?.name} {waybill.out_stock?.name}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={{ ...styles.tableCell, borderBottom: '1px solid black' }}>
|
||||
<Text style={styles.textPadding}>{waybill.shipper_contact}</Text>
|
||||
<Text style={styles.textPadding}>{waybill.shipper_contact?.name}</Text>
|
||||
</View>
|
||||
<View style={{ ...styles.tableCell, borderBottom: '1px solid black' }}>
|
||||
<Text style={styles.textPadding}> {waybill.shipper_contact_phone}</Text>
|
||||
<Text style={styles.textPadding}> {waybill.shipper_contact?.phone}</Text>
|
||||
</View>
|
||||
<Text style={styles.tableCellLast}></Text>
|
||||
</View>
|
||||
@ -380,7 +383,7 @@ const PreviewDocument = ({ waybill, settings }: { waybill: Waybill; settings: an
|
||||
<View style={styles.tableContent}>
|
||||
<Text style={styles.tableCellTitle}>发货方地址</Text>
|
||||
<View style={styles.tableCell3}>
|
||||
<Text style={styles.textPadding}>{waybill.shipper_address}</Text>
|
||||
<Text style={styles.textPadding}>{waybill.out_stock?.address}</Text>
|
||||
</View>
|
||||
<Text style={styles.tableCell}></Text>
|
||||
<Text style={styles.tableCell}></Text>
|
||||
@ -393,14 +396,14 @@ const PreviewDocument = ({ waybill, settings }: { waybill: Waybill; settings: an
|
||||
</View>
|
||||
<View style={{ ...styles.tableCell3, borderBottom: '1px solid black' }}>
|
||||
<Text style={styles.textPadding}>
|
||||
{waybill.consignee_company} {waybill.consignee_name}
|
||||
{waybill.in_stock?.company?.name} {waybill.in_stock?.name}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={{ ...styles.tableCell, borderBottom: '1px solid black' }}>
|
||||
<Text style={styles.textPadding}>{waybill.consignee_contact}</Text>
|
||||
<Text style={styles.textPadding}>{waybill.consignee_contact?.name}</Text>
|
||||
</View>
|
||||
<View style={{ ...styles.tableCell, borderBottom: '1px solid black' }}>
|
||||
<Text style={styles.textPadding}>{waybill.consignee_contact_phone}</Text>
|
||||
<Text style={styles.textPadding}>{waybill.consignee_contact?.phone}</Text>
|
||||
</View>
|
||||
<Text style={styles.tableCellLast}></Text>
|
||||
</View>
|
||||
@ -408,7 +411,7 @@ const PreviewDocument = ({ waybill, settings }: { waybill: Waybill; settings: an
|
||||
<View style={styles.tableContent}>
|
||||
<Text style={styles.tableCellTitle}>收货方地址</Text>
|
||||
<View style={styles.tableCell3}>
|
||||
<Text style={styles.textPadding}>{waybill.consignee_address}</Text>
|
||||
<Text style={styles.textPadding}>{waybill.in_stock?.address}</Text>
|
||||
</View>
|
||||
<Text style={styles.tableCell}></Text>
|
||||
<Text style={styles.tableCell}></Text>
|
||||
@ -418,7 +421,7 @@ const PreviewDocument = ({ waybill, settings }: { waybill: Waybill; settings: an
|
||||
<View style={styles.tableContentPayment}>
|
||||
<Text style={styles.tableCellTitle}>承运方单位</Text>
|
||||
<View style={{ ...styles.tableCell3, borderBottom: '1px solid black' }}>
|
||||
<Text style={styles.textPadding}>{waybill.carrier}</Text>
|
||||
<Text style={styles.textPadding}>{waybill.carrier?.name}</Text>
|
||||
</View>
|
||||
<Text style={{ ...styles.tableCell, borderBottom: '1px solid black' }}></Text>
|
||||
<Text style={{ ...styles.tableCell, borderBottom: '1px solid black' }}></Text>
|
||||
@ -428,15 +431,15 @@ const PreviewDocument = ({ waybill, settings }: { waybill: Waybill; settings: an
|
||||
<View style={styles.tableContentPayment}>
|
||||
<Text style={styles.tableCellTitle}>驾驶员</Text>
|
||||
<View style={styles.tableCell}>
|
||||
<Text style={styles.textPadding}>{waybill.driver}</Text>
|
||||
<Text style={styles.textPadding}>{waybill.driver?.name}</Text>
|
||||
</View>
|
||||
<Text style={styles.tableCellTitle}>身份证</Text>
|
||||
<Text style={styles.tableCell}>{waybill.driver_idcard}</Text>
|
||||
<Text style={styles.tableCell}>{waybill.driver?.id_card}</Text>
|
||||
<View style={styles.tableCell}>
|
||||
<Text style={styles.textPadding}>{waybill.vehicles}</Text>
|
||||
<Text style={styles.textPadding}>{waybill.record.vehicles.map((item) => item?.number).join(' ')}</Text>
|
||||
</View>
|
||||
<View style={styles.tableCell}>
|
||||
<Text style={styles.textPadding}>{waybill.driver_phone}</Text>
|
||||
<Text style={styles.textPadding}>{waybill.driver?.phone}</Text>
|
||||
</View>
|
||||
<Text style={styles.tableCellLast}></Text>
|
||||
</View>
|
||||
|
@ -59,7 +59,6 @@ export class PluginRentalServer extends Plugin {
|
||||
|
||||
await collectionRepo.createMany({
|
||||
records: categories
|
||||
.filter(Boolean)
|
||||
.filter((item) => typeof item.id !== 'undefined')
|
||||
.map((item) => ({ collectionName, categoryId: item.id })),
|
||||
});
|
||||
|
@ -1,38 +1,19 @@
|
||||
import Database, { CreateOptions, MagicAttributeModel } from '@tachybase/database';
|
||||
import { Db, Service } from '@tachybase/utils';
|
||||
import { Op } from 'sequelize';
|
||||
|
||||
@Service()
|
||||
export class ContractRuleService {
|
||||
@Db()
|
||||
private db: Database;
|
||||
// 合同重复项需要重新是实现
|
||||
|
||||
async load() {
|
||||
// 合同方案规则重复校验
|
||||
this.db.on('contract_plan_lease_items.beforeSave', this.leaseItemBeforeSave.bind(this));
|
||||
// 上表最底表的hooks不会作用到合同方案整体的重复判断,所以需要contract_plan的hooks
|
||||
this.db.on('contract_plans.beforeSave', this.contractPlansBeforeSave.bind(this));
|
||||
}
|
||||
|
||||
async leaseItemBeforeSave(model: MagicAttributeModel, options: CreateOptions): Promise<void> {
|
||||
if (!options.values) return;
|
||||
// 只适用单个表数据修改
|
||||
if (options.values.contract_plan?.id && options.values.new_products?.id) {
|
||||
const where = {
|
||||
contract_plan_id: options.values.contract_plan.id,
|
||||
new_products_id: options.values.new_products.id,
|
||||
};
|
||||
if (!model.isNewRecord) {
|
||||
where['id'] = {
|
||||
[Op.ne]: model.id,
|
||||
};
|
||||
}
|
||||
const data = await this.db.getRepository('contract_plan_lease_items').findOne({
|
||||
where,
|
||||
});
|
||||
if (data) {
|
||||
throw new Error('租金存在');
|
||||
}
|
||||
}
|
||||
// beforeSave无法获取多对多关联关系的数据
|
||||
this.db.on('contract_plan_lease_items.beforeCreate', this.contractPlanLeaseItemsBeforeSave.bind(this));
|
||||
this.db.on('contract_plan_lease_items.beforeUpdate', this.contractPlanLeaseItemsBeforeSave.bind(this));
|
||||
this.db.on('contract_plan_fee_items.beforeCreate', this.contractPlanFeeItemsBeforeSave.bind(this));
|
||||
this.db.on('contract_plan_fee_items.beforeUpdate', this.contractPlanFeeItemsBeforeSave.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -43,28 +24,158 @@ export class ContractRuleService {
|
||||
*/
|
||||
async contractPlansBeforeSave(model: MagicAttributeModel, options: CreateOptions): Promise<void> {
|
||||
if (!options.values) return;
|
||||
const leaseData = options.values.lease_items.map((item) => item.new_products);
|
||||
const repeatData = this.repeatQuery(leaseData);
|
||||
const leaseData2 = options.values.lease_items.map((item) => item.products);
|
||||
const repeatData = this.repeatQuery2(leaseData2);
|
||||
if (repeatData.length > 0) {
|
||||
throw new Error('租金规则中的产品重复!' + repeatData.map((item) => item.name));
|
||||
const products = repeatData.map((item) => item.label).join(',');
|
||||
throw new Error('租金规则中的产品重复!重复产品:' + products);
|
||||
}
|
||||
|
||||
const feeData = options.values.fee_items.map((item) => item.new_fee_products);
|
||||
const repeatFeeData = this.repeatQuery(feeData);
|
||||
if (repeatFeeData.length > 0) {
|
||||
throw new Error('费用规则中的产品重复!' + repeatFeeData.map((item) => item.name));
|
||||
const feeData = options.values.fee_items.map((fee) => fee.fee_product);
|
||||
const feeRepeatData = this.repeatQuery(feeData);
|
||||
if (feeRepeatData.length > 0) {
|
||||
const products = feeRepeatData.map((item) => item.label).join(',');
|
||||
throw new Error('费用规则中的产品重复!重复费用:' + products);
|
||||
}
|
||||
}
|
||||
|
||||
repeatQuery(data: any[]): any[] {
|
||||
const repea = [];
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
for (let j = i + 1; j < data.length; j++) {
|
||||
if (data[i].id === data[j].id) {
|
||||
repea.push(data[i]);
|
||||
const productFeeRepeatData = [];
|
||||
for (const index in options.values.lease_items) {
|
||||
const fees = options.values.lease_items[index].fee_items?.filter(Boolean);
|
||||
if (!fees) return;
|
||||
// 租金,费用,租金费用使用同一判断重复方法,需要处理一下租金费用数据结构
|
||||
const transFee = fees.map((item) => {
|
||||
if (Object.keys(item).length > 0 && item.fee_product) {
|
||||
return { ...item, id: item.fee_product.id, raw_category_id: item.fee_product.id };
|
||||
}
|
||||
});
|
||||
const data = this.repeatQuery(transFee);
|
||||
if (data.length > 0) {
|
||||
productFeeRepeatData.push({ index, value: data.map((item) => item.fee_product.label).join(',') });
|
||||
}
|
||||
}
|
||||
return repea;
|
||||
if (productFeeRepeatData.length > 0) {
|
||||
const tips = [];
|
||||
for (const iterator of productFeeRepeatData) {
|
||||
const tip = `第${Number(iterator.index) + 1}条租金数据中费用重复添加`;
|
||||
tips.push(tip);
|
||||
}
|
||||
throw new Error(tips.join(','));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 租金单条规则创建before seqlizeHooks事件
|
||||
* @param model
|
||||
* @param options
|
||||
* @returns
|
||||
*/
|
||||
async contractPlanLeaseItemsBeforeSave(model: MagicAttributeModel, options: CreateOptions): Promise<void> {
|
||||
if (!options.values?.contract_plan && !options.values?.products) return;
|
||||
const plan = await this.db.getRepository('contract_plans').findOne({
|
||||
where: {
|
||||
id: options.values?.contract_plan?.id || options.values?.contract_plan_id,
|
||||
},
|
||||
appends: ['lease_items', 'lease_items.products'],
|
||||
});
|
||||
const add = options.values.products;
|
||||
const productData = plan.lease_items
|
||||
.filter((item) => item.id !== options.values.id && item.products.length === add.length)
|
||||
.map((item) => item.products)
|
||||
.flat();
|
||||
productData.forEach((item) => {
|
||||
const isHas = add.find(
|
||||
(p) =>
|
||||
(p.id < 99999 && (p.id === item.id || (item.id > 99999 && p.raw_category_id === item.raw_category_id))) ||
|
||||
(p.id > 99999 && p.raw_category_id === item.raw_category_id),
|
||||
);
|
||||
if (isHas) {
|
||||
throw new Error('方案中存在此产品');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 费用规则创建before seqlizeHooks事件
|
||||
* @param model
|
||||
* @param options
|
||||
* @returns
|
||||
*/
|
||||
async contractPlanFeeItemsBeforeSave(model: MagicAttributeModel, options: CreateOptions): Promise<void> {
|
||||
if (!options.values?.contract_plan || !options.values?.fee_product) return;
|
||||
const plan = await this.db.getRepository('contract_plans').findOne({
|
||||
where: {
|
||||
id: options.values.contract_plan.id,
|
||||
},
|
||||
appends: ['lease_items', 'lease_items.products', 'fee_items', 'fee_items.fee_product'],
|
||||
});
|
||||
if (options.values.lease_product) {
|
||||
// 待页面完成确定入参数格式后
|
||||
// const feeProduct = plan.fee_items.filter((item) => item.lease_item_id === options.values.lease_product.id // 确定options.values.lease_product是否为数组格式)
|
||||
} else {
|
||||
const add = options.values.fee_product;
|
||||
if (!Array.isArray(add)) return;
|
||||
const feeData = plan.fee_items.filter((item) => !item.lease_item_id).map((item) => item.fee_product);
|
||||
feeData.forEach((item) => {
|
||||
const isHas = add.find((p) => p.id === item.id);
|
||||
if (isHas) {
|
||||
throw new Error('方案中存在此赔偿项');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 租金规则重复查询
|
||||
* @param data
|
||||
* @returns
|
||||
*/
|
||||
repeatQuery(data: any[]): any[] {
|
||||
if (data.filter(Boolean).length > 0) {
|
||||
const queryData = data.filter(Boolean);
|
||||
if (queryData.length > 0) {
|
||||
const arr = [];
|
||||
for (let index = 0; index < queryData.length; index++) {
|
||||
const repea = queryData.slice(index + 1).filter((item) => {
|
||||
if (item) {
|
||||
return (
|
||||
item.id === queryData[index].id ||
|
||||
(item.raw_category_id === queryData[index].raw_category_id &&
|
||||
(item.id > 99999 || queryData[index].id > 99999))
|
||||
);
|
||||
}
|
||||
});
|
||||
arr.push(...repea.filter(Boolean));
|
||||
}
|
||||
return arr;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 与原实现相差较多,新写一实现方法
|
||||
* 租金产品多选重复查询,一个组合算是一个整体进行比较
|
||||
* @param data
|
||||
* @returns
|
||||
*/
|
||||
repeatQuery2(data: any[]): any[] {
|
||||
const result = data.reduce((acc, curr) => {
|
||||
const found = acc.find((subArr) => subArr.length === curr.length);
|
||||
if (found) {
|
||||
found.push(...curr);
|
||||
} else {
|
||||
acc.push(curr);
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
const rep = [];
|
||||
result.forEach((item) => {
|
||||
const repeatData = this.repeatQuery(item);
|
||||
if (repeatData.length > 0) {
|
||||
rep.push(...item);
|
||||
}
|
||||
});
|
||||
return rep;
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ export class ContractService {
|
||||
if (!options.values) return;
|
||||
if (options.values.settlementTemplate) {
|
||||
const temp = {
|
||||
上个月: `MONTH(EOMONTH(TODAY(), -1))`, // 工作流默认
|
||||
上个月: `MONTH(EOMONTH(TODAY(), -1))`,
|
||||
本月: `MONTH(TODAY())`,
|
||||
当年: `YEAR(EOMONTH(TODAY(), -1))`,
|
||||
};
|
||||
|
@ -9,315 +9,329 @@ import Database from '@tachybase/database';
|
||||
export class RecordPdfService {
|
||||
@Db()
|
||||
private db: Database;
|
||||
async transformPdfV2(recordData: any, lease_data: any, fee_data: any, options: RecordPdfOptions) {
|
||||
const { isDouble, printSetup } = options;
|
||||
|
||||
/**
|
||||
* 注意点
|
||||
* 1. 正常租赁产品
|
||||
* 2. 租赁产品的维修赔偿
|
||||
* 3. 无关联产品的维修赔偿(实际总重量,出入库量)
|
||||
* 4. 无关联产品的维修赔偿(人工录入)
|
||||
* 5. 报价
|
||||
*/
|
||||
async transformPdfV2(
|
||||
intermediate, // 中间表
|
||||
baseRecord, //订单基础数据
|
||||
leaseData, // 租金数据
|
||||
leaseFeeData, // 赔偿数据
|
||||
noLeaseProductFeeData,
|
||||
noRuleexcluded,
|
||||
contracts,
|
||||
options,
|
||||
) {
|
||||
const { printSetup } = options;
|
||||
const movement = (movement: string) => {
|
||||
const data = {
|
||||
'-1': '出库',
|
||||
'1': '入库',
|
||||
};
|
||||
return data[movement];
|
||||
};
|
||||
const record_category = (category) => {
|
||||
const data = {
|
||||
'1': '购销',
|
||||
'2': '租赁',
|
||||
'3': '暂存',
|
||||
// 非盘点单的情况就是暂存单
|
||||
};
|
||||
return data[category];
|
||||
};
|
||||
const needRecord = {
|
||||
record_number: baseRecord.number,
|
||||
record_date: baseRecord.date,
|
||||
record_origin: baseRecord?.origin,
|
||||
record_party_b: movement(contracts.movement) === '出库' ? baseRecord?.in_stock : baseRecord?.out_stock, // 还需要判断第三个合同的情况,确定一下出库入是否合同公司有关
|
||||
record_party_a: movement(contracts.movement) === '入库' ? baseRecord?.in_stock : baseRecord?.out_stock,
|
||||
vehicles: baseRecord?.vehicles,
|
||||
record_category: record_category(contracts.record_category),
|
||||
contract_first_party: contracts.first_party, //公司信息,甲方,我们
|
||||
movement: movement(contracts.movement),
|
||||
pdfExplain: baseRecord.pdfExplain,
|
||||
nickname: baseRecord.nickname,
|
||||
userPhone: baseRecord.userPhone,
|
||||
systemName: baseRecord.systemName,
|
||||
plate: baseRecord.plate,
|
||||
};
|
||||
// !租金数据
|
||||
const leasePorducts = leaseData.map((leas) => {
|
||||
const data = {
|
||||
...leas,
|
||||
};
|
||||
let total: number;
|
||||
const unit = leas.unit;
|
||||
let conversion_unit = leas.conversion_unit;
|
||||
if (leas.conversion_logic_id === ConversionLogics.Keep) {
|
||||
total = leas.count;
|
||||
conversion_unit = leas.unit;
|
||||
} else if (
|
||||
leas.conversion_logic_id === ConversionLogics.Product ||
|
||||
leas.conversion_logic_id === ConversionLogics.ActualWeight
|
||||
) {
|
||||
const ratio = leas.convertible ? leas.products_ratio : 1;
|
||||
total = leas.count * ratio;
|
||||
conversion_unit = leas.convertible ? leas.conversion_unit : leas.unit;
|
||||
} else if (leas.conversion_logic_id === ConversionLogics.ProductWeight) {
|
||||
total = leas.count * leas.products_weight;
|
||||
conversion_unit = 'KG';
|
||||
} else if (leas.conversion_logic_id > 4) {
|
||||
if (leas.wr_logic_id === ConversionLogics.Keep) {
|
||||
total = leas.count * leas.wr_weight;
|
||||
} else if (leas.wr_logic_id === ConversionLogics.Product) {
|
||||
const ratio = leas.convertible ? leas.products_ratio : 1;
|
||||
total = leas.count * leas.wr_weight * ratio;
|
||||
// 直发单不需要打印预览
|
||||
if (recordData.category === RecordCategory.purchase2lease || recordData.category === RecordCategory.lease2lease)
|
||||
return;
|
||||
|
||||
// 盘点/暂存单使用默认产品表的换算逻辑
|
||||
if (recordData.category === RecordCategory.staging || recordData.category === RecordCategory.inventory) {
|
||||
lease_data = lease_data.map((item) => {
|
||||
const data = {
|
||||
...item,
|
||||
};
|
||||
// 根据产品表换算
|
||||
data['conversion_logic_id'] = 2;
|
||||
return data;
|
||||
});
|
||||
}
|
||||
let make_price;
|
||||
|
||||
// 购销单计算报价数据
|
||||
if (recordData.category === RecordCategory.purchase) {
|
||||
const price_rule = lease_data.map((item) => {
|
||||
const data = {
|
||||
name: item.price_label,
|
||||
unit_price: item.price_price,
|
||||
comment: item.price_comment,
|
||||
};
|
||||
if (!item.conversion_logic_id) return;
|
||||
if (item.conversion_logic_id === ConversionLogics.Keep) {
|
||||
data['count'] = item.count;
|
||||
data['unit'] = item.unit;
|
||||
} else if (item.conversion_logic_id === ConversionLogics.Product) {
|
||||
if (item.convertible) {
|
||||
data['count'] = item.count * item.ratio;
|
||||
data['unit'] = item.conversion_unit;
|
||||
} else {
|
||||
data['count'] = item.count;
|
||||
data['unit'] = item.unit;
|
||||
}
|
||||
} else if (item.conversion_logic_id === ConversionLogics.ProductWeight) {
|
||||
data['count'] = item.count * item.weight;
|
||||
data['unit'] = 'KG';
|
||||
} else if (item.conversion_logic_id === ConversionLogics.ActualWeight) {
|
||||
const weight = recordData.record_group_weight_items?.find((w) => w.category.id === item.product_category_id);
|
||||
if (weight) {
|
||||
data['count'] = weight.weight;
|
||||
data['unit'] = '吨';
|
||||
} else {
|
||||
data['count'] = recordData.weight;
|
||||
data['unit'] = '吨';
|
||||
}
|
||||
} else {
|
||||
data['unit'] = 'KG';
|
||||
if (item.wr.conversion_logic_id === ConversionLogics.Keep) {
|
||||
data['count'] = item.count * item.wr.weight;
|
||||
} else if (item.wr.conversion_logic_id === ConversionLogics.Product) {
|
||||
data['count'] = item.count * item.ratio * item.wr.weight;
|
||||
}
|
||||
}
|
||||
conversion_unit = 'KG';
|
||||
}
|
||||
data['total'] = total;
|
||||
data.unit = unit;
|
||||
data.conversion_unit = conversion_unit;
|
||||
return data;
|
||||
});
|
||||
// !租金赔偿
|
||||
const leaseProductsFees = leaseFeeData.map((fee) => {
|
||||
const data = {
|
||||
products_id: fee.products_id,
|
||||
name: fee.fee_custom_name || fee.fee_product,
|
||||
comment: fee.is_excluded ? fee.comment + '_不计入合同' : fee.comment,
|
||||
};
|
||||
let count: number;
|
||||
if (fee.count_source === SourcesType.staff) {
|
||||
count = fee.fee_count;
|
||||
} else if (
|
||||
fee.count_source === SourcesType.inAndOut ||
|
||||
(fee.count_source === SourcesType.inbound && contracts.movement === '1') ||
|
||||
(fee.count_source === SourcesType.outbound && contracts.movement === '0')
|
||||
) {
|
||||
count = fee.count;
|
||||
}
|
||||
let total: number;
|
||||
let conversion_unit = fee.fee_rule_unit;
|
||||
if (fee.conversion_logic_id === ConversionLogics.Keep) {
|
||||
total = count;
|
||||
conversion_unit = fee.fee_unit;
|
||||
} else if (
|
||||
fee.conversion_logic_id === ConversionLogics.Product ||
|
||||
fee.conversion_logic_id === ConversionLogics.ActualWeight
|
||||
) {
|
||||
const ratio = fee.fee_convertible ? fee.fee_ratio : 1;
|
||||
total = count * ratio;
|
||||
} else if (fee.conversion_logic_id === ConversionLogics.ProductWeight) {
|
||||
total = count * fee.fee_weight;
|
||||
conversion_unit = 'KG';
|
||||
} else if (fee.conversion_logic_id > 4) {
|
||||
const ProductWeightRule = leaseData.find((leas) => leas.products_id === fee.products_id);
|
||||
if (ProductWeightRule.wr_logic_id === ConversionLogics.Keep) {
|
||||
total = count * ProductWeightRule.wr_weight;
|
||||
} else if (ProductWeightRule.wr_logic_id === ConversionLogics.Product) {
|
||||
const ratio = ProductWeightRule.convertible ? ProductWeightRule.products_ratio : 1;
|
||||
total = count * ProductWeightRule.wr_weight * ratio;
|
||||
data['all_price'] = data['count'] * data['unit_price'];
|
||||
return data;
|
||||
});
|
||||
|
||||
const setData = Object.values(
|
||||
price_rule.reduce((acc, item) => {
|
||||
if (!item) {
|
||||
console.error('报价计算出错', price_rule);
|
||||
return acc;
|
||||
}
|
||||
if (!acc[item.name]) {
|
||||
acc[item.name] = { ...item };
|
||||
} else {
|
||||
acc[item.name].count += item.count;
|
||||
acc[item.name].all_price += item.all_price;
|
||||
}
|
||||
return acc;
|
||||
}, {}),
|
||||
);
|
||||
make_price = setData;
|
||||
}
|
||||
|
||||
// !产品
|
||||
const leaseData = lease_data
|
||||
.map((lease) => {
|
||||
const data = {
|
||||
name: lease.label,
|
||||
count: lease.count,
|
||||
unit: lease.unit,
|
||||
comment: lease.item_comment,
|
||||
product_id: lease.product_id,
|
||||
category_id: lease.category_id,
|
||||
product_category_name: lease.product_category_name,
|
||||
};
|
||||
if (lease.conversion_logic_id === ConversionLogics.Keep) {
|
||||
data['total'] = lease.count;
|
||||
data['conversion_unit'] = lease.unit;
|
||||
} else if (lease.conversion_logic_id === ConversionLogics.Product) {
|
||||
if (lease.convertible) {
|
||||
data['total'] = lease.count * lease.ratio;
|
||||
data['conversion_unit'] = lease.conversion_unit;
|
||||
} else {
|
||||
data['total'] = lease.count;
|
||||
data['conversion_unit'] = lease.unit;
|
||||
}
|
||||
} else if (lease.conversion_logic_id === ConversionLogics.ProductWeight) {
|
||||
data['total'] = lease.count * lease.weight;
|
||||
data['conversion_unit'] = 'KG';
|
||||
} else if (lease.conversion_logic_id === ConversionLogics.ActualWeight) {
|
||||
if (lease.convertible) {
|
||||
data['total'] = lease.count * lease.ratio;
|
||||
data['conversion_unit'] = lease.conversion_unit;
|
||||
} else {
|
||||
data['total'] = lease.count;
|
||||
data['conversion_unit'] = lease.unit;
|
||||
}
|
||||
} else {
|
||||
data['conversion_unit'] = 'KG';
|
||||
if (lease.wr?.conversion_logic_id === ConversionLogics.Keep) {
|
||||
data['total'] = lease.count * lease.wr?.weight;
|
||||
} else if (lease.wr?.conversion_logic_id === ConversionLogics.Product) {
|
||||
data['total'] = lease.count * lease.ratio * lease.wr?.weight;
|
||||
}
|
||||
}
|
||||
conversion_unit = 'KG';
|
||||
return data;
|
||||
})
|
||||
.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)
|
||||
: fee_data.filter((item) => item.product_id);
|
||||
const transFormProductFee = product_fee.map((item, index) => {
|
||||
// 购销/暂存/盘点无费用信息
|
||||
if (
|
||||
recordData.category === RecordCategory.purchase ||
|
||||
recordData.category === RecordCategory.staging ||
|
||||
recordData.category === RecordCategory.inventory
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (printSetup === PrintSetup.DisplayAndPrice) {
|
||||
data['count'] = total;
|
||||
data['unit'] = conversion_unit;
|
||||
data['total'] = total * fee.unit_price;
|
||||
data['conversion_unit'] = '元';
|
||||
// 人工录入没有数量
|
||||
if (item.count_source === SourcesType.staff && !item.fee_count) 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,
|
||||
isExcluded: item.is_excluded,
|
||||
name: item.custom_name || item.label,
|
||||
count1: item.count_source === SourcesType.staff ? item.fee_count : item.product_count,
|
||||
unit: item.unit,
|
||||
comment: '',
|
||||
product_id: item.product_id + '.' + (index + 1),
|
||||
category_id: item.product_category_id,
|
||||
};
|
||||
if (item.conversion_logic_id === ConversionLogics.Keep) {
|
||||
data['total'] = data.count1;
|
||||
} else if (item.conversion_logic_id === ConversionLogics.Product) {
|
||||
if (item.convertible) {
|
||||
data['total'] = data.count1 * item.product_ratio;
|
||||
} else {
|
||||
data['total'] = data.count1;
|
||||
}
|
||||
} else if (item.conversion_logic_id === ConversionLogics.ProductWeight) {
|
||||
data['total'] = data.count1 * item.product_weight;
|
||||
} else if (item.conversion_logic_id === ConversionLogics.ActualWeight) {
|
||||
data['total'] = item.actual_weight || item.record_weight;
|
||||
} else {
|
||||
data['conversion_unit'] = conversion_unit;
|
||||
data['total'] = total;
|
||||
if (item.weight_rules?.conversion_logic_id === ConversionLogics.Keep) {
|
||||
data['total'] = data.count1 * item.weight_rules.weight;
|
||||
} else if (item.weight_rules?.conversion_logic_id === ConversionLogics.Product) {
|
||||
data['total'] = data.count1 * item.weight_rules.weight * item.product_ratio;
|
||||
}
|
||||
}
|
||||
data['conversion_unit'] = item.unit;
|
||||
if (printSetup === PrintSetup.DisplayAndPrice) {
|
||||
data['count'] = data['total'];
|
||||
data['total'] = data['total'] * item.unit_price;
|
||||
data['conversion_unit'] = '元';
|
||||
}
|
||||
return data;
|
||||
});
|
||||
const rentData = [...leasePorducts, ...leaseProductsFees].sort((a, b) => a.products_id - b.products_id);
|
||||
// !无关联赔偿 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.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: item.unit,
|
||||
comment: '',
|
||||
};
|
||||
if (item.conversion_logic_id === ConversionLogics.Keep) {
|
||||
data['total'] = lease_data.reduce((a, b) => a + b.count, 0);
|
||||
} else if (item.conversion_logic_id === ConversionLogics.Product) {
|
||||
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['total'] = lease_data.reduce((a, b) => a + b.count * b.weight, 0) / 1000;
|
||||
} else if (item.conversion_logic_id === ConversionLogics.ActualWeight) {
|
||||
data['total'] = item.record_weight;
|
||||
} else {
|
||||
if (item.weight_rules?.length) {
|
||||
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,
|
||||
);
|
||||
if (weight_rule && weight_rule.conversion_logic_id === ConversionLogics.Keep) {
|
||||
return a + b.count * weight_rule.weight;
|
||||
} else if (weight_rule && weight_rule.conversion_logic_id === ConversionLogics.Product) {
|
||||
return a + b.count * b.ratio * weight_rule.weight;
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
data['conversion_unit'] = '吨';
|
||||
if (printSetup === PrintSetup.DisplayAndPrice) {
|
||||
data['count'] = data['total'];
|
||||
data['total'] = data['total'] * item.unit_price;
|
||||
data['conversion_unit'] = '元';
|
||||
}
|
||||
return data;
|
||||
})
|
||||
.filter((item) => item && item.total);
|
||||
|
||||
const product_fees = transFormProductFee.filter(Boolean);
|
||||
// 内容(租金+费用)
|
||||
const product_correlation = [...leaseData, ...product_fees].sort((a, b) => a.product_id - b.product_id);
|
||||
|
||||
// 生成小计
|
||||
const productTotal = {};
|
||||
leasePorducts.forEach((element) => {
|
||||
leaseData.forEach((element) => {
|
||||
if (element) {
|
||||
productTotal[element.parentId] = {
|
||||
name: element.parentName + '[小计]',
|
||||
total: (productTotal[element.parentId]?.total ?? 0) + element.total,
|
||||
productTotal[element.category_id] = {
|
||||
name: element.product_category_name + '[小计]',
|
||||
total: (productTotal[element.category_id]?.total ?? 0) + element?.total,
|
||||
conversion_unit: element.conversion_unit,
|
||||
count: '',
|
||||
unit: '',
|
||||
isTotal: true,
|
||||
comment: '',
|
||||
parentId: element.parentId,
|
||||
// 报价用
|
||||
priceName: element.parentName,
|
||||
price: element.unit_price,
|
||||
category_id: element.category_id,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// 插入小计
|
||||
const productTotalItems = Object.entries(productTotal).map(([_, value]) => value);
|
||||
productTotalItems.forEach((itemB: any) => {
|
||||
const lastIndex = rentData.map((itemA) => itemA.parentId).lastIndexOf(itemB.parentId);
|
||||
const lastIndex = product_correlation.map((itemA) => itemA.category_id).lastIndexOf(itemB.category_id);
|
||||
if (lastIndex !== -1) {
|
||||
rentData.splice(lastIndex + 1, 0, itemB);
|
||||
product_correlation.splice(lastIndex + 1, 0, itemB);
|
||||
} else {
|
||||
rentData.push(itemB);
|
||||
product_correlation.push(itemB);
|
||||
}
|
||||
});
|
||||
|
||||
// !无关联费用(人工录入)
|
||||
const noproFeesStaff = noLeaseProductFeeData
|
||||
.filter((item) => item.count_source === SourcesType.staff)
|
||||
.map((fee) => {
|
||||
const data = {
|
||||
fee_products_id: fee.fee_products_id,
|
||||
name: fee.name,
|
||||
comment: fee.is_excluded ? fee.comment + '_不计入合同' : fee.comment,
|
||||
};
|
||||
let total: number;
|
||||
let conversion_unit;
|
||||
if (fee.conversion_logic_id === ConversionLogics.Keep) {
|
||||
total = fee.count;
|
||||
conversion_unit = fee.unit;
|
||||
} else if (
|
||||
fee.conversion_logic_id === ConversionLogics.Product ||
|
||||
fee.conversion_logic_id === ConversionLogics.ActualWeight
|
||||
) {
|
||||
const ratio = fee.convertible ? fee.ratio : 1;
|
||||
total = fee.count * ratio;
|
||||
conversion_unit = fee.convertible ? fee.conversion_unit : fee.unit;
|
||||
} else if (fee.conversion_logic_id === ConversionLogics.ProductWeight) {
|
||||
total = fee.count * fee.weight;
|
||||
conversion_unit = 'KG';
|
||||
} else if (fee.conversion_logic_id > 4) {
|
||||
if (fee.wr_logic_id === ConversionLogics.Keep) {
|
||||
total = fee.count * fee.wr_weight;
|
||||
} else if (fee.wr_logic_id === ConversionLogics.Product) {
|
||||
const ratio = fee.convertible ? fee.ratio : 1;
|
||||
total = fee.count * fee.wr_weight * ratio;
|
||||
}
|
||||
conversion_unit = 'KG';
|
||||
}
|
||||
if (printSetup === PrintSetup.DisplayAndPrice) {
|
||||
data['count'] = total;
|
||||
data['unit'] = conversion_unit;
|
||||
data['total'] = total * fee.unit_price;
|
||||
data['conversion_unit'] = '元';
|
||||
} else {
|
||||
data['conversion_unit'] = conversion_unit;
|
||||
data['total'] = total;
|
||||
}
|
||||
return data;
|
||||
});
|
||||
rentData.push(...noproFeesStaff);
|
||||
|
||||
// !无关联费用(出入库量)
|
||||
if (printSetup === PrintSetup.Display || printSetup === PrintSetup.DisplayAndPrice) {
|
||||
const noproFees = noLeaseProductFeeData
|
||||
.filter((item) => item.count_source !== SourcesType.staff)
|
||||
.map((fee) => {
|
||||
const data = {
|
||||
name: fee.custom_name || fee.name,
|
||||
};
|
||||
if (
|
||||
fee.count_source === SourcesType.inAndOut ||
|
||||
(fee.count_source === SourcesType.inbound && intermediate.movement === '1') ||
|
||||
(fee.count_source === SourcesType.outbound && intermediate.movement === '-1')
|
||||
) {
|
||||
let total = 0;
|
||||
let conversion_unit: string;
|
||||
leaseData.forEach((ele) => {
|
||||
if (fee.conversion_logic_id === ConversionLogics.Keep) {
|
||||
total += ele.count;
|
||||
conversion_unit = ele.unit;
|
||||
} else if (fee.conversion_logic_id === ConversionLogics.Product) {
|
||||
const ratio = ele.convertible ? ele.ratio : 1;
|
||||
total += ele.count * ratio;
|
||||
conversion_unit = ele.convertible ? ele.conversion_unit : ele.unit;
|
||||
} else if (fee.count_logic_id === ConversionLogics.ActualWeight) {
|
||||
total = baseRecord.weight;
|
||||
conversion_unit = '吨';
|
||||
} else if (fee.conversion_logic_id === ConversionLogics.ProductWeight) {
|
||||
total += ele.count * ele.weight;
|
||||
conversion_unit = 'KG';
|
||||
} else if (fee.conversion_logic_id > 4) {
|
||||
const weightRule = fee.weight_rules.find((item) => item.new_product_id === ele.products_id);
|
||||
if (weightRule) {
|
||||
if (weightRule.conversion_logic_id === ConversionLogics.Keep) {
|
||||
total += ele.count * weightRule.weight;
|
||||
} else if (weightRule.conversion_logic_id === ConversionLogics.Product) {
|
||||
const ratio = weightRule.convertible ? weightRule.ratio : 1;
|
||||
total += ele.count * weightRule.weight * ratio;
|
||||
}
|
||||
conversion_unit = 'KG';
|
||||
}
|
||||
}
|
||||
});
|
||||
data['isFee'] = true;
|
||||
conversion_unit = fee.fee_rule_unit || conversion_unit;
|
||||
if (printSetup === PrintSetup.DisplayAndPrice) {
|
||||
data['count'] = total;
|
||||
data['unit'] = conversion_unit;
|
||||
data['total'] = total * fee.unit_price;
|
||||
data['conversion_unit'] = '元';
|
||||
} else {
|
||||
data['conversion_unit'] = conversion_unit;
|
||||
data['total'] = total;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
})
|
||||
.filter(Boolean);
|
||||
rentData.push(...noproFees);
|
||||
const excluded = noRuleexcluded
|
||||
.map((item) => {
|
||||
const data = {
|
||||
name: item.custom_name || item.fee_name,
|
||||
total: item.count,
|
||||
comment: item.is_excluded ? (item.comment || '') + ' 不计入合同' : item.comment || '',
|
||||
conversion_unit: '',
|
||||
};
|
||||
return data;
|
||||
})
|
||||
.filter(Boolean);
|
||||
rentData.push(...excluded);
|
||||
}
|
||||
|
||||
// 报价
|
||||
let priceRule = [];
|
||||
if (needRecord.record_category === '购销') {
|
||||
priceRule = productTotalItems.map((item: any) => {
|
||||
return {
|
||||
name: item.priceName,
|
||||
unit_price: item.price,
|
||||
unit: item.conversion_unit,
|
||||
count: item.total,
|
||||
all_price: item.total * item.price,
|
||||
comment: item.comment,
|
||||
};
|
||||
});
|
||||
}
|
||||
// 注意不记录合同
|
||||
const recordPdfData = [...product_correlation, ...manualData, ...no_product_fee].filter(Boolean);
|
||||
return await renderItV2({
|
||||
detail: needRecord,
|
||||
record: rentData,
|
||||
priceRule,
|
||||
options,
|
||||
detail: recordData,
|
||||
record: recordPdfData,
|
||||
priceRule: make_price,
|
||||
isDouble,
|
||||
printSetup,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,63 @@
|
||||
import Database, { CreateOptions, MagicAttributeModel } from '@tachybase/database';
|
||||
import Database, { CreateOptions, MagicAttributeModel, Transaction } from '@tachybase/database';
|
||||
import { Db, Service } from '@tachybase/utils';
|
||||
import { ConversionLogics, RecordCategory, settlementStatus } from '../../utils/constants';
|
||||
import { ConversionLogics, Movement, RecordCategory, RecordTypes, settlementStatus } from '../../utils/constants';
|
||||
import validateLicensePlate from '../../utils/validateLIcensePlate';
|
||||
import { QueryTypes } from 'sequelize';
|
||||
import _ from 'lodash';
|
||||
|
||||
@Service()
|
||||
export class RecordService {
|
||||
@Db()
|
||||
private db: Database;
|
||||
async load() {
|
||||
this.db.on('records.afterSave', this.recordsAfterSave.bind(this));
|
||||
this.db.on('records.beforeSave', this._calcAllPrice.bind(this));
|
||||
// 盘点单
|
||||
this.db.on('records.afterSaveWithAssociations', this._createStock.bind(this));
|
||||
}
|
||||
|
||||
async load() {
|
||||
// 1. 创建项目/更新项目( 直发单,生成对应租赁/购销,出入库单数据, 并且设置订单多对多project字段关系)
|
||||
this.db.on('records.afterCreate', this.afterCreateDirectRecord.bind(this));
|
||||
this.db.on('records.afterUpdate', this.afterUpdateDirectRecord.bind(this));
|
||||
this.db.on('records.afterSave', this.recordsAfterSave.bind(this));
|
||||
}
|
||||
/**
|
||||
* 处理直发单生成单
|
||||
*/
|
||||
async afterCreateDirectRecord(model: MagicAttributeModel, options: CreateOptions): Promise<void> {
|
||||
const { values, transaction, context } = options;
|
||||
if (!values) {
|
||||
return;
|
||||
}
|
||||
if (values.record_category === RecordTypes.purchaseDirect || values.record_category === RecordTypes.rentDirect) {
|
||||
await this._createRecord(model, values, transaction, context, null);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 处理直发单生成单
|
||||
*/
|
||||
async afterUpdateDirectRecord(model: MagicAttributeModel, options: CreateOptions): Promise<void> {
|
||||
const { values, transaction, context } = options;
|
||||
if (!values) {
|
||||
return;
|
||||
}
|
||||
// 运输单的创建会走订单的update,如果存在waybill一定是在录运输单
|
||||
if (values.waybill) return;
|
||||
if (values.record_category === RecordTypes.purchaseDirect || values.record_category === RecordTypes.rentDirect) {
|
||||
const deleteDatas = await this.db.getRepository('records').find({ where: { direct_record_id: model.id } });
|
||||
// 删除订单多对多项目表数据
|
||||
const records = await this.db.getRepository('records').find({ where: { direct_record_id: model.id } });
|
||||
await this._deleteReocrdProject(
|
||||
records.map((item) => item.id),
|
||||
transaction,
|
||||
);
|
||||
// 删除新建时创建的订单
|
||||
await this.db.sequelize.query(
|
||||
`
|
||||
delete from records
|
||||
where records.direct_record_id = ${model.id}
|
||||
`,
|
||||
{
|
||||
transaction,
|
||||
},
|
||||
);
|
||||
const numbers = deleteDatas.map((item) => item.number);
|
||||
await this._createRecord(model, values, transaction, context, numbers);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 订单afterSave hooks
|
||||
* @param model
|
||||
@ -23,11 +66,173 @@ export class RecordService {
|
||||
async recordsAfterSave(model: MagicAttributeModel, options: CreateOptions): Promise<void> {
|
||||
// 运输单导致的订单更新不必走以下订单逻辑,减少性能消耗,有waybill一定是运输单录入
|
||||
if (options.values?.waybill) return;
|
||||
// 订单新建更新后(根据合同确定出入库字段)
|
||||
await this._setProject(model, options);
|
||||
// 订单发生变化时更新对应结算单的状态(需要重新计算)
|
||||
await this._updateSettlementStatus(model, options);
|
||||
// 车牌号校验
|
||||
await this._checkPlateNumber(model, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验车牌号
|
||||
*/
|
||||
async _checkPlateNumber(record: MagicAttributeModel, options: CreateOptions) {
|
||||
const { transaction, context } = options;
|
||||
if (record.dataValues?.vehicles) {
|
||||
const ids = record.dataValues.vehicles.filter((item) => typeof item === 'number').join(',');
|
||||
const vehicles = await this.db.sequelize.query(`select * from vehicles where id in (${ids})`, {
|
||||
transaction,
|
||||
});
|
||||
if (vehicles[0].length) {
|
||||
vehicles[0].forEach((item: any) => {
|
||||
if (item.number) {
|
||||
const validate = validateLicensePlate(item.number);
|
||||
if (!validate) {
|
||||
throw new Error('车牌号格式错误');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 新版订单录入界面,手动赋值对应的出入库信息
|
||||
async _setProject(record: MagicAttributeModel, options: CreateOptions) {
|
||||
const { values, transaction, context } = options;
|
||||
|
||||
// 非新增和修改订单信息的
|
||||
if (!values || values.record_category === undefined) {
|
||||
return;
|
||||
}
|
||||
// 暂存和盘点是不需要处理的
|
||||
if (values.category === RecordCategory.inventory) {
|
||||
// values.category === RecordCategory.staging ||
|
||||
return;
|
||||
}
|
||||
const where = {};
|
||||
// 订单导入直接取值
|
||||
if (values.import && values.in_stock && values.out_stock) {
|
||||
where['in_stock_id'] = values.in_stock.id;
|
||||
where['out_stock_id'] = values.out_stock.id;
|
||||
} else {
|
||||
let out_stock, in_stock;
|
||||
if (values.record_category === RecordTypes.purchaseDirect || values.record_category === RecordTypes.rentDirect) {
|
||||
// 采购直发/租赁直发
|
||||
const inContract = values.in_contract;
|
||||
const contractProject = await this.db
|
||||
.getRepository('project')
|
||||
.findOne({ where: { id: inContract.project_id } });
|
||||
in_stock = contractProject.dataValues;
|
||||
if (values.record_category === RecordTypes.rentDirect) {
|
||||
const project = await this.db
|
||||
.getRepository('project')
|
||||
.findOne({ where: { id: values.out_contract.project_id } });
|
||||
out_stock = project.dataValues;
|
||||
} else {
|
||||
out_stock = values.out_stock;
|
||||
}
|
||||
} else if (
|
||||
values.record_category === RecordTypes.rentInStock ||
|
||||
values.record_category === RecordTypes.rentOutStock
|
||||
) {
|
||||
if (!values.contract) return;
|
||||
const contract = values.contract;
|
||||
const contractProject = await this.db.getRepository('project').findOne({ where: { id: contract.project_id } });
|
||||
// 租赁出库/租赁入库,确定出入库
|
||||
// out_stock, in_stock
|
||||
// 租赁入库, out_stock = 合同中project_id, in_stock = 合同中项目的associated_company_id => 项目表id
|
||||
const associatedCompanyProject = await this.db
|
||||
.getRepository('project')
|
||||
.findOne({ where: { company_id: contractProject.associated_company_id, category: '1' } });
|
||||
|
||||
if (values.record_category === RecordTypes.rentInStock) {
|
||||
out_stock = contractProject.dataValues;
|
||||
in_stock = associatedCompanyProject?.dataValues;
|
||||
} else {
|
||||
out_stock = associatedCompanyProject?.dataValues;
|
||||
in_stock = contractProject.dataValues;
|
||||
}
|
||||
} else if (
|
||||
values.record_category === RecordTypes.purchaseInStock ||
|
||||
values.record_category === RecordTypes.sellOutStock
|
||||
) {
|
||||
out_stock = values.out_stock;
|
||||
const associatedCompanyProject = await this.db
|
||||
.getRepository('project')
|
||||
.findOne({ where: { company_id: out_stock.company_id } });
|
||||
in_stock = associatedCompanyProject;
|
||||
} else if (values.category === RecordCategory.staging) {
|
||||
in_stock = values.in_stock;
|
||||
out_stock = values.out_stock;
|
||||
}
|
||||
if (in_stock) {
|
||||
where['in_stock_id'] = in_stock.id;
|
||||
}
|
||||
if (out_stock) {
|
||||
where['out_stock_id'] = out_stock.id;
|
||||
}
|
||||
}
|
||||
await record.update(where, { transaction });
|
||||
if (where['in_stock_id'] && where['out_stock_id']) {
|
||||
// 设置完出库入,设置项目
|
||||
await this._updateRecordProjects(record, values, transaction, where);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 订单多对多项目hook赋值方法
|
||||
* @param model
|
||||
* @param values
|
||||
* @param transaction
|
||||
* @param where
|
||||
*/
|
||||
async _updateRecordProjects(model, values, transaction, where) {
|
||||
if (
|
||||
values.category === RecordCategory.purchase2lease ||
|
||||
values.category === RecordCategory.lease2lease ||
|
||||
values.category === RecordCategory.staging
|
||||
) {
|
||||
await this._deleteReocrdProject([model.id], transaction);
|
||||
await this.db.sequelize.query(
|
||||
`
|
||||
INSERT INTO record_projects (project_id, record_id)
|
||||
SELECT ${where.in_stock_id} AS project_id, ${model.id} AS record_id
|
||||
UNION ALL
|
||||
SELECT ${where.out_stock_id} AS project_id, ${model.id} AS project_id;
|
||||
`,
|
||||
{ transaction },
|
||||
);
|
||||
} else {
|
||||
await this._deleteReocrdProject([model.id], transaction);
|
||||
await this.db.sequelize.query(
|
||||
`
|
||||
INSERT INTO record_projects (project_id, record_id)
|
||||
SELECT
|
||||
CASE WHEN movement = '1' THEN ${where.out_stock_id} ELSE ${where.in_stock_id} END AS project_id,
|
||||
id AS record_id
|
||||
FROM records
|
||||
WHERE records.id = ${model.id}
|
||||
`,
|
||||
{ transaction },
|
||||
);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 订单发生变化时删除已经存在的多对多关系的表数据
|
||||
* @param id
|
||||
* @param transaction
|
||||
*/
|
||||
async _deleteReocrdProject(id: number[], transaction: Transaction) {
|
||||
await this.db.getRepository('record_projects').destroy({
|
||||
transaction,
|
||||
filter: {
|
||||
record_id: {
|
||||
$eq: id,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新订单对应的结算表状态
|
||||
*/
|
||||
@ -60,177 +265,235 @@ export class RecordService {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 校验车牌号
|
||||
*/
|
||||
async _checkPlateNumber(record: MagicAttributeModel, options: CreateOptions) {
|
||||
const { transaction, context } = options;
|
||||
if (record.dataValues?.vehicles) {
|
||||
const ids = record.dataValues.vehicles.filter((item) => typeof item === 'number').join(',');
|
||||
const vehicles = await this.db.sequelize.query(`select * from vehicles where id in (${ids})`, {
|
||||
transaction,
|
||||
});
|
||||
if (vehicles[0].length) {
|
||||
vehicles[0].forEach((item: any) => {
|
||||
if (item.number) {
|
||||
const validate = validateLicensePlate(item.number);
|
||||
if (!validate) {
|
||||
throw new Error('车牌号格式错误');
|
||||
}
|
||||
}
|
||||
});
|
||||
if (values?.category === RecordCategory.purchase) {
|
||||
// 定价
|
||||
const rule = values.price_items;
|
||||
// 产品
|
||||
const products = values.items;
|
||||
// 分组实际总量
|
||||
const weight_items = values.group_weight_items;
|
||||
let allPrice = 0;
|
||||
for (const item of rule) {
|
||||
const data = await this._amountCalculation(item, products, weight_items, values.weight);
|
||||
allPrice += data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 报价合同计算总金额
|
||||
*/
|
||||
async _calcAllPrice(record: MagicAttributeModel, options: CreateOptions) {
|
||||
const { values } = options;
|
||||
if (!values) return;
|
||||
if (values.new_contracts.length) {
|
||||
const contracts = values.new_contracts.map((item) => item.contract).find((i) => i.record_category === '1');
|
||||
if (contracts && values.items && values.items?.length > 0) {
|
||||
const leaseRule = await this.db.getRepository('contract_plan_lease_items').find({
|
||||
const recordId = record.id;
|
||||
// 更新订单总金额字段
|
||||
await this.db.getModel('records').update(
|
||||
{ all_price: allPrice },
|
||||
{
|
||||
where: {
|
||||
contract_id: contracts.id,
|
||||
id: recordId,
|
||||
},
|
||||
appends: ['conversion_logic', 'conversion_logic.weight_items'],
|
||||
});
|
||||
const sql = `
|
||||
WITH RECURSIVE tree1 AS (
|
||||
SELECT id, "parentId"
|
||||
FROM products
|
||||
WHERE id = :dataId
|
||||
UNION ALL
|
||||
SELECT p.id, p."parentId"
|
||||
FROM tree1 up
|
||||
JOIN products p ON up."parentId" = p.id
|
||||
)
|
||||
select id
|
||||
from tree1
|
||||
`;
|
||||
let allPrice = 0;
|
||||
for (const item of values.items) {
|
||||
const treeIds = await this.db.sequelize.query(sql, {
|
||||
replacements: {
|
||||
dataId: item.new_product.id,
|
||||
},
|
||||
type: QueryTypes.SELECT,
|
||||
});
|
||||
const rule = leaseRule.find((rule) => treeIds.find((i: any) => i.id === rule.new_products_id));
|
||||
if (rule) {
|
||||
const price = rule.unit_price || 0;
|
||||
const count = item.count || 0;
|
||||
if (rule.conversion_logic_id === ConversionLogics.Keep) {
|
||||
allPrice += price * count;
|
||||
} else if (
|
||||
rule.conversion_logic_id === ConversionLogics.Product ||
|
||||
rule.conversion_logic_id === ConversionLogics.ActualWeight
|
||||
) {
|
||||
const ratio = item.new_product.parent?.convertible ? item.new_product.ratio : 1;
|
||||
allPrice += price * count * ratio;
|
||||
} else if (rule.conversion_logic_id === ConversionLogics.ProductWeight) {
|
||||
allPrice += price * count * (item.new_product.weight || 0);
|
||||
} else {
|
||||
const weightRule = rule.conversion_logic.weight_items.find((weight) =>
|
||||
treeIds.find((i: any) => i.id === weight.new_product_id),
|
||||
);
|
||||
if (weightRule.conversion_logic_id === ConversionLogics.Keep) {
|
||||
allPrice += price * count * weightRule.weight;
|
||||
} else if (weightRule.conversion_logic_id === ConversionLogics.Product) {
|
||||
const ratio = item.new_product.parent?.convertible ? item.new_product.ratio : 1;
|
||||
allPrice += price * count * ratio * weightRule.weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (values.all_price !== allPrice) {
|
||||
record.all_price = allPrice;
|
||||
}
|
||||
}
|
||||
transaction,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 盘点单创建
|
||||
* 根据产品数据计算金额
|
||||
* @param rule 单个规则
|
||||
* @param products 全部产品
|
||||
* @param weight_items 全部分组实际重量
|
||||
* @returns 单个规则产生的总金额
|
||||
*/
|
||||
async _createStock(record: MagicAttributeModel, options: CreateOptions) {
|
||||
const { values, transaction, context } = options;
|
||||
if (!values) return;
|
||||
const record_contract = record.get('new_contracts').filter((item) => typeof item === 'object');
|
||||
if (record_contract.length) {
|
||||
const stockProduct = await this.db.getRepository('products').find({
|
||||
private async _amountCalculation(rule, products, weight_items, recprdWeight) {
|
||||
const calc_products = products.filter(
|
||||
(product) => product.product.category_id === rule.product.id - 99999 || product.product.id === rule.product.id,
|
||||
);
|
||||
const categoryIds = calc_products.map((item) => item.product.category_id).filter(Boolean);
|
||||
const categoryIdsStr = categoryIds.join(',');
|
||||
|
||||
const datas = await this.db.sequelize.query(`
|
||||
SELECT pc.*
|
||||
FROM product_category pc
|
||||
WHERE pc.id IN (${categoryIdsStr ? categoryIdsStr : 'null'});
|
||||
`);
|
||||
// 相关分类数据
|
||||
const categoryDatas = datas[0];
|
||||
if (!categoryDatas.length) return;
|
||||
if (rule.conversion_logic.id === ConversionLogics.Keep) {
|
||||
const allPrice = calc_products.reduce(
|
||||
(accumulator, currentValue) => accumulator + currentValue.count * rule.unit_price,
|
||||
0,
|
||||
);
|
||||
return allPrice;
|
||||
} else if (rule.conversion_logic.id === ConversionLogics.Product) {
|
||||
const allPrice = calc_products.reduce((accumulator, currentValue) => {
|
||||
const category: any = categoryDatas.find((item: any) => currentValue.product.category_id === item.id);
|
||||
if (category.convertible) {
|
||||
return accumulator + currentValue.count * currentValue.product.ratio * rule.unit_price;
|
||||
} else {
|
||||
return accumulator + currentValue.count * rule.unit_price;
|
||||
}
|
||||
}, 0);
|
||||
return allPrice;
|
||||
} else if (rule.conversion_logic.id === ConversionLogics.ProductWeight) {
|
||||
const allPrice = calc_products.reduce(
|
||||
(accumulator, currentValue) => accumulator + currentValue.count * currentValue.product.weight * rule.unit_price,
|
||||
0,
|
||||
);
|
||||
return allPrice / 1000;
|
||||
} else if (rule.conversion_logic.id === ConversionLogics.ActualWeight) {
|
||||
// 根据产品找分组实际重量
|
||||
const weightDate =
|
||||
weight_items.find((item) => item.products?.find((product) => product?.id === rule.product.id - 99999))
|
||||
?.weight || recprdWeight;
|
||||
if (weightDate) {
|
||||
const allPrice = weightDate * rule.unit_price;
|
||||
return allPrice;
|
||||
} else {
|
||||
const allPrice = calc_products.reduce((accumulator, currentValue) => {
|
||||
const category: any = categoryDatas.find((item: any) => currentValue.product.category_id === item.id);
|
||||
if (category.convertible) {
|
||||
return accumulator + currentValue.count * currentValue.product.ratio * rule.unit_price;
|
||||
} else {
|
||||
return accumulator + currentValue.count * rule.unit_price;
|
||||
}
|
||||
}, 0);
|
||||
return allPrice;
|
||||
}
|
||||
} else {
|
||||
const ids = calc_products
|
||||
.map((item) => item.product.category_id)
|
||||
.filter(Boolean)
|
||||
.join(',');
|
||||
const rules = this.db.sequelize.query(`
|
||||
select wr.*
|
||||
from weight_rules wr
|
||||
where wr.product_id IN (${ids}) and wr.logic_id = ${rule.conversion_logic.id}
|
||||
`);
|
||||
const weight_rules = rules[0];
|
||||
const allPrice = calc_products.reduce((accumulator, currentValue) => {
|
||||
const weight_rule: any = weight_rules?.find((item: any) => currentValue.product_id === item.id);
|
||||
const category: any = categoryDatas.find((item: any) => currentValue.product.category_id === item.id);
|
||||
if (category.convertible && weight_rule?.logic_id === ConversionLogics.Keep) {
|
||||
return accumulator + currentValue.count * currentValue.product.ratio * rule.unit_price;
|
||||
} else if (category.convertible && weight_rule?.logic_id === ConversionLogics.Product) {
|
||||
return accumulator + currentValue.count * currentValue.product.ratio * weight_rule.weight * rule.unit_price;
|
||||
} else if (!category.convertible && weight_rule?.logic_id === ConversionLogics.Keep) {
|
||||
return accumulator + currentValue.count * rule.unit_price;
|
||||
} else {
|
||||
return accumulator + currentValue.count * weight_rule?.weight * rule.unit_price;
|
||||
}
|
||||
}, 0);
|
||||
return allPrice || 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据直发单创建对应出库订单
|
||||
*/
|
||||
async _createRecord(model, values, transaction, context, numbers) {
|
||||
delete values.number;
|
||||
delete values.id;
|
||||
values.vehicles?.forEach((item) => delete item.record_vehicles);
|
||||
//采购直发单
|
||||
if (values.record_category === RecordTypes.purchaseDirect && values.category === RecordCategory.purchase2lease) {
|
||||
const inProject = await this.db.getModel('project').findOne({
|
||||
where: {
|
||||
id: values.in_contract.project_id,
|
||||
},
|
||||
});
|
||||
const base_project = await this.db.getModel('project').findOne({
|
||||
where: {
|
||||
company_id: inProject.associated_company_id, // 签约公司id
|
||||
category: '1',
|
||||
},
|
||||
});
|
||||
const sql = `
|
||||
WITH RECURSIVE tree1 AS (
|
||||
SELECT id, "parentId"
|
||||
FROM products
|
||||
WHERE id = :dataId
|
||||
UNION ALL
|
||||
SELECT p.id, p."parentId"
|
||||
FROM tree1 up
|
||||
JOIN products p ON up."parentId" = p.id
|
||||
)
|
||||
select id
|
||||
from tree1
|
||||
`;
|
||||
for (const i of record_contract) {
|
||||
const item = i.dataValues;
|
||||
const stock = {
|
||||
record_contract_id: item.id,
|
||||
items: [],
|
||||
project_id: item.contract.dataValues.project_id,
|
||||
};
|
||||
if (!item.fees) return;
|
||||
const stockItems = await Promise.all(
|
||||
item.fees.map(async (fee) => {
|
||||
if (typeof fee !== 'object') return;
|
||||
const treeIds = await this.db.sequelize.query(sql, {
|
||||
replacements: {
|
||||
dataId: fee.dataValues.new_fee_product.id,
|
||||
},
|
||||
type: QueryTypes.SELECT,
|
||||
});
|
||||
// 两数组ID,取并集
|
||||
const isStockProduct = _.intersectionBy(stockProduct, treeIds, 'id');
|
||||
if (isStockProduct.length > 0) {
|
||||
// 这里一般是无关联产品的费用,有赔偿标记的类别为需要找对应的产品
|
||||
// 这里需要平替找到对应的产品,目前没有这个分类的产品
|
||||
const parent = await this.db.getRepository('products').find({
|
||||
where: {
|
||||
id: fee.dataValues.new_fee_product.parentId,
|
||||
},
|
||||
});
|
||||
const fee_products = await this.db.getRepository('products').find({
|
||||
where: {
|
||||
name: fee.dataValues.new_fee_product.name,
|
||||
},
|
||||
appends: ['parent'],
|
||||
});
|
||||
const pro = fee_products.find((pro) => pro.parent?.name === parent.name);
|
||||
return { new_product: pro || fee.dataValues.new_fee_product, count: fee.count };
|
||||
} else {
|
||||
if (fee.dataValues.new_product) {
|
||||
return { new_product: fee.dataValues.new_product, count: fee.count };
|
||||
}
|
||||
}
|
||||
}),
|
||||
);
|
||||
if (stockItems.filter(Boolean).length > 0) {
|
||||
stock.items = stockItems;
|
||||
await this.db.getRepository('record_stock').updateOrCreate({
|
||||
filterKeys: ['record_contract_id'],
|
||||
values: stock,
|
||||
transaction,
|
||||
});
|
||||
}
|
||||
//1. 创建购销入库单
|
||||
const purchaseData = {
|
||||
...values,
|
||||
direct_record_id: model.id,
|
||||
};
|
||||
purchaseData['record_category'] = RecordTypes.purchaseInStock;
|
||||
purchaseData['movement'] = Movement.in;
|
||||
purchaseData['category'] = RecordCategory.purchase;
|
||||
purchaseData['in_stock'] = base_project.dataValues;
|
||||
if (numbers?.[0]) {
|
||||
purchaseData['number'] = numbers[0];
|
||||
}
|
||||
purchaseData.items.forEach((element) => {
|
||||
delete element.record_id;
|
||||
delete element.id;
|
||||
});
|
||||
await this.db.getRepository('records').create({ values: purchaseData, transaction, context });
|
||||
// 2. 创建租赁出库单
|
||||
const leaseData = {
|
||||
...values,
|
||||
direct_record_id: model.id,
|
||||
};
|
||||
leaseData['record_category'] = RecordTypes.rentOutStock;
|
||||
leaseData['movement'] = Movement.out;
|
||||
leaseData['category'] = RecordCategory.lease;
|
||||
leaseData['contract'] = values.in_contract;
|
||||
leaseData['out_stock'] = base_project.dataValues;
|
||||
leaseData['in_stock'] = inProject.dataValues;
|
||||
if (numbers?.[1]) {
|
||||
leaseData['number'] = numbers[1];
|
||||
}
|
||||
leaseData.items.forEach((element) => {
|
||||
delete element.record_id;
|
||||
delete element.id;
|
||||
});
|
||||
await this.db.getRepository('records').create({ values: leaseData, transaction, context });
|
||||
}
|
||||
if (values.record_category === RecordTypes.rentDirect && values.category === RecordCategory.lease2lease) {
|
||||
// 1.创建租赁入库
|
||||
const leaseInData = {
|
||||
...values,
|
||||
direct_record_id: model.id,
|
||||
};
|
||||
const outProject = await this.db.getModel('project').findOne({
|
||||
where: {
|
||||
id: values.out_contract.project_id,
|
||||
},
|
||||
});
|
||||
const inProject = await this.db.getModel('project').findOne({
|
||||
where: {
|
||||
id: values.in_contract.project_id,
|
||||
},
|
||||
});
|
||||
const baseProject = await this.db.getModel('project').findOne({
|
||||
where: {
|
||||
company_id: inProject.associated_company_id, // 签约公司id
|
||||
category: '1',
|
||||
},
|
||||
});
|
||||
leaseInData['record_category'] = RecordTypes.rentInStock;
|
||||
leaseInData['movement'] = Movement.in;
|
||||
leaseInData['category'] = RecordCategory.lease;
|
||||
leaseInData['contract'] = values.out_contract;
|
||||
leaseInData['out_stock'] = outProject.dataValues;
|
||||
leaseInData['in_stock'] = baseProject.dataValues;
|
||||
if (numbers?.[0]) {
|
||||
leaseInData['number'] = numbers[0];
|
||||
}
|
||||
leaseInData.items.forEach((element) => {
|
||||
delete element.record_id;
|
||||
delete element.id;
|
||||
});
|
||||
await this.db.getRepository('records').create({ values: leaseInData, transaction, context });
|
||||
// 2.创建租赁出库单
|
||||
const leaseOutData = {
|
||||
...values,
|
||||
direct_record_id: model.id,
|
||||
};
|
||||
leaseOutData['record_category'] = RecordTypes.rentOutStock;
|
||||
leaseOutData['movement'] = Movement.out;
|
||||
leaseOutData['category'] = RecordCategory.lease;
|
||||
leaseOutData['contract'] = values.in_contract;
|
||||
leaseOutData['out_stock'] = baseProject.dataValues;
|
||||
leaseOutData['in_stock'] = inProject.dataValues;
|
||||
if (numbers?.[1]) {
|
||||
leaseOutData['number'] = numbers[1];
|
||||
}
|
||||
leaseOutData.items.forEach((element) => {
|
||||
delete element.record_id;
|
||||
delete element.id;
|
||||
});
|
||||
await this.db.getRepository('records').create({ values: leaseOutData, transaction, context });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -887,8 +887,8 @@ export class SettlementService {
|
||||
});
|
||||
calc.list.forEach((value) => {
|
||||
const productDate = converDate(value.date, 'YYYY-MM-DD');
|
||||
if ((value.name as string)?.includes('-')) {
|
||||
const name = value.name?.split('-')[0];
|
||||
if ((value.name as string).includes('-')) {
|
||||
const name = value.name.split('-')[0];
|
||||
const valueItem = calc.list.filter(
|
||||
(item) => converDate(item.date, 'YYYY-MM-DD') === productDate && item.name === name,
|
||||
)[0];
|
||||
@ -896,8 +896,8 @@ export class SettlementService {
|
||||
value.date = dayjs(valueItem.date).add(1, 'seconds');
|
||||
}
|
||||
}
|
||||
if (value.name?.includes('&&')) {
|
||||
value.name = value.name.replace('&&', '');
|
||||
if (value.name.includes('$$')) {
|
||||
value.name = value.name.replace('$$', '');
|
||||
}
|
||||
});
|
||||
calc.list?.sort((a, b) => {
|
||||
|
@ -0,0 +1,120 @@
|
||||
SELECT
|
||||
r.*,
|
||||
-- ================================出入库信息================================
|
||||
(
|
||||
SELECT
|
||||
TO_JSONB(
|
||||
JSONB_SET(
|
||||
TO_JSONB(project),
|
||||
'{associated_company}',
|
||||
COALESCE(TO_JSONB(c2), '{}'::jsonb)
|
||||
)
|
||||
)
|
||||
FROM
|
||||
project
|
||||
LEFT JOIN company c2 ON project.associated_company_id = c2.id
|
||||
WHERE
|
||||
project.id = r.out_stock_id
|
||||
) AS out_stock,
|
||||
-- 查订单入库方
|
||||
(
|
||||
SELECT
|
||||
TO_JSONB(
|
||||
JSONB_SET(
|
||||
TO_JSONB(project),
|
||||
'{associated_company}',
|
||||
COALESCE(TO_JSONB(c), '{}'::jsonb)
|
||||
)
|
||||
)
|
||||
FROM
|
||||
project
|
||||
LEFT JOIN company c ON project.associated_company_id = c.id
|
||||
WHERE
|
||||
project.id = r.in_stock_id
|
||||
) AS in_stock,
|
||||
TO_JSONB(
|
||||
-- 项目/客户数据(只有租赁才有此项目,其他项目就是出入库数据)
|
||||
JSONB_SET(
|
||||
TO_JSONB(c),
|
||||
'{project}',
|
||||
(
|
||||
SELECT
|
||||
COALESCE(
|
||||
TO_JSONB(
|
||||
JSONB_SET(
|
||||
TO_JSONB(p3),
|
||||
'{associated_company}',
|
||||
CASE
|
||||
WHEN p3.associated_company_id IS NOT NULL THEN (
|
||||
SELECT
|
||||
COALESCE(TO_JSONB(c), '{}'::jsonb)
|
||||
FROM
|
||||
company c
|
||||
WHERE
|
||||
p3.associated_company_id = c.id
|
||||
)
|
||||
ELSE '{}'::jsonb
|
||||
END
|
||||
) || JSONB_SET(
|
||||
TO_JSONB(p3),
|
||||
'{company}',
|
||||
(
|
||||
SELECT
|
||||
TO_JSONB(c)
|
||||
FROM
|
||||
company c
|
||||
WHERE
|
||||
p3.company_id = c.id
|
||||
)
|
||||
) || JSONB_SET(
|
||||
TO_JSONB(p3),
|
||||
'{contacts}',
|
||||
(
|
||||
SELECT
|
||||
COALESCE(JSONB_AGG(c), '[]'::jsonb)
|
||||
FROM
|
||||
project_contacts pc
|
||||
JOIN contacts c ON pc.contact_id = c.id
|
||||
WHERE
|
||||
p3.id = pc.project_id
|
||||
)
|
||||
)
|
||||
),
|
||||
'{}'::jsonb
|
||||
)
|
||||
FROM
|
||||
project p3
|
||||
WHERE
|
||||
c.project_id = p3.id
|
||||
)
|
||||
)
|
||||
) AS contract,
|
||||
-- ==========================================车号==========================================
|
||||
(
|
||||
SELECT
|
||||
COALESCE(JSONB_AGG(v), '[]'::jsonb)
|
||||
FROM
|
||||
record_vehicles rv
|
||||
JOIN vehicles v ON rv.vehicle_id = v.id
|
||||
WHERE
|
||||
r.id = rv.record_id
|
||||
) AS vehicles,
|
||||
-- 查询分组实际重量
|
||||
(
|
||||
SELECT
|
||||
JSONB_AGG(
|
||||
JSONB_SET(TO_JSONB(rgwi), '{category}', TO_JSONB(pc))
|
||||
)
|
||||
FROM
|
||||
record_group_weight_items rgwi
|
||||
JOIN record_group_weight_items_products rgwip ON rgwip.item_id = rgwi.id
|
||||
JOIN product_category pc ON rgwip.product_category_id = pc.id
|
||||
WHERE
|
||||
rgwi.record_id = r.id
|
||||
) AS record_group_weight_items
|
||||
FROM
|
||||
records r
|
||||
-- 合同数据(租赁有合同)
|
||||
LEFT JOIN contracts c ON r.contract_id = c.id
|
||||
WHERE
|
||||
r.id = :recordId
|
@ -0,0 +1,122 @@
|
||||
SELECT
|
||||
r.movement AS record_movement,
|
||||
r.weight AS record_weight,
|
||||
NULL AS actual_weight,
|
||||
NULL AS product_id,
|
||||
NULL AS product_count,
|
||||
NULL AS fee_count,
|
||||
NULL AS is_excluded,
|
||||
cpfi.fee_product_id,
|
||||
p.*,
|
||||
p.weight AS product_weight,
|
||||
NULL AS product_ratio,
|
||||
NULL AS convertible,
|
||||
NULL AS product_category_id,
|
||||
cpfi.unit_price,
|
||||
cpfi.conversion_logic_id,
|
||||
cpfi.unit,
|
||||
cpfi.count_source,
|
||||
cpfi."comment",
|
||||
cpfi.id,
|
||||
(
|
||||
SELECT
|
||||
JSONB_AGG(wr)
|
||||
FROM
|
||||
weight_rules wr
|
||||
WHERE
|
||||
wr.logic_id = cpfi.conversion_logic_id
|
||||
) AS weight_rules
|
||||
FROM
|
||||
records r
|
||||
LEFT JOIN contracts c ON r.contract_id = c.id
|
||||
LEFT JOIN contract_items ci ON c.id = ci.contract_id
|
||||
AND ci.start_date <= r.date
|
||||
AND ci.end_date >= r."date"
|
||||
LEFT JOIN contract_plans cp ON ci.contract_plan_id = cp.id
|
||||
LEFT JOIN contract_plan_fee_items cpfi ON cp.id = cpfi.contract_plan_id --有lease_item_id证明是关联产品的费用
|
||||
JOIN product p ON p.id = cpfi.fee_product_id
|
||||
LEFT JOIN product_category pc3 ON p.category_id = pc3.id
|
||||
JOIN product_category pc ON pc.id = p.category_id
|
||||
JOIN unit_conversion_logics ucl ON ucl.id = cpfi.conversion_logic_id
|
||||
WHERE
|
||||
r.id = :recordId
|
||||
GROUP BY
|
||||
cpfi.id,
|
||||
p.id,
|
||||
r.id
|
||||
UNION
|
||||
SELECT
|
||||
r2.movement AS record_movement,
|
||||
r2.weight AS record_weight,
|
||||
rwi.weight AS actual_weight,
|
||||
ri.product_id,
|
||||
ri.count AS product_count,
|
||||
rifi.count AS fee_count,
|
||||
rifi.is_excluded AS is_excluded, -- 不计入合同
|
||||
cpfi2.fee_product_id,
|
||||
p1.*,
|
||||
p2.weight AS product_weight,
|
||||
p2.ratio AS product_ratio,
|
||||
pc2.convertible AS convertible,
|
||||
pc2.id AS product_category_id,
|
||||
cpfi2.unit_price,
|
||||
cpfi2.conversion_logic_id,
|
||||
cpfi2.unit,
|
||||
cpfi2.count_source,
|
||||
cpfi2."comment",
|
||||
cpfi2.id,
|
||||
(
|
||||
SELECT
|
||||
TO_JSONB(wr)
|
||||
FROM
|
||||
weight_rules wr
|
||||
WHERE
|
||||
ucl2.id > 4
|
||||
AND wr.logic_id = ucl2.id
|
||||
AND wr.product_id = ri.product_id
|
||||
LIMIT
|
||||
1
|
||||
) AS weight_rules
|
||||
FROM
|
||||
records r2
|
||||
LEFT JOIN contracts c2 ON r2.contract_id = c2.id
|
||||
LEFT JOIN contract_items ci2 ON c2.id = ci2.contract_id
|
||||
AND ci2.start_date <= r2.date
|
||||
AND ci2.end_date >= r2."date"
|
||||
LEFT JOIN contract_plans cp2 ON ci2.contract_plan_id = cp2.id
|
||||
LEFT JOIN contract_plan_lease_items cpli ON cp2.id = cpli.contract_plan_id -- 查租金
|
||||
JOIN contract_plan_lease_items_products cplip ON cplip.lease_item_id = cpli.id -- 查租金产品
|
||||
JOIN contract_plan_fee_items cpfi2 ON cpfi2.lease_item_id = cpli.id
|
||||
AND cpfi2.count_source = '0' -- 查费用
|
||||
JOIN unit_conversion_logics ucl2 ON ucl2.id = cpfi2.conversion_logic_id -- 查计算规则
|
||||
JOIN record_items ri ON ri.record_id = r2.id
|
||||
AND (
|
||||
ri.product_id = cplip.product_id
|
||||
OR (
|
||||
SELECT
|
||||
p.category_id
|
||||
FROM
|
||||
product p
|
||||
WHERE
|
||||
p.id = ri.product_id
|
||||
) = cplip.product_id - 99999
|
||||
)
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
record_group_weight_items.id,
|
||||
COMMENT,
|
||||
weight,
|
||||
record_id,
|
||||
product_category_id
|
||||
FROM
|
||||
record_group_weight_items
|
||||
JOIN record_group_weight_items_products ON record_group_weight_items.id = record_group_weight_items_products.item_id
|
||||
) rwi ON r2.id = rwi.record_id
|
||||
AND rwi.product_category_id = ri.product_id
|
||||
LEFT JOIN record_item_fee_items rifi ON ri.id = rifi.record_item_id
|
||||
AND rifi.product_id = cpfi2.fee_product_id
|
||||
JOIN product p1 ON p1.id = cpfi2.fee_product_id
|
||||
LEFT JOIN product p2 ON ri.product_id = p2.id
|
||||
LEFT JOIN product_category pc2 ON p2.category_id = pc2.id
|
||||
WHERE
|
||||
r2.id = :recordId
|
@ -0,0 +1,112 @@
|
||||
-- 租金
|
||||
-- distinct说明:sql根据订单中产品去合同规则中找规则,如果合同存在单个产品多条规则,会连接查询出多条规则,所以需要distinct
|
||||
-- 直接disinct掉,不会有任何影响,因为查询数据只关注点单产品数量,根换算逻辑,正好多条规则换算逻辑是一样的
|
||||
SELECT DISTINCT
|
||||
r.category,
|
||||
ri.comment AS item_comment,
|
||||
ri.count,
|
||||
ri.product_id,
|
||||
p.label,
|
||||
p.ratio,
|
||||
p.weight,
|
||||
p.category_id,
|
||||
pc.name AS product_category_name,
|
||||
pc.unit,
|
||||
pc.convertible,
|
||||
pc.conversion_unit,
|
||||
lr.unit_price AS price_price,
|
||||
vp."label" AS price_label,
|
||||
lr."comment" AS price_comment,
|
||||
rwi.product_category_id,
|
||||
CASE
|
||||
WHEN r.category = '0' THEN cpli.conversion_logic_id
|
||||
ELSE lr.conversion_logic_id
|
||||
END AS conversion_logic_id,
|
||||
CASE
|
||||
WHEN ucl.id > 4
|
||||
AND c.id IS NOT NULL THEN (
|
||||
SELECT
|
||||
TO_JSONB(wr)
|
||||
FROM
|
||||
weight_rules wr
|
||||
WHERE
|
||||
ucl.id = wr.logic_id
|
||||
AND (
|
||||
wr.product_id = p.id
|
||||
OR wr.product_id = pc.id + 99999
|
||||
)
|
||||
)
|
||||
WHEN lr.conversion_logic_id > 4
|
||||
AND c.id IS NULL THEN (
|
||||
SELECT
|
||||
TO_JSONB(wr2)
|
||||
FROM
|
||||
weight_rules wr2
|
||||
WHERE
|
||||
lr.conversion_logic_id = wr2.logic_id
|
||||
AND (
|
||||
wr2.product_id = p.id
|
||||
OR wr2.product_id = pc.id + 99999
|
||||
)
|
||||
)
|
||||
END AS wr
|
||||
FROM
|
||||
records r
|
||||
LEFT JOIN record_items ri ON r.id = ri.record_id
|
||||
LEFT JOIN product p ON ri.product_id = p.id
|
||||
LEFT JOIN product_category pc ON p.category_id = pc.id
|
||||
---- 租赁找合同规则
|
||||
LEFT JOIN contracts c ON r.contract_id = c.id
|
||||
LEFT JOIN contract_items ci ON c.id = ci.contract_id
|
||||
AND ci.start_date <= r.date
|
||||
AND ci.end_date >= r."date"
|
||||
LEFT JOIN contract_plans cp ON ci.contract_plan_id = cp.id
|
||||
LEFT JOIN contract_plan_lease_items cpli ON cp.id = cpli.contract_plan_id
|
||||
LEFT JOIN unit_conversion_logics ucl ON cpli.conversion_logic_id = ucl.id
|
||||
AND cpli.conversion_logic_id > 4
|
||||
------ 购销找租金定价
|
||||
LEFT JOIN lease_rules lr ON r.id = lr.record_id
|
||||
AND (
|
||||
lr.product_id = p.id
|
||||
OR lr.product_id = pc.id + 99999
|
||||
)
|
||||
LEFT JOIN view_products vp ON vp.id = lr.product_id
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
record_group_weight_items.id,
|
||||
COMMENT,
|
||||
weight,
|
||||
record_id,
|
||||
product_category_id
|
||||
FROM
|
||||
record_group_weight_items
|
||||
JOIN record_group_weight_items_products ON record_group_weight_items.id = record_group_weight_items_products.item_id
|
||||
) rwi ON r.id = rwi.record_id
|
||||
AND rwi.product_category_id = pc.id
|
||||
WHERE
|
||||
r.id = :recordId
|
||||
AND (
|
||||
CASE
|
||||
WHEN c.id IS NOT NULL THEN (
|
||||
ri.product_id = (
|
||||
SELECT
|
||||
cplip.product_id
|
||||
FROM
|
||||
contract_plan_lease_items_products cplip
|
||||
WHERE
|
||||
cplip.lease_item_id = cpli.id
|
||||
AND cplip.product_id = p.id
|
||||
)
|
||||
OR pc.id + 99999 = (
|
||||
SELECT
|
||||
cplip.product_id
|
||||
FROM
|
||||
contract_plan_lease_items_products cplip
|
||||
WHERE
|
||||
cplip.lease_item_id = cpli.id
|
||||
AND cplip.product_id - 99999 = pc.id
|
||||
)
|
||||
)
|
||||
ELSE TRUE
|
||||
END
|
||||
)
|
@ -1,64 +1,114 @@
|
||||
SELECT
|
||||
r.number record_number,
|
||||
w.arrival_date, -- 到货日期
|
||||
w.off_date, -- 承运日期
|
||||
w.weight_or_amount, -- 吨/趟
|
||||
w.unit_price, -- 单价
|
||||
w.additional_cost, -- 附加金额
|
||||
w.pay_date, -- 付款日期
|
||||
w.comment,
|
||||
p."name" AS payer_name, -- 付款方
|
||||
c."name" AS payer_company, -- 付款方公司
|
||||
a."name" AS payee_account_name, -- 收款账户
|
||||
a."number" AS payee_account_number, -- 收款账户
|
||||
a.bank AS payee_account_bank, -- 收款名称
|
||||
p2.address AS shipper_address, -- 发货方
|
||||
p2."name" AS shipper_name, -- 发货方单位
|
||||
c3.name AS shipper_company, -- 发货方单位
|
||||
c4."name" AS shipper_contact, -- 发货方联系人
|
||||
c4.phone AS shipper_contact_phone, -- 发货方联系人
|
||||
c2."name" AS consignee_contact, -- 收款人
|
||||
p3.name AS consignee_name, -- 收货方单位
|
||||
p3.address AS consignee_address,
|
||||
c5."name" AS consignee_company, -- 收货方单位
|
||||
c6."name" AS consignee_contact, -- 收货人
|
||||
c6.phone AS consignee_contact_phone,
|
||||
c7.name AS carrier, -- 承运商
|
||||
c8.name AS driver, -- 驾驶员
|
||||
c8.phone AS driver_phone,
|
||||
c8.id_card AS driver_idcard, --驾驶员
|
||||
(
|
||||
SELECT
|
||||
STRING_AGG(v.number::TEXT, ', ')
|
||||
FROM
|
||||
record_vehicles rv
|
||||
JOIN vehicles v ON rv.vehicle_id = v.id
|
||||
WHERE
|
||||
r.id = rv.record_id
|
||||
) AS vehicles,
|
||||
(
|
||||
SELECT
|
||||
waybills_explain
|
||||
FROM
|
||||
basic_configuration
|
||||
) side_information
|
||||
) side_information,
|
||||
w.*,
|
||||
TO_JSONB(
|
||||
JSONB_SET(
|
||||
TO_JSONB(payer),
|
||||
'{company}',
|
||||
(
|
||||
SELECT
|
||||
TO_JSONB(c2)
|
||||
FROM
|
||||
company c2
|
||||
WHERE
|
||||
payer.company_id = c2.id
|
||||
)
|
||||
)
|
||||
) AS payer, -- 付款方, 查公司company_id
|
||||
TO_JSONB(payee_account) AS payee_account, -- 收款方账号
|
||||
TO_JSONB(shipper_contact) AS shipper_contact, -- 发货方联系人
|
||||
TO_JSONB(consignee_contact) AS consignee_contact, -- 收货方联系人
|
||||
TO_JSONB(carrier) AS carrier, -- 承运商
|
||||
TO_JSONB(driver) AS driver, --司机
|
||||
TO_JSONB(
|
||||
JSONB_SET(
|
||||
TO_JSONB(in_stock),
|
||||
'{company}',
|
||||
(
|
||||
SELECT
|
||||
TO_JSONB(c)
|
||||
FROM
|
||||
company c
|
||||
WHERE
|
||||
in_stock.company_id = c.id
|
||||
)
|
||||
)
|
||||
) AS in_stock,
|
||||
TO_JSONB(
|
||||
JSONB_SET(
|
||||
TO_JSONB(out_stock),
|
||||
'{company}',
|
||||
(
|
||||
SELECT
|
||||
TO_JSONB(c)
|
||||
FROM
|
||||
company c
|
||||
WHERE
|
||||
out_stock.company_id = c.id
|
||||
)
|
||||
)
|
||||
) AS out_stock,
|
||||
TO_JSONB(records.*) || JSONB_BUILD_OBJECT(
|
||||
'items',
|
||||
(
|
||||
SELECT
|
||||
JSONB_AGG(
|
||||
TO_JSONB(record_items) || JSONB_BUILD_OBJECT(
|
||||
'product',
|
||||
TO_JSONB(product.*) || JSONB_BUILD_OBJECT('category', TO_JSONB(product_category.*))
|
||||
)
|
||||
)
|
||||
FROM
|
||||
record_items
|
||||
LEFT JOIN product ON record_items.product_id = product.id
|
||||
LEFT JOIN product_category ON product.category_id = product_category.id
|
||||
WHERE
|
||||
records.id = record_items.record_id
|
||||
),
|
||||
'vehicles',
|
||||
(
|
||||
SELECT
|
||||
COALESCE(JSONB_AGG(v), '[]'::jsonb)
|
||||
FROM
|
||||
record_vehicles rv
|
||||
JOIN vehicles v ON rv.vehicle_id = v.id
|
||||
WHERE
|
||||
records.id = rv.record_id
|
||||
)
|
||||
) AS record
|
||||
FROM
|
||||
waybills w
|
||||
JOIN records r ON r.id = w.record_id
|
||||
LEFT JOIN record_contract rc ON r.id = rc.record_id
|
||||
LEFT JOIN project p ON w.payer_id = p.id
|
||||
LEFT JOIN company c ON p.company_id = c.id
|
||||
LEFT JOIN account a ON w.payee_account_id = a.id
|
||||
LEFT JOIN contacts c2 ON w.consignee_contact_id = c2.id
|
||||
JOIN project p2 ON r.out_stock_id = p2.id -- 发货方
|
||||
LEFT JOIN company c3 ON p2.company_id = c3.id
|
||||
LEFT JOIN contacts c4 ON w.shipper_contact_id = c4.id
|
||||
JOIN project p3 ON r.in_stock_id = p3.id -- 收货方
|
||||
LEFT JOIN company c5 ON p3.company_id = c5.id
|
||||
LEFT JOIN contacts c6 ON w.consignee_contact_id = c6.id
|
||||
LEFT JOIN company c7 ON w.carrier_id = c7.id
|
||||
LEFT JOIN contacts c8 ON w.driver_id = c8.id
|
||||
LEFT JOIN
|
||||
-- 付款方
|
||||
project payer ON w.payer_id = payer.id
|
||||
LEFT JOIN
|
||||
-- 收款方账户
|
||||
account payee_account ON w.payee_account_id = payee_account.id
|
||||
LEFT JOIN
|
||||
-- 发货方联系人
|
||||
contacts shipper_contact ON w.shipper_contact_id = shipper_contact.id
|
||||
LEFT JOIN
|
||||
-- 收货方联系人
|
||||
contacts consignee_contact ON w.consignee_contact_id = consignee_contact.id
|
||||
LEFT JOIN
|
||||
-- 承运商
|
||||
company carrier ON w.carrier_id = carrier.id
|
||||
LEFT JOIN
|
||||
-- 司机
|
||||
contacts driver ON w.driver_id = driver.id
|
||||
JOIN
|
||||
-- 订单信息
|
||||
records ON w.record_id = records.id
|
||||
JOIN record_items ON record_items.record_id = w.record_id
|
||||
JOIN product ON product.id = record_items.product_id
|
||||
JOIN product_category ON product_category.id = product.category_id
|
||||
LEFT JOIN record_vehicles ON records.id = record_vehicles.record_id
|
||||
LEFT JOIN project in_stock ON records.in_stock_id = in_stock.id
|
||||
LEFT JOIN project out_stock ON records.out_stock_id = out_stock.id
|
||||
WHERE
|
||||
w.id = :recordId
|
||||
LIMIT
|
||||
1 --rc数量不为1
|
||||
|
@ -0,0 +1,276 @@
|
||||
SELECT
|
||||
s.*,
|
||||
TO_JSONB(
|
||||
JSONB_SET(
|
||||
TO_JSONB(c),
|
||||
'{rule_items}',
|
||||
(
|
||||
SELECT
|
||||
JSONB_AGG(
|
||||
JSONB_SET(
|
||||
TO_JSONB(ci),
|
||||
'{rule}',
|
||||
TO_JSONB(
|
||||
-- 租金
|
||||
JSONB_SET(
|
||||
TO_JSONB(cp),
|
||||
'{lease_items}',
|
||||
(
|
||||
SELECT
|
||||
JSONB_AGG(
|
||||
JSONB_SET(
|
||||
TO_JSONB(cpli),
|
||||
'{ucl}',
|
||||
TO_JSONB(
|
||||
JSONB_SET(
|
||||
TO_JSONB(ucl),
|
||||
'{weight_items}',
|
||||
(
|
||||
SELECT
|
||||
COALESCE(JSONB_AGG(wr), '[]'::jsonb)
|
||||
FROM
|
||||
weight_rules wr
|
||||
WHERE
|
||||
ucl.id = wr.logic_id
|
||||
AND ucl.id > 4
|
||||
)
|
||||
)
|
||||
)
|
||||
) || JSONB_SET(
|
||||
TO_JSONB(cpli),
|
||||
'{product_fee}',
|
||||
(
|
||||
SELECT
|
||||
COALESCE(
|
||||
JSONB_AGG(
|
||||
JSONB_SET(TO_JSONB(cpfi), '{product}', TO_JSONB(product)) || JSONB_SET(
|
||||
TO_JSONB(cpfi),
|
||||
'{weight_items}',
|
||||
(
|
||||
SELECT
|
||||
COALESCE(JSONB_AGG(wrs), '[]'::jsonb)
|
||||
FROM
|
||||
weight_rules wrs
|
||||
WHERE
|
||||
wrs.logic_id = cpfi.conversion_logic_id
|
||||
AND cpfi.conversion_logic_id > 4
|
||||
)
|
||||
)
|
||||
),
|
||||
'[]'::jsonb
|
||||
)
|
||||
FROM
|
||||
contract_plan_fee_items cpfi
|
||||
JOIN product ON cpfi.fee_product_id = product.id
|
||||
WHERE
|
||||
cpfi.lease_item_id = cpli.id
|
||||
)
|
||||
) || JSONB_SET(
|
||||
TO_JSONB(cpli),
|
||||
'{products}',
|
||||
(
|
||||
SELECT
|
||||
JSONB_AGG(cplip)
|
||||
FROM
|
||||
contract_plan_lease_items_products cplip
|
||||
WHERE
|
||||
cplip.lease_item_id = cpli.id
|
||||
)
|
||||
)
|
||||
)
|
||||
FROM
|
||||
contract_plan_lease_items cpli
|
||||
JOIN unit_conversion_logics ucl ON ucl.id = cpli.conversion_logic_id
|
||||
WHERE
|
||||
cpli.contract_plan_id = cp.id
|
||||
)
|
||||
) ||
|
||||
-- 费用
|
||||
JSONB_SET(
|
||||
TO_JSONB(cp),
|
||||
'{fee_item}',
|
||||
(
|
||||
SELECT
|
||||
COALESCE(
|
||||
JSONB_AGG(
|
||||
JSONB_SET(
|
||||
TO_JSONB(cpfi),
|
||||
'{ucl}',
|
||||
TO_JSONB(
|
||||
JSONB_SET(
|
||||
TO_JSONB(ucl),
|
||||
'{weight_items}',
|
||||
(
|
||||
SELECT
|
||||
COALESCE(JSONB_AGG(wr), '[]'::jsonb)
|
||||
FROM
|
||||
weight_rules wr
|
||||
WHERE
|
||||
cpfi.conversion_logic_id = wr.logic_id
|
||||
AND cpfi.conversion_logic_id > 4
|
||||
)
|
||||
)
|
||||
)
|
||||
) || JSONB_SET(
|
||||
TO_JSONB(cpfi),
|
||||
'{product}',
|
||||
(
|
||||
SELECT
|
||||
TO_JSONB(product)
|
||||
FROM
|
||||
product
|
||||
WHERE
|
||||
cpfi.fee_product_id = product.id
|
||||
)
|
||||
)
|
||||
),
|
||||
'[]'::jsonb
|
||||
)
|
||||
FROM
|
||||
contract_plan_fee_items cpfi
|
||||
JOIN unit_conversion_logics ucl ON ucl.id = cpfi.conversion_logic_id
|
||||
WHERE
|
||||
cpfi.contract_plan_id = cp.id
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
FROM
|
||||
contract_items ci
|
||||
LEFT JOIN contract_plans cp ON ci.contract_plan_id = cp.id
|
||||
WHERE
|
||||
ci.contract_id = COALESCE(main.id, c.id)
|
||||
AND ci.start_date IS NOT NULL
|
||||
AND ci.end_date IS NOT NULL
|
||||
)
|
||||
)
|
||||
) AS contracts,
|
||||
(
|
||||
SELECT
|
||||
JSONB_AGG(
|
||||
JSONB_SET(
|
||||
TO_JSONB(r),
|
||||
'{record_items}',
|
||||
(
|
||||
SELECT
|
||||
COALESCE(
|
||||
JSONB_AGG(
|
||||
JSONB_SET(
|
||||
TO_JSONB(ri),
|
||||
'{product}',
|
||||
-- 产品
|
||||
(
|
||||
SELECT
|
||||
TO_JSONB(
|
||||
JSONB_SET(
|
||||
TO_JSONB(p),
|
||||
'{product_category}',
|
||||
-- 产品分类
|
||||
TO_JSONB(pc)
|
||||
)
|
||||
)
|
||||
FROM
|
||||
product p
|
||||
JOIN product_category pc ON p.category_id = pc.id
|
||||
WHERE
|
||||
p.id = ri.product_id
|
||||
)
|
||||
) || JSONB_SET(
|
||||
TO_JSONB(ri),
|
||||
'{record_item_fee_items}',
|
||||
(
|
||||
SELECT
|
||||
COALESCE(
|
||||
JSONB_AGG(
|
||||
JSONB_SET(TO_JSONB(rifi), '{product}', TO_JSONB(p))
|
||||
),
|
||||
'[]'::jsonb
|
||||
)
|
||||
FROM
|
||||
record_item_fee_items rifi
|
||||
JOIN product p ON rifi.product_id = p.id
|
||||
WHERE
|
||||
rifi.record_item_id = ri.id
|
||||
)
|
||||
)
|
||||
),
|
||||
'[]'::jsonb
|
||||
)
|
||||
FROM
|
||||
record_items ri
|
||||
WHERE
|
||||
ri.record_id = r.id
|
||||
)
|
||||
) || JSONB_SET(
|
||||
-- 维修赔偿(无产品关联,如:运费)
|
||||
TO_JSONB(r),
|
||||
'{fee_item}',
|
||||
(
|
||||
SELECT
|
||||
COALESCE(
|
||||
JSONB_AGG(
|
||||
JSONB_SET(TO_JSONB(rfi), '{product}', TO_JSONB(p))
|
||||
),
|
||||
'[]'::jsonb
|
||||
)
|
||||
FROM
|
||||
record_fee_items rfi
|
||||
JOIN product p ON rfi.product_id = p.id
|
||||
WHERE
|
||||
rfi.record_id = r.id
|
||||
)
|
||||
) || JSONB_SET(
|
||||
TO_JSONB(r),
|
||||
'{weight_items}',
|
||||
(
|
||||
SELECT
|
||||
COALESCE(JSONB_AGG(rwi), '[]'::jsonb)
|
||||
FROM
|
||||
(
|
||||
SELECT
|
||||
record_group_weight_items.id,
|
||||
COMMENT,
|
||||
weight,
|
||||
record_id,
|
||||
product_category_id
|
||||
FROM
|
||||
record_group_weight_items
|
||||
JOIN record_group_weight_items_products ON record_group_weight_items.id = record_group_weight_items_products.item_id
|
||||
) rwi
|
||||
WHERE
|
||||
rwi.record_id = r.id
|
||||
)
|
||||
)
|
||||
)
|
||||
FROM
|
||||
records r
|
||||
WHERE
|
||||
r.contract_id = COALESCE(main.id, c.id)
|
||||
AND r.category = '0'
|
||||
AND (s.end_date + INTERVAL '1 day - 1 millisecond') >= r.date
|
||||
) AS records,
|
||||
(
|
||||
SELECT
|
||||
COALESCE(JSONB_AGG(sai), '[]'::jsonb)
|
||||
FROM
|
||||
settlement_add_items sai
|
||||
WHERE
|
||||
s.id = sai.add_id
|
||||
) AS settlement_add_items,
|
||||
(
|
||||
SELECT
|
||||
JSONB_AGG(s1)
|
||||
FROM
|
||||
settlements s1
|
||||
WHERE
|
||||
s1.contract_id = c.id
|
||||
) AS settlements
|
||||
FROM
|
||||
settlements s
|
||||
JOIN
|
||||
-- 合同 一对一
|
||||
contracts c ON c.id = s.contract_id
|
||||
LEFT JOIN contracts main ON main.id = c.alternative_contract_id
|
||||
WHERE
|
||||
s.id = :settlementsId
|
@ -48,28 +48,6 @@ SELECT
|
||||
WHERE
|
||||
contracts."updatedById" = u.id
|
||||
)
|
||||
) || JSONB_SET(
|
||||
TO_JSONB(contracts),
|
||||
'{first_party}',
|
||||
(
|
||||
SELECT
|
||||
TO_JSONB(c)
|
||||
FROM
|
||||
company c
|
||||
WHERE
|
||||
c.id = contracts.first_party_id
|
||||
)
|
||||
) || JSONB_SET(
|
||||
TO_JSONB(contracts),
|
||||
'{party_b}',
|
||||
(
|
||||
SELECT
|
||||
TO_JSONB(c)
|
||||
FROM
|
||||
company c
|
||||
WHERE
|
||||
c.id = contracts.party_b_id
|
||||
)
|
||||
)
|
||||
) AS contracts,
|
||||
(
|
||||
|
@ -84,6 +84,18 @@ export enum SourcesType {
|
||||
* 3 出入库量
|
||||
*/
|
||||
inAndOut = '3',
|
||||
/**
|
||||
* 4 出库单数
|
||||
*/
|
||||
outboundNumber = '4',
|
||||
/**
|
||||
* 5 入库单数
|
||||
*/
|
||||
inboundNumber = '5',
|
||||
/**
|
||||
* 6 出入库单数
|
||||
*/
|
||||
inAndOutNumber = '6',
|
||||
}
|
||||
|
||||
export enum PromptText {
|
||||
|
Loading…
Reference in New Issue
Block a user