def generate_stamps_authenticator(self): url = "%s" % (self.stamps_api_url) headers = { 'SOAPAction': "http://stamps.com/xml/namespace/2019/09/swsim/SwsimV84/AuthenticateUser", 'Content-Type': 'text/xml; charset="utf-8"' } master_node = etree.Element('Envelope') master_node.attrib[ 'xmlns'] = "http://schemas.xmlsoap.org/soap/envelope/" submater_node = etree.SubElement(master_node, 'Body') root_node = etree.SubElement(submater_node, "AuthenticateUser") root_node.attrib[ 'xmlns'] = "http://stamps.com/xml/namespace/2019/09/swsim/SwsimV84" shipment_data = etree.SubElement(root_node, "Credentials") etree.SubElement( shipment_data, "IntegrationID").text = "%s" % (self.stamps_integrator_id) etree.SubElement(shipment_data, "Username").text = "%s" % (self.stamps_user_name) etree.SubElement(shipment_data, "Password").text = "%s" % (self.stamps_password) request_data = etree.tostring(master_node) try: _logger.info("Stamps Authenticator Request Data : %s" % (request_data)) result = requests.post(url=url, data=request_data, headers=headers) except Exception as e: raise ValidationError(e) if result.status_code != 200: raise ValidationError( _("Label Request Data Invalid! %s ") % (result.content)) api = Response(result) result = api.dict() if result.get('Envelope') and result.get('Envelope').get( 'Body') and result.get('Envelope').get('Body').get( 'AuthenticateUserResponse') and result.get('Envelope').get( 'Body').get('AuthenticateUserResponse').get( 'Authenticator'): self.stamps_authenticator = result.get('Envelope').get('Body').get( 'AuthenticateUserResponse').get('Authenticator') return { 'effect': { 'fadeout': 'slow', 'message': "Yeah! Shipping Charge has been retrieved.", 'img_url': '/web/static/src/img/smile.svg', 'type': 'rainbow_man', } } else: raise ValidationError("%s" % (result))
def aramex_get_rate_shipment(self, shipper_address, recipient_address, total_weight, description, payment_option): self.ensure_one() try: headers = { "Content-Type": "text/xml; charset=utf-8", "SOAPAction": "http://ws.aramex.net/ShippingAPI/v1/Service_1_0/CalculateRate" } body = self.body_request_for_aramex_rate_calculation( shipper_address, recipient_address, total_weight, description, payment_option) _logger.info("Aramex Rate Requesting Data: %s" % (body)) url = self.get_aramex_url("/RateCalculator/Service_1_0.svc") response_body = request(method='POST', url=url, headers=headers, data=body) if response_body.status_code == 200: api = Response(response_body) results = api.dict() _logger.info("Aramex Rate Response Data : %s" % (results)) product_details = results.get('Envelope', {}).get( 'Body', {}).get('RateCalculatorResponse', {}) or False service_detail = product_details.get('TotalAmount', {}) shipment_charge = service_detail.get('Value', False) notification = product_details.get('Notifications') haserror = product_details.get('HasErrors') if haserror == 'false': return { 'success': True, 'price': float(shipment_charge), 'error_message': False, 'warning_message': False } else: error_details = notification else: error_details = "%s" % (response_body) except Exception as e: error_details = e return { 'success': False, 'price': 0.0, 'error_message': error_details, 'warning_message': False }
def call_lable_api(self, api_name, xml_data): """Call the API from USPS. These method used to calling label genrating API in USPS. Also use this method for cancel request calling. @param: API name and xml data. @return: API response(Give API response.) @author: Jigar v vagadiya on 27 June 2017.""" url = 'https://secure.shippingapis.com/ShippingAPI.dll?' data1 = {'API': api_name, 'xml': xml_data} _logger.info("Request Data : %s" % (data1)) try: response_text = requests.post(url=url, data=data1) api = Response(response_text) result = api.dict() _logger.info("Response Data : %s" % (result)) except Exception as e: raise Warning(e) return result
def stamps_send_shipping(self, pickings): response = [] for picking in pickings: try: request_data = self.stamps_label_request_data(picking) url = "%s" % (self.company_id.stamps_api_url) headers = { 'SOAPAction': "http://stamps.com/xml/namespace/2021/01/swsim/SwsimV111/CreateIndicium", 'Content-Type': 'text/xml; charset="utf-8"' } try: _logger.info("Stamps.com Request Data : %s" % (request_data)) result = requests.post(url=url, data=request_data, headers=headers) except Exception as e: raise ValidationError(e) if result.status_code != 200: raise ValidationError(_("Label Request Data Invalid! %s ") % (result.content)) api = Response(result) result = api.dict() _logger.info("Stamps.com Shipment Response Data : %s" % (result)) res = result.get('Envelope', {}).get('Body', {}).get('CreateIndiciumResponse', {}) if not res: raise ValidationError(_("Error Response %s") % (result)) TrackingNumber = res.get('TrackingNumber') StampsTxID = res.get('StampsTxID') stamps_URL = res.get('URL') Amount = res.get('Rate').get('Amount') message = (_("Label created!<br/> <b>Label Tracking Number : </b>%s<br/> <b> Parcel Number : %s") % ( TrackingNumber, StampsTxID)) picking.message_post(body=message) picking.carrier_tracking_ref = TrackingNumber picking.stamps_label_url = stamps_URL picking.stamps_tx_id = StampsTxID picking.delivery_cost = Amount shipping_data = { 'exact_price': float(Amount) or 0.0, 'tracking_number': TrackingNumber} response += [shipping_data] except Exception as e: raise ValidationError(e) return response
def call_api(self, api_name, xml_data): """Call the rate API from USPS. These method used to calling rate API. @param: API name and XML data. @return: API response(Give API response.) @author: Jigar v vagadiya on 27 June 2017.""" if not self.prod_environment: url = 'http://testing.shippingapis.com/ShippingAPI.dll?' else: url = 'http://production.shippingapis.com/ShippingAPI.dll?' data1 = {'API': api_name, 'xml': xml_data} _logger.info("Request Data : %s" % (data1)) try: response_text = requests.post(url=url, data=data1) api = Response(response_text) result = api.dict() _logger.info("Response Data : %s" % (result)) except Exception as e: raise Warning(e) return result
def stamps_cancel_shipment(self, picking): master_node = etree.Element('Envelope') master_node.attrib['xmlns'] = "http://schemas.xmlsoap.org/soap/envelope/" submater_node = etree.SubElement(master_node, 'Body') root_node = etree.SubElement(submater_node, "CancelIndicium") root_node.attrib['xmlns'] = "http://stamps.com/xml/namespace/2021/01/swsim/SwsimV111" shipment_data = etree.SubElement(root_node, "Credentials") etree.SubElement(shipment_data, "IntegrationID").text = "%s" % ( self.company_id and self.company_id.stamps_integrator_id) etree.SubElement(shipment_data, "Username").text = "%s" % (self.company_id and self.company_id.stamps_user_name) etree.SubElement(shipment_data, "Password").text = "%s" % (self.company_id and self.company_id.stamps_password) etree.SubElement(root_node, "TrackingNumber").text = "%s" % (picking.carrier_tracking_ref) try: request_data = etree.tostring(master_node) url = "%s" % (self.company_id.stamps_api_url) headers = { 'SOAPAction': "http://stamps.com/xml/namespace/2021/01/swsim/SwsimV111/CancelIndicium", 'Content-Type': 'text/xml; charset="utf-8"' } try: _logger.info("Stamps.com Request Data : %s" % (request_data)) result = requests.post(url=url, data=request_data, headers=headers) except Exception as e: raise ValidationError(e) if result.status_code != 200: raise ValidationError(_("Label Request Data Invalid! %s ") % (result.content)) api = Response(result) result = api.dict() if result.get('Envelope').get('Body').get('Fault'): raise ValidationError(result.get('Envelope').get('Body').get('Fault')) else: _logger.info("Stamps.com cancel Shipment Response Data : %s" % (result)) except Exception as e: raise ValidationError(e)
def aramex_get_status(self): self.ensure_one() root_node = etree.Element("Envelope") root_node.attrib['xmlns'] = "http://schemas.xmlsoap.org/soap/envelope/" picking_company_id = self.company_id body = etree.SubElement(root_node, "Body") shipment_tracking_request = etree.SubElement( body, "ShipmentTrackingRequest") shipment_tracking_request.attrib[ 'xmlns'] = "http://ws.aramex.net/ShippingAPI/v1/" client_info = etree.SubElement(shipment_tracking_request, "ClientInfo") etree.SubElement( client_info, "UserName").text = self.carrier_id.aramex_username or '' etree.SubElement( client_info, "Password").text = self.carrier_id.aramex_password or '' etree.SubElement(client_info, "Version").text = self.carrier_id.aramex_version or '' etree.SubElement( client_info, "AccountNumber").text = self.carrier_id.aramex_account_number or '' etree.SubElement( client_info, "AccountPin").text = self.carrier_id.aramex_account_pin or '' etree.SubElement( client_info, "AccountEntity").text = self.carrier_id.aramex_account_entity or '' etree.SubElement( client_info, "AccountCountryCode" ).text = picking_company_id.country_id and picking_company_id.country_id.code or '' transaction = etree.SubElement(shipment_tracking_request, "Transaction") etree.SubElement(transaction, "Reference1").text = "" etree.SubElement(transaction, "Reference2").text = "" etree.SubElement(transaction, "Reference3").text = "" etree.SubElement(transaction, "Reference4").text = "" etree.SubElement(transaction, "Reference5").text = "" shipmets = etree.SubElement(shipment_tracking_request, "Shipments") etree.SubElement( shipmets, "string", attrib={ "xmlns": "http://schemas.microsoft.com/2003/10/Serialization/Arrays" }).text = "%s" % self.carrier_tracking_ref etree.SubElement(shipment_tracking_request, "GetLastTrackingUpdateOnly").text = "true" body = etree.tostring(root_node).decode('utf-8') try: headers = { "Content-Type": "text/xml; charset=utf-8", "SOAPAction": "http://ws.aramex.net/ShippingAPI/v1/Service_1_0/TrackShipments" } _logger.info("aramex Tracking Requesting Data: %s" % body) url = "http://ws.aramex.net/ShippingAPI.V2/Tracking/Service_1_0.svc" response_body = request(method='POST', url=url, headers=headers, data=body) if response_body.status_code == 200: api = Response(response_body) results = api.dict() _logger.info("Aramex Tracking Response Data : %s" % results) response_details = results.get("Envelope", {}).get( "Body", {}).get("ShipmentTrackingResponse", {}) if response_details and response_details.get( "TrackingResults", {}): response_status = response_details.get( "TrackingResults", {}).get( "KeyValueOfstringArrayOfTrackingResultmFAkxlpY", {}).get("Value", {}).get("TrackingResult", {}).get("UpdateDescription", {}) _logger.info( "======Aramex Status === {}".format(response_status)) return response_status else: raise Warning(response_body.text) except Exception as e: raise Warning(e)
def dhl_de_ept_cancel_shipment(self, pickings): """ Cancel the shipment order when click on cancel button. @param @return: Cancel the shipment request. @author: Jigar v Vagadiya on 21-july-2017. """ for picking in pickings: url = self.get_url() root_node = etree.Element("soapenv:Envelope") root_node.attrib[ 'xmlns:soapenv'] = "http://schemas.xmlsoap.org/soap/envelope/" root_node.attrib['xmlns:cis'] = "http://dhl.de/webservice/cisbase" root_node.attrib[ 'xmlns:bus'] = "http://dhl.de/webservices/businesscustomershipping" header_node = etree.SubElement(root_node, "soapenv:Header") authentification_node = etree.SubElement(header_node, "cis:Authentification") etree.SubElement(authentification_node, "cis:user").text = str( self.shipping_instance_id.userid) etree.SubElement(authentification_node, "cis:signature").text = str( self.shipping_instance_id.password) shipment_body_node = etree.SubElement(root_node, "soapenv:Body") shipment_order_node = etree.SubElement( shipment_body_node, "bus:DeleteShipmentOrderRequest") version_node = etree.SubElement(shipment_order_node, "bus:Version") etree.SubElement(version_node, "majorRelease").text = "" etree.SubElement(version_node, "minorRelease").text = "" tracking_no_lists = str(picking.carrier_tracking_ref) tracking_nos = tracking_no_lists.split(',') for tracking_no in tracking_nos: if tracking_no: etree.SubElement( shipment_order_node, "cis:shipmentNumber").text = str(tracking_no) headers = { "Content-Type": "application/soap+xml;charset=UTF-8", "SOAPAction": "urn:createShipmentOrder", 'Content-Length': str(len(etree.tostring(root_node))), } try: result = requests.post( url=url, data=etree.tostring(root_node), headers=headers, auth=HTTPBasicAuth( str(self.shipping_instance_id.http_userid), str(self.shipping_instance_id.http_password))) except Exception as e: raise Warning(_(e)) if result.status_code != 200: error = "Error Code : %s - %s" % (result.status_code, result.reason) raise Warning(_(error)) api = Response(result) result = api.dict() fault_res = result.get('Envelope', {}).get('Body', {}).get('Fault', {}) if fault_res: response_code = fault_res.get('faultcode') status_message = fault_res.get('faultstring') error = "Error Code : %s - %s" % (response_code, status_message) if response_code != "0": raise Warning(_(error)) check_data = result.get('Envelope', {}).get('Body', {}).get( 'DeleteShipmentOrderResponse', {}) response_code = check_data.get('Status', {}).get('statusCode') status_message = check_data.get('Status', {}).get('statusMessage', {}) error_msg = check_data.get('Status', {}).get('statusText') response_detail = result.get('Envelope', {}).get('Body', {}).get( 'DeleteShipmentOrderResponse', {}) if isinstance(response_detail, dict): response_detail = [response_detail] for detail in response_detail: creation_detail = detail.get('DeletionState', {}) if isinstance(creation_detail, dict): creation_detail = [creation_detail] for cdetail in creation_detail: status = cdetail.get('Status', {}) status_code = status.get('statusCode', {}) status_message = cdetail.get('shipmentNumber') message = (_("Shipment cancelled : %s ") % (status_message)) msg = "Error : %s" % (result) if status_code != "0": raise Warning(_(msg)) picking.message_post(body=message) error = "Error Code : %s - %s - %s" % (response_code, status_message, error_msg) if response_code != "0": raise Warning(_(error))
def dhl_de_ept_send_shipping(self, pickings): """ Generate the Lable of perticular shipping service for DHL @param :picking Detail @return: Lable(final data pass in to DHL). @author: Emipro Technologies Pvt Ltd """ response = [] res_country_group = self.env['res.country.group'] context = self._context to_address = context.get('WizardSendToShip_id', False) if to_address: for picking in pickings: self.check_instance_state() self.check_appropriate_data(picking) url = self.get_url() total_bulk_weight = self.convert_weight( picking.weight_uom_id, self.weight_uom_id, picking.weight_bulk) root_node = etree.Element("soapenv:Envelope") root_node.attrib[ 'xmlns:soapenv'] = "http://schemas.xmlsoap.org/soap/envelope/" root_node.attrib[ 'xmlns:cis'] = "http://dhl.de/webservice/cisbase" root_node.attrib[ 'xmlns:bus'] = "http://dhl.de/webservices/businesscustomershipping" header_node = etree.SubElement(root_node, "soapenv:Header") authentification_node = etree.SubElement( header_node, "cis:Authentification") etree.SubElement(authentification_node, "cis:user").text = str( self.shipping_instance_id.userid) etree.SubElement(authentification_node, "cis:signature").text = str( self.shipping_instance_id.password) shipment_body_node = etree.SubElement(root_node, "soapenv:Body") shipment_order_node = etree.SubElement( shipment_body_node, "bus:CreateShipmentOrderRequest") version_node = etree.SubElement(shipment_order_node, "bus:Version") etree.SubElement(version_node, "majorRelease").text = "" etree.SubElement(version_node, "minorRelease").text = "" for package in picking.package_ids: product_weight = self.convert_weight( picking.weight_uom_id, self.weight_uom_id, package.shipping_weight) self.api_attribute_formater(picking, to_address, product_weight, package, shipment_order_node) if total_bulk_weight: self.api_attribute_formater(picking, to_address, total_bulk_weight, 1, shipment_order_node) headers = { "Content-Type": "application/soap+xml;charset=UTF-8", "SOAPAction": "urn:createShipmentOrder", 'Content-Length': str(len(etree.tostring(root_node))), } try: _logger.info( "DHL Request URL : %s\n DHL Request Header: %s\n DHL Request Data : %s " % (url, headers, etree.tostring(root_node))) result = requests.post( url=url, data=etree.tostring(root_node), headers=headers, auth=HTTPBasicAuth( str(self.shipping_instance_id.http_userid), str(self.shipping_instance_id.http_password))) except Exception as e: raise Warning(_(e)) if result.status_code != 200: error = "Error Code : %s - %s" % (result.status_code, result.reason) raise Warning(_(error)) # Todo : For Domestic shipment Multiple package is supported and For International shipment need to varify. - jigarv api = Response(result) result = api.dict() self.check_error_in_response(result) final_tracking_no = [] label_data = result.get('Envelope', {}).get('Body', {}).get( 'CreateShipmentOrderResponse', {}) if label_data: _logger.info("DHL Response Data : %s" % (result)) if isinstance(label_data, dict): label_data = [label_data] for detail in label_data: creation_detail = detail.get('CreationState', {}) if isinstance(creation_detail, dict): creation_detail = [creation_detail] for cdetail in creation_detail: tracking_no = cdetail.get('LabelData', {}).get('shipmentNumber') binary_data = cdetail.get('LabelData', {}).get('labelData') exportlabeldata = cdetail.get( 'LabelData', {}).get('exportLabelData') label_binary_data = binascii.a2b_base64( str(binary_data)) message_ept = (_( "Shipment created!<br/> <b>Shipment Tracking Number : </b>%s" ) % (tracking_no)) if exportlabeldata: exportbinarydata = binascii.a2b_base64( str(exportlabeldata)) picking.message_post( body=message_ept, attachments=[('DHL Label-%s.%s' % (tracking_no, "pdf"), label_binary_data), ('DHL ExportLabel -%s.%s' % (tracking_no, "pdf"), exportbinarydata)]) else: picking.message_post(body=message_ept, attachments=[ ('DHL Label-%s.%s' % (tracking_no, "pdf"), label_binary_data) ]) final_tracking_no.append(tracking_no) shipping_data = { 'exact_price': picking.sale_id and picking.sale_id.delivery_price or 0.0, 'tracking_number': ",".join(final_tracking_no) } response += [shipping_data] return response else: raise Warning("Enter recipient Address!")
def aramex_return_send_shipping(self, sale_ids): self.ensure_one() response = [] for sale_id in sale_ids: payment_option = self.aramex_payment_options total_value = 0.0 total_bulk_weight = 10 # picking.weight_bulk list_name = [] picking_company_id = sale_id.partner_id picking_partner_id = sale_id.company_id cCity = picking_company_id.city # text = "aweer wqمرحباмир" final_city = "" for t in cCity.split(): result = regex.sub(u'[^\p{Latin}]', u'', t) if final_city: final_city = final_city + " " + result else: final_city = result picking_company_id.city = final_city extra_price = 0.0 try: headers = { "Content-Type": "text/xml; charset=utf-8", "SOAPAction": "http://ws.aramex.net/ShippingAPI/v1/Service_1_0/CreateShipments" } if not sale_id.picking_ids[0]: raise Warning("Delivery Order not found") return_shipment = True body = self.body_request_for_aramex_send_shipping( sale_id.picking_ids[0], picking_company_id, picking_partner_id, total_value, total_bulk_weight, extra_price, payment_option, return_shipment) _logger.info("aramex Shipment Requesting Data: %s" % (body)) url = self.get_aramex_url("/Shipping/Service_1_0.svc") response_body = request(method='POST', url=url, headers=headers, data=body) if response_body.status_code == 200: api = Response(response_body) results = api.dict() _logger.info("aramex Shipment Response Data : %s" % (results)) product_details = results.get('Envelope', {}).get( 'Body', {}) and results.get('Envelope', {}).get( 'Body', {}).get('ShipmentCreationResponse', {}) or False processed_shipment = product_details and product_details.get( 'Shipments', {}) and product_details.get( 'Shipments', {}).get('ProcessedShipment', {}) or False haserror = product_details and product_details.get( 'HasErrors') final_tracking_no = [] if haserror == 'false' and processed_shipment: if isinstance(processed_shipment, dict): processed_shipment = [processed_shipment] for detail in processed_shipment: label_detail = detail.get( 'ShipmentLabel', {}) and detail.get( 'ShipmentLabel', {}).get( 'LabelFileContents', {}) tracking_no = detail.get('ID', {}) if detail.get('ShipmentAttachments', {}): commercial_invloce = detail.get( 'ShipmentAttachments', {}) and detail.get( 'ShipmentAttachments', {}).get( 'ProcessedShipmentAttachment', {} ) and detail.get( 'ShipmentAttachments', {}).get( 'ProcessedShipmentAttachment', {}).get('Url', {}) if commercial_invloce: pdf_converter = binascii.a2b_base64( (base64.b64encode( requests.get(commercial_invloce). content)).decode('utf-8')) mesage_obj = ( "Commercial Invoice Generated ") if sale_id: sale_id.message_post( body=mesage_obj, attachments= [('Aramex Commercial Invoice_%s.pdf' % (tracking_no), pdf_converter)]) form_binary_data = binascii.a2b_base64( str(label_detail)) label = label_detail sale_id.return_label_attachment_id = self.env[ 'ir.attachment'].create({ 'datas': label, 'name': 'return_lable_{}.pdf'.format(tracking_no), 'datas_fname': 'return_lable_{}.pdf'.format(tracking_no) }) mesage_obj = (_( "Shipment created!<br /> <b>Shipment Tracking Number : </b>%s" ) % (tracking_no)) if sale_id: sale_id.message_post( body=mesage_obj, attachments=[ ('Aramex Label Form_%s.pdf' % (tracking_no), form_binary_data) ]) final_tracking_no.append(tracking_no) shipping_data = { 'exact_price': extra_price, 'tracking_number': ','.join(final_tracking_no) } if tracking_no: sale_id.return_carrier_id = self.id sale_id.return_tracking_ref = final_tracking_no[ 0] else: raise Warning("%s" % response_body.text) response = [shipping_data] return response else: raise Warning(results) else: raise Warning(response_body.text) except Exception as e: raise Warning(e)
def Aramex_send_shipping(self, pickings): self.ensure_one() response = [] for picking in pickings: if picking.sale_id.eg_magento_payment_method_id.code in [ 'cod', 'COD' ]: payment_option = "CASH" else: payment_option = self.aramex_payment_options # for line in picking.move_line_ids: # if not line.product_id.weight and line.product_id.type != "service": # raise Warning("please enter weight for product: %s" % str(line.product_id.name)) total_value = 0.0 if picking.sale_id.eg_magento_payment_method_id.code in [ 'cod', 'COD' ]: if not picking.invoice_id: raise Warning("Invoice not found!!!") total_value = picking.invoice_id.amount_total total_weight = picking.shipping_weight # total_value = sum([(line.product_uom_qty * line.product_id.list_price) for line in picking.move_lines]) total_bulk_weight = 10 # picking.weight_bulk list_name = [] for product_list in picking.move_lines: list_name.append(product_list.product_id.name) product_name = ','.join(list_name) picking_partner_id = picking.partner_id picking_company_id = picking.company_id cCity = picking_partner_id.city # text = "aweer wqمرحباмир" final_city = "" for t in cCity.split(): result = regex.sub(u'[^\p{Latin}]', u'', t) if final_city: final_city = final_city + " " + result else: final_city = result picking_partner_id.city = final_city # if picking.carrier_id.free_over and self.sale_id: extra_price = 0.0 # elif self.is_fixed_price: # extra_price = self.fixed_amount # else: # res = self.aramex_get_rate_shipment(picking_company_id, picking_partner_id, total_weight, product_name, # payment_option) # extra_price = res.get('price') if res.get('success') else 0.0 try: headers = { "Content-Type": "text/xml; charset=utf-8", "SOAPAction": "http://ws.aramex.net/ShippingAPI/v1/Service_1_0/CreateShipments" } body = self.body_request_for_aramex_send_shipping( picking, picking_company_id, picking_partner_id, total_value, total_bulk_weight, extra_price, payment_option) _logger.info("aramex Shipment Requesting Data: %s" % (body)) url = self.get_aramex_url("/Shipping/Service_1_0.svc") response_body = request(method='POST', url=url, headers=headers, data=body) if response_body.status_code == 200: api = Response(response_body) results = api.dict() _logger.info("aramex Shipment Response Data : %s" % (results)) product_details = results.get('Envelope', {}).get( 'Body', {}) and results.get('Envelope', {}).get( 'Body', {}).get('ShipmentCreationResponse', {}) or False processed_shipment = product_details and product_details.get( 'Shipments', {}) and product_details.get( 'Shipments', {}).get('ProcessedShipment', {}) or False haserror = product_details and product_details.get( 'HasErrors') final_tracking_no = [] if haserror == 'false' and processed_shipment: if isinstance(processed_shipment, dict): processed_shipment = [processed_shipment] for detail in processed_shipment: label_detail = detail.get( 'ShipmentLabel', {}) and detail.get( 'ShipmentLabel', {}).get( 'LabelFileContents', {}) tracking_no = detail.get('ID', {}) if detail.get('ShipmentAttachments', {}): commercial_invloce = detail.get( 'ShipmentAttachments', {}) and detail.get( 'ShipmentAttachments', {}).get( 'ProcessedShipmentAttachment', {} ) and detail.get( 'ShipmentAttachments', {}).get( 'ProcessedShipmentAttachment', {}).get('Url', {}) if commercial_invloce: pdf_converter = binascii.a2b_base64( (base64.b64encode( requests.get(commercial_invloce). content)).decode('utf-8')) mesage_obj = ( "Commercial Invoice Generated ") if picking.sale_id: picking.sale_id.message_post( body=mesage_obj, attachments= [('Aramex Commercial Invoice_%s.pdf' % (tracking_no), pdf_converter)]) picking.message_post( body=mesage_obj, attachments=[ ('Aramex Commercial Invoice_%s.pdf' % (tracking_no), pdf_converter) ]) form_binary_data = binascii.a2b_base64( str(label_detail)) mesage_obj = (_( "Shipment created!<br /> <b>Shipment Tracking Number : </b>%s" ) % (tracking_no)) if picking.sale_id: picking.sale_id.message_post( body=mesage_obj, attachments=[ ('Aramex Label Form_%s.pdf' % (tracking_no), form_binary_data) ]) picking.message_post( body=mesage_obj, attachments=[('Aramex Label Form_%s.pdf' % (tracking_no), form_binary_data) ]) final_tracking_no.append(tracking_no) shipping_data = { 'exact_price': extra_price, 'tracking_number': ','.join(final_tracking_no) } response = [shipping_data] return response else: raise Warning(results) else: raise Warning(response_body.text) except Exception as e: raise Warning(e)
def stamps_rate_shipment(self, orders): for order in orders : order_lines_without_weight = order.order_line.filtered( lambda line_item: not line_item.product_id.type in ['service', 'digital'] and not line_item.product_id.weight and not line_item.is_delivery) for order_line in order_lines_without_weight: return {'success': False, 'price': 0.0, 'error_message': "Please define weight in product : \n %s" % (order_line.product_id.name), 'warning_message': False} # Shipper and Recipient Address sender_id = order.warehouse_id.partner_id receiver_id = order.partner_shipping_id # check sender Address if not sender_id.zip or not sender_id.city or not sender_id.country_id: return {'success': False, 'price': 0.0, 'error_message': "Please Define Proper Sender Address!", 'warning_message': False} # check Receiver Address if not receiver_id.zip or not receiver_id.city or not receiver_id.country_id: return {'success': False, 'price': 0.0, 'error_message': "Please Define Proper Recipient Address!", 'warning_message': False} total_weight = sum([(line.product_id.weight * line.product_uom_qty) for line in order.order_line]) or 0.0 pound_for_kg = 2.20462 uom_id = self.env['product.template']._get_weight_uom_id_from_ir_config_parameter() if uom_id.name == 'lb': weight_lb = round(total_weight, 3) else: weight_lb = round(total_weight * pound_for_kg, 3) # pound_for_kg = 2.20462 # ounce_for_kg = 35.274 # WeightLb = round(total_weight * pound_for_kg, 3) # WeightOz = round(total_weight * ounce_for_kg, 3) master_node = etree.Element('Envelope') master_node.attrib['xmlns'] = "http://schemas.xmlsoap.org/soap/envelope/" submater_node = etree.SubElement(master_node, 'Body') root_node = etree.SubElement(submater_node, "GetRates") root_node.attrib['xmlns'] = "http://stamps.com/xml/namespace/2021/01/swsim/SwsimV111" # etree.SubElement(root_node, "Authenticator").text = self.company_id and self.company_id.stamps_authenticator shipment_data = etree.SubElement(root_node, "Credentials") etree.SubElement(shipment_data, "IntegrationID").text = "%s" % ( self.company_id and self.company_id.stamps_integrator_id) etree.SubElement(shipment_data, "Username").text = "%s" % ( self.company_id and self.company_id.stamps_user_name) etree.SubElement(shipment_data, "Password").text = "%s" % ( self.company_id and self.company_id.stamps_password) shipment_data = etree.SubElement(root_node, "Rate") from_tag = etree.SubElement(shipment_data, "From") etree.SubElement(from_tag, "State").text = "%s" % (sender_id.state_id.code) etree.SubElement(from_tag, "ZIPCode").text = "%s" % (sender_id.zip) etree.SubElement(from_tag, "Country").text = "%s" % (sender_id.country_id.code) to_tag = etree.SubElement(shipment_data, "To") etree.SubElement(to_tag, "Country").text = "%s" % (receiver_id.country_id.code) etree.SubElement(shipment_data, "WeightLb").text = "%s" % (int(weight_lb)) etree.SubElement(shipment_data, "PackageType").text = "%s" % (self.stamps_package_type) current_date = datetime.strftime(datetime.now(pytz.utc), "%Y-%m-%d") # '2020-10-01' etree.SubElement(shipment_data, "ShipDate").text = current_date etree.SubElement(root_node, 'Carrier') request_data = etree.tostring(master_node) url = "%s" % (self.company_id.stamps_api_url) stamp_shipping_charge_obj = self.env['stamp.shipping.charge'] headers = { 'SOAPAction': "http://stamps.com/xml/namespace/2021/01/swsim/SwsimV111/GetRates", 'Content-Type': 'text/xml; charset="utf-8"' } try: _logger.info("Stamps.com Request Data : %s" % (request_data)) result = requests.post(url=url, data=request_data, headers=headers) except Exception as e: return {'success': False, 'price': 0.0, 'error_message': e, 'warning_message': False} if result.status_code != 200: return {'success': False, 'price': 0.0, 'error_message': "Rate Request Data Invalid! %s " % result.content, 'warning_message': False} api = Response(result) result = api.dict() _logger.info("Stamps.com Rate Response Data : %s" % (result)) existing_records = stamp_shipping_charge_obj.sudo().search([('sale_order_id', '=', order and order.id)]) existing_records.sudo().unlink() res = result.get('Envelope', {}).get('Body', {}).get('GetRatesResponse', {}).get('Rates', {}).get('Rate', {}) if res: if isinstance(res, dict): res = [res] for rate in res: _logger.info("In for Loop") stamp_service_name = rate.get('ServiceType') stamp_service_charge = rate.get('Amount') stamp_service_shipping_day = rate.get('DeliverDays') stamp_shipping_charge_obj.sudo().create( {'stamp_service_name': stamp_service_name, 'stamp_service_rate': stamp_service_charge, 'stamp_service_delivery_date': stamp_service_shipping_day, 'sale_order_id': order and order.id, } ) stamp_service_charge_id = stamp_shipping_charge_obj.sudo().search( [('sale_order_id', '=', order and order.id)], order="stamp_service_rate", limit=1) order.stamp_shipping_charge_id = stamp_service_charge_id and stamp_service_charge_id.id return {'success': True, 'price': stamp_service_charge_id and stamp_service_charge_id.stamp_service_rate or 0.0, 'error_message': False, 'warning_message': False} # if rate.get('Rate').get('ServiceType') == self.stam_service_info and rate.get('Rate').get('PackageType') == self.stamps_package_type: # Amount = rate.get('Rate').get('Amount') # return {'success': True, 'price':float(Amount), 'error_message': False, 'warning_message': False} # else: # return {'success': False, 'price':0.0, 'error_message': "Error in rate response : %s "%(res), 'warning_message': False} if not res: return {'success': False, 'price': 0.0, 'error_message': "Error Response %s" % (result), 'warning_message': False}
def generate_delivery_method_report(self): """ generate delivery method report as selected date wise..... @param @return: Set the Date and genrate the report. @author: Jigar v Vagadiya on dated 29-July-2017. """ url = "https://cig.dhl.de/services/production/soap" context = self._context context.get('active_ids') shipping_active_id = self.env['shipping.instance.ept'].browse( context['active_ids'])[0] root_node = etree.Element("soapenv:Envelope") root_node.attrib[ 'xmlns:soapenv'] = "http://schemas.xmlsoap.org/soap/envelope/" root_node.attrib['xmlns:cis'] = "http://dhl.de/webservice/cisbase" root_node.attrib[ 'xmlns:bus'] = "http://dhl.de/webservices/businesscustomershipping" header_node = etree.SubElement(root_node, "soapenv:Header") authentification_node = etree.SubElement(header_node, "cis:Authentification") etree.SubElement(authentification_node, "cis:user").text = str(shipping_active_id.userid) etree.SubElement(authentification_node, "cis:signature").text = str( shipping_active_id.password) shipment_body_node = etree.SubElement(root_node, "soapenv:Body") shipment_order_node = etree.SubElement(shipment_body_node, "bus:GetManifestRequest") version_node = etree.SubElement(shipment_order_node, "bus:Version") etree.SubElement(version_node, "majorRelease").text = "2.2" etree.SubElement(version_node, "minorRelease").text = "2.1" etree.SubElement(shipment_order_node, "manifestDate").text = str(self.date) headers = { "Content-Type": "application/soap+xml;charset=UTF-8", "SOAPAction": "urn:createShipmentOrder", 'Content-Length': str(len(etree.tostring(root_node))), } # print(etree.tostring(root_node)) try: result = requests.post(url=url, data=etree.tostring(root_node), headers=headers, auth=HTTPBasicAuth( str(shipping_active_id.http_userid), str(shipping_active_id.http_password))) except Exception as e: raise Warning(e) if result.status_code != 200: error = "Error Code : %s - %s" % (result.status_code, result.reason) raise Warning(_(error)) api = Response(result) result = api.dict() fault_res = result.get('Envelope', {}).get('Body', {}).get('Fault', {}) if fault_res: response_code = fault_res.get('faultcode') status_message = fault_res.get('faultstring') error = "Error Code : %s - %s" % (response_code, status_message) if response_code != "0": raise Warning(_(error)) check_data = result.get('Envelope', {}).get('Body', {}).get('GetManifestResponse', {}) response_code = check_data.get('Status', {}).get('statusCode') status_message = check_data.get('Status', {}).get('statusMessage', {}) error_msg = check_data.get('Status', {}).get('statusText') error = "Error Code : %s - %s - %s" % (response_code, status_message, error_msg) if response_code != "0": raise Warning(_(error)) lable_data = check_data.get('manifestData') # lable_data='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 / hgaKeTOv2wDjVkVSYP6jF6spTOlEgJW3IMtrBtzCuIQ5ZqqENGtSN1EeIkElKjfgUx3xPqDuqXul + h5shV3eVLx9d9Q2qVox7V3SwrSO2opilREuPri6uzQDWuIFLUuwS51qg22A8yTJoralxALF88A7MdqmX + qHpaXQYanPb3MW / s37bj6R1YB / aUN + aLZ7uQoyeTxS9XwpP6Fx0U1Hz0eBT + bUc5Gp5KA + o / ksIc / c / +0 j0LXqDaiq7U1xazAlBbU / pD3nTU1uCEF4EPaewPsRfvxQmkdrhuHKr / S7QJ1c6Uvqc3uaplURvse7rUcpqLfj5QB5F9Q3WI7TIkBnggUj9fKNljjzuZkjMoUtnKS6vzU3PKprrCd0PHQ7xYFcJjBaxmNatZzWpWs5rVrGY1q1nNalazmtWsZjWrWc1qVrOa1axmNatZzWpWs5rVrGY1q1nNalazmtWsZjWrWc1qVrOa1axmNatZzWpWs5rVrGY1q1nNalazmtWsZjWrWc1qVrOa1axmNatZ / e + tdptU226F6qg / qT77mpmfUgezVPfNg0vlbETtNqfG9VVvWX0qtdlX7x6ou9WpH9Zz16uv + f591HJ7atdmtQE11CH2nc5C5YAr5pMa7vQitEmYHCUcje9ljq1r1qUWr1QSTQ6vFS473tOdJN6YgB9FoBovgXLGC6ofo05CqAhPDN8XtaY7QhhPlwQTUF + D + kqc7 + Jgx6jjoP5upvZVbUktVqiWTsXWdlggctB4mSooFRrUEJXYd0WNF6Mxa1IHFdQf2Y1qg3eccebX3GTRodpm33dhXWqNl5EBNVbUAS / mg + oWdy2oKQ6x3VkX1D9G7Q2qfRuwoo4Kr5GNTlRbLCOkvj0if7iMWj + qdnjBiJWp26rGEpBkKOpc1LKqr9epdqO6wztFLaraozqsSu1Q7cRMDXcEqoVIVW2wlVyfWlR130AOIIo6LdRufeo0U9MFP1EdRnX4QQ + XKFqTOs7Vsar9pP5W9ytUB13rkCxcxjuohmNyUL / SScb1qc2ovs14h9TdoI5fm6TWV / Nh5Taq8Q7WfDaPaoFR1sraxjBT26aoIX6yY9uYRLs + tZ + rZVXbqhYrVWunsNEuaodqOA5bAWrRi76oO4wNVxWpQi4DhXhQKyzRLWRexl6JLD6gGuhQ9ten / lbM1HCH1G9BLYoak / VVqaP4RqG8qD1GHPAxxI + G5JijoxoazGZN6iS + B / WPg1pnuiN + BrWt6oxdDd + sSt2Lt7C / f5nUeCcKqEkayB6bqu7F69WoPfU9gbyJVQ01Bd7pJTU + UJWTGlIZe7UiNd6C / G / 9 rLeD7oC1jbluhkT4n / nPK1H / xbVVfeADzTttznthsE + obelPOth + uJn6zNfM / KQaksR / 5 QPtxz + yXbEay0fnHvbP3Od5F + qZrz75KTVWC / FQv6Nf / GZcldqpI9VmTepCOvQk7AWeN0YrVDeH1OqxWnAd6nwomOsXpWaN6tX9sJrVrGY1q1nNalavVp1qnoXXxi7pY39w9kov9IrUqE2yoEoi4A / 6 wsNXSvJS6iSKOtFUJ3qyE / JgXvxQ3VxK7VAdJeQzKKeycbjvVKxOHWQOXzc5foX5Sy8O / c6hrVFcVO1l9kZASovdTUkcOhyhJM0nOO8urLZV3docWkwPobjYh1libHKa3W3KAXop9d9Q7SROGepCi1NDgsoHuqLCssusqrtL1XyotjgU6tqq1vnAZLK9 / ss1qL8CNQ0y0jQcfaiL1R9Q + 58 uqe7 / VNRlX8OODjg0g0UZ2x6c7ll75xtP89BwziIWGO / apHIsc9POr / 5 WZpoOYlANhToq7CL2osNa3L / Fl6Ci3kDpx8EwWdW + hfYp4LYLqNOg1jgVH2o / mprT4ZwiaHD8G9HVLvjGdpY + SlE7b3pU2xcv38eo4w8SCmowUWKVTGpoVABjSP0jtj1FLTqc / DKob0ENj + eXn8B6jDq8r + pmV9RJJvFzJ6DEdDTNdlALcdXgtL + 7 SAHWLhj4Pd83 / hJqf1XUicImLDISmpqrJup / 4 lHaoNiWCOWjxBkvtQ65hqNWZJfki / cTH6Xui7qn772oIQKUOKwBakXTEUkNdUacqXHCeb7FbRdQu6rOkxr2YlKJ5tx6Pak7nCQyqvGz2Xx7gokjx6h3vezLvm4Oqc2kzqQ2Va1Q3V1fSC2rOtGTi9pM6nZUN0Wti7rHJ1xOrWoJid9gxUtqj00Nqu1SHUAYmqrWCaOu63ARda + rOvwg2plaiNJELtRCaAyaJnWLU0suoIaCIfAkDagcrKn1dVX3YlS3ozoKQ + qkE05Hu7iaxnjn6jiq3aTGxJjUmGD6Hy6thrxA1xa9qsMhNXZA1CFhVOsLqmmCJw08j2o6ecbtqdHnmkENueYPp5gw9wVqM1O3o9pM6jBXvzKXUUNtULKCoqasgOprOgGlqktWUGYB9ILUEIzbHF + ZeFm1pQkVlIFh2ygXal3UlPRWdQe / jNNu1cXU6HMd7jbKdh + oKUd / oIbfEO061NizgDEfnpneDW0j5oZdUzskixoSH4fTbk / QSXmsGstHmV8LSa5tI / ay5t9dO9R8ESInVDf5H / 8 ANb6qz6TucNul1IZOJDDYeHwEiUidMMq9HtRJGNth0v5ee5rdTEsE0GRh3Hb2fj5BasoQxdg7WfJGBVt0UeNWUOOJHHTWo6KT7SFxFF0 + fyszqLEPIcx6gilHB / VPVZ2r2i7UGJPTtgupMbiIQ6 + 7 yqU / BFp0P6jxiXh8olrTfKkd1Tcin + D0n2PVGQK5vgwSBIH1M / Z7aExqqjqU6CNgd0NLFeH1oKZfOO / ROPK72mxj5QE38M + 7 nP8yDDaNM4puaHte9CXc5EupV / XDalazmtWsZjWrWc1qVrOa1axelxr7Us98Wt0LqLFbNMl / E7XrZl + HWJOaBhIPqGmwY6Z251vF7Bh1e5zarmpO8PFqtSI19dEdpZZbUc / u36RmPer + KfX857 / 7 Van1cWpa1ZbVz1GnbzapxnU97VuV3WuZyyTUHLFBKXUITVLFWSMrU + MaquIble3XuAopTkLNHo / Qqn6L42Fqber4ms6CwFk3uAopzad1M / UbHHuUq1O / kzR / JaG6TEIF / KT + UbT1dPU11Xw4RxXXU02Nl32ZhJrt1aTGD6LXp75qMq6nGmWUaT4JtaobXKHU0hGwohY9dDRJT0WV5GISalUrb3C6y8rUHucqG1yfD9ffm01CrWqNU5 / cEIOvRp331KZWFlVtRnVYUXztaO4QrppU1XjqXTep21F9vrWNP62 + LYsGknqYhEpLXExqW9SuXZfa0XJUoK6TUK1cqssEDLuibHcHKdhcjZNQ6UySB + pmRWogLdQ4T8TPoqdR3csVqcWeGiehxlmLPqqTWpfajOo6CZUyhfnReDjeXpN6qET21WddhegT6l7RGaRFPUxCpflB8 / qamqN2RWqclDq2jXU6JzXeM3W73 + e3AnVZBRZamKfV56yuP6VOGidbaw + xapDDJNQ9dWnKxZrUODs8KAvxtZPDJNRuT61z99hZ6pdRR5wdHsp5D3KYhKqwMoENuqhDE7qDZ9FfTo0nbOB6qkl8LYdJqIJamVEdqZVZmbqf1PagOq1OHUDd4CqwvXglh0mopJzU / frUHebe4oPK9p0cJqEOCyRWdVnmcU3q8vN3 + PMb / qNMQu33Gu90zmbxePXqfljNalazmtWsZjWrWc1qVrOa1az + D1T7vSfEg52Qi6X4aNUqUwc9sEcinl2NI0jYh4rnouN4gBcGZ7bQtmnmIc6cHIf / aZKRoiGcMqBnz62OpJZFj2qLakHLT2Y7XIQZZ + uMC5EmUU66pz4pHMaJZ1 / pLkxqSWpB6nZQm + GzTep6vWY60z4P + vOqcU0C2mG0yE2LKxOg2pSxsGEtAuzhHndp + IrUXS9seyG1U2mhTk1aqMvYqJf9pMZRsZBtSysVXUYNdcHfssfVspIgtcz / L2qnaZvFlVbps + n867h8Ki6r + TsuwoEXtfoKnrY7u5oON6z9mr6oaUgG12vBZR + GepAmaQ + 1 H / YPl0tyQdWHsxT / cn71UGfjFaMfqusRSMO7kxrHeXEVmrqiSz63ui + rWNhRHQc1brP18fqN / LSnNulSatqXtxbXU7MLNW6b1PSN1Nk4lqZAXVJdSsCt68YSIge1Q3XZy8Xu / aAuy0Lh0PuF1FRH7Fw7qhtSG9o2qumzuTpfay3qa1KX + hobc5wfd13UdlLfDuquLHfm2 / 6 iaomXOuxr2whlW4MYty3Vu7AWdZmmgIutNbToE83DiRrKBW4b1PUbqfMQLS2IR1fQvKwaF6GNNXqS5UpbuG1PXScRuXWoexzux5CDItWGgmfatlTX + SNYNjAez5dW66DH + JoWH1Jl21KtqhqiJ6qn3WXVCQOKIZcJZXI7bVuoaflUUmtBK8pdWm3KgtekThRfd7RtqdY1BQs1afOrUJd9DZVI1BA8P66O4huNE + UuqKaJtAb + arwps9 + swlaGto3qcfnUkje + pUPgwq0Mzh7KTahqrzAOoW2LVma6trGAIu + 6 S6tDUZc6JAdQRxUeqOM0X6scqJdXQxQSS30NhaaqG4qe8kw9vBZ8wAZrwItFT81RarGnxrXzL6ju67KXoE6lRcc5ZzopX / KEWVZAy6cOaqy6L5jL1GUvxRDzFXVUtM0OJyTRRWi6Ushzvfj0BdXk8Rjp1xwdp4dXtZ1lu21dPnXoW6DFQLH5vJC6zb87rCpqLoMND9R8irbZXC + xYU3 + Fy2fmoe + hcuqrc43t1WN / RyRaj6nbova1jBP5Ts / nXxi6aw26sW5jNpB3bHDvYdrv4LlrXbYwmjaNvbzeZGkG2aO / z3TBSMM9ZhdRg1vr65xL2LkierSO6lp29inim3O7XB6ki9Lr + KcyjaXkzmbM6tDUXtUm0ltaJsdrgsSizpUtSR16Qm + iBqiC00tBuw / XdQdRqq0bbxyGexWtRtOYPN0So0oM0Evo8YIVc3U70RD69iqotbjCIe5ntSmqL28mNrvnXPkDp4XE5r9vsF8ylNoeLyR1axmNatZzWpWs5rVrGY1q1nNalazmtWsZjWrWc1qVrOa1axmNatZzWpWs5rVrGY1q1nNalazmtWsZjWrWc1qVrOa1axmNatZzWpWs5rVrGY1q1nNalazmtWsZjWrWc1qVrOa1axmNatZzWpWs5rVrGY1q1nNalazmtWsZjWrWc1qVrOa1axmNatZzWpWs5rVrGY1q1nNalazmtWsZjWrWc1qVrOa1axmNatZzWpWs5rVrGY1q1nNalazmtWsZjWrWc1qVrOa1axmNatZzWpWs5rVrGY1q1nNalazmtWsZjWrWc1qVrOa1aje4I9hNatZzWpWs5rVrGb1f4KaswJWs5rVrGY1q1nNalazmtWsZjWrWc1qVrOa1axmNatZzWpWs5rVrGY1q1nNalazmtWsZjWrWc1qVrP6y9VJmPov / 9 hv96J5uNGPv7f / E0V7OnWCJ3sD7y5yEPhGQijY7HB2sYKtHQKaAhQ6wb9sB / cdYAV + kvKMnIwfPwj + Pjzj0Id8YbUraomOhRrvBHp / C3dQLfKkjofUEj6NhKefXi2KWqBjoca3DiKX3YrqviG1JrUf1e2oDqTuxenV / aDuwp5aDOq0VCtSu0Ed2 / u5Oql0BnUa1K3fV3e4R7tMj6I6yZlaTOrbUd2gOp5FbYraeBEPq73QDtXwMKolquErSg / Usarfn1wdwQxfrRMGduINPYB702uL1QqpHSBRHTSp6bBMQmdf1N2kxqNUwx6 / P7kaymsOqge1zr + XqkDjn4RqRzewd38FtS9qUdRt7kkdurv5K4Ja5v89uVriO6sMpWBsbUjdj2qLBQfVZlLHUjxIfb2nVqdsG4s6VLXVdqnO2PZRMYHCQGrXFnWXRalcHqq7HIw / o9o9UON9izfUdIPadkXdono84EK + nlr + 9 aipqKBa5EmNzWB9dj2GY7sadQOH6KDuB7XZUxellfRM355F3YxqfVhd6mVQN1UNRZ5qx4W6x / cuankGtRjVak8NX7mcqaFpPKC2ojSpEVsl + BpA3ZxeTVUYqZ08oIavO9GLpgZbTlIrVOs9NQW78PW4LohzqM2gFns13546VPWP8pAaQgAzqNuTq7FpLvW1HxqOQd1BUAEHa6xq3Dyqx4NAVLVTsAn / z / HRJOcl1bKozZhSDW3jvtoU9Ztmrs67nv7pNPyaK2p1cjUd + 9 iiw3Gp8iIOAeRcDU0jqd + Khfq6pw9rTajq9JmB6hfmMi2oIRqKw7sVdaCgIjY1d0yNrep3pB5LwXUq6hYPDgVpYy / GGOV0agsFIyg4hNLw26Sm0H6hRktRdwfUAtUe1bQfTp / tqpKB9cO7VTWWdyj2g5oeRfV70c7VN1XdQc0IDQym8kKfXB2AR9ku7fWZWu + r69HYLtUqtSVwgpjXS0jR4XfVydVYnAOVB1f3UVWbfbUe1GahjpM6kBr3w6nV / dAfkodKpKoxAWtRMxyNg9rqR9UNqtMZ + kNy6VRAUt1H075eqmvb2LqqLlWFrmr84LFJqgZSp1ZDwByoshq68ya161A91NdyUKtSX5O617HbU8MB0p1cHVBNJdrO1BojDexlaMe2sUaqEIou1GGmFqnEJKdXJ2gW1bxTtagxuF + oQ80K2jBTYycQHgFFnUTUn9 + p + lnqvqr7UR321RjQmfRA3ZSY71F1OoM6j + o4V2NqVtUlK8BInNSQAJR + s4WaniR + MfTKZ1DboQuj9oFVdVPC0FGNe5DUaaaOC3Vf1PnzYtXPVHdPqWPtgtRj3ijMQ / XQfT2o35xD7R5XY3HGBlNPOXrpMWuxPsaUtqjbmTqLH9tLqzsKKrALsPaHVDW + DVaDZQykdl + XonxOtRnVy36 + oh57zKya1GFS387V9a / THY342k + r01LtZFXb0s + 3 VJfcoBaU06oxP3lEDQ5s6KACtID / J / apNlXtBDUkRV27r + 3 Z1JB + tb + N9fWfl / U1FPeqxn72uz01jlKScOi + huLzr6L++0 nra3gjKNoBKrKW1Lvsm6U66qE / spc4ViCq2qNaDerSpQrF546GFbLv4gnjENiHAdQyVLU1i + gJquSqxjEaVEeKWkEdaFzmw0JdUjZSK39S9TRoV + LLeXwNalnVoaoxjx / U4xjY0H1d1L6ORJ4uvi55OKWMg1rN1b4JFBFSrFHUpqjjbLxx7L4u6mZI70 + mpjeilHFQ67k6DOq + qvtBnWZju0P3dZqrT5g3lgSWRnQHdbtQC9 + W2nAcR9eTOu6p + 5 J6yiG9P5k6Y5YVBfXilGK + 6 J2M4ucazGHqS3MWVFH3Zc4ClYP7qi4ZfpC1T / iEaspdrBh3vXq07ZeHfnlpS + NzTtrPt5ofVrOa1axmNatZzWpWs5rVrGY1q1nNalazmtWsZjWrWc1qVrOa1axmNatZzWpWs5rVrGY1q49V9 + JK49ldTjTxvRART03EmbEmmmTwjIbrbMVH0cHfO1w6KFzBn / c4AVG8Fy2elqY8PVkkg4uzCHONv4KzQXOvLT4pCHWLExhji / +VV5dZ0gn1XU7wqx + FhF / pcW2BIPRtbFjNalazmtWsZjWrWc1qVrOa1axmNatZzWpWs5rVrGY1q1nNalazmtWsZjWrWc1qVrOa1axmNatZzWpWs5rVrGY1q1nNalazmtWsZjWrWc1qVrOa1axmNatZzWpWs5rVrGY1q1nNalazmtWsZjWrWc1qVrOa1axmNatZzWpWs5rVrGY1q1nNalazmtWsZjWrWc1qVrOa1axmNatZzWpWs5rVrGY1q1nNalazmtWsZjWrWc1qVrOa1axmNatZzWpWs5rVrGY1q1nNalazmtWsZjWrWc1qVrOa1axmNatZzWpWs5rVrGY1q1nNalazmtWsZjWrWc1qVrOa1axmNatZzWpWs5rVrGY1q1nNalazmtWsZjWrWc1qVrOa1axmNatZzWpWb++H1axmNatZzWpWs5rVrGY1q1nNalazmtWsZjWrWc1qVrOa1axmNatZvX11wDFsgTdRaLi9p61OdHVzFLnewI818AvCjK / d4m0Sqt5kj6 / jy + Y8PobD5L2Q9SUE3jHPVFt4jyjwjTwiexqI7wW + bsLNDv / lytuQweL7O3xC + Zjl9 + gG3qzDJyh65SjxI4qyCwI9VF851Gd8ubq8PaosvTupYYOit2xhq87lBjc39WmuvLksnxtAdEOkXlRTKJ8On2DKa5VXNvUjPkMN70GzKDQ + s8m9GNQS9x + 8E xkqJBSDqOr65rZ8OLhJ + DppUHtZn4xbgyhfF / 3 tPnmwfeIJ9B60axOq46huCqdHP91QWRj2qpu9ucV / 2 / qdKXSNavhFUXZ + EOXrcvXJ3bPUsYEvMrYObkS3G9Uq4D7SoU0CjiW6wbc0sEOvE5V2fPP39Oa2AxDdBOUVlLG + qOE14akuJ3yL0FnaalU0WVw9Ux1UavIfWAYB9tuoBi1WEX0bZS8y3eBbtq7Nf8mDWnQW3 / w6O11uvIYjEOB / Lcc5qnOE304y / xO3l1rIwIvZ9nlqTSAgB3zV + IrUf8DX2pUHFODohvaqM + WdHVWM5c3 / giC68QZ8bqjVoFRhNQIvkZp6cGZ6Hain3PPUXmd8Aryux3IX03B0i668lwIr3RCTngQul8ubm / qFlRvfgnrcjaAuD9QdI + ngxxv5bLWhjz + o8wM1FNmWbugtw0yNv7Ov7id1P6jrjlmo / fPUILBFXfbbTE1vA2 / pWroparVU64fq4UBLX8vyOKq7qqaXP7O6Warlk + r4alCbk6jbom731fXrdYZu6LE4UwMj7KnxaBzeL7yWpQTVHVPUMr / E0Qi / TuqhPM7UpVAaVJtRLcvvDGq1VOuk + rnamWnH0AceCrfrXmJfx0fVe / taUrX9mFrFSe3fLdVhpi4V / bPVQ922UOtH1NiiH1QHGXU / vID7WCu4 + halZlUlwrX5JdQe2 + RmpqZaDo6ZuTqWZgP3pqtMNVT6dBNEMH2TykaLLQ7ybCmEtN8hVDAYKjQvoobmTnwQ7ULttVCH1BiTuOaQOoof29T48o4NHivvhBnUFKkGZTES / Eo + X43RL4SkvwgzqbEy / lZQ3eU03YzqkhWYmXoovhA2QttU8qCifit0VXvaGlSJzp + ZFWATYOhJ4ifKpJohFsz + G0HNitV0M6gDhpz4vpPa1ugEYlJ4gRJJ9xgz2R + FLOoauIevMUj1JWp9jhqTONx9oJaTGmIdVGNFIjTdFHVD3wuoZTn8pvwRb4CGajQlVdQNqSHOU4O6naeeX6hW / bCvhZuroUiL70EtUS0Xal0yq5m6qzdYQoQkddSoFj + P6rKvxStSP7OEQGVFaijXCg + zQQ0lB44q0cYmCU03k1qWJH5Ul5BIUGJkkjAUSUdsJ61MYlCXcg1VNSZBz6xDIGkiNRRvjZnAoIZjCxJfCwiBD4i5mkJb0Y7qNFSZkZ7b0tZAaoUtSlUbUuNxbZ + bN8Ib / YQ1H5Rc08 / UeNRj2wbgH8vNoMZUDXftpC6xP / YjfCtUGsIuirUx3CN1pjKGvS94 / PtnZmCwD6iVkZhvzdQCizzucfhU9WZqZVqqMsY6hBpRvPFGYJEowUqHalPVeACrepBD8xnE86InOOwpDmmwDoA9UNX4l6c2xgqs0sWslRkqulE9VNfQFDpU02s4LHoW25iqLuUGq54k03PVTtVIdaFGXVF7iUVcztVVOaop7qLd2YbmUXWcqfOnqr5PqWNLaoHkSY0cJOucDDZ6htRDpEppmA5D9DRWfLaD2qaZqxFsa1jZDLELhFD2meo8pIR2rsbIIugxuc2LmK + GHUPMN1Z88BJJ9HM1Re9T4kExH6mdfra6e6hG5Khu680j6rHig5foj1T7Z6tFVc / LdY256cXHYjtkYDO1nld8WPGIfl6uCTylpjUmh98KJ1HjtkPqsFTTv4acYKmmrG5QixOoayrX5rG + HrqdKFu13VCMluo09RzUGzyg4b8kB7XH3exn6oTfDx6Sz1X3B9RDGST1WEUMvTiltOuhF2c8Wh9Tj91bL6guXRSgnrXow7eJlqmKGHrMas0y9Jjtq0uLPvSXYP7Zi9lB619ODfW1R0ZVD30XtcdpVHdl51JpN + X7mZV7DP4brLTVoA64m4OiDJjq6x6 / nyiHrrYvV8Nr / E6pC37lVQ1xHfXzjTVW2Ux9qt2YutQ + VYG96nRj8YPbNkxq7GigPtV / lBadvtPYPFf9GzbcAWMxqEflQt3Tt01d2zW4o9aZUrY / 9 xQAlCI / qTWVqloZJwwAqI6Hrfc04JEpmIov0H + Nffza4liBl3Voo6izeI3dZhDE0g0WjW9xa8RhmA841vG6lJtR7SS8hJd2VCfxC440UNd2yV / st6JNeJrs89RlMKuMy6ilGoP3OI021XGZ8aFhXGZS + zoCYwb1MKpDDw3jMl0vnjsuE0r2CS85jIZNakfDS + PIHm5uCDmM8pUxpkkd6ku0g3oYQcPxsvISvqSoz8xlaPSy7B5RxksntS87vx0hkXL5MjxGQ6BqqY51 + C6PalsGMtsyCkivLOtvP0 / dVDoNwS7Usey5XG6oBhjGHmnYNJUvfVL39LwhlU2yjk572gNiGqJ + dn9ISefE2N / 5 IEKh49CqKagN1IUuxsB6mWIMjdC8MShpm55eIn2qWPNMC1azmtWsZjWrWc1qVrOa1axmNatZzWpWs5rVrGY1q1nNalazmtWs3oR6gz + G1axmNatZzWpWs5rV / wlqzgpYzWpWs5rVrGY1q1n9760W2tEJUS4JY + nssC6KJppcFkBM2klWs5rVrGY1q1nNalazmtWsZjWrWc1qVrOa1axmNatZzWpWs5rVrGY1q1nNalazmtWsZjWrWc1qVrOa1axmNatZzWpWs5rVrGY1q1nNalazmtWsZjWrWc1qVrOa1axmNavPpj7nD6tZzWpWs5rVrGY1q1nNalazegtqr3IvWngN + HeAf3abUNsGEnFd5B7yc7MJtWiyFzIn5KJab0Hdq9vsOtjf74HrcujVFtTJ / JF3yM3Atfn3vA01FOdrKBo + 35 Qj8norapVDd4 / czahjm3sNt7f5LvffwYa7LanvgJvebEidDPx / l29z / GUraiLD / 9 f5vqi3cTTqSR3CVtTQqozq++2 oGzogSX2L6k20Mll0VI1gS3OH6k3EIdkZUt9g6wjqfhtqr0e1DlSnbEEd1UINd7agTs2g7g2owzZymdwMR2NqQX27kWzXpVrzRQGJzPVG1H5oZUitNqIOH2fqM1Z8L6GGmC + h2mxFfVXi61vsD0ntptSYy4A6bkbdlbyR1Gesrp + pzjJ7UN + QOm9C / Qe05GN / SIA7m1DH7hbMOyrdqBZyE + razxe / N5tSw7EIfxL2qW5GnWgalikd15tRZ9dhr + RZg72XqPku9sNqVrOa1axmNatZzWpWs5rVrGY1q1nN6m2oN / nz / wHOIWb9CkJcBAAAAABJRU5ErkJggg ==' label_binary_data = binascii.a2b_base64(str(lable_data)) self.write({'datas': label_binary_data}) file_name = 'DHL-%s.%s' % (self.date, "pdf") return { 'type': 'ir.actions.act_url', 'url': '/web/binary/download_document?model=wizard.delivery.report.ept&field=datas&id=%s&filename=%s' % (self.id, file_name), 'target': 'self', }
def aramex_check_delivery_status(self): self.ensure_one() picking = self.env['stock.picking'].search( [ ('sale_id', '=', self.name), ('carrier_tracking_ref', '!=', False), ('state', 'in', ['done']), ('carrier_id.delivery_type', '=', 'Aramex'), # ('payment_gateway_id.code', 'in', ['cod', 'COD']) ], order="id desc", limit=1) if picking: root_node = etree.Element("Envelope") root_node.attrib[ 'xmlns'] = "http://schemas.xmlsoap.org/soap/envelope/" Body = etree.SubElement(root_node, "Body") # <body><ShipmentCreationRequest> ShipmentTrackingRequest = etree.SubElement( Body, "ShipmentTrackingRequest") ShipmentTrackingRequest.attrib[ 'xmlns'] = "http://ws.aramex.net/ShippingAPI/v1/" ClientInfo = etree.SubElement(ShipmentTrackingRequest, "ClientInfo") etree.SubElement( ClientInfo, "UserName").text = self.carrier_id.aramex_username or '' etree.SubElement( ClientInfo, "Password").text = self.carrier_id.aramex_password or '' etree.SubElement( ClientInfo, "Version").text = self.carrier_id.aramex_version or '' etree.SubElement( ClientInfo, "AccountNumber" ).text = self.carrier_id.aramex_account_number or '' etree.SubElement( ClientInfo, "AccountPin").text = self.carrier_id.aramex_account_pin or '' etree.SubElement( ClientInfo, "AccountEntity" ).text = self.carrier_id.aramex_account_entity or '' etree.SubElement(ClientInfo, "AccountCountryCode" ).text = self.company_id.country_id.code or '' Shipments = etree.SubElement(ShipmentTrackingRequest, "Shipments") etree.SubElement( Shipments, "string", attrib={ 'xmlns': "http://schemas.microsoft.com/2003/10/Serialization/Arrays" }).text = picking.carrier_tracking_ref etree.SubElement(ShipmentTrackingRequest, "GetLastTrackingUpdateOnly").text = "true" url = "http://ws.aramex.net/shippingapi/tracking/service_1_0.svc" headers = { "Content-Type": "text/xml; charset=utf-8", "SOAPAction": "http://ws.aramex.net/ShippingAPI/v1/Service_1_0/TrackShipments" } body = etree.tostring(root_node).decode('utf-8') _logger.info("aramex Shipment Requesting Data: %s" % (body)) res = request(method='POST', url=url, headers=headers, data=body) if res.status_code == 200: api = Response(res) results = api.dict() _logger.info("aramex Shipment Response Data : %s" % (results)) product_details = results.get('Envelope', {}).get( 'Body', {}).get('ShipmentTrackingResponse', {}) haserror = product_details.get('HasErrors') if haserror != 'false': raise ValidationError('%s' % results) tracking_status = product_details.get( 'TrackingResults', {}).get('KeyValueOfstringArrayOfTrackingResultmFAkxlpY', {}).get('Value', {}) status = tracking_status.get('TrackingResult', {}).get('UpdateDescription', {}) if status == 'Delivered': for inv in self.invoice_ids: if inv.state == 'open': # To Do: journal_id search should be more accurate, fix it journal_id = self.env['account.journal'].search( [('code', '=', 'Aramex')], limit=1) if journal_id: # def pay_and_reconcile(self, pay_journal, pay_amount=None, date=None, writeoff_acc=None) inv.pay_and_reconcile(journal_id.id, pay_amount=inv.residual, date=None, writeoff_acc=None) break else: print(status)