feat: add pre/post-tax price linkage, hide barcode, and tablet adapt

Co-authored-by: aider (openai/DeepSeek-V3.2-Thinking) <aider@aider.chat>
This commit is contained in:
dxc
2026-02-27 15:44:10 +08:00
parent 4324e5a688
commit 3c1c822f88
4 changed files with 49 additions and 14 deletions

View File

@ -52,6 +52,7 @@ def filter_item_by_permissions(item_dict, user_permissions):
'inspection_status': 'inbound_buy:inspection_status',
'warehouse_location': 'inbound_buy:warehouse_location',
'unit_price': 'inbound_buy:unit_price',
'post_tax_unit_price': 'inbound_buy:post_tax_unit_price',
'tax_rate': 'inbound_buy:tax_rate',
'total_price': 'inbound_buy:total_price',
'currency': 'inbound_buy:currency',
@ -166,6 +167,7 @@ def submit():
'inspection_status': 'inbound_buy:inspection_status',
'warehouse_location': 'inbound_buy:warehouse_location',
'unit_price': 'inbound_buy:unit_price',
'post_tax_unit_price': 'inbound_buy:post_tax_unit_price',
'tax_rate': 'inbound_buy:tax_rate',
'total_price': 'inbound_buy:total_price',
'currency': 'inbound_buy:currency',
@ -230,6 +232,7 @@ def update_buy(id):
'inspection_status': 'inbound_buy:inspection_status',
'warehouse_location': 'inbound_buy:warehouse_location',
'unit_price': 'inbound_buy:unit_price',
'post_tax_unit_price': 'inbound_buy:post_tax_unit_price',
'tax_rate': 'inbound_buy:tax_rate',
'total_price': 'inbound_buy:total_price',
'currency': 'inbound_buy:currency',

View File

@ -34,6 +34,7 @@ class StockBuy(db.Model):
# 财务与商务
unit_price = db.Column(db.Numeric(19, 4), default=0) # 现意为:不含税单价
post_tax_unit_price = db.Column(db.Numeric(19, 4), default=0) # 税后单价
total_price = db.Column(db.Numeric(19, 4), default=0) # 总价
# [新增] 税率
tax_rate = db.Column(db.Numeric(5, 2), default=0)
@ -98,6 +99,7 @@ class StockBuy(db.Model):
'qty_available': float(self.available_quantity or 0),
'unit_price': float(self.unit_price or 0),
'post_tax_unit_price': float(self.post_tax_unit_price or 0),
'total_price': float(self.total_price or 0),
# [新增] 税率
'tax_rate': float(self.tax_rate or 0),

View File

@ -138,6 +138,7 @@ class BuyInboundService:
# 价格信息
unit_price=u_price,
post_tax_unit_price=float(data.get('post_tax_unit_price') or 0),
tax_rate=tax_rate, # [新增]
total_price=in_qty * u_price,
currency=data.get('currency', 'CNY'),
@ -184,6 +185,8 @@ class BuyInboundService:
# [新增] 更新税率
if 'tax_rate' in data: stock.tax_rate = float(data['tax_rate'])
# 更新税后单价
if 'post_tax_unit_price' in data: stock.post_tax_unit_price = float(data['post_tax_unit_price'])
if 'in_quantity' in data:
diff = float(data['in_quantity']) - float(stock.in_quantity)

View File

