!9052 Merge branch 'dev' of <a href="https://gitee.com/jinan-pengyusen-data/gzth">https://gitee.com/jinan-pengyusen-data/gzth</a> into dev_wang
Merge pull request !9052 from 李鹏宇/dev_wang
This commit is contained in:
@@ -100,19 +100,49 @@ class InheritMaintenanceEquipment(models.Model):
|
||||
workbook = load_workbook(template_path)
|
||||
sheet = workbook.active
|
||||
|
||||
# 统计导出数据中最常见的年月(用于标题)
|
||||
year_month_list = []
|
||||
for record in equipment_records:
|
||||
if record.purchase_date:
|
||||
year_month_list.append((record.purchase_date.year, record.purchase_date.month))
|
||||
|
||||
if year_month_list:
|
||||
# 取出现次数最多的年月
|
||||
from collections import Counter
|
||||
most_common_ym = Counter(year_month_list).most_common(1)[0][0]
|
||||
title_year, title_month = most_common_ym
|
||||
else:
|
||||
# 如果没有购入日期,使用当前年月
|
||||
now = datetime.datetime.now()
|
||||
title_year, title_month = now.year, now.month
|
||||
|
||||
# 修改A1单元格:生成动态标题
|
||||
title_text = f'{title_year}年{title_month}月固定资产盘点表'
|
||||
sheet['A1'] = title_text
|
||||
sheet['A1'].alignment = Alignment(horizontal='left', vertical='center')
|
||||
|
||||
# 修改K1单元格:生成制表人信息(直接替换,不追加)
|
||||
current_date = datetime.datetime.now().strftime('%Y-%m-%d')
|
||||
k1_text = f'制表人:叶华锋 {current_date}'
|
||||
sheet['K1'] = k1_text
|
||||
sheet['K1'].alignment = Alignment(horizontal='left', vertical='center')
|
||||
|
||||
# 从第3行开始写入数据(第1-2行是表头)
|
||||
row = 3
|
||||
|
||||
# 设置列宽(A列序号列设置为较窄,C列型号列也设置较窄)
|
||||
sheet.column_dimensions['A'].width = 6 # 序号列宽度
|
||||
sheet.column_dimensions['C'].width = 12 # 型号列宽度
|
||||
# 设置列宽
|
||||
sheet.column_dimensions['A'].width = 6 # 序号列
|
||||
sheet.column_dimensions['B'].width = 20 # 资产编号列(加宽)
|
||||
sheet.column_dimensions['C'].width = 30 # 设备名称列(加宽)
|
||||
sheet.column_dimensions['D'].width = 12 # 型号列
|
||||
sheet.column_dimensions['K'].width = 25 # 制表人列(确保内容完整显示)
|
||||
|
||||
# 获取模板样式行(使用第3行作为参考)
|
||||
template_row_idx = 3
|
||||
if sheet.max_row >= template_row_idx:
|
||||
# 先保存第3行的样式
|
||||
template_styles = {}
|
||||
for col in range(1, 11): # A到J列(10列)
|
||||
for col in range(1, 12): # A到K列(11列)
|
||||
cell = sheet.cell(row=template_row_idx, column=col)
|
||||
template_styles[col] = {
|
||||
'font': copy(cell.font),
|
||||
@@ -132,54 +162,57 @@ class InheritMaintenanceEquipment(models.Model):
|
||||
for merged_range_str in merged_cells_to_unmerge:
|
||||
sheet.unmerge_cells(merged_range_str)
|
||||
|
||||
# 先为所有列应用模板样式
|
||||
for col in range(1, 11): # A到J列
|
||||
# 先为所有列应用模板样式并统一居中对齐
|
||||
for col in range(1, 12): # A到K列
|
||||
cell = sheet.cell(row=row, column=col)
|
||||
if col in template_styles:
|
||||
cell.font = copy(template_styles[col]['font'])
|
||||
cell.fill = copy(template_styles[col]['fill'])
|
||||
cell.border = copy(template_styles[col]['border'])
|
||||
# 统一设置居中对齐
|
||||
cell.alignment = Alignment(horizontal='center', vertical='center')
|
||||
# 统一设置居中对齐
|
||||
cell.alignment = Alignment(horizontal='center', vertical='center')
|
||||
|
||||
# A列:序号(从1开始)
|
||||
sheet.cell(row=row, column=1, value=index)
|
||||
|
||||
# B列:设备名称
|
||||
sheet.cell(row=row, column=2, value=record.name or '')
|
||||
# B列:资产编号
|
||||
sheet.cell(row=row, column=2, value=record.serial_no or '')
|
||||
|
||||
# C列:型号
|
||||
sheet.cell(row=row, column=3, value=record.model or '')
|
||||
# C列:设备名称
|
||||
sheet.cell(row=row, column=3, value=record.name or '')
|
||||
|
||||
# D列:原值
|
||||
sheet.cell(row=row, column=4, value=record.cost or 0)
|
||||
# D列:型号
|
||||
sheet.cell(row=row, column=4, value=record.model or '')
|
||||
|
||||
# E列:寿命
|
||||
# E列:原值
|
||||
sheet.cell(row=row, column=5, value=record.cost or 0)
|
||||
|
||||
# F列:寿命
|
||||
warranty_date = ''
|
||||
if record.warranty_date:
|
||||
warranty_date = record.warranty_date.strftime('%Y-%m-%d')
|
||||
sheet.cell(row=row, column=5, value=warranty_date)
|
||||
sheet.cell(row=row, column=6, value=warranty_date)
|
||||
|
||||
# F列:设备状态
|
||||
# G列:设备状态
|
||||
mainten_state = ''
|
||||
if record.mainten_state:
|
||||
mainten_state = dict(record._fields['mainten_state'].selection).get(record.mainten_state, '')
|
||||
sheet.cell(row=row, column=6, value=mainten_state)
|
||||
sheet.cell(row=row, column=7, value=mainten_state)
|
||||
|
||||
# G列:员工
|
||||
sheet.cell(row=row, column=7, value=record.employee_id.name if record.employee_id else '')
|
||||
# H列:员工
|
||||
sheet.cell(row=row, column=8, value=record.employee_id.name if record.employee_id else '')
|
||||
|
||||
# H列:部门
|
||||
sheet.cell(row=row, column=8, value=record.department_id1.name if record.department_id1 else '')
|
||||
# I列:部门
|
||||
sheet.cell(row=row, column=9, value=record.department_id1.name if record.department_id1 else '')
|
||||
|
||||
# I列:设备类别
|
||||
sheet.cell(row=row, column=9, value=record.category_id.name if record.category_id else '')
|
||||
# J列:设备类别
|
||||
sheet.cell(row=row, column=10, value=record.category_id.name if record.category_id else '')
|
||||
|
||||
# J列:公司(company 字段)
|
||||
# K列:公司(company 字段)
|
||||
company = ''
|
||||
if record.company:
|
||||
company = dict(record._fields['company'].selection).get(record.company, '')
|
||||
sheet.cell(row=row, column=10, value=company)
|
||||
sheet.cell(row=row, column=11, value=company)
|
||||
|
||||
# 设置最小行高,确保内容显示完整
|
||||
if not sheet.row_dimensions[row].height or sheet.row_dimensions[row].height < 30:
|
||||
@@ -193,8 +226,8 @@ class InheritMaintenanceEquipment(models.Model):
|
||||
output.seek(0)
|
||||
excel_data = base64.b64encode(output.read())
|
||||
|
||||
# 创建附件
|
||||
filename = f'固定资产盘点表_{datetime.datetime.now().strftime("%Y%m%d%H%M%S")}.xlsx'
|
||||
# 创建附件(文件名只包含日期,不含时分秒)
|
||||
filename = f'固定资产盘点表_{datetime.datetime.now().strftime("%Y%m%d")}.xlsx'
|
||||
attachment = self.env['ir.attachment'].create({
|
||||
'name': filename,
|
||||
'type': 'binary',
|
||||
|
||||
Binary file not shown.
@@ -26,3 +26,5 @@ class ProductProduct(models.Model):
|
||||
|
||||
class StockMove(models.Model):
|
||||
_inherit = 'stock.move'
|
||||
|
||||
|
||||
|
||||
@@ -38,9 +38,20 @@ class StockPicking(models.Model):
|
||||
)
|
||||
available_product_ids = fields.Many2many(
|
||||
'product.product',
|
||||
'stock_picking_product_available_rel',
|
||||
'picking_id',
|
||||
'product_id',
|
||||
compute='_compute_available_product_ids',
|
||||
string="可用产品"
|
||||
)
|
||||
available_location_ids = fields.Many2many(
|
||||
'stock.location',
|
||||
'stock_picking_location_available_rel',
|
||||
'picking_id',
|
||||
'location_id',
|
||||
compute='_compute_available_location_ids',
|
||||
string="可用仓库"
|
||||
)
|
||||
can_certify = fields.Boolean(
|
||||
string="可以证明",
|
||||
compute='_compute_can_certify',
|
||||
@@ -81,19 +92,39 @@ class StockPicking(models.Model):
|
||||
})
|
||||
return result
|
||||
|
||||
@api.depends('location_id')
|
||||
@api.depends('location_id', 'picking_type_code')
|
||||
def _compute_available_product_ids(self):
|
||||
"""根据仓库计算可用产品列表"""
|
||||
"""根据仓库和作业类型计算可用产品列表"""
|
||||
for record in self:
|
||||
if record.location_id:
|
||||
# 查询该仓库中有库存的产品
|
||||
# 如果是入库单,返回所有产品(不限制)
|
||||
if record.picking_type_code == 'incoming':
|
||||
record.available_product_ids = self.env['product.product'].search([])
|
||||
# 如果是借用/领用等,只返回该仓库中有库存的产品
|
||||
elif record.location_id:
|
||||
quants = self.env['stock.quant'].search([
|
||||
('location_id', '=', record.location_id.id)
|
||||
('location_id', '=', record.location_id.id),
|
||||
('quantity', '>', 0) # 只查询有库存的
|
||||
])
|
||||
record.available_product_ids = quants.mapped('product_id')
|
||||
else:
|
||||
record.available_product_ids = False
|
||||
|
||||
|
||||
@api.depends('picking_type_code')
|
||||
def _compute_available_location_ids(self):
|
||||
"""根据作业类型计算可用仓库列表"""
|
||||
for record in self:
|
||||
# 如果是入库单,不限制仓库选择
|
||||
if record.picking_type_code == 'incoming':
|
||||
record.available_location_ids = self.env['stock.location'].search([])
|
||||
# 如果是借用/领用等,只显示有库存的仓库
|
||||
else:
|
||||
quants = self.env['stock.quant'].search([
|
||||
('quantity', '>', 0)
|
||||
])
|
||||
record.available_location_ids = quants.mapped('location_id')
|
||||
|
||||
|
||||
@api.onchange('user_id')
|
||||
def _onchange_user_id(self):
|
||||
if self.user_id:
|
||||
@@ -173,9 +204,73 @@ class StockPicking(models.Model):
|
||||
record._compute_json_display()
|
||||
return True
|
||||
|
||||
def action_update_name_by_products(self):
|
||||
"""批量更新入库单名称(根据产品生成)"""
|
||||
updated_count = 0
|
||||
for picking in self:
|
||||
# 只处理入库单
|
||||
if picking.picking_type_code == 'incoming' and picking.move_ids_without_package:
|
||||
product_names = picking.move_ids_without_package.mapped('product_id.name')
|
||||
if product_names:
|
||||
products_str = '/'.join(product_names)
|
||||
# 添加入库单ID确保唯一性
|
||||
new_name = f"{products_str}的入库单-{picking.id}"
|
||||
picking.write({'name': new_name})
|
||||
updated_count += 1
|
||||
|
||||
# 返回提示消息
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'display_notification',
|
||||
'params': {
|
||||
'title': '更新完成',
|
||||
'message': f'已成功更新 {updated_count} 条入库单的名称',
|
||||
'type': 'success',
|
||||
'sticky': False,
|
||||
}
|
||||
}
|
||||
|
||||
def action_acceptance(self):
|
||||
"""验收按钮"""
|
||||
self.ensure_one()
|
||||
self.acceptance_date = fields.Datetime.now()
|
||||
self.receipt_status = 'certification' # 状态变为证明
|
||||
return True
|
||||
return True
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
"""重写create方法,根据产品生成入库单名称"""
|
||||
pickings = super(StockPicking, self).create(vals_list)
|
||||
|
||||
for picking in pickings:
|
||||
# 只处理入库单(picking_type_code为incoming)
|
||||
if picking.picking_type_code == 'incoming' and picking.move_ids_without_package:
|
||||
# 获取所有产品名称
|
||||
product_names = picking.move_ids_without_package.mapped('product_id.name')
|
||||
if product_names:
|
||||
# 用/连接产品名称
|
||||
products_str = '/'.join(product_names)
|
||||
# 生成新的name格式:产品/产品/产品的入库单-ID(确保唯一性)
|
||||
new_name = f"{products_str}的入库单-{picking.id}"
|
||||
# 更新name字段
|
||||
picking.write({'name': new_name})
|
||||
|
||||
return pickings
|
||||
|
||||
def write(self, vals):
|
||||
"""重写write方法,当产品变化时更新入库单名称"""
|
||||
result = super(StockPicking, self).write(vals)
|
||||
|
||||
# 如果修改了move_ids相关字段,更新name
|
||||
if 'move_ids_without_package' in vals or 'move_ids' in vals:
|
||||
for picking in self:
|
||||
if picking.picking_type_code == 'incoming' and picking.move_ids_without_package:
|
||||
product_names = picking.move_ids_without_package.mapped('product_id.name')
|
||||
if product_names:
|
||||
products_str = '/'.join(product_names)
|
||||
new_name = f"{products_str}的入库单-{picking.id}"
|
||||
# 避免递归调用,使用super().write
|
||||
if picking.name != new_name:
|
||||
super(StockPicking, picking).write({'name': new_name})
|
||||
|
||||
return result
|
||||
@@ -8,8 +8,11 @@
|
||||
<xpath expr="//field[@name='picking_type_id']" position="after">
|
||||
<field name="department_id" options="{'no_create': True}" invisible="1"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='location_id'][@groups='stock.group_stock_multi_locations']" position="attributes">
|
||||
<attribute name="domain">[('id', 'in', available_location_ids)]</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='picking_type_id']" position="attributes">
|
||||
<attribute name="readonly">receipt_status in ['acceptance', 'certification']</attribute>
|
||||
<attribute name="readonly">state != 'draft' and receipt_status in ['acceptance', 'certification']</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='origin']" position="attributes">
|
||||
<attribute name="invisible">1</attribute>
|
||||
@@ -18,6 +21,7 @@
|
||||
<field name="purchase_id" string="源单据" readonly="1" options="{'no_create': True, 'no_open': False}"/>
|
||||
<field name="user_id" string="采购人员"/>
|
||||
<field name="available_product_ids" invisible="1"/>
|
||||
<field name="available_location_ids" invisible="1"/>
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="can_certify" invisible="1"/>
|
||||
</xpath>
|
||||
@@ -31,14 +35,14 @@
|
||||
<xpath expr="//page[@name='operations']/field[@name='move_ids_without_package']" position="after">
|
||||
<group>
|
||||
<group>
|
||||
<field name="employee_id" string="验收人" required="1" options="{'no_create': True}" readonly="receipt_status == 'certification'"/>
|
||||
<field name="document_ids" widget="preview_many2many" readonly="receipt_status == 'certification'"/>
|
||||
<field name="acceptance_date" readonly="receipt_status == 'certification'"/>
|
||||
<field name="employee_id" string="验收人" required="1" options="{'no_create': True}" readonly="state != 'draft' and receipt_status == 'certification'"/>
|
||||
<field name="document_ids" widget="preview_many2many" readonly="state != 'draft' and receipt_status == 'certification'"/>
|
||||
<field name="acceptance_date" readonly="state != 'draft' and receipt_status == 'certification'"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="certifier_id" options="{'no_create': True}" readonly="receipt_status == 'acceptance'"/>
|
||||
<field name="certifier_document_ids" widget="preview_many2many" readonly="receipt_status == 'acceptance'"/>
|
||||
<field name="certification_date" readonly="receipt_status == 'acceptance'"/>
|
||||
<field name="certifier_id" options="{'no_create': True}" readonly="state != 'draft' and receipt_status == 'acceptance'"/>
|
||||
<field name="certifier_document_ids" widget="preview_many2many" readonly="state != 'draft' and receipt_status == 'acceptance'"/>
|
||||
<field name="certification_date" readonly="state != 'draft' and receipt_status == 'acceptance'"/>
|
||||
</group>
|
||||
</group>
|
||||
</xpath>
|
||||
@@ -66,10 +70,10 @@
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='partner_id']" position="attributes">
|
||||
<attribute name="string">供应商</attribute>
|
||||
<attribute name="readonly">receipt_status in ['acceptance', 'certification']</attribute>
|
||||
<attribute name="readonly">state != 'draft' and receipt_status in ['acceptance', 'certification']</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='scheduled_date']" position="attributes">
|
||||
<attribute name="readonly">receipt_status in ['acceptance', 'certification']</attribute>
|
||||
<attribute name="readonly">state != 'draft' and receipt_status in ['acceptance', 'certification']</attribute>
|
||||
</xpath>
|
||||
<xpath expr="(//field[@name='state'][@widget='statusbar'])[1]" position="replace">
|
||||
<field name="receipt_status" widget="statusbar" statusbar_visible="acceptance,certification,receipt" invisible="picking_type_code != 'incoming'"/>
|
||||
@@ -84,6 +88,11 @@
|
||||
<field name="model">stock.picking</field>
|
||||
<field name="inherit_id" ref="stock.vpicktree"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//tree/header" position="inside">
|
||||
<button name="action_update_name_by_products" type="object" string="根据产品更新名称"
|
||||
class="btn-secondary"
|
||||
help="将选中的入库单名称更新为:产品1/产品2/产品3的入库单"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='name']" position="attributes">
|
||||
<attribute name="string">编号</attribute>
|
||||
</xpath>
|
||||
|
||||
Reference in New Issue
Block a user