Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
# Conflicts:
#	royal_mail_rest_api/tracking.py
  • Loading branch information
Bobspadger committed Mar 29, 2018
2 parents 86bd711 + 81780c7 commit 3cba28a
Show file tree
Hide file tree
Showing 8 changed files with 455 additions and 1 deletion.
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ python:
- 3.6
- 3.5
- 3.4
- 2.7

# Command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors
install: pip install -U tox-travis
Expand Down
49 changes: 49 additions & 0 deletions docs/example_shipping.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
Example Shipping object from Royal Mail
=======================================

.. code-block:: json
{
"shipmentType":"Delivery",
"service":{
"format":"P",
"occurrence":"1",
"offering":"TPN",
"type":"T",
"signature":"true",
"enhancements":["14"
]
},
"shippingDate":"2017-09-25",
"items":[
{
"count":1,
"weight":{
"unitOfMeasure":"g",
"value":100
}
}
],
"recipientContact":{
"name":"Joe Bloggs",
"complementaryName":"null",
"email":"joe.bloggs@royalmail.com"
},
"recipientAddress":{
"buildingName":"Cable and Engineering Limited",
"buildingNumber":"1",
"addressLine1":"Broadgate Circle",
"addressLine2":"Address line 2",
"addressLine3":"Address Line 3",
"postTown":"London",
"country":"GB",
"postCode":"EC1A 1BB"
},
"senderReference":"Senders Ref",
"departmentReference":"Dept Ref",
"customerReference":"Do not use",
"safePlace":"null"
}
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Welcome to Royal Mail Rest API's documentation!
readme
installation
usage
example_shipping
modules
contributing
authors
Expand Down
13 changes: 13 additions & 0 deletions docs/modules.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Modules
=======


.. automodule:: royal_mail_rest_api.api
:members:

.. automodule:: royal_mail_rest_api.tracking
:members:

.. automodule:: royal_mail_rest_api.shipping
:members:

5 changes: 5 additions & 0 deletions royal_mail_rest_api/credentials_example.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[royal_mail]
CLIENT_ID: ''
CLIENT_SECRET: ''
USERNAME: ''
PASSWORD_HASHED: ''
11 changes: 11 additions & 0 deletions royal_mail_rest_api/get_credentials.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import configparser


def return_credentials():
config = configparser.ConfigParser()
config.read('credentials.ini')
return config


if __name__ == '__main__':
return_credentials()
175 changes: 175 additions & 0 deletions royal_mail_rest_api/shipping.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import requests
from royal_mail_rest_api.api import RoyalMailBaseClass


class ShippingApi(RoyalMailBaseClass):
token_url = '/shipping/v2/token'
post_domestic_url = '/shipping/v2/domestic'
delete_shipment_url = '/shipping/v2/'
put_shipment_label_url = '/shipping/v2/'
put_shipment_update_url = '/shipping/v2/'
post_manifest_url = '/shipping/v2/manifest'

def __init__(self, client_id, client_secret, username, password):
"""
authenticate with the Shipping service.
Password is an SHA1 hashed password. The royal mail develop tools have an html file to do this for you
https://developer.royalmail.net/node/18564
https://developer.royalmail.net/sites/developer.royalmail.net/files/rmg_shipping_api_v2_rest_password_generator_0.zip
:param client_id:
:param client_secret:
:param username:
:param password:
"""

self.client_id = client_id
self.client_secret = client_secret
self.username = username
self.password = password
self._create_authentication_header()


def _create_authentication_header(self):
self.header = {'X-IBM-Client-Id': self.client_id,
'X-IBM-Client-Secret': self.client_secret,
'x-rmg-user-name': self.username,
'x-rmg-password': self.password,
'accept': 'application/json',
'content-type': 'application/json'}

def _create_token_header(self):
self.tokenheader = {'X-IBM-Client-Id': self.client_id,
'X-IBM-Client-Secret': self.client_secret,
'x-rmg-auth-token': self.token,
'accept': 'application/json'}

def get_token(self):
"""
Summary
=======
Method to get a JWT token
Description
-----------
This method will accept a DMO/NEOPOST user name and password. On successful validation of the user credential it will issue a JWT token to the user which will be valid for 4 hours. On subsequent requests, user will pass the JWT token in the request header.
:return:
"""


result = requests.get('{}{}'.format(self.url, self.token_url), headers=self.header)
result.raise_for_status()
result = result.json()
self.token = result['token']
self._create_token_header()

def post_domestic(self, data):
"""
Summary
=======
Operation to create a shipment
Description
-----------
This method will take a domestic shipment request in the body and on successful response, it will return the shipment numbers and item details.
:return:
"""
data = data
result = requests.post('{}{}'.format(self.url,self.post_domestic_url), json=data, headers=self.tokenheader)
result.raise_for_status()
return result.json()

def put_shipment(self, shipment_number, data):
"""
Summary
=======
updateShipment
Description
-----------
Update a shipment. Send a shipment request in body. On successful response, it will return shipment number and warnings. Service related information can not be updated, and if passed as part of request, it will be ignored.
:return:
"""
# TODO: returning 400 errors at present
result = requests.put('{}{}{}'.format(self.url, self.put_shipment_update_url, shipment_number), json=data, headers=self.tokenheader)
result.raise_for_status()
return result.json()

def delete_shipment(self, shipment_number):
"""
Description
Delete a shipment. Send a shipment identifier in Url. Successful response will be 200 with no content.
:return:
"""
result = requests.delete('{}{}{}'.format(self.url, self.delete_shipment_url, shipment_number), headers=self.tokenheader)
result.raise_for_status()
return result.json()


def put_shipment_label(self, shipment_number):
"""
Description
-----------
This method returns a label for the shipment identifier passed in the url.
:return:
"""
result = requests.put('{}{}{}/label'.format(self.url, self.put_shipment_label_url, shipment_number), headers=self.tokenheader)
result.raise_for_status()
return result.json()

def post_manifest(self, manifest_options=None):
"""
Description
-----------
This method creates a shipping manifest
:return:
"""
result = requests.post('{}{}'.format(self.url, self.post_manifest_url), json=manifest_options, headers=self.tokenheader)
result.raise_for_status()
return result.json()

def put_manifest(self, sales_order_number=None, manifest_batch_number=None):
"""
Description
-----------
This method return a manifest label for a previously manifested shipment.
:return:
"""
items = {'salesOrderNumber': sales_order_number, 'manifestBatchNumber': manifest_batch_number}
params = ['{}={}'.format(k, str(v)) for k, v in items.items() if v is not None]

query_params = '&'.join(params)

result = requests.put('{}{}?{}'.format(self.url, self.post_manifest_url, query_params), headers=self.tokenheader)
result.raise_for_status()
return result.json()


if __name__ == '__main__':
from royal_mail_rest_api.get_credentials import return_credentials
creds = return_credentials()

CLIENT_ID = creds['royal_mail']['CLIENT_ID']
CLIENT_SECRET = creds['royal_mail']['CLIENT_SECRET']
USERNAME = creds['royal_mail']['USERNAME']
PASSWORD_HASHED = creds['royal_mail']['PASSWORD_HASHED']

shipping_api = ShippingApi(CLIENT_ID, CLIENT_SECRET, USERNAME, PASSWORD_HASHED)
token = shipping_api.get_token()

0 comments on commit 3cba28a

Please sign in to comment.