package mtwmapi import ( "git.rosy.net.cn/jx-callback/globals" "strings" "git.rosy.net.cn/baseapi/utils" ) const ( ActTypeStoreFullDiscount = 0 ActTypeSkuFullDiscount = 1 RetailActTypeDirectDown = 1001 // 折扣活动 RetailActTypeSecKill = 56 // 爆品活动 MaxRetailDiscountCreateBatchSize = 200 MaxRetailDiscountDeleteBatchSize = 100 ) const ( // 指定商品满减活动状态 SkuFullDiscountStatusExpired = 0 // 过期 SkuFullDiscountStatusValid = 1 // 生效 SkuFullDiscountStatusNew = 2 // 待生效 // 全店满减活动状态 StoreFullDiscountStatusNew = 0 // 待生效 StoreFullDiscountStatusValid = 1 // 生效 StoreFullDiscountStatusExpired = 2 // 过期 ShippingFeeStatusNotStart = "NOT_START" // 待生效 ShippingFeeStatusInProgress = "IN_PROGRESS" // 已生效 ShippingFeeStatusExpired = "EXPIRED" // 已过期 ShippingFeeStatusApprove = "APPROVE" // 待审批 ShippingFeeStatusFreeze = "FREEZE" // 冻结中 RetailDiscountStatusExpired = 0 // 已过期 RetailDiscountStatusValid = 1 // 已生效 RetailDiscountStatusNew = 2 // 待生效 UserTypeAll = 0 // 不限 UserTypeNewCommer = 1 // 门店新客 SettingTypeAsDiscount = 0 // 按折扣系数开展活动 SettingTypeAsPrice = 1 // 按折扣价格开展活动s ) var ( ActTypeList = []int{ 1, //-门店商品类+集合类活动, 2, //-劵类(支持返回的券活动:商家券/活动商家券/商品券/活动商品券/配送券/活动配送券/商品配送券/活动商品配送券) } ) type FullDiscountActInfo struct { ActIDs string `json:"act_ids"` ActName string `json:"act_name"` StartTime int64 `json:"start_time"` // 活动开始时间,单位秒 EndTime int64 `json:"end_time"` // 活动结束时间,单位秒 ActType int `json:"act_type"` Status int `json:"-"` } type FullDiscountActDetail struct { OriginalPrice float64 `json:"origin_price"` // 满 ActPrice float64 `json:"act_price"` // 减 } type FullDiscountSku struct { AppFoodCode string `json:"app_food_code"` DayLimit int `json:"day_limit"` Name string `json:"-"` // 设置操作时无用 } type FullDiscountActData struct { ActInfo *FullDiscountActInfo `json:"act_info"` ActRemark string `json:"act_remark"` AppPoiCode string `json:"app_poi_code"` ActDetails []*FullDiscountActDetail `json:"act_details"` } type FullDiscountFoodsInfo struct { ActInfo *FullDiscountActInfo `json:"act_info"` ActRemark string `json:"act_remark"` AppPoiCode string `json:"app_poi_code"` AppFoods []*FullDiscountSku `json:"app_foods"` } type ShippingFeeActDetail struct { LimitPrice float64 `json:"limit_price"` DiscountPrice float64 `json:"discount_price"` // list时用 PoiCharge float64 `json:"poi_charge,omitempty"` MtCharge float64 `json:"mt_charge,omitempty"` } type ShippingFeeActData struct { StartTime int64 `json:"start_time"` // 活动开始时间,单位秒 EndTime int64 `json:"end_time"` // 活动结束时间,单位秒 WeeksTime string `json:"weeks_time,omitempty"` Period string `json:"period,omitempty"` ActDetail []*ShippingFeeActDetail `json:"act_detail"` MaxPrice float64 `json:"max_price,omitempty"` // list时用 AppPoiCode string `json:"app_poi_code,omitempty"` ActID int64 `json:"act_id,omitempty"` ActStatus string `json:"actStatus,omitempty"` } type RetailDiscountActData struct { AppFoodCode string `json:"app_food_code"` UserType int `json:"user_type"` StartTime int64 `json:"start_time"` // 活动开始时间,单位秒 EndTime int64 `json:"end_time"` // 活动结束时间,单位秒 OrderLimit int `json:"order_limit"` // 每单限购:1)只能是正整数或-1。2)最大为10。 DayLimit int `json:"day_limit"` // 当日活动库存:只能是正整数或-1。 Period string `json:"period,omitempty"` WeeksTime string `json:"weeks_time,omitempty"` SettingType int `json:"setting_type"` ActPrice float64 `json:"act_price,omitempty"` // 折扣价格(单位元):必须为大于0的数字,且不能超过2位小数。 DiscountCoefficient float64 `json:"discount_coefficient,omitempty"` // 折扣系数:必须大于0小于9.8,最多支持两位小数。如输入3,即为3折 Sequence int `json:"sequence,omitempty"` ItemID int64 `json:"item_id,omitempty"` // 活动ID,为什么这里又是int64 // list时用 OriginalPrice float64 `json:"origin_price,omitempty"` // 商品原价,单位元 Stock int `json:"stock,omitempty"` // 当日剩余活动商品数量。只有当发起查询时间处于活动生效时段内时(start_time、end_time、period、weeks_time均需满足),该字段才代表实际剩余活动商品数量,否则显示的是创建活动时规定的当日活动库存 Status int `json:"status,omitempty"` // 活动状态,0:已过期,1:已生效,2:待生效。 Name string `json:"name,omitempty"` //SkuId string `json:"sku_id"` // 京西商品id } type GetStoreRetailDiscountActData struct { AppFoodCode string `json:"app_food_code"` UserType int `json:"user_type"` StartTime int64 `json:"start_time"` // 活动开始时间,单位秒 EndTime int64 `json:"end_time"` // 活动结束时间,单位秒 OrderLimit int `json:"order_limit"` // 每单限购:1)只能是正整数或-1。2)最大为10。 DayLimit int `json:"day_limit"` // 当日活动库存:只能是正整数或-1。 Period string `json:"period,omitempty"` WeeksTime string `json:"weeks_time,omitempty"` SettingType int `json:"setting_type"` ActPrice float64 `json:"act_price,omitempty"` // 折扣价格(单位元):必须为大于0的数字,且不能超过2位小数。 DiscountCoefficient float64 `json:"discount_coefficient,omitempty"` // 折扣系数:必须大于0小于9.8,最多支持两位小数。如输入3,即为3折 Sequence int `json:"sequence,omitempty"` ItemID int64 `json:"item_id,omitempty"` // 活动ID,为什么这里又是int64 // list时用 OriginalPrice float64 `json:"origin_price,omitempty"` // 商品原价,单位元 Stock int `json:"stock,omitempty"` // 当日剩余活动商品数量。只有当发起查询时间处于活动生效时段内时(start_time、end_time、period、weeks_time均需满足),该字段才代表实际剩余活动商品数量,否则显示的是创建活动时规定的当日活动库存 Status int `json:"status,omitempty"` // 活动状态,0:已过期,1:已生效,2:待生效。 Name string `json:"name,omitempty"` SkuId string `json:"sku_id"` // 京西商品id } type RetailDiscountActResult struct { AppFoodCode string `json:"app_food_code"` StartTime int64 `json:"start_time"` // 活动开始时间,单位秒 EndTime int64 `json:"end_time"` // 活动结束时间,单位秒 ActID int64 `json:"act_id,omitempty"` Period string `json:"period"` WeeksTime string `json:"weeks_time"` } type RetailDiscountActDataLimit struct { ItemID int64 `json:"item_id"` // 活动ID,为什么这里又是int64 DayLimit int `json:"day_limit,omitempty"` // 当日活动库存,只能为正整数或-1,-1表示无限库存 OrderLimit int `json:"order_limit,omitempty"` // 每单可购买的折扣商品数量 } type LimitTime struct { StartTime int64 `json:"start_time"` // 活动开始时间,单位秒 EndTime int64 `json:"end_time"` // 活动结束时间,单位秒 } type CouponInfo struct { LimitPrice float64 `json:"limit_price"` //使用门槛,单位元 CouponPrice float64 `json:"coupon_price"` // 优惠券金额,单位元 UserType int `json:"user_type"` // 可领用户类型,新客、老客、全部 ValidityDays int `json:"validity_days"` //使用有效期,用户领用了此商家券后在领用日起多久内可有效使用 Stock int `json:"stock"` } type CouponResult struct { StartTime int64 `json:"start_time"` // 活动开始时间,单位秒 EndTime int64 `json:"end_time"` // 活动结束时间,单位秒 ActID int64 `json:"act_id,omitempty"` } type CouponData struct { LimitPrice float64 `json:"limit_price"` //使用门槛,单位元 CouponPrice float64 `json:"coupon_price"` // 优惠券金额,单位元 UserType int `json:"user_type"` // 可领用户类型,新客、老客、全部 ValidityDays int `json:"validity_days"` //使用有效期,用户领用了此商家券后在领用日起多久内可有效使用 Stock int `json:"stock"` UseCount int `json:"use_count"` // 劵已使用数量 SentCount int `json:"sent_count"` // 劵已发数量 } type CouponActInfo struct { AppPoiCode string `json:"app_poi_code"` StartTime int64 `json:"start_time"` // 活动开始时间,单位秒 EndTime int64 `json:"end_time"` // 活动结束时间,单位秒 ActData []*CouponData `json:"act_data"` // 活动数据 ActID int64 `json:"actId"` RemainDays int `json:"remain_days"` // 活动剩余天数 Status int `json:"status"` // 活动状态 } type ActItemErrMsg struct { ActID int64 `json:"act_id"` ErrorMsg string `json:"error_msg"` } // 批量创建指定商品满减活动或创建店内满减活动 // http://developer.waimai.meituan.com/home/docDetail/255 func (a *API) FullDiscountBatchSave(poiCode string, actInfo *FullDiscountActInfo, actList []*FullDiscountActDetail, actSkuList []*FullDiscountSku) (actIDList []int64, err error) { params := map[string]interface{}{ KeyAppPoiCode: poiCode, "act_info": string(utils.MustMarshal(actInfo)), "act_details": string(utils.MustMarshal(actList)), } if actInfo.ActType == ActTypeSkuFullDiscount { params["app_foods"] = string(utils.MustMarshal(actSkuList)) } result, err := a.AccessAPI2("act/full/discount/batchsave", false, params, resultKeySuccessMsg, "") if err == nil { err = utils.UnmarshalUseNumber([]byte(result.(string)), &actIDList) } return actIDList, err } // 批量查询指定商品满减活动或店内满减活动 // http://developer.waimai.meituan.com/home/docDetail/256 func (a *API) FullDiscountList(poiCode string, actType int) (actInfoList []*FullDiscountActData, err error) { result, err := a.AccessAPI("act/full/discount/list", false, map[string]interface{}{ KeyAppPoiCode: poiCode, "act_type": actType, }) if err == nil && result != nil { err = utils.Map2StructByJson(result, &actInfoList, false) } return actInfoList, err } // 批量删除指定商品满减活动或店内满减活动 // http://developer.waimai.meituan.com/home/docDetail/257 func (a *API) FullDiscountDelete(poiCode string, actIDList []string, actType int) (err error) { _, err = a.AccessAPI("act/full/discount/delete", false, map[string]interface{}{ KeyAppPoiCode: poiCode, "act_ids": strings.Join(actIDList, ","), "act_type": actType, }) return err } // 批量添加活动商品至指定商品满减活动 // http://developer.waimai.meituan.com/home/docDetail/258 func (a *API) FullDiscountFoodsBatchSave(poiCode, actID string, appFoodList []*FullDiscountSku) (err error) { _, err = a.AccessAPI("act/full/discount/foods/batchsave", false, map[string]interface{}{ KeyAppPoiCode: poiCode, "act_id": actID, "app_foods": string(utils.MustMarshal(appFoodList)), }) return err } // 批量查询指定商品满减活动中的活动商品 // http://developer.waimai.meituan.com/home/docDetail/259 func (a *API) FullDiscountFoodsList(poiCode, actID string) (actFoodsInfo *FullDiscountFoodsInfo, err error) { limit := 200 for { var result interface{} offset := 0 result, err = a.AccessAPI("act/full/discount/foods/list", false, map[string]interface{}{ KeyAppPoiCode: poiCode, "act_id": actID, "limit": limit, "offset": offset, }) if err == nil && result != nil { tmpActFoodsInfo := &FullDiscountFoodsInfo{} if err = utils.Map2StructByJson(result, tmpActFoodsInfo, false); err != nil { return nil, err } if actFoodsInfo == nil { actFoodsInfo = tmpActFoodsInfo } else { actFoodsInfo.AppFoods = append(actFoodsInfo.AppFoods, tmpActFoodsInfo.AppFoods...) } offset++ break } else { break } } return actFoodsInfo, err } // 批量删除活动商品至指定商品满减活动 // appFoodCodeList 删除商品数量上限为100,如果删除门店多个活动商品,用英文逗号隔开 // http://developer.waimai.meituan.com/home/docDetail/260 func (a *API) FullDiscountFoodsDelete(poiCode, actID string, appFoodCodeList []string) (err error) { _, err = a.AccessAPI("act/full/discount/foods/delete", false, map[string]interface{}{ KeyAppPoiCode: poiCode, "act_id": actID, "app_food_codes": strings.Join(appFoodCodeList, ","), }) return err } // 批量修改指定商品满减活动中商品的当日活动库存 // http://developer.waimai.meituan.com/home/docDetail/261 func (a *API) FullDiscountFoodsDayLimit(poiCode, actID string, appFoodList []*FullDiscountSku) (err error) { _, err = a.AccessAPI("act/full/discount/foods/daylimit", false, map[string]interface{}{ KeyAppPoiCode: poiCode, "act_id": actID, "app_foods": string(utils.MustMarshal(appFoodList)), }) return err } // 阶梯满减配送费活动一个门店只可能有一个活动,所以不涉及actID的概念 // 批量创建阶梯满减配送费活动 // http://developer.waimai.meituan.com/home/docDetail/281 func (a *API) FulllDiscountShippingFeeBatchSave(poiCode string, actData []*ShippingFeeActData) (err error) { _, err = a.AccessAPI("act/full/discount/shippingfee/batchsave", false, map[string]interface{}{ KeyAppPoiCode: poiCode, "act_data": string(utils.MustMarshal(actData)), }) return err } // 查询阶梯满减配送费活动 // http://developer.waimai.meituan.com/home/docDetail/282 func (a *API) FulllDiscountShippingFeeList(poiCode string) (actList []*ShippingFeeActData, err error) { result, err := a.AccessAPI("act/full/discount/shippingfee/list", true, map[string]interface{}{ KeyAppPoiCode: poiCode, }) if err == nil { err = utils.Map2StructByJson(result, &actList, false) } return actList, err } // 批量删除阶梯满减配送费活动 // http://developer.waimai.meituan.com/home/docDetail/283 func (a *API) FulllDiscountShippingFeeBatchDelete(poiCode string, actIDList []string) (err error) { _, err = a.AccessAPI("act/full/discount/shippingfee/batchdelete", false, map[string]interface{}{ KeyAppPoiCode: poiCode, "act_ids": strings.Join(actIDList, ","), }) return err } // 批量创建或更新零售折扣商品 // http://developer.waimai.meituan.com/home/docDetail/287 func (a *API) RetailDiscountBatchSave(poiCode string, actType int, actData []*RetailDiscountActData) (actResult []*RetailDiscountActResult /*failedList []*AppFoodResult, */, err error) { if actType == 0 { actType = RetailActTypeDirectDown } result, err := a.AccessAPI2("act/retail/discount/batchsave", false, map[string]interface{}{ KeyAppPoiCode: poiCode, "act_data": string(utils.MustMarshal(actData)), "act_type": actType, }, "", "") if err == nil { resultMap := result.(map[string]interface{}) err = utils.UnmarshalUseNumber([]byte(resultMap[resultKeySuccessMsg].(string)), &actResult) // if err == nil { // failedList, err = handleRetailBatchResult(resultMap[resultKeyMsg]) // } } return actResult /*failedList, */, err } func (a *API) RetailDiscountBatchSave2(poiCode string, actType int, actData []*RetailDiscountActData) (actResult []*RetailDiscountActResult, failedList []*AppFoodResult, err error) { if actType == 0 { actType = RetailActTypeDirectDown } result, err := a.AccessAPI2("act/retail/discount/batchsave", false, map[string]interface{}{ KeyAppPoiCode: poiCode, "act_data": string(utils.MustMarshal(actData)), "act_type": actType, }, "", "") var msg string if err == nil { resultMap := result.(map[string]interface{}) err = utils.UnmarshalUseNumber([]byte(resultMap[resultKeySuccessMsg].(string)), &actResult) if err == nil { msg = utils.Interface2String(resultMap[resultKeyMsg]) globals.SugarLogger.Debugf("RetailDiscountBatchSave2 test0129 msg:%v", utils.Format4Output(msg, false)) } } else { msg = getMsgFromError(err) globals.SugarLogger.Debugf("RetailDiscountBatchSave2 test0129 err:%v", err) } failedList = parseErr4ErrList(msg) return actResult, failedList, err } func parseErr4ErrList(msg string) (failedList []*AppFoodResult) { if msg != "" { var mapData map[string]interface{} if err := utils.UnmarshalUseNumber([]byte(msg), &mapData); err == nil { utils.Map2StructByJson(mapData["error_list"], &failedList, false) } } return failedList } // 查询门店零售折扣商品 // http://developer.waimai.meituan.com/home/docDetail/288 func (a *API) RetailDiscountList(poiCode string, actType int) (actList []*GetStoreRetailDiscountActData, err error) { limit := 200 offset := 0 if actType == 0 { actType = RetailActTypeDirectDown } for { result, err := a.AccessAPI("act/retail/discount/list", true, map[string]interface{}{ KeyAppPoiCode: poiCode, "act_type": actType, "limit": limit, "offset": offset, }) if err == nil { var tmpActList []*GetStoreRetailDiscountActData if err = utils.Map2StructByJson(result, &tmpActList, false); err != nil { return nil, err } actList = append(actList, tmpActList...) if len(tmpActList) < limit { break } offset++ } else { return nil, err } } return actList, err } // 批量删除零售折扣商品 // http://developer.waimai.meituan.com/home/docDetail/289 func (a *API) RetailDiscountDelete2(poiCode string, actType int, actIDList []string) (failedList []*ActItemErrMsg, err error) { if actType == 0 { actType = RetailActTypeDirectDown } result, err := a.AccessAPI("act/retail/discount/batchdelete", false, map[string]interface{}{ KeyAppPoiCode: poiCode, "act_type": actType, "item_ids": strings.Join(actIDList, ","), }) var msg string if err == nil { msg = getMsgFromResult(result) } else { msg = getMsgFromError(err) } failedList = parseErr4RetailDiscountDelete(msg) return failedList, err } func (a *API) RetailiscountDelete(poiCode string, actType int, actIDList []string) (err error) { _, err = a.RetailDiscountDelete2(poiCode, actType, actIDList) return err } func getMsgFromResult(result interface{}) (msg string) { if resultMap, ok := result.(map[string]interface{}); ok { msg = utils.Interface2String(resultMap[resultKeyMsg]) } return msg } func getMsgFromError(err error) (msg string) { if errExt, ok := err.(*utils.ErrorWithCode); ok { msg = errExt.ErrMsg() } return msg } func parseErr4RetailDiscountDelete(msg string) (failedList []*ActItemErrMsg) { if msg != "" { var mapData map[string]interface{} if err := utils.UnmarshalUseNumber([]byte(msg), &mapData); err == nil { utils.Map2StructByJson(mapData["error_list"], &failedList, false) } } return failedList } func ParseErr4RetailDiscountDelete(err error) (failedList []*ActItemErrMsg) { return parseErr4RetailDiscountDelete(getMsgFromError(err)) } func CanDeleteActErrMsgIgnore(errMsg string) bool { return errMsg == "" || errMsg == "活动ID不存在" } // 批量修改零售折扣商品当日活动库存 // http://developer.waimai.meituan.com/home/docDetail/290 func (a *API) RetailDiscountBatchStock(poiCode, actDataList []*RetailDiscountActDataLimit) (err error) { _, err = a.AccessAPI("act/retail/discount/batchstock", false, map[string]interface{}{ KeyAppPoiCode: poiCode, "act_data": string(utils.MustMarshal(actDataList)), }) return err } // 批量修改零售折扣商品每单限购数量 // http://developer.waimai.meituan.com/home/docDetail/291 func (a *API) RetailDiscountBatchLimit(poiCode, actDataList []*RetailDiscountActDataLimit) (err error) { _, err = a.AccessAPI("act/retail/discount/batchlimit", false, map[string]interface{}{ KeyAppPoiCode: poiCode, "act_data": string(utils.MustMarshal(actDataList)), }) return err } // 批量新增商家券(店内发券)活动 // http://developer.waimai.meituan.com/home/docDetail/312 func (a *API) InStoreCouponBatchSave(poiCode string, limitTime *LimitTime, couponInfoList []*CouponInfo) (couponResultList []*CouponResult, err error) { result, err := a.AccessAPI2("act/instore/coupon/batchsave", false, map[string]interface{}{ KeyAppPoiCode: poiCode, "limit_time": string(utils.MustMarshal(limitTime)), "act_data": string(utils.MustMarshal(couponInfoList)), }, resultKeySuccessMsg, "") if err == nil { err = utils.UnmarshalUseNumber([]byte(result.(string)), &couponResultList) } return couponResultList, err } // 批量删除商家券(店内发券)活动 // http://developer.waimai.meituan.com/home/docDetail/313 func (a *API) InStoreCouponDelete(poiCode string, actIDList []string) (err error) { _, err = a.AccessAPI("act/instore/coupon/delete", false, map[string]interface{}{ KeyAppPoiCode: poiCode, "act_ids": strings.Join(actIDList, ","), }) return err } // 查询商家券(店内发券)活动 // http://developer.waimai.meituan.com/home/docDetail/314 // 页码从1开始 func (a *API) InStoreCouponList(poiCode string, pageNum, pageSize int) (couponActList []*CouponActInfo, err error) { result, err := a.AccessAPI("act/instore/coupon/list", false, map[string]interface{}{ KeyAppPoiCode: poiCode, "page_num": pageNum, "page_size": pageSize, }) if err == nil { err = utils.Map2StructByJson(result, &couponActList, false) } return couponActList, err } type GetByAppPoiCodeAndTypeResult struct { ActName string `json:"act_name"` ActType int `json:"act_type"` ActStatus int `json:"act_status"` ActCount int `json:"act_count"` ItemCount int `json:"item_count"` StartTime int `json:"start_time"` EndTime int `json:"end_time"` } // 查询门店内活动信息 // https://developer.waimai.meituan.com/home/docDetail/444 func (a *API) GetByAppPoiCodeAndType(appPoiCode string, status, actType int) (getByAppPoiCodeAndTypeResult []*GetByAppPoiCodeAndTypeResult, err error) { result, err := a.AccessAPI("act/all/get/byAppPoiCodeAndType", true, map[string]interface{}{ KeyAppPoiCode: appPoiCode, "status": status, "type": actType, }) if err == nil { err = utils.Map2StructByJson(result, &getByAppPoiCodeAndTypeResult, false) } return getByAppPoiCodeAndTypeResult, err }