Skip to content

Commit

Permalink
link payment inititation and connectors
Browse files Browse the repository at this point in the history
  • Loading branch information
paul-nicolas committed Aug 26, 2023
1 parent b04006a commit 04f583f
Show file tree
Hide file tree
Showing 12 changed files with 203 additions and 132 deletions.
195 changes: 91 additions & 104 deletions components/payments/internal/app/api/connector.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@ package api

import (
"encoding/json"
"math/big"
"net/http"
"time"

"github.com/pkg/errors"

"github.com/formancehq/payments/internal/app/storage"

"github.com/google/uuid"
Expand Down Expand Up @@ -255,107 +252,97 @@ func reset[Config models.ConnectorConfigObject](
}
}

type transferRequest struct {
Amount *big.Int `json:"amount"`
Source string `json:"source"`
Destination string `json:"destination"`
Asset string `json:"asset"`

currency string
}

func (req *transferRequest) validate() error {
if req.Amount.Cmp(big.NewInt(0)) <= 0 {
return errors.New("amount must be greater than 0")
}

if req.Asset == "" {
return errors.New("asset is required")
}

if len(req.Asset) < 3 { //nolint:gomnd // allow length 3 for POC
return errors.New("asset is invalid")
}

req.currency = req.Asset[:3]

if req.Destination == "" {
return errors.New("destination is required")
}

return nil
}

type initiateTransferResponse struct {
ID string `json:"id"`
}

func initiatePayment[Config models.ConnectorConfigObject](connectorManager *integration.ConnectorManager[Config],
) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// var req transferRequest

// err := json.NewDecoder(r.Body).Decode(&req)
// if err != nil {
// handleError(w, r, err)

// return
// }

// err = req.validate()
// if err != nil {
// handleErrorBadRequest(w, r, err)

// return
// }

// installed, err := connectorManager.IsInstalled(r.Context())
// if err != nil {
// handleError(w, r, err)

// return
// }

// if !installed {
// handleError(w, r, errors.New("connector not installed"))

// return
// }

// transfer := integration.Transfer{
// Source: req.Source,
// Destination: req.Destination,
// Currency: req.currency,
// Amount: req.Amount,
// }

// transferID, err := connectorManager.InitiateTransfer(r.Context(), transfer)
// if err != nil {
// handleError(w, r, err)

// return
// }

// err = json.NewEncoder(w).Encode(api.BaseResponse[initiateTransferResponse]{
// Data: &initiateTransferResponse{
// ID: transferID.String(),
// },
// })
// if err != nil {
// panic(err)
// }
}
}

type listTransfersResponseElement struct {
ID string `json:"id"`
Source string `json:"source"`
Destination string `json:"destination"`
Amount *big.Int `json:"amount"`
Currency string `json:"asset"`
Status string `json:"status"`
Error *string `json:"error"`
}
// type transferRequest struct {
// Amount *big.Int `json:"amount"`
// Source string `json:"source"`
// Destination string `json:"destination"`
// Asset string `json:"asset"`

// currency string
// }

// func (req *transferRequest) validate() error {
// if req.Amount.Cmp(big.NewInt(0)) <= 0 {
// return errors.New("amount must be greater than 0")
// }

// if req.Asset == "" {
// return errors.New("asset is required")
// }

// if len(req.Asset) < 3 { //nolint:gomnd // allow length 3 for POC
// return errors.New("asset is invalid")
// }

// req.currency = req.Asset[:3]

// if req.Destination == "" {
// return errors.New("destination is required")
// }

// return nil
// }

// type initiateTransferResponse struct {
// ID string `json:"id"`
// }

// func initiatePayment[Config models.ConnectorConfigObject](connectorManager *integration.ConnectorManager[Config],
// ) http.HandlerFunc {
// return func(w http.ResponseWriter, r *http.Request) {
// var req transferRequest

// err := json.NewDecoder(r.Body).Decode(&req)
// if err != nil {
// handleError(w, r, err)

// return
// }

// err = req.validate()
// if err != nil {
// handleErrorBadRequest(w, r, err)

// return
// }

// installed, err := connectorManager.IsInstalled(r.Context())
// if err != nil {
// handleError(w, r, err)

// return
// }

// if !installed {
// handleError(w, r, errors.New("connector not installed"))

// return
// }

// transfer := integration.Transfer{
// Source: req.Source,
// Destination: req.Destination,
// Currency: req.currency,
// Amount: req.Amount,
// }

