diff --git a/yuthon_maintain/models/inherit_maintenance_equipment.py b/yuthon_maintain/models/inherit_maintenance_equipment.py index f4e58720e..cd72e0355 100644 --- a/yuthon_maintain/models/inherit_maintenance_equipment.py +++ b/yuthon_maintain/models/inherit_maintenance_equipment.py @@ -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', diff --git a/yuthon_property/static/tmpl/gudingzichanpandianbiao.xlsx b/yuthon_property/static/tmpl/gudingzichanpandianbiao.xlsx index 6a8a70b88..5cf4559ef 100644 Binary files a/yuthon_property/static/tmpl/gudingzichanpandianbiao.xlsx and b/yuthon_property/static/tmpl/gudingzichanpandianbiao.xlsx differ diff --git a/yuthon_stock/models/inherit_stock_move.py b/yuthon_stock/models/inherit_stock_move.py index cef654be0..8561887ed 100644 --- a/yuthon_stock/models/inherit_stock_move.py +++ b/yuthon_stock/models/inherit_stock_move.py @@ -26,3 +26,5 @@ class ProductProduct(models.Model): class StockMove(models.Model): _inherit = 'stock.move' + + diff --git a/yuthon_stock/models/inherit_stock_picking.py b/yuthon_stock/models/inherit_stock_picking.py index d25969e31..42659ac5a 100644 --- a/yuthon_stock/models/inherit_stock_picking.py +++ b/yuthon_stock/models/inherit_stock_picking.py @@ -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 \ No newline at end of file + 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 \ No newline at end of file diff --git a/yuthon_stock/views/inherit_stock_picking.xml b/yuthon_stock/views/inherit_stock_picking.xml index da76036bf..b29f956a6 100644 --- a/yuthon_stock/views/inherit_stock_picking.xml +++ b/yuthon_stock/views/inherit_stock_picking.xml @@ -8,8 +8,11 @@ + + [('id', 'in', available_location_ids)] + - receipt_status in ['acceptance', 'certification'] + state != 'draft' and receipt_status in ['acceptance', 'certification'] 1 @@ -18,6 +21,7 @@ + @@ -31,14 +35,14 @@ - - - + + + - - - + + + @@ -66,10 +70,10 @@ 供应商 - receipt_status in ['acceptance', 'certification'] + state != 'draft' and receipt_status in ['acceptance', 'certification'] - receipt_status in ['acceptance', 'certification'] + state != 'draft' and receipt_status in ['acceptance', 'certification'] @@ -84,6 +88,11 @@ stock.picking + +