details:   https://code.tryton.org/tryton/commit/1d15a4b5bb79
branch:    default
user:      Cédric Krier <[email protected]>
date:      Thu Jul 03 16:49:46 2025 +0200
description:
        Add carrier selection for Shopify order

        Closes #14102
diffstat:

 modules/web_shop_shopify/CHANGELOG                               |   1 +
 modules/web_shop_shopify/carrier.py                              |  59 
++++++++++
 modules/web_shop_shopify/carrier.xml                             |  23 +++
 modules/web_shop_shopify/doc/design.rst                          |  14 ++
 modules/web_shop_shopify/sale.py                                 |  19 ++-
 modules/web_shop_shopify/setup.py                                |   1 +
 modules/web_shop_shopify/tests/scenario_web_shop_shopify.rst     |  26 +++-
 modules/web_shop_shopify/tests/test_module.py                    |   2 +-
 modules/web_shop_shopify/tryton.cfg                              |   7 +
 modules/web_shop_shopify/view/carrier_form.xml                   |   8 +
 modules/web_shop_shopify/view/carrier_selection_shopify_form.xml |  17 ++
 modules/web_shop_shopify/view/carrier_selection_shopify_list.xml |   9 +
 12 files changed, 175 insertions(+), 11 deletions(-)

diffs (315 lines):

diff -r 420f26f83887 -r 1d15a4b5bb79 modules/web_shop_shopify/CHANGELOG
--- a/modules/web_shop_shopify/CHANGELOG        Mon Dec 01 16:46:23 2025 +0100
+++ b/modules/web_shop_shopify/CHANGELOG        Thu Jul 03 16:49:46 2025 +0200
@@ -1,3 +1,4 @@
+* Add carrier selection
 * Use GraphQL API
 * Add option to notify customer about fulfillment
 * Support taxes from shipping product
diff -r 420f26f83887 -r 1d15a4b5bb79 modules/web_shop_shopify/carrier.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/web_shop_shopify/carrier.py       Thu Jul 03 16:49:46 2025 +0200
@@ -0,0 +1,59 @@
+# This file is part of Tryton.  The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
+
+import re
+
+from trytond.model import MatchMixin, ModelSQL, ModelView, fields
+from trytond.pool import PoolMeta
+
+
+class Carrier(metaclass=PoolMeta):
+    __name__ = 'carrier'
+
+    shopify_selections = fields.One2Many(
+        'carrier.selection.shopify', 'carrier', "Shopify Selections",
+        help="Define the criteria that will match this carrier "
+        "with the Shopify shipping methods.")
+
+    def shopify_match(self, shop, shipping_line, pattern=None):
+        pattern = pattern.copy() if pattern is not None else {}
+        pattern.setdefault('shop', shop.id)
+        pattern.setdefault('code', shipping_line.get('code'))
+        pattern.setdefault('title', shipping_line.get('title'))
+        for selection in self.shopify_selections:
+            if selection.match(pattern):
+                return True
+        return False
+
+
+class SelectionShopify(MatchMixin, ModelSQL, ModelView):
+    __name__ = 'carrier.selection.shopify'
+
+    @classmethod
+    def __setup__(cls):
+        super().__setup__()
+        cls.__access__.add('carrier')
+
+    carrier = fields.Many2One(
+        'carrier', "Carrier", required=True, ondelete='CASCADE')
+    shop = fields.Many2One(
+        'web.shop', "Shop",
+        domain=[
+            ('type', '=', 'shopify'),
+            ])
+    code = fields.Char(
+        "Code",
+        help="The code of the shipping line.")
+    title = fields.Char(
+        "Title",
+        help="A regular expression to match the shipping line title.\n"
+        "Leave empty to allow any title.")
+
+    def match(self, pattern, match_none=False):
+        if 'title' in pattern:
+            pattern = pattern.copy()
+            title = pattern.pop('title') or ''
+            if (self.title is not None
+                    and not re.search(self.title, title, flags=re.I)):
+                return False
+        return super().match(pattern, match_none=match_none)
diff -r 420f26f83887 -r 1d15a4b5bb79 modules/web_shop_shopify/carrier.xml
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/web_shop_shopify/carrier.xml      Thu Jul 03 16:49:46 2025 +0200
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!-- This file is part of Tryton.  The COPYRIGHT file at the top level of
+this repository contains the full copyright notices and license terms. -->
+<tryton>
+    <data depends="carrier">
+        <record model="ir.ui.view" id="carrier_view_form">
+            <field name="model">carrier</field>
+            <field name="inherit" ref="carrier.carrier_view_form"/>
+            <field name="name">carrier_form</field>
+        </record>
+
+        <record model="ir.ui.view" id="carrier_selection_shopify_view_form">
+            <field name="model">carrier.selection.shopify</field>
+            <field name="type">form</field>
+            <field name="name">carrier_selection_shopify_form</field>
+        </record>
+        <record model="ir.ui.view" id="carrier_selection_shopify_view_list">
+            <field name="model">carrier.selection.shopify</field>
+            <field name="type">tree</field>
+            <field name="name">carrier_selection_shopify_list</field>
+        </record>
+    </data>
+</tryton>
diff -r 420f26f83887 -r 1d15a4b5bb79 modules/web_shop_shopify/doc/design.rst
--- a/modules/web_shop_shopify/doc/design.rst   Mon Dec 01 16:46:23 2025 +0100
+++ b/modules/web_shop_shopify/doc/design.rst   Thu Jul 03 16:49:46 2025 +0200
@@ -55,3 +55,17 @@
 
 The *Shopify Inventory Item* concept manages the Shopify inventory item of each
 `Varient <product:model-product.product>`.
