Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

16.0 add grap custom import #1

Merged
merged 6 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# <GRAP>
# Ignore Opened csv files
.~lock.*
# Do not share pdf file. (grap-odoo-business-supplier-invoice)
*.pdf
# </GRAP>
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright (C) 2024 - Today: GRAP (http://www.grap.coop)
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

{
"name": "GRAP - Custom Import Fiscal Classification",
"summary": "Extra GRAP Tools to import data for"
" Account Product Fiscal Classification",
"version": "16.0.1.0.0",
"category": "Tools",
"author": "GRAP",
"website": "https://github.com/grap/grap-odoo-import",
"license": "AGPL-3",
"depends": ["grap_custom_import_product", "account_product_fiscal_classification"],
"auto_install": True,
"installable": True,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import product_product
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Copyright (C) 2024 - Today: GRAP (http://www.grap.coop)
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo import _, fields, models
from odoo.exceptions import ValidationError
from odoo.osv import expression


class ProductProduct(models.Model):
_inherit = "product.product"

grap_import_vat_amount = fields.Float(string="VAT Amount (For import)", store=False)

# pylint: disable=missing-return
def _custom_import_hook_vals(self, old_vals, new_vals):
super()._custom_import_hook_vals(old_vals, new_vals)
self._custom_import_handle_fiscal_classification_id(old_vals, new_vals)

def _custom_import_get_fiscal_classifications(self, vat_amount):
domain = expression.OR(
[[("company_id", "=", self.env.company.id)], [("company_id", "=", False)]]
)
if vat_amount:
domain = expression.AND(
[domain, [("sale_tax_ids.amount", "=", 100 * vat_amount)]]
)
else:
domain = expression.AND([domain, [("sale_tax_ids", "=", False)]])

return (
self.env["account.product.fiscal.classification"]
.search(domain)
.filtered(lambda x: len(x.sale_tax_ids) < 2)
)

def _custom_import_handle_fiscal_classification_id(self, old_vals, new_vals):
vat_amount = old_vals.get("grap_import_vat_amount")
if not vat_amount and not self.env.context.get("install_mode"):
raise ValidationError(

Check warning on line 40 in grap_custom_import_account_product_fiscal_classification/models/product_product.py

View check run for this annotation

Codecov / codecov/patch

grap_custom_import_account_product_fiscal_classification/models/product_product.py#L40

Added line #L40 was not covered by tests
_(
"No VAT Amount found for the product %(product_name)s",
product_name=old_vals.get("name"),
)
)
classifications = self._custom_import_get_fiscal_classifications(vat_amount)

if len(classifications) == 1:
new_vals["fiscal_classification_id"] = classifications.id
return

elif len(classifications) == 0:
raise ValidationError(

Check warning on line 53 in grap_custom_import_account_product_fiscal_classification/models/product_product.py

View check run for this annotation

Codecov / codecov/patch

grap_custom_import_account_product_fiscal_classification/models/product_product.py#L53

Added line #L53 was not covered by tests
_(
"No Fiscal Classification Found for the product %(product_name)s."
" Vat Amount %(vat_amount)s",
product_name=old_vals.get("name"),
vat_amount=vat_amount,
)
)

raise ValidationError(
_(

Check warning on line 63 in grap_custom_import_account_product_fiscal_classification/models/product_product.py

View check run for this annotation

Codecov / codecov/patch

grap_custom_import_account_product_fiscal_classification/models/product_product.py#L62-L63

Added lines #L62 - L63 were not covered by tests
"Many Fiscal Classifications Found for the product %(product_name)s."
" Vat Amount %(vat_amount)s. Fiscal Classifications : %(classification_names)s",
product_name=old_vals.get("name"),
vat_amount=vat_amount,
classification_names=",".join(classifications.mapped("name")),
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* Sylvain LE GAL <https://twitter.com/legalsylvain>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
This module improve the "import" features provided by Odoo.

* ``product.product``:

* Allow to recover ``multiplier_qty`` field in the supplier info level.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
* handle selection of classifications for ``recurring_consignment``,
once the module is ported in V16.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import test_module
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
name,uom_id,categ_id,barcode,list_price,grap_import_supplier_name,grap_import_supplier_product_code,grap_import_supplier_product_name,grap_import_supplier_gross_price,grap_import_vat_amount
Mention Good (Late chocolate),Units,All / Saleable,3222472195092,2.29,Ready Mat,GOOD,MENTION GOOD,1.98,0.20
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Copyright (C) 2024 - Today: GRAP (http://www.grap.coop)
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo.tests import tagged

from odoo.addons.grap_custom_import_product.tests.test_module import TestModuleProduct


@tagged("post_install", "-at_install")
class TestModuleProductSupplierinfoQtyMultiplier(TestModuleProduct):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.ProductProduct = cls.env["product.product"]
cls.classification_20 = cls.env.ref(
"account_product_fiscal_classification.fiscal_classification_A_company_1"
)

def test_01_import_product_account_product_fiscal_classification(self):
products, messages = self._test_import_file(
"grap_custom_import_account_product_fiscal_classification",
"product.product",
"product.csv",
)
self.assertFalse(messages)
self.assertEqual(len(products), 1)
self.assertEqual(products.fiscal_classification_id, self.classification_20)
Empty file.
1 change: 1 addition & 0 deletions grap_custom_import_base/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
15 changes: 15 additions & 0 deletions grap_custom_import_base/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright (C) 2019 - Today: GRAP (http://www.grap.coop)
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

{
"name": "GRAP - Custom Import Base Module",
"summary": "Extra GRAP Tools to import data for base module",
"version": "16.0.1.0.0",
"category": "Tools",
"author": "GRAP",
"website": "https://github.com/grap/grap-odoo-import",
"license": "AGPL-3",
"depends": ["base_import"],
"installable": True,
}
2 changes: 2 additions & 0 deletions grap_custom_import_base/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import custom_import_mixin
from . import res_partner
82 changes: 82 additions & 0 deletions grap_custom_import_base/models/custom_import_mixin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Copyright (C) 2024 - Today: GRAP (http://www.grap.coop)
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo import _, models
from odoo.exceptions import ValidationError


class CustomImportMixin(models.AbstractModel):
_name = "custom.import.mixin"
_description = "Mixin providing helper for imports"

def _custom_import_prevent_duplicate_fields(self):
"""Define the fields that will be used to prevent
Duplicates in the import"""
return []

def _custom_import_hook_vals(self, old_vals, new_vals):
# Check if existing duplicates are present in the database
for field in self._custom_import_prevent_duplicate_fields():
if new_vals.get(field):
items = self.search([(field, "=", new_vals.get(field))])
if items:
raise ValidationError(
_(
"The following items still exist in the database"
" for the field %(field)s. Values: %(values)s",
field=field,
values=",".join(items.mapped(field)),
)
)
return new_vals

def _custom_import_check_duplicates_new_vals(self, vals_list):
for field in self._custom_import_prevent_duplicate_fields():
duplicates = []
for vals in vals_list:
if vals.get(field):
if vals[field] in duplicates:
raise ValidationError(
_(
"The file contain many item(s) with"
" the same value '%(value)s' for the"
" field '%(field)s'.",
field=field,
value=vals[field],
)
)
duplicates.append(vals[field])

def _custom_import_get_or_create(
self, model_name, search_field_name, vals, field_name
):
ItemModel = self.env[model_name]
if not vals.get(field_name):
return False
items = ItemModel.search([(search_field_name, "=", vals[field_name])])
if len(items) == 0:
return ItemModel.create({"name": vals[field_name]})
elif len(items) == 1:
return items
elif len(items) >= 2:
raise ValidationError(
_(
"%(item_qty)d items found for the field %(field_name)s."
" Value: '%(value)s'."
),
item_qty=len(items),
field_name=field_name,
value=vals["field_name"],
)

# Overload Section
def _load_records_create(self, vals_list):
new_vals_list = []
for vals in vals_list:
new_vals = vals.copy()
self._custom_import_hook_vals(vals, new_vals)
new_vals_list.append(new_vals)
# TODO, move this check in another part
self._custom_import_check_duplicates_new_vals(new_vals_list)
return super()._load_records_create(new_vals_list)
19 changes: 19 additions & 0 deletions grap_custom_import_base/models/res_partner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright (C) 2024 - Today: GRAP (http://www.grap.coop)
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

import logging

from odoo import models

logger = logging.getLogger(__name__)


class ResPartner(models.Model):
_name = "res.partner"
_inherit = ["res.partner", "custom.import.mixin"]

def _custom_import_prevent_duplicate_fields(self):
res = super()._custom_import_prevent_duplicate_fields()
res += ["name", "vat"]
return res
1 change: 1 addition & 0 deletions grap_custom_import_base/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* Sylvain LE GAL <https://twitter.com/legalsylvain>
7 changes: 7 additions & 0 deletions grap_custom_import_base/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
This module improve the "import" features provided by Odoo.

It provides generic tools for that purpose, and improve imports for some models.

* ``res.partner``:

* Prevent to create duplicates regarding ``name`` and ``vat`` fields.
1 change: 1 addition & 0 deletions grap_custom_import_base/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import test_module
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
name,email,phone,mobile,website,street,street2,zip,city,country_id,vat
Relais Vert,[email protected],04 90 67 23 72,06 12 34 56 78,https://www.relais-vert.com/,ZONE BELLECOUR 3,621 Allée BELLECOUR,84200,CARPENTRAS,France,FR72352867493
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name,email,phone,mobile,website,street,street2,zip,city,country_id,vat
Relais Vert,[email protected],04 90 67 23 72,06 12 34 56 78,https://www.relais-vert.com/,ZONE BELLECOUR 3,621 Allée BELLECOUR,84200,CARPENTRAS,France,FR72352867493
Reloud Vert,[email protected],04 90 67 23 72,06 12 34 56 78,https://www.relais-vert.com/,ZONE BELLECOUR 3,621 Allée BELLECOUR,84200,CARPENTRAS,France,FR72352867493
71 changes: 71 additions & 0 deletions grap_custom_import_base/tests/test_module.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Copyright (C) 2024 - Today: GRAP (http://www.grap.coop)
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo.modules.module import get_module_resource
from odoo.tests import tagged
from odoo.tests.common import TransactionCase


@tagged("post_install", "-at_install")
class TestModuleBase(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.ResPartner = cls.env["res.partner"]
cls.Wizard = cls.env["base_import.import"]

def _test_import_file(self, module, model, file_name):
preview_options = {"headers": True, "quoting": '"'}
import_options = {"has_headers": True, "quoting": '"'}

# Read File
file_path = get_module_resource(module, "tests/templates/", model, file_name)
extension = file_path.split(".")[-1]
if extension == "csv":
file_type = "text/csv"
else:
file_type = "Unimplemented Extension"

Check warning on line 28 in grap_custom_import_base/tests/test_module.py

View check run for this annotation

Codecov / codecov/patch

grap_custom_import_base/tests/test_module.py#L28

Added line #L28 was not covered by tests

file_content = open(file_path, "rb").read()

# Create Wizard
import_wizard = self.Wizard.create(
{"res_model": model, "file": file_content, "file_type": file_type}
)

# Run Preview
result_parse = import_wizard.parse_preview(preview_options)
column_list = [x[0] for x in result_parse["preview"]]

# Execute Import
results = import_wizard.execute_import(column_list, column_list, import_options)

items = self.env[model].browse(results.get("ids"))
return items, results["messages"]

def test_01_import_supplier(self):
partners, messages = self._test_import_file(
"grap_custom_import_base", "res.partner", "supplier.csv"
)
self.assertFalse(messages)
self.assertEqual(len(partners), 1)
self.assertEqual(partners.name, "Relais Vert")

def test_02_existing_duplicates_name(self):
partners, messages = self._test_import_file(
"grap_custom_import_base", "res.partner", "supplier.csv"
)
self.assertFalse(messages)
partners, messages = self._test_import_file(
"grap_custom_import_base", "res.partner", "supplier.csv"
)
self.assertEqual(len(messages), 1)
self.assertEqual(messages[0].get("type"), "error")

def test_03_import_supplier_new_duplicates_vat(self):
partners, messages = self._test_import_file(
"grap_custom_import_base", "res.partner", "supplier_new_duplicates_vat.csv"
)
self.assertEqual(len(messages), 1)
self.assertEqual(messages[0].get("type"), "error")
Empty file.
1 change: 1 addition & 0 deletions grap_custom_import_product/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
16 changes: 16 additions & 0 deletions grap_custom_import_product/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright (C) 2019 - Today: GRAP (http://www.grap.coop)
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

{
"name": "GRAP - Custom Import Product Module",
"summary": "Extra GRAP Tools to import data for product module",
"version": "16.0.1.0.0",
"category": "Tools",
"author": "GRAP",
"website": "https://github.com/grap/grap-odoo-import",
"license": "AGPL-3",
"depends": ["grap_custom_import_base", "product"],
"auto_install": True,
"installable": True,
}
1 change: 1 addition & 0 deletions grap_custom_import_product/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import product_product
Loading
Loading