import { message } from 'kts-xui'; import { chain, bignumber } from 'mathjs'; import idGenerator from '../../tools/idGenerator'; import { IGood, InvoiceControllerState, LineAttributeType } from '..'; import { format15 } from '../../tools/calculate'; export default async function mergeDetails(state: InvoiceControllerState, selectedGoodIndex?: string[]) { if (state.goodsListState.editGood || !selectedGoodIndex || selectedGoodIndex.length < 2) return; const goodsList = state.goodsListState.goodsList.filter(e => selectedGoodIndex.indexOf(e.$index) >= 0); if (goodsList.length < 2) return; grouping(goodsList).forEach(merge); /** 分组 */ function grouping(goodsList: IGood[]): IGood[][] { const grouped: any = {}; goodsList.forEach(good => { const key = (() => { switch (good.lineAttribute) { case LineAttributeType.折让行: return LineAttributeType.折让行 case LineAttributeType.赠品行: return LineAttributeType.赠品行 default: return LineAttributeType.正常 } })() if (!grouped[key]) { grouped[key] = []; } grouped[key].push({ ...good, lineAttribute: key }); }) return Object.values(grouped); } /** 合并 */ async function merge(goodsList: IGood[]) { if (goodsList.length < 2) return; const selectedGoodIndex = goodsList.map(e => e.$index); try { // 创建合并后的商品对象 let sum: IGood = { $index: idGenerator(), lineAttribute: goodsList[0].lineAttribute, } // 存在税率不一样的明细,不能合并 await checkTaxTate(goodsList); // 填充行明细信息 sum = await fillingInformationGood(goodsList, sum); // 合并数量 sum.quantity = await mergeQuantity(goodsList, state.calculatingDigits); // 合并金额(不含税) sum.lineAmountExcludeTax = await mergeLineAmountExcludeTax(goodsList); // 合并金额(含税) sum.lineAmountIncludeTax = await mergeLineAmountIncludeTax(goodsList); // 计算单价(不含税) sum.priceExcludeTax = await calculatePriceExcludeTax(sum, state.calculatingDigits); // 计算单价(含税) sum.priceIncludeTax = await calculatePriceIncludeTax(sum, state.calculatingDigits); // 计算税额 sum.taxAmount = chain(bignumber(sum.lineAmountIncludeTax)).subtract(bignumber(sum.lineAmountExcludeTax)).done().toNumber() // 校验数据 是否数量和金额是否同号 await checkSameNumber(sum); const p = state.goodsListState.goodsList.indexOf(goodsList[0]); state.goodsListState.goodsList = state.goodsListState.goodsList.filter(e => selectedGoodIndex.indexOf(e.$index) < 0); state.goodsListState.goodsList.splice(p, 0, sum); state.goodsListState.goodsList = state.goodsListState.goodsList.filter(e => e.lineAmountExcludeTax !== 0); state.goodsListState.goodsMap = new Map(); state.goodsListState.goodsList.forEach(e => { state.goodsListState.goodsMap.set(e.$index, e) }); state.goodsListState.selectedGoodIndex = []; } catch (error: any) { showError(error) } } } /** 计算单价(含税) */ async function calculatePriceIncludeTax(sum: IGood, calculatingDigits?: number) { if (!sum.quantity) return undefined; const value = chain(bignumber(sum.lineAmountIncludeTax)).divide(bignumber(sum.quantity)).done().toNumber() return format15(value, calculatingDigits) || undefined; } /** 计算单价(不含税) */ async function calculatePriceExcludeTax(sum: IGood, calculatingDigits?: number) { if (!sum.quantity) return undefined; const value = chain(bignumber(sum.lineAmountExcludeTax)).divide(bignumber(sum.quantity)).done().toNumber(); return format15(value, calculatingDigits) || undefined; } /** 合并金额(含税) */ async function mergeLineAmountIncludeTax(goodsList: IGood[]) { let sum = chain(bignumber(0)); goodsList.forEach(e => { sum = sum.add(bignumber(e.lineAmountIncludeTax || 0)) }) return sum.done().toNumber(); } /** 合并金额(不含税) */ async function mergeLineAmountExcludeTax(goodsList: IGood[]) { let sum = chain(bignumber(0)); goodsList.forEach(e => { sum = sum.add(bignumber(e.lineAmountExcludeTax || 0)) }) return sum.done().toNumber(); } /** 合并数量 */ async function mergeQuantity(goodsList: IGood[], calculatingDigits?: number) { let sum = chain(bignumber(0)); goodsList.forEach(e => { sum = sum.add(bignumber(e.quantity || 0)) }) return sum.done().toNumber() ? format15(sum.done().toNumber() || 0, calculatingDigits) as any : undefined } /** 填充行明细信息 */ async function fillingInformationGood(goodsList: IGood[], sum: IGood) { sum = { ...sum }; const goods = goodsList[findMaxIndex(goodsList.map(e => e.lineAmountIncludeTax || 0))] return { ...goods, lineAttribute: sum.lineAttribute }; } /** 存在税率不一样的明细,不能合并 */ async function checkTaxTate(goodsList: IGood[]) { const tax = goodsList[0].taxRate; for (let i = 1; i < goodsList.length; i++) { if (tax !== goodsList[i].taxRate) { throw new Error('存在税率不一样的明细,不能合并'); } } } /** 校验数据 是否数量和金额是否同号 */ async function checkSameNumber(good: IGood) { if (!good.quantity) return; if (!good.lineAmountExcludeTax && good.lineAmountExcludeTax !== 0) { const content = '金额不能为空'; message.error({ content, key: content }); throw new Error(content); } if ( good.quantity >= 0 && good.lineAmountExcludeTax >= 0 || good.lineAmountExcludeTax === 0 || good.quantity < 0 && good.lineAmountExcludeTax < 0 ) { return; } else { const content = '合并失败,合并后“数量”和“金额”必须同时为正数或同时为负数。'; message.error({ content, key: content }); throw new Error(content); } } /** 显示错误信息 */ function showError(error: Error) { console.log(error); message.error({ content: error.message, key: error.message }); } /** 查询最大数据的索引 */ function findMaxIndex(arr: number[]): number { if (arr.length === 0) { throw new Error("数组为空"); } let maxIndex = 0; let maxValue = arr[0]; for (let i = arr.length - 1; i >= 0; i--) { if (arr[i] > maxValue) { maxValue = arr[i]; maxIndex = i; } } return maxIndex; }