diff --git a/yuthon_maintain/models/inherit_maintenance_equipment.py b/yuthon_maintain/models/inherit_maintenance_equipment.py index 8333d9f5d..b2aeab175 100644 --- a/yuthon_maintain/models/inherit_maintenance_equipment.py +++ b/yuthon_maintain/models/inherit_maintenance_equipment.py @@ -5,6 +5,10 @@ import datetime import qrcode from io import BytesIO import base64 +from openpyxl import load_workbook +from openpyxl.styles import Alignment +from copy import copy +from odoo.modules import get_module_resource def generate_qr(data): qr = qrcode.QRCode( @@ -74,6 +78,131 @@ class InheritMaintenanceEquipment(models.Model): 'is_fixed_assets': True, }) + def export_inventory_report(self): + """导出固定资产盘点表""" + equipment_ids = self._context.get('active_ids', []) + if not equipment_ids: + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'title': '警告', + 'message': '请至少选择一条设备记录', + 'type': 'warning', + 'sticky': False, + } + } + + equipment_records = self.env['maintenance.equipment'].browse(equipment_ids) + + # 加载模板文件(模板在 yuthon_property 模块的 static/tmpl 目录下) + template_path = get_module_resource('yuthon_property', 'static', 'tmpl', 'gudingzichanpandianbiao.xlsx') + workbook = load_workbook(template_path) + sheet = workbook.active + + # 从第3行开始写入数据(第1-2行是表头) + row = 3 + + # 获取模板样式行(使用第3行作为参考) + template_row_idx = 3 + if sheet.max_row >= template_row_idx: + # 先保存第3行的样式 + template_styles = {} + for col in range(1, 11): # A到J列(10列) + cell = sheet.cell(row=template_row_idx, column=col) + template_styles[col] = { + 'font': copy(cell.font), + 'fill': copy(cell.fill), + 'border': copy(cell.border), + 'alignment': copy(cell.alignment), + } + else: + template_styles = {} + + for index, record in enumerate(equipment_records, start=1): + # 先解除当前行的合并单元格(如果有) + merged_cells_to_unmerge = [] + for merged_range in sheet.merged_cells.ranges: + if merged_range.min_row <= row <= merged_range.max_row: + merged_cells_to_unmerge.append(str(merged_range)) + for merged_range_str in merged_cells_to_unmerge: + sheet.unmerge_cells(merged_range_str) + + # 先为所有列应用模板样式 + for col in range(1, 11): # A到J列 + 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 = copy(template_styles[col]['alignment']) + + # A列:序号(从1开始) + sheet.cell(row=row, column=1, value=index) + + # B列:设备名称 + sheet.cell(row=row, column=2, value=record.name or '') + + # C列:型号 + sheet.cell(row=row, column=3, value=record.model or '') + + # D列:原值 + sheet.cell(row=row, column=4, value=record.cost or 0) + + # E列:寿命 + warranty_date = '' + if record.warranty_date: + warranty_date = record.warranty_date.strftime('%Y-%m-%d') + sheet.cell(row=row, column=5, value=warranty_date) + + # F列:设备状态 + 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) + + # 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.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.company_id.name if record.company_id else '') + + # 设置最小行高,确保内容显示完整 + if not sheet.row_dimensions[row].height or sheet.row_dimensions[row].height < 30: + sheet.row_dimensions[row].height = 30 + + row += 1 + + # 保存到内存 + output = BytesIO() + workbook.save(output) + output.seek(0) + excel_data = base64.b64encode(output.read()) + + # 创建附件 + filename = f'固定资产盘点表_{datetime.datetime.now().strftime("%Y%m%d%H%M%S")}.xlsx' + attachment = self.env['ir.attachment'].create({ + 'name': filename, + 'type': 'binary', + 'datas': excel_data, + 'res_model': 'maintenance.equipment', + 'res_id': equipment_records[0].id, + 'mimetype': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + }) + + # 返回下载链接 + return { + 'type': 'ir.actions.act_url', + 'url': f'/web/content/{attachment.id}?download=true', + 'target': 'self', + } + class MaintenanceEquipmentLine(models.Model): _name = 'maintenance.equipment.line' diff --git a/yuthon_maintain/views/maintenance_equipment_views.xml b/yuthon_maintain/views/maintenance_equipment_views.xml index b223d5e21..84c373bba 100644 --- a/yuthon_maintain/views/maintenance_equipment_views.xml +++ b/yuthon_maintain/views/maintenance_equipment_views.xml @@ -186,4 +186,13 @@ code action = model.add_office_supplies() + + + 导出盘点表 + + + list + code + action = model.export_inventory_report() + \ No newline at end of file diff --git a/yuthon_property/static/tmpl/gudingzichanpandianbiao.xlsx b/yuthon_property/static/tmpl/gudingzichanpandianbiao.xlsx new file mode 100644 index 000000000..6a8a70b88 Binary files /dev/null and b/yuthon_property/static/tmpl/gudingzichanpandianbiao.xlsx differ diff --git a/yuthon_stock/models/inherit_stock_picking.py b/yuthon_stock/models/inherit_stock_picking.py index a6b95e3ec..d25969e31 100644 --- a/yuthon_stock/models/inherit_stock_picking.py +++ b/yuthon_stock/models/inherit_stock_picking.py @@ -64,7 +64,7 @@ class StockPicking(models.Model): record.can_certify = True def read(self, fields=None, load='_classic_read'): - """重写read方法,打开验收状态的入库单时自动更新验收时间""" + """重写read方法,打开验收/证明状态的入库单时自动更新时间""" result = super(StockPicking, self).read(fields, load) # 导入Fields模块 from odoo import fields as odoo_fields @@ -74,6 +74,11 @@ class StockPicking(models.Model): record.write({ 'acceptance_date': odoo_fields.Datetime.now() }) + elif record.receipt_status == 'certification': + # 使用write方法更新证明时间 + record.write({ + 'certification_date': odoo_fields.Datetime.now() + }) return result @api.depends('location_id')