@ -1,7 +1,7 @@
<template>
<div class="buy-module">
<div class="header-container">
<div class="search-form-area">
<div class="header-container" style="flex-wrap: wrap;">
<div class="search-form-area" style="flex-wrap: wrap;">
<el-select
v-model="queryParams.company"
@ -197,7 +197,7 @@
<el-dialog
v-model="visible"
:title="dialogStatus === 'create' ? '新增采购入库' : '编辑入库信息'"
width="1000px"
:width="'min(1000px, 95vw)'"
top="4vh"
destroy-on-close
:close-on-click-modal="false"
@ -296,9 +296,7 @@
<el-col :span="6">
<el-form-item label="入库日期" prop="in_date"><el-date-picker v-model="form.in_date" type="date" value-format="YYYY-MM-DD" style="width:100%" disabled/></el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="条码" prop="barcode"><el-input v-model="form.barcode" placeholder="扫描条码" clearable/></el-form-item>
</el-col>
<!-- 条形码输入框已隐藏 -->
<el-col :span="6">
<el-form-item label="库位" prop="warehouse_location">
<el-autocomplete
@ -346,7 +344,7 @@
<el-row :gutter="20" style="margin-top: 10px;">
<el-col :span="6">
<el-form-item label="入库数量" prop="in_quantity">
<el-input-number v-model="form.in_quantity" :min="1" controls-position="right" style="width:100%" class="strong-input"/>
<el-input-number v-model="form.in_quantity" :min="1" controls-position="right" style="width:100%" class="strong-input" @change="updatePrices('qty')"/>
</el-form-item>
</el-col>
@ -435,7 +433,7 @@
<el-col :span="6">
<el-form-item label="税率">
<el-select v-model="form.tax_rate" style="width:100%">
<el-select v-model="form.tax_rate" style="width:100%" @change="updatePrices('tax')">
<el-option label="0%" :value="0" />
<el-option label="1%" :value="1" />
<el-option label="13%" :value="13" />
@ -443,7 +441,8 @@
</el-form-item>
</el-col>
<el-col :span="6"><el-form-item label="不含税单价" prop="unit_price"><el-input-number v-model="form.unit_price" :precision="4" controls-position="right" style="width:100%"/></el-form-item></el-col>
<el-col :span="6"><el-form-item label="单价" prop="unit_price"><el-input-number v-model="form.unit_price" :precision="4" controls-position="right" style="width:100%" @change="updatePrices('pre')"/></el-form-item></el-col>
<el-col :span="6"><el-form-item label="税后单价"><el-input-number v-model="form.post_tax_unit_price" :precision="4" controls-position="right" style="width:100%" @change="updatePrices('post')"/></el-form-item></el-col>
<el-col :span="6"><el-form-item label="总价"><el-input-number v-model="form.total_price" :precision="2" disabled :controls="false" style="width:100%" class="total-price-input"/></el-form-item></el-col>
</el-row>
@ -842,7 +841,7 @@ const form = reactive({
material_name: '', spec_model: '', category: '', unit: '', material_type: '',
sku: '', barcode: '', in_date: '', serial_number: '', batch_number: '', status: '在库', inspection_status: '未检',
in_quantity: 1, stock_quantity: 1, available_quantity: 1, warehouse_location: '',
unit_price: 0, total_price: 0,
unit_price: 0, post_tax_unit_price: 0, total_price: 0,
tax_rate: 0,
currency: 'CNY', exchange_rate: 1.00,
supplier_name: '', purchaser: '', purchaser_email: '', source_link: '', detail_link: '',
@ -1039,7 +1038,25 @@ const handleEntryModeChange = (val: string) => {
if(formRef.value) formRef.value.clearValidate('batch_number')
}
}
watch(() => [form.in_quantity, form.unit_price], () => { form.total_price = Number((form.in_quantity * form.unit_price).toFixed(4)) })
// 价格联动计算
const updatePrices = (source: string) => {
const taxMultiplier = 1 + (form.tax_rate || 0) / 100;
if (source === 'pre') {
form.post_tax_unit_price = Number((form.unit_price * taxMultiplier).toFixed(4));
} else if (source === 'post') {
form.unit_price = Number((form.post_tax_unit_price / taxMultiplier).toFixed(4));
} else if (source === 'tax') {
form.post_tax_unit_price = Number((form.unit_price * taxMultiplier).toFixed(4));
}
form.total_price = Number((form.in_quantity * form.unit_price).toFixed(4));
}
watch(() => [form.in_quantity, form.unit_price], () => {
form.total_price = Number((form.in_quantity * form.unit_price).toFixed(4));
// 同时更新税后单价
const taxMultiplier = 1 + (form.tax_rate || 0) / 100;
form.post_tax_unit_price = Number((form.unit_price * taxMultiplier).toFixed(4));
})
const fetchData = async () => {
loading.value = true
@ -1105,6 +1122,10 @@ const handleUpdate = (row: any) => {
source_link: row.source_link, detail_link: row.detail_link,
arrival_photo: row.arrival_photo || [], inspection_report: row.inspection_report || []
})
// 计算税后单价
const taxMultiplier = 1 + (form.tax_rate || 0) / 100;
form.post_tax_unit_price = Number((form.unit_price * taxMultiplier).toFixed(4));
arrivalFileList.value = form.arrival_photo.map(url => ({ name: url.split('/').pop(), url: getImageUrl(url) }))
const reports = form.inspection_report || []
const reportImgs = reports.filter(r => !isExternalLink(r))
@ -1127,7 +1148,13 @@ const submitForm = async () => {
const onlyImages = finalReportList.filter(item => !isExternalLink(item))
if (inspection_report_url.value) onlyImages.push(inspection_report_url.value)
const payload = { ...form, inspection_report: onlyImages, in_quantity: Number(form.in_quantity), unit_price: Number(form.unit_price) }
const payload = {
...form,
inspection_report: onlyImages,
in_quantity: Number(form.in_quantity),
unit_price: Number(form.unit_price),
post_tax_unit_price: Number(form.post_tax_unit_price)
}
try {
if (dialogStatus.value === 'create') {
const res: any = await createBuyInbound(payload)