diff --git a/modules/web_shop/sale.py b/modules/web_shop/sale.py index 751cb05593..ce43dd9cb3 100644 --- a/modules/web_shop/sale.py +++ b/modules/web_shop/sale.py @@ -110,3 +110,12 @@ class Sale(metaclass=PoolMeta): def web_shop_update(cls, sales): for web_shop, s_sales in groupby(sales, lambda s: s.web_shop): web_shop.update_sales(list(s_sales)) + + +class Line_GiftCard(metaclass=PoolMeta): + __name__ = 'sale.line' + + def get_gift_cards(self): + if self.sale.web_shop and self.sale.web_shop.is_managing_gift_card: + return + return super().get_gift_cards() diff --git a/modules/web_shop/tryton.cfg b/modules/web_shop/tryton.cfg index a8ba9e6c50..b030c45398 100644 --- a/modules/web_shop/tryton.cfg +++ b/modules/web_shop/tryton.cfg @@ -14,6 +14,7 @@ extras_depend: account_tax_rule_country product_attribute product_image + sale_gift_card sale_price_list sale_shipment_cost xml: @@ -50,6 +51,10 @@ model: model: product.Image +[register sale_gift_card] +model: + sale.Line_GiftCard + [register sale_price_list] model: web.Shop_PriceList diff --git a/modules/web_shop/web.py b/modules/web_shop/web.py index 8e3ef38501..e77e01c536 100644 --- a/modules/web_shop/web.py +++ b/modules/web_shop/web.py @@ -274,6 +274,11 @@ class Shop(DeactivableMixin, ModelSQL, ModelView): def update_sales(self, sales): assert all(s.web_shop == self for s in sales) + @property + def is_managing_gift_card(self): + "Return if the webshop manages gift cards" + pass + class Shop_PriceList(metaclass=PoolMeta): __name__ = 'web.shop' diff --git a/modules/web_shop_shopify/CHANGELOG b/modules/web_shop_shopify/CHANGELOG index 5736d972cd..41c4ec1e7d 100644 --- a/modules/web_shop_shopify/CHANGELOG +++ b/modules/web_shop_shopify/CHANGELOG @@ -1,3 +1,4 @@ +* Add support for gift card products * Add support for Python 3.14 * Remove support for Python 3.9 * Manage payment terms diff --git a/modules/web_shop_shopify/doc/usage.rst b/modules/web_shop_shopify/doc/usage.rst index 57dc02db67..19f275a8fa 100644 --- a/modules/web_shop_shopify/doc/usage.rst +++ b/modules/web_shop_shopify/doc/usage.rst @@ -89,3 +89,20 @@ You can use these links to create an `admin link extension - ``GET`` ``//web_shop_shopify/customers/`` - ``GET`` ``//web_shop_shopify/orders/`` + +.. _Setup Gift Cards: + +Setup Gift Cards +================ + +To use gift cards on Shopify, you must activate the :doc:`*Sale Gift Card +Module* `. +`Products ` defined as gift cards are also +registered as such on Shopify. +When a gift card is sold on Shopify, no `gift card +` is created by the corresponding `sale +` order as these are managed by Shopify. +When a gift card is redeemed on Shopify, it appears as a payment from the +``gift_card`` gateway. +It is recommended that you use this criteria to setup a different `payment journal +`. diff --git a/modules/web_shop_shopify/product.py b/modules/web_shop_shopify/product.py index 7aca43832e..044e899e90 100644 --- a/modules/web_shop_shopify/product.py +++ b/modules/web_shop_shopify/product.py @@ -240,6 +240,24 @@ class Template_SaleSecondaryUnit(metaclass=PoolMeta): return uom +class Template_GiftCard(metaclass=PoolMeta): + __name__ = 'product.template' + + @classmethod + def __setup__(cls): + super().__setup__() + readonly = cls.gift_card.states.get('readonly', False) + cls.gift_card.states['readonly'] = ( + readonly | Eval('shopify_identifiers', [])) + + def get_shopify(self, shop, categories): + product = super().get_shopify(shop, categories) + if not product.get('id'): + # The product gift_card attribute cannot be changed after creation + product['giftCard'] = self.gift_card + return product + + class Product(IdentifiersMixin, metaclass=PoolMeta): __name__ = 'product.product' @@ -365,6 +383,21 @@ class Product(IdentifiersMixin, metaclass=PoolMeta): factor=self.shopify_uom_factor, rate=self.shopify_uom_rate) +class Product_GiftCard(metaclass=PoolMeta): + __name__ = 'product.product' + + def get_shopify( + self, shop, sale_price, sale_tax, price, tax, + shop_taxes_included=True): + variant = super().get_shopify( + shop, sale_price, sale_tax, price, tax, + shop_taxes_included=shop_taxes_included) + if self.gift_card: + # taxable is readonly for gift card on Shopify + variant.pop('taxable', None) + return variant + + class ProductURL(metaclass=PoolMeta): __name__ = 'product.web_shop_url' diff --git a/modules/web_shop_shopify/tryton.cfg b/modules/web_shop_shopify/tryton.cfg index f4a4d2bf33..5af6bb82e1 100644 --- a/modules/web_shop_shopify/tryton.cfg +++ b/modules/web_shop_shopify/tryton.cfg @@ -20,6 +20,7 @@ extras_depend: product_kit product_measurements sale_discount + sale_gift_card sale_invoice_grouping sale_secondary_unit sale_shipment_cost @@ -92,6 +93,11 @@ model: model: sale.Line_Discount +[register sale_gift_card] +model: + product.Template_GiftCard + product.Product_GiftCard + [register sale_secondary_unit] model: product.Template_SaleSecondaryUnit diff --git a/modules/web_shop_shopify/web.py b/modules/web_shop_shopify/web.py index d626f797ff..afa52c3533 100644 --- a/modules/web_shop_shopify/web.py +++ b/modules/web_shop_shopify/web.py @@ -222,6 +222,13 @@ class Shop(metaclass=PoolMeta): '/%(database_name)s/web_shop_shopify/webhook/%(shop)s/order' % url_part)) + @property + def is_managing_gift_card(self): + managing = super().is_managing_gift_card + if self.type == 'shopify': + managing = True + return managing + @classmethod def view_attributes(cls): return super().view_attributes() + [