details: https://code.tryton.org/tryton/commit/e3cb55f2d8f6
branch: default
user: Cédric Krier <[email protected]>
date: Fri Jan 09 18:31:28 2026 +0100
description:
Add support for gift card products on Shopify
Closes #14417
diffstat:
modules/web_shop/sale.py | 9 +++++++++
modules/web_shop/tryton.cfg | 5 +++++
modules/web_shop/web.py | 5 +++++
modules/web_shop_shopify/CHANGELOG | 1 +
modules/web_shop_shopify/doc/usage.rst | 17 +++++++++++++++++
modules/web_shop_shopify/product.py | 33 +++++++++++++++++++++++++++++++++
modules/web_shop_shopify/tryton.cfg | 6 ++++++
modules/web_shop_shopify/web.py | 7 +++++++
8 files changed, 83 insertions(+), 0 deletions(-)
diffs (175 lines):
diff -r dd98790370ed -r e3cb55f2d8f6 modules/web_shop/sale.py
--- a/modules/web_shop/sale.py Thu Mar 05 11:48:32 2026 +0100
+++ b/modules/web_shop/sale.py Fri Jan 09 18:31:28 2026 +0100
@@ -110,3 +110,12 @@
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 -r dd98790370ed -r e3cb55f2d8f6 modules/web_shop/tryton.cfg
--- a/modules/web_shop/tryton.cfg Thu Mar 05 11:48:32 2026 +0100
+++ b/modules/web_shop/tryton.cfg Fri Jan 09 18:31:28 2026 +0100
@@ -14,6 +14,7 @@
account_tax_rule_country
product_attribute
product_image
+ sale_gift_card
sale_price_list
sale_shipment_cost
xml:
@@ -50,6 +51,10 @@
model:
product.Image
+[register sale_gift_card]
+model:
+ sale.Line_GiftCard
+
[register sale_price_list]
model:
web.Shop_PriceList
diff -r dd98790370ed -r e3cb55f2d8f6 modules/web_shop/web.py
--- a/modules/web_shop/web.py Thu Mar 05 11:48:32 2026 +0100
+++ b/modules/web_shop/web.py Fri Jan 09 18:31:28 2026 +0100
@@ -274,6 +274,11 @@
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 -r dd98790370ed -r e3cb55f2d8f6 modules/web_shop_shopify/CHANGELOG
--- a/modules/web_shop_shopify/CHANGELOG Thu Mar 05 11:48:32 2026 +0100
+++ b/modules/web_shop_shopify/CHANGELOG Fri Jan 09 18:31:28 2026 +0100
@@ -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 -r dd98790370ed -r e3cb55f2d8f6 modules/web_shop_shopify/doc/usage.rst
--- a/modules/web_shop_shopify/doc/usage.rst Thu Mar 05 11:48:32 2026 +0100
+++ b/modules/web_shop_shopify/doc/usage.rst Fri Jan 09 18:31:28 2026 +0100
@@ -89,3 +89,20 @@
- ``GET`` ``/<database_name>/web_shop_shopify/customers/<customer id>``
- ``GET`` ``/<database_name>/web_shop_shopify/orders/<order id>``
+
+.. _Setup Gift Cards:
+
+Setup Gift Cards
+================
+
+To use gift cards on Shopify, you must activate the :doc:`*Sale Gift Card
+Module* <sale_gift_card:index>`.
+`Products <sale_gift_card:concept-product>` defined as gift cards are also
+registered as such on Shopify.
+When a gift card is sold on Shopify, no `gift card
+<sale_gift_card:model-sale.gift_card>` is created by the corresponding `sale
+<sale_gift_card:model-sale.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
+<account_payment:model-account.payment.journal>`.
diff -r dd98790370ed -r e3cb55f2d8f6 modules/web_shop_shopify/product.py
--- a/modules/web_shop_shopify/product.py Thu Mar 05 11:48:32 2026 +0100
+++ b/modules/web_shop_shopify/product.py Fri Jan 09 18:31:28 2026 +0100
@@ -240,6 +240,24 @@
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 @@
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 -r dd98790370ed -r e3cb55f2d8f6 modules/web_shop_shopify/tryton.cfg
--- a/modules/web_shop_shopify/tryton.cfg Thu Mar 05 11:48:32 2026 +0100
+++ b/modules/web_shop_shopify/tryton.cfg Fri Jan 09 18:31:28 2026 +0100
@@ -20,6 +20,7 @@
product_kit
product_measurements
sale_discount
+ sale_gift_card
sale_invoice_grouping
sale_secondary_unit
sale_shipment_cost
@@ -92,6 +93,11 @@
model:
sale.Line_Discount
+[register sale_gift_card]
+model:
+ product.Template_GiftCard
+ product.Product_GiftCard
+
[register sale_secondary_unit]
model:
product.Template_SaleSecondaryUnit
diff -r dd98790370ed -r e3cb55f2d8f6 modules/web_shop_shopify/web.py
--- a/modules/web_shop_shopify/web.py Thu Mar 05 11:48:32 2026 +0100
+++ b/modules/web_shop_shopify/web.py Fri Jan 09 18:31:28 2026 +0100
@@ -222,6 +222,13 @@
'/%(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() + [