payment_order.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. package schema
  2. import (
  3. "time"
  4. "entgo.io/ent"
  5. "entgo.io/ent/dialect"
  6. "entgo.io/ent/dialect/entsql"
  7. "entgo.io/ent/schema"
  8. "entgo.io/ent/schema/edge"
  9. "entgo.io/ent/schema/field"
  10. "entgo.io/ent/schema/index"
  11. )
  12. // PaymentOrder holds the schema definition for the PaymentOrder entity.
  13. //
  14. // 删除策略:硬删除
  15. // PaymentOrder 使用硬删除而非软删除,原因如下:
  16. // - 订单通过 status 字段追踪完整生命周期,无需依赖软删除
  17. // - 订单审计通过 PaymentAuditLog 表记录,删除前可归档
  18. // - 减少查询复杂度,避免软删除过滤开销
  19. type PaymentOrder struct {
  20. ent.Schema
  21. }
  22. func (PaymentOrder) Annotations() []schema.Annotation {
  23. return []schema.Annotation{
  24. entsql.Annotation{Table: "payment_orders"},
  25. }
  26. }
  27. func (PaymentOrder) Fields() []ent.Field {
  28. return []ent.Field{
  29. // 用户信息(冗余存储,避免关联查询)
  30. field.Int64("user_id"),
  31. field.String("user_email").
  32. MaxLen(255),
  33. field.String("user_name").
  34. MaxLen(100),
  35. field.String("user_notes").
  36. Optional().
  37. Nillable().
  38. SchemaType(map[string]string{dialect.Postgres: "text"}),
  39. // 金额信息
  40. field.Float("amount").
  41. SchemaType(map[string]string{dialect.Postgres: "decimal(20,2)"}),
  42. field.Float("pay_amount").
  43. SchemaType(map[string]string{dialect.Postgres: "decimal(20,2)"}),
  44. field.Float("fee_rate").
  45. SchemaType(map[string]string{dialect.Postgres: "decimal(10,4)"}).
  46. Default(0),
  47. field.String("recharge_code").
  48. MaxLen(64),
  49. // 支付信息
  50. field.String("out_trade_no").
  51. MaxLen(64).
  52. Default(""),
  53. field.String("payment_type").
  54. MaxLen(30),
  55. field.String("payment_trade_no").
  56. MaxLen(128),
  57. field.String("pay_url").
  58. Optional().
  59. Nillable().
  60. SchemaType(map[string]string{dialect.Postgres: "text"}),
  61. field.String("qr_code").
  62. Optional().
  63. Nillable().
  64. SchemaType(map[string]string{dialect.Postgres: "text"}),
  65. field.String("qr_code_img").
  66. Optional().
  67. Nillable().
  68. SchemaType(map[string]string{dialect.Postgres: "text"}),
  69. // 订单类型 & 订阅关联
  70. field.String("order_type").
  71. MaxLen(20).
  72. Default("balance"),
  73. field.Int64("plan_id").
  74. Optional().
  75. Nillable(),
  76. field.Int64("subscription_group_id").
  77. Optional().
  78. Nillable(),
  79. field.Int("subscription_days").
  80. Optional().
  81. Nillable(),
  82. field.String("provider_instance_id").
  83. Optional().
  84. Nillable().
  85. MaxLen(64),
  86. field.String("provider_key").
  87. Optional().
  88. Nillable().
  89. MaxLen(30),
  90. field.JSON("provider_snapshot", map[string]any{}).
  91. Optional().
  92. SchemaType(map[string]string{dialect.Postgres: "jsonb"}),
  93. // 状态
  94. field.String("status").
  95. MaxLen(30).
  96. Default("PENDING"),
  97. // 退款信息
  98. field.Float("refund_amount").
  99. SchemaType(map[string]string{dialect.Postgres: "decimal(20,2)"}).
  100. Default(0),
  101. field.String("refund_reason").
  102. Optional().
  103. Nillable().
  104. SchemaType(map[string]string{dialect.Postgres: "text"}),
  105. field.Time("refund_at").
  106. Optional().
  107. Nillable().
  108. SchemaType(map[string]string{dialect.Postgres: "timestamptz"}),
  109. field.Bool("force_refund").
  110. Default(false),
  111. field.Time("refund_requested_at").
  112. Optional().
  113. Nillable().
  114. SchemaType(map[string]string{dialect.Postgres: "timestamptz"}),
  115. field.String("refund_request_reason").
  116. Optional().
  117. Nillable().
  118. SchemaType(map[string]string{dialect.Postgres: "text"}),
  119. field.String("refund_requested_by").
  120. Optional().
  121. Nillable().
  122. MaxLen(20),
  123. // 时间节点
  124. field.Time("expires_at").
  125. SchemaType(map[string]string{dialect.Postgres: "timestamptz"}),
  126. field.Time("paid_at").
  127. Optional().
  128. Nillable().
  129. SchemaType(map[string]string{dialect.Postgres: "timestamptz"}),
  130. field.Time("completed_at").
  131. Optional().
  132. Nillable().
  133. SchemaType(map[string]string{dialect.Postgres: "timestamptz"}),
  134. field.Time("failed_at").
  135. Optional().
  136. Nillable().
  137. SchemaType(map[string]string{dialect.Postgres: "timestamptz"}),
  138. field.String("failed_reason").
  139. Optional().
  140. Nillable().
  141. SchemaType(map[string]string{dialect.Postgres: "text"}),
  142. // 来源信息
  143. field.String("client_ip").
  144. MaxLen(50),
  145. field.String("src_host").
  146. MaxLen(255),
  147. field.String("src_url").
  148. Optional().
  149. Nillable().
  150. SchemaType(map[string]string{dialect.Postgres: "text"}),
  151. // 时间戳
  152. field.Time("created_at").
  153. Immutable().
  154. Default(time.Now).
  155. SchemaType(map[string]string{dialect.Postgres: "timestamptz"}),
  156. field.Time("updated_at").
  157. Default(time.Now).
  158. UpdateDefault(time.Now).
  159. SchemaType(map[string]string{dialect.Postgres: "timestamptz"}),
  160. }
  161. }
  162. func (PaymentOrder) Edges() []ent.Edge {
  163. return []ent.Edge{
  164. edge.From("user", User.Type).
  165. Ref("payment_orders").
  166. Field("user_id").
  167. Unique().
  168. Required(),
  169. }
  170. }
  171. func (PaymentOrder) Indexes() []ent.Index {
  172. return []ent.Index{
  173. index.Fields("out_trade_no").
  174. Unique().
  175. Annotations(entsql.IndexWhere("out_trade_no <> ''")),
  176. index.Fields("user_id"),
  177. index.Fields("status"),
  178. index.Fields("expires_at"),
  179. index.Fields("created_at"),
  180. index.Fields("paid_at"),
  181. index.Fields("payment_type", "paid_at"),
  182. index.Fields("order_type"),
  183. }
  184. }