Skip to content

Commit f86bd27

Browse files
allmightyspiffGitHub Enterprise
authored andcommitted
Merge pull request #913 from SoftLayer/issues903
account item-detail will try looking up the billing_invoice_item
2 parents 1b8581b + f8fdc76 commit f86bd27

File tree

5 files changed

+349
-4
lines changed

5 files changed

+349
-4
lines changed

plugin/commands/account/item-detail.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,20 @@ func (cmd *ItemDetailCommand) Run(args []string) error {
4848

4949
outputFormat := cmd.GetOutputFlag()
5050

51-
mask := "mask[orderItem[id,order[id,userRecord[id,email,displayName,userStatus]]],nextInvoiceTotalRecurringAmount,location, hourlyFlag, children]"
51+
mask := `mask[
52+
orderItem[id,order[id,userRecord[id,email,displayName,userStatus]]],
53+
nextInvoiceTotalRecurringAmount,location, hourlyFlag, children
54+
]`
55+
// The ID entered is from 'account billing-items'
5256
item, err := cmd.AccountManager.GetItemDetail(itemID, mask)
5357
if err != nil {
54-
subs := map[string]interface{}{"itemID": itemID}
55-
return slErr.NewAPIError(T("Failed to get the item {{.itemID}}. ", subs), err.Error(), 2)
58+
// ID entered might be from 'account invoice-detail <ID>'
59+
item, err = cmd.AccountManager.GetItemDetailFromInvoiceItem(itemID, mask)
60+
if err != nil {
61+
subs := map[string]interface{}{"itemID": itemID}
62+
return slErr.NewAPIError(T("Failed to get the item {{.itemID}}. ", subs), err.Error(), 2)
63+
}
64+
5665
}
5766
PrintItemDetail(itemID, item, cmd.UI, outputFormat)
5867
return nil

plugin/commands/account/item-detail_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"github.com/IBM-Cloud/ibm-cloud-cli-sdk/testhelpers/terminal"
55
. "github.com/onsi/ginkgo/v2"
66
. "github.com/onsi/gomega"
7+
. "github.com/onsi/gomega/gstruct"
78
"github.com/softlayer/softlayer-go/session"
89

910
"github.ibm.com/SoftLayer/softlayer-cli/plugin/commands/account"
@@ -17,14 +18,20 @@ var _ = Describe("Account list ItemDetail", func() {
1718
cliCommand *account.ItemDetailCommand
1819
fakeSession *session.Session
1920
slCommand *metadata.SoftlayerCommand
21+
fakeHandler *testhelpers.FakeTransportHandler
2022
)
2123
BeforeEach(func() {
2224
fakeUI = terminal.NewFakeUI()
2325
fakeSession = testhelpers.NewFakeSoftlayerSession([]string{})
26+
fakeHandler = testhelpers.GetSessionHandler(fakeSession)
2427
slCommand = metadata.NewSoftlayerCommand(fakeUI, fakeSession)
2528
cliCommand = account.NewItemDetailCommand(slCommand)
2629
cliCommand.Command.PersistentFlags().Var(cliCommand.OutputFlag, "output", "--output=JSON for json output.")
2730
})
31+
AfterEach(func() {
32+
fakeHandler.ClearApiCallLogs()
33+
fakeHandler.ClearErrors()
34+
})
2835

2936
Describe("Account item detail", func() {
3037
Context("Account item detail, Invalid Usage", func() {
@@ -81,6 +88,26 @@ var _ = Describe("Account list ItemDetail", func() {
8188
Expect(fakeUI.Outputs()).To(ContainSubstring(`}`))
8289
Expect(fakeUI.Outputs()).To(ContainSubstring(`]`))
8390
})
91+
It("Test Fallback to GetItemDetailFromInvoiceItem", func() {
92+
fakeHandler.AddApiError("SoftLayer_Billing_Item", "getObject", 404, "NOT FOUND")
93+
err := testhelpers.RunCobraCommand(cliCommand.Command, "999")
94+
Expect(err).NotTo(HaveOccurred())
95+
output := fakeUI.Outputs()
96+
apiCalls := fakeHandler.ApiCallLogs
97+
Expect(len(apiCalls)).To(Equal(2))
98+
Expect(output).To(ContainSubstring("gw.ibm.me"))
99+
Expect(output).To(ContainSubstring("Dual Intel Xeon Gold 5218 (32 Cores, 2.30 GHz)"))
100+
Expect(apiCalls[0]).To(MatchFields(IgnoreExtras, Fields{
101+
"Service": Equal("SoftLayer_Billing_Item"),
102+
"Method": Equal("getObject"),
103+
"Options": PointTo(MatchFields(IgnoreExtras, Fields{"Id": PointTo(Equal(999))})),
104+
}))
105+
Expect(apiCalls[1]).To(MatchFields(IgnoreExtras, Fields{
106+
"Service": Equal("SoftLayer_Billing_Invoice_Item"),
107+
"Method": Equal("getBillingItem"),
108+
"Options": PointTo(MatchFields(IgnoreExtras, Fields{"Id": PointTo(Equal(999))})),
109+
}))
110+
})
84111
})
85112
})
86113
})

