Skip to content

Commit f764db2

Browse files
Merge pull request softlayer#458 from Neetuj/billing
Adding billing
2 parents 3287aef + 7cae91d commit f764db2

11 files changed

Lines changed: 454 additions & 4 deletions

File tree

SoftLayer/CLI/billing/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
"""Billing."""
2+
# :license: MIT, see LICENSE for more details.

SoftLayer/CLI/billing/info.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
"""List billing details of Account."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
5+
import SoftLayer
6+
from SoftLayer.CLI import environment
7+
from SoftLayer.CLI import formatting
8+
9+
import click
10+
11+
12+
@click.command()
13+
@environment.pass_env
14+
def cli(env):
15+
"""List billing details of Account."""
16+
billing = SoftLayer.BillingManager(env.client)
17+
table = formatting.Table(['Name', 'Value'])
18+
info = billing.get_info()
19+
table.add_row(['accountId', info['accountId']])
20+
table.add_row(['id', info['id']])
21+
table.add_row(['paymentTerms', info['paymentTerms']])
22+
table.add_row(['modifyDate', info['modifyDate']])
23+
table.add_row(['anniversaryDayOfMonth', info['anniversaryDayOfMonth']])
24+
table.add_row(['lastFourPaymentCardDigits',
25+
info['lastFourPaymentCardDigits']])
26+
table.add_row(['cardExpirationMonth', info['cardExpirationMonth']])
27+
table.add_row(['cardExpirationYear', info['cardExpirationYear']])
28+
table.add_row(['percentDiscountOnetime', info['percentDiscountOnetime']])
29+
table.add_row(['sparePoolAmount', info['sparePoolAmount']])
30+
table.add_row(['lastPaymentDate', info['lastPaymentDate']])
31+
table.add_row(['createDate', info['createDate']])
32+
table.add_row(['percentDiscountRecurring',
33+
info['percentDiscountRecurring']])
34+
pass_table = formatting.Table(['Name', 'Value'])
35+
result = info['currency']
36+
for key in result.keys():
37+
pass_table.add_row([key, result[key]])
38+
table.add_row(['currency', pass_table])
39+
return table

SoftLayer/CLI/billing/list.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"""List billing information of orders."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
5+
import SoftLayer
6+
from SoftLayer.CLI import environment
7+
from SoftLayer.CLI import formatting
8+
from SoftLayer import utils
9+
10+
import click
11+
12+
13+
@click.command()
14+
@click.option('--start_date', '-f', help='cost incurred from this start date')
15+
@click.option('--end_date', '-e',
16+
help='cost incurred before this end date'
17+
' (default is current time stamp)')
18+
@environment.pass_env
19+
def cli(env, start_date, end_date):
20+
"""List billing information for orders."""
21+
billing = SoftLayer.BillingManager(env.client)
22+
from_date = start_date
23+
to_date = end_date
24+
table = formatting.Table(['Order ID', 'Resource Name', 'Resource Type',
25+
'cost', 'create_date'])
26+
resources = billing.list_resources(from_date, to_date)
27+
28+
for resource in resources:
29+
resource = utils.NestedDict(resource)
30+
table.add_row([
31+
resource['id'],
32+
resource['hostName'],
33+
resource['resourceType'],
34+
resource['cost'],
35+
resource['createDate']
36+
])
37+
38+
return table

SoftLayer/CLI/billing/summary.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
"""List billing summary."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
5+
import SoftLayer
6+
from SoftLayer.CLI import environment
7+
from SoftLayer.CLI import formatting
8+
9+
import click
10+
11+
12+
@click.command()
13+
@environment.pass_env
14+
def cli(env):
15+
"""List billing summary."""
16+
billing = SoftLayer.BillingManager(env.client)
17+
table = formatting.Table(['Name', 'Value'])
18+
result = billing.get_summary()
19+
balance = result['balance']
20+
next_balance = result['nextbalance']
21+
last_bill_date = result['lastbilldate']
22+
table.add_row(['Current Balance', balance])
23+
table.add_row(['Estimated Next Balance', next_balance])
24+
table.add_row(['Last Billing Date', last_bill_date])
25+
return table

SoftLayer/CLI/routes.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77
"""
88

