Skip to content

Commit 1ed83f4

Browse files
Merge pull request #1338 from ATGE/issues/1336
#1336 add Invoice Item id as param valid in account item-detail command
2 parents 7c73def + 9c05c45 commit 1ed83f4

File tree

4 files changed

+105
-58
lines changed

4 files changed

+105
-58
lines changed
Lines changed: 53 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,53 @@
1-
"""Gets some details about a specific billing item."""
2-
# :license: MIT, see LICENSE for more details.
3-
import click
4-
5-
from SoftLayer.CLI import environment
6-
from SoftLayer.CLI import formatting
7-
from SoftLayer.managers.account import AccountManager as AccountManager
8-
from SoftLayer import utils
9-
10-
11-
@click.command()
12-
@click.argument('identifier')
13-
@environment.pass_env
14-
def cli(env, identifier):
15-
"""Gets detailed information about a billing item."""
16-
manager = AccountManager(env.client)
17-
item = manager.get_billing_item(identifier)
18-
env.fout(item_table(item))
19-
20-
21-
def item_table(item):
22-
"""Formats a table for billing items"""
23-
24-
date_format = '%Y-%m-%d'
25-
table = formatting.KeyValueTable(["Key", "Value"], title="{}".format(item.get('description', 'Billing Item')))
26-
table.add_row(['createDate', utils.clean_time(item.get('createDate'), date_format, date_format)])
27-
table.add_row(['cycleStartDate', utils.clean_time(item.get('cycleStartDate'), date_format, date_format)])
28-
table.add_row(['cancellationDate', utils.clean_time(item.get('cancellationDate'), date_format, date_format)])
29-
table.add_row(['description', item.get('description')])
30-
fqdn = "{}.{}".format(item.get('hostName'), item.get('domain'))
31-
if fqdn != ".":
32-
table.add_row(['FQDN', fqdn])
33-
34-
if item.get('hourlyFlag', False):
35-
table.add_row(['hourlyRecurringFee', item.get('hourlyRecurringFee')])
36-
table.add_row(['hoursUsed', item.get('hoursUsed')])
37-
table.add_row(['currentHourlyCharge', item.get('currentHourlyCharge')])
38-
else:
39-
table.add_row(['recurringFee', item.get('recurringFee')])
40-
41-
ordered_by = "IBM"
42-
user = utils.lookup(item, 'orderItem', 'order', 'userRecord')
43-
if user:
44-
ordered_by = "{} ({})".format(user.get('displayName'), utils.lookup(user, 'userStatus', 'name'))
45-
table.add_row(['Ordered By', ordered_by])
46-
table.add_row(['Notes', item.get('notes')])
47-
table.add_row(['Location', utils.lookup(item, 'location', 'name')])
48-
if item.get('children'):
49-
for child in item.get('children'):
50-
table.add_row([child.get('categoryCode'), child.get('description')])
51-
52-
return table
1+
"""Gets some details about a specific billing item."""
2+
# :license: MIT, see LICENSE for more details.
3+
import click
4+
5+
from SoftLayer.CLI import environment
6+
from SoftLayer.CLI import formatting
7+
from SoftLayer.managers.account import AccountManager as AccountManager
8+
from SoftLayer import utils
9+
10+
11+
@click.command()
12+
@click.argument('identifier')
13+
@environment.pass_env
14+
def cli(env, identifier):
15+
"""Gets detailed information about a billing item."""
16+
manager = AccountManager(env.client)
17+
item = manager.get_item_detail(identifier)
18+
env.fout(item_table(item))
19+
20+
21+
def item_table(item):
22+
"""Formats a table for billing items"""
23+
24+
date_format = '%Y-%m-%d'
25+
table = formatting.Table(["Key", "Value"], title="{}".format(item.get('description', 'Billing Item')))
26+
table.add_row(['createDate', utils.clean_time(item.get('createDate'), date_format, date_format)])
27+
table.add_row(['cycleStartDate', utils.clean_time(item.get('cycleStartDate'), date_format, date_format)])
28+
table.add_row(['cancellationDate', utils.clean_time(item.get('cancellationDate'), date_format, date_format)])
29+
table.add_row(['description', item.get('description')])
30+
table.align = 'l'
31+
fqdn = "{}.{}".format(item.get('hostName'), item.get('domain'))
32+
if fqdn != ".":
33+
table.add_row(['FQDN', fqdn])
34+
35+
if item.get('hourlyFlag', False):
36+
table.add_row(['hourlyRecurringFee', item.get('hourlyRecurringFee')])
37+
table.add_row(['hoursUsed', item.get('hoursUsed')])
38+
table.add_row(['currentHourlyCharge', item.get('currentHourlyCharge')])
39+
else:
40+
table.add_row(['recurringFee', item.get('recurringFee')])
41+
42+
ordered_by = "IBM"
43+
user = utils.lookup(item, 'orderItem', 'order', 'userRecord')
44+
if user:
45+
ordered_by = "{} ({})".format(user.get('displayName'), utils.lookup(user, 'userStatus', 'name'))
46+
table.add_row(['Ordered By', ordered_by])
47+
table.add_row(['Notes', item.get('notes')])
48+
table.add_row(['Location', utils.lookup(item, 'location', 'name')])
49+
if item.get('children'):
50+
for child in item.get('children'):
51+
table.add_row([child.get('categoryCode'), child.get('description')])
52+
53+
return table
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from SoftLayer.fixtures.SoftLayer_Billing_Item import getObject as billingItem
2+
3+
getBillingItem = billingItem

