- get and cancel promotion

This commit is contained in:
gazebo
2018-11-05 15:08:30 +08:00
parent 34c74cd40a
commit cf4bfb3dd8
5 changed files with 326 additions and 35 deletions

View File

@@ -32,11 +32,6 @@ const (
PromotionLimitedTimeMinPercentage = 80
)
const (
PromotionStatusCreated = 1
PromotionStatusEnded = 2
)
const (
colSkuIDIndex = 0
colSkuPriceIndex = 3
@@ -51,11 +46,16 @@ const (
MaxPromotionSkuCount = jdapi.MaxPromotionSkuCount
)
const (
defSearchDays = 7
)
type SkuPrice struct {
SkuID int `json:"skuID"`
PriceType int `json:"priceType"`
Price int `json:"price"` // 分,这个不是单价
LimitSkuCount int `json:"limitSkuCount"`
SkuID int `json:"skuID"`
PriceType int `json:"priceType"`
Price int `json:"price"` // 分,这个不是单价是这个sku的活动价
LimitSkuCount int `json:"limitSkuCount"`
IsLock int8 `json:"isLock"`
}
type PromotionParams struct {
@@ -73,6 +73,14 @@ type tStoreSkuBindExt struct {
JdID int64 `orm:"column(jd_id)"`
}
type tPromotionInfo struct {
model.Promotion
StoreIDStr string `orm:"column(store_id_str)" json:"-"`
SkuPriceStr string `orm:"column(sku_price_str)" json:"-"`
StoreIDs []int `orm:"-" json:"storeIDs"`
SkuPrices []*SkuPrice `orm:"-" json:"skuPrices"`
}
var (
ErrEmptySkus = errors.New("空sku或指定的SKU没有被门店认领请检查")
)
@@ -82,6 +90,7 @@ type JdPromotionHandler interface {
CreatePromotionRules(infoId int64, outInfoId string, limitDevice, limitPin, limitCount, limitDaily int) (err error)
CreatePromotionSku(infoId int64, outInfoId string, skus []map[string]interface{}) (skusResult []map[string]interface{}, err error)
ConfirmPromotion(infoId int64, outInfoId string) (err error)
CancelPromotion(infoId int64, outInfoId string) (err error)
}
type JdDirectDownHandler struct {
@@ -99,6 +108,9 @@ func (p *JdDirectDownHandler) CreatePromotionSku(infoId int64, outInfoId string,
func (p *JdDirectDownHandler) ConfirmPromotion(infoId int64, outInfoId string) (err error) {
return api.JdAPI.ConfirmPromotionSingle(infoId, outInfoId)
}
func (p *JdDirectDownHandler) CancelPromotion(infoId int64, outInfoId string) (err error) {
return api.JdAPI.CancelPromotionSingle(infoId, outInfoId)
}
type JdLimitedTimeHandler struct {
}
@@ -115,6 +127,9 @@ func (p *JdLimitedTimeHandler) CreatePromotionSku(infoId int64, outInfoId string
func (p *JdLimitedTimeHandler) ConfirmPromotion(infoId int64, outInfoId string) (err error) {
return api.JdAPI.ConfirmPromotionLimitTime(infoId, outInfoId)
}
func (p *JdLimitedTimeHandler) CancelPromotion(infoId int64, outInfoId string) (err error) {
return api.JdAPI.CancelPromotionLimitTime(infoId, outInfoId)
}
type JdNullHandler struct {
}
@@ -131,6 +146,9 @@ func (p *JdNullHandler) CreatePromotionSku(infoId int64, outInfoId string, skus
func (p *JdNullHandler) ConfirmPromotion(infoId int64, outInfoId string) (err error) {
return nil
}
func (p *JdNullHandler) CancelPromotion(infoId int64, outInfoId string) (err error) {
return nil
}
func init() {
gob.Register(&PromotionParams{})
@@ -224,19 +242,19 @@ func CreateJdPromotion(ctx *jxcontext.Context, isIDJd bool, isAsync bool, params
}
promotion := &model.Promotion{
Name: params.Name,
VendorID: model.VendorIDJD,
Type: params.Type,
Status: PromotionStatusCreated,
SyncStatus: model.SyncFlagNewMask,
BeginAt: params.BeginAt,
EndAt: params.EndAt,
Name: params.Name,
Advertising: params.Advertising,
VendorID: model.VendorIDJD,
Type: params.Type,
Status: model.PromotionStatusLocalCreated,
BeginAt: params.BeginAt,
EndAt: params.EndAt,
}
dao.WrapAddIDCULDEntity(promotion, userName)
// if promotion.Params, err = jxutils.SerializeData(params); err != nil {
// return "", err
// }
promotion.Params = string(utils.MustMarshal(params))
// promotion.Params = string(utils.MustMarshal(params))
dao.Begin(db)
defer func() {
dao.Rollback(db)
@@ -246,18 +264,32 @@ func CreateJdPromotion(ctx *jxcontext.Context, isIDJd bool, isAsync bool, params
return "", err
}
var promotionHandler JdPromotionHandler
if params.Type == PromotionTypeDirectDown {
promotionHandler = &JdDirectDownHandler{}
} else if params.Type == PromotionTypeLimitedTime {
promotionHandler = &JdLimitedTimeHandler{}
} else {
panic(fmt.Sprintf("unknown promotion type:%d", params.Type))
for _, storeID := range params.StoreIDs {
promotionStore := &model.PromotionStore{
PromotionID: promotion.ID,
StoreID: storeID,
}
if err = dao.CreateEntity(db, promotionStore); err != nil {
return "", err
}
}
if !globals.EnableStoreWrite {
promotionHandler = &JdNullHandler{}
for _, skuPrice := range params.SkuPrices {
promotionSku := &model.PromotionSku{
PromotionID: promotion.ID,
SkuID: skuPrice.SkuID,
PriceType: skuPrice.PriceType,
Price: skuPrice.Price,
LimitSkuCount: skuPrice.LimitSkuCount,
}
if err = dao.CreateEntity(db, promotionSku); err != nil {
return "", err
}
}
promotionHandler := getPromotionHander(params.Type)
if promotionHandler == nil {
return "", errors.New("非法的促销类型")
}
infoId, err2 := promotionHandler.CreatePromotionInfos(params.Name, params.BeginAt, params.EndAt, utils.Int2Str(promotion.ID), params.Advertising)
if err = err2; err != nil {
return "", err
@@ -301,6 +333,14 @@ func CreateJdPromotion(ctx *jxcontext.Context, isIDJd bool, isAsync bool, params
_, err = task2.GetResult(0)
} else if step == 3 {
err = promotionHandler.ConfirmPromotion(infoId, "")
if err == nil {
promotion.Status = model.PromotionStatusRemoteCreated
} else {
promotion.Status = model.PromotionStatusRemoteFailed
}
db := dao.GetDB()
dao.WrapUpdateULEntity(promotion, userName)
_, err = dao.UpdateEntity(db, promotion, "Status")
}
return nil, err
}, 4)
@@ -362,6 +402,166 @@ func CreateJdPromotion(ctx *jxcontext.Context, isIDJd bool, isAsync bool, params
// return CreateJdPromotion(ctx, true, isAsync, promotionParams, userName)
// }
func GetJdPromotions(ctx *jxcontext.Context, keyword string, params map[string]interface{}, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
sql := `
SELECT SQL_CALC_FOUND_ROWS
t1.id,
t1.created_at,
t1.updated_at,
t1.last_operator,
t1.vendor_id,
t1.name,
t1.type,
t1.status,
t1.vendor_promotion_id,
t1.begin_at,
t1.end_at,
t1.advertising,
CONCAT("[", GROUP_CONCAT(DISTINCT t2.store_id), "]") store_id_str,
CONCAT("[", GROUP_CONCAT(DISTINCT CONCAT('{"skuID":', t3.sku_id, ', "priceType":', t3.price_type, ', "price":', t3.price, ', "limitSkuCount":', t3.limit_sku_count, ', "isLock":', t3.is_lock, '}')), "]") sku_price_str
FROM promotion t1
JOIN promotion_store t2 ON t1.id = t2.promotion_id
JOIN promotion_sku t3 ON t1.id = t3.promotion_id
WHERE t1.deleted_at = ?
`
sqlParams := []interface{}{
utils.DefaultTimeValue,
}
if keyword != "" {
keywordLike := "%" + keyword + "%"
sql += " AND ( t1.name LIKE ?"
sqlParams = append(sqlParams, keywordLike)
keywordInt := utils.Str2Int64WithDefault(keyword, 0)
if keywordInt > 0 {
sql += `
OR t1.id = ? OR t1.vendor_promotion_id = ?
OR (SELECT COUNT(*) FROM promotion_store tt1 WHERE tt1.promotion_id = t1.id AND tt1.store_id = ?) > 0
OR (SELECT COUNT(*) FROM promotion_sku tt1 WHERE tt1.promotion_id = t1.id AND tt1.sku_id = ?) > 0
`
sqlParams = append(sqlParams, keywordInt, keywordInt, keywordInt, keywordInt)
}
sql += ")"
}
if params["vendorID"] != nil {
sql += " AND t1.vendor_id = ?"
sqlParams = append(sqlParams, params["vendorID"].(int))
}
if params["promotionID"] != nil {
sql += " AND t1.id = ?"
sqlParams = append(sqlParams, params["promotionID"].(int))
}
if params["vendorPromotionID"] != nil {
sql += " AND t1.vendor_promotion_id = ?"
sqlParams = append(sqlParams, params["vendorPromotionID"].(int))
}
if params["name"] != nil {
sql += " AND t1.name LIKE ?"
sqlParams = append(sqlParams, "%"+params["name"].(string)+"%")
}
if params["beginAt"] != nil {
sql += " AND t1.begin_at <= ?"
sqlParams = append(sqlParams, utils.Str2Time(params["beginAt"].(string)))
}
if params["endAt"] != nil {
sql += " AND t1.end_at >= ?"
sqlParams = append(sqlParams, utils.Str2Time(params["endAt"].(string)))
}
days := defSearchDays
if params["days"] != nil {
days = params["days"].(int)
}
sql += " AND t1.created_at >= ?"
sqlParams = append(sqlParams, time.Now().Add(-time.Duration(days)*24*time.Hour))
if params["type"] != nil {
sql += " AND t1.type = ?"
sqlParams = append(sqlParams, params["type"].(int))
}
if params["storeID"] != nil {
sql += " AND (SELECT COUNT(*) FROM promotion_store tt1 WHERE tt1.promotion_id = t1.id AND tt1.store_id = ?) > 0"
sqlParams = append(sqlParams, params["storeID"].(int))
}
if params["skuID"] != nil {
sql += " AND (SELECT COUNT(*) FROM promotion_sku tt1 WHERE tt1.promotion_id = t1.id AND tt1.sku_id = ?) > 0"
sqlParams = append(sqlParams, params["skuID"].(int))
}
sql += `
GROUP BY
1,2,3,4,5,6,7,8,9,10,11,12
ORDER BY t1.id DESC
LIMIT ? OFFSET ?
`
pageSize = jxutils.FormalizePageSize(pageSize)
if offset < 0 {
offset = 0
}
sqlParams = append(sqlParams, pageSize, offset)
db := dao.GetDB()
dao.Begin(db)
defer func() {
dao.Rollback(db)
if r := recover(); r != nil {
panic(r)
}
}()
// globals.SugarLogger.Debug(utils.Format4Output(sqlParams, false))
// globals.SugarLogger.Debug(sql)
var promotionList []*tPromotionInfo
if err = dao.GetRows(db, &promotionList, sql, sqlParams...); err == nil {
for _, v := range promotionList {
if v.StoreIDStr != "" {
if err = utils.UnmarshalUseNumber([]byte(v.StoreIDStr), &v.StoreIDs); err != nil {
return nil, err
}
}
if v.SkuPriceStr != "" {
if err = utils.UnmarshalUseNumber([]byte(v.SkuPriceStr), &v.SkuPrices); err != nil {
return nil, err
}
}
}
pagedInfo = &model.PagedInfo{}
countInfo := &struct{ Ct int }{}
if err = dao.GetRow(db, countInfo, "SELECT FOUND_ROWS() ct"); err == nil {
pagedInfo.TotalCount = countInfo.Ct
}
pagedInfo.Data = promotionList
}
dao.Commit(db)
return pagedInfo, err
}
func CancelJdPromotion(ctx *jxcontext.Context, promotionID int) (err error) {
db := dao.GetDB()
promotion := model.Promotion{}
promotion.ID = promotionID
if err = dao.GetEntity(db, promotion); err != nil {
return err
}
promotionHandler := getPromotionHander(promotion.Type)
if promotionHandler == nil {
return errors.New("非法的促销类型")
}
err = promotionHandler.CancelPromotion(utils.Str2Int64(promotion.VendorPromotionID), "")
return err
}
func excelStr2Time(timeStr string) (tm time.Time, err error) {
return time.ParseInLocation("2006年1月2日15点4分5秒", timeStr, time.Local)
}
func getPromotionHander(promotionType int) JdPromotionHandler {
var promotionHandler JdPromotionHandler
if promotionType == PromotionTypeDirectDown {
promotionHandler = &JdDirectDownHandler{}
} else if promotionType == PromotionTypeLimitedTime {
promotionHandler = &JdLimitedTimeHandler{}
} else {
// panic(fmt.Sprintf("unknown promotion type:%d", promotionType))
return nil
}
if !globals.EnableStoreWrite {
promotionHandler = &JdNullHandler{}
}
return promotionHandler
}

View File

@@ -4,18 +4,25 @@ import (
"time"
)
const (
PromotionStatusLocalCreated = 0 // 本地成功创建,
PromotionStatusRemoteFailed = 1 // 远程创建失败,
PromotionStatusRemoteCreated = 2 // 远程成功创建,
PromotionStatusCanceled = 3 // 被显示取消
PromotionStatusEnded = 4 // 已经超过活动时间,且被显示置为结束
)
type Promotion struct {
ModelIDCULD
VendorID int `orm:"column(vendor_id)"`
Name string `orm:"size(64)" json:"name"`
Type int
Status int
SyncStatus int
VendorID int `orm:"column(vendor_id)"`
Name string `orm:"size(64)" json:"name"`
Advertising string `orm:"size(255)" json:"advertising"`
Type int `json:"type"`
Status int `json:"status"`
VendorPromotionID string `orm:"size(64);column(vendor_promotion_id);index" json:"vendorPromotionID"`
BeginAt time.Time `orm:"type(datetime);index" json:"beginAt"`
EndAt time.Time `orm:"type(datetime);index" json:"endAt"`
Params string `orm:"type(text)" json:"params"`
}
func (*Promotion) TableUnique() [][]string {
@@ -23,3 +30,31 @@ func (*Promotion) TableUnique() [][]string {
[]string{"Name", "VendorID", "Type", "DeletedAt"},
}
}
type PromotionStore struct {
ID int `orm:"column(id)" json:"id"`
PromotionID int `orm:"column(promotion_id)" json:"promotionID"`
StoreID int `orm:"column(store_id)" json:"storeID"`
}
func (*PromotionStore) TableUnique() [][]string {
return [][]string{
[]string{"PromotionID", "StoreID"},
}
}
type PromotionSku struct {
ID int `orm:"column(id)" json:"id"`
PromotionID int `orm:"column(promotion_id)" json:"promotionID"`
SkuID int `orm:"column(sku_id)" json:"skuID"`
PriceType int `json:"priceType"`
Price int `json:"price"` // 分,活动价,这个不是单价
LimitSkuCount int `json:"limitSkuCount"`
IsLock int8 `json:"isLock"` // 是否锁定门店商品信息
}
func (*PromotionSku) TableUnique() [][]string {
return [][]string{
[]string{"PromotionID", "SkuID"},
}
}

View File

@@ -19,8 +19,8 @@ type PromotionController struct {
// @Param token header string true "认证token"
// @Param vendorID formData int true "厂商ID当前只支持京东0 "
// @Param name formData string true "促销名,必须唯一(所以名子上最好带上日期)"
// @Param beginAt formData string true "开始时间"
// @Param endAt formData string true "结束时间"
// @Param beginAt formData string true "开始日期"
// @Param endAt formData string true "结束日期"
// @Param type formData int true "促销类型3直降4限时抢购"
// @Param storeIDs formData string true "json数据storeID列表[1,2,3]"
// @Param skuPrices formData string true "json数据价格信息列表"
@@ -99,3 +99,43 @@ func (c *PromotionController) SendAdvertingByGoodsOrder() {
return retVal, "", err
})
}
// @Title 查询促销
// @Description 查询促销
// @Param token header string true "认证token"
// @Param keyword query string false "关键字"
// @Param vendorID query int false "厂商ID当前只支持京东0 "
// @Param promotionID query int false "活动id"
// @Param vendorPromotionID query int false "厂商活动id"
// @Param days query int false "多少天内创建的缺省7天"
// @Param name query string false "促销名,不完全匹配"
// @Param beginAt query string false "开始日期,包括"
// @Param endAt query string false "结束日期,包括"
// @Param type query int false "促销类型3直降4限时抢购"
// @Param storeID query int false "包含门店"
// @Param skuID query int false "包含sku"
// @Param offset query int false "活动列表起始序号以0开始缺省为0"
// @Param pageSize query int false "活动列表页大小缺省为50-1表示全部"
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /GetPromotions [get]
func (c *PromotionController) GetPromotions() {
c.callGetPromotions(func(params *tPromotionGetPromotionsParams) (retVal interface{}, errCode string, err error) {
retVal, err = promotion.GetJdPromotions(params.Ctx, params.Keyword, params.MapData, params.Offset, params.PageSize)
return retVal, "", err
})
}
// @Title 查询促销
// @Description 查询促销
// @Param token header string true "认证token"
// @Param promotionID query int true "活动id"
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /CancelPomotion [put]
func (c *PromotionController) CancelPomotion() {
c.callCancelPomotion(func(params *tPromotionCancelPomotionParams) (retVal interface{}, errCode string, err error) {
err = promotion.CancelJdPromotion(params.Ctx, params.PromotionID)
return retVal, "", err
})
}

View File

@@ -34,7 +34,7 @@ func Init() {
orm.RegisterModel(&model.SkuCategory{})
// orm.RegisterModel(&model.DurableTask{}, &model.DurableTaskItem{})
orm.RegisterModel(&model.Promotion{})
orm.RegisterModel(&model.Promotion{}, &model.PromotionStore{}, &model.PromotionSku{})
}
// create table
orm.RunSyncdb("default", false, true)

View File

@@ -215,6 +215,14 @@ func init() {
MethodParams: param.Make(),
Params: nil})
beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:PromotionController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:PromotionController"],
beego.ControllerComments{
Method: "CancelPomotion",
Router: `/CancelPomotion`,
AllowHTTPMethods: []string{"put"},
MethodParams: param.Make(),
Params: nil})
beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:PromotionController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:PromotionController"],
beego.ControllerComments{
Method: "CreatePromotion",
@@ -223,6 +231,14 @@ func init() {
MethodParams: param.Make(),
Params: nil})
beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:PromotionController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:PromotionController"],
beego.ControllerComments{
Method: "GetPromotions",
Router: `/GetPromotions`,
AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(),
Params: nil})
beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:PromotionController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:PromotionController"],
beego.ControllerComments{
Method: "SendAdvertingByGoodsOrder",