@@ -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)" `
JdSku ID 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 . JdSku ID
}
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 . KeyOut StationNo : utils . Int2Str ( skuBind . StoreID ) ,
jdapi . KeyOut SkuId : utils . Int2Str ( skuBind . SkuID ) ,
jdapi . KeyStationNo : utils . Str2Int64 ( skuBind . Vendor StoreID) ,
jdapi . KeySkuId : skuBind . Jd SkuID,
// 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 , "" )
}