99
ALL_ROUTES = [
10+
('billing', 'SoftLayer.CLI.billing'),
11+
('billing:list', 'SoftLayer.CLI.billing.list:cli'),
12+
('billing:info', 'SoftLayer.CLI.billing.info:cli'),
13+
('billing:summary', 'SoftLayer.CLI.billing.summary:cli'),
14+
1015
('call-api', 'SoftLayer.CLI.call_api:cli'),
1116

1217
('vs', 'SoftLayer.CLI.virt'),

SoftLayer/managers/__init__.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
:license: MIT, see LICENSE for more details.
99
"""
1010
# pylint: disable=w0401
11-
11+
from SoftLayer.managers.billing import BillingManager # NOQA
1212
from SoftLayer.managers.cdn import CDNManager # NOQA
1313
from SoftLayer.managers.dns import DNSManager # NOQA
1414
from SoftLayer.managers.firewall import FirewallManager # NOQA
@@ -25,8 +25,9 @@
2525
from SoftLayer.managers.ticket import TicketManager # NOQA
2626
from SoftLayer.managers.vs import VSManager # NOQA
2727

28-
__all__ = ['DNSManager', 'FirewallManager', 'HardwareManager',
29-
'ImageManager', 'MessagingManager', 'MetadataManager', 'CDNManager',
30-
'NetworkManager', 'SshKeyManager', 'SSLManager', 'TicketManager',
28+
__all__ = ['BillingManager', 'DNSManager', 'FirewallManager',
29+
'HardwareManager', 'ImageManager', 'MessagingManager',
30+
'MetadataManager', 'CDNManager', 'NetworkManager',
31+
'SshKeyManager', 'SSLManager', 'TicketManager',
3132
'VSManager', 'ISCSIManager', 'LoadBalancerManager',
3233
'OrderingManager']

SoftLayer/managers/billing.py

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
"""
2+
SoftLayer.billing
3+
~~~~~~~~~~~~
4+
Billing Manager/helpers
5+
6+
:license: MIT, see LICENSE for more details.
7+
"""
8+
import calendar
9+
import datetime
10+
11+
from SoftLayer import utils
12+
13+
import math
14+
import time
15+
16+
17+
class BillingManager(object):
18+
"""Manages Billing details.
19+
20+
:param SoftLayer.managers.orderingManager
21+
"""
22+
23+
def __init__(self, client):
24+
"""init
25+
26+
:param client
27+
:return: billing account info
28+
"""
29+
self.client = client
30+
self.account = self.client['Account']
31+
self.billing_order = self.client['Billing_Order']
32+
33+
def get_info(self):
34+
"""get info
35+
36+
:return: billing account info
37+
"""
38+
result = self.account.getBillingInfo()
39+
return result
40+
41+
def get_balance(self):
42+
"""get balance
43+
44+
:return: billing account info
45+
"""
46+
result = self.account.getBalance()
47+
return result
48+
49+
def get_next_balance(self):
50+
"""get next balance
51+
52+
:return: billing account info
53+
"""
54+
result = self.account.getNextInvoiceTotalAmount()
55+
return result
56+
57+
def get_latest_bill_date(self):
58+
"""get latest balance
59+
60+
:return: billing account info
61+
"""
62+
result = self.account.getLatestBillDate()
63+
return result
64+
65+
def get_summary(self):
66+
"""get summary
67+
68+
:return: billing account info
69+
"""
70+
result = {
71+
'lastbilldate': self.get_latest_bill_date(),
72+
'balance': self.get_balance(),
73+
'nextbalance': self.get_next_balance()
74+
}
75+
return result
76+
77+
def get_next_bill_items(self):
78+
"""get next bill items
79+
80+
:return: billing account info
81+
"""
82+
result = self.account.getAllBillingItems()
83+
return result
84+
85+
def list_resources(self, from_date=None, to_date=None, **kwargs):
86+
"""Retrieve a list of all ordered resources along with their costing.
87+
88+
:param dict \\*\\*kwargs: response-level option (limit)
89+
:returns: Returns a list of dictionaries representing the
90+
matching ordered resorces by a user along with their costing
91+
"""
92+
params = {}
93+
if 'mask' not in kwargs:
94+
items = set([
95+
'order[items[description,billingItem[id,hostName,'
96+
'hourlyRecurringFee,cancellationDate,createDate,'
97+
'laborFee,oneTimeFee,setupFee]]]'
98+
])
99+
params['mask'] = "mask[%s]" % ','.join(items)
100+
101+
_filter = utils.NestedDict({})
102+
user = self.account.getCurrentUser(mask='mask[id]')
103+
_filter['orders']['userRecordId'] = utils.query_filter(user['id'])
104+
date_format = '%Y-%m-%d'
105+
106+
if from_date and to_date:
107+
_filter['orders']['createDate'] = utils.query_filter_date(
108+
from_date, to_date)
109+
elif from_date:
110+
from_date_filter = '>=' + ' ' + from_date
111+
_filter['orders']['createDate'] = utils.query_filter(
112+
from_date_filter)
113+
elif to_date:
114+
to_date_filter = '<=' + ' ' + to_date
115+
_filter['orders']['createDate'] = utils.query_filter(
116+
to_date_filter)
117+
orders = self.account.getOrders(filter=_filter.to_dict())
118+
result = []
119+
120+
for order in orders:
121+
billing_order = self.client['Billing_Order']
122+
params['id'] = order_id = order['id']
123+
items = billing_order.getItems(**params)
124+
cost = float(0.0)
125+
resource_type = ''
126+
flag = 1
127+
hostname = ''
128+
creation_date = ''
129+
130+
for item in items:
131+
if flag == 1:
132+
resource_type = item['description']
133+
134+
if 'Core' in resource_type and flag == 1:
135+
hostname = item['billingItem']['hostName']
136+
flag = 0
137+
usedmonths = 1
138+
139+
creation_date = item['billingItem']['createDate']
140+
cancellation_date = item['billingItem']['cancellationDate']
141+
142+
if 'hourlyRecurringFee' not in item['billingItem']:
143+
create_date = datetime.datetime.strptime(
144+
format_date(
145+
item['billingItem']['createDate']), date_format)
146+
if cancellation_date:
147+
cancel_date = datetime.datetime.strptime(
148+
format_date(
149+
item['billingItem']['cancellationDate']),
150+
date_format)
151+
usedmonths = get_month_delta(create_date, cancel_date)
152+
else:
153+
now = datetime.datetime.strptime(
154+
format_date(str(datetime.datetime.now())),
155+
date_format)
156+
usedmonths = get_month_delta(create_date, now)
157+
158+
usedmonths += 1
159+
160+
cost += float(
161+
billing_order.getOrderTotalOneTime(
162+
id=order['id']
163+
) + billing_order.getOrderTotalRecurring(
164+
id=order['id']
165+
) * usedmonths
166+
)
167+
168+
elif not cancellation_date:
169+
virtual_guest = self.account.getHourlyVirtualGuests(
170+
filter={
171+
'hourlyVirtualGuests': {
172+
'hourlyVirtualGuests': {
173+
'billingItem': {
174+
'id': {
175+
'operation':
176+
item['billingItem']['id']}}}}})
177+
if virtual_guest:
178+
guest = virtual_guest[0]
179+
cost = guest['billingItem']['currentHourlyCharge']
180+
181+
else:
182+
create_date = datetime.datetime.strptime(
183+
format_date(creation_date), date_format)
184+
cancel_date = datetime.datetime.strptime(
185+
format_date(cancellation_date), date_format)
186+
d1_ts = time.mktime(create_date.timetuple())
187+
d2_ts = time.mktime(cancel_date.timetuple())
188+
usedhours = math.ceil(d2_ts - d1_ts)/3600
189+
cost += usedhours * float(
190+
item['billingItem']['hourlyRecurringFee']
191+
) + float(
192+
item['billingItem']['laborFee']
193+
) + float(
194+
item['billingItem']['oneTimeFee']
195+
) + float(
196+
item['billingItem']['setupFee'])
197+
resource = {
198+
'id': order_id,
199+
'resourceType': resource_type,
200+
'hostName': hostname,
201+
'createDate': creation_date,
202+
'cost': cost
203+
}
204+
result.append(resource)
205+
return result
206+
207+
208+
def format_date(date):
209+
"""format date.
210+
211+
:param date: YY-MM-DD
212+
"""
213+
result = date.replace('T', ' ')
214+
return result[0:10]
215+
216+
217+
def get_month_delta(date1, date2):
218+
"""get month
219+
220+
:param date1: YY-MM-DD
221+
:param date2: YY-MM-DD
222+
:return: delta
223+
"""
224+
delta = 0
225+
while True:
226+
mdays = calendar.monthrange(date1.year, date1.month)[1]
227+
date1 += datetime.timedelta(days=mdays)
228+
if date1 <= date2:
229+
delta += 1
230+
else:
231+
break
232+
return delta

0 commit comments

Comments
 (0)