From dbfa49862af0cc57269f5782c5c26032032be9b7 Mon Sep 17 00:00:00 2001 From: Paul Nicolas Date: Tue, 30 Jan 2024 16:18:24 +0100 Subject: [PATCH] feat(payments): add mangopay bank accounts creation (#1159) --- .../fctl/cmd/payments/bankaccounts/list.go | 3 +- .../fctl/cmd/payments/bankaccounts/show.go | 1 + .../cmd/api/internal/api/bank_accounts.go | 3 + .../api/internal/api/bank_accounts_test.go | 3 + .../connectors/internal/api/bank_account.go | 2 + .../internal/api/bank_account_test.go | 1 + .../mangopay/client/bank_accounts.go | 144 +++++++++++++- .../connectors/mangopay/client/metadata.go | 13 ++ .../internal/connectors/mangopay/connector.go | 16 +- .../task_create_external_bank_account.go | 188 ++++++++++++++++++ .../connectors/mangopay/task_resolve.go | 19 +- .../internal/storage/bank_accounts.go | 2 +- components/payments/openapi.yaml | 3 + releases/sdks/go/.speakeasy/gen.lock | 4 +- .../go/docs/pkg/models/shared/bankaccount.md | 1 + .../sdks/go/pkg/models/shared/bankaccount.go | 8 + 16 files changed, 396 insertions(+), 15 deletions(-) create mode 100644 components/payments/cmd/connectors/internal/connectors/mangopay/client/metadata.go create mode 100644 components/payments/cmd/connectors/internal/connectors/mangopay/task_create_external_bank_account.go diff --git a/components/fctl/cmd/payments/bankaccounts/list.go b/components/fctl/cmd/payments/bankaccounts/list.go index 027135aeb9..55249e0094 100644 --- a/components/fctl/cmd/payments/bankaccounts/list.go +++ b/components/fctl/cmd/payments/bankaccounts/list.go @@ -113,6 +113,7 @@ func (c *ListController) Render(cmd *cobra.Command, args []string) error { tableData := fctl.Map(c.store.Cursor.Data, func(bc shared.BankAccount) []string { return []string{ bc.ID, + bc.Name, bc.CreatedAt.Format(time.RFC3339), bc.Country, string(bc.ConnectorID), @@ -125,7 +126,7 @@ func (c *ListController) Render(cmd *cobra.Command, args []string) error { }(), } }) - tableData = fctl.Prepend(tableData, []string{"ID", "CreatedAt", "Country", "ConnectorID", "Provider"}) + tableData = fctl.Prepend(tableData, []string{"ID", "Name", "CreatedAt", "Country", "ConnectorID", "Provider"}) return pterm.DefaultTable. WithHasHeader(). WithWriter(cmd.OutOrStdout()). diff --git a/components/fctl/cmd/payments/bankaccounts/show.go b/components/fctl/cmd/payments/bankaccounts/show.go index 6c20e20ea4..2e48ff516f 100644 --- a/components/fctl/cmd/payments/bankaccounts/show.go +++ b/components/fctl/cmd/payments/bankaccounts/show.go @@ -100,6 +100,7 @@ func (c *ShowController) Render(cmd *cobra.Command, args []string) error { fctl.Section.WithWriter(cmd.OutOrStdout()).Println("Information") tableData := pterm.TableData{} tableData = append(tableData, []string{pterm.LightCyan("ID"), c.store.BankAccount.ID}) + tableData = append(tableData, []string{pterm.LightCyan("Name"), c.store.BankAccount.Name}) tableData = append(tableData, []string{pterm.LightCyan("CreatedAt"), c.store.BankAccount.CreatedAt.Format(time.RFC3339)}) tableData = append(tableData, []string{pterm.LightCyan("Country"), c.store.BankAccount.Country}) tableData = append(tableData, []string{pterm.LightCyan("ConnectorID"), string(c.store.BankAccount.ConnectorID)}) diff --git a/components/payments/cmd/api/internal/api/bank_accounts.go b/components/payments/cmd/api/internal/api/bank_accounts.go index 879f799100..4e6b51f627 100644 --- a/components/payments/cmd/api/internal/api/bank_accounts.go +++ b/components/payments/cmd/api/internal/api/bank_accounts.go @@ -13,6 +13,7 @@ import ( type bankAccountResponse struct { ID string `json:"id"` + Name string `json:"name"` CreatedAt time.Time `json:"createdAt"` Country string `json:"country"` ConnectorID string `json:"connectorID"` @@ -45,6 +46,7 @@ func listBankAccountsHandler(b backend.Backend) http.HandlerFunc { for i := range ret { data[i] = &bankAccountResponse{ ID: ret[i].ID.String(), + Name: ret[i].Name, CreatedAt: ret[i].CreatedAt, Country: ret[i].Country, ConnectorID: ret[i].ConnectorID.String(), @@ -93,6 +95,7 @@ func readBankAccountHandler(b backend.Backend) http.HandlerFunc { data := &bankAccountResponse{ ID: account.ID.String(), + Name: account.Name, CreatedAt: account.CreatedAt, Country: account.Country, ConnectorID: account.ConnectorID.String(), diff --git a/components/payments/cmd/api/internal/api/bank_accounts_test.go b/components/payments/cmd/api/internal/api/bank_accounts_test.go index 1e3e00c6c0..177913cfb4 100644 --- a/components/payments/cmd/api/internal/api/bank_accounts_test.go +++ b/components/payments/cmd/api/internal/api/bank_accounts_test.go @@ -184,6 +184,7 @@ func TestListBankAccounts(t *testing.T) { expectedBankAccountsResponse := []*bankAccountResponse{ { ID: listBankAccountsResponse[0].ID.String(), + Name: listBankAccountsResponse[0].Name, CreatedAt: listBankAccountsResponse[0].CreatedAt, Country: listBankAccountsResponse[0].Country, ConnectorID: listBankAccountsResponse[0].ConnectorID.String(), @@ -192,6 +193,7 @@ func TestListBankAccounts(t *testing.T) { }, { ID: listBankAccountsResponse[1].ID.String(), + Name: listBankAccountsResponse[1].Name, CreatedAt: listBankAccountsResponse[1].CreatedAt, Country: listBankAccountsResponse[1].Country, ConnectorID: listBankAccountsResponse[1].ConnectorID.String(), @@ -333,6 +335,7 @@ func TestGetBankAccount(t *testing.T) { expectedBankAccountResponse := &bankAccountResponse{ ID: getBankAccountResponse.ID.String(), + Name: getBankAccountResponse.Name, CreatedAt: getBankAccountResponse.CreatedAt, Country: getBankAccountResponse.Country, ConnectorID: getBankAccountResponse.ConnectorID.String(), diff --git a/components/payments/cmd/connectors/internal/api/bank_account.go b/components/payments/cmd/connectors/internal/api/bank_account.go index d590d28da1..e886fbd5bd 100644 --- a/components/payments/cmd/connectors/internal/api/bank_account.go +++ b/components/payments/cmd/connectors/internal/api/bank_account.go @@ -15,6 +15,7 @@ import ( type bankAccountResponse struct { ID string `json:"id"` + Name string `json:"name"` CreatedAt time.Time `json:"createdAt"` Country string `json:"country"` ConnectorID string `json:"connectorID"` @@ -63,6 +64,7 @@ func createBankAccountHandler( data := &bankAccountResponse{ ID: bankAccount.ID.String(), + Name: bankAccount.Name, CreatedAt: bankAccount.CreatedAt, Country: bankAccount.Country, ConnectorID: bankAccountRequest.ConnectorID, diff --git a/components/payments/cmd/connectors/internal/api/bank_account_test.go b/components/payments/cmd/connectors/internal/api/bank_account_test.go index a5e4169057..6dabd6a402 100644 --- a/components/payments/cmd/connectors/internal/api/bank_account_test.go +++ b/components/payments/cmd/connectors/internal/api/bank_account_test.go @@ -209,6 +209,7 @@ func TestCreateBankAccounts(t *testing.T) { expectedCreateBankAccountResponse := &bankAccountResponse{ ID: createBankAccountResponse.ID.String(), + Name: createBankAccountResponse.Name, CreatedAt: createBankAccountResponse.CreatedAt, Country: createBankAccountResponse.Country, ConnectorID: createBankAccountResponse.ConnectorID.String(), diff --git a/components/payments/cmd/connectors/internal/connectors/mangopay/client/bank_accounts.go b/components/payments/cmd/connectors/internal/connectors/mangopay/client/bank_accounts.go index 0d0c5da972..47a9c02c1a 100644 --- a/components/payments/cmd/connectors/internal/connectors/mangopay/client/bank_accounts.go +++ b/components/payments/cmd/connectors/internal/connectors/mangopay/client/bank_accounts.go @@ -1,6 +1,7 @@ package client import ( + "bytes" "context" "encoding/json" "fmt" @@ -11,13 +12,150 @@ import ( "github.com/formancehq/payments/cmd/connectors/internal/connectors" ) -type bankAccount struct { +type OwnerAddress struct { + AddressLine1 string `json:"AddressLine1,omitempty"` + AddressLine2 string `json:"AddressLine2,omitempty"` + City string `json:"City,omitempty"` + // Region is needed if country is either US, CA or MX + Region string `json:"Region,omitempty"` + PostalCode string `json:"PostalCode,omitempty"` + // ISO 3166-1 alpha-2 format. + Country string `json:"Country,omitempty"` +} + +type CreateIBANBankAccountRequest struct { + OwnerName string `json:"OwnerName"` + OwnerAddress *OwnerAddress `json:"OwnerAddress,omitempty"` + IBAN string `json:"IBAN,omitempty"` + BIC string `json:"BIC,omitempty"` + // Metadata + Tag string `json:"Tag,omitempty"` +} + +func (c *Client) CreateIBANBankAccount(ctx context.Context, userID string, req *CreateIBANBankAccountRequest) (*BankAccount, error) { + f := connectors.ClientMetrics(ctx, "mangopay", "create_iban_bank_account") + now := time.Now() + defer f(ctx, now) + + endpoint := fmt.Sprintf("%s/v2.01/%s/users/%s/bankaccounts/iban", c.endpoint, c.clientID, userID) + return c.createBankAccount(ctx, endpoint, req) +} + +type CreateUSBankAccountRequest struct { + OwnerName string `json:"OwnerName"` + OwnerAddress *OwnerAddress `json:"OwnerAddress,omitempty"` + AccountNumber string `json:"AccountNumber"` + ABA string `json:"ABA"` + DepositAccountType string `json:"DepositAccountType,omitempty"` + Tag string `json:"Tag,omitempty"` +} + +func (c *Client) CreateUSBankAccount(ctx context.Context, userID string, req *CreateUSBankAccountRequest) (*BankAccount, error) { + f := connectors.ClientMetrics(ctx, "mangopay", "create_us_bank_account") + now := time.Now() + defer f(ctx, now) + + endpoint := fmt.Sprintf("%s/v2.01/%s/users/%s/bankaccounts/us", c.endpoint, c.clientID, userID) + return c.createBankAccount(ctx, endpoint, req) +} + +type CreateCABankAccountRequest struct { + OwnerName string `json:"OwnerName"` + OwnerAddress *OwnerAddress `json:"OwnerAddress,omitempty"` + AccountNumber string `json:"AccountNumber"` + InstitutionNumber string `json:"InstitutionNumber"` + BranchCode string `json:"BranchCode"` + BankName string `json:"BankName"` + Tag string `json:"Tag,omitempty"` +} + +func (c *Client) CreateCABankAccount(ctx context.Context, userID string, req *CreateCABankAccountRequest) (*BankAccount, error) { + f := connectors.ClientMetrics(ctx, "mangopay", "create_ca_bank_account") + now := time.Now() + defer f(ctx, now) + + endpoint := fmt.Sprintf("%s/v2.01/%s/users/%s/bankaccounts/ca", c.endpoint, c.clientID, userID) + return c.createBankAccount(ctx, endpoint, req) +} + +type CreateGBBankAccountRequest struct { + OwnerName string `json:"OwnerName"` + OwnerAddress *OwnerAddress `json:"OwnerAddress,omitempty"` + AccountNumber string `json:"AccountNumber"` + SortCode string `json:"SortCode"` + Tag string `json:"Tag,omitempty"` +} + +func (c *Client) CreateGBBankAccount(ctx context.Context, userID string, req *CreateGBBankAccountRequest) (*BankAccount, error) { + f := connectors.ClientMetrics(ctx, "mangopay", "create_gb_bank_account") + now := time.Now() + defer f(ctx, now) + + endpoint := fmt.Sprintf("%s/v2.01/%s/users/%s/bankaccounts/gb", c.endpoint, c.clientID, userID) + return c.createBankAccount(ctx, endpoint, req) +} + +type CreateOtherBankAccountRequest struct { + OwnerName string `json:"OwnerName"` + OwnerAddress *OwnerAddress `json:"OwnerAddress,omitempty"` + AccountNumber string `json:"AccountNumber"` + BIC string `json:"BIC,omitempty"` + Country string `json:"Country,omitempty"` + Tag string `json:"Tag,omitempty"` +} + +func (c *Client) CreateOtherBankAccount(ctx context.Context, userID string, req *CreateOtherBankAccountRequest) (*BankAccount, error) { + f := connectors.ClientMetrics(ctx, "mangopay", "create_other_bank_account") + now := time.Now() + defer f(ctx, now) + + endpoint := fmt.Sprintf("%s/v2.01/%s/users/%s/bankaccounts/other", c.endpoint, c.clientID, userID) + return c.createBankAccount(ctx, endpoint, req) +} + +func (c *Client) createBankAccount(ctx context.Context, endpoint string, req any) (*BankAccount, error) { + body, err := json.Marshal(req) + if err != nil { + return nil, fmt.Errorf("failed to marshal bank account request: %w", err) + } + + httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, bytes.NewBuffer(body)) + if err != nil { + return nil, fmt.Errorf("failed to create bank account request: %w", err) + } + httpReq.Header.Set("Content-Type", "application/json") + + resp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, fmt.Errorf("failed to create bank account: %w", err) + } + + defer func() { + err = resp.Body.Close() + if err != nil { + c.logger.Error(err) + } + }() + + if resp.StatusCode != http.StatusOK { + return nil, unmarshalError(resp.StatusCode, resp.Body).Error() + } + + var bankAccount BankAccount + if err := json.NewDecoder(resp.Body).Decode(&bankAccount); err != nil { + return nil, fmt.Errorf("failed to unmarshal bank account response body: %w", err) + } + + return &bankAccount, nil +} + +type BankAccount struct { ID string `json:"Id"` OwnerName string `json:"OwnerName"` CreationDate int64 `json:"CreationDate"` } -func (c *Client) GetBankAccounts(ctx context.Context, userID string, page, pageSize int) ([]*bankAccount, error) { +func (c *Client) GetBankAccounts(ctx context.Context, userID string, page, pageSize int) ([]*BankAccount, error) { f := connectors.ClientMetrics(ctx, "mangopay", "list_bank_accounts") now := time.Now() defer f(ctx, now) @@ -50,7 +188,7 @@ func (c *Client) GetBankAccounts(ctx context.Context, userID string, page, pageS return nil, unmarshalError(resp.StatusCode, resp.Body).Error() } - var bankAccounts []*bankAccount + var bankAccounts []*BankAccount if err := json.NewDecoder(resp.Body).Decode(&bankAccounts); err != nil { return nil, fmt.Errorf("failed to unmarshal wallets response body: %w", err) } diff --git a/components/payments/cmd/connectors/internal/connectors/mangopay/client/metadata.go b/components/payments/cmd/connectors/internal/connectors/mangopay/client/metadata.go new file mode 100644 index 0000000000..883f497488 --- /dev/null +++ b/components/payments/cmd/connectors/internal/connectors/mangopay/client/metadata.go @@ -0,0 +1,13 @@ +package client + +const ( + mangopayMetadataSpecNamespace = "com.mangopay.spec/" +) + +func ExtractNamespacedMetadata(metadata map[string]string, key string) string { + value, ok := metadata[mangopayMetadataSpecNamespace+key] + if !ok { + return "" + } + return value +} diff --git a/components/payments/cmd/connectors/internal/connectors/mangopay/connector.go b/components/payments/cmd/connectors/internal/connectors/mangopay/connector.go index d51bc39cc6..2e59a883d9 100644 --- a/components/payments/cmd/connectors/internal/connectors/mangopay/connector.go +++ b/components/payments/cmd/connectors/internal/connectors/mangopay/connector.go @@ -130,7 +130,21 @@ func (c *Connector) ReversePayment(ctx task.ConnectorContext, transferReversal * } func (c *Connector) CreateExternalBankAccount(ctx task.ConnectorContext, bankAccount *models.BankAccount) error { - return connectors.ErrNotImplemented + descriptor, err := models.EncodeTaskDescriptor(TaskDescriptor{ + Name: "Create external bank account", + Key: taskNameCreateExternalBankAccount, + BankAccountID: bankAccount.ID, + }) + if err != nil { + return err + } + if err := ctx.Scheduler().Schedule(ctx.Context(), descriptor, models.TaskSchedulerOptions{ + ScheduleOption: models.OPTIONS_RUN_NOW_SYNC, + }); err != nil { + return err + } + + return nil } var _ connectors.Connector = &Connector{} diff --git a/components/payments/cmd/connectors/internal/connectors/mangopay/task_create_external_bank_account.go b/components/payments/cmd/connectors/internal/connectors/mangopay/task_create_external_bank_account.go new file mode 100644 index 0000000000..fc04ebca6c --- /dev/null +++ b/components/payments/cmd/connectors/internal/connectors/mangopay/task_create_external_bank_account.go @@ -0,0 +1,188 @@ +package mangopay + +import ( + "context" + "encoding/json" + "fmt" + "time" + + "github.com/formancehq/payments/cmd/connectors/internal/connectors" + "github.com/formancehq/payments/cmd/connectors/internal/connectors/mangopay/client" + "github.com/formancehq/payments/cmd/connectors/internal/ingestion" + "github.com/formancehq/payments/cmd/connectors/internal/storage" + "github.com/formancehq/payments/cmd/connectors/internal/task" + "github.com/formancehq/payments/internal/models" + "github.com/formancehq/payments/internal/otel" + "github.com/google/uuid" + "go.opentelemetry.io/otel/attribute" +) + +func taskCreateExternalBankAccount(mangopayClient *client.Client, bankAccountID uuid.UUID) task.Task { + return func( + ctx context.Context, + connectorID models.ConnectorID, + taskID models.TaskID, + storageReader storage.Reader, + ingester ingestion.Ingester, + ) error { + ctx, span := connectors.StartSpan( + ctx, + "mangopay.taskCreateExternalBankAccount", + attribute.String("connectorID", connectorID.String()), + attribute.String("taskID", taskID.String()), + attribute.String("bankAccountID", bankAccountID.String()), + ) + defer span.End() + + bankAccount, err := storageReader.GetBankAccount(ctx, bankAccountID, true) + if err != nil { + otel.RecordError(span, err) + return err + } + + if err := createExternalBankAccount(ctx, connectorID, mangopayClient, bankAccount, ingester); err != nil { + otel.RecordError(span, err) + return err + } + + return nil + } +} + +func createExternalBankAccount( + ctx context.Context, + connectorID models.ConnectorID, + mangopayClient *client.Client, + bankAccount *models.BankAccount, + ingester ingestion.Ingester, +) error { + userID := client.ExtractNamespacedMetadata(bankAccount.Metadata, "userID") + if userID == "" { + return fmt.Errorf("missing userID in bank account metadata") + } + + ownerAddress := client.OwnerAddress{ + AddressLine1: client.ExtractNamespacedMetadata(bankAccount.Metadata, "owner/addressLine1"), + AddressLine2: client.ExtractNamespacedMetadata(bankAccount.Metadata, "owner/addressLine2"), + City: client.ExtractNamespacedMetadata(bankAccount.Metadata, "owner/city"), + Region: client.ExtractNamespacedMetadata(bankAccount.Metadata, "owner/region"), + PostalCode: client.ExtractNamespacedMetadata(bankAccount.Metadata, "owner/postalCode"), + Country: bankAccount.Country, + } + + var mangopayBankAccount *client.BankAccount + if bankAccount.IBAN != "" { + req := &client.CreateIBANBankAccountRequest{ + OwnerName: bankAccount.Name, + OwnerAddress: &ownerAddress, + IBAN: bankAccount.IBAN, + BIC: bankAccount.SwiftBicCode, + Tag: client.ExtractNamespacedMetadata(bankAccount.Metadata, "tag"), + } + + var err error + mangopayBankAccount, err = mangopayClient.CreateIBANBankAccount(ctx, userID, req) + if err != nil { + return err + } + } else { + switch bankAccount.Country { + case "US": + req := &client.CreateUSBankAccountRequest{ + OwnerName: bankAccount.Name, + OwnerAddress: &ownerAddress, + AccountNumber: bankAccount.AccountNumber, + ABA: client.ExtractNamespacedMetadata(bankAccount.Metadata, "aba"), + DepositAccountType: client.ExtractNamespacedMetadata(bankAccount.Metadata, "depositAccountType"), + Tag: client.ExtractNamespacedMetadata(bankAccount.Metadata, "tag"), + } + + var err error + mangopayBankAccount, err = mangopayClient.CreateUSBankAccount(ctx, userID, req) + if err != nil { + return err + } + + case "CA": + req := &client.CreateCABankAccountRequest{ + OwnerName: bankAccount.Name, + OwnerAddress: &ownerAddress, + AccountNumber: bankAccount.AccountNumber, + InstitutionNumber: client.ExtractNamespacedMetadata(bankAccount.Metadata, "institutionNumber"), + BranchCode: client.ExtractNamespacedMetadata(bankAccount.Metadata, "branchCode"), + BankName: client.ExtractNamespacedMetadata(bankAccount.Metadata, "bankName"), + Tag: client.ExtractNamespacedMetadata(bankAccount.Metadata, "tag"), + } + + var err error + mangopayBankAccount, err = mangopayClient.CreateCABankAccount(ctx, userID, req) + if err != nil { + return err + } + + case "GB": + req := &client.CreateGBBankAccountRequest{ + OwnerName: bankAccount.Name, + OwnerAddress: &ownerAddress, + AccountNumber: bankAccount.AccountNumber, + SortCode: client.ExtractNamespacedMetadata(bankAccount.Metadata, "sortCode"), + Tag: client.ExtractNamespacedMetadata(bankAccount.Metadata, "tag"), + } + + var err error + mangopayBankAccount, err = mangopayClient.CreateGBBankAccount(ctx, userID, req) + if err != nil { + return err + } + + default: + req := &client.CreateOtherBankAccountRequest{ + OwnerName: bankAccount.Name, + OwnerAddress: &ownerAddress, + AccountNumber: bankAccount.AccountNumber, + BIC: bankAccount.SwiftBicCode, + Country: bankAccount.Country, + Tag: client.ExtractNamespacedMetadata(bankAccount.Metadata, "tag"), + } + + var err error + mangopayBankAccount, err = mangopayClient.CreateOtherBankAccount(ctx, userID, req) + if err != nil { + return err + } + } + } + + if mangopayBankAccount != nil { + buf, err := json.Marshal(mangopayBankAccount) + if err != nil { + return err + } + + externalAccount := &models.Account{ + ID: models.AccountID{ + Reference: mangopayBankAccount.ID, + ConnectorID: connectorID, + }, + CreatedAt: time.Unix(mangopayBankAccount.CreationDate, 0), + Reference: mangopayBankAccount.ID, + ConnectorID: connectorID, + AccountName: mangopayBankAccount.OwnerName, + Type: models.AccountTypeExternal, + Metadata: map[string]string{ + "user_id": userID, + }, + RawData: buf, + } + + if err := ingester.IngestAccounts(ctx, ingestion.AccountBatch{externalAccount}); err != nil { + return err + } + + if err := ingester.LinkBankAccountWithAccount(ctx, bankAccount, &externalAccount.ID); err != nil { + return err + } + } + + return nil +} diff --git a/components/payments/cmd/connectors/internal/connectors/mangopay/task_resolve.go b/components/payments/cmd/connectors/internal/connectors/mangopay/task_resolve.go index 1b8ca0561a..4a3ec209bc 100644 --- a/components/payments/cmd/connectors/internal/connectors/mangopay/task_resolve.go +++ b/components/payments/cmd/connectors/internal/connectors/mangopay/task_resolve.go @@ -7,16 +7,18 @@ import ( "github.com/formancehq/payments/cmd/connectors/internal/connectors/mangopay/client" "github.com/formancehq/payments/cmd/connectors/internal/task" "github.com/formancehq/stack/libs/go-libs/logging" + "github.com/google/uuid" ) const ( - taskNameMain = "main" - taskNameFetchUsers = "fetch-users" - taskNameFetchTransactions = "fetch-transactions" - taskNameFetchWallets = "fetch-wallets" - taskNameFetchBankAccounts = "fetch-bank-accounts" - taskNameInitiatePayment = "initiate-payment" - taskNameUpdatePaymentStatus = "update-payment-status" + taskNameMain = "main" + taskNameFetchUsers = "fetch-users" + taskNameFetchTransactions = "fetch-transactions" + taskNameFetchWallets = "fetch-wallets" + taskNameFetchBankAccounts = "fetch-bank-accounts" + taskNameInitiatePayment = "initiate-payment" + taskNameUpdatePaymentStatus = "update-payment-status" + taskNameCreateExternalBankAccount = "create-external-bank-account" ) // TaskDescriptor is the definition of a task. @@ -28,6 +30,7 @@ type TaskDescriptor struct { TransferID string `json:"transferID" yaml:"transferID" bson:"transferID"` PaymentID string `json:"paymentID" yaml:"paymentID" bson:"paymentID"` Attempt int `json:"attempt" yaml:"attempt" bson:"attempt"` + BankAccountID uuid.UUID `json:"bankAccountID,omitempty" yaml:"bankAccountID" bson:"bankAccountID"` PollingPeriod connectors.Duration `json:"pollingPeriod" yaml:"pollingPeriod" bson:"pollingPeriod"` } @@ -65,6 +68,8 @@ func resolveTasks(logger logging.Logger, config Config) func(taskDefinition Task return taskUpdatePaymentStatus(mangopayClient, taskDescriptor.TransferID, taskDescriptor.PaymentID, taskDescriptor.Attempt) case taskNameFetchWallets: return taskFetchWallets(mangopayClient, &config, taskDescriptor.UserID) + case taskNameCreateExternalBankAccount: + return taskCreateExternalBankAccount(mangopayClient, taskDescriptor.BankAccountID) } // This should never happen. diff --git a/components/payments/cmd/connectors/internal/storage/bank_accounts.go b/components/payments/cmd/connectors/internal/storage/bank_accounts.go index 9b9f240043..cd79ec7072 100644 --- a/components/payments/cmd/connectors/internal/storage/bank_accounts.go +++ b/components/payments/cmd/connectors/internal/storage/bank_accounts.go @@ -131,7 +131,7 @@ func (s *Storage) GetBankAccount(ctx context.Context, id uuid.UUID, expand bool) var account models.BankAccount query := s.db.NewSelect(). Model(&account). - Column("id", "name", "created_at", "country", "connector_id", "account_id") + Column("id", "name", "created_at", "country", "connector_id", "account_id", "metadata") if expand { query = query.ColumnExpr("pgp_sym_decrypt(account_number, ?, ?) AS decrypted_account_number", s.configEncryptionKey, encryptionOptions). diff --git a/components/payments/openapi.yaml b/components/payments/openapi.yaml index 07dba8b113..8d43658648 100644 --- a/components/payments/openapi.yaml +++ b/components/payments/openapi.yaml @@ -1612,12 +1612,15 @@ components: type: object required: - id + - name - createdAt - country - connectorID properties: id: type: string + name: + type: string createdAt: type: string format: date-time diff --git a/releases/sdks/go/.speakeasy/gen.lock b/releases/sdks/go/.speakeasy/gen.lock index 7e1e1ddfc2..91d815dc8a 100755 --- a/releases/sdks/go/.speakeasy/gen.lock +++ b/releases/sdks/go/.speakeasy/gen.lock @@ -1,7 +1,7 @@ lockVersion: 2.0.0 -id: 56faf5b1-a0b7-4376-b1c2-f09970aebb37 +id: f22dcee1-cc7d-4ffc-a2e0-adaef7f75d78 management: - docChecksum: 886bd72ffc6be508169d70e9641d3ad4 + docChecksum: 7f85b4b8a58b19ef87e35ad7ff6d851b docVersion: INTERNAL speakeasyVersion: internal generationVersion: 2.237.2 diff --git a/releases/sdks/go/docs/pkg/models/shared/bankaccount.md b/releases/sdks/go/docs/pkg/models/shared/bankaccount.md index 6079be149d..c02246b852 100644 --- a/releases/sdks/go/docs/pkg/models/shared/bankaccount.md +++ b/releases/sdks/go/docs/pkg/models/shared/bankaccount.md @@ -13,5 +13,6 @@ | `Iban` | **string* | :heavy_minus_sign: | N/A | | `ID` | *string* | :heavy_check_mark: | N/A | | `Metadata` | map[string]*string* | :heavy_minus_sign: | N/A | +| `Name` | *string* | :heavy_check_mark: | N/A | | `Provider` | **string* | :heavy_minus_sign: | N/A | | `SwiftBicCode` | **string* | :heavy_minus_sign: | N/A | \ No newline at end of file diff --git a/releases/sdks/go/pkg/models/shared/bankaccount.go b/releases/sdks/go/pkg/models/shared/bankaccount.go index 1f0e26537e..b83ce484f5 100644 --- a/releases/sdks/go/pkg/models/shared/bankaccount.go +++ b/releases/sdks/go/pkg/models/shared/bankaccount.go @@ -16,6 +16,7 @@ type BankAccount struct { Iban *string `json:"iban,omitempty"` ID string `json:"id"` Metadata map[string]string `json:"metadata,omitempty"` + Name string `json:"name"` Provider *string `json:"provider,omitempty"` SwiftBicCode *string `json:"swiftBicCode,omitempty"` } @@ -87,6 +88,13 @@ func (o *BankAccount) GetMetadata() map[string]string { return o.Metadata } +func (o *BankAccount) GetName() string { + if o == nil { + return "" + } + return o.Name +} + func (o *BankAccount) GetProvider() *string { if o == nil { return nil