feat: add table for purchase
This commit is contained in:
@@ -351,6 +351,7 @@ func (s *Service) VerifyPurchase(ctx context.Context, userID int64, req Purchase
|
||||
// را بهدست آوریم؛ سپس با همان SKU خرید را تأیید میکنیم.
|
||||
var coins, tickets int64
|
||||
var vipDays int
|
||||
var priceToman int
|
||||
var booster *Booster
|
||||
var sku string
|
||||
switch req.Kind {
|
||||
@@ -359,28 +360,28 @@ func (s *Service) VerifyPurchase(ctx context.Context, userID int64, req Purchase
|
||||
if p == nil {
|
||||
return ErrNotFound
|
||||
}
|
||||
coins, vipDays, sku = p.Coins, p.VIPDays, p.SKU
|
||||
coins, vipDays, priceToman, sku = p.Coins, p.VIPDays, p.PriceToman, p.SKU
|
||||
if s.isVIP(ctx, userID) {
|
||||
coins += coins / 10 // پاداش ۱۰٪ VIP
|
||||
coins += coins / 10 // پاداش ۱۰٪ VIP (قیمت را تغییر نمیدهد)
|
||||
}
|
||||
case "ticket":
|
||||
p := s.findTicketPackage(req.ProductID)
|
||||
if p == nil {
|
||||
return ErrNotFound
|
||||
}
|
||||
tickets, sku = p.Tickets, p.SKU
|
||||
tickets, priceToman, sku = p.Tickets, p.PriceToman, p.SKU
|
||||
case "booster":
|
||||
booster = s.findBooster(req.ProductID)
|
||||
if booster == nil {
|
||||
return ErrNotFound
|
||||
}
|
||||
sku = booster.SKU
|
||||
priceToman, sku = booster.PriceToman, booster.SKU
|
||||
case "vip":
|
||||
p := s.findVIPPackage(req.ProductID)
|
||||
if p == nil {
|
||||
return ErrNotFound
|
||||
}
|
||||
vipDays, sku = p.Months*30, p.SKU // هر ماه = ۳۰ روز
|
||||
vipDays, priceToman, sku = p.Months*30, p.PriceToman, p.SKU // هر ماه = ۳۰ روز
|
||||
default:
|
||||
return ErrNotFound
|
||||
}
|
||||
@@ -407,9 +408,9 @@ func (s *Service) VerifyPurchase(ctx context.Context, userID int64, req Purchase
|
||||
|
||||
// ثبت خرید (یکتا بودن store+token ⇒ ضد دوبارهاعتبارسنجی)
|
||||
if _, err := tx.ExecContext(ctx,
|
||||
`INSERT INTO purchases (user_id, store, product_id, purchase_token, status, coins, tickets, vip_days)
|
||||
VALUES (?, ?, ?, ?, 'verified', ?, ?, ?)`,
|
||||
userID, req.Store, req.ProductID, req.Token, coins, tickets, vipDays); err != nil {
|
||||
`INSERT INTO purchases (user_id, store, product_id, purchase_token, status, coins, tickets, vip_days, kind, price_toman)
|
||||
VALUES (?, ?, ?, ?, 'verified', ?, ?, ?, ?, ?)`,
|
||||
userID, req.Store, req.ProductID, req.Token, coins, tickets, vipDays, req.Kind, priceToman); err != nil {
|
||||
if isUnique(err) {
|
||||
return ErrAlreadyOwned // قبلاً پردازش شده
|
||||
}
|
||||
|
||||
@@ -192,6 +192,16 @@ func TestPurchaseCreditsAndIdempotent(t *testing.T) {
|
||||
if c := coinsOf(t, svc, id); c != pkg.Coins {
|
||||
t.Fatalf("want %d coins, got %d", pkg.Coins, c)
|
||||
}
|
||||
// نوع و قیمتِ خرید باید ثبت شده باشند (پنلِ تراکنشها).
|
||||
var kind string
|
||||
var priceToman int
|
||||
if err := svc.db.QueryRow(`SELECT kind, price_toman FROM purchases WHERE user_id=?`, id).
|
||||
Scan(&kind, &priceToman); err != nil {
|
||||
t.Fatalf("read purchase: %v", err)
|
||||
}
|
||||
if kind != "coin" || priceToman != pkg.PriceToman {
|
||||
t.Fatalf("want kind=coin price=%d, got kind=%q price=%d", pkg.PriceToman, kind, priceToman)
|
||||
}
|
||||
// همان توکن دوباره ⇒ قبلاً پردازش شده، بدون شارژ مجدد
|
||||
if err := svc.VerifyPurchase(ctx, id, req); err != ErrAlreadyOwned {
|
||||
t.Fatalf("want ErrAlreadyOwned, got %v", err)
|
||||
|
||||
Reference in New Issue
Block a user