def test_common_failed_get_label(): vals = copy.deepcopy(DATA) # Weight vals["parcels"][0]["weight"] = 99.99 with pytest.raises(CarrierError, match="weight exceeds"): roulier.get("gls_fr_rest", "get_label", vals) vals["parcels"][0]["weight"] = 0 with pytest.raises(CarrierError, match="define a weight"): roulier.get("gls_fr_rest", "get_label", vals) vals["parcels"][0]["weight"] = DATA["parcels"][0]["weight"] # Country vals["parcels"][0]["weight"] = 1 vals["to_address"].pop("country") with pytest.raises(InvalidApiInput, match="empty values not allowed"): roulier.get("gls_fr_rest", "get_label", vals) vals["to_address"]["country"] = "42" with pytest.raises(CarrierError, match="'Country' in Delivery is not valid"): roulier.get("gls_fr_rest", "get_label", vals) # no address del vals["to_address"] with pytest.raises(CarrierError, match="at least a delivery or pickup address"): roulier.get("gls_fr_rest", "get_label", vals)
def test_common_success_get_packing_slip(): if _do_not_execute_test_on_remote(): return # first, we need to create a valid parcel number vals = copy.deepcopy(DATA) vals["service"]["product"] = "COL" vals["parcels"][0]["nonMachinable"] = True result = roulier.get("laposte_fr", "get_label", vals) # now we can get the packing slip for this parcel vals = copy.deepcopy(PACKING_SLIP_DATA) vals["parcels_numbers"] = [ p["tracking"]["number"] for p in result["parcels"] ] res = roulier.get("laposte_fr", "get_packing_slip", vals) assert res["packing_slip"].get("number") assert res["packing_slip"].get("number_of_parcels") == len( vals["parcels_numbers"]) # now we can get the packing slip with it's ID vals = copy.deepcopy(PACKING_SLIP_DATA) vals["packing_slip_number"] = res["packing_slip"]["number"] new_res = roulier.get("laposte_fr", "get_packing_slip", vals) # we sould get the same result: it's not a newly generated document. assert res == new_res
def test_auth(): if _do_not_execute_test_on_remote(): return vals = copy.deepcopy(DATA) vals["auth"]["login"] = "******" vals["service"]["product"] = "COL" with pytest.raises(CarrierError, match="Identifiant ou mot de passe incorrect"): roulier.get("laposte_fr", "get_label", vals)
def test_language_get_label(): vals = copy.deepcopy(DATA) # Weight vals["parcels"][0]["weight"] = 99.99 with pytest.raises(CarrierError, match="weight exceeds"): roulier.get("gls_fr_rest", "get_label", vals) vals["service"]["language"] = "fr" with pytest.raises(CarrierError, match="poids dépasse"): roulier.get("gls_fr_rest", "get_label", vals)
def test_label_basic_checks(): vals = copy.deepcopy(DATA) vals["service"]["product"] = "whatisitproduct" with pytest.raises(InvalidApiInput, match="unallowed value whatisitproduct"): roulier.get("gls_fr_rest", "get_label", vals) del vals["service"]["product"] result = roulier.get("gls_fr_rest", "get_label", vals) assert_result(vals, result, 1, 0)
def test_relai(): vals = copy.deepcopy(DATA) vals["service"]["product"] = "DPD_Relais" with assert_raises(InvalidApiInput, {"service": [{ "pickupLocationId": "mandatory" }]}): roulier.get("dpd_fr_soap", "get_label", vals) vals["service"]["pickupLocationId"] = "P62025" result = roulier.get("dpd_fr_soap", "get_label", vals) assert_result(vals, result, 1, 1)
def test_SRS(): vals = copy.deepcopy(DATA) vals["parcels"][0]["services"] = [{"product": SERVICE_SRS}] with pytest.raises(CarrierError, match="is missing: Return Address"): roulier.get("gls_fr_rest", "get_label", vals) vals["return_address"] = copy.deepcopy(vals["to_address"]) with pytest.raises(CarrierError, match="is missing: Return parcel weight"): roulier.get("gls_fr_rest", "get_label", vals) vals["returns"] = [{"weight": 1}] result = roulier.get("gls_fr_rest", "get_label", vals) assert_result(vals, result, 1, 0)
def test_packing_slip_basic_checks(): if _do_not_execute_test_on_remote(): return vals = copy.deepcopy(PACKING_SLIP_DATA) regex = r".*((packing_slip_number|parcels_numbers)': \['required field'.*){2}" with pytest.raises(InvalidApiInput, match=regex): roulier.get("laposte_fr", "get_packing_slip", vals) vals["parcels_numbers"] = ["123", "456"] vals["packing_slip_number"] = "123" regex = r"'parcels_numbers' must not be present with 'packing_slip_number'" with pytest.raises(InvalidApiInput, match=regex): roulier.get("laposte_fr", "get_packing_slip", vals)
def test_label_basic_checks(): vals = copy.deepcopy(DATA) vals["service"]["product"] = "whatisitproduct" with assert_raises(InvalidApiInput, {"service": [{ "product": "unallowed" }]}): roulier.get("dpd_fr_soap", "get_label", vals) del vals["service"]["product"] vals["parcels"][0].pop("weight") with assert_raises(InvalidApiInput, {"parcels": [{ 0: [{ "weight": "float" }] }]}): roulier.get("dpd_fr_soap", "get_label", vals) vals["parcels"][0]["weight"] = DATA["parcels"][0]["weight"] vals["to_address"].pop("country") with assert_raises(InvalidApiInput, {"to_address": [{ "country": "empty" }]}): roulier.get("dpd_fr_soap", "get_label", vals) # no address del vals["to_address"] with assert_raises(InvalidApiInput, {"to_address": "empty"}): roulier.get("dpd_fr_soap", "get_label", vals)
def test_common_failed_get_packing_slip(): if _do_not_execute_test_on_remote(): return vals = copy.deepcopy(PACKING_SLIP_DATA) vals["parcels_numbers"] = ["123", "456"] regex = r"'id': 50031" # numéro de colis invalide with pytest.raises(CarrierError, match=regex): roulier.get("laposte_fr", "get_packing_slip", vals) del vals["parcels_numbers"] vals["packing_slip_number"] = "0" regex = r"'id': 50027" # not found with pytest.raises(CarrierError, match=regex): roulier.get("laposte_fr", "get_packing_slip", vals)
def test_COM_product(): """Outre-Mer - Colissimo Domicile - sans signature""" if _do_not_execute_test_on_remote(): return vals = copy.deepcopy(DATA) vals["service"]["product"] = "COM" vals["service"]["transportationAmount"] = 123 vals["service"]["totalAmount"] = 123 vals["to_address"]["country"] = "GP" # Guadeloupe vals["to_address"]["zip"] = "97100" # Basse-Terre vals["parcels"][0]["customs"] = { "articles": [{ "quantity": "2", "weight": 0.5, "originCountry": "FR", "description": "Printed circuits", "hsCode": "853400", "value": 1.0, }], "category": 3, } vals["parcels"][0]["totalAmount"] = 123 # Frais de transport result = roulier.get("laposte_fr", "get_label", vals) label = assert_label(result) assert "data" in label
def _call_roulier_api(self, picking): """Create a label for a given package_id (self).""" # There is low chance you need to override it. # Don't forget to implement _a-carrier_before_call # and _a-carrier_after_call self.write({'carrier_id': picking.carrier_id.id}) roulier_instance = roulier.get(picking.carrier_type) payload = roulier_instance.api() sender = picking._get_sender(self) receiver = picking._get_receiver(self) payload['auth'] = picking._get_auth(self) payload['from_address'] = picking._convert_address(sender) payload['to_address'] = picking._convert_address(receiver) if self._should_include_customs(picking): payload['customs'] = self._get_customs(picking) payload['service'] = picking._get_service(self) payload['parcels'] = self._get_parcels(picking) # hook to override request / payload payload = self._before_call(picking, payload) try: # api call ret = roulier_instance.get_label(payload) except InvalidApiInput as e: raise UserError(self._invalid_api_input_handling(payload, e)) except CarrierError as e: raise UserError(self._carrier_error_handling(payload, e)) # give result to someone else return self._after_call(picking, ret)
def _call_roulier_api(self, picking): """Create a label for a given package_id (self).""" # There is low chance you need to override it. # Don't forget to implement _a-carrier_before_call # and _a-carrier_after_call account = picking._get_account(self) self.write({"carrier_id": picking.carrier_id.id}) payload = {} payload["auth"] = picking._get_auth(account, package=self) payload["from_address"] = picking._get_from_address(package=self) payload["to_address"] = picking._get_to_address(package=self) payload["service"] = picking._get_service(account, package=self) payload["parcels"] = self._get_parcels(picking) # hook to override request / payload payload = self._before_call(picking, payload) try: # api call ret = roulier.get(picking.delivery_type, "get_label", payload) except InvalidApiInput as e: raise UserError(self._invalid_api_input_handling(payload, e)) except CarrierError as e: raise UserError(self._carrier_error_handling(payload, e)) # give result to someone else return self._after_call(picking, ret)
def test_dpd_format_invalid(): vals = copy.deepcopy(DATA) vals["service"]["labelFormat"] = "invalid" with assert_raises(InvalidApiInput, {"service": [{ "labelFormat": "unallowed" }]}): result = roulier.get("dpd_fr_soap", "get_label", vals)
def test_SRS_return_only(): vals = copy.deepcopy(DATA) vals["parcels"][0]["services"] = [{"product": SERVICE_SRS}] vals["pickup_address"] = copy.deepcopy(vals["to_address"]) vals["returns"] = [{"weight": 1}] result = roulier.get("gls_fr_rest", "get_label", vals) assert_result(vals, result, 1, 0, False) # no label: GLS will generate it inside the agency
def test_predict(): vals = copy.deepcopy(DATA) vals["service"]["product"] = "DPD_Predict" with assert_raises( InvalidApiInput, {"service": [{ "notifications": "must be set to Predict" }]}): roulier.get("dpd_fr_soap", "get_label", vals) vals["service"]["notifications"] = "wrong" with assert_raises( InvalidApiInput, {"service": [{ "notifications": "must be set to Predict" }]}): roulier.get("dpd_fr_soap", "get_label", vals) vals["service"]["notifications"] = "Predict" # no mobile number with assert_raises(CarrierError, [{ "id": "InvalidInput", "message": "no sms number given" }]): roulier.get("dpd_fr_soap", "get_label", vals) vals["to_address"]["phone"] = "+330623456789" result = roulier.get("dpd_fr_soap", "get_label", vals) assert_result(vals, result, 1, 1)
def test_DOS_product(): """France - Colissimo Domicile - avec signature""" if _do_not_execute_test_on_remote(): return vals = copy.deepcopy(DATA) vals["service"]["product"] = "DOS" result = roulier.get("laposte_fr", "get_label", vals) label = assert_label(result) assert "data" in label
def test_DOM_product_raise(): if _do_not_execute_test_on_remote(): return vals = copy.deepcopy(DATA) vals["service"]["product"] = "DOM" vals["to_address"]["zip"] = "99999" with pytest.raises( CarrierError, match="Le code pays ou le code postal du destinataire est incorrect " "pour le code produit fourni", ): roulier.get("laposte_fr", "get_label", vals) # 30108 = Le code postal de l'expéditeur ne correspond pas au pays vals["to_address"]["zip"] = "21000" vals["from_address"]["zip"] = "9999" with pytest.raises(CarrierError, match="30108"): roulier.get("laposte_fr", "get_label", vals)
def test_SHD(): vals = copy.deepcopy(DATA) vals["to_address"]["contact"] = "Dylann" vals["parcels"][0]["services"] = [{ "product": SERVICE_SHD, "pickupLocationId": "2500389381" }] result = roulier.get("gls_fr_rest", "get_label", vals) assert_result(vals, result, 1, 0)
def test_vat_country_missing_icoterm(): vals = copy.deepcopy(DATA) vals["to_address"]["name"] = "Prince" vals["to_address"]["street1"] = "Place de Bel-Air" vals["to_address"]["zip"] = "1204" vals["to_address"]["city"] = "Geneve" vals["to_address"]["country"] = "CH" with pytest.raises(CarrierError, match="is missing: Incoterm"): result = roulier.get("gls_fr_rest", "get_label", vals)
def test_connexion(): roulier.get( "gls_fr_glsbox", "get_label", { "auth": { "login": credentials["login"], "isTest": credentials["isTest"] }, "service": { "agencyId": credentials["agencyId"], "customerId": credentials["customerId"], "shippingDate": date.today(), "shippingId": "125874", "intructions": "Sent from automatic test", "parcel_total_number": 1, }, "from_address": { "company": "my company", "name": "my name", "street1": "blablabla street", "zip": "69000", "city": "Lyon", "phone": "04 99 99 99 99", "email": "*****@*****.**", }, "to_address": { "company": "my customer", "name": "Martine MARTIN", "street1": "13 avenue des champs Elysées", "zip": "75001", "city": "Paris", "phone": "01 99 99 99 99", "email": "*****@*****.**", "country": "FR", }, "parcels": [{ "weight": 3.4, "parcel_number_label": 1, "parcel_number_barcode": 1, "custom_sequence": "1234567899", }], }, )
def test_vat_country_valid(): """ Test using incoterm for VAT countries From https://gls-group.eu/IE/media/downloads/Customer_information_Brexit~1.pdf When exporting with GLS to the UK, dispatchers can choosebetween these Incoterms for commercial customs clearance: •Incoterm 10 (DDP): Freight costs, customs clearance costs, customs duties and taxes paid – the sender pays all costsincurred, the importer bears no costs. •Incoterm 20 (DAP): Freight costs paid, customs clearance costs, customs duties and taxes unpaid – the sender pays for freight only, the importer bears all other costs. •Incoterm 30 (DDP, VAT unpaid): Freight costs, customs clearance costs and customs duties paid, taxes unpaid – the sender pays for freight, customs clearance costs and customs duties, the importer pays for the taxes incurred. •Incoterm 40 (DAP, cleared): Freight costs and customs clearance costs paid, customs duties and taxes unpaid – the sender pays for freight and customs clearance costs, the importer pays customs duties and taxes. •Incoterm 60 (Pick&ShipService, Pick&ReturnService): Freight costs, customs clearance costs, customs duties and taxes paid – the customer pays all costs incurred, the importer bears no costs. In future, we will be able to offer additional, cost-effective inco-terms for customs clearance of single parcels to the UK. •Incoterm 13 (DDP): Freight costs, customs clearance costs, customs duties and taxes paid – the sender pays all costs incurred, the importer bears no costs. •Incoterm 23 (DAP): Freight costs paid, customs clearance costs, customs duties and taxes unpaid – the sender paysfor freight only, the importer bears all other costs. •Incoterm 43 (DAP, cleared): Freight costs and customs clear-ance costs paid, customs duties and taxes unpaid – the sender pays for freight and customs clearance costs, the importer pays customs duties and taxes. •Incoterm 18 (DDP, VAT pre-registration): Freight costs, cus-toms clearance costs and taxes paid – the sender pays all costs incurred, the importer bears no costs. For single or various parcels with a goods value of less than GBP 135. Here, the import VAT can be paid directly to the British tax authorities. From GLS-Web-API_FR_V01-03.pdf •Incoterm 50: Marchandise livrée, dédouanement export & import payés, exemption de faible valeur autorisation libre. """ vals = copy.deepcopy(DATA) vals["to_address"]["name"] = "Prince" vals["to_address"]["street1"] = "Place de Bel-Air" vals["to_address"]["zip"] = "1204" vals["to_address"]["city"] = "Geneve" vals["to_address"]["country"] = "CH" vals["service"]["incoterm"] = "20" result = roulier.get("gls_fr_rest", "get_label", vals) assert_result(vals, result, 1, 0)
def test_label_basic_checks(): if _do_not_execute_test_on_remote(): return with pytest.raises(InvalidApiInput, match="empty values not allowed"): roulier.get("laposte_fr", "get_label", DATA) vals = copy.deepcopy(DATA) vals["service"]["product"] = "whatisitproduct" with pytest.raises(CarrierError, match="'id': 30109"): roulier.get("laposte_fr", "get_label", vals) vals["service"]["product"] = "COL" vals["parcels"][0]["nonMachinable"] = True result = roulier.get("laposte_fr", "get_label", vals) assert sorted(result.keys()) == ["annexes", "parcels"], EXCEPTION_MESSAGE % vals print(_print_label_with_labelary_dot_com(result)) parcel = result["parcels"][0] assert sorted(parcel.keys()) == ["id", "label", "reference", "tracking"], (EXCEPTION_MESSAGE % vals)
def test_common_failed_get_label(): vals = copy.deepcopy(DATA) # Weight vals["parcels"][0]["weight"] = 999.99 with assert_raises(CarrierError, [{"id": "InvalidWeight"}]): roulier.get("dpd_fr_soap", "get_label", vals) vals["parcels"][0]["weight"] = 0 with assert_raises(CarrierError, [{"id": "InvalidWeight"}]): roulier.get("dpd_fr_soap", "get_label", vals) vals["parcels"][0]["weight"] = DATA["parcels"][0]["weight"] # Country vals["to_address"]["country"] = "ZZ" with assert_raises(CarrierError, [{"id": "InvalidCountryPrefix"}]): roulier.get("dpd_fr_soap", "get_label", vals)
def _call_roulier_api(self, picking): """Create a label for a given package_id (self).""" # There is low chance you need to override it. # Don't forget to implement _a-carrier_before_call # and _a-carrier_after_call self.ensure_one() self.carrier_type = picking.carrier_type # on memory value ! roulier_instance = roulier.get(picking.carrier_type) payload = roulier_instance.api() sender = picking._get_sender(self) receiver = picking._get_receiver(self) payload['auth'] = picking._get_auth(self) payload['from_address'] = picking._convert_address(sender) payload['to_address'] = picking._convert_address(receiver) if self._should_include_customs(picking): payload['customs'] = self._get_customs(picking) payload['service'] = picking._get_service(self) payload['parcel'] = self._get_parcel(picking) # hook to override request / payload payload = self._before_call(picking, payload) try: # api call ret = roulier_instance.get_label(payload) except InvalidApiInput as e: raise UserError(self._error_handling(payload, e.message)) except Exception as e: raise UserError(e.message) # minimum error handling if ret.get('status', '') == 'error': raise UserError(self._error_handling(payload, ret)) # give result to someone else return self._after_call(picking, ret)
def test_common_failed_get_label(): if _do_not_execute_test_on_remote(): return vals = copy.deepcopy(DATA) vals["service"]["product"] = "COL" # Weight vals["parcels"][0]["weight"] = 35 with pytest.raises(CarrierError, match="Le poids du colis est incorrect"): roulier.get("laposte_fr", "get_label", vals) vals["parcels"][0]["weight"] = 0 with pytest.raises(CarrierError, match="Le poids du colis n'a pas été transmis"): roulier.get("laposte_fr", "get_label", vals) vals["parcels"][0]["weight"] = DATA["parcels"][0]["weight"] # country old = "FR" with pytest.raises(InvalidApiInput, match="empty values not allowed"): del vals["from_address"]["country"] roulier.get("laposte_fr", "get_label", vals) with pytest.raises(InvalidApiInput, match="empty values not allowed"): vals["from_address"]["country"] = old del vals["to_address"]["country"] roulier.get("laposte_fr", "get_label", vals) vals["to_address"]["country"] = old
def test_full_customs_declarations(): """Complete customsDeclarations""" if _do_not_execute_test_on_remote(): return vals = copy.deepcopy(DATA) vals["service"]["product"] = "COM" vals["to_address"]["country"] = "GP" # Guadeloupe vals["to_address"]["zip"] = "97100" # Basse-Terre vals["parcels"][0]["customs"] = { "articles": [{ "description": "Printed circuits", "quantity": "2", "weight": 0.5, "value": 1.0, "hsCode": "853400", "originCountry": "FR", "currency": "EUR", "artref": "artref", "originalIdent": "A", "vatAmount": 0, "customsFees": 0, }], "category": 3, "original": { "originalIdent": "A", "originalInvoiceNumber": "111141111", "originalInvoiceDate": "2016-11-02", "originalParcelNumber": "7Q06270508932", }, "importersReference": "", "importersContact": "", "officeOrigin": "", "comments": "comments", "description": "Fake description", "invoiceNumber": "111141111", "licenceNumber": "", "certificatNumber": "", "importerAddress": { "company": "company name", "lastName": "Lastname", "firstName": "Firstname", "line0": "line0", "line1": "line1", "line2": "line2", "line3": "line3", "country": "FR", "city": "city", "zip": "75007", "phone": "+12089145766", "mobile": "0600000007", "door1": "", "door2": "", "email": "*****@*****.**", "intercom": "intercom", "language": "FR", }, } vals["parcels"][0]["totalAmount"] = 123 # Frais de transport result = roulier.get("laposte_fr", "get_label", vals) label = assert_label(result) assert "data" in label
def test_auth(): vals = copy.deepcopy(DATA) vals["auth"]["login"] = "******" with assert_raises(CarrierError, [{"id": "PermissionDenied"}]): roulier.get("dpd_fr_soap", "get_label", vals)
def test_dpd_classic(): vals = copy.deepcopy(DATA) result = roulier.get("dpd_fr_soap", "get_label", vals) assert_result(vals, result, 1, 1)
def test_dpd_invalid_ip(): vals = copy.deepcopy(DATA) with assert_raises(CarrierError, [{"id": "IpPermissionDenied"}]): roulier.get("dpd_fr_soap", "get_label", vals)