- CreatePromotionByExcel
This commit is contained in:
@@ -4,14 +4,17 @@ import (
|
|||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"mime/multipart"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.rosy.net.cn/baseapi/platformapi/jdapi"
|
"git.rosy.net.cn/baseapi/platformapi/jdapi"
|
||||||
"git.rosy.net.cn/baseapi/utils"
|
"git.rosy.net.cn/baseapi/utils"
|
||||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
"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/jxutils/tasksch"
|
||||||
"git.rosy.net.cn/jx-callback/business/model"
|
"git.rosy.net.cn/jx-callback/business/model"
|
||||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||||
|
"git.rosy.net.cn/jx-callback/globals"
|
||||||
"git.rosy.net.cn/jx-callback/globals/api"
|
"git.rosy.net.cn/jx-callback/globals/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -35,6 +38,15 @@ const (
|
|||||||
PromotionStatusEnded = 2
|
PromotionStatusEnded = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
colSkuIDIndex = 0
|
||||||
|
colSkuPriceIndex = 3
|
||||||
|
colNameIndex = 5
|
||||||
|
colStoreIDIndex = 6
|
||||||
|
colBeginAtIndex = 9
|
||||||
|
colEndAtIndex = 10
|
||||||
|
)
|
||||||
|
|
||||||
type SkuPrice struct {
|
type SkuPrice struct {
|
||||||
SkuID int `json:"skuID"`
|
SkuID int `json:"skuID"`
|
||||||
PriceType int `json:"priceType"`
|
PriceType int `json:"priceType"`
|
||||||
@@ -51,6 +63,11 @@ type PromotionParams struct {
|
|||||||
SkuPrices []*SkuPrice
|
SkuPrices []*SkuPrice
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type tStoreSkuBindExt struct {
|
||||||
|
model.StoreSkuBind
|
||||||
|
JdID int64 `orm:"column(jd_id)"`
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrEmptySkus = errors.New("空sku")
|
ErrEmptySkus = errors.New("空sku")
|
||||||
)
|
)
|
||||||
@@ -94,56 +111,94 @@ func (p *JdLimitedTimeHandler) ConfirmPromotion(infoId int64, outInfoId string)
|
|||||||
return api.JdAPI.ConfirmPromotionLimitTime(infoId, outInfoId)
|
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() {
|
func init() {
|
||||||
gob.Register(&PromotionParams{})
|
gob.Register(&PromotionParams{})
|
||||||
gob.Register([]*SkuPrice{})
|
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 {
|
if len(params.SkuPrices) == 0 {
|
||||||
return "", ErrEmptySkus
|
return "", ErrEmptySkus
|
||||||
}
|
}
|
||||||
db := dao.GetDB()
|
db := dao.GetDB()
|
||||||
skuIDs := make([]int, len(params.SkuPrices))
|
skuIDs := make([]int, len(params.SkuPrices))
|
||||||
skuPriceMap := make(map[int]*SkuPrice)
|
skuPriceMap := make(map[int64]*SkuPrice)
|
||||||
for k, v := range params.SkuPrices {
|
for k, v := range params.SkuPrices {
|
||||||
skuIDs[k] = v.SkuID
|
skuIDs[k] = v.SkuID
|
||||||
skuPriceMap[v.SkuID] = v
|
skuPriceMap[int64(v.SkuID)] = v
|
||||||
}
|
}
|
||||||
sql := `
|
sql := ""
|
||||||
SELECT t1.*
|
var sqlParam []interface{}
|
||||||
|
if isIDJd {
|
||||||
|
sql = `
|
||||||
|
SELECT t1.*, t2.jd_id
|
||||||
FROM store_sku_bind t1
|
FROM store_sku_bind t1
|
||||||
WHERE t1.jd_sync_status = 0 AND t1.deleted_at = ? AND t1.store_id = ? AND t1.sku_id IN (
|
JOIN sku t2 ON t1.sku_id = t2.id AND t2.deleted_at = ?
|
||||||
` + dao.GenQuestionMarks(len(skuIDs)) + ")"
|
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 := ""
|
errMsg := ""
|
||||||
modifyPricesList := make(map[int][]*jdapi.SkuPriceInfo)
|
modifyPricesList := make(map[int][]*jdapi.SkuPriceInfo)
|
||||||
promotionPrices := make([]map[string]interface{}, len(params.StoreIDs)*len(params.SkuPrices))
|
promotionPrices := make([]map[string]interface{}, len(params.StoreIDs)*len(params.SkuPrices))
|
||||||
index := 0
|
index := 0
|
||||||
|
var jxStoreIDs []int
|
||||||
for _, storeID := range params.StoreIDs {
|
for _, storeID := range params.StoreIDs {
|
||||||
var skuBinds []*model.StoreSkuBind
|
var skuBinds []*tStoreSkuBindExt
|
||||||
if err = dao.GetRows(db, &skuBinds, sql, utils.DefaultTimeValue, storeID, skuIDs); err != nil {
|
if err = dao.GetRows(db, &skuBinds, sql, append(sqlParam, storeID)...); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
for _, skuBind := range skuBinds {
|
for k, skuBind := range skuBinds {
|
||||||
promotionSkuPrice := skuPriceMap[skuBind.SkuID]
|
if k == 0 {
|
||||||
|
jxStoreIDs = append(jxStoreIDs, skuBind.StoreID)
|
||||||
|
}
|
||||||
|
mapSkuID := int64(skuBind.SkuID)
|
||||||
|
if isIDJd {
|
||||||
|
mapSkuID = skuBind.JdID
|
||||||
|
}
|
||||||
|
promotionSkuPrice := skuPriceMap[mapSkuID]
|
||||||
if promotionSkuPrice.PriceType == PriceTypePercentage {
|
if promotionSkuPrice.PriceType == PriceTypePercentage {
|
||||||
promotionSkuPrice.Price = skuBind.Price * promotionSkuPrice.Price / 100
|
promotionSkuPrice.Price = skuBind.Price * promotionSkuPrice.Price / 100
|
||||||
}
|
}
|
||||||
if promotionSkuPrice.Price >= skuBind.Price {
|
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 errMsg == "" {
|
||||||
if params.Type == PromotionTypeLimitedTime {
|
if params.Type == PromotionTypeLimitedTime {
|
||||||
if skuBind.Price*PromotionLimitedTimeMinPercentage/100 < promotionSkuPrice.Price {
|
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),
|
OutSkuId: utils.Int2Str(skuBind.SkuID),
|
||||||
Price: promotionSkuPrice.Price*100/PromotionLimitedTimeMinPercentage + 1,
|
Price: promotionSkuPrice.Price*100/PromotionLimitedTimeMinPercentage + 1,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
promotionPrices[index] = map[string]interface{}{
|
promotionPrices[index] = map[string]interface{}{
|
||||||
jdapi.KeyOutStationNo: utils.Int2Str(storeID),
|
jdapi.KeyOutStationNo: utils.Int2Str(skuBind.StoreID),
|
||||||
jdapi.KeyOutSkuId: utils.Int2Str(skuBind.SkuID),
|
jdapi.KeyOutSkuId: utils.Int2Str(skuBind.SkuID),
|
||||||
jdapi.KeyPromotionPrice: promotionSkuPrice.Price,
|
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]
|
promotionPrices = promotionPrices[:index]
|
||||||
if len(promotionPrices) == 0 {
|
if len(promotionPrices) == 0 {
|
||||||
return "", ErrEmptySkus
|
return "", ErrEmptySkus
|
||||||
}
|
}
|
||||||
if errMsg != "" {
|
|
||||||
return "", errors.New(errMsg)
|
|
||||||
}
|
|
||||||
|
|
||||||
promotion := &model.Promotion{
|
promotion := &model.Promotion{
|
||||||
Name: params.Name,
|
Name: params.Name,
|
||||||
@@ -189,6 +244,10 @@ func CreateJdPromotion(isAsync bool, params *PromotionParams, userName string) (
|
|||||||
} else {
|
} else {
|
||||||
panic(fmt.Sprintf("unknown promotion type:%d", params.Type))
|
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)
|
infoId, err2 := promotionHandler.CreatePromotionInfos(params.Name, params.BeginAt, params.EndAt, utils.Int2Str(promotion.ID), params.Advertising)
|
||||||
if err = err2; err != nil {
|
if err = err2; err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@@ -212,7 +271,7 @@ func CreateJdPromotion(isAsync bool, params *PromotionParams, userName string) (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}, params.StoreIDs)
|
}, jxStoreIDs)
|
||||||
if _, err = task.GetResult(0); err != nil {
|
if _, err = task.GetResult(0); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -234,3 +293,57 @@ func CreateJdPromotion(isAsync bool, params *PromotionParams, userName string) (
|
|||||||
|
|
||||||
return "", err
|
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)
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package excel
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||||
@@ -66,6 +67,17 @@ func Obj2Excel(sheetList []*Obj2ExcelSheetConfig) []byte {
|
|||||||
return buf.Bytes()
|
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 {
|
func genAxis(row, col int) string {
|
||||||
return fmt.Sprintf("%c%d", col+65, row+1)
|
return fmt.Sprintf("%c%d", col+65, row+1)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"io"
|
||||||
|
|
||||||
"github.com/astaxie/beego"
|
"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.StoreIDs), &promotionParams.StoreIDs); err == nil {
|
||||||
if err = utils.UnmarshalUseNumber([]byte(params.SkuPrices), &promotionParams.SkuPrices); 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
|
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
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -207,6 +207,14 @@ func init() {
|
|||||||
MethodParams: param.Make(),
|
MethodParams: param.Make(),
|
||||||
Params: nil})
|
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.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:SkuController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:SkuController"],
|
||||||
beego.ControllerComments{
|
beego.ControllerComments{
|
||||||
Method: "AddCategory",
|
Method: "AddCategory",
|
||||||
|
|||||||
Reference in New Issue
Block a user