adding api call to get sales orders in a given range

udating the api to be able to return salesorders between a given range,
as well as the client/shell to make use of this.

Has resulted in a lot of duplicate code, but next patch will go through
and clean up a bunch of that, and extract a few validators into either decorators,
or at least helper functions.

Change-Id: I59ed58c32b8dd4a75babf70df188e965e5e94a16
This commit is contained in:
adriant 2014-05-09 17:42:08 +12:00
parent 66a8c0ad78
commit a0b8ec9b7f
5 changed files with 139 additions and 43 deletions

View File

@ -2,15 +2,17 @@ from decorator import decorator
import flask
import itertools
import json
from artifice.models import Tenant
def _validate(data, *args, **kwargs):
for key in itertools.chain(args, kwargs.keys()):
if not key in data:
flask.abort(400, json.dumps({'error': 'missing parameter',
'param': key}))
'param': key}))
for key, val in kwargs.iteritems():
flask.abort(400, json.dumps({'error': 'validation failed',
'param': key}))
'param': key}))
def must(*args, **kwargs):
@ -47,3 +49,19 @@ def json_must(*args, **kwargs):
return func(*iargs)
return decorator(dejson, func)
return unpack
def validate_tenant_id(tenant_id, session):
"""Tenant ID validation that check that the id you passed is valid,
and that a tenant with this ID exists.
- returns tenant query, or a tuple if validation failure."""
if isinstance(tenant_id, unicode):
tenant_query = session.query(Tenant).\
filter(Tenant.id == tenant_id)
if tenant_query.count() == 0:
return 400, {"errors": ["No tenant matching ID found."]}
elif tenant_id is not None:
return 400, {"error": ["tenant must be a unicode string."]}
else:
return 400, {"missing parameter": {"tenant": "Tenant id."}}
return tenant_query[0]

View File

@ -3,7 +3,7 @@ from flask import Flask, Blueprint
from artifice import interface, database, config
from artifice.transformers import active_transformers
from artifice.rates import RatesFile
from artifice.models import SalesOrder, Tenant
from artifice.models import SalesOrder
from artifice.helpers import convert_to
import sqlalchemy
from sqlalchemy import create_engine, func
@ -12,7 +12,7 @@ from sqlalchemy.pool import NullPool
from datetime import datetime, timedelta
import json
from .helpers import returns_json, json_must
from .helpers import returns_json, json_must, validate_tenant_id
engine = None
@ -224,19 +224,12 @@ def add_costs_for_tenant(tenant, RatesManager):
def generate_sales_order(draft, tenant_id, end):
session = Session()
if isinstance(tenant_id, unicode):
tenant_query = session.query(Tenant).\
filter(Tenant.id == tenant_id)
if tenant_query.count() == 0:
return 400, {"errors": ["No tenant matching ID found."]}
elif tenant_id is not None:
return 400, {"error": ["tenant must be a unicode string."]}
else:
return 400, {"missing parameter": {"tenant": "Tenant id."}}
db = database.Database(session)
valid_tenant = validate_tenant_id(tenant_id, session)
if isinstance(valid_tenant, tuple):
return valid_tenant
rates = RatesFile(config.rates_config)
# Get the last sales order for this tenant, to establish
@ -268,7 +261,7 @@ def generate_sales_order(draft, tenant_id, end):
session.commit()
# Transform the query result into a billable dict.
tenant_dict = build_tenant_dict(tenant_query[0], usage, db)
tenant_dict = build_tenant_dict(valid_tenant, usage, db)
tenant_dict = add_costs_for_tenant(tenant_dict, rates)
# add sales order range:
@ -285,39 +278,22 @@ def generate_sales_order(draft, tenant_id, end):
def regenerate_sales_order(tenant_id, target):
session = Session()
db = database.Database(session)
if isinstance(tenant_id, unicode):
tenant_query = session.query(Tenant).\
filter(Tenant.id == tenant_id)
if tenant_query.count() == 0:
return 400, {"errors": ["No tenant matching ID found."]}
elif tenant_id is not None:
return 400, {"error": ["tenant must be a unicode string."]}
else:
return 400, {"missing parameter": {"tenant": "Tenant id."}}
if target is not None:
try:
target = datetime.strptime(target, iso_date)
except ValueError:
return 400, {"errors": ["date given needs to be in format: " +
"y-m-d"]}
else:
return 400, {"missing parameter": {"date": "target date in format: " +
"y-m-d"}}
rates = RatesFile(config.rates_config)
valid_tenant = validate_tenant_id(tenant_id, session)
if isinstance(valid_tenant, tuple):
return valid_tenant
try:
sales_order = db.get_sales_order(tenant_id, target)
sales_order = db.get_sales_orders(tenant_id, target, target)
except IndexError:
return 400, {"errors": ["Given date not in existing sales orders."]}
usage = db.usage(sales_order.start, sales_order.end, tenant_id)
# Transform the query result into a billable dict.
tenant_dict = build_tenant_dict(tenant_query[0], usage, db)
tenant_dict = build_tenant_dict(valid_tenant, usage, db)
tenant_dict = add_costs_for_tenant(tenant_dict, rates)
# add sales order range:
@ -327,6 +303,34 @@ def regenerate_sales_order(tenant_id, target):
return 200, tenant_dict
def regenerate_sales_order_range(tenant_id, start, end):
session = Session()
db = database.Database(session)
rates = RatesFile(config.rates_config)
valid_tenant = validate_tenant_id(tenant_id, session)
if isinstance(valid_tenant, tuple):
return valid_tenant
sales_orders = db.get_sales_orders(tenant_id, start, end)
tenants = []
for sales_order in sales_orders:
usage = db.usage(sales_order.start, sales_order.end, tenant_id)
# Transform the query result into a billable dict.
tenant_dict = build_tenant_dict(valid_tenant, usage, db)
tenant_dict = add_costs_for_tenant(tenant_dict, rates)
# add sales order range:
tenant_dict['start'] = str(sales_order.start)
tenant_dict['end'] = str(sales_order.end)
tenants.append(tenant_dict)
return 200, tenants
@app.route("sales_order", methods=["POST"])
@json_must()
@returns_json
@ -377,8 +381,43 @@ def run_sales_historic_generation():
tenant_id = flask.request.json.get("tenant", None)
target = flask.request.json.get("date", None)
if target is not None:
try:
target = datetime.strptime(target, iso_date)
except ValueError:
return 400, {"errors": ["date given needs to be in format: " +
"y-m-d"]}
else:
return 400, {"missing parameter": {"date": "target date in format: " +
"y-m-d"}}
return regenerate_sales_order(tenant_id, target)
@app.route("sales_range", methods=["POST"])
@json_must()
@returns_json
def run_sales_historic_range_generation():
tenant_id = flask.request.json.get("tenant", None)
start = flask.request.json.get("start", None)
end = flask.request.json.get("end", None)
try:
if start is not None:
start = datetime.strptime(start, iso_date)
else:
return 400, {"missing parameter": {"start": "start date in format: " +
"y-m-d"}}
if end is not None:
end = datetime.strptime(end, iso_date)
else:
end = datetime.utcnow()
except ValueError:
return 400, {"errors": ["dates given need to be in format: " +
"y-m-d"]}
return regenerate_sales_order_range(tenant_id, start, end)
if __name__ == '__main__':
pass

