untangle rates from exporters
Change-Id: I3aa000ab0d40ba7b7305b85b297c95714434d196
This commit is contained in:
parent
38e990663b
commit
dd425ef89c
@ -1,6 +1,7 @@
|
||||
import flask
|
||||
from flask import Flask, Blueprint
|
||||
from artifice import interface, database
|
||||
from artifice.sales_order import RatesFile
|
||||
from artifice.models import UsageEntry, SalesOrder, Tenant, billing
|
||||
import sqlalchemy
|
||||
from sqlalchemy import create_engine, func
|
||||
@ -170,7 +171,7 @@ def run_usage_collection():
|
||||
return json.dumps(resp)
|
||||
|
||||
|
||||
def generate_sales_order(tenant, session, end):
|
||||
def generate_sales_order(tenant, session, end, rates):
|
||||
db = database.Database(session)
|
||||
|
||||
session.begin()
|
||||
@ -196,7 +197,7 @@ def generate_sales_order(tenant, session, end):
|
||||
# and will probably result in the CSV exporter being changed.
|
||||
billable = billing.build_billable(usage, session)
|
||||
session.close()
|
||||
exporter = invoicer(start, end, config["export_config"])
|
||||
exporter = invoicer(start, end, config["export_config"], rates)
|
||||
exporter.bill(billable)
|
||||
exporter.close()
|
||||
return {"id": tenant.id,
|
||||
@ -262,9 +263,10 @@ def run_sales_order_generation():
|
||||
|
||||
# Handled like this for a later move to Celery distributed workers
|
||||
resp = {"tenants": []}
|
||||
rates = RatesFile(config['export_config'])
|
||||
|
||||
for tenant in tenant_query:
|
||||
resp['tenants'].append(generate_sales_order(tenant, session, end))
|
||||
resp['tenants'].append(generate_sales_order(tenant, session, end, rates))
|
||||
|
||||
return 200, resp
|
||||
|
||||
|
@ -2,8 +2,7 @@ import requests
|
||||
from decimal import Decimal
|
||||
|
||||
|
||||
class ClerkRatesMixin(object):
|
||||
|
||||
class ClerkRatesSource(object):
|
||||
def rate(self, name, loc_name):
|
||||
url = "http://10.5.36.32/"
|
||||
url = (url + "regions/" + loc_name +
|
||||
|
@ -5,13 +5,14 @@ from artifice import sales_order
|
||||
from decimal import *
|
||||
|
||||
|
||||
class Csv(sales_order.RatesFileMixin, sales_order.SalesOrder):
|
||||
class Csv(sales_order.SalesOrder):
|
||||
|
||||
def __init__(self, start, end, config):
|
||||
super(Csv, self).__init__(start, end, config)
|
||||
def __init__(self, start, end, config, rates):
|
||||
super(Csv, self).__init__(start, end, config, rates)
|
||||
self.lines = {}
|
||||
self.total = Decimal(0.0)
|
||||
self.tenant = None
|
||||
self.rates = rates
|
||||
|
||||
def _bill(self, tenant):
|
||||
"""Generates the lines for a sales order for the tenant."""
|
||||
@ -49,7 +50,7 @@ class Csv(sales_order.RatesFileMixin, sales_order.SalesOrder):
|
||||
# GET REGION FROM CONFIG:
|
||||
region = 'wellington'
|
||||
|
||||
rate = self.rate(service.name, region)
|
||||
rate = self.rates.rate(service.name, region)
|
||||
cost = usage * rate
|
||||
total_cost += cost
|
||||
appendee.append(service.name)
|
||||
|
@ -18,7 +18,7 @@ class SalesOrder(object):
|
||||
|
||||
# __metaclass__ = requirements
|
||||
|
||||
def __init__(self, start, end, config):
|
||||
def __init__(self, start, end, config, rates):
|
||||
self.start = start
|
||||
self.end = end
|
||||
self.config = config
|
||||
@ -33,10 +33,12 @@ class SalesOrder(object):
|
||||
raise NotImplementedError("Not implemented in base class")
|
||||
|
||||
|
||||
class RatesFileMixin(object):
|
||||
class RatesFile(object):
|
||||
# Mixin
|
||||
# Adds a rates file loader, expecting various things from the
|
||||
# configuration
|
||||
def __init__(self, config):
|
||||
self.config = config
|
||||
|
||||
def rate(self, name, region=None):
|
||||
try:
|
||||
|
@ -2,7 +2,6 @@ from artifice import sales_order
|
||||
|
||||
|
||||
class MockExporter(sales_order.SalesOrder):
|
||||
|
||||
def _bill(self, tenant):
|
||||
pass
|
||||
|
||||
|
@ -4,6 +4,7 @@ from artifice.plugins import csv_exporter
|
||||
from decimal import Decimal
|
||||
import csv
|
||||
import os
|
||||
import mock
|
||||
|
||||
|
||||
config = {
|
||||
@ -27,44 +28,18 @@ class TestCSVExporter(test_interface.TestInterface):
|
||||
tenant = helpers.build_billable(numb_resources, volume)
|
||||
self.tenant = tenant
|
||||
|
||||
# mock rates provider that just yields 1.0 for everything.
|
||||
rates = mock.Mock()
|
||||
rates.rate.return_value = Decimal(1.0)
|
||||
|
||||
sales_order = csv_exporter.Csv(self.start, self.end,
|
||||
csv_config)
|
||||
csv_config, rates)
|
||||
sales_order.bill(tenant)
|
||||
self.filename = sales_order.filename
|
||||
sales_order.close()
|
||||
|
||||
def get_rate(self, service):
|
||||
try:
|
||||
self.__rates
|
||||
except AttributeError:
|
||||
self.__rates = {}
|
||||
if not self.__rates:
|
||||
self.__rates = {}
|
||||
try:
|
||||
fh = open(config["rates"]["file"])
|
||||
# Makes no opinions on the file structure
|
||||
reader = csv.reader(fh, delimiter="|")
|
||||
for row in reader:
|
||||
# The default layout is expected to be:
|
||||
# location | rate name | rate measurement | rate value
|
||||
self.__rates[row[1].strip()] = {
|
||||
"cost": Decimal(row[3].strip()),
|
||||
"region": row[0].strip(),
|
||||
"measures": row[2].strip()
|
||||
}
|
||||
if not self.__rates:
|
||||
raise IndexError("malformed rates CSV!")
|
||||
fh.close()
|
||||
except KeyError:
|
||||
# couldn't actually find the useful info for rateS?
|
||||
print "Couldn't find rates info configuration option!"
|
||||
raise
|
||||
except IndexError:
|
||||
raise IndexError("Malformed rates CSV!")
|
||||
except IOError:
|
||||
print "Couldn't open the file!"
|
||||
raise
|
||||
return self.__rates[service]["cost"] # ignore the regions-ness for now
|
||||
return Decimal(1.0);
|
||||
|
||||
def test_generate_csv(self):
|
||||
"""Generates a CSV, checks that:
|
||||
|
Loading…
x
Reference in New Issue
Block a user