369 lines
13 KiB
Go
369 lines
13 KiB
Go
package jd
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"git.rosy.net.cn/jx-callback/business/model/dao"
|
|
"git.rosy.net.cn/jx-callback/business/partner"
|
|
|
|
"git.rosy.net.cn/jx-callback/business/jxutils"
|
|
|
|
"git.rosy.net.cn/jx-callback/globals"
|
|
|
|
"git.rosy.net.cn/baseapi/platformapi/jdapi"
|
|
"git.rosy.net.cn/baseapi/utils"
|
|
"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"
|
|
)
|
|
|
|
type LogicUpdateInfo struct {
|
|
Item interface{}
|
|
KVs map[string]interface{}
|
|
Condition map[string]interface{}
|
|
}
|
|
|
|
var (
|
|
jdSkuActStatusMap = map[int]int{
|
|
jdapi.PromotionStateNotConfirm: model.ActStatusNA,
|
|
jdapi.PromotionStateConfirmed: model.ActStatusCreated,
|
|
jdapi.PromotionStateCanceled: model.ActStatusCanceled,
|
|
jdapi.PromotionStateEnded: model.ActStatusEnded,
|
|
}
|
|
)
|
|
|
|
func splitPromotionSku(skus []*jdapi.PromotionSku, maxCount int) (skusList [][]*jdapi.PromotionSku) {
|
|
for {
|
|
skusLen := len(skus)
|
|
if skusLen <= maxCount {
|
|
skusList = append(skusList, skus)
|
|
break
|
|
}
|
|
skusList = append(skusList, skus[:maxCount])
|
|
skus = skus[maxCount:]
|
|
}
|
|
return skusList
|
|
}
|
|
|
|
func jdSkuActType2Jx(actType int) int {
|
|
if actType == jdapi.PromotionTypeDirectDown {
|
|
return model.ActSkuDirectDown
|
|
} else if actType == jdapi.PromotionTypeSeckill || actType == jdapi.PromotionTypeLimitedTime {
|
|
return model.ActSkuSecKill
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func jdSkuActStatus2Jx(jdActState int) int {
|
|
return jdSkuActStatusMap[jdActState]
|
|
}
|
|
|
|
func CreatePromotionInfos(promotionType int, name string, beginDate, endDate time.Time, outInfoId, advertising, traceId string) (infoId int64, err error) {
|
|
if globals.EnableJdStoreWrite {
|
|
if promotionType == model.ActSkuDirectDown {
|
|
return getAPI("").CreatePromotionInfosSingle(name, beginDate, endDate, outInfoId, advertising, traceId)
|
|
} else {
|
|
return getAPI("").CreatePromotionInfosLimitTime(name, beginDate, endDate, outInfoId, advertising, traceId)
|
|
}
|
|
} else {
|
|
infoId = jxutils.GenFakeID()
|
|
}
|
|
return infoId, err
|
|
}
|
|
|
|
func CreatePromotionRules(promotionType int, infoId int64, outInfoId string, limitDevice, limitPin, limitCount, limitDaily int, traceId string) (err error) {
|
|
if globals.EnableJdStoreWrite {
|
|
if promotionType == model.ActSkuDirectDown {
|
|
return getAPI("").CreatePromotionRulesSingle(infoId, outInfoId, limitDevice, limitPin, limitCount, limitDaily, traceId)
|
|
} else {
|
|
return getAPI("").CreatePromotionRulesLimitTime(infoId, outInfoId, limitDevice, limitPin, limitCount, limitDaily, traceId)
|
|
}
|
|
}
|
|
return err
|
|
}
|
|
|
|
func CreatePromotionSku(promotionType int, infoId int64, outInfoId string, skus []*jdapi.PromotionSku, traceId string) (skusResult []*jdapi.PromotionSku, err error) {
|
|
if globals.EnableJdStoreWrite {
|
|
for _, batchSkus := range splitPromotionSku(skus, jdapi.MaxPromotionSkuCount) {
|
|
var tmpSkusResult []*jdapi.PromotionSku
|
|
var tmpErr error
|
|
if promotionType == model.ActSkuDirectDown {
|
|
tmpSkusResult, tmpErr = getAPI("").CreatePromotionSkuSingle(infoId, outInfoId, batchSkus, traceId)
|
|
} else {
|
|
tmpSkusResult, tmpErr = getAPI("").CreatePromotionSkuLimitTime(infoId, outInfoId, batchSkus, traceId)
|
|
}
|
|
if err = tmpErr; err != nil {
|
|
break
|
|
}
|
|
skusResult = append(skusResult, tmpSkusResult...)
|
|
}
|
|
}
|
|
return skusResult, err
|
|
}
|
|
|
|
func CancelPromotionSku(promotionType int, infoId int64, outInfoId string, skus []*jdapi.PromotionSku, traceId string) (err error) {
|
|
if globals.EnableJdStoreWrite {
|
|
for _, batchSkus := range splitPromotionSku(skus, jdapi.MaxPromotionSkuCount) {
|
|
var tmpErr error
|
|
if promotionType == model.ActSkuDirectDown {
|
|
tmpErr = getAPI("").CancelPromotionSkuSingle(infoId, outInfoId, batchSkus, traceId)
|
|
} else {
|
|
tmpErr = getAPI("").CancelPromotionSkuLimitTime(infoId, outInfoId, batchSkus, traceId)
|
|
}
|
|
if err = tmpErr; err != nil {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
return err
|
|
}
|
|
|
|
func ConfirmPromotion(promotionType int, infoId int64, outInfoId, traceId string) (err error) {
|
|
if globals.EnableJdStoreWrite {
|
|
if promotionType == model.ActSkuDirectDown {
|
|
return getAPI("").ConfirmPromotionSingle(infoId, outInfoId, traceId)
|
|
} else {
|
|
return getAPI("").ConfirmPromotionLimitTime(infoId, outInfoId, traceId)
|
|
}
|
|
}
|
|
return err
|
|
}
|
|
|
|
func CancelPromotion(promotionType int, infoId int64, outInfoId, traceId string) (err error) {
|
|
if globals.EnableJdStoreWrite {
|
|
if promotionType == model.ActSkuDirectDown {
|
|
return getAPI("").CancelPromotionSingle(infoId, outInfoId, traceId)
|
|
} else {
|
|
return getAPI("").CancelPromotionLimitTime(infoId, outInfoId, traceId)
|
|
}
|
|
}
|
|
return err
|
|
}
|
|
|
|
func AdjustPromotionTime(promotionType int, infoId int64, outInfoId string, endDate time.Time, traceId string) (err error) {
|
|
if globals.EnableJdStoreWrite {
|
|
if promotionType == model.ActSkuDirectDown {
|
|
return getAPI("").AdjustPromotionTimeSingle(infoId, outInfoId, endDate, traceId)
|
|
} else {
|
|
return getAPI("").AdjustPromotionTimeLimitTime(infoId, outInfoId, endDate, traceId)
|
|
}
|
|
}
|
|
return err
|
|
}
|
|
|
|
func AdjustPromotionSku(promotionType int, infoId int64, outInfoId string, skus []*jdapi.PromotionSku, traceId string) (skusResult []*jdapi.PromotionSku, err error) {
|
|
if globals.EnableJdStoreWrite {
|
|
if promotionType == model.ActSkuDirectDown {
|
|
return getAPI("").AdjustPromotionSkuSingle(infoId, outInfoId, skus, traceId)
|
|
} else {
|
|
return getAPI("").AdjustPromotionSkuLimitTime(infoId, outInfoId, skus, traceId)
|
|
}
|
|
}
|
|
return skusResult, err
|
|
}
|
|
|
|
func storeSku2Jd(actStoreSku []*model.ActStoreSku2, handler func(syncStatus int8) bool) (jdActStoreSku []*jdapi.PromotionSku) {
|
|
for _, v := range actStoreSku {
|
|
if handler(v.SyncStatus) {
|
|
if v.VendorStoreID != "" && v.VendorSkuID != "" {
|
|
jdActStoreSku = append(jdActStoreSku, &jdapi.PromotionSku{
|
|
StationNo: utils.Str2Int64(v.VendorStoreID),
|
|
SkuID: utils.Str2Int64(v.VendorSkuID),
|
|
PromotionPrice: v.ActualActPrice,
|
|
LimitSkuCount: v.Stock,
|
|
})
|
|
}
|
|
}
|
|
}
|
|
return jdActStoreSku
|
|
}
|
|
|
|
func createSkuAct(ctx *jxcontext.Context, act *model.Act2, actStoreSku []*model.ActStoreSku2) (vendorActID string, err error) {
|
|
traceInfo := ctx.GetTrackInfo()
|
|
outInfoID := ""
|
|
if act.VendorActID == "" {
|
|
outInfoID = utils.Int2Str(act.ID)
|
|
}
|
|
infoID, err2 := CreatePromotionInfos(act.Type, act.GetRealActName(), act.BeginAt, act.EndAt, outInfoID, act.Advertising, traceInfo)
|
|
if err = err2; err == nil {
|
|
vendorActID = utils.Int64ToStr(infoID)
|
|
if err = CreatePromotionRules(act.Type, infoID, "", act.LimitUser, act.LimitUser, act.LimitCount, 1, traceInfo); err == nil {
|
|
if _, err = CreatePromotionSku(act.Type, infoID, "", storeSku2Jd(actStoreSku, model.IsSyncStatusNeedCreate), traceInfo); err == nil {
|
|
if err = ConfirmPromotion(act.Type, infoID, "", traceInfo); err == nil {
|
|
for _, v := range actStoreSku {
|
|
v.VendorActID = vendorActID
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if err != nil {
|
|
CancelPromotion(act.Type, infoID, "", traceInfo)
|
|
}
|
|
}
|
|
return vendorActID, err
|
|
}
|
|
|
|
func cancelSkuActSkus(ctx *jxcontext.Context, actType int, vendorActID string, actStoreSku []*model.ActStoreSku2) (err error) {
|
|
if vendorActID != "" {
|
|
if skuList := storeSku2Jd(actStoreSku, model.IsSyncStatusNeedDelete); len(skuList) > 0 {
|
|
err = CancelPromotionSku(actType, utils.Str2Int64(vendorActID), "", skuList, ctx.GetTrackInfo())
|
|
}
|
|
}
|
|
return err
|
|
}
|
|
|
|
func cancelSkuAct(ctx *jxcontext.Context, actType int, vendorActID string) (err error) {
|
|
if vendorActID != "" {
|
|
err = CancelPromotion(actType, utils.Str2Int64(vendorActID), "", ctx.GetTrackInfo())
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (c *PurchaseHandler) SyncAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actOrderRules []*model.ActOrderRule, actStoreSkuList []*model.ActStoreSku2) (err error) {
|
|
globals.SugarLogger.Debugf("jd SyncAct, actID:%d", act.ID)
|
|
vendorActInfoMap := make(map[string][]*model.ActStoreSku2)
|
|
deleteActInfoMap := make(map[string][]*model.ActStoreSku2)
|
|
var actStoreSkuList4Create []*model.ActStoreSku2
|
|
var updateItems []*dao.KVUpdateItem
|
|
|
|
actStoreSkuMap := partner.SplitActStoreSku(actStoreSkuList)
|
|
for storeID := range actStoreSkuMap {
|
|
for _, actStoreSku := range actStoreSkuMap[storeID] {
|
|
vendorActInfoMap[actStoreSku.VendorActID] = append(vendorActInfoMap[actStoreSku.VendorActID], actStoreSku)
|
|
if model.IsSyncStatusDelete(actStoreSku.SyncStatus) {
|
|
vendorActID := actStoreSku.VendorActID
|
|
if vendorActID == "" {
|
|
vendorActID = act.VendorActID
|
|
}
|
|
deleteActInfoMap[vendorActID] = append(deleteActInfoMap[vendorActID], actStoreSku)
|
|
} else if model.IsSyncStatusNew(actStoreSku.SyncStatus) {
|
|
actStoreSkuList4Create = append(actStoreSkuList4Create, actStoreSku)
|
|
}
|
|
}
|
|
}
|
|
err = func() (err error) {
|
|
if model.IsSyncStatusDelete(act.SyncStatus) {
|
|
for vendorActID := range vendorActInfoMap {
|
|
if vendorActID != "" {
|
|
if err = cancelSkuAct(ctx, act.Type, vendorActID); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
for _, actStoreSkuList := range vendorActInfoMap {
|
|
updateItems = append(updateItems, partner.ActStoreSku2Update(actStoreSkuList, model.SyncFlagModifiedMask)...)
|
|
}
|
|
updateItems = append(updateItems, partner.Act2Update(act, model.SyncFlagModifiedMask))
|
|
} else if model.IsSyncStatusNew(act.SyncStatus) {
|
|
if act.VendorActID, err = createSkuAct(ctx, act, actStoreSkuList4Create); err != nil {
|
|
return err
|
|
}
|
|
updateItems = append(updateItems, partner.ActStoreSku2Update(actStoreSkuList4Create, model.SyncFlagNewMask)...)
|
|
updateItems = append(updateItems, partner.Act2Update(act, model.SyncFlagNewMask))
|
|
} else if model.IsSyncStatusUpdate(act.SyncStatus) {
|
|
// globals.SugarLogger.Debug(utils.Format4Output(updateItems, false))
|
|
if len(actStoreSkuList4Create) > 0 {
|
|
if _, err = createSkuAct(ctx, act, actStoreSkuList4Create); err != nil {
|
|
return err
|
|
}
|
|
updateItems = append(updateItems, partner.ActStoreSku2Update(actStoreSkuList4Create, model.SyncFlagNewMask)...)
|
|
}
|
|
for vendorActID := range deleteActInfoMap {
|
|
if vendorActID != "" {
|
|
if len(vendorActInfoMap[vendorActID]) == len(deleteActInfoMap[vendorActID]) {
|
|
// todo 如果这个取消导致了整活动被取消的话,怎么设置京西活动的状态
|
|
err = cancelSkuAct(ctx, act.Type, vendorActID)
|
|
} else {
|
|
err = cancelSkuActSkus(ctx, act.Type, vendorActID, deleteActInfoMap[vendorActID])
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
updateItems = append(updateItems, partner.ActStoreSku2Update(deleteActInfoMap[vendorActID], model.SyncFlagDeletedMask)...)
|
|
}
|
|
if err == nil {
|
|
updateItems = append(updateItems, partner.Act2Update(act, model.SyncFlagModifiedMask))
|
|
}
|
|
}
|
|
return err
|
|
}()
|
|
db := dao.GetDB()
|
|
// globals.SugarLogger.Debug(utils.Format4Output(updateItems, false))
|
|
_, err2 := dao.BatchUpdateEntityByKV(db, updateItems)
|
|
if err == nil {
|
|
err = err2
|
|
}
|
|
return err
|
|
}
|
|
|
|
func OnActMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
|
|
jxutils.CallMsgHandler(func() {
|
|
retVal = curPurchaseHandler.onActMsg(msg)
|
|
}, jxutils.ComposeUniversalOrderID(msg.BillID, model.VendorIDJD))
|
|
return retVal
|
|
}
|
|
|
|
func (c *PurchaseHandler) onActMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
|
|
if msg.StatusID == jdapi.PromotionStatusSingleOK || msg.StatusID == jdapi.PromotionStatusLimitTimeOK {
|
|
promotionID := msg.BillID
|
|
// 等几秒再执行的原因是防止通过后台自己创建时,本地还没有建好,消息就过来,导致重复记录
|
|
// 可能的问题是在重启时丢失消息
|
|
utils.AfterFuncWithRecover(5*time.Second, func() {
|
|
if !partner.CurActManager.IsVendorActExist(jxcontext.AdminCtx, promotionID, model.VendorIDJD) {
|
|
act, actStoreSkuList, err := getActFromJD(promotionID)
|
|
if err == nil && len(actStoreSkuList) > 0 {
|
|
_, err = partner.CurActManager.CreateActFromVendor(jxcontext.AdminCtx, act, actStoreSkuList)
|
|
}
|
|
if err != nil {
|
|
retVal = jdapi.Err2CallbackResponse(err, promotionID)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
return retVal
|
|
}
|
|
|
|
func getActFromJD(promotionID string) (act *model.Act2, actStoreSkuList []*model.ActStoreSku2, err error) {
|
|
result, err := getAPI("").QueryPromotionInfo(utils.Str2Int64(promotionID))
|
|
if err == nil && len(result.SkuResultList) > 0 {
|
|
act = &model.Act2{
|
|
Act: model.Act{
|
|
Name: fmt.Sprintf("%s-%d", result.Source, result.PromotionInfoID),
|
|
Type: jdSkuActType2Jx(result.PromotionType),
|
|
Status: jdSkuActStatus2Jx(result.PromotionState),
|
|
BeginAt: result.SkuResultList[0].BeginTime.GoTime(),
|
|
EndAt: result.SkuResultList[0].EndTime.GoTime(),
|
|
Source: result.Source,
|
|
CreateType: model.ActCreateTypeCallback,
|
|
PricePercentage: 0,
|
|
LimitDaily: result.SkuResultList[0].LimitDaily,
|
|
LimitCount: 1,
|
|
},
|
|
VendorID: model.VendorIDJD,
|
|
VendorActID: promotionID,
|
|
}
|
|
if utils.IsTimeZero(act.BeginAt) {
|
|
act.BeginAt = result.BeginTime.GoTime()
|
|
}
|
|
if utils.IsTimeZero(act.EndAt) {
|
|
act.EndAt = result.EndTime.GoTime().Add(24*time.Hour - 1*time.Second)
|
|
}
|
|
if result.SkuResultList[0].LimitPin == 1 || result.SkuResultList[0].LimitDevice == 1 {
|
|
act.LimitUser = 1
|
|
}
|
|
|
|
for _, v := range result.SkuResultList {
|
|
if v.PromotionState != jdapi.PromotionStateCanceled {
|
|
actStoreSkuList = append(actStoreSkuList, &model.ActStoreSku2{
|
|
VendorStoreID: utils.Int64ToStr(v.StationNo),
|
|
VendorSkuID: utils.Int64ToStr(v.SkuID),
|
|
ActualActPrice: int64(v.PromotionPrice),
|
|
})
|
|
}
|
|
}
|
|
}
|
|
return act, actStoreSkuList, err
|
|
}
|