Merge branch 'master' of e.coding.net:rosydev/jx-callback

This commit is contained in:
gazebo
2019-12-10 17:47:19 +08:00
10 changed files with 350 additions and 162 deletions

View File

@@ -639,17 +639,28 @@ func AddSkuName(ctx *jxcontext.Context, skuNameExt *model.SkuNameExt, userName s
skuNameExt.SpecUnit = skuNameExt.Skus[0].SpecUnit
}
picType := true
for _, imgName := range []string{skuNameExt.Img, skuNameExt.Img2} {
if imgName != "" {
_, err2 := datares.TryRegisterDataResource(ctx, skuNameExt.Name, imgName, model.ImgTypeMain, false)
dataRes, err2 := datares.TryRegisterDataResource(ctx, skuNameExt.Name, imgName, model.ImgTypeMain, false)
if dataRes.ResourceType == model.MimeTypeJpeg || dataRes.ResourceType == model.MimeTypePng {
picType = false
}
if err = err2; err != nil {
return nil, err
}
}
}
if picType {
return nil, fmt.Errorf("商品图片应至少包含一张非gif格式的图片")
}
if skuNameExt.DescImg != "" {
_, err2 := datares.TryRegisterDataResource(ctx, skuNameExt.Name+"desc", skuNameExt.DescImg, model.ImgTypeDesc, false)
dataRes, err2 := datares.TryRegisterDataResource(ctx, skuNameExt.Name+"desc", skuNameExt.DescImg, model.ImgTypeDesc, false)
if dataRes.ResourceType == model.MimeTypeGif {
return nil, fmt.Errorf("商品详情图片不能上传gif格式的图片")
}
if err = err2; err != nil {
return nil, err
}

View File

@@ -3,7 +3,9 @@ package cms
import (
"errors"
"fmt"
"io"
"math"
"mime/multipart"
"sort"
"strconv"
"sync"
@@ -23,6 +25,7 @@ import (
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals"
"github.com/360EntSecGroup-Skylar/excelize"
"github.com/astaxie/beego/orm"
)
@@ -34,80 +37,6 @@ const (
CopyStoreSkuModeUpdatePrice = "updatePrice" // 增量复制价格
)
type StoreSkuExt struct {
NameID int `orm:"column(name_id)" json:"nameID"`
SkuID int `orm:"column(sku_id)" json:"id"`
Comment string `orm:"size(255)" json:"comment"`
SkuCategoryID int `orm:"column(sku_category_id)" json:"categoryID"`
SkuSpecQuality float32 `json:"specQuality"`
SkuSpecUnit string `orm:"size(8)" json:"specUnit"` // 质量或容量
Weight int `json:"weight"` // 重量/质量单位为克当相应的SkuName的SpecUnit为g或kg时必须等于SpecQuality
JdID string `orm:"column(sku_jd_id);null;index" json:"jdID"`
SkuStatus int `json:"status"`
BindCreatedAt time.Time `orm:"auto_now_add;type(datetime)" json:"createdAt"`
BindUpdatedAt time.Time `orm:"auto_now;type(datetime)" json:"updatedAt"`
BindLastOperator string `orm:"size(32)" json:"lastOperator"` // 最后操作员
BindDeletedAt time.Time `orm:"type(datetime)" json:"deletedAt"`
SubStoreID int `orm:"column(sub_store_id)" json:"subStoreID"`
BindPrice int `json:"price"` // 单位为分不用int64的原因是这里不需要累加
UnitPrice int `json:"unitPrice"` // 这个是一斤的门店商品价放在这里的原因是避免额外增加一张store sku_name表逻辑上要保证同一SKU NAME中的所有SKU这个字段的数据一致
StoreSkuStatus int `json:"storeSkuStatus"`
EbaiID string `orm:"column(ebai_id);index" json:"ebaiID"`
MtwmID string `orm:"column(mtwm_id)" json:"mtwmID"` // 这个也不是必须的只是为了DAO取数据语句一致
// WscID string `orm:"column(wsc_id);index" json:"wscID"` // 表示微盟skuId
// WscID2 string `orm:"column(wsc_id2);index" json:"wscID2"` // 表示微盟goodsId
JdSyncStatus int8 `orm:"default(2)" json:"jdSyncStatus"`
EbaiSyncStatus int8 `orm:"default(2)" json:"ebaiSyncStatus"`
MtwmSyncStatus int8 `orm:"default(2)" json:"mtwmSyncStatus"`
// WscSyncStatus int8 `orm:"default(2)" json:"wscSyncStatus"`
JdPrice int `json:"jdPrice"`
EbaiPrice int `json:"ebaiPrice"`
MtwmPrice int `json:"mtwmPrice"`
JxPrice int `json:"jxPrice"`
AutoSaleAt time.Time `orm:"type(datetime);null" json:"autoSaleAt"`
ActPrice int `json:"actPrice"`
ActID int `orm:"column(act_id)" json:"actID"`
ActType int `orm:"column(act_type)" json:"actType"`
EarningPrice int `json:"earningPrice"`
EarningActID int `orm:"column(earning_act_id)" json:"earningActID"`
RealEarningPrice int `json:"realEarningPrice"`
StatusSaleBegin int16 `json:"statusSaleBegin"` //商品可售时间范围
StatusSaleEnd int16 `json:"statusSaleEnd"`
Count int `json:"count"`
Times int `json:"times"`
}
// GetStoreSkus用
type StoreSkuNameExt struct {
StoreID int `orm:"column(store_id)" json:"storeID"`
StoreName string `json:"storeName"`
model.SkuName
PayPercentage int `json:"-"`
UnitPrice int `json:"unitPrice"`
Skus []*StoreSkuExt `orm:"-" json:"skus,omitempty"`
SkusStr string `json:"-"`
PendingOpType int8 `json:"pendingOpType"` // 取值同 StoreOpRequest.Type
PendingUnitPrice int `json:"pendingUnitPrice"` // 这个是待审核的价格申请
}
// GetStoreSkus用
type StoreSkuNamesInfo struct {
TotalCount int `json:"totalCount"`
SkuNames []*StoreSkuNameExt `json:"skuNames"`
}
// UpdateStoreSku用API调用时
type StoreSkuBindSkuInfo struct {
SkuID int `json:"skuID"`
@@ -171,7 +100,36 @@ type tGetStoresSkusInfo struct {
model.SkuName
PayPercentage int `json:"-"`
StoreSkuExt
dao.StoreSkuExt
}
type SheetParam struct {
OutSkuIDCol int
SkuNameIDCol int
SkuPriceCol int
SkuNameCol int
SkuUnitCol int
SkuRow int
}
type DataSuccess struct {
NameID string `json:"商品编码"`
Name string `json:"商品名称"`
OrgPrice float64 `json:"原价"`
NowPrice float64 `json:"现价"`
MixPrice float64 `json:"涨跌"`
}
type DataFailed struct {
NameID string `json:"商品ID"`
Name string `json:"商品名称"`
Comment string `json:"备注"`
}
type DataLock struct {
dataSuccessList []DataSuccess
dataFailedList []DataFailed
locker sync.RWMutex
}
const (
@@ -187,9 +145,10 @@ var (
"18180948107": 1, // 徐
// "13684045763": 1, // 周
}
dataLock DataLock
)
func GetStoreSkus(ctx *jxcontext.Context, storeID int, skuIDs []int, isFocus bool, keyword string, isBySku, isAct bool, params map[string]interface{}, offset, pageSize int) (skuNamesInfo *StoreSkuNamesInfo, err error) {
func GetStoreSkus(ctx *jxcontext.Context, storeID int, skuIDs []int, isFocus bool, keyword string, isBySku, isAct bool, params map[string]interface{}, offset, pageSize int) (skuNamesInfo *dao.StoreSkuNamesInfo, err error) {
return GetStoresSkus(ctx, []int{storeID}, skuIDs, isFocus, keyword, isBySku, isAct, params, offset, pageSize)
}
@@ -373,11 +332,11 @@ func getGetStoresSkusBaseSQL(db *dao.DaoDB, storeIDs, skuIDs []int, isFocus bool
return sql, sqlParams, err
}
func GetStoresSkus(ctx *jxcontext.Context, storeIDs, skuIDs []int, isFocus bool, keyword string, isBySku, isAct bool, params map[string]interface{}, offset, pageSize int) (skuNamesInfo *StoreSkuNamesInfo, err error) {
func GetStoresSkus(ctx *jxcontext.Context, storeIDs, skuIDs []int, isFocus bool, keyword string, isBySku, isAct bool, params map[string]interface{}, offset, pageSize int) (skuNamesInfo *dao.StoreSkuNamesInfo, err error) {
return GetStoresSkusNew(ctx, storeIDs, skuIDs, isFocus, keyword, isBySku, isAct, params, offset, pageSize)
}
func GetStoresSkusNew(ctx *jxcontext.Context, storeIDs, skuIDs []int, isFocus bool, keyword string, isBySku, isAct bool, params map[string]interface{}, offset, pageSize int) (skuNamesInfo *StoreSkuNamesInfo, err error) {
func GetStoresSkusNew(ctx *jxcontext.Context, storeIDs, skuIDs []int, isFocus bool, keyword string, isBySku, isAct bool, params map[string]interface{}, offset, pageSize int) (skuNamesInfo *dao.StoreSkuNamesInfo, err error) {
if !isFocus && !isBySku && (len(storeIDs) > 1 || len(storeIDs) == 0) {
return nil, fmt.Errorf("未关注按SkuName只能查询单店")
}
@@ -416,7 +375,7 @@ func GetStoresSkusNew(ctx *jxcontext.Context, storeIDs, skuIDs []int, isFocus bo
catOrderBy = "t2.seq, "
}
skuNamesInfo = &StoreSkuNamesInfo{}
skuNamesInfo = &dao.StoreSkuNamesInfo{}
if !isBySku && sqlPageSize != model.UnlimitedPageSize {
sql2 := `
SELECT SQL_CALC_FOUND_ROWS
@@ -476,12 +435,12 @@ func GetStoresSkusNew(ctx *jxcontext.Context, storeIDs, skuIDs []int, isFocus bo
}
dao.Commit(db)
globals.SugarLogger.Debugf("GetStoresSkusNew get result2:%v", time.Now().Sub(beginTime))
storeNameMap := make(map[int64]*StoreSkuNameExt)
storeNameMap := make(map[int64]*dao.StoreSkuNameExt)
for _, v := range tmpList {
var storeName *StoreSkuNameExt
var storeName *dao.StoreSkuNameExt
index := jxutils.Combine2Int(v.StoreID, v.ID)
if isBySku || storeNameMap[index] == nil {
storeName = &StoreSkuNameExt{
storeName = &dao.StoreSkuNameExt{
StoreID: v.StoreID,
StoreName: v.StoreName,
SkuName: v.SkuName,
@@ -508,7 +467,7 @@ func GetStoresSkusNew(ctx *jxcontext.Context, storeIDs, skuIDs []int, isFocus bo
storeIDs, skuIDs = GetStoreAndSkuIDsFromInfo(skuNamesInfo)
}
beginTime := time.Now()
err = updateActPrice4StoreSkuNameNew(db, storeIDs, skuIDs, skuNamesInfo, actVendorID)
err = dao.UpdateActPrice4StoreSkuNameNew(db, storeIDs, skuIDs, skuNamesInfo, actVendorID)
globals.SugarLogger.Debugf("GetStoresSkusNew updateActPrice4StoreSkuName:%v", time.Now().Sub(beginTime))
if !isFocus {
err = updateUnitPrice4StoreSkuNameNew(db, skuNamesInfo)
@@ -519,7 +478,7 @@ func GetStoresSkusNew(ctx *jxcontext.Context, storeIDs, skuIDs []int, isFocus bo
return skuNamesInfo, err
}
func GetStoreAndSkuIDsFromInfo(skuNamesInfo *StoreSkuNamesInfo) (storeIDs, skuIDs []int) {
func GetStoreAndSkuIDsFromInfo(skuNamesInfo *dao.StoreSkuNamesInfo) (storeIDs, skuIDs []int) {
storeIDMap := make(map[int]int)
skuIDMap := make(map[int]int)
for _, skuName := range skuNamesInfo.SkuNames {
@@ -532,7 +491,7 @@ func GetStoreAndSkuIDsFromInfo(skuNamesInfo *StoreSkuNamesInfo) (storeIDs, skuID
}
// 根据已经部分关注的商品,得到已经存在的门店商品单价
func updateUnitPrice4StoreSkuNameNew(db *dao.DaoDB, skuNamesInfo *StoreSkuNamesInfo) (err error) {
func updateUnitPrice4StoreSkuNameNew(db *dao.DaoDB, skuNamesInfo *dao.StoreSkuNamesInfo) (err error) {
storeIDMap := make(map[int]int)
skuNameIDMap := make(map[int]int)
for _, skuName := range skuNamesInfo.SkuNames {
@@ -554,49 +513,7 @@ func updateUnitPrice4StoreSkuNameNew(db *dao.DaoDB, skuNamesInfo *StoreSkuNamesI
return err
}
// skuIDs为空会导致性能极低所以要skuIDs必须有值
func updateActPrice4StoreSkuNameNew(db *dao.DaoDB, storeIDs, skuIDs []int, skuNamesInfo *StoreSkuNamesInfo, actVendorID int) (err error) {
if len(skuIDs) == 0 {
return nil
}
var vendorIDs []int
if actVendorID >= 0 {
vendorIDs = []int{actVendorID}
}
actStoreSkuList, err := dao.GetEffectiveActStoreSkuInfo(db, 0, vendorIDs, storeIDs, skuIDs, time.Now(), time.Now())
if err != nil {
globals.SugarLogger.Errorf("GetEffectiveActStoreSkuInfo can not get sku promotion info for error:%v", err)
return err
}
actStoreSkuMap4Act := jxutils.NewActStoreSkuMap(actStoreSkuList, true)
actStoreSkuMap4EarningPrice := jxutils.NewActStoreSkuMap(actStoreSkuList, false)
for _, skuName := range skuNamesInfo.SkuNames {
if len(skuName.Skus) > 0 {
for _, v := range skuName.Skus {
if actStoreSku := actStoreSkuMap4Act.GetActStoreSku(skuName.StoreID, v.SkuID, -1); actStoreSku != nil {
v.ActPrice = int(actStoreSku.ActualActPrice)
v.ActID = actStoreSku.ActID
v.ActType = actStoreSku.Type
}
if actStoreSku := actStoreSkuMap4EarningPrice.GetActStoreSku(skuName.StoreID, v.SkuID, -1); actStoreSku != nil {
v.EarningPrice = int(actStoreSku.EarningPrice)
v.EarningActID = actStoreSku.ActID
}
v.RealEarningPrice = v.EarningPrice
if v.RealEarningPrice == 0 {
v.RealEarningPrice = int(jxutils.CaculateSkuEarningPrice(int64(v.BindPrice), int64(v.BindPrice), skuName.PayPercentage))
}
}
} else {
skuName.UnitPrice = skuName.Price
}
}
return err
}
func updateSaleInfo4StoreSkuName(ctx *jxcontext.Context, db *dao.DaoDB, storeIDs, skuIDs []int, params map[string]interface{}, skuNamesInfo *StoreSkuNamesInfo, offset, pageSize int) (err error) {
func updateSaleInfo4StoreSkuName(ctx *jxcontext.Context, db *dao.DaoDB, storeIDs, skuIDs []int, params map[string]interface{}, skuNamesInfo *dao.StoreSkuNamesInfo, offset, pageSize int) (err error) {
var (
saleInfoList []*SkuSaleInfo
timeList []time.Time
@@ -625,9 +542,9 @@ func updateSaleInfo4StoreSkuName(ctx *jxcontext.Context, db *dao.DaoDB, storeIDs
for _, saleInfo := range saleInfoList {
saleInfoMap[jxutils.Combine2Int(saleInfo.StoreID, saleInfo.SkuID)] = saleInfo
}
var newSkuNames []*StoreSkuNameExt
var newSkuNames []*dao.StoreSkuNameExt
for _, skuName := range skuNamesInfo.SkuNames {
var newSkus []*StoreSkuExt
var newSkus []*dao.StoreSkuExt
for _, sku := range skuName.Skus {
saleInfo := saleInfoMap[jxutils.Combine2Int(skuName.StoreID, sku.SkuID)]
if saleInfo == nil && fromCount == 0 {
@@ -2161,16 +2078,16 @@ func ReCalculateJxPrice(ctx *jxcontext.Context, storeIDs []int) (err error) {
return err
}
func GetTopSkusByStoreIDs(ctx *jxcontext.Context, storeIDs []int) (skuAndNameExt []*dao.SkuAndNameExt, err error) {
func GetTopSkusByStoreIDs(ctx *jxcontext.Context, storeIDs []int) (storeSkuNameExt []*dao.StoreSkuNameExt, err error) {
if len(storeIDs) == 0 {
return skuAndNameExt, err
return storeSkuNameExt, err
}
db := dao.GetDB()
skuAndNameExt, err = dao.GetTopSkusByStoreIDs(db, storeIDs)
storeSkuNameExt, err = dao.GetTopSkusByStoreIDs(db, storeIDs)
if err != nil {
return nil, err
}
return skuAndNameExt, err
return storeSkuNameExt, err
}
func GetTopCategorysByStoreIDs(ctx *jxcontext.Context, storeIDs []int) (skuCategory []*model.SkuCategory, err error) {
@@ -2190,3 +2107,77 @@ func RefershStoreSkusMidPrice(ctx *jxcontext.Context, storeIDs []int) (err error
_, err = dao.RefershStoreSkusMidPrice(db, storeIDs)
return err
}
func RefreshJxPriceByExcel(ctx *jxcontext.Context, storeIDs []int, files []*multipart.FileHeader, isAsync, isContinueWhenError bool) (hint string, err error) {
if len(files) == 0 {
return "", errors.New("没有文件上传!")
}
if len(storeIDs) == 0 {
return "", errors.New("请选择至少一个门店!")
}
fileHeader := files[0]
file, err := fileHeader.Open()
hint, err = RefreshJxPriceByExcelBin(ctx, storeIDs, file, true, true)
file.Close()
return hint, err
}
func RefreshJxPriceByExcelBin(ctx *jxcontext.Context, storeIDs []int, reader io.Reader, isAsync, isContinueWhenError bool) (hint string, err error) {
var storeSkuNamePriceList []*model.StoreSkuNamePrice
dataLock.dataFailedList = dataLock.dataFailedList[0:0]
dataLock.dataSuccessList = dataLock.dataSuccessList[0:0]
sheetParam := &SheetParam{
SkuNameIDCol: 5,
SkuPriceCol: 3,
SkuNameCol: 1,
SkuRow: 1,
SkuUnitCol: 2,
OutSkuIDCol: 0,
}
xlsx, err := excelize.OpenReader(reader)
if err != nil {
return "", err
}
rows, _ := xlsx.GetRows(xlsx.GetSheetName(1))
for rowNum, row := range rows {
if rowNum < sheetParam.SkuRow {
continue
}
storeSkuNamePrice := &model.StoreSkuNamePrice{}
GetCellIntoStruct(rowNum, row, sheetParam, storeSkuNamePrice)
storeSkuNamePriceList = append(storeSkuNamePriceList, storeSkuNamePrice)
}
return hint, err
}
func GetCellIntoStruct(rowNum int, row []string, sheetParam *SheetParam, storeSkuNamePrice *model.StoreSkuNamePrice) {
for k, cell := range row {
if k == sheetParam.OutSkuIDCol {
storeSkuNamePrice.OutSkuID = cell
}
if k == sheetParam.SkuNameCol {
storeSkuNamePrice.Name = cell
}
if k == sheetParam.SkuNameIDCol {
storeSkuNamePrice.NameIDGroup = cell
}
if k == sheetParam.SkuPriceCol {
storeSkuNamePrice.Price = int(utils.Float64TwoInt64(utils.Str2Float64(cell) * 100))
}
if k == sheetParam.SkuUnitCol {
storeSkuNamePrice.Unit = cell
}
}
}
func (d *DataLock) AppendDataSuccess(dataSuccess DataSuccess) {
d.locker.Lock()
defer d.locker.Unlock()
d.dataSuccessList = append(d.dataSuccessList, dataSuccess)
}
func (d *DataLock) AppendDataFailed(dataFailed DataFailed) {
d.locker.Lock()
defer d.locker.Unlock()
d.dataFailedList = append(d.dataFailedList, dataFailed)
}

View File

@@ -224,8 +224,8 @@ func GetMultiStoreAllSkuInfo(ctx *jxcontext.Context, vendorMap map[int]bool) {
}
}
func GetFilterJxSkuInfoMap(jxSkuInfoList []*StoreSkuNameExt) map[int]*StoreSkuNameExt {
filterJxSkuInfoMap := make(map[int]*StoreSkuNameExt)
func GetFilterJxSkuInfoMap(jxSkuInfoList []*dao.StoreSkuNameExt) map[int]*dao.StoreSkuNameExt {
filterJxSkuInfoMap := make(map[int]*dao.StoreSkuNameExt)
for _, value := range jxSkuInfoList {
for _, skuInfo := range value.Skus {
filterJxSkuInfoMap[skuInfo.SkuID] = value
@@ -322,7 +322,7 @@ func IsSkuCanSale(saleStatus int) bool {
//京西平台和其他平台商品的对比
//storeIDStr 京西商家id vendorStoreID 平台商家id
func CompareJxAndVendor(vendorID int, storeIDStr, vendorStoreID, storeName string, filterJxSkuInfoMap map[int]*StoreSkuNameExt, filterVendorSkuInfoMap map[int]*partner.SkuNameInfo) {
func CompareJxAndVendor(vendorID int, storeIDStr, vendorStoreID, storeName string, filterJxSkuInfoMap map[int]*dao.StoreSkuNameExt, filterVendorSkuInfoMap map[int]*partner.SkuNameInfo) {
for skuID, jxSkuInfo := range filterJxSkuInfoMap {
skuIDStr := utils.Int2Str(skuID)
var jxSkuDetailName string
@@ -542,11 +542,11 @@ func CheckSkuDiffBetweenJxAndVendor(ctx *jxcontext.Context, vendorIDList []int,
storeID := jxStoreInfoListValue.ID
storeIDStr := utils.Int2Str(storeID)
storeName := jxStoreInfoListValue.Name
jxSkuInfoDataSingle := &StoreSkuNamesInfo{}
jxSkuInfoDataMulti := &StoreSkuNamesInfo{}
jxSkuInfoDataSingle := &dao.StoreSkuNamesInfo{}
jxSkuInfoDataMulti := &dao.StoreSkuNamesInfo{}
if jxStoreInfoListValue.StoreMaps != nil {
var filterJxSkuInfoMapSingle map[int]*StoreSkuNameExt
var filterJxSkuInfoMapMulti map[int]*StoreSkuNameExt
var filterJxSkuInfoMapSingle map[int]*dao.StoreSkuNameExt
var filterJxSkuInfoMapMulti map[int]*dao.StoreSkuNameExt
for _, vendorListValue := range jxStoreInfoListValue.StoreMaps {
vendorID := int(utils.MustInterface2Int64(vendorListValue["vendorID"]))
var flag = false