From 870281afd02202c8aa45cf4526480854ab50f904 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 15 Mar 2021 21:32:01 +0100 Subject: [PATCH] Add new model for shipment pick-ups Using this model, the user can select a number of pickings and request them to be picked up from a user-specified address. --- __openerp__.py | 4 +- models/__init__.py | 2 +- models/shipcloud.py | 21 ++++++++++ models/shipcloud_pickup.py | 75 ++++++++++++++++++++++++++++++++++++ security/ir.model.access.csv | 2 + views/shipcloud_pickup.xml | 63 ++++++++++++++++++++++++++++++ 6 files changed, 165 insertions(+), 2 deletions(-) create mode 100644 models/shipcloud_pickup.py create mode 100644 security/ir.model.access.csv create mode 100644 views/shipcloud_pickup.xml diff --git a/__openerp__.py b/__openerp__.py index c5a9482..2c5d948 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -3,13 +3,15 @@ 'category': 'Website/Shipping Logistics', 'summary': 'Integrate shipping via shipcloud.io directly within Odoo', 'website': 'https://sysmocom.de/', - 'version': '0.1', + 'version': '0.2', 'description':""" """, 'author': 'Harald Welte', 'depends': ['odoo_shipping_service_apps', 'shipment_packaging'], 'data': [ + 'security/ir.model.access.csv', 'views/sc_delivery_carrier.xml', + 'views/shipcloud_pickup.xml', 'views/res_config.xml', 'data/data.xml', ], diff --git a/models/__init__.py b/models/__init__.py index d1ec237..bdec616 100644 --- a/models/__init__.py +++ b/models/__init__.py @@ -1 +1 @@ -import res_config, shipcloud, shipcloud_delivery_carrier, shipcloud_shipping_service +import res_config, shipcloud, shipcloud_delivery_carrier, shipcloud_shipping_service, shipcloud_pickup diff --git a/models/shipcloud.py b/models/shipcloud.py index 95c8215..26d4651 100644 --- a/models/shipcloud.py +++ b/models/shipcloud.py @@ -115,6 +115,12 @@ class api(object): res = self._transport.rest_delete('/shipments/%s' % shipment_id, None, sandbox) return res + def create_pickup(self, pickup): + # Assume if the user passed a sandbox API key, we use it for create shipment requests + sandbox = True if self._transport._auth_sandbox else False + res = self._transport.rest_post('/pickup_requests', pickup, sandbox) + return res + def gen_customs_item(origin, desc, hts, qty, value, net_weight): """Generate a dict for a customs_declaration.item in accordance with @@ -218,3 +224,18 @@ def gen_quote_req(shipment): sh['package'] = _filter_dict(sh['package'], permitted_pkg_keys) return _filter_dict(sh, permitted_sh_keys) + +def gen_pickup(addr, earliest, latest, shipment_ids, carrier='ups'): + """Generate a dict for a pickup request in accordance with + https://developers.shipcloud.io/reference/pickup_requests_request_schema.html""" + permitted_addr_keys = [ 'company', 'first_name', 'last_name', 'care_of', + 'street', 'street_no', 'city', 'zip_code', 'state', 'country', 'phone' ] + pickup = { + 'carrier': carrier, + 'pickup_time': { + 'earliest': earliest, + 'latest': latest, + }, + 'pickup_address': _filter_dict(addr, permitted_addr_keys) + } + return pickup diff --git a/models/shipcloud_pickup.py b/models/shipcloud_pickup.py new file mode 100644 index 0000000..ef0e536 --- /dev/null +++ b/models/shipcloud_pickup.py @@ -0,0 +1,75 @@ +from openerp import api, fields, models +import logging +from openerp.exceptions import Warning +from shipcloud_delivery_carrier import build_sc_addr + +import shipcloud + +_logger = logging.getLogger(__name__) + + +class SCPickup(models.Model): + _name = "delivery.carrier.pickup" + + # carrier who should be picking up + carrier = fields.Selection([('ups','UPS'), ('dpd','DPD'), ('hermes','Hermes'), ('gls','GLS')], + string='Carrier', required=True, default='ups') + # pickings (shipments) to be picked up + pickings = fields.Many2many('stock.picking', string='Pickings', required=True) + # address from where to pick up + address = fields.Many2one('res.partner', string='Pick-up address', required=True) + # earliest pick-up time + earliest = fields.Datetime('Earliest', required=True, default=fields.Datetime.now()) + # latest pick-up time + latest = fields.Datetime('Latest', required=True) + # draft: not yet requested from shipcloud; confirmed: confirmed by shipcloud + state = fields.Selection([('draft', 'Draft'), ('confirmed', 'Confirmed'), ('done','Done')], + string='Status', default='draft', readonly=True, required=True, copy=False) + sc_pickup_id = fields.Char('Shipcloud Pick-up ID', readonly=True, copy=False) + + + def _shipcloud_api(self): + config = self._get_config() + api_key = config['sc_api_key_prod'] + sandbox_api_key = None if config['sc_api_use_prod'] else config['sc_api_key_sandbox'] + return shipcloud.api(api_key, sandbox_api_key) + + @api.one + def button_request(self): + # consistency check + for p in self.pickings: + if p.carrier_id.delivery_type != 'sc': + raise Warning("Picking %s doesn't use shipcloud" % (p.name)) + if not p.label_genrated: + raise Warning("Picking %s doesn't have a label yet" % (p.name)) + if not p.sc_shipment_id: + raise Warning("Picking %s has not shipcloud label/id" % (p.name)) + # collect the SC shipment IDs of all the pickings + sc_ship_ids = [] + for p in self.pickings: + sc_ship_ids.append({'id': p.sc_shipment_id}) + sc_addr = build_sc_addr(p.address) + sc_earliest = self.earliest.astimezone().isoformat() + _logger.info("earliest: %s -> %s" % (self.earliest, sc_earliest)) + sc_latest = self.latest.astimezone().isoformat() + sc_pickup = shipcloud.gen_pickup(sc_addr, sc_earliest, sc_latest, sc_ship_ids, self.carrier) + # actually use the SC API to request the pickup + api = self._shipcloud_api() + try: + result = api.create_pickup(sc_pickup) + except shipcloud.ApiError as err: + raise Warning(err) + self.sc_pickup_id = result['id'] + self.state = 'confirmed' + + # somehow this didn't work as a new (v8) style ORM ?!? + def default_get(self, cr, user, fields_list, context=None): + if context is None: + context = {} + res = super(SCPickup, self).default_get(cr, user, fields_list, context=context) + if context.get('active_model') == 'stock.picking' and context.get('active_ids'): + picking_ids = context['active_ids'] + res['pickings'] = picking_ids + # intentionally no default pick-up address to avoid the mistakes of + # leaving the default and hence scheduling a pick-up from the wrong address + return res diff --git a/security/ir.model.access.csv b/security/ir.model.access.csv new file mode 100644 index 0000000..55905a6 --- /dev/null +++ b/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +delivery_carrier_pickup,delivery.carrier.pickup all,odoo_shipcloud.model_delivery_carrier_pickup,stock.group_stock_user,1,1,1,0 diff --git a/views/shipcloud_pickup.xml b/views/shipcloud_pickup.xml new file mode 100644 index 0000000..016321a --- /dev/null +++ b/views/shipcloud_pickup.xml @@ -0,0 +1,63 @@ + + + + + delivery.carrier.pickup.form + delivery.carrier.pickup + form + +
+
+
+ +
+

Pick-up request

+
+ + + + + + + + + + + + +
+
+
+
+ + + delivery.carrier.pickup.tree + delivery.carrier.pickup + tree + + + + + + + + + + + + Pick-Up + delivery.carrier.pickup + form + tree,form + + + + + + + + +
+