diff --git a/business/jxstore/promotion/jd_promotion.go b/business/jxstore/promotion/jd_promotion.go index 1986344a0..fac82f7b1 100644 --- a/business/jxstore/promotion/jd_promotion.go +++ b/business/jxstore/promotion/jd_promotion.go @@ -4,14 +4,17 @@ import ( "encoding/gob" "errors" "fmt" + "mime/multipart" "time" "git.rosy.net.cn/baseapi/platformapi/jdapi" "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/business/jxutils" + "git.rosy.net.cn/jx-callback/business/jxutils/excel" "git.rosy.net.cn/jx-callback/business/jxutils/tasksch" "git.rosy.net.cn/jx-callback/business/model" "git.rosy.net.cn/jx-callback/business/model/dao" + "git.rosy.net.cn/jx-callback/globals" "git.rosy.net.cn/jx-callback/globals/api" ) @@ -35,6 +38,15 @@ const ( PromotionStatusEnded = 2 ) +const ( + colSkuIDIndex = 0 + colSkuPriceIndex = 3 + colNameIndex = 5 + colStoreIDIndex = 6 + colBeginAtIndex = 9 + colEndAtIndex = 10 +) + type SkuPrice struct { SkuID int `json:"skuID"` PriceType int `json:"priceType"` @@ -51,6 +63,11 @@ type PromotionParams struct { SkuPrices []*SkuPrice } +type tStoreSkuBindExt struct { + model.StoreSkuBind + JdID int64 `orm:"column(jd_id)"` +} + var ( ErrEmptySkus = errors.New("空sku") ) @@ -94,56 +111,94 @@ func (p *JdLimitedTimeHandler) ConfirmPromotion(infoId int64, outInfoId string) return api.JdAPI.ConfirmPromotionLimitTime(infoId, outInfoId) } +type JdNullHandler struct { +} + +func (p *JdNullHandler) CreatePromotionInfos(name string, beginDate, endDate time.Time, outInfoId, advertising string) (infoId int64, err error) { + return jxutils.GenFakeID(), nil +} +func (p *JdNullHandler) CreatePromotionRules(infoId int64, outInfoId string, limitDevice, limitPin, limitCount, limitDaily int) (err error) { + return nil +} +func (p *JdNullHandler) CreatePromotionSku(infoId int64, outInfoId string, skus []map[string]interface{}) (skusResult []map[string]interface{}, err error) { + return nil, nil +} +func (p *JdNullHandler) ConfirmPromotion(infoId int64, outInfoId string) (err error) { + return nil +} + func init() { gob.Register(&PromotionParams{}) gob.Register([]*SkuPrice{}) } -func CreateJdPromotion(isAsync bool, params *PromotionParams, userName string) (hint string, err error) { +func CreateJdPromotion(isIDJd bool, isAsync bool, params *PromotionParams, userName string) (hint string, err error) { if len(params.SkuPrices) == 0 { return "", ErrEmptySkus } db := dao.GetDB() skuIDs := make([]int, len(params.SkuPrices)) - skuPriceMap := make(map[int]*SkuPrice) + skuPriceMap := make(map[int64]*SkuPrice) for k, v := range params.SkuPrices { skuIDs[k] = v.SkuID - skuPriceMap[v.SkuID] = v + skuPriceMap[int64(v.SkuID)] = v } - sql := ` - SELECT t1.* + sql := "" + var sqlParam []interface{} + if isIDJd { + sql = ` + SELECT t1.*, t2.jd_id FROM store_sku_bind t1 - WHERE t1.jd_sync_status = 0 AND t1.deleted_at = ? AND t1.store_id = ? AND t1.sku_id IN ( - ` + dao.GenQuestionMarks(len(skuIDs)) + ")" + 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 = ?" + } + sqlParam = append(sqlParam, utils.DefaultTimeValue, skuIDs) errMsg := "" modifyPricesList := make(map[int][]*jdapi.SkuPriceInfo) promotionPrices := make([]map[string]interface{}, len(params.StoreIDs)*len(params.SkuPrices)) index := 0 + var jxStoreIDs []int for _, storeID := range params.StoreIDs { - var skuBinds []*model.StoreSkuBind - if err = dao.GetRows(db, &skuBinds, sql, utils.DefaultTimeValue, storeID, skuIDs); err != nil { + var skuBinds []*tStoreSkuBindExt + if err = dao.GetRows(db, &skuBinds, sql, append(sqlParam, storeID)...); err != nil { return "", err } - for _, skuBind := range skuBinds { - promotionSkuPrice := skuPriceMap[skuBind.SkuID] + for k, skuBind := range skuBinds { + if k == 0 { + jxStoreIDs = append(jxStoreIDs, skuBind.StoreID) + } + mapSkuID := int64(skuBind.SkuID) + if isIDJd { + mapSkuID = skuBind.JdID + } + promotionSkuPrice := skuPriceMap[mapSkuID] if promotionSkuPrice.PriceType == PriceTypePercentage { promotionSkuPrice.Price = skuBind.Price * promotionSkuPrice.Price / 100 } if promotionSkuPrice.Price >= skuBind.Price { - errMsg += fmt.Sprintf("促销价大于等于原价,storeID:%d, skuID:%d\n", storeID, skuBind.SkuID) + errMsg += fmt.Sprintf("促销价大于等于原价,storeID:%d, skuID:%d\n", skuBind.StoreID, skuBind.SkuID) } if errMsg == "" { if params.Type == PromotionTypeLimitedTime { if skuBind.Price*PromotionLimitedTimeMinPercentage/100 < promotionSkuPrice.Price { - modifyPricesList[storeID] = append(modifyPricesList[storeID], &jdapi.SkuPriceInfo{ + modifyPricesList[skuBind.StoreID] = append(modifyPricesList[skuBind.StoreID], &jdapi.SkuPriceInfo{ OutSkuId: utils.Int2Str(skuBind.SkuID), Price: promotionSkuPrice.Price*100/PromotionLimitedTimeMinPercentage + 1, }) } } promotionPrices[index] = map[string]interface{}{ - jdapi.KeyOutStationNo: utils.Int2Str(storeID), + jdapi.KeyOutStationNo: utils.Int2Str(skuBind.StoreID), jdapi.KeyOutSkuId: utils.Int2Str(skuBind.SkuID), jdapi.KeyPromotionPrice: promotionSkuPrice.Price, } @@ -151,13 +206,13 @@ func CreateJdPromotion(isAsync bool, params *PromotionParams, userName string) ( } } } + if errMsg != "" { + return "", errors.New(errMsg) + } promotionPrices = promotionPrices[:index] if len(promotionPrices) == 0 { return "", ErrEmptySkus } - if errMsg != "" { - return "", errors.New(errMsg) - } promotion := &model.Promotion{ Name: params.Name, @@ -189,6 +244,10 @@ func CreateJdPromotion(isAsync bool, params *PromotionParams, userName string) ( } else { panic(fmt.Sprintf("unknown promotion type:%d", params.Type)) } + if !globals.EnableStoreWrite { + promotionHandler = &JdNullHandler{} + } + infoId, err2 := promotionHandler.CreatePromotionInfos(params.Name, params.BeginAt, params.EndAt, utils.Int2Str(promotion.ID), params.Advertising) if err = err2; err != nil { return "", err @@ -212,7 +271,7 @@ func CreateJdPromotion(isAsync bool, params *PromotionParams, userName string) ( } } return nil, nil - }, params.StoreIDs) + }, jxStoreIDs) if _, err = task.GetResult(0); err != nil { return "", err } @@ -234,3 +293,57 @@ func CreateJdPromotion(isAsync bool, params *PromotionParams, userName string) ( return "", err } + +func CreatePromotionByExcel(isAsync bool, promotionType int, fileHeader *multipart.FileHeader, userName string) (hint string, err error) { + file, err := fileHeader.Open() + if err != nil { + return hint, err + } + contents := excel.Excel2Slice(file) + file.Close() + var promotionParams *PromotionParams + for _, v := range contents { + promotionParams = &PromotionParams{ + Name: v[1][colNameIndex], + Type: promotionType, + } + if promotionParams.BeginAt, err = excelStr2Time(v[1][colBeginAtIndex]); err != nil { + return hint, err + } + if promotionParams.EndAt, err = excelStr2Time(v[1][colEndAtIndex]); err != nil { + return hint, err + } + + for rowIndex, row := range v { + if rowIndex > 0 { + isBreak := true + if row[colSkuIDIndex] != "" { + isBreak = false + jdSkuID := int(utils.Str2Int64(row[colSkuIDIndex])) + promotionParams.SkuPrices = append(promotionParams.SkuPrices, &SkuPrice{ + SkuID: jdSkuID, + PriceType: PriceTypePrice, + Price: int(jxutils.StandardPrice2Int(utils.Str2Float64(row[colSkuPriceIndex]))), + }) + } + if row[colStoreIDIndex] != "" { + isBreak = false + jdStoreID := int(utils.Str2Int64(row[colStoreIDIndex])) + promotionParams.StoreIDs = append(promotionParams.StoreIDs, jdStoreID) + } + if isBreak { + break + } + } + } + + break + } + // globals.SugarLogger.Debug(utils.Format4Output(promotionParams, false)) + // globals.SugarLogger.Debug(isAsync) + return CreateJdPromotion(true, isAsync, promotionParams, userName) +} + +func excelStr2Time(timeStr string) (tm time.Time, err error) { + return time.ParseInLocation("2006年1月2日15点4分5秒", timeStr, time.Local) +} diff --git a/business/jxutils/excel/excel.go b/business/jxutils/excel/excel.go index f6bd9edc0..8ab3d32ac 100644 --- a/business/jxutils/excel/excel.go +++ b/business/jxutils/excel/excel.go @@ -3,6 +3,7 @@ package excel import ( "bytes" "fmt" + "io" "reflect" "git.rosy.net.cn/jx-callback/business/jxutils" @@ -66,6 +67,17 @@ func Obj2Excel(sheetList []*Obj2ExcelSheetConfig) []byte { return buf.Bytes() } +func Excel2Slice(reader io.Reader) (contents map[string][][]string) { + globals.SugarLogger.Debug("Excel2Slice") + if excelFile, err := excelize.OpenReader(reader); err == nil { + contents = make(map[string][][]string) + for _, v := range excelFile.GetSheetMap() { + contents[v] = excelFile.GetRows(v) + } + } + return contents +} + func genAxis(row, col int) string { return fmt.Sprintf("%c%d", col+65, row+1) } diff --git a/controllers/promotion.go b/controllers/promotion.go index e23bcfb2b..64491b7f8 100644 --- a/controllers/promotion.go +++ b/controllers/promotion.go @@ -2,6 +2,7 @@ package controllers import ( "errors" + "io" "github.com/astaxie/beego" @@ -43,9 +44,43 @@ func (c *PromotionController) CreatePromotion() { } if err = utils.UnmarshalUseNumber([]byte(params.StoreIDs), &promotionParams.StoreIDs); err == nil { if err = utils.UnmarshalUseNumber([]byte(params.SkuPrices), &promotionParams.SkuPrices); err == nil { - retVal, err = promotion.CreateJdPromotion(params.IsAsync, promotionParams, GetUserNameFromToken(params.Token)) + retVal, err = promotion.CreateJdPromotion(false, params.IsAsync, promotionParams, GetUserNameFromToken(params.Token)) } } return retVal, "", err }) } + +// @Param token header string true "认证token" + +// @Title 发送文件给门店 +// @Description 发送文件给门店,调用GET方法得到浏览器端参考的上传HTML实现,userfiles +// @Param type formData int true "是否异步,缺省是同步" +// @Param isAsync formData bool false "是否异常,缺省否(暂时只支持同步)" +// @Success 200 {object} controllers.CallResult +// @Failure 200 {object} controllers.CallResult +// @router /CreatePromotionByExcel [post,get] +func (c *PromotionController) CreatePromotionByExcel() { + if c.Ctx.Input.IsGet() { + w := c.Ctx.ResponseWriter + // 上传页面 + w.Header().Add("Content-Type", "text/html") + w.WriteHeader(200) + html := ` +
+ Send this file: + + + +
+` + io.WriteString(w, html) + } else if c.Ctx.Input.IsPost() { + c.callCreatePromotionByExcel(func(params *tPromotionCreatePromotionByExcelParams) (retVal interface{}, errCode string, err error) { + r := c.Ctx.Request + files := r.MultipartForm.File["userfile"] + retVal, err = promotion.CreatePromotionByExcel(params.IsAsync, params.Type, files[0], "userName") //GetUserNameFromToken(params.Token)) + return retVal, "", err + }) + } +} diff --git a/routers/commentsRouter_controllers.go b/routers/commentsRouter_controllers.go index 696b48289..218df1614 100644 --- a/routers/commentsRouter_controllers.go +++ b/routers/commentsRouter_controllers.go @@ -207,6 +207,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: "CreatePromotionByExcel", + Router: `/CreatePromotionByExcel`, + AllowHTTPMethods: []string{"post","get"}, + MethodParams: param.Make(), + Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:SkuController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:SkuController"], beego.ControllerComments{ Method: "AddCategory",