- auto create jd promotion on jd new promotion event

This commit is contained in:
gazebo
2018-11-08 16:08:35 +08:00
parent bd6cf367a0
commit 69aad912cd
5 changed files with 227 additions and 40 deletions

View File

@@ -53,6 +53,18 @@ const (
userName = "jdpromotion"
)
const (
keyPromotionSource = "promotionSource"
keyPromotionStatus = "promotionStatus"
keyLimitDevice = "limitDevice"
keyLimitPin = "limitPin"
keyLimitCount = "limitCount"
keyLimitDaily = "limitDaily"
)
const (
PromotionSourceOpenPlatform = "开放平台"
)
type SkuPrice struct {
SkuID int `json:"skuID"`
PriceType int `json:"priceType"`
@@ -86,7 +98,8 @@ type PromotionParams struct {
type tStoreSkuBindExt struct {
model.StoreSkuBind
JdID int64 `orm:"column(jd_id)"`
JdSkuID int64 `orm:"column(jd_id)"`
VendorStoreID string `orm:"column(vendor_store_id)"`
}
type tPromotionInfo struct {
@@ -101,6 +114,19 @@ var (
ErrEmptySkus = errors.New("空sku或指定的SKU没有被门店认领请检查")
)
var (
jd2jxPromotionStatusMap = map[int]int{
jdapi.PromotionStateNotConfirm: model.PromotionStatusRemoteCreated,
jdapi.PromotionStateConfirmed: model.PromotionStatusRemoteCreated,
jdapi.PromotionStateCanceled: model.PromotionStatusCanceled,
jdapi.PromotionStateEnded: model.PromotionStatusEnded,
}
)
var (
ErrLimitDeviceIsInvalid = errors.New("必须指定一个limitCount当limitPin或limitDevice不都为0时")
)
type JdPromotionHandler interface {
CreatePromotionInfos(name string, beginDate, endDate time.Time, outInfoId, advertising string) (infoId int64, err error)
CreatePromotionRules(infoId int64, outInfoId string, limitDevice, limitPin, limitCount, limitDaily int) (err error)
@@ -198,17 +224,49 @@ func Init() {
scheduleRoutine()
}
func CreateJdPromotion(ctx *jxcontext.Context, isIDJd bool, isAsync, isContinueWhenError bool, vendorPromotionID string, params *PromotionParams, userName string) (hint string, err error) {
func CreateJdPromotion(ctx *jxcontext.Context, isIDJd bool, isAsync, isContinueWhenError bool, vendorPromotionID string, params *PromotionParams, mapData map[string]interface{}) (hint string, err error) {
if vendorPromotionID != "" && len(vendorPromotionID) != len("14863853") {
return "", fmt.Errorf("%s看起来不像是一个有效的京东活动ID请仔细检查一下", vendorPromotionID)
}
if len(params.SkuPrices) == 0 {
return "", ErrEmptySkus
}
limitDaily := 1
if limitDaily2, ok := mapData[keyLimitDaily]; ok {
limitDaily = jxutils.Int2OneZero(limitDaily2.(int))
}
limitPin := 1
if limitPin2, ok := mapData[keyLimitPin]; ok {
limitPin = jxutils.Int2OneZero(limitPin2.(int))
}
limitDevice := 1
if limitDevice2, ok := mapData[keyLimitDevice]; ok {
limitDevice = jxutils.Int2OneZero(limitDevice2.(int))
}
limitCount := 1
if limitCount2, ok := mapData[keyLimitCount]; ok {
limitCount = limitCount2.(int)
}
if (limitDevice == 1 || limitPin == 1) && limitCount == 0 {
return "", ErrLimitDeviceIsInvalid
}
userName := ctx.GetUserName()
db := dao.GetDB()
modifyPricesList := make(map[int][]*jdapi.SkuPriceInfo)
promotionPrices := make([]map[string]interface{}, len(params.StoreIDs)*len(params.SkuPrices))
var jxStoreIDs []int
promotion := &model.Promotion{
Name: params.Name,
Advertising: params.Advertising,
VendorID: model.VendorIDJD,
Type: params.Type,
Status: model.PromotionStatusLocalCreated,
BeginAt: params.BeginAt,
EndAt: params.EndAt,
CreateType: model.PromotionCreateTypeByJX,
Source: PromotionSourceOpenPlatform,
}
if vendorPromotionID == "" {
skuIDs := make([]int, len(params.SkuPrices))
@@ -217,25 +275,24 @@ func CreateJdPromotion(ctx *jxcontext.Context, isIDJd bool, isAsync, isContinueW
skuIDs[k] = v.SkuID
skuPriceMap[int64(v.SkuID)] = v
}
sql := ""
var sqlParam []interface{}
if isIDJd {
sql = `
SELECT t1.*, t2.jd_id
FROM store_sku_bind t1
JOIN sku t2 ON t1.sku_id = t2.id AND t2.deleted_at = ?
JOIN store_map t3 ON t1.store_id = t3.store_id AND t3.vendor_id = ? AND t3.deleted_at = ?
WHERE t1.jd_sync_status = 0 AND t1.deleted_at = ? AND t2.jd_id IN (
` + dao.GenQuestionMarks(len(skuIDs)) + ") AND t3.vendor_store_id = ?"
sqlParam = append(sqlParam, utils.DefaultTimeValue, model.VendorIDJD, utils.DefaultTimeValue)
} else {
sql = `
SELECT t1.*, 0 jd_id
FROM store_sku_bind t1
WHERE t1.jd_sync_status = 0 AND t1.deleted_at = ? AND t1.sku_id IN (
` + dao.GenQuestionMarks(len(skuIDs)) + ") AND t1.store_id = ?"
sql := `
SELECT t1.*, t2.jd_id, t3.vendor_store_id
FROM store_sku_bind t1
JOIN sku t2 ON t1.sku_id = t2.id
JOIN store_map t3 ON t1.store_id = t3.store_id AND t3.vendor_id = ? AND t3.deleted_at = ?
WHERE t1.deleted_at = ?
`
sqlParam := []interface{}{
model.VendorIDJD,
utils.DefaultTimeValue,
utils.DefaultTimeValue,
skuIDs,
}
if isIDJd {
sql += " AND t2.jd_id IN (" + dao.GenQuestionMarks(len(skuIDs)) + ") AND t3.vendor_store_id = ?"
} else {
sql += " AND t1.sku_id IN (" + dao.GenQuestionMarks(len(skuIDs)) + ") AND t1.store_id = ?"
}
sqlParam = append(sqlParam, utils.DefaultTimeValue, skuIDs)
errMsg := ""
index := 0
@@ -250,7 +307,7 @@ func CreateJdPromotion(ctx *jxcontext.Context, isIDJd bool, isAsync, isContinueW
}
mapSkuID := int64(skuBind.SkuID)
if isIDJd {
mapSkuID = skuBind.JdID
mapSkuID = skuBind.JdSkuID
}
promotionSkuPrice := skuPriceMap[mapSkuID]
if promotionSkuPrice.PriceType == PriceTypePercentage {
@@ -272,8 +329,10 @@ func CreateJdPromotion(ctx *jxcontext.Context, isIDJd bool, isAsync, isContinueW
}
}
promotionPrices[index] = map[string]interface{}{
jdapi.KeyOutStationNo: utils.Int2Str(skuBind.StoreID),
jdapi.KeyOutSkuId: utils.Int2Str(skuBind.SkuID),
jdapi.KeyStationNo: utils.Str2Int64(skuBind.VendorStoreID),
jdapi.KeySkuId: skuBind.JdSkuID,
// jdapi.KeyOutStationNo: utils.Int2Str(skuBind.StoreID),
// jdapi.KeyOutSkuId: utils.Int2Str(skuBind.SkuID),
jdapi.KeyPromotionPrice: promotionSkuPrice.Price,
jdapi.KeyLimitSkuCount: promotionSkuPrice.LimitSkuCount,
}
@@ -288,22 +347,17 @@ func CreateJdPromotion(ctx *jxcontext.Context, isIDJd bool, isAsync, isContinueW
if len(promotionPrices) == 0 {
return "", ErrEmptySkus
}
}
promotion := &model.Promotion{
Name: params.Name,
Advertising: params.Advertising,
VendorID: model.VendorIDJD,
Type: params.Type,
Status: model.PromotionStatusLocalCreated,
BeginAt: params.BeginAt,
EndAt: params.EndAt,
CreateType: model.PromotionCreateTypeByJX,
}
if vendorPromotionID != "" {
} else {
promotion.VendorPromotionID = vendorPromotionID
promotion.CreateType = model.PromotionCreateTypeByVendor
if status, ok := mapData[keyPromotionStatus]; ok {
promotion.Status = status.(int)
}
if source, ok := mapData[keyPromotionSource]; ok {
promotion.Source = source.(string)
}
}
dao.WrapAddIDCULDEntity(promotion, userName)
// if promotion.Params, err = jxutils.SerializeData(params); err != nil {
// return "", err
@@ -379,7 +433,7 @@ func CreateJdPromotion(ctx *jxcontext.Context, isIDJd bool, isAsync, isContinueW
task.AddChild(task1).Run()
_, err = task1.GetResult(0)
} else if step == 1 {
err = promotionHandler.CreatePromotionRules(infoId, "", 1, 1, 1, 1)
err = promotionHandler.CreatePromotionRules(infoId, "", limitDevice, limitPin, limitCount, limitDaily)
} else if step == 2 {
task2 := tasksch.NewParallelTask("CreateJdPromotion CreatePromotionSku", tasksch.NewParallelConfig().SetBatchSize(MaxPromotionSkuCount).SetIsContinueWhenError(isContinueWhenError), userName, func(task *tasksch.ParallelTask, batchItemList []interface{}, params2 ...interface{}) (retVal interface{}, err error) {
skus := make([]map[string]interface{}, len(batchItemList))
@@ -873,9 +927,93 @@ func OnStoreStockMsg(msg *jdapi.CallbackStoreStockMsg) (retVal *jdapi.CallbackRe
}
func OnNewPromotionMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
result, err := api.JdAPI.QueryPromotionInfo(utils.Str2Int64(msg.BillID))
return createLocalPromotionFromRemote(utils.Str2Int64(msg.BillID))
}
func createLocalPromotionFromRemote(promotionInfoId int64) (retVal *jdapi.CallbackResponse) {
result, err := api.JdAPI.QueryPromotionInfo(promotionInfoId)
if err == nil {
globals.SugarLogger.Debug(utils.Format4Output(result, false))
db := dao.GetDB()
promotion := &model.Promotion{
VendorPromotionID: utils.Int64ToStr(promotionInfoId),
}
if err = dao.GetEntity(db, promotion, "VendorPromotionID"); dao.IsNoRowsError(err) {
storeIDMap := make(map[int64]int)
skuIDMap := make(map[int64]int)
skuMap := make(map[int64]*jdapi.PromotionSkuResult)
// 注意这样处理可能是有问题我们假定的是门店信息与SKU信息的叉乘
for _, v := range result.SkuResultList {
storeIDMap[v.StationNo] = 1
skuIDMap[v.SkuId] = 1
skuMap[v.SkuId] = v
}
jdStoreIDs := make([]string, len(storeIDMap))
index := 0
for k := range storeIDMap {
jdStoreIDs[index] = utils.Int64ToStr(k)
index++
}
jdSkuIDs := jxutils.Int64Map2List(skuIDMap)
var skuList []*model.Sku
var storeMapList []*model.StoreMap
if err = dao.GetRows(db, &storeMapList, `
SELECT *
FROM store_map
WHERE vendor_id = ? AND deleted_at = ? AND vendor_store_id IN (`+
dao.GenQuestionMarks(len(jdStoreIDs))+")",
model.VendorIDJD, utils.DefaultTimeValue, jdStoreIDs); err != nil {
return jdapi.Err2CallbackResponse(err, "")
}
if err = dao.GetRows(db, &skuList, `
SELECT *
FROM sku
WHERE jd_id IN (`+
dao.GenQuestionMarks(len(jdSkuIDs))+")",
jdSkuIDs); err != nil {
return jdapi.Err2CallbackResponse(err, "")
}
jxStoreIDs := make([]int, len(storeMapList))
for k, v := range storeMapList {
jxStoreIDs[k] = v.StoreID
}
priceList := make([]*SkuPrice, len(skuList))
var skuResult *jdapi.PromotionSkuResult
for k, v := range skuList {
skuResult = skuMap[v.JdID]
priceList[k] = &SkuPrice{
SkuID: v.ID,
PriceType: PriceTypePrice,
Price: skuResult.PromotionPrice,
LimitSkuCount: 0,
IsLock: 0,
}
}
// globals.SugarLogger.Debugf("jxStoreIDs:%s", utils.Format4Output(jxStoreIDs, false))
// globals.SugarLogger.Debugf("priceList:%s", utils.Format4Output(priceList, false))
promotionParams := &PromotionParams{
Name: result.Source + "-" + utils.Int64ToStr(result.PromotionInfoId),
Advertising: "",
Type: result.PromotionType,
BeginAt: result.BeginTime,
EndAt: result.EndTime,
StoreIDs: jxStoreIDs,
SkuPrices: priceList,
}
mapData := map[string]interface{}{
keyPromotionStatus: jd2jxPromotionStatusMap[result.PromotionState],
keyPromotionSource: result.Source,
}
if skuResult != nil {
mapData[keyLimitDaily] = skuResult.LimitDaily
mapData[keyLimitDevice] = skuResult.LimitDevice
mapData[keyLimitPin] = skuResult.LimitPin
}
_, err = CreateJdPromotion(jxcontext.AdminCtx, false, true, false, utils.Int64ToStr(promotionInfoId), promotionParams, mapData)
if dao.IsDuplicateError(err) || err == ErrLimitDeviceIsInvalid {
err = nil
}
}
}
return jdapi.Err2CallbackResponse(err, "")
}

View File

@@ -0,0 +1,23 @@
package promotion
import (
"testing"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
"git.rosy.net.cn/jx-callback/globals/beegodb"
"github.com/astaxie/beego"
)
func init() {
beego.InitBeegoBeforeTest("/Users/xujianhua/go/src/git.rosy.net.cn/jx-callback/conf/app.conf")
beego.BConfig.RunMode = "alpha" // InitBeegoBeforeTest会将runmode设置为test
globals.Init()
beegodb.Init()
api.Init()
}
func TestCreateLocalPromotionFromRemote(t *testing.T) {
t.Log(createLocalPromotionFromRemote(14510904))
}