161 lines
6.5 KiB
Python
161 lines
6.5 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""盘点明细编辑向导:弹出窗口编辑 single line,填写后提交"""
|
||
import logging
|
||
from odoo import api, fields, models
|
||
from odoo.exceptions import UserError
|
||
|
||
_logger = logging.getLogger(__name__)
|
||
|
||
|
||
class YuthonInventoryLineWizard(models.TransientModel):
|
||
"""盘点明细行编辑弹窗"""
|
||
_name = 'yuthon.inventory.line.wizard'
|
||
_description = '盘点明细编辑向导'
|
||
|
||
# ========== 关联明细行 ==========
|
||
line_id = fields.Many2one(
|
||
'yuthon.inventory.sheet.line',
|
||
string='明细行',
|
||
readonly=True,
|
||
)
|
||
|
||
# ========== 只读展示字段 ==========
|
||
product_name = fields.Char(string='产品/设备名称', readonly=True)
|
||
specification = fields.Char(string='规格型号', readonly=True)
|
||
|
||
# 是否为办公用品(用于控制库存位置字段的显示/隐藏)
|
||
is_office = fields.Boolean(
|
||
string='是否办公用品',
|
||
compute='_compute_is_office',
|
||
)
|
||
|
||
# 库存位置:办公用品可编辑,固定资产不显示
|
||
stock_location_id = fields.Many2one(
|
||
'stock.location',
|
||
string='库存位置',
|
||
domain="[('usage', '=', 'internal')]",
|
||
)
|
||
|
||
on_hand_qty = fields.Float(string='在手数量(系统数)', readonly=True)
|
||
|
||
# ========== 可编辑字段 ==========
|
||
actual_qty = fields.Float(string='实际盘点数量', digits='Product Unit of Measure')
|
||
|
||
# 固定资产:员工下拉(办公用品隐藏)
|
||
employee_id = fields.Many2one(
|
||
'hr.employee',
|
||
string='使用人',
|
||
)
|
||
|
||
# 使用部门(只读,根据选中的员工自动带出)
|
||
department_name = fields.Char(
|
||
string='使用部门',
|
||
compute='_compute_department_name',
|
||
readonly=True,
|
||
)
|
||
|
||
difference_reason = fields.Char(string='差额原因',
|
||
help='实际数量与在手数量有差额时必须填写')
|
||
|
||
# ========== 计算字段 ==========
|
||
difference_qty = fields.Float(
|
||
string='差额',
|
||
compute='_compute_difference',
|
||
digits='Product Unit of Measure',
|
||
)
|
||
|
||
@api.depends('line_id')
|
||
def _compute_is_office(self):
|
||
"""根据关联明细行的类型判断是否为办公用品"""
|
||
for wiz in self:
|
||
wiz.is_office = bool(wiz.line_id and wiz.line_id.sheet_type == 'office')
|
||
|
||
@api.depends('employee_id', 'employee_id.department_id')
|
||
def _compute_department_name(self):
|
||
"""根据选中的员工自动带出所属部门名称"""
|
||
for wiz in self:
|
||
if wiz.employee_id and wiz.employee_id.department_id:
|
||
wiz.department_name = wiz.employee_id.department_id.name
|
||
else:
|
||
wiz.department_name = ''
|
||
|
||
@api.depends('actual_qty', 'on_hand_qty')
|
||
def _compute_difference(self):
|
||
"""动态计算差额"""
|
||
for wiz in self:
|
||
wiz.difference_qty = (wiz.actual_qty or 0.0) - (wiz.on_hand_qty or 0.0)
|
||
|
||
@api.model
|
||
def default_get(self, fields_list):
|
||
"""打开弹窗时从明细行预填数据"""
|
||
res = super().default_get(fields_list)
|
||
line_id = self.env.context.get('default_line_id')
|
||
if line_id:
|
||
line = self.env['yuthon.inventory.sheet.line'].browse(line_id)
|
||
if line.exists():
|
||
# 预填固定资产的员工(按名称匹配 hr.employee)
|
||
employee_id = False
|
||
if line.sheet_type == 'fixed_asset' and line.user_name:
|
||
employee = self.env['hr.employee'].sudo().search([
|
||
('name', '=', line.user_name),
|
||
], limit=1)
|
||
if employee:
|
||
employee_id = employee.id
|
||
|
||
res.update({
|
||
'line_id': line.id,
|
||
'product_name': line.product_name or '',
|
||
'specification': line.specification or '',
|
||
'is_office': (line.sheet_type == 'office'),
|
||
'stock_location_id': line.stock_location_id.id if (line.sheet_type == 'office' and line.stock_location_id) else False,
|
||
'on_hand_qty': line.on_hand_qty or 0.0,
|
||
'actual_qty': line.actual_qty if line.actual_qty else 0.0,
|
||
'employee_id': employee_id, # 固定资产预填员工,办公用品留空
|
||
'difference_reason': line.difference_reason or '',
|
||
})
|
||
return res
|
||
|
||
def action_save(self):
|
||
"""保存数据到明细行(仅写回编辑字段,不执行提交/库存调整逻辑)
|
||
固定资产:员工下拉选择后同步写回 maintenance.equipment
|
||
"""
|
||
self.ensure_one()
|
||
line = self.line_id
|
||
if not line:
|
||
raise UserError('未找到关联的盘点明细行!')
|
||
|
||
# 写回用户编辑过的字段(库存位置改动会触发 inverse 移动库存)
|
||
write_vals = {
|
||
'actual_qty': self.actual_qty,
|
||
'difference_reason': self.difference_reason,
|
||
}
|
||
# 办公用品:使用人/部门保持 Char 写法
|
||
if line.sheet_type == 'office':
|
||
write_vals['user_name'] = ''
|
||
write_vals['department_name'] = ''
|
||
else:
|
||
# 固定资产:将 employee_id 的名称写回 line 的 user_name
|
||
# department_name 由 compute 自动取,无需手动写入
|
||
write_vals['user_name'] = self.employee_id.name if self.employee_id else ''
|
||
write_vals['department_name'] = self.department_name or ''
|
||
|
||
# 办公用品才写回库存位置
|
||
if line.sheet_type == 'office' and self.stock_location_id:
|
||
write_vals['stock_location_id'] = self.stock_location_id.id
|
||
line.write(write_vals)
|
||
|
||
# 固定资产:直接将 employee_id 和 department_id1 同步到 maintenance.equipment
|
||
if line.sheet_type == 'fixed_asset' and line.equipment_id:
|
||
eq = line.equipment_id
|
||
eq_vals = {}
|
||
eq_vals['employee_id'] = self.employee_id.id if self.employee_id else False
|
||
# 部门从员工的 department_id 取出 → 写入设备的 department_id1
|
||
if self.employee_id and self.employee_id.department_id:
|
||
eq_vals['department_id1'] = self.employee_id.department_id.id
|
||
else:
|
||
eq_vals['department_id1'] = False
|
||
eq.sudo().write(eq_vals)
|
||
|
||
# 关闭弹窗(不执行提交,用户回到列表后点「提交」按钮)
|
||
return {'type': 'ir.actions.act_window_close'}
|