@@ -0,0 +1,146 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"daili/internal/domain"
|
||||
)
|
||||
|
||||
// Package 服务套餐。
|
||||
type Package struct {
|
||||
ID int64
|
||||
Name string
|
||||
Unit string
|
||||
DefaultAmount int
|
||||
PriceCents int
|
||||
HasPrice bool
|
||||
Color string
|
||||
Note string
|
||||
Archived bool
|
||||
SortOrder int
|
||||
CreatedAt string
|
||||
UpdatedAt string
|
||||
SubCount int
|
||||
ActiveCount int
|
||||
}
|
||||
|
||||
// UnitLabel 返回类型中文名。
|
||||
func (p *Package) UnitLabel() string {
|
||||
if p.Unit == domain.UnitCount {
|
||||
return "按次"
|
||||
}
|
||||
return "按日"
|
||||
}
|
||||
|
||||
func scanPackage(row interface{ Scan(dest ...any) error }) (*Package, error) {
|
||||
var p Package
|
||||
var price sql.NullInt64
|
||||
var archived int
|
||||
err := row.Scan(&p.ID, &p.Name, &p.Unit, &p.DefaultAmount, &price, &p.Color, &p.Note,
|
||||
&archived, &p.SortOrder, &p.CreatedAt, &p.UpdatedAt)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
p.Archived = archived == 1
|
||||
if price.Valid {
|
||||
p.PriceCents = int(price.Int64)
|
||||
p.HasPrice = true
|
||||
}
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
// ListPackages 列出套餐(含订阅计数)。
|
||||
func (db *DB) ListPackages(includeArchived bool) ([]Package, error) {
|
||||
q := `SELECT p.id,p.name,p.unit,p.default_amount,p.price_cents,p.color,p.note,p.archived,p.sort_order,p.created_at,p.updated_at,
|
||||
(SELECT COUNT(*) FROM subscriptions s WHERE s.package_id=p.id),
|
||||
(SELECT COUNT(*) FROM subscriptions s WHERE s.package_id=p.id AND s.status<>'closed')
|
||||
FROM packages p`
|
||||
if !includeArchived {
|
||||
q += ` WHERE p.archived=0`
|
||||
}
|
||||
q += ` ORDER BY p.archived, p.sort_order, p.id`
|
||||
rows, err := db.sql.Query(q)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
out := []Package{}
|
||||
for rows.Next() {
|
||||
var p Package
|
||||
var price sql.NullInt64
|
||||
var archived int
|
||||
if err := rows.Scan(&p.ID, &p.Name, &p.Unit, &p.DefaultAmount, &price, &p.Color, &p.Note,
|
||||
&archived, &p.SortOrder, &p.CreatedAt, &p.UpdatedAt, &p.SubCount, &p.ActiveCount); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.Archived = archived == 1
|
||||
if price.Valid {
|
||||
p.PriceCents = int(price.Int64)
|
||||
p.HasPrice = true
|
||||
}
|
||||
out = append(out, p)
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
// Package 取单个套餐。
|
||||
func (db *DB) Package(id int64) (*Package, error) {
|
||||
return scanPackage(db.sql.QueryRow(`SELECT id,name,unit,default_amount,price_cents,color,note,archived,sort_order,created_at,updated_at
|
||||
FROM packages WHERE id=?`, id))
|
||||
}
|
||||
|
||||
// CreatePackage 新建套餐。
|
||||
func (db *DB) CreatePackage(p *Package) (int64, error) {
|
||||
now := nowStamp()
|
||||
p.Unit = normalizeUnit(p.Unit)
|
||||
if p.DefaultAmount <= 0 {
|
||||
p.DefaultAmount = 30
|
||||
}
|
||||
if strings.TrimSpace(p.Color) == "" {
|
||||
p.Color = "#2F5D50"
|
||||
}
|
||||
var price any
|
||||
if p.HasPrice {
|
||||
price = p.PriceCents
|
||||
}
|
||||
res, err := db.sql.Exec(`INSERT INTO packages(name,unit,default_amount,price_cents,color,note,archived,sort_order,created_at,updated_at)
|
||||
VALUES(?,?,?,?,?,?,0,?,?,?)`,
|
||||
p.Name, p.Unit, p.DefaultAmount, price, p.Color, p.Note, p.SortOrder, now, now)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return res.LastInsertId()
|
||||
}
|
||||
|
||||
// UpdatePackage 更新套餐。
|
||||
func (db *DB) UpdatePackage(p *Package) error {
|
||||
p.Unit = normalizeUnit(p.Unit)
|
||||
if p.DefaultAmount <= 0 {
|
||||
p.DefaultAmount = 30
|
||||
}
|
||||
if strings.TrimSpace(p.Color) == "" {
|
||||
p.Color = "#2F5D50"
|
||||
}
|
||||
var price any
|
||||
if p.HasPrice {
|
||||
price = p.PriceCents
|
||||
}
|
||||
_, err := db.sql.Exec(`UPDATE packages SET name=?,unit=?,default_amount=?,price_cents=?,color=?,note=?,sort_order=?,updated_at=?
|
||||
WHERE id=?`, p.Name, p.Unit, p.DefaultAmount, price, p.Color, p.Note, p.SortOrder, nowStamp(), p.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
// SetPackageArchived 归档/取消归档。
|
||||
func (db *DB) SetPackageArchived(id int64, archived bool) error {
|
||||
v := 0
|
||||
if archived {
|
||||
v = 1
|
||||
}
|
||||
_, err := db.sql.Exec(`UPDATE packages SET archived=?, updated_at=? WHERE id=?`, v, nowStamp(), id)
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user