Files
jx-callback/business/jxstore/act/act.go
2019-07-03 15:31:55 +08:00

433 lines
13 KiB
Go

package act
import (
"fmt"
"time"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"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"
)
type ActOrderRuleParam struct {
SalePrice int64 `orm:"" json:"salePrice"` // 满的价格
DeductPrice int64 `orm:"" json:"deductPrice"` // 减的价格
}
type ActStoreSkuParam struct {
model.ActStoreSku
}
type ActDetail struct {
model.Act2
}
type ActMapPureInfo struct {
VendorID int `orm:"column(vendor_id)" json:"vendorID"`
VendorActID string `orm:"column(vendor_act_id);size(48)" json:"vendorActID"`
SyncStatus int `orm:"default(2)" json:"syncStatus"`
}
type ActVendorInfo struct {
model.Act
VendorList []*ActMapPureInfo
}
func ActStoreSkuParam2Model(ctx *jxcontext.Context, db *dao.DaoDB, act *model.Act, vendorIDs []int, actStoreSku []*ActStoreSkuParam) (validVendorIDs []int, actStoreSkuList []*model.ActStoreSku, actStoreSkuMapList []*model.ActStoreSkuMap, err error) {
wholeValidVendorMap := make(map[int]int)
if len(actStoreSku) > 0 {
storeIDMap := make(map[int]int)
skuIDMap := make(map[int]int)
storeSkuParamMap := make(map[int][]*ActStoreSkuParam)
for _, v := range actStoreSku {
storeIDMap[v.StoreID] = 1
skuIDMap[v.SkuID] = 1
storeSkuParamMap[v.StoreID] = append(storeSkuParamMap[v.StoreID], v)
}
storeSkuList, err2 := dao.GetStoresSkusInfo(db, jxutils.IntMap2List(storeIDMap), jxutils.IntMap2List(skuIDMap))
if err = err2; err != nil {
return nil, nil, nil, err
}
storeSkuMap := make(map[int64]*model.StoreSkuBind)
for _, v := range storeSkuList {
storeSkuMap[jxutils.Combine2Int(v.StoreID, v.SkuID)] = v
}
for storeID, oneStoreSkuParam := range storeSkuParamMap {
validVendorMap := make(map[int]int)
validSkuMap := make(map[int]int)
for _, vendorID := range vendorIDs {
storeDetail, err2 := dao.GetStoreDetail(db, storeID, vendorID)
if err = err2; err == nil {
for _, v := range oneStoreSkuParam {
if storeSkuInfo := storeSkuMap[jxutils.Combine2Int(v.StoreID, v.SkuID)]; storeSkuInfo != nil {
validVendorMap[vendorID] = 1
validSkuMap[v.SkuID] = 1
actSkuMap := &model.ActStoreSkuMap{
ActID: act.ID,
StoreID: storeID,
SkuID: v.SkuID,
VendorID: vendorID,
SyncStatus: model.SyncFlagNewMask,
}
if v.ActPrice != 0 {
actSkuMap.ActualActPrice = v.ActPrice
} else {
percentage := act.PricePercentage
if v.PricePercentage != 0 {
percentage = v.PricePercentage
}
percentage = percentage * int(storeDetail.PricePercentage) / 100
actSkuMap.ActualActPrice = int64(jxutils.CaculateSkuVendorPrice(storeSkuInfo.Price, percentage, 0))
}
dao.WrapAddIDCULDEntity(actSkuMap, ctx.GetUserName())
actStoreSkuMapList = append(actStoreSkuMapList, actSkuMap)
}
}
wholeValidVendorMap[vendorID] = 1
} else if !dao.IsNoRowsError(err) {
return nil, nil, nil, err
} else {
err = nil
}
}
for _, v := range oneStoreSkuParam {
if validSkuMap[v.SkuID] == 1 { // todo 这里是否需要判断
if storeSkuInfo := storeSkuMap[jxutils.Combine2Int(v.StoreID, v.SkuID)]; storeSkuInfo != nil {
storeSku := &v.ActStoreSku
storeSku.ActID = act.ID
storeSku.OriginalPrice = int64(storeSkuInfo.Price)
dao.WrapAddIDCULDEntity(storeSku, ctx.GetUserName())
actStoreSkuList = append(actStoreSkuList, storeSku)
}
}
}
}
}
return jxutils.IntMap2List(wholeValidVendorMap), actStoreSkuList, actStoreSkuMapList, err
}
func addActStoreBind(ctx *jxcontext.Context, db *dao.DaoDB, actStoreSkuList []*model.ActStoreSku, actStoreSkuMapList []*model.ActStoreSkuMap) (err error) {
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
storeSkuMap := make(map[int64]int)
for _, v := range actStoreSkuList {
err = dao.CreateEntity(db, v)
if err != nil {
dao.Rollback(db)
return err
}
storeSkuMap[jxutils.Combine2Int(v.StoreID, v.SkuID)] = v.ID
}
for _, v := range actStoreSkuMapList {
v.BindID = storeSkuMap[jxutils.Combine2Int(v.StoreID, v.SkuID)]
}
if len(actStoreSkuMapList) > 0 {
err = dao.CreateMultiEntities(db, actStoreSkuMapList)
if err != nil {
dao.Rollback(db)
return err
}
}
dao.Commit(db)
return err
}
func AddActStoreBind(ctx *jxcontext.Context, actID int, actStoreSku []*ActStoreSkuParam) (err error) {
db := dao.GetDB()
var vendorIDs []int
actMap, err := dao.GetActVendorInfo(db, actID, nil)
if err != nil {
return err
}
for vendorID := range actMap {
vendorIDs = append(vendorIDs, vendorID)
}
var act *model.Act
if len(vendorIDs) > 0 {
act = &actMap[vendorIDs[0]].Act
} else {
act = &model.Act{}
act.ID = actID
if err = dao.GetEntity(db, act); err != nil {
return err
}
}
_, actStoreSkuList, actStoreSkuMapList, err := ActStoreSkuParam2Model(ctx, db, act, vendorIDs, actStoreSku)
if err != nil {
return err
}
dao.Begin(db)
defer func() {
if r := recover(); r != nil || err != nil {
dao.Rollback(db)
if r != nil {
panic(r)
}
}
}()
if err = addActStoreBind(ctx, db, actStoreSkuList, actStoreSkuMapList); err != nil {
return err
}
for _, act := range actMap {
if _, err = dao.UpdateEntityLogically(db, partner.Act2ActMap(act),
map[string]interface{}{
model.FieldSyncStatus: act.SyncStatus | model.SyncFlagModifiedMask,
}, ctx.GetUserName(), nil); err != nil {
return err
}
}
dao.Commit(db)
return err
}
func CreateAct(ctx *jxcontext.Context, act *model.Act, vendorIDs []int, actRules []*ActOrderRuleParam, actStoreSku []*ActStoreSkuParam, isAsync bool) (hint string, err error) {
db := dao.GetDB()
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
if act.LimitCount == 0 {
act.LimitCount = 1 // 缺省限购一份,如果确定不限,明确给一个很大的值
}
act.Status = model.ActStatusCreated
dao.WrapAddIDCULDEntity(act, ctx.GetUserName())
err = dao.CreateEntity(db, act)
if err != nil {
dao.Rollback(db)
return "", err
}
validVendorIDs, actStoreSkuList, actStoreSkuMapList, err := ActStoreSkuParam2Model(ctx, db, act, vendorIDs, actStoreSku)
if err != nil {
return "", err
}
var actMapList []*model.ActMap
for _, vendorID := range validVendorIDs {
actMap := &model.ActMap{
ActID: act.ID,
VendorID: vendorID,
SyncStatus: model.SyncFlagNewMask,
}
dao.WrapAddIDCULDEntity(actMap, ctx.GetUserName())
actMapList = append(actMapList, actMap)
}
if len(actMapList) > 0 {
err = dao.CreateMultiEntities(db, actMapList)
if err != nil {
dao.Rollback(db)
return "", err
}
}
if err = addActStoreBind(ctx, db, actStoreSkuList, actStoreSkuMapList); err != nil {
dao.Rollback(db)
return "", err
}
dao.Commit(db)
hint, err = SyncAct(ctx, nil, act.ID, nil, nil, nil, isAsync)
if !isAsync {
hint = utils.Int2Str(act.ID)
}
return hint, err
}
func QueryActs(ctx *jxcontext.Context, actID int, offset, pageSize int, keyword string, statusList []int, actTypeList []int, storeID, skuID, cityCode int, beginAt, endAt, createdAtFrom, createdAtTo time.Time) (pagedInfo *dao.PagedActListInfo, err error) {
return dao.QueryActs(dao.GetDB(), actID, offset, pageSize, keyword, statusList, actTypeList, storeID, skuID, cityCode, beginAt, endAt, createdAtFrom, createdAtTo)
}
func GetActVendorInfo(ctx *jxcontext.Context, actID int) (actVendorInfo *ActVendorInfo, err error) {
db := dao.GetDB()
actMap, err := dao.GetActVendorInfo(db, actID, nil)
if err != nil {
return nil, err
}
if len(actMap) == 0 {
return nil, fmt.Errorf("不能找到活动:%d", actID)
}
actVendorInfo = &ActVendorInfo{}
for vendorID, v := range actMap {
if actVendorInfo.ID == 0 {
actVendorInfo.Act = v.Act
}
actVendorInfo.VendorList = append(actVendorInfo.VendorList, &ActMapPureInfo{
VendorID: vendorID,
SyncStatus: v.SyncStatus,
VendorActID: v.VendorActID,
})
}
return actVendorInfo, err
}
func GetActStoreSkuInfo(ctx *jxcontext.Context, actID int, vendorIDs []int) (actStoreSkuList []*model.ActStoreSku2, err error) {
db := dao.GetDB()
actStoreSkuMap, err := dao.GetActStoreSkuVendorInfo(db, actID, vendorIDs, nil, nil)
if err != nil {
return nil, err
}
if len(actStoreSkuMap) == 0 {
return nil, fmt.Errorf("不能找到活动:%d", actID)
}
for _, v := range actStoreSkuMap {
actStoreSkuList = append(actStoreSkuList, v...)
}
return actStoreSkuList, err
}
func CancelAct(ctx *jxcontext.Context, actID int) (err error) {
db := dao.GetDB()
if err = deleteActStoreBind(ctx, db, actID, nil); err != nil {
return err
}
_, err = SyncAct(ctx, nil, actID, nil, nil, nil, false)
return err
}
func DeleteActStoreBind(ctx *jxcontext.Context, actID int, actStoreSku []*ActStoreSkuParam) (err error) {
return deleteActStoreBind(ctx, dao.GetDB(), actID, actStoreSku)
}
func deleteActStoreBind(ctx *jxcontext.Context, db *dao.DaoDB, actID int, actStoreSkuParam []*ActStoreSkuParam) (err error) {
actMap, err := dao.GetActVendorInfo(db, actID, nil)
if err != nil {
return err
}
actStoreSkuMap, err := dao.GetActStoreSkuVendorInfo(db, actID, nil, nil, nil)
if err != nil {
return err
}
dao.Begin(db)
defer func() {
if r := recover(); r != nil || err != nil {
dao.Rollback(db)
if r != nil {
panic(r)
}
}
}()
actStoreSkuParamMap := make(map[int64]*ActStoreSkuParam)
for _, v := range actStoreSkuParam {
actStoreSkuParamMap[jxutils.Combine2Int(v.StoreID, v.SkuID)] = v
if _, err = dao.DeleteEntityLogically(db, &model.ActStoreSku{}, nil, ctx.GetUserName(),
map[string]interface{}{
model.FieldActID: actID,
model.FieldStoreID: v.StoreID,
model.FieldSkuID: v.SkuID,
}); err != nil {
return err
}
}
isNeedCancelAct := true
for vendorID, act := range actMap {
isDeleteAll := true
isDeleteAtLeastOne := false
actStoreSkuMap := partner.SplitActStoreSku(actStoreSkuMap[vendorID])
for storeID := range actStoreSkuMap {
for _, actStoreSku := range actStoreSkuMap[storeID] {
if actStoreSkuParam == nil || actStoreSkuParamMap[jxutils.Combine2Int(actStoreSku.StoreID, actStoreSku.SkuID)] != nil {
if _, err = dao.UpdateEntityLogically(db, partner.ActStoreSku2ActStoreSkuMap(actStoreSku),
map[string]interface{}{
model.FieldSyncStatus: actStoreSku.SyncStatus | model.SyncFlagDeletedMask,
}, ctx.GetUserName(), nil); err != nil {
return err
}
isDeleteAtLeastOne = true
} else {
isNeedCancelAct = false
isDeleteAll = false
}
}
}
if isDeleteAll || isDeleteAtLeastOne {
syncStatus := model.SyncFlagModifiedMask
if isDeleteAll {
syncStatus = model.SyncFlagDeletedMask
}
syncStatus |= act.SyncStatus
if _, err = dao.UpdateEntityLogically(db, partner.Act2ActMap(act),
map[string]interface{}{
model.FieldSyncStatus: syncStatus,
}, ctx.GetUserName(), nil); err != nil {
return err
}
}
if isDeleteAll != isNeedCancelAct {
globals.SugarLogger.Warnf("deleteActStoreBind, actID:%d isDeleteAll:%t != isNeedCancelAct:%t", act.ID, isDeleteAll, isNeedCancelAct)
}
}
if isNeedCancelAct {
act := &model.Act{}
act.ID = actID
if _, err = dao.UpdateEntityLogically(db, act,
map[string]interface{}{
model.FieldStatus: model.ActStatusCanceled,
}, ctx.GetUserName(), nil); err != nil {
return err
}
}
dao.Commit(db)
return err
}
func SyncAct(ctx *jxcontext.Context, parentTask tasksch.ITask, actID int, vendorIDs, storeIDs, skuIDs []int, isAsync bool) (hint string, err error) {
db := dao.GetDB()
actMap, err := dao.GetActVendorInfo(db, actID, vendorIDs)
if err != nil {
return "", err
}
actStoreSkuMap, err := dao.GetActStoreSkuVendorInfo(db, actID, nil, storeIDs, skuIDs)
if err != nil {
return "", err
}
if vendorIDs == nil {
vendorIDs = partner.GetVendorIDsFromActMap(actMap)
}
task := tasksch.NewParallelTask("SyncAct", nil, ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
vendorID := batchItemList[0].(int)
if handler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IPurchasePlatformActHandler); handler != nil {
if err = handler.SyncAct(ctx, nil, actMap[vendorID], nil, actStoreSkuMap[vendorID]); err == nil {
retVal = []int{1}
}
}
return retVal, err
}, vendorIDs)
tasksch.HandleTask(task, parentTask, true).Run()
if !isAsync {
result, err2 := task.GetResult(0)
if err = err2; err == nil {
hint = utils.Int2Str(len(result))
}
} else {
hint = task.GetID()
}
return hint, err
}