From 80d3a625fe2f02069b1d9e037f4c28bcc2861ccc Mon Sep 17 00:00:00 2001 From: maxwelbm Date: Thu, 14 Nov 2024 18:39:42 -0300 Subject: [PATCH] feat: create sub command delete from products --- .../mdz/internal/domain/repository/product.go | 1 + .../domain/repository/product_mock.go | 14 +++ components/mdz/internal/rest/product.go | 26 +++++ components/mdz/internal/rest/product_test.go | 33 ++++++ components/mdz/pkg/cmd/portfolio/delete.go | 4 +- components/mdz/pkg/cmd/product/delete.go | 107 ++++++++++++++++++ components/mdz/pkg/cmd/product/delete_test.go | 45 ++++++++ components/mdz/pkg/cmd/product/product.go | 1 + 8 files changed, 229 insertions(+), 2 deletions(-) create mode 100644 components/mdz/pkg/cmd/product/delete.go create mode 100644 components/mdz/pkg/cmd/product/delete_test.go diff --git a/components/mdz/internal/domain/repository/product.go b/components/mdz/internal/domain/repository/product.go index 3284cf6b..90552019 100644 --- a/components/mdz/internal/domain/repository/product.go +++ b/components/mdz/internal/domain/repository/product.go @@ -7,4 +7,5 @@ type Product interface { Get(organizationID, ledgerID string, limit, page int) (*mmodel.Products, error) GetByID(organizationID, ledgerID, productID string) (*mmodel.Product, error) Update(organizationID, ledgerID, productID string, inp mmodel.UpdateProductInput) (*mmodel.Product, error) + Delete(organizationID, ledgerID, productID string) error } diff --git a/components/mdz/internal/domain/repository/product_mock.go b/components/mdz/internal/domain/repository/product_mock.go index 7def08e3..0e837151 100644 --- a/components/mdz/internal/domain/repository/product_mock.go +++ b/components/mdz/internal/domain/repository/product_mock.go @@ -55,6 +55,20 @@ func (mr *MockProductMockRecorder) Create(organizationID, ledgerID, inp any) *go return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockProduct)(nil).Create), organizationID, ledgerID, inp) } +// Delete mocks base method. +func (m *MockProduct) Delete(organizationID, ledgerID, productID string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", organizationID, ledgerID, productID) + ret0, _ := ret[0].(error) + return ret0 +} + +// Delete indicates an expected call of Delete. +func (mr *MockProductMockRecorder) Delete(organizationID, ledgerID, productID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockProduct)(nil).Delete), organizationID, ledgerID, productID) +} + // Get mocks base method. func (m *MockProduct) Get(organizationID, ledgerID string, limit, page int) (*mmodel.Products, error) { m.ctrl.T.Helper() diff --git a/components/mdz/internal/rest/product.go b/components/mdz/internal/rest/product.go index 3fc1dce8..b240f7b1 100644 --- a/components/mdz/internal/rest/product.go +++ b/components/mdz/internal/rest/product.go @@ -148,6 +148,32 @@ func (r *product) Update( return &productResp, nil } +func (r *product) Delete(organizationID, ledgerID, productID string) error { + uri := fmt.Sprintf("%s/v1/organizations/%s/ledgers/%s/products/%s", + r.Factory.Env.URLAPILedger, organizationID, ledgerID, productID) + + req, err := http.NewRequest(http.MethodDelete, uri, nil) + if err != nil { + return errors.New("creating request: " + err.Error()) + } + + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+r.Factory.Token) + + resp, err := r.Factory.HTTPClient.Do(req) + if err != nil { + return errors.New("making Delete request: " + err.Error()) + } + + defer resp.Body.Close() + + if err := checkResponse(resp, http.StatusNoContent); err != nil { + return err + } + + return nil +} + func NewProduct(f *factory.Factory) *product { return &product{f} } diff --git a/components/mdz/internal/rest/product_test.go b/components/mdz/internal/rest/product_test.go index a5576a75..a0e02d22 100644 --- a/components/mdz/internal/rest/product_test.go +++ b/components/mdz/internal/rest/product_test.go @@ -297,3 +297,36 @@ func Test_product_Update(t *testing.T) { info := httpmock.GetCallCountInfo() assert.Equal(t, 1, info["PATCH "+uri]) } + +func Test_product_Delete(t *testing.T) { + productID := "01930219-2c25-7a37-a5b9-610d44ae0a27" + ledgerID := "0192fc1e-14bf-7894-b167-6e4a878b3a95" + organizationID := "0192fc1d-f34d-78c9-9654-83e497349241" + URIAPILedger := "http://127.0.0.1:3000" + + client := &http.Client{} + httpmock.ActivateNonDefault(client) + defer httpmock.DeactivateAndReset() + + uri := fmt.Sprintf("%s/v1/organizations/%s/ledgers/%s/products/%s", + URIAPILedger, organizationID, ledgerID, productID) + + httpmock.RegisterResponder(http.MethodDelete, uri, + httpmock.NewStringResponder(http.StatusNoContent, "")) + + factory := &factory.Factory{ + HTTPClient: client, + Env: &environment.Env{ + URLAPILedger: URIAPILedger, + }, + } + + product := NewProduct(factory) + + err := product.Delete(organizationID, ledgerID, productID) + + assert.NoError(t, err) + + info := httpmock.GetCallCountInfo() + assert.Equal(t, 1, info["DELETE "+uri]) +} diff --git a/components/mdz/pkg/cmd/portfolio/delete.go b/components/mdz/pkg/cmd/portfolio/delete.go index 782bf2cd..3da4a29f 100644 --- a/components/mdz/pkg/cmd/portfolio/delete.go +++ b/components/mdz/pkg/cmd/portfolio/delete.go @@ -40,8 +40,8 @@ func (f *factoryPortfolioDelete) ensureFlagInput(cmd *cobra.Command) error { f.LedgerID = id } - if !cmd.Flags().Changed("asset-id") && len(f.PortfolioID) < 1 { - id, err := tui.Input("Enter your asset-id") + if !cmd.Flags().Changed("portfolio-id") && len(f.PortfolioID) < 1 { + id, err := tui.Input("Enter your portfolio-id") if err != nil { return err } diff --git a/components/mdz/pkg/cmd/product/delete.go b/components/mdz/pkg/cmd/product/delete.go new file mode 100644 index 00000000..2c654929 --- /dev/null +++ b/components/mdz/pkg/cmd/product/delete.go @@ -0,0 +1,107 @@ +package product + +import ( + "fmt" + + "github.com/LerianStudio/midaz/components/mdz/internal/domain/repository" + "github.com/LerianStudio/midaz/components/mdz/internal/rest" + "github.com/LerianStudio/midaz/components/mdz/pkg/cmd/utils" + "github.com/LerianStudio/midaz/components/mdz/pkg/factory" + "github.com/LerianStudio/midaz/components/mdz/pkg/output" + "github.com/LerianStudio/midaz/components/mdz/pkg/tui" + "github.com/spf13/cobra" +) + +type factoryProductDelete struct { + factory *factory.Factory + repoProduct repository.Product + tuiInput func(message string) (string, error) + OrganizationID string + LedgerID string + ProductID string +} + +func (f *factoryProductDelete) ensureFlagInput(cmd *cobra.Command) error { + if !cmd.Flags().Changed("organization-id") && len(f.OrganizationID) < 1 { + id, err := tui.Input("Enter your organization-id") + if err != nil { + return err + } + + f.OrganizationID = id + } + + if !cmd.Flags().Changed("ledger-id") && len(f.LedgerID) < 1 { + id, err := tui.Input("Enter your ledger-id") + if err != nil { + return err + } + + f.LedgerID = id + } + + if !cmd.Flags().Changed("product-id") && len(f.ProductID) < 1 { + id, err := tui.Input("Enter your product-id") + if err != nil { + return err + } + + f.ProductID = id + } + + return nil +} + +func (f *factoryProductDelete) runE(cmd *cobra.Command, _ []string) error { + if err := f.ensureFlagInput(cmd); err != nil { + return err + } + + err := f.repoProduct.Delete(f.OrganizationID, f.LedgerID, f.ProductID) + if err != nil { + return err + } + + output.Printf(f.factory.IOStreams.Out, + fmt.Sprintf("The Product ID %s has been successfully deleted.", f.ProductID)) + + return nil +} + +func (f *factoryProductDelete) setFlags(cmd *cobra.Command) { + cmd.Flags().StringVar(&f.OrganizationID, "organization-id", "", "Specify the organization ID.") + cmd.Flags().StringVar(&f.LedgerID, "ledger-id", "", "Specify the ledger ID") + cmd.Flags().StringVar(&f.ProductID, "product-id", "", "Specify the portfolio ID") + cmd.Flags().BoolP("help", "h", false, "Displays more information about the Mdz CLI") +} + +func newInjectFacDelete(f *factory.Factory) *factoryProductDelete { + return &factoryProductDelete{ + factory: f, + repoProduct: rest.NewProduct(f), + tuiInput: tui.Input, + } +} + +func newCmdProductDelete(f *factoryProductDelete) *cobra.Command { + cmd := &cobra.Command{ + Use: "delete", + Short: "Removes an existing product.", + Long: utils.Format( + "The delete subcommand allows you to delete a product, removing its", + "settings and clustering rules. It is useful for deactivating obsolete", + "clusters or adjusting the organization of products without changing", + "the structure of customers.", + ), + Example: utils.Format( + "$ mdz product delete --organization-id '1234' --ledger-id '4421' --product-id '55232'", + "$ mdz product delete -i 12314", + "$ mdz product delete -h", + ), + RunE: f.runE, + } + + f.setFlags(cmd) + + return cmd +} diff --git a/components/mdz/pkg/cmd/product/delete_test.go b/components/mdz/pkg/cmd/product/delete_test.go new file mode 100644 index 00000000..c7b8194f --- /dev/null +++ b/components/mdz/pkg/cmd/product/delete_test.go @@ -0,0 +1,45 @@ +package product + +import ( + "bytes" + "testing" + + "github.com/LerianStudio/midaz/components/mdz/internal/domain/repository" + "github.com/LerianStudio/midaz/components/mdz/pkg/factory" + "github.com/LerianStudio/midaz/components/mdz/pkg/iostreams" + "github.com/stretchr/testify/assert" + "go.uber.org/mock/gomock" +) + +func Test_newCmdProductDelete(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockRepo := repository.NewMockProduct(ctrl) + + factory := factoryProductDelete{ + factory: &factory.Factory{IOStreams: &iostreams.IOStreams{ + Out: &bytes.Buffer{}, + Err: &bytes.Buffer{}, + }}, + repoProduct: mockRepo, + OrganizationID: "321", + LedgerID: "123", + ProductID: "444", + } + + cmd := newCmdProductDelete(&factory) + cmd.SetArgs([]string{ + "--organization-id", "321", + "--ledger-id", "123", + "--product-id", "444", + }) + + mockRepo.EXPECT().Delete(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + + err := cmd.Execute() + assert.NoError(t, err) + + output := factory.factory.IOStreams.Out.(*bytes.Buffer).String() + assert.Contains(t, output, "The Product ID 444 has been successfully deleted.") +} diff --git a/components/mdz/pkg/cmd/product/product.go b/components/mdz/pkg/cmd/product/product.go index 5a972fe6..b3606478 100644 --- a/components/mdz/pkg/cmd/product/product.go +++ b/components/mdz/pkg/cmd/product/product.go @@ -15,6 +15,7 @@ func (f *factoryProduct) setCmds(cmd *cobra.Command) { cmd.AddCommand(newCmdProductList(newInjectFacList(f.factory))) cmd.AddCommand(newCmdProductDescribe(newInjectFacDescribe(f.factory))) cmd.AddCommand(newCmdProductUpdate(newInjectFacUpdate(f.factory))) + cmd.AddCommand(newCmdProductDelete(newInjectFacDelete(f.factory))) } func NewCmdProduct(f *factory.Factory) *cobra.Command {