Documentation
¶
Index ¶
- Variables
- type CreateCheckoutRequest
- type CreateCheckoutResponse
- type EventData
- type Factory
- type GatewayInfo
- type GatewayRegistry
- type HTTPHandler
- type InteractionType
- type InternalPaymentEvent
- type PaymentGateway
- type PaymentRepository
- type PaymentService
- type PaymentStatus
- type PaymentTransaction
- type RenderInfo
- type SessionRequest
- type SessionResponse
- type TaskCompleter
- type ValidateReferenceRequest
- type ValidateReferenceResponse
- type ValidationResponse
- type ValidationTransaction
- type WebhookPayload
- type WebhookResponse
- type WebhookStatus
Constants ¶
This section is empty.
Variables ¶
var ErrAmountMismatch = errors.New("webhook amount/currency mismatch")
ErrAmountMismatch indicates a successful-payment webhook reported an amount or currency that doesn't match the recorded transaction. Permanent and suspicious, so it is never marked paid and the gateway should not retry.
var ErrTransactionNotFound = errors.New("payment transaction not found")
ErrTransactionNotFound indicates no payment transaction matches a given reference. This is a permanent condition, so callers (e.g. the webhook handler) should not ask the gateway to retry.
var ErrUnsupportedWebhookStatus = errors.New("unsupported webhook status")
ErrUnsupportedWebhookStatus indicates a gateway status that could not be normalized into a WebhookStatus. It is a permanent condition (retrying the same payload won't help), so callers should not signal the gateway to retry.
Functions ¶
This section is empty.
Types ¶
type CreateCheckoutRequest ¶
type CreateCheckoutRequest struct {
GatewayID string `json:"gateway_id"`
Amount decimal.Decimal `json:"amount"`
Currency string `json:"currency"`
SuccessRedirectURL string `json:"success_redirect_url,omitempty"` // Optional: User redirect on success
CancelRedirectURL string `json:"cancel_redirect_url,omitempty"` // Optional: User redirect on cancel
ExpiresAt time.Time `json:"expires_at"` // Aligned with Task TTL
Metadata map[string]string `json:"metadata"` // Pass-through data (e.g., TaskID)
}
CreateCheckoutRequest is the payload sent to initialize a session.
type CreateCheckoutResponse ¶
type CreateCheckoutResponse struct {
ReferenceNumber string `json:"reference_number"` // The generated NSW reference
SessionID string `json:"session_id"`
Type InteractionType `json:"type"`
CheckoutURL string `json:"checkout_url,omitempty"` // The hosted URL to redirect the user to
Instructions string `json:"instructions,omitempty"`
ExpiresIn int `json:"expires_in_seconds"`
}
CreateCheckoutResponse is the expected reply from LankaPay.
type EventData ¶
type EventData struct {
TaskID string `json:"task_id"`
ReferenceNumber string `json:"reference_number"`
GatewayTransactionID string `json:"gateway_transaction_id"`
Status PaymentStatus `json:"status"`
AmountPaid decimal.Decimal `json:"amount_paid"`
Currency string `json:"currency"`
ConfirmedAt string `json:"confirmed_at"`
}
type Factory ¶
type Factory func(config json.RawMessage) (PaymentGateway, error)
Factory constructs a configured, ready-to-use gateway from its raw config. One factory per gateway type; the registry calls it once at init so gateways are immutable after construction (no post-init config mutation).
type GatewayInfo ¶
type GatewayInfo struct {
ID string `json:"id"`
IsActive bool `json:"is_active"`
RenderInfo RenderInfo `json:"render_info"`
Config json.RawMessage `json:"config,omitempty"`
}
GatewayInfo is the aggregate DTO used for gateway discovery.
type GatewayRegistry ¶
type GatewayRegistry interface {
// Get retrieves a gateway implementation by its ID.
Get(id string) (PaymentGateway, error)
// ListInfo returns the aggregated metadata for all supported gateways.
ListInfo() []GatewayInfo
}
GatewayRegistry manages the discovery and lookup of payment gateways.
func NewRegistry ¶
func NewRegistry(configPath string, factories map[string]Factory) (GatewayRegistry, error)
NewRegistry initializes a new registry by loading configuration from a file. For each configured gateway it invokes the matching factory to construct a fully configured implementation, so gateways are immutable after init.
type HTTPHandler ¶
type HTTPHandler struct {
// contains filtered or unexported fields
}
HTTPHandler handles public HTTP requests for the Payment Service.
func NewHTTPHandler ¶
func NewHTTPHandler(service PaymentService) *HTTPHandler
NewHTTPHandler creates a new handler.
func (*HTTPHandler) HandleValidateReference ¶
func (h *HTTPHandler) HandleValidateReference(w http.ResponseWriter, r *http.Request)
HandleValidateReference handles POST /api/v1/payments/:gatewayId/validate Called by gateways to query if a reference number is valid and payable.
func (*HTTPHandler) HandleWebhook ¶
func (h *HTTPHandler) HandleWebhook(w http.ResponseWriter, r *http.Request)
HandleWebhook handles POST /api/v1/payments/:gatewayID/webhook Called by payment gateways to notify about payment successes and failures.
type InteractionType ¶
type InteractionType string
const ( FlowTypeRedirect InteractionType = "REDIRECT" FlowTypeInstruction InteractionType = "INSTRUCTION" )
type InternalPaymentEvent ¶
type InternalPaymentEvent struct {
EventType string `json:"event_type"`
Data EventData `json:"data"`
}
InternalPaymentEvent represents the internal event the Payment Service fires for the Task Engine.
type PaymentGateway ¶
type PaymentGateway interface {
// GetFlowType returns the flow type of the gateway (REDIRECT or INSTRUCTION).
GetFlowType() InteractionType
// CreateSession initializes a payment session with the gateway.
CreateSession(ctx context.Context, req SessionRequest) (*SessionResponse, error)
// ExtractReferenceNumber parses the gateway-specific validation request to extract the reference number.
ExtractReferenceNumber(ctx context.Context, reqData json.RawMessage) (string, error)
// HandleValidateReference formats the gateway-specific validation response.
// tx is nil when no matching transaction exists (unknown reference or a
// mismatched gateway); isPayable is the domain decision (exists, owned by
// this gateway, pending, and not expired) the gateway should reflect back.
HandleValidateReference(ctx context.Context, tx *ValidationTransaction, isPayable bool, reqData json.RawMessage) (*ValidationResponse, error)
// ParseWebhook processes raw gateway notifications into a domain-neutral
// payload (for the service to act on) together with the gateway-specific
// acknowledgement to relay back once the notification has been accepted.
ParseWebhook(ctx context.Context, body []byte, headers map[string][]string) (*WebhookPayload, *WebhookResponse, error)
}
PaymentGateway defines the interface for external payment gateway integration.
type PaymentRepository ¶
type PaymentRepository interface {
Create(ctx context.Context, tx *PaymentTransaction) error
GetByReferenceNumber(ctx context.Context, referenceNumber string) (*PaymentTransaction, error)
// GetByReferenceNumberForUpdate reads a transaction while holding a row-level
// write lock (SELECT ... FOR UPDATE). Must be called inside RunInTransaction.
GetByReferenceNumberForUpdate(ctx context.Context, referenceNumber string) (*PaymentTransaction, error)
GetByTaskID(ctx context.Context, taskID string) (*PaymentTransaction, error)
Update(ctx context.Context, tx *PaymentTransaction) error
UpdateStatus(ctx context.Context, referenceNumber string, status PaymentStatus) error
// RunInTransaction runs fn inside a DB transaction, passing a repository bound
// to that transaction. The transaction commits when fn returns nil and rolls
// back on error.
RunInTransaction(ctx context.Context, fn func(repo PaymentRepository) error) error
WithTx(tx *gorm.DB) PaymentRepository
}
PaymentRepository defines the interface for managing PaymentTransactions.
func NewPaymentRepository ¶
func NewPaymentRepository(db *gorm.DB) PaymentRepository
NewPaymentRepository creates a new instance of PaymentRepository.
type PaymentService ¶
type PaymentService interface {
// ListAvailableMethods returns the rendering information for all active payment gateways.
ListAvailableMethods(ctx context.Context) ([]GatewayInfo, error)
// CreateCheckoutSession initializes a payment session and generates a ReferenceNumber.
CreateCheckoutSession(ctx context.Context, req CreateCheckoutRequest) (*CreateCheckoutResponse, error)
// ValidateReference is used for real-time validation requests from gateways.
ValidateReference(ctx context.Context, gatewayID string, rawBody json.RawMessage) (*ValidationResponse, error)
// ProcessWebhook handles asynchronous notifications from payment gateways and
// returns the gateway-specific acknowledgement to relay back to the gateway.
ProcessWebhook(ctx context.Context, gatewayID string, body []byte, headers map[string][]string) (*WebhookResponse, error)
// SetTaskCompleter injects the dependency used to advance the workflow when
// a payment settles. Wired post-construction to avoid an import cycle with taskv2.
SetTaskCompleter(completer TaskCompleter)
}
PaymentService defines the high-level orchestration for payments.
func NewPaymentService ¶
func NewPaymentService(repo PaymentRepository, registry GatewayRegistry) PaymentService
NewPaymentService initializes a new payment service.
type PaymentStatus ¶
type PaymentStatus string
const ( PaymentStatusPending PaymentStatus = "PENDING" PaymentStatusSuccess PaymentStatus = "SUCCESS" PaymentStatusFailed PaymentStatus = "FAILED" )
type PaymentTransaction ¶
type PaymentTransaction struct {
ID string `json:"id" gorm:"type:text;not null;primaryKey"`
ReferenceNumber string `json:"reference_number" gorm:"uniqueIndex"` // Generated by Payment Service
TaskID string `json:"task_id" gorm:"index"` // Links back to the FSM Task Node
GatewayID string `json:"gateway_id" gorm:"index"` // e.g., "lankapay"
SessionID string `json:"session_id"` // Gateway-specific session identifier
Amount decimal.Decimal `json:"amount"`
Currency string `json:"currency"` // "LKR" or foreign currency
Status PaymentStatus `json:"status"` // PENDING, SUCCESS, FAILED, EXPIRED
PaymentMethod string `json:"payment_method"` // CC, BANK_TRANSFER (populated on webhook)
ExpiryDate time.Time `json:"expiry_date"`
GatewayMetadata map[string]string `json:"gateway_metadata" gorm:"serializer:json"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
PaymentTransaction represents the internal state of a payment
type RenderInfo ¶
type RenderInfo struct {
DisplayName string `json:"display_name"`
Description string `json:"description"`
LogoURL string `json:"logo_url"`
DisplayOrder int `json:"display_order"`
PrimaryColor string `json:"primary_color,omitempty"`
}
RenderInfo contains UI-specific metadata for displaying a payment method.
type SessionRequest ¶
type SessionResponse ¶
type SessionResponse struct {
SessionID string `json:"session_id"`
Type InteractionType `json:"type"`
CheckoutURL string `json:"checkout_url,omitempty"`
Instructions string `json:"instructions,omitempty"`
}
type TaskCompleter ¶
type TaskCompleter interface {
CompleteTaskStep(ctx context.Context, taskID string, payload map[string]any) error
}
TaskCompleter resumes a suspended workflow step once a payment reaches a terminal outcome. It is satisfied by the taskv2 TaskManager.
type ValidateReferenceRequest ¶
type ValidateReferenceRequest struct {
PaymentReference string `json:"paymentReference"` // Maps to our ReferenceNumber
ServiceType string `json:"serviceType"` // e.g., NSW_IMPORT_PERMIT_CD
}
ValidateReferenceRequest is the payload GovPay sends when a user enters a reference in their bank app.
type ValidateReferenceResponse ¶
type ValidateReferenceResponse struct {
Amount decimal.Decimal `json:"amount"`
Currency string `json:"currency"`
TraderName string `json:"traderName"`
OGAName string `json:"ogaName"`
ExpiryDate string `json:"expiryDate"` // ISO8601 format string
IsPayable bool `json:"isPayable"` // false if already paid or expired
Remarks string `json:"remarks,omitempty"`
}
ValidateReferenceResponse is the payload we return to GovPay to auto-populate the user's screen.
type ValidationResponse ¶
type ValidationResponse struct {
Payload json.RawMessage
HTTPStatus int
}
ValidationResponse represents a structured response for a validation request.
type ValidationTransaction ¶
type ValidationTransaction struct {
ReferenceNumber string `json:"reference_number"`
Amount decimal.Decimal `json:"amount"`
Currency string `json:"currency"`
Status string `json:"status"`
ExpiryDate time.Time `json:"expiry_date"`
Metadata map[string]string `json:"metadata"`
}
ValidationTransaction represents a minimal view of a payment transaction for validation purposes.
type WebhookPayload ¶
type WebhookPayload struct {
ReferenceNumber string `json:"reference_number"`
SessionID string `json:"session_id"`
GatewayTransactionID string `json:"gateway_transaction_id"`
Status WebhookStatus `json:"status"`
Amount decimal.Decimal `json:"amount"`
Currency string `json:"currency"`
PaymentMethod string `json:"payment_method"`
Timestamp string `json:"timestamp"`
Metadata map[string]string `json:"metadata"`
}
WebhookPayload represents the external callback from LankaPay to the Payment Service.
type WebhookResponse ¶
type WebhookResponse struct {
Payload json.RawMessage
HTTPStatus int
}
WebhookResponse is the gateway-specific acknowledgement returned to the gateway after a webhook (payment-completion) notification has been processed. For GovPay+ this carries the UpdateResponse (paymentData receipt).
type WebhookStatus ¶
type WebhookStatus string
WebhookStatus is the canonical, gateway-neutral outcome a gateway must normalize its own status vocabulary into when parsing a webhook.
const ( WebhookStatusPending WebhookStatus = "PENDING" WebhookStatusSuccess WebhookStatus = "SUCCESS" WebhookStatusFailed WebhookStatus = "FAILED" )