distil/artifice/plugins/csv_exporter.py
adriant fb51469ec9 updated the csv exporter to output in a given type order.
It will write resource types in a given order,
then any types not requiring an order will be listed after the ordered types.

added tests for the csv_exporter, and tested that the ordering system works.
renamed the csv test module.

added a helper function to build billable objects.
2014-03-04 16:21:30 +13:00

130 lines
4.4 KiB
Python

import os
from csv import writer
from artifice import sales_order
# from artifice import clerk_mixins
from decimal import *
class Csv(sales_order.RatesFileMixin, sales_order.SalesOrder):
def __init__(self, start, end, config):
super(Csv, self).__init__(start, end, config)
self.lines = {}
self.total = Decimal(0.0)
self.tenant = None
def _bill(self, tenant):
"""Generates the lines for a sales order for the tenant."""
if self.tenant is not None:
raise AttributeError("Sales order already has a tenant.")
# Usage is one of VMs, Storage, or Volumes.
for resource in tenant.resources.values():
print " * " + resource.metadata['type']
print " - resource id: " + str(resource.id)
self.add_line(resource.metadata['type'], [resource.id])
headers = []
values = []
for key, value in resource.metadata.iteritems():
print " - " + key + ": " + str(value)
headers.append(key + str(":"))
values.append(value)
self.add_line(resource.metadata['type'], headers)
self.add_line(resource.metadata['type'], values)
headers = ["service:", "usage:", "rate:", "cost:"]
self.add_line(resource.metadata['type'], headers)
total_cost = Decimal(0.0)
for service in resource.services.values():
appendee = []
cost = Decimal(0.0)
usage = Decimal(service.volume)
# GET REGION FROM CONFIG:
region = 'wellington'
rate = self.rate(service.name, region)
cost = usage * rate
total_cost += cost
appendee.append(service.name)
appendee.append(usage)
appendee.append(rate)
appendee.append(round(cost, 2))
print " - " + service.name + ": " + str(usage)
print " - rate: " + str(rate)
print " - cost: " + str(round(cost))
self.add_line(resource.metadata['type'], appendee)
appendee = ["total cost:", round(total_cost, 2)]
self.add_line(resource.metadata['type'], appendee)
print " - total cost: " + str(round(total_cost))
self.add_line(resource.metadata['type'], [])
# adds resource total to sales-order total.
self.total += total_cost
self.tenant = tenant
def add_line(self, res_type, line):
"""Adds a line to the given resource type list."""
try:
self.lines[res_type].append(line)
except KeyError:
self.lines[res_type] = [line]
@property
def filename(self):
fn_dict = dict(tenant=self.tenant.name, start=self.start,
end=self.end)
fn = os.path.join(
self.config["output_path"],
self.config["output_file"] % fn_dict
)
return fn
def close(self):
"""Closes the sales order, and exports the lines to a csv file."""
try:
with open(self.filename) as temp_fh:
pass
raise RuntimeError("Can't write to an existing file!")
except IOError:
pass
with open(self.filename, "w") as fh:
csvwriter = writer(fh, dialect='excel', delimiter=',')
csvwriter.writerow(["", "from", "until"])
csvwriter.writerow(["usage range: ", str(self.start),
str(self.end)])
csvwriter.writerow([])
# write types in given order
for key in self.config["type_order"]:
try:
for line in self.lines[key]:
csvwriter.writerow(line)
csvwriter.writerow([])
except KeyError:
# not a problem, no resources of that type present
pass
# write remaining types if any:
keys = list(set(self.lines) - set(self.config["type_order"]))
for key in keys:
for line in self.lines[key]:
csvwriter.writerow(line)
csvwriter.writerow([])
# write a blank line
csvwriter.writerow([])
# write total
csvwriter.writerow(["invoice total cost: ", round(self.total, 2)])