Skip to content

Commit f6696cb

Browse files
allmightyspiffGitHub Enterprise
authored andcommitted
Merge pull request #696 from Edson-Rios/issue694
New command `ibmcloud sl order cancelation`
2 parents a12cf65 + 194ca9d commit f6696cb

8 files changed

Lines changed: 363 additions & 18 deletions

File tree

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package order
2+
3+
import (
4+
"github.com/IBM-Cloud/ibm-cloud-cli-sdk/bluemix/terminal"
5+
"github.com/softlayer/softlayer-go/datatypes"
6+
"github.com/spf13/cobra"
7+
"github.ibm.com/SoftLayer/softlayer-cli/plugin/errors"
8+
. "github.ibm.com/SoftLayer/softlayer-cli/plugin/i18n"
9+
"github.ibm.com/SoftLayer/softlayer-cli/plugin/managers"
10+
"github.ibm.com/SoftLayer/softlayer-cli/plugin/metadata"
11+
"github.ibm.com/SoftLayer/softlayer-cli/plugin/utils"
12+
)
13+
14+
type CancelationCommand struct {
15+
*metadata.SoftlayerCommand
16+
OrderManager managers.OrderManager
17+
Command *cobra.Command
18+
}
19+
20+
func NewCancelationCommand(sl *metadata.SoftlayerCommand) (cmd *CancelationCommand) {
21+
thisCmd := &CancelationCommand{
22+
SoftlayerCommand: sl,
23+
OrderManager: managers.NewOrderManager(sl.Session),
24+
}
25+
26+
cobraCmd := &cobra.Command{
27+
Use: "cancelation",
28+
Short: T("List cancelations."),
29+
Args: metadata.NoArgs,
30+
RunE: func(cmd *cobra.Command, args []string) error {
31+
return thisCmd.Run(args)
32+
},
33+
}
34+
35+
thisCmd.Command = cobraCmd
36+
return thisCmd
37+
}
38+
39+
func (cmd *CancelationCommand) Run(args []string) error {
40+
outputFormat := cmd.GetOutputFlag()
41+
42+
mask := ""
43+
items, err := cmd.OrderManager.GetAllCancelation(mask)
44+
if err != nil {
45+
return errors.NewAPIError(T("Failed to list all item cancelations."), err.Error(), 2)
46+
}
47+
48+
PrintItemsCancelation(items, cmd.UI, outputFormat)
49+
return nil
50+
}
51+
52+
func PrintItemsCancelation(items []datatypes.Billing_Item_Cancellation_Request, ui terminal.UI, outputFormat string) {
53+
table := ui.Table([]string{
54+
T("Case Number"),
55+
T("Number Of Items Cancelled"),
56+
T("Created"),
57+
T("Status"),
58+
T("Requested by"),
59+
})
60+
61+
for _, item := range items {
62+
requestedBy := utils.FormatStringPointer(item.User.FirstName) + " " + utils.FormatStringPointer(item.User.LastName)
63+
table.Add(
64+
utils.FormatIntPointer(item.TicketId),
65+
utils.FormatUIntPointer(item.ItemCount),
66+
utils.FormatSLTimePointer(item.CreateDate),
67+
utils.FormatStringPointer(item.Status.Name),
68+
requestedBy,
69+
)
70+
}
71+
utils.PrintTable(ui, table, outputFormat)
72+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package order_test
2+
3+
import (
4+
"github.com/IBM-Cloud/ibm-cloud-cli-sdk/testhelpers/terminal"
5+
. "github.com/onsi/ginkgo"
6+
. "github.com/onsi/gomega"
7+
8+
"github.com/softlayer/softlayer-go/session"
9+
10+
"github.ibm.com/SoftLayer/softlayer-cli/plugin/commands/order"
11+
"github.ibm.com/SoftLayer/softlayer-cli/plugin/metadata"
12+
"github.ibm.com/SoftLayer/softlayer-cli/plugin/testhelpers"
13+
)
14+
15+
var _ = Describe("order cancelation", func() {
16+
var (
17+
fakeUI *terminal.FakeUI
18+
cliCommand *order.CancelationCommand
19+
fakeSession *session.Session
20+
slCommand *metadata.SoftlayerCommand
21+
)
22+
BeforeEach(func() {
23+
fakeUI = terminal.NewFakeUI()
24+
fakeSession = testhelpers.NewFakeSoftlayerSession([]string{})
25+
slCommand = metadata.NewSoftlayerCommand(fakeUI, fakeSession)
26+
cliCommand = order.NewCancelationCommand(slCommand)
27+
cliCommand.Command.PersistentFlags().Var(cliCommand.OutputFlag, "output", "--output=JSON for json output.")
28+
})
29+
30+
Describe("order cancelation", func() {
31+
Context("Return error", func() {
32+
It("Set invalid output", func() {
33+
err := testhelpers.RunCobraCommand(cliCommand.Command, "--output=xml")
34+
Expect(err).To(HaveOccurred())
35+
Expect(err.Error()).To(ContainSubstring("Incorrect Usage: Invalid output format, only JSON is supported now."))
36+
})
37+
})
38+
39+
Context("Return no error", func() {
40+
It("List order cancelations", func() {
41+
err := testhelpers.RunCobraCommand(cliCommand.Command)
42+
Expect(err).NotTo(HaveOccurred())
43+
Expect(fakeUI.Outputs()).To(ContainSubstring("Case Number"))
44+
Expect(fakeUI.Outputs()).To(ContainSubstring("153572280"))
45+
Expect(fakeUI.Outputs()).To(ContainSubstring("Number"))
46+
Expect(fakeUI.Outputs()).To(ContainSubstring("1"))
47+
Expect(fakeUI.Outputs()).To(ContainSubstring("Status"))
48+
Expect(fakeUI.Outputs()).To(ContainSubstring("Approved"))
49+
Expect(fakeUI.Outputs()).To(ContainSubstring("Requested by"))
50+
Expect(fakeUI.Outputs()).To(ContainSubstring("UserTest UserLastName"))
51+
})
52+
53+
It("List order cancelations in json format", func() {
54+
err := testhelpers.RunCobraCommand(cliCommand.Command, "--output=json")
55+
Expect(err).NotTo(HaveOccurred())
56+
Expect(fakeUI.Outputs()).To(ContainSubstring(`"Case Number": "153572280",`))
57+
Expect(fakeUI.Outputs()).To(ContainSubstring(`"Number Of Items Cancelled": "1",`))
58+
Expect(fakeUI.Outputs()).To(ContainSubstring(`"Status": "Approved",`))
59+
Expect(fakeUI.Outputs()).To(ContainSubstring(`"Requested by": "UserTest UserLastName"`))
60+
Expect(fakeUI.Outputs()).To(ContainSubstring(`[`))
61+
Expect(fakeUI.Outputs()).To(ContainSubstring(`{`))
62+
Expect(fakeUI.Outputs()).To(ContainSubstring(`}`))
63+
Expect(fakeUI.Outputs()).To(ContainSubstring(`]`))
64+
})
65+
})
66+
67+
})
68+
})

plugin/commands/order/order.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ func SetupCobraCommands(sl *metadata.SoftlayerCommand) *cobra.Command {
2828
cobraCmd.AddCommand(NewQuoteCommand(sl).Command)
2929
cobraCmd.AddCommand(NewQuoteDeleteCommand(sl).Command)
3030
cobraCmd.AddCommand(NewLookupCommand(sl).Command)
31+
cobraCmd.AddCommand(NewCancelationCommand(sl).Command)
3132
return cobraCmd
3233
}
3334

plugin/commands/order/order_suite_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ var availableCommands = []string{
3131
"quote-detail",
3232
"quote-list",
3333
"quote-save",
34+
"cancelation",
3435
}
3536

3637
// This test suite exists to make sure commands don't get accidently removed from the actionBindings

plugin/i18n/resources/en_US.all.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1559,6 +1559,10 @@
15591559
"id": "Capture virtual server instance into an image",
15601560
"translation": "Capture virtual server instance into an image"
15611561
},
1562+
{
1563+
"id": "Case Number",
1564+
"translation": "Case Number"
1565+
},
15621566
{
15631567
"id": "Category",
15641568
"translation": "Category"
@@ -3823,6 +3827,10 @@
38233827
"id": "Failed to list VLANs on your account.\n",
38243828
"translation": "Failed to list VLANs on your account.\n"
38253829
},
3830+
{
3831+
"id": "Failed to list all item cancelations.",
3832+
"translation": "Failed to list all item cancelations."
3833+
},
38263834
{
38273835
"id": "Failed to list available OS's.",
38283836
"translation": "Failed to list available OS's."
@@ -6231,6 +6239,10 @@
62316239
"id": "Number",
62326240
"translation": "Number"
62336241
},
6242+
{
6243+
"id": "Number Of Items Cancelled",
6244+
"translation": "Number Of Items Cancelled"
6245+
},
62346246
{
62356247
"id": "Number of CPU cores",
62366248
"translation": "Number of CPU cores"
@@ -7339,6 +7351,10 @@
73397351
"id": "Request configuration of a tunnel context",
73407352
"translation": "Request configuration of a tunnel context"
73417353
},
7354+
{
7355+
"id": "Requested by",
7356+
"translation": "Requested by"
7357+
},
73427358
{
73437359
"id": "Required User",
73447360
"translation": "Required User"

plugin/managers/order.go

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,19 @@ type OrderManager interface {
4444
OrderQuote(quoteId int, extra datatypes.Container_Product_Order) (datatypes.Container_Product_Order_Receipt, error)
4545
GetRecalculatedOrderContainer(quoteId int) (datatypes.Container_Product_Order, error)
4646
GetOrderDetail(orderId int, mask string) (datatypes.Billing_Order, error)
47+
GetAllCancelation(mask string) ([]datatypes.Billing_Item_Cancellation_Request, error)
4748
DeleteQuote(quoteId int) (datatypes.Billing_Order_Quote, error)
4849
}
4950

5051
type orderManager struct {
51-
PackageService services.Product_Package
52-
OrderService services.Product_Order
53-
LocationService services.Location_Datacenter
54-
PackagePreset services.Product_Package_Preset
55-
AccountService services.Account
56-
BillingOrderQuoteService services.Billing_Order_Quote
57-
Session *session.Session
52+
PackageService services.Product_Package
53+
OrderService services.Product_Order
54+
LocationService services.Location_Datacenter
55+
PackagePreset services.Product_Package_Preset
56+
AccountService services.Account
57+
BillingOrderQuoteService services.Billing_Order_Quote
58+
BillingItemCancellationRequestService services.Billing_Item_Cancellation_Request
59+
Session *session.Session
5860
}
5961

6062
func NewOrderManager(session *session.Session) *orderManager {
@@ -65,14 +67,15 @@ func NewOrderManager(session *session.Session) *orderManager {
6567
services.GetProductPackagePresetService(session),
6668
services.GetAccountService(session),
6769
services.GetBillingOrderQuoteService(session),
70+
services.GetBillingItemCancellationRequestService(session),
6871
session,
6972
}
7073
}
7174

72-
//Get a single package with a given key.
73-
//If no packages are found, returns None
74-
//packageKeyname: string representing the package key name we are interested in.
75-
//mask: Mask to specify the properties we want to retrieve
75+
// Get a single package with a given key.
76+
// If no packages are found, returns None
77+
// packageKeyname: string representing the package key name we are interested in.
78+
// mask: Mask to specify the properties we want to retrieve
7679
func (i orderManager) GetPackageByKey(packageKeyname, mask string) (datatypes.Product_Package, error) {
7780
filters := filter.New(filter.Path("keyName").Eq(packageKeyname))
7881
packages, err := i.PackageService.Filter(filters.Build()).Mask(mask).GetAllObjects()
@@ -85,8 +88,8 @@ func (i orderManager) GetPackageByKey(packageKeyname, mask string) (datatypes.Pr
8588
return packages[len(packages)-1], nil
8689
}
8790

88-
//Get details about an image
89-
//image: The ID of the image.
91+
// Get details about an image
92+
// image: The ID of the image.
9093
func (i orderManager) ListCategories(packageKeyname string) ([]datatypes.Product_Package_Order_Configuration, error) {
9194

9295
packages, err := i.GetPackageByKey(packageKeyname, "id")
@@ -399,23 +402,23 @@ func (i orderManager) GetPresetPrices(presetId int) (datatypes.Product_Package_P
399402
return prices, nil
400403
}
401404

402-
//Returns active quotes on your account
405+
// Returns active quotes on your account
403406
func (i orderManager) GetActiveQuotes(mask string) ([]datatypes.Billing_Order_Quote, error) {
404407
if mask == "" {
405408
mask = "mask[order[id,items[id,package[id,keyName]]]]"
406409
}
407410
return i.AccountService.Mask(mask).GetActiveQuotes()
408411
}
409412

410-
//Returns active quote detail on your account
413+
// Returns active quote detail on your account
411414
func (i orderManager) GetQuote(quoteId int, mask string) (datatypes.Billing_Order_Quote, error) {
412415
if mask == "" {
413416
mask = "mask[order[id,items[package[id,keyName]]]]"
414417
}
415418
return i.BillingOrderQuoteService.Id(quoteId).Mask(mask).GetObject()
416419
}
417420

418-
//Save quote
421+
// Save quote
419422
func (i orderManager) SaveQuote(quoteId int) (datatypes.Billing_Order_Quote, error) {
420423
return i.BillingOrderQuoteService.Id(quoteId).SaveQuote()
421424
}
@@ -443,8 +446,8 @@ func (i orderManager) GetRecalculatedOrderContainer(quoteId int) (datatypes.Cont
443446
}
444447

445448
// Return order detail
446-
//int orderId: The order identifier.
447-
//string mask: The object mask.
449+
// int orderId: The order identifier.
450+
// string mask: The object mask.
448451
func (i orderManager) GetOrderDetail(orderId int, mask string) (datatypes.Billing_Order, error) {
449452
if mask == "" {
450453
mask = `mask[orderTotalAmount,orderApprovalDate,
@@ -461,6 +464,17 @@ func (i orderManager) GetOrderDetail(orderId int, mask string) (datatypes.Billin
461464
return billingOrderService.Id(orderId).Mask(mask).GetObject()
462465
}
463466

467+
/*
468+
Returns all service cancellation requests
469+
https://sldn.softlayer.com/reference/services/SoftLayer_Billing_Item_Cancellation_Request/getAllCancellationRequests/
470+
*/
471+
func (i orderManager) GetAllCancelation(mask string) ([]datatypes.Billing_Item_Cancellation_Request, error) {
472+
if mask == "" {
473+
mask = "mask[id,itemCount,modifyDate,createDate,ticketId,ticket[assignedUserId,id,attachedHardware[id,hostname,domain],attachedVirtualGuests[id,hostname,domain],attachedDedicatedHosts[id,name],serviceProviderResourceId],status[name,id],user[id,firstName,lastName],items[billingItem[cancellationDate,categoryCode,pendingCancellationFlag]]]"
474+
}
475+
return i.BillingItemCancellationRequestService.Mask(mask).GetAllCancellationRequests()
476+
}
477+
464478
// Delete the quote of an order.
465479
func (i orderManager) DeleteQuote(quoteId int) (datatypes.Billing_Order_Quote, error) {
466480
return i.BillingOrderQuoteService.Id(quoteId).DeleteQuote()

0 commit comments

Comments
 (0)