Files
2026-08-25 17:59:42 +08:00

60 lines
1.9 KiB
Go

package billing
import (
"errors"
"strconv"
"juhe-factory/api/internal/model"
"github.com/google/uuid"
"gorm.io/gorm"
)
// PrechargeGenerationTask creates a task and reserves its full quoted cost in
// the same transaction. A zero price is allowed only when the model has an
// explicit zero-price record; callers must reject a missing price record.
func PrechargeGenerationTask(tx *gorm.DB, task *model.GenerationTask, unitPrice string, quantity int, remark string) error {
price, err := strconv.ParseFloat(unitPrice, 64)
if err != nil || price < 0 || quantity <= 0 {
return errors.New("生成任务价格无效")
}
var amount string
if err := tx.Raw("SELECT round(?::numeric * ?::numeric,2)::text", unitPrice, quantity).Scan(&amount).Error; err != nil {
return err
}
if amount == "" {
return errors.New("生成任务价格无效")
}
task.EstimatedPoints = amount
task.PrepaidPoints = amount
if task.ID == uuid.Nil {
task.ID = uuid.New()
}
if amountValue, _ := strconv.ParseFloat(amount, 64); amountValue > 0 {
if _, err := DebitPoints(tx, task.UserID, amount, "generation_hold", task.ID.String(), remark, "generation:hold:"+task.ID.String()); err != nil {
return err
}
}
if err := tx.Create(task).Error; err != nil {
return err
}
return nil
}
// RefundGenerationTask refunds a prepaid task exactly once. The caller must
// hold a row lock on task inside the same transaction.
func RefundGenerationTask(tx *gorm.DB, task *model.GenerationTask, remark string) (bool, error) {
amount, _ := strconv.ParseFloat(task.PrepaidPoints, 64)
if task.CostRefunded || amount <= 0 {
return false, nil
}
refunded, err := RefundDebit(tx, task.UserID, "generation:hold:"+task.ID.String(), "generation:refund:"+task.ID.String(),
"generation_refund", task.ID.String(), remark)
if err != nil {
return false, err
}
task.CostRefunded = true
return refunded, nil
}