SoftLayer/managers/account.py

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import logging
1010

11+
from SoftLayer import SoftLayerAPIError
1112
from SoftLayer import utils
1213

1314
# Invalid names are ignored due to long method names and short argument names
@@ -21,6 +22,11 @@ class AccountManager(utils.IdentifierMixin, object):
2122
2223
:param SoftLayer.API.BaseClient client: the client instance
2324
"""
25+
_DEFAULT_BILLING_ITEM_MASK = """mask[
26+
orderItem[id,order[id,userRecord[id,email,displayName,userStatus]]],
27+
nextInvoiceTotalRecurringAmount,
28+
location, hourlyFlag, children
29+
]"""
2430

2531
def __init__(self, client):
2632
self.client = client
@@ -205,20 +211,41 @@ def get_account_billing_items(self, mask=None):
205211
def get_billing_item(self, identifier, mask=None):
206212
"""Gets details about a billing item
207213
208-
:param int identifier Billing_Item id
214+
:param int identifier: Billing_Item id
209215
:param string mask: Object mask to use.
210216
:return: Billing_Item
211217
"""
212218

213219
if mask is None:
214-
mask = """mask[
215-
orderItem[id,order[id,userRecord[id,email,displayName,userStatus]]],
216-
nextInvoiceTotalRecurringAmount,
217-
location, hourlyFlag, children
218-
]"""
220+
mask = self._DEFAULT_BILLING_ITEM_MASK
219221

220222
return self.client.call('Billing_Item', 'getObject', id=identifier, mask=mask)
221223

224+
def get_billing_item_from_invoice(self, identifier, mask=None):
225+
"""Gets details about a billing item of a billing invoice item
226+
227+
:param int identifier: Billing_Invoice_Item id
228+
:param mask: Object mask to use.
229+
:return: Billing_Item
230+
"""
231+
if mask is None:
232+
mask = self._DEFAULT_BILLING_ITEM_MASK
233+
return self.client.call('Billing_Invoice_Item', 'getBillingItem', id=identifier, mask=mask)
234+
235+
def get_item_detail(self, identifier):
236+
"""Gets details about a billing item
237+
238+
:param int identifier: Billing_Item id or Billing_Invoice_Item
239+
:return: Billing_Item
240+
"""
241+
242+
try:
243+
return self.get_billing_item(identifier)
244+
except SoftLayerAPIError as exception:
245+
if exception.faultCode == 404:
246+
return self.get_billing_item_from_invoice(identifier)
247+
raise
248+
222249
def cancel_item(self, identifier, reason="No longer needed", note=None):
223250
"""Cancels a specific billing item with a reason
224251

tests/managers/account_tests.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"""
66

77
from SoftLayer.managers.account import AccountManager as AccountManager
8+
from SoftLayer import SoftLayerAPIError
89
from SoftLayer import testing
910

1011

@@ -133,3 +134,18 @@ def test_cancel_item(self):
133134
self.manager.cancel_item(12345, reason, note)
134135
self.assert_called_with('SoftLayer_Billing_Item', 'cancelItem',
135136
args=(False, True, reason, note), identifier=12345)
137+
138+
def test_get_billing_item_from_invoice(self):
139+
self.manager.get_billing_item_from_invoice(12345)
140+
self.assert_called_with('SoftLayer_Billing_Invoice_Item', 'getBillingItem', identifier=12345)
141+
142+
def test_get_item_details_with_billing_item_id(self):
143+
self.manager.get_item_detail(12345)
144+
self.assert_called_with('SoftLayer_Billing_Item', 'getObject', identifier=12345)
145+
146+
def test_get_item_details_with_invoice_item_id(self):
147+
mock = self.set_mock('SoftLayer_Billing_Item', 'getObject')
148+
mock.side_effect = SoftLayerAPIError(404, "Unable to find object with id of '123456'.")
149+
self.manager.get_item_detail(123456)
150+
self.assert_called_with('SoftLayer_Billing_Item', 'getObject', identifier=123456)
151+
self.assert_called_with('SoftLayer_Billing_Invoice_Item', 'getBillingItem', identifier=123456)

0 commit comments

Comments
 (0)