diff --git a/yuthon_sps_approval/models/inherit_product_template.py b/yuthon_sps_approval/models/inherit_product_template.py
index 22e98163a..51f692c00 100644
--- a/yuthon_sps_approval/models/inherit_product_template.py
+++ b/yuthon_sps_approval/models/inherit_product_template.py
@@ -6,6 +6,7 @@ class ProductTemplate(models.Model):
_inherit = 'product.template'
is_fixed_assets = fields.Boolean(string='是否固定资产', default=True)
+ journal_item_count = fields.Integer(string='会计凭证行数量', compute='_compute_journal_item_count')
@api.onchange('is_fixed_assets')
def _onchange_fixed_assets(self):
@@ -21,4 +22,99 @@ class ProductTemplate(models.Model):
template_ids = self.env["product.template"].browse(self._context.get('active_ids', self._context.get('active_id')))
company_id = self.env['res.company'].search([('name', '=', '集团本部')])
for template in template_ids:
- template.write({'company_id': company_id.id})
\ No newline at end of file
+ template.write({'company_id': company_id.id})
+
+ # 常见关联模型映射(表名 → 中文显示名)
+ _DELETE_CHECK_MODELS = [
+ # (模型名, 关联字段, 中文名, 描述模板)
+ ('account.move.line', 'product_id', '会计凭证行(Journal Item)', '该产品已被 {count} 条会计凭证行引用'),
+ ('sale.order.line', 'product_template_id', '销售订单行', '该产品已被 {count} 条销售订单行引用'),
+ ('purchase.order.line', 'product_template_id', '采购订单行', '该产品已被 {count} 条采购订单行引用'),
+ ('stock.move', 'product_tmpl_id', '库存移动单', '该产品已被 {count} 条库存移动单引用'),
+ ('stock.move.line', 'product_tmpl_id', '库存移动明细', '该产品已被 {count} 条库存移动明细引用'),
+ ('stock.quant', 'product_tmpl_id', '库存数量记录', '该产品存在 {count} 条库存数量记录'),
+ ('maintenance.equipment', 'product_tmpl_id', '固定资产设备', '该产品已关联 {count} 个设备'),
+ ('mrp.production', 'product_tmpl_id', '生产工单', '该产品已关联 {count} 张生产工单'),
+ ('mrp.bom', 'product_tmpl_id', '物料清单(BOM)', '该产品已关联 {count} 个物料清单'),
+ ('pos.order.line', 'product_id', 'POS订单行', '该产品已被 {count} 条POS订单行引用'),
+ ]
+
+ def unlink(self):
+ """重写删除方法,删除前检查关联数据并给出友好提示"""
+ # 逐个检查每个产品的关联情况
+ blocked_products = []
+ for record in self:
+ references = self._check_product_references(record)
+ if references:
+ blocked_products.append((record.display_name, references))
+
+ # 如果有被阻塞的产品,汇总提示
+ if blocked_products:
+ detail_lines = []
+ for prod_name, refs in blocked_products:
+ for ref_msg in refs:
+ detail_lines.append(f'• 【{prod_name}】{ref_msg}')
+ raise UserError(
+ '以下产品无法删除,因为它们已被其他业务数据引用:\n\n'
+ + '\n'.join(detail_lines) +
+ '\n\n建议操作:请使用「存档」功能替代「删除」,'
+ '存档后产品不会在列表中展示且不影响已有数据。'
+ )
+ return super().unlink()
+
+ def _check_product_references(self, record):
+ """检查单个产品的关联引用,返回提示信息列表"""
+ results = []
+ # 获取该产品所有变体ID
+ variant_ids = record.product_variant_ids.ids
+
+ for model_name, field_name, cn_name, msg_template in self._DELETE_CHECK_MODELS:
+ try:
+ # 检查模型是否存在
+ if model_name not in self.env:
+ continue
+
+ domain = []
+ # 根据关联字段是 product_id 还是 product_tmpl_id 构建搜索条件
+ if field_name == 'product_id':
+ domain = [('product_id', 'in', variant_ids)]
+ elif field_name == 'product_template_id' or field_name == 'product_tmpl_id':
+ domain = [(field_name, '=', record.id)]
+
+ count = self.env[model_name].search_count(domain)
+ if count > 0:
+ results.append(msg_template.format(count=count))
+ except Exception:
+ # 某些模型可能查询异常,跳过不影响主流程
+ continue
+
+ return results
+
+ def _compute_journal_item_count(self):
+ """计算该产品关联的会计凭证行数量"""
+ for record in self:
+ # 获取所有变体ID
+ variant_ids = record.product_variant_ids.ids
+ if 'account.move.line' in record.env:
+ # 按变体product_id统计凭证行数量
+ count = self.env['account.move.line'].search_count([
+ ('product_id', 'in', variant_ids)
+ ])
+ record.journal_item_count = count
+ else:
+ record.journal_item_count = 0
+
+ def action_view_journal_items(self):
+ """打开关联的会计凭证行列表"""
+ self.ensure_one()
+ variant_ids = self.product_variant_ids.ids
+ # 构建搜索域:按产品的变体ID查找凭证行
+ domain = [('product_id', 'in', variant_ids)]
+ return {
+ 'name': f'{self.display_name} - 会计凭证行',
+ 'type': 'ir.actions.act_window',
+ 'res_model': 'account.move.line',
+ 'view_mode': 'tree,form',
+ 'domain': domain,
+ 'context': {'default_product_id': variant_ids[0] if variant_ids else False},
+ }
\ No newline at end of file
diff --git a/yuthon_sps_approval/views/inherit_product_template.xml b/yuthon_sps_approval/views/inherit_product_template.xml
index de4a4b445..d7d15446b 100644
--- a/yuthon_sps_approval/views/inherit_product_template.xml
+++ b/yuthon_sps_approval/views/inherit_product_template.xml
@@ -26,6 +26,17 @@
+
+
+
+
+
\ No newline at end of file