improved logging in callbacks
This commit is contained in:
@@ -21,6 +21,7 @@ import (
|
||||
msg "github.com/tech/sendico/pkg/messaging"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
"github.com/tech/sendico/pkg/mservice"
|
||||
"github.com/tech/sendico/pkg/mutil/mzap"
|
||||
feesv1 "github.com/tech/sendico/pkg/proto/billing/fees/v1"
|
||||
tracev1 "github.com/tech/sendico/pkg/proto/common/trace/v1"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
@@ -385,7 +386,7 @@ func (s *Service) computeQuoteWithTime(ctx context.Context, orgRef bson.ObjectID
|
||||
|
||||
logFields := []zap.Field{zap.Time("booked_at_used", bookedAt)}
|
||||
if !orgRef.IsZero() {
|
||||
logFields = append(logFields, zap.String("organization_ref", orgRef.Hex()))
|
||||
logFields = append(logFields, mzap.ObjRef("organization_ref", orgRef))
|
||||
}
|
||||
|
||||
logFields = append(logFields, logFieldsFromIntent(intent)...)
|
||||
|
||||
@@ -73,9 +73,10 @@ func validateQuoteIdempotency(previewOnly bool, idempotencyKey string) error {
|
||||
}
|
||||
|
||||
type InitiatePayment struct {
|
||||
PaymentBase `json:",inline"`
|
||||
Intent *PaymentIntent `json:"intent,omitempty"`
|
||||
QuoteRef string `json:"quoteRef,omitempty"`
|
||||
PaymentBase `json:",inline"`
|
||||
Intent *PaymentIntent `json:"intent,omitempty"`
|
||||
QuoteRef string `json:"quoteRef,omitempty"`
|
||||
ClientPaymentRef string `json:"clientPaymentRef,omitempty"`
|
||||
}
|
||||
|
||||
func (r InitiatePayment) Validate() error {
|
||||
@@ -106,8 +107,9 @@ func (r InitiatePayment) Validate() error {
|
||||
}
|
||||
|
||||
type InitiatePayments struct {
|
||||
PaymentBase `json:",inline"`
|
||||
QuoteRef string `json:"quoteRef,omitempty"`
|
||||
PaymentBase `json:",inline"`
|
||||
QuoteRef string `json:"quoteRef,omitempty"`
|
||||
ClientPaymentRef string `json:"clientPaymentRef,omitempty"`
|
||||
}
|
||||
|
||||
func (r *InitiatePayments) Validate() error {
|
||||
|
||||
@@ -120,11 +120,11 @@ func (a *AccountAPI) resetPassword(r *http.Request) http.HandlerFunc {
|
||||
var user model.Account
|
||||
err = a.db.Get(ctx, accountRef, &user)
|
||||
if errors.Is(err, merrors.ErrNoData) {
|
||||
a.logger.Info("User not found for password reset", zap.String("account_ref", accountRef.Hex()))
|
||||
a.logger.Info("User not found for password reset", mzap.ObjRef("account_ref", accountRef))
|
||||
return response.NotFound(a.logger, a.Name(), "User not found")
|
||||
}
|
||||
if err != nil {
|
||||
a.logger.Warn("Failed to get user for password reset", zap.Error(err), zap.String("account_ref", accountRef.Hex()))
|
||||
a.logger.Warn("Failed to get user for password reset", zap.Error(err), mzap.ObjRef("account_ref", accountRef))
|
||||
return response.Auto(a.logger, a.Name(), err)
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ func (a *AccountAPI) resetPassword(r *http.Request) http.HandlerFunc {
|
||||
}
|
||||
|
||||
if t.AccountRef != accountRef {
|
||||
a.logger.Warn("Token account reference does not match request account reference", zap.String("token_account_ref", t.AccountRef.Hex()), zap.String("request_account_ref", accountRef.Hex()))
|
||||
a.logger.Warn("Token account reference does not match request account reference", mzap.ObjRef("token_account_ref", t.AccountRef), mzap.ObjRef("request_account_ref", accountRef))
|
||||
return response.DataConflict(a.logger, a.Name(), "Token does not match account")
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
"github.com/tech/sendico/pkg/mutil/mzap"
|
||||
"github.com/tech/sendico/pkg/vault/kv"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
"go.uber.org/zap"
|
||||
@@ -152,7 +153,7 @@ func (m *vaultSigningSecretManager) Provision(
|
||||
}
|
||||
|
||||
secretRef := "vault:" + secretPath + "#" + m.field
|
||||
m.logger.Info("Callback signing secret stored", zap.String("secret_ref", secretRef), zap.String("callback_ref", callbackRef.Hex()))
|
||||
m.logger.Info("Callback signing secret stored", zap.String("secret_ref", secretRef), mzap.ObjRef("callback_ref", callbackRef))
|
||||
|
||||
return secretRef, secret, nil
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
"github.com/tech/sendico/pkg/model/account_role"
|
||||
"github.com/tech/sendico/pkg/mservice"
|
||||
"github.com/tech/sendico/pkg/mutil/mzap"
|
||||
describablev1 "github.com/tech/sendico/pkg/proto/common/describable/v1"
|
||||
ledgerv1 "github.com/tech/sendico/pkg/proto/ledger/v1"
|
||||
"github.com/tech/sendico/server/interface/api/srequest"
|
||||
@@ -88,7 +89,7 @@ func (a *LedgerAPI) createAccount(r *http.Request, account *model.Account, token
|
||||
Describable: describable,
|
||||
})
|
||||
if err != nil {
|
||||
a.logger.Warn("Failed to create ledger account", zap.Error(err), zap.String("organization_ref", orgRef.Hex()))
|
||||
a.logger.Warn("Failed to create ledger account", zap.Error(err), mzap.ObjRef("organization_ref", orgRef))
|
||||
return response.Auto(a.logger, mservice.Ledger, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ func (a *LedgerAPI) listAccounts(r *http.Request, account *model.Account, token
|
||||
|
||||
resp, err := a.client.ListAccounts(ctx, req)
|
||||
if err != nil {
|
||||
a.logger.Warn("Failed to list ledger accounts", zap.Error(err), zap.String("organization_ref", orgRef.Hex()))
|
||||
a.logger.Warn("Failed to list ledger accounts", zap.Error(err), mzap.ObjRef("organization_ref", orgRef))
|
||||
return response.Auto(a.logger, mservice.Ledger, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ func (a *PaymentAPI) initiatePayment(r *http.Request, account *model.Account, to
|
||||
req := &orchestrationv2.ExecutePaymentRequest{
|
||||
Meta: requestMeta(orgRef.Hex(), payload.IdempotencyKey),
|
||||
QuotationRef: quotationRef,
|
||||
ClientPaymentRef: metadataValue(payload.Metadata, "client_payment_ref"),
|
||||
ClientPaymentRef: strings.TrimSpace(payload.ClientPaymentRef),
|
||||
}
|
||||
|
||||
resp, err := a.execution.ExecutePayment(ctx, req)
|
||||
@@ -110,6 +110,7 @@ func decodeInitiatePayload(r *http.Request) (*srequest.InitiatePayment, error) {
|
||||
}
|
||||
payload.IdempotencyKey = strings.TrimSpace(payload.IdempotencyKey)
|
||||
payload.QuoteRef = strings.TrimSpace(payload.QuoteRef)
|
||||
payload.ClientPaymentRef = strings.TrimSpace(payload.ClientPaymentRef)
|
||||
|
||||
if err := payload.Validate(); err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -14,12 +14,12 @@ import (
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
)
|
||||
|
||||
func TestInitiateByQuote_DoesNotUseIntentRef(t *testing.T) {
|
||||
func TestInitiateByQuote_ForwardsClientPaymentRef(t *testing.T) {
|
||||
orgRef := bson.NewObjectID()
|
||||
exec := &fakeExecutionClientForBatch{}
|
||||
api := newBatchAPI(exec)
|
||||
|
||||
body := `{"idempotencyKey":"idem-by-quote","quoteRef":"quote-1","metadata":{"client_payment_ref":"client-ref-1"}}`
|
||||
body := `{"idempotencyKey":"idem-by-quote","quoteRef":"quote-1","clientPaymentRef":"client-ref-1"}`
|
||||
rr := invokeInitiateByQuote(t, api, orgRef, body)
|
||||
if got, want := rr.Code, http.StatusOK; got != want {
|
||||
t.Fatalf("status mismatch: got=%d want=%d body=%s", got, want, rr.Body.String())
|
||||
@@ -32,6 +32,24 @@ func TestInitiateByQuote_DoesNotUseIntentRef(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestInitiateByQuote_DoesNotForwardLegacyClientPaymentRefFromMetadata(t *testing.T) {
|
||||
orgRef := bson.NewObjectID()
|
||||
exec := &fakeExecutionClientForBatch{}
|
||||
api := newBatchAPI(exec)
|
||||
|
||||
body := `{"idempotencyKey":"idem-by-quote","quoteRef":"quote-1","metadata":{"client_payment_ref":"legacy-client-ref"}}`
|
||||
rr := invokeInitiateByQuote(t, api, orgRef, body)
|
||||
if got, want := rr.Code, http.StatusOK; got != want {
|
||||
t.Fatalf("status mismatch: got=%d want=%d body=%s", got, want, rr.Body.String())
|
||||
}
|
||||
if got, want := len(exec.executeReqs), 1; got != want {
|
||||
t.Fatalf("execute calls mismatch: got=%d want=%d", got, want)
|
||||
}
|
||||
if got := exec.executeReqs[0].GetClientPaymentRef(); got != "" {
|
||||
t.Fatalf("expected empty client_payment_ref, got=%q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInitiateByQuote_RejectsMetadataIntentRef(t *testing.T) {
|
||||
orgRef := bson.NewObjectID()
|
||||
exec := &fakeExecutionClientForBatch{}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/tech/sendico/pkg/api/http/response"
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
"github.com/tech/sendico/pkg/mutil/mzap"
|
||||
orchestrationv2 "github.com/tech/sendico/pkg/proto/payments/orchestration/v2"
|
||||
"github.com/tech/sendico/server/interface/api/srequest"
|
||||
"github.com/tech/sendico/server/interface/api/sresponse"
|
||||
@@ -39,7 +40,7 @@ func (a *PaymentAPI) initiatePaymentsByQuote(r *http.Request, account *model.Acc
|
||||
return response.BadPayload(a.logger, a.Name(), err)
|
||||
}
|
||||
|
||||
clientPaymentRef := metadataValue(payload.Metadata, "client_payment_ref")
|
||||
clientPaymentRef := strings.TrimSpace(payload.ClientPaymentRef)
|
||||
idempotencyKey := strings.TrimSpace(payload.IdempotencyKey)
|
||||
quotationRef := strings.TrimSpace(payload.QuoteRef)
|
||||
|
||||
@@ -50,7 +51,7 @@ func (a *PaymentAPI) initiatePaymentsByQuote(r *http.Request, account *model.Acc
|
||||
}
|
||||
resp, err := a.execution.ExecuteBatchPayment(ctx, req)
|
||||
if err != nil {
|
||||
a.logger.Warn("Failed to initiate batch payments", zap.Error(err), zap.String("organization_ref", orgRef.Hex()))
|
||||
a.logger.Warn("Failed to initiate batch payments", zap.Error(err), mzap.ObjRef("organization_ref", orgRef))
|
||||
return grpcErrorResponse(a.logger, a.Name(), err)
|
||||
}
|
||||
|
||||
@@ -72,6 +73,7 @@ func decodeInitiatePaymentsPayload(r *http.Request) (*srequest.InitiatePayments,
|
||||
}
|
||||
payload.IdempotencyKey = strings.TrimSpace(payload.IdempotencyKey)
|
||||
payload.QuoteRef = strings.TrimSpace(payload.QuoteRef)
|
||||
payload.ClientPaymentRef = strings.TrimSpace(payload.ClientPaymentRef)
|
||||
|
||||
if err := payload.Validate(); err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -50,7 +50,7 @@ func TestInitiatePaymentsByQuote_ForwardsClientPaymentRef(t *testing.T) {
|
||||
exec := &fakeExecutionClientForBatch{}
|
||||
api := newBatchAPI(exec)
|
||||
|
||||
body := `{"idempotencyKey":"idem-batch","quoteRef":"quote-1","metadata":{"client_payment_ref":"client-ref-1"}}`
|
||||
body := `{"idempotencyKey":"idem-batch","quoteRef":"quote-1","clientPaymentRef":"client-ref-1"}`
|
||||
rr := invokeInitiatePaymentsByQuote(t, api, orgRef, body)
|
||||
if got, want := rr.Code, http.StatusOK; got != want {
|
||||
t.Fatalf("status mismatch: got=%d want=%d body=%s", got, want, rr.Body.String())
|
||||
@@ -67,6 +67,25 @@ func TestInitiatePaymentsByQuote_ForwardsClientPaymentRef(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestInitiatePaymentsByQuote_DoesNotForwardLegacyClientPaymentRefFromMetadata(t *testing.T) {
|
||||
orgRef := bson.NewObjectID()
|
||||
exec := &fakeExecutionClientForBatch{}
|
||||
api := newBatchAPI(exec)
|
||||
|
||||
body := `{"idempotencyKey":"idem-batch","quoteRef":"quote-1","metadata":{"client_payment_ref":"legacy-client-ref"}}`
|
||||
rr := invokeInitiatePaymentsByQuote(t, api, orgRef, body)
|
||||
if got, want := rr.Code, http.StatusOK; got != want {
|
||||
t.Fatalf("status mismatch: got=%d want=%d body=%s", got, want, rr.Body.String())
|
||||
}
|
||||
|
||||
if got, want := len(exec.executeBatchReqs), 1; got != want {
|
||||
t.Fatalf("execute batch calls mismatch: got=%d want=%d", got, want)
|
||||
}
|
||||
if got := exec.executeBatchReqs[0].GetClientPaymentRef(); got != "" {
|
||||
t.Fatalf("expected empty client_payment_ref, got=%q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInitiatePaymentsByQuote_RejectsDeprecatedIntentRefField(t *testing.T) {
|
||||
orgRef := bson.NewObjectID()
|
||||
exec := &fakeExecutionClientForBatch{}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/tech/sendico/pkg/api/http/response"
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
"github.com/tech/sendico/pkg/mutil/mzap"
|
||||
quotationv2 "github.com/tech/sendico/pkg/proto/payments/quotation/v2"
|
||||
"github.com/tech/sendico/server/interface/api/srequest"
|
||||
"github.com/tech/sendico/server/interface/api/sresponse"
|
||||
@@ -61,7 +62,7 @@ func (a *PaymentAPI) quotePayment(r *http.Request, account *model.Account, token
|
||||
|
||||
resp, err := a.quotation.QuotePayment(ctx, req)
|
||||
if err != nil {
|
||||
a.logger.Warn("Failed to quote payment", zap.Error(err), zap.String("organization_ref", orgRef.Hex()))
|
||||
a.logger.Warn("Failed to quote payment", zap.Error(err), mzap.ObjRef("organization_ref", orgRef))
|
||||
return grpcErrorResponse(a.logger, a.Name(), err)
|
||||
}
|
||||
|
||||
@@ -117,7 +118,7 @@ func (a *PaymentAPI) quotePayments(r *http.Request, account *model.Account, toke
|
||||
|
||||
resp, err := a.quotation.QuotePayments(ctx, req)
|
||||
if err != nil {
|
||||
a.logger.Warn("Failed to quote payments", zap.Error(err), zap.String("organization_ref", orgRef.Hex()))
|
||||
a.logger.Warn("Failed to quote payments", zap.Error(err), mzap.ObjRef("organization_ref", orgRef))
|
||||
return grpcErrorResponse(a.logger, a.Name(), err)
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
"github.com/tech/sendico/pkg/mservice"
|
||||
"github.com/tech/sendico/pkg/mutil/mzap"
|
||||
connectorv1 "github.com/tech/sendico/pkg/proto/connector/v1"
|
||||
"github.com/tech/sendico/server/interface/api/sresponse"
|
||||
mutil "github.com/tech/sendico/server/internal/mutil/param"
|
||||
@@ -65,24 +66,24 @@ func (a *WalletAPI) getWalletBalance(r *http.Request, account *model.Account, to
|
||||
return response.Auto(a.logger, a.Name(), merrors.NoData("no crypto gateways available"))
|
||||
}
|
||||
a.logger.Debug("Resolved CRYPTO gateways for wallet balance lookup",
|
||||
zap.String("organization_ref", orgRef.Hex()),
|
||||
mzap.ObjRef("organization_ref", orgRef),
|
||||
zap.String("wallet_ref", walletRef),
|
||||
zap.Int("gateway_count", len(cryptoGateways)))
|
||||
|
||||
route, routeErr := a.walletRoute(ctx, orgRef.Hex(), walletRef)
|
||||
if routeErr != nil {
|
||||
a.logger.Warn("Failed to resolve wallet route", zap.Error(routeErr), zap.String("wallet_ref", walletRef), zap.String("organization_ref", orgRef.Hex()))
|
||||
a.logger.Warn("Failed to resolve wallet route", zap.Error(routeErr), zap.String("wallet_ref", walletRef), mzap.ObjRef("organization_ref", orgRef))
|
||||
}
|
||||
if route != nil {
|
||||
a.logger.Debug("Resolved stored wallet route",
|
||||
zap.String("organization_ref", orgRef.Hex()),
|
||||
mzap.ObjRef("organization_ref", orgRef),
|
||||
zap.String("wallet_ref", walletRef),
|
||||
zap.String("route_network", route.Network),
|
||||
zap.String("route_gateway_id", route.GatewayID))
|
||||
preferred := findGatewayForRoute(cryptoGateways, route)
|
||||
if preferred != nil {
|
||||
a.logger.Debug("Using preferred gateway from stored wallet route",
|
||||
zap.String("organization_ref", orgRef.Hex()),
|
||||
mzap.ObjRef("organization_ref", orgRef),
|
||||
zap.String("wallet_ref", walletRef),
|
||||
zap.String("gateway_id", preferred.ID),
|
||||
zap.String("network", preferred.Network),
|
||||
@@ -91,7 +92,7 @@ func (a *WalletAPI) getWalletBalance(r *http.Request, account *model.Account, to
|
||||
if preferredErr == nil && bal != nil {
|
||||
a.rememberWalletRoute(ctx, orgRef.Hex(), walletRef, preferred.Network, preferred.ID)
|
||||
a.logger.Debug("Wallet balance resolved via preferred gateway",
|
||||
zap.String("organization_ref", orgRef.Hex()),
|
||||
mzap.ObjRef("organization_ref", orgRef),
|
||||
zap.String("wallet_ref", walletRef),
|
||||
zap.String("gateway_id", preferred.ID),
|
||||
zap.String("network", preferred.Network))
|
||||
@@ -124,20 +125,20 @@ func (a *WalletAPI) getWalletBalance(r *http.Request, account *model.Account, to
|
||||
}
|
||||
} else {
|
||||
a.logger.Warn("Stored wallet route did not match any healthy discovery gateway",
|
||||
zap.String("organization_ref", orgRef.Hex()),
|
||||
mzap.ObjRef("organization_ref", orgRef),
|
||||
zap.String("wallet_ref", walletRef),
|
||||
zap.String("route_network", route.Network),
|
||||
zap.String("route_gateway_id", route.GatewayID))
|
||||
}
|
||||
} else {
|
||||
a.logger.Debug("Stored wallet route not found; using gateway fallback",
|
||||
zap.String("organization_ref", orgRef.Hex()),
|
||||
mzap.ObjRef("organization_ref", orgRef),
|
||||
zap.String("wallet_ref", walletRef))
|
||||
}
|
||||
|
||||
// Fall back to querying remaining gateways in parallel.
|
||||
a.logger.Debug("Starting fallback wallet balance fan-out",
|
||||
zap.String("organization_ref", orgRef.Hex()),
|
||||
mzap.ObjRef("organization_ref", orgRef),
|
||||
zap.String("wallet_ref", walletRef),
|
||||
zap.Int("gateway_count", len(cryptoGateways)))
|
||||
bal, err := a.queryBalanceFromGateways(ctx, cryptoGateways, orgRef.Hex(), walletRef)
|
||||
|
||||
@@ -81,7 +81,7 @@ func (a *WalletAPI) create(r *http.Request, account *model.Account, token *sresp
|
||||
return response.Auto(a.logger, a.Name(), merrors.InvalidArgument("no gateway available for network: "+networkName))
|
||||
}
|
||||
a.logger.Debug("Selected gateway for wallet creation",
|
||||
zap.String("organization_ref", orgRef.Hex()),
|
||||
mzap.ObjRef("organization_ref", orgRef),
|
||||
zap.String("network", networkName),
|
||||
zap.String("gateway_id", gateway.ID),
|
||||
zap.String("gateway_network", gateway.Network),
|
||||
@@ -134,7 +134,7 @@ func (a *WalletAPI) create(r *http.Request, account *model.Account, token *sresp
|
||||
a.rememberWalletRoute(ctx, orgRef.Hex(), walletRef, networkName, gateway.ID)
|
||||
a.rememberWalletRoute(ctx, orgRef.Hex(), walletRef, gateway.Network, gateway.ID)
|
||||
a.logger.Debug("Persisted wallet route after wallet creation",
|
||||
zap.String("organization_ref", orgRef.Hex()),
|
||||
mzap.ObjRef("organization_ref", orgRef),
|
||||
zap.String("wallet_ref", walletRef),
|
||||
zap.String("network", networkName),
|
||||
zap.String("gateway_id", gateway.ID))
|
||||
|
||||
@@ -59,7 +59,7 @@ func (a *WalletAPI) listWallets(r *http.Request, account *model.Account, token *
|
||||
return sresponse.Wallets(a.logger, nil, token)
|
||||
}
|
||||
a.logger.Debug("Resolved CRYPTO gateways for wallet list",
|
||||
zap.String("organization_ref", orgRef.Hex()),
|
||||
mzap.ObjRef("organization_ref", orgRef),
|
||||
zap.Int("gateway_count", len(cryptoGateways)))
|
||||
|
||||
// Build request
|
||||
@@ -80,7 +80,7 @@ func (a *WalletAPI) listWallets(r *http.Request, account *model.Account, token *
|
||||
allAccounts := a.queryAllGateways(ctx, cryptoGateways, req)
|
||||
dedupedAccounts := dedupeAccountsByWalletRef(allAccounts)
|
||||
a.logger.Debug("Wallet list fan-out completed",
|
||||
zap.String("organization_ref", orgRef.Hex()),
|
||||
mzap.ObjRef("organization_ref", orgRef),
|
||||
zap.Int("accounts_raw", len(allAccounts)),
|
||||
zap.Int("accounts_deduped", len(dedupedAccounts)),
|
||||
zap.Int("gateway_count", len(cryptoGateways)))
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/tech/sendico/edge/callbacks/internal/storage"
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
"github.com/tech/sendico/pkg/mutil/mzap"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
@@ -171,14 +172,14 @@ func (s *service) handleTask(ctx context.Context, workerID string, task *model.T
|
||||
result = "blocked"
|
||||
s.logger.Warn("Blocked task delivery due to URL validation failure",
|
||||
zap.String("worker_id", workerID),
|
||||
zap.String("task_id", task.ID.Hex()),
|
||||
mzap.ObjRef("task_ref", task.ID),
|
||||
zap.String("event_id", task.EventID),
|
||||
zap.Error(err),
|
||||
)
|
||||
if markErr := s.tasks.MarkFailed(ctx, task.ID, attempt, err.Error(), statusCode, time.Now().UTC()); markErr != nil {
|
||||
s.logger.Warn("Failed to mark blocked task as failed",
|
||||
zap.String("worker_id", workerID),
|
||||
zap.String("task_id", task.ID.Hex()),
|
||||
mzap.ObjRef("task_ref", task.ID),
|
||||
zap.Error(markErr),
|
||||
)
|
||||
}
|
||||
@@ -195,7 +196,7 @@ func (s *service) handleTask(ctx context.Context, workerID string, task *model.T
|
||||
result = "sign_error"
|
||||
s.logger.Warn("Failed to sign task payload",
|
||||
zap.String("worker_id", workerID),
|
||||
zap.String("task_id", task.ID.Hex()),
|
||||
mzap.ObjRef("task_ref", task.ID),
|
||||
zap.String("event_id", task.EventID),
|
||||
zap.String("signing_mode", task.SigningMode),
|
||||
zap.Error(err),
|
||||
@@ -203,7 +204,7 @@ func (s *service) handleTask(ctx context.Context, workerID string, task *model.T
|
||||
if markErr := s.tasks.MarkFailed(ctx, task.ID, attempt, err.Error(), statusCode, time.Now().UTC()); markErr != nil {
|
||||
s.logger.Warn("Failed to mark signing-error task as failed",
|
||||
zap.String("worker_id", workerID),
|
||||
zap.String("task_id", task.ID.Hex()),
|
||||
mzap.ObjRef("task_ref", task.ID),
|
||||
zap.Error(markErr),
|
||||
)
|
||||
}
|
||||
@@ -218,7 +219,7 @@ func (s *service) handleTask(ctx context.Context, workerID string, task *model.T
|
||||
result = "request_error"
|
||||
s.logger.Warn("Failed to build callback request",
|
||||
zap.String("worker_id", workerID),
|
||||
zap.String("task_id", task.ID.Hex()),
|
||||
mzap.ObjRef("task_ref", task.ID),
|
||||
zap.String("event_id", task.EventID),
|
||||
zap.String("endpoint_url", task.EndpointURL),
|
||||
zap.Error(err),
|
||||
@@ -226,7 +227,7 @@ func (s *service) handleTask(ctx context.Context, workerID string, task *model.T
|
||||
if markErr := s.tasks.MarkFailed(ctx, task.ID, attempt, err.Error(), statusCode, time.Now().UTC()); markErr != nil {
|
||||
s.logger.Warn("Failed to mark request-error task as failed",
|
||||
zap.String("worker_id", workerID),
|
||||
zap.String("task_id", task.ID.Hex()),
|
||||
mzap.ObjRef("task_ref", task.ID),
|
||||
zap.Error(markErr),
|
||||
)
|
||||
}
|
||||
@@ -253,7 +254,7 @@ func (s *service) handleTask(ctx context.Context, workerID string, task *model.T
|
||||
case outcomeDelivered:
|
||||
result = string(outcomeDelivered)
|
||||
if err := s.tasks.MarkDelivered(ctx, task.ID, statusCode, time.Since(started), now); err != nil {
|
||||
s.logger.Warn("Failed to mark task delivered", zap.String("worker_id", workerID), zap.String("task_id", task.ID.Hex()), zap.Error(err))
|
||||
s.logger.Warn("Failed to mark task delivered", zap.String("worker_id", workerID), mzap.ObjRef("task_ref", task.ID), zap.Error(err))
|
||||
}
|
||||
case outcomeRetry:
|
||||
if attempt < task.MaxAttempts {
|
||||
@@ -265,7 +266,7 @@ func (s *service) handleTask(ctx context.Context, workerID string, task *model.T
|
||||
}
|
||||
s.logger.Warn("Task delivery retry scheduled",
|
||||
zap.String("worker_id", workerID),
|
||||
zap.String("task_id", task.ID.Hex()),
|
||||
mzap.ObjRef("task_ref", task.ID),
|
||||
zap.String("event_id", task.EventID),
|
||||
zap.Int("attempt", attempt),
|
||||
zap.Int("status_code", statusCode),
|
||||
@@ -273,7 +274,7 @@ func (s *service) handleTask(ctx context.Context, workerID string, task *model.T
|
||||
zap.Time("next_attempt_at", next),
|
||||
)
|
||||
if err := s.tasks.MarkRetry(ctx, task.ID, attempt, next, lastErr, statusCode, now); err != nil {
|
||||
s.logger.Warn("Failed to mark task retry", zap.String("worker_id", workerID), zap.String("task_id", task.ID.Hex()), zap.Error(err))
|
||||
s.logger.Warn("Failed to mark task retry", zap.String("worker_id", workerID), mzap.ObjRef("task_ref", task.ID), zap.Error(err))
|
||||
}
|
||||
} else {
|
||||
result = string(outcomeFailed)
|
||||
@@ -283,7 +284,7 @@ func (s *service) handleTask(ctx context.Context, workerID string, task *model.T
|
||||
}
|
||||
s.logger.Warn("Task delivery failed after reaching max attempts",
|
||||
zap.String("worker_id", workerID),
|
||||
zap.String("task_id", task.ID.Hex()),
|
||||
mzap.ObjRef("task_ref", task.ID),
|
||||
zap.String("event_id", task.EventID),
|
||||
zap.Int("attempt", attempt),
|
||||
zap.Int("max_attempts", task.MaxAttempts),
|
||||
@@ -291,7 +292,7 @@ func (s *service) handleTask(ctx context.Context, workerID string, task *model.T
|
||||
zap.String("reason", lastErr),
|
||||
)
|
||||
if err := s.tasks.MarkFailed(ctx, task.ID, attempt, lastErr, statusCode, now); err != nil {
|
||||
s.logger.Warn("Failed to mark task failed", zap.String("worker_id", workerID), zap.String("task_id", task.ID.Hex()), zap.Error(err))
|
||||
s.logger.Warn("Failed to mark task failed", zap.String("worker_id", workerID), mzap.ObjRef("task_ref", task.ID), zap.Error(err))
|
||||
}
|
||||
}
|
||||
default:
|
||||
@@ -302,14 +303,14 @@ func (s *service) handleTask(ctx context.Context, workerID string, task *model.T
|
||||
}
|
||||
s.logger.Warn("Task delivery failed",
|
||||
zap.String("worker_id", workerID),
|
||||
zap.String("task_id", task.ID.Hex()),
|
||||
mzap.ObjRef("task_ref", task.ID),
|
||||
zap.String("event_id", task.EventID),
|
||||
zap.Int("attempt", attempt),
|
||||
zap.Int("status_code", statusCode),
|
||||
zap.String("reason", lastErr),
|
||||
)
|
||||
if err := s.tasks.MarkFailed(ctx, task.ID, attempt, lastErr, statusCode, now); err != nil {
|
||||
s.logger.Warn("Failed to mark task failed", zap.String("worker_id", workerID), zap.String("task_id", task.ID.Hex()), zap.Error(err))
|
||||
s.logger.Warn("Failed to mark task failed", zap.String("worker_id", workerID), mzap.ObjRef("task_ref", task.ID), zap.Error(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/tech/sendico/edge/callbacks/internal/storage"
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
"github.com/tech/sendico/pkg/mutil/mzap"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@@ -45,7 +46,7 @@ func (s *service) Resolve(ctx context.Context, eventType string, organizationRef
|
||||
if err != nil {
|
||||
s.logger.Warn("Failed to resolve active endpoints",
|
||||
zap.String("event_type", eventType),
|
||||
zap.String("organization_ref", organizationRef.Hex()),
|
||||
mzap.ObjRef("organization_ref", organizationRef),
|
||||
zap.Error(err),
|
||||
)
|
||||
return nil, err
|
||||
@@ -53,7 +54,7 @@ func (s *service) Resolve(ctx context.Context, eventType string, organizationRef
|
||||
|
||||
s.logger.Debug("Resolved active endpoints",
|
||||
zap.String("event_type", eventType),
|
||||
zap.String("organization_ref", organizationRef.Hex()),
|
||||
mzap.ObjRef("organization_ref", organizationRef),
|
||||
zap.Int("endpoints", len(endpoints)),
|
||||
)
|
||||
|
||||
|
||||
@@ -66,8 +66,7 @@ func (s *Service) postCreditResponder(_ context.Context, req *ledgerv1.PostCredi
|
||||
existingEntry, err := s.storage.JournalEntries().GetByIdempotencyKey(ctx, orgRef, req.IdempotencyKey)
|
||||
if err == nil && existingEntry != nil {
|
||||
recordDuplicateRequest(journalEntryTypeCredit)
|
||||
logger.Info("Duplicate credit request (idempotency)",
|
||||
zap.String("existingEntryID", existingEntry.GetID().Hex()))
|
||||
logger.Info("Duplicate credit request (idempotency)", mzap.StorableRef(existingEntry))
|
||||
return &ledgerv1.PostResponse{
|
||||
JournalEntryRef: existingEntry.GetID().Hex(),
|
||||
Version: existingEntry.Version,
|
||||
|
||||
@@ -64,8 +64,7 @@ func (s *Service) postDebitResponder(_ context.Context, req *ledgerv1.PostDebitR
|
||||
existingEntry, err := s.storage.JournalEntries().GetByIdempotencyKey(ctx, orgRef, req.IdempotencyKey)
|
||||
if err == nil && existingEntry != nil {
|
||||
recordDuplicateRequest(journalEntryTypeDebit)
|
||||
logger.Info("Duplicate debit request (idempotency)",
|
||||
zap.String("existingEntryID", existingEntry.GetID().Hex()))
|
||||
logger.Info("Duplicate debit request (idempotency)", mzap.StorableRef(existingEntry))
|
||||
return &ledgerv1.PostResponse{
|
||||
JournalEntryRef: existingEntry.GetID().Hex(),
|
||||
Version: existingEntry.Version,
|
||||
@@ -123,7 +122,7 @@ func (s *Service) postDebitResponder(_ context.Context, req *ledgerv1.PostDebitR
|
||||
if err == storage.ErrAccountNotFound {
|
||||
return nil, merrors.NoData(fmt.Sprintf("charges[%d]: account not found", i))
|
||||
}
|
||||
logger.Warn("Failed to get charge account", zap.Error(err), zap.String("chargeAccountRef", chargeAccountRef.Hex()))
|
||||
logger.Warn("Failed to get charge account", zap.Error(err), mzap.ObjRef("charge_account_ref", chargeAccountRef))
|
||||
return nil, merrors.Internal("failed to get charge account")
|
||||
}
|
||||
if err := validateAccountForOrg(chargeAccount, orgRef, charge.Money.Currency); err != nil {
|
||||
|
||||
@@ -62,7 +62,7 @@ func (s *Service) postExternalCreditResponder(_ context.Context, req *ledgerv1.P
|
||||
if err == nil && existingEntry != nil {
|
||||
recordDuplicateRequest(journalEntryTypeCredit)
|
||||
logger.Info("Duplicate external credit request (idempotency)",
|
||||
zap.String("existingEntryID", existingEntry.GetID().Hex()))
|
||||
mzap.StorableRef(existingEntry))
|
||||
return &ledgerv1.PostResponse{
|
||||
JournalEntryRef: existingEntry.GetID().Hex(),
|
||||
Version: existingEntry.Version,
|
||||
@@ -140,7 +140,7 @@ func (s *Service) postExternalCreditResponder(_ context.Context, req *ledgerv1.P
|
||||
if err == storage.ErrAccountNotFound {
|
||||
return nil, merrors.NoData(fmt.Sprintf("charges[%d]: account not found", i))
|
||||
}
|
||||
logger.Warn("Failed to get charge account", zap.Error(err), zap.String("chargeAccountRef", chargeAccountRef.Hex()))
|
||||
logger.Warn("Failed to get charge account", zap.Error(err), mzap.ObjRef("charge_account_ref", chargeAccountRef))
|
||||
return nil, merrors.Internal("failed to get charge account")
|
||||
}
|
||||
if err := validateAccountForOrg(chargeAccount, orgRef, charge.Money.Currency); err != nil {
|
||||
@@ -287,8 +287,7 @@ func (s *Service) postExternalDebitResponder(_ context.Context, req *ledgerv1.Po
|
||||
existingEntry, err := s.storage.JournalEntries().GetByIdempotencyKey(ctx, orgRef, req.IdempotencyKey)
|
||||
if err == nil && existingEntry != nil {
|
||||
recordDuplicateRequest(journalEntryTypeDebit)
|
||||
logger.Info("Duplicate external debit request (idempotency)",
|
||||
zap.String("existingEntryID", existingEntry.GetID().Hex()))
|
||||
logger.Info("Duplicate external debit request (idempotency)", mzap.StorableRef(existingEntry))
|
||||
return &ledgerv1.PostResponse{
|
||||
JournalEntryRef: existingEntry.GetID().Hex(),
|
||||
Version: existingEntry.Version,
|
||||
@@ -366,7 +365,7 @@ func (s *Service) postExternalDebitResponder(_ context.Context, req *ledgerv1.Po
|
||||
if err == storage.ErrAccountNotFound {
|
||||
return nil, merrors.NoData(fmt.Sprintf("charges[%d]: account not found", i))
|
||||
}
|
||||
logger.Warn("Failed to get charge account", zap.Error(err), zap.String("chargeAccountRef", chargeAccountRef.Hex()))
|
||||
logger.Warn("Failed to get charge account", zap.Error(err), mzap.ObjRef("charge_account_ref", chargeAccountRef))
|
||||
return nil, merrors.Internal("failed to get charge account")
|
||||
}
|
||||
if err := validateAccountForOrg(chargeAccount, orgRef, charge.Money.Currency); err != nil {
|
||||
|
||||
@@ -77,8 +77,7 @@ func (s *Service) fxResponder(_ context.Context, req *ledgerv1.FXRequest) gsresp
|
||||
existingEntry, err := s.storage.JournalEntries().GetByIdempotencyKey(ctx, orgRef, req.IdempotencyKey)
|
||||
if err == nil && existingEntry != nil {
|
||||
recordDuplicateRequest(journalEntryTypeFX)
|
||||
logger.Info("Duplicate FX request (idempotency)",
|
||||
zap.String("existingEntryID", existingEntry.GetID().Hex()))
|
||||
logger.Info("Duplicate FX request (idempotency)", mzap.StorableRef(existingEntry))
|
||||
return &ledgerv1.PostResponse{
|
||||
JournalEntryRef: existingEntry.GetID().Hex(),
|
||||
Version: existingEntry.Version,
|
||||
@@ -162,7 +161,7 @@ func (s *Service) fxResponder(_ context.Context, req *ledgerv1.FXRequest) gsresp
|
||||
if err == storage.ErrAccountNotFound {
|
||||
return nil, merrors.NoData(fmt.Sprintf("charges[%d]: account not found", i))
|
||||
}
|
||||
logger.Warn("Failed to get FX charge account", zap.Error(err), zap.String("chargeAccountRef", chargeAccountRef.Hex()))
|
||||
logger.Warn("Failed to get FX charge account", zap.Error(err), mzap.ObjRef("charge_account_ref", chargeAccountRef))
|
||||
return nil, merrors.Internal("failed to get charge account")
|
||||
}
|
||||
if err := validateAccountForOrg(chargeAccount, orgRef, charge.Money.Currency); err != nil {
|
||||
|
||||
@@ -139,7 +139,7 @@ func (s *Service) resolveSettlementAccount(ctx context.Context, orgRef bson.Obje
|
||||
if errors.Is(err, storage.ErrAccountNotFound) {
|
||||
return nil, merrors.NoData("contra account not found")
|
||||
}
|
||||
s.logger.Warn("Failed to load override contra account", zap.Error(err), zap.String("accountRef", overrideRef.Hex()))
|
||||
s.logger.Warn("Failed to load override contra account", zap.Error(err), mzap.ObjRef("account_ref", overrideRef))
|
||||
return nil, merrors.Internal("failed to load contra account")
|
||||
}
|
||||
if err := validateAccountForOrg(account, orgRef, currency); err != nil {
|
||||
|
||||
@@ -87,8 +87,7 @@ func (s *Service) transferResponder(_ context.Context, req *ledgerv1.TransferReq
|
||||
existingEntry, err := s.storage.JournalEntries().GetByIdempotencyKey(ctx, orgRef, req.IdempotencyKey)
|
||||
if err == nil && existingEntry != nil {
|
||||
recordDuplicateRequest(journalEntryTypeTransfer)
|
||||
logger.Info("Duplicate transfer request (idempotency)",
|
||||
zap.String("existingEntryID", existingEntry.GetID().Hex()))
|
||||
logger.Info("Duplicate transfer request (idempotency)", mzap.StorableRef(existingEntry))
|
||||
return &ledgerv1.PostResponse{
|
||||
JournalEntryRef: existingEntry.GetID().Hex(),
|
||||
Version: existingEntry.Version,
|
||||
@@ -172,7 +171,7 @@ func (s *Service) transferResponder(_ context.Context, req *ledgerv1.TransferReq
|
||||
if err == storage.ErrAccountNotFound {
|
||||
return nil, merrors.NoData(fmt.Sprintf("charges[%d]: account not found", i))
|
||||
}
|
||||
logger.Warn("Failed to get charge account", zap.Error(err), zap.String("chargeAccountRef", chargeAccountRef.Hex()))
|
||||
logger.Warn("Failed to get charge account", zap.Error(err), mzap.ObjRef("charge_account_ref", chargeAccountRef))
|
||||
return nil, merrors.Internal("failed to get charge account")
|
||||
}
|
||||
if err := validateAccountForOrg(chargeAccount, orgRef, charge.Money.Currency); err != nil {
|
||||
|
||||
@@ -83,17 +83,17 @@ func (b *balancesStore) Upsert(ctx context.Context, balance *model.AccountBalanc
|
||||
|
||||
if err := b.repo.FindOneByFilter(ctx, filter, existing); err != nil {
|
||||
if errors.Is(err, merrors.ErrNoData) {
|
||||
b.logger.Debug("Inserting new balance", zap.String("accountRef", balance.AccountRef.Hex()))
|
||||
b.logger.Debug("Inserting new balance", mzap.ObjRef("account_ref", balance.AccountRef))
|
||||
return b.repo.Insert(ctx, balance, filter)
|
||||
}
|
||||
b.logger.Warn("Failed to fetch balance", zap.Error(err), zap.String("accountRef", balance.AccountRef.Hex()))
|
||||
b.logger.Warn("Failed to fetch balance", zap.Error(err), mzap.ObjRef("account_ref", balance.AccountRef))
|
||||
return err
|
||||
}
|
||||
|
||||
if existing.GetID() != nil {
|
||||
balance.SetID(*existing.GetID())
|
||||
}
|
||||
b.logger.Debug("Updating balance", zap.String("accountRef", balance.AccountRef.Hex()),
|
||||
b.logger.Debug("Updating balance", mzap.ObjRef("account_ref", balance.AccountRef),
|
||||
zap.String("balance", balance.Balance))
|
||||
return b.repo.Update(ctx, balance)
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
|
||||
const (
|
||||
paymentTypeAccount pkgmodel.PaymentType = 8
|
||||
maxPrivateMethodResolutionDepth = 8
|
||||
maxPrivateMethodResolutionDepth int = 8
|
||||
)
|
||||
|
||||
func (s *Service) GetPaymentMethodPrivate(ctx context.Context, req *methodsv1.GetPaymentMethodPrivateRequest) (*methodsv1.GetPaymentMethodPrivateResponse, error) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
np "github.com/tech/sendico/pkg/messaging/notifications/processor"
|
||||
nm "github.com/tech/sendico/pkg/model/notification"
|
||||
"github.com/tech/sendico/pkg/mservice"
|
||||
"github.com/tech/sendico/pkg/mutil/mzap"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@@ -62,25 +63,25 @@ func (s *Service) onRecipientNotification(
|
||||
if err != nil {
|
||||
s.logger.Warn("Failed to cascade archive payment methods by recipient",
|
||||
zap.Error(err),
|
||||
zap.String("recipient_ref", recipientRef.Hex()),
|
||||
zap.String("actor_account_ref", actorAccountRef.Hex()))
|
||||
mzap.ObjRef("recipient_ref", recipientRef),
|
||||
mzap.ObjRef("actor_account_ref", actorAccountRef))
|
||||
return err
|
||||
}
|
||||
s.logger.Info("Recipient archive cascade applied to payment methods",
|
||||
zap.String("recipient_ref", recipientRef.Hex()),
|
||||
zap.String("actor_account_ref", actorAccountRef.Hex()),
|
||||
mzap.ObjRef("recipient_ref", recipientRef),
|
||||
mzap.ObjRef("actor_account_ref", actorAccountRef),
|
||||
zap.Int("updated_count", updated))
|
||||
case nm.NADeleted:
|
||||
if err := s.pmstore.DeleteByRecipient(ctx, recipientRef); err != nil {
|
||||
s.logger.Warn("Failed to cascade delete payment methods by recipient",
|
||||
zap.Error(err),
|
||||
zap.String("recipient_ref", recipientRef.Hex()),
|
||||
zap.String("actor_account_ref", actorAccountRef.Hex()))
|
||||
mzap.ObjRef("recipient_ref", recipientRef),
|
||||
mzap.ObjRef("actor_account_ref", actorAccountRef))
|
||||
return err
|
||||
}
|
||||
s.logger.Info("Recipient delete cascade applied to payment methods",
|
||||
zap.String("recipient_ref", recipientRef.Hex()),
|
||||
zap.String("actor_account_ref", actorAccountRef.Hex()))
|
||||
mzap.ObjRef("recipient_ref", recipientRef),
|
||||
mzap.ObjRef("actor_account_ref", actorAccountRef))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
pm "github.com/tech/sendico/pkg/model"
|
||||
"github.com/tech/sendico/pkg/mutil/mzap"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@@ -24,7 +25,7 @@ type svc struct {
|
||||
func (s *svc) Create(in Input) (payment *Payment, err error) {
|
||||
logger := s.logger
|
||||
logger.Debug("Starting Create",
|
||||
zap.String("organization_ref", in.OrganizationRef.Hex()),
|
||||
mzap.ObjRef("organization_ref", in.OrganizationRef),
|
||||
zap.String("quotation_ref", strings.TrimSpace(in.QuotationRef)),
|
||||
zap.Int("steps_count", len(in.Steps)),
|
||||
)
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/tech/sendico/payments/storage/model"
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
"github.com/tech/sendico/pkg/mutil/mzap"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
@@ -26,7 +27,7 @@ func (s *svc) TryReuse(
|
||||
) (payment *model.Payment, reused bool, err error) {
|
||||
logger := s.logger
|
||||
logger.Debug("Starting Try reuse",
|
||||
zap.String("organization_ref", in.OrganizationID.Hex()),
|
||||
mzap.ObjRef("organization_ref", payment.OrganizationRef),
|
||||
zap.Bool("has_idempotency_key", strings.TrimSpace(in.IdempotencyKey) != ""),
|
||||
)
|
||||
defer func(start time.Time) {
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/tech/sendico/payments/orchestrator/internal/service/orchestrationv2/prepo"
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
"github.com/tech/sendico/pkg/mutil/mzap"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@@ -61,7 +62,7 @@ func newService(deps Dependencies) (Service, error) {
|
||||
func (s *svc) GetPayment(ctx context.Context, in GetPaymentInput) (payment *agg.Payment, err error) {
|
||||
logger := s.logger
|
||||
logger.Debug("Starting Get payment",
|
||||
zap.String("organization_ref", in.OrganizationRef.Hex()),
|
||||
mzap.ObjRef("organization_ref", in.OrganizationRef),
|
||||
zap.String("payment_ref", strings.TrimSpace(in.PaymentRef)),
|
||||
)
|
||||
defer func(start time.Time) {
|
||||
@@ -93,7 +94,7 @@ func (s *svc) GetPayment(ctx context.Context, in GetPaymentInput) (payment *agg.
|
||||
func (s *svc) ListPayments(ctx context.Context, in ListPaymentsInput) (out *ListPaymentsOutput, err error) {
|
||||
logger := s.logger
|
||||
logger.Debug("Starting List payments",
|
||||
zap.String("organization_ref", in.OrganizationRef.Hex()),
|
||||
mzap.ObjRef("organization_ref", in.OrganizationRef),
|
||||
zap.String("quotation_ref", strings.TrimSpace(in.QuotationRef)),
|
||||
zap.Int("states_count", len(in.States)),
|
||||
zap.Int32("limit", in.Limit),
|
||||
|
||||
@@ -175,13 +175,13 @@ func (s *svc) GetByPaymentRef(ctx context.Context, orgRef bson.ObjectID, payment
|
||||
logger := s.logger
|
||||
requestPaymentRef := strings.TrimSpace(paymentRef)
|
||||
logger.Debug("Starting Get by payment ref",
|
||||
zap.String("organization_ref", orgRef.Hex()),
|
||||
mzap.ObjRef("organization_ref", orgRef),
|
||||
zap.String("payment_ref", requestPaymentRef),
|
||||
)
|
||||
defer func(start time.Time) {
|
||||
fields := []zap.Field{
|
||||
zap.Int64("duration_ms", time.Since(start).Milliseconds()),
|
||||
zap.String("organization_ref", orgRef.Hex()),
|
||||
mzap.ObjRef("organization_ref", orgRef),
|
||||
zap.String("payment_ref", requestPaymentRef),
|
||||
}
|
||||
if payment != nil {
|
||||
@@ -225,7 +225,7 @@ func (s *svc) GetByPaymentRefGlobal(ctx context.Context, paymentRef string) (pay
|
||||
}
|
||||
if payment != nil {
|
||||
fields = append(fields,
|
||||
zap.String("organization_ref", payment.OrganizationRef.Hex()),
|
||||
mzap.ObjRef("organization_ref", payment.OrganizationRef),
|
||||
zap.String("state", string(payment.State)),
|
||||
zap.Uint64("version", payment.Version),
|
||||
)
|
||||
@@ -253,7 +253,7 @@ func (s *svc) GetByIdempotencyKey(ctx context.Context, orgRef bson.ObjectID, ide
|
||||
logger := s.logger
|
||||
hasKey := strings.TrimSpace(idempotencyKey) != ""
|
||||
logger.Debug("Starting Get by idempotency key",
|
||||
zap.String("organization_ref", orgRef.Hex()),
|
||||
mzap.ObjRef("organization_ref", orgRef),
|
||||
zap.Bool("has_idempotency_key", hasKey),
|
||||
)
|
||||
defer func(start time.Time) {
|
||||
@@ -298,7 +298,7 @@ func (s *svc) GetByIdempotencyKey(ctx context.Context, orgRef bson.ObjectID, ide
|
||||
func (s *svc) ListByQuotationRef(ctx context.Context, in ListByQuotationRefInput) (out *ListOutput, err error) {
|
||||
logger := s.logger
|
||||
logger.Debug("Starting List by quotation ref",
|
||||
zap.String("organization_ref", in.OrganizationRef.Hex()),
|
||||
mzap.ObjRef("organization_ref", in.OrganizationRef),
|
||||
zap.String("quotation_ref", strings.TrimSpace(in.QuotationRef)),
|
||||
zap.Int32("limit", in.Limit),
|
||||
)
|
||||
@@ -337,7 +337,7 @@ func (s *svc) ListByQuotationRef(ctx context.Context, in ListByQuotationRefInput
|
||||
func (s *svc) ListByState(ctx context.Context, in ListByStateInput) (out *ListOutput, err error) {
|
||||
logger := s.logger
|
||||
logger.Debug("Starting List by state",
|
||||
zap.String("organization_ref", in.OrganizationRef.Hex()),
|
||||
mzap.ObjRef("organization_ref", in.OrganizationRef),
|
||||
zap.String("state", string(in.State)),
|
||||
zap.Int32("limit", in.Limit),
|
||||
)
|
||||
|
||||
@@ -5,12 +5,13 @@ import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"github.com/tech/sendico/pkg/discovery"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/tech/sendico/pkg/discovery"
|
||||
|
||||
"github.com/tech/sendico/payments/orchestrator/internal/service/orchestrationv2/agg"
|
||||
"github.com/tech/sendico/payments/orchestrator/internal/service/orchestrationv2/batchmeta"
|
||||
"github.com/tech/sendico/payments/orchestrator/internal/service/orchestrationv2/idem"
|
||||
@@ -60,8 +61,8 @@ func (s *svc) ExecuteBatchPayment(ctx context.Context, req *orchestrationv2.Exec
|
||||
}
|
||||
|
||||
resolved, err := s.quote.ResolveAll(ctx, s.quoteStore, qsnap.ResolveAllInput{
|
||||
OrganizationID: requestCtx.OrganizationID,
|
||||
QuotationRef: requestCtx.QuotationRef,
|
||||
OrganizationRef: requestCtx.OrganizationID,
|
||||
QuotationRef: requestCtx.QuotationRef,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, remapResolveError(err)
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
pon "github.com/tech/sendico/pkg/messaging/notifications/paymentorchestrator"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
"github.com/tech/sendico/pkg/mutil/mzap"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
@@ -64,7 +65,7 @@ func (p *brokerPaymentStatusPublisher) Publish(_ context.Context, in paymentStat
|
||||
if paymentRef == "" || payment.OrganizationRef.IsZero() {
|
||||
p.logger.Warn("Skipping payment status publish due to missing identifiers",
|
||||
zap.String("payment_ref", paymentRef),
|
||||
zap.String("organization_ref", payment.OrganizationRef.Hex()),
|
||||
mzap.ObjRef("organization_ref", payment.OrganizationRef),
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -36,8 +36,8 @@ type Output struct {
|
||||
|
||||
// ResolveAllInput defines lookup scope for resolving all items in a batch quotation.
|
||||
type ResolveAllInput struct {
|
||||
OrganizationID bson.ObjectID
|
||||
QuotationRef string
|
||||
OrganizationRef bson.ObjectID
|
||||
QuotationRef string
|
||||
}
|
||||
|
||||
// ResolveAllOutput contains all resolved items from a batch quotation.
|
||||
|
||||
@@ -41,8 +41,8 @@ func TestResolveAll_BatchReturnsAllItems(t *testing.T) {
|
||||
return record, nil
|
||||
},
|
||||
}, ResolveAllInput{
|
||||
OrganizationID: orgID,
|
||||
QuotationRef: "batch-quote-ref",
|
||||
OrganizationRef: orgID,
|
||||
QuotationRef: "batch-quote-ref",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("ResolveAll returned error: %v", err)
|
||||
@@ -94,8 +94,8 @@ func TestResolveAll_SingleShapeReturnsOneItem(t *testing.T) {
|
||||
return record, nil
|
||||
},
|
||||
}, ResolveAllInput{
|
||||
OrganizationID: orgID,
|
||||
QuotationRef: "single-quote-ref",
|
||||
OrganizationRef: orgID,
|
||||
QuotationRef: "single-quote-ref",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("ResolveAll returned error: %v", err)
|
||||
@@ -137,8 +137,8 @@ func TestResolveAll_NonExecutableItemFails(t *testing.T) {
|
||||
return record, nil
|
||||
},
|
||||
}, ResolveAllInput{
|
||||
OrganizationID: orgID,
|
||||
QuotationRef: "batch-mixed",
|
||||
OrganizationRef: orgID,
|
||||
QuotationRef: "batch-mixed",
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatal("expected error for non-executable item")
|
||||
@@ -172,8 +172,8 @@ func TestResolveAll_ExpiredQuoteFails(t *testing.T) {
|
||||
return record, nil
|
||||
},
|
||||
}, ResolveAllInput{
|
||||
OrganizationID: orgID,
|
||||
QuotationRef: "expired-quote",
|
||||
OrganizationRef: orgID,
|
||||
QuotationRef: "expired-quote",
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatal("expected error for expired quote")
|
||||
@@ -187,8 +187,8 @@ func TestResolveAll_EmptyQuotationRefFails(t *testing.T) {
|
||||
resolver := New(Dependencies{Logger: zap.NewNop()})
|
||||
|
||||
_, err := resolver.ResolveAll(context.Background(), &fakeStore{}, ResolveAllInput{
|
||||
OrganizationID: bson.NewObjectID(),
|
||||
QuotationRef: "",
|
||||
OrganizationRef: bson.NewObjectID(),
|
||||
QuotationRef: "",
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatal("expected error for empty quotation_ref")
|
||||
@@ -199,8 +199,8 @@ func TestResolveAll_QuoteNotFoundFails(t *testing.T) {
|
||||
resolver := New(Dependencies{Logger: zap.NewNop()})
|
||||
|
||||
_, err := resolver.ResolveAll(context.Background(), &fakeStore{}, ResolveAllInput{
|
||||
OrganizationID: bson.NewObjectID(),
|
||||
QuotationRef: "nonexistent",
|
||||
OrganizationRef: bson.NewObjectID(),
|
||||
QuotationRef: "nonexistent",
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatal("expected error for not-found quote")
|
||||
@@ -234,8 +234,8 @@ func TestResolveAll_SetsQuoteRefWhenEmpty(t *testing.T) {
|
||||
return record, nil
|
||||
},
|
||||
}, ResolveAllInput{
|
||||
OrganizationID: orgID,
|
||||
QuotationRef: "batch-ref",
|
||||
OrganizationRef: orgID,
|
||||
QuotationRef: "batch-ref",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("ResolveAll returned error: %v", err)
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
quotestorage "github.com/tech/sendico/payments/storage/quote"
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
"github.com/tech/sendico/pkg/mutil/mzap"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@@ -33,7 +34,7 @@ func (s *svc) Resolve(
|
||||
) (out *Output, err error) {
|
||||
logger := s.logger
|
||||
logger.Debug("Starting Resolve",
|
||||
zap.String("organization_ref", in.OrganizationID.Hex()),
|
||||
mzap.ObjRef("organization_ref", in.OrganizationID),
|
||||
zap.String("quotation_ref", strings.TrimSpace(in.QuotationRef)),
|
||||
)
|
||||
defer func(start time.Time) {
|
||||
@@ -105,7 +106,7 @@ func (s *svc) ResolveAll(
|
||||
) (out *ResolveAllOutput, err error) {
|
||||
logger := s.logger
|
||||
logger.Debug("Starting ResolveAll",
|
||||
zap.String("organization_ref", in.OrganizationID.Hex()),
|
||||
mzap.ObjRef("organization_ref", in.OrganizationRef),
|
||||
zap.String("quotation_ref", strings.TrimSpace(in.QuotationRef)),
|
||||
)
|
||||
defer func(start time.Time) {
|
||||
@@ -126,7 +127,7 @@ func (s *svc) ResolveAll(
|
||||
if store == nil {
|
||||
return nil, merrors.InvalidArgument("quotes store is required")
|
||||
}
|
||||
if in.OrganizationID.IsZero() {
|
||||
if in.OrganizationRef.IsZero() {
|
||||
return nil, merrors.InvalidArgument("organization_id is required")
|
||||
}
|
||||
quoteRef := strings.TrimSpace(in.QuotationRef)
|
||||
@@ -134,7 +135,7 @@ func (s *svc) ResolveAll(
|
||||
return nil, merrors.InvalidArgument("quotation_ref is required")
|
||||
}
|
||||
|
||||
record, err := store.GetByRef(ctx, in.OrganizationID, quoteRef)
|
||||
record, err := store.GetByRef(ctx, in.OrganizationRef, quoteRef)
|
||||
if err != nil {
|
||||
if errors.Is(err, quotestorage.ErrQuoteNotFound) || errors.Is(err, merrors.ErrNoData) {
|
||||
return nil, ErrQuoteNotFound
|
||||
|
||||
@@ -3,10 +3,12 @@ package orchestrator
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/tech/sendico/pkg/discovery"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/tech/sendico/pkg/discovery"
|
||||
"github.com/tech/sendico/pkg/mutil/mzap"
|
||||
|
||||
"github.com/tech/sendico/payments/orchestrator/internal/service/orchestrationv2/agg"
|
||||
"github.com/tech/sendico/payments/orchestrator/internal/service/orchestrationv2/erecon"
|
||||
"github.com/tech/sendico/payments/orchestrator/internal/service/orchestrationv2/prepo"
|
||||
@@ -111,7 +113,7 @@ func (s *Service) onPaymentGatewayExecution(ctx context.Context, msg *pmodel.Pay
|
||||
|
||||
s.logger.Debug("Reconciling payment from gateway execution event",
|
||||
zap.String("payment_ref", strings.TrimSpace(payment.PaymentRef)),
|
||||
zap.String("organization_ref", payment.OrganizationRef.Hex()),
|
||||
mzap.ObjRef("organization_ref", payment.OrganizationRef),
|
||||
zap.String("step_ref", strings.TrimSpace(event.StepRef)),
|
||||
zap.String("status", strings.TrimSpace(string(event.Status))),
|
||||
zap.String("transfer_ref", strings.TrimSpace(event.TransferRef)),
|
||||
@@ -457,7 +459,7 @@ func (s *Service) pollObserveCandidate(ctx context.Context, payment *agg.Payment
|
||||
|
||||
s.logger.Debug("Reconciling payment from observe polling result",
|
||||
zap.String("payment_ref", strings.TrimSpace(payment.PaymentRef)),
|
||||
zap.String("organization_ref", payment.OrganizationRef.Hex()),
|
||||
mzap.ObjRef("organization_ref", payment.OrganizationRef),
|
||||
zap.String("step_ref", candidate.stepRef),
|
||||
zap.String("status", strings.TrimSpace(string(event.Status))),
|
||||
zap.String("transfer_ref", candidate.transferRef),
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
"github.com/tech/sendico/pkg/mutil/mzap"
|
||||
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
|
||||
endpointv1 "github.com/tech/sendico/pkg/proto/payments/endpoint/v1"
|
||||
quotationv2 "github.com/tech/sendico/pkg/proto/payments/quotation/v2"
|
||||
@@ -33,7 +34,7 @@ type quoteIntentLogSummary struct {
|
||||
|
||||
func (s *QuotationServiceV2) quotePaymentLogger(req *quotationv2.QuotePaymentRequest) mlogger.Logger {
|
||||
return s.logger.With(
|
||||
zap.String("flow_ref", bson.NewObjectID().Hex()),
|
||||
mzap.ObjRef("flow_ref", bson.NewObjectID()),
|
||||
zap.String("rpc_method", "QuotePayment"),
|
||||
zap.String("organization_ref", strings.TrimSpace(req.GetMeta().GetOrganizationRef())),
|
||||
zap.String("idempotency_key", strings.TrimSpace(req.GetIdempotencyKey())),
|
||||
@@ -44,7 +45,7 @@ func (s *QuotationServiceV2) quotePaymentLogger(req *quotationv2.QuotePaymentReq
|
||||
|
||||
func (s *QuotationServiceV2) quotePaymentsLogger(req *quotationv2.QuotePaymentsRequest) mlogger.Logger {
|
||||
return s.logger.With(
|
||||
zap.String("flow_ref", bson.NewObjectID().Hex()),
|
||||
mzap.ObjRef("flow_ref", bson.NewObjectID()),
|
||||
zap.String("rpc_method", "QuotePayments"),
|
||||
zap.String("organization_ref", strings.TrimSpace(req.GetMeta().GetOrganizationRef())),
|
||||
zap.String("idempotency_key", strings.TrimSpace(req.GetIdempotencyKey())),
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/tech/sendico/pkg/db/storable"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
"github.com/tech/sendico/pkg/mutil/mzap"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@@ -43,7 +44,7 @@ func (db *IndexableDB[T]) Reorder(ctx context.Context, objectRef bson.ObjectID,
|
||||
if err != nil {
|
||||
db.logger.Error("Failed to get object for reordering",
|
||||
zap.Error(err),
|
||||
zap.String("object_ref", objectRef.Hex()),
|
||||
mzap.ObjRef("object_ref", objectRef),
|
||||
zap.Int("new_index", newIndex))
|
||||
return err
|
||||
}
|
||||
@@ -53,7 +54,7 @@ func (db *IndexableDB[T]) Reorder(ctx context.Context, objectRef bson.ObjectID,
|
||||
currentIndex := indexable.Index
|
||||
if currentIndex == newIndex {
|
||||
db.logger.Debug("No reordering needed - same index",
|
||||
zap.String("object_ref", objectRef.Hex()),
|
||||
mzap.ObjRef("object_ref", objectRef),
|
||||
zap.Int("current_index", currentIndex),
|
||||
zap.Int("new_index", newIndex))
|
||||
return nil // No change needed
|
||||
@@ -71,14 +72,14 @@ func (db *IndexableDB[T]) Reorder(ctx context.Context, objectRef bson.ObjectID,
|
||||
if err != nil {
|
||||
db.logger.Error("Failed to shift objects during reordering (moving down)",
|
||||
zap.Error(err),
|
||||
zap.String("object_ref", objectRef.Hex()),
|
||||
mzap.ObjRef("object_ref", objectRef),
|
||||
zap.Int("current_index", currentIndex),
|
||||
zap.Int("new_index", newIndex),
|
||||
zap.Int("updated_count", updatedCount))
|
||||
return err
|
||||
}
|
||||
db.logger.Debug("Successfully shifted objects (moving down)",
|
||||
zap.String("object_ref", objectRef.Hex()),
|
||||
mzap.ObjRef("object_ref", objectRef),
|
||||
zap.Int("updated_count", updatedCount))
|
||||
} else {
|
||||
// Moving up: shift items between newIndex and currentIndex-1 down by +1
|
||||
@@ -91,14 +92,14 @@ func (db *IndexableDB[T]) Reorder(ctx context.Context, objectRef bson.ObjectID,
|
||||
if err != nil {
|
||||
db.logger.Error("Failed to shift objects during reordering (moving up)",
|
||||
zap.Error(err),
|
||||
zap.String("object_ref", objectRef.Hex()),
|
||||
mzap.ObjRef("object_ref", objectRef),
|
||||
zap.Int("current_index", currentIndex),
|
||||
zap.Int("new_index", newIndex),
|
||||
zap.Int("updated_count", updatedCount))
|
||||
return err
|
||||
}
|
||||
db.logger.Debug("Successfully shifted objects (moving up)",
|
||||
zap.String("object_ref", objectRef.Hex()),
|
||||
mzap.ObjRef("object_ref", objectRef),
|
||||
zap.Int("updated_count", updatedCount))
|
||||
}
|
||||
|
||||
@@ -108,14 +109,14 @@ func (db *IndexableDB[T]) Reorder(ctx context.Context, objectRef bson.ObjectID,
|
||||
if err != nil {
|
||||
db.logger.Error("Failed to update target object index",
|
||||
zap.Error(err),
|
||||
zap.String("object_ref", objectRef.Hex()),
|
||||
mzap.ObjRef("object_ref", objectRef),
|
||||
zap.Int("current_index", currentIndex),
|
||||
zap.Int("new_index", newIndex))
|
||||
return err
|
||||
}
|
||||
|
||||
db.logger.Info("Successfully reordered object",
|
||||
zap.String("object_ref", objectRef.Hex()),
|
||||
mzap.ObjRef("object_ref", objectRef),
|
||||
zap.Int("old_index", currentIndex),
|
||||
zap.Int("new_index", newIndex))
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user