plugin/managers/account.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ type AccountManager interface {
2323
GetInvoices(limit int, closed bool, getAll bool) ([]datatypes.Billing_Invoice, error)
2424
CancelItem(identifier int) error
2525
GetItemDetail(identifier int, mask string) (datatypes.Billing_Item, error)
26+
GetItemDetailFromInvoiceItem(identifier int, mask string) (datatypes.Billing_Item, error)
2627
GetActiveVirtualLicenses(mask string) ([]datatypes.Software_VirtualLicense, error)
2728
GetActiveAccountLicenses(mask string) ([]datatypes.Software_AccountLicense, error)
2829
GetAccountAllBillingOrders(mask string, limit int) ([]datatypes.Billing_Order, error)
@@ -184,7 +185,10 @@ func (a accountManager) GetInvoices(limit int, closed bool, getAll bool) ([]data
184185
mask := "mask[invoiceTotalAmount, itemCount]"
185186
filters := filter.New()
186187
filters = append(filters, filter.Path("invoices.id").OrderBy("DESC"))
187-
if !closed || !getAll {
188+
if getAll { // If they want all invoice, included Closed status
189+
closed = true
190+
}
191+
if !closed {
188192
filters = append(filters, filter.Path("invoices.statusCode").Eq("OPEN"))
189193
}
190194
resourceList := []datatypes.Billing_Invoice{}
@@ -239,6 +243,15 @@ func (a accountManager) GetItemDetail(identifier int, mask string) (datatypes.Bi
239243
return BillingItemService.Mask(mask).Id(identifier).GetObject()
240244
}
241245

246+
/*
247+
Gets the detail of a item from an invoice item
248+
https://sldn.softlayer.com/reference/services/SoftLayer_Billing_Invoice_Item/getBillingItem/
249+
*/
250+
func (a accountManager) GetItemDetailFromInvoiceItem(identifier int, mask string) (datatypes.Billing_Item, error) {
251+
BillingItemService := services.GetBillingInvoiceItemService(a.Session)
252+
return BillingItemService.Mask(mask).Id(identifier).GetBillingItem()
253+
}
254+
242255
/*
243256
Gets virtual software licenses controlled by an account
244257
https://sldn.softlayer.com/reference/services/SoftLayer_Account/getActiveVirtualLicenses/
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
{
2+
"allowCancellationFlag": 1,
3+
"cancellationDate": null,
4+
"categoryCode": "server",
5+
"createDate": "2024-09-26T02:15:54-07:00",
6+
"cycleStartDate": "2025-03-04T00:08:01-06:00",
7+
"description": "Dual Intel Xeon Gold 5218 (32 Cores, 2.30 GHz)",
8+
"domainName": "ibm.me",
9+
"hostName": "gw",
10+
"id": 1168682641,
11+
"laborFee": "0",
12+
"laborFeeTaxRate": "0",
13+
"lastBillDate": "2025-03-04T00:08:01-06:00",
14+
"modifyDate": "2025-03-04T00:08:01-06:00",
15+
"nextBillDate": "2025-04-03T22:00:00-07:00",
16+
"oneTimeFee": "0",
17+
"oneTimeFeeTaxRate": "0",
18+
"orderItemId": 1088026403,
19+
"packageId": 1057,
20+
"parentId": null,
21+
"recurringFee": "0",
22+
"recurringFeeTaxRate": "0",
23+
"recurringMonths": 1,
24+
"serviceProviderId": 1,
25+
"setupFee": "0",
26+
"setupFeeTaxRate": "0",
27+
"children": [
28+
{
29+
"allowCancellationFlag": 1,
30+
"associatedBillingItemId": "1168682641",
31+
"cancellationDate": null,
32+
"categoryCode": "second_processor",
33+
"createDate": "2024-09-26T02:15:54-07:00",
34+
"cycleStartDate": "2025-03-04T00:08:01-06:00",
35+
"description": "Intel Xeon Gold 5218 (32 Cores, 2.30 GHz)",
36+
"id": 1168682643,
37+
"laborFee": "0",
38+
"laborFeeTaxRate": "0",
39+
"lastBillDate": "2025-03-04T00:08:01-06:00",
40+
"modifyDate": "2025-03-04T00:08:01-06:00",
41+
"nextBillDate": "2025-04-03T22:00:00-07:00",
42+
"oneTimeFee": "0",
43+
"oneTimeFeeTaxRate": "0",
44+
"orderItemId": 1088026405,
45+
"packageId": 1057,
46+
"parentId": 1168682641,
47+
"recurringFee": "0",
48+
"recurringFeeTaxRate": "0",
49+
"recurringMonths": 1,
50+
"serviceProviderId": 1,
51+
"setupFee": "0",
52+
"setupFeeTaxRate": "0"
53+
},
54+
{
55+
"allowCancellationFlag": 1,
56+
"associatedBillingItemId": "1168682641",
57+
"cancellationDate": null,
58+
"categoryCode": "sriov_enabled",
59+
"createDate": "2024-09-26T02:15:54-07:00",
60+
"cycleStartDate": "2025-03-04T00:08:02-06:00",
61+
"description": "SRIOV Enabled",
62+
"id": 1168682655,
63+
"laborFee": "0",
64+
"laborFeeTaxRate": "0",
65+
"lastBillDate": "2025-03-04T00:08:02-06:00",
66+
"modifyDate": "2025-03-04T00:08:02-06:00",
67+
"nextBillDate": "2025-04-03T22:00:00-07:00",
68+
"oneTimeFee": "0",
69+
"oneTimeFeeTaxRate": "0",
70+
"orderItemId": 1088026417,
71+
"packageId": 1057,
72+
"parentId": 1168682641,
73+
"recurringFee": "0",
74+
"recurringFeeTaxRate": "0",
75+
"recurringMonths": 1,
76+
"serviceProviderId": 1,
77+
"setupFee": "0",
78+
"setupFeeTaxRate": "0"
79+
},
80+
{
81+
"allowCancellationFlag": 1,
82+
"associatedBillingItemId": "1168682641",
83+
"cancellationDate": null,
84+
"categoryCode": "bandwidth",
85+
"createDate": "2024-09-26T02:15:54-07:00",
86+
"cycleStartDate": "2025-03-04T00:08:02-06:00",
87+
"description": "20000 GB Bandwidth Allotment",
88+
"id": 1168682657,
89+
"laborFee": "0",
90+
"laborFeeTaxRate": "0",
91+
"lastBillDate": "2025-03-04T00:08:02-06:00",
92+
"modifyDate": "2025-03-04T00:08:02-06:00",
93+
"nextBillDate": "2025-04-03T22:00:00-07:00",
94+
"oneTimeFee": "0",
95+
"oneTimeFeeTaxRate": "0",
96+
"orderItemId": 1088026419,
97+
"packageId": 1057,
98+
"parentId": 1168682641,
99+
"recurringFee": "0",
100+
"recurringFeeTaxRate": "0",
101+
"recurringMonths": 1,
102+
"serviceProviderId": 1,
103+
"setupFee": "0",
104+
"setupFeeTaxRate": "0"
105+
},
106+
{
107+
"allowCancellationFlag": 1,
108+
"associatedBillingItemId": "1168682641",
109+
"cancellationDate": null,
110+
"categoryCode": "port_speed",
111+
"createDate": "2024-09-26T02:15:54-07:00",
112+
"cycleStartDate": "2025-03-04T00:08:02-06:00",
113+
"description": "10 Gbps Dual Public & Private Network Uplinks (Unbonded)",
114+
"id": 1168682659,
115+
"laborFee": "0",
116+
"laborFeeTaxRate": "0",
117+
"lastBillDate": "2025-03-04T00:08:02-06:00",
118+
"modifyDate": "2025-03-04T00:08:02-06:00",
119+
"nextBillDate": "2025-04-03T22:00:00-07:00",
120+
"oneTimeFee": "0",
121+
"oneTimeFeeTaxRate": "0",
122+
"orderItemId": 1088026421,
123+
"packageId": 1057,
124+
"parentId": 1168682641,
125+
"recurringFee": "0",
126+
"recurringFeeTaxRate": "0",
127+
"recurringMonths": 1,
128+
"serviceProviderId": 1,
129+
"setupFee": "0",
130+
"setupFeeTaxRate": "0"
131+
},
132+
{
133+
"allowCancellationFlag": 1,
134+
"associatedBillingItemId": "1168682641",
135+
"cancellationDate": null,
136+
"categoryCode": "service_port",
137+
"createDate": "2024-09-26T02:15:54-07:00",
138+
"cycleStartDate": "2025-03-04T00:08:02-06:00",
139+
"description": "10 Gbps Dual Private Uplinks (Unbonded)",
140+
"id": 1168682661,
141+
"laborFee": "0",
142+
"laborFeeTaxRate": "0",
143+
"lastBillDate": "2025-03-04T00:08:02-06:00",
144+
"modifyDate": "2025-03-04T00:08:02-06:00",
145+
"nextBillDate": "2025-04-03T22:00:00-07:00",
146+
"oneTimeFee": "0",
147+
"oneTimeFeeTaxRate": "0",
148+
"orderItemId": 1088026423,
149+
"packageId": 1057,
150+
"parentId": 1168682641,
151+
"recurringFee": "0",
152+
"recurringFeeTaxRate": "0",
153+
"recurringMonths": 1,
154+
"serviceProviderId": 1,
155+
"setupFee": "0",
156+
"setupFeeTaxRate": "0"
157+
},
158+
{
159+
"allowCancellationFlag": 1,
160+
"associatedBillingItemId": "1168682641",
161+
"cancellationDate": null,
162+
"categoryCode": "public_port",
163+
"createDate": "2024-09-26T02:15:54-07:00",
164+
"cycleStartDate": "2025-03-04T00:08:02-06:00",
165+
"description": "10 Gbps Dual Public Uplinks (Unbonded)",
166+
"id": 1168682663,
167+
"laborFee": "0",
168+
"laborFeeTaxRate": "0",
169+
"lastBillDate": "2025-03-04T00:08:02-06:00",
170+
"modifyDate": "2025-03-04T00:08:02-06:00",
171+
"nextBillDate": "2025-04-03T22:00:00-07:00",
172+
"oneTimeFee": "0",
173+
"oneTimeFeeTaxRate": "0",
174+
"orderItemId": 1088026425,
175+
"packageId": 1057,
176+
"parentId": 1168682641,
177+
"recurringFee": "0",
178+
"recurringFeeTaxRate": "0",
179+
"recurringMonths": 1,
180+
"serviceProviderId": 1,
181+
"setupFee": "0",
182+
"setupFeeTaxRate": "0"
183+
}
184+
],
185+
"hourlyFlag": false,
186+
"location": {
187+
"id": 449506,
188+
"longName": "Frankfurt 2",
189+
"name": "fra02",
190+
"statusId": 2,
191+
"locationStatus": {
192+
"id": 2,
193+
"status": "Active"
194+
}
195+
},
196+
"nextInvoiceTotalRecurringAmount": 0,
197+
"orderItem": {
198+
"id": 1088026403,
199+
"order": {
200+
"id": 119644655,
201+
"userRecord": {
202+
"displayName": "IUBMASC",
203+
"email": "[email protected]",
204+
"iamId": "SL-1234",
205+
"id": 8150224,
206+
"userStatus": {
207+
"id": 1001,
208+
"keyName": "ACTIVE",
209+
"name": "Active"
210+
}
211+
}
212+
}
213+
},
214+
"resourceTableId": 1901854
215+
}

0 commit comments

Comments
 (0)