types.go 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. // Package payment provides the core payment provider abstraction,
  2. // registry, load balancing, and shared utilities for the payment subsystem.
  3. package payment
  4. import "context"
  5. // PaymentType represents a supported payment method.
  6. type PaymentType = string
  7. // Supported payment type constants.
  8. const (
  9. TypeAlipay PaymentType = "alipay"
  10. TypeWxpay PaymentType = "wxpay"
  11. TypeAlipayDirect PaymentType = "alipay_direct"
  12. TypeWxpayDirect PaymentType = "wxpay_direct"
  13. TypeStripe PaymentType = "stripe"
  14. TypeCard PaymentType = "card"
  15. TypeLink PaymentType = "link"
  16. TypeEasyPay PaymentType = "easypay"
  17. TypeAirwallex PaymentType = "airwallex"
  18. )
  19. // Order status constants shared across payment and service layers.
  20. const (
  21. OrderStatusPending = "PENDING"
  22. OrderStatusPaid = "PAID"
  23. OrderStatusRecharging = "RECHARGING"
  24. OrderStatusCompleted = "COMPLETED"
  25. OrderStatusExpired = "EXPIRED"
  26. OrderStatusCancelled = "CANCELLED"
  27. OrderStatusFailed = "FAILED"
  28. OrderStatusRefundRequested = "REFUND_REQUESTED"
  29. OrderStatusRefunding = "REFUNDING"
  30. OrderStatusRefundPending = "REFUND_PENDING"
  31. OrderStatusPartiallyRefunded = "PARTIALLY_REFUNDED"
  32. OrderStatusRefunded = "REFUNDED"
  33. OrderStatusRefundFailed = "REFUND_FAILED"
  34. )
  35. // Order types distinguish balance recharges from subscription purchases.
  36. const (
  37. OrderTypeBalance = "balance"
  38. OrderTypeSubscription = "subscription"
  39. )
  40. // Entity statuses shared across users, groups, etc.
  41. const (
  42. EntityStatusActive = "active"
  43. )
  44. // Deduction types for refund flow.
  45. const (
  46. DeductionTypeBalance = "balance"
  47. DeductionTypeSubscription = "subscription"
  48. DeductionTypeNone = "none"
  49. )
  50. // Payment notification status values.
  51. const (
  52. NotificationStatusSuccess = "success"
  53. NotificationStatusPaid = "paid"
  54. )
  55. // Provider-level status constants returned by provider implementations
  56. // to the service layer (lowercase, distinct from OrderStatus uppercase constants).
  57. const (
  58. ProviderStatusPending = "pending"
  59. ProviderStatusPaid = "paid"
  60. ProviderStatusSuccess = "success"
  61. ProviderStatusFailed = "failed"
  62. ProviderStatusRefunded = "refunded"
  63. )
  64. // DefaultLoadBalanceStrategy is the default load-balancing strategy
  65. // used when no strategy is configured.
  66. const DefaultLoadBalanceStrategy = "round-robin"
  67. // ConfigKeyPublishableKey is the config map key for Stripe's publishable key.
  68. const ConfigKeyPublishableKey = "publishableKey"
  69. // GetBasePaymentType extracts the base payment method from a composite key.
  70. // For example, "alipay_direct" -> "alipay".
  71. func GetBasePaymentType(t string) string {
  72. switch {
  73. case t == TypeEasyPay:
  74. return TypeEasyPay
  75. case t == TypeAirwallex:
  76. return TypeAirwallex
  77. case t == TypeStripe || t == TypeCard || t == TypeLink:
  78. return TypeStripe
  79. case len(t) >= len(TypeAlipay) && t[:len(TypeAlipay)] == TypeAlipay:
  80. return TypeAlipay
  81. case len(t) >= len(TypeWxpay) && t[:len(TypeWxpay)] == TypeWxpay:
  82. return TypeWxpay
  83. default:
  84. return t
  85. }
  86. }
  87. // CreatePaymentRequest holds the parameters for creating a new payment.
  88. type CreatePaymentRequest struct {
  89. OrderID string // Internal order ID
  90. Amount string // 支付金额,按服务商实例配置的币种解释
  91. PaymentType string // e.g. "alipay", "wxpay", "stripe"
  92. Subject string // Product description
  93. NotifyURL string // Webhook callback URL
  94. ReturnURL string // Browser redirect URL after payment
  95. OpenID string // WeChat JSAPI payer OpenID when available
  96. ClientIP string // Payer's IP address
  97. IsMobile bool // Whether the request comes from a mobile device
  98. // AlipayMobilePrecreate routes a mobile Alipay request through
  99. // alipay.trade.precreate instead of alipay.trade.wap.pay.
  100. AlipayMobilePrecreate bool
  101. InstanceSubMethods string // Comma-separated sub-methods from instance supported_types (for Stripe)
  102. }
  103. // CreatePaymentResultType describes the shape of the create-payment result.
  104. type CreatePaymentResultType = string
  105. const (
  106. CreatePaymentResultOrderCreated CreatePaymentResultType = "order_created"
  107. CreatePaymentResultOAuthRequired CreatePaymentResultType = "oauth_required"
  108. CreatePaymentResultJSAPIReady CreatePaymentResultType = "jsapi_ready"
  109. )
  110. // WechatOAuthInfo describes the next step when WeChat OAuth is required before payment.
  111. type WechatOAuthInfo struct {
  112. AuthorizeURL string `json:"authorize_url,omitempty"`
  113. AppID string `json:"appid,omitempty"`
  114. OpenID string `json:"openid,omitempty"`
  115. Scope string `json:"scope,omitempty"`
  116. State string `json:"state,omitempty"`
  117. RedirectURL string `json:"redirect_url,omitempty"`
  118. }
  119. // WechatJSAPIPayload contains the fields the frontend needs to invoke WeChat JSAPI payment.
  120. type WechatJSAPIPayload struct {
  121. AppID string `json:"appId,omitempty"`
  122. TimeStamp string `json:"timeStamp,omitempty"`
  123. NonceStr string `json:"nonceStr,omitempty"`
  124. Package string `json:"package,omitempty"`
  125. SignType string `json:"signType,omitempty"`
  126. PaySign string `json:"paySign,omitempty"`
  127. }
  128. // CreatePaymentResponse is returned after successfully initiating a payment.
  129. type CreatePaymentResponse struct {
  130. TradeNo string // Third-party transaction ID
  131. PayURL string // H5 payment URL (alipay/wxpay)
  132. QRCode string // QR code content for scanning
  133. ClientSecret string // Stripe PaymentIntent 客户端密钥
  134. IntentID string // 前端 SDK 需要的服务商支付意图 ID
  135. Currency string // 服务商支付币种
  136. CountryCode string // 服务商收银台国家/地区代码
  137. PaymentEnv string // 服务商前端环境标识
  138. ResultType CreatePaymentResultType // Typed result contract for frontend flows
  139. OAuth *WechatOAuthInfo // WeChat OAuth bootstrap payload when required
  140. JSAPI *WechatJSAPIPayload // WeChat JSAPI invocation payload when ready
  141. }
  142. // QueryOrderResponse describes the payment status from the upstream provider.
  143. type QueryOrderResponse struct {
  144. TradeNo string
  145. Status string // "pending", "paid", "failed", "refunded"
  146. Amount float64 // 按服务商返回币种解释的金额
  147. PaidAt string // RFC3339 timestamp or empty
  148. Metadata map[string]string
  149. }
  150. // PaymentNotification is the parsed result of a webhook/notify callback.
  151. type PaymentNotification struct {
  152. TradeNo string
  153. OrderID string
  154. Amount float64
  155. Status string // "success" or "failed"
  156. RawData string // Raw notification body for audit
  157. Metadata map[string]string
  158. }
  159. // RefundRequest contains the parameters for requesting a refund.
  160. type RefundRequest struct {
  161. TradeNo string
  162. OrderID string
  163. Amount string // Refund amount formatted to 2 decimal places
  164. Reason string
  165. }
  166. // RefundQueryRequest contains identifiers needed to query a previously
  167. // requested refund.
  168. type RefundQueryRequest struct {
  169. TradeNo string
  170. OrderID string
  171. RefundID string
  172. Amount string
  173. }
  174. // RefundResponse is returned after a refund request.
  175. type RefundResponse struct {
  176. RefundID string
  177. Status string // "success", "pending", "failed"
  178. }
  179. // InstanceSelection holds the selected provider instance and its decrypted config.
  180. type InstanceSelection struct {
  181. InstanceID string
  182. ProviderKey string // Provider key of the selected instance (e.g. "alipay", "easypay")
  183. Config map[string]string
  184. SupportedTypes string // Comma-separated list of supported payment types from the instance
  185. PaymentMode string // Payment display mode: "qrcode", "redirect", "popup"
  186. }
  187. // Provider defines the interface that all payment providers must implement.
  188. type Provider interface {
  189. // Name returns a human-readable name for this provider.
  190. Name() string
  191. // ProviderKey returns the unique key identifying this provider type (e.g. "easypay").
  192. ProviderKey() string
  193. // SupportedTypes returns the list of payment types this provider handles.
  194. SupportedTypes() []PaymentType
  195. // CreatePayment initiates a payment and returns the upstream response.
  196. CreatePayment(ctx context.Context, req CreatePaymentRequest) (*CreatePaymentResponse, error)
  197. // QueryOrder queries the payment status of the given trade number.
  198. QueryOrder(ctx context.Context, tradeNo string) (*QueryOrderResponse, error)
  199. // VerifyNotification parses and verifies a webhook callback.
  200. // Returns nil for unrecognized or irrelevant events (caller should return 200).
  201. VerifyNotification(ctx context.Context, rawBody string, headers map[string]string) (*PaymentNotification, error)
  202. // Refund requests a refund from the upstream provider.
  203. Refund(ctx context.Context, req RefundRequest) (*RefundResponse, error)
  204. }
  205. // RefundQueryProvider extends Provider with refund status querying.
  206. type RefundQueryProvider interface {
  207. Provider
  208. QueryRefund(ctx context.Context, req RefundQueryRequest) (*RefundResponse, error)
  209. }
  210. // CancelableProvider extends Provider with the ability to cancel pending payments.
  211. type CancelableProvider interface {
  212. Provider
  213. // CancelPayment cancels/expires a pending payment on the upstream platform.
  214. CancelPayment(ctx context.Context, tradeNo string) error
  215. }
  216. // MerchantIdentityProvider exposes the current non-sensitive merchant identity
  217. // derived from provider configuration for snapshot consistency checks.
  218. type MerchantIdentityProvider interface {
  219. MerchantIdentityMetadata() map[string]string
  220. }