mirror of
https://github.com/luxfi/bank.git
synced 2026-10-30 17:02:07 +00:00
bankd no longer registers /v1/bank/webhooks/currencycloud/* or /v1/bank/webhooks/ifx/* endpoints — those were a layering leak. All provider webhooks now arrive normalized via the existing HMAC-protected /v1/bank/webhooks/payments/callback after forexd ingests and translates them. payments.go: paymentCallbackPayload accepts the normalized shape (provider, eventType, externalId, status, reason). A transaction is resolved either by internal id or by the provider-issued externalId stored in the ccTransactionId column. mapCallbackStatus learns "cancelled"/"canceled" so the full lifecycle from forexd round-trips intact.
72 lines
2.0 KiB
Go
72 lines
2.0 KiB
Go
package hooks
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
)
|
|
|
|
func TestMapCallbackStatus(t *testing.T) {
|
|
cases := []struct{ in, want string }{
|
|
{"completed", "completed"},
|
|
{"settled", "completed"},
|
|
{"failed", "failed"},
|
|
{"rejected", "failed"},
|
|
{"cancelled", "cancelled"},
|
|
{"canceled", "cancelled"},
|
|
{"processing", "processing"},
|
|
{"in_progress", "processing"},
|
|
{"", "pending"},
|
|
{"weird", "pending"},
|
|
}
|
|
for _, c := range cases {
|
|
if got := mapCallbackStatus(c.in); got != c.want {
|
|
t.Errorf("mapCallbackStatus(%q) = %q, want %q", c.in, got, c.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestValidTransition(t *testing.T) {
|
|
cases := []struct {
|
|
from, to string
|
|
want bool
|
|
}{
|
|
{"pending", "processing", true},
|
|
{"pending", "failed", true},
|
|
{"pending", "cancelled", true},
|
|
{"processing", "completed", true},
|
|
{"processing", "failed", true},
|
|
{"processing", "cancelled", true},
|
|
{"completed", "failed", false},
|
|
{"completed", "processing", false},
|
|
{"failed", "completed", false},
|
|
{"cancelled", "completed", false},
|
|
}
|
|
for _, c := range cases {
|
|
if got := validTransition(c.from, c.to); got != c.want {
|
|
t.Errorf("validTransition(%q,%q) = %v, want %v", c.from, c.to, got, c.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPaymentCallbackPayloadShape(t *testing.T) {
|
|
// Normalized event from forexd: provider/eventType/externalId carry the
|
|
// provider-issued reference; bank looks the record up by externalId.
|
|
in := `{"provider":"currencycloud","eventType":"payment","externalId":"cc-99","status":"completed","reason":""}`
|
|
var p paymentCallbackPayload
|
|
if err := json.Unmarshal([]byte(in), &p); err != nil {
|
|
t.Fatalf("unmarshal: %v", err)
|
|
}
|
|
if p.Provider != "currencycloud" || p.EventType != "payment" {
|
|
t.Errorf("provider/eventType not captured: %+v", p)
|
|
}
|
|
if p.ExternalID != "cc-99" {
|
|
t.Errorf("externalId = %q, want cc-99", p.ExternalID)
|
|
}
|
|
if p.TransactionID != "" {
|
|
t.Errorf("transactionId should be empty for provider-only events, got %q", p.TransactionID)
|
|
}
|
|
if p.Status != "completed" {
|
|
t.Errorf("status = %q, want completed", p.Status)
|
|
}
|
|
}
|