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
24 changes: 17 additions & 7 deletions SoftLayer/CLI/account/invoice_detail.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,22 @@ def cli(env, identifier, details):

manager = AccountManager(env.client)
top_items = manager.get_billing_items(identifier)
table = get_invoice_table(identifier, top_items, details)
env.fout(table)


def nice_string(ugly_string, limit=100):
"""Format and trims strings"""
return (ugly_string[:limit] + '..') if len(ugly_string) > limit else ugly_string


def get_invoice_table(identifier, top_items, details):
"""Formats a table for invoice top level items.

:param int identifier: Invoice identifier.
:param list top_items: invoiceTopLevelItems.
:param bool details: To add very detailed list of charges.
"""

title = "Invoice %s" % identifier
table = formatting.Table(["Item Id", "Category", "Description", "Single",
Expand Down Expand Up @@ -52,10 +68,4 @@ def cli(env, identifier, details):
'---',
'---'
])

env.fout(table)


def nice_string(ugly_string, limit=100):
"""Format and trims strings"""
return (ugly_string[:limit] + '..') if len(ugly_string) > limit else ugly_string
return table
4 changes: 2 additions & 2 deletions SoftLayer/CLI/account/orders.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Order list account"""
"""Lists account orders."""
# :license: MIT, see LICENSE for more details.

import click
Expand All @@ -16,7 +16,7 @@
show_default=True)
@environment.pass_env
def cli(env, limit):
"""Order list account."""
"""Lists account orders. Use `slcli order lookup <ID>` to find more details about a specific order."""
manager = AccountManager(env.client)
orders = manager.get_account_all_billing_orders(limit)

Expand Down
67 changes: 67 additions & 0 deletions SoftLayer/CLI/order/lookup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""Provides some details related to the order."""
# :license: MIT, see LICENSE for more details.

import click

from SoftLayer.CLI.account.invoice_detail import get_invoice_table

from SoftLayer.CLI import environment
from SoftLayer.CLI import formatting
from SoftLayer.managers import ordering
from SoftLayer import utils


@click.command()
@click.argument('identifier')
@click.option('--details', is_flag=True, default=False, show_default=True,
help="Shows a very detailed list of charges")
@environment.pass_env
def cli(env, identifier, details):
"""Provides some details related to order owner, date order, cost information, initial invoice."""

manager = ordering.OrderingManager(env.client)
order = manager.get_order_detail(identifier)
order_table = get_order_table(order)

invoice = order.get('initialInvoice', {})
top_items = invoice.get('invoiceTopLevelItems', [])
invoice_id = invoice.get('id')
invoice_table = get_invoice_table(invoice_id, top_items, details)

order_table.add_row(['Initial Invoice', invoice_table])

env.fout(order_table)


def get_order_table(order):
"""Formats a table for billing order"""

title = "Order {id}".format(id=order.get('id'))
date_format = '%Y-%m-%d'
table = formatting.Table(["Key", "Value"], title=title)
table.align = 'l'

ordered_by = "IBM"
user = order.get('userRecord', None)
if user:
ordered_by = "{} ({})".format(user.get('displayName'), utils.lookup(user, 'userStatus', 'name'))
table.add_row(['Ordered By', ordered_by])

table.add_row(['Create Date', utils.clean_time(order.get('createDate'), date_format, date_format)])
table.add_row(['Modify Date', utils.clean_time(order.get('modifyDate'), date_format, date_format)])
table.add_row(['Order Approval Date', utils.clean_time(order.get('orderApprovalDate'), date_format, date_format)])
table.add_row(['Status', order.get('status')])
table.add_row(['Order Total Amount', "{price:.2f}".format(price=float(order.get('orderTotalAmount', '0')))])
table.add_row(['Invoice Total Amount', "{price:.2f}".
format(price=float(order.get('initialInvoice', {}).get('invoiceTotalAmount', '0')))])

items = order.get('items', [])
item_table = formatting.Table(["Item Description"])
item_table.align['description'] = 'l'

for item in items:
item_table.add_row([item.get('description')])

table.add_row(['Items', item_table])

return table
1 change: 1 addition & 0 deletions SoftLayer/CLI/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@
('order:quote-list', 'SoftLayer.CLI.order.quote_list:cli'),
('order:quote-detail', 'SoftLayer.CLI.order.quote_detail:cli'),
('order:quote', 'SoftLayer.CLI.order.quote:cli'),
('order:lookup', 'SoftLayer.CLI.order.lookup:cli'),

('rwhois', 'SoftLayer.CLI.rwhois'),
('rwhois:edit', 'SoftLayer.CLI.rwhois.edit:cli'),
Expand Down
25 changes: 25 additions & 0 deletions SoftLayer/fixtures/SoftLayer_Billing_Order.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,28 @@
'orderApprovalDate': '2019-09-15T13:13:13-06:00',
'orderTotalAmount': '0'
}]

