-
-
Notifications
You must be signed in to change notification settings - Fork 49
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(fctl): add reconciliation (#1077)
- Loading branch information
1 parent
5eceba9
commit 562120a
Showing
21 changed files
with
1,039 additions
and
49 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
package reconciliation | ||
|
||
import ( | ||
"fmt" | ||
"time" | ||
|
||
fctl "github.com/formancehq/fctl/pkg" | ||
"github.com/formancehq/formance-sdk-go/pkg/models/operations" | ||
"github.com/formancehq/formance-sdk-go/pkg/models/shared" | ||
"github.com/pterm/pterm" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
type ListStore struct { | ||
Cursor *shared.ReconciliationsCursorResponseCursor `json:"cursor"` | ||
} | ||
|
||
type ListController struct { | ||
store *ListStore | ||
|
||
cursorFlag string | ||
pageSizeFlag string | ||
} | ||
|
||
var _ fctl.Controller[*ListStore] = (*ListController)(nil) | ||
|
||
func NewListStore() *ListStore { | ||
return &ListStore{ | ||
Cursor: &shared.ReconciliationsCursorResponseCursor{}, | ||
} | ||
} | ||
|
||
func NewListController() *ListController { | ||
return &ListController{ | ||
store: NewListStore(), | ||
|
||
cursorFlag: "cursor", | ||
pageSizeFlag: "page-size", | ||
} | ||
} | ||
|
||
func (c *ListController) GetStore() *ListStore { | ||
return c.store | ||
} | ||
|
||
func (c *ListController) Run(cmd *cobra.Command, args []string) (fctl.Renderable, error) { | ||
cfg, err := fctl.GetConfig(cmd) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
organizationID, err := fctl.ResolveOrganizationID(cmd, cfg) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
stack, err := fctl.ResolveStack(cmd, cfg, organizationID) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
client, err := fctl.NewStackClient(cmd, cfg, stack) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var cursor *string | ||
if c := fctl.GetString(cmd, c.cursorFlag); c != "" { | ||
cursor = &c | ||
} | ||
|
||
var pageSize *int64 | ||
if ps := fctl.GetInt(cmd, c.pageSizeFlag); ps > 0 { | ||
pageSize = fctl.Ptr(int64(ps)) | ||
} | ||
|
||
response, err := client.Reconciliation.ListReconciliations( | ||
cmd.Context(), | ||
operations.ListReconciliationsRequest{ | ||
Cursor: cursor, | ||
PageSize: pageSize, | ||
}, | ||
) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if response.StatusCode >= 300 { | ||
return nil, fmt.Errorf("unexpected status code: %d", response.StatusCode) | ||
} | ||
|
||
c.store.Cursor = &response.ReconciliationsCursorResponse.Cursor | ||
|
||
return c, nil | ||
} | ||
|
||
func (c *ListController) Render(cmd *cobra.Command, args []string) error { | ||
tableData := fctl.Map(c.store.Cursor.Data, func(p shared.Reconciliation) []string { | ||
return []string{ | ||
p.ID, | ||
p.PolicyID, | ||
p.CreatedAt.Format(time.RFC3339), | ||
p.ReconciledAtLedger.Format(time.RFC3339), | ||
p.ReconciledAtPayments.Format(time.RFC3339), | ||
p.Status, | ||
} | ||
}) | ||
tableData = fctl.Prepend(tableData, []string{"ID", "PolicyID", "CreatedAt", "ReconciledAtLedger", | ||
"ReconciledAtPayments", "Status"}) | ||
if err := pterm.DefaultTable. | ||
WithHasHeader(). | ||
WithWriter(cmd.OutOrStdout()). | ||
WithData(tableData). | ||
Render(); err != nil { | ||
return err | ||
} | ||
|
||
tableData = pterm.TableData{} | ||
tableData = append(tableData, []string{pterm.LightCyan("HasMore"), fmt.Sprintf("%v", c.store.Cursor.HasMore)}) | ||
tableData = append(tableData, []string{pterm.LightCyan("PageSize"), fmt.Sprintf("%d", c.store.Cursor.PageSize)}) | ||
tableData = append(tableData, []string{pterm.LightCyan("Next"), func() string { | ||
if c.store.Cursor.Next == nil { | ||
return "" | ||
} | ||
return *c.store.Cursor.Next | ||
}()}) | ||
tableData = append(tableData, []string{pterm.LightCyan("Previous"), func() string { | ||
if c.store.Cursor.Previous == nil { | ||
return "" | ||
} | ||
return *c.store.Cursor.Previous | ||
}()}) | ||
|
||
if err := pterm.DefaultTable. | ||
WithWriter(cmd.OutOrStdout()). | ||
WithData(tableData). | ||
Render(); err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func NewListCommand() *cobra.Command { | ||
c := NewListController() | ||
return fctl.NewCommand("list", | ||
fctl.WithAliases("ls", "l"), | ||
fctl.WithArgs(cobra.ExactArgs(0)), | ||
fctl.WithShortDescription("List reconciliations"), | ||
fctl.WithStringFlag(c.cursorFlag, "", "Cursor"), | ||
fctl.WithIntFlag(c.pageSizeFlag, 0, "PageSize"), | ||
fctl.WithController[*ListStore](c), | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
package policies | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
|
||
fctl "github.com/formancehq/fctl/pkg" | ||
"github.com/formancehq/formance-sdk-go/pkg/models/shared" | ||
"github.com/pkg/errors" | ||
"github.com/pterm/pterm" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
type CreateStore struct { | ||
PolicyID string `json:"policyID"` | ||
} | ||
type CreateController struct { | ||
store *CreateStore | ||
} | ||
|
||
var _ fctl.Controller[*CreateStore] = (*CreateController)(nil) | ||
|
||
func NewCreateStore() *CreateStore { | ||
return &CreateStore{} | ||
} | ||
|
||
func NewCreateController() *CreateController { | ||
return &CreateController{ | ||
store: NewCreateStore(), | ||
} | ||
} | ||
|
||
func NewCreateCommand() *cobra.Command { | ||
c := NewCreateController() | ||
return fctl.NewCommand("create <file>|-", | ||
fctl.WithConfirmFlag(), | ||
fctl.WithShortDescription("Create a policy"), | ||
fctl.WithAliases("cr", "c"), | ||
fctl.WithArgs(cobra.ExactArgs(1)), | ||
fctl.WithController[*CreateStore](c), | ||
) | ||
} | ||
|
||
func (c *CreateController) GetStore() *CreateStore { | ||
return c.store | ||
} | ||
|
||
func (c *CreateController) Run(cmd *cobra.Command, args []string) (fctl.Renderable, error) { | ||
soc, err := fctl.GetStackOrganizationConfig(cmd) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if !fctl.CheckStackApprobation(cmd, soc.Stack, "You are about to create a new policy") { | ||
return nil, fctl.ErrMissingApproval | ||
} | ||
|
||
client, err := fctl.NewStackClient(cmd, soc.Config, soc.Stack) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "creating stack client") | ||
} | ||
|
||
script, err := fctl.ReadFile(cmd, soc.Stack, args[0]) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
request := shared.PolicyRequest{} | ||
if err := json.Unmarshal([]byte(script), &request); err != nil { | ||
return nil, err | ||
} | ||
|
||
//nolint:gosimple | ||
response, err := client.Reconciliation.CreatePolicy(cmd.Context(), request) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if response.StatusCode >= 300 { | ||
return nil, fmt.Errorf("unexpected status code: %d", response.StatusCode) | ||
} | ||
|
||
c.store.PolicyID = response.PolicyResponse.Data.ID | ||
|
||
return c, nil | ||
} | ||
|
||
func (c *CreateController) Render(cmd *cobra.Command, args []string) error { | ||
pterm.Success.WithWriter(cmd.OutOrStdout()).Printfln("Policy created with ID: %s", c.store.PolicyID) | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package policies | ||
|
||
import ( | ||
"fmt" | ||
|
||
fctl "github.com/formancehq/fctl/pkg" | ||
"github.com/formancehq/formance-sdk-go/pkg/models/operations" | ||
"github.com/pkg/errors" | ||
"github.com/pterm/pterm" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
type DeleteStore struct { | ||
PolicyID string `json:"policyID"` | ||
Success bool `json:"success"` | ||
} | ||
|
||
type DeleteController struct { | ||
store *DeleteStore | ||
} | ||
|
||
var _ fctl.Controller[*DeleteStore] = (*DeleteController)(nil) | ||
|
||
func NewDeleteStore() *DeleteStore { | ||
return &DeleteStore{} | ||
} | ||
|
||
func NewDeleteController() *DeleteController { | ||
return &DeleteController{ | ||
store: NewDeleteStore(), | ||
} | ||
} | ||
func NewDeleteCommand() *cobra.Command { | ||
c := NewDeleteController() | ||
return fctl.NewCommand("delete <policyID>", | ||
fctl.WithConfirmFlag(), | ||
fctl.WithAliases("d"), | ||
fctl.WithShortDescription("Delete a policy"), | ||
fctl.WithArgs(cobra.ExactArgs(1)), | ||
fctl.WithController[*DeleteStore](c), | ||
) | ||
} | ||
|
||
func (c *DeleteController) GetStore() *DeleteStore { | ||
return c.store | ||
} | ||
|
||
func (c *DeleteController) Run(cmd *cobra.Command, args []string) (fctl.Renderable, error) { | ||
cfg, err := fctl.GetConfig(cmd) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "retrieving config") | ||
} | ||
|
||
organizationID, err := fctl.ResolveOrganizationID(cmd, cfg) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
stack, err := fctl.ResolveStack(cmd, cfg, organizationID) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if !fctl.CheckStackApprobation(cmd, stack, "You are about to delete '%s'", args[0]) { | ||
return nil, fctl.ErrMissingApproval | ||
} | ||
|
||
client, err := fctl.NewStackClient(cmd, cfg, stack) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "creating stack client") | ||
} | ||
|
||
response, err := client.Reconciliation.DeletePolicy( | ||
cmd.Context(), | ||
operations.DeletePolicyRequest{ | ||
PolicyID: args[0], | ||
}, | ||
) | ||
|
||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if response.StatusCode >= 300 { | ||
return nil, fmt.Errorf("unexpected status code: %d", response.StatusCode) | ||
} | ||
|
||
c.store.PolicyID = args[0] | ||
c.store.Success = true | ||
|
||
return c, nil | ||
} | ||
|
||
func (c *DeleteController) Render(cmd *cobra.Command, args []string) error { | ||
pterm.Success.WithWriter(cmd.OutOrStdout()).Printfln("Policy %s Deleted!", c.store.PolicyID) | ||
return nil | ||
} |
Oops, something went wrong.