From 11a970653323b020b1bfad228bd34a2d567cad22 Mon Sep 17 00:00:00 2001 From: BadPixxel Date: Tue, 21 Jul 2020 12:06:31 +0200 Subject: [PATCH 1/9] WIP Suppliers --- docker-compose.yml | 4 +- odoo/addons/splashsync/objects/product.py | 6 +- .../splashsync/objects/products/__init__.py | 1 + .../splashsync/objects/products/supplier.py | 263 ++++++++++++++++++ 4 files changed, 270 insertions(+), 4 deletions(-) create mode 100644 odoo/addons/splashsync/objects/products/supplier.py diff --git a/docker-compose.yml b/docker-compose.yml index 9f21eaf..ec41956 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -39,9 +39,9 @@ services: - ./docker/x86:/etc/odoo:ro - ./odoo/addons/splashsync:/mnt/extra-addons/splashsync:ro - ../Py-Core:/mnt/splashpy -# entrypoint: bash /etc/odoo/entrypoint.sh odoo -i "splashsync,product,stock,website_sale_comparison" + entrypoint: bash /etc/odoo/entrypoint.sh odoo -i "splashsync,product,stock,website_sale_comparison,purchase" # entrypoint: bash /etc/odoo/entrypoint.sh odoo -i "splashsync" - entrypoint: bash /etc/odoo/entrypoint.sh odoo +# entrypoint: bash /etc/odoo/entrypoint.sh odoo hostname: latest.odoo.local networks: odoo: { ipv4_address: 172.120.0.99, aliases: [ latest.odoo.local ] } diff --git a/odoo/addons/splashsync/objects/product.py b/odoo/addons/splashsync/objects/product.py index 0040b3a..b2a25ca 100755 --- a/odoo/addons/splashsync/objects/product.py +++ b/odoo/addons/splashsync/objects/product.py @@ -13,7 +13,8 @@ from . import OdooObject from splashpy import const -from .products import ProductsVariants, ProductsAttributes, ProductsPrices, ProductsImages, ProductsFeatures, ProductsRelations +from .products import ProductsVariants, ProductsAttributes, ProductsPrices, ProductsImages +from .products import ProductsFeatures, ProductsRelations, ProductsSupplier class Product( @@ -23,7 +24,8 @@ class Product( ProductsPrices, ProductsImages, ProductsFeatures, - ProductsRelations + ProductsRelations, + ProductsSupplier ): # ====================================================================# # Splash Object Definition diff --git a/odoo/addons/splashsync/objects/products/__init__.py b/odoo/addons/splashsync/objects/products/__init__.py index db21978..04be141 100644 --- a/odoo/addons/splashsync/objects/products/__init__.py +++ b/odoo/addons/splashsync/objects/products/__init__.py @@ -18,4 +18,5 @@ from .prices import ProductsPrices from .images import ProductsImages from .relations import ProductsRelations +from .supplier import ProductsSupplier diff --git a/odoo/addons/splashsync/objects/products/supplier.py b/odoo/addons/splashsync/objects/products/supplier.py new file mode 100644 index 0000000..0e13d62 --- /dev/null +++ b/odoo/addons/splashsync/objects/products/supplier.py @@ -0,0 +1,263 @@ +# -*- coding: utf-8 -*- +# +# This file is part of SplashSync Project. +# +# Copyright (C) 2015-2019 Splash Sync +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# For the full copyright and license information, please view the LICENSE +# file that was distributed with this source code. +# + +from odoo import http +from splashpy import const, Framework +from splashpy.componants import FieldFactory +from odoo.addons.splashsync.helpers import AttributesHelper, LinesHelper, ValuesHelper, SettingsManager + + +class ProductsSupplier: + """ + Access to product First Supplier Fields + """ + + # Static Prefix for Feature Attributes + prefix = "__feature_id__" + + def buildSupplierFields(self): + pass + # from odoo.addons.splashsync.helpers import TransHelper + # # ====================================================================# + # # Set default System Language + # FieldFactory.setDefaultLanguage(TransHelper.get_default_iso()) + # # ====================================================================# + # # Walk on Available Attributes + # for attribute in ProductsFeatures.find_all(): + # # ====================================================================# + # # Walk on Available Languages + # for iso_code, lang_name in TransHelper.get_all().items(): + # # ==================================================================== # + # # Product Feature Field + # FieldFactory.create(const.__SPL_T_VARCHAR__, self.encode(attribute), attribute.display_name) + # FieldFactory.group("Features") + # FieldFactory.microData("http://schema.org/Product", attribute.name) + # # ==================================================================== # + # # Add Language Params + # FieldFactory.description("["+lang_name+"] "+attribute.display_name) + # FieldFactory.setMultilang(iso_code) + # # ==================================================================== # + # # Filter Variants Attributes During Tests + # if Framework.isDebugMode() and attribute.name in AttributesHelper.attr_test: + # FieldFactory.isNotTested() + # if iso_code != TransHelper.get_default_iso(): + # FieldFactory.association(self.encode(attribute)) + + def getSupplierFields(self, index, field_id): + """ + Get Product Attributes List + :param index: str + :param field_id: str + :return: None + """ + # ==================================================================== # + # Check field_id this Feature Field... + attr_id = self.decode(field_id) + if attr_id is None: + return + self._in.__delitem__(index) + self._out[field_id] = None + # ==================================================================== # + # Check if Product has Attribute Value + for attr_value in self.object.attribute_value_ids: + if attr_value.attribute_id.id == attr_id: + self._out[field_id] = attr_value.name + self.__getFeatureTranslatedFields(field_id, attr_value) + return + # ==================================================================== # + # Check if Product has Advanced Feature Value + if SettingsManager.is_prd_adv_variants(): + for attr_value in self.object.features_value_ids: + if attr_value.attribute_id.id == attr_id: + self._out[field_id] = attr_value.name + self.__getFeatureTranslatedFields(field_id, attr_value) + return + # ==================================================================== # + # Check if Product has Feature Value + for attr_value in self.template.valid_product_attribute_value_ids: + if attr_value.attribute_id.id == attr_id: + self._out[field_id] = attr_value.name + self.__getFeatureTranslatedFields(field_id, attr_value) + return + # ==================================================================== # + # Complete Not Found Feature Translations + self.__isEmptyFeatureTranslatedFields(field_id) + + # def setFeatureFields(self, field_id, field_data): + # """ + # Update Product Features Values (Standard Mode) + # :param field_id: str + # :param field_data: hash + # :return: None + # """ + # # ==================================================================== # + # # Check field_id this Feature Field... + # attr_id = self.decode(field_id) + # if attr_id is None or SettingsManager.is_prd_adv_variants(): + # return + # self._in.__delitem__(field_id) + # # ==================================================================== # + # # Check if Product has Feature Value + # attr_lines = self.template.attribute_line_ids.filtered( + # lambda l: l.attribute_id.create_variant == "no_variant" and l.attribute_id.id == attr_id + # ) + # for attr_line in attr_lines: + # # ==================================================================== # + # # Find or Create Attribute Value + # new_value = ValuesHelper.touch(attr_line.attribute_id, field_data, True) + # # ==================================================================== # + # # Empty Value or Creation Fail => Remove Product Attribute + # if new_value is None: + # self.template.attribute_line_ids = [(3, attr_line.id, 0)] + # self.__isEmptyFeatureTranslatedFields(field_id) + # return + # # ====================================================================# + # # If Values are Different => Update Values + # if len(attr_line.value_ids) != 1 or new_value.id != attr_line.value_ids[0].id: + # attr_line.value_ids = [(6, 0, [new_value.id])] + # # ====================================================================# + # # Update Product Attribute Translations + # self.__setFeatureTranslatedFields(field_id, new_value) + # return + # # ==================================================================== # + # # Add Product Feature Value + # if field_data is not None and len(str(field_data)) > 0: + # # Find or Create Attribute Value + # new_value = ValuesHelper.touch(AttributesHelper.load(attr_id), str(field_data), True) + # LinesHelper.add(self.template, new_value) + # self.__setFeatureTranslatedFields(field_id, new_value) + # # ==================================================================== # + # # Complete Empty Feature Translations + # else: + # self.__isEmptyFeatureTranslatedFields(field_id) + # + # def setAdvancedFeatureFields(self, field_id, field_data): + # """ + # Update Product Attributes Values (Mode 2 => FAIL) + # :param field_id: str + # :param field_data: hash + # :return: None + # """ + # # ==================================================================== # + # # Check field_id this Feature Field... + # attr_id = self.decode(field_id) + # if attr_id is None or not SettingsManager.is_prd_adv_variants(): + # return + # self._in.__delitem__(field_id) + # # ====================================================================# + # # Find Product Current Feature Values + # current = self.object.features_value_ids.filtered(lambda v: v.attribute_id.id == attr_id) + # # ==================================================================== # + # # Empty Product Feature Value + # if field_data is None or len(str(field_data)) == 0: + # if len(current): + # # Remove Product Feature + # self.object.features_value_ids = [(3, current.id, 0)] + # # Update Translations + # self.__isEmptyFeatureTranslatedFields(field_id) + # return + # # ==================================================================== # + # # Load Attribute + # attribute = current.attribute_id if len(current) else AttributesHelper.load(attr_id) + # # ==================================================================== # + # # Find or Create Attribute Value + # new_value = ValuesHelper.touch(attribute, field_data, True) + # # ====================================================================# + # # If Values are Similar => Nothing to Do => Exit + # if len(current) == 1 and new_value.id == current.id: + # self.__setFeatureTranslatedFields(field_id, new_value) + # return + # # ====================================================================# + # # Update Feature Value => Remove Old Value => Add New Value + # if len(current): + # self.object.features_value_ids = [(3, current.id, 0), (4, new_value.id, 0)] + # else: + # self.object.features_value_ids = [(4, new_value.id, 0)] + # # ====================================================================# + # # Update Translations + # self.__setFeatureTranslatedFields(field_id, new_value) + # + # # ====================================================================# + # # Products Feature Field Ids Management + # # ====================================================================# + # + # @staticmethod + # def find_all(): + # """ + # Get List of All Available Attributes Types + # :return: dict + # """ + # return http.request.env["product.attribute"].search([("create_variant", "=", "no_variant")], order="id") + # + # # ====================================================================# + # # Products Feature Field Ids Management + # # ====================================================================# + # + # def encode(self, attribute): + # """ + # Decode Filed Id to Extract Pointed Attribute Id + # :param attribute: product.attribute + # :return: string + # """ + # return ProductsFeatures.prefix + str(attribute.id) + # + # def decode(self, field_id): + # """ + # Decode Filed Id to Extract Pointed Attribute Id + # :param field_id: str + # :return: None|int + # """ + # if not isinstance(field_id, str) or field_id.find(ProductsFeatures.prefix) != 0: + # return None + # try: + # return int(field_id[len(ProductsFeatures.prefix): len(field_id)]) + # except: + # return None + # + # # ====================================================================# + # # Products Feature Translations Management + # # ====================================================================# + # + # def __getFeatureTranslatedFields(self, field_id, attr_value): + # from odoo.addons.splashsync.helpers import TransHelper + # for iso_code in TransHelper.get_extra_iso(): + # iso_field_id = field_id+"_"+iso_code + # for key, val in self._in.copy().items(): + # if iso_field_id != val: + # continue + # self._out[iso_field_id] = TransHelper.get(attr_value, 'name', iso_code, attr_value.name) + # self._in.__delitem__(key) + # + # def __setFeatureTranslatedFields(self, field_id, attr_value): + # from odoo.addons.splashsync.helpers import TransHelper + # for iso_code in TransHelper.get_extra_iso(): + # iso_field_id = field_id+"_"+iso_code + # if iso_field_id not in self._in.keys(): + # continue + # TransHelper.set(attr_value, 'name', iso_code, self._in[iso_field_id]) + # self._in.__delitem__(iso_field_id) + # + # def __isEmptyFeatureTranslatedFields(self, field_id): + # from odoo.addons.splashsync.helpers import TransHelper + # for iso_code in TransHelper.get_extra_iso(): + # iso_field_id = field_id+"_"+iso_code + # # Read Mode + # for key, val in self._in.copy().items(): + # if iso_field_id != val: + # continue + # self._out[iso_field_id] = "" + # self._in.__delitem__(key) + # # Write Mode + # if iso_field_id in self._in.keys(): + # self._in.__delitem__(iso_field_id) From 0c3c4ca8c7b21c8ebb03e69e111e94a0560d95b0 Mon Sep 17 00:00:00 2001 From: BadPixxel Date: Wed, 22 Jul 2020 00:29:23 +0200 Subject: [PATCH 2/9] WIP Suppliers --- docker-compose.yml | 4 +- .../splashsync/helpers/objects/__init__.py | 1 + .../helpers/objects/products/suppliers.py | 75 ++++ odoo/addons/splashsync/objects/product.py | 1 + .../splashsync/objects/products/supplier.py | 363 +++++++----------- 5 files changed, 215 insertions(+), 229 deletions(-) create mode 100644 odoo/addons/splashsync/helpers/objects/products/suppliers.py diff --git a/docker-compose.yml b/docker-compose.yml index ec41956..c4989a4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -39,9 +39,9 @@ services: - ./docker/x86:/etc/odoo:ro - ./odoo/addons/splashsync:/mnt/extra-addons/splashsync:ro - ../Py-Core:/mnt/splashpy - entrypoint: bash /etc/odoo/entrypoint.sh odoo -i "splashsync,product,stock,website_sale_comparison,purchase" +# entrypoint: bash /etc/odoo/entrypoint.sh odoo -i "splashsync,product,stock,website_sale_comparison,purchase" # entrypoint: bash /etc/odoo/entrypoint.sh odoo -i "splashsync" -# entrypoint: bash /etc/odoo/entrypoint.sh odoo + entrypoint: bash /etc/odoo/entrypoint.sh odoo hostname: latest.odoo.local networks: odoo: { ipv4_address: 172.120.0.99, aliases: [ latest.odoo.local ] } diff --git a/odoo/addons/splashsync/helpers/objects/__init__.py b/odoo/addons/splashsync/helpers/objects/__init__.py index 67da461..0a7fe56 100755 --- a/odoo/addons/splashsync/helpers/objects/__init__.py +++ b/odoo/addons/splashsync/helpers/objects/__init__.py @@ -24,3 +24,4 @@ from .products.attributes import AttributesHelper, ValuesHelper, LinesHelper from .products.images import ProductImagesHelper +from .products.suppliers import SupplierHelper diff --git a/odoo/addons/splashsync/helpers/objects/products/suppliers.py b/odoo/addons/splashsync/helpers/objects/products/suppliers.py new file mode 100644 index 0000000..36ed8d7 --- /dev/null +++ b/odoo/addons/splashsync/helpers/objects/products/suppliers.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +# +# This file is part of SplashSync Project. +# +# Copyright (C) 2015-2019 Splash Sync +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# For the full copyright and license information, please view the LICENSE +# file that was distributed with this source code. +# + +from odoo import http + + +class SupplierHelper: + """Collection of Static Functions to manage Odoo Product Supplier Info""" + + vendorDomain = "res.partner" + domain = "product.supplierinfo" + filter = [("supplier", "=", True), ("is_company", "=", True)] + + @staticmethod + def first(product): + """ + Get Product First Supplier Info + :param product: Product + :return: None, product.supplierinfo + """ + if len(product.seller_ids) < 1: + return None + return product.seller_ids[0] + + @staticmethod + def create(product, vendor_name, vendor_price): + """ + Create a Product Supplier Info Object + :param product: Product + :param vendor_name: str + :param vendor_price: float + :return: None, product.supplierinfo + """ + from odoo.addons.splashsync.helpers import M2OHelper + # ====================================================================# + # Validate Supplier Partner + vendor_id = M2OHelper.verify_name(vendor_name, "name", SupplierHelper.vendorDomain, SupplierHelper.filter) + if vendor_id is None or vendor_id <= 0: + return None + try: + # ====================================================================# + # Create Supplier Info + supplier = SupplierHelper.getModel().create({ + "name": vendor_id, + "product_id": product.id, + "min_qty": 1, + "price": vendor_price, + }) + # ====================================================================# + # Connect Supplier Info + product.seller_ids = [(6, 0, [supplier.id])] + + return supplier + except Exception: + return None + + # ====================================================================# + # Odoo ORM Access + # ====================================================================# + + @staticmethod + def getModel(): + """Get Product Supplier Infos Model Class""" + return http.request.env[SupplierHelper.domain].sudo() diff --git a/odoo/addons/splashsync/objects/product.py b/odoo/addons/splashsync/objects/product.py index b2a25ca..4195a5f 100755 --- a/odoo/addons/splashsync/objects/product.py +++ b/odoo/addons/splashsync/objects/product.py @@ -58,6 +58,7 @@ def get_composite_fields(): "rating_last_image", "rating_last_feedback", "sale_line_warn", "message_unread_counter", "purchase_line_warn", "price", "lst_price", "list_price", "price_extra", "variant_price_extra", "standard_price", + "service_to_purchase" ] @staticmethod diff --git a/odoo/addons/splashsync/objects/products/supplier.py b/odoo/addons/splashsync/objects/products/supplier.py index 0e13d62..4d59f36 100644 --- a/odoo/addons/splashsync/objects/products/supplier.py +++ b/odoo/addons/splashsync/objects/products/supplier.py @@ -15,249 +15,158 @@ from odoo import http from splashpy import const, Framework from splashpy.componants import FieldFactory -from odoo.addons.splashsync.helpers import AttributesHelper, LinesHelper, ValuesHelper, SettingsManager - +from odoo.addons.splashsync.helpers import M2OHelper +from odoo.addons.splashsync.helpers import SupplierHelper class ProductsSupplier: """ Access to product First Supplier Fields """ - - # Static Prefix for Feature Attributes - prefix = "__feature_id__" + # Static List of First Supplier Field Ids + supplierFields = ["supplier_name", "supplier_sku", "supplier_min_qty", "supplier_price"] def buildSupplierFields(self): - pass - # from odoo.addons.splashsync.helpers import TransHelper - # # ====================================================================# - # # Set default System Language - # FieldFactory.setDefaultLanguage(TransHelper.get_default_iso()) - # # ====================================================================# - # # Walk on Available Attributes - # for attribute in ProductsFeatures.find_all(): - # # ====================================================================# - # # Walk on Available Languages - # for iso_code, lang_name in TransHelper.get_all().items(): - # # ==================================================================== # - # # Product Feature Field - # FieldFactory.create(const.__SPL_T_VARCHAR__, self.encode(attribute), attribute.display_name) - # FieldFactory.group("Features") - # FieldFactory.microData("http://schema.org/Product", attribute.name) - # # ==================================================================== # - # # Add Language Params - # FieldFactory.description("["+lang_name+"] "+attribute.display_name) - # FieldFactory.setMultilang(iso_code) - # # ==================================================================== # - # # Filter Variants Attributes During Tests - # if Framework.isDebugMode() and attribute.name in AttributesHelper.attr_test: - # FieldFactory.isNotTested() - # if iso_code != TransHelper.get_default_iso(): - # FieldFactory.association(self.encode(attribute)) + # ==================================================================== # + # Safety Check + if "seller_ids" not in self.getModel().fields_get(): + return + # ====================================================================# + # First Supplier Name + FieldFactory.create(const.__SPL_T_VARCHAR__, "supplier_name", "Supplier Name") + FieldFactory.microData("http://schema.org/Product", "supplierName") + FieldFactory.addChoices(M2OHelper.get_name_values(SupplierHelper.vendorDomain, SupplierHelper.filter)) + FieldFactory.isNotTested() + # ====================================================================# + # First Supplier Price + FieldFactory.create(const.__SPL_T_DOUBLE__, "supplier_price", "Supplier Price") + FieldFactory.microData("http://schema.org/Product", "supplierPrice") + FieldFactory.association("supplier_name") + # ====================================================================# + # First Supplier SKU + FieldFactory.create(const.__SPL_T_VARCHAR__, "supplier_sku", "Supplier SKU") + FieldFactory.microData("http://schema.org/Product", "mpn") + FieldFactory.association("supplier_name", "supplier_price") + # ====================================================================# + # First Supplier MOQ + FieldFactory.create(const.__SPL_T_INT__, "supplier_min_qty", "Supplier MOQ") + FieldFactory.microData("http://schema.org/Product", "supplierMinQty") + FieldFactory.association("supplier_name", "supplier_price") def getSupplierFields(self, index, field_id): """ - Get Product Attributes List + Get Product First Supplier Fields :param index: str :param field_id: str :return: None """ # ==================================================================== # - # Check field_id this Feature Field... - attr_id = self.decode(field_id) - if attr_id is None: + # Check field_id this First Supplier Field... + if not self.isSupplierField(field_id): return - self._in.__delitem__(index) - self._out[field_id] = None - # ==================================================================== # - # Check if Product has Attribute Value - for attr_value in self.object.attribute_value_ids: - if attr_value.attribute_id.id == attr_id: - self._out[field_id] = attr_value.name - self.__getFeatureTranslatedFields(field_id, attr_value) - return - # ==================================================================== # - # Check if Product has Advanced Feature Value - if SettingsManager.is_prd_adv_variants(): - for attr_value in self.object.features_value_ids: - if attr_value.attribute_id.id == attr_id: - self._out[field_id] = attr_value.name - self.__getFeatureTranslatedFields(field_id, attr_value) - return # ==================================================================== # - # Check if Product has Feature Value - for attr_value in self.template.valid_product_attribute_value_ids: - if attr_value.attribute_id.id == attr_id: - self._out[field_id] = attr_value.name - self.__getFeatureTranslatedFields(field_id, attr_value) - return + # Read First Supplier Value + self._out[field_id] = self.__get_supplier_values(field_id) + self._in.__delitem__(index) + + def setSupplierFields(self, field_id, field_data): + """ + Set Product First Supplier Fields + :param field_id: str + :param field_data: hash + :return: None + """ # ==================================================================== # - # Complete Not Found Feature Translations - self.__isEmptyFeatureTranslatedFields(field_id) + # Check field_id this First Supplier Field... + if not self.isSupplierField(field_id): + return + # ====================================================================# + # Try to fetch Current First Supplier + supplier = SupplierHelper.first(self.object) + # ====================================================================# + # Try to Create if Valid Supplier Info Provided + if supplier is None and self.__has_supplier_info(): + supplier = SupplierHelper.create(self.object, self._in["supplier_name"], self._in["supplier_price"]) + # ====================================================================# + # Unable to Load/Create Supplier Info + if supplier is None: + self._in.__delitem__(field_id) + return + # ====================================================================# + # Update Supplier Info + return self.__set_supplier_values(field_id, field_data, supplier) + + def __get_supplier_values(self, value_id): + """ + Get List of Attributes Values for given Field + :param value_id: str + :return: dict + """ + # ====================================================================# + # Load First Product Supplier Info + supplier = SupplierHelper.first(self.object) + if supplier is None: + return None + # ====================================================================# + # Get Value + if value_id == "supplier_name": + return supplier.name.name + elif value_id == "supplier_sku": + return supplier.product_code + elif value_id == "supplier_min_qty": + return supplier.min_qty + elif value_id == "supplier_price": + return supplier.price + + return None + + def __set_supplier_values(self, field_id, field_data, supplier): + """ + Set Product Supplier Fields + :param field_id: str + :param field_data: hash + :param supplier: product.supplierinfo + :return: None + """ + # ====================================================================# + # Set Value + self._in.__delitem__(field_id) + if field_id == "supplier_name": + # ====================================================================# + # Validate & Update Supplier Partner + new_partner = M2OHelper.verify_name(field_data, "name", SupplierHelper.vendorDomain, SupplierHelper.filter) + if new_partner is not None and new_partner > 0: + M2OHelper.set_name( + supplier, "name", field_data, + domain=SupplierHelper.vendorDomain, filters=SupplierHelper.filter + ) + elif field_id == "supplier_sku": + supplier.product_code = field_data + elif field_id == "supplier_min_qty": + supplier.min_qty = field_data + elif field_id == "supplier_price": + supplier.price = field_data + + def __has_supplier_info(self): + """ + Verify Product Supplier Info are Available on Input Fields + :return: bool + """ + # ====================================================================# + # Check Required Data are there + if "supplier_name" not in self._in: + return False + if str(self._in["supplier_name"]).__len__() < 3: + return False + if "supplier_price" not in self._in: + return False + try: + if float(self._in["supplier_price"]) <= 0: + return False + except Exception: + return False + + return True - # def setFeatureFields(self, field_id, field_data): - # """ - # Update Product Features Values (Standard Mode) - # :param field_id: str - # :param field_data: hash - # :return: None - # """ - # # ==================================================================== # - # # Check field_id this Feature Field... - # attr_id = self.decode(field_id) - # if attr_id is None or SettingsManager.is_prd_adv_variants(): - # return - # self._in.__delitem__(field_id) - # # ==================================================================== # - # # Check if Product has Feature Value - # attr_lines = self.template.attribute_line_ids.filtered( - # lambda l: l.attribute_id.create_variant == "no_variant" and l.attribute_id.id == attr_id - # ) - # for attr_line in attr_lines: - # # ==================================================================== # - # # Find or Create Attribute Value - # new_value = ValuesHelper.touch(attr_line.attribute_id, field_data, True) - # # ==================================================================== # - # # Empty Value or Creation Fail => Remove Product Attribute - # if new_value is None: - # self.template.attribute_line_ids = [(3, attr_line.id, 0)] - # self.__isEmptyFeatureTranslatedFields(field_id) - # return - # # ====================================================================# - # # If Values are Different => Update Values - # if len(attr_line.value_ids) != 1 or new_value.id != attr_line.value_ids[0].id: - # attr_line.value_ids = [(6, 0, [new_value.id])] - # # ====================================================================# - # # Update Product Attribute Translations - # self.__setFeatureTranslatedFields(field_id, new_value) - # return - # # ==================================================================== # - # # Add Product Feature Value - # if field_data is not None and len(str(field_data)) > 0: - # # Find or Create Attribute Value - # new_value = ValuesHelper.touch(AttributesHelper.load(attr_id), str(field_data), True) - # LinesHelper.add(self.template, new_value) - # self.__setFeatureTranslatedFields(field_id, new_value) - # # ==================================================================== # - # # Complete Empty Feature Translations - # else: - # self.__isEmptyFeatureTranslatedFields(field_id) - # - # def setAdvancedFeatureFields(self, field_id, field_data): - # """ - # Update Product Attributes Values (Mode 2 => FAIL) - # :param field_id: str - # :param field_data: hash - # :return: None - # """ - # # ==================================================================== # - # # Check field_id this Feature Field... - # attr_id = self.decode(field_id) - # if attr_id is None or not SettingsManager.is_prd_adv_variants(): - # return - # self._in.__delitem__(field_id) - # # ====================================================================# - # # Find Product Current Feature Values - # current = self.object.features_value_ids.filtered(lambda v: v.attribute_id.id == attr_id) - # # ==================================================================== # - # # Empty Product Feature Value - # if field_data is None or len(str(field_data)) == 0: - # if len(current): - # # Remove Product Feature - # self.object.features_value_ids = [(3, current.id, 0)] - # # Update Translations - # self.__isEmptyFeatureTranslatedFields(field_id) - # return - # # ==================================================================== # - # # Load Attribute - # attribute = current.attribute_id if len(current) else AttributesHelper.load(attr_id) - # # ==================================================================== # - # # Find or Create Attribute Value - # new_value = ValuesHelper.touch(attribute, field_data, True) - # # ====================================================================# - # # If Values are Similar => Nothing to Do => Exit - # if len(current) == 1 and new_value.id == current.id: - # self.__setFeatureTranslatedFields(field_id, new_value) - # return - # # ====================================================================# - # # Update Feature Value => Remove Old Value => Add New Value - # if len(current): - # self.object.features_value_ids = [(3, current.id, 0), (4, new_value.id, 0)] - # else: - # self.object.features_value_ids = [(4, new_value.id, 0)] - # # ====================================================================# - # # Update Translations - # self.__setFeatureTranslatedFields(field_id, new_value) - # - # # ====================================================================# - # # Products Feature Field Ids Management - # # ====================================================================# - # - # @staticmethod - # def find_all(): - # """ - # Get List of All Available Attributes Types - # :return: dict - # """ - # return http.request.env["product.attribute"].search([("create_variant", "=", "no_variant")], order="id") - # - # # ====================================================================# - # # Products Feature Field Ids Management - # # ====================================================================# - # - # def encode(self, attribute): - # """ - # Decode Filed Id to Extract Pointed Attribute Id - # :param attribute: product.attribute - # :return: string - # """ - # return ProductsFeatures.prefix + str(attribute.id) - # - # def decode(self, field_id): - # """ - # Decode Filed Id to Extract Pointed Attribute Id - # :param field_id: str - # :return: None|int - # """ - # if not isinstance(field_id, str) or field_id.find(ProductsFeatures.prefix) != 0: - # return None - # try: - # return int(field_id[len(ProductsFeatures.prefix): len(field_id)]) - # except: - # return None - # - # # ====================================================================# - # # Products Feature Translations Management - # # ====================================================================# - # - # def __getFeatureTranslatedFields(self, field_id, attr_value): - # from odoo.addons.splashsync.helpers import TransHelper - # for iso_code in TransHelper.get_extra_iso(): - # iso_field_id = field_id+"_"+iso_code - # for key, val in self._in.copy().items(): - # if iso_field_id != val: - # continue - # self._out[iso_field_id] = TransHelper.get(attr_value, 'name', iso_code, attr_value.name) - # self._in.__delitem__(key) - # - # def __setFeatureTranslatedFields(self, field_id, attr_value): - # from odoo.addons.splashsync.helpers import TransHelper - # for iso_code in TransHelper.get_extra_iso(): - # iso_field_id = field_id+"_"+iso_code - # if iso_field_id not in self._in.keys(): - # continue - # TransHelper.set(attr_value, 'name', iso_code, self._in[iso_field_id]) - # self._in.__delitem__(iso_field_id) - # - # def __isEmptyFeatureTranslatedFields(self, field_id): - # from odoo.addons.splashsync.helpers import TransHelper - # for iso_code in TransHelper.get_extra_iso(): - # iso_field_id = field_id+"_"+iso_code - # # Read Mode - # for key, val in self._in.copy().items(): - # if iso_field_id != val: - # continue - # self._out[iso_field_id] = "" - # self._in.__delitem__(key) - # # Write Mode - # if iso_field_id in self._in.keys(): - # self._in.__delitem__(iso_field_id) + @staticmethod + def isSupplierField(field_id): + return field_id in ProductsSupplier.supplierFields From 5619f266f07d7cb1bfa9fa58112416f367429e9b Mon Sep 17 00:00:00 2001 From: BadPixxel Date: Wed, 22 Jul 2020 00:51:48 +0200 Subject: [PATCH 3/9] WIP Suppliers --- .../splashsync/objects/products/supplier.py | 22 ++++++++++++++++--- setup.py | 2 +- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/odoo/addons/splashsync/objects/products/supplier.py b/odoo/addons/splashsync/objects/products/supplier.py index 4d59f36..ebbf76a 100644 --- a/odoo/addons/splashsync/objects/products/supplier.py +++ b/odoo/addons/splashsync/objects/products/supplier.py @@ -23,7 +23,10 @@ class ProductsSupplier: Access to product First Supplier Fields """ # Static List of First Supplier Field Ids - supplierFields = ["supplier_name", "supplier_sku", "supplier_min_qty", "supplier_price"] + supplierFields = [ + "supplier_name", "supplier_sku", "supplier_min_qty", + "supplier_price", "supplier_currency" + ] def buildSupplierFields(self): # ==================================================================== # @@ -51,6 +54,11 @@ def buildSupplierFields(self): FieldFactory.create(const.__SPL_T_INT__, "supplier_min_qty", "Supplier MOQ") FieldFactory.microData("http://schema.org/Product", "supplierMinQty") FieldFactory.association("supplier_name", "supplier_price") + # ====================================================================# + # First Supplier Currency + FieldFactory.create(const.__SPL_T_CURRENCY__, "supplier_currency", "Supplier Currency") + FieldFactory.microData("http://schema.org/Product", "supplierCurrency") + FieldFactory.association("supplier_name", "supplier_price") def getSupplierFields(self, index, field_id): """ @@ -116,6 +124,8 @@ def __get_supplier_values(self, value_id): return supplier.min_qty elif value_id == "supplier_price": return supplier.price + elif value_id == "supplier_currency": + return supplier.currency_id.name return None @@ -133,8 +143,8 @@ def __set_supplier_values(self, field_id, field_data, supplier): if field_id == "supplier_name": # ====================================================================# # Validate & Update Supplier Partner - new_partner = M2OHelper.verify_name(field_data, "name", SupplierHelper.vendorDomain, SupplierHelper.filter) - if new_partner is not None and new_partner > 0: + new_currency = M2OHelper.verify_name(field_data, "name", SupplierHelper.vendorDomain, SupplierHelper.filter) + if new_currency is not None and new_currency > 0: M2OHelper.set_name( supplier, "name", field_data, domain=SupplierHelper.vendorDomain, filters=SupplierHelper.filter @@ -145,6 +155,12 @@ def __set_supplier_values(self, field_id, field_data, supplier): supplier.min_qty = field_data elif field_id == "supplier_price": supplier.price = field_data + elif field_id == "supplier_currency": + # ====================================================================# + # Validate & Update Supplier Partner + new_currency = M2OHelper.verify_name(field_data, "name", "res.currency") + if new_currency is not None and new_currency > 0: + M2OHelper.set_name(supplier, "currency_id", field_data, domain="res.currency") def __has_supplier_info(self): """ diff --git a/setup.py b/setup.py index b6fac3d..ddf83c8 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ setup( name='splashsync', - version="0.1.0", + version="0.1.1", packages=find_packages(), namespace_packages=['odoo.addons.splashsync'], install_requires=["splashpy"], From 695eb050a9dba24072fd117b9f3aab63de5c5598 Mon Sep 17 00:00:00 2001 From: BadPixxel Date: Wed, 22 Jul 2020 01:48:46 +0200 Subject: [PATCH 4/9] WIP Suppliers --- odoo/addons/splashsync/objects/products/supplier.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/odoo/addons/splashsync/objects/products/supplier.py b/odoo/addons/splashsync/objects/products/supplier.py index ebbf76a..e7f0750 100644 --- a/odoo/addons/splashsync/objects/products/supplier.py +++ b/odoo/addons/splashsync/objects/products/supplier.py @@ -58,7 +58,7 @@ def buildSupplierFields(self): # First Supplier Currency FieldFactory.create(const.__SPL_T_CURRENCY__, "supplier_currency", "Supplier Currency") FieldFactory.microData("http://schema.org/Product", "supplierCurrency") - FieldFactory.association("supplier_name", "supplier_price") + FieldFactory.isNotTested() def getSupplierFields(self, index, field_id): """ From 29042b14a463a0f970285fd664d1311add6984fa Mon Sep 17 00:00:00 2001 From: BadPixxel Date: Fri, 24 Jul 2020 12:23:58 +0200 Subject: [PATCH 5/9] WIP Suppliers --- odoo/addons/splashsync/objects/products/relations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/odoo/addons/splashsync/objects/products/relations.py b/odoo/addons/splashsync/objects/products/relations.py index 33473ac..b02fe42 100644 --- a/odoo/addons/splashsync/objects/products/relations.py +++ b/odoo/addons/splashsync/objects/products/relations.py @@ -46,7 +46,7 @@ def buildRelationFields(self): FieldFactory.create(const.__SPL_T_VARCHAR__, "public_categ_ids", "Categorie Id") FieldFactory.microData("http://schema.org/Product", "publicCategoryId") FieldFactory.isReadOnly() - FieldFactory.create(const.__SPL_T_INLINE__, "public_categ", "Public Categorie") + FieldFactory.create(const.__SPL_T_VARCHAR__, "public_categ", "Public Categorie") FieldFactory.microData("http://schema.org/Product", "publicCategory") FieldFactory.addChoices(M2OHelper.get_name_values("product.public.category")) FieldFactory.isNotTested() From e3eb7f40b4efe351b860a8f1d8b691e28fb6efea Mon Sep 17 00:00:00 2001 From: BadPixxel Date: Mon, 27 Jul 2020 13:23:56 +0200 Subject: [PATCH 6/9] ADD Suppliers Formated Price --- .../splashsync/objects/products/supplier.py | 48 ++++++++++++++----- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/odoo/addons/splashsync/objects/products/supplier.py b/odoo/addons/splashsync/objects/products/supplier.py index e7f0750..a6d9b4c 100644 --- a/odoo/addons/splashsync/objects/products/supplier.py +++ b/odoo/addons/splashsync/objects/products/supplier.py @@ -15,8 +15,8 @@ from odoo import http from splashpy import const, Framework from splashpy.componants import FieldFactory -from odoo.addons.splashsync.helpers import M2OHelper -from odoo.addons.splashsync.helpers import SupplierHelper +from splashpy.helpers import PricesHelper +from odoo.addons.splashsync.helpers import M2OHelper, SettingsManager, TaxHelper, SupplierHelper class ProductsSupplier: """ @@ -25,7 +25,7 @@ class ProductsSupplier: # Static List of First Supplier Field Ids supplierFields = [ "supplier_name", "supplier_sku", "supplier_min_qty", - "supplier_price", "supplier_currency" + "supplier_price", "supplier_price_dbl", "supplier_currency" ] def buildSupplierFields(self): @@ -40,10 +40,15 @@ def buildSupplierFields(self): FieldFactory.addChoices(M2OHelper.get_name_values(SupplierHelper.vendorDomain, SupplierHelper.filter)) FieldFactory.isNotTested() # ====================================================================# + # First Supplier Price as Double + FieldFactory.create(const.__SPL_T_DOUBLE__, "supplier_price_dbl", "Supplier Price (Float)") + FieldFactory.microData("http://schema.org/Product", "supplierPriceDbl") + FieldFactory.association("supplier_name") + # ==================================================================== # # First Supplier Price - FieldFactory.create(const.__SPL_T_DOUBLE__, "supplier_price", "Supplier Price") + FieldFactory.create(const.__SPL_T_PRICE__, "supplier_price", "Supplier Price") FieldFactory.microData("http://schema.org/Product", "supplierPrice") - FieldFactory.association("supplier_name") + FieldFactory.isNotTested() # ====================================================================# # First Supplier SKU FieldFactory.create(const.__SPL_T_VARCHAR__, "supplier_sku", "Supplier SKU") @@ -93,7 +98,7 @@ def setSupplierFields(self, field_id, field_data): # ====================================================================# # Try to Create if Valid Supplier Info Provided if supplier is None and self.__has_supplier_info(): - supplier = SupplierHelper.create(self.object, self._in["supplier_name"], self._in["supplier_price"]) + supplier = SupplierHelper.create(self.object, self._in["supplier_name"], self._in["supplier_price_dbl"]) # ====================================================================# # Unable to Load/Create Supplier Info if supplier is None: @@ -122,8 +127,18 @@ def __get_supplier_values(self, value_id): return supplier.product_code elif value_id == "supplier_min_qty": return supplier.min_qty - elif value_id == "supplier_price": + elif value_id == "supplier_price_dbl": return supplier.price + elif value_id == "supplier_price": + # ==================================================================== # + # Load Product Configuration + is_adv_taxes = SettingsManager.is_prd_adv_taxes() + return PricesHelper.encode( + float(supplier.price), + TaxHelper.get_tax_rate(self.object.taxes_id, 'purchase') if not is_adv_taxes else float(0), + None, + supplier.currency_id.name + ) elif value_id == "supplier_currency": return supplier.currency_id.name @@ -153,8 +168,13 @@ def __set_supplier_values(self, field_id, field_data, supplier): supplier.product_code = field_data elif field_id == "supplier_min_qty": supplier.min_qty = field_data - elif field_id == "supplier_price": + elif field_id == "supplier_price_dbl": supplier.price = field_data + elif field_id == "supplier_price": + try: + supplier.price = float(PricesHelper.taxExcluded(field_data)) + except TypeError: + supplier.price = 0 elif field_id == "supplier_currency": # ====================================================================# # Validate & Update Supplier Partner @@ -168,15 +188,21 @@ def __has_supplier_info(self): :return: bool """ # ====================================================================# - # Check Required Data are there + # Check Supplier SKU is there if "supplier_name" not in self._in: return False if str(self._in["supplier_name"]).__len__() < 3: return False - if "supplier_price" not in self._in: + # ====================================================================# + # Check Required Data are there + if "supplier_price" in self._in: + self._in["supplier_price_dbl"] = float(PricesHelper.taxExcluded(self._in["supplier_price"])) + # ====================================================================# + # Check Supplier Price is there + if "supplier_price_dbl" not in self._in: return False try: - if float(self._in["supplier_price"]) <= 0: + if float(self._in["supplier_price_dbl"]) <= 0: return False except Exception: return False From ed214782dab553115ddf4088f853def839f75659 Mon Sep 17 00:00:00 2001 From: BadPixxel Date: Mon, 27 Jul 2020 13:53:35 +0200 Subject: [PATCH 7/9] ADD Suppliers Formated Price --- .../splashsync/objects/products/supplier.py | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/odoo/addons/splashsync/objects/products/supplier.py b/odoo/addons/splashsync/objects/products/supplier.py index a6d9b4c..b6371bf 100644 --- a/odoo/addons/splashsync/objects/products/supplier.py +++ b/odoo/addons/splashsync/objects/products/supplier.py @@ -27,6 +27,8 @@ class ProductsSupplier: "supplier_name", "supplier_sku", "supplier_min_qty", "supplier_price", "supplier_price_dbl", "supplier_currency" ] + # Static Storage for New Supplier Price + supplierCreatePrice = None def buildSupplierFields(self): # ==================================================================== # @@ -98,7 +100,7 @@ def setSupplierFields(self, field_id, field_data): # ====================================================================# # Try to Create if Valid Supplier Info Provided if supplier is None and self.__has_supplier_info(): - supplier = SupplierHelper.create(self.object, self._in["supplier_name"], self._in["supplier_price_dbl"]) + supplier = SupplierHelper.create(self.object, self._in["supplier_name"], self.supplierCreatePrice) # ====================================================================# # Unable to Load/Create Supplier Info if supplier is None: @@ -194,15 +196,22 @@ def __has_supplier_info(self): if str(self._in["supplier_name"]).__len__() < 3: return False # ====================================================================# - # Check Required Data are there + # Check Supplier Price is there + if "supplier_price_dbl" not in self._in and "supplier_price" not in self._in: + return False + # ====================================================================# + # Detect Received Supplier Price + self.supplierCreatePrice = None + if "supplier_price_dbl" in self._in: + self.supplierCreatePrice = self._in["supplier_price_dbl"] if "supplier_price" in self._in: - self._in["supplier_price_dbl"] = float(PricesHelper.taxExcluded(self._in["supplier_price"])) + self.supplierCreatePrice = PricesHelper.taxExcluded(self._in["supplier_price"]) # ====================================================================# - # Check Supplier Price is there - if "supplier_price_dbl" not in self._in: + # Verify Supplier Price is Valid + if self.supplierCreatePrice is None: return False try: - if float(self._in["supplier_price_dbl"]) <= 0: + if float(self.supplierCreatePrice) <= 0: return False except Exception: return False From 336c64d5e64f184d44c526f218c6727d44527a5e Mon Sep 17 00:00:00 2001 From: BadPixxel Date: Mon, 27 Jul 2020 14:20:42 +0200 Subject: [PATCH 8/9] ADD Suppliers Formated Price --- odoo/addons/splashsync/objects/products/supplier.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/odoo/addons/splashsync/objects/products/supplier.py b/odoo/addons/splashsync/objects/products/supplier.py index b6371bf..e46d708 100644 --- a/odoo/addons/splashsync/objects/products/supplier.py +++ b/odoo/addons/splashsync/objects/products/supplier.py @@ -55,12 +55,12 @@ def buildSupplierFields(self): # First Supplier SKU FieldFactory.create(const.__SPL_T_VARCHAR__, "supplier_sku", "Supplier SKU") FieldFactory.microData("http://schema.org/Product", "mpn") - FieldFactory.association("supplier_name", "supplier_price") + FieldFactory.association("supplier_name", "supplier_price_dbl") # ====================================================================# # First Supplier MOQ FieldFactory.create(const.__SPL_T_INT__, "supplier_min_qty", "Supplier MOQ") FieldFactory.microData("http://schema.org/Product", "supplierMinQty") - FieldFactory.association("supplier_name", "supplier_price") + FieldFactory.association("supplier_name", "supplier_price_dbl") # ====================================================================# # First Supplier Currency FieldFactory.create(const.__SPL_T_CURRENCY__, "supplier_currency", "Supplier Currency") From 4f162426aba01b3099684b23241ecd96304d0259 Mon Sep 17 00:00:00 2001 From: BadPixxel Date: Mon, 27 Jul 2020 14:41:47 +0200 Subject: [PATCH 9/9] ADD Suppliers Formated Price --- odoo/addons/splashsync/objects/products/supplier.py | 1 + 1 file changed, 1 insertion(+) diff --git a/odoo/addons/splashsync/objects/products/supplier.py b/odoo/addons/splashsync/objects/products/supplier.py index e46d708..360cb53 100644 --- a/odoo/addons/splashsync/objects/products/supplier.py +++ b/odoo/addons/splashsync/objects/products/supplier.py @@ -50,6 +50,7 @@ def buildSupplierFields(self): # First Supplier Price FieldFactory.create(const.__SPL_T_PRICE__, "supplier_price", "Supplier Price") FieldFactory.microData("http://schema.org/Product", "supplierPrice") + FieldFactory.isWriteOnly(Framework.isDebugMode()) FieldFactory.isNotTested() # ====================================================================# # First Supplier SKU