getObject = {
'accountId': 1234,
'createDate': '2020-09-23T16:22:30-06:00',
'id': 6543210,
'impersonatingUserRecordId': None,
'initialInvoice': {
'amount': '0',
'id': 60012345,
'invoiceTotalAmount': '0'
},
'items': [{
'description': 'Dual Intel Xeon Silver 4210 (20 Cores, 2.20 GHz)'
}],
'modifyDate': '2020-09-23T16:22:32-06:00',
'orderQuoteId': None,
'orderTypeId': 11,
'presaleEventId': None,
'privateCloudOrderFlag': False,
'status': 'APPROVED',
'userRecord': {
'displayName': 'testUser'
},
'userRecordId': 7654321,
}
23 changes: 22 additions & 1 deletion SoftLayer/managers/ordering.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

from SoftLayer import exceptions


CATEGORY_MASK = '''id, isRequired, itemCategory[id, name, categoryCode]'''

ITEM_MASK = '''id, keyName, description, itemCategory, categories, prices'''
Expand Down Expand Up @@ -61,6 +60,28 @@ def get_packages_of_type(self, package_types, mask=None):
packages = self.filter_outlet_packages(packages)
return packages

def get_order_detail(self, order_id, mask=None):
"""Get order details.

:param int order_id: to specify the order that we want to retrieve.
:param string mask: Mask to specify the properties we want to retrieve.
"""
_default_mask = (
'mask[orderTotalAmount,orderApprovalDate,'
'initialInvoice[id,amount,invoiceTotalAmount,'
'invoiceTopLevelItems[id, description, hostName, domainName, oneTimeAfterTaxAmount,'
'recurringAfterTaxAmount, createDate,'
'categoryCode,'
'category[name],'
'location[name],'
'children[id, category[name], description, oneTimeAfterTaxAmount,recurringAfterTaxAmount]]],'
'items[description],userRecord[displayName,userStatus]]')

mask = _default_mask if mask is None else mask

order = self.billing_svc.getObject(mask=mask, id=order_id)
return order

@staticmethod
def filter_outlet_packages(packages):
"""Remove packages designated as OUTLET.
Expand Down
6 changes: 6 additions & 0 deletions docs/cli/ordering.rst
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,9 @@ Quotes
.. click:: SoftLayer.CLI.order.place_quote:cli
:prog: order place-quote
:show-nested:

Lookup
======
.. click:: SoftLayer.CLI.order.lookup:cli
:prog: order lookup
:show-nested:
7 changes: 7 additions & 0 deletions tests/CLI/modules/order_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,13 @@ def _get_verified_order_return(self):
'recurringFee': '150'}
return {'orderContainers': [{'prices': [price1, price2]}]}

def test_order_lookup(self):
result = self.run_command(['order', 'lookup', '12345'])
self.assert_no_fail(result)
self.assert_called_with('SoftLayer_Billing_Order', 'getObject', identifier='12345')
self.assertIn('Ordered By', result.output)
self.assertIn('Initial Invoice', result.output)


def _get_all_packages():
package_type = {'keyName': 'BARE_METAL_CPU'}
Expand Down
27 changes: 24 additions & 3 deletions tests/managers/ordering_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -731,7 +731,7 @@ def test_get_item_capacity_core(self):
"capacity": "1",
"id": 10201,
"keyName": "GUEST_CORE_1_DEDICATED",
}]
}]

item_capacity = self.ordering.get_item_capacity(items, ['GUEST_CORE_1_DEDICATED', 'OS_RHEL_7_X_LAMP_64_BIT'])

Expand All @@ -748,7 +748,7 @@ def test_get_item_capacity_storage(self):
"capacity": "1",
"id": 10201,
"keyName": "READHEAVY_TIER",
}]
}]

item_capacity = self.ordering.get_item_capacity(items, ['READHEAVY_TIER', 'STORAGE_SPACE_FOR_2_IOPS_PER_GB'])

Expand All @@ -766,7 +766,7 @@ def test_get_item_capacity_intel(self):
"capacity": "1",
"id": 10201,
"keyName": "GUEST_CORE_1_DEDICATED",
}]
}]

item_capacity = self.ordering.get_item_capacity(items, ['INTEL_XEON_2690_2_60', 'BANDWIDTH_20000_GB'])

Expand Down Expand Up @@ -805,3 +805,24 @@ def test_get_item_prices_by_location(self):

self.assertEqual(options[0]['item']['keyName'], item_prices[0]['item']['keyName'])
self.assertEqual(options[0]['hourlyRecurringFee'], item_prices[0]['hourlyRecurringFee'])

def test_get_oder_detail_mask(self):
order_id = 12345
test_mask = 'mask[id]'
self.ordering.get_order_detail(order_id, mask=test_mask)
self.assert_called_with('SoftLayer_Billing_Order', 'getObject', identifier=order_id, mask=test_mask)

def test_get_oder_detail_default_mask(self):
order_id = 12345
_default_mask = (
'mask[orderTotalAmount,orderApprovalDate,'
'initialInvoice[id,amount,invoiceTotalAmount,'
'invoiceTopLevelItems[id, description, hostName, domainName, oneTimeAfterTaxAmount,'
'recurringAfterTaxAmount, createDate,'
'categoryCode,'
'category[name],'
'location[name],'
'children[id, category[name], description, oneTimeAfterTaxAmount,recurringAfterTaxAmount]]],'
'items[description],userRecord[displayName,userStatus]]')
self.ordering.get_order_detail(order_id)
self.assert_called_with('SoftLayer_Billing_Order', 'getObject', identifier=order_id, mask=_default_mask)