+
+.. _model-carrier:
+
+Carrier
+=======
+
+When the *Carrier Module* is activated, the `Carrier <carrier:model-carrier>`
+is extended to allow to define the :guilabel:`Code` of the Shopify shipping
+method.
+
+.. seealso::
+
+   The `Carrier <carrier:model-carrier>` concept is introduced by the
+   :doc:`Carrier Module <carrier:index>`.
diff -r 420f26f83887 -r 1d15a4b5bb79 modules/web_shop_shopify/sale.py
--- a/modules/web_shop_shopify/sale.py  Mon Dec 01 16:46:23 2025 +0100
+++ b/modules/web_shop_shopify/sale.py  Thu Jul 03 16:49:46 2025 +0200
@@ -722,6 +722,14 @@
         return super().set_shipment_cost()
 
     @classmethod
+    def shopify_fields(cls):
+        fields = super().shopify_fields()
+        shipping_line = fields.setdefault('shippingLine', {})
+        shipping_line.setdefault('code')
+        shipping_line.setdefault('title')
+        return fields
+
+    @classmethod
     def get_from_shopify(cls, shop, order, sale=None):
         pool = Pool()
         Tax = pool.get('account.tax')
@@ -729,11 +737,16 @@
         sale = super().get_from_shopify(shop, order, sale=sale)
 
         shipment_cost_method = None
-        if order['shippingLines']:
+        if shipping_line := order['shippingLine']:
             available_carriers = sale.on_change_with_available_carriers()
             carrier = None
-            if available_carriers:
-                carrier = available_carriers[0]
+            for carrier in available_carriers:
+                if carrier.shopify_match(shop, shipping_line):
+                    carrier = carrier
+                    break
+            else:
+                if available_carriers:
+                    carrier = available_carriers[0]
             setattr_changed(sale, 'carrier', carrier)
             if sale.carrier:
                 shipment_cost_method = 'order'
