feat: fix 401 auth error and bridge stocktake discrepancies to adjustment module

This commit is contained in:
DXC
2026-03-19 14:36:56 +08:00
parent 5454947176
commit 50cf63414f
2 changed files with 136 additions and 31 deletions

View File

@ -8,6 +8,7 @@ from app.models.base import MaterialBase
from app.models.inbound.buy import StockBuy from app.models.inbound.buy import StockBuy
from app.models.inbound.semi import StockSemi from app.models.inbound.semi import StockSemi
from app.models.inbound.product import StockProduct from app.models.inbound.product import StockProduct
from app.models.inbound.stocktake import StocktakeDraft
from datetime import datetime from datetime import datetime
import random import random
import string import string
@ -221,3 +222,77 @@ def get_stocks():
'limit': limit 'limit': limit
} }
}) })
# --------------------------------------------------------
# 5. 一键引入盘点差异
# POST /api/v1/stock/adjustment/import-from-stocktake
# --------------------------------------------------------
@adjustment_bp.route('/import-from-stocktake', methods=['POST'])
@jwt_required()
@permission_required('stock_adjustment:operation')
def import_from_stocktake():
"""从盘点差异记录导入为盘盈盘亏单"""
identity = get_jwt_identity()
operator = identity.get('username', 'system') if isinstance(identity, dict) else str(identity)
try:
# 查询所有有差异的盘点记录
drafts = StocktakeDraft.query.filter(StocktakeDraft.diff_qty != 0).all()
if not drafts:
return jsonify({'code': 200, 'msg': '暂无盘点差异记录', 'data': {'count': 0}})
count = 0
for draft in drafts:
# 判断盘盈/盘亏
diff = float(draft.diff_qty or 0)
if diff == 0:
continue
adjust_type = 'profit' if diff > 0 else 'loss'
adjust_quantity = abs(diff)
# 获取物料基础信息
base_id = None
sku = ''
warehouse_location = ''
# 根据source_table获取对应的库存记录
stock_model = get_stock_model(draft.source_table)
if stock_model and draft.stock_id:
stock = stock_model.query.get(draft.stock_id)
if stock:
base_id = getattr(stock, 'base_id', None)
sku = getattr(stock, 'sku', None) or getattr(stock, 'SKU', '')
warehouse_location = getattr(stock, 'warehouse_location', '')
# 生成调整单号
order_no = generate_order_no()
# 使用备注或默认原因
reason = draft.remark if draft.remark else '盘点差异自动生成'
# 创建调整单
adjustment = StockAdjustment(
order_no=order_no,
base_id=base_id,
stock_id=draft.stock_id,
source_table=draft.source_table,
sku=sku,
warehouse_location=warehouse_location,
adjust_type=adjust_type,
adjust_quantity=adjust_quantity,
reason=reason,
status='pending',
operator=operator
)
db.session.add(adjustment)
count += 1
db.session.commit()
return jsonify({'code': 200, 'msg': '导入成功', 'data': {'count': count}})
except Exception as e:
db.session.rollback()
return jsonify({'code': 500, 'msg': f'导入失败: {str(e)}'}), 500

View File

