feat: live module and jenkins pipeline to harbor deploy
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
package recharge
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
|
||||
biz "kra/internal/biz/recharge"
|
||||
"kra/internal/data/ledger"
|
||||
)
|
||||
|
||||
type Provider interface{ DB() *gorm.DB }
|
||||
type repo struct{ data Provider }
|
||||
|
||||
func NewRepo(data Provider) biz.Repo { return &repo{data: data} }
|
||||
func (r *repo) db(ctx context.Context) *gorm.DB { return r.data.DB().WithContext(ctx) }
|
||||
|
||||
func (r *repo) Plans(ctx context.Context) ([]*biz.Plan, error) {
|
||||
var rows []ledger.RechargePlanPO
|
||||
if err := r.db(ctx).Where("enabled = ?", true).Order("sort ASC,id ASC").Find(&rows).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := make([]*biz.Plan, 0, len(rows))
|
||||
for _, v := range rows {
|
||||
out = append(out, &biz.Plan{ID: v.ID, Sort: v.Sort, Diamonds: v.Diamonds, AmountCents: v.AmountCents, Enabled: v.Enabled})
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (r *repo) SavePlans(ctx context.Context, plans []*biz.Plan) error {
|
||||
return r.db(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
if err := tx.Session(&gorm.Session{AllowGlobalUpdate: true}).Delete(&ledger.RechargePlanPO{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
for _, p := range plans {
|
||||
if err := tx.Create(&ledger.RechargePlanPO{Sort: p.Sort, Diamonds: p.Diamonds, AmountCents: p.AmountCents, Enabled: true}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
type row struct {
|
||||
ledger.RechargeOrderPO
|
||||
Username string `gorm:"column:username"`
|
||||
Nickname string `gorm:"column:nickname"`
|
||||
Provider string `gorm:"column:provider"`
|
||||
ProviderTradeNo string `gorm:"column:provider_trade_no"`
|
||||
PaymentStatus string `gorm:"column:payment_status"`
|
||||
FulfillmentStatus string `gorm:"column:fulfillment_status"`
|
||||
RefundStatus string `gorm:"column:refund_status"`
|
||||
}
|
||||
|
||||
func query(db *gorm.DB, f biz.Filter) *gorm.DB {
|
||||
q := db.Model(&ledger.RechargeOrderPO{}).
|
||||
Joins("LEFT JOIN sys_users ON sys_users.id = live_recharge_orders.user_id").
|
||||
Joins("LEFT JOIN pay_orders ON pay_orders.business_type = ? AND pay_orders.business_id = live_recharge_orders.order_no AND pay_orders.trade_no = live_recharge_orders.order_no", biz.BusinessType)
|
||||
if f.OrderNo != "" {
|
||||
q = q.Where("live_recharge_orders.order_no = ?", f.OrderNo)
|
||||
}
|
||||
if f.UserKeyword != "" {
|
||||
v := "%" + f.UserKeyword + "%"
|
||||
q = q.Where("sys_users.username LIKE ? OR sys_users.nick_name LIKE ?", v, v)
|
||||
}
|
||||
if f.PaymentStatus != "" {
|
||||
q = q.Where("pay_orders.payment_status = ?", f.PaymentStatus)
|
||||
}
|
||||
if f.Provider != "" {
|
||||
q = q.Where("pay_orders.provider = ?", f.Provider)
|
||||
}
|
||||
if len(f.CreatedAt) == 2 {
|
||||
q = q.Where("live_recharge_orders.created_at BETWEEN ? AND ?", f.CreatedAt[0], f.CreatedAt[1])
|
||||
}
|
||||
return q
|
||||
}
|
||||
|
||||
const orderSelect = "live_recharge_orders.*,sys_users.username,sys_users.nick_name AS nickname,pay_orders.provider,pay_orders.provider_trade_no,pay_orders.payment_status,pay_orders.fulfillment_status,pay_orders.refund_status"
|
||||
|
||||
func (r *repo) List(ctx context.Context, f biz.Filter, o biz.ListOptions) ([]*biz.Order, int64, *biz.Summary, error) {
|
||||
q := query(r.db(ctx), f)
|
||||
var total int64
|
||||
if err := q.Count(&total).Error; err != nil {
|
||||
return nil, 0, nil, err
|
||||
}
|
||||
var s struct{ PaidCount, AmountCents int64 }
|
||||
if err := query(r.db(ctx), f).Select("COALESCE(SUM(CASE WHEN live_recharge_orders.credited_at IS NOT NULL THEN 1 ELSE 0 END),0) AS paid_count,COALESCE(SUM(CASE WHEN live_recharge_orders.credited_at IS NOT NULL THEN live_recharge_orders.amount_cents ELSE 0 END),0) AS amount_cents").Scan(&s).Error; err != nil {
|
||||
return nil, 0, nil, err
|
||||
}
|
||||
var rows []row
|
||||
if err := q.Select(orderSelect).Order(orderBy(o.OrderBy)).Offset(o.Offset).Limit(o.Limit).Scan(&rows).Error; err != nil {
|
||||
return nil, 0, nil, err
|
||||
}
|
||||
out := make([]*biz.Order, 0, len(rows))
|
||||
for i := range rows {
|
||||
out = append(out, toBiz(&rows[i]))
|
||||
}
|
||||
return out, total, &biz.Summary{Count: total, PaidCount: s.PaidCount, AmountCents: s.AmountCents}, nil
|
||||
}
|
||||
|
||||
func (r *repo) Get(ctx context.Context, no string) (*biz.Order, error) {
|
||||
var v row
|
||||
if err := query(r.db(ctx), biz.Filter{OrderNo: no}).Select(orderSelect).Scan(&v).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v.ID == 0 {
|
||||
return nil, biz.ErrNotFound
|
||||
}
|
||||
return toBiz(&v), nil
|
||||
}
|
||||
|
||||
func (r *repo) Create(ctx context.Context, userID, planID uint) (*biz.Order, error) {
|
||||
var plan ledger.RechargePlanPO
|
||||
if err := r.db(ctx).Where("id = ? AND enabled = ?", planID, true).First(&plan).Error; err != nil {
|
||||
return nil, biz.ErrInvalid
|
||||
}
|
||||
rate := int64(10)
|
||||
var set ledger.SettingPO
|
||||
if err := r.db(ctx).Where(&ledger.SettingPO{Key: "diamond_rate_cents"}).First(&set).Error; err == nil {
|
||||
if v, e := strconv.ParseInt(set.Value, 10, 64); e == nil {
|
||||
rate = v
|
||||
}
|
||||
}
|
||||
v := ledger.RechargeOrderPO{OrderNo: number("CZ"), UserID: userID, Diamonds: plan.Diamonds, AmountCents: plan.AmountCents, RateCents: rate}
|
||||
if err := r.db(ctx).Create(&v).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r.Get(ctx, v.OrderNo)
|
||||
}
|
||||
|
||||
func (r *repo) MarkPaid(ctx context.Context, no string) (*biz.Order, error) {
|
||||
var credited ledger.RechargeOrderPO
|
||||
err := r.db(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
var v ledger.RechargeOrderPO
|
||||
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).Where("order_no = ?", no).First(&v).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return biz.ErrNotFound
|
||||
}
|
||||
return err
|
||||
}
|
||||
if v.CreditedAt != nil {
|
||||
credited = v
|
||||
return nil
|
||||
}
|
||||
now := time.Now()
|
||||
v.CreditedAt = &now
|
||||
if err := tx.Save(&v).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
wallet := ledger.WalletPO{UserID: v.UserID}
|
||||
if err := tx.Where("user_id = ?", v.UserID).FirstOrCreate(&wallet).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Model(&wallet).Updates(map[string]any{"diamond_balance": gorm.Expr("diamond_balance + ?", v.Diamonds), "total_recharge_cents": gorm.Expr("total_recharge_cents + ?", v.AmountCents)}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
credited = v
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return toBiz(&row{RechargeOrderPO: credited}), nil
|
||||
}
|
||||
|
||||
func toBiz(v *row) *biz.Order {
|
||||
return &biz.Order{
|
||||
ID: v.ID, OrderNo: v.OrderNo, UserID: v.UserID, Username: v.Username, Nickname: v.Nickname,
|
||||
Diamonds: v.Diamonds, AmountCents: v.AmountCents, Provider: v.Provider, ProviderTradeNo: v.ProviderTradeNo,
|
||||
PaymentStatus: v.PaymentStatus, FulfillmentStatus: v.FulfillmentStatus, RefundStatus: v.RefundStatus,
|
||||
CreatedAt: v.CreatedAt, CreditedAt: v.CreditedAt,
|
||||
}
|
||||
}
|
||||
|
||||
func orderBy(v string) string {
|
||||
m := map[string]string{"diamonds_asc": "live_recharge_orders.diamonds ASC", "diamonds_desc": "live_recharge_orders.diamonds DESC", "amount_asc": "live_recharge_orders.amount_cents ASC", "amount_desc": "live_recharge_orders.amount_cents DESC", "created_at_asc": "live_recharge_orders.created_at ASC"}
|
||||
if x := m[strings.ToLower(v)]; x != "" {
|
||||
return x
|
||||
}
|
||||
return "live_recharge_orders.created_at DESC"
|
||||
}
|
||||
|
||||
func number(p string) string {
|
||||
return fmt.Sprintf("%s%s%06d", p, time.Now().Format("20060102150405"), time.Now().UnixNano()%1000000)
|
||||
}
|
||||
Reference in New Issue
Block a user