diff options
| author | wan <wan@odoo.com> | 2019-06-18 14:43:07 +0000 |
|---|---|---|
| committer | wan <wan@odoo.com> | 2019-07-19 09:34:59 +0000 |
| commit | f722ef0cb079ab2368d4f4075e4c42c0ab9c376a (patch) | |
| tree | d110cb3bec6b6b62c9a61c6b615b8cb7b74cbd7b | |
| parent | 4b66aa58b9daf83bd72b0e1830d25fcf074320c6 (diff) | |
[IMP] account, _facturx, l10n[be,it]_edi: remove account.invoice.import.wizard
Since the wizard is not shown anymore (skipped to go right to file selection), we can remove it. Small refactoring had to be done for l10n_it in order to upload files with multiple invoices inside and to detect format
closes odoo/odoo#34145
Signed-off-by: Quentin De Paoli (qdp) <qdp@openerp.com>
| -rw-r--r-- | addons/account/__manifest__.py | 1 | ||||
| -rw-r--r-- | addons/account/models/account.py | 29 | ||||
| -rw-r--r-- | addons/account/static/src/js/bills_tree_upload.js | 12 | ||||
| -rw-r--r-- | addons/account/static/src/xml/bills_tree_upload_views.xml | 11 | ||||
| -rw-r--r-- | addons/account/wizard/__init__.py | 1 | ||||
| -rw-r--r-- | addons/account/wizard/account_invoice_import.py | 47 | ||||
| -rw-r--r-- | addons/account/wizard/account_invoice_import_view.xml | 29 | ||||
| -rw-r--r-- | addons/account_facturx/models/account_move.py | 12 | ||||
| -rw-r--r-- | addons/l10n_be_edi/models/account_invoice.py | 2 | ||||
| -rw-r--r-- | addons/l10n_it_edi/models/account_invoice.py | 49 | ||||
| -rw-r--r-- | addons/l10n_it_edi/models/ir_mail_server.py | 9 |
11 files changed, 73 insertions, 129 deletions
diff --git a/addons/account/__manifest__.py b/addons/account/__manifest__.py index f7ab4fcac79..bdbefa57126 100644 --- a/addons/account/__manifest__.py +++ b/addons/account/__manifest__.py @@ -24,7 +24,6 @@ You could use this simplified accounting in case you work with an (external) acc 'data/digest_data.xml', 'views/account_menuitem.xml', 'views/account_payment_view.xml', - 'wizard/account_invoice_import_view.xml', 'wizard/account_unreconcile_view.xml', 'wizard/account_move_reversal_view.xml', 'views/account_move_views.xml', diff --git a/addons/account/models/account.py b/addons/account/models/account.py index 5f591c991b9..d99559672c3 100644 --- a/addons/account/models/account.py +++ b/addons/account/models/account.py @@ -9,6 +9,7 @@ from odoo.tools.float_utils import float_round as round, float_compare from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT from odoo.exceptions import UserError, ValidationError from odoo import api, fields, models, _ +from odoo.tests.common import Form class AccountAccountType(models.Model): @@ -953,6 +954,34 @@ class AccountJournal(models.Model): # We simply call the setup bar function. return self.env['res.company'].setting_init_bank_account_action() + def create_invoice_from_attachment(self, attachment_ids=[]): + ''' Create the invoices from files. + :return: A action redirecting to account.move tree/form view. + ''' + attachments = self.env['ir.attachment'].browse(attachment_ids) + if not attachments: + raise UserError(_("No attachment was provided")) + + invoices = self.env['account.move'] + for attachment in attachments: + invoice = self.env['account.move'].create({}) + attachment.write({'res_model': 'account.move', 'res_id': invoice.id}) + invoice.message_post(attachment_ids=[attachment.id]) + invoices += invoice + + action_vals = { + 'name': _('Generated Documents'), + 'domain': [('id', 'in', invoices.ids)], + 'res_model': 'account.move', + 'views': [[False, "tree"], [False, "form"]], + 'type': 'ir.actions.act_window', + } + if len(invoices) == 1: + action_vals.update({'res_id': invoices[0].id, 'view_mode': 'form'}) + else: + action_vals['view_mode'] = 'tree,form' + return action_vals + class ResPartnerBank(models.Model): _inherit = "res.partner.bank" diff --git a/addons/account/static/src/js/bills_tree_upload.js b/addons/account/static/src/js/bills_tree_upload.js index 835dc42b7d9..2287ca09d7c 100644 --- a/addons/account/static/src/js/bills_tree_upload.js +++ b/addons/account/static/src/js/bills_tree_upload.js @@ -32,15 +32,12 @@ odoo.define('account.upload.bill.mixin', function (require) { var attachent_ids = attachments.reduce(function(filtered, record) { if (record.id) { filtered.push(record.id); - } + } return filtered; }, []); - if (!attachent_ids.length) { - return self.do_notify(_t("Error"), _t("An error occurred during the upload")); - } return this._rpc({ - model: 'account.invoice.import.wizard', - method: 'create_invoices', + model: 'account.journal', + method: 'create_invoice_from_attachment', args: ["", attachent_ids], context: this.initialState.context, }).then(function(result) { @@ -50,9 +47,6 @@ odoo.define('account.upload.bill.mixin', function (require) { _onUpload: function (event) { var self = this; - if (!this.initialState.context.journal_type) { - this.initialState.context.journal_type = event.currentTarget.attributes['journal_type'].value; - } // If hidden upload form don't exists, create it var $formContainer = this.$('.o_content').find('.o_vendor_bill_upload'); if (!$formContainer.length) { diff --git a/addons/account/static/src/xml/bills_tree_upload_views.xml b/addons/account/static/src/xml/bills_tree_upload_views.xml index af9385a5780..93502ee9136 100644 --- a/addons/account/static/src/xml/bills_tree_upload_views.xml +++ b/addons/account/static/src/xml/bills_tree_upload_views.xml @@ -4,6 +4,7 @@ <t t-name="account.BillsHiddenUploadForm"> <div class="d-none o_vendor_bill_upload"> <t t-call="HiddenInputFile"> + <t t-set="multi_upload" t-value="true"/> <t t-set="fileupload_id" t-value="widget.fileUploadID"/> <t t-set="fileupload_action" t-translation="off">/web/binary/upload_attachment</t> <input type="hidden" name="model" t-att-value="'account.move'"/> @@ -19,11 +20,9 @@ r.push(context.engine.tools.call(context, 'ImportView.import_button', dict)); }; </t> - <t t-if="widget.initialState.context.journal_type === 'purchase'"> - <button type="button" class="btn btn-secondary o_button_upload_bill"> - Upload - </button> - </t> + <button type="button" class="btn btn-secondary o_button_upload_bill"> + Upload + </button> </t> </t> -</templates>
\ No newline at end of file +</templates> diff --git a/addons/account/wizard/__init__.py b/addons/account/wizard/__init__.py index f61453de267..c23f76b521b 100644 --- a/addons/account/wizard/__init__.py +++ b/addons/account/wizard/__init__.py @@ -3,7 +3,6 @@ from . import account_unreconcile -from . import account_invoice_import from . import account_validate_account_move from . import pos_box from . import account_move_reversal diff --git a/addons/account/wizard/account_invoice_import.py b/addons/account/wizard/account_invoice_import.py deleted file mode 100644 index 4ce6675bc81..00000000000 --- a/addons/account/wizard/account_invoice_import.py +++ /dev/null @@ -1,47 +0,0 @@ -# -*- coding: utf-8 -*- -from odoo import api, fields, models, _ -from odoo.tests.common import Form -from odoo.exceptions import UserError - - -class ImportInvoiceImportWizard(models.TransientModel): - _name = 'account.invoice.import.wizard' - _description = 'Import Your Vendor Bills from Files.' - - attachment_ids = fields.Many2many('ir.attachment', string='Files') - - def _create_invoice_from_file(self, attachment): - invoice = self.env['account.move'].create({}) - attachment.write({'res_model': 'account.move', 'res_id': invoice.id}) - invoice.message_post(attachment_ids=[attachment.id]) - return invoice - - def _create_invoice(self, attachment): - return self._create_invoice_from_file(attachment) - - def create_invoices(self, attachment_ids=[]): - ''' Create the invoices from files. - :return: A action redirecting to account.invoice tree/form view. - ''' - attachments = self.attachment_ids or self.env['ir.attachment'].browse(attachment_ids) - if not attachments: - raise UserError(_("No attachment was provided")) - - invoices = self.env['account.move'] - for attachment in attachments: - invoices += self._create_invoice(attachment) - - action_vals = { - 'name': _('Generated Documents'), - 'domain': [('id', 'in', invoices.ids)], - 'view_type': 'form', - 'res_model': 'account.move', - 'views': [[False, "tree"], [False, "form"]], - 'type': 'ir.actions.act_window', - 'context': self.env.context, - } - if len(invoices) == 1: - action_vals.update({'res_id': invoices[0].id, 'view_mode': 'form'}) - else: - action_vals['view_mode'] = 'tree,form' - return action_vals diff --git a/addons/account/wizard/account_invoice_import_view.xml b/addons/account/wizard/account_invoice_import_view.xml deleted file mode 100644 index 9e9a2cd3b69..00000000000 --- a/addons/account/wizard/account_invoice_import_view.xml +++ /dev/null @@ -1,29 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<odoo> - <data> - <record id="account_invoice_import_wizard_form_view" model="ir.ui.view"> - <field name="name">account.invoice.import.wizard.form</field> - <field name="model">account.invoice.import.wizard</field> - <field name="arch" type="xml"> - <form> - <group> - <field name="attachment_ids" widget="many2many_binary" colspan="2" - string="Upload Files" nolabel="1"/> - </group> - <footer> - <button string="Import" name="create_invoices" type="object" class="oe_highlight"/> - <button string="Cancel" class="btn btn-secondary" special="cancel"/> - </footer> - </form> - </field> - </record> - - <record id="account_invoice_import_wizard_action" model="ir.actions.act_window"> - <field name="name">Import Vendor Bills</field> - <field name="res_model">account.invoice.import.wizard</field> - <field name="view_mode">form</field> - <field name="target">new</field> - <field name="context">{'default_type': 'in_invoice', 'default_journal_id': active_id}</field> - </record> - </data> -</odoo> diff --git a/addons/account_facturx/models/account_move.py b/addons/account_facturx/models/account_move.py index 844068b684e..cc8b53dc45d 100644 --- a/addons/account_facturx/models/account_move.py +++ b/addons/account_facturx/models/account_move.py @@ -291,7 +291,7 @@ class AccountMove(models.Model): :return: a list of triplet (xml_type, check_func, decode_func) * xml_type: The format name, e.g 'UBL 2.1' - * check_func: A function taking an etree as parameter and returning a dict: + * check_func: A function taking an etree and a file name as parameter and returning a dict: * flag: The etree is part of this format. * error: Error message. * decode_func: A function taking an etree as parameter and returning an invoice record. @@ -310,20 +310,20 @@ class AccountMove(models.Model): raise UserError(_('The xml file is badly formatted : {}').format(attachment.name)) for xml_type, check_func, decode_func in decoders: - check_res = check_func(tree) + check_res = check_func(tree, attachment.name) if check_res.get('flag') and not check_res.get('error'): - invoice = decode_func(tree) - if invoice: + invoice_ids = decode_func(tree) + if invoice_ids: try: # don't propose to send to ocr - invoice.extract_state = 'done' + invoice_ids.write({'extract_state': 'done'}) except AttributeError: # account_invoice_exctract not installed pass break try: - return invoice + return invoice_ids except UnboundLocalError: raise UserError(_('No decoder was found for the xml file: {}. The file is badly formatted, not supported or the decoder is not installed').format(attachment.name)) diff --git a/addons/l10n_be_edi/models/account_invoice.py b/addons/l10n_be_edi/models/account_invoice.py index 0429b630f91..e70ab5fddb1 100644 --- a/addons/l10n_be_edi/models/account_invoice.py +++ b/addons/l10n_be_edi/models/account_invoice.py @@ -25,7 +25,7 @@ class AccountMove(models.Model): return namespaces @api.model - def _detect_ubl_2_1(self, tree): + def _detect_ubl_2_1(self, tree, file_name): # Quick check the tree looks like an UBL 2.1 file. flag = tree.tag == '{urn:oasis:names:specification:ubl:schema:xsd:Invoice-2}Invoice' error = None diff --git a/addons/l10n_it_edi/models/account_invoice.py b/addons/l10n_it_edi/models/account_invoice.py index bc0dbc4a838..4b4457c042e 100644 --- a/addons/l10n_it_edi/models/account_invoice.py +++ b/addons/l10n_it_edi/models/account_invoice.py @@ -290,23 +290,22 @@ class AccountMove(models.Model): ) self.l10n_it_send_state = 'invalid' - def _import_xml_invoice(self, content, attachment): + def _import_xml_invoice(self, tree): ''' Extract invoice values from the E-Invoice xml tree passed as parameter. :param content: The tree of the xml file. :return: A dictionary containing account.invoice values to create/update it. ''' - try: - tree = etree.fromstring(content) - except: - _logger.info('Error during decoding XML file') - return self.env['account.move'] - invoices = self.env['account.move'] + multi = False # possible to have multiple invoices in the case of an invoice batch, the batch itself is repeated for every invoice of the batch for body_tree in tree.xpath('//FatturaElettronicaBody', namespaces=tree.nsmap): + if multi: + # make sure all the iterations create a new invoice record (except the first which could have already created one) + self = self.env['account.move'] + multi = True elements = tree.xpath('//DatiGeneraliDocumento/TipoDocumento', namespaces=tree.nsmap) if elements and elements[0].text and elements[0].text == 'TD01': @@ -654,7 +653,8 @@ class AccountMove(models.Model): }) # default_res_id is had to context to avoid facturx to import his content - new_invoice.with_context(default_res_id=new_invoice.id).message_post( + # no_new_invoice to prevent from looping on the message_post that would create a new invoice without it + new_invoice.with_context(no_new_invoice=True, default_res_id=new_invoice.id).message_post( body=(_("Attachment from XML")), attachment_ids=[attachment_64.id] ) @@ -662,10 +662,6 @@ class AccountMove(models.Model): for message in message_to_log: new_invoice.message_post(body=message) - if attachment: - new_invoice.l10n_it_einvoice_name = attachment.name - attachment.write({'res_model': 'account.move', 'res_id': new_invoice.id}) - new_invoice.message_post(attachment_ids=[attachment.id]) invoices += new_invoice return invoices @@ -695,6 +691,20 @@ class AccountMove(models.Model): output_str += "<li>%s: %s</li>" % (element.tag, text) return output_str + "</ul>" + @api.model + def _get_xml_decoders(self): + # Override + ubl_decoders = [('Italy', self._detect_italy_edi, self._import_xml_invoice)] + return super(AccountMove, self)._get_xml_decoders() + ubl_decoders + + @api.model + def _detect_italy_edi(self, tree, file_name): + # Quick check the file name looks like the one of an Italian EDI XML. + flag = re.search("([A-Z]{2}[A-Za-z0-9]{2,28}_[A-Za-z0-9]{0,5}.(xml.p7m|xml))", file_name) + error = None + + return {'flag': flag, 'error': error} + class AccountTax(models.Model): _name = "account.tax" _inherit = "account.tax" @@ -730,18 +740,3 @@ class AccountTax(models.Model): raise ValidationError("If the tax has exoneration, you must enter a kind of exoneration, a law reference and the amount of the tax must be 0.0.") if tax.l10n_it_kind_exoneration == 'N6' and tax.l10n_it_vat_due_date == 'S': raise UserError(_("'Scissione dei pagamenti' is not compatible with exoneration of kind 'N6'")) - -class ImportInvoiceImportWizard(models.TransientModel): - _name = 'account.invoice.import.wizard' - _inherit = 'account.invoice.import.wizard' - - def _create_invoice_from_file(self, attachment): - if attachment.mimetype == 'application/xml' and re.search("([A-Z]{2}[A-Za-z0-9]{2,28}_[A-Za-z0-9]{0,5}.(xml.p7m|xml))", attachment.name): - if self.env['account.move'].search([('l10n_it_einvoice_name', '=', attachment.name)], limit=1): - # invoice already exist - raise UserError(_('E-invoice already exist: %s') % attachment.name) - self = self.with_context(default_journal_id= self.journal_id.id) - invoice = self.env['account.move']._import_xml_invoice(base64.decodestring(attachment.datas), attachment) - else: - invoice = super(ImportInvoiceImportWizard, self)._create_invoice_from_file(attachment) - return invoice diff --git a/addons/l10n_it_edi/models/ir_mail_server.py b/addons/l10n_it_edi/models/ir_mail_server.py index 8af502b2c09..f36ef683dee 100644 --- a/addons/l10n_it_edi/models/ir_mail_server.py +++ b/addons/l10n_it_edi/models/ir_mail_server.py @@ -19,7 +19,7 @@ from lxml import etree from datetime import datetime from odoo import api, fields, models, tools, _ -from odoo.exceptions import ValidationError +from odoo.exceptions import ValidationError, UserError _logger = logging.getLogger(__name__) @@ -137,7 +137,12 @@ class FetchmailServer(models.Model): 'type': 'binary', }) - invoice = self.env['account.move']._import_xml_invoice(att_content, invoice_attachment) + try: + tree = etree.fromstring(att_content) + except Exception: + raise UserError(_('The xml file is badly formatted : {}').format(att_name)) + + invoice = self.env['account.move']._import_xml_invoice(tree) invoice.l10n_it_send_state = "new" invoice.source_email = from_address self._cr.commit() |
