You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
488 lines
14 KiB
488 lines
14 KiB
package service
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/spf13/cast"
|
|
"gorm.io/gorm"
|
|
|
|
"bkb-seller/global"
|
|
"bkb-seller/model"
|
|
"bkb-seller/model/request"
|
|
"bkb-seller/model/response"
|
|
"bkb-seller/utils"
|
|
)
|
|
|
|
func GetTbGoods(uuid string, id uint) (error, model.TbGoodsDetail) {
|
|
var (
|
|
err error
|
|
result model.TbGoodsDetail
|
|
)
|
|
err = global.MG_DB.Table("tb_goods").Select("id,category_id,title,title_eng,images,content,content_text,retail_price,stock,sales,tags,online,created_at,updated_at").Where("create_by = ? AND id = ?", uuid, id).
|
|
Preload("Specs", func(db *gorm.DB) *gorm.DB {
|
|
return db.Select("id,goods_id,specs,sku_no,stock,price,image,goods_no").Where("status = 1")
|
|
}).First(&result).Error
|
|
if err != nil {
|
|
return err, result
|
|
}
|
|
for i := 0; i < len(result.Specs); i++ {
|
|
err = json.Unmarshal([]byte(result.Specs[i].Specs), &result.Specs[i].Attributes)
|
|
if err != nil {
|
|
return err, result
|
|
}
|
|
}
|
|
_, result.Breadcrumb = GetTbCategoryBreadcrumb(result.CategoryId) // 获取分类面包屑
|
|
return nil, result
|
|
}
|
|
|
|
func GetTbGoodsList(info request.SearchTbGoods) (err error, list any, total int64) {
|
|
limit := info.PageSize
|
|
offset := info.PageSize * (info.Page - 1)
|
|
db := global.MG_DB.Model(&model.TbGoods{}).Where("create_by = ?", info.CreateBy)
|
|
if info.SpuNo != "" {
|
|
db = db.Where("spu_no = ?", info.SpuNo)
|
|
}
|
|
if info.Title != "" {
|
|
db = db.Where("title LIKE ?", "%"+info.Title+"%")
|
|
}
|
|
if info.Status == 1 { // 在售中
|
|
db = db.Where("stock > 0 AND online = 'on'")
|
|
} else if info.Status == 2 { // 已下架
|
|
db = db.Where("online = 'off'")
|
|
} else if info.Status == 3 { // 已售罄
|
|
db = db.Where("stock <= 0")
|
|
}
|
|
err = db.Count(&total).Error
|
|
var res []model.TbGoods4List
|
|
err = db.Select("id,spu_no,title,title_eng,images,retail_price,price_min,price_max,stock,sales,online,created_at,updated_at").Order("id DESC").Limit(limit).Offset(offset).Find(&res).Error
|
|
if err != nil {
|
|
return err, nil, 0
|
|
}
|
|
var ids []uint
|
|
for i := 0; i < len(res); i++ {
|
|
ids = append(ids, res[i].ID)
|
|
if res[i].Online == "on" {
|
|
if res[i].Stock == 0 {
|
|
res[i].Status = 3
|
|
} else {
|
|
res[i].Status = 1
|
|
}
|
|
} else { // 下架
|
|
res[i].Status = 2
|
|
}
|
|
// res[i].CreatedAtUnix = res[i].CreatedAt.Unix()
|
|
// res[i].UpdatedAtUnix = res[i].UpdatedAt.Unix()
|
|
}
|
|
if len(ids) != 0 {
|
|
// 计算30天销量
|
|
endTime, _ := time.Parse(utils.DateFormat, utils.GetNow().Format(utils.DateFormat))
|
|
startTime := endTime.AddDate(0, 0, -29)
|
|
countMap := batchGetGoodsOrderCount(info.CreateBy, ids, &startTime, &endTime)
|
|
for i := 0; i < len(res); i++ {
|
|
if val, ok := countMap[res[i].ID]; ok {
|
|
res[i].Sales30 = val
|
|
}
|
|
}
|
|
}
|
|
return err, res, total
|
|
}
|
|
|
|
func CreateTbGoodsSeries(uuid, storeNo string, info request.CreateTbGoods) (id uint,spuNo string,err error) {
|
|
// check attributes
|
|
// code := makeCode(int(goodsId), specValues)
|
|
// newSpecs, _ := json.Marshal(specValues)
|
|
imgs := strings.Split(info.Images, ",")
|
|
var goods model.TbGoods
|
|
tx := global.MG_DB.Begin()
|
|
if goods.SpuNo == "" {
|
|
goods.SpuNo = utils.GetCurrentTimeStr()
|
|
}
|
|
goods.StoreNo = storeNo
|
|
goods.CategoryId = info.CategoryId
|
|
goods.Title = info.Title
|
|
goods.TitleEng = info.TitleEng
|
|
goods.Images = info.Images
|
|
goods.Content = info.Content
|
|
goods.ContentText = info.ContentText
|
|
goods.RetailPrice = info.RetailPrice
|
|
goods.Sales = 0
|
|
goods.Views = 0
|
|
goods.Favourites = 0
|
|
goods.Tags = info.Tags
|
|
goods.Online = info.Online
|
|
goods.CreateBy = uuid
|
|
goods.Cover = imgs[0]
|
|
err = tx.Model(&model.TbGoods{}).Create(&goods).Error
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return 0,"",err
|
|
}
|
|
var specs []model.TbGoodsSpecs
|
|
for i := 0; i < len(info.Specs); i++ {
|
|
var spec model.TbGoodsSpecs
|
|
spec.GoodsId = goods.ID
|
|
spec.SkuNo = utils.GetCurrentTimeStr()
|
|
specValues, _ := ToSpecValues(info.Specs[i].Attributes)
|
|
code := makeCode(goods.ID, specValues)
|
|
attribute, _ := json.Marshal(specValues)
|
|
// attribute, _ := json.Marshal(info.Specs[i].Attributes)
|
|
spec.Code = code
|
|
spec.Specs = string(attribute)
|
|
spec.Stock = info.Specs[i].Stock
|
|
spec.Price = info.Specs[i].Price
|
|
spec.CreateBy = uuid
|
|
spec.StoreNo = storeNo
|
|
if info.Specs[i].Image == "" {
|
|
spec.Image = "https://minio.sumweal.com/nft/221109/Ddvz989FB85u31TToa2xUT8WeYZ5q2g0678GGPRx7NXKM11F1U.png"
|
|
} else {
|
|
spec.Image = info.Specs[i].Image
|
|
}
|
|
spec.GoodsNo = info.Specs[i].GoodsNo
|
|
spec.Status = 1
|
|
goods.Stock += info.Specs[i].Stock
|
|
if goods.PriceMin == 0 || goods.PriceMin > info.Specs[i].Price { // 获取最低规格价格
|
|
goods.PriceMin = info.Specs[i].Price
|
|
}
|
|
if goods.PriceMax == 0 || goods.PriceMax < info.Specs[i].Price { // 获取最高规格价格
|
|
goods.PriceMax = info.Specs[i].Price
|
|
}
|
|
specs = append(specs, spec)
|
|
}
|
|
if len(specs) != 0 {
|
|
err = tx.Model(&model.TbGoodsSpecs{}).Create(&specs).Error
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return 0,"",err
|
|
}
|
|
}
|
|
goods.ListPrice = goods.PriceMin
|
|
err = tx.Model(&model.TbGoods{}).Where("id = ?", goods.ID).UpdateColumns(map[string]any{"stock": goods.Stock, "list_price": goods.ListPrice, "price_min": goods.PriceMin, "price_max": goods.PriceMax}).Error
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return 0,"",err
|
|
}
|
|
tx.Commit()
|
|
id = goods.ID
|
|
return id, goods.SpuNo, nil
|
|
}
|
|
|
|
func UpdateTbGoodsSeries(uuid string, info request.UpdateTbGoods) (err error, id uint) {
|
|
var (
|
|
tmp, goods model.TbGoods
|
|
)
|
|
err = global.MG_DB.Model(&model.TbGoods{}).Where("create_by = ? AND id = ?", uuid, info.ID).First(&tmp).Error
|
|
if err != nil {
|
|
return errors.New("商品不存在"), info.ID
|
|
}
|
|
imgs := strings.Split(info.Images, ",")
|
|
tx := global.MG_DB.Begin()
|
|
goods.CategoryId = info.CategoryId
|
|
goods.Title = info.Title
|
|
goods.TitleEng = info.TitleEng
|
|
goods.Images = info.Images
|
|
goods.Content = info.Content
|
|
goods.ContentText = info.ContentText
|
|
goods.RetailPrice = info.RetailPrice
|
|
goods.Tags = info.Tags
|
|
goods.Online = info.Online
|
|
goods.Cover = imgs[0]
|
|
err = tx.Where("id = ?", info.ID).Select("CategoryId", "Title", "TitleEng", "Images", "Content", "ContentText", "RetailPrice", "Tags", "Online", "Cover").Updates(&goods).Error
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return err, 0
|
|
}
|
|
var (
|
|
delSpecIds []uint
|
|
specs []model.TbGoodsSpecs
|
|
)
|
|
for i := 0; i < len(info.Specs); i++ {
|
|
if info.Specs[i].ID == 0 { // 新建规格
|
|
var spec model.TbGoodsSpecs
|
|
spec.GoodsId = tmp.ID
|
|
spec.SkuNo = utils.GetCurrentTimeStr()
|
|
specValues, _ := ToSpecValues(info.Specs[i].Attributes)
|
|
code := makeCode(spec.GoodsId, specValues)
|
|
// attribute, _ := json.Marshal(info.Specs[i].Attributes)
|
|
attribute, _ := json.Marshal(specValues)
|
|
spec.Code = code
|
|
spec.Specs = string(attribute)
|
|
spec.Stock = info.Specs[i].Stock
|
|
spec.Price = info.Specs[i].Price
|
|
if info.Specs[i].Image == "" {
|
|
spec.Image = "https://minio.sumweal.com/nft/221109/Ddvz989FB85u31TToa2xUT8WeYZ5q2g0678GGPRx7NXKM11F1U.png"
|
|
} else {
|
|
spec.Image = info.Specs[i].Image
|
|
}
|
|
spec.GoodsNo = info.Specs[i].GoodsNo
|
|
spec.Status = 1
|
|
specs = append(specs, spec)
|
|
} else { // 编辑
|
|
var spec model.TbGoodsSpecs
|
|
spec.GoodsId = tmp.ID
|
|
if info.Specs[i].SkuNo == "" {
|
|
spec.SkuNo = utils.GetCurrentTimeStr()
|
|
}
|
|
specValues, _ := ToSpecValues(info.Specs[i].Attributes)
|
|
code := makeCode(spec.GoodsId, specValues)
|
|
// attribute, _ := json.Marshal(info.Specs[i].Attributes)
|
|
attribute, _ := json.Marshal(specValues)
|
|
spec.Code = code
|
|
spec.Specs = string(attribute)
|
|
spec.Stock = info.Specs[i].Stock
|
|
spec.Price = info.Specs[i].Price
|
|
if info.Specs[i].Image == "" {
|
|
spec.Image = "https://minio.sumweal.com/nft/221109/Ddvz989FB85u31TToa2xUT8WeYZ5q2g0678GGPRx7NXKM11F1U.png"
|
|
} else {
|
|
spec.Image = info.Specs[i].Image
|
|
}
|
|
spec.GoodsNo = info.Specs[i].GoodsNo
|
|
err = tx.Model(&model.TbGoodsSpecs{}).Where("create_by = ? AND id = ?",uuid, info.Specs[i].ID).Select("GoodsNo", "Specs", "Stock", "Price", "Image", "Code").Updates(&spec).Error
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return err, 0
|
|
}
|
|
delSpecIds = append(delSpecIds, info.Specs[i].ID)
|
|
}
|
|
goods.Stock += info.Specs[i].Stock
|
|
if goods.PriceMin == 0 || goods.PriceMin > info.Specs[i].Price { // 获取最低规格价格
|
|
goods.PriceMin = info.Specs[i].Price
|
|
}
|
|
if goods.PriceMax == 0 || goods.PriceMax < info.Specs[i].Price { // 获取最高规格价格
|
|
goods.PriceMax = info.Specs[i].Price
|
|
}
|
|
}
|
|
if len(delSpecIds) == 0 {
|
|
err = tx.Model(&model.TbGoodsSpecs{}).Where("goods_id = ?", tmp.ID).Delete(&[]model.TbGoodsSpecs{}).Error
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return err, 0
|
|
}
|
|
} else {
|
|
err = tx.Model(&model.TbGoodsSpecs{}).Where("goods_id = ? AND id NOT IN (?)", tmp.ID, delSpecIds).Delete(&[]model.TbGoodsSpecs{}).Error
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return err, 0
|
|
}
|
|
}
|
|
if len(specs) != 0 {
|
|
err = tx.Model(&model.TbGoodsSpecs{}).Create(&specs).Error
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return err, 0
|
|
}
|
|
}
|
|
goods.ListPrice = goods.PriceMin
|
|
err = tx.Model(&model.TbGoods{}).Where("id = ?", info.ID).UpdateColumns(map[string]any{"stock": goods.Stock, "list_price": goods.ListPrice, "price_min": goods.PriceMin, "price_max": goods.PriceMax}).Error
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return err, 0
|
|
}
|
|
tx.Commit()
|
|
DealGoodsStatus([]uint{tmp.ID})
|
|
id = tmp.ID
|
|
return
|
|
}
|
|
|
|
func BatchUpdateTbGoodsOnline(uuid string, info request.BatchOnline) (err error) {
|
|
err = global.MG_DB.Model(&model.TbGoods{}).Where("create_by = ? AND id IN (?)", uuid, info.Ids).Update("online", info.Online).Error
|
|
if err != nil {
|
|
return err
|
|
}
|
|
DealGoodsStatus(info.Ids)
|
|
return nil
|
|
}
|
|
|
|
func BatchDeleteTbGoods(uuid string, info request.IdsReq) (err error) {
|
|
err = global.MG_DB.Model(&model.TbGoods{}).Where("create_by = ? AND id IN (?)", uuid, info.Ids).Delete(&[]model.TbGoods{}).Error
|
|
if err != nil {
|
|
return err
|
|
}
|
|
DealDeleteGoodsStatus(info.Ids)
|
|
return nil
|
|
}
|
|
|
|
func DealGoodsStatus(ids []uint) {
|
|
var (
|
|
err error
|
|
list []model.TbGoods
|
|
)
|
|
err = global.MG_DB.Model(&model.TbGoods{}).Where("id IN (?)", ids).Find(&list).Error
|
|
if err != nil {
|
|
return
|
|
}
|
|
for i := 0; i < len(list); i++ {
|
|
if list[i].Online == "on" && list[i].Stock > 0 { // 上架且库存为0
|
|
// 更新关联任务商品状态
|
|
tx := global.MG_DB.Begin()
|
|
err = tx.Model(&model.Mission{}).Where("goods_id = ?", list[i].ID).Update("goods_status", 1).Error
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return
|
|
}
|
|
tx.Commit()
|
|
} else {
|
|
// 更新关联任务商品状态
|
|
tx := global.MG_DB.Begin()
|
|
err = tx.Model(&model.Mission{}).Where("goods_id = ?", list[i].ID).Update("goods_status", 2).Error
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return
|
|
}
|
|
tx.Commit()
|
|
}
|
|
}
|
|
}
|
|
|
|
func DealDeleteGoodsStatus(ids []uint) {
|
|
// 更新关联任务商品状态
|
|
tx := global.MG_DB.Begin()
|
|
err := tx.Model(&model.Mission{}).Where("goods_id IN (?)", ids).Update("goods_status", 2).Error
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return
|
|
}
|
|
tx.Commit()
|
|
}
|
|
|
|
func ToSpecValues(attrs []request.TbGoodsAttributeValue) (specValues []request.GoodsAttributeValue, err error) {
|
|
specValues = make([]request.GoodsAttributeValue, 0)
|
|
for _, v := range attrs {
|
|
var attrModel model.TbAttribute
|
|
var valueId uint
|
|
err = global.MG_DB.Model(&model.TbAttribute{}).Where("id=?", v.AttributeId).First(&attrModel).Error
|
|
if err != nil {
|
|
return
|
|
}
|
|
var specValue model.SpecValue
|
|
global.MG_DB.Model(&model.SpecValue{}).Where("value=? and spec_id=?", v.Value, v.AttributeId).First(&specValue)
|
|
valueId = specValue.ID
|
|
if specValue.ID == 0 {
|
|
newSpecValue := model.SpecValue{
|
|
Value: v.Value,
|
|
SpecId: v.AttributeId,
|
|
}
|
|
err = global.MG_DB.Model(&model.SpecValue{}).Create(&newSpecValue).Error
|
|
if err != nil {
|
|
return
|
|
}
|
|
valueId = newSpecValue.ID
|
|
}
|
|
|
|
specValues = append(specValues, request.GoodsAttributeValue{
|
|
AttributeId: v.AttributeId,
|
|
Key: attrModel.Name,
|
|
Value: v.Value,
|
|
ValueId: uint(valueId),
|
|
})
|
|
}
|
|
return
|
|
}
|
|
|
|
func makeCode(goodsId uint, specValues []request.GoodsAttributeValue) string {
|
|
var code = cast.ToString(goodsId) + "$"
|
|
for k, v := range specValues {
|
|
code = code + cast.ToString(v.AttributeId) + "-" + cast.ToString(v.ValueId)
|
|
if k != len(specValues)-1 {
|
|
code = code + "#"
|
|
}
|
|
}
|
|
return code
|
|
}
|
|
|
|
func ListSku(goodsId uint) (list []model.TbGoodsSpecs, err error) {
|
|
list = make([]model.TbGoodsSpecs, 0)
|
|
err = global.MG_DB.Model(&model.TbGoodsSpecs{}).Where("goods_id = ? and status=1", goodsId).Find(&list).Error
|
|
if err != nil {
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
func UpdateSkuList(info request.UpdateSku) (err error) {
|
|
var (
|
|
stock int64
|
|
priceMax,priceMin float64
|
|
check model.TbGoodsSpecs
|
|
)
|
|
if len(info.SkuList) == 0 {
|
|
return
|
|
}
|
|
err = global.MG_DB.Model(&model.TbGoodsSpecs{}).Where("id = ?",info.SkuList[0].ID).First(&check).Error
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
|
|
tx := global.MG_DB.Begin()
|
|
for _, v := range info.SkuList {
|
|
err = tx.Model(&model.TbGoodsSpecs{}).Where("id = ?", v.ID).Updates(map[string]any{"price": v.Price, "stock": v.Stock}).Error
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return
|
|
}
|
|
stock += v.Stock
|
|
if v.Price > priceMax {
|
|
priceMax = v.Price
|
|
}
|
|
if (v.Price < priceMin && priceMin > 0) || priceMin == 0 {
|
|
priceMin = v.Price
|
|
}
|
|
}
|
|
err = tx.Model(&model.TbGoods{}).Where("id = ?", check.GoodsId).Updates(map[string]any{"price_min": priceMin, "stock": stock,"price_max":priceMax}).Error
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return
|
|
}
|
|
tx.Commit()
|
|
|
|
|
|
|
|
return
|
|
}
|
|
|
|
type GoodsSpecs struct {
|
|
GoodsId uint ` json:"goods_id"` // spu id
|
|
Title string ` json:"title"` // 商品标题
|
|
Stock int64 ` json:"stock"` // 库存
|
|
Specs json.RawMessage ` json:"specs"` // 规格
|
|
}
|
|
|
|
func GetSale(uuid string,page, size int, title string) (list []*response.GoodsSaleItem, total int64, err error) {
|
|
skuList := make([]GoodsSpecs, 0)
|
|
|
|
|
|
db := global.MG_DB.Model(&model.TbGoodsSpecs{}).Select("tb_goods_specs.stock", "title", "specs", "goods_id").Joins("JOIN tb_goods on tb_goods_specs.goods_id=tb_goods.id").
|
|
Where("tb_goods.create_by = ? AND tb_goods.title like ?",uuid, "%"+title+"%")
|
|
db.Count(&total)
|
|
err = db.Limit(size).Offset(size * (page - 1)).Find(&skuList).Error
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
list = make([]*response.GoodsSaleItem, 0)
|
|
|
|
for _, v := range skuList {
|
|
specList := make([]request.GoodsAttributeValue, 0)
|
|
json.Unmarshal(v.Specs, &specList)
|
|
values := make([]string, 0)
|
|
for _, spec := range specList {
|
|
values = append(values, spec.Value)
|
|
}
|
|
|
|
item := &response.GoodsSaleItem{
|
|
GoodsId: cast.ToString(v.GoodsId),
|
|
Title: v.Title,
|
|
SkuName: strings.Join(values, " "),
|
|
Stock: uint(v.Stock),
|
|
TodaySale: 0,//TODO:: 统计 sku 销售量
|
|
SevenSale: 0,
|
|
ThirtySale: 0,
|
|
}
|
|
list = append(list, item)
|
|
|
|
}
|
|
return
|
|
}
|
|
|