Commit 60226f1594559ffdd5fd714f4109f0bd497098cc
1 parent
03c75022
修改调价调拨单
Showing
13 changed files
with
953 additions
and
71 deletions
Antis.Erp.Plat/antis-ncc-admin/src/views/wtBjdbd/Form.vue
| 1 | -<template> | 1 | +<template> |
| 2 | <el-dialog :title="!dataForm.id ? '新建' : isDetail ? '详情':'编辑'" :close-on-click-modal="false" :visible.sync="visible" class="NCC-dialog NCC-dialog_center" lock-scroll width="80%"> | 2 | <el-dialog :title="!dataForm.id ? '新建' : isDetail ? '详情':'编辑'" :close-on-click-modal="false" :visible.sync="visible" class="NCC-dialog NCC-dialog_center" lock-scroll width="80%"> |
| 3 | <el-row :gutter="15" class="" > | 3 | <el-row :gutter="15" class="" > |
| 4 | <el-form ref="elForm" :model="dataForm" size="small" label-width="100px" label-position="right" :disabled="!!isDetail" :rules="rules"> | 4 | <el-form ref="elForm" :model="dataForm" size="small" label-width="100px" label-position="right" :disabled="!!isDetail" :rules="rules"> |
| @@ -41,11 +41,16 @@ | @@ -41,11 +41,16 @@ | ||
| 41 | </el-col> | 41 | </el-col> |
| 42 | <el-col :span="12"> | 42 | <el-col :span="12"> |
| 43 | <el-form-item label="变价系数%" prop="bjsx"> | 43 | <el-form-item label="变价系数%" prop="bjsx"> |
| 44 | - <el-input v-model="dataForm.bjsx" placeholder="请输入变价系数" clearable :style='{"width":"100%"}' @input="handlePriceAdjustmentChange"> | 44 | + <el-input v-model="dataForm.bjsx" placeholder="如 95 表示 95%" clearable :style='{"width":"100%"}' @input="handlePriceAdjustmentChange" @change="handlePriceAdjustmentChange"> |
| 45 | <template slot="append">%</template> | 45 | <template slot="append">%</template> |
| 46 | </el-input> | 46 | </el-input> |
| 47 | </el-form-item> | 47 | </el-form-item> |
| 48 | </el-col> | 48 | </el-col> |
| 49 | + <el-col :span="12"> | ||
| 50 | + <el-form-item label="变价成本合计"> | ||
| 51 | + <el-input :value="cbjeDisplay" placeholder="保存后由系统按变价后金额汇总" readonly :style='{"width":"100%"}' /> | ||
| 52 | + </el-form-item> | ||
| 53 | + </el-col> | ||
| 49 | <el-col :span="12" v-if="false"> | 54 | <el-col :span="12" v-if="false"> |
| 50 | <el-form-item label="供应商" prop="gys"> | 55 | <el-form-item label="供应商" prop="gys"> |
| 51 | <el-select v-model="dataForm.gys" placeholder="请选择" clearable :style='{"width":"100%"}' filterable > | 56 | <el-select v-model="dataForm.gys" placeholder="请选择" clearable :style='{"width":"100%"}' filterable > |
| @@ -134,17 +139,18 @@ | @@ -134,17 +139,18 @@ | ||
| 134 | ></el-input> | 139 | ></el-input> |
| 135 | </template> | 140 | </template> |
| 136 | </el-table-column> | 141 | </el-table-column> |
| 137 | - <el-table-column prop="dj" label="成本单价"> | 142 | + <el-table-column prop="dj" label="成本单价" width="110"> |
| 138 | <template slot-scope="scope"> | 143 | <template slot-scope="scope"> |
| 139 | <el-input | 144 | <el-input |
| 140 | v-model="scope.row.dj" | 145 | v-model="scope.row.dj" |
| 141 | - placeholder="请输入" | 146 | + placeholder="参考成本,过账以服务端为准" |
| 142 | clearable | 147 | clearable |
| 148 | + :readonly="!!isDetail" | ||
| 143 | @input="handleAmountChange(scope.row)" | 149 | @input="handleAmountChange(scope.row)" |
| 144 | ></el-input> | 150 | ></el-input> |
| 145 | </template> | 151 | </template> |
| 146 | </el-table-column> | 152 | </el-table-column> |
| 147 | - <el-table-column prop="bjhcb" label="变价后成本" width="120"> | 153 | + <el-table-column prop="bjhcb" label="变价后单价" width="120"> |
| 148 | <template slot-scope="scope"> | 154 | <template slot-scope="scope"> |
| 149 | <el-input | 155 | <el-input |
| 150 | v-model="scope.row.bjhcb" | 156 | v-model="scope.row.bjhcb" |
| @@ -155,6 +161,11 @@ | @@ -155,6 +161,11 @@ | ||
| 155 | ></el-input> | 161 | ></el-input> |
| 156 | </template> | 162 | </template> |
| 157 | </el-table-column> | 163 | </el-table-column> |
| 164 | + <el-table-column prop="cbje" label="变价后金额" width="100" show-overflow-tooltip> | ||
| 165 | + <template slot-scope="scope"> | ||
| 166 | + <span>{{ formatMxCbje(scope.row) }}</span> | ||
| 167 | + </template> | ||
| 168 | + </el-table-column> | ||
| 158 | <el-table-column prop="je" label="销售总额" v-if="false"> | 169 | <el-table-column prop="je" label="销售总额" v-if="false"> |
| 159 | <template slot-scope="scope"> | 170 | <template slot-scope="scope"> |
| 160 | <el-input v-model="scope.row.je" placeholder="请输入" clearable readonly></el-input> | 171 | <el-input v-model="scope.row.je" placeholder="请输入" clearable readonly></el-input> |
| @@ -300,6 +311,7 @@ | @@ -300,6 +311,7 @@ | ||
| 300 | kh:undefined, | 311 | kh:undefined, |
| 301 | gys:undefined, | 312 | gys:undefined, |
| 302 | bjsx:undefined, // 变价系数% | 313 | bjsx:undefined, // 变价系数% |
| 314 | + cbje: undefined, // 主表变价成本合计(服务端汇总) | ||
| 303 | wtXsckdMxList:[], | 315 | wtXsckdMxList:[], |
| 304 | ysje:undefined, | 316 | ysje:undefined, |
| 305 | skzh:undefined, | 317 | skzh:undefined, |
| @@ -336,6 +348,12 @@ | @@ -336,6 +348,12 @@ | ||
| 336 | totalJe() { | 348 | totalJe() { |
| 337 | return (this.dataForm.wtXsckdMxList || []).reduce((sum, row) => sum + (parseFloat(row.je) || 0), 0) | 349 | return (this.dataForm.wtXsckdMxList || []).reduce((sum, row) => sum + (parseFloat(row.je) || 0), 0) |
| 338 | }, | 350 | }, |
| 351 | + cbjeDisplay() { | ||
| 352 | + const v = this.dataForm.cbje | ||
| 353 | + if (v == null || v === '') return '无' | ||
| 354 | + const n = Number(v) | ||
| 355 | + return isNaN(n) ? '无' : n.toFixed(2) | ||
| 356 | + }, | ||
| 339 | 357 | ||
| 340 | }, | 358 | }, |
| 341 | watch: { | 359 | watch: { |
| @@ -371,6 +389,11 @@ | @@ -371,6 +389,11 @@ | ||
| 371 | }, | 389 | }, |
| 372 | deep: true, | 390 | deep: true, |
| 373 | immediate: false | 391 | immediate: false |
| 392 | + }, | ||
| 393 | + 'dataForm.bjsx'() { | ||
| 394 | + this.$nextTick(() => { | ||
| 395 | + this.calculateAllAdjustedCosts(); | ||
| 396 | + }); | ||
| 374 | } | 397 | } |
| 375 | }, | 398 | }, |
| 376 | created() { | 399 | created() { |
| @@ -641,6 +664,88 @@ | @@ -641,6 +664,88 @@ | ||
| 641 | goBack() { | 664 | goBack() { |
| 642 | this.$emit('refresh') | 665 | this.$emit('refresh') |
| 643 | }, | 666 | }, |
| 667 | + /** 明细变价后金额:已过账用服务端 cbje;未过账用数量×变价后单价预览 */ | ||
| 668 | + formatMxCbje(row) { | ||
| 669 | + if (!row) return '无' | ||
| 670 | + if (row.cbje != null && row.cbje !== '') { | ||
| 671 | + const n = Number(row.cbje) | ||
| 672 | + return isNaN(n) ? '无' : n.toFixed(2) | ||
| 673 | + } | ||
| 674 | + const sl = parseInt(row.sl, 10) | ||
| 675 | + const bjh = parseFloat(row.bjhcb) | ||
| 676 | + if (sl > 0 && !isNaN(bjh) && bjh > 0) { | ||
| 677 | + return (sl * bjh).toFixed(2) | ||
| 678 | + } | ||
| 679 | + return '无' | ||
| 680 | + }, | ||
| 681 | + /** | ||
| 682 | + * 从 wt_sp_cost 拉取调出方成本单价并回填 dj,再算变价后单价 | ||
| 683 | + * @param {boolean} silent 无成本记录时不弹警告(避免刷屏) | ||
| 684 | + */ | ||
| 685 | + async applyOutboundCostPrice(row, silent = false) { | ||
| 686 | + if (!row || !row.spbh || !row.ckck) return | ||
| 687 | + try { | ||
| 688 | + const spbh = encodeURIComponent(String(row.spbh)) | ||
| 689 | + const ck = encodeURIComponent(String(row.ckck)) | ||
| 690 | + const res = await request({ | ||
| 691 | + url: `/api/Extend/WtXsckd/GetOutboundCostPrice?spbh=${spbh}&ckOrMdId=${ck}`, | ||
| 692 | + method: 'get' | ||
| 693 | + }) | ||
| 694 | + const payload = res.data | ||
| 695 | + if (payload && payload.success && payload.data != null) { | ||
| 696 | + const p = Number(payload.data) | ||
| 697 | + if (!isNaN(p) && p > 0) { | ||
| 698 | + this.$set(row, 'dj', p.toFixed(4)) | ||
| 699 | + this.calculateRowAdjustedCost(row) | ||
| 700 | + this.$forceUpdate() | ||
| 701 | + } | ||
| 702 | + } else if (!silent && payload && payload.msg) { | ||
| 703 | + this.$message.warning(payload.msg) | ||
| 704 | + } | ||
| 705 | + } catch (e) { | ||
| 706 | + if (!silent) console.error(e) | ||
| 707 | + } | ||
| 708 | + }, | ||
| 709 | + /** 组装提交体:变价系数转数值、显式 isDraft、去掉前端临时字段 */ | ||
| 710 | + buildPayload(isDraft) { | ||
| 711 | + const bjsxNum = parseFloat(this.dataForm.bjsx) | ||
| 712 | + const mx = (this.dataForm.wtXsckdMxList || []).map(r => { | ||
| 713 | + const { productQuery, spxlhLoaded, loadingStock, ...rest } = r | ||
| 714 | + return rest | ||
| 715 | + }) | ||
| 716 | + return { | ||
| 717 | + ...this.dataForm, | ||
| 718 | + bjsx: isNaN(bjsxNum) ? null : bjsxNum, | ||
| 719 | + isDraft: !!isDraft, | ||
| 720 | + djlx: '变价调拨单', | ||
| 721 | + // 正式保存一律待审核(含从草稿转正);草稿仅保存草稿 | ||
| 722 | + djzt: isDraft ? '草稿' : '待审核', | ||
| 723 | + wtXsckdMxList: mx | ||
| 724 | + } | ||
| 725 | + }, | ||
| 726 | + /** 正式保存前业务校验(草稿不走此函数) */ | ||
| 727 | + validateBjdFormalBasics() { | ||
| 728 | + if (!this.dataForm.cjck || !this.dataForm.rkck) | ||
| 729 | + return '请选择出库仓库与入库仓库' | ||
| 730 | + if (this.dataForm.cjck === this.dataForm.rkck) | ||
| 731 | + return '出库仓库与入库仓库不能相同' | ||
| 732 | + const coef = parseFloat(this.dataForm.bjsx) | ||
| 733 | + if (this.dataForm.bjsx === '' || this.dataForm.bjsx === undefined || isNaN(coef) || coef <= 0) | ||
| 734 | + return '请输入大于 0 的变价系数(%)' | ||
| 735 | + if (!this.dataForm.wtXsckdMxList || !this.dataForm.wtXsckdMxList.length) | ||
| 736 | + return '请添加至少一条明细' | ||
| 737 | + let hasSp = false | ||
| 738 | + for (let i = 0; i < this.dataForm.wtXsckdMxList.length; i++) { | ||
| 739 | + const row = this.dataForm.wtXsckdMxList[i] | ||
| 740 | + if (!row.spbh) continue | ||
| 741 | + hasSp = true | ||
| 742 | + const q = parseInt(row.sl, 10) | ||
| 743 | + if (!q || q <= 0) | ||
| 744 | + return `第${i + 1}行请填写有效数量或选择序列号` | ||
| 745 | + } | ||
| 746 | + if (!hasSp) return '请至少选择一条商品明细' | ||
| 747 | + return '' | ||
| 748 | + }, | ||
| 644 | init(id, isDetail) { | 749 | init(id, isDetail) { |
| 645 | var _this = this; | 750 | var _this = this; |
| 646 | console.log('id',id,'detail',isDetail) | 751 | console.log('id',id,'detail',isDetail) |
| @@ -666,6 +771,8 @@ | @@ -666,6 +771,8 @@ | ||
| 666 | _this.dataForm = res.data; | 771 | _this.dataForm = res.data; |
| 667 | console.log('编辑时加载的数据:', _this.dataForm); | 772 | console.log('编辑时加载的数据:', _this.dataForm); |
| 668 | console.log('明细数据:', _this.dataForm.wtXsckdMxList); | 773 | console.log('明细数据:', _this.dataForm.wtXsckdMxList); |
| 774 | + if (_this.dataForm.bjsx != null && _this.dataForm.bjsx !== '') | ||
| 775 | + _this.$set(_this.dataForm, 'bjsx', String(_this.dataForm.bjsx)) | ||
| 669 | 776 | ||
| 670 | // 为每个明细项添加productQuery字段 | 777 | // 为每个明细项添加productQuery字段 |
| 671 | if (_this.dataForm.wtXsckdMxList) { | 778 | if (_this.dataForm.wtXsckdMxList) { |
| @@ -673,6 +780,13 @@ | @@ -673,6 +780,13 @@ | ||
| 673 | if (!item.hasOwnProperty('productQuery')) { | 780 | if (!item.hasOwnProperty('productQuery')) { |
| 674 | _this.$set(item, 'productQuery', ''); | 781 | _this.$set(item, 'productQuery', ''); |
| 675 | } | 782 | } |
| 783 | + // 服务端过账快照成本 → 与「成本单价」展示一致 | ||
| 784 | + if (item.cbdj != null && item.cbdj !== '') { | ||
| 785 | + _this.$set(item, 'dj', Number(item.cbdj)) | ||
| 786 | + } | ||
| 787 | + if (item.bjhcb != null && item.bjhcb !== '') { | ||
| 788 | + _this.$set(item, 'bjhcb', Number(item.bjhcb).toFixed(4)) | ||
| 789 | + } | ||
| 676 | }); | 790 | }); |
| 677 | } | 791 | } |
| 678 | 792 | ||
| @@ -700,9 +814,7 @@ | @@ -700,9 +814,7 @@ | ||
| 700 | this.$refs['elForm'].validate(async (valid) => { | 814 | this.$refs['elForm'].validate(async (valid) => { |
| 701 | if (valid) { | 815 | if (valid) { |
| 702 | try { | 816 | try { |
| 703 | - // 标记为草稿 | ||
| 704 | - this.dataForm.djzt = '草稿'; | ||
| 705 | - const draftData = { ...this.dataForm, isDraft: true, djzt: '草稿' }; | 817 | + const draftData = this.buildPayload(true); |
| 706 | let res; | 818 | let res; |
| 707 | if (!this.dataForm.id) { | 819 | if (!this.dataForm.id) { |
| 708 | res = await request({ | 820 | res = await request({ |
| @@ -734,6 +846,11 @@ | @@ -734,6 +846,11 @@ | ||
| 734 | }); | 846 | }); |
| 735 | }, | 847 | }, |
| 736 | async dataFormSubmit() { | 848 | async dataFormSubmit() { |
| 849 | + const basicErr = this.validateBjdFormalBasics() | ||
| 850 | + if (basicErr) { | ||
| 851 | + this.$message.error(basicErr) | ||
| 852 | + return | ||
| 853 | + } | ||
| 737 | // 1. 明细校验:序列号数量与销售数量一致性 | 854 | // 1. 明细校验:序列号数量与销售数量一致性 |
| 738 | let validationErrors = []; | 855 | let validationErrors = []; |
| 739 | for (let i = 0; i < this.dataForm.wtXsckdMxList.length; i++) { | 856 | for (let i = 0; i < this.dataForm.wtXsckdMxList.length; i++) { |
| @@ -878,7 +995,7 @@ | @@ -878,7 +995,7 @@ | ||
| 878 | const res = await request({ | 995 | const res = await request({ |
| 879 | url: `/api/Extend/WtXsckd`, | 996 | url: `/api/Extend/WtXsckd`, |
| 880 | method: 'post', | 997 | method: 'post', |
| 881 | - data: this.dataForm, | 998 | + data: this.buildPayload(false), |
| 882 | }) | 999 | }) |
| 883 | 1000 | ||
| 884 | // 更新序列号状态 | 1001 | // 更新序列号状态 |
| @@ -891,7 +1008,7 @@ | @@ -891,7 +1008,7 @@ | ||
| 891 | const res = await request({ | 1008 | const res = await request({ |
| 892 | url: '/api/Extend/WtXsckd/' + this.dataForm.id, | 1009 | url: '/api/Extend/WtXsckd/' + this.dataForm.id, |
| 893 | method: 'PUT', | 1010 | method: 'PUT', |
| 894 | - data: this.dataForm | 1011 | + data: this.buildPayload(false) |
| 895 | }) | 1012 | }) |
| 896 | 1013 | ||
| 897 | // 更新序列号状态 | 1014 | // 更新序列号状态 |
| @@ -947,7 +1064,7 @@ | @@ -947,7 +1064,7 @@ | ||
| 947 | const res = await request({ | 1064 | const res = await request({ |
| 948 | url: `/api/Extend/WtXsckd`, | 1065 | url: `/api/Extend/WtXsckd`, |
| 949 | method: 'post', | 1066 | method: 'post', |
| 950 | - data: this.dataForm, | 1067 | + data: this.buildPayload(false), |
| 951 | }) | 1068 | }) |
| 952 | 1069 | ||
| 953 | // 更新序列号状态 | 1070 | // 更新序列号状态 |
| @@ -960,7 +1077,7 @@ | @@ -960,7 +1077,7 @@ | ||
| 960 | const res = await request({ | 1077 | const res = await request({ |
| 961 | url: '/api/Extend/WtXsckd/' + this.dataForm.id, | 1078 | url: '/api/Extend/WtXsckd/' + this.dataForm.id, |
| 962 | method: 'PUT', | 1079 | method: 'PUT', |
| 963 | - data: this.dataForm | 1080 | + data: this.buildPayload(false) |
| 964 | }) | 1081 | }) |
| 965 | 1082 | ||
| 966 | // 更新序列号状态 | 1083 | // 更新序列号状态 |
| @@ -1109,7 +1226,7 @@ | @@ -1109,7 +1226,7 @@ | ||
| 1109 | handleMainWarehouseChange(value) { | 1226 | handleMainWarehouseChange(value) { |
| 1110 | // 同步更新所有明细行的出库仓库 | 1227 | // 同步更新所有明细行的出库仓库 |
| 1111 | this.syncDetailWarehouses(); | 1228 | this.syncDetailWarehouses(); |
| 1112 | - // 更新所有明细行的库存 | 1229 | + // 更新所有明细行的库存与成本参考价 |
| 1113 | this.dataForm.wtXsckdMxList.forEach(row => { | 1230 | this.dataForm.wtXsckdMxList.forEach(row => { |
| 1114 | if (row.spbh) { | 1231 | if (row.spbh) { |
| 1115 | this.getStockQuantity(row); | 1232 | this.getStockQuantity(row); |
| @@ -1232,6 +1349,10 @@ | @@ -1232,6 +1349,10 @@ | ||
| 1232 | row.loadingStock = false; | 1349 | row.loadingStock = false; |
| 1233 | console.log('=== 库存查询完成 ==='); | 1350 | console.log('=== 库存查询完成 ==='); |
| 1234 | } | 1351 | } |
| 1352 | + // 无论库存接口是否成功,都尝试拉取成本单价(与过账取价一致) | ||
| 1353 | + if (row.spbh && row.ckck) { | ||
| 1354 | + await this.applyOutboundCostPrice(row, true); | ||
| 1355 | + } | ||
| 1235 | }, | 1356 | }, |
| 1236 | 1357 | ||
| 1237 | // 计算总金额 | 1358 | // 计算总金额 |
| @@ -1493,11 +1614,13 @@ | @@ -1493,11 +1614,13 @@ | ||
| 1493 | sums[index] = '合计'; | 1614 | sums[index] = '合计'; |
| 1494 | return; | 1615 | return; |
| 1495 | } | 1616 | } |
| 1496 | - if (['kucun', 'sl', 'je'].includes(column.property)) { | 1617 | + if (['kucun', 'sl', 'je', 'cbje', 'dj', 'bjhcb'].includes(column.property)) { |
| 1497 | sums[index] = data.reduce((total, row) => { | 1618 | sums[index] = data.reduce((total, row) => { |
| 1498 | const value = parseFloat(row[column.property]); | 1619 | const value = parseFloat(row[column.property]); |
| 1499 | return total + (isNaN(value) ? 0 : value); | 1620 | return total + (isNaN(value) ? 0 : value); |
| 1500 | }, 0); | 1621 | }, 0); |
| 1622 | + if (['cbje', 'dj', 'bjhcb'].includes(column.property) && sums[index] !== '') | ||
| 1623 | + sums[index] = Number(sums[index]).toFixed(2) | ||
| 1501 | } else { | 1624 | } else { |
| 1502 | sums[index] = ''; | 1625 | sums[index] = ''; |
| 1503 | } | 1626 | } |
| @@ -1509,7 +1632,7 @@ | @@ -1509,7 +1632,7 @@ | ||
| 1509 | const label = (option.label || '').toLowerCase(); | 1632 | const label = (option.label || '').toLowerCase(); |
| 1510 | return label.includes(query.toLowerCase()); | 1633 | return label.includes(query.toLowerCase()); |
| 1511 | }, | 1634 | }, |
| 1512 | - handleProductChange(row) { | 1635 | + async handleProductChange(row) { |
| 1513 | // 选中商品后可自动回填商品名称等信息 | 1636 | // 选中商品后可自动回填商品名称等信息 |
| 1514 | const product = this.spbhOptions.find(item => item.F_Id === row.spbh); | 1637 | const product = this.spbhOptions.find(item => item.F_Id === row.spbh); |
| 1515 | if (product) { | 1638 | if (product) { |
| @@ -1540,14 +1663,9 @@ | @@ -1540,14 +1663,9 @@ | ||
| 1540 | return; | 1663 | return; |
| 1541 | } | 1664 | } |
| 1542 | 1665 | ||
| 1543 | - // 如果已选择出库仓库,自动获取库存 | 1666 | + // 如果已选择出库仓库,自动获取库存(内部会再拉成本单价) |
| 1544 | console.log('开始获取库存...'); | 1667 | console.log('开始获取库存...'); |
| 1545 | - this.getStockQuantity(row); | ||
| 1546 | - | ||
| 1547 | - // 如果有变价系数,计算该行的变价后成本 | ||
| 1548 | - if (this.dataForm.bjsx && this.dataForm.bjsx !== '') { | ||
| 1549 | - this.calculateRowAdjustedCost(row); | ||
| 1550 | - } | 1668 | + await this.getStockQuantity(row); |
| 1551 | } | 1669 | } |
| 1552 | }, | 1670 | }, |
| 1553 | handleProductQuery(val, scope) { | 1671 | handleProductQuery(val, scope) { |
| @@ -1567,7 +1685,10 @@ | @@ -1567,7 +1685,10 @@ | ||
| 1567 | }, | 1685 | }, |
| 1568 | // 处理变价系数变化,重新计算所有明细的变价后成本 | 1686 | // 处理变价系数变化,重新计算所有明细的变价后成本 |
| 1569 | handlePriceAdjustmentChange() { | 1687 | handlePriceAdjustmentChange() { |
| 1570 | - this.calculateAllAdjustedCosts(); | 1688 | + this.$nextTick(() => { |
| 1689 | + this.calculateAllAdjustedCosts(); | ||
| 1690 | + this.$forceUpdate(); | ||
| 1691 | + }); | ||
| 1571 | }, | 1692 | }, |
| 1572 | 1693 | ||
| 1573 | // 计算所有明细的变价后成本 | 1694 | // 计算所有明细的变价后成本 |
| @@ -1575,7 +1696,7 @@ | @@ -1575,7 +1696,7 @@ | ||
| 1575 | if (!this.dataForm.bjsx || this.dataForm.bjsx === '') { | 1696 | if (!this.dataForm.bjsx || this.dataForm.bjsx === '') { |
| 1576 | // 如果没有输入变价系数,清空所有变价后成本 | 1697 | // 如果没有输入变价系数,清空所有变价后成本 |
| 1577 | this.dataForm.wtXsckdMxList.forEach(row => { | 1698 | this.dataForm.wtXsckdMxList.forEach(row => { |
| 1578 | - row.bjhcb = ''; | 1699 | + this.$set(row, 'bjhcb', ''); |
| 1579 | }); | 1700 | }); |
| 1580 | return; | 1701 | return; |
| 1581 | } | 1702 | } |
| @@ -1593,24 +1714,25 @@ | @@ -1593,24 +1714,25 @@ | ||
| 1593 | // 例如:成本100,系数95,则变价后成本 = 100 / (95/100) = 100 / 0.95 = 105.26 | 1714 | // 例如:成本100,系数95,则变价后成本 = 100 / (95/100) = 100 / 0.95 = 105.26 |
| 1594 | 1715 | ||
| 1595 | this.dataForm.wtXsckdMxList.forEach(row => { | 1716 | this.dataForm.wtXsckdMxList.forEach(row => { |
| 1596 | - if (row.dj && row.dj !== '') { | 1717 | + if (row.dj !== undefined && row.dj !== null && row.dj !== '') { |
| 1597 | const cost = parseFloat(row.dj); | 1718 | const cost = parseFloat(row.dj); |
| 1598 | if (!isNaN(cost) && cost > 0) { | 1719 | if (!isNaN(cost) && cost > 0) { |
| 1599 | const adjustedCost = cost / (coefficient / 100); | 1720 | const adjustedCost = cost / (coefficient / 100); |
| 1600 | - row.bjhcb = adjustedCost.toFixed(2); | 1721 | + this.$set(row, 'bjhcb', adjustedCost.toFixed(4)); |
| 1601 | } else { | 1722 | } else { |
| 1602 | - row.bjhcb = ''; | 1723 | + this.$set(row, 'bjhcb', ''); |
| 1603 | } | 1724 | } |
| 1604 | } else { | 1725 | } else { |
| 1605 | - row.bjhcb = ''; | 1726 | + this.$set(row, 'bjhcb', ''); |
| 1606 | } | 1727 | } |
| 1607 | }); | 1728 | }); |
| 1729 | + this.$forceUpdate(); | ||
| 1608 | }, | 1730 | }, |
| 1609 | 1731 | ||
| 1610 | // 计算单行的变价后成本 | 1732 | // 计算单行的变价后成本 |
| 1611 | calculateRowAdjustedCost(row) { | 1733 | calculateRowAdjustedCost(row) { |
| 1612 | if (!this.dataForm.bjsx || this.dataForm.bjsx === '' || !row.dj || row.dj === '') { | 1734 | if (!this.dataForm.bjsx || this.dataForm.bjsx === '' || !row.dj || row.dj === '') { |
| 1613 | - row.bjhcb = ''; | 1735 | + this.$set(row, 'bjhcb', ''); |
| 1614 | return; | 1736 | return; |
| 1615 | } | 1737 | } |
| 1616 | 1738 | ||
| @@ -1618,17 +1740,15 @@ | @@ -1618,17 +1740,15 @@ | ||
| 1618 | const cost = parseFloat(row.dj); | 1740 | const cost = parseFloat(row.dj); |
| 1619 | 1741 | ||
| 1620 | if (isNaN(coefficient) || isNaN(cost) || cost <= 0) { | 1742 | if (isNaN(coefficient) || isNaN(cost) || cost <= 0) { |
| 1621 | - row.bjhcb = ''; | 1743 | + this.$set(row, 'bjhcb', ''); |
| 1622 | return; | 1744 | return; |
| 1623 | } | 1745 | } |
| 1624 | 1746 | ||
| 1625 | // 按照公式计算:变价后成本 = 成本 / (系数/100) | 1747 | // 按照公式计算:变价后成本 = 成本 / (系数/100) |
| 1626 | // 例如:成本100,系数95,则变价后成本 = 100 / (95/100) = 100 / 0.95 = 105.26 | 1748 | // 例如:成本100,系数95,则变价后成本 = 100 / (95/100) = 100 / 0.95 = 105.26 |
| 1627 | const adjustedCost = cost / (coefficient / 100); | 1749 | const adjustedCost = cost / (coefficient / 100); |
| 1628 | - row.bjhcb = adjustedCost.toFixed(2); | ||
| 1629 | - }, | ||
| 1630 | - | ||
| 1631 | - // 处理变价系数变化,重新计算所有明细的变价后成本 | 1750 | + this.$set(row, 'bjhcb', adjustedCost.toFixed(4)); |
| 1751 | + } | ||
| 1632 | } | 1752 | } |
| 1633 | } | 1753 | } |
| 1634 | </script> | 1754 | </script> |
Antis.Erp.Plat/antis-ncc-admin/src/views/wtBjdbd/index.vue
| 1 | -<template> | 1 | +<template> |
| 2 | <div class="NCC-common-layout"> | 2 | <div class="NCC-common-layout"> |
| 3 | <div class="NCC-common-layout-center"> | 3 | <div class="NCC-common-layout-center"> |
| 4 | <el-row class="NCC-common-search-box" :gutter="16"> | 4 | <el-row class="NCC-common-search-box" :gutter="16"> |
| @@ -106,10 +106,30 @@ | @@ -106,10 +106,30 @@ | ||
| 106 | </div> | 106 | </div> |
| 107 | </div> | 107 | </div> |
| 108 | <NCC-table v-loading="listLoading" :data="list" has-c @selection-change="handleSelectionChange"> | 108 | <NCC-table v-loading="listLoading" :data="list" has-c @selection-change="handleSelectionChange"> |
| 109 | - <el-table-column prop="id" label="单据编号" align="left" /> | 109 | + <el-table-column prop="id" label="单据编号" align="left" width="160"> |
| 110 | + <template slot-scope="scope"> | ||
| 111 | + <i class="el-icon-document" style="color:#409EFF;margin-right:4px" /> | ||
| 112 | + {{ scope.row.id || '无' }} | ||
| 113 | + </template> | ||
| 114 | + </el-table-column> | ||
| 110 | <el-table-column prop="djrq" label="单据日期" align="left" :formatter="ncc.tableDateFormat" /> | 115 | <el-table-column prop="djrq" label="单据日期" align="left" :formatter="ncc.tableDateFormat" /> |
| 111 | - <el-table-column label="出库仓库" prop="cjck" align="left"> | ||
| 112 | - <template slot-scope="scope">{{ scope.row.cjck | dynamicText(cjckOptions) }}</template> | 116 | + <el-table-column label="出库仓库" prop="cjck" align="left" min-width="100" show-overflow-tooltip> |
| 117 | + <template slot-scope="scope"> | ||
| 118 | + <i class="el-icon-office-building" style="color:#909399;margin-right:4px" /> | ||
| 119 | + {{ scope.row.cjck | dynamicText(cjckOptions) }} | ||
| 120 | + </template> | ||
| 121 | + </el-table-column> | ||
| 122 | + <el-table-column prop="bjsx" label="变价系数%" align="right" width="100"> | ||
| 123 | + <template slot-scope="scope"> | ||
| 124 | + <i class="el-icon-sort" style="color:#E6A23C;margin-right:4px" /> | ||
| 125 | + {{ scope.row.bjsx != null && scope.row.bjsx !== '' ? scope.row.bjsx + '%' : '无' }} | ||
| 126 | + </template> | ||
| 127 | + </el-table-column> | ||
| 128 | + <el-table-column prop="cbje" label="变价成本合计" align="right" width="120"> | ||
| 129 | + <template slot-scope="scope"> | ||
| 130 | + <i class="el-icon-coin" style="color:#67C23A;margin-right:4px" /> | ||
| 131 | + {{ scope.row.cbje != null && scope.row.cbje !== '' ? scope.row.cbje : '无' }} | ||
| 132 | + </template> | ||
| 113 | </el-table-column> | 133 | </el-table-column> |
| 114 | <el-table-column prop="jsr" label="经手人" align="left" /> | 134 | <el-table-column prop="jsr" label="经手人" align="left" /> |
| 115 | <el-table-column prop="ysje" label="优惠金额" align="left" /> | 135 | <el-table-column prop="ysje" label="优惠金额" align="left" /> |
| @@ -122,7 +142,14 @@ | @@ -122,7 +142,14 @@ | ||
| 122 | <el-table-column prop="gzr" label="过账人" align="left" /> | 142 | <el-table-column prop="gzr" label="过账人" align="left" /> |
| 123 | <el-table-column prop="bz" label="备注" align="left" /> | 143 | <el-table-column prop="bz" label="备注" align="left" /> |
| 124 | <el-table-column prop="djlx" label="单据类型" align="left" /> | 144 | <el-table-column prop="djlx" label="单据类型" align="left" /> |
| 125 | - <el-table-column prop="djzt" label="单据状态" align="left" /> | 145 | + <el-table-column prop="djzt" label="单据状态" align="left" width="100"> |
| 146 | + <template slot-scope="scope"> | ||
| 147 | + <el-tag v-if="scope.row.djzt === '草稿'" type="info" size="mini">草稿</el-tag> | ||
| 148 | + <el-tag v-else-if="scope.row.djzt === '待审核'" type="warning" size="mini">待审核</el-tag> | ||
| 149 | + <el-tag v-else-if="scope.row.djzt === '已审核'" type="success" size="mini">已审核</el-tag> | ||
| 150 | + <el-tag v-else type="warning" size="mini">{{ scope.row.djzt || '无' }}</el-tag> | ||
| 151 | + </template> | ||
| 152 | + </el-table-column> | ||
| 126 | <el-table-column label="操作" fixed="right" width="100"> | 153 | <el-table-column label="操作" fixed="right" width="100"> |
| 127 | <template slot-scope="scope"> | 154 | <template slot-scope="scope"> |
| 128 | <el-button type="text" @click="addOrUpdateHandle(scope.row.id)" >编辑</el-button> | 155 | <el-button type="text" @click="addOrUpdateHandle(scope.row.id)" >编辑</el-button> |
| @@ -174,10 +201,12 @@ | @@ -174,10 +201,12 @@ | ||
| 174 | }, | 201 | }, |
| 175 | formVisible: false, | 202 | formVisible: false, |
| 176 | exportBoxVisible: false, | 203 | exportBoxVisible: false, |
| 177 | - columnList: [ | 204 | + columnList: [ |
| 178 | { prop: 'id', label: '单据编号' }, | 205 | { prop: 'id', label: '单据编号' }, |
| 179 | { prop: 'djrq', label: '单据日期' }, | 206 | { prop: 'djrq', label: '单据日期' }, |
| 180 | { prop: 'cjck', label: '出库仓库' }, | 207 | { prop: 'cjck', label: '出库仓库' }, |
| 208 | + { prop: 'bjsx', label: '变价系数%' }, | ||
| 209 | + { prop: 'cbje', label: '变价成本合计' }, | ||
| 181 | { prop: 'jsr', label: '经手人' }, | 210 | { prop: 'jsr', label: '经手人' }, |
| 182 | { prop: 'ysje', label: '优惠金额' }, | 211 | { prop: 'ysje', label: '优惠金额' }, |
| 183 | { prop: 'skzh', label: '收款账户' }, | 212 | { prop: 'skzh', label: '收款账户' }, |
| @@ -187,6 +216,7 @@ | @@ -187,6 +216,7 @@ | ||
| 187 | { prop: 'gzr', label: '过账人' }, | 216 | { prop: 'gzr', label: '过账人' }, |
| 188 | { prop: 'bz', label: '备注' }, | 217 | { prop: 'bz', label: '备注' }, |
| 189 | { prop: 'djlx', label: '单据类型' }, | 218 | { prop: 'djlx', label: '单据类型' }, |
| 219 | + { prop: 'djzt', label: '单据状态' }, | ||
| 190 | ], | 220 | ], |
| 191 | cjckOptions : [], | 221 | cjckOptions : [], |
| 192 | rkckOptions : [], | 222 | rkckOptions : [], |
| @@ -335,6 +365,7 @@ | @@ -335,6 +365,7 @@ | ||
| 335 | for (let key in this.query) { | 365 | for (let key in this.query) { |
| 336 | this.query[key] = undefined | 366 | this.query[key] = undefined |
| 337 | } | 367 | } |
| 368 | + this.query.djlx = '变价调拨单' | ||
| 338 | this.listQuery = { | 369 | this.listQuery = { |
| 339 | currentPage: 1, | 370 | currentPage: 1, |
| 340 | pageSize: 20, | 371 | pageSize: 20, |
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXsckd/Form.vue
| @@ -83,7 +83,7 @@ | @@ -83,7 +83,7 @@ | ||
| 83 | <el-option | 83 | <el-option |
| 84 | v-for="item in getFilteredSpbhOptions(scope.row.productQuery)" | 84 | v-for="item in getFilteredSpbhOptions(scope.row.productQuery)" |
| 85 | :key="item.F_Id" | 85 | :key="item.F_Id" |
| 86 | - :label="item.spbm + ' ' + (item.F_Spmc || '')" | 86 | + :label="getSpOptionLabel(item)" |
| 87 | :value="item.F_Id" | 87 | :value="item.F_Id" |
| 88 | /> | 88 | /> |
| 89 | </el-select> | 89 | </el-select> |
| @@ -147,6 +147,16 @@ | @@ -147,6 +147,16 @@ | ||
| 147 | <el-input v-model="scope.row.je" placeholder="请输入" clearable readonly></el-input> | 147 | <el-input v-model="scope.row.je" placeholder="请输入" clearable readonly></el-input> |
| 148 | </template> | 148 | </template> |
| 149 | </el-table-column> | 149 | </el-table-column> |
| 150 | + <el-table-column prop="cbdj" label="成本单价" width="100" align="right"> | ||
| 151 | + <template slot-scope="scope"> | ||
| 152 | + <span class="cost-cell">{{ formatCostCell(scope.row.cbdj) }}</span> | ||
| 153 | + </template> | ||
| 154 | + </el-table-column> | ||
| 155 | + <el-table-column prop="cbje" label="成本金额" width="100" align="right"> | ||
| 156 | + <template slot-scope="scope"> | ||
| 157 | + <span class="cost-cell">{{ formatCostCell(scope.row.cbje) }}</span> | ||
| 158 | + </template> | ||
| 159 | + </el-table-column> | ||
| 150 | <el-table-column prop="description" label="备注"> | 160 | <el-table-column prop="description" label="备注"> |
| 151 | <template slot-scope="scope"> | 161 | <template slot-scope="scope"> |
| 152 | <el-input v-model="scope.row.description" placeholder="请输入备注" clearable></el-input> | 162 | <el-input v-model="scope.row.description" placeholder="请输入备注" clearable></el-input> |
| @@ -218,6 +228,11 @@ | @@ -218,6 +228,11 @@ | ||
| 218 | </el-form-item> | 228 | </el-form-item> |
| 219 | </el-col> | 229 | </el-col> |
| 220 | <el-col :span="8"> | 230 | <el-col :span="8"> |
| 231 | + <el-form-item label="出库成本合计"> | ||
| 232 | + <el-input :value="displayOutboundCostTotalText" placeholder="按明细成本汇总" readonly :style='{"width":"100%"}' /> | ||
| 233 | + </el-form-item> | ||
| 234 | + </el-col> | ||
| 235 | + <el-col :span="8"> | ||
| 221 | <el-form-item label="收款金额" prop="skje"> | 236 | <el-form-item label="收款金额" prop="skje"> |
| 222 | <el-input v-model="dataForm.skje" placeholder="自动计算" clearable :style='{"width":"100%"}' readonly> | 237 | <el-input v-model="dataForm.skje" placeholder="自动计算" clearable :style='{"width":"100%"}' readonly> |
| 223 | </el-input> | 238 | </el-input> |
| @@ -295,6 +310,7 @@ | @@ -295,6 +310,7 @@ | ||
| 295 | id:'', | 310 | id:'', |
| 296 | djrq:undefined, | 311 | djrq:undefined, |
| 297 | cjck:undefined, | 312 | cjck:undefined, |
| 313 | + cjckId: undefined, | ||
| 298 | rkck:undefined, | 314 | rkck:undefined, |
| 299 | jsr:undefined, | 315 | jsr:undefined, |
| 300 | kh:undefined, | 316 | kh:undefined, |
| @@ -312,9 +328,12 @@ | @@ -312,9 +328,12 @@ | ||
| 312 | bz:undefined, | 328 | bz:undefined, |
| 313 | djlx:undefined, | 329 | djlx:undefined, |
| 314 | djzt: '', // 单据状态 | 330 | djzt: '', // 单据状态 |
| 331 | + cbje: undefined, // 主表出库成本合计(详情/已保存单据由后端返回) | ||
| 315 | }, | 332 | }, |
| 316 | rules: { | 333 | rules: { |
| 317 | }, | 334 | }, |
| 335 | + // 当前出库门店下各商品成本预览(下拉展示用,key=商品F_Id) | ||
| 336 | + productCostPreviewMap: {}, | ||
| 318 | cjckOptions : [], | 337 | cjckOptions : [], |
| 319 | rkckOptions : [], | 338 | rkckOptions : [], |
| 320 | khOptions : [], | 339 | khOptions : [], |
| @@ -338,6 +357,18 @@ | @@ -338,6 +357,18 @@ | ||
| 338 | totalJe() { | 357 | totalJe() { |
| 339 | return (this.dataForm.wtXsckdMxList || []).reduce((sum, row) => sum + (parseFloat(row.je) || 0), 0) | 358 | return (this.dataForm.wtXsckdMxList || []).reduce((sum, row) => sum + (parseFloat(row.je) || 0), 0) |
| 340 | }, | 359 | }, |
| 360 | + // 详情页优先用主表 cbje;新建/编辑按明细成本金额汇总 | ||
| 361 | + displayOutboundCostTotal() { | ||
| 362 | + if (this.isDetail && this.dataForm.cbje != null && this.dataForm.cbje !== '') { | ||
| 363 | + const m = parseFloat(this.dataForm.cbje) | ||
| 364 | + if (!isNaN(m)) return m | ||
| 365 | + } | ||
| 366 | + return (this.dataForm.wtXsckdMxList || []).reduce((s, r) => s + (parseFloat(r.cbje) || 0), 0) | ||
| 367 | + }, | ||
| 368 | + displayOutboundCostTotalText() { | ||
| 369 | + const v = this.displayOutboundCostTotal | ||
| 370 | + return (typeof v === 'number' && !isNaN(v)) ? v.toFixed(2) : '0.00' | ||
| 371 | + }, | ||
| 341 | 372 | ||
| 342 | }, | 373 | }, |
| 343 | watch: {}, | 374 | watch: {}, |
| @@ -633,6 +664,13 @@ | @@ -633,6 +664,13 @@ | ||
| 633 | method: 'get' | 664 | method: 'get' |
| 634 | }).then(res =>{ | 665 | }).then(res =>{ |
| 635 | _this.dataForm = res.data; | 666 | _this.dataForm = res.data; |
| 667 | + // 详情接口 cjck 可能为门店名称,下拉需绑定原始ID | ||
| 668 | + if (res.data.cjckId) { | ||
| 669 | + _this.dataForm.cjck = res.data.cjckId; | ||
| 670 | + _this.dataForm.cjckId = res.data.cjckId; | ||
| 671 | + } else if (res.data.cjck) { | ||
| 672 | + _this.dataForm.cjckId = res.data.cjck; | ||
| 673 | + } | ||
| 636 | console.log('编辑时加载的数据:', _this.dataForm); | 674 | console.log('编辑时加载的数据:', _this.dataForm); |
| 637 | console.log('明细数据:', _this.dataForm.wtXsckdMxList); | 675 | console.log('明细数据:', _this.dataForm.wtXsckdMxList); |
| 638 | 676 | ||
| @@ -672,6 +710,7 @@ | @@ -672,6 +710,7 @@ | ||
| 672 | _this.restoreSerialNumbers(); | 710 | _this.restoreSerialNumbers(); |
| 673 | // 编辑时自动获取所有明细行的账面库存 | 711 | // 编辑时自动获取所有明细行的账面库存 |
| 674 | _this.$nextTick(() => { | 712 | _this.$nextTick(() => { |
| 713 | + _this.loadProductCostPreviewMap(); | ||
| 675 | _this.dataForm.wtXsckdMxList.forEach(row => { | 714 | _this.dataForm.wtXsckdMxList.forEach(row => { |
| 676 | if (row.spbh && row.ckck) { | 715 | if (row.spbh && row.ckck) { |
| 677 | _this.getStockQuantity(row); | 716 | _this.getStockQuantity(row); |
| @@ -684,10 +723,14 @@ | @@ -684,10 +723,14 @@ | ||
| 684 | // 新建时加载默认选项设置 | 723 | // 新建时加载默认选项设置 |
| 685 | request({ url: '/api/Extend/WtMrsz', method: 'get' }).then(res => { | 724 | request({ url: '/api/Extend/WtMrsz', method: 'get' }).then(res => { |
| 686 | if (res.data) { | 725 | if (res.data) { |
| 687 | - if (res.data.mrck) _this.dataForm.cjck = res.data.mrck | 726 | + if (res.data.mrck) { |
| 727 | + _this.dataForm.cjck = res.data.mrck | ||
| 728 | + _this.dataForm.cjckId = res.data.mrck | ||
| 729 | + } | ||
| 688 | if (res.data.mrwldw) _this.dataForm.kh = res.data.mrwldw | 730 | if (res.data.mrwldw) _this.dataForm.kh = res.data.mrwldw |
| 689 | if (res.data.mrskzh) _this.dataForm.skzh = res.data.mrskzh | 731 | if (res.data.mrskzh) _this.dataForm.skzh = res.data.mrskzh |
| 690 | } | 732 | } |
| 733 | + _this.loadProductCostPreviewMap(); | ||
| 691 | }).catch(() => {}) | 734 | }).catch(() => {}) |
| 692 | } | 735 | } |
| 693 | }) | 736 | }) |
| @@ -1030,6 +1073,8 @@ | @@ -1030,6 +1073,8 @@ | ||
| 1030 | sl:undefined, | 1073 | sl:undefined, |
| 1031 | dj:undefined, | 1074 | dj:undefined, |
| 1032 | je:undefined, | 1075 | je:undefined, |
| 1076 | + cbdj: undefined, | ||
| 1077 | + cbje: undefined, | ||
| 1033 | selectedSerialNumbers: [], // 添加序列号数组 | 1078 | selectedSerialNumbers: [], // 添加序列号数组 |
| 1034 | loadingStock: false, // 库存加载状态 | 1079 | loadingStock: false, // 库存加载状态 |
| 1035 | productQuery: '', // 为每一行添加独立的查询条件 | 1080 | productQuery: '', // 为每一行添加独立的查询条件 |
| @@ -1050,7 +1095,10 @@ | @@ -1050,7 +1095,10 @@ | ||
| 1050 | this.currentBarcodeRow.sptm = barcodeData.barcode | 1095 | this.currentBarcodeRow.sptm = barcodeData.barcode |
| 1051 | this.currentBarcodeRow.spmc = barcodeData.productName | 1096 | this.currentBarcodeRow.spmc = barcodeData.productName |
| 1052 | this.currentBarcodeRow.spbh = barcodeData.productCode | 1097 | this.currentBarcodeRow.spbh = barcodeData.productCode |
| 1053 | - // 可根据需要回填其他字段 | 1098 | + if (!this.currentBarcodeRow.ckck && this.dataForm.cjck) { |
| 1099 | + this.currentBarcodeRow.ckck = this.dataForm.cjck | ||
| 1100 | + } | ||
| 1101 | + this.fetchRowCost(this.currentBarcodeRow) | ||
| 1054 | } | 1102 | } |
| 1055 | }, | 1103 | }, |
| 1056 | 1104 | ||
| @@ -1087,6 +1135,7 @@ | @@ -1087,6 +1135,7 @@ | ||
| 1087 | if (currentRow.dj) { | 1135 | if (currentRow.dj) { |
| 1088 | currentRow.je = (parseFloat(currentRow.sl) * parseFloat(currentRow.dj)).toFixed(2) | 1136 | currentRow.je = (parseFloat(currentRow.sl) * parseFloat(currentRow.dj)).toFixed(2) |
| 1089 | } | 1137 | } |
| 1138 | + this.updateRowCostAmount(currentRow) | ||
| 1090 | // 更新总收款金额 | 1139 | // 更新总收款金额 |
| 1091 | this.calculateTotalAmount(); | 1140 | this.calculateTotalAmount(); |
| 1092 | 1141 | ||
| @@ -1097,6 +1146,7 @@ | @@ -1097,6 +1146,7 @@ | ||
| 1097 | const sl = parseFloat(row.sl) || 0; | 1146 | const sl = parseFloat(row.sl) || 0; |
| 1098 | const dj = parseFloat(row.dj) || 0; | 1147 | const dj = parseFloat(row.dj) || 0; |
| 1099 | row.je = (sl * dj).toFixed(2); | 1148 | row.je = (sl * dj).toFixed(2); |
| 1149 | + this.updateRowCostAmount(row) | ||
| 1100 | // 自动计算总收款金额 | 1150 | // 自动计算总收款金额 |
| 1101 | this.calculateTotalAmount(); | 1151 | this.calculateTotalAmount(); |
| 1102 | // 检查数量与序列号数量是否一致 | 1152 | // 检查数量与序列号数量是否一致 |
| @@ -1113,12 +1163,17 @@ | @@ -1113,12 +1163,17 @@ | ||
| 1113 | 1163 | ||
| 1114 | // 处理主表出库仓库变化 | 1164 | // 处理主表出库仓库变化 |
| 1115 | handleMainWarehouseChange(value) { | 1165 | handleMainWarehouseChange(value) { |
| 1166 | + if (value != null && value !== '') { | ||
| 1167 | + this.dataForm.cjckId = value | ||
| 1168 | + } | ||
| 1116 | // 同步更新所有明细行的出库仓库 | 1169 | // 同步更新所有明细行的出库仓库 |
| 1117 | this.syncDetailWarehouses(); | 1170 | this.syncDetailWarehouses(); |
| 1118 | - // 更新所有明细行的库存 | 1171 | + this.loadProductCostPreviewMap() |
| 1172 | + // 更新所有明细行的库存与成本预览 | ||
| 1119 | this.dataForm.wtXsckdMxList.forEach(row => { | 1173 | this.dataForm.wtXsckdMxList.forEach(row => { |
| 1120 | if (row.spbh) { | 1174 | if (row.spbh) { |
| 1121 | this.getStockQuantity(row); | 1175 | this.getStockQuantity(row); |
| 1176 | + this.fetchRowCost(row); | ||
| 1122 | } | 1177 | } |
| 1123 | }); | 1178 | }); |
| 1124 | }, | 1179 | }, |
| @@ -1147,7 +1202,7 @@ | @@ -1147,7 +1202,7 @@ | ||
| 1147 | try { | 1202 | try { |
| 1148 | // 确保参数不为空且转换为字符串 | 1203 | // 确保参数不为空且转换为字符串 |
| 1149 | const productId = String(row.spbh || ''); | 1204 | const productId = String(row.spbh || ''); |
| 1150 | - const warehouseId = String(row.ckck || ''); | 1205 | + const warehouseId = String(row.ckck || this.dataForm.cjckId || this.dataForm.cjck || ''); |
| 1151 | 1206 | ||
| 1152 | // 构建URL参数 | 1207 | // 构建URL参数 |
| 1153 | const url = `/api/Extend/WtXsckd/GetStockQuantity?productId=${encodeURIComponent(productId)}&warehouseId=${encodeURIComponent(warehouseId)}`; | 1208 | const url = `/api/Extend/WtXsckd/GetStockQuantity?productId=${encodeURIComponent(productId)}&warehouseId=${encodeURIComponent(warehouseId)}`; |
| @@ -1487,11 +1542,12 @@ | @@ -1487,11 +1542,12 @@ | ||
| 1487 | sums[index] = '合计'; | 1542 | sums[index] = '合计'; |
| 1488 | return; | 1543 | return; |
| 1489 | } | 1544 | } |
| 1490 | - if (['kucun', 'sl', 'je'].includes(column.property)) { | ||
| 1491 | - sums[index] = data.reduce((total, row) => { | 1545 | + if (['kucun', 'sl', 'je', 'cbje'].includes(column.property)) { |
| 1546 | + const t = data.reduce((total, row) => { | ||
| 1492 | const value = parseFloat(row[column.property]); | 1547 | const value = parseFloat(row[column.property]); |
| 1493 | return total + (isNaN(value) ? 0 : value); | 1548 | return total + (isNaN(value) ? 0 : value); |
| 1494 | }, 0); | 1549 | }, 0); |
| 1550 | + sums[index] = (column.property === 'cbje' || column.property === 'je') ? t.toFixed(2) : t; | ||
| 1495 | } else { | 1551 | } else { |
| 1496 | sums[index] = ''; | 1552 | sums[index] = ''; |
| 1497 | } | 1553 | } |
| @@ -1503,7 +1559,93 @@ | @@ -1503,7 +1559,93 @@ | ||
| 1503 | const label = (option.label || '').toLowerCase(); | 1559 | const label = (option.label || '').toLowerCase(); |
| 1504 | return label.includes(query.toLowerCase()); | 1560 | return label.includes(query.toLowerCase()); |
| 1505 | }, | 1561 | }, |
| 1562 | + // 成本/库存接口使用的门店或仓库ID | ||
| 1563 | + costContextCk() { | ||
| 1564 | + if (this.dataForm.cjckId != null && this.dataForm.cjckId !== '') { | ||
| 1565 | + return this.dataForm.cjckId | ||
| 1566 | + } | ||
| 1567 | + return this.dataForm.cjck | ||
| 1568 | + }, | ||
| 1569 | + formatCostCell(val) { | ||
| 1570 | + if (val == null || val === '') return '无' | ||
| 1571 | + const n = parseFloat(val) | ||
| 1572 | + if (isNaN(n)) return '无' | ||
| 1573 | + return n.toFixed(2) | ||
| 1574 | + }, | ||
| 1575 | + getSpOptionLabel(item) { | ||
| 1576 | + const base = ((item.spbm || '') + ' ' + (item.F_Spmc || '')).trim() | ||
| 1577 | + const c = this.productCostPreviewMap[item.F_Id] | ||
| 1578 | + if (c != null && c !== '' && !isNaN(parseFloat(c))) { | ||
| 1579 | + return base + ' (成本¥' + parseFloat(c).toFixed(2) + ')' | ||
| 1580 | + } | ||
| 1581 | + if (!this.costContextCk()) { | ||
| 1582 | + return base + ' (选仓库后显示成本)' | ||
| 1583 | + } | ||
| 1584 | + return base | ||
| 1585 | + }, | ||
| 1586 | + async loadProductCostPreviewMap() { | ||
| 1587 | + const ck = this.costContextCk() | ||
| 1588 | + if (!ck) { | ||
| 1589 | + this.productCostPreviewMap = {} | ||
| 1590 | + return | ||
| 1591 | + } | ||
| 1592 | + try { | ||
| 1593 | + const res = await request({ | ||
| 1594 | + url: '/api/Extend/WtTjd/Actions/GetCostPreviewForStore', | ||
| 1595 | + method: 'get', | ||
| 1596 | + data: { ck } | ||
| 1597 | + }) | ||
| 1598 | + let items = res.data | ||
| 1599 | + if (items && items.items) items = items.items | ||
| 1600 | + else if (res.items) items = res.items | ||
| 1601 | + const map = {} | ||
| 1602 | + ;(Array.isArray(items) ? items : []).forEach(x => { | ||
| 1603 | + if (x && x.spbh != null && map[x.spbh] == null) { | ||
| 1604 | + map[x.spbh] = parseFloat(x.cbj) || 0 | ||
| 1605 | + } | ||
| 1606 | + }) | ||
| 1607 | + this.productCostPreviewMap = map | ||
| 1608 | + } catch (e) { | ||
| 1609 | + console.warn('loadProductCostPreviewMap failed', e) | ||
| 1610 | + this.productCostPreviewMap = {} | ||
| 1611 | + } | ||
| 1612 | + }, | ||
| 1613 | + async fetchRowCost(row) { | ||
| 1614 | + const ck = row.ckck || this.costContextCk() | ||
| 1615 | + if (!row.spbh || !ck) { | ||
| 1616 | + this.$set(row, 'cbdj', undefined) | ||
| 1617 | + this.$set(row, 'cbje', undefined) | ||
| 1618 | + return | ||
| 1619 | + } | ||
| 1620 | + try { | ||
| 1621 | + const res = await request({ | ||
| 1622 | + url: '/api/Extend/WtTjd/Actions/GetCost', | ||
| 1623 | + method: 'get', | ||
| 1624 | + data: { spbh: row.spbh, ck } | ||
| 1625 | + }) | ||
| 1626 | + let payload = res.data | ||
| 1627 | + if (payload && typeof payload.cbj === 'undefined' && res.data && res.data.data) { | ||
| 1628 | + payload = res.data.data | ||
| 1629 | + } | ||
| 1630 | + const cbj = parseFloat(payload && payload.cbj != null ? payload.cbj : 0) || 0 | ||
| 1631 | + this.$set(row, 'cbdj', cbj) | ||
| 1632 | + this.updateRowCostAmount(row) | ||
| 1633 | + } catch (e) { | ||
| 1634 | + this.$set(row, 'cbdj', 0) | ||
| 1635 | + this.updateRowCostAmount(row) | ||
| 1636 | + } | ||
| 1637 | + }, | ||
| 1638 | + updateRowCostAmount(row) { | ||
| 1639 | + const sl = parseFloat(row.sl) || 0 | ||
| 1640 | + const cbdj = parseFloat(row.cbdj) || 0 | ||
| 1641 | + this.$set(row, 'cbje', (cbdj * sl).toFixed(2)) | ||
| 1642 | + }, | ||
| 1506 | handleProductChange(row) { | 1643 | handleProductChange(row) { |
| 1644 | + if (!row.spbh) { | ||
| 1645 | + this.$set(row, 'cbdj', undefined) | ||
| 1646 | + this.$set(row, 'cbje', undefined) | ||
| 1647 | + return | ||
| 1648 | + } | ||
| 1507 | // 选中商品后可自动回填商品名称等信息 | 1649 | // 选中商品后可自动回填商品名称等信息 |
| 1508 | const product = this.spbhOptions.find(item => item.F_Id === row.spbh); | 1650 | const product = this.spbhOptions.find(item => item.F_Id === row.spbh); |
| 1509 | if (product) { | 1651 | if (product) { |
| @@ -1536,9 +1678,11 @@ | @@ -1536,9 +1678,11 @@ | ||
| 1536 | return; | 1678 | return; |
| 1537 | } | 1679 | } |
| 1538 | 1680 | ||
| 1539 | - // 如果已选择出库仓库,自动获取库存 | 1681 | + // 如果已选择出库仓库,自动获取库存与成本 |
| 1540 | console.log('开始获取库存...'); | 1682 | console.log('开始获取库存...'); |
| 1541 | - this.getStockQuantity(row); | 1683 | + this.getStockQuantity(row).finally(() => { |
| 1684 | + this.fetchRowCost(row) | ||
| 1685 | + }); | ||
| 1542 | } | 1686 | } |
| 1543 | }, | 1687 | }, |
| 1544 | handleProductQuery(val, scope) { | 1688 | handleProductQuery(val, scope) { |
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXsckd/index.vue
| @@ -127,6 +127,9 @@ | @@ -127,6 +127,9 @@ | ||
| 127 | <el-table-column label="优惠金额" align="left" min-width="90"> | 127 | <el-table-column label="优惠金额" align="left" min-width="90"> |
| 128 | <template slot-scope="scope">{{ getDisplayDiscountAmount(scope.row) }}</template> | 128 | <template slot-scope="scope">{{ getDisplayDiscountAmount(scope.row) }}</template> |
| 129 | </el-table-column> | 129 | </el-table-column> |
| 130 | + <el-table-column label="出库成本" align="left" min-width="90"> | ||
| 131 | + <template slot-scope="scope">{{ getDisplayOutboundCost(scope.row) }}</template> | ||
| 132 | + </el-table-column> | ||
| 130 | <el-table-column label="收款账户" prop="skzh" align="left"> | 133 | <el-table-column label="收款账户" prop="skzh" align="left"> |
| 131 | <template slot-scope="scope">{{ scope.row.skzh | dynamicText(skzhOptions) }}</template> | 134 | <template slot-scope="scope">{{ scope.row.skzh | dynamicText(skzhOptions) }}</template> |
| 132 | </el-table-column> | 135 | </el-table-column> |
| @@ -259,6 +262,11 @@ | @@ -259,6 +262,11 @@ | ||
| 259 | } | 262 | } |
| 260 | return (row.skje != null && row.skje !== '') ? parseFloat(row.skje).toFixed(2) : '0.00'; | 263 | return (row.skje != null && row.skje !== '') ? parseFloat(row.skje).toFixed(2) : '0.00'; |
| 261 | }, | 264 | }, |
| 265 | + // ✅ 出库成本:使用主表字段 cbje,空值按金额风格显示为 0.00 | ||
| 266 | + getDisplayOutboundCost(row) { | ||
| 267 | + const val = parseFloat(row.cbje); | ||
| 268 | + return isNaN(val) ? '0.00' : val.toFixed(2); | ||
| 269 | + }, | ||
| 262 | getcjckOptions(){ | 270 | getcjckOptions(){ |
| 263 | previewDataInterface('681758216954053893').then(res => { | 271 | previewDataInterface('681758216954053893').then(res => { |
| 264 | this.cjckOptions = res.data | 272 | this.cjckOptions = res.data |
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/WtXsckdCrInput.cs
| @@ -39,6 +39,21 @@ namespace NCC.Extend.Entitys.Dto.WtXsckd | @@ -39,6 +39,21 @@ namespace NCC.Extend.Entitys.Dto.WtXsckd | ||
| 39 | public decimal? ydje { get; set; } | 39 | public decimal? ydje { get; set; } |
| 40 | 40 | ||
| 41 | /// <summary> | 41 | /// <summary> |
| 42 | + /// 成本金额(主表汇总) | ||
| 43 | + /// </summary> | ||
| 44 | + public decimal? cbje { get; set; } | ||
| 45 | + | ||
| 46 | + /// <summary> | ||
| 47 | + /// 变价系数%(变价调拨单) | ||
| 48 | + /// </summary> | ||
| 49 | + public decimal? bjsx { get; set; } | ||
| 50 | + | ||
| 51 | + /// <summary> | ||
| 52 | + /// 是否草稿保存(草稿不触发变价调拨成本过账) | ||
| 53 | + /// </summary> | ||
| 54 | + public bool isDraft { get; set; } | ||
| 55 | + | ||
| 56 | + /// <summary> | ||
| 42 | /// 优惠金额 | 57 | /// 优惠金额 |
| 43 | /// </summary> | 58 | /// </summary> |
| 44 | public decimal ysje { get; set; } | 59 | public decimal ysje { get; set; } |
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/WtXsckdInfoOutput.cs
| @@ -24,6 +24,11 @@ namespace NCC.Extend.Entitys.Dto.WtXsckd | @@ -24,6 +24,11 @@ namespace NCC.Extend.Entitys.Dto.WtXsckd | ||
| 24 | public string cjck { get; set; } | 24 | public string cjck { get; set; } |
| 25 | 25 | ||
| 26 | /// <summary> | 26 | /// <summary> |
| 27 | + /// 出库仓库/门店原始ID(cjck 可能为展示名称,成本与库存接口请用此字段) | ||
| 28 | + /// </summary> | ||
| 29 | + public string cjckId { get; set; } | ||
| 30 | + | ||
| 31 | + /// <summary> | ||
| 27 | /// 入库仓库 | 32 | /// 入库仓库 |
| 28 | /// </summary> | 33 | /// </summary> |
| 29 | public string rkck { get; set; } | 34 | public string rkck { get; set; } |
| @@ -39,6 +44,16 @@ namespace NCC.Extend.Entitys.Dto.WtXsckd | @@ -39,6 +44,16 @@ namespace NCC.Extend.Entitys.Dto.WtXsckd | ||
| 39 | public decimal? ydje { get; set; } | 44 | public decimal? ydje { get; set; } |
| 40 | 45 | ||
| 41 | /// <summary> | 46 | /// <summary> |
| 47 | + /// 出库成本合计(主表汇总) | ||
| 48 | + /// </summary> | ||
| 49 | + public decimal? cbje { get; set; } | ||
| 50 | + | ||
| 51 | + /// <summary> | ||
| 52 | + /// 变价系数%(变价调拨单) | ||
| 53 | + /// </summary> | ||
| 54 | + public decimal? bjsx { get; set; } | ||
| 55 | + | ||
| 56 | + /// <summary> | ||
| 42 | /// 优惠金额 | 57 | /// 优惠金额 |
| 43 | /// </summary> | 58 | /// </summary> |
| 44 | public decimal ysje { get; set; } | 59 | public decimal ysje { get; set; } |
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/WtXsckdListOutput.cs
| @@ -33,6 +33,16 @@ namespace NCC.Extend.Entitys.Dto.WtXsckd | @@ -33,6 +33,16 @@ namespace NCC.Extend.Entitys.Dto.WtXsckd | ||
| 33 | public decimal? ydje { get; set; } | 33 | public decimal? ydje { get; set; } |
| 34 | 34 | ||
| 35 | /// <summary> | 35 | /// <summary> |
| 36 | + /// 成本金额(主表汇总) | ||
| 37 | + /// </summary> | ||
| 38 | + public decimal? cbje { get; set; } | ||
| 39 | + | ||
| 40 | + /// <summary> | ||
| 41 | + /// 变价系数%(变价调拨单) | ||
| 42 | + /// </summary> | ||
| 43 | + public decimal? bjsx { get; set; } | ||
| 44 | + | ||
| 45 | + /// <summary> | ||
| 36 | /// 优惠金额 | 46 | /// 优惠金额 |
| 37 | /// </summary> | 47 | /// </summary> |
| 38 | public decimal ysje { get; set; } | 48 | public decimal ysje { get; set; } |
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/WtXsckdMxCrInput.cs
| @@ -64,6 +64,11 @@ namespace NCC.Extend.Entitys.Dto.WtXsckd | @@ -64,6 +64,11 @@ namespace NCC.Extend.Entitys.Dto.WtXsckd | ||
| 64 | public decimal je { get; set; } | 64 | public decimal je { get; set; } |
| 65 | 65 | ||
| 66 | /// <summary> | 66 | /// <summary> |
| 67 | + /// 变价后成本单价(变价调拨单,服务端会按系数重算覆盖) | ||
| 68 | + /// </summary> | ||
| 69 | + public decimal? bjhcb { get; set; } | ||
| 70 | + | ||
| 71 | + /// <summary> | ||
| 67 | /// 单据类型 | 72 | /// 单据类型 |
| 68 | /// </summary> | 73 | /// </summary> |
| 69 | public string djlx { get; set; } | 74 | public string djlx { get; set; } |
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/WtXsckdMxInfoOutput.cs
| @@ -67,6 +67,22 @@ namespace NCC.Extend.Entitys.Dto.WtXsckd | @@ -67,6 +67,22 @@ namespace NCC.Extend.Entitys.Dto.WtXsckd | ||
| 67 | /// 金额 | 67 | /// 金额 |
| 68 | /// </summary> | 68 | /// </summary> |
| 69 | public decimal je { get; set; } | 69 | public decimal je { get; set; } |
| 70 | + | ||
| 71 | + /// <summary> | ||
| 72 | + /// 成本单价(出库快照) | ||
| 73 | + /// </summary> | ||
| 74 | + public decimal? cbdj { get; set; } | ||
| 75 | + | ||
| 76 | + /// <summary> | ||
| 77 | + /// 成本金额(出库快照) | ||
| 78 | + /// </summary> | ||
| 79 | + public decimal? cbje { get; set; } | ||
| 80 | + | ||
| 81 | + /// <summary> | ||
| 82 | + /// 变价后成本单价(变价调拨单) | ||
| 83 | + /// </summary> | ||
| 84 | + public decimal? bjhcb { get; set; } | ||
| 85 | + | ||
| 70 | /// <summary> | 86 | /// <summary> |
| 71 | /// 单据类型 | 87 | /// 单据类型 |
| 72 | /// </summary> | 88 | /// </summary> |
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/WtXsckdEntity.cs
| @@ -48,6 +48,18 @@ namespace NCC.Extend.Entitys | @@ -48,6 +48,18 @@ namespace NCC.Extend.Entitys | ||
| 48 | public decimal? Ydje { get; set; } | 48 | public decimal? Ydje { get; set; } |
| 49 | 49 | ||
| 50 | /// <summary> | 50 | /// <summary> |
| 51 | + /// 成本金额(主表汇总) | ||
| 52 | + /// </summary> | ||
| 53 | + [SugarColumn(ColumnName = "cbje", IsNullable = true)] | ||
| 54 | + public decimal? Cbje { get; set; } | ||
| 55 | + | ||
| 56 | + /// <summary> | ||
| 57 | + /// 变价系数%(变价调拨单:统一应用到所有明细,变价后单价=原成本/(系数/100)) | ||
| 58 | + /// </summary> | ||
| 59 | + [SugarColumn(ColumnName = "bjsx", IsNullable = true)] | ||
| 60 | + public decimal? Bjsx { get; set; } | ||
| 61 | + | ||
| 62 | + /// <summary> | ||
| 51 | /// 优惠金额 | 63 | /// 优惠金额 |
| 52 | /// </summary> | 64 | /// </summary> |
| 53 | [SugarColumn(ColumnName = "ysje")] | 65 | [SugarColumn(ColumnName = "ysje")] |
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/WtXsckdMxEntity.cs
| @@ -107,5 +107,11 @@ namespace NCC.Extend.Entitys | @@ -107,5 +107,11 @@ namespace NCC.Extend.Entitys | ||
| 107 | [SugarColumn(ColumnName = "cbje")] | 107 | [SugarColumn(ColumnName = "cbje")] |
| 108 | public decimal? Cbje { get; set; } | 108 | public decimal? Cbje { get; set; } |
| 109 | 109 | ||
| 110 | + /// <summary> | ||
| 111 | + /// 变价后成本单价(变价调拨单入库计价) | ||
| 112 | + /// </summary> | ||
| 113 | + [SugarColumn(ColumnName = "bjhcb", IsNullable = true)] | ||
| 114 | + public decimal? Bjhcb { get; set; } | ||
| 115 | + | ||
| 110 | } | 116 | } |
| 111 | } | 117 | } |
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend/WtTjdService.cs
| @@ -426,18 +426,79 @@ namespace NCC.Extend.WtTjd | @@ -426,18 +426,79 @@ namespace NCC.Extend.WtTjd | ||
| 426 | /// 查询指定商品在指定仓库的成本价 | 426 | /// 查询指定商品在指定仓库的成本价 |
| 427 | /// </summary> | 427 | /// </summary> |
| 428 | /// <param name="spbh">商品编号</param> | 428 | /// <param name="spbh">商品编号</param> |
| 429 | - /// <param name="ck">仓库ID</param> | ||
| 430 | - /// <returns>成本价</returns> | 429 | + /// <param name="ck">门店ID或仓库ID(与销售出库单主表 cjck / 明细 ckck 一致)</param> |
| 430 | + /// <returns>成本价与在库数量</returns> | ||
| 431 | [HttpGet("Actions/GetCost")] | 431 | [HttpGet("Actions/GetCost")] |
| 432 | public async Task<dynamic> GetCost([FromQuery] string spbh, [FromQuery] string ck) | 432 | public async Task<dynamic> GetCost([FromQuery] string spbh, [FromQuery] string ck) |
| 433 | { | 433 | { |
| 434 | if (string.IsNullOrEmpty(spbh) || string.IsNullOrEmpty(ck)) | 434 | if (string.IsNullOrEmpty(spbh) || string.IsNullOrEmpty(ck)) |
| 435 | - return new { cbj = 0m }; | 435 | + return new { cbj = 0m, sl = 0 }; |
| 436 | + | ||
| 437 | + var warehouseIds = await _db.Queryable<WtCkEntity>() | ||
| 438 | + .Where(c => c.Ssmd == ck || c.Id == ck) | ||
| 439 | + .Select(c => c.Id) | ||
| 440 | + .ToListAsync(); | ||
| 441 | + if (warehouseIds == null || warehouseIds.Count == 0) | ||
| 442 | + warehouseIds = new List<string> { ck }; | ||
| 443 | + | ||
| 444 | + var inClause = string.Join(",", warehouseIds.Select((_, i) => $"@ck{i}")); | ||
| 445 | + var parms = warehouseIds | ||
| 446 | + .Select((id, i) => new SugarParameter($"@ck{i}", id)) | ||
| 447 | + .Concat(new[] { new SugarParameter("@spbh", spbh) }) | ||
| 448 | + .ToArray(); | ||
| 449 | + | ||
| 450 | + var rows = await _db.Ado.SqlQueryAsync<dynamic>( | ||
| 451 | + $"SELECT cbj, sl FROM wt_sp_cost WHERE spbh = @spbh AND ck IN ({inClause}) AND cbj > 0 LIMIT 1", | ||
| 452 | + parms); | ||
| 453 | + | ||
| 454 | + if (rows != null && rows.Count > 0) | ||
| 455 | + { | ||
| 456 | + return new | ||
| 457 | + { | ||
| 458 | + cbj = Convert.ToDecimal(rows[0].cbj), | ||
| 459 | + sl = Convert.ToInt32(rows[0].sl) | ||
| 460 | + }; | ||
| 461 | + } | ||
| 462 | + | ||
| 463 | + return new { cbj = 0m, sl = 0 }; | ||
| 464 | + } | ||
| 465 | + | ||
| 466 | + /// <summary> | ||
| 467 | + /// 按出库门店/仓库批量查询成本价(用于销售出库单商品下拉展示,口径与 GetCost 一致) | ||
| 468 | + /// </summary> | ||
| 469 | + /// <param name="ck">门店ID或仓库ID</param> | ||
| 470 | + [HttpGet("Actions/GetCostPreviewForStore")] | ||
| 471 | + public async Task<dynamic> GetCostPreviewForStore([FromQuery] string ck) | ||
| 472 | + { | ||
| 473 | + if (string.IsNullOrEmpty(ck)) | ||
| 474 | + return new { items = Array.Empty<object>() }; | ||
| 475 | + | ||
| 476 | + var warehouseIds = await _db.Queryable<WtCkEntity>() | ||
| 477 | + .Where(c => c.Ssmd == ck || c.Id == ck) | ||
| 478 | + .Select(c => c.Id) | ||
| 479 | + .ToListAsync(); | ||
| 480 | + if (warehouseIds == null || warehouseIds.Count == 0) | ||
| 481 | + warehouseIds = new List<string> { ck }; | ||
| 436 | 482 | ||
| 437 | - var cost = await _db.Queryable<WtSpCostEntity>() | ||
| 438 | - .FirstAsync(c => c.Spbh == spbh && c.Ck == ck); | 483 | + var inClause = string.Join(",", warehouseIds.Select((_, i) => $"@ck{i}")); |
| 484 | + var parms = warehouseIds.Select((id, i) => new SugarParameter($"@ck{i}", id)).ToArray(); | ||
| 485 | + | ||
| 486 | + var rows = await _db.Ado.SqlQueryAsync<dynamic>( | ||
| 487 | + $"SELECT spbh, cbj FROM wt_sp_cost WHERE ck IN ({inClause}) AND cbj > 0", | ||
| 488 | + parms); | ||
| 489 | + | ||
| 490 | + var list = new List<object>(); | ||
| 491 | + var seen = new HashSet<string>(); | ||
| 492 | + foreach (var r in rows ?? new List<dynamic>()) | ||
| 493 | + { | ||
| 494 | + var spbh = r.spbh?.ToString(); | ||
| 495 | + if (string.IsNullOrEmpty(spbh) || seen.Contains(spbh)) | ||
| 496 | + continue; | ||
| 497 | + seen.Add(spbh); | ||
| 498 | + list.Add(new { spbh, cbj = Convert.ToDecimal(r.cbj) }); | ||
| 499 | + } | ||
| 439 | 500 | ||
| 440 | - return new { cbj = cost?.Cbj ?? 0m, sl = cost?.Sl ?? 0 }; | 501 | + return new { items = list }; |
| 441 | } | 502 | } |
| 442 | 503 | ||
| 443 | /// <summary> | 504 | /// <summary> |
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend/WtXsckdService.cs
| @@ -47,6 +47,9 @@ namespace NCC.Extend.WtXsckd | @@ -47,6 +47,9 @@ namespace NCC.Extend.WtXsckd | ||
| 47 | // 序列号生成信号量,确保线程安全 | 47 | // 序列号生成信号量,确保线程安全 |
| 48 | private static readonly SemaphoreSlim _serialNumberSemaphore = new SemaphoreSlim(1, 1); | 48 | private static readonly SemaphoreSlim _serialNumberSemaphore = new SemaphoreSlim(1, 1); |
| 49 | private static bool _ydjeColumnChecked; | 49 | private static bool _ydjeColumnChecked; |
| 50 | + private static bool _cbjeColumnChecked; | ||
| 51 | + private static bool _bjsxColumnChecked; | ||
| 52 | + private static bool _bjhcbColumnChecked; | ||
| 50 | 53 | ||
| 51 | /// <summary> | 54 | /// <summary> |
| 52 | /// 确保原价金额列存在(迁移) | 55 | /// 确保原价金额列存在(迁移) |
| @@ -74,6 +77,81 @@ namespace NCC.Extend.WtXsckd | @@ -74,6 +77,81 @@ namespace NCC.Extend.WtXsckd | ||
| 74 | } | 77 | } |
| 75 | 78 | ||
| 76 | /// <summary> | 79 | /// <summary> |
| 80 | + /// 确保成本金额列存在(迁移) | ||
| 81 | + /// </summary> | ||
| 82 | + private void EnsureCbjeColumn() | ||
| 83 | + { | ||
| 84 | + if (_cbjeColumnChecked) return; | ||
| 85 | + lock (typeof(WtXsckdService)) | ||
| 86 | + { | ||
| 87 | + if (_cbjeColumnChecked) return; | ||
| 88 | + try | ||
| 89 | + { | ||
| 90 | + if (!_db.DbMaintenance.IsAnyTable("wt_xsckd")) { _cbjeColumnChecked = true; return; } | ||
| 91 | + var columns = _db.DbMaintenance.GetColumnInfosByTableName("wt_xsckd"); | ||
| 92 | + var columnNames = columns.Select(c => c.DbColumnName.ToLower()).ToHashSet(); | ||
| 93 | + if (!columnNames.Contains("cbje")) | ||
| 94 | + { | ||
| 95 | + _db.Ado.ExecuteCommand("ALTER TABLE `wt_xsckd` ADD COLUMN `cbje` decimal(18,2) NULL COMMENT '成本金额'"); | ||
| 96 | + Console.WriteLine("✅ 已添加字段: cbje (成本金额)"); | ||
| 97 | + } | ||
| 98 | + } | ||
| 99 | + catch (Exception ex) { Console.WriteLine($"EnsureCbjeColumn: {ex.Message}"); } | ||
| 100 | + _cbjeColumnChecked = true; | ||
| 101 | + } | ||
| 102 | + } | ||
| 103 | + | ||
| 104 | + /// <summary> | ||
| 105 | + /// 确保变价系数列存在(变价调拨单主表) | ||
| 106 | + /// </summary> | ||
| 107 | + private void EnsureBjsxColumn() | ||
| 108 | + { | ||
| 109 | + if (_bjsxColumnChecked) return; | ||
| 110 | + lock (typeof(WtXsckdService)) | ||
| 111 | + { | ||
| 112 | + if (_bjsxColumnChecked) return; | ||
| 113 | + try | ||
| 114 | + { | ||
| 115 | + if (!_db.DbMaintenance.IsAnyTable("wt_xsckd")) { _bjsxColumnChecked = true; return; } | ||
| 116 | + var columns = _db.DbMaintenance.GetColumnInfosByTableName("wt_xsckd"); | ||
| 117 | + var columnNames = columns.Select(c => c.DbColumnName.ToLower()).ToHashSet(); | ||
| 118 | + if (!columnNames.Contains("bjsx")) | ||
| 119 | + { | ||
| 120 | + _db.Ado.ExecuteCommand("ALTER TABLE `wt_xsckd` ADD COLUMN `bjsx` decimal(18,4) NULL COMMENT '变价系数%'"); | ||
| 121 | + Console.WriteLine("✅ 已添加字段: bjsx (变价系数%)"); | ||
| 122 | + } | ||
| 123 | + } | ||
| 124 | + catch (Exception ex) { Console.WriteLine($"EnsureBjsxColumn: {ex.Message}"); } | ||
| 125 | + _bjsxColumnChecked = true; | ||
| 126 | + } | ||
| 127 | + } | ||
| 128 | + | ||
| 129 | + /// <summary> | ||
| 130 | + /// 确保变价后成本单价列存在(变价调拨单明细) | ||
| 131 | + /// </summary> | ||
| 132 | + private void EnsureBjhcbColumn() | ||
| 133 | + { | ||
| 134 | + if (_bjhcbColumnChecked) return; | ||
| 135 | + lock (typeof(WtXsckdService)) | ||
| 136 | + { | ||
| 137 | + if (_bjhcbColumnChecked) return; | ||
| 138 | + try | ||
| 139 | + { | ||
| 140 | + if (!_db.DbMaintenance.IsAnyTable("wt_xsckd_mx")) { _bjhcbColumnChecked = true; return; } | ||
| 141 | + var columns = _db.DbMaintenance.GetColumnInfosByTableName("wt_xsckd_mx"); | ||
| 142 | + var columnNames = columns.Select(c => c.DbColumnName.ToLower()).ToHashSet(); | ||
| 143 | + if (!columnNames.Contains("bjhcb")) | ||
| 144 | + { | ||
| 145 | + _db.Ado.ExecuteCommand("ALTER TABLE `wt_xsckd_mx` ADD COLUMN `bjhcb` decimal(18,4) NULL COMMENT '变价后成本单价'"); | ||
| 146 | + Console.WriteLine("✅ 已添加字段: bjhcb (变价后成本单价)"); | ||
| 147 | + } | ||
| 148 | + } | ||
| 149 | + catch (Exception ex) { Console.WriteLine($"EnsureBjhcbColumn: {ex.Message}"); } | ||
| 150 | + _bjhcbColumnChecked = true; | ||
| 151 | + } | ||
| 152 | + } | ||
| 153 | + | ||
| 154 | + /// <summary> | ||
| 77 | /// 初始化一个<see cref="WtXsckdService"/>类型的新实例 | 155 | /// 初始化一个<see cref="WtXsckdService"/>类型的新实例 |
| 78 | /// </summary> | 156 | /// </summary> |
| 79 | public WtXsckdService( | 157 | public WtXsckdService( |
| @@ -95,8 +173,11 @@ namespace NCC.Extend.WtXsckd | @@ -95,8 +173,11 @@ namespace NCC.Extend.WtXsckd | ||
| 95 | [HttpGet("{id}")] | 173 | [HttpGet("{id}")] |
| 96 | public async Task<dynamic> GetInfo(string id) | 174 | public async Task<dynamic> GetInfo(string id) |
| 97 | { | 175 | { |
| 176 | + EnsureBjsxColumn(); | ||
| 177 | + EnsureBjhcbColumn(); | ||
| 98 | var entity = await _db.Queryable<WtXsckdEntity>().FirstAsync(p => p.Id == id); | 178 | var entity = await _db.Queryable<WtXsckdEntity>().FirstAsync(p => p.Id == id); |
| 99 | var output = entity.Adapt<WtXsckdInfoOutput>(); | 179 | var output = entity.Adapt<WtXsckdInfoOutput>(); |
| 180 | + output.cjckId = entity.Cjck; | ||
| 100 | 181 | ||
| 101 | // ✅ 将出库仓库ID转换为门店名称 | 182 | // ✅ 将出库仓库ID转换为门店名称 |
| 102 | if (!string.IsNullOrEmpty(entity.Cjck)) | 183 | if (!string.IsNullOrEmpty(entity.Cjck)) |
| @@ -193,6 +274,8 @@ namespace NCC.Extend.WtXsckd | @@ -193,6 +274,8 @@ namespace NCC.Extend.WtXsckd | ||
| 193 | public async Task<dynamic> GetList([FromQuery] WtXsckdListQueryInput input) | 274 | public async Task<dynamic> GetList([FromQuery] WtXsckdListQueryInput input) |
| 194 | { | 275 | { |
| 195 | EnsureYdjeColumn(); | 276 | EnsureYdjeColumn(); |
| 277 | + EnsureCbjeColumn(); | ||
| 278 | + EnsureBjsxColumn(); | ||
| 196 | var sidx = input.sidx == null ? "id" : input.sidx; | 279 | var sidx = input.sidx == null ? "id" : input.sidx; |
| 197 | List<string> queryDjrq = input.djrq != null ? input.djrq.Split(',').ToObeject<List<string>>() : null; | 280 | List<string> queryDjrq = input.djrq != null ? input.djrq.Split(',').ToObeject<List<string>>() : null; |
| 198 | DateTime? startDjrq = queryDjrq != null ? Ext.GetDateTime(queryDjrq.First()) : null; | 281 | DateTime? startDjrq = queryDjrq != null ? Ext.GetDateTime(queryDjrq.First()) : null; |
| @@ -230,6 +313,8 @@ namespace NCC.Extend.WtXsckd | @@ -230,6 +313,8 @@ namespace NCC.Extend.WtXsckd | ||
| 230 | // jsr=xsckd.Jsr, | 313 | // jsr=xsckd.Jsr, |
| 231 | jsr = SqlFunc.Subqueryable<UserEntity>().Where(u => u.Id == xsckd.Jsr).Select(u => u.RealName), | 314 | jsr = SqlFunc.Subqueryable<UserEntity>().Where(u => u.Id == xsckd.Jsr).Select(u => u.RealName), |
| 232 | ydje = xsckd.Ydje, | 315 | ydje = xsckd.Ydje, |
| 316 | + cbje = xsckd.Cbje, | ||
| 317 | + bjsx = xsckd.Bjsx, | ||
| 233 | ysje = xsckd.Ysje, | 318 | ysje = xsckd.Ysje, |
| 234 | skzh = xsckd.Skzh, | 319 | skzh = xsckd.Skzh, |
| 235 | skje = xsckd.Skje, | 320 | skje = xsckd.Skje, |
| @@ -262,10 +347,15 @@ namespace NCC.Extend.WtXsckd | @@ -262,10 +347,15 @@ namespace NCC.Extend.WtXsckd | ||
| 262 | [AllowAnonymous] // 允许抖音物流系统匿名调用 | 347 | [AllowAnonymous] // 允许抖音物流系统匿名调用 |
| 263 | public async Task<dynamic> Create([FromBody] WtXsckdCrInput input) | 348 | public async Task<dynamic> Create([FromBody] WtXsckdCrInput input) |
| 264 | { | 349 | { |
| 350 | + EnsureCbjeColumn(); | ||
| 351 | + EnsureBjsxColumn(); | ||
| 352 | + EnsureBjhcbColumn(); | ||
| 265 | // 匿名访问时,userInfo可能为null,需要安全处理 | 353 | // 匿名访问时,userInfo可能为null,需要安全处理 |
| 266 | var userInfo = await _userManager.GetUserInfo(); | 354 | var userInfo = await _userManager.GetUserInfo(); |
| 267 | var entity = input.Adapt<WtXsckdEntity>(); | 355 | var entity = input.Adapt<WtXsckdEntity>(); |
| 268 | entity.Ydje = input.ydje; | 356 | entity.Ydje = input.ydje; |
| 357 | + entity.Cbje = input.cbje; | ||
| 358 | + entity.Bjsx = input.bjsx; | ||
| 269 | 359 | ||
| 270 | // 获取用户ID(匿名访问时为null或空字符串) | 360 | // 获取用户ID(匿名访问时为null或空字符串) |
| 271 | string? userId = null; | 361 | string? userId = null; |
| @@ -675,7 +765,9 @@ namespace NCC.Extend.WtXsckd | @@ -675,7 +765,9 @@ namespace NCC.Extend.WtXsckd | ||
| 675 | } | 765 | } |
| 676 | 766 | ||
| 677 | // ========== P4: 自动维护 wt_sp_cost 成本表 ========== | 767 | // ========== P4: 自动维护 wt_sp_cost 成本表 ========== |
| 678 | - await UpdateSpCostOnCreate(input.djlx, entity, wtXsckdMxEntityList); | 768 | + await UpdateSpCostOnCreate(input.djlx, entity, wtXsckdMxEntityList, input.isDraft); |
| 769 | + await RecalculateMainCbje(newEntity.Id, input.djlx, | ||
| 770 | + input.isDraft || string.Equals(entity.Djzt, "草稿", StringComparison.Ordinal)); | ||
| 679 | 771 | ||
| 680 | //关闭事务 | 772 | //关闭事务 |
| 681 | _db.CommitTran(); | 773 | _db.CommitTran(); |
| @@ -898,7 +990,7 @@ namespace NCC.Extend.WtXsckd | @@ -898,7 +990,7 @@ namespace NCC.Extend.WtXsckd | ||
| 898 | { | 990 | { |
| 899 | exportData = await this.GetNoPagingList(input); | 991 | exportData = await this.GetNoPagingList(input); |
| 900 | } | 992 | } |
| 901 | - List<ParamsModel> paramList = "[{\"value\":\"单据编号\",\"field\":\"id\"},{\"value\":\"单据日期\",\"field\":\"djrq\"},{\"value\":\"出库仓库\",\"field\":\"cjck\"},{\"value\":\"经手人\",\"field\":\"jsr\"},{\"value\":\"优惠金额\",\"field\":\"ysje\"},{\"value\":\"收款账户\",\"field\":\"skzh\"},{\"value\":\"收款金额\",\"field\":\"skje\"},{\"value\":\"制单人\",\"field\":\"zdr\"},{\"value\":\"审核人\",\"field\":\"shr\"},{\"value\":\"过账人\",\"field\":\"gzr\"},{\"value\":\"备注\",\"field\":\"bz\"},{\"value\":\"单据类型\",\"field\":\"djlx\"},]".ToList<ParamsModel>(); | 993 | + List<ParamsModel> paramList = "[{\"value\":\"单据编号\",\"field\":\"id\"},{\"value\":\"单据日期\",\"field\":\"djrq\"},{\"value\":\"出库仓库\",\"field\":\"cjck\"},{\"value\":\"变价系数%\",\"field\":\"bjsx\"},{\"value\":\"成本金额\",\"field\":\"cbje\"},{\"value\":\"经手人\",\"field\":\"jsr\"},{\"value\":\"优惠金额\",\"field\":\"ysje\"},{\"value\":\"收款账户\",\"field\":\"skzh\"},{\"value\":\"收款金额\",\"field\":\"skje\"},{\"value\":\"制单人\",\"field\":\"zdr\"},{\"value\":\"审核人\",\"field\":\"shr\"},{\"value\":\"过账人\",\"field\":\"gzr\"},{\"value\":\"备注\",\"field\":\"bz\"},{\"value\":\"单据类型\",\"field\":\"djlx\"},{\"value\":\"单据状态\",\"field\":\"djzt\"},]".ToList<ParamsModel>(); |
| 902 | ExcelConfig excelconfig = new ExcelConfig(); | 994 | ExcelConfig excelconfig = new ExcelConfig(); |
| 903 | excelconfig.FileName = "销售出库单.xls"; | 995 | excelconfig.FileName = "销售出库单.xls"; |
| 904 | excelconfig.HeadFont = "微软雅黑"; | 996 | excelconfig.HeadFont = "微软雅黑"; |
| @@ -968,7 +1060,13 @@ namespace NCC.Extend.WtXsckd | @@ -968,7 +1060,13 @@ namespace NCC.Extend.WtXsckd | ||
| 968 | [HttpPut("{id}")] | 1060 | [HttpPut("{id}")] |
| 969 | public async Task Update(string id, [FromBody] WtXsckdUpInput input) | 1061 | public async Task Update(string id, [FromBody] WtXsckdUpInput input) |
| 970 | { | 1062 | { |
| 1063 | + EnsureCbjeColumn(); | ||
| 1064 | + EnsureBjsxColumn(); | ||
| 1065 | + EnsureBjhcbColumn(); | ||
| 1066 | + var oldHeader = await _db.Queryable<WtXsckdEntity>().FirstAsync(p => p.Id == id); | ||
| 1067 | + var oldMxList = await _db.Queryable<WtXsckdMxEntity>().Where(u => u.Djbh == id).ToListAsync(); | ||
| 971 | var entity = input.Adapt<WtXsckdEntity>(); | 1068 | var entity = input.Adapt<WtXsckdEntity>(); |
| 1069 | + entity.Bjsx = input.bjsx; | ||
| 972 | 1070 | ||
| 973 | // ✅ 确保会员手机号码字段被正确映射和保存 | 1071 | // ✅ 确保会员手机号码字段被正确映射和保存 |
| 974 | entity.Hysjh = input.hysjh ?? ""; | 1072 | entity.Hysjh = input.hysjh ?? ""; |
| @@ -978,6 +1076,14 @@ namespace NCC.Extend.WtXsckd | @@ -978,6 +1076,14 @@ namespace NCC.Extend.WtXsckd | ||
| 978 | { | 1076 | { |
| 979 | //开启事务 | 1077 | //开启事务 |
| 980 | _db.BeginTran(); | 1078 | _db.BeginTran(); |
| 1079 | + | ||
| 1080 | + // 变价调拨单:编辑前先按库中旧单回滚成本,避免重复过账 | ||
| 1081 | + if (oldHeader.Djlx == "变价调拨单" | ||
| 1082 | + && !string.Equals(oldHeader.Djzt, "草稿", StringComparison.Ordinal) | ||
| 1083 | + && oldMxList.Count > 0) | ||
| 1084 | + { | ||
| 1085 | + await RollbackVariablePriceTransferCost(oldHeader, oldMxList); | ||
| 1086 | + } | ||
| 981 | 1087 | ||
| 982 | //更新销售出库单记录 | 1088 | //更新销售出库单记录 |
| 983 | await _db.Updateable(entity).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync(); | 1089 | await _db.Updateable(entity).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync(); |
| @@ -997,6 +1103,10 @@ namespace NCC.Extend.WtXsckd | @@ -997,6 +1103,10 @@ namespace NCC.Extend.WtXsckd | ||
| 997 | await _db.Insertable(wtXsckdMxEntityList).ExecuteCommandAsync(); | 1103 | await _db.Insertable(wtXsckdMxEntityList).ExecuteCommandAsync(); |
| 998 | } | 1104 | } |
| 999 | 1105 | ||
| 1106 | + await UpdateSpCostOnCreate(entity.Djlx, entity, wtXsckdMxEntityList, input.isDraft); | ||
| 1107 | + await RecalculateMainCbje(id, entity.Djlx, | ||
| 1108 | + input.isDraft || string.Equals(entity.Djzt, "草稿", StringComparison.Ordinal)); | ||
| 1109 | + | ||
| 1000 | // 自动生成导购提成记录 | 1110 | // 自动生成导购提成记录 |
| 1001 | if (entity.Djlx == "销售出库单") | 1111 | if (entity.Djlx == "销售出库单") |
| 1002 | { | 1112 | { |
| @@ -1286,6 +1396,53 @@ ORDER BY t.`商品编号`"; | @@ -1286,6 +1396,53 @@ ORDER BY t.`商品编号`"; | ||
| 1286 | } | 1396 | } |
| 1287 | } | 1397 | } |
| 1288 | 1398 | ||
| 1399 | + /// <summary> | ||
| 1400 | + /// 按商品与出库门店/仓库查询加权成本单价(与销售出库、变价调拨过账取价逻辑一致,供前端录入参考) | ||
| 1401 | + /// </summary> | ||
| 1402 | + /// <param name="spbh">商品主键 F_Id</param> | ||
| 1403 | + /// <param name="ckOrMdId">明细 ckck 或主表 cjck(可为门店ID或仓库ID)</param> | ||
| 1404 | + [HttpGet("GetOutboundCostPrice")] | ||
| 1405 | + public async Task<dynamic> GetOutboundCostPrice(string spbh, string ckOrMdId) | ||
| 1406 | + { | ||
| 1407 | + if (string.IsNullOrWhiteSpace(spbh) || string.IsNullOrWhiteSpace(ckOrMdId)) | ||
| 1408 | + { | ||
| 1409 | + return new { success = false, msg = "商品编号与仓库不能为空", data = (decimal?)null }; | ||
| 1410 | + } | ||
| 1411 | + | ||
| 1412 | + try | ||
| 1413 | + { | ||
| 1414 | + var warehouseIds = await _db.Queryable<WtCkEntity>() | ||
| 1415 | + .Where(c => c.Ssmd == ckOrMdId || c.Id == ckOrMdId) | ||
| 1416 | + .Select(c => c.Id) | ||
| 1417 | + .ToListAsync(); | ||
| 1418 | + if (warehouseIds == null || warehouseIds.Count == 0) | ||
| 1419 | + { | ||
| 1420 | + warehouseIds = new List<string> { ckOrMdId.Trim() }; | ||
| 1421 | + } | ||
| 1422 | + | ||
| 1423 | + var ps = new List<SugarParameter> { new SugarParameter("@spbh", spbh.Trim()) }; | ||
| 1424 | + for (var i = 0; i < warehouseIds.Count; i++) | ||
| 1425 | + ps.Add(new SugarParameter($"@ck{i}", warehouseIds[i])); | ||
| 1426 | + var inSql = string.Join(",", warehouseIds.Select((_, i) => $"@ck{i}")); | ||
| 1427 | + | ||
| 1428 | + var rows = await _db.Ado.SqlQueryAsync<decimal?>( | ||
| 1429 | + $"SELECT cbj FROM wt_sp_cost WHERE spbh = @spbh AND ck IN ({inSql}) AND cbj > 0 ORDER BY sl DESC LIMIT 1", | ||
| 1430 | + ps.ToArray()); | ||
| 1431 | + | ||
| 1432 | + var price = rows?.FirstOrDefault(); | ||
| 1433 | + if (price == null || price <= 0) | ||
| 1434 | + { | ||
| 1435 | + return new { success = false, msg = "未查询到成本单价,请先维护采购/入库成本", data = (decimal?)null }; | ||
| 1436 | + } | ||
| 1437 | + | ||
| 1438 | + return new { success = true, data = Math.Round(price.Value, 4), msg = "操作成功" }; | ||
| 1439 | + } | ||
| 1440 | + catch (Exception ex) | ||
| 1441 | + { | ||
| 1442 | + return new { success = false, msg = "查询成本失败: " + ex.Message, data = (decimal?)null }; | ||
| 1443 | + } | ||
| 1444 | + } | ||
| 1445 | + | ||
| 1289 | [HttpGet("GetSaleStatistics")] | 1446 | [HttpGet("GetSaleStatistics")] |
| 1290 | public async Task<dynamic> GetSaleStatistics() | 1447 | public async Task<dynamic> GetSaleStatistics() |
| 1291 | { | 1448 | { |
| @@ -2820,6 +2977,30 @@ ORDER BY t.`商品编号`;"; | @@ -2820,6 +2977,30 @@ ORDER BY t.`商品编号`;"; | ||
| 2820 | } | 2977 | } |
| 2821 | } | 2978 | } |
| 2822 | 2979 | ||
| 2980 | + /// <summary> | ||
| 2981 | + /// 销售/预售/变价调拨单重算并回写主表成本金额(变价调拨为明细变价后成本金额合计) | ||
| 2982 | + /// </summary> | ||
| 2983 | + /// <param name="skipForBjdDraft">变价调拨草稿时不回写主表 cbje(明细未过账)</param> | ||
| 2984 | + private async Task RecalculateMainCbje(string djbh, string djlx, bool skipForBjdDraft = false) | ||
| 2985 | + { | ||
| 2986 | + if (string.IsNullOrEmpty(djbh)) return; | ||
| 2987 | + if (djlx == "变价调拨单" && skipForBjdDraft) return; | ||
| 2988 | + if (djlx != "销售出库单" && djlx != "预售出库单" && djlx != "变价调拨单") return; | ||
| 2989 | + | ||
| 2990 | + decimal cbje = 0; | ||
| 2991 | + var result = await _db.Ado.SqlQueryAsync<decimal?>( | ||
| 2992 | + "SELECT IFNULL(SUM(IFNULL(cbje, 0)), 0) FROM wt_xsckd_mx WHERE djbh = @djbh", | ||
| 2993 | + new { djbh }); | ||
| 2994 | + if (result != null && result.Count > 0) | ||
| 2995 | + { | ||
| 2996 | + cbje = result[0] ?? 0; | ||
| 2997 | + } | ||
| 2998 | + | ||
| 2999 | + await _db.Ado.ExecuteCommandAsync( | ||
| 3000 | + "UPDATE wt_xsckd SET cbje = @cbje WHERE F_Id = @id", | ||
| 3001 | + new { cbje, id = djbh }); | ||
| 3002 | + } | ||
| 3003 | + | ||
| 2823 | #region P4: wt_sp_cost 成本表自动维护 | 3004 | #region P4: wt_sp_cost 成本表自动维护 |
| 2824 | 3005 | ||
| 2825 | /// <summary> | 3006 | /// <summary> |
| @@ -2880,10 +3061,29 @@ ORDER BY t.`商品编号`;"; | @@ -2880,10 +3061,29 @@ ORDER BY t.`商品编号`;"; | ||
| 2880 | /// 采购入库 → 审核通过后才更新(见 UpdateSpCostOnPurchaseApproval) | 3061 | /// 采购入库 → 审核通过后才更新(见 UpdateSpCostOnPurchaseApproval) |
| 2881 | /// 销售/预售出库 → 快照成本到明细 + 减少数量 | 3062 | /// 销售/预售出库 → 快照成本到明细 + 减少数量 |
| 2882 | /// 销售退货 → 恢复数量(成本不变) | 3063 | /// 销售退货 → 恢复数量(成本不变) |
| 3064 | + /// 变价调拨单 → 调出仓按原成本加权减少,调入仓按变价后单价加权增加(草稿/ isDraft 不过账) | ||
| 2883 | /// </summary> | 3065 | /// </summary> |
| 2884 | - private async Task UpdateSpCostOnCreate(string djlx, WtXsckdEntity entity, List<WtXsckdMxEntity> mxList) | 3066 | + private async Task UpdateSpCostOnCreate(string djlx, WtXsckdEntity entity, List<WtXsckdMxEntity> mxList, bool isDraft = false) |
| 2885 | { | 3067 | { |
| 2886 | if (mxList == null || mxList.Count == 0) return; | 3068 | if (mxList == null || mxList.Count == 0) return; |
| 3069 | + | ||
| 3070 | + if (djlx == "变价调拨单") | ||
| 3071 | + { | ||
| 3072 | + EnsureBjsxColumn(); | ||
| 3073 | + EnsureBjhcbColumn(); | ||
| 3074 | + if (isDraft || string.Equals(entity.Djzt, "草稿", StringComparison.Ordinal)) | ||
| 3075 | + return; | ||
| 3076 | + try | ||
| 3077 | + { | ||
| 3078 | + await ApplyVariablePriceTransferCost(entity, mxList); | ||
| 3079 | + } | ||
| 3080 | + catch (Exception ex) | ||
| 3081 | + { | ||
| 3082 | + Console.WriteLine($"变价调拨成本过账失败: {ex.Message}"); | ||
| 3083 | + throw; | ||
| 3084 | + } | ||
| 3085 | + return; | ||
| 3086 | + } | ||
| 2887 | 3087 | ||
| 2888 | try | 3088 | try |
| 2889 | { | 3089 | { |
| @@ -2891,17 +3091,22 @@ ORDER BY t.`商品编号`;"; | @@ -2891,17 +3091,22 @@ ORDER BY t.`商品编号`;"; | ||
| 2891 | { | 3091 | { |
| 2892 | var outStoreId = entity.Cjck; | 3092 | var outStoreId = entity.Cjck; |
| 2893 | if (string.IsNullOrEmpty(outStoreId)) return; | 3093 | if (string.IsNullOrEmpty(outStoreId)) return; |
| 2894 | - | ||
| 2895 | - var warehouseIds = await _db.Queryable<WtCkEntity>() | ||
| 2896 | - .Where(c => c.Ssmd == outStoreId) | ||
| 2897 | - .Select(c => c.Id) | ||
| 2898 | - .ToListAsync(); | ||
| 2899 | - if (warehouseIds == null || warehouseIds.Count == 0) return; | ||
| 2900 | - | 3094 | + |
| 2901 | foreach (var detail in mxList) | 3095 | foreach (var detail in mxList) |
| 2902 | { | 3096 | { |
| 2903 | if (string.IsNullOrEmpty(detail.Spbh)) continue; | 3097 | if (string.IsNullOrEmpty(detail.Spbh)) continue; |
| 2904 | if (!int.TryParse(detail.Sl, out int qty) || qty <= 0) continue; | 3098 | if (!int.TryParse(detail.Sl, out int qty) || qty <= 0) continue; |
| 3099 | + | ||
| 3100 | + // 兼容前端传门店ID或仓库ID:按明细仓库优先,其次主表出库仓库 | ||
| 3101 | + var detailStoreOrWarehouseId = !string.IsNullOrEmpty(detail.Ckck) ? detail.Ckck : outStoreId; | ||
| 3102 | + var warehouseIds = await _db.Queryable<WtCkEntity>() | ||
| 3103 | + .Where(c => c.Ssmd == detailStoreOrWarehouseId || c.Id == detailStoreOrWarehouseId) | ||
| 3104 | + .Select(c => c.Id) | ||
| 3105 | + .ToListAsync(); | ||
| 3106 | + if (warehouseIds == null || warehouseIds.Count == 0) | ||
| 3107 | + { | ||
| 3108 | + warehouseIds = new List<string> { detailStoreOrWarehouseId }; | ||
| 3109 | + } | ||
| 2905 | 3110 | ||
| 2906 | var costResult = await _db.Ado.SqlQueryAsync<decimal?>( | 3111 | var costResult = await _db.Ado.SqlQueryAsync<decimal?>( |
| 2907 | $"SELECT cbj FROM wt_sp_cost WHERE spbh = @spbh AND ck IN ({string.Join(",", warehouseIds.Select((_, i) => $"@ck{i}"))}) AND cbj > 0 LIMIT 1", | 3112 | $"SELECT cbj FROM wt_sp_cost WHERE spbh = @spbh AND ck IN ({string.Join(",", warehouseIds.Select((_, i) => $"@ck{i}"))}) AND cbj > 0 LIMIT 1", |
| @@ -2910,12 +3115,9 @@ ORDER BY t.`商品编号`;"; | @@ -2910,12 +3115,9 @@ ORDER BY t.`商品编号`;"; | ||
| 2910 | 3115 | ||
| 2911 | decimal costPrice = costResult?.FirstOrDefault() ?? 0; | 3116 | decimal costPrice = costResult?.FirstOrDefault() ?? 0; |
| 2912 | 3117 | ||
| 2913 | - if (costPrice > 0) | ||
| 2914 | - { | ||
| 2915 | - await _db.Ado.ExecuteCommandAsync( | ||
| 2916 | - "UPDATE wt_xsckd_mx SET cbdj = @cbdj, cbje = @cbje WHERE F_Id = @id", | ||
| 2917 | - new { cbdj = costPrice, cbje = Math.Round(costPrice * qty, 2), id = detail.Id }); | ||
| 2918 | - } | 3118 | + await _db.Ado.ExecuteCommandAsync( |
| 3119 | + "UPDATE wt_xsckd_mx SET cbdj = @cbdj, cbje = @cbje WHERE F_Id = @id", | ||
| 3120 | + new { cbdj = costPrice, cbje = Math.Round(costPrice * qty, 2), id = detail.Id }); | ||
| 2919 | 3121 | ||
| 2920 | foreach (var whId in warehouseIds) | 3122 | foreach (var whId in warehouseIds) |
| 2921 | { | 3123 | { |
| @@ -3209,6 +3411,243 @@ ORDER BY t.`商品编号`;"; | @@ -3209,6 +3411,243 @@ ORDER BY t.`商品编号`;"; | ||
| 3209 | } | 3411 | } |
| 3210 | } | 3412 | } |
| 3211 | } | 3413 | } |
| 3414 | + else if (djlx == "变价调拨单") | ||
| 3415 | + { | ||
| 3416 | + if (string.Equals(entity.Djzt, "草稿", StringComparison.Ordinal)) return; | ||
| 3417 | + EnsureBjsxColumn(); | ||
| 3418 | + EnsureBjhcbColumn(); | ||
| 3419 | + var mxList = await _db.Queryable<WtXsckdMxEntity>().Where(d => d.Djbh == id).ToListAsync(); | ||
| 3420 | + if (mxList.Count > 0) | ||
| 3421 | + await RollbackVariablePriceTransferCost(entity, mxList); | ||
| 3422 | + } | ||
| 3423 | + } | ||
| 3424 | + | ||
| 3425 | + /// <summary> | ||
| 3426 | + /// 将门店ID或仓库ID解析为仓库ID列表(与同价/销售成本逻辑一致) | ||
| 3427 | + /// </summary> | ||
| 3428 | + private async Task<List<string>> ResolveWarehouseIdListAsync(string storeOrWarehouseId) | ||
| 3429 | + { | ||
| 3430 | + if (string.IsNullOrEmpty(storeOrWarehouseId)) return new List<string>(); | ||
| 3431 | + var warehouseIds = await _db.Queryable<WtCkEntity>() | ||
| 3432 | + .Where(c => c.Ssmd == storeOrWarehouseId || c.Id == storeOrWarehouseId) | ||
| 3433 | + .Select(c => c.Id) | ||
| 3434 | + .ToListAsync(); | ||
| 3435 | + if (warehouseIds == null || warehouseIds.Count == 0) | ||
| 3436 | + warehouseIds = new List<string> { storeOrWarehouseId }; | ||
| 3437 | + return warehouseIds; | ||
| 3438 | + } | ||
| 3439 | + | ||
| 3440 | + /// <summary> | ||
| 3441 | + /// 变价后单价 = 原成本单价 / (系数% / 100),如 100 与 95% → 105.26 | ||
| 3442 | + /// </summary> | ||
| 3443 | + private static decimal ComputeVariableAdjustedUnitCost(decimal originalUnit, decimal bjsxPercent) | ||
| 3444 | + { | ||
| 3445 | + if (bjsxPercent <= 0) throw new Exception("变价系数必须大于0"); | ||
| 3446 | + return Math.Round(originalUnit / (bjsxPercent / 100m), 4); | ||
| 3447 | + } | ||
| 3448 | + | ||
| 3449 | + /// <summary> | ||
| 3450 | + /// 调出仓选取 wt_sp_cost 行:优先库存不少于数量且成本>0,否则取有库存且成本>0的第一条 | ||
| 3451 | + /// </summary> | ||
| 3452 | + private async Task<(string ck, decimal unitCost, int sl)> PickOutboundCostRowForTransferAsync(string spbh, List<string> outWarehouseIds, int qty) | ||
| 3453 | + { | ||
| 3454 | + if (outWarehouseIds == null || outWarehouseIds.Count == 0) | ||
| 3455 | + throw new Exception($"商品 {spbh} 未解析到调出仓库"); | ||
| 3456 | + | ||
| 3457 | + var ps = new List<SugarParameter> { new SugarParameter("@spbh", spbh) }; | ||
| 3458 | + for (var i = 0; i < outWarehouseIds.Count; i++) | ||
| 3459 | + ps.Add(new SugarParameter($"@ck{i}", outWarehouseIds[i])); | ||
| 3460 | + var inSql = string.Join(",", outWarehouseIds.Select((_, i) => $"@ck{i}")); | ||
| 3461 | + | ||
| 3462 | + var rows = await _db.Ado.SqlQueryAsync<dynamic>( | ||
| 3463 | + $"SELECT ck, cbj, sl FROM wt_sp_cost WHERE spbh = @spbh AND ck IN ({inSql}) ORDER BY sl DESC", | ||
| 3464 | + ps.ToArray()); | ||
| 3465 | + | ||
| 3466 | + if (rows == null || rows.Count == 0) | ||
| 3467 | + throw new Exception($"商品 {spbh} 在调出方无成本数据,请先维护采购/入库成本"); | ||
| 3468 | + | ||
| 3469 | + foreach (var r in rows) | ||
| 3470 | + { | ||
| 3471 | + int sl = Convert.ToInt32(r.sl); | ||
| 3472 | + decimal cbj = Convert.ToDecimal(r.cbj); | ||
| 3473 | + if (sl >= qty && cbj > 0) | ||
| 3474 | + return (r.ck.ToString(), cbj, sl); | ||
| 3475 | + } | ||
| 3476 | + foreach (var r in rows) | ||
| 3477 | + { | ||
| 3478 | + int sl = Convert.ToInt32(r.sl); | ||
| 3479 | + decimal cbj = Convert.ToDecimal(r.cbj); | ||
| 3480 | + if (sl > 0 && cbj > 0) | ||
| 3481 | + return (r.ck.ToString(), cbj, sl); | ||
| 3482 | + } | ||
| 3483 | + throw new Exception($"商品 {spbh} 在调出仓可用数量不足或成本为0,无法变价调拨"); | ||
| 3484 | + } | ||
| 3485 | + | ||
| 3486 | + /// <summary> | ||
| 3487 | + /// 回滚时按原成本加回调出仓:优先匹配与过账时快照成本单价一致的仓库行 | ||
| 3488 | + /// </summary> | ||
| 3489 | + private async Task<string> PickOutboundCkForRollbackAddAsync(string spbh, List<string> outWarehouseIds, decimal snapshotOriginalCbj, int qty) | ||
| 3490 | + { | ||
| 3491 | + if (outWarehouseIds == null || outWarehouseIds.Count == 0) | ||
| 3492 | + throw new Exception($"商品 {spbh} 未解析到调出仓库"); | ||
| 3493 | + var ps = new List<SugarParameter> { new SugarParameter("@spbh", spbh) }; | ||
| 3494 | + for (var i = 0; i < outWarehouseIds.Count; i++) | ||
| 3495 | + ps.Add(new SugarParameter($"@ck{i}", outWarehouseIds[i])); | ||
| 3496 | + var inSql = string.Join(",", outWarehouseIds.Select((_, i) => $"@ck{i}")); | ||
| 3497 | + var rows = await _db.Ado.SqlQueryAsync<dynamic>( | ||
| 3498 | + $"SELECT ck, cbj, sl FROM wt_sp_cost WHERE spbh = @spbh AND ck IN ({inSql}) ORDER BY sl ASC, cbj ASC", | ||
| 3499 | + ps.ToArray()); | ||
| 3500 | + if (rows != null && rows.Count > 0) | ||
| 3501 | + { | ||
| 3502 | + foreach (var r in rows) | ||
| 3503 | + { | ||
| 3504 | + decimal cbj = Convert.ToDecimal(r.cbj); | ||
| 3505 | + if (Math.Abs(cbj - snapshotOriginalCbj) < 0.02m) | ||
| 3506 | + return r.ck.ToString(); | ||
| 3507 | + } | ||
| 3508 | + } | ||
| 3509 | + try | ||
| 3510 | + { | ||
| 3511 | + var picked = await PickOutboundCostRowForTransferAsync(spbh, outWarehouseIds, Math.Max(1, qty)); | ||
| 3512 | + return picked.ck; | ||
| 3513 | + } | ||
| 3514 | + catch | ||
| 3515 | + { | ||
| 3516 | + return outWarehouseIds[0]; | ||
| 3517 | + } | ||
| 3518 | + } | ||
| 3519 | + | ||
| 3520 | + /// <summary> | ||
| 3521 | + /// 加权减少库存与成本(与采购退货扣减一致) | ||
| 3522 | + /// </summary> | ||
| 3523 | + private async Task SpCostWeightedRemoveAsync(string spbh, string ck, int qty, decimal unitPrice) | ||
| 3524 | + { | ||
| 3525 | + var existing = await _db.Ado.SqlQueryAsync<dynamic>( | ||
| 3526 | + "SELECT cbj, sl FROM wt_sp_cost WHERE spbh = @spbh AND ck = @ck LIMIT 1", | ||
| 3527 | + new { spbh, ck }); | ||
| 3528 | + if (existing == null || existing.Count == 0) | ||
| 3529 | + throw new Exception($"成本记录不存在: {spbh} 仓库 {ck}"); | ||
| 3530 | + decimal currentCbj = Convert.ToDecimal(existing[0].cbj); | ||
| 3531 | + int currentSl = Convert.ToInt32(existing[0].sl); | ||
| 3532 | + if (currentSl < qty) | ||
| 3533 | + throw new Exception($"库存不足: {spbh} 仓库 {ck} 当前{currentSl} 需要{qty}"); | ||
| 3534 | + int newSl = currentSl - qty; | ||
| 3535 | + decimal newCbj = 0; | ||
| 3536 | + if (newSl > 0) | ||
| 3537 | + newCbj = Math.Round((currentCbj * currentSl - unitPrice * qty) / newSl, 2); | ||
| 3538 | + await _db.Ado.ExecuteCommandAsync( | ||
| 3539 | + "UPDATE wt_sp_cost SET cbj = @cbj, sl = @sl, update_time = NOW() WHERE spbh = @spbh AND ck = @ck", | ||
| 3540 | + new { cbj = newCbj, sl = newSl, spbh, ck }); | ||
| 3541 | + } | ||
| 3542 | + | ||
| 3543 | + /// <summary> | ||
| 3544 | + /// 加权增加库存与成本(与采购入库增加一致) | ||
| 3545 | + /// </summary> | ||
| 3546 | + private async Task SpCostWeightedAddAsync(string spbh, string ck, int qty, decimal unitPrice) | ||
| 3547 | + { | ||
| 3548 | + var existing = await _db.Ado.SqlQueryAsync<dynamic>( | ||
| 3549 | + "SELECT cbj, sl FROM wt_sp_cost WHERE spbh = @spbh AND ck = @ck LIMIT 1", | ||
| 3550 | + new { spbh, ck }); | ||
| 3551 | + if (existing != null && existing.Count > 0) | ||
| 3552 | + { | ||
| 3553 | + decimal oldCbj = Convert.ToDecimal(existing[0].cbj); | ||
| 3554 | + int oldSl = Convert.ToInt32(existing[0].sl); | ||
| 3555 | + int newSl = oldSl + qty; | ||
| 3556 | + decimal newCbj = newSl > 0 | ||
| 3557 | + ? Math.Round((oldCbj * oldSl + unitPrice * qty) / newSl, 2) | ||
| 3558 | + : unitPrice; | ||
| 3559 | + await _db.Ado.ExecuteCommandAsync( | ||
| 3560 | + "UPDATE wt_sp_cost SET cbj = @cbj, sl = @sl, update_time = NOW() WHERE spbh = @spbh AND ck = @ck", | ||
| 3561 | + new { cbj = newCbj, sl = newSl, spbh, ck }); | ||
| 3562 | + } | ||
| 3563 | + else | ||
| 3564 | + { | ||
| 3565 | + var rowId = $"{spbh}_{ck}"; | ||
| 3566 | + await _db.Ado.ExecuteCommandAsync( | ||
| 3567 | + "INSERT INTO wt_sp_cost (F_Id, spbh, ck, cbj, sl, update_time) VALUES (@id, @spbh, @ck, @cbj, @sl, NOW())", | ||
| 3568 | + new { id = rowId, spbh, ck, cbj = unitPrice, sl = qty }); | ||
| 3569 | + } | ||
| 3570 | + } | ||
| 3571 | + | ||
| 3572 | + /// <summary> | ||
| 3573 | + /// 变价调拨单过账:调出按快照原成本扣减,调入按变价后单价增加,并回写明细 cbdj/bjhcb/cbje | ||
| 3574 | + /// </summary> | ||
| 3575 | + private async Task ApplyVariablePriceTransferCost(WtXsckdEntity entity, List<WtXsckdMxEntity> mxList) | ||
| 3576 | + { | ||
| 3577 | + if (string.Equals((entity.Cjck ?? "").Trim(), (entity.Rkck ?? "").Trim(), StringComparison.Ordinal)) | ||
| 3578 | + throw new Exception("变价调拨单出库仓与入库仓不能相同"); | ||
| 3579 | + var coef = entity.Bjsx ?? 0; | ||
| 3580 | + if (coef <= 0) | ||
| 3581 | + throw new Exception("变价系数必须大于0"); | ||
| 3582 | + | ||
| 3583 | + foreach (var detail in mxList) | ||
| 3584 | + { | ||
| 3585 | + if (string.IsNullOrEmpty(detail.Spbh)) continue; | ||
| 3586 | + if (!int.TryParse(detail.Sl, out int qty) || qty <= 0) continue; | ||
| 3587 | + | ||
| 3588 | + var outRef = !string.IsNullOrEmpty(detail.Ckck) ? detail.Ckck : entity.Cjck; | ||
| 3589 | + var inRef = !string.IsNullOrEmpty(detail.Rkck) ? detail.Rkck : entity.Rkck; | ||
| 3590 | + if (string.IsNullOrEmpty(outRef) || string.IsNullOrEmpty(inRef)) | ||
| 3591 | + throw new Exception($"商品 {detail.Spmc ?? detail.Spbh} 未指定完整的出库/入库仓库"); | ||
| 3592 | + | ||
| 3593 | + var outIds = await ResolveWarehouseIdListAsync(outRef); | ||
| 3594 | + var (outCk, originalUnit, _) = await PickOutboundCostRowForTransferAsync(detail.Spbh, outIds, qty); | ||
| 3595 | + var adjustedUnit = ComputeVariableAdjustedUnitCost(originalUnit, coef); | ||
| 3596 | + var inIds = await ResolveWarehouseIdListAsync(inRef); | ||
| 3597 | + if (inIds == null || inIds.Count == 0) | ||
| 3598 | + throw new Exception($"商品 {detail.Spbh} 未解析到入库仓库"); | ||
| 3599 | + var inCk = inIds[0]; | ||
| 3600 | + | ||
| 3601 | + await SpCostWeightedRemoveAsync(detail.Spbh, outCk, qty, originalUnit); | ||
| 3602 | + await SpCostWeightedAddAsync(detail.Spbh, inCk, qty, adjustedUnit); | ||
| 3603 | + | ||
| 3604 | + await _db.Ado.ExecuteCommandAsync( | ||
| 3605 | + "UPDATE wt_xsckd_mx SET cbdj = @cbdj, bjhcb = @bjhcb, cbje = @cbje WHERE F_Id = @id", | ||
| 3606 | + new | ||
| 3607 | + { | ||
| 3608 | + cbdj = originalUnit, | ||
| 3609 | + bjhcb = adjustedUnit, | ||
| 3610 | + cbje = Math.Round(adjustedUnit * qty, 2), | ||
| 3611 | + id = detail.Id | ||
| 3612 | + }); | ||
| 3613 | + } | ||
| 3614 | + } | ||
| 3615 | + | ||
| 3616 | + /// <summary> | ||
| 3617 | + /// 变价调拨单成本回滚:调入按变价后单价扣回,调出按原成本加回(删除/编辑前调用) | ||
| 3618 | + /// </summary> | ||
| 3619 | + private async Task RollbackVariablePriceTransferCost(WtXsckdEntity entity, List<WtXsckdMxEntity> mxList) | ||
| 3620 | + { | ||
| 3621 | + foreach (var detail in mxList) | ||
| 3622 | + { | ||
| 3623 | + if (string.IsNullOrEmpty(detail.Spbh)) continue; | ||
| 3624 | + if (!int.TryParse(detail.Sl, out int qty) || qty <= 0) continue; | ||
| 3625 | + | ||
| 3626 | + var outRef = !string.IsNullOrEmpty(detail.Ckck) ? detail.Ckck : entity.Cjck; | ||
| 3627 | + var inRef = !string.IsNullOrEmpty(detail.Rkck) ? detail.Rkck : entity.Rkck; | ||
| 3628 | + if (string.IsNullOrEmpty(outRef) || string.IsNullOrEmpty(inRef)) continue; | ||
| 3629 | + | ||
| 3630 | + decimal originalUnit = detail.Cbdj ?? detail.Dj; | ||
| 3631 | + if (originalUnit <= 0) continue; | ||
| 3632 | + | ||
| 3633 | + decimal adjustedUnit = 0; | ||
| 3634 | + if (detail.Bjhcb.HasValue && detail.Bjhcb.Value > 0) | ||
| 3635 | + adjustedUnit = detail.Bjhcb.Value; | ||
| 3636 | + else if (entity.Bjsx.HasValue && entity.Bjsx.Value > 0) | ||
| 3637 | + adjustedUnit = ComputeVariableAdjustedUnitCost(originalUnit, entity.Bjsx.Value); | ||
| 3638 | + if (adjustedUnit <= 0) continue; | ||
| 3639 | + | ||
| 3640 | + var inIds = await ResolveWarehouseIdListAsync(inRef); | ||
| 3641 | + var outIds = await ResolveWarehouseIdListAsync(outRef); | ||
| 3642 | + if (inIds == null || inIds.Count == 0 || outIds == null || outIds.Count == 0) continue; | ||
| 3643 | + var inCk = inIds[0]; | ||
| 3644 | + | ||
| 3645 | + // 调入仓按变价后单价扣减(与过账时增加互逆) | ||
| 3646 | + await SpCostWeightedRemoveAsync(detail.Spbh, inCk, qty, adjustedUnit); | ||
| 3647 | + | ||
| 3648 | + var outCk = await PickOutboundCkForRollbackAddAsync(detail.Spbh, outIds, originalUnit, qty); | ||
| 3649 | + await SpCostWeightedAddAsync(detail.Spbh, outCk, qty, originalUnit); | ||
| 3650 | + } | ||
| 3212 | } | 3651 | } |
| 3213 | 3652 | ||
| 3214 | #endregion | 3653 | #endregion |