// transferID, err := connectorManager.InitiateTransfer(r.Context(), transfer)
// if err != nil {
// handleError(w, r, err)

// return
// }

// err = json.NewEncoder(w).Encode(api.BaseResponse[initiateTransferResponse]{
// Data: &initiateTransferResponse{
// ID: transferID.String(),
// },
// })
// if err != nil {
// panic(err)
// }
// }
// }

func connectorNotInstalled[Config models.ConnectorConfigObject](connectorManager *integration.ConnectorManager[Config],
w http.ResponseWriter, r *http.Request,
Expand Down
10 changes: 7 additions & 3 deletions components/payments/internal/app/api/connectormodule.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ import (
type connectorHandler struct {
Handler http.Handler
Provider models.ConnectorProvider

// TODO(polo): refactor to remove this ugly hack to access the connector manager
initiatePayment func(ctx context.Context, transfer models.TransferInitiation) error
}

func addConnector[ConnectorConfig models.ConnectorConfigObject](loader integration.Loader[ConnectorConfig],
Expand Down Expand Up @@ -51,14 +54,15 @@ func addConnector[ConnectorConfig models.ConnectorConfigObject](loader integrati
}, resolver, metricsRegistry, maxTasks)
})

return integration.NewConnectorManager[ConnectorConfig](
return integration.NewConnectorManager(
store, loader, schedulerFactory, publisher)
}),
fx.Provide(fx.Annotate(func(cm *integration.ConnectorManager[ConnectorConfig],
) connectorHandler {
return connectorHandler{
Handler: connectorRouter(loader.Name(), cm),
Provider: loader.Name(),
Handler: connectorRouter(loader.Name(), cm),
Provider: loader.Name(),
initiatePayment: cm.InitiatePayment,
}
}, fx.ResultTags(`group:"connectorHandlers"`))),
fx.Invoke(func(lc fx.Lifecycle, cm *integration.ConnectorManager[ConnectorConfig]) {
Expand Down
15 changes: 6 additions & 9 deletions components/payments/internal/app/api/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,13 @@ func httpRouter(
authGroup.Path("/accounts/{accountID}").Methods(http.MethodGet).Handler(readAccountHandler(store))
authGroup.Path("/accounts/{accountID}/balances").Methods(http.MethodGet).Handler(listBalancesForAccount(store))

authGroup.Path("/transfer-initiation").Methods(http.MethodPost).Handler(createTransferInitiationHandler(store))
paymentsHandlers := make(map[models.ConnectorProvider]paymentHandler)
for _, h := range connectorHandlers {
paymentsHandlers[h.Provider] = h.initiatePayment
}
authGroup.Path("/transfer-initiation").Methods(http.MethodPost).Handler(createTransferInitiationHandler(store, paymentsHandlers))
authGroup.Path("/transfer-initiation").Methods(http.MethodGet).Handler(listTransferInitiationsHandler(store))
authGroup.Path("/transfer-initiation/{transferID}/status").Methods(http.MethodPost).Handler(udateTransferInitiationStatusHandler(store))
authGroup.Path("/transfer-initiation/{transferID}/status").Methods(http.MethodPost).Handler(udateTransferInitiationStatusHandler(store, paymentsHandlers))
authGroup.Path("/transfer-initiation/{transferID}").Methods(http.MethodGet).Handler(readTransferInitiationHandler(store))
authGroup.Path("/transfer-initiation/{transferID}").Methods(http.MethodDelete).Handler(deleteTransferInitiationHandler(store))

Expand All @@ -66,12 +70,6 @@ func httpRouter(

connectorGroup.Path("/configs").Handler(connectorConfigsHandler())

// Deprecated
// TODO: Remove this endpoint
// Use /connectors/stripe/transfers instead
connectorGroup.Path("/stripe/transfers").Methods(http.MethodPost).
Handler(handleStripeTransfers(store))

for _, h := range connectorHandlers {
connectorGroup.PathPrefix("/" + h.Provider.String()).Handler(
http.StripPrefix("/connectors", h.Handler))
Expand All @@ -95,7 +93,6 @@ func connectorRouter[Config models.ConnectorConfigObject](
addRoute(r, provider, "/reset", http.MethodPost, reset(manager))
addRoute(r, provider, "/tasks", http.MethodGet, listTasks(manager))
addRoute(r, provider, "/tasks/{taskID}", http.MethodGet, readTask(manager))
addRoute(r, provider, "/payments", http.MethodPost, initiatePayment(manager))

return r
}
Expand Down
Loading

0 comments on commit 04f583f

Please sign in to comment.