from openerp import api, fields, models import logging import pytz 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=lambda self: fields.Datetime.now(), readonly=True, states={'draft': [('readonly', False)]}) # latest pick-up time latest = fields.Datetime('Latest', required=True, default=lambda self: fields.Datetime.now(), readonly=True, states={'draft': [('readonly', False)]}) # 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) carrier_pickup_number = fields.Char('Carrier Pick-up Number', readonly=True, copy=False) def _shipcloud_api(self): config = self.env['delivery.carrier']._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): def field_to_datetime(self, dtfield): tz_name = self._context.get('tz') or self.env.user.tz tz = pytz.timezone(tz_name) dt = fields.Datetime.from_string(dtfield) return fields.Datetime.context_timestamp(self, dt) # 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(self.address) sc_earliest = field_to_datetime(self, self.earliest).isoformat() sc_latest = field_to_datetime(self, self.latest).isoformat() _logger.info("earliest: %s -> %s" % (self.earliest, sc_earliest)) _logger.info("latest: %s -> %s" % (self.latest, sc_latest)) 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(str(err)) _logger.info("shipcloud response: %s", result) self.sc_pickup_id = result['id'] self.carrier_pickup_number = result['carrier_pickup_number'] 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