146 lines
3.5 KiB
Go
146 lines
3.5 KiB
Go
package quotation
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/shopspring/decimal"
|
|
"github.com/tech/sendico/payments/storage/model"
|
|
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
|
|
sharedv1 "github.com/tech/sendico/pkg/proto/payments/shared/v1"
|
|
)
|
|
|
|
func perIntentIdempotencyKey(base string, index int, total int) string {
|
|
base = strings.TrimSpace(base)
|
|
if base == "" {
|
|
return ""
|
|
}
|
|
if total <= 1 {
|
|
return base
|
|
}
|
|
return fmt.Sprintf("%s:%d", base, index+1)
|
|
}
|
|
|
|
func minQuoteExpiry(expires []time.Time) (time.Time, bool) {
|
|
var min time.Time
|
|
for _, exp := range expires {
|
|
if exp.IsZero() {
|
|
continue
|
|
}
|
|
if min.IsZero() || exp.Before(min) {
|
|
min = exp
|
|
}
|
|
}
|
|
if min.IsZero() {
|
|
return time.Time{}, false
|
|
}
|
|
return min, true
|
|
}
|
|
|
|
func aggregatePaymentQuotes(quotes []*sharedv1.PaymentQuote) (*sharedv1.PaymentQuoteAggregate, error) {
|
|
if len(quotes) == 0 {
|
|
return nil, nil
|
|
}
|
|
debitTotals := map[string]decimal.Decimal{}
|
|
settlementTotals := map[string]decimal.Decimal{}
|
|
feeTotals := map[string]decimal.Decimal{}
|
|
networkTotals := map[string]decimal.Decimal{}
|
|
|
|
for _, quote := range quotes {
|
|
if quote == nil {
|
|
continue
|
|
}
|
|
if err := accumulateMoney(debitTotals, quote.GetDebitAmount()); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := accumulateMoney(settlementTotals, quote.GetExpectedSettlementAmount()); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := accumulateMoney(feeTotals, quote.GetExpectedFeeTotal()); err != nil {
|
|
return nil, err
|
|
}
|
|
if nf := quote.GetNetworkFee(); nf != nil {
|
|
if err := accumulateMoney(networkTotals, nf.GetNetworkFee()); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
}
|
|
|
|
return &sharedv1.PaymentQuoteAggregate{
|
|
DebitAmounts: totalsToMoney(debitTotals),
|
|
ExpectedSettlementAmounts: totalsToMoney(settlementTotals),
|
|
ExpectedFeeTotals: totalsToMoney(feeTotals),
|
|
NetworkFeeTotals: totalsToMoney(networkTotals),
|
|
}, nil
|
|
}
|
|
|
|
func accumulateMoney(totals map[string]decimal.Decimal, money *moneyv1.Money) error {
|
|
if money == nil {
|
|
return nil
|
|
}
|
|
currency := strings.TrimSpace(money.GetCurrency())
|
|
if currency == "" {
|
|
return nil
|
|
}
|
|
amount, err := decimal.NewFromString(money.GetAmount())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if current, ok := totals[currency]; ok {
|
|
totals[currency] = current.Add(amount)
|
|
return nil
|
|
}
|
|
totals[currency] = amount
|
|
return nil
|
|
}
|
|
|
|
func totalsToMoney(totals map[string]decimal.Decimal) []*moneyv1.Money {
|
|
if len(totals) == 0 {
|
|
return nil
|
|
}
|
|
currencies := make([]string, 0, len(totals))
|
|
for currency := range totals {
|
|
currencies = append(currencies, currency)
|
|
}
|
|
sort.Strings(currencies)
|
|
|
|
result := make([]*moneyv1.Money, 0, len(currencies))
|
|
for _, currency := range currencies {
|
|
amount := totals[currency]
|
|
result = append(result, &moneyv1.Money{
|
|
Amount: amount.String(),
|
|
Currency: currency,
|
|
})
|
|
}
|
|
return result
|
|
}
|
|
|
|
func intentsFromProto(intents []*sharedv1.PaymentIntent) []model.PaymentIntent {
|
|
if len(intents) == 0 {
|
|
return nil
|
|
}
|
|
result := make([]model.PaymentIntent, 0, len(intents))
|
|
for _, intent := range intents {
|
|
result = append(result, intentFromProto(intent))
|
|
}
|
|
return result
|
|
}
|
|
|
|
func quoteSnapshotsFromProto(quotes []*sharedv1.PaymentQuote) []*model.PaymentQuoteSnapshot {
|
|
if len(quotes) == 0 {
|
|
return nil
|
|
}
|
|
result := make([]*model.PaymentQuoteSnapshot, 0, len(quotes))
|
|
for _, quote := range quotes {
|
|
if quote == nil {
|
|
continue
|
|
}
|
|
if snapshot := quoteSnapshotToModel(quote); snapshot != nil {
|
|
result = append(result, snapshot)
|
|
}
|
|
}
|
|
return result
|
|
}
|