Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 

127 строки
3.9 KiB

  1. package model
  2. import (
  3. "time"
  4. "gorm.io/gorm"
  5. )
  6. const (
  7. PendingSyncStatusPending = "pending"
  8. PendingSyncStatusSynced = "synced"
  9. PendingSyncStatusFailed = "failed"
  10. PendingSyncStatusArchived = "archived"
  11. )
  12. // PendingSyncRecord 待同步消费记录
  13. type PendingSyncRecord struct {
  14. Id int `json:"id" gorm:"primaryKey"`
  15. UserId int `json:"user_id" gorm:"index:idx_user_status"`
  16. RemoteUserId int `json:"remote_user_id" gorm:"index"`
  17. RequestId string `json:"request_id" gorm:"type:varchar(128);uniqueIndex"`
  18. Quota int `json:"quota"`
  19. EstimatedQuota int `json:"estimated_quota"`
  20. Status string `json:"status" gorm:"default:'pending';index:idx_user_status;index:idx_status_created"`
  21. CreatedAt int64 `json:"created_at" gorm:"index:idx_status_created"`
  22. SyncedAt int64 `json:"synced_at"`
  23. RetryCount int `json:"retry_count" gorm:"default:0"`
  24. ErrorMsg string `json:"error_msg"`
  25. }
  26. func (PendingSyncRecord) TableName() string {
  27. return "pending_sync_records"
  28. }
  29. // GetPendingSyncQuota 获取用户待同步金额总和
  30. func GetPendingSyncQuota(userId int) int {
  31. var total int64
  32. DB.Model(&PendingSyncRecord{}).
  33. Where("user_id = ? AND status IN ?", userId, []string{PendingSyncStatusPending, PendingSyncStatusFailed}).
  34. Select("COALESCE(SUM(quota), 0)").
  35. Scan(&total)
  36. return int(total)
  37. }
  38. // CreatePendingSyncRecord 创建待同步记录
  39. func CreatePendingSyncRecord(userId, remoteUserId int, requestId string, quota, estimatedQuota int) error {
  40. record := PendingSyncRecord{
  41. UserId: userId,
  42. RemoteUserId: remoteUserId,
  43. RequestId: requestId,
  44. Quota: quota,
  45. EstimatedQuota: estimatedQuota,
  46. Status: PendingSyncStatusPending,
  47. CreatedAt: time.Now().Unix(),
  48. }
  49. return DB.Create(&record).Error
  50. }
  51. // GetPendingRecordsForSync 获取待同步记录
  52. func GetPendingRecordsForSync(limit, maxRetry int) []PendingSyncRecord {
  53. var records []PendingSyncRecord
  54. DB.Where("status IN ? AND retry_count < ?",
  55. []string{PendingSyncStatusPending, PendingSyncStatusFailed},
  56. maxRetry).
  57. Limit(limit).
  58. Order("created_at asc").
  59. Find(&records)
  60. return records
  61. }
  62. // MarkRecordSynced 标记记录为已同步
  63. func MarkRecordSynced(recordId int) error {
  64. return DB.Model(&PendingSyncRecord{}).Where("id = ?", recordId).Updates(map[string]interface{}{
  65. "status": PendingSyncStatusSynced,
  66. "synced_at": time.Now().Unix(),
  67. }).Error
  68. }
  69. // MarkRecordFailed 标记记录为失败
  70. func MarkRecordFailed(recordId int, errMsg string) error {
  71. return DB.Model(&PendingSyncRecord{}).Where("id = ?", recordId).Updates(map[string]interface{}{
  72. "status": PendingSyncStatusFailed,
  73. "retry_count": gorm.Expr("retry_count + 1"),
  74. "error_msg": errMsg,
  75. }).Error
  76. }
  77. // UpdatePendingSyncRecordQuota 更新待同步记录的实际扣费额度,返回影响的行数
  78. func UpdatePendingSyncRecordQuota(requestId string, actualQuota int) int64 {
  79. result := DB.Model(&PendingSyncRecord{}).
  80. Where("request_id = ? AND status = ?", requestId, PendingSyncStatusPending).
  81. Update("quota", actualQuota)
  82. if result.Error != nil {
  83. return 0
  84. }
  85. return result.RowsAffected
  86. }
  87. // CleanupOldSyncedRecords 清理超过指定天数的已同步记录
  88. func CleanupOldSyncedRecords(days int) int64 {
  89. result := DB.Where("status = ? AND synced_at < ?",
  90. PendingSyncStatusSynced,
  91. time.Now().Unix()-int64(days*86400)).
  92. Delete(&PendingSyncRecord{})
  93. return result.RowsAffected
  94. }
  95. // GetPendingQuotaByUser 获取每个用户的待同步金额
  96. func GetPendingQuotaByUser() map[int]int {
  97. type result struct {
  98. UserId int
  99. Total int
  100. }
  101. var results []result
  102. DB.Model(&PendingSyncRecord{}).
  103. Select("user_id, COALESCE(SUM(quota), 0) as total").
  104. Where("status IN ?", []string{PendingSyncStatusPending, PendingSyncStatusFailed}).
  105. Group("user_id").
  106. Scan(&results)
  107. m := make(map[int]int)
  108. for _, r := range results {
  109. m[r.UserId] = r.Total
  110. }
  111. return m
  112. }