Merge pull request 'fixed payment reference' (#571) from tg-567 into main
All checks were successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
All checks were successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #571
This commit was merged in pull request #571.
This commit is contained in:
@@ -58,7 +58,7 @@ func (e *gatewayCardPayoutExecutor) ExecuteCardPayout(ctx context.Context, req s
|
|||||||
|
|
||||||
stepToken := cardPayoutStepToken(req.Step)
|
stepToken := cardPayoutStepToken(req.Step)
|
||||||
operationRef := cardPayoutOperationRef(req.Payment, stepToken)
|
operationRef := cardPayoutOperationRef(req.Payment, stepToken)
|
||||||
payoutRef := cardPayoutRef(req.Payment, stepToken)
|
payoutRef := cardPayoutRef(req.Payment)
|
||||||
idempotencyKey := cardPayoutIdempotencyKey(req.Payment, stepToken)
|
idempotencyKey := cardPayoutIdempotencyKey(req.Payment, stepToken)
|
||||||
projectID := cardPayoutProjectID(req.Payment)
|
projectID := cardPayoutProjectID(req.Payment)
|
||||||
customer := cardPayoutCustomerFromPayment(req.Payment, card, req.Step.Metadata)
|
customer := cardPayoutCustomerFromPayment(req.Payment, card, req.Step.Metadata)
|
||||||
@@ -219,12 +219,12 @@ func cardPayoutOperationRef(payment *agg.Payment, stepToken string) string {
|
|||||||
return joinRef(base, stepToken)
|
return joinRef(base, stepToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
func cardPayoutRef(payment *agg.Payment, stepToken string) string {
|
func cardPayoutRef(payment *agg.Payment) string {
|
||||||
base := ""
|
base := ""
|
||||||
if payment != nil {
|
if payment != nil {
|
||||||
base = firstNonEmpty(strings.TrimSpace(payment.PaymentRef), strings.TrimSpace(payment.IdempotencyKey), "card_payout")
|
base = firstNonEmpty(strings.TrimSpace(payment.PaymentRef), strings.TrimSpace(payment.IdempotencyKey), "card_payout")
|
||||||
}
|
}
|
||||||
return joinRef(base, stepToken)
|
return base
|
||||||
}
|
}
|
||||||
|
|
||||||
func cardPayoutIdempotencyKey(payment *agg.Payment, stepToken string) string {
|
func cardPayoutIdempotencyKey(payment *agg.Payment, stepToken string) string {
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ func TestGatewayCardPayoutExecutor_ExecuteCardPayout_SubmitsCardPayout(t *testin
|
|||||||
if payoutReq == nil {
|
if payoutReq == nil {
|
||||||
t.Fatal("expected payout request to be submitted")
|
t.Fatal("expected payout request to be submitted")
|
||||||
}
|
}
|
||||||
if got, want := payoutReq.GetPayoutId(), "payment-1:hop_4_card_payout_send"; got != want {
|
if got, want := payoutReq.GetPayoutId(), "payment-1"; got != want {
|
||||||
t.Fatalf("payout_id mismatch: got=%q want=%q", got, want)
|
t.Fatalf("payout_id mismatch: got=%q want=%q", got, want)
|
||||||
}
|
}
|
||||||
if got, want := payoutReq.GetOperationRef(), "payment-1:hop_4_card_payout_send"; got != want {
|
if got, want := payoutReq.GetOperationRef(), "payment-1:hop_4_card_payout_send"; got != want {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package orchestrator
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
"github.com/tech/sendico/pkg/discovery"
|
"github.com/tech/sendico/pkg/discovery"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -68,6 +69,10 @@ func (e *gatewayLedgerExecutor) ExecuteLedger(ctx context.Context, req sexec.Ste
|
|||||||
organizationRef := req.Payment.OrganizationRef.Hex()
|
organizationRef := req.Payment.OrganizationRef.Hex()
|
||||||
description := ledgerDescription(req.Step)
|
description := ledgerDescription(req.Step)
|
||||||
metadata := ledgerTransferMetadata(req.Payment, req.Step, roles)
|
metadata := ledgerTransferMetadata(req.Payment, req.Step, roles)
|
||||||
|
charges, err := ledgerChargesForStep(req.Payment, req.Step, action, amount)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
var resp *ledgerv1.PostResponse
|
var resp *ledgerv1.PostResponse
|
||||||
switch action {
|
switch action {
|
||||||
@@ -77,6 +82,7 @@ func (e *gatewayLedgerExecutor) ExecuteLedger(ctx context.Context, req sexec.Ste
|
|||||||
OrganizationRef: organizationRef,
|
OrganizationRef: organizationRef,
|
||||||
Money: amount,
|
Money: amount,
|
||||||
Description: description,
|
Description: description,
|
||||||
|
Charges: charges,
|
||||||
Metadata: metadata,
|
Metadata: metadata,
|
||||||
Role: ledgerRoleToProto(roles.to),
|
Role: ledgerRoleToProto(roles.to),
|
||||||
})
|
})
|
||||||
@@ -86,6 +92,7 @@ func (e *gatewayLedgerExecutor) ExecuteLedger(ctx context.Context, req sexec.Ste
|
|||||||
OrganizationRef: organizationRef,
|
OrganizationRef: organizationRef,
|
||||||
Money: amount,
|
Money: amount,
|
||||||
Description: description,
|
Description: description,
|
||||||
|
Charges: charges,
|
||||||
Metadata: metadata,
|
Metadata: metadata,
|
||||||
Role: ledgerRoleToProto(roles.from),
|
Role: ledgerRoleToProto(roles.from),
|
||||||
})
|
})
|
||||||
@@ -183,6 +190,111 @@ func settlementMoneyForLedger(payment *agg.Payment, source *paymenttypes.Money)
|
|||||||
return source
|
return source
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ledgerChargesForStep(payment *agg.Payment, step xplan.Step, action model.RailOperation, amount *moneyv1.Money) ([]*ledgerv1.PostingLine, error) {
|
||||||
|
if !shouldAttachLedgerCharges(payment, step, action) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if payment == nil || payment.QuoteSnapshot == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
currency := ""
|
||||||
|
if amount != nil {
|
||||||
|
currency = strings.TrimSpace(amount.GetCurrency())
|
||||||
|
}
|
||||||
|
return feeLinesToLedgerCharges(payment.QuoteSnapshot.FeeLines, currency)
|
||||||
|
}
|
||||||
|
|
||||||
|
func shouldAttachLedgerCharges(payment *agg.Payment, step xplan.Step, action model.RailOperation) bool {
|
||||||
|
switch action {
|
||||||
|
case discovery.RailOperationExternalCredit, discovery.RailOperationExternalDebit:
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fromRail, toRail, ok := ledgerBoundaryRails(payment, step)
|
||||||
|
if !ok {
|
||||||
|
// Prefer attaching on external debits when boundary metadata is unavailable.
|
||||||
|
return action == discovery.RailOperationExternalDebit
|
||||||
|
}
|
||||||
|
|
||||||
|
switch action {
|
||||||
|
case discovery.RailOperationExternalCredit:
|
||||||
|
return isLedgerExternalRail(fromRail) && isLedgerInternalRail(toRail)
|
||||||
|
case discovery.RailOperationExternalDebit:
|
||||||
|
return isLedgerExternalRail(toRail)
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func feeLinesToLedgerCharges(lines []*paymenttypes.FeeLine, currency string) ([]*ledgerv1.PostingLine, error) {
|
||||||
|
if len(lines) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make([]*ledgerv1.PostingLine, 0, len(lines))
|
||||||
|
for i := range lines {
|
||||||
|
line := lines[i]
|
||||||
|
if line == nil || line.GetMoney() == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
accountRef := strings.TrimSpace(line.GetLedgerAccountRef())
|
||||||
|
if accountRef == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
lineCurrency := strings.TrimSpace(line.GetMoney().GetCurrency())
|
||||||
|
if currency != "" && !strings.EqualFold(lineCurrency, currency) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
amount, err := decimal.NewFromString(strings.TrimSpace(line.GetMoney().GetAmount()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, merrors.InvalidArgument(fmt.Sprintf("ledger step: fee_lines[%d].money.amount is invalid", i))
|
||||||
|
}
|
||||||
|
amount = normalizeChargeAmountForSide(amount, line.GetSide())
|
||||||
|
|
||||||
|
result = append(result, &ledgerv1.PostingLine{
|
||||||
|
LedgerAccountRef: accountRef,
|
||||||
|
Money: &moneyv1.Money{
|
||||||
|
Amount: amount.String(),
|
||||||
|
Currency: lineCurrency,
|
||||||
|
},
|
||||||
|
LineType: feeLineTypeToLedger(line.GetLineType()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if len(result) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func normalizeChargeAmountForSide(amount decimal.Decimal, side paymenttypes.EntrySide) decimal.Decimal {
|
||||||
|
switch side {
|
||||||
|
case paymenttypes.EntrySideDebit:
|
||||||
|
if amount.Sign() > 0 {
|
||||||
|
return amount.Neg()
|
||||||
|
}
|
||||||
|
case paymenttypes.EntrySideCredit:
|
||||||
|
if amount.Sign() < 0 {
|
||||||
|
return amount.Neg()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return amount
|
||||||
|
}
|
||||||
|
|
||||||
|
func feeLineTypeToLedger(lineType paymenttypes.PostingLineType) ledgerv1.LineType {
|
||||||
|
switch lineType {
|
||||||
|
case paymenttypes.PostingLineTypeSpread:
|
||||||
|
return ledgerv1.LineType_LINE_SPREAD
|
||||||
|
case paymenttypes.PostingLineTypeReversal:
|
||||||
|
return ledgerv1.LineType_LINE_REVERSAL
|
||||||
|
default:
|
||||||
|
// Ledger supports fee/spread/reversal only; map TAX/UNSPECIFIED to fee.
|
||||||
|
return ledgerv1.LineType_LINE_FEE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func payoutMoneyForLedger(_ *agg.Payment, settlement *paymenttypes.Money) *paymenttypes.Money {
|
func payoutMoneyForLedger(_ *agg.Payment, settlement *paymenttypes.Money) *paymenttypes.Money {
|
||||||
return settlement
|
return settlement
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -222,6 +222,199 @@ func TestGatewayLedgerExecutor_ExecuteLedger_ExternalDebitUsesPostDebitWithCharg
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGatewayLedgerExecutor_ExecuteLedger_ExternalDebitForwardsQuoteFeeLinesAsCharges(t *testing.T) {
|
||||||
|
orgID := bson.NewObjectID()
|
||||||
|
payment := testLedgerExecutorPayment(orgID)
|
||||||
|
payment.QuoteSnapshot.FeeLines = []*paymenttypes.FeeLine{
|
||||||
|
{
|
||||||
|
LedgerAccountRef: "fee-ledger-1",
|
||||||
|
Money: &paymenttypes.Money{Amount: "2.50", Currency: "RUB"},
|
||||||
|
LineType: paymenttypes.PostingLineTypeFee,
|
||||||
|
Side: paymenttypes.EntrySideDebit,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
LedgerAccountRef: "spread-ledger-1",
|
||||||
|
Money: &paymenttypes.Money{Amount: "1.25", Currency: "RUB"},
|
||||||
|
LineType: paymenttypes.PostingLineTypeSpread,
|
||||||
|
Side: paymenttypes.EntrySideCredit,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
LedgerAccountRef: "mismatch-ledger-1",
|
||||||
|
Money: &paymenttypes.Money{Amount: "5", Currency: "USDT"},
|
||||||
|
LineType: paymenttypes.PostingLineTypeFee,
|
||||||
|
Side: paymenttypes.EntrySideDebit,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var postReq *ledgerv1.PostDebitRequest
|
||||||
|
executor := &gatewayLedgerExecutor{
|
||||||
|
ledgerClient: &ledgerclient.Fake{
|
||||||
|
PostExternalDebitWithChargesFn: func(_ context.Context, req *ledgerv1.PostDebitRequest) (*ledgerv1.PostResponse, error) {
|
||||||
|
postReq = req
|
||||||
|
return &ledgerv1.PostResponse{JournalEntryRef: "entry-ext-debit-fees"}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := executor.ExecuteLedger(context.Background(), sexec.StepRequest{
|
||||||
|
Payment: payment,
|
||||||
|
Step: xplan.Step{
|
||||||
|
StepRef: "edge_3_4_ledger_debit",
|
||||||
|
StepCode: "edge.3_4.ledger.debit",
|
||||||
|
Action: discovery.RailOperationExternalDebit,
|
||||||
|
Rail: discovery.RailLedger,
|
||||||
|
Metadata: map[string]string{
|
||||||
|
"mode": "finalize_debit",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
StepExecution: agg.StepExecution{
|
||||||
|
StepRef: "edge_3_4_ledger_debit",
|
||||||
|
StepCode: "edge.3_4.ledger.debit",
|
||||||
|
Attempt: 1,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ExecuteLedger returned error: %v", err)
|
||||||
|
}
|
||||||
|
if postReq == nil {
|
||||||
|
t.Fatal("expected external debit request")
|
||||||
|
}
|
||||||
|
if got, want := len(postReq.GetCharges()), 2; got != want {
|
||||||
|
t.Fatalf("charges count mismatch: got=%d want=%d", got, want)
|
||||||
|
}
|
||||||
|
if got, want := postReq.GetCharges()[0].GetLedgerAccountRef(), "fee-ledger-1"; got != want {
|
||||||
|
t.Fatalf("charges[0].ledger_account_ref mismatch: got=%q want=%q", got, want)
|
||||||
|
}
|
||||||
|
if got, want := postReq.GetCharges()[0].GetMoney().GetCurrency(), "RUB"; got != want {
|
||||||
|
t.Fatalf("charges[0].money.currency mismatch: got=%q want=%q", got, want)
|
||||||
|
}
|
||||||
|
if got, want := postReq.GetCharges()[0].GetMoney().GetAmount(), "-2.5"; got != want {
|
||||||
|
t.Fatalf("charges[0].money.amount mismatch: got=%q want=%q", got, want)
|
||||||
|
}
|
||||||
|
if got, want := postReq.GetCharges()[0].GetLineType(), ledgerv1.LineType_LINE_FEE; got != want {
|
||||||
|
t.Fatalf("charges[0].line_type mismatch: got=%v want=%v", got, want)
|
||||||
|
}
|
||||||
|
if got, want := postReq.GetCharges()[1].GetLedgerAccountRef(), "spread-ledger-1"; got != want {
|
||||||
|
t.Fatalf("charges[1].ledger_account_ref mismatch: got=%q want=%q", got, want)
|
||||||
|
}
|
||||||
|
if got, want := postReq.GetCharges()[1].GetMoney().GetAmount(), "1.25"; got != want {
|
||||||
|
t.Fatalf("charges[1].money.amount mismatch: got=%q want=%q", got, want)
|
||||||
|
}
|
||||||
|
if got, want := postReq.GetCharges()[1].GetLineType(), ledgerv1.LineType_LINE_SPREAD; got != want {
|
||||||
|
t.Fatalf("charges[1].line_type mismatch: got=%v want=%v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGatewayLedgerExecutor_ExecuteLedger_ExternalCreditSkipsChargesForExternalToExternalBoundary(t *testing.T) {
|
||||||
|
orgID := bson.NewObjectID()
|
||||||
|
payment := testLedgerExecutorPayment(orgID)
|
||||||
|
payment.QuoteSnapshot.FeeLines = []*paymenttypes.FeeLine{
|
||||||
|
{
|
||||||
|
LedgerAccountRef: "fee-ledger-1",
|
||||||
|
Money: &paymenttypes.Money{Amount: "1.00", Currency: "USDT"},
|
||||||
|
LineType: paymenttypes.PostingLineTypeFee,
|
||||||
|
Side: paymenttypes.EntrySideDebit,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var postReq *ledgerv1.PostCreditRequest
|
||||||
|
executor := &gatewayLedgerExecutor{
|
||||||
|
ledgerClient: &ledgerclient.Fake{
|
||||||
|
PostExternalCreditWithChargesFn: func(_ context.Context, req *ledgerv1.PostCreditRequest) (*ledgerv1.PostResponse, error) {
|
||||||
|
postReq = req
|
||||||
|
return &ledgerv1.PostResponse{JournalEntryRef: "entry-ext-credit-no-dup"}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := executor.ExecuteLedger(context.Background(), sexec.StepRequest{
|
||||||
|
Payment: payment,
|
||||||
|
Step: xplan.Step{
|
||||||
|
StepRef: "edge_1_2_ledger_credit",
|
||||||
|
StepCode: "edge.1_2.ledger.credit",
|
||||||
|
Action: discovery.RailOperationExternalCredit,
|
||||||
|
Rail: discovery.RailLedger,
|
||||||
|
},
|
||||||
|
StepExecution: agg.StepExecution{
|
||||||
|
StepRef: "edge_1_2_ledger_credit",
|
||||||
|
StepCode: "edge.1_2.ledger.credit",
|
||||||
|
Attempt: 1,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ExecuteLedger returned error: %v", err)
|
||||||
|
}
|
||||||
|
if postReq == nil {
|
||||||
|
t.Fatal("expected external credit request")
|
||||||
|
}
|
||||||
|
if got, want := len(postReq.GetCharges()), 0; got != want {
|
||||||
|
t.Fatalf("charges count mismatch: got=%d want=%d", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGatewayLedgerExecutor_ExecuteLedger_ExternalCreditForwardsChargesForExternalToInternalBoundary(t *testing.T) {
|
||||||
|
orgID := bson.NewObjectID()
|
||||||
|
payment := testLedgerExecutorPayment(orgID)
|
||||||
|
payment.QuoteSnapshot.ExpectedSettlementAmount = &paymenttypes.Money{Amount: "10", Currency: "USD"}
|
||||||
|
payment.QuoteSnapshot.Route = &paymenttypes.QuoteRouteSpecification{
|
||||||
|
Hops: []*paymenttypes.QuoteRouteHop{
|
||||||
|
{Index: 1, Rail: "CRYPTO", Role: paymenttypes.QuoteRouteHopRoleSource},
|
||||||
|
{Index: 2, Rail: "LEDGER", Role: paymenttypes.QuoteRouteHopRoleTransit},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
payment.QuoteSnapshot.FeeLines = []*paymenttypes.FeeLine{
|
||||||
|
{
|
||||||
|
LedgerAccountRef: "fee-ledger-1",
|
||||||
|
Money: &paymenttypes.Money{Amount: "0.75", Currency: "USD"},
|
||||||
|
LineType: paymenttypes.PostingLineTypeTax, // mapped to LINE_FEE in ledger
|
||||||
|
Side: paymenttypes.EntrySideDebit,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var postReq *ledgerv1.PostCreditRequest
|
||||||
|
executor := &gatewayLedgerExecutor{
|
||||||
|
ledgerClient: &ledgerclient.Fake{
|
||||||
|
PostExternalCreditWithChargesFn: func(_ context.Context, req *ledgerv1.PostCreditRequest) (*ledgerv1.PostResponse, error) {
|
||||||
|
postReq = req
|
||||||
|
return &ledgerv1.PostResponse{JournalEntryRef: "entry-ext-credit-fees"}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := executor.ExecuteLedger(context.Background(), sexec.StepRequest{
|
||||||
|
Payment: payment,
|
||||||
|
Step: xplan.Step{
|
||||||
|
StepRef: "edge_1_2_ledger_credit",
|
||||||
|
StepCode: "edge.1_2.ledger.credit",
|
||||||
|
Action: discovery.RailOperationExternalCredit,
|
||||||
|
Rail: discovery.RailLedger,
|
||||||
|
},
|
||||||
|
StepExecution: agg.StepExecution{
|
||||||
|
StepRef: "edge_1_2_ledger_credit",
|
||||||
|
StepCode: "edge.1_2.ledger.credit",
|
||||||
|
Attempt: 1,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ExecuteLedger returned error: %v", err)
|
||||||
|
}
|
||||||
|
if postReq == nil {
|
||||||
|
t.Fatal("expected external credit request")
|
||||||
|
}
|
||||||
|
if got, want := postReq.GetMoney().GetCurrency(), "USD"; got != want {
|
||||||
|
t.Fatalf("money.currency mismatch: got=%q want=%q", got, want)
|
||||||
|
}
|
||||||
|
if got, want := len(postReq.GetCharges()), 1; got != want {
|
||||||
|
t.Fatalf("charges count mismatch: got=%d want=%d", got, want)
|
||||||
|
}
|
||||||
|
if got, want := postReq.GetCharges()[0].GetMoney().GetAmount(), "-0.75"; got != want {
|
||||||
|
t.Fatalf("charges[0].money.amount mismatch: got=%q want=%q", got, want)
|
||||||
|
}
|
||||||
|
if got, want := postReq.GetCharges()[0].GetLineType(), ledgerv1.LineType_LINE_FEE; got != want {
|
||||||
|
t.Fatalf("charges[0].line_type mismatch: got=%v want=%v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestGatewayLedgerExecutor_ExecuteLedger_FinalizeDebitUsesHoldToTransitAndSettlementAmount(t *testing.T) {
|
func TestGatewayLedgerExecutor_ExecuteLedger_FinalizeDebitUsesHoldToTransitAndSettlementAmount(t *testing.T) {
|
||||||
orgID := bson.NewObjectID()
|
orgID := bson.NewObjectID()
|
||||||
payment := testLedgerExecutorPayment(orgID)
|
payment := testLedgerExecutorPayment(orgID)
|
||||||
|
|||||||
Reference in New Issue
Block a user