Files
cmautobuy/admin/repository/shop.go
T

209 lines
7.2 KiB
Go

package repository
import (
"database/sql"
"errors"
"fmt"
"strings"
"cmautobuy/admin/model"
"github.com/go-sql-driver/mysql"
)
var (
ErrShopNameExists = errors.New("店铺名称已经存在")
ErrShopAliasExists = errors.New("渠道店铺名称已经关联")
ErrShopHasReferences = errors.New("店铺仍有关联数据")
)
// ListShops 返回管理页的一店一行汇总。
func ListShops(q Execer) ([]model.Shop, error) {
rows, err := q.Query(`SELECT s.shop_id,s.display_name,s.normalized_name,s.enabled,
COUNT(DISTINCT sp.goods_id),s.created_by_user_id,s.created_at,s.updated_at
FROM shops s
LEFT JOIN shopee_products sp ON sp.shop_id=s.shop_id AND sp.deleted_at IS NULL
GROUP BY s.shop_id ORDER BY s.enabled DESC,s.normalized_name`)
if err != nil {
return nil, fmt.Errorf("查询店铺列表失败: %w", err)
}
defer rows.Close()
var result []model.Shop
for rows.Next() {
var item model.Shop
var enabled int
if err := rows.Scan(&item.ShopID, &item.DisplayName, &item.NormalizedName, &enabled,
&item.ShopeeProductCount,
&item.CreatedByUserID, &item.CreatedAt, &item.UpdatedAt); err != nil {
return nil, err
}
item.Enabled = enabled == 1
result = append(result, item)
}
return result, rows.Err()
}
func GetShop(q Execer, shopID string) (model.Shop, bool, error) {
var item model.Shop
var enabled int
err := q.QueryRow(`SELECT shop_id,display_name,normalized_name,enabled,created_by_user_id,created_at,updated_at
FROM shops WHERE shop_id=?`, shopID).Scan(&item.ShopID, &item.DisplayName,
&item.NormalizedName, &enabled, &item.CreatedByUserID, &item.CreatedAt, &item.UpdatedAt)
if errors.Is(err, sql.ErrNoRows) {
return model.Shop{}, false, nil
}
if err != nil {
return model.Shop{}, false, fmt.Errorf("查询店铺失败: %w", err)
}
item.Enabled = enabled == 1
return item, true, nil
}
// ListEnabledSybShopMappings 返回“店铺精确名称 → 店铺 ID”。
func ListEnabledSybShopMappings(q Execer) (map[string]string, error) {
rows, err := q.Query(`SELECT normalized_name,shop_id FROM shops WHERE enabled=1 ORDER BY normalized_name`)
if err != nil {
return nil, fmt.Errorf("查询启用的 SYB 店铺配置失败: %w", err)
}
defer rows.Close()
result := map[string]string{}
for rows.Next() {
var name, shopID string
if err := rows.Scan(&name, &shopID); err != nil {
return nil, err
}
result[name] = shopID
}
return result, rows.Err()
}
func FindShopIDByName(q Execer, rawName string) (string, error) {
name := strings.TrimSpace(rawName)
if name == "" {
return "", nil
}
var shopID string
err := q.QueryRow(`SELECT shop_id FROM shops WHERE normalized_name=?`, name).Scan(&shopID)
if errors.Is(err, sql.ErrNoRows) {
return "", nil
}
if err != nil {
return "", fmt.Errorf("按店铺名称查询店铺失败: %w", err)
}
return shopID, nil
}
func InsertShop(q Execer, item model.Shop) error {
_, err := q.Exec(`INSERT INTO shops(shop_id,display_name,normalized_name,enabled,created_by_user_id,created_at,updated_at)
VALUES(?,?,?,?,?,?,?)`, item.ShopID, item.DisplayName, item.NormalizedName, item.Enabled,
item.CreatedByUserID, item.CreatedAt, item.UpdatedAt)
if err != nil {
var mysqlErr *mysql.MySQLError
if errors.As(err, &mysqlErr) && mysqlErr.Number == 1062 {
return ErrShopNameExists
}
return fmt.Errorf("新增店铺失败: %w", err)
}
return nil
}
func InsertShopAlias(q Execer, item model.ShopChannelAlias) error {
_, err := q.Exec(`INSERT INTO shop_channel_aliases(alias_id,shop_id,channel,alias_name,normalized_alias,enabled,created_at,updated_at)
VALUES(?,?,?,?,?,?,?,?)`, item.AliasID, item.ShopID, item.Channel, item.AliasName,
item.NormalizedAlias, item.Enabled, item.CreatedAt, item.UpdatedAt)
if err != nil {
var mysqlErr *mysql.MySQLError
if errors.As(err, &mysqlErr) && mysqlErr.Number == 1062 {
return ErrShopAliasExists
}
return fmt.Errorf("新增渠道店铺名称失败: %w", err)
}
return nil
}
func UpdateShopName(q Execer, shopID, displayName, normalizedName, updatedAt string) (bool, error) {
result, err := q.Exec(`UPDATE shops SET display_name=?,normalized_name=?,updated_at=? WHERE shop_id=?`,
displayName, normalizedName, updatedAt, shopID)
if err != nil {
var mysqlErr *mysql.MySQLError
if errors.As(err, &mysqlErr) && mysqlErr.Number == 1062 {
return false, ErrShopNameExists
}
return false, fmt.Errorf("更新店铺名称失败: %w", err)
}
n, err := result.RowsAffected()
return n == 1, err
}
func SetShopEnabled(q Execer, shopID string, enabled bool, updatedAt string) (bool, error) {
result, err := q.Exec(`UPDATE shops SET enabled=?,updated_at=? WHERE shop_id=?`, enabled, updatedAt, shopID)
if err != nil {
return false, fmt.Errorf("更新店铺状态失败: %w", err)
}
n, err := result.RowsAffected()
return n == 1, err
}
func SetShopCompatibilityAliasesEnabled(q Execer, shopID string, enabled bool, updatedAt string) error {
_, err := q.Exec(`UPDATE shop_channel_aliases SET enabled=?,updated_at=? WHERE shop_id=?`, enabled, updatedAt, shopID)
if err != nil {
return fmt.Errorf("同步店铺兼容数据状态失败: %w", err)
}
return nil
}
func ReplaceShopAlias(q Execer, aliasID, shopID, channel, aliasName, updatedAt string, enabled bool) error {
if _, err := q.Exec(`DELETE FROM shop_channel_aliases WHERE shop_id=? AND channel=?`, shopID, channel); err != nil {
return fmt.Errorf("移除旧渠道店铺名称失败: %w", err)
}
if strings.TrimSpace(aliasName) == "" {
return nil
}
return InsertShopAlias(q, model.ShopChannelAlias{AliasID: aliasID, ShopID: shopID, Channel: channel,
AliasName: aliasName, NormalizedAlias: strings.TrimSpace(aliasName), Enabled: enabled,
CreatedAt: updatedAt, UpdatedAt: updatedAt})
}
// RebuildShopAssociations 按唯一店铺名称精确重建一个店铺的派生关联。
func RebuildShopAssociations(q Execer, shopID string) error {
if _, err := q.Exec(`UPDATE syb_orders SET shop_id=NULL WHERE shop_id=?`, shopID); err != nil {
return err
}
if _, err := q.Exec(`UPDATE shopee_products SET shop_id=NULL WHERE shop_id=?`, shopID); err != nil {
return err
}
if _, err := q.Exec(`UPDATE syb_orders so JOIN shops s
ON s.shop_id=? AND s.normalized_name=TRIM(so.shop_name) COLLATE utf8mb4_bin
SET so.shop_id=s.shop_id`, shopID); err != nil {
return err
}
if _, err := q.Exec(`UPDATE shopee_products sp JOIN shops s
ON s.shop_id=? AND s.normalized_name=TRIM(sp.shopee_shop_name) COLLATE utf8mb4_bin
SET sp.shop_id=s.shop_id`, shopID); err != nil {
return err
}
return nil
}
func DeleteDisabledShop(q Execer, shopID string) (bool, error) {
var references int
if err := q.QueryRow(`SELECT (SELECT COUNT(*) FROM syb_orders WHERE shop_id=?)+
(SELECT COUNT(*) FROM shopee_products WHERE shop_id=?)`, shopID, shopID).Scan(&references); err != nil {
return false, err
}
if references > 0 {
return false, ErrShopHasReferences
}
result, err := q.Exec(`DELETE FROM shops WHERE shop_id=? AND enabled=0`, shopID)
if err != nil {
return false, fmt.Errorf("删除停用店铺失败: %w", err)
}
n, err := result.RowsAffected()
return n == 1, err
}
func CountUnlinkedShopeeShops(q Execer) (int, error) {
var count int
err := q.QueryRow(`SELECT COUNT(*) FROM shopee_products WHERE deleted_at IS NULL AND shop_id IS NULL`).Scan(&count)
return count, err
}