feat: add TenantLedger model and query generation

- Introduced TenantLedger model with fields for managing tenant transactions, including ID, TenantID, UserID, OrderID, transaction Type, Amount, and balance details.
- Implemented CRUD operations for TenantLedger with methods for Create, Update, Delete, and Reload.
- Generated query methods for TenantLedger to facilitate database interactions, including filtering, pagination, and aggregation functions.
- Established relationships with Order model for foreign key references.
This commit is contained in:
2025-12-18 13:12:26 +08:00
parent f93caefcb2
commit 1da84f2af3
42 changed files with 6468 additions and 265 deletions

View File

@@ -1343,6 +1343,346 @@ func (x NullMediaAssetTypeStr) Value() (driver.Value, error) {
return x.MediaAssetType.String(), nil
}
const (
// OrderStatusCreated is a OrderStatus of type created.
OrderStatusCreated OrderStatus = "created"
// OrderStatusPaid is a OrderStatus of type paid.
OrderStatusPaid OrderStatus = "paid"
// OrderStatusRefunding is a OrderStatus of type refunding.
OrderStatusRefunding OrderStatus = "refunding"
// OrderStatusRefunded is a OrderStatus of type refunded.
OrderStatusRefunded OrderStatus = "refunded"
// OrderStatusCanceled is a OrderStatus of type canceled.
OrderStatusCanceled OrderStatus = "canceled"
// OrderStatusFailed is a OrderStatus of type failed.
OrderStatusFailed OrderStatus = "failed"
)
var ErrInvalidOrderStatus = fmt.Errorf("not a valid OrderStatus, try [%s]", strings.Join(_OrderStatusNames, ", "))
var _OrderStatusNames = []string{
string(OrderStatusCreated),
string(OrderStatusPaid),
string(OrderStatusRefunding),
string(OrderStatusRefunded),
string(OrderStatusCanceled),
string(OrderStatusFailed),
}
// OrderStatusNames returns a list of possible string values of OrderStatus.
func OrderStatusNames() []string {
tmp := make([]string, len(_OrderStatusNames))
copy(tmp, _OrderStatusNames)
return tmp
}
// OrderStatusValues returns a list of the values for OrderStatus
func OrderStatusValues() []OrderStatus {
return []OrderStatus{
OrderStatusCreated,
OrderStatusPaid,
OrderStatusRefunding,
OrderStatusRefunded,
OrderStatusCanceled,
OrderStatusFailed,
}
}
// String implements the Stringer interface.
func (x OrderStatus) String() string {
return string(x)
}
// IsValid provides a quick way to determine if the typed value is
// part of the allowed enumerated values
func (x OrderStatus) IsValid() bool {
_, err := ParseOrderStatus(string(x))
return err == nil
}
var _OrderStatusValue = map[string]OrderStatus{
"created": OrderStatusCreated,
"paid": OrderStatusPaid,
"refunding": OrderStatusRefunding,
"refunded": OrderStatusRefunded,
"canceled": OrderStatusCanceled,
"failed": OrderStatusFailed,
}
// ParseOrderStatus attempts to convert a string to a OrderStatus.
func ParseOrderStatus(name string) (OrderStatus, error) {
if x, ok := _OrderStatusValue[name]; ok {
return x, nil
}
return OrderStatus(""), fmt.Errorf("%s is %w", name, ErrInvalidOrderStatus)
}
var errOrderStatusNilPtr = errors.New("value pointer is nil") // one per type for package clashes
// Scan implements the Scanner interface.
func (x *OrderStatus) Scan(value interface{}) (err error) {
if value == nil {
*x = OrderStatus("")
return
}
// A wider range of scannable types.
// driver.Value values at the top of the list for expediency
switch v := value.(type) {
case string:
*x, err = ParseOrderStatus(v)
case []byte:
*x, err = ParseOrderStatus(string(v))
case OrderStatus:
*x = v
case *OrderStatus:
if v == nil {
return errOrderStatusNilPtr
}
*x = *v
case *string:
if v == nil {
return errOrderStatusNilPtr
}
*x, err = ParseOrderStatus(*v)
default:
return errors.New("invalid type for OrderStatus")
}
return
}
// Value implements the driver Valuer interface.
func (x OrderStatus) Value() (driver.Value, error) {
return x.String(), nil
}
// Set implements the Golang flag.Value interface func.
func (x *OrderStatus) Set(val string) error {
v, err := ParseOrderStatus(val)
*x = v
return err
}
// Get implements the Golang flag.Getter interface func.
func (x *OrderStatus) Get() interface{} {
return *x
}
// Type implements the github.com/spf13/pFlag Value interface.
func (x *OrderStatus) Type() string {
return "OrderStatus"
}
type NullOrderStatus struct {
OrderStatus OrderStatus
Valid bool
}
func NewNullOrderStatus(val interface{}) (x NullOrderStatus) {
err := x.Scan(val) // yes, we ignore this error, it will just be an invalid value.
_ = err // make any errcheck linters happy
return
}
// Scan implements the Scanner interface.
func (x *NullOrderStatus) Scan(value interface{}) (err error) {
if value == nil {
x.OrderStatus, x.Valid = OrderStatus(""), false
return
}
err = x.OrderStatus.Scan(value)
x.Valid = (err == nil)
return
}
// Value implements the driver Valuer interface.
func (x NullOrderStatus) Value() (driver.Value, error) {
if !x.Valid {
return nil, nil
}
// driver.Value accepts int64 for int values.
return string(x.OrderStatus), nil
}
type NullOrderStatusStr struct {
NullOrderStatus
}
func NewNullOrderStatusStr(val interface{}) (x NullOrderStatusStr) {
x.Scan(val) // yes, we ignore this error, it will just be an invalid value.
return
}
// Value implements the driver Valuer interface.
func (x NullOrderStatusStr) Value() (driver.Value, error) {
if !x.Valid {
return nil, nil
}
return x.OrderStatus.String(), nil
}
const (
// OrderTypeContentPurchase is a OrderType of type content_purchase.
OrderTypeContentPurchase OrderType = "content_purchase"
// OrderTypeTopup is a OrderType of type topup.
OrderTypeTopup OrderType = "topup"
)
var ErrInvalidOrderType = fmt.Errorf("not a valid OrderType, try [%s]", strings.Join(_OrderTypeNames, ", "))
var _OrderTypeNames = []string{
string(OrderTypeContentPurchase),
string(OrderTypeTopup),
}
// OrderTypeNames returns a list of possible string values of OrderType.
func OrderTypeNames() []string {
tmp := make([]string, len(_OrderTypeNames))
copy(tmp, _OrderTypeNames)
return tmp
}
// OrderTypeValues returns a list of the values for OrderType
func OrderTypeValues() []OrderType {
return []OrderType{
OrderTypeContentPurchase,
OrderTypeTopup,
}
}
// String implements the Stringer interface.
func (x OrderType) String() string {
return string(x)
}
// IsValid provides a quick way to determine if the typed value is
// part of the allowed enumerated values
func (x OrderType) IsValid() bool {
_, err := ParseOrderType(string(x))
return err == nil
}
var _OrderTypeValue = map[string]OrderType{
"content_purchase": OrderTypeContentPurchase,
"topup": OrderTypeTopup,
}
// ParseOrderType attempts to convert a string to a OrderType.
func ParseOrderType(name string) (OrderType, error) {
if x, ok := _OrderTypeValue[name]; ok {
return x, nil
}
return OrderType(""), fmt.Errorf("%s is %w", name, ErrInvalidOrderType)
}
var errOrderTypeNilPtr = errors.New("value pointer is nil") // one per type for package clashes
// Scan implements the Scanner interface.
func (x *OrderType) Scan(value interface{}) (err error) {
if value == nil {
*x = OrderType("")
return
}
// A wider range of scannable types.
// driver.Value values at the top of the list for expediency
switch v := value.(type) {
case string:
*x, err = ParseOrderType(v)
case []byte:
*x, err = ParseOrderType(string(v))
case OrderType:
*x = v
case *OrderType:
if v == nil {
return errOrderTypeNilPtr
}
*x = *v
case *string:
if v == nil {
return errOrderTypeNilPtr
}
*x, err = ParseOrderType(*v)
default:
return errors.New("invalid type for OrderType")
}
return
}
// Value implements the driver Valuer interface.
func (x OrderType) Value() (driver.Value, error) {
return x.String(), nil
}
// Set implements the Golang flag.Value interface func.
func (x *OrderType) Set(val string) error {
v, err := ParseOrderType(val)
*x = v
return err
}
// Get implements the Golang flag.Getter interface func.
func (x *OrderType) Get() interface{} {
return *x
}
// Type implements the github.com/spf13/pFlag Value interface.
func (x *OrderType) Type() string {
return "OrderType"
}
type NullOrderType struct {
OrderType OrderType
Valid bool
}
func NewNullOrderType(val interface{}) (x NullOrderType) {
err := x.Scan(val) // yes, we ignore this error, it will just be an invalid value.
_ = err // make any errcheck linters happy
return
}
// Scan implements the Scanner interface.
func (x *NullOrderType) Scan(value interface{}) (err error) {
if value == nil {
x.OrderType, x.Valid = OrderType(""), false
return
}
err = x.OrderType.Scan(value)
x.Valid = (err == nil)
return
}
// Value implements the driver Valuer interface.
func (x NullOrderType) Value() (driver.Value, error) {
if !x.Valid {
return nil, nil
}
// driver.Value accepts int64 for int values.
return string(x.OrderType), nil
}
type NullOrderTypeStr struct {
NullOrderType
}
func NewNullOrderTypeStr(val interface{}) (x NullOrderTypeStr) {
x.Scan(val) // yes, we ignore this error, it will just be an invalid value.
return
}
// Value implements the driver Valuer interface.
func (x NullOrderTypeStr) Value() (driver.Value, error) {
if !x.Valid {
return nil, nil
}
return x.OrderType.String(), nil
}
const (
// RoleUser is a Role of type user.
RoleUser Role = "user"
@@ -1503,6 +1843,186 @@ func (x NullRoleStr) Value() (driver.Value, error) {
return x.Role.String(), nil
}
const (
// TenantLedgerTypeCreditTopup is a TenantLedgerType of type credit_topup.
TenantLedgerTypeCreditTopup TenantLedgerType = "credit_topup"
// TenantLedgerTypeDebitPurchase is a TenantLedgerType of type debit_purchase.
TenantLedgerTypeDebitPurchase TenantLedgerType = "debit_purchase"
// TenantLedgerTypeCreditRefund is a TenantLedgerType of type credit_refund.
TenantLedgerTypeCreditRefund TenantLedgerType = "credit_refund"
// TenantLedgerTypeFreeze is a TenantLedgerType of type freeze.
TenantLedgerTypeFreeze TenantLedgerType = "freeze"
// TenantLedgerTypeUnfreeze is a TenantLedgerType of type unfreeze.
TenantLedgerTypeUnfreeze TenantLedgerType = "unfreeze"
// TenantLedgerTypeAdjustment is a TenantLedgerType of type adjustment.
TenantLedgerTypeAdjustment TenantLedgerType = "adjustment"
)
var ErrInvalidTenantLedgerType = fmt.Errorf("not a valid TenantLedgerType, try [%s]", strings.Join(_TenantLedgerTypeNames, ", "))
var _TenantLedgerTypeNames = []string{
string(TenantLedgerTypeCreditTopup),
string(TenantLedgerTypeDebitPurchase),
string(TenantLedgerTypeCreditRefund),
string(TenantLedgerTypeFreeze),
string(TenantLedgerTypeUnfreeze),
string(TenantLedgerTypeAdjustment),
}
// TenantLedgerTypeNames returns a list of possible string values of TenantLedgerType.
func TenantLedgerTypeNames() []string {
tmp := make([]string, len(_TenantLedgerTypeNames))
copy(tmp, _TenantLedgerTypeNames)
return tmp
}
// TenantLedgerTypeValues returns a list of the values for TenantLedgerType
func TenantLedgerTypeValues() []TenantLedgerType {
return []TenantLedgerType{
TenantLedgerTypeCreditTopup,
TenantLedgerTypeDebitPurchase,
TenantLedgerTypeCreditRefund,
TenantLedgerTypeFreeze,
TenantLedgerTypeUnfreeze,
TenantLedgerTypeAdjustment,
}
}
// String implements the Stringer interface.
func (x TenantLedgerType) String() string {
return string(x)
}
// IsValid provides a quick way to determine if the typed value is
// part of the allowed enumerated values
func (x TenantLedgerType) IsValid() bool {
_, err := ParseTenantLedgerType(string(x))
return err == nil
}
var _TenantLedgerTypeValue = map[string]TenantLedgerType{
"credit_topup": TenantLedgerTypeCreditTopup,
"debit_purchase": TenantLedgerTypeDebitPurchase,
"credit_refund": TenantLedgerTypeCreditRefund,
"freeze": TenantLedgerTypeFreeze,
"unfreeze": TenantLedgerTypeUnfreeze,
"adjustment": TenantLedgerTypeAdjustment,
}
// ParseTenantLedgerType attempts to convert a string to a TenantLedgerType.
func ParseTenantLedgerType(name string) (TenantLedgerType, error) {
if x, ok := _TenantLedgerTypeValue[name]; ok {
return x, nil
}
return TenantLedgerType(""), fmt.Errorf("%s is %w", name, ErrInvalidTenantLedgerType)
}
var errTenantLedgerTypeNilPtr = errors.New("value pointer is nil") // one per type for package clashes
// Scan implements the Scanner interface.
func (x *TenantLedgerType) Scan(value interface{}) (err error) {
if value == nil {
*x = TenantLedgerType("")
return
}
// A wider range of scannable types.
// driver.Value values at the top of the list for expediency
switch v := value.(type) {
case string:
*x, err = ParseTenantLedgerType(v)
case []byte:
*x, err = ParseTenantLedgerType(string(v))
case TenantLedgerType:
*x = v
case *TenantLedgerType:
if v == nil {
return errTenantLedgerTypeNilPtr
}
*x = *v
case *string:
if v == nil {
return errTenantLedgerTypeNilPtr
}
*x, err = ParseTenantLedgerType(*v)
default:
return errors.New("invalid type for TenantLedgerType")
}
return
}
// Value implements the driver Valuer interface.
func (x TenantLedgerType) Value() (driver.Value, error) {
return x.String(), nil
}
// Set implements the Golang flag.Value interface func.
func (x *TenantLedgerType) Set(val string) error {
v, err := ParseTenantLedgerType(val)
*x = v
return err
}
// Get implements the Golang flag.Getter interface func.
func (x *TenantLedgerType) Get() interface{} {
return *x
}
// Type implements the github.com/spf13/pFlag Value interface.
func (x *TenantLedgerType) Type() string {
return "TenantLedgerType"
}
type NullTenantLedgerType struct {
TenantLedgerType TenantLedgerType
Valid bool
}
func NewNullTenantLedgerType(val interface{}) (x NullTenantLedgerType) {
err := x.Scan(val) // yes, we ignore this error, it will just be an invalid value.
_ = err // make any errcheck linters happy
return
}
// Scan implements the Scanner interface.
func (x *NullTenantLedgerType) Scan(value interface{}) (err error) {
if value == nil {
x.TenantLedgerType, x.Valid = TenantLedgerType(""), false
return
}
err = x.TenantLedgerType.Scan(value)
x.Valid = (err == nil)
return
}
// Value implements the driver Valuer interface.
func (x NullTenantLedgerType) Value() (driver.Value, error) {
if !x.Valid {
return nil, nil
}
// driver.Value accepts int64 for int values.
return string(x.TenantLedgerType), nil
}
type NullTenantLedgerTypeStr struct {
NullTenantLedgerType
}
func NewNullTenantLedgerTypeStr(val interface{}) (x NullTenantLedgerTypeStr) {
x.Scan(val) // yes, we ignore this error, it will just be an invalid value.
return
}
// Value implements the driver Valuer interface.
func (x NullTenantLedgerTypeStr) Value() (driver.Value, error) {
if !x.Valid {
return nil, nil
}
return x.TenantLedgerType.String(), nil
}
const (
// TenantStatusPendingVerify is a TenantStatus of type pending_verify.
TenantStatusPendingVerify TenantStatus = "pending_verify"

View File

@@ -1,6 +1,10 @@
package consts
import "quyun/v2/app/requests"
import (
"time"
"quyun/v2/app/requests"
)
// Format
//
@@ -275,6 +279,10 @@ const (
// DefaultContentPreviewSeconds is the default preview duration in seconds when content.preview_seconds is unset/invalid.
// 默认试看时长(秒):当未配置或传入非法值时使用。
DefaultContentPreviewSeconds int32 = 60
// DefaultOrderRefundWindow is the default refundable time window starting from paid_at.
// 默认退款时间窗paid_at + 24h租户管理侧可以通过强制退款绕过该限制需审计
DefaultOrderRefundWindow = 24 * time.Hour
)
// content_prices
@@ -360,3 +368,101 @@ func ContentAccessStatusItems() []requests.KV {
}
return items
}
// orders
// swagger:enum OrderType
// ENUM( content_purchase, topup )
type OrderType string
// Description returns the Chinese label for the specific enum value.
func (t OrderType) Description() string {
switch t {
case OrderTypeContentPurchase:
return "购买内容"
case OrderTypeTopup:
return "充值"
default:
return "未知类型"
}
}
// OrderTypeItems returns the KV list for FE dropdowns.
func OrderTypeItems() []requests.KV {
values := OrderTypeValues()
items := make([]requests.KV, 0, len(values))
for _, v := range values {
items = append(items, requests.NewKV(string(v), v.Description()))
}
return items
}
// swagger:enum OrderStatus
// ENUM( created, paid, refunding, refunded, canceled, failed )
type OrderStatus string
// Description returns the Chinese label for the specific enum value.
func (t OrderStatus) Description() string {
switch t {
case OrderStatusCreated:
return "已创建"
case OrderStatusPaid:
return "已支付"
case OrderStatusRefunding:
return "退款中"
case OrderStatusRefunded:
return "已退款"
case OrderStatusCanceled:
return "已取消"
case OrderStatusFailed:
return "失败"
default:
return "未知状态"
}
}
// OrderStatusItems returns the KV list for FE dropdowns.
func OrderStatusItems() []requests.KV {
values := OrderStatusValues()
items := make([]requests.KV, 0, len(values))
for _, v := range values {
items = append(items, requests.NewKV(string(v), v.Description()))
}
return items
}
// tenant_ledgers
// swagger:enum TenantLedgerType
// ENUM( credit_topup, debit_purchase, credit_refund, freeze, unfreeze, adjustment )
type TenantLedgerType string
// Description returns the Chinese label for the specific enum value.
func (t TenantLedgerType) Description() string {
switch t {
case TenantLedgerTypeCreditTopup:
return "充值入账"
case TenantLedgerTypeDebitPurchase:
return "购买扣款"
case TenantLedgerTypeCreditRefund:
return "退款回滚"
case TenantLedgerTypeFreeze:
return "冻结"
case TenantLedgerTypeUnfreeze:
return "解冻"
case TenantLedgerTypeAdjustment:
return "人工调账"
default:
return "未知类型"
}
}
// TenantLedgerTypeItems returns the KV list for FE dropdowns.
func TenantLedgerTypeItems() []requests.KV {
values := TenantLedgerTypeValues()
items := make([]requests.KV, 0, len(values))
for _, v := range values {
items = append(items, requests.NewKV(string(v), v.Description()))
}
return items
}