- CreatePromotionByExcel

This commit is contained in:
gazebo
2018-10-14 12:47:17 +08:00
parent b158fd09ea
commit 8b34b12a6e
4 changed files with 187 additions and 19 deletions

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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 := `
<form enctype="multipart/form-data" action="/v2/promotion/CreatePromotionByExcel" method="POST">
Send this file: <input name="userfile" accept="*.xlsx" type="file" />
<input type="text" name="type" />
<input type="text" name="isAsync" />
<input type="submit" value="Send File" />
</form>
`
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
})
}
}

View File

@@ -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",