mntx error codes update

This commit is contained in:
Stephan D
2026-03-06 12:14:32 +01:00
parent be49254769
commit c60e7d2329
12 changed files with 1405 additions and 118 deletions

View File

@@ -166,25 +166,16 @@ func (c *Client) sendTokenization(ctx context.Context, req CardTokenizeRequest)
}
}
if apiResp.Operation.RequestID != "" {
result.ProviderRequestID = apiResp.Operation.RequestID
} else if apiResp.RequestID != "" {
result.ProviderRequestID = apiResp.RequestID
}
result.ProviderStatus = strings.TrimSpace(apiResp.Status)
if result.ProviderStatus == "" {
result.ProviderStatus = strings.TrimSpace(apiResp.Operation.Status)
}
result.ProviderRequestID = providerRequestID(apiResp)
result.ProviderStatus = providerStatus(apiResp)
if !result.Accepted {
result.ErrorCode = apiResp.Code
if result.ErrorCode == "" {
errorCode, errorMessage := providerError(apiResp)
if !result.Accepted || isProviderStatusError(result.ProviderStatus) {
result.ErrorCode = errorCode
if !result.Accepted && result.ErrorCode == "" {
result.ErrorCode = http.StatusText(resp.StatusCode)
}
result.ErrorMessage = apiResp.Message
if result.ErrorMessage == "" {
result.ErrorMessage = apiResp.Operation.Message
}
result.ErrorMessage = errorMessage
}
c.logger.Info("Monetix tokenization response",
@@ -288,25 +279,16 @@ func (c *Client) send(ctx context.Context, req any, path string, dispatchLog fun
}
}
if apiResp.Operation.RequestID != "" {
result.ProviderRequestID = apiResp.Operation.RequestID
} else if apiResp.RequestID != "" {
result.ProviderRequestID = apiResp.RequestID
}
result.ProviderStatus = strings.TrimSpace(apiResp.Status)
if result.ProviderStatus == "" {
result.ProviderStatus = strings.TrimSpace(apiResp.Operation.Status)
}
result.ProviderRequestID = providerRequestID(apiResp)
result.ProviderStatus = providerStatus(apiResp)
if !result.Accepted {
result.ErrorCode = apiResp.Code
if result.ErrorCode == "" {
errorCode, errorMessage := providerError(apiResp)
if !result.Accepted || isProviderStatusError(result.ProviderStatus) {
result.ErrorCode = errorCode
if !result.Accepted && result.ErrorCode == "" {
result.ErrorCode = http.StatusText(resp.StatusCode)
}
result.ErrorMessage = apiResp.Message
if result.ErrorMessage == "" {
result.ErrorMessage = apiResp.Operation.Message
}
result.ErrorMessage = errorMessage
}
if responseLog != nil {
@@ -324,6 +306,32 @@ func normalizeExpiryYear(year int) int {
return year
}
func providerRequestID(resp APIResponse) string {
return firstNonEmpty(resp.Operation.RequestID, resp.RequestID)
}
func providerStatus(resp APIResponse) string {
return firstNonEmpty(resp.Status, resp.Operation.Status)
}
func providerError(resp APIResponse) (code, message string) {
return firstNonEmpty(resp.Code, resp.Operation.Code), firstNonEmpty(resp.Message, resp.Operation.Message)
}
func isProviderStatusError(status string) bool {
return strings.EqualFold(strings.TrimSpace(status), "error")
}
func firstNonEmpty(values ...string) string {
for _, value := range values {
trimmed := strings.TrimSpace(value)
if trimmed != "" {
return trimmed
}
}
return ""
}
func normalizeRequestExpiryYear(req any) {
switch r := req.(type) {
case *CardPayoutRequest:

View File

@@ -175,6 +175,99 @@ func TestSendCardPayout_HTTPError(t *testing.T) {
}
}
func TestSendCardPayout_HTTPAcceptedBodyErrorStillAccepted(t *testing.T) {
httpClient := &http.Client{
Transport: roundTripperFunc(func(r *http.Request) (*http.Response, error) {
body := `{"status":"error","code":"3062","message":"Payment details not received"}`
return &http.Response{
StatusCode: http.StatusOK,
Body: io.NopCloser(strings.NewReader(body)),
Header: http.Header{"Content-Type": []string{"application/json"}},
}, nil
}),
}
cfg := Config{
BaseURL: "https://monetix.test",
SecretKey: "secret",
}
client := NewClient(cfg, httpClient, zap.NewNop())
req := CardPayoutRequest{
General: General{ProjectID: 1, PaymentID: "payout-1"},
Customer: Customer{
ID: "cust-1",
FirstName: "Jane",
LastName: "Doe",
IP: "203.0.113.10",
},
Payment: Payment{Amount: 1000, Currency: "RUB"},
Card: Card{PAN: "4111111111111111", Year: 2030, Month: 12, CardHolder: "JANE DOE"},
}
result, err := client.CreateCardPayout(context.Background(), req)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if !result.Accepted {
t.Fatalf("expected accepted response")
}
if result.ProviderStatus != "error" {
t.Fatalf("expected provider status error, got %q", result.ProviderStatus)
}
if result.ErrorCode != "3062" {
t.Fatalf("expected error code %q, got %q", "3062", result.ErrorCode)
}
if result.ErrorMessage != "Payment details not received" {
t.Fatalf("expected error message, got %q", result.ErrorMessage)
}
}
func TestSendCardPayout_HTTPErrorFallsBackToOperationCode(t *testing.T) {
httpClient := &http.Client{
Transport: roundTripperFunc(func(r *http.Request) (*http.Response, error) {
body := `{"operation":{"code":"3061","message":"Transaction not found"}}`
return &http.Response{
StatusCode: http.StatusBadRequest,
Body: io.NopCloser(strings.NewReader(body)),
Header: http.Header{"Content-Type": []string{"application/json"}},
}, nil
}),
}
cfg := Config{
BaseURL: "https://monetix.test",
SecretKey: "secret",
}
client := NewClient(cfg, httpClient, zap.NewNop())
req := CardPayoutRequest{
General: General{ProjectID: 1, PaymentID: "payout-1"},
Customer: Customer{
ID: "cust-1",
FirstName: "Jane",
LastName: "Doe",
IP: "203.0.113.10",
},
Payment: Payment{Amount: 1000, Currency: "RUB"},
Card: Card{PAN: "4111111111111111", Year: 2030, Month: 12, CardHolder: "JANE DOE"},
}
result, err := client.CreateCardPayout(context.Background(), req)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if result.Accepted {
t.Fatalf("expected rejected response")
}
if result.ErrorCode != "3061" {
t.Fatalf("expected error code %q, got %q", "3061", result.ErrorCode)
}
if result.ErrorMessage != "Transaction not found" {
t.Fatalf("expected error message, got %q", result.ErrorMessage)
}
}
type errorReadCloser struct {
err error
}