目录
1.建立个性化导入的临时模型
from odoo import models, fields, api class NameImport(models.TransientModel): _name = 'name.import' # 临时模型名名称,一般 项目简称.功能.import _description = '临时模型的导入功能的具体描述' # 导入的文件 inventory_file = fields.Binary(string="选择模板", help="File Import") # 导入文件的名称 inventory_file_name = fields.Char(string="导入文件的名称")
2.个性化导入的临时模型的xml视图
<?xml version="1.0" encoding="utf-8" ?> <odoo> <data> <record id="name_import_form" model="ir.ui.view"> <field name="name">个性化导入form视图</field> <field name="model">个性化导入的临时模型的名称</field> <field name="arch" type="xml"> <form> <button name="download_import_temp" string="下载导入模板" type="object" class="oe_link"/> <group> <field name="inventory_file" filename="inventory_file_name"/> <field name="inventory_file_name" invisible="1"/> </group> <footer> <button name="import_confirm" string="确定" type="object" class="oe_highlight"/> <button string="取消" class="oe_link" special="cancel"/> </footer> </form> </field> </record> <act_window id="name_import_action" name="导入" res_model="个性化导入的临时模型的名称" binding_model="导入按钮绑定到那个模型上,即给那个模型创建个性化导入功能" view_mode="form" view_id="name_import_form" target="new" context="{'on_tree': '2', 'btn_class': 'btn-secondary'}"/> <report id="name_import_temp_xlsx" model="个性化导入的临时模型的名称" string="个性化的导入的下载模板时的名称" report_type="xlsx" name="个性化导入的下载模板时,对应的xlxs模型逻辑的模型名,取report.后面的所有值" file="个性化的导入的下载模板时的名称" attachment_use="False" /> </data> </odoo>
效果:
3.下载导入模板的逻辑
在个性化导入的临时模型中添加该方法,
注意: 函数名是对应的xml中下载导入模板按钮的name的值
report_name的取值是下方的,xlsx的模型的report.后面的值
# 下载导入模板 def download_import_temp(self): return { 'type': 'ir.actions.report', 'report_name': 'report.后面的值', 'report_type': 'xlsx' }
对应的下载导入模板的模型类
下方的逻辑为示例
需注意的:
row1一般是示例标题,就是表头
row2一般是示例的第一行数据
设置好格式和样式直接写入即可
class InsuranceImportTempXlsx(models.AbstractModel): _name = 'report.模块名.功能_import_temp_xlsx' _inherit = 'report.report_xlsx.abstract' _description = '下载xx导入模板' # 描述 def dict_union(self, dict1, dict2): """ :return: """ return {**dict1, **dict2} def generate_xlsx_report(self, wb, data, objs): # 要写入excel模板的数据 row1 = ['*公司', '*员工', '*员工编号', '*养老单位缴纳基数', '*养老单位缴纳金额', '*失业单位缴纳基数', '*失业单位缴纳金额', '*医疗单位缴纳基数', '*医疗单位缴纳金额', '*工伤单位缴纳基数', '*工伤单位缴纳金额', '*生育单位缴纳基数', '*生育单位缴纳金额', '*单位补充医保缴费基数', '*单位补充医保缴费金额', '*单位职业年金缴费基数', '*单位职业年金缴费金额', '*个人所有保险缴费金额', '*住房公积金单位缴纳基数', '*住房公积金单位缴纳金额', '*住房公积金个人缴纳金额'] row2 = ['山东省肿瘤医院', '[H0001]1', 'H0001', '0', '0.00', '0', '0.00', '0', '0.00', '0', '0.00', '0', '0.00', '0', '0.00', '0', '0.00', '0.00', '0', '0.00', '0.00', '导入时请勿删除示例!!!'] # format ten_font_style = { 'font_name': u'微软雅黑', 'font_size': 10, 'valign': 'vcenter', 'align': 'center', 'text_wrap': True } bold_style = wb.add_format(self.dict_union(ten_font_style, {'bold': True})) green_bold_style = wb.add_format(self.dict_union(ten_font_style, {'bold': True, 'font_color': 'green'})) red_style = wb.add_format(self.dict_union(ten_font_style, {'font_color': 'red'})) # blue_style = wb.add_format(self.dict_union(ten_font_style, {'font_color': 'blue'})) ws = wb.add_worksheet('五险一金导入模板') ws.set_column(0, 0, 19.5) ws.set_column(1, 2, 8.5) ws.set_column(3, 21, 30) row_pos = 0 ws.set_row(row_pos, 23) for index, value in enumerate(row1): if index < 3: ws.write(row_pos, index, value, bold_style) elif index < 21: ws.write(row_pos, index, value, green_bold_style) else: ws.write(row_pos, index, value, red_style) row_pos += 1 ws.set_row(row_pos, 15) for index, value in enumerate(row2): ws.write(row_pos, index, value, red_style)
4. 导入的功能
在个性化导入的临时模型中写入
- import_confirm也是对应xml中按钮的名称,这个函数的功能是建立后台任务,让后台任务去进行导入
- import_confirm中的method的对应的方法就是具体的读取并写入系统的逻辑,
- 注意的是,读取的时候,第一行和第二行为标题和示例数据需要跳过,从第三行开始读取即可,
# 薪酬数据导入 def import_confirm(self): now_datetime = fields.Datetime.to_string(fields.Datetime.context_timestamp(self, fields.Datetime.now())) # 导入对象 objs = ['sdszl.hr.insurance'] self.env['ir.actuator.user.list'].sudo().create({ 'name': '五险一金导入程序', 'description': f"导入对象:{objs}-{now_datetime}", 'model_name': 'sdszl.hr.insurance.import', 'method': 'write_to_model', 'method_args': [self.id, objs], }).run_actuator() return { 'type': 'ir.actions.act_multi', 'actions': [ {'type': 'ir.actions.act_window_close'}, { 'type': 'ir.actions.act_window.message', 'title': '信息', 'message': "已提交请求,可在用户任务中查看请求状态", } ] } def write_to_model(self, objs): if not self.inventory_file: raise ValidationError('未上传文件') # 对传入的文件进行base64解码,然后调用open_workbook对文件进行解析 book = xlrd.open_workbook(file_contents=base64.b64decode(self.inventory_file)) # 读入第一个sheet页 sh = book.sheet_by_index(0) insurance_obj = self.env['sdszl.hr.insurance'] insurance_data = [] # 开始处理数据行,跳过标题行和示例行,从第三行开始 error_list = [] row_num = 2 for rx in range(2, sh.nrows): row_num += 1 row = sh.row_values(rx) row_error = [] company_name = row[0] company = self.env['res.company'].search([('name', '=', company_name)], limit=1) if not company: row_error.append(f'第{row_num}行,找不到公司{company_name}!') employee_code = row[2] employee = self.env['eno.employee'].search([ ('company_id.name', '=', company_name), ('code', '=', employee_code)], limit=1) if not employee: row_error.append(f'找不到公司为 {company_name},编号为 {employee_code}的员工!') if not row_error: old_data = insurance_obj.search([('company_id.name', '=', company_name), ('employee_code', '=', employee_code)], limit=1) if old_data: old_data.update({ 'yl_payment_base': row[3], 'yl_payment_proportion': row[4], 'sy_payment_base': row[5], 'sy_payment_proportion': row[6], 'yli_payment_base': row[7], 'yli_payment_proportion': row[8], 'gs_payment_base': row[9], 'gs_payment_proportion': row[10], 'syu_payment_base': row[11], 'syu_payment_proportion': row[12], 'bq_payment_base': row[13], 'bq_payment_proportion': row[14], 'zy_payment_base': row[15], 'zy_payment_proportion': row[16], 'gr_payment_proportion': row[17], 'gjj_payment_base': row[18], 'gjj_payment_proportion_1': row[19], 'gjj_payment_proportion_2': row[20], }) else: insurance_data.append({ 'company_id': company.id, 'employee_id': employee.id, 'yl_payment_base': row[3], 'yl_payment_proportion': row[4], 'sy_payment_base': row[5], 'sy_payment_proportion': row[6], 'yli_payment_base': row[7], 'yli_payment_proportion': row[8], 'gs_payment_base': row[9], 'gs_payment_proportion': row[10], 'syu_payment_base': row[11], 'syu_payment_proportion': row[12], 'bq_payment_base': row[13], 'bq_payment_proportion': row[14], 'zy_payment_base': row[15], 'zy_payment_proportion': row[16], 'gr_payment_proportion': row[17], 'gjj_payment_base': row[18], 'gjj_payment_proportion_1': row[19], 'gjj_payment_proportion_2': row[20], }) else: errors = '\n'.join(row_error) error_list.append(f"第{row_num}行:\n{errors}") if error_list: raise ValidationError('\n'.join(error_list)) else: insurance_obj.create(insurance_data)
odoo13中的个性化导入
于 2022-07-07 11:21:09 首次发布