feat: 支付订单/会员/回调日志 DAO

This commit is contained in:
2026-07-31 13:23:17 +08:00
parent 985abaf91b
commit ff8047c8b3
3 changed files with 163 additions and 0 deletions
+38
View File
@@ -0,0 +1,38 @@
package dao
import (
"context"
"slogan-agent/styleagent/consts"
"slogan-agent/styleagent/model/entity"
"github.com/gogf/gf/v2/frame/g"
)
var PayNotifyLog = &payNotifyLogDao{}
type payNotifyLogDao struct{}
func init() {
ctx := context.Background()
_, err := g.DB().Exec(ctx, `CREATE TABLE IF NOT EXISTS `+consts.TableNamePayNotifyLog+` (
id INTEGER PRIMARY KEY AUTOINCREMENT,
order_no TEXT NOT NULL DEFAULT '',
body TEXT NOT NULL DEFAULT '',
sign TEXT NOT NULL DEFAULT '',
remote_ip TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL DEFAULT 'ok',
created_at DATETIME DEFAULT (datetime('now','localtime'))
)`)
if err != nil {
g.Log().Warningf(ctx, "create pay_notify_log table failed: %v", err)
}
}
func (d *payNotifyLogDao) Insert(ctx context.Context, log *entity.PayNotifyLog) error {
_, err := g.DB().Model(consts.TableNamePayNotifyLog).Ctx(ctx).Data(g.Map{
"order_no": log.OrderNo, "body": log.Body, "sign": log.Sign,
"remote_ip": log.RemoteIp, "status": log.Status,
}).Insert()
return err
}
+72
View File
@@ -0,0 +1,72 @@
package dao
import (
"context"
"slogan-agent/styleagent/consts"
"slogan-agent/styleagent/model/entity"
"github.com/gogf/gf/v2/frame/g"
)
var PaymentOrder = &paymentOrderDao{}
type paymentOrderDao struct{}
func init() {
ctx := context.Background()
_, err := g.DB().Exec(ctx, `CREATE TABLE IF NOT EXISTS `+consts.TableNamePaymentOrder+` (
id INTEGER PRIMARY KEY AUTOINCREMENT,
order_no TEXT NOT NULL UNIQUE,
user_id INTEGER NOT NULL DEFAULT 0,
plan_id INTEGER NOT NULL DEFAULT 0,
amount_fen INTEGER NOT NULL DEFAULT 0,
channel TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL DEFAULT 'pending',
trade_no TEXT NOT NULL DEFAULT '',
notify_raw TEXT NOT NULL DEFAULT '',
paid_at DATETIME,
created_at DATETIME DEFAULT (datetime('now','localtime'))
)`)
if err != nil {
g.Log().Warningf(ctx, "create payment_order table failed: %v", err)
}
_, _ = g.DB().Exec(ctx, `CREATE INDEX IF NOT EXISTS idx_payment_order_user ON `+consts.TableNamePaymentOrder+`(user_id, created_at)`)
}
func (d *paymentOrderDao) Insert(ctx context.Context, order *entity.PaymentOrder) (int64, error) {
r, err := g.DB().Model(consts.TableNamePaymentOrder).Ctx(ctx).Data(g.Map{
"order_no": order.OrderNo, "user_id": order.UserId, "plan_id": order.PlanId,
"amount_fen": order.AmountFen, "channel": order.Channel, "status": order.Status,
}).Insert()
if err != nil {
return 0, err
}
return r.LastInsertId()
}
func (d *paymentOrderDao) GetByOrderNo(ctx context.Context, orderNo string) (*entity.PaymentOrder, error) {
var o *entity.PaymentOrder
err := g.DB().Model(consts.TableNamePaymentOrder).Ctx(ctx).
Where("order_no", orderNo).Scan(&o)
return o, err
}
// MarkPaid 状态机 pending→paid(只更新 pending 行,返回是否成功,回调并发安全)
func (d *paymentOrderDao) MarkPaid(ctx context.Context, orderNo, tradeNo, notifyRaw string) (bool, error) {
r, err := g.DB().Exec(ctx,
"UPDATE "+consts.TableNamePaymentOrder+" SET status=?, trade_no=?, notify_raw=?, paid_at=datetime('now','localtime') WHERE order_no=? AND status=?",
consts.PayStatusPaid, tradeNo, notifyRaw, orderNo, consts.PayStatusPending)
if err != nil {
return false, err
}
n, _ := r.RowsAffected()
return n > 0, nil
}
func (d *paymentOrderDao) GetByUser(ctx context.Context, userId int64) ([]*entity.PaymentOrder, error) {
var list []*entity.PaymentOrder
err := g.DB().Model(consts.TableNamePaymentOrder).Ctx(ctx).
Where("user_id", userId).OrderDesc("id").Limit(20).Scan(&list)
return list, err
}
+53
View File
@@ -0,0 +1,53 @@
package dao
import (
"context"
"slogan-agent/styleagent/consts"
"slogan-agent/styleagent/model/entity"
"github.com/gogf/gf/v2/frame/g"
)
var UserMember = &userMemberDao{}
type userMemberDao struct{}
func init() {
ctx := context.Background()
_, err := g.DB().Exec(ctx, `CREATE TABLE IF NOT EXISTS `+consts.TableNameUserMember+` (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL UNIQUE,
plan_id INTEGER NOT NULL DEFAULT 0,
expire_at DATETIME,
source TEXT NOT NULL DEFAULT 'vip_pay',
created_at DATETIME DEFAULT (datetime('now','localtime')),
updated_at DATETIME
)`)
if err != nil {
g.Log().Warningf(ctx, "create user_member table failed: %v", err)
}
}
func (d *userMemberDao) GetByUser(ctx context.Context, userId int64) (*entity.UserMember, error) {
var m *entity.UserMember
err := g.DB().Model(consts.TableNameUserMember).Ctx(ctx).
Where("user_id", userId).Scan(&m)
return m, err
}
// Upsert 无则插入有则整体覆盖(expire_at 由 Service 算好传入)
func (d *userMemberDao) Upsert(ctx context.Context, userId, planId int64, expireAt, source string) error {
_, err := g.DB().Exec(ctx,
"INSERT INTO "+consts.TableNameUserMember+" (user_id, plan_id, expire_at, source, created_at, updated_at) VALUES (?, ?, ?, ?, datetime('now','localtime'), datetime('now','localtime')) "+
"ON CONFLICT(user_id) DO UPDATE SET plan_id=excluded.plan_id, expire_at=excluded.expire_at, source=excluded.source, updated_at=datetime('now','localtime')",
userId, planId, expireAt, source)
return err
}
// IsVip 当前是否会员(未过期)
func (d *userMemberDao) IsVip(ctx context.Context, userId int64) bool {
n, err := g.DB().Model(consts.TableNameUserMember).Ctx(ctx).
Where("user_id", userId).Where("expire_at > datetime('now','localtime')").Count()
return err == nil && n > 0
}