109 lines
3.5 KiB
Go
109 lines
3.5 KiB
Go
package sendico
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
|
|
"git.sendico.io/tech/sxchnge/product/payments"
|
|
"go.mongodb.org/mongo-driver/v2/bson"
|
|
)
|
|
|
|
// Accounts exposes only dedicated, organization-owned customer ledgers tagged by
|
|
// trusted platform provisioning. The integration login's personal/pooled ledgers
|
|
// never become customer balances. Method bindings are provisioned on that ledger.
|
|
func (c *Client) Accounts(ctx context.Context, subject string) ([]payments.Account, error) {
|
|
if !validRef(subject) {
|
|
return nil, payments.Unavailable
|
|
}
|
|
var currencies struct {
|
|
Rows []currencyDTO `json:"currencies"`
|
|
}
|
|
if err := c.paymentRequest(ctx, http.MethodGet, "/payments/fx/currencies/"+c.config.OrganizationID, nil, ¤cies); err != nil {
|
|
return nil, err
|
|
}
|
|
scales := map[string]int{}
|
|
for _, row := range currencies.Rows {
|
|
if row.Scale != nil && *row.Scale >= 0 && *row.Scale <= 8 {
|
|
scales[row.Code] = *row.Scale
|
|
}
|
|
}
|
|
var data accountListDTO
|
|
root := "/ledger_accounts/" + c.config.OrganizationID
|
|
if err := c.paymentRequest(ctx, http.MethodGet, root, nil, &data); err != nil {
|
|
return nil, err
|
|
}
|
|
accounts := []payments.Account{}
|
|
for _, row := range data.Accounts {
|
|
if row.Metadata["sxchnge_subject_ref"] != subject {
|
|
continue
|
|
}
|
|
if !c.validCustomerAccount(row, subject) {
|
|
return nil, payments.Unavailable
|
|
}
|
|
scale, ok := scales[row.Currency]
|
|
if !ok {
|
|
return nil, payments.Unsupported
|
|
}
|
|
var balance struct {
|
|
Value balanceDTO `json:"balance"`
|
|
}
|
|
if err := c.paymentRequest(ctx, http.MethodGet, root+"/"+row.ID+"/balance", nil, &balance); err != nil {
|
|
return nil, err
|
|
}
|
|
account, err := mapAccount(row, balance.Value, scale)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
accounts = append(accounts, account)
|
|
}
|
|
return accounts, nil
|
|
}
|
|
func (c *Client) Quote(ctx context.Context, subject string, r payments.Request, accounts []payments.Account) (payments.Quote, error) {
|
|
mapped, err := mapIntent(subject, r, accounts)
|
|
if err != nil {
|
|
return payments.Quote{}, err
|
|
}
|
|
var response struct {
|
|
Quote paymentQuoteDTO `json:"quote"`
|
|
Subject string `json:"externalSubjectRef"`
|
|
}
|
|
err = c.paymentRequest(ctx, http.MethodPost, "/payments/quote/"+c.config.OrganizationID, quoteRequestDTO{Key: "sxchnge:quote:" + bson.NewObjectID().Hex(), Intent: mapped.wire}, &response)
|
|
if err != nil {
|
|
return payments.Quote{}, err
|
|
}
|
|
if response.Subject != subject {
|
|
return payments.Quote{}, payments.Unavailable
|
|
}
|
|
return mapPaymentQuote(response.Quote, mapped.request, mapped.source, mapped.destination)
|
|
}
|
|
func (c *Client) Execute(ctx context.Context, quote, key string) (payments.RemoteOperation, error) {
|
|
if !safePaymentRef(quote) {
|
|
return payments.RemoteOperation{}, payments.Unavailable
|
|
}
|
|
var result struct {
|
|
Payment paymentDTO `json:"payment"`
|
|
}
|
|
payload := struct {
|
|
Quote string `json:"quoteRef"`
|
|
Key string `json:"idempotencyKey"`
|
|
}{quote, key}
|
|
err := c.paymentRequest(ctx, http.MethodPost, "/payments/by-quote/"+c.config.OrganizationID, payload, &result)
|
|
if err != nil {
|
|
return payments.RemoteOperation{}, err
|
|
}
|
|
return mapPayment(result.Payment)
|
|
}
|
|
func (c *Client) Payment(ctx context.Context, id string) (payments.RemoteOperation, error) {
|
|
if !safePaymentRef(id) {
|
|
return payments.RemoteOperation{}, payments.Unavailable
|
|
}
|
|
var result struct {
|
|
Payment paymentDTO `json:"payment"`
|
|
}
|
|
err := c.paymentRequest(ctx, http.MethodGet, "/payments/by-ref/"+id, nil, &result)
|
|
if err != nil {
|
|
return payments.RemoteOperation{}, err
|
|
}
|
|
return mapPayment(result.Payment)
|
|
}
|