From b329442e5dd93d8fcd874f04f13d9ce7de73668c Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Mon, 26 Jul 2021 12:10:56 +0200 Subject: [PATCH 01/65] Initial check-in of account_invoice_import_simple_pdf This new module is an improved alternative to the module account_invoice_import_invoice2data. Refer to README for more information. --- account_invoice_import_simple_pdf/README.rst | 1 + account_invoice_import_simple_pdf/__init__.py | 2 + .../__manifest__.py | 27 ++ .../demo/demo_data.xml | 70 ++++ .../models/__init__.py | 3 + ...ccount_invoice_import_simple_pdf_fields.py | 393 ++++++++++++++++++ ...nvoice_import_simple_pdf_invoice_number.py | 108 +++++ .../models/res_partner.py | 389 +++++++++++++++++ .../readme/CONFIGURE.rst | 1 + .../readme/CONTRIBUTORS.rst | 1 + .../readme/DESCRIPTION.rst | 35 ++ .../readme/INSTALL.rst | 19 + .../security/ir.model.access.csv | 5 + .../static/description/icon.png | Bin 0 -> 9455 bytes .../tests/__init__.py | 1 + .../tests/pdf/bouygues_telecom-test.pdf | Bin 0 -> 165905 bytes .../tests/test_invoice_import.py | 392 +++++++++++++++++ ...count_invoice_import_simple_pdf_fields.xml | 83 ++++ ...voice_import_simple_pdf_invoice_number.xml | 68 +++ .../views/res_partner.xml | 127 ++++++ .../wizard/__init__.py | 1 + .../wizard/account_invoice_import.py | 189 +++++++++ .../wizard/account_invoice_import_view.xml | 22 + 23 files changed, 1937 insertions(+) create mode 100644 account_invoice_import_simple_pdf/README.rst create mode 100644 account_invoice_import_simple_pdf/__init__.py create mode 100644 account_invoice_import_simple_pdf/__manifest__.py create mode 100644 account_invoice_import_simple_pdf/demo/demo_data.xml create mode 100644 account_invoice_import_simple_pdf/models/__init__.py create mode 100644 account_invoice_import_simple_pdf/models/account_invoice_import_simple_pdf_fields.py create mode 100644 account_invoice_import_simple_pdf/models/account_invoice_import_simple_pdf_invoice_number.py create mode 100644 account_invoice_import_simple_pdf/models/res_partner.py create mode 100644 account_invoice_import_simple_pdf/readme/CONFIGURE.rst create mode 100644 account_invoice_import_simple_pdf/readme/CONTRIBUTORS.rst create mode 100644 account_invoice_import_simple_pdf/readme/DESCRIPTION.rst create mode 100644 account_invoice_import_simple_pdf/readme/INSTALL.rst create mode 100644 account_invoice_import_simple_pdf/security/ir.model.access.csv create mode 100644 account_invoice_import_simple_pdf/static/description/icon.png create mode 100644 account_invoice_import_simple_pdf/tests/__init__.py create mode 100644 account_invoice_import_simple_pdf/tests/pdf/bouygues_telecom-test.pdf create mode 100644 account_invoice_import_simple_pdf/tests/test_invoice_import.py create mode 100644 account_invoice_import_simple_pdf/views/account_invoice_import_simple_pdf_fields.xml create mode 100644 account_invoice_import_simple_pdf/views/account_invoice_import_simple_pdf_invoice_number.xml create mode 100644 account_invoice_import_simple_pdf/views/res_partner.xml create mode 100644 account_invoice_import_simple_pdf/wizard/__init__.py create mode 100644 account_invoice_import_simple_pdf/wizard/account_invoice_import.py create mode 100644 account_invoice_import_simple_pdf/wizard/account_invoice_import_view.xml diff --git a/account_invoice_import_simple_pdf/README.rst b/account_invoice_import_simple_pdf/README.rst new file mode 100644 index 0000000000..262ac82139 --- /dev/null +++ b/account_invoice_import_simple_pdf/README.rst @@ -0,0 +1 @@ +Will be auto-generated from readme subdir diff --git a/account_invoice_import_simple_pdf/__init__.py b/account_invoice_import_simple_pdf/__init__.py new file mode 100644 index 0000000000..9b4296142f --- /dev/null +++ b/account_invoice_import_simple_pdf/__init__.py @@ -0,0 +1,2 @@ +from . import models +from . import wizard diff --git a/account_invoice_import_simple_pdf/__manifest__.py b/account_invoice_import_simple_pdf/__manifest__.py new file mode 100644 index 0000000000..4c0bb45cdd --- /dev/null +++ b/account_invoice_import_simple_pdf/__manifest__.py @@ -0,0 +1,27 @@ +# Copyright 2021 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Account Invoice Import Simple PDF", + "version": "14.0.1.0.0", + "category": "Accounting/Accounting", + "license": "AGPL-3", + "summary": "Import simple PDF vendor bills", + "author": "Akretion,Odoo Community Association (OCA)", + "maintainers": ["alexis-via"], + "website": "https://github.com/OCA/edi", + "depends": ["account_invoice_import"], + "excludes": ["account_invoice_import_invoice2data"], + "external_dependencies": {"python": ["PyMuPDF", "regex", "dateparser"]}, + "data": [ + "security/ir.model.access.csv", + "wizard/account_invoice_import_view.xml", + "views/res_partner.xml", + "views/account_invoice_import_simple_pdf_fields.xml", + "views/account_invoice_import_simple_pdf_invoice_number.xml", + ], + "demo": ["demo/demo_data.xml"], + "installable": True, + "application": True, +} diff --git a/account_invoice_import_simple_pdf/demo/demo_data.xml b/account_invoice_import_simple_pdf/demo/demo_data.xml new file mode 100644 index 0000000000..55a0ae8a21 --- /dev/null +++ b/account_invoice_import_simple_pdf/demo/demo_data.xml @@ -0,0 +1,70 @@ + + + + + Mobile phone + + + + service + + + + Bouygues Telecom + + 1 + 37 rue Boissière + 75116 + Paris + + http://www.bouyguestelecom.fr + FR74397480930 + dd-mm-y4 + slash + + first + coma + space + + + + + digit + 14 + 14 + + + + + amount_total + max + + + + + amount_untaxed + first + Montant de la facture soumis à TVA + + + + + date + first + + + + + invoice_number + first + + + + Bouygues Telecom mobile + + 1line_static_product + Mobile phone: subscription and communication + + + + diff --git a/account_invoice_import_simple_pdf/models/__init__.py b/account_invoice_import_simple_pdf/models/__init__.py new file mode 100644 index 0000000000..7d7aab1c50 --- /dev/null +++ b/account_invoice_import_simple_pdf/models/__init__.py @@ -0,0 +1,3 @@ +from . import account_invoice_import_simple_pdf_fields +from . import account_invoice_import_simple_pdf_invoice_number +from . import res_partner diff --git a/account_invoice_import_simple_pdf/models/account_invoice_import_simple_pdf_fields.py b/account_invoice_import_simple_pdf/models/account_invoice_import_simple_pdf_fields.py new file mode 100644 index 0000000000..93c3ec5e3c --- /dev/null +++ b/account_invoice_import_simple_pdf/models/account_invoice_import_simple_pdf_fields.py @@ -0,0 +1,393 @@ +# Copyright 2021 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +import logging + +from odoo import _, api, fields, models +from odoo.exceptions import UserError, ValidationError +from odoo.tools.misc import format_date + +from .res_partner import ERROR_STYLE + +logger = logging.getLogger(__name__) + +try: + import regex +except ImportError: + logger.debug("Cannot import regex") +try: + import dateparser +except ImportError: + logger.debug("Cannot import dateparser") + + +class AccountInvoiceImportSimplePdfFields(models.Model): + _name = "account.invoice.import.simple.pdf.fields" + _description = "Fields for Simple PDF invoice import" + _order = "partner_id, sequence, id" + + partner_id = fields.Many2one("res.partner", string="Vendor", ondelete="cascade") + # the order has no impact, it's just for readability + sequence = fields.Integer(default=10) + name = fields.Selection( + [ + ("amount_total", "Total"), + ("amount_untaxed", "Untaxed Amount"), + ("amount_tax", "Tax Amount"), + ("date", "Invoice Date"), + ("date_due", "Due Date"), + ("date_start", "Start Date"), + ("date_end", "End Date"), + ("invoice_number", "Invoice Number"), + ("description", "Description"), + ], + required=True, + string="Field", + ) + regexp = fields.Char(string="Specific Regular Expression") + date_format = fields.Selection( + "_date_format_sel", + string="Specific Date Format", + help="Leave empty if the format used is the same as the format defined " + "in the global section.", + ) + date_separator = fields.Selection( + "_date_separator_sel", + string="Specific Date Separator", + help="Leave empty if the format used is the same as the format defined " + "in the global section.", + ) + start = fields.Char(string="Start String") + end = fields.Char(string="End String") + extract_rule = fields.Selection( + [ + ("first", "First"), + ("last", "Last"), + ("position_start", "Specific Position from Start"), + ("position_end", "Specific Position from End"), + ("min", "Min"), + ("max", "Max"), + ("position_min", "Specific Position from Min"), + ("position_max", "Specific Position from Max"), + ], + string="Extract Rule", + required=True, + ) + position = fields.Integer(default=2) + + @api.model + def _date_format_sel(self): + return self.env["res.partner"]._simple_pdf_date_format_sel() + + @api.model + def _date_separator_sel(self): + return self.env["res.partner"]._simple_pdf_date_separator_sel() + + _sql_constraints = [ + ( + "position_specific_positive", + "CHECK(position > 0)", + "The position must be strictly positive.", + ), + ( + "partner_field_unique", + "unique(partner_id, name)", + "There is already an entry for that field.", + ), + ] + + @api.constrains("name", "regexp") + def _check_field_config(self): + for field in self: + if field.name == "description" and not field.regexp: + raise ValidationError( + _( + "You must set a Specific Regular Expression on " + "the 'Description' field." + ) + ) + + @api.onchange("name") + def field_change(self): + if not self.extract_rule: + if self.name == "amount_total": + self.extract_rule = "max" + elif self.name in ("invoice_number", "description", "date"): + self.extract_rule = "first" + + def get_value_from_list(self, data_list, test_info, raise_if_none=True): + assert isinstance(data_list, list) + if not data_list: + if raise_if_none: + raise UserError( + _("No valid data extracted for field '%s'.") % self.name + ) + else: + return None + if self.extract_rule in ("min", "max", "position_min", "position_max"): + data_list_sorted = list(data_list) + data_list_sorted.sort() + if self.name.startswith("date"): + test_info[self.name]["sorted_list"] = [ + format_date(self.env, date_dt) for date_dt in data_list_sorted + ] + else: + test_info[self.name]["sorted_list"] = data_list_sorted + if self.extract_rule == "max": + return data_list_sorted[-1] + elif self.extract_rule == "min": + return data_list_sorted[0] + elif self.extract_rule in ("position_min", "position_max"): + if len(data_list) < self.position: + error_msg = _( + "Partner '%s' is configured with an extract rule '%s' with " + "position %d for field '%s' but the list of " + "extracted valid data only has %d entries." + ) % ( + self.partner_id.display_name, + test_info["extract_rule_sel"][self.extract_rule], + self.position, + test_info["field_name_sel"][self.name], + len(data_list), + ) + if raise_if_none: + raise UserError(error_msg) + else: + test_info[self.name]["error_msg"] = error_msg + return None + sign = self.extract_rule == "position_min" and 1 or -1 + position = self.position + if self.extract_rule == "position_min": + position -= 1 + return data_list[position * sign] + elif self.extract_rule == "first": + return data_list[0] + elif self.extract_rule == "last": + return data_list[-1] + elif self.extract_rule in ("position_start", "position_end"): + if len(data_list) < self.position: + error_msg = _( + "Partner '%s' is configured with an extract rule '%s' with " + "position %d for field '%s' but the list of extracted " + "valid data only has %d entries." + ) % ( + self.partner_id.display_name, + test_info["extract_rule_sel"][self.extract_rule], + self.position, + test_info["field_name_sel"][self.name], + len(data_list), + ) + if raise_if_none: + raise UserError(error_msg) + else: + test_info[self.name]["error_msg"] = error_msg + return None + sign = self.extract_rule == "position_start" and 1 or -1 + position = self.position + if self.extract_rule == "position_start": + position -= 1 + return data_list[position * sign] + else: + raise UserError(_("Bad configuration")) + + def restrict_text(self, raw_text, test_info): + self.ensure_one() + restrict_text = raw_text + start = self.start and self.start.strip() or False + end = self.end and self.end.strip() or False + if start: + position = restrict_text.rfind(start) + if position >= 0: + restrict_text = restrict_text[position + len(start) :] + test_info[self.name]["start"] = _("Successful cut on '%s'") % start + else: + error_msg = _("String '%s' not found") % start + test_info[self.name]["start"] = "%s" % (ERROR_STYLE, error_msg) + if end: + position = restrict_text.rfind(end) + if position >= 0: + restrict_text = restrict_text[:position] + test_info[self.name]["end"] = _("Successful cut on '%s'") % end + else: + error_msg = _("String '%s' not found") % end + test_info[self.name]["end"] = "%s" % (ERROR_STYLE, error_msg) + return restrict_text + + def _get_date(self, parsed_inv, raw_text, partner_config, test_info): + date_format = self.date_format or partner_config["date_format"] + error_arg = ( + partner_config["display_name"], + test_info["field_name_sel"][self.name], + ) + if not date_format: + raise UserError( + _("No date format configured on partner '%s' nor on the field '%s'.") + % error_arg + ) + date_separator = self.date_separator or partner_config["date_separator"] + if not date_separator: + raise UserError( + _("No date separator configured on partner '%s' nor on the field '%s'.") + % error_arg + ) + date_separator_char = partner_config["separator2char"][date_separator] + + if self.regexp: + pattern = self.regexp + else: + pattern = date_format + for src, dest in partner_config["date_format2regex"].items(): + pattern = pattern.replace(src, dest) + + if date_separator_char == chr(32): + date_separator_regex = ",?%s+" % test_info["space_pattern"] + else: + date_separator_regex = regex.escape(date_separator_char) + + pattern = pattern.replace("-", date_separator_regex) + test_info[self.name] = { + "pattern": pattern, + "date_format": test_info["date_format_sel"][date_format].replace( + " ", date_separator_char + ), + } + restrict_text = self.restrict_text(raw_text, test_info) + res_regex = regex.findall(pattern, restrict_text) + valid_dates_dt = [] + date_formatdt = date_format + for src, dest in partner_config["date_format2dt"].items(): + date_formatdt = date_formatdt.replace(src, dest) + date_formatdt = date_formatdt.replace("-", date_separator_char) + languages = ( + partner_config["lang_short"] and [partner_config["lang_short"]] or None + ) + for date_raw in res_regex: + date_dt = dateparser.parse( + date_raw, date_formats=[date_formatdt], languages=languages + ) + if date_dt: + valid_dates_dt.append(date_dt) + else: + logger.debug( + "Failed to parse date %s using format %s and language %s", + date_raw, + date_formatdt, + partner_config["lang_short"], + ) + test_info[self.name].update( + { + "res_regex": res_regex, + "valid_list": [ + format_date(self.env, vdate_dt) for vdate_dt in valid_dates_dt + ], + } + ) + if self.name == "date_due" or test_info["test_mode"]: + raise_if_none = False + else: + raise_if_none = True + date_dt = self.get_value_from_list( + valid_dates_dt, test_info, raise_if_none=raise_if_none + ) + if date_dt: + parsed_inv[self.name] = date_dt + else: + parsed_inv["failed_fields"].append(self.name) + + def _get_amount(self, parsed_inv, raw_text, partner_config, test_info): + thousand_sep = partner_config["thousand_sep"] + if not thousand_sep: + thousand_sep_pattern = "" + elif thousand_sep == chr(32): + thousand_sep_pattern = test_info["space_pattern"] + else: + thousand_sep_pattern = regex.escape(thousand_sep) + decimal_sep = partner_config["decimal_sep"] + decimal_sep_pattern = regex.escape(decimal_sep) + decimal_places = partner_config["currency"].decimal_places + if self.regexp: + pattern = self.regexp + else: + if decimal_places: + pattern = r"(?:\d{1,3}%s)*\d{1,3}%s\d{%d}" % ( + thousand_sep_pattern, + decimal_sep_pattern, + decimal_places, + ) + else: + pattern = r"(?:\d{1,3}%s)*\d{1,3}" % thousand_sep_pattern + test_info[self.name] = {"pattern": pattern} + # don't take if followed by a % ? => means it's a rate + restrict_text = self.restrict_text(raw_text, test_info) + # I don't move the code that filters out percentrages and capital + # to simple_pdf_text_extraction() because I want to have raw + # test for start/end cut + # filter out percentage with decimal like VAT rates or discounts + # for example '5.5 %' or '20.0%' + restrict_text_filtered = regex.sub( + r"\d{1,2}%s\d{1,2}\s?%%" % regex.escape(decimal_sep), "", restrict_text + ) + # filter out discounts or VAT rates without decimal e.g. 20% + restrict_text_filtered = regex.sub(r"\d{1,3}\s?%", "", restrict_text_filtered) + # Try to filter out capital amounts + # Yes, this is a hack :) + # Works in EN and FR... what about other languages ? + restrict_text_filtered = regex.sub( + r"[Cc]apital.{1,30}(?:\d{1,3}%s)*\d{1,3}" % regex.escape(thousand_sep), + "", + restrict_text_filtered, + ) + res_regex = regex.findall(pattern, restrict_text_filtered) + valid_amounts = [] + for amount_raw in res_regex: + if thousand_sep_pattern: + amount_raw = regex.sub(thousand_sep_pattern, "", amount_raw) + if decimal_places: + amount_raw_list = list(amount_raw) + amount_raw_list[-decimal_places - 1] = "." + amount_raw = "".join(amount_raw_list) + try: + valid_amounts.append(float(amount_raw)) + except ValueError: + logger.debug("%s is an invalid float", amount_raw) + test_info[self.name].update( + { + "res_regex": res_regex, + "valid_list": valid_amounts, + } + ) + raise_if_none = not test_info["test_mode"] and True or False + amount = self.get_value_from_list( + valid_amounts, test_info, raise_if_none=raise_if_none + ) + parsed_inv[self.name] = amount + + def _get_invoice_number(self, parsed_inv, raw_text, partner_config, test_info): + partner = partner_config["recordset"] + pattern = self.regexp or partner._prepare_simple_pdf_invoice_number_regex() + test_info[self.name] = {"pattern": pattern} + restrict_text = self.restrict_text(raw_text, test_info) + res_regex = regex.findall(pattern, restrict_text) + test_info[self.name]["res_regex"] = res_regex + + inv_number = self.get_value_from_list(res_regex, test_info, raise_if_none=False) + if inv_number: + parsed_inv[self.name] = inv_number.strip() + else: + parsed_inv["failed_fields"].append(self.name) + + def _get_description(self, parsed_inv, raw_text, partner_config, test_info): + self.ensure_one() + pattern = self.regexp + test_info[self.name] = {"pattern": pattern} + restrict_text = self.restrict_text(raw_text, test_info) + res_regex = regex.findall(pattern, restrict_text) + test_info[self.name]["res_regex"] = res_regex + description = self.get_value_from_list( + res_regex, test_info, raise_if_none=False + ) + if description: + parsed_inv[self.name] = description.strip() + else: + parsed_inv["failed_fields"].append(self.name) diff --git a/account_invoice_import_simple_pdf/models/account_invoice_import_simple_pdf_invoice_number.py b/account_invoice_import_simple_pdf/models/account_invoice_import_simple_pdf_invoice_number.py new file mode 100644 index 0000000000..c45ef6b1f8 --- /dev/null +++ b/account_invoice_import_simple_pdf/models/account_invoice_import_simple_pdf_invoice_number.py @@ -0,0 +1,108 @@ +# Copyright 2021 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +import logging + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + +logger = logging.getLogger(__name__) + +MAX_PAST_YEARS = 5 + +try: + import regex +except ImportError: + logger.debug("Cannot import regex") + + +class AccountInvoiceImportSimplePdfInvoiceNumber(models.Model): + _name = "account.invoice.import.simple.pdf.invoice.number" + _description = "Invoice number format for Simple PDF invoice import" + _order = "sequence, id" + + partner_id = fields.Many2one("res.partner", string="Vendor", ondelete="cascade") + sequence = fields.Integer(default=10) + string_type = fields.Selection("_string_type_sel", string="Type", required=True) + fixed_char = fields.Char() + occurrence_min = fields.Integer(string="Minimum Occurence", default=1) + occurrence_max = fields.Integer(string="Maximum Occurence", default=1) + + _sql_constraints = [ + ( + "occurrence_min_positive", + "CHECK(occurrence_min > 0)", + "The minimum occurence must be strictly positive.", + ), + ( + "occurrence_max_positive", + "CHECK(occurrence_max > 0)", + "The maximum occurence must be strictly positive.", + ), + ] + + @api.model + def _string_type_sel(self): + return [ + ("fixed", "Fixed"), + ("letter_upper", "Upper Letter"), + ("letter_lower", "Lower Letter"), + ("digit", "Digit(s)"), + ("space", "Space"), + ("year2", "Year on 2 digits"), + ("year4", "Year on 4 digits"), + ("month", "Month (2 digits)"), + ] + + @api.constrains("string_type", "fixed_char", "occurrence_min", "occurrence_max") + def _check_invoice_number_format(self): + for rec in self: + if rec.string_type == "fixed": + fixed_char_stripped = rec.fixed_char and rec.fixed_char.strip() + if not fixed_char_stripped: + raise ValidationError(_("Missing fixed char.")) + elif rec.string_type in ("letter_upper", "letter_lower", "digit", "space"): + if rec.occurrence_max < rec.occurrence_min: + raise ValidationError( + _( + "The maximum occurence (%d) must be equal to or above " + "the minimum occurence (%d)." + ) + % (rec.occurrence_max, rec.occurrence_min) + ) + + @api.onchange("occurrence_min") + def occurrence_min_change(self): + if self.occurrence_min > self.occurrence_max: + self.occurrence_max = self.occurrence_min + + def _prepare_invoice_number_regex(self, regex_list): + self.ensure_one() + type2regex = { + "letter_upper": "[A-Z]", + "letter_lower": "[a-z]", + "digit": r"\d", + "space": r"\s", + } + if self.string_type == "fixed": + regex_list.append(regex.escape(self.fixed_char.strip())) + elif self.string_type in ("letter_upper", "letter_lower", "digit", "space"): + if self.occurrence_min == self.occurrence_max: + suffix = "{%d}" % self.occurrence_min + else: + suffix = "{%d,%d}" % (self.occurrence_min, self.occurrence_max) + + regex_list.append(type2regex[self.string_type] + suffix) + elif self.string_type in ("year2", "year4"): + # match on current and previous year only + current_year = fields.Date.context_today(self).year + + years = [current_year - y for y in range(MAX_PAST_YEARS + 1)] + if self.string_type == "year2": + years_str = [str(y)[-2:] for y in years] + else: + years_str = [str(y) for y in years] + regex_list.append("(?:%s)" % "|".join(years_str)) + elif self.string_type == "month": + regex_list.append("(?:01|02|03|04|05|06|07|08|09|10|11|12)") diff --git a/account_invoice_import_simple_pdf/models/res_partner.py b/account_invoice_import_simple_pdf/models/res_partner.py new file mode 100644 index 0000000000..b423ec80dd --- /dev/null +++ b/account_invoice_import_simple_pdf/models/res_partner.py @@ -0,0 +1,389 @@ +# Copyright 2021 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +import base64 +import logging + +from odoo import _, api, fields, models +from odoo.exceptions import UserError, ValidationError +from odoo.tools.misc import format_amount, format_date, format_datetime + +logger = logging.getLogger(__name__) +ERROR_STYLE = ' style="color:red;"' + +try: + import regex +except ImportError: + logger.debug("Cannot import regex") + + +class ResPartner(models.Model): + _inherit = "res.partner" + + @api.model + def _simple_pdf_date_format_sel(self): + return [ + ("dd-mm-y4", _("DD MM YYYY")), + ("dd-month-y4", _("DD Month YYYY")), + ("month-dd-y4", _("Month DD YYYY")), + ("mm-dd-y4", _("MM DD YYYY")), + ("y4-mm-dd", _("YYYY MM DD")), + ("dd-mm-y2", _("DD MM YY")), + ("dd-month-y2", _("DD Month YY")), + ("month-dd-y2", _("Month DD YY")), + ("mm-dd-y2", _("MM DD YY")), + ] + + @api.model + def _simple_pdf_date_separator_sel(self): + return [ + ("slash", "/"), + ("dash", _("dash")), + ("dot", _("dot")), + ("space", _("space")), + ] + + simple_pdf_keyword = fields.Char( + help="If empty, Odoo will use the VAT number to identify the partner. " + "To match on several keywords, separate them with '|' (pipe)." + ) + simple_pdf_date_format = fields.Selection( + "_simple_pdf_date_format_sel", + string="Date Format", + default="dd-mm-y4", + help="If the date format uses 'Month', check that the language is " + "properly configured on the partner. 'Month' works both in full and " + "short version ('January' and 'Jan.').", + ) + simple_pdf_date_separator = fields.Selection( + "_simple_pdf_date_separator_sel", + default="slash", + string="Date Separator", + help="If the date looks like 'Sep. 4, 2021', use 'space' as date " + "separator (Odoo will ignore the dot and coma).", + ) + simple_pdf_decimal_separator = fields.Selection( + [ + ("dot", "dot"), + ("coma", "coma"), + ], + string="Decimal Separator", + help="If empty, Odoo will use the decimal separator configured on " + "the language of the partner.", + ) + simple_pdf_thousand_separator = fields.Selection( + [ + ("none", "none"), + ("space", "space"), + ("dot", "dot"), + ("coma", "coma"), + ], + string="Thousand Separator", + help="If empty, Odoo will use the thousand separator configured on " + "the language of the partner.", + ) + simple_pdf_pages = fields.Selection( + [ + ("first", "First Page Only"), + ("all", "All Pages"), + ], + default="all", + string="Page Analysis", + ) + simple_pdf_currency_id = fields.Many2one( + "res.currency", + string="Invoice Import Currency", + ondelete="restrict", + help="If empty, Odoo will use the company currency.", + ) + simple_pdf_field_ids = fields.One2many( + "account.invoice.import.simple.pdf.fields", + "partner_id", + string="Fields for PDF Invoice Import", + ) + simple_pdf_invoice_number_ids = fields.One2many( + "account.invoice.import.simple.pdf.invoice.number", + "partner_id", + string="Invoice Import Number Format", + ) + simple_pdf_test_file = fields.Binary( + string="Test PDF Invoice File", attachment=True + ) + simple_pdf_test_filename = fields.Char(string="Test PDF Invoice Filename") + simple_pdf_test_raw_text = fields.Text(string="Test Text Extraction", readonly=True) + simple_pdf_test_results = fields.Html(string="Test Results", readonly=True) + + @api.constrains("simple_pdf_decimal_separator", "simple_pdf_thousand_separator") + def _check_simple_pdf_separator(self): + for partner in self: + if ( + partner.simple_pdf_decimal_separator + and partner.simple_pdf_decimal_separator + == partner.simple_pdf_thousand_separator + ): + raise ValidationError( + _( + "For partner '%s', the decimal separator cannot be " + "the same as the thousand separator." + ) + % partner.display_name + ) + + @api.onchange("simple_pdf_decimal_separator") + def simple_pdf_decimal_separator_change(self): + if ( + self.simple_pdf_decimal_separator == "coma" + and self.simple_pdf_thousand_separator == "coma" + ): + self.simple_pdf_thousand_separator = "dot" + + @api.onchange("simple_pdf_date_format") + def simple_pdf_date_format_change(self): + if self.simple_pdf_date_format and "month" in self.simple_pdf_date_format: + self.simple_pdf_date_separator = "space" + + def _prepare_simple_pdf_invoice_number_regex(self): + self.ensure_one() + if not self.simple_pdf_invoice_number_ids: + raise UserError( + _("Missing invoice number format configuration on partner '%s'.") + % self.display_name + ) + regex = [] + for entry in self.simple_pdf_invoice_number_ids: + entry._prepare_invoice_number_regex(regex) + regex_string = "".join(regex) + return regex_string + + def pdf_simple_generate_default_fields(self): + self.ensure_one() + assert not self.parent_id + assert self.is_company + assert not self.simple_pdf_field_ids + def_fields = [ + {"name": "amount_total", "extract_rule": "max"}, + {"name": "amount_untaxed", "extract_rule": "position_end", "position": 3}, + {"name": "invoice_number", "extract_rule": "first"}, + {"name": "date", "extract_rule": "first"}, + ] + self.write( + { + "simple_pdf_field_ids": [(0, 0, field_val) for field_val in def_fields], + } + ) + + def pdf_simple_test_cleanup(self): + self.ensure_one() + self.write( + { + "simple_pdf_test_raw_text": False, + "simple_pdf_test_results": False, + "simple_pdf_test_filename": False, + "simple_pdf_test_file": False, + } + ) + + def pdf_simple_test_run(self): + self.ensure_one() + aiio = self.env["account.invoice.import"] + rpo = self.env["res.partner"] + vals = {} + test_results = [] + test_results.append("%s
" % _("Errors are in red.")) + test_results.append( + "%s %s" + % (_("Test Date:"), format_datetime(self.env, fields.Datetime.now())) + ) + if not self.simple_pdf_test_file: + raise UserError(_("You must upload a test PDF invoice.")) + test_info = {"test_mode": True} + aiio._simple_pdf_update_test_info(test_info) + file_data = base64.b64decode(self.simple_pdf_test_file) + raw_text_dict = aiio.simple_pdf_text_extraction(file_data, test_info) + if self.simple_pdf_pages == "first": + vals["simple_pdf_test_raw_text"] = raw_text_dict["first"] + else: + vals["simple_pdf_test_raw_text"] = raw_text_dict["all"] + test_results.append("

