from odoo import models, fields, api, _, SUPERUSER_ID from odoo.exceptions import UserError, ValidationError from dateutil.relativedelta import relativedelta from datetime import datetime, time, timedelta import xlrd import base64 import pandas as pd import re class InitializeWizard(models.TransientModel): _name = 'initialize.wizard' _description = '应收账单初始化数据弹窗' excel_file = fields.Binary(string="上传Excel表") excel_name = fields.Char(string="文件名") def confirm(self): """ 导入excel文件,按行读取数据并处理,去重显示未找到的合同 """ if not self.excel_file: raise ValidationError('请上传文件。') book = xlrd.open_workbook(file_contents=base64.decodebytes(self.excel_file)) sh = book.sheet_by_index(0) success_count = 0 missing_contracts = set() other_errors = [] # 记录其他错误 for rx in range(1, sh.nrows): row = sh.row(rx) contract_code = row[0].value # 检查合同是否存在 contract_id = self.env['property.lease.contract'].search([('contract_code', '=', contract_code)], limit=1) if not contract_id: # 合同不存在,添加到集合(自动去重) missing_contracts.add(contract_code) continue # 合同存在,处理该行数据 try: self.property_initializer_data(row, contract_id) success_count += 1 except Exception as e: other_errors.append(f"合同 {contract_code} 处理失败:{str(e)}") # 生成处理结果信息 result_msg = f"处理完成,成功导入 {success_count} 条数据" # 添加未找到的合同信息(去重后) if missing_contracts: contracts_list = ", ".join(str(contract) for contract in missing_contracts) result_msg += f",以下合同不存在:{contracts_list}" # 添加其他错误信息 if other_errors: result_msg += "\n其他错误:\n" + "\n".join(other_errors) # 显示处理结果 return { 'type': 'ir.actions.client', 'tag': 'display_notification', 'params': { 'message': result_msg, 'type': 'info', 'sticky': True, } } def property_initializer_data(self, row, contract_id): # 直接使用传入的已验证存在的contract_id property_id = self.env['yuthon.property'].search([('name', '=', row[1].value)], limit=1) lessee_id = self.env['property.tenant.information'].search([('name', '=', row[2].value)], limit=1) due_date_value = row[3].value if isinstance(due_date_value, float): due_date = datetime(1899, 12, 30) + timedelta(days=due_date_value) else: due_date = datetime.strptime(due_date_value, '%Y-%m-%d') due_date_end = False if row[4].value: end_date_value = row[4].value if isinstance(end_date_value, float): due_date_end = datetime(1899, 12, 30) + timedelta(days=end_date_value) else: due_date_end = datetime.strptime(end_date_value, '%Y-%m-%d') original_amount = row[5].value submitted = row[6].value management_type_id = self.env['yuthon.management.type'].search([('name', '=', row[8].value)], limit=1) remark = row[7].value # 查找应收款记录 receivable = self.env['property.accounts.receivable'].search([ ('contract_id', '=', contract_id.id), ('due_date', '=', due_date), ('due_date_end', '=', due_date_end), ]) if not receivable: self.env['property.accounts.receivable'].create({ 'contract_id': contract_id.id, 'lessee_id': lessee_id.id, 'due_date': due_date, 'due_date_end': due_date_end, 'original_amount': original_amount, 'submitted': submitted, 'management_type_id': management_type_id.id, 'remark': remark, }) else: receivable.write({ 'contract_id': contract_id.id, 'lessee_id': lessee_id.id, 'due_date': due_date, 'due_date_end': due_date_end, 'original_amount': original_amount, 'submitted': submitted, 'management_type_id': management_type_id.id, 'remark': remark, })