diff --git a/styleagent/dao/pay_notify_log_dao.go b/styleagent/dao/pay_notify_log_dao.go new file mode 100644 index 0000000..f70b115 --- /dev/null +++ b/styleagent/dao/pay_notify_log_dao.go @@ -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 +} diff --git a/styleagent/dao/payment_order_dao.go b/styleagent/dao/payment_order_dao.go new file mode 100644 index 0000000..0c06fc8 --- /dev/null +++ b/styleagent/dao/payment_order_dao.go @@ -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 +} diff --git a/styleagent/dao/user_member_dao.go b/styleagent/dao/user_member_dao.go new file mode 100644 index 0000000..aa42150 --- /dev/null +++ b/styleagent/dao/user_member_dao.go @@ -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 +}