Fulfil REST API Client in Python
- Free software: ISC license
- Documentation: https://fulfil-python-api.readthedocs.org.
- Examples: https://github.com/fulfilio/fulfil-python-api/tree/master/examples.
- Ability to call models
pip install fulfil_client
from fulfil_client import Client
client = Client('<subdomain>', '<api_key>')
Product = client.model('product.product')
# find products
some_products = Product.find()
# find products that have a name similar to iphone
iphones = Product.find(['name', 'ilike', 'iphone'])
Contact can have multiple addresses and contact mechanisms i.e. phone, email.
from fulfil_client import Client
client = Client('<subdomain>', '<api_key>')
Contact = client.model('party.party')
Country = client.model('country.country')
Subdivision = client.model('country.subdivision')
country_usa, = Country.find([('code', '=', 'US')])
state_california, = Subdivision.find([('code', '=', 'US-CA')])
# Creating a contact with address and contact mechanisms
contact, = Contact.create([{
'name': 'Jon Doe',
'addresses': [('create', [{
'name': 'Jone Doe Apartment',
'street': '9805 Kaiden Grove',
'city': 'New Leland',
'zip': '57726',
'country': country_usa['id'],
'subdivision': state_california['id']
}])],
'contact_mechanisms': [('create', [{
'type': 'phone',
'value': '243243234'
}, {
'email': 'email',
'value': 'hello@jondoe.com'
}])]
}])
print contact
# Searching for a contact
contact, = Contact.find([('name', '=', 'Jon Doe')])
print contact
# Get a contact by ID
contact = Contact.get(contact['id'])
print contact
Products are grouped by templates, which have common information shared by products a.k.a. variants.
from decimal import Decimal
# Creating a Product Template
Template = client.model('product.template')
iphone, = Template.create([{
'name': 'iPhone',
'account_category': True,
}])
# Creating products
Product = client.model('product.product')
iphone6, = Product.create([{
'template': iphone['id'],
'variant_name': 'iPhone 6',
'code': 'IPHONE-6',
'list_price': Decimal('699'),
'cost_price': Decimal('599'),
}])
# Another variation
iphone6s, = Product.create([{
'template': iphone['id'],
'variant_name': 'iPhone 6S',
'code': 'IPHONE-6S',
'list_price': Decimal('899'),
'cost_price': Decimal('699'),
}])
contact = Contact.get(contact['id'])
iphone6 = Product.get(iphone6['id'])
iphone6s = Product.get(iphone6s['id'])
# Creating a Sale
Sale = client.model('sale.sale')
sale, = Sale.create([{
'party': contact['id'],
'shipment_address': contact['addresses'][0],
'invoice_address': contact['addresses'][0],
'lines': [('create', [{
'product': iphone6['id'],
'description': iphone6['rec_name'],
'unit': iphone6['default_uom'],
'unit_price': iphone6['list_price'],
'quantity': 3
}, {
'product': iphone6s['id'],
'description': iphone6s['rec_name'],
'unit': iphone6['default_uom'],
'unit_price': iphone6s['list_price'],
'quantity': 1
}])]
}])
The report data (including rendering) information can be fetched over the API.
Below is the example code to fetch sales by month report.
report = client.interactive_report('sales_by_month.ireport')
data = report.execute(start_date=date(2017,1,1), end_date=date(2017, 12,1))
from fulfil_client import Client, SessionAuth
client = Client('subdomain')
user_id, session = client.login('username', 'password')
client.set_auth(SessionAuth(user_id, session))
from fulfil_client import Client, BearerAuth
client = Client('subdomain')
client.set_auth(BearerAuth(bearer_token))
Flask example
from fulfil_client.oauth import Session
from fulfil_client import Client, BearerAuth
Session.setup(CLIENT_ID, CLIENT_SECRET)
fulfil_session = Session('localhost') # Provide subdomain
@app.route('/')
def index():
callback_url = url_for('authorized')
if 'oauth_token' not in session:
authorization_url, state = fulfil_session.create_authorization_url(
redirect_uri=callback_url, scope=['user_session']
)
session['oauth_state'] = state
return redirect(authorization_url)
client = Client('subdomain')
client.set_auth(BearerAuth(session['oauth_token']['access_token']))
Party = client.model('party.party')
return jsonify(Party.find())
@app.route('/authorized')
def authorized():
"""Callback route to fetch access token from grant code
"""
token = fulfil_session.get_token(code=request.args.get('code'))
session['oauth_token'] = token
return jsonify(oauth_token=token)
There is a convenience function that can verify the webhooks originating from Fulfil for you.
from fulfil_client import verify_webhook
@app.route('/webhook', methods=['POST'])
def webhook():
data = flask.request.get_data()
verified = verify_webhook(
data,
secret, # This should be saved somewhere
flask.request.headers.get('X-Fulfil-Hmac-SHA256')
)
if not verified:
abort(401)
The libary also provides a mocking function powered by the mock library of python.
For example, if you want to test the function below
def api_calling_method():
client = fulfil_client.Client('apple', 'apples-api-key')
Product = client.model('product.product')
products = Product.search_read_all([], None, ['id'])
Product.write(
[p['id'] for p in products],
{'active': False}
)
return client
Then the test case can mock the API call
def test_mock_1():
with MockFulfil('fulfil_client.Client') as mocked_fulfil:
Product = mocked_fulfil.model('product.product')
# Set the return value of the search call without
# hitting the server.
Product.search_read_all.return_value = [
{'id': 1},
{'id': 2},
{'id': 3},
]
# Call the function
api_calling_method()
# Now assert
Product.search_read_all.assert_called()
Product.search_read_all.assert_called_with([], None, ['id'])
Product.write.assert_called_with(
[1, 2, 3], {'active': False}
)
The Product object returned is a mock.Mock object and supports all of the assertions supported by python Mock objects.
Fulfil.IO Inc.