コード例 #1
0
    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))
コード例 #2
0
    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
        }
コード例 #3
0
 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
コード例 #4
0
ファイル: delivery_carrier.py プロジェクト: confianz/ruvati
    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
コード例 #5
0
 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
コード例 #6
0
ファイル: delivery_carrier.py プロジェクト: confianz/ruvati
    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)
コード例 #7
0
ファイル: stock_picking.py プロジェクト: FIDINGSARL/baytonia
    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)
コード例 #8
0
    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))
コード例 #9
0
    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!")
コード例 #10
0
    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)
コード例 #11
0
    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)
コード例 #12
0
ファイル: delivery_carrier.py プロジェクト: confianz/ruvati
    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}
コード例 #13
0
    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='iVBORw0KGgoAAAANSUhEUgAABaEAAAhxAQAAAADXrBwRAAA+pElEQVR42u3dv5IbN7YwcLThWjhQGQ4dqAw/gkIFKrWrvhfxIzhUoJoG7wQT7iPsm3wXcyfYcB/hw9QGDheuDQzX4ja+cw7Q/zicEaUZkt27Z2xRYpND/thEA+cAaLTIG/wRgtWsZjWrWc1qVrOa1axmNatZzWpWs5rVrGb12dRBnOKnYzWrWf356u6YTfijPudFWc1qVrOa1axmNatfXh1Nvs5O5twLsyG1zpISrB5Cu02p+6o2m1KnqtabUkflF+r7bah1ArUMQ7XSPKKmg1bC59P4IfErane4PYkWcqgeft0KlaPQVgh5cnXAAt3DLv+UGrikhuMWmKi2Je3TqJZF7YSEpK05lzp9Wi1zaspx62dqv1Dbs6tv4es2qL7O+TfYeLunbqpag21Su7kaHj2ruldQQLNrEiLabN+aHv56RC2MG9X2aqZOojuTWtd9HXEnotoLEH9nUqnCR/WVgGMt9yrAHs0JS1RR57/BByc1vKDM/8zBnKEOkVUdoFiKotawJ00oleGo7qo6qh725aiGf8/U+MJnUTdV7b+XfXOP6qBjI4z/Xi3VFuqLDkqSSvIxNX1x51AnjECw5nNXDda6Tf4VSot2xr9/qP6pqNWjanMmNYV70Mpom6say64OxnVyqXY5/Ezq+Kjan0udqbGTDtR2UhtQZ7m/r71vSa1narFQt+dSW1livgbUcqa2x6ltexG1a0jdNtlh5UBq3x5U3wcDah0WajNTu7OpQ4lUgQtVcotqV9XNfs13i+qokTWqnZqru3OpsRKBIA7VHZRxaAFFUYul+qopam9IDVtLHNLA55albTTPUnv1GeqMairQUAgQHw6rPzT5OmosSws1fFUvo8ZX/gw1HE+DGnZcA1HcQTV8HUXdLdQR4+uXUEM0oz5D7SZ1pOL9vpbrvZhP5ZsEMUiTF+qEbf9LqN0UdR2j9pO6Fx1WgIfVJquZejgaob5/maORxoC+RA3vDOrdI+quqMWe2qkXUfeobj9bvStvS+pgfPm25zUfvjDE4a5b1Nc5qBepryOqzTFq2HWT2lLjNqjdE+pF2wgx9Yu0jTTsqI9Uq+KRpXCAepd3EGsrOLLaw2rfLtXpBdXqKHUDQODSm0Izkjpst22EvAbia/3bnhrqjQa/h0XMh/HiS8R8HtXyGDUmgYH6nrCgUCdHtgpy2QgZWNirrzvKhTGKPYnaiSnh/ERPMCVaTVEHTFYFVAkOM/A3Jj5QxxZrxagXucxC/Yxcxgrpj1RbatiKOmK6KDF0kqIXv0C2+4hapeZRtXqGuvw5Qu2heS5ZARaXtofDASoySBB28NZCPlQ7iFQh/cn97GhUixz9X1+oFlRIj1LTew9P+RXuw19d3/0Ov9jmP/brEHgxd4WVpWg9ZvEW3wlKORwaVwI7+ODAyNdfqtb4dXfPG+EI7X6P2ahuat9TUZcDuqqxbvxSNQU3z1T7A2oPmyFxF9kt1GZS5y9Wl56u56lTdk+p/ULdztT2y9VdSUKfo/52HKd5qLYQ0MqZOs/UHornF6rzs9VxGh84OFZg2+mpi9fqP39coRATVbPumermzCMcL6FO0yDFudRyVgd8aR1i9WXU5nk137nHwMoIyzbVgdWsZjWrWc3qU6ipM8RvU92y+vTqntVnVjtWr1RNXVWuy27sIDy3mvp/ht67o9VNUXd2fzLeqtWws21LarEldTuqu4uoP7Hpk2qzGbV2BvtiaTBpQ2o/qr3ejjoYnO1LE8nUptTfFHVcjbq2OVE+qo6mf1XUSa5EXQc801g/HNrX6bVal7rOYXDjkO9T6n4l6lhnA+CY7xPq93JVal/H1ad5I4dqvjiom/Wom6o2j7Uy7WXVfTmNvF2qRVXrR9SiDV2zPnVX1OrRmG+V6hYH2J9Q55DtutQ45mpwFlmsVd9Dtcz+hOr4JeoWdjeoNc1HPazWk/oENd8jgcXT6sLKWLSbR45GaoO6x9X4qu/b2fZ5QPtX+DPe9fT/+NO3X6jGiR+18rBfqoZoQLybQXsxe41ruD/GtzjgPkMm84VqelP1sur0lNq9kHrYNe5xNeReLUVP6hh1NI+q23Oqr+GofVyNp4X17Xzzr4+Ua1Db7rPLdaYud//Zapxp/1RWcLvcvLjXz76FQX3/WXXIc9VBP1NtzquOpHbmGLV/Si3OpobDCSI/7A9pn6f+n8uou8fUyfhg4IUxC/VUgtMPECU0+TqIK30DTnzm/+j8XRdkxlP4cvjlnUniuWorH1NDDZXUU/18pHbaUscJvbCArA3nag3qO5qPd6f77zrYO3SOZvj5nQkYTx6h9s9Ry6fUVglNp0mHFk+XTt+Jzlf1db6LWLruVP8GXgbUeHrHT++Mx9j9CDXsD7evLjXDY5HqTG2eUquvvtUJG5gITzcqffdzd5vydTK9vst34aNBdXrT3fjuNsPdIJO5j+YotXigrnFI/4j6yXBtrja2VbG9pglx8HdqYnsHDVRP6huPLeTdDaj/O3T3Ge4G+Iz/SEepkXhYnR7JwI5WQ+upYndHM9ng76Qm9W2+uc+ovk6/dPDgPRydmPobqGGOUYeH6li++PhItnu0unP5JqA64yF2l/Skvs9/vi3qWNVwN7RHqz2ezn5Q7R7pWThaDbc3gapu28LfyaSZGgoJvPDd3aCGu6E7Wk2Tc7u93d+WwC0/U32H6nuqp+BvVLuqDqi+AfVtDIP65ng1Bn39ntqjOo6nGzxPTa8SFPyNaqhji7o3eK4YqENVw93j1UlMp1RN6o7U6sXUaVTrqr6q6vvfwCpmanGMOoivHqidKP0H5gXU9VQLPOUC1dB4kzpeGUtqD2qPalvU8Si1E/qBmjKvOEZGL6G+rmqoA4v6Y1vU4T507u2kDt8eo4bmbew8HU/Dk/nlSkh54DZgepVaiJGK+h1WJ6j+e+iuy9GYUe2PKdd4tqfdU5c2MYoXqkOWat+ROr3tqvr/BGyKRvXtkWpaNmN5gOqqbl9eHfbUEdR6pr47To2n3i7VpZGJj/YEf566q+quqGNVf9/dFrUKV7q0jaS+Pk6tctg7ey3UfWyfG4c8oe6/y89SQ1ayd6agH6qU58Z8qI5lD9zB3wu1KGkZhFRV7T9L3U7rkg2VYTOEfvL5auqX+RWD6oUaz2TvSA0NjsZINXRFnY5Sd1MyOlSGQ4LySO/k56n1H5jLKvgb1Td4NOqibn8t6k651uNdqkOCPkLdPKzCx045+wJqPNwxruxLK2PxjDXIwKh7HFsZLBDiaxMgA6NWxjXqCLU8WNRnLfsz1bmoTa7qpqqvS5cl1Xf2lQqQ7ZLay+YItXqwKY59HC+idrLUSk5S9KTAa0lNp/uR2r3HFV2EphZd745QmwebwtjHUSuT580xw7MgcZmOVO7iHvlX+ec/h6f8kf8b/it3++4fR4zLtA82+fF9X0R9ktGkh5tcs3r1gU12OqtrQ+ppNGJD6qniO6COdPDWL2O3+GV5UXWaesEOqHWtEagozX51t1zNZ0XqIMy+Glezk+Xfl1VPjcx+HQKZ3SF1swb11Mjsq8UBtahno55XfWjOwiPqtGa1m9TLOCSK/nH1bj1qu1AHlX99qO5ivXdZtS2TcPpuvFbMoNYPa77VqTXl7zM1nsB0QB1WpW7Gs+MHdUtqeFIT6bm2rKDbZMpo16Ge1supalfUuFKcM9gjgervUI0LPaxIvehZwBkRuKCazI2l5WWK2u+wJK1JrR+qcQGcBsc0G1J/b+53Pa2tth71osfMkjr+SeAZFDi6PKr1utTdQp3LxFrbie9lKmuCgfp219NcorOqH6wOMVfnh2ocRBRXeJoPqV/rux0uDbYitTqo9q3Iq1NPwfXeCEdRu863zVx9vSr1NDloTx1aOhCL+gd1sy71+DOqMeYDNS5ci+tEj2po11esTjO1rWqpdhgmrlfdzdSlZcnJSL3LYsVqN1enmbrfjDqqcjQaoXdJrvhodO1MjStek9qaHVTiF1G7z1JjfR3amdqsWO0Nqn1pZSZ1ewn18WtreU3qdql2K1cHWu4cl6ltehlaO1O7y6i7I9SxSapGqh9lMLXmcx0cjfbcajEE/J9Ul74nPFkG/hFwxb1ME8l2EZfbO28/3/HqntSYeoEyztTpAuouH7uCI6kx25XCJPFzUecMbeObFas97GKNy9pJ2/ZNGNVZxLOr22HxyU+vp0owXDj1Xzn/bTZ69mvuxhc9jxrPGorHrQJ71IueSa1oPf6NqXFM1G1PjcsUN1tT++PXv16bWm5Nffy67mtSx02q09Er/69J3R99lYU1qfPRV7RYldqNPb5bUvtjr9SyKnWarte5pevt2tn65ttRP7mJ1axmNatZzWpW/1urPZ7eYtXW1G0OV6LZmtpknzanxjUl4ibVQd9uTa3xIq9/bEwdQT1eUGtL6rutqW9xoafrjal70W5QnYQB9U29OMNW1EHoXmYV1KbU/ntFarkt9XvVN72OYlNq18kM6iTaTakzqfv9hZPWrbagFrhCidqa2oLaym2pG1L7TUWqeOV596HNUWxR3W9P/bYbp8NspVxDS/Omy4v1ObejdptTf5c3pkYsTeBh9enVLU4AzctT0tcfqerfUF0WF91QLkMro/pt9T1hV1nCq1dvKnpKg3pbPcGwk0m9qawg1/69beWNT7woq1nN6v8UtTjFD6tZzeoXqUMe/0nm0Na6fueFaz5Ws5rVrGY1q1nN6o2qabXwFapdxhO5o67XqUN1mi6uhQvbr1XdPKbu16wWOal6d6mOK1b3qK4Fek+t/7pmdS8PqkObV6zu8rBefMGPJ+9161Xjdd4aP6/5hssc+rxi9Y9ttgv1cDlAt2J1fAPq27n6dgvqX1q6BMGkvqvPuV2z+oPBizbP1Df1Obs/1qsOqFZz9dBRvHPtetW46K6eq4ezfndCr1ed9tTjNTHsilv0+6TrysxVPQax9r1cr7pX46WBSY03dOUl261XfQvqcFid16vGa+otaj58narerVgtl+rx8ua7FavxIpW3zVydN6Fu8p2dqV0eW/T1qhXYrufq2y2oNdiUm2UF4/Va3KrVLms/U1/nMSu4Xqu6B3Wv/ZQ35nHCll9tKyP+ZLL7aII5oA7v1xqHiK8hTv3YztTTxdviamM+8XWb/Yc2Tn1P08Xb8CJA61WHN106pMaLKm6wT/WW+6//E9T1TMtgtqSunY393puvUV0uZkw3dX2wIJYTZ1eutkXtxHKS8rrVfV06c1qLcgvqVNT9tO7nFtShcNN0mZYtqH1Rx+mSOFtQQwaOS/AG8SexOJN43WoLVlJ3flNqGrHwol4kfRtqrO/+N+P5uGk76r62LV7mfkvqEu47tSV1mtR5S2qzQfVw/VdWn149XLUWh0E3qm43p26od2Mj6uEy9E5sUe1Fl7YTqU5qk7aTFQzqIPbWF1q1Gsoz9eIEIcN28kbX9JSbR9F4uSF1pHwxiU30h4hyhQjXeFEu7jMt9r4FtStcsd9jtsLzwGZqK4aOs25D6tpV5jalHi6R45fdIatXl/Vo7f7RuG61zPS2x9V8h170ImqNl6EdulY3ozYY75XeyfWrVblxcAyiOgh/TJ/qCtQlekIxyLFlb7emxijqiGx3NepMvQuQ7dqtqQ1ess8tKuxNqHGmx6LCXr06FXXcnBp7gfvDakrQaiZc2qFyzcx/rUOdF8Okg7okaJbKfCh1Y5k7eb0StT2kxqvtYntfolmdhwv2RnnhnoUn1QEbn1Cae1unC+B2uwI1db67Q2qHjU8oQ6jD2DV9BatWU9wd6Mp4Pe3xQEp3UXUgdfu4Wkh6Fu7xJN6sSB2fVBsvc9D4hCh6ilrWoO6eVIMzNPibWE5kLkfmxdXxE+okutjkf2a8mDSoLRyZr0n9y2XVuM5yR4OlTh1S13YRwiuvUP0b3f9ruKQ60Xfe0X17SN1UNXwkDymmHlr3C6sxb8yPqmNTr+8NarcadU85eolBDsXX+2q1EjUU1gabvXFI/VG1LWcMrkCdoZGm04ygrjiUgeEquxTprUttS+8kBEb2UI6+UrUrXWXukTlmYaYW5UzYNah9GSTwj/Q9TWq9JnUJjIbJiI+rLanD02qvFVSlQeVbn2ML97C+j11vNCQRPt/c4Yq98Fi2LdzceQ2P/SDExwabgh9wwtgP+uFy9wfUUYyjSYfGwOJc3a5GXYLmR0eTqOYzFPutSU0nApacpX1CjVMDUN1cUj37qcss718LblCLMjVqbeqhi8B3h9QJ5zKYsrDFqtSHf2bxNapxasB21FAyAtWMZa7OZtQaB0HKjNDNqHFsjLIztaUSgucaU7+U3pQaknGsyOufrajhfajbqcuXbxuPV0O9B1qSbkgNexk7H5oSimxFXfYxzYnalBrraaeL2m9I3WHKmClv3JS6JAafzHZXpE7YobZB9dCRo7elrh2Un+znW5E6NqW63pYaxwpIXfqvN6KG2s5vT4397dStVsZlNpHLtDS2QerY9FtRS+yXr2rxoYzcYRM/dAuuNG8UNAYiaDSkju1uQt1WdU8dmFtR56rO1IG5EXUzqt3QdbwBtRrVfujpXrt6mDU0RCQHuvJXmoF9YgCC1axmNatZzWpWs5rVrGY1q1n976I++XVJWc1qVh+nPtEPq1nNalazmtWsZjWrWc1qVrOa1axmNatZzWpWs/o/SL2hH1azmtWsZjWrWc1qVrOa1axmNatZzWpWs5rVrGY1q1n9smq6qJjOvtvRRi9ar3MwOaZufGavco+rbgqNa8Dg0/Nf6VIwQYgu1tXOcQ0eeIQu/YAL5sKvh/Z06iYnlV1n60aNavh/pk50pYGEK014gESNW+oKNq0X5eIe+HIRl4cxEV6EFnP1J1SDZ1Tj/vS06v5vcVJH9OEuVLTATtDlsuyS1E60uH4uXZwEHylqusCQO6W6ndRxps5ztcMrlQgVq5rWrWlIbYmJy9jQI+WuDrj7T6rWkzo06YA6wONRj2pf1NqSugkmdraLKpZHMqn9e1y+/XTqzs3U8LZ/8xIXELufqeFz7JLChVTidy2tMPYVlHTjOjga38uk/4C9CgcwPtLTQoBCOzy6xQnVQc3UhtbkAtffw/RMKMVNj2tu6//FasHq/H8V1DO4rnK4wt+G447qC6t7uuJDMi7bvQtcv7A6ykmNJRHU4Pr7bwu1pJ1oclUDLrRYRXj4DkjtizqROrY2u9Oq01zdUcW7p/4vUMN/eP1bVH9d1fjv26SrGqucr3Wihc8DlA+X03cnVPfNpLao3qH67j6Py4H/SfUzdf+K1H5US1Tj54VH4qTu4ptzqTOpv9ZQO6hB3X+L6oZODwVpej2o4SC4nqvhkaL2GdXhlxOq877a5Veo1oM6fYtlt6HLoIE6VnWHajWqsTiDGquSfEtqfy61OKj+Yal+t1Dj94D1J3jhkWgkqS2qwynVYlLTFXwdltybv4/lOr7H2q1BDKrDR1I7VPd6VEOlDo9Eus7RNalvT6zG0x0ntb+CMvDnu1Fd6uQdrX8PEJ+qGvZuMkVts7UNPhK+w+pOkfr6Auq/Tk1jv1DfLtS9TBJ/z8LLwSOBVjin765T51V/XKrdoFak3s3Use0bCLB7bJgEPhIaj+UGmitxdV51eAfHm57Ut1UNGFRfz9R4wbGfJYbbFuo+eCQojL5N9q/ElT7f0QgxH6nNzfjE66VaLdW2kZgN2M518EjQRR3Ejx9NOFPN1wDAh+9R/efZEwXVIbisQGhp5b+hDvF4DTWJGZvt/Ht4JGAkEvFaZT9/2LvC9Snra1DH7z/q+UVJQP0R1XFQi1ENbYv/VmKqBcE2qEWASoUa0MZ92LuGzCnbxqq2S/UVqdu5mloZqMH7K4l4V9SR1NC6/+3savFQjXFIWKoxDsHEHiqQ3VJN8d+J1b2cx3ygTiIdVFMWsFTL0u8gl2pHLxzPr+5bk2f9IRSp+trFkaZItagxwoawA0oz1CCj+qT9IcusoEU1pLxpqaaswC3UmBVgYw6VNeVgRZ1QPYSPp1THWd7oDKh7VF+Z4bI7pG56OubmauNbyhIjBdWg7opaU2mnePyEar/I0Ud1O+UygNv1ZRdO6gjZbpqpMS/APQ13mtOrIdwpalrgVqJaPlRboO6ptaOOM6gA8dq+wVh8pJdwjMIv/gMLz0nV7aSmDpgM6rindr/QLkyidGZa7PrBJilnbVtURy3o80D0hOD7oE6s7iZ1GtVpqcblbxv6VKSGp/WiITVsQTV2oJXPQ8eoF/o8faqopt5JfHfsCJ6rcSncpRovxFjUdPVnulJZokthFrU5rVrP1NgLeVCNi/buqZ0ualmuWY07FzvCm6o+af/13k98rDl7GL7VZahCrdjrdclKNw7JeYSD1axmNatZzWpWs5rVrGb1SdQb/DGsZjWrWc1qVrOa1az+T1BzVsBqVrOa1axmNatZzWpWs5rV51dHg2fU0WmrZW7sJtQ45SrSmaybUuOcQVS3W1J7nB+LarNBtcG/N6RWNPfaRLUltcNz+Q2dFLAh9f/InL8GNZ31h6epJbkB9TUgXw3q/luc5rsB9Y3M/WtQ0zkk/SvRuU2odzmRukH1N6KzW1CrXY7vRjWu+ZA2oNY2h4+juvFts4U6RLscEqrxjK5ehlZuQN0bl+8ntQrv1SbUvrud1Hob6gTq6zSW662o8Wxj0WxP3Ra13JA6blVtSN1vSR062M1Jg1ptSY1Jehria1TLTahxBTLMZXRRQ9uInQ3rVvtB7QZ1swH1PZ52l4YcHdX27frVt3QyoKHzAIvaifWr70Z1rmq/CTU0L2M/H6rjBtQb+mE1q1nNalazmtWsZjWrWc1qVrP6WDUm5DwX50xqnotzbjXPxTmDmufinE/Nc3HOqOa5OGdT81ycs6l5Ls751DwX56xqnotzPjXPxTmXGpN0notzFjXPxTmfmufinFPNc3FYzWpWs5rVrGY1q1nNalazmtX/xmq8jCf+2YB61quHafqav4XJNrvkGF69ji7BtwF1M1OLclm49atTUf+O6tbmIN2G1KWcuM6bfhNqMVP7bsV7eq6Oe+pt1Nfxpw4vyD2o7TbU4ecuvpWxXM3Yd7uNqH0X3zRV7XKzEXVo44+iqndbUXvsZRelXNMVozehvg8mKteR1qnNqHGg0Ve12Yr6DtTGb21f3yUdW1/mOrlmK+rrmTrbraitAPUwr6welVtQq0ntu43U12KuDu1m1BLKdTeotxGHYLg3V28j5uvNUr2NrADUu2ig7qCrhPvWtVtQJ1Rrl6sa8sa0gbwxtdlGJbIANeToXWi2kKPHNrsommxf6w31h8QO1D/K7Ei9lb4nUPsPb1X2pMZ+vmYDR2MtJTWvabHy25p67T+sZjWrWf1i6s38sJrVrGY1q1nN6iPV1yUVW73aP6FOZtieWuymon9BDq8vrU5CPq62ouvLeYNe4fhHhCd7nWNzaXVYdiUs1LgQQCpq28BHILVV2V+oz2Q2SvqEGk/prctywC9Y0aIa/neivbDa6YPq3yldaHwb66iv6248qnu1yzaYC6tt98chNVmDzoNa+e6/caEimbTDvuMLq5vDNR9ZsS+qHHlJhzZHA7la0r52G69WDQddqOpY1TQQ3F9YXabzGfjKsYPvOl97nG9R1diVHWypuOEZVR061asLq+H902uD1bHGNXGubduLzpf5IjgJyrsH6vbiaqyO0/fGQo2mcE2cawGHXFvVuJvvF+ou4+DkOtTfGdH0UKl9I7r/EjoIM1dj4S7qgOqwCrXGxuQH6ZLa0Zo4Qvt3upZrHDK9LWpNJR8qFFTLVahB4ZO+xTVx7Eflr+bqO6z+ihpbmXY9agWVcDS3uCaO7ZXrF2oaPEgKmkPXRWFQ3aQ1qDWoPxhcE6fdoVrN1Dek7qU3WKU4jWob16A2VQ2ka4g4lurSeuPKAHA3KlQ7cXn1DtRCfBBiUIu5WhW1/YZmcmEhCq3/am3qvKem5RegaHxvKPggdfjT5evrx9WWnkkxR / 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',
        }
コード例 #14
0
ファイル: sale_order.py プロジェクト: FIDINGSARL/baytonia
    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)