root / logic / credits.py @ 93c39abe
History | View | Annotate | Download (4.1 kB)
1 | 09c936a7 | Vassilios Karakoidas | #
|
---|---|---|---|
2 | 09c936a7 | Vassilios Karakoidas | # Business Logic for all Credit related activity
|
3 | 09c936a7 | Vassilios Karakoidas | #
|
4 | 09c936a7 | Vassilios Karakoidas | # Copyright 2010 Greek Research and Technology Network
|
5 | 09c936a7 | Vassilios Karakoidas | #
|
6 | 92c53da1 | Vassilios Karakoidas | |
7 | 7b7f9205 | Vassilios Karakoidas | from datetime import datetime |
8 | 7b7f9205 | Vassilios Karakoidas | from django.db import transaction |
9 | c8926262 | Vassilios Karakoidas | |
10 | 234f8b07 | Vangelis Koukis | from synnefo.db.models import Debit, FlavorCost |
11 | 234f8b07 | Vangelis Koukis | |
12 | 7b7f9205 | Vassilios Karakoidas | @transaction.commit_on_success
|
13 | 7b7f9205 | Vassilios Karakoidas | def debit_account(user , amount, vm, description): |
14 | 7b7f9205 | Vassilios Karakoidas | """Charges the user with the specified amount of credits for a vm (resource)"""
|
15 | 92c53da1 | Vassilios Karakoidas | date_now = datetime.now() |
16 | 7b7f9205 | Vassilios Karakoidas | user.credit = user.credit - amount |
17 | 7b7f9205 | Vassilios Karakoidas | user.save() |
18 | 7b7f9205 | Vassilios Karakoidas | |
19 | 7b7f9205 | Vassilios Karakoidas | # then write the debit entry
|
20 | 7b7f9205 | Vassilios Karakoidas | debit = Debit() |
21 | 7b7f9205 | Vassilios Karakoidas | debit.user = user |
22 | 7b7f9205 | Vassilios Karakoidas | debit.vm = vm |
23 | 7b7f9205 | Vassilios Karakoidas | debit.when = date_now |
24 | 7b7f9205 | Vassilios Karakoidas | debit.description = description |
25 | 7b7f9205 | Vassilios Karakoidas | debit.save() |
26 | 7b7f9205 | Vassilios Karakoidas | |
27 | 7b7f9205 | Vassilios Karakoidas | |
28 | 7b7f9205 | Vassilios Karakoidas | @transaction.commit_on_success
|
29 | 7b7f9205 | Vassilios Karakoidas | def credit_account(self, amount, creditor, description): |
30 | 7b7f9205 | Vassilios Karakoidas | """No clue :)"""
|
31 | 7b7f9205 | Vassilios Karakoidas | return
|
32 | 92c53da1 | Vassilios Karakoidas | |
33 | 92c53da1 | Vassilios Karakoidas | |
34 | 92c53da1 | Vassilios Karakoidas | @transaction.commit_on_success
|
35 | 92c53da1 | Vassilios Karakoidas | def charge(vm): |
36 | 92c53da1 | Vassilios Karakoidas | """Charges the owner of this VM.
|
37 | 92c53da1 | Vassilios Karakoidas |
|
38 | 92c53da1 | Vassilios Karakoidas | Charges the owner of a VM for the period
|
39 | 92c53da1 | Vassilios Karakoidas | from vm.charged to datetime.now(), based on the
|
40 | 92c53da1 | Vassilios Karakoidas | current operating state.
|
41 | 92c53da1 | Vassilios Karakoidas |
|
42 | 92c53da1 | Vassilios Karakoidas | """
|
43 | 92c53da1 | Vassilios Karakoidas | charged_states = ('STARTED', 'STOPPED') |
44 | 92c53da1 | Vassilios Karakoidas | |
45 | 92c53da1 | Vassilios Karakoidas | start_datetime = vm.charged |
46 | 92c53da1 | Vassilios Karakoidas | vm.charged = datetime.now() |
47 | 92c53da1 | Vassilios Karakoidas | |
48 | 92c53da1 | Vassilios Karakoidas | # Only charge for a specific set of states
|
49 | dfd19c2d | Vassilios Karakoidas | if vm.operstate in charged_states: |
50 | 92c53da1 | Vassilios Karakoidas | cost_list = [] |
51 | 92c53da1 | Vassilios Karakoidas | |
52 | 92c53da1 | Vassilios Karakoidas | # remember, we charge only for Started and Stopped
|
53 | dfd19c2d | Vassilios Karakoidas | if vm.operstate == 'STARTED': |
54 | 8d97deff | Vassilios Karakoidas | cost_list = get_cost_active(vm.flavor, start_datetime, vm.charged) |
55 | dfd19c2d | Vassilios Karakoidas | elif vm.operstate == 'STOPPED': |
56 | 8d97deff | Vassilios Karakoidas | cost_list = get_cost_inactive(vm.flavor, start_datetime, vm.charged) |
57 | 92c53da1 | Vassilios Karakoidas | |
58 | 92c53da1 | Vassilios Karakoidas | # find the total vost
|
59 | 92c53da1 | Vassilios Karakoidas | total_cost = sum([x[1] for x in cost_list]) |
60 | 92c53da1 | Vassilios Karakoidas | |
61 | 92c53da1 | Vassilios Karakoidas | # add the debit entry
|
62 | dfd19c2d | Vassilios Karakoidas | description = "Server = %s, charge = %d for state: %s" % (vm.name, total_cost, vm.operstate)
|
63 | 92c53da1 | Vassilios Karakoidas | debit_account(vm.owner, total_cost, vm, description) |
64 | 92c53da1 | Vassilios Karakoidas | |
65 | 92c53da1 | Vassilios Karakoidas | vm.save() |
66 | 111b2cda | Vassilios Karakoidas | |
67 | 8d97deff | Vassilios Karakoidas | |
68 | 111b2cda | Vassilios Karakoidas | def get_costs(vm, start_datetime, end_datetime, active): |
69 | 111b2cda | Vassilios Karakoidas | """Return a list with FlavorCost objects for the specified duration"""
|
70 | 111b2cda | Vassilios Karakoidas | def between(enh_fc, a_date): |
71 | 111b2cda | Vassilios Karakoidas | """Checks if a date is between a FlavorCost duration"""
|
72 | 111b2cda | Vassilios Karakoidas | if enh_fc.effective_from <= a_date and enh_fc.effective_to is None: |
73 | 111b2cda | Vassilios Karakoidas | return True |
74 | 111b2cda | Vassilios Karakoidas | |
75 | 111b2cda | Vassilios Karakoidas | return enh_fc.effective_from <= a_date and enh_fc.effective_to >= a_date |
76 | 111b2cda | Vassilios Karakoidas | |
77 | 111b2cda | Vassilios Karakoidas | # Get the related FlavorCost objects, sorted.
|
78 | 111b2cda | Vassilios Karakoidas | price_list = FlavorCost.objects.filter(flavor=vm).order_by('effective_from')
|
79 | 111b2cda | Vassilios Karakoidas | |
80 | 111b2cda | Vassilios Karakoidas | # add the extra field FlavorCost.effective_to
|
81 | 111b2cda | Vassilios Karakoidas | for idx in range(0, len(price_list)): |
82 | 111b2cda | Vassilios Karakoidas | if idx + 1 == len(price_list): |
83 | 111b2cda | Vassilios Karakoidas | price_list[idx].effective_to = None
|
84 | 111b2cda | Vassilios Karakoidas | else:
|
85 | 111b2cda | Vassilios Karakoidas | price_list[idx].effective_to = price_list[idx + 1].effective_from
|
86 | 111b2cda | Vassilios Karakoidas | |
87 | 111b2cda | Vassilios Karakoidas | price_result = [] |
88 | 111b2cda | Vassilios Karakoidas | found_start = False
|
89 | 111b2cda | Vassilios Karakoidas | |
90 | 111b2cda | Vassilios Karakoidas | # Find the affected FlavorCost, according to the
|
91 | 111b2cda | Vassilios Karakoidas | # dates, and put them in price_result
|
92 | 111b2cda | Vassilios Karakoidas | for p in price_list: |
93 | 111b2cda | Vassilios Karakoidas | if between(p, start_datetime):
|
94 | 111b2cda | Vassilios Karakoidas | found_start = True
|
95 | 111b2cda | Vassilios Karakoidas | p.effective_from = start_datetime |
96 | 111b2cda | Vassilios Karakoidas | if between(p, end_datetime):
|
97 | 111b2cda | Vassilios Karakoidas | p.effective_to = end_datetime |
98 | 111b2cda | Vassilios Karakoidas | price_result.append(p) |
99 | 111b2cda | Vassilios Karakoidas | break
|
100 | 111b2cda | Vassilios Karakoidas | if found_start:
|
101 | 111b2cda | Vassilios Karakoidas | price_result.append(p) |
102 | 111b2cda | Vassilios Karakoidas | |
103 | 111b2cda | Vassilios Karakoidas | results = [] |
104 | 111b2cda | Vassilios Karakoidas | |
105 | 111b2cda | Vassilios Karakoidas | # Create the list and the result tuples
|
106 | 111b2cda | Vassilios Karakoidas | for p in price_result: |
107 | 111b2cda | Vassilios Karakoidas | if active:
|
108 | 111b2cda | Vassilios Karakoidas | cost = p.cost_active |
109 | 111b2cda | Vassilios Karakoidas | else:
|
110 | 111b2cda | Vassilios Karakoidas | cost = p.cost_inactive |
111 | 111b2cda | Vassilios Karakoidas | |
112 | c8926262 | Vassilios Karakoidas | results.append( ( p.effective_from, calculate_cost(p.effective_from, p.effective_to, cost)) ) |
113 | 111b2cda | Vassilios Karakoidas | |
114 | 111b2cda | Vassilios Karakoidas | return results
|
115 | c8926262 | Vassilios Karakoidas | |
116 | c8926262 | Vassilios Karakoidas | |
117 | c8926262 | Vassilios Karakoidas | def calculate_cost(start_date, end_date, cost): |
118 | c8926262 | Vassilios Karakoidas | """Calculate the total cost for the specified duration"""
|
119 | c8926262 | Vassilios Karakoidas | td = end_date - start_date |
120 | c8926262 | Vassilios Karakoidas | sec = float(td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / float(10**6) |
121 | c8926262 | Vassilios Karakoidas | total_hours = float(sec) / float(60.0*60.0) |
122 | c8926262 | Vassilios Karakoidas | total_cost = float(cost)*total_hours
|
123 | c8926262 | Vassilios Karakoidas | |
124 | c8926262 | Vassilios Karakoidas | return round(total_cost) |
125 | 8d97deff | Vassilios Karakoidas | |
126 | 8d97deff | Vassilios Karakoidas | |
127 | 8d97deff | Vassilios Karakoidas | def get_cost_active(vm, start_datetime, end_datetime): |
128 | 8d97deff | Vassilios Karakoidas | """Returns a list with the active costs for the specified duration"""
|
129 | 8d97deff | Vassilios Karakoidas | return get_costs(vm, start_datetime, end_datetime, True) |
130 | 8d97deff | Vassilios Karakoidas | |
131 | 8d97deff | Vassilios Karakoidas | |
132 | 8d97deff | Vassilios Karakoidas | def get_cost_inactive(vm, start_datetime, end_datetime): |
133 | 8d97deff | Vassilios Karakoidas | """Returns a list with the inactive costs for the specified duration"""
|
134 | 8d97deff | Vassilios Karakoidas | return get_costs(vm, start_datetime, end_datetime, False) |