1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from collections import defaultdict
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):
__name__ = 'stock.shipment.out'
shopify_identifiers = fields.One2Many(
'stock.shipment.shopify_identifier', 'shipment',
lazy_gettext('web_shop_shopify.msg_shopify_identifiers'))
def get_shopify(self, sale):
if self.state != 'done':
return
shopify_id = self.get_shopify_identifier(sale)
if shopify_id:
# Fulfillment can not be modified
return
else:
fulfillment = FulfillmentV2()
for shop_warehouse in sale.web_shop.shopify_warehouses:
if shop_warehouse.warehouse == self.warehouse:
location_id = int(shop_warehouse.shopify_id)
break
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:
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_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):
for record in self.shopify_identifiers:
if record.sale == sale:
return record.shopify_identifier
def set_shopify_identifier(self, sale, identifier=None):
pool = Pool()
Identifier = pool.get('stock.shipment.shopify_identifier')
for record in self.shopify_identifiers:
if record.sale == sale:
if not identifier:
Identifier.delete([record])
return
else:
if record.shopify_identifier != identifier:
record.shopify_identifier = identifier
record.save()
return record
if identifier:
record = Identifier(shipment=self, sale=sale)
record.shopify_identifier = identifier
record.save()
return record
@classmethod
def search_shopify_identifier(cls, sale, identifier):
records = cls.search([
('shopify_identifiers', 'where', [
('sale', '=', sale.id),
('shopify_identifier', '=', identifier),
]),
])
if records:
record, = records
return record
@classmethod
def copy(cls, records, default=None):
if default is None:
default = {}
else:
default = default.copy()
default.setdefault('shopify_identifiers')
return super().copy(records, default=default)
class ShipmentShopifyIdentifier(IdentifierMixin, ModelSQL, ModelView):
"Shopify Shipment Identifier"
__name__ = 'stock.shipment.shopify_identifier'
shipment = fields.Reference("Shipment", [
('stock.shipment.out', "Customer Shipment"),
], required=True)
sale = fields.Many2One('sale.sale', "Sale", required=True)
@classmethod
def __setup__(cls):
super().__setup__()
cls.shopify_identifier_signed.states = {
'required': True,
}
t = cls.__table__()
cls._sql_constraints += [
('shipment_sale_unique',
Unique(t, t.shipment, t.sale, t.shopify_identifier_signed),
'web_shop_shopify.msg_identifier_shipment_sale_unique'),
]
class ShipmentOut_PackageShipping(metaclass=PoolMeta):
__name__ = 'stock.shipment.out'
def get_shopify(self, sale):
fulfillment = super().get_shopify(sale)
if fulfillment and self.packages:
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, fulfillment_orders, location_id):
pool = Pool()
SaleLine = pool.get('sale.line')
Uom = pool.get('product.uom')
if (not isinstance(self.origin, SaleLine)
or not self.origin.shopify_identifier):
return
identifier = self.origin.shopify_identifier
quantity = int(Uom.compute_qty(
self.unit, 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)
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,
))
|