changeset c1591e56fd06 in modules/web_shop_shopify:default
details:
https://hg.tryton.org/modules/web_shop_shopify?cmd=changeset&node=c1591e56fd06
description:
Replace deprecated fulfillment by fulfillment order
issue11746
review421851003
diffstat:
CHANGELOG | 2 +
doc/usage.rst | 10 +++++--
message.xml | 3 ++
setup.py | 3 +-
stock.py | 78 +++++++++++++++++++++++++++++++++++++++++-----------------
web.py | 2 +-
6 files changed, 69 insertions(+), 29 deletions(-)
diffs (192 lines):
diff -r 90ea9f496a0b -r c1591e56fd06 CHANGELOG
--- a/CHANGELOG Mon Oct 10 18:51:28 2022 +0200
+++ b/CHANGELOG Mon Oct 10 18:52:53 2022 +0200
@@ -1,3 +1,5 @@
+* Replace deprecated fulfillment by fulfillment order
+
Version 6.4.0 - 2022-05-02
* Bug fixes (see mercurial logs for details)
* Support webhook for orders
diff -r 90ea9f496a0b -r c1591e56fd06 doc/usage.rst
--- a/doc/usage.rst Mon Oct 10 18:51:28 2022 +0200
+++ b/doc/usage.rst Mon Oct 10 18:52:53 2022 +0200
@@ -7,9 +7,9 @@
Configure Shopify Web Shop
==========================
-First you must create a new `private app
-<https://help.shopify.com/en/manual/apps/private-apps>`_ for your Shopify
-store with, as a minimum, the following permissions:
+First you must create a new `custom app
+<https://help.shopify.com/en/manual/apps/app-types#custom-apps>`_ for your
+Shopify store with, as a minimum, the following permissions:
* Fulfillment services: Read and write
@@ -21,6 +21,10 @@
* Products: Read and write
+ * Assigned fulfillment: Read and write
+
+ * Merchant-managed fulfillment orders: Read and write
+
You also need to copy the password that is generated.
When setting the :doc:`Web Shop <web_shop:index>`'s type to "Shopify", you
diff -r 90ea9f496a0b -r c1591e56fd06 message.xml
--- a/message.xml Mon Oct 10 18:51:28 2022 +0200
+++ b/message.xml Mon Oct 10 18:52:53 2022 +0200
@@ -67,5 +67,8 @@
<record model="ir.message" id="msg_sale_line_without_product">
<field name="text">To process the sale "%(sale)s" you must set a
product on the line "%(line)s".</field>
</record>
+ <record model="ir.message" id="msg_fulfillment_order_line_not_found">
+ <field name="text">Failed to find fulfillment order for
%(quantity)s of move "%(move)s".</field>
+ </record>
</data>
</tryton>
diff -r 90ea9f496a0b -r c1591e56fd06 setup.py
--- a/setup.py Mon Oct 10 18:51:28 2022 +0200
+++ b/setup.py Mon Oct 10 18:52:53 2022 +0200
@@ -61,8 +61,7 @@
break
if local_version:
version += '+' + '.'.join(local_version)
-requires = [
- 'ShopifyAPI<12.0.0', 'pyactiveresource', 'python-sql', 'python-dateutil']
+requires = ['ShopifyAPI', 'pyactiveresource', 'python-sql', 'python-dateutil']
for dep in info.get('depends', []):
if not re.match(r'(ir|res)(\W|$)', dep):
requires.append(get_require_version('trytond_%s' % dep))
diff -r 90ea9f496a0b -r c1591e56fd06 stock.py
--- a/stock.py Mon Oct 10 18:51:28 2022 +0200
+++ b/stock.py Mon Oct 10 18:52:53 2022 +0200
@@ -1,12 +1,17 @@
# 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 shopify
+
+from collections import defaultdict
-from trytond.i18n import lazy_gettext
+import shopify
+from shopify.resources.fulfillment import FulfillmentV2
+
+from trytond.i18n import gettext, lazy_gettext
from trytond.model import ModelSQL, ModelView, Unique, fields
from trytond.pool import Pool, PoolMeta
from .common import IdentifierMixin
+from .exceptions import ShopifyError
class ShipmentOut(metaclass=PoolMeta):
@@ -24,21 +29,28 @@
# Fulfillment can not be modified
return
else:
- fulfillment = shopify.Fulfillment(
- prefix_options={'order_id': sale.shopify_identifier})
+ fulfillment = FulfillmentV2()
for shop_warehouse in sale.web_shop.shopify_warehouses:
if shop_warehouse.warehouse == self.warehouse:
- fulfillment.location_id = int(shop_warehouse.shopify_id)
+ location_id = int(shop_warehouse.shopify_id)
break
- line_items = []
+ else:
+ location_id = None
+ fulfillment_orders = shopify.FulfillmentOrders.find(
+ order_id=sale.shopify_identifier)
+ line_items = defaultdict(list)
for move in self.outgoing_moves:
if move.sale == sale:
- line_item = move.get_shopify()
- if line_item:
- line_items.append(line_item)
+ for order_id, line_item in move.get_shopify(
+ fulfillment_orders, location_id):
+ line_items[order_id].append(line_item)
if not line_items:
return
- fulfillment.line_items = line_items
+ fulfillment.line_items_by_fulfillment_order = [{
+ 'fulfillment_order_id': order_id,
+ 'fulfillment_order_line_items': line_items,
+ }
+ for order_id, line_items in line_items.items()]
return fulfillment
def get_shopify_identifier(self, sale):
@@ -116,25 +128,45 @@
def get_shopify(self, sale):
fulfillment = super().get_shopify(sale)
if fulfillment and self.packages:
- fulfillment.tracking_numbers = [
- p.shipping_reference for p in self.packages
- if p.shipping_reference]
- fulfillment.tracking_urls = [
- p.shipping_tracking_url for p in self.packages
- if p.shipping_tracking_url]
+ tracking_info = []
+ for package in self.packages:
+ tracking_info.append({
+ 'number': package.shipping_reference,
+ 'url': package.shipping_tracking_url,
+ })
+ fulfillment.tracking_info = tracking_info
return fulfillment
class Move(metaclass=PoolMeta):
__name__ = 'stock.move'
- def get_shopify(self):
+ def get_shopify(self, fulfillment_orders, location_id):
pool = Pool()
SaleLine = pool.get('sale.line')
Uom = pool.get('product.uom')
- if isinstance(self.origin, SaleLine):
- return {
- 'id': self.origin.shopify_identifier,
- 'quantity': int(Uom.compute_qty(
- self.uom, self.quantity, self.origin.unit)),
- }
+ if not isinstance(self.origin, SaleLine):
+ return
+ identifier = self.origin.shopify_identifier
+ quantity = int(Uom.compute_qty(
+ self.uom, self.quantity, self.origin.unit))
+ for fulfillment_order in fulfillment_orders:
+ if fulfillment_order.assigned_location_id != location_id:
+ continue
+ for line_item in fulfillment_order.line_items:
+ if line_item.line_item_id == identifier:
+ qty = min(quantity, line_item.fulfillable_quantity)
+ qty = quantity
+ yield fulfillment_order.id, {
+ 'id': line_item.id,
+ 'quantity': qty,
+ }
+ quantity -= qty
+ if quantity <= 0:
+ return
+ else:
+ raise ShopifyError(gettext(
+ 'web_shop_shopify.msg_fulfillment_order_line_not_found',
+ quantity=quantity,
+ move=self.rec_name,
+ ))
diff -r 90ea9f496a0b -r c1591e56fd06 web.py
--- a/web.py Mon Oct 10 18:51:28 2022 +0200
+++ b/web.py Mon Oct 10 18:52:53 2022 +0200
@@ -36,7 +36,7 @@
shopify_url = fields.Char("Shop URL", states=_states)
shopify_version = fields.Selection(
'get_shopify_versions', "Version", states=_states)
- shopify_password = fields.Char("Password", states=_states, strip=False)
+ shopify_password = fields.Char("Access Token", states=_states, strip=False)
shopify_webhook_shared_secret = fields.Char(
"Webhook Shared Secret", strip=False,
states={