Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 53 additions & 52 deletions SoftLayer/CLI/account/item_detail.py
Original file line number Diff line number Diff line change
@@ -1,52 +1,53 @@
"""Gets some details about a specific billing item."""
# :license: MIT, see LICENSE for more details.
import click

from SoftLayer.CLI import environment
from SoftLayer.CLI import formatting
from SoftLayer.managers.account import AccountManager as AccountManager
from SoftLayer import utils


@click.command()
@click.argument('identifier')
@environment.pass_env
def cli(env, identifier):
"""Gets detailed information about a billing item."""
manager = AccountManager(env.client)
item = manager.get_billing_item(identifier)
env.fout(item_table(item))


def item_table(item):
"""Formats a table for billing items"""

date_format = '%Y-%m-%d'
table = formatting.KeyValueTable(["Key", "Value"], title="{}".format(item.get('description', 'Billing Item')))
table.add_row(['createDate', utils.clean_time(item.get('createDate'), date_format, date_format)])
table.add_row(['cycleStartDate', utils.clean_time(item.get('cycleStartDate'), date_format, date_format)])
table.add_row(['cancellationDate', utils.clean_time(item.get('cancellationDate'), date_format, date_format)])
table.add_row(['description', item.get('description')])
fqdn = "{}.{}".format(item.get('hostName'), item.get('domain'))
if fqdn != ".":
table.add_row(['FQDN', fqdn])

if item.get('hourlyFlag', False):
table.add_row(['hourlyRecurringFee', item.get('hourlyRecurringFee')])
table.add_row(['hoursUsed', item.get('hoursUsed')])
table.add_row(['currentHourlyCharge', item.get('currentHourlyCharge')])
else:
table.add_row(['recurringFee', item.get('recurringFee')])

ordered_by = "IBM"
user = utils.lookup(item, 'orderItem', 'order', 'userRecord')
if user:
ordered_by = "{} ({})".format(user.get('displayName'), utils.lookup(user, 'userStatus', 'name'))
table.add_row(['Ordered By', ordered_by])
table.add_row(['Notes', item.get('notes')])
table.add_row(['Location', utils.lookup(item, 'location', 'name')])
if item.get('children'):
for child in item.get('children'):
table.add_row([child.get('categoryCode'), child.get('description')])

return table
"""Gets some details about a specific billing item."""
# :license: MIT, see LICENSE for more details.
import click

from SoftLayer.CLI import environment
from SoftLayer.CLI import formatting
from SoftLayer.managers.account import AccountManager as AccountManager
from SoftLayer import utils


@click.command()
@click.argument('identifier')
@environment.pass_env
def cli(env, identifier):
"""Gets detailed information about a billing item."""
manager = AccountManager(env.client)
item = manager.get_item_detail(identifier)
env.fout(item_table(item))


def item_table(item):
"""Formats a table for billing items"""

date_format = '%Y-%m-%d'
table = formatting.Table(["Key", "Value"], title="{}".format(item.get('description', 'Billing Item')))
table.add_row(['createDate', utils.clean_time(item.get('createDate'), date_format, date_format)])
table.add_row(['cycleStartDate', utils.clean_time(item.get('cycleStartDate'), date_format, date_format)])
table.add_row(['cancellationDate', utils.clean_time(item.get('cancellationDate'), date_format, date_format)])
table.add_row(['description', item.get('description')])
table.align = 'l'
fqdn = "{}.{}".format(item.get('hostName'), item.get('domain'))
if fqdn != ".":
table.add_row(['FQDN', fqdn])

if item.get('hourlyFlag', False):
table.add_row(['hourlyRecurringFee', item.get('hourlyRecurringFee')])
table.add_row(['hoursUsed', item.get('hoursUsed')])
table.add_row(['currentHourlyCharge', item.get('currentHourlyCharge')])
else:
table.add_row(['recurringFee', item.get('recurringFee')])

