+24
-99
@@ -12,100 +12,10 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/go-sql-driver/mysql"
|
||||
|
||||
"cmautobuy/admin/model"
|
||||
"cmautobuy/admin/spec"
|
||||
)
|
||||
|
||||
var ErrSybAllowedShopExists = errors.New("顺运宝允许店铺已经存在")
|
||||
|
||||
// ListSybAllowedShops 返回全部准入项;管理页需要同时看到已停用项。
|
||||
func ListSybAllowedShops(q Execer) ([]model.SybAllowedShop, error) {
|
||||
rows, err := q.Query(`SELECT shop_id,shop_name,normalized_name,enabled,created_by_user_id,created_at,updated_at
|
||||
FROM syb_allowed_shops ORDER BY enabled DESC,normalized_name`)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询顺运宝允许店铺失败: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
var result []model.SybAllowedShop
|
||||
for rows.Next() {
|
||||
var item model.SybAllowedShop
|
||||
var enabled int
|
||||
if err := rows.Scan(&item.ShopID, &item.ShopName, &item.NormalizedName, &enabled,
|
||||
&item.CreatedByUserID, &item.CreatedAt, &item.UpdatedAt); err != nil {
|
||||
return nil, fmt.Errorf("读取顺运宝允许店铺失败: %w", err)
|
||||
}
|
||||
item.Enabled = enabled == 1
|
||||
result = append(result, item)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, fmt.Errorf("读取顺运宝允许店铺失败: %w", err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func ListEnabledSybShopNames(q Execer) ([]string, error) {
|
||||
rows, err := q.Query(`SELECT normalized_name FROM syb_allowed_shops WHERE enabled=1 ORDER BY normalized_name`)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询启用的顺运宝店铺失败: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
var names []string
|
||||
for rows.Next() {
|
||||
var name string
|
||||
if err := rows.Scan(&name); err != nil {
|
||||
return nil, fmt.Errorf("读取启用的顺运宝店铺失败: %w", err)
|
||||
}
|
||||
names = append(names, name)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, fmt.Errorf("读取启用的顺运宝店铺失败: %w", err)
|
||||
}
|
||||
return names, nil
|
||||
}
|
||||
|
||||
func InsertSybAllowedShop(q Execer, item model.SybAllowedShop) error {
|
||||
_, err := q.Exec(`INSERT INTO syb_allowed_shops
|
||||
(shop_id,shop_name,normalized_name,enabled,created_by_user_id,created_at,updated_at)
|
||||
VALUES(?,?,?,?,?,?,?)`, item.ShopID, item.ShopName, 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 ErrSybAllowedShopExists
|
||||
}
|
||||
return fmt.Errorf("新增顺运宝允许店铺失败: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetSybAllowedShopEnabled(q Execer, shopID string, enabled bool, updatedAt string) (bool, error) {
|
||||
result, err := q.Exec(`UPDATE syb_allowed_shops SET enabled=?,updated_at=? WHERE shop_id=?`, enabled, updatedAt, shopID)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("更新顺运宝允许店铺失败: %w", err)
|
||||
}
|
||||
affected, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("确认顺运宝允许店铺更新结果失败: %w", err)
|
||||
}
|
||||
return affected == 1, nil
|
||||
}
|
||||
|
||||
// DeleteDisabledSybAllowedShop 只删除提交瞬间仍处于停用状态的配置项。
|
||||
// enabled 条件是最终并发保护,不能只依赖管理页隐藏启用项的删除按钮。
|
||||
func DeleteDisabledSybAllowedShop(q Execer, shopID string) (bool, error) {
|
||||
result, err := q.Exec(`DELETE FROM syb_allowed_shops WHERE shop_id=? AND enabled=0`, shopID)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("删除已停用的顺运宝店铺失败: %w", err)
|
||||
}
|
||||
affected, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("确认顺运宝店铺删除结果失败: %w", err)
|
||||
}
|
||||
return affected == 1, nil
|
||||
}
|
||||
|
||||
// ---------- 会话缓存 ----------
|
||||
|
||||
// SaveSybSession 写入或更新顺运宝登录会话缓存(按用户名 upsert)。
|
||||
@@ -333,6 +243,12 @@ func UpsertSybOrder(q Execer, o model.SybOrder) (created bool, err error) {
|
||||
if o.SybID == "" {
|
||||
return false, fmt.Errorf("syb_id 不能为空")
|
||||
}
|
||||
if strings.TrimSpace(o.ShopID) == "" && strings.TrimSpace(o.ShopName) != "" {
|
||||
o.ShopID, err = FindShopIDByAlias(q, "syb", o.ShopName)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("解析顺运宝明细 %s 的业务店铺失败: %w", o.SybID, err)
|
||||
}
|
||||
}
|
||||
var specKey any
|
||||
if strings.TrimSpace(o.ProductSpec) != "" {
|
||||
key, keyErr := spec.SpecKey(o.ProductSpec)
|
||||
@@ -353,17 +269,18 @@ func UpsertSybOrder(q Execer, o model.SybOrder) (created bool, err error) {
|
||||
|
||||
now := model.NowISO()
|
||||
if strings.TrimSpace(o.ShopeeGoodsID) != "" {
|
||||
if err := upsertSybShopeeProduct(q, o.ShopeeGoodsID, o.Title, o.ShopName, o.ImageURL, now); err != nil {
|
||||
if err := upsertSybShopeeProduct(q, o.ShopeeGoodsID, o.ShopID, o.Title, o.ShopName, o.ImageURL, now); err != nil {
|
||||
return false, fmt.Errorf("为顺运宝明细 %s 补建蝦皮商品骨架失败: %w", o.SybID, err)
|
||||
}
|
||||
}
|
||||
_, err = q.Exec(`
|
||||
INSERT INTO syb_orders
|
||||
(syb_id, order_no, shop_name, title, product_spec, spec_key, shopee_goods_id,
|
||||
(syb_id, order_no, shop_id, shop_name, title, product_spec, spec_key, shopee_goods_id,
|
||||
quantity, price_twd_cent, image_url, syb_data, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
VALUES (?, ?, NULLIF(?,''), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
order_no = VALUES(order_no),
|
||||
shop_id = VALUES(shop_id),
|
||||
shop_name = VALUES(shop_name),
|
||||
title = VALUES(title),
|
||||
product_spec = VALUES(product_spec),
|
||||
@@ -374,7 +291,7 @@ func UpsertSybOrder(q Execer, o model.SybOrder) (created bool, err error) {
|
||||
image_url = VALUES(image_url),
|
||||
syb_data = VALUES(syb_data),
|
||||
updated_at = VALUES(updated_at)`,
|
||||
o.SybID, o.OrderNo, nullableText(o.ShopName), o.Title, nullableText(o.ProductSpec), specKey, nullableText(o.ShopeeGoodsID),
|
||||
o.SybID, o.OrderNo, strings.TrimSpace(o.ShopID), nullableText(o.ShopName), o.Title, nullableText(o.ProductSpec), specKey, nullableText(o.ShopeeGoodsID),
|
||||
o.Quantity, o.PriceTwdCent, nullableText(o.ImageURL),
|
||||
o.SybData, now, now)
|
||||
if err != nil {
|
||||
@@ -387,20 +304,24 @@ func UpsertSybOrder(q Execer, o model.SybOrder) (created bool, err error) {
|
||||
//
|
||||
// 店铺和图片是字段级低优先级数据:只能补空值,或更新原本同样来自 syb 的值;
|
||||
// 人工字段和商品目录等权威来源永远不被顺运宝覆盖。空值也不能清除已有内容。
|
||||
func upsertSybShopeeProduct(q Execer, goodsID, title, shopName, imageURL, observedAt string) error {
|
||||
func upsertSybShopeeProduct(q Execer, goodsID, shopID, title, shopName, imageURL, observedAt string) error {
|
||||
_, err := q.Exec(`
|
||||
INSERT INTO shopee_products
|
||||
(goods_id,title,image_url,shopee_shop_name,
|
||||
(goods_id,shop_id,title,image_url,shopee_shop_name,
|
||||
image_source,image_observed_at,image_is_manual,
|
||||
shop_name_source,shop_name_observed_at,shop_name_is_manual,
|
||||
source,source_observed_at,created_at,updated_at)
|
||||
VALUES (?, ?, NULLIF(TRIM(?),''), NULLIF(TRIM(?),''),
|
||||
VALUES (?, NULLIF(TRIM(?),''), ?, NULLIF(TRIM(?),''), NULLIF(TRIM(?),''),
|
||||
CASE WHEN TRIM(?)='' THEN NULL ELSE 'syb' END,
|
||||
CASE WHEN TRIM(?)='' THEN NULL ELSE ? END, 0,
|
||||
CASE WHEN TRIM(?)='' THEN NULL ELSE 'syb' END,
|
||||
CASE WHEN TRIM(?)='' THEN NULL ELSE ? END, 0,
|
||||
'syb', ?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
shop_id = CASE
|
||||
WHEN VALUES(shop_id) IS NOT NULL AND (shop_id IS NULL OR shop_name_source='syb') THEN VALUES(shop_id)
|
||||
ELSE shop_id
|
||||
END,
|
||||
title = CASE
|
||||
WHEN source='syb' AND TRIM(VALUES(title))<>'' THEN VALUES(title)
|
||||
ELSE title
|
||||
@@ -445,7 +366,7 @@ func upsertSybShopeeProduct(q Execer, goodsID, title, shopName, imageURL, observ
|
||||
OR (shop_name_source='syb' AND TRIM(VALUES(shopee_shop_name))<>'') THEN VALUES(updated_at)
|
||||
ELSE updated_at
|
||||
END`,
|
||||
goodsID, title, imageURL, shopName,
|
||||
goodsID, shopID, title, imageURL, shopName,
|
||||
imageURL, imageURL, observedAt,
|
||||
shopName, shopName, observedAt,
|
||||
observedAt, observedAt, observedAt)
|
||||
@@ -490,7 +411,11 @@ func backfillSybProductMetadata(db *sql.DB) error {
|
||||
return fmt.Errorf("读取历史顺运宝图片失败: %w", err)
|
||||
}
|
||||
for goodsID, item := range items {
|
||||
if err := upsertSybShopeeProduct(db, goodsID, "", item.shopName, item.imageURL, item.observedAt); err != nil {
|
||||
shopID, err := FindShopIDByAlias(db, "syb", item.shopName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("解析历史顺运宝店铺失败: %w", err)
|
||||
}
|
||||
if err := upsertSybShopeeProduct(db, goodsID, shopID, "", item.shopName, item.imageURL, item.observedAt); err != nil {
|
||||
return fmt.Errorf("回填蝦皮商品 %s 的顺运宝元数据失败: %w", goodsID, err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user