%s

    " % _("Searching Partner")) + partner_id = aiio.simple_pdf_match_partner( + raw_text_dict["all_no_space"], test_results + ) + partner_ok = False + if partner_id: + partner = rpo.browse(partner_id) + if partner_id == self.id: + partner_ok = True + partner_result = _("Current partner found") + else: + partner_result = "%s %s" % ( + _("Found another partner:"), + partner.display_name, + ) + else: + partner_result = _("No partner found.") + test_results.append( + "
  • %s %s
" + % (_("Result:"), not partner_ok and ERROR_STYLE or "", partner_result) + ) + if partner_ok: + partner_config = self._simple_pdf_partner_config() + test_results.append("

%s

    " % _("Amount Setup")) + test_results.append( + """
  • %s "%s" (%s)
  • """ + % ( + _("Decimal Separator:"), + partner_config["decimal_sep"], + partner_config["char2separator"].get( + partner_config["decimal_sep"], _("unknown") + ), + ) + ) + test_results.append( + """
  • %s "%s" (%s)
""" + % ( + _("Thousand Separator:"), + partner_config["thousand_sep"], + partner_config["char2separator"].get( + partner_config["thousand_sep"], _("unknown") + ), + ) + ) + parsed_inv = aiio.simple_pdf_parse_invoice(file_data, test_info) + key2label = { + "pattern": _("Regular Expression"), + "date_format": _("Date Format"), + "res_regex": _("Raw List"), + "valid_list": _("Valid-data Filtered List"), + "sorted_list": _("Ordered List"), + "error_msg": _("Error message"), + "start": _("Start String"), + "end": _("End String"), + } + for field in self.simple_pdf_field_ids: + test_results.append( + "

%s

    " % test_info["field_name_sel"][field.name] + ) + extract_method = test_info["extract_rule_sel"][field.extract_rule] + if field.extract_rule.startswith("position_"): + extract_method += _(", Position: %d") % field.position + test_results.append( + "
  • %s %s
  • " % (_("Extract Rule:"), extract_method) + ) + for key, value in test_info[field.name].items(): + if key != "pattern" or self.env.user.has_group("base.group_system"): + test_results.append("
  • %s: %s
  • " % (key2label[key], value)) + + result = parsed_inv.get(field.name) + if "date" in field.name and result: + result = format_date(self.env, result) + if "amount" in field.name and result: + result = format_amount( + self.env, result, parsed_inv["currency"]["recordset"] + ) + test_results.append( + "
  • %s %s
" + % ( + _("Result:"), + not result and ERROR_STYLE or "", + result or _("None"), + ) + ) + vals["simple_pdf_test_results"] = "\n".join(test_results) + self.write(vals) + + def _simple_pdf_partner_config(self): + self.ensure_one() + separator2char = { + "slash": "/", + "dash": "-", + "dot": ".", + "coma": ",", + "space": chr(32), # regular space + "none": "", + } + char2separator = {val: key for key, val in separator2char.items()} + date_format2regex = { + "dd": r"\d{1,2}", # We have to match on July 4, 2021 + "mm": r"\d{1,2}", + "y4": r"\d{4}", + "y2": r"\d{2}", + "month": r"\p{L}{3,15}\.?", # \p{L} : any unicode letter (but not digit) + # option dot for short month (e.g. 'feb.') + } + date_format2dt = { + "dd": "%d", + "mm": "%m", + "month": "%B", + "y4": "%Y", + "y2": "%y", + } + lang = False + if self.lang: + lang = self.env["res.lang"].search([("code", "=", self.lang)], limit=1) + if self.simple_pdf_decimal_separator: + decimal_sep = separator2char[self.simple_pdf_decimal_separator] + elif lang: + decimal_sep = lang.decimal_point + else: + raise UserError( + _( + "Could not get the decimal separator for partner '%s': " + "the fields 'Language' and 'Decimal Separator' are " + "both empty for this partner." + ) + % self.display_name + ) + if self.simple_pdf_thousand_separator: + thousand_sep = separator2char[self.simple_pdf_thousand_separator] + elif lang: + thousand_sep = lang.thousands_sep + # Remplace all white space characters (no-break-space, narrow no-break-space) + # by regular space + if regex.match(r"^\s$", thousand_sep): + thousand_sep = chr(32) # regular space + else: + thousand_sep = "" + logger.debug("decimal_sep=|%s| thousand_sep=|%s|", decimal_sep, thousand_sep) + partner_config = { + "recordset": self, + "display_name": self.display_name, + "date_format": self.simple_pdf_date_format, + "date_separator": self.simple_pdf_date_separator, + "currency": self.simple_pdf_currency_id or self.env.company.currency_id, + "decimal_sep": decimal_sep, + "thousand_sep": thousand_sep, + "separator2char": separator2char, + "char2separator": char2separator, + "date_format2regex": date_format2regex, + "date_format2dt": date_format2dt, + "lang_short": self.lang and self.lang[:2] or None, + } + # Check field list + field_list = [field.name for field in self.simple_pdf_field_ids] + amount_total_count = field_list.count("amount_total") + amount_untaxed_count = field_list.count("amount_untaxed") + amount_tax = field_list.count("amount_tax") + amount_fields_count = amount_total_count + amount_untaxed_count + amount_tax + if "date" not in field_list: + raise UserError( + _( + "You must configure a field extraction rule for " + "field 'Date' for partner '%s'." + ) + % self.display_name + ) + if amount_fields_count == 0: + raise UserError( + _("There is no amount field configured for partner '%s'.") + % self.display_name + ) + if amount_fields_count == 1 and amount_total_count == 0: + raise UserError( + _( + "For partner '%s', only one amount field is configured " + "but it is not 'Amount Total'." + ) + % self.display_name + ) + return partner_config diff --git a/account_invoice_import_simple_pdf/readme/CONFIGURE.rst b/account_invoice_import_simple_pdf/readme/CONFIGURE.rst new file mode 100644 index 0000000000..5b33e96629 --- /dev/null +++ b/account_invoice_import_simple_pdf/readme/CONFIGURE.rst @@ -0,0 +1 @@ +You will find a full demonstration about how to configure and use this module in this `screencast `_. diff --git a/account_invoice_import_simple_pdf/readme/CONTRIBUTORS.rst b/account_invoice_import_simple_pdf/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000000..ff65d68ce6 --- /dev/null +++ b/account_invoice_import_simple_pdf/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Alexis de Lattre diff --git a/account_invoice_import_simple_pdf/readme/DESCRIPTION.rst b/account_invoice_import_simple_pdf/readme/DESCRIPTION.rst new file mode 100644 index 0000000000..a50c5f4c63 --- /dev/null +++ b/account_invoice_import_simple_pdf/readme/DESCRIPTION.rst @@ -0,0 +1,35 @@ +This module is an extension of the module *account_invoice_import*: it adds support for simple PDF invoices i.e. PDF invoice that don't have an embedded XML file. This module has been developped to solve the drawbacks of the OCA module **account_invoice_import_invoice2data** ; its advantages are the following: + +* Possibility to add support for a new vendor without developper skills: the accountant can do it! +* Adding support for a new vendor is faster. +* More tolerance on vendor invoice layout changes. +* Easier to install. + +With this module, you can import all the invoices that you were able to import with the module *account_invoice_import_invoice2data*. In fact, this module uses the same design when importing a PDF vendor bill: + +1. raw text extraction of the PDF file, +2. identify the partner using the VAT number (if the VAT number is present in the raw text extraction) or some keywords, +3. use regular expressions (regex) to extract the data needed to create the vendor bill in Odoo (single line configuration). + +The main difference with the OCA module *account_invoice_import_invoice2data* is that the regular expressions are auto-generated from the configuration made by the user in Odoo. No need to be a regex expert! But you can still write regex to extract some fields for some very specific needs. + +The module can extract the following fields: + +* Total Amount with taxes +* Total Untaxed Amount +* Total Tax Amount +* Invoice Date +* Due Date +* Start Date +* End Date +* Invoice Number +* Description (for that field, you have to write a regex) + +In this list, only 3 fields are required: + +* Invoice Date +* 2 out of the 3 Amount fields (the 3rd can be deducted from the 2 others: Total Amount = Total Untaxed + Total Tax) + +To take advantage of the fields *Start Date* and *End Date*, you need the OCA module *account_invoice_start_end_dates* from the `account-closing `_ project. + +To know the full story behind the development of this module, read this `blog post `_. diff --git a/account_invoice_import_simple_pdf/readme/INSTALL.rst b/account_invoice_import_simple_pdf/readme/INSTALL.rst new file mode 100644 index 0000000000..ac75273c55 --- /dev/null +++ b/account_invoice_import_simple_pdf/readme/INSTALL.rst @@ -0,0 +1,19 @@ +This module requires several Python libraries: + +* `PyMuPDF `_ which is a Python binding for `MuPDF `_, a lightweight PDF toolkit/viewer/renderer published under the AGPL licence by the company `Artifex Software `_ +* `regex `_ which is backward-compatible with the *re* module of the Python standard library, but has additional functionalities. +* `dateparser `_ which is a powerful date parsing library. + +If you use Debian (Bullseye or higher) or Ubuntu (20.04 or higher), run the following command: + +.. code:: + + sudo apt install python3-fitz python3-regex python3-dateparser + +You can also install these Python librairies via pip: + +.. code:: + + sudo pip3 install --upgrade PyMuPDF regex dateparser + +but beware that *PyMuPDF* is just a binding on MuPDF, so it will require MuPDF and all the development libs required to compile the binding. So, for *PyMuPDF*, it's much easier to install it via the packages of your Linux distribution (package name **python3-fitz** on Debian/Ubuntu, but the package name may be different in other distributions). diff --git a/account_invoice_import_simple_pdf/security/ir.model.access.csv b/account_invoice_import_simple_pdf/security/ir.model.access.csv new file mode 100644 index 0000000000..ce06b9780e --- /dev/null +++ b/account_invoice_import_simple_pdf/security/ir.model.access.csv @@ -0,0 +1,5 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_account_invoice_import_simple_pdf_fields_full,Full access on account.invoice.import.simple.pdf.fields,model_account_invoice_import_simple_pdf_fields,account.group_account_invoice,1,1,1,1 +access_account_invoice_import_simple_pdf_fields_read,Read access on account.invoice.import.simple.pdf.fields,model_account_invoice_import_simple_pdf_fields,account.group_account_readonly,1,0,0,0 +access_account_invoice_import_simple_pdf_invoice_number_full,Full access on account.invoice.import.simple.pdf.invoice.number,model_account_invoice_import_simple_pdf_invoice_number,account.group_account_invoice,1,1,1,1 +access_account_invoice_import_simple_pdf_invoice_number_read,Read access on account.invoice.import.simple.pdf.invoice.number,model_account_invoice_import_simple_pdf_invoice_number,account.group_account_readonly,1,0,0,0 diff --git a/account_invoice_import_simple_pdf/static/description/icon.png b/account_invoice_import_simple_pdf/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 diff --git a/account_invoice_import_simple_pdf/tests/__init__.py b/account_invoice_import_simple_pdf/tests/__init__.py new file mode 100644 index 0000000000..d0a138175d --- /dev/null +++ b/account_invoice_import_simple_pdf/tests/__init__.py @@ -0,0 +1 @@ +from . import test_invoice_import diff --git a/account_invoice_import_simple_pdf/tests/pdf/bouygues_telecom-test.pdf b/account_invoice_import_simple_pdf/tests/pdf/bouygues_telecom-test.pdf new file mode 100644 index 0000000000000000000000000000000000000000..02de6cd8e4fe6b15dbaaadb946f9461855eba9b6 GIT binary patch literal 165905 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 szrT4s#qa0-4Y-51sedze*roCL>F)6 +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import base64 + +from odoo import fields +from odoo.tests.common import TransactionCase +from odoo.tools import file_open, float_compare + + +class TestInvoiceImport(TransactionCase): + def setUp(self): + super().setUp() + self.partner = self.env["res.partner"].create( + { + "name": "Test Partner", + "is_company": True, + "country_id": self.env.ref("base.fr").id, + "simple_pdf_date_format": "dd-mm-y4", + "simple_pdf_date_separator": "slash", + "lang": "fr_FR", + } + ) + aiispfo = self.env["account.invoice.import.simple.pdf.fields"] + self.date_field = aiispfo.create( + { + "name": "date", + "extract_rule": "first", + "partner_id": self.partner.id, + } + ) + self.amount_field = aiispfo.create( + { + "name": "amount_total", + "extract_rule": "first", + "partner_id": self.partner.id, + } + ) + self.inv_num_field = aiispfo.create( + { + "name": "invoice_number", + "extract_rule": "first", + "partner_id": self.partner.id, + } + ) + + self.partner_config = self.partner._simple_pdf_partner_config() + self.test_info = {"test_mode": True} + self.env["account.invoice.import"]._simple_pdf_update_test_info(self.test_info) + aiispfo = self.env["account.invoice.import.simple.pdf.fields"] + self.space_chars = list(self.test_info["space_pattern"][1:-1]) + frtax = self.env["account.tax"].create( + { + "name": "French VAT purchase 20.0%", + "description": "FR-VAT-buy-20.0", + "amount": 20, + "amount_type": "percent", + "type_tax_use": "purchase", + } + ) + self.module = "account_invoice_import_simple_pdf" + self.product = self.env.ref("%s.mobile_phone" % self.module) + self.product.supplier_taxes_id = [(6, 0, [frtax.id])] + self.demo_partner = self.env.ref("%s.bouygues_telecom" % self.module) + self.filename = "bouygues_telecom-test.pdf" + with file_open("%s/tests/pdf/%s" % (self.module, self.filename), "rb") as f: + self.pdf_file = f.read() + self.pdf_file_b64 = base64.b64encode(self.pdf_file) + + def test_date_parsing(self): + date_test = { + "14/07/2021": { + "date_format": "dd-mm-y4", + "date_separator": "slash", + "lang": "any", + }, + "14/7/2021": { + "date_format": "dd-mm-y4", + "date_separator": "slash", + "lang": "any", + }, + "14-7-2021": { + "date_format": "dd-mm-y4", + "date_separator": "dash", + "lang": "any", + }, + "7/14/2021": { + "date_format": "mm-dd-y4", + "date_separator": "slash", + "lang": "any", + }, + "7.14.2021": { + "date_format": "mm-dd-y4", + "date_separator": "dot", + "lang": "any", + }, + "14%sJuillet%s2021": { + "date_format": "dd-month-y4", + "date_separator": "space", + "lang": "fr", + }, + "14%s Juillet%s2021": { + "date_format": "dd-month-y4", + "date_separator": "space", + "lang": "fr", + }, # with double space + "14%sJuillet,%s2021": { + "date_format": "dd-month-y4", + "date_separator": "space", + "lang": "fr", + }, + "14%sjuillet%s2021": { + "date_format": "dd-month-y4", + "date_separator": "space", + "lang": "fr", + }, + "14%sjuillet,%s2021": { + "date_format": "dd-month-y4", + "date_separator": "space", + "lang": "fr", + }, + "14%sjuil.%s2021": { + "date_format": "dd-month-y4", + "date_separator": "space", + "lang": "fr", + }, + "14%sjuil.,%s2021": { + "date_format": "dd-month-y4", + "date_separator": "space", + "lang": "fr", + }, + "july%s14%s2021": { + "date_format": "month-dd-y4", + "date_separator": "space", + "lang": "en", + }, + "july%s14,%s2021": { + "date_format": "month-dd-y4", + "date_separator": "space", + "lang": "en", + }, + "jul.%s14,%s2021": { + "date_format": "month-dd-y4", + "date_separator": "space", + "lang": "en", + }, + } + for src, config in date_test.items(): + raw_text = "Debit 15.12\n%s\n12.99 Total" % src + if config["date_separator"] == "space": + raw_text_list = [ + raw_text % (space_char, space_char) + for space_char in self.space_chars + ] + else: + raw_text_list = [raw_text] + parsed_inv = {"failed_fields": []} + self.date_field.write( + { + "date_format": config["date_format"], + "date_separator": config["date_separator"], + } + ) + lang_list = config["lang"] == "any" and ["fr", "en"] or [config["lang"]] + for lang in lang_list: + self.partner_config["lang_short"] = lang + for raw_txt in raw_text_list: + self.date_field._get_date( + parsed_inv, raw_txt, self.partner_config, self.test_info + ) + res_date = parsed_inv["date"] + self.assertEqual(fields.Date.to_string(res_date), "2021-07-14") + + def test_amount_parsing(self): + amount_test = { + "$ 1.02": { + "decimal_separator": "dot", + "thousand_separator": "coma", + "result": 1.02, + "currency": "USD", + }, + "$ 459.09": { + "decimal_separator": "dot", + "thousand_separator": "coma", + "result": 459.09, + "currency": "USD", + }, + "$ 1,459.32": { + "decimal_separator": "dot", + "thousand_separator": "coma", + "result": 1459.32, + "currency": "USD", + }, + "1.459,32 €": { + "decimal_separator": "coma", + "thousand_separator": "dot", + "result": 1459.32, + "currency": "EUR", + }, + "59,32 €": { + "decimal_separator": "coma", + "thousand_separator": "space", + "result": 59.32, + "currency": "EUR", + }, + "781.459,32 €": { + "decimal_separator": "coma", + "thousand_separator": "dot", + "result": 781459.32, + "currency": "EUR", + }, + "781%s459,32€": { + "decimal_separator": "coma", + "thousand_separator": "space", + "result": 781459.32, + "currency": "EUR", + }, + "99459,32 €": { + "decimal_separator": "coma", + "thousand_separator": "none", + "result": 99459.32, + "currency": "EUR", + }, + "14%s459 XPF": { + "decimal_separator": "coma", + "thousand_separator": "space", + "result": 14459, + "currency": "XPF", + }, # XPF decimal places = 0 + "14%s459,123 XPF": { + "decimal_separator": "coma", + "thousand_separator": "space", + "result": 14459.123, + "currency": "TND", + }, # TND decimal places = 3 + "88,459.1234 VEF": { + "decimal_separator": "dot", + "thousand_separator": "coma", + "result": 88459.1234, + "currency": "VEF", + }, # VEF decimal places = 4 + } + for src, config in amount_test.items(): + raw_text = ( + "Invoice Date: 05/12/2019\n%s\nSAS with a capital of 1,234,322.23 USD" + % src + ) + if config["thousand_separator"] == "space" and "%s" in raw_text: + raw_text_list = [ + raw_text % space_char for space_char in self.space_chars + ] + else: + raw_text_list = [raw_text] + parsed_inv = {"failed_fields": []} + self.partner.write( + { + "simple_pdf_decimal_separator": config["decimal_separator"], + "simple_pdf_thousand_separator": config["thousand_separator"], + "simple_pdf_currency_id": self.env.ref( + "base.%s" % config["currency"] + ).id, + } + ) + partner_config = self.partner._simple_pdf_partner_config() + if partner_config["currency"].decimal_places == 0: + self.amount_field.write({"extract_rule": "last"}) + else: + self.amount_field.write({"extract_rule": "first"}) + for raw_txt in raw_text_list: + self.amount_field._get_amount( + parsed_inv, raw_txt, partner_config, self.test_info + ) + res_amount = parsed_inv["amount_total"] + self.assertFalse( + partner_config["currency"].compare_amounts( + res_amount, config["result"] + ) + ) + + def test_invoice_number_parsing(self): + inv_num_test = { + "INV/2020/05/0042": [ + {"string_type": "fixed", "fixed_char": "INV/"}, + {"string_type": "year4"}, + {"string_type": "fixed", "fixed_char": "/"}, + {"string_type": "month"}, + {"string_type": "fixed", "fixed_char": "/"}, + {"string_type": "digit", "occurrence_min": 4, "occurrence_max": 5}, + ], + "I210042": [ + {"string_type": "fixed", "fixed_char": "I"}, + {"string_type": "year2"}, + {"string_type": "digit", "occurrence_min": 4, "occurrence_max": 5}, + ], + "INV2107ZB0042": [ + {"string_type": "fixed", "fixed_char": "INV"}, + {"string_type": "year2"}, + {"string_type": "month"}, + { + "string_type": "letter_upper", + "occurrence_min": 2, + "occurrence_max": 2, + }, + {"string_type": "digit", "occurrence_min": 4, "occurrence_max": 5}, + ], + # If you wonder which company can have such a stupid invoice number, + # the answer is... Orange ! I won't say what I think about these guys... + "04B700L456 21A7- 1J01": [ + {"string_type": "fixed", "fixed_char": "04B700L456"}, + {"string_type": "space"}, + {"string_type": "year2"}, + { + "string_type": "letter_upper", + "occurrence_min": 1, + "occurrence_max": 1, + }, + {"string_type": "digit", "occurrence_min": 1, "occurrence_max": 1}, + {"string_type": "fixed", "fixed_char": "-"}, + {"string_type": "space"}, + {"string_type": "fixed", "fixed_char": "1J"}, + {"string_type": "month"}, + ], + } + for src, config_list in inv_num_test.items(): + raw_txt = "Invoice number: %s dated 20/08/2020" % src + self.partner.simple_pdf_invoice_number_ids.unlink() + self.partner.write( + {"simple_pdf_invoice_number_ids": [(0, 0, x) for x in config_list]} + ) + parsed_inv = {"failed_fields": []} + self.inv_num_field._get_invoice_number( + parsed_inv, raw_txt, self.partner_config, self.test_info + ) + self.assertEqual(src, parsed_inv["invoice_number"]) + + def test_raw_extraction(self): + aiio = self.env["account.invoice.import"] + res = aiio.simple_pdf_text_extraction(self.pdf_file, self.test_info) + self.assertIsInstance(res, dict) + self.assertTrue(len(res["all"]) >= len(res["first"])) + self.assertIn("FR 74 397 480 930", res["first"]) + self.assertIn("FR74397480930", res["first_no_space"]) + + def test_complete_import(self): + wiz = self.env["account.invoice.import"].create( + { + "invoice_file": self.pdf_file_b64, + "invoice_filename": self.filename, + } + ) + wiz.import_invoice() + # Check result of invoice creation + invoices = self.env["account.move"].search( + [ + ("partner_id", "=", self.demo_partner.id), + ("state", "=", "draft"), + ("move_type", "=", "in_invoice"), + ("ref", "=", "11608848301659"), + ] + ) + inv_config = self.env.ref("%s.bouygues_telecom_import_config" % self.module) + self.assertEqual(len(invoices), 1) + inv = invoices[0] + self.assertEqual(fields.Date.to_string(inv.invoice_date), "2019-11-02") + self.assertEqual(inv.journal_id.type, "purchase") + self.assertEqual(inv.currency_id, self.env.ref("base.EUR")) + self.assertFalse(inv.currency_id.compare_amounts(inv.amount_total, 12.99)) + self.assertFalse(inv.currency_id.compare_amounts(inv.amount_untaxed, 10.83)) + self.assertEqual(len(inv.invoice_line_ids), 1) + iline = inv.invoice_line_ids[0] + self.assertEqual(iline.name, inv_config.label) + self.assertEqual(iline.product_id, self.product) + self.assertEqual(iline.tax_ids, self.product.supplier_taxes_id) + self.assertEqual(float_compare(iline.quantity, 1.0, precision_digits=2), 0) + self.assertEqual(float_compare(iline.price_unit, 10.83, precision_digits=2), 0) + inv.unlink() + + def test_test_mode(self): + self.demo_partner.write( + { + "simple_pdf_test_file": self.pdf_file_b64, + "simple_pdf_test_filename": self.filename, + } + ) + self.demo_partner.pdf_simple_test_run() + self.assertTrue(self.demo_partner.simple_pdf_test_results) + self.assertTrue(self.demo_partner.simple_pdf_test_raw_text) + self.demo_partner.pdf_simple_test_cleanup() + self.assertFalse(self.demo_partner.simple_pdf_test_results) + self.assertFalse(self.demo_partner.simple_pdf_test_raw_text) + self.assertFalse(self.demo_partner.simple_pdf_test_file) diff --git a/account_invoice_import_simple_pdf/views/account_invoice_import_simple_pdf_fields.xml b/account_invoice_import_simple_pdf/views/account_invoice_import_simple_pdf_fields.xml new file mode 100644 index 0000000000..6a2f292f97 --- /dev/null +++ b/account_invoice_import_simple_pdf/views/account_invoice_import_simple_pdf_fields.xml @@ -0,0 +1,83 @@ + + + + + + + account.invoice.import.simple.pdf.fields + +
+ + + + + + + + + + + + + + + +
+
+
+ + + account.invoice.import.simple.pdf.fields + + + + + + + + + + + + + + + + + + +
diff --git a/account_invoice_import_simple_pdf/views/account_invoice_import_simple_pdf_invoice_number.xml b/account_invoice_import_simple_pdf/views/account_invoice_import_simple_pdf_invoice_number.xml new file mode 100644 index 0000000000..2eb8705392 --- /dev/null +++ b/account_invoice_import_simple_pdf/views/account_invoice_import_simple_pdf_invoice_number.xml @@ -0,0 +1,68 @@ + + + + + + + account.invoice.import.simple.pdf.invoice.number + +
+ + + + + + + +
+
+
+ + + account.invoice.import.simple.pdf.invoice.number + + + + + + + + + + + + + + +
diff --git a/account_invoice_import_simple_pdf/views/res_partner.xml b/account_invoice_import_simple_pdf/views/res_partner.xml new file mode 100644 index 0000000000..f4d80e3686 --- /dev/null +++ b/account_invoice_import_simple_pdf/views/res_partner.xml @@ -0,0 +1,127 @@ + + + + + + + res.partner + + +
+ + +
+ +
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+
+ + +
diff --git a/account_invoice_import_simple_pdf/wizard/__init__.py b/account_invoice_import_simple_pdf/wizard/__init__.py new file mode 100644 index 0000000000..9817a01c22 --- /dev/null +++ b/account_invoice_import_simple_pdf/wizard/__init__.py @@ -0,0 +1 @@ +from . import account_invoice_import diff --git a/account_invoice_import_simple_pdf/wizard/account_invoice_import.py b/account_invoice_import_simple_pdf/wizard/account_invoice_import.py new file mode 100644 index 0000000000..bb58e9fbd5 --- /dev/null +++ b/account_invoice_import_simple_pdf/wizard/account_invoice_import.py @@ -0,0 +1,189 @@ +# Copyright 2021 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import logging +from tempfile import NamedTemporaryFile + +from odoo import _, api, models +from odoo.exceptions import UserError + +logger = logging.getLogger(__name__) + +try: + import fitz +except ImportError: + logger.debug("Cannot import PyMuPDF") +try: + import regex +except ImportError: + logger.debug("Cannot import regex") + + +class AccountInvoiceImport(models.TransientModel): + _inherit = "account.invoice.import" + + @api.model + def fallback_parse_pdf_invoice(self, file_data): + """This method must be inherited by additional modules with + the same kind of logic as the account_bank_statement_import_* + modules""" + return self.simple_pdf_parse_invoice(file_data) + + @api.model + def simple_pdf_text_extraction(self, file_data, test_info): + res = {} + fileobj = NamedTemporaryFile("wb", prefix="odoo-simple-pdf-", suffix=".pdf") + fileobj.write(file_data) + # Extract text from PDF + # Very interesting reading: + # https://github.com/erfelipe/PDFtextExtraction + res["all"] = "" + doc = fitz.open(fileobj.name) + for page in doc: + res["all"] += page.getText("text") + res["first"] = doc[0].getText("text") + res["all_no_space"] = regex.sub( + "%s+" % test_info["space_pattern"], "", res["all"] + ) + res["first_no_space"] = regex.sub( + "%s+" % test_info["space_pattern"], "", res["first"] + ) + fileobj.close() + return res + + @api.model + def simple_pdf_match_partner(self, raw_text_no_space, test_results=None): + if test_results is None: + test_results = [] + partner_id = False + rpo = self.env["res.partner"] + partners = rpo.search_read( + [ + "|", + ("vat", "!=", False), + ("simple_pdf_keyword", "!=", False), + ("parent_id", "=", False), + ("is_company", "=", True), + ] + ) + for partner in partners: + if partner["simple_pdf_keyword"] and partner["simple_pdf_keyword"].strip(): + keywords = partner["simple_pdf_keyword"].replace(" ", "").split("|") + found_res = [keyword in raw_text_no_space for keyword in keywords] + if all(found_res): + partner_id = partner["id"] + result_label = _("Successful match on %d keywords (%s)") % ( + len(keywords), + ", ".join(keywords), + ) + test_results.append("
  • %s
  • " % result_label) + break + elif partner["vat"]: + if partner["vat"] in raw_text_no_space: + partner_id = partner["id"] + result_label = ( + _("Successful match on VAT number '%s'") % partner["vat"] + ) + test_results.append("
  • %s
  • " % result_label) + break + return partner_id + + @api.model + def _get_space_pattern(self): + # https://en.wikipedia.org/wiki/Whitespace_character + space_ints = [ + 32, + 160, + 8192, + 8193, + 8194, + 8195, + 8196, + 8197, + 8198, + 8199, + 8200, + 8201, + 8202, + 8239, + 8287, + ] + return "[%s]" % "".join([chr(x) for x in space_ints]) + + @api.model + def _simple_pdf_update_test_info(self, test_info): + aiispfo = self.env["account.invoice.import.simple.pdf.fields"] + test_info.update( + { + "date_format_sel": dict( + aiispfo.fields_get("date_format", "selection")["date_format"][ + "selection" + ] + ), + "field_name_sel": dict( + aiispfo.fields_get("name", "selection")["name"]["selection"] + ), + "extract_rule_sel": dict( + aiispfo.fields_get("extract_rule", "selection")["extract_rule"][ + "selection" + ] + ), + "space_pattern": self._get_space_pattern(), + } + ) + + @api.model + def simple_pdf_parse_invoice(self, file_data, test_info=None): + if test_info is None: + test_info = {"test_mode": False} + self._simple_pdf_update_test_info(test_info) + rpo = self.env["res.partner"] + logger.info("Trying to analyze PDF invoice with simple pdf module") + raw_text_dict = self.simple_pdf_text_extraction(file_data, test_info) + partner_id = self.simple_pdf_match_partner(raw_text_dict["all_no_space"]) + if not partner_id: + raise UserError(_("Simple PDF Import: count not find Vendor.")) + partner = rpo.browse(partner_id) + raw_text = ( + partner.simple_pdf_pages and raw_text_dict["first"] or raw_text_dict["all"] + ) + logger.info( + "Simple pdf import found partner %s ID %d", partner.display_name, partner_id + ) + partner_config = partner._simple_pdf_partner_config() + parsed_inv = { + "partner": {"recordset": partner}, + "currency": {"recordset": partner_config["currency"]}, + "failed_fields": [], + "chatter_msg": [], + } + + # Check field config + for field in partner.simple_pdf_field_ids: + logger.debug("Working on field %s", field.name) + if field.name.startswith("date"): + field._get_date(parsed_inv, raw_text, partner_config, test_info) + elif field.name.startswith("amount_"): + field._get_amount(parsed_inv, raw_text, partner_config, test_info) + elif field.name == "invoice_number": + field._get_invoice_number( + parsed_inv, raw_text, partner_config, test_info + ) + elif field.name == "description": + field._get_description(parsed_inv, raw_text, partner_config, test_info) + + failed_fields = parsed_inv.pop("failed_fields") + if failed_fields: + parsed_inv["chatter_msg"].append( + _("Failed to extract the following field(s): %s.") + % ", ".join( + [ + "%s" % test_info["field_name_sel"][failed_field] + for failed_field in failed_fields + ] + ) + ) + + logger.info("simple pdf parsed_inv=%s", parsed_inv) + return parsed_inv diff --git a/account_invoice_import_simple_pdf/wizard/account_invoice_import_view.xml b/account_invoice_import_simple_pdf/wizard/account_invoice_import_view.xml new file mode 100644 index 0000000000..c57a04fba5 --- /dev/null +++ b/account_invoice_import_simple_pdf/wizard/account_invoice_import_view.xml @@ -0,0 +1,22 @@ + + + + + + + account.invoice.import + + +
      +
    • regular PDF file without any embedded XML file via a pre-configuration in Odoo.
    • +
    +
    +
    + + +
    From 21f217873d92d52fc179f68199e489ce5884298f Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Tue, 24 Aug 2021 09:24:37 +0200 Subject: [PATCH 02/65] Temporary workaround of odoo bug https://github.com/odoo/odoo/issues/75492 Make pre-commit green --- .../models/account_invoice_import_simple_pdf_fields.py | 6 +++++- account_invoice_import_simple_pdf/models/res_partner.py | 8 ++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/account_invoice_import_simple_pdf/models/account_invoice_import_simple_pdf_fields.py b/account_invoice_import_simple_pdf/models/account_invoice_import_simple_pdf_fields.py index 93c3ec5e3c..ca12750185 100644 --- a/account_invoice_import_simple_pdf/models/account_invoice_import_simple_pdf_fields.py +++ b/account_invoice_import_simple_pdf/models/account_invoice_import_simple_pdf_fields.py @@ -116,7 +116,11 @@ def field_change(self): elif self.name in ("invoice_number", "description", "date"): self.extract_rule = "first" - def get_value_from_list(self, data_list, test_info, raise_if_none=True): + # This method is just 1 line over the complexity limit of C901 + # and I don't see a good way to split it + def get_value_from_list( # noqa: C901 + self, data_list, test_info, raise_if_none=True + ): assert isinstance(data_list, list) if not data_list: if raise_if_none: diff --git a/account_invoice_import_simple_pdf/models/res_partner.py b/account_invoice_import_simple_pdf/models/res_partner.py index b423ec80dd..ea94d702c5 100644 --- a/account_invoice_import_simple_pdf/models/res_partner.py +++ b/account_invoice_import_simple_pdf/models/res_partner.py @@ -48,17 +48,21 @@ def _simple_pdf_date_separator_sel(self): help="If empty, Odoo will use the VAT number to identify the partner. " "To match on several keywords, separate them with '|' (pipe)." ) + # Temporary hack: I disable the default values for the fields + # simple_pdf_date_format and simple_pdf_date_separator + # to avoid the following bug: + # https://github.com/odoo/odoo/issues/75492 simple_pdf_date_format = fields.Selection( "_simple_pdf_date_format_sel", string="Date Format", - default="dd-mm-y4", + # default="dd-mm-y4", help="If the date format uses 'Month', check that the language is " "properly configured on the partner. 'Month' works both in full and " "short version ('January' and 'Jan.').", ) simple_pdf_date_separator = fields.Selection( "_simple_pdf_date_separator_sel", - default="slash", + # default="slash", string="Date Separator", help="If the date looks like 'Sep. 4, 2021', use 'space' as date " "separator (Odoo will ignore the dot and coma).", From 3db926ec85efe79464427bba0ae86bf718310083 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Tue, 31 Aug 2021 12:42:06 +0200 Subject: [PATCH 03/65] Improve handling of start/end string cut when there are multiplue occurences of cut string Add tests on string cut method --- ...ccount_invoice_import_simple_pdf_fields.py | 24 ++++++++++----- .../tests/test_invoice_import.py | 29 ++++++++++++++++++- 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/account_invoice_import_simple_pdf/models/account_invoice_import_simple_pdf_fields.py b/account_invoice_import_simple_pdf/models/account_invoice_import_simple_pdf_fields.py index ca12750185..9fff2545b2 100644 --- a/account_invoice_import_simple_pdf/models/account_invoice_import_simple_pdf_fields.py +++ b/account_invoice_import_simple_pdf/models/account_invoice_import_simple_pdf_fields.py @@ -201,7 +201,7 @@ def restrict_text(self, raw_text, test_info): start = self.start and self.start.strip() or False end = self.end and self.end.strip() or False if start: - position = restrict_text.rfind(start) + position = restrict_text.find(start) if position >= 0: restrict_text = restrict_text[position + len(start) :] test_info[self.name]["start"] = _("Successful cut on '%s'") % start @@ -209,13 +209,23 @@ def restrict_text(self, raw_text, test_info): error_msg = _("String '%s' not found") % start test_info[self.name]["start"] = "%s" % (ERROR_STYLE, error_msg) if end: - position = restrict_text.rfind(end) - if position >= 0: - restrict_text = restrict_text[:position] - test_info[self.name]["end"] = _("Successful cut on '%s'") % end - else: - error_msg = _("String '%s' not found") % end + if not restrict_text or (restrict_text and not restrict_text.strip()): + error_msg = _( + "No text to cut, maybe because start string " + "was the very end of the document" + ) test_info[self.name]["end"] = "%s" % (ERROR_STYLE, error_msg) + else: + position = restrict_text.find(end) + if position >= 0: + restrict_text = restrict_text[:position] + test_info[self.name]["end"] = _("Successful cut on '%s'") % end + else: + error_msg = _("String '%s' not found") % end + test_info[self.name]["end"] = "%s" % ( + ERROR_STYLE, + error_msg, + ) return restrict_text def _get_date(self, parsed_inv, raw_text, partner_config, test_info): diff --git a/account_invoice_import_simple_pdf/tests/test_invoice_import.py b/account_invoice_import_simple_pdf/tests/test_invoice_import.py index c1bdb331fc..7c88f4fbd7 100644 --- a/account_invoice_import_simple_pdf/tests/test_invoice_import.py +++ b/account_invoice_import_simple_pdf/tests/test_invoice_import.py @@ -19,7 +19,6 @@ def setUp(self): "country_id": self.env.ref("base.fr").id, "simple_pdf_date_format": "dd-mm-y4", "simple_pdf_date_separator": "slash", - "lang": "fr_FR", } ) aiispfo = self.env["account.invoice.import.simple.pdf.fields"] @@ -172,6 +171,34 @@ def test_date_parsing(self): res_date = parsed_inv["date"] self.assertEqual(fields.Date.to_string(res_date), "2021-07-14") + def test_restrict_text(self): + cut_test = { + "T1 ici et là POUET là et par là POUET": { + "start": "POUET", + "end": "POUET", + "res": " là et par là ", + }, + "T2 ici et là POUET là et par là POUET": { + "start": "POUET", + "res": " là et par là POUET", + }, + "T3 ici et là POUET là et par là POUET": { + "end": "POUET", + "res": "T3 ici et là ", + }, + } + # I use the date field, but I could use any other field + self.test_info[self.date_field.name] = {} + for raw_txt, config in cut_test.items(): + self.date_field.write( + { + "start": config.get("start"), + "end": config.get("end"), + } + ) + res = self.date_field.restrict_text(raw_txt, self.test_info) + self.assertEqual(res, config["res"]) + def test_amount_parsing(self): amount_test = { "$ 1.02": { From 5d474a12f9f30801b28109f097a48456f280a078 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Wed, 15 Sep 2021 18:37:07 +0200 Subject: [PATCH 04/65] [FIX] when the invoice has the VAT number of the supplier and also the VAT number of the customer --- .../wizard/account_invoice_import.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/account_invoice_import_simple_pdf/wizard/account_invoice_import.py b/account_invoice_import_simple_pdf/wizard/account_invoice_import.py index bb58e9fbd5..d81f5f9bfc 100644 --- a/account_invoice_import_simple_pdf/wizard/account_invoice_import.py +++ b/account_invoice_import_simple_pdf/wizard/account_invoice_import.py @@ -58,6 +58,9 @@ def simple_pdf_match_partner(self, raw_text_no_space, test_results=None): test_results = [] partner_id = False rpo = self.env["res.partner"] + # Warning: invoices have the VAT number of the supplier, but they often + # also have the VAT number of the customer (i.e. the VAT number of our company) + # So we exclude it from the search partners = rpo.search_read( [ "|", @@ -65,6 +68,7 @@ def simple_pdf_match_partner(self, raw_text_no_space, test_results=None): ("simple_pdf_keyword", "!=", False), ("parent_id", "=", False), ("is_company", "=", True), + ("id", "!=", self.env.company.partner_id.id), ] ) for partner in partners: From 652a056c204ef856289204950e4550bd6222f8f4 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Wed, 13 Oct 2021 10:02:48 +0200 Subject: [PATCH 05/65] [FIX] Read of the "Page Analysis" parameter Before this fix, Page Analysis was always "First page" in the code. FIX on view inheritance to avoid access right issues --- .../views/res_partner.xml | 11 +++++------ .../wizard/account_invoice_import.py | 4 +++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/account_invoice_import_simple_pdf/views/res_partner.xml b/account_invoice_import_simple_pdf/views/res_partner.xml index f4d80e3686..1c24cd28d9 100644 --- a/account_invoice_import_simple_pdf/views/res_partner.xml +++ b/account_invoice_import_simple_pdf/views/res_partner.xml @@ -13,20 +13,19 @@ name="inherit_id" ref="account_invoice_import.view_partner_property_form" /> +
    -
    +
    -
    @@ -47,6 +27,7 @@ string="Invoice Currency" options="{'no_create': True, 'no_create_edit': True}" /> + @@ -118,7 +99,7 @@ - + diff --git a/account_invoice_import_simple_pdf/migrations/14.0.1.0.1/pre-migration.py b/account_invoice_import_simple_pdf/migrations/14.0.1.0.1/pre-migration.py deleted file mode 100644 index 42fbf8f6ed..0000000000 --- a/account_invoice_import_simple_pdf/migrations/14.0.1.0.1/pre-migration.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright 2021 Akretion France (http://www.akretion.com/) -# @author: Alexis de Lattre -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - - -def migrate(cr, version): - if not version: - return - - # Fix typo coma -> comma - cr.execute( - """ - UPDATE res_partner SET simple_pdf_decimal_separator='comma' - WHERE simple_pdf_decimal_separator='coma' - """ - ) - - cr.execute( - """ - UPDATE res_partner SET simple_pdf_thousand_separator='comma' - WHERE simple_pdf_thousand_separator='coma' - """ - ) diff --git a/account_invoice_import_simple_pdf/wizard/__init__.py b/account_invoice_import_simple_pdf/wizard/__init__.py deleted file mode 100644 index 9817a01c22..0000000000 --- a/account_invoice_import_simple_pdf/wizard/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import account_invoice_import diff --git a/account_invoice_import_simple_pdf/wizard/account_invoice_import_view.xml b/account_invoice_import_simple_pdf/wizard/account_invoice_import_view.xml deleted file mode 100644 index c57a04fba5..0000000000 --- a/account_invoice_import_simple_pdf/wizard/account_invoice_import_view.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - account.invoice.import - - -
      -
    • regular PDF file without any embedded XML file via a pre-configuration in Odoo.
    • -
    -
    -
    - - -
    diff --git a/setup/account_edi_simple_pdf/odoo/addons/account_edi_simple_pdf b/setup/account_edi_simple_pdf/odoo/addons/account_edi_simple_pdf new file mode 120000 index 0000000000..38411f94ce --- /dev/null +++ b/setup/account_edi_simple_pdf/odoo/addons/account_edi_simple_pdf @@ -0,0 +1 @@ +../../../../account_edi_simple_pdf \ No newline at end of file diff --git a/setup/account_invoice_import_simple_pdf/setup.py b/setup/account_edi_simple_pdf/setup.py similarity index 100% rename from setup/account_invoice_import_simple_pdf/setup.py rename to setup/account_edi_simple_pdf/setup.py diff --git a/setup/account_invoice_import_simple_pdf/odoo/addons/account_invoice_import_simple_pdf b/setup/account_invoice_import_simple_pdf/odoo/addons/account_invoice_import_simple_pdf deleted file mode 120000 index f89e3301fa..0000000000 --- a/setup/account_invoice_import_simple_pdf/odoo/addons/account_invoice_import_simple_pdf +++ /dev/null @@ -1 +0,0 @@ -../../../../account_invoice_import_simple_pdf \ No newline at end of file