satellite/payments: add STORJ amount and rate to Stripe TX metadata
Jira: https://storjlabs.atlassian.net/browse/USR-968 We want to keep track of the STORJ amount and exchange rate in the metadata of Stripe Customer Balance Transaction to be able to generate reports without the need of requesting CoinPayments for this info. Change-Id: Ia93af95706cd2312cf688f044874495279fe8fa2
This commit is contained in:
parent
0949731caa
commit
a20e85824a
@ -336,6 +336,8 @@ func (service *Service) applyTransactionBalance(ctx context.Context, tx Transact
|
||||
Description: stripe.String(StripeDepositTransactionDescription),
|
||||
}
|
||||
params.AddMetadata("txID", tx.ID.String())
|
||||
params.AddMetadata("storj_amount", tx.Amount.String())
|
||||
params.AddMetadata("storj_usd_rate", rate.String())
|
||||
_, err = service.stripeClient.CustomerBalanceTransactions().New(params)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -18,7 +18,18 @@ import (
|
||||
"storj.io/common/uuid"
|
||||
)
|
||||
|
||||
// MockStripeClient Stripe client mock.
|
||||
// mockClient singleton of mockStripeClient.
|
||||
//
|
||||
// The satellite has a Core part and API part which mostly duplicate each
|
||||
// other. Each of them have a StripeClient instance. This is not a problem in
|
||||
// production, because the stripeClient implementation is stateless and calls
|
||||
// the Web API of the same Stripe backend. But it is a problem in test
|
||||
// environments as the mockStripeClient client is stateful - the data is stored
|
||||
// in in-memory maps. Therefore, we need it to be a singleton, so the Core and
|
||||
// API parts share the same state.
|
||||
var mockClient StripeClient
|
||||
|
||||
// mockStripeClient Stripe client mock.
|
||||
type mockStripeClient struct {
|
||||
customers *mockCustomers
|
||||
paymentMethods *mockPaymentMethods
|
||||
@ -30,14 +41,17 @@ type mockStripeClient struct {
|
||||
|
||||
// NewStripeMock creates new Stripe client mock.
|
||||
func NewStripeMock() StripeClient {
|
||||
return &mockStripeClient{
|
||||
customers: newMockCustomers(),
|
||||
paymentMethods: &mockPaymentMethods{},
|
||||
invoices: &mockInvoices{},
|
||||
invoiceItems: &mockInvoiceItems{},
|
||||
customerBalanceTransactions: newMockCustomerBalanceTransactions(),
|
||||
charges: &mockCharges{},
|
||||
if mockClient == nil {
|
||||
mockClient = &mockStripeClient{
|
||||
customers: newMockCustomers(),
|
||||
paymentMethods: &mockPaymentMethods{},
|
||||
invoices: &mockInvoices{},
|
||||
invoiceItems: &mockInvoiceItems{},
|
||||
customerBalanceTransactions: newMockCustomerBalanceTransactions(),
|
||||
charges: &mockCharges{},
|
||||
}
|
||||
}
|
||||
return mockClient
|
||||
}
|
||||
|
||||
func (m *mockStripeClient) Customers() StripeCustomers {
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stripe/stripe-go"
|
||||
"github.com/zeebo/errs"
|
||||
|
||||
"storj.io/common/errs2"
|
||||
@ -20,6 +21,7 @@ import (
|
||||
"storj.io/common/testcontext"
|
||||
"storj.io/common/testrand"
|
||||
"storj.io/common/uuid"
|
||||
"storj.io/storj/private/testplanet"
|
||||
"storj.io/storj/satellite"
|
||||
"storj.io/storj/satellite/payments/coinpayments"
|
||||
"storj.io/storj/satellite/payments/stripecoinpayments"
|
||||
@ -339,3 +341,71 @@ func compareTransactions(t *testing.T, exp, act stripecoinpayments.Transaction)
|
||||
assert.Equal(t, exp.Timeout, act.Timeout)
|
||||
assert.False(t, act.CreatedAt.IsZero())
|
||||
}
|
||||
|
||||
func TestTransactions_ApplyTransactionBalance(t *testing.T) {
|
||||
testplanet.Run(t, testplanet.Config{
|
||||
SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 1,
|
||||
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
|
||||
satellite := planet.Satellites[0]
|
||||
transactions := satellite.API.DB.StripeCoinPayments().Transactions()
|
||||
userID := planet.Uplinks[0].Projects[0].Owner.ID
|
||||
|
||||
satellite.Core.Payments.Chore.TransactionCycle.Pause()
|
||||
satellite.Core.Payments.Chore.AccountBalanceCycle.Pause()
|
||||
|
||||
// Emulate a deposit through CoinPayments.
|
||||
txID := coinpayments.TransactionID("testID")
|
||||
storjAmount, ok := new(big.Float).SetString("100")
|
||||
require.True(t, ok)
|
||||
storjUSDRate, ok := new(big.Float).SetString("0.2")
|
||||
require.True(t, ok)
|
||||
|
||||
createTx := stripecoinpayments.Transaction{
|
||||
ID: txID,
|
||||
AccountID: userID,
|
||||
Address: "testAddress",
|
||||
Amount: *storjAmount,
|
||||
Received: *storjAmount,
|
||||
Status: coinpayments.StatusPending,
|
||||
Key: "testKey",
|
||||
Timeout: time.Second * 60,
|
||||
}
|
||||
|
||||
tx, err := transactions.Insert(ctx, createTx)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, tx)
|
||||
|
||||
update := stripecoinpayments.TransactionUpdate{
|
||||
TransactionID: createTx.ID,
|
||||
Status: coinpayments.StatusReceived,
|
||||
Received: *storjAmount,
|
||||
}
|
||||
|
||||
err = transactions.Update(ctx, []stripecoinpayments.TransactionUpdate{update}, coinpayments.TransactionIDList{createTx.ID})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Check that the CoinPayments transaction is waiting to be applied to the Stripe customer balance.
|
||||
page, err := transactions.ListUnapplied(ctx, 0, 1, time.Now())
|
||||
require.NoError(t, err)
|
||||
require.Len(t, page.Transactions, 1)
|
||||
|
||||
err = transactions.LockRate(ctx, txID, storjUSDRate)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Trigger the AccountBalanceCycle. This calls Service.applyTransactionBalance()
|
||||
satellite.Core.Payments.Chore.AccountBalanceCycle.TriggerWait()
|
||||
|
||||
cusID, err := satellite.API.DB.StripeCoinPayments().Customers().GetCustomerID(ctx, userID)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Check that the CoinPayments deposit is reflected in the Stripe customer balance.
|
||||
it := satellite.API.Payments.Stripe.CustomerBalanceTransactions().List(&stripe.CustomerBalanceTransactionListParams{Customer: stripe.String(cusID)})
|
||||
require.NoError(t, it.Err())
|
||||
require.True(t, it.Next())
|
||||
cbt := it.CustomerBalanceTransaction()
|
||||
require.EqualValues(t, -2000, cbt.Amount)
|
||||
require.EqualValues(t, txID, cbt.Metadata["txID"])
|
||||
require.EqualValues(t, "100", cbt.Metadata["storj_amount"])
|
||||
require.EqualValues(t, "0.2", cbt.Metadata["storj_usd_rate"])
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user