diff --git a/sale_channel/models/sale_channel.py b/sale_channel/models/sale_channel.py
index 4c3d4626..ff7448a9 100644
--- a/sale_channel/models/sale_channel.py
+++ b/sale_channel/models/sale_channel.py
@@ -21,15 +21,17 @@ class SaleChannel(models.Model):
def _scheduler_export(self):
for record in self:
for struct_key in record._get_struct_to_export():
- for items in record._get_items_to_export(struct_key):
- description = "Export {} from {} whose id is {}".format(
- items,
+ for i, items in enumerate(record._get_items_to_export(struct_key)):
+ key = f"{i}_export_items_{struct_key}_for_channel_{record.id}"
+ description = "Export part {} from {}({}) whose id is {}".format(
+ i,
record.name,
+ struct_key,
record.id,
)
- record.with_delay(description=description)._job_trigger_export(
- struct_key, items
- )
+ record.with_delay(
+ description=description, identity_key=key
+ )._job_trigger_export(struct_key, items)
def _job_trigger_export(self, struct_key, items):
"""
@@ -44,7 +46,7 @@ def _get_struct_to_export(self):
"""
Retrieves the item types to export
"""
- NotImplementedError("Something is missing")
+ return []
def _map_items(self, struct_key, items):
"""
@@ -64,7 +66,7 @@ def _get_items_to_export(self, struct_key):
:return: A list of several lists of Odoo objects to export split
according to a predefined size
"""
- raise NotImplementedError("Nothing found to export with %s" % struct_key)
+ return []
def _trigger_export(self, struct_key, mapped_items):
"""
@@ -79,19 +81,20 @@ def _trigger_export(self, struct_key, mapped_items):
@abstractmethod
def _scheduler_import(self):
for record in self:
- for struct_key in record._get_struct_to_import():
+ for i, struct_key in enumerate(record._get_struct_to_import()):
+ key = f"{i}import_{struct_key}_for_channel{record.id}"
description = "Import {} from {} whose id is {}".format(
struct_key,
record.name,
record.id,
)
- record.with_delay(description=description)._job_trigger_import(
- struct_key
- )
+ record.with_delay(
+ description=description, identity_key=key
+ )._job_trigger_import(struct_key)
def _get_struct_to_import(self):
"""Retrieves the item types to import"""
- NotImplementedError("Something is missing")
+ return []
def _job_trigger_import(self, struct_key):
"""
diff --git a/sale_channel/models/sale_channel_relation.py b/sale_channel/models/sale_channel_relation.py
index 0ed5cd7c..4b73ccc2 100644
--- a/sale_channel/models/sale_channel_relation.py
+++ b/sale_channel/models/sale_channel_relation.py
@@ -17,3 +17,7 @@ class SaleChannelRelation(models.AbstractModel):
sale_channel_sync_date = fields.Datetime(
help="Date of last import sync for the related record"
)
+
+ sale_channel_id = fields.Many2one(
+ comodel_name="sale.channel", string="sale channel", required=True
+ )
diff --git a/sale_channel/models/sale_order_sale_channel_rel.py b/sale_channel/models/sale_order_sale_channel_rel.py
index 40abffb8..cb2724a1 100644
--- a/sale_channel/models/sale_order_sale_channel_rel.py
+++ b/sale_channel/models/sale_order_sale_channel_rel.py
@@ -7,8 +7,14 @@ class SaleOrderSaleChannelRel(models.Model):
_inherit = "sale.channel.relation"
_description = " sale order sale channel relation"
- sale_channel_id = fields.Many2one(
- comodel_name="sale.channel", string="sale channel"
+ sale_order_id = fields.Many2one(
+ comodel_name="sale.order", string="sale order", required=True
)
- sale_order_id = fields.Many2one(comodel_name="sale.order", string="sale order")
+ _sql_constraints = [
+ (
+ "unique_sale_order_sale_channel",
+ "unique(sale_channel_id, sale_order_id)",
+ "The combination of Sale Channel and Sale Order must be unique",
+ )
+ ]
diff --git a/sale_channel_account/models/__init__.py b/sale_channel_account/models/__init__.py
index d7234b58..61877425 100644
--- a/sale_channel_account/models/__init__.py
+++ b/sale_channel_account/models/__init__.py
@@ -1,4 +1 @@
-from . import account_fiscal_position
-from . import account_analytic_account
-from . import account_payment_mode
from . import sale_channel
diff --git a/sale_channel_account/models/account_analytic_account.py b/sale_channel_account/models/account_analytic_account.py
deleted file mode 100644
index 5a799397..00000000
--- a/sale_channel_account/models/account_analytic_account.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from odoo import fields, models
-
-
-class AccountAnalyticAccount(models.Model):
- _inherit = "account.analytic.account"
-
- sale_channel_ids = fields.One2many(
- comodel_name="sale.channel", inverse_name="analytic_account_id"
- )
diff --git a/sale_channel_account/models/account_fiscal_position.py b/sale_channel_account/models/account_fiscal_position.py
deleted file mode 100644
index 31da4f00..00000000
--- a/sale_channel_account/models/account_fiscal_position.py
+++ /dev/null
@@ -1,11 +0,0 @@
-from odoo import fields, models
-
-
-class AccountFiscalPosition(models.Model):
- _name = "account.fiscal.position"
- _inherit = [_name, "sale.channel.owner"]
-
- channel_ids = fields.Many2many(
- comodel_name="sale.channel",
- string="Binded Sale Channels",
- )
diff --git a/sale_channel_account/models/account_payment_mode.py b/sale_channel_account/models/account_payment_mode.py
deleted file mode 100644
index 71ffa699..00000000
--- a/sale_channel_account/models/account_payment_mode.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from odoo import fields, models
-
-
-class AccountPaymentMode(models.Model):
- _inherit = "account.payment.mode"
-
- sale_channel_ids = fields.One2many(
- comodel_name="sale.channel", inverse_name="payment_mode_id"
- )
diff --git a/sale_channel_account/models/sale_channel.py b/sale_channel_account/models/sale_channel.py
index c6b3abdc..eaebb3c9 100644
--- a/sale_channel_account/models/sale_channel.py
+++ b/sale_channel_account/models/sale_channel.py
@@ -11,8 +11,6 @@ class SaleChannel(models.Model):
analytic_account_id = fields.Many2one(
comodel_name="account.analytic.account",
string="Analytic account",
- help="If specified, this analytic account will be used to fill the "
- "field on the sale order created by the connector.",
)
payment_mode_id = fields.Many2one(
diff --git a/sale_channel_mirakl/mirakl_mapper/country_builder.py b/sale_channel_mirakl/mirakl_mapper/country_builder.py
deleted file mode 100644
index cef13e8c..00000000
--- a/sale_channel_mirakl/mirakl_mapper/country_builder.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from typing import Optional
-
-from pydantic import BaseModel
-
-
-class CountryBuilder(BaseModel):
- shipping_zone_code: Optional[str] = None # not required, Can be None
-
- def build_country(self, sale_channel):
- country = super().build_country(sale_channel)
- if self.shipping_zone_code:
- country = (
- sale_channel.env["res.country"].search(
- [("code", "=", self.shipping_zone_code)],
- limit=1,
- )
- or country
- )
- return country
diff --git a/sale_channel_mirakl/mirakl_mapper/mirakl_billing_address.py b/sale_channel_mirakl/mirakl_mapper/mirakl_billing_address.py
index be33df0e..ab9bd640 100644
--- a/sale_channel_mirakl/mirakl_mapper/mirakl_billing_address.py
+++ b/sale_channel_mirakl/mirakl_mapper/mirakl_billing_address.py
@@ -5,3 +5,7 @@
class MiraklBillingAddress(MiraklImportMapper, MiraklPartnerAddress):
customer_notification_email: str = ""
+
+ def build_country(self, sale_channel):
+ country = sale_channel.default_country_id
+ return country
diff --git a/sale_channel_mirakl/mirakl_mapper/mirakl_catalog.py b/sale_channel_mirakl/mirakl_mapper/mirakl_catalog.py
index c336bada..c46c3514 100644
--- a/sale_channel_mirakl/mirakl_mapper/mirakl_catalog.py
+++ b/sale_channel_mirakl/mirakl_mapper/mirakl_catalog.py
@@ -14,12 +14,6 @@ class MiraklCatalog(MiraklExportMapper):
@classmethod
def map_item(cls, mirakl_channel, product):
- """
- Build a mirakl record from an odoo record
- :param mirakl_channel: Mirakl channel on which the product is attached
- :param product: product to map
- :return: a pydantic object corresponding to the form expected by mirakl
- """
cat = product.categ_id.display_name or ""
cat = cat.replace(
"/", ">"
diff --git a/sale_channel_mirakl/mirakl_mapper/mirakl_customer.py b/sale_channel_mirakl/mirakl_mapper/mirakl_customer.py
index 4082f054..606b0419 100644
--- a/sale_channel_mirakl/mirakl_mapper/mirakl_customer.py
+++ b/sale_channel_mirakl/mirakl_mapper/mirakl_customer.py
@@ -1,17 +1,19 @@
-from .country_builder import CountryBuilder
+from typing import Optional
+
from .mirakl_billing_address import MiraklBillingAddress
from .mirakl_import_mapper import MiraklImportMapper
from .mirakl_shipping_address import MiraklShippingAddress
from .res_partner_builder import ResPartnerBuilder
-class MiraklCustomer(MiraklImportMapper, ResPartnerBuilder, CountryBuilder):
+class MiraklCustomer(MiraklImportMapper, ResPartnerBuilder):
_odoo_model = "res.partner"
_identity_key = "customer_id"
billing_address: MiraklBillingAddress
locale: str = ""
shipping_address: MiraklShippingAddress
+ shipping_zone_code: Optional[str] = None
def __init__(self, **kwargs):
"""
@@ -30,15 +32,3 @@ def __init__(self, **kwargs):
shipping_address["customer_id"] = kwargs.get("customer_id", "") + "_shipping"
kwargs["shipping_address"] = shipping_address
super().__init__(**kwargs)
-
- def build_country(self, sale_channel):
- country = super().build_country(sale_channel)
- if self.shipping_zone_code:
- country = (
- sale_channel.env["res.country"].search(
- [("code", "=", self.shipping_zone_code)],
- limit=1,
- )
- or country
- )
- return country
diff --git a/sale_channel_mirakl/mirakl_mapper/mirakl_export_mapper.py b/sale_channel_mirakl/mirakl_mapper/mirakl_export_mapper.py
index 75e51f10..d1e810f0 100644
--- a/sale_channel_mirakl/mirakl_mapper/mirakl_export_mapper.py
+++ b/sale_channel_mirakl/mirakl_mapper/mirakl_export_mapper.py
@@ -4,6 +4,8 @@
class MiraklExportMapper(BaseModel):
+ _identity_key = None
+
def get_key(self):
return getattr(self, self._identity_key, "")
@@ -14,6 +16,15 @@ def to_json(self):
as keys and the appropriate values to add to the export file
"""
+ @classmethod
+ def map_item(cls, mirakl_channel, product):
+ """
+ Build a mirakl record from an odoo record
+ :param mirakl_channel: Mirakl channel on which the product is attached
+ :param product: product to map
+ :return: a pydantic object corresponding to the form expected by mirakl
+ """
+
@classmethod
def get_file_header(cls):
"""
diff --git a/sale_channel_mirakl/mirakl_mapper/mirakl_offer.py b/sale_channel_mirakl/mirakl_mapper/mirakl_offer.py
index 73641bd7..82a29d74 100644
--- a/sale_channel_mirakl/mirakl_mapper/mirakl_offer.py
+++ b/sale_channel_mirakl/mirakl_mapper/mirakl_offer.py
@@ -10,12 +10,6 @@ class MiraklOffer(MiraklExportMapper):
@classmethod
def map_item(cls, mirakl_channel, product):
- """
- Build a mirakl record from an odoo record
- :param mirakl_channel: Mirakl channel on which the product is attached
- :param product: product to map
- :return: a pydantic object corresponding to the form expected by mirakl
- """
relation_prod_channel = product.product_tmpl_id.prod_sale_channel_ids.filtered(
lambda r: r.sale_channel_id == mirakl_channel.channel_id
)
diff --git a/sale_channel_mirakl/mirakl_mapper/mirakl_product.py b/sale_channel_mirakl/mirakl_mapper/mirakl_product.py
index c4508062..b8e8eac0 100644
--- a/sale_channel_mirakl/mirakl_mapper/mirakl_product.py
+++ b/sale_channel_mirakl/mirakl_mapper/mirakl_product.py
@@ -11,12 +11,6 @@ class MiraklProduct(MiraklExportMapper):
@classmethod
def map_item(cls, mirakl_channel, product):
- """
- Build a mirakl record from an odoo record
- :param mirakl_channel: Mirakl channel on which the product is attached
- :param product: product to map
- :return: a pydantic object corresponding to the form expected by mirakl
- """
cat = product.categ_id.display_name or ""
cat = cat.replace(
"/", ">"
diff --git a/sale_channel_mirakl/mirakl_mapper/mirakl_sale_order.py b/sale_channel_mirakl/mirakl_mapper/mirakl_sale_order.py
index b0948b23..fab03a80 100644
--- a/sale_channel_mirakl/mirakl_mapper/mirakl_sale_order.py
+++ b/sale_channel_mirakl/mirakl_mapper/mirakl_sale_order.py
@@ -81,12 +81,10 @@ def get_pricelist(self, mirakl_channel):
return product_pricelist
def get_order_lines(self, mirakl_channel):
- order_lines_values = []
- for order_line in self.order_lines:
- order_lines_values.append(
- Command.create(order_line.odoo_model_dump(mirakl_channel))
- )
- return order_lines_values
+ return [
+ Command.create(order_line.odoo_model_dump(mirakl_channel))
+ for order_line in self.order_lines
+ ]
def odoo_model_dump(self, mirakl_channel):
"""
diff --git a/sale_channel_mirakl/mirakl_mapper/mirakl_shipping_address.py b/sale_channel_mirakl/mirakl_mapper/mirakl_shipping_address.py
index 311228ad..883adc6a 100644
--- a/sale_channel_mirakl/mirakl_mapper/mirakl_shipping_address.py
+++ b/sale_channel_mirakl/mirakl_mapper/mirakl_shipping_address.py
@@ -1,21 +1,8 @@
-from .country_builder import CountryBuilder
from .mirakl_import_mapper import MiraklImportMapper
from .mirakl_partner_address import MiraklPartnerAddress
-class MiraklShippingAddress(MiraklImportMapper, MiraklPartnerAddress, CountryBuilder):
+class MiraklShippingAddress(MiraklImportMapper, MiraklPartnerAddress):
additional_info: str
shipping_zone_code: str = ""
-
- def build_country(self, sale_channel):
- country = super().build_country(sale_channel)
- if self.shipping_zone_code:
- country = (
- sale_channel.env["res.country"].search(
- [("code", "=", self.shipping_zone_code)],
- limit=1,
- )
- or country
- )
- return country
diff --git a/sale_channel_mirakl/mirakl_mapper/res_partner_builder.py b/sale_channel_mirakl/mirakl_mapper/res_partner_builder.py
index 902a4a5f..a042f4db 100644
--- a/sale_channel_mirakl/mirakl_mapper/res_partner_builder.py
+++ b/sale_channel_mirakl/mirakl_mapper/res_partner_builder.py
@@ -23,13 +23,15 @@ def build_name(self):
return name
def build_country(self, sale_channel):
- if self.country_iso_code:
- country = sale_channel.env["res.country"].search(
- [("code", "=", self.country_iso_code)],
- limit=1,
+ country = sale_channel.default_country_id
+ if self.shipping_zone_code:
+ country = (
+ sale_channel.env["res.country"].search(
+ [("code", "=", self.shipping_zone_code)],
+ limit=1,
+ )
+ or country
)
- else:
- country = sale_channel.default_country_id
return country
def odoo_model_dump(self, mirakl_channel):
diff --git a/sale_channel_mirakl/models/__init__.py b/sale_channel_mirakl/models/__init__.py
index 26e047f9..f4920085 100644
--- a/sale_channel_mirakl/models/__init__.py
+++ b/sale_channel_mirakl/models/__init__.py
@@ -1,15 +1,11 @@
-from . import mirakl_binding
from . import sale_channel_owner
from . import mirakl_importer
from . import mirakl_res_partner_importer
-from . import mirakl_customer_importer
from . import mirakl_sale_order_importer
from . import product_template
-from . import product_product
from . import res_partner_sale_channel_rel
from . import res_partner
from . import sale_channel
from . import sale_channel_mirakl
from . import mirakl_sale_order_line_importer
from . import sale_order
-from . import product_pricelist
diff --git a/sale_channel_mirakl/models/mirakl_binding.py b/sale_channel_mirakl/models/mirakl_binding.py
deleted file mode 100644
index 7aab2527..00000000
--- a/sale_channel_mirakl/models/mirakl_binding.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from odoo import fields, models
-
-
-# A bouger dans SCOwner
-class MiraklBinding(models.AbstractModel):
- _name = "mirakl.binding"
- _description = "used to attache several items to mirakl sale channel"
-
- is_from_mirakl = fields.Boolean()
diff --git a/sale_channel_mirakl/models/mirakl_customer_importer.py b/sale_channel_mirakl/models/mirakl_customer_importer.py
deleted file mode 100644
index 7561ef1c..00000000
--- a/sale_channel_mirakl/models/mirakl_customer_importer.py
+++ /dev/null
@@ -1,37 +0,0 @@
-import logging
-
-from odoo import fields, models, tools
-
-_logger = logging.getLogger(__name__)
-
-
-class MiraklCustomerImporter(models.Model):
- _name = "mirakl.customer.importer"
- _inherit = "mirakl.importer"
- _description = "Mirakl customer importer"
-
- def _get_binding(self, sale_channel, mirakl_record):
- external_id = mirakl_record.get_key()
- binding_model = mirakl_record._odoo_model
-
- if binding_model == "res.partner":
- binding = self.env[binding_model].search(
- [
- (
- "res_partner_sale_channel_ids.sale_channel_external_code",
- "=",
- tools.ustr(external_id),
- ),
- ("channel_ids", "in", sale_channel.channel_id.id),
- ],
- limit=2,
- )
-
- if len(binding) > 1:
- _logger.warning(
- "there are many records linked to the same mirakl record"
- )
- binding = fields.first(binding)
- return binding
- else:
- return super()._get_binding(sale_channel, mirakl_record)
diff --git a/sale_channel_mirakl/models/mirakl_importer.py b/sale_channel_mirakl/models/mirakl_importer.py
index c33aa7da..1d30b360 100644
--- a/sale_channel_mirakl/models/mirakl_importer.py
+++ b/sale_channel_mirakl/models/mirakl_importer.py
@@ -55,7 +55,7 @@ def _get_binding(self, sale_channel, mirakl_record):
def _get_importers(self):
importers = {
- MiraklCustomer: "mirakl.customer.importer",
+ MiraklCustomer: "mirakl.res.partner.importer",
MiraklBillingAddress: "mirakl.res.partner.importer",
MiraklShippingAddress: "mirakl.res.partner.importer",
MiraklSaleOrder: "mirakl.sale.order.importer",
diff --git a/sale_channel_mirakl/models/mirakl_res_partner_importer.py b/sale_channel_mirakl/models/mirakl_res_partner_importer.py
index b66cbf05..15adf901 100644
--- a/sale_channel_mirakl/models/mirakl_res_partner_importer.py
+++ b/sale_channel_mirakl/models/mirakl_res_partner_importer.py
@@ -5,7 +5,7 @@
_logger = logging.getLogger(__name__)
-class MiraklResPartnerImporter(models.Model):
+class MiraklResPartnerImporter(models.AbstractModel):
_name = "mirakl.res.partner.importer"
_inherit = "mirakl.importer"
_description = "Mirakl res partner importer"
@@ -14,24 +14,19 @@ def _get_binding(self, sale_channel, mirakl_record):
external_id = mirakl_record.get_key()
binding_model = mirakl_record._odoo_model
- if binding_model == "res.partner":
- binding = self.env[binding_model].search(
- [
- (
- "res_partner_sale_channel_ids.sale_channel_external_code",
- "=",
- tools.ustr(external_id),
- ),
- ("channel_ids", "in", sale_channel.channel_id.id),
- ],
- limit=2,
- )
+ binding = self.env[binding_model].search(
+ [
+ (
+ "res_partner_sale_channel_ids.sale_channel_external_code",
+ "=",
+ tools.ustr(external_id),
+ ),
+ ("channel_ids", "in", sale_channel.channel_id.id),
+ ],
+ limit=2,
+ )
- if len(binding) > 1:
- _logger.warning(
- "there are many records linked to the same mirakl record"
- )
- binding = fields.first(binding)
- return binding
- else:
- return super()._get_binding(sale_channel, mirakl_record)
+ if len(binding) > 1:
+ _logger.warning("there are many records linked to the same mirakl record")
+ binding = fields.first(binding)
+ return binding
diff --git a/sale_channel_mirakl/models/mirakl_sale_order_importer.py b/sale_channel_mirakl/models/mirakl_sale_order_importer.py
index 039a7536..93efc9b2 100644
--- a/sale_channel_mirakl/models/mirakl_sale_order_importer.py
+++ b/sale_channel_mirakl/models/mirakl_sale_order_importer.py
@@ -198,13 +198,14 @@ def _import_sale_orders_batch(self, sale_channel, filters=None):
)
imported_orders = result["orders"] or []
- created_or_updated_orders = []
+ created_or_updated_orders = self.env["sale.order"].browse()
for mirakl_sale_order in self._map_orders(imported_orders):
if not self._get_binding(
sale_channel,
mirakl_sale_order,
):
- created_or_updated_orders.append(
- self.create_or_update_record(sale_channel, mirakl_sale_order)
+ created_or_updated_orders |= self.create_or_update_record(
+ sale_channel, mirakl_sale_order
)
+
return created_or_updated_orders
diff --git a/sale_channel_mirakl/models/mirakl_sale_order_line_importer.py b/sale_channel_mirakl/models/mirakl_sale_order_line_importer.py
index b81fb23b..1baedb54 100644
--- a/sale_channel_mirakl/models/mirakl_sale_order_line_importer.py
+++ b/sale_channel_mirakl/models/mirakl_sale_order_line_importer.py
@@ -5,10 +5,20 @@
_logger = logging.getLogger(__name__)
-class MiraklSaleOrderLineImporter(models.Model):
+class MiraklSaleOrderLineImporter(models.AbstractModel):
_name = "mirakl.sale.order.line.importer"
_description = "sale order line importer"
_inherit = "mirakl.importer"
def _create_record(self, binding_model, odoo_data):
+ """
+ this method has been overridden because contrary to the super class,
+ we create the odoo record with a 'create' method which ensures that all the
+ necessary fields are provided.
+
+ Except for the creation of a sale order, it is imperative to have
+ lines and for lines, you must have an id for the sale order except with a
+ 'new' method, we leave it to the ORM to create the order and its lines.
+ each instance as it should be by attaching them to each other
+ """
return self.env[binding_model].new(odoo_data)
diff --git a/sale_channel_mirakl/models/product_pricelist.py b/sale_channel_mirakl/models/product_pricelist.py
deleted file mode 100644
index 3d7ed1d1..00000000
--- a/sale_channel_mirakl/models/product_pricelist.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from odoo import fields, models
-
-
-class ProductPricelist(models.Model):
- _name = "product.pricelist"
- _inherit = [_name, "sale.channel.owner"]
-
- channel_ids = fields.Many2many(
- comodel_name="sale.channel", string="Binded Sale Channels"
- )
diff --git a/sale_channel_mirakl/models/product_product.py b/sale_channel_mirakl/models/product_product.py
deleted file mode 100644
index 124d1e7c..00000000
--- a/sale_channel_mirakl/models/product_product.py
+++ /dev/null
@@ -1,6 +0,0 @@
-from odoo import models
-
-
-class ProductProduct(models.Model):
- _name = "product.product"
- _inherit = ["mirakl.binding", _name]
diff --git a/sale_channel_mirakl/models/res_partner.py b/sale_channel_mirakl/models/res_partner.py
index 5d74d446..57b2c4a4 100644
--- a/sale_channel_mirakl/models/res_partner.py
+++ b/sale_channel_mirakl/models/res_partner.py
@@ -3,7 +3,7 @@
class ResPartner(models.Model):
_name = "res.partner"
- _inherit = [_name, "mirakl.binding", "sale.channel.owner"]
+ _inherit = [_name, "sale.channel.owner"]
channel_ids = fields.Many2many(
comodel_name="sale.channel",
diff --git a/sale_channel_mirakl/models/res_partner_sale_channel_rel.py b/sale_channel_mirakl/models/res_partner_sale_channel_rel.py
index 4ca8da75..201b0c04 100644
--- a/sale_channel_mirakl/models/res_partner_sale_channel_rel.py
+++ b/sale_channel_mirakl/models/res_partner_sale_channel_rel.py
@@ -11,6 +11,4 @@ class ResPartnerSaleChannelRel(models.Model):
_description = "Res partner sale channel Relation"
_inherit = "sale.channel.relation"
- sale_channel_id = fields.Many2one("sale.channel", string="Sale Channel")
-
- res_partner_id = fields.Many2one("res.partner", string="Res Partner")
+ res_partner_id = fields.Many2one("res.partner", string="Res Partner", required=True)
diff --git a/sale_channel_mirakl/models/sale_channel.py b/sale_channel_mirakl/models/sale_channel.py
index ad8d3b5e..3c97e6b3 100644
--- a/sale_channel_mirakl/models/sale_channel.py
+++ b/sale_channel_mirakl/models/sale_channel.py
@@ -1,6 +1,5 @@
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
-from odoo.tools import split_every
MIRAKL = "mirakl"
@@ -36,38 +35,40 @@ def _check_uniqueness(self):
)
def _get_struct_to_export(self):
+ struct_keys = super()._get_struct_to_export()
if self.channel_type == MIRAKL:
- for channel in self.mirakl_channel_ids:
- yield channel.data_to_export
- else:
- super()._get_struct_to_export()
-
- def split_products(self, products):
- """
- constructs a list of product lists whose length of e
- ach sublist depends on a given parameter.
- This is to avoid launching the export of too many products at once.
- :param products: list of products to split
- :return: A generator that returns each sublist of products one by one
- """
- return split_every(self.max_items_to_export, products)
+ struct_keys.extend([c.data_to_export for c in self.mirakl_channel_ids])
+ return struct_keys
def _get_items_to_export(self, struct_key):
if self.channel_type == MIRAKL:
- products = self.env["product.product"].search(
- [("product_tmpl_id.channel_ids", "in", self.id)]
- )
- products_list = self.split_products(products) # List of lists of products
- return products_list
+ yield from self._get_items_to_export_mirakl_product()
return super()._get_items_to_export(struct_key)
+ def _get_items_to_export_mirakl_product(self):
+ domain = [("product_tmpl_id.channel_ids", "in", self.id)]
+ if self.max_items_to_export <= 0:
+ products = self.env["product.product"].search(domain)
+ yield products
+ else:
+ products = self.env["product.product"].search(
+ domain, limit=self.max_items_to_export
+ )
+ already_loaded = self.max_items_to_export
+ while products:
+ yield products
+ products = self.env["product.product"].search(
+ domain, limit=self.max_items_to_export, offset=already_loaded
+ )
+ already_loaded += self.max_items_to_export
+
def _map_items(self, struct_key, items):
if self.channel_type == MIRAKL:
for item in self.mirakl_channel_ids._map_items(struct_key, items):
yield item
else:
- super()._map_items(struct_key, items)
+ return super()._map_items(struct_key, items)
def _trigger_export(self, struct_key, pydantic_items):
if self.channel_type == MIRAKL:
@@ -75,15 +76,15 @@ def _trigger_export(self, struct_key, pydantic_items):
lambda r: r.data_to_export == struct_key
)
return mirakl_channel._export_data(pydantic_items)
-
return super()._trigger_export(struct_key, pydantic_items)
def _get_struct_to_import(self):
+ struct_keys = super()._get_struct_to_import()
if self.channel_type == MIRAKL:
- for record in self.mirakl_channel_ids:
- yield record.data_to_import
- else:
- super()._get_struct_to_import()
+ struct_keys.extend(
+ record.data_to_import for record in self.mirakl_channel_ids
+ )
+ return struct_keys
def _job_trigger_import(self, struct_key):
if self.channel_type == MIRAKL:
diff --git a/sale_channel_mirakl/models/sale_channel_mirakl.py b/sale_channel_mirakl/models/sale_channel_mirakl.py
index 01013e29..4b067133 100644
--- a/sale_channel_mirakl/models/sale_channel_mirakl.py
+++ b/sale_channel_mirakl/models/sale_channel_mirakl.py
@@ -263,10 +263,8 @@ def _create_and_fill_csv_file(self, pydantic_items):
# deletion_day = fields.Datetime.now() + timedelta(
# days=self.attachment_delation_day
# )
- #
- # attachment.with_delay(eta=deletion_day).unlink() Currently, I have to
- # comment because having skipped the execution of the jobs for my tests,
- # the attachment is deleted before being returned
+ # attachment.with_delay(eta=deletion_day).unlink()
+ # TODO : Patch the ir_attachment 'unlink' method in tests
return attachment
@@ -274,10 +272,11 @@ def _export_data(self, pydantic_items):
"""
Super class data export method adapted to Mirakl
(Export products or offers)
- :param items: items to export.
+ :param pydantic_items: items to export.
"""
self.ensure_one()
attachment = self._create_and_fill_csv_file(pydantic_items)
+
self.post(attachment)
def _get_mappers(self):
diff --git a/sale_channel_mirakl/models/sale_channel_owner.py b/sale_channel_mirakl/models/sale_channel_owner.py
index c7ac8928..1d7866be 100644
--- a/sale_channel_mirakl/models/sale_channel_owner.py
+++ b/sale_channel_mirakl/models/sale_channel_owner.py
@@ -1,5 +1,7 @@
from odoo import api, fields, models
+from .sale_channel import MIRAKL
+
class SaleChannelOwner(models.AbstractModel):
_inherit = "sale.channel.owner"
@@ -13,8 +15,12 @@ class SaleChannelOwner(models.AbstractModel):
store=True,
help="Date of last import sync for the related record",
)
+ is_from_mirakl = fields.Boolean(
+ compute="_compute_is_from_mirakl",
+ store=True,
+ )
- def _get_values_for_updating(self, field_name, only_single_result=False):
+ def _get_values_for_updating(self, field_name):
"""
:param field_name: field to update
:param only_single_result: set to True if we want the values to
@@ -47,17 +53,9 @@ def _get_values_for_updating(self, field_name, only_single_result=False):
fields=[relation_field, f"{field_name}s:array_agg({field_name})"],
groupby=[relation_field],
)
- if only_single_result:
- values_for_updating = {
- x[relation_field][0]: x.get(f"{field_name}s", [])
- for x in result
- if x.get(relation_field + "_count", 0) == 1
- }
- else:
- values_for_updating = {
- x[relation_field][0]: x.get(f"{field_name}s", [])
- for x in result
- }
+ values_for_updating = {
+ x[relation_field][0]: x.get(f"{field_name}s", []) for x in result
+ }
return values_for_updating
@@ -84,9 +82,13 @@ def _compute_sync_date(self):
field_name = "sale_channel_sync_date"
self.update({field_name: False})
- values_for_updating = self._get_values_for_updating(
- field_name, only_single_result=True
- )
+ values_for_updating = self._get_values_for_updating(field_name)
if values_for_updating:
for record in self:
record.sale_channel_sync_date = values_for_updating.get(record.id)[0]
+
+ @api.depends("channel_ids")
+ def _compute_is_from_mirakl(self):
+ for record in self:
+ if any(x.channel_type == MIRAKL for x in record.channel_ids):
+ record.is_from_mirakl = True
diff --git a/sale_channel_mirakl/models/sale_order.py b/sale_channel_mirakl/models/sale_order.py
index 44912098..0c284d48 100644
--- a/sale_channel_mirakl/models/sale_order.py
+++ b/sale_channel_mirakl/models/sale_order.py
@@ -2,8 +2,7 @@
class SaleOrder(models.Model):
- _name = "sale.order"
- _inherit = ["mirakl.binding", _name]
+ _inherit = "sale.order"
channel_ids = fields.Many2many(
comodel_name="sale.channel",
diff --git a/sale_channel_mirakl/security/ir.model.access.csv b/sale_channel_mirakl/security/ir.model.access.csv
index fcf3d687..811bb4e0 100644
--- a/sale_channel_mirakl/security/ir.model.access.csv
+++ b/sale_channel_mirakl/security/ir.model.access.csv
@@ -1,11 +1,8 @@
"id","name","model_id/id","group_id/id","perm_read","perm_write","perm_create","perm_unlink"
-access_mirakl_binding,access.mirakl.binding,model_mirakl_binding,base.group_user,1,1,1,1
access_mirakl_sale_order_importer,access.mirakl.sale.order.importer,model_mirakl_sale_order_importer,base.group_user,1,1,1,1
-access_product_product,access.product.product,model_product_product,base.group_user,1,1,1,1
access_sale_channel,access.sale.channel,model_sale_channel,base.group_user,1,1,1,0
access_sale_channel_mirakl,access.sale.channel.mirakl,model_sale_channel_mirakl,base.group_user,1,1,1,0
access_sale_order,access.sale.order,model_sale_order,base.group_user,1,0,1,0
access_res_partner_sale_channel_rel,access.res.partner.sale.channel.rel,model_res_partner_sale_channel_rel,base.group_user,1,0,0,0
access_mirakl_res_partner_importer,access.mirakl.res.partner.importer,model_mirakl_res_partner_importer,base.group_user,1,0,0,0
-access_mirakl_customer_importer,access.mirakl.customer.importer,model_mirakl_customer_importer,base.group_user,1,0,0,0
access_mirakl_sale_order_line_importer,access_mirakl_sale_order_line_importer,model_mirakl_sale_order_line_importer,base.group_user,1,0,0,0
diff --git a/sale_channel_mirakl/tests/common.py b/sale_channel_mirakl/tests/common.py
index 4e1edb6b..0b1842e3 100644
--- a/sale_channel_mirakl/tests/common.py
+++ b/sale_channel_mirakl/tests/common.py
@@ -1,5 +1,6 @@
import csv
from base64 import b64decode
+from contextlib import contextmanager
from io import StringIO
from odoo import Command
@@ -40,9 +41,10 @@ def setUpClass(cls):
cls.product2 = cls.env.ref("product.product_product_8")
cls.product3 = cls.env.ref("product.product_product_5")
cls.product4 = cls.env.ref("product.product_product_11b")
- cls.product_pricelist = cls.env.ref("product.list0")
cls.currency = cls.env.ref("base.EUR")
- cls.product_pricelist.write({"currency_id": cls.currency.id})
+ cls.product_pricelist = cls.env.ref("product.list0").copy(
+ {"currency_id": cls.currency.id}
+ )
cls.payment_mode = cls.env.ref("account_payment_mode.payment_mode_outbound_ct1")
cls.product1.write(
@@ -216,6 +218,63 @@ def setUpClass(cls):
}
)
+ @contextmanager
+ def _patch_process_request(self, sale_channel):
+ def _mock_process_request(
+ self_local,
+ url,
+ headers=None,
+ params=None,
+ data=None,
+ files=None,
+ ignore_result=False,
+ request_type=None,
+ ):
+ self.url = url
+ self.headers = headers
+ self.files = files
+ self.request_type = request_type
+
+ sale_channel._patch_method("_process_request", _mock_process_request)
+ yield
+ sale_channel._revert_method("_process_request")
+
+ @contextmanager
+ def _patch_call_request(self, sale_channel):
+ def _sub_function(
+ self_local,
+ url,
+ headers=None,
+ params=None,
+ data=None,
+ files=None,
+ ignore_result=False,
+ request_type=None,
+ ):
+ return self.mirakl_sale_orders
+
+ sale_channel._patch_method("_process_request", _sub_function)
+ yield
+ sale_channel._revert_method("_process_request")
+
+ @contextmanager
+ def _patch_import_one_sale_order(self, sale_channel):
+ def _only_one_sale_order(
+ self_local,
+ url,
+ headers=None,
+ params=None,
+ data=None,
+ files=None,
+ ignore_result=False,
+ request_type=None,
+ ):
+ return self.a_sale_order
+
+ sale_channel._patch_method("_process_request", _only_one_sale_order)
+ yield
+ sale_channel._revert_method("_process_request")
+
def setUp(self):
super().setUp()
self.a_sale_order = {
diff --git a/sale_channel_mirakl/tests/test_products_and_offers_exporter.py b/sale_channel_mirakl/tests/test_products_and_offers_exporter.py
index e5ee3498..035e4732 100644
--- a/sale_channel_mirakl/tests/test_products_and_offers_exporter.py
+++ b/sale_channel_mirakl/tests/test_products_and_offers_exporter.py
@@ -17,9 +17,26 @@
PROD_ID_TYPE = "SHOP_SKU"
EMPTY_STRING = ""
CARRIAGE_RETURN = "\r\n"
+PRODUCT_FILE_HEADER = (
+ '"sku";"ean";"PRODUCT_TITLE";"PRODUCT_DESCRIPTION";"PRODUCT_CAT_CODE"'
+)
+OFFER_FILE_HEADER = '"sku";"product-id";"product-id-type";"state"'
+CATALOG_FILE_HEADER = (
+ '"sku";"ean";"PRODUCT_TITLE";"PRODUCT_DESCRIPTION";'
+ '"PRODUCT_CAT_CODE";"product-id";"product-id-type";"state"'
+)
class TestProductOfferExporter(common.SetUpMiraklBase):
+ @contextmanager
+ def _patch_unlink_attachment(self, attachment):
+ def _local_unlink(self_local):
+ return True
+
+ attachment._patch_method("unlink", _local_unlink)
+ yield
+ attachment._revert_method("unlink")
+
def test_make_product_file(self):
struct_key = self.mirakl_sc_for_product.data_to_export
@@ -113,33 +130,12 @@ def _check_parameters_test(self, url, files, request_type):
self.assertDictEqual(self.files, files)
self.assertEqual(self.request_type, request_type)
- @contextmanager
- def _patch_process_request(self, sale_channel):
- def _mock_process_request(
- self_local,
- url,
- headers=None,
- params=None,
- data=None,
- files=None,
- ignore_result=False,
- request_type=None,
- ):
- self.url = url
- self.headers = headers
- self.files = files
- self.request_type = request_type
-
- sale_channel._patch_method("_process_request", _mock_process_request)
- yield
- sale_channel._revert_method("_process_request")
-
def test_post_products_file_on_mirakl(self):
expected_filename = "{}_{}".format(
"Product", self.mirakl_sc_for_product.offer_filename
)
expected_file_content = (
- '"sku";"ean";"PRODUCT_TITLE";"PRODUCT_DESCRIPTION";"PRODUCT_CAT_CODE"\r\n'
+ PRODUCT_FILE_HEADER + "\r\n"
'"{p2_dfl}";"{p2_brcd}";"{p2_name}";"{p2_desc}";"{cat}"{car_return}'
'"{p1_dfl}";"{empty}";"{p1_name}";"{p1_name}";"{cat}"{car_return}'.format(
p2_dfl=self.product2.default_code,
@@ -167,7 +163,7 @@ def test_post_offers_file_on_mirakl(self):
"Offer", self.mirakl_sc_for_offer.offer_filename
)
expected_file_content = (
- '"sku";"product-id";"product-id-type";"state"\r\n'
+ OFFER_FILE_HEADER + "\r\n"
'"{p2_dfl}";"{p2_brcd}";"{ean}";"{state}"{car_return}'
'"{p1_dfl}";"{p1_dfl}";"{prod_id_type}";"{state}"{car_return}'.format(
p2_dfl=self.product2.default_code,
@@ -194,8 +190,7 @@ def test_post_offers_file_on_mirakl(self):
def test_post_catalog_file_on_mirakl(self):
expected_filename = self.mirakl_sc_for_offer.offer_filename
expected_file_content = (
- '"sku";"ean";"PRODUCT_TITLE";"PRODUCT_DESCRIPTION";"PRODUCT_CAT_CODE"'
- ';"product-id";"product-id-type";"state"\r\n'
+ CATALOG_FILE_HEADER + "\r\n"
'"{p2_dfl}";"{p2_brcd}";"{p2_name}";"{p2_desc}";"{cat}";"{p2_brcd}";'
'"{ean}";"{state}"{car_return}'
'"{p1_dfl}";"{empty}";"{p1_name}";"{p1_name}";"{cat}";"{p1_dfl}";'
@@ -231,51 +226,14 @@ def test_get_struct_to_import(self):
for struct_key in self.mirakl_sc_import.channel_id._get_struct_to_import():
self.assertEqual(struct_key, SALE_ORDER)
- @contextmanager
- def _patch_call_request(self, sale_channel):
- def _sub_function(
- self_local,
- url,
- headers=None,
- params=None,
- data=None,
- files=None,
- ignore_result=False,
- request_type=None,
- ):
-
- return self.mirakl_sale_orders
-
- sale_channel._patch_method("_process_request", _sub_function)
- yield
- sale_channel._revert_method("_process_request")
-
def test_sale_orders_import(self):
with self._patch_call_request(self.mirakl_sc_import):
self.mirakl_sc_import.channel_id._scheduler_import()
- @contextmanager
- def _patch_import_one_sale_order(self, sale_channel):
- def _only_one_sale_order(
- self_local,
- url,
- headers=None,
- params=None,
- data=None,
- files=None,
- ignore_result=False,
- request_type=None,
- ):
- return self.a_sale_order
-
- sale_channel._patch_method("_process_request", _only_one_sale_order)
- yield
- sale_channel._revert_method("_process_request")
-
def test_import_one_sale_order(self):
with self._patch_import_one_sale_order(self.mirakl_sc_import):
orders = self.sale_channel_4._job_trigger_import(SALE_ORDER)
self.assertEqual(1, len(orders))
- self.assertEqual(type(orders[0]), self.env[SALE_ORDER].__class__)
- self.assertTrue(orders[0].is_from_mirakl)
+ self.assertEqual(orders._name, SALE_ORDER)
+ self.assertTrue(orders.is_from_mirakl)
diff --git a/sale_channel_mirakl/views/sale_channel_mirakl.xml b/sale_channel_mirakl/views/sale_channel_mirakl.xml
index 921a9819..8ddea513 100644
--- a/sale_channel_mirakl/views/sale_channel_mirakl.xml
+++ b/sale_channel_mirakl/views/sale_channel_mirakl.xml
@@ -6,10 +6,15 @@
mirakl.backend.tree
sale.channel.mirakl
-
-
-
-
+
+
+
+
+
+
+
+
+
@@ -19,17 +24,30 @@
sale.channel.mirakl
diff --git a/sale_channel_product/models/product_template_sale_channel_rel.py b/sale_channel_product/models/product_template_sale_channel_rel.py
index dee62b77..4f1e51c1 100644
--- a/sale_channel_product/models/product_template_sale_channel_rel.py
+++ b/sale_channel_product/models/product_template_sale_channel_rel.py
@@ -7,6 +7,6 @@ class ProductTemplateSaleChannelRel(models.Model):
_description = "Product template sale channel Relation"
_inherit = "sale.channel.relation"
- sale_channel_id = fields.Many2one("sale.channel", string="Sale Channel")
-
- product_template_id = fields.Many2one("product.template", string="Product Template")
+ product_template_id = fields.Many2one(
+ "product.template", string="Product Template", required=True
+ )