diff -r 420f26f83887 -r 1d15a4b5bb79 modules/web_shop_shopify/setup.py
--- a/modules/web_shop_shopify/setup.py Mon Dec 01 16:46:23 2025 +0100
+++ b/modules/web_shop_shopify/setup.py Thu Jul 03 16:49:46 2025 +0200
@@ -53,6 +53,7 @@
 tests_require = [
     get_require_version('proteus'),
     get_require_version('trytond_account_payment_clearing'),
+    get_require_version('trytond_carrier'),
     get_require_version('trytond_customs'),
     get_require_version('trytond_product_image'),
     get_require_version('trytond_product_image_attribute'),
diff -r 420f26f83887 -r 1d15a4b5bb79 
modules/web_shop_shopify/tests/scenario_web_shop_shopify.rst
--- a/modules/web_shop_shopify/tests/scenario_web_shop_shopify.rst      Mon Dec 
01 16:46:23 2025 +0100
+++ b/modules/web_shop_shopify/tests/scenario_web_shop_shopify.rst      Thu Jul 
03 16:49:46 2025 +0200
@@ -46,6 +46,7 @@
     >>> config = activate_modules([
     ...         'web_shop_shopify',
     ...         'account_payment_clearing',
+    ...         'carrier',
     ...         'customs',
     ...         'product_measurements',
     ...         'product_image',
@@ -280,7 +281,7 @@
     ...     
'https://downloads.tryton.org/tests/shopify/chair-white.jpg').read()
     >>> variant2.save()
 
-Create carrier::
+Create carriers::
 
     >>> carrier_template = ProductTemplate()
     >>> carrier_template.name = 'Carrier Product'
@@ -294,12 +295,23 @@
     >>> carrier_product.cost_price = Decimal('2')
     >>> carrier_product.save()
 
-    >>> carrier = Carrier()
-    >>> party = Party(name='Carrier')
+    >>> carrier1 = Carrier()
+    >>> party = Party(name="Carrier 1")
     >>> party.save()
-    >>> carrier.party = party
-    >>> carrier.carrier_product = carrier_product
-    >>> carrier.save()
+    >>> carrier1.party = party
+    >>> carrier1.carrier_product = carrier_product
+    >>> carrier1.save()
+
+    >>> carrier2 = Carrier()
+    >>> party = Party(name="Carrier 2")
+    >>> party.save()
+    >>> carrier2.party = party
+    >>> carrier2.carrier_product = carrier_product
+    >>> _ = carrier2.shopify_selections.new(code='SHIP')
+    >>> carrier2.save()
+
+    >>> CarrierSelection(carrier=carrier1).save()
+    >>> CarrierSelection(carrier=carrier2).save()
 
 Fill warehouse::
 
@@ -562,7 +574,7 @@
     'processing'
     >>> payment.amount
     Decimal('0')
-    >>> assertEqual(sale.carrier, carrier)
+    >>> assertEqual(sale.carrier, carrier2)
     >>> sale.state
     'quotation'
     >>> sale.party.name
diff -r 420f26f83887 -r 1d15a4b5bb79 
modules/web_shop_shopify/tests/test_module.py
--- a/modules/web_shop_shopify/tests/test_module.py     Mon Dec 01 16:46:23 
2025 +0100
+++ b/modules/web_shop_shopify/tests/test_module.py     Thu Jul 03 16:49:46 
2025 +0200
@@ -10,7 +10,7 @@
     'Test Web Shop Shopify module'
     module = 'web_shop_shopify'
     extras = [
-        'customs', 'product_image', 'product_image_attribute',
+        'carrier', 'customs', 'product_image', 'product_image_attribute',
         'product_measurements', 'sale_discount', 'sale_invoice_grouping',
         'sale_secondary_unit', 'sale_shipment_cost', 'stock_package_shipping']
 
diff -r 420f26f83887 -r 1d15a4b5bb79 modules/web_shop_shopify/tryton.cfg
--- a/modules/web_shop_shopify/tryton.cfg       Mon Dec 01 16:46:23 2025 +0100
+++ b/modules/web_shop_shopify/tryton.cfg       Thu Jul 03 16:49:46 2025 +0200
@@ -13,6 +13,7 @@
     stock
     web_shop
 extras_depend:
+    carrier
     customs
     product_image
     product_image_attribute
@@ -27,6 +28,7 @@
     product.xml
     web.xml
     stock.xml
+    carrier.xml
     message.xml
 
 [register]
@@ -58,6 +60,11 @@
 wizard:
     party.Replace
 
+[register carrier]
+model:
+    carrier.Carrier
+    carrier.SelectionShopify
+
 [register customs]
 model:
     product.ShopifyInventoryItem_Customs
diff -r 420f26f83887 -r 1d15a4b5bb79 
modules/web_shop_shopify/view/carrier_form.xml
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/web_shop_shopify/view/carrier_form.xml    Thu Jul 03 16:49:46 
2025 +0200
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<!-- This file is part of Tryton.  The COPYRIGHT file at the top level of
+this repository contains the full copyright notices and license terms. -->
+<data>
+    <xpath expr="/form" position="inside">
+        <field name="shopify_selections" colspan="4"/>
+    </xpath>
+</data>
diff -r 420f26f83887 -r 1d15a4b5bb79 
modules/web_shop_shopify/view/carrier_selection_shopify_form.xml
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/web_shop_shopify/view/carrier_selection_shopify_form.xml  Thu Jul 
03 16:49:46 2025 +0200
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<!-- This file is part of Tryton.  The COPYRIGHT file at the top level of
+this repository contains the full copyright notices and license terms. -->
+<form cursor="shop" col="2">
+    <label name="carrier"/>
+    <field name="carrier"/>
+
+    <separator string="Criteria" id="criteria" colspan="2"/>
+    <label name="shop"/>
+    <field name="shop"/>
+
+    <label name="code"/>
+    <field name="code"/>
+
+    <label name="title"/>
+    <field name="title"/>
+</form>
diff -r 420f26f83887 -r 1d15a4b5bb79 
modules/web_shop_shopify/view/carrier_selection_shopify_list.xml
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/web_shop_shopify/view/carrier_selection_shopify_list.xml  Thu Jul 
03 16:49:46 2025 +0200
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<!-- This file is part of Tryton.  The COPYRIGHT file at the top level of
+this repository contains the full copyright notices and license terms. -->
+<tree>
+    <field name="carrier" expand="2"/>
+    <field name="shop" expand="1"/>
+    <field name="code" expand="1"/>
+    <field name="title" expand="1"/>
+</tree>

Reply via email to