368 lines
13 KiB
Go
368 lines
13 KiB
Go
package mtwm
|
||
|
||
import (
|
||
"errors"
|
||
"strings"
|
||
|
||
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
|
||
"git.rosy.net.cn/baseapi/utils"
|
||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||
"git.rosy.net.cn/jx-callback/business/model"
|
||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||
"git.rosy.net.cn/jx-callback/business/partner"
|
||
"git.rosy.net.cn/jx-callback/business/partner/putils"
|
||
"git.rosy.net.cn/jx-callback/globals"
|
||
"git.rosy.net.cn/jx-callback/globals/api"
|
||
)
|
||
|
||
func jxActType2Mtwm(actType int) int {
|
||
if actType == model.ActSkuDirectDown {
|
||
actType = mtwmapi.RetailActTypeDirectDown
|
||
} else if actType == model.ActSkuSecKill {
|
||
actType = mtwmapi.RetailActTypeSecKill
|
||
} else {
|
||
actType = 0
|
||
}
|
||
return actType
|
||
}
|
||
|
||
func actOrderRules2Mtwm(actOrderRules []*model.ActOrderRule) (actDetails []*mtwmapi.FullDiscountActDetail) {
|
||
for _, v := range actOrderRules {
|
||
actDetails = append(actDetails, &mtwmapi.FullDiscountActDetail{
|
||
OriginalPrice: jxutils.IntPrice2Standard(v.SalePrice),
|
||
ActPrice: jxutils.IntPrice2Standard(v.DeductPrice),
|
||
})
|
||
}
|
||
return actDetails
|
||
}
|
||
|
||
func storeSku2ActData(act *model.Act2, actStoreSku []*model.ActStoreSku2, handler func(int8) bool) (actData []*mtwmapi.RetailDiscountActData) {
|
||
orderLimit := 1
|
||
if act.LimitCount > 0 {
|
||
orderLimit = act.LimitCount
|
||
}
|
||
for _, v := range actStoreSku {
|
||
if handler == nil || handler(v.SyncStatus) {
|
||
dayLimit := -1
|
||
if v.Stock > 0 {
|
||
dayLimit = v.Stock
|
||
}
|
||
actData = append(actData, &mtwmapi.RetailDiscountActData{
|
||
AppFoodCode: utils.Int2Str(v.SkuID),
|
||
// UserType: 0,
|
||
StartTime: act.BeginAt.Unix(),
|
||
EndTime: act.EndAt.Unix(),
|
||
OrderLimit: orderLimit,
|
||
DayLimit: dayLimit,
|
||
// Period: "",
|
||
// WeeksTime: "",
|
||
SettingType: mtwmapi.SettingTypeAsPrice,
|
||
ActPrice: jxutils.IntPrice2Standard(v.ActualActPrice),
|
||
// DiscountCoefficient: 0,
|
||
// Sequence: int(v.ActPrice), // 此字段不允许重复
|
||
// ItemID: utils.Str2Int64WithDefault(v.VendorActID, 0),
|
||
})
|
||
}
|
||
}
|
||
return actData
|
||
}
|
||
|
||
func storeSku2ActData4Delete(actStoreSku []*model.ActStoreSku2, handler func(int8) bool) (actIDList []string) {
|
||
for _, v := range actStoreSku {
|
||
if handler == nil || handler(v.SyncStatus) {
|
||
if v.VendorActID != "" {
|
||
actIDList = append(actIDList, v.VendorActID)
|
||
}
|
||
}
|
||
}
|
||
return actIDList
|
||
}
|
||
|
||
func isCreateOrUpdate(syncStatus int8) bool {
|
||
return model.IsSyncStatusNeedCreate(syncStatus) || model.IsSyncStatusNeedUpdate(syncStatus)
|
||
}
|
||
|
||
func createOneShopAct(act *model.Act2, vendorStoreID string, actStoreSku []*model.ActStoreSku2) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||
actData := storeSku2ActData(act, actStoreSku, isCreateOrUpdate)
|
||
if len(actData) > 0 {
|
||
if globals.EnableMtwmStoreWrite {
|
||
actResult, faileInfoList, err2 := api.MtwmAPI.RetailDiscountBatchSave2(vendorStoreID, jxActType2Mtwm(act.Type), actData)
|
||
|
||
//5873
|
||
if err2 != nil && strings.Contains(err2.Error(), "未获取有效门店id") {
|
||
|
||
temp, err := dao.GetStoreDetailForDD(dao.GetDB(), 0, model.VendorIDMTWM, vendorStoreID, "")
|
||
if err == nil {
|
||
actResult, faileInfoList, err2 = getAPI(temp.VendorOrgCode, 0, vendorStoreID).RetailDiscountBatchSave2(vendorStoreID, jxActType2Mtwm(act.Type), actData)
|
||
}
|
||
|
||
}
|
||
|
||
//actResult, faileInfoList, err2 := getAPI(tempStore.VendorOrgCode, 0, vendorStoreID).RetailDiscountBatchSave2(vendorStoreID, jxActType2Mtwm(act.Type), actData)
|
||
err = err2
|
||
// 忽略错误,都放在failedList里
|
||
// if err != nil {
|
||
// return nil, err
|
||
// }
|
||
actStoreSkuMap := make(map[int]*model.ActStoreSku2)
|
||
for _, v := range actStoreSku {
|
||
actStoreSkuMap[v.SkuID] = v
|
||
}
|
||
|
||
for _, v := range actResult {
|
||
if v2 := actStoreSkuMap[int(utils.Str2Int64WithDefault(v.AppFoodCode, 0))]; v2 != nil {
|
||
v2.VendorActID = utils.Int64ToStr(v.ActID)
|
||
}
|
||
}
|
||
for _, v := range faileInfoList {
|
||
if v2 := actStoreSkuMap[int(utils.Str2Int64WithDefault(v.AppFoodCode, 0))]; v2 != nil {
|
||
failedList = append(failedList, &partner.StoreSkuInfoWithErr{
|
||
StoreSkuInfo: &partner.StoreSkuInfo{
|
||
SkuID: v2.SkuID,
|
||
},
|
||
VendoreID: model.VendorIDMTWM,
|
||
StoreID: int(utils.Str2Int64WithDefault(vendorStoreID, 0)),
|
||
ErrMsg: v.ErrorMsg,
|
||
})
|
||
}
|
||
}
|
||
} else {
|
||
for _, v := range actStoreSku {
|
||
v.VendorActID = utils.Int64ToStr(jxutils.GenFakeID())
|
||
}
|
||
}
|
||
}
|
||
return failedList, err
|
||
}
|
||
|
||
func cancelOneShopAct(act *model.Act2, vendorStoreID string, actStoreSku []*model.ActStoreSku2) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||
if list := storeSku2ActData4Delete(actStoreSku, nil /*model.IsSyncStatusNeedDelete*/); len(list) > 0 {
|
||
if globals.EnableMtwmStoreWrite {
|
||
failedList2, err2 := api.MtwmAPI.RetailDiscountDelete2(vendorStoreID, jxActType2Mtwm(act.Type), list)
|
||
globals.SugarLogger.Debugf("==============failedList2 := %s", utils.Format4Output(failedList2, false))
|
||
globals.SugarLogger.Debugf("==============err2 := %v", err2)
|
||
globals.SugarLogger.Debugf("==============vendorStoreID := %s", utils.Format4Output(vendorStoreID, false))
|
||
globals.SugarLogger.Debugf("============== jxActType2Mtwm(act.Type) := %s", utils.Format4Output(jxActType2Mtwm(act.Type), false))
|
||
globals.SugarLogger.Debugf("==============list := %s", utils.Format4Output(list, false))
|
||
actStoreSkuMap := make(map[string]*model.ActStoreSku2)
|
||
for _, v := range actStoreSku {
|
||
actStoreSkuMap[v.VendorActID] = v
|
||
}
|
||
for _, v := range failedList2 {
|
||
if !mtwmapi.CanDeleteActErrMsgIgnore(v.ErrorMsg) {
|
||
failedList = append(failedList, &partner.StoreSkuInfoWithErr{
|
||
StoreSkuInfo: &partner.StoreSkuInfo{
|
||
SkuID: actStoreSkuMap[utils.Int64ToStr(v.ActID)].SkuID,
|
||
},
|
||
StoreID: int(utils.Str2Int64WithDefault(vendorStoreID, 0)),
|
||
ErrMsg: v.ErrorMsg,
|
||
VendoreID: model.VendorIDMTWM,
|
||
})
|
||
}
|
||
}
|
||
err = err2
|
||
err = nil // 强制不返回错误,使用部分错误
|
||
}
|
||
}
|
||
return failedList, err
|
||
}
|
||
|
||
func getActStoreSkuFromTaskResult(taskReslt []interface{}) (list []*model.ActStoreSku2) {
|
||
for _, v := range taskReslt {
|
||
actStoreSkuList := v.([]*model.ActStoreSku2)
|
||
list = append(list, actStoreSkuList...)
|
||
}
|
||
return list
|
||
}
|
||
|
||
func createSkuAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actStoreSku []*model.ActStoreSku2) (createdList []*model.ActStoreSku2, err error) {
|
||
actStoreSkuListList := partner.SplitActStoreSku2List(actStoreSku)
|
||
task := tasksch.NewParallelTask("mtwm createSkuAct", nil, ctx,
|
||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||
list := batchItemList[0].([]*model.ActStoreSku2)
|
||
|
||
failedList, err2 := createOneShopAct(act, list[0].VendorStoreID, list)
|
||
if err = err2; err2 == nil {
|
||
if len(failedList) > 0 {
|
||
failedMap := putils.StoreSkuInfoWithErrList2MapBySku(failedList)
|
||
list = []*model.ActStoreSku2{}
|
||
for _, v := range actStoreSku {
|
||
if failedMap[v.SkuID] == nil {
|
||
list = append(list, v)
|
||
}
|
||
}
|
||
list = []*model.ActStoreSku2{}
|
||
}
|
||
retVal = []interface{}{list}
|
||
}
|
||
return retVal, err
|
||
}, actStoreSkuListList)
|
||
tasksch.HandleTask(task, parentTask, true).Run()
|
||
result, err := task.GetResult(0)
|
||
return getActStoreSkuFromTaskResult(result), err
|
||
}
|
||
|
||
func cancelSkuAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actStoreSku []*model.ActStoreSku2) (canceledList []*model.ActStoreSku2, err error) {
|
||
actStoreSkuListList := partner.SplitActStoreSku2List(actStoreSku)
|
||
task := tasksch.NewParallelTask("mtwm cancelSkuAct", nil, ctx,
|
||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||
actStoreSkuList := batchItemList[0].([]*model.ActStoreSku2)
|
||
if _, err = cancelOneShopAct(act, actStoreSkuList[0].VendorStoreID, actStoreSkuList); err == nil {
|
||
retVal = []interface{}{actStoreSkuList}
|
||
}
|
||
return retVal, err
|
||
}, actStoreSkuListList)
|
||
tasksch.HandleTask(task, parentTask, true).Run()
|
||
result, err := task.GetResult(0)
|
||
return getActStoreSkuFromTaskResult(result), err
|
||
}
|
||
|
||
func (c *PurchaseHandler) SyncAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actOrderRules []*model.ActOrderRule, actStoreSkuList []*model.ActStoreSku2) (err error) {
|
||
var actStoreSkuList4Create, actStoreSkuList4Delete []*model.ActStoreSku2
|
||
var updateItems []*dao.KVUpdateItem
|
||
|
||
actStoreSkuMap := partner.SplitActStoreSku(actStoreSkuList)
|
||
for storeID := range actStoreSkuMap {
|
||
for _, actStoreSku := range actStoreSkuMap[storeID] {
|
||
if model.IsSyncStatusDelete(actStoreSku.SyncStatus) {
|
||
actStoreSkuList4Delete = append(actStoreSkuList4Delete, actStoreSku)
|
||
} else if model.IsSyncStatusNew(actStoreSku.SyncStatus) {
|
||
actStoreSkuList4Create = append(actStoreSkuList4Create, actStoreSku)
|
||
}
|
||
}
|
||
}
|
||
globals.SugarLogger.Debugf("=========actStoreSkuList4Create := %s", utils.Format4Output(actStoreSkuList4Create, false))
|
||
|
||
err = func() (err error) {
|
||
globals.SugarLogger.Debugf("=========act := %s", utils.Format4Output(act, false))
|
||
if model.IsSyncStatusDelete(act.SyncStatus) {
|
||
globals.SugarLogger.Debugf("=========act := %s", "delete")
|
||
canceledList, err2 := cancelSkuAct(ctx, nil, act, actStoreSkuList)
|
||
updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, canceledList, model.SyncFlagModifiedMask)...)
|
||
if err = err2; err == nil {
|
||
updateItems = append(updateItems, partner.Act2Update(ctx, act, model.SyncFlagModifiedMask))
|
||
}
|
||
} else if model.IsSyncStatusNew(act.SyncStatus) {
|
||
globals.SugarLogger.Debugf("=========act := %s", "create")
|
||
createdList, err2 := createSkuAct(ctx, nil, act, actStoreSkuList4Create)
|
||
updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, createdList, model.SyncFlagNewMask)...)
|
||
if err = err2; err == nil {
|
||
updateItems = append(updateItems, partner.Act2Update(ctx, act, model.SyncFlagNewMask))
|
||
}
|
||
} else if model.IsSyncStatusUpdate(act.SyncStatus) {
|
||
globals.SugarLogger.Debugf("=========act := %s", "update")
|
||
if len(actStoreSkuList4Create) > 0 {
|
||
addedList, err2 := createSkuAct(ctx, nil, act, actStoreSkuList4Create)
|
||
updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, addedList, model.SyncFlagNewMask)...)
|
||
if err = err2; err != nil {
|
||
return err
|
||
}
|
||
}
|
||
if len(actStoreSkuList4Delete) > 0 {
|
||
deletedList, err2 := cancelSkuAct(ctx, nil, act, actStoreSkuList4Delete)
|
||
updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, deletedList, model.SyncFlagDeletedMask)...)
|
||
if err = err2; err != nil {
|
||
return err
|
||
}
|
||
}
|
||
if err == nil {
|
||
updateItems = append(updateItems, partner.Act2Update(ctx, act, model.SyncFlagModifiedMask))
|
||
}
|
||
}
|
||
return err
|
||
}()
|
||
db := dao.GetDB()
|
||
_, err2 := dao.BatchUpdateActEntity(db, model.IsSyncStatusDelete(act.SyncStatus), updateItems)
|
||
if err == nil {
|
||
err = err2
|
||
}
|
||
return err
|
||
}
|
||
|
||
func (c *PurchaseHandler) GetActAmple(ctx *jxcontext.Context, vendorStoreID, vendorOrgCode string) (ample int, err error) {
|
||
for _, v := range mtwmapi.ActTypeList {
|
||
//1表示进行中
|
||
if actList, err := getAPI(vendorOrgCode, 0, vendorStoreID).GetByAppPoiCodeAndType(vendorOrgCode, 1, v); err == nil {
|
||
ample += len(actList)
|
||
}
|
||
}
|
||
return ample, err
|
||
}
|
||
|
||
const (
|
||
ActTypeBuy = 1 //买赠活动
|
||
ActTypeDeduction = 2 //商品满减
|
||
ActTypeDirectDown = 3 //折扣(爆品)
|
||
ActTypeXM = 4 //X元M件
|
||
ActTypeN = 5 //第N件优惠
|
||
|
||
ActTypeDeductionAll = 0 //全店满减
|
||
ActTypeDeductionOne = 1 //指定商品满减
|
||
|
||
)
|
||
|
||
func GetActByAppPoiCode(vendorStoreID, vendorOrgCode string, sTime, eTime int64, actType int) (map[int]interface{}, error) {
|
||
if len(vendorStoreID) == 0 || len(vendorOrgCode) == 0 || sTime == 0 || eTime == 0 {
|
||
return nil, errors.New("未选中门店或时间,请检查")
|
||
}
|
||
var (
|
||
temp []interface{}
|
||
resp = make(map[int]interface{})
|
||
a = getAPI(vendorOrgCode, 0, vendorStoreID)
|
||
)
|
||
switch actType {
|
||
case ActTypeDeduction:
|
||
actInfo, err := a.FullDiscountList(vendorStoreID, ActTypeDeductionAll)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
//获取活动商品
|
||
for _, v := range actInfo {
|
||
sku, err := a.FullDiscountFoodsList(vendorStoreID, v.ActInfo.ActIDs)
|
||
//actID := utils.Str2Int(v.ActInfo.ActIDs)
|
||
if err != nil || sku == nil {
|
||
temp = append(temp, actInfo)
|
||
}
|
||
if CheckActTime(sTime, eTime, v.ActInfo.StartTime, v.ActInfo.EndTime) {
|
||
temp = append(temp, sku)
|
||
//temp[actID] = sku
|
||
}
|
||
}
|
||
resp[ActTypeDeduction] = temp
|
||
return resp, nil
|
||
case ActTypeDirectDown:
|
||
killInfo, err := a.RetailDiscountList(vendorStoreID, mtwmapi.RetailActTypeSecKill)
|
||
if err != nil || killInfo == nil {
|
||
resp[mtwmapi.RetailActTypeSecKill] = ""
|
||
} else {
|
||
for _, v := range killInfo {
|
||
if CheckActTime(sTime, eTime, v.StartTime, v.EndTime) {
|
||
temp = append(temp, v)
|
||
}
|
||
}
|
||
resp[mtwmapi.RetailActTypeSecKill] = temp
|
||
}
|
||
downInfo, err1 := a.RetailDiscountList(vendorStoreID, mtwmapi.RetailActTypeDirectDown)
|
||
if err1 != nil || downInfo == nil {
|
||
resp[mtwmapi.RetailActTypeDirectDown] = ""
|
||
} else {
|
||
for _, k := range downInfo {
|
||
if CheckActTime(sTime, eTime, k.StartTime, k.EndTime) {
|
||
temp = append(temp, k)
|
||
}
|
||
}
|
||
resp[mtwmapi.RetailActTypeDirectDown] = temp
|
||
}
|
||
return resp, nil
|
||
}
|
||
return nil, nil
|
||
}
|
||
func CheckActTime(startTime, endTime, sTime, eTime int64) bool {
|
||
if sTime > endTime || eTime < startTime {
|
||
return false
|
||
}
|
||
return true
|
||
}
|