Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version: '3.8'
version: "3.8"
volumes:
postgres:

Expand All @@ -10,7 +10,7 @@ services:
ports:
- 8092:80
environment:
DEBUG: true
DEBUG: true

postgres:
image: "postgres:14-alpine"
Expand Down Expand Up @@ -82,7 +82,7 @@ services:
image: golang:1.23.4-alpine
command: go run ./ server
healthcheck:
test: [ "CMD", "curl", "-f", "http://127.0.0.1:8080/_healthcheck" ]
test: ["CMD", "curl", "-f", "http://127.0.0.1:8080/_healthcheck"]
interval: 10s
timeout: 5s
retries: 5
Expand All @@ -105,13 +105,13 @@ services:
PLUGIN_MAGIC_COOKIE: mysupercookie
TEMPORAL_INIT_SEARCH_ATTRIBUTES: true
STACK_URL: http://gateway:8092
STACK_PUBLIC_URL: ${STACK_PUBLIC_URL:?mandatory}
STACK_PUBLIC_URL: http://localhost:8080

payments-worker:
image: golang:1.23.4-alpine
command: go run ./ worker
healthcheck:
test: [ "CMD", "curl", "-f", "http://127.0.0.1:8080/_healthcheck" ]
test: ["CMD", "curl", "-f", "http://127.0.0.1:8080/_healthcheck"]
interval: 10s
timeout: 5s
retries: 5
Expand All @@ -133,4 +133,4 @@ services:
PLUGIN_MAGIC_COOKIE: mysupercookie
TEMPORAL_INIT_SEARCH_ATTRIBUTES: false
STACK_URL: http://gateway:8092
STACK_PUBLIC_URL: ${STACK_PUBLIC_URL:?mandatory}
STACK_PUBLIC_URL: http://localhost:8080
42 changes: 42 additions & 0 deletions docs/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5730,6 +5730,12 @@ xor

xor