View File

@ -90,11 +90,11 @@ class Database(object):
filter(Resource.id == resource_id)
return json.loads(info[0].info)
def get_sales_order(self, tenant_id, target):
def get_sales_orders(self, tenant_id, start, end):
query = self.session.query(SalesOrder).\
filter(SalesOrder.start <= target, SalesOrder.end >= target).\
filter(SalesOrder.start <= end, SalesOrder.end >= start).\
filter(SalesOrder.tenant_id == tenant_id)
return query[0]
return query
def merge_resource_metadata(self, md_dict, entry):
fields = config.collection['metadata_def'].get(md_dict['type'], {})

View File

@ -65,3 +65,23 @@ class Client(object):
print json.dumps(response.json(), indent=2, sort_keys=True)
except ConnectionError as e:
print e
def sales_range(self, tenants, start, end):
url = self.endpoint + "sales_range"
for tenant in tenants:
data = {"tenant": tenant, "start": start, "end": end}
try:
response = requests.post(url,
headers={"Content-Type":
"application/json",
"token": self.auth_token},
data=json.dumps(data))
if response.status_code != 200:
raise AttributeError("Sales order cycle failed: " +
response.text + " code: " +
str(response.status_code))
else:
print json.dumps(response.json(), indent=2, sort_keys=True)
except ConnectionError as e:
print e

View File

@ -82,6 +82,22 @@ if __name__ == '__main__':
"-d", "--date", dest="date",
help='target search date for sales order.')
range_parser = subparsers.add_parser(
'sales-range',
help=('regenerate historic sales orders for given tenants,' +
'in a given range'))
range_parser.add_argument(
"-t", "--tenant", dest="tenants",
help='Tenants to create sales drafts for.',
action="append", default=[])
range_parser.add_argument(
"-s", "--start", dest="start",
help='start of range for sales orders.')
range_parser.add_argument(
"-e", "--end", dest="end",
help='end of range for sales orders. Defaults to now.',
default=None)
args = parser.parse_args()
conf = {'api': {'endpoint': 'http://0.0.0.0:8000/',
@ -107,3 +123,6 @@ if __name__ == '__main__':
if args.command == 'sales-historic':
client.sales_historic(args.tenants, args.date)
if args.command == 'sales-range':
client.sales_range(args.tenants, args.start, args.end)