From a632ee2ac358b9db810709ff21c1236cf6c38457 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Mon, 29 Jan 2024 11:21:55 +0100 Subject: [PATCH] [MIG] account_import_helper to v17 Several improvements: - better handling of company. - single step wizard - move description from manifest to README --- account_import_helper/README.rst | 50 ++++++++++++++++++ account_import_helper/__init__.py | 2 +- account_import_helper/__manifest__.py | 45 +--------------- .../demo/chart_to_import.csv | 10 ---- .../demo/chart_to_import.xlsx | Bin 0 -> 5072 bytes account_import_helper/models/__init__.py | 1 + .../{account.py => models/res_company.py} | 17 +++--- .../wizard/account_chart_generate.py | 18 ++++--- .../wizard/account_chart_generate_view.xml | 19 ++----- 9 files changed, 74 insertions(+), 88 deletions(-) create mode 100644 account_import_helper/README.rst delete mode 100644 account_import_helper/demo/chart_to_import.csv create mode 100644 account_import_helper/demo/chart_to_import.xlsx create mode 100644 account_import_helper/models/__init__.py rename account_import_helper/{account.py => models/res_company.py} (93%) diff --git a/account_import_helper/README.rst b/account_import_helper/README.rst new file mode 100644 index 0000000..98fd939 --- /dev/null +++ b/account_import_helper/README.rst @@ -0,0 +1,50 @@ +===================== +Account Import Helper +===================== + +This module provides methods to help on the import of accounting-related data, in particular the chart of accounts. + +First, in a standard test Odoo database with the chart of account of the official addons, use the wizard available via the menu *Configuration > Technical > Chart Generate > Chart Generate* to generate the file *account.account.csv*. + +Then, in the future production database, after the installation of the official addons that has the chart of accounts for the country: + +* Unconfigure the links to the accounts from several objects and ir.properties: + +.. code:: + + UPDATE account_journal set default_account_id=null, suspense_account_id=null; + + DELETE from pos_payment_method; + + UPDATE ir_property SET value_reference=null WHERE value_reference like 'account.account,%'; + +* Delete all accounts: + +.. code:: + + DELETE FROM account_account; + +* In the menu *Invoicing > Configuration > Accounting > Chart of accounts*, import the file *account.account.csv* with *Encoding* set to **utf-8** and *Use first row as header* enabled. + +* In the menu *Invoicing > Configuration > Accounting > Taxes*, reconfigure the account on taxes. + +* In the menu *Invoicing > Configuration > Accounting > Fiscal Positions*, on each fiscal position, configure the account mapping. + +* In the menu *Invoicing > Configuration > Accounting > Journals*, on each journal, configure all the fields that point to accounts. + +* On the page *Invoicing > Configuration > Settings*, update the section *Default Accounts* + +* In the menu *Settings > Technical > Parameters > Company Properties*, edit the 4 properties + + - property_account_receivable_id + - property_account_payable_id + - property_account_expense_categ_id + - property_account_income_categ_id + +and set the field *value* with **account.account,67** where 67 is the ID of the account you want to have as default for that property. + + +Contributors +============ + +This module has been written by Alexis de Lattre from `Akretion France `_. diff --git a/account_import_helper/__init__.py b/account_import_helper/__init__.py index 92c3542..9b42961 100644 --- a/account_import_helper/__init__.py +++ b/account_import_helper/__init__.py @@ -1,2 +1,2 @@ -from . import account +from . import models from . import wizard diff --git a/account_import_helper/__manifest__.py b/account_import_helper/__manifest__.py index d3f6689..e006542 100644 --- a/account_import_helper/__manifest__.py +++ b/account_import_helper/__manifest__.py @@ -8,49 +8,6 @@ "category": "Partner", "license": "AGPL-3", "summary": "Helper methods to import accounting-related data", - "description": """ -Account Import Helper -===================== - -This module provides methods to help on the import of accounting-related data, in particular the chart of accounts. - -First, in a standard test Odoo database with the chart of account of the official addons, use the wizard available via the menu *Configuration > Technical > Chart Generate > Chart Generate* to generate the file *account.account.csv*. - -Then, in the future production database, after the installation of the official addons that has the chart of accounts for the country: - -* Unconfigure the links to the accounts from several objects and ir.properties: - -UPDATE account_journal set default_account_id=null, suspense_account_id=null; - -DELETE from pos_payment_method; - -UPDATE ir_property SET value_reference=null WHERE value_reference like 'account.account,%'; - -* Delete all accounts: - -DELETE FROM account_account; - -* Go to the menu *Invoicing > Configuration > Accounting > Chart of accounts* and import the file *account.account.csv* with Encoding = UTF-8 - -* In the menu *Accounting > Configuration > Accounting > Taxes* and reconfigure the account on taxes. - -* In the menu *Accounting > Configuration > Accounting > Fiscal Positions*, on each fiscal position, configure the account mapping. - -* In the menu *Accounting > Configuration > Accounting > Journals*, on each journal, configure all the fields that point to accounts. - -* On the page *Accounting > Configuration > Settings*, configure the *Inter-Banks Transfer Account* (field displayed by my module account_usability) - -* In the menu *Settings > Technical > Parameters > Company Properties*, edit the 4 properties - - - property_account_receivable_id - - property_account_payable_id - - property_account_expense_categ_id - - property_account_income_categ_id - -and set the field *value* with *account.account,67* where 67 is the ID of the account you want to have as default for that property. - -This module has been written by Alexis de Lattre from Akretion. - """, "author": "Akretion", "website": "https://github.com/akretion/odoo-import-helper", "depends": ["account"], @@ -59,5 +16,5 @@ "security/ir.model.access.csv", "wizard/account_chart_generate_view.xml", ], - "installable": False, + "installable": True, } diff --git a/account_import_helper/demo/chart_to_import.csv b/account_import_helper/demo/chart_to_import.csv deleted file mode 100644 index f66d00d..0000000 --- a/account_import_helper/demo/chart_to_import.csv +++ /dev/null @@ -1,10 +0,0 @@ -401000,Fournisseurs -411000,Clients -607000,Marchandises,Produits achetés pour revente -626000,Telecom -706100,Vente de Service France -706200,Vente de Service UE -706300,Vente de Service Reste du monde -707100,Vente marchandise France -707200,Vente marchandise UE -707300,Vente marchandise Reste du monde diff --git a/account_import_helper/demo/chart_to_import.xlsx b/account_import_helper/demo/chart_to_import.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..391dd6070f185e95f016217e934f1d29f227e7fb GIT binary patch literal 5072 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 O40|bI_0j+LU;Y=3jix35 literal 0 HcmV?d00001 diff --git a/account_import_helper/models/__init__.py b/account_import_helper/models/__init__.py new file mode 100644 index 0000000..aff44f3 --- /dev/null +++ b/account_import_helper/models/__init__.py @@ -0,0 +1 @@ +from . import res_company diff --git a/account_import_helper/account.py b/account_import_helper/models/res_company.py similarity index 93% rename from account_import_helper/account.py rename to account_import_helper/models/res_company.py index 05b367b..b8a5cda 100644 --- a/account_import_helper/account.py +++ b/account_import_helper/models/res_company.py @@ -19,8 +19,8 @@ # - can use 580001 -class AccountAccount(models.Model): - _inherit = "account.account" +class ResCompany(models.Model): + _inherit = "res.company" @api.model def generate_id2xmlid(self, object_name): @@ -31,7 +31,6 @@ def generate_id2xmlid(self, object_name): obj_id2xmlid[entry.res_id] = "{}.{}".format(entry.module, entry.name) return obj_id2xmlid - @api.model def generate_custom_chart( self, custom_chart, @@ -45,12 +44,12 @@ def generate_custom_chart( # tuple: ('622600', {'name': 'Honoraires comptables'}) # in the second value of the tuple, we often only put name, # but we can put other odoo properties + self.ensure_one() taxtemplate2xmlid = self.generate_id2xmlid("account.tax.template") logger.info("taxtemplate2xmlid = %s", taxtemplate2xmlid) - company = self.env.user.company_id # pre-load odoo's chart of account odoo_chart = {} - accounts = self.search([("company_id", "=", company.id)]) + accounts = self.env['account.account'].search([("company_id", "=", self.id)]) odoo_code_size = False for account in accounts: taxes_xmlids = [taxtemplate2xmlid[tax.id] for tax in account.tax_ids] @@ -100,11 +99,11 @@ def generate_custom_chart( size = odoo_code_size else: size = len(custom_code) - match = False + exit_while = False matching_code = custom_code if custom2odoo_code_map and custom_code in custom2odoo_code_map: matching_code = custom2odoo_code_map[custom_code] - while size > 1 and not match: + while size > 1 and not exit_while: short_matching_code = matching_code[:size] for odoo_code, odoo_dict in odoo_chart.items(): if odoo_code.startswith(short_matching_code): @@ -119,10 +118,10 @@ def generate_custom_chart( if not with_taxes: custom_dict["tax_xmlids"] = "" res.append(custom_dict) - match = True + exit_while = True break size -= 1 - if not match: + if not exit_while: raise UserError( _("Customer account %s '%s' didn't match any Odoo account") % (custom_code, src_custom_dict.get("name")) diff --git a/account_import_helper/wizard/account_chart_generate.py b/account_import_helper/wizard/account_chart_generate.py index 4a728dc..938fb46 100644 --- a/account_import_helper/wizard/account_chart_generate.py +++ b/account_import_helper/wizard/account_chart_generate.py @@ -35,9 +35,9 @@ class AccountChartGenerate(models.TransientModel): input_has_header_line = fields.Boolean(string="Has a header line", help="Enable this option if the first line of the XLSX file is a header line which must be skipped.") out_csv_file = fields.Binary(string="Result CSV file", readonly=True) out_csv_filename = fields.Char(readonly=True) - state = fields.Selection( - [("step1", "step1"), ("step2", "step2")], default="step1", required=True - ) + company_id = fields.Many2one( + 'res.company', string="Source Company", required=True, readonly=True, + default=lambda self: self.env.company) def _prepare_custom2odoo_code_map(self): custom2odoo_code_map = {} @@ -74,7 +74,7 @@ def run(self): fileobj.close() pprint(custom_chart) logger.info("Starting to generate CSV file") - res = self.env["account.account"].generate_custom_chart( + res = self.company_id.generate_custom_chart( custom_chart, module=self.module, xmlid_prefix=self.xmlid_prefix, @@ -102,14 +102,16 @@ def run(self): res_file = fout.read() self.write( { - "state": "step2", "out_csv_file": base64.b64encode(res_file.encode('utf-8')), "out_csv_filename": "account.account-%s.csv" % self.module, } ) fout.close() logger.info("End of the generation of CSV file") - action = self.env["ir.actions.actions"]._for_xml_id( - "account_import_helper.account_chart_generate_action") - action["res_id"] = self.ids[0] + action = { + 'name': 'Result', + 'type': 'ir.actions.act_url', + 'url': f"web/content/?model=account.chart.generate&id={self.id}&filename_field=out_csv_filename&field=out_csv_file&download=true&filename={self.out_csv_filename}", + 'target': 'new', + } return action diff --git a/account_import_helper/wizard/account_chart_generate_view.xml b/account_import_helper/wizard/account_chart_generate_view.xml index fb08024..995fcee 100644 --- a/account_import_helper/wizard/account_chart_generate_view.xml +++ b/account_import_helper/wizard/account_chart_generate_view.xml @@ -12,7 +12,7 @@ account.chart.generate
-
+

Input XLSX file must have 3 columns:

  • A. Account Code (field code, required)
  • @@ -21,9 +21,7 @@
- - - + @@ -31,9 +29,7 @@ - - - +