|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|*anonymous*|[V3CheckoutConfig](#schemav3checkoutconfig)|false|none|none|

xor

|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|*anonymous*|[V3ColumnConfig](#schemav3columnconfig)|false|none|none|
Expand Down Expand Up @@ -5912,6 +5918,42 @@ xor
|userCertificateKey|string|true|none|none|
|username|string|true|none|none|

<h2 id="tocS_V3CheckoutConfig">V3CheckoutConfig</h2>
<!-- backwards compatibility -->
<a id="schemav3checkoutconfig"></a>
<a id="schema_V3CheckoutConfig"></a>
<a id="tocSv3checkoutconfig"></a>
<a id="tocsv3checkoutconfig"></a>

```json
{
"entityId": "string",
"environment": "string",
"name": "string",
"oauthClientID": "string",
"oauthClientSecret": "string",
"pageSize": "25",
"pollingPeriod": "2m",
"processingChannelId": "string",
"provider": "Checkout"
}

```

### Properties

|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|entityId|string|true|none|none|
|environment|string|true|none|none|
|name|string|true|none|none|
|oauthClientID|string|true|none|none|
|oauthClientSecret|string|true|none|none|
|pageSize|integer|false|none|none|
|pollingPeriod|string|false|none|none|
|processingChannelId|string|true|none|none|
|provider|string|false|none|none|

<h2 id="tocS_V3ColumnConfig">V3ColumnConfig</h2>
<!-- backwards compatibility -->
<a id="schemav3columnconfig"></a>
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ require (
github.com/ThreeDotsLabs/watermill v1.4.7
github.com/adyen/adyen-go-api-library/v7 v7.3.1
github.com/bombsimon/logrusr/v3 v3.1.0
github.com/checkout/checkout-sdk-go v1.7.2
github.com/emvi/iso-639-1 v1.1.1
github.com/formancehq/go-libs/v3 v3.0.2-0.20250814071617-0f5bb98d939b
github.com/formancehq/payments/genericclient v0.0.0-00010101000000-000000000000
Expand Down Expand Up @@ -132,6 +133,7 @@ require (
github.com/goccy/go-json v0.10.3 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/go-tpm v0.9.5 // indirect
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
Expand Down
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,8 @@ github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/checkout/checkout-sdk-go v1.7.2 h1:tRxQ4bT0zxfV1Pox+x5pvAC55Il+BJIQBB1hcuA9HSw=
github.com/checkout/checkout-sdk-go v1.7.2/go.mod h1:NL0iaELZA1BleG4dUINHaa8LgcizKUnzWWuTVukTswo=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
Expand Down Expand Up @@ -776,6 +778,7 @@ github.com/formancehq/go-libs/v3 v3.0.2-0.20250814071617-0f5bb98d939b h1:jmWZvgO
github.com/formancehq/go-libs/v3 v3.0.2-0.20250814071617-0f5bb98d939b/go.mod h1:HgSiCLTW/yu3Or5gWB20/N8/xWV6zkdI8WoQXP4vLLs=
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/gabriel-vasile/mimetype v1.4.1/go.mod h1:05Vi0w3Y9c/lNvJOdmIwvrrAhX3rYhfQQCaf9VJcv7M=
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
github.com/get-momo/atlar-v1-go-client v1.4.0 h1:DIRwP3gRfvdXAxEeMNua6HPsScXZzDB9nySdYVv5FD0=
Expand Down Expand Up @@ -915,6 +918,8 @@ github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/go-tpm v0.9.5 h1:ocUmnDebX54dnW+MQWGQRbdaAcJELsa6PqZhJ48KwVU=
github.com/google/go-tpm v0.9.5/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
Expand Down
58 changes: 58 additions & 0 deletions internal/connectors/plugins/public/checkout/accounts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package checkout

import (
"context"
"encoding/json"
"time"

"github.com/formancehq/payments/internal/models"
)

type accountsState struct {
LastPage int `json:"lastPage"`
}

func (p *Plugin) fetchNextAccounts(ctx context.Context, req models.FetchNextAccountsRequest) (models.FetchNextAccountsResponse, error) {
const page = 0

pagedAccounts, err := p.client.GetAccounts(ctx, page, req.PageSize)
if err != nil {
return models.FetchNextAccountsResponse{}, err
}

accounts := make([]models.PSPAccount, 0, len(pagedAccounts))
for _, acc := range pagedAccounts {
raw, _ := json.Marshal(acc)

md := map[string]string{
"status": acc.Status,
}

var namePtr *string
if acc.Name != "" {
n := acc.Name
namePtr = &n
}

accounts = append(accounts, models.PSPAccount{
Reference: acc.ID,
Name: namePtr,
DefaultAsset: nil,
Metadata: md,
Raw: raw,
CreatedAt: time.Now().UTC(),
})
}

if req.PageSize > 0 && len(accounts) > req.PageSize {
accounts = accounts[:req.PageSize]
}

newState, _ := json.Marshal(accountsState{LastPage: 0})

return models.FetchNextAccountsResponse{
Accounts: accounts,
NewState: newState,
HasMore: false,
}, nil
}
35 changes: 35 additions & 0 deletions internal/connectors/plugins/public/checkout/balances.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package checkout

import (
"context"
"math/big"
"time"

"github.com/formancehq/payments/internal/models"
"github.com/formancehq/go-libs/v3/currency"
)

func (p *Plugin) fetchNextBalances(ctx context.Context, req models.FetchNextBalancesRequest) (models.FetchNextBalancesResponse, error) {
balances, err := p.client.GetAccountBalances(ctx)
if err != nil {
return models.FetchNextBalancesResponse{}, err
}

accountBalances := make([]models.PSPBalance, 0, len(balances))

for _, b := range balances {
asset := currency.FormatAsset(supportedCurrenciesWithDecimal, b.Currency)

accountBalances = append(accountBalances, models.PSPBalance{
AccountReference: b.CurrencyAccountID,
Asset: asset,
Amount: big.NewInt(b.Available),
CreatedAt: time.Now().UTC(),
})
}

return models.FetchNextBalancesResponse{
Balances: accountBalances,
HasMore: false,
}, nil
}
12 changes: 12 additions & 0 deletions internal/connectors/plugins/public/checkout/capabilities.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package checkout

import "github.com/formancehq/payments/internal/models"

var capabilities = []models.Capability{
models.CAPABILITY_FETCH_ACCOUNTS,
models.CAPABILITY_FETCH_BALANCES,
models.CAPABILITY_FETCH_PAYMENTS,

models.CAPABILITY_CREATE_TRANSFER,
models.CAPABILITY_CREATE_PAYOUT,
}
51 changes: 51 additions & 0 deletions internal/connectors/plugins/public/checkout/client/accounts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package client

import (
"context"
"encoding/json"
"fmt"

"github.com/formancehq/payments/internal/connectors/metrics"
)

type Account struct {
ID string `json:"id"`
Name string `json:"name"`
Status string `json:"status"`
}

func (c *client) GetAccounts(ctx context.Context, page int, pageSize int) ([]*Account, error) {
ctx = context.WithValue(ctx, metrics.MetricOperationContextKey, "list_accounts")

if page > 1 {
return []*Account{}, nil
}
if c.sdk == nil || c.entityID == "" {
return nil, fmt.Errorf("checkout sdk not initialized or missing entityID")
}

entity, err := c.sdk.Accounts.GetEntity(c.entityID)
if err != nil {
return nil, fmt.Errorf("checkout.accounts.getEntity(%s): %w", c.entityID, err)
}

if b, err := json.MarshalIndent(entity, "", " "); err == nil {
fmt.Printf("Received entity from Checkout: %s\n", string(b))
}

id := c.entityID
name := fmt.Sprint(entity.Company.LegalName)
status := fmt.Sprint(entity.Status)

accounts := []*Account{{
ID: id,
Name: name,
Status: status,
}}

if b, _ := json.Marshal(accounts); true {
fmt.Printf("[checkout] GetAccounts returns %d account(s): %s\n", len(accounts), string(b))
}

return accounts, nil
}
56 changes: 56 additions & 0 deletions internal/connectors/plugins/public/checkout/client/balances.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package client

import (
"context"
"encoding/json"
"fmt"

"github.com/checkout/checkout-sdk-go/balances"

"github.com/formancehq/payments/internal/connectors/metrics"
)

type Balance struct {
Descriptor string `json:"descriptor"`
CurrencyAccountID string `json:"currencyAccountId"`
Currency string `json:"currency"`
Available int64 `json:"available"`
Pending int64 `json:"pending"`
Payable int64 `json:"payable"`
Collateral int64 `json:"collateral"`
}

func (c *client) GetAccountBalances(ctx context.Context) ([]*Balance, error) {
ctx = context.WithValue(ctx, metrics.MetricOperationContextKey, "list_account_balances")

if c.sdk == nil || c.entityID == "" {
return nil, fmt.Errorf("checkout sdk not initialized or missing entityID")
}

resp, err := c.sdk.Balances.RetrieveEntityBalances(
c.entityID,
balances.QueryFilter{WithCurrencyAccountId: true},
)
if err != nil {
return nil, fmt.Errorf("checkout.accounts.getEntityBalances(%s): %w", c.entityID, err)
}

balances := make([]*Balance, 0, len(resp.Data))
for _, ab := range resp.Data {
balances = append(balances, &Balance{
Descriptor: ab.Descriptor,
CurrencyAccountID: ab.CurrencyAccountId,
Currency: ab.HoldingCurrency,
Available: ab.Balances.Available,
Pending: ab.Balances.Pending,
Payable: ab.Balances.Payable,
Collateral: ab.Balances.Collateral,
})
}

if b, _ := json.Marshal(balances); true {
fmt.Printf("[checkout] GetAccountBalances returns %d balance(s): %s\n", len(balances), string(b))
}

return balances, nil
}
Loading