@ -13,6 +13,9 @@
<el-option label="已取消" value="cancelled" /> <el-option label="已取消" value="cancelled" />
</el-select> </el-select>
<el-button type="primary" @click="fetchData">查询</el-button> <el-button type="primary" @click="fetchData">查询</el-button>
<el-button v-if="userStore.hasPermission('stock_adjustment:operation')" type="warning" @click="handleImportStocktake">
一键引入盘点差异
</el-button>
<el-button v-if="userStore.hasPermission('stock_adjustment:operation')" type="success" @click="showDialog = true"> <el-button v-if="userStore.hasPermission('stock_adjustment:operation')" type="success" @click="showDialog = true">
新增调整单 新增调整单
</el-button> </el-button>
@ -132,8 +135,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import { ElMessage } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { useUserStore } from '@/stores/user' import { useUserStore } from '@/stores/user'
import request from '@/utils/request'
const userStore = useUserStore() const userStore = useUserStore()
@ -182,19 +186,20 @@ const selectedStock = ref<any>(null)
async function fetchData() { async function fetchData() {
loading.value = true loading.value = true
try { try {
const params = new URLSearchParams({ const res = await request({
page: page.value.toString(), url: '/api/v1/stock/adjustment/list',
limit: limit.value.toString() method: 'get',
params: {
page: page.value,
limit: limit.value,
keyword: keyword.value || undefined,
adjust_type: searchAdjustType.value || undefined,
status: searchStatus.value || undefined
}
}) })
if (keyword.value) params.append('keyword', keyword.value) if (res.code === 200) {
if (searchAdjustType.value) params.append('adjust_type', searchAdjustType.value) list.value = res.data.items
if (searchStatus.value) params.append('status', searchStatus.value) total.value = res.data.total
const res = await fetch(`/api/v1/stock/adjustment/list?${params}`)
const json = await res.json()
if (json.code === 200) {
list.value = json.data.items
total.value = json.data.total
} }
} catch (e) { } catch (e) {
ElMessage.error('获取数据失败') ElMessage.error('获取数据失败')
@ -207,18 +212,19 @@ async function fetchData() {
async function fetchStocks() { async function fetchStocks() {
stockLoading.value = true stockLoading.value = true
try { try {
const params = new URLSearchParams({ const res = await request({
source_table: form.value.source_table, url: '/api/v1/stock/adjustment/stocks',
page: stockPage.value.toString(), method: 'get',
limit: stockLimit.value.toString() params: {
source_table: form.value.source_table,
page: stockPage.value,
limit: stockLimit.value,
keyword: stockKeyword.value || undefined
}
}) })
if (stockKeyword.value) params.append('keyword', stockKeyword.value) if (res.code === 200) {
stockList.value = res.data.items
const res = await fetch(`/api/v1/stock/adjustment/stocks?${params}`) stockTotal.value = res.data.total
const json = await res.json()
if (json.code === 200) {
stockList.value = json.data.items
stockTotal.value = json.data.total
} }
} catch (e) { } catch (e) {
ElMessage.error('获取库存失败') ElMessage.error('获取库存失败')
@ -263,13 +269,12 @@ async function submitForm() {
submitLoading.value = true submitLoading.value = true
try { try {
const res = await fetch('/api/v1/stock/adjustment/create', { const res = await request({
method: 'POST', url: '/api/v1/stock/adjustment/create',
headers: { 'Content-Type': 'application/json' }, method: 'post',
body: JSON.stringify(form.value) data: form.value
}) })
const json = await res.json() if (res.code === 200) {
if (json.code === 200) {
ElMessage.success('提交成功') ElMessage.success('提交成功')
showDialog.value = false showDialog.value = false
fetchData() fetchData()
@ -283,7 +288,7 @@ async function submitForm() {
} }
selectedStock.value = null selectedStock.value = null
} else { } else {
ElMessage.error(json.msg || '提交失败') ElMessage.error(res.msg || '提交失败')
} }
} catch (e) { } catch (e) {
ElMessage.error('提交失败') ElMessage.error('提交失败')
@ -292,6 +297,31 @@ async function submitForm() {
} }
} }
// 一键引入盘点差异
async function handleImportStocktake() {
try {
await ElMessageBox.confirm('确定要将当前所有的盘点差异导入为盘盈盘亏单吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
const res = await request({
url: '/api/v1/stock/adjustment/import-from-stocktake',
method: 'post'
})
if (res.code === 200) {
ElMessage.success(`成功导入 ${res.data.count} 条盘点差异记录`)
fetchData()
} else {
ElMessage.error(res.msg || '导入失败')
}
} catch (e) {
if (e !== 'cancel') {
ElMessage.error('导入失败')
}
}
}
onMounted(() => { onMounted(() => {
fetchData() fetchData()
}) })