ordered_by = "IBM"
user = utils.lookup(item, 'orderItem', 'order', 'userRecord')
if user:
ordered_by = "{} ({})".format(user.get('displayName'), utils.lookup(user, 'userStatus', 'name'))
table.add_row(['Ordered By', ordered_by])
table.add_row(['Notes', item.get('notes')])
table.add_row(['Location', utils.lookup(item, 'location', 'name')])
if item.get('children'):
for child in item.get('children'):
table.add_row([child.get('categoryCode'), child.get('description')])

return table
3 changes: 3 additions & 0 deletions SoftLayer/fixtures/SoftLayer_Billing_Invoice_Item.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from SoftLayer.fixtures.SoftLayer_Billing_Item import getObject as billingItem

getBillingItem = billingItem
39 changes: 33 additions & 6 deletions SoftLayer/managers/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import logging

from SoftLayer import SoftLayerAPIError
from SoftLayer import utils

# Invalid names are ignored due to long method names and short argument names
Expand All @@ -21,6 +22,11 @@ class AccountManager(utils.IdentifierMixin, object):

:param SoftLayer.API.BaseClient client: the client instance
"""
_DEFAULT_BILLING_ITEM_MASK = """mask[
orderItem[id,order[id,userRecord[id,email,displayName,userStatus]]],
nextInvoiceTotalRecurringAmount,
location, hourlyFlag, children
]"""

def __init__(self, client):
self.client = client
Expand Down Expand Up @@ -205,20 +211,41 @@ def get_account_billing_items(self, mask=None):
def get_billing_item(self, identifier, mask=None):
"""Gets details about a billing item

:param int identifier Billing_Item id
:param int identifier: Billing_Item id
:param string mask: Object mask to use.
:return: Billing_Item
"""

if mask is None:
mask = """mask[
orderItem[id,order[id,userRecord[id,email,displayName,userStatus]]],
nextInvoiceTotalRecurringAmount,
location, hourlyFlag, children
]"""
mask = self._DEFAULT_BILLING_ITEM_MASK

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

def get_billing_item_from_invoice(self, identifier, mask=None):
"""Gets details about a billing item of a billing invoice item

:param int identifier: Billing_Invoice_Item id
:param mask: Object mask to use.
:return: Billing_Item
"""
if mask is None:
mask = self._DEFAULT_BILLING_ITEM_MASK
return self.client.call('Billing_Invoice_Item', 'getBillingItem', id=identifier, mask=mask)

def get_item_detail(self, identifier):
"""Gets details about a billing item

:param int identifier: Billing_Item id or Billing_Invoice_Item
:return: Billing_Item
"""

try:
return self.get_billing_item(identifier)
except SoftLayerAPIError as exception:
if exception.faultCode == 404:
return self.get_billing_item_from_invoice(identifier)
raise

def cancel_item(self, identifier, reason="No longer needed", note=None):
"""Cancels a specific billing item with a reason

Expand Down
16 changes: 16 additions & 0 deletions tests/managers/account_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"""

from SoftLayer.managers.account import AccountManager as AccountManager
from SoftLayer import SoftLayerAPIError
from SoftLayer import testing


Expand Down Expand Up @@ -133,3 +134,18 @@ def test_cancel_item(self):
self.manager.cancel_item(12345, reason, note)
self.assert_called_with('SoftLayer_Billing_Item', 'cancelItem',
args=(False, True, reason, note), identifier=12345)

def test_get_billing_item_from_invoice(self):
self.manager.get_billing_item_from_invoice(12345)
self.assert_called_with('SoftLayer_Billing_Invoice_Item', 'getBillingItem', identifier=12345)

def test_get_item_details_with_billing_item_id(self):
self.manager.get_item_detail(12345)
self.assert_called_with('SoftLayer_Billing_Item', 'getObject', identifier=12345)

def test_get_item_details_with_invoice_item_id(self):
mock = self.set_mock('SoftLayer_Billing_Item', 'getObject')
mock.side_effect = SoftLayerAPIError(404, "Unable to find object with id of '123456'.")
self.manager.get_item_detail(123456)
self.assert_called_with('SoftLayer_Billing_Item', 'getObject', identifier=123456)
self.assert_called_with('SoftLayer_Billing_Invoice_Item', 'getBillingItem', identifier=123456)