This commit is contained in:
苏尹岚
2020-10-14 11:57:12 +08:00
parent 5f791290ca
commit accb629e14
200 changed files with 206 additions and 51995 deletions

View File

@@ -1,340 +0,0 @@
package ebai
import (
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"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"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
func actType2Ebai(actType int) int {
if actType < model.ActOrderBegin {
return ebaiapi.ActivityTypeDirectDown
}
return ebaiapi.ActivityTypeFullDiscount
}
func actOrderRules2Ebai(actOrderRules []*model.ActOrderRule) (ebaiRules []*ebaiapi.ActivityRule) {
for _, v := range actOrderRules {
ebaiRules = append(ebaiRules, &ebaiapi.ActivityRule{
Accords: int(jxutils.IntPrice2Standard(v.SalePrice)),
Sale: int(jxutils.IntPrice2Standard(v.DeductPrice)),
})
}
return ebaiRules
}
func actStoreSu2Ebai4Add(oneStoreActSku []*model.ActStoreSku2) (skus []*ebaiapi.ActivitySkuInfo4Add) {
for _, v := range oneStoreActSku {
if v.VendorSkuID != "" {
if model.IsSyncStatusNeedCreate(v.SyncStatus) {
skus = append(skus, &ebaiapi.ActivitySkuInfo4Add{
SkuID: v.VendorSkuID,
SpecialPrice: v.ActualActPrice,
Stock: v.Stock,
})
}
}
}
return skus
}
func actStoreSu2Ebai4Update(oneStoreActSku []*model.ActStoreSku2) (skus []*ebaiapi.ActivitySkuInfo4Update) {
for _, v := range oneStoreActSku {
if v.VendorSkuID != "" {
if model.IsSyncStatusNeedUpdate(v.SyncStatus) {
skus = append(skus, &ebaiapi.ActivitySkuInfo4Update{
ShopID: utils.Int2Str(v.StoreID),
SkuID: v.VendorSkuID,
SpecialPrice: v.ActPrice,
Stock: v.Stock,
})
}
}
}
return skus
}
func actStoreSu2Ebai4Delete(oneStoreActSku []*model.ActStoreSku2) (skus []string) {
for _, v := range oneStoreActSku {
if v.VendorSkuID != "" {
if model.IsSyncStatusNeedDelete(v.SyncStatus) {
skus = append(skus, v.VendorSkuID)
}
}
}
return skus
}
func act2EbaiActivity(act *model.Act2, actOrderRules []*model.ActOrderRule) (activity *ebaiapi.ActivityInfo) {
activity = &ebaiapi.ActivityInfo{
ActivityName: utils.LimitMixedStringLen(act.GetRealActName(), ebaiapi.MaxActivityNameLength),
ActivityType: actType2Ebai(act.Type),
StartTime: act.BeginAt.Unix(),
EndTime: act.EndAt.Unix(),
OpenTime: "00:00",
CloseTime: "23:59",
WeekDay: "0,1,2,3,4,5,6",
ActivityDesc: act.Advertising,
ShowCategory: model.ActTypeName[act.Type],
PromotionSkuDesc: utils.LimitMixedStringLen(act.Advertising, ebaiapi.MaxActivityDescLength),
DayLimit: act.LimitDaily,
ActivityPlatform: ebaiapi.ActivityPFAll,
}
if act.LimitCount > 0 {
activity.OrderLimit = act.LimitCount
}
if activity.DayLimit == 0 {
activity.DayLimit = 999
}
if actOrderRules != nil {
activity.Rule = actOrderRules2Ebai(actOrderRules)
}
return activity
}
func createOneShopAct(act *model.Act2, shopID string, oneStoreActSku []*model.ActStoreSku2) (ebaiActIDStr string, err error) {
globals.SugarLogger.Debugf("ebai createOneShopAct")
activity := act2EbaiActivity(act, nil)
if globals.EnableEbaiStoreWrite {
ebaiActID, err2 := api.EbaiAPI.ActivityCreate(shopID, 0, 0, activity)
if err = err2; err == nil {
ebaiActIDStr = utils.Int64ToStr(ebaiActID)
if _, err = ActivitySkuAddBatch(ebaiActID, shopID, 0, activity.ActivityType, actStoreSu2Ebai4Add(oneStoreActSku), false); err != nil {
ActivityDisable(ebaiActID, shopID, 0, 0)
}
}
} else {
ebaiActIDStr = utils.Int64ToStr(jxutils.GenFakeID())
}
return ebaiActIDStr, err
}
func ActivitySkuAddBatch(activityID int64, shopID string, baiduShopID int64, activityType int, skuList []*ebaiapi.ActivitySkuInfo4Add, isSkuIDCustom bool) (successIDs []string, err error) {
globals.SugarLogger.Debugf("ebai ActivitySkuAddBatch")
if globals.EnableEbaiStoreWrite {
successIDs, err = api.EbaiAPI.ActivitySkuAddBatch(activityID, shopID, baiduShopID, activityType, skuList, isSkuIDCustom)
} else {
for _, v := range skuList {
successIDs = append(successIDs, v.SkuID)
}
}
return successIDs, err
}
func ActivitySkuDeleteBatch(activityID int64, shopID string, baiduShopID int64, skuIDs []string, isSkuIDCustom bool) (successIDs []string, err error) {
globals.SugarLogger.Debugf("ebai ActivitySkuDeleteBatch")
if globals.EnableEbaiStoreWrite {
successIDs, err = api.EbaiAPI.ActivitySkuDeleteBatch(activityID, shopID, baiduShopID, skuIDs, isSkuIDCustom)
} else {
successIDs = append([]string{}, skuIDs...)
}
return successIDs, err
}
func ActivitySkuUpdateBatch(activityID int64, actSkuInfoList []*ebaiapi.ActivitySkuInfo4Update) (faildInfoList []string, err error) {
globals.SugarLogger.Debugf("ebai ActivitySkuUpdateBatch")
if globals.EnableEbaiStoreWrite {
faildInfoList, err = api.EbaiAPI.ActivitySkuUpdateBatch(activityID, actSkuInfoList)
}
return faildInfoList, err
}
func ActivityDisable(activityID int64, shopID string, baiduShopID, supplierID int64) (err error) {
globals.SugarLogger.Debugf("ebai ActivityDisable")
if globals.EnableEbaiStoreWrite {
err = api.EbaiAPI.ActivityDisable(activityID, shopID, baiduShopID, supplierID)
}
return err
}
func getActStoreSkuFromTaskResult(taskReslt []interface{}) (list []*model.ActStoreSku2) {
for _, v := range taskReslt {
actStoreSkuList := v.([]*model.ActStoreSku2)
list = append(list, actStoreSkuList...)
}
return list
}
func createSkuAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actStoreSku []*model.ActStoreSku2) (createdList []*model.ActStoreSku2, err error) {
globals.SugarLogger.Debugf("ebai createSkuAct")
actStoreSkuListList := partner.SplitActStoreSku2List(actStoreSku)
task := tasksch.NewParallelTask("ebai createSkuAct", nil, ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
list := batchItemList[0].([]*model.ActStoreSku2)
var vendorActID string
if vendorActID, err = createOneShopAct(act, utils.Int2Str(list[0].StoreID), list); err == nil {
for _, v := range list {
v.VendorActID = vendorActID
}
retVal = []interface{}{list}
}
return retVal, err
}, actStoreSkuListList)
tasksch.HandleTask(task, parentTask, true).Run()
result, err := task.GetResult(0)
return getActStoreSkuFromTaskResult(result), err
}
func cancelSkuAct(ctx *jxcontext.Context, parentTask tasksch.ITask, actStoreSkuMap map[string][]*model.ActStoreSku2) (canceledList []*model.ActStoreSku2, err error) {
globals.SugarLogger.Debugf("ebai cancelSkuAct")
var vendorActIDs []string
for k := range actStoreSkuMap {
vendorActIDs = append(vendorActIDs, k)
}
task := tasksch.NewParallelTask("ebai cancelSkuAct", nil, ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
vendorActID := batchItemList[0].(string)
actStoreSkuList := actStoreSkuMap[vendorActID]
if vendorActID != "" {
err = ActivityDisable(utils.Str2Int64(vendorActID), utils.Int2Str(actStoreSkuList[0].StoreID), 0, 0)
}
if err == nil {
retVal = []interface{}{actStoreSkuList}
}
return retVal, err
}, vendorActIDs)
tasksch.HandleTask(task, parentTask, true).Run()
result, err := task.GetResult(0)
return getActStoreSkuFromTaskResult(result), err
}
func deleteSkuActSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, actStoreSkuMap, vendorActInfoMap map[string][]*model.ActStoreSku2) (deletedList []*model.ActStoreSku2, err error) {
globals.SugarLogger.Debugf("ebai deleteSkuActSkus")
var vendorActIDs []string
for k := range actStoreSkuMap {
if k != "" {
vendorActIDs = append(vendorActIDs, k)
}
}
if len(vendorActIDs) > 0 {
task := tasksch.NewParallelTask("ebai deleteSkuAct", nil, ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
vendorActID := batchItemList[0].(string)
actStoreSkuList := actStoreSkuMap[vendorActID]
vendorActStoreSkuList := vendorActInfoMap[vendorActID]
if len(actStoreSkuList) < len(vendorActStoreSkuList) {
if list := actStoreSu2Ebai4Delete(actStoreSkuList); len(list) > 0 {
_, err = ActivitySkuDeleteBatch(utils.Str2Int64(vendorActID), utils.Int2Str(actStoreSkuList[0].StoreID), 0, list, false)
}
} else {
err = ActivityDisable(utils.Str2Int64(vendorActID), utils.Int2Str(actStoreSkuList[0].StoreID), 0, 0)
}
if err == nil {
retVal = []interface{}{actStoreSkuList}
}
return retVal, err
}, vendorActIDs)
tasksch.HandleTask(task, parentTask, true).Run()
result, err2 := task.GetResult(0)
err = err2
deletedList = getActStoreSkuFromTaskResult(result)
}
return deletedList, err
}
func addSkuActSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actStoreSku []*model.ActStoreSku2, vendorActIDMap map[int]string) (addedList []*model.ActStoreSku2, err error) {
globals.SugarLogger.Debugf("ebai addSkuActSkus, actID:%d", act.ID)
actStoreSkuListList := partner.SplitActStoreSku2List(actStoreSku)
if len(actStoreSkuListList) > 0 {
task := tasksch.NewParallelTask("ebai addSkuActSkus", nil, ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
actStoreSkuList := batchItemList[0].([]*model.ActStoreSku2)
vendorActID := vendorActIDMap[actStoreSkuList[0].StoreID]
if vendorActID != "" {
if list := actStoreSu2Ebai4Add(actStoreSkuList); len(list) > 0 {
_, err = ActivitySkuAddBatch(utils.Str2Int64(vendorActID), utils.Int2Str(actStoreSkuList[0].StoreID), 0, actType2Ebai(act.Type), list, false)
}
} else {
vendorActID, err = createOneShopAct(act, utils.Int2Str(actStoreSkuList[0].StoreID), actStoreSkuList)
}
if err == nil {
for _, v := range actStoreSkuList {
v.VendorActID = vendorActID
}
retVal = []interface{}{actStoreSkuList}
}
return retVal, err
}, actStoreSkuListList)
tasksch.HandleTask(task, parentTask, true).Run()
result, err2 := task.GetResult(0)
err = err2
addedList = getActStoreSkuFromTaskResult(result)
}
return addedList, err
}
func (c *PurchaseHandler) SyncAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actOrderRules []*model.ActOrderRule, actStoreSkuList []*model.ActStoreSku2) (err error) {
globals.SugarLogger.Debugf("ebai SyncAct, actID:%d", act.ID)
vendorActInfoMap := make(map[string][]*model.ActStoreSku2)
deleteActInfoMap := make(map[string][]*model.ActStoreSku2)
vendorActIDMap := make(map[int]string)
var actStoreSkuList4Create []*model.ActStoreSku2
var updateItems []*dao.KVUpdateItem
actStoreSkuMap := partner.SplitActStoreSku(actStoreSkuList)
for storeID := range actStoreSkuMap {
for _, actStoreSku := range actStoreSkuMap[storeID] {
vendorActInfoMap[actStoreSku.VendorActID] = append(vendorActInfoMap[actStoreSku.VendorActID], actStoreSku)
if vendorActIDMap[storeID] == "" && actStoreSku.VendorActID != "" {
vendorActIDMap[storeID] = actStoreSku.VendorActID
}
if model.IsSyncStatusDelete(actStoreSku.SyncStatus) {
vendorActID := actStoreSku.VendorActID
if vendorActID == "" {
vendorActID = act.VendorActID
}
deleteActInfoMap[vendorActID] = append(deleteActInfoMap[vendorActID], actStoreSku)
} else if model.IsSyncStatusNew(actStoreSku.SyncStatus) {
actStoreSkuList4Create = append(actStoreSkuList4Create, actStoreSku)
}
}
}
err = func() (err error) {
if model.IsSyncStatusDelete(act.SyncStatus) {
canceledList, err2 := cancelSkuAct(ctx, nil, vendorActInfoMap)
updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, canceledList, model.SyncFlagModifiedMask)...)
if err = err2; err == nil {
updateItems = append(updateItems, partner.Act2Update(ctx, act, model.SyncFlagModifiedMask))
}
} else if model.IsSyncStatusNew(act.SyncStatus) {
createdList, err2 := createSkuAct(ctx, nil, act, actStoreSkuList4Create)
updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, createdList, model.SyncFlagNewMask)...)
if err = err2; err == nil {
updateItems = append(updateItems, partner.Act2Update(ctx, act, model.SyncFlagNewMask))
}
} else if model.IsSyncStatusUpdate(act.SyncStatus) {
// globals.SugarLogger.Debug(utils.Format4Output(updateItems, false))
if len(actStoreSkuList4Create) > 0 {
addedList, err2 := addSkuActSkus(ctx, nil, act, actStoreSkuList4Create, vendorActIDMap)
updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, addedList, model.SyncFlagNewMask)...)
if err = err2; err != nil {
return err
}
}
if len(deleteActInfoMap) > 0 {
deletedList, err2 := deleteSkuActSkus(ctx, nil, deleteActInfoMap, vendorActInfoMap)
updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, deletedList, model.SyncFlagDeletedMask)...)
if err = err2; err != nil {
return err
}
}
if err == nil {
updateItems = append(updateItems, partner.Act2Update(ctx, act, model.SyncFlagModifiedMask))
}
}
return err
}()
db := dao.GetDB()
_, err2 := dao.BatchUpdateActEntity(db, model.IsSyncStatusDelete(act.SyncStatus), updateItems)
if err == nil {
err = err2
}
return err
}

View File

@@ -1,117 +0,0 @@
package ebai
import (
"fmt"
"time"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/jx-callback/globals/api"
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/model"
)
type tShowStatusAndTypeInfo struct {
ShowStatus int
ActivityType int
}
func ebaiPageActType2Jx(activityType int) int {
if activityType == ebaiapi.PageActivityTypeSkuDiscount || activityType == ebaiapi.PageActivityTypeSkuDirectDown {
return model.ActSkuDirectDown
} else if activityType == ebaiapi.PageActivityTypeSkuSpecialPrice {
return model.ActSkuSecKill
}
return 0
}
func ebaiPageActStatus2Jx(status int) int {
if status == ebaiapi.PageActivityStatusWaiting || status == ebaiapi.PageActivityStatusOnGoing {
return model.ActStatusCreated
} else if status == ebaiapi.PageActivityStatusEnded {
return model.ActStatusEnded
}
return model.ActStatusNA
}
func (c *PurchaseHandler) GetPageActList(ctx *jxcontext.Context, createdFrom time.Time) (actList []*model.Act2, err error) {
var typeAndStatusList []*tShowStatusAndTypeInfo
for _, showStatus := range []int{
ebaiapi.PageActivityShowStatusWaiting,
ebaiapi.PageActivityShowStatusOnGoing,
// ebaiapi.PageActivityStatusEnded,
} {
for _, activityType := range []int{
ebaiapi.PageActivityTypeSkuDiscount,
ebaiapi.PageActivityTypeSkuSpecialPrice,
ebaiapi.PageActivityTypeSkuDirectDown,
} {
typeAndStatusList = append(typeAndStatusList, &tShowStatusAndTypeInfo{
ShowStatus: showStatus,
ActivityType: activityType,
})
}
}
task := tasksch.NewParallelTask("ebai GetPageActList", tasksch.NewParallelConfig().SetParallelCount(10), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
info := batchItemList[0].(*tShowStatusAndTypeInfo)
list, err := api.EbaiAPI.BegetActivityList(info.ShowStatus, info.ActivityType, 0, api.EbaiAPI.GetSupplierID())
if err == nil {
retVal = list
}
return retVal, err
}, typeAndStatusList)
task.Run()
list, err := task.GetResult(0)
if len(list) > 0 {
for _, v := range list {
ebaiAct := v.(*ebaiapi.PageActItem)
if utils.Timestamp2Time(ebaiAct.CreateTime).Sub(createdFrom) > 0 {
act := &model.Act2{
Act: model.Act{
Name: fmt.Sprintf("%s-%s", ebaiAct.ActivityName, ebaiAct.ActivityID),
Type: ebaiPageActType2Jx(ebaiAct.ActivityType),
Status: ebaiPageActStatus2Jx(ebaiAct.Status),
Source: ebaiAct.User,
CreateType: model.ActCreateTypeSpider,
BeginAt: utils.Timestamp2Time(ebaiAct.StartTime),
EndAt: utils.Timestamp2Time(ebaiAct.EndTime),
VendorMask: model.GetVendorMask(model.VendorIDEBAI),
LimitCount: 1,
},
VendorID: model.VendorIDEBAI,
VendorOrgCode: api.EbaiAPI.GetSource(),
VendorActID: ebaiAct.ActivityID,
}
actList = append(actList, act)
}
}
}
return actList, err
}
func (c *PurchaseHandler) GetPageActSkuList(ctx *jxcontext.Context, vendorPageActID string) (actStoreSkuList []*model.ActStoreSku2, err error) {
skus, err := api.EbaiAPI.BegetActSkuList(utils.Str2Int64(vendorPageActID), 0, api.EbaiAPI.GetSupplierID())
if err != nil {
return nil, err
}
for _, v := range skus {
actStoreSku := &model.ActStoreSku2{
ActStoreSku: model.ActStoreSku{
Stock: v.Stock,
OriginalPrice: jxutils.StandardPrice2Int(v.OriginalPrice),
},
VendorStoreID: utils.Int64ToStr(v.Wid),
VendorSkuID: v.SkuID,
VendorActID: v.ActivityID,
ActualActPrice: jxutils.StandardPrice2Int(v.PromotionPrice),
}
actStoreSkuList = append(actStoreSkuList, actStoreSku)
}
return actStoreSkuList, nil
}

View File

@@ -1,28 +0,0 @@
package ebai
import (
"testing"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
_ "git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
_ "git.rosy.net.cn/jx-callback/business/jxcallback/scheduler/defsch"
)
func TestGetPageActList(t *testing.T) {
actList, err := new(PurchaseHandler).GetPageActList(jxcontext.AdminCtx, utils.DefaultTimeValue)
if err != nil {
t.Fatal(err)
}
t.Log(utils.Format4Output(actList, false))
t.Log(len(actList))
}
func TestGetPageActSkuList(t *testing.T) {
actList, err := new(PurchaseHandler).GetPageActSkuList(jxcontext.AdminCtx, "3000000001477429")
if err != nil {
t.Fatal(err)
}
t.Log(utils.Format4Output(actList, false))
}

View File

@@ -1,45 +0,0 @@
package ebai
import (
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/globals"
)
func OnCallbackMsg(msg *ebaiapi.CallbackMsg) (response *ebaiapi.CallbackResponse) {
globals.SugarLogger.Debugf("ebai OnCallbackMsg msg:%s", utils.Format4Output(msg, true))
if CurPurchaseHandler != nil {
if orderID := GetOrderIDFromMsg(msg); orderID != "" {
jxutils.CallMsgHandler(func() {
switch msg.Cmd {
case ebaiapi.CmdOrderCreate, ebaiapi.CmdOrderStatus, ebaiapi.CmdOrderUserCancel, ebaiapi.CmdOrderPartRefund:
response = CurPurchaseHandler.onOrderMsg(msg)
case ebaiapi.CmdOrderDeliveryStatus:
response = CurPurchaseHandler.onWaybillMsg(msg)
}
}, jxutils.ComposeUniversalOrderID(orderID, model.VendorIDEBAI))
}
if /*msg.Cmd == ebaiapi.CmdOrderPartRefund || msg.Cmd == ebaiapi.CmdOrderUserCancel || */ msg.Cmd == ebaiapi.CmdOrderDeliveryStatus {
response = CurPurchaseHandler.OnFinancialMsg(msg)
} else if msg.Cmd == ebaiapi.CmdShopMsgPush {
response = CurPurchaseHandler.onShopMsgPush(msg)
}
}
return response
}
func GetOrderIDFromMsg(msg *ebaiapi.CallbackMsg) string {
return GetOrderIDFromMap(msg.Body)
}
func GetOrderIDFromMap(orderMap map[string]interface{}) string {
if orderID := orderMap["order_id"]; orderID != nil {
if tryOrderID, ok := orderID.(string); ok {
return tryOrderID
}
return utils.Int64ToStr(utils.MustInterface2Int64(orderID))
}
return ""
}

View File

@@ -1,47 +0,0 @@
package ebai
import (
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
func (p *PurchaseHandler) UpdatePlaces() (err error) {
provinces, err := api.EbaiAPI.CommonShopCities(0)
if err == nil {
task := tasksch.NewParallelTask("UpdatePlaces", nil, jxcontext.AdminCtx,
func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
province := batchItemList[0].(*ebaiapi.CityInfo)
retSlice := make([]*ebaiapi.CityInfo, 0)
if province.IsOpen != 0 {
retSlice = append(retSlice, province)
cities, err := api.EbaiAPI.CommonShopCities(province.ID)
for _, city := range cities {
if city.IsOpen != 0 {
retSlice = append(retSlice, city)
districts, err2 := api.EbaiAPI.CommonShopCities(city.ID)
if err = err2; err == nil {
for _, district := range districts {
if district.IsOpen != 0 {
retSlice = append(retSlice, district)
}
}
} else {
break
}
}
}
}
return retSlice, err
}, provinces)
task.Run()
places, err2 := task.GetResult(0)
if err = err2; err == nil {
globals.SugarLogger.Debug(utils.Format4Output(places, false))
}
}
return err
}

View File

@@ -1,12 +0,0 @@
package ebai
import (
"testing"
)
func TestUpdatePlacese(t *testing.T) {
err := new(PurchaseHandler).UpdatePlaces()
if err != nil {
t.Fatal(err.Error())
}
}

View File

@@ -1,143 +0,0 @@
package ebai
import (
"sync"
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/business/partner/putils"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
var (
CurPurchaseHandler *PurchaseHandler
)
type PurchaseHandler struct {
partner.BasePurchasePlatform
putils.DefSingleStorePlatform
shopList []*ebaiapi.ShopInfo
locker sync.RWMutex
}
func init() {
if api.EbaiAPI != nil {
CurPurchaseHandler = New()
partner.RegisterPurchasePlatform(CurPurchaseHandler)
}
}
func New() (obj *PurchaseHandler) {
obj = new(PurchaseHandler)
obj.ISingleStoreStoreSkuHandler = obj
return obj
}
func EbaiBusStatus2JxStatus(ebaiStatus int) int {
if ebaiStatus == ebaiapi.ShopBusStatusHaveRest {
return model.StoreStatusClosed
}
if ebaiStatus == ebaiapi.ShopBusStatusSuspended {
return model.StoreStatusDisabled
}
return model.StoreStatusOpened
}
func (p *PurchaseHandler) GetVendorID() int {
return model.VendorIDEBAI
}
func (p *PurchaseHandler) UploadImg(ctx *jxcontext.Context, vendorOrgCode, imgURL string, imgData []byte, imgName string, imgType int) (imgHint string, err error) {
globals.SugarLogger.Debugf("ebai UploadImg imgURL:%s, imgName:%s, imgType:%d", imgURL, imgName, imgType)
if globals.EnableEbaiStoreWrite {
if imgType == model.ImgTypeMain {
imgHint, err = api.EbaiAPI.PictureUpload(imgURL, imgData)
} else if imgType == model.ImgTypeDesc {
imgHint, err = api.EbaiAPI.SkuUploadRTF(p.getShopID4UploadRTF(), ebaiapi.BuildRFTFromImgs(imgURL))
}
} else {
imgHint = imgURL + ".ebai"
}
return imgHint, err
}
func getShopIDFromList(shopList []*ebaiapi.ShopInfo) (shopID string) {
if len(shopList) > 0 {
shopID = shopList[0].ShopID
}
return shopID
}
func (p *PurchaseHandler) getShopID4UploadRTF() (shopID string) {
var shopList []*ebaiapi.ShopInfo
p.locker.RLock()
shopList = p.shopList
p.locker.RUnlock()
if len(shopList) > 0 {
return getShopIDFromList(shopList)
}
p.locker.Lock()
shopList = p.shopList
if len(shopList) > 0 {
p.locker.Unlock()
return getShopIDFromList(shopList)
}
defer p.locker.Unlock()
shopList, err := api.EbaiAPI.ShopList(ebaiapi.SysStatusAll)
if err == nil {
if len(shopList) > 0 {
p.shopList = shopList
shopID = getShopIDFromList(shopList)
} else {
// p.shopList = []*ebaiapi.ShopInfo{
// &ebaiapi.ShopInfo{
// ShopID: "",
// },
// }
}
}
return shopID
}
func (p *PurchaseHandler) getVendorCategories(level int, pid int64) (vendorCats []*model.SkuVendorCategory, err error) {
cats, err := api.EbaiAPI.SkuCategoryList("", level, pid)
if err != nil {
return nil, err
}
for _, v := range cats {
cat := &model.SkuVendorCategory{
VendorID: model.VendorIDEBAI,
Name: v.CatName,
Level: level,
VendorCategoryID: v.CatID,
}
if level > 1 {
cat.ParentID = v.ParentID
if level == 3 {
cat.IsLeaf = 1
}
}
vendorCats = append(vendorCats, cat)
if level < 3 {
childVendorCats, err2 := p.getVendorCategories(level+1, utils.Str2Int64(v.CatID))
if err2 == nil && len(childVendorCats) > 0 {
vendorCats = append(vendorCats, childVendorCats...)
} else {
cat.IsLeaf = 1
}
}
}
return vendorCats, nil
}
func (p *PurchaseHandler) GetVendorCategories(ctx *jxcontext.Context) (vendorCats []*model.SkuVendorCategory, err error) {
vendorCats, err = p.getVendorCategories(1, 0)
return vendorCats, err
}

View File

@@ -1,32 +0,0 @@
package ebai
import (
"testing"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
_ "git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
_ "git.rosy.net.cn/jx-callback/business/jxcallback/scheduler/defsch"
"git.rosy.net.cn/jx-callback/globals/testinit"
)
const (
// testShopBaiduID = "2233976901"
// testShopID = 100077
testShopBaiduID = "2267254343"
testShopID = 2
)
func init() {
testinit.Init()
}
func TestGetVendorCategories(t *testing.T) {
catList, err := new(PurchaseHandler).GetVendorCategories(jxcontext.AdminCtx)
if err != nil {
t.Fatal(err)
}
t.Log(utils.Format4Output(catList, false))
}

View File

@@ -1,288 +0,0 @@
package ebai
import (
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
func (p *PurchaseHandler) OnFinancialMsg(msg *ebaiapi.CallbackMsg) (response *ebaiapi.CallbackResponse) {
utils.CallFuncAsync(func() {
response = p.onFinancialMsg(msg)
})
return response
}
// 存储饿百退款订单结账信息
func (p *PurchaseHandler) onFinancialMsg(msg *ebaiapi.CallbackMsg) (response *ebaiapi.CallbackResponse) {
var err error
if msg.Cmd == ebaiapi.CmdOrderPartRefund { // 部分退款处理
if int(utils.MustInterface2Int64(msg.Body["status"])) == ebaiapi.OrderPartRefundSuccess {
// 获取到部分退款订单id
afsOrderID := GetOrderIDFromMsg(msg)
// 处理部分退款信息
orderData, err2 := api.EbaiAPI.OrderPartRefundGet(afsOrderID)
if err = err2; err == nil {
afsOrder := CurPurchaseHandler.AfsOrderDetail2Financial(orderData)
err = partner.CurOrderManager.SaveAfsOrderFinancialInfo(afsOrder)
}
}
} else if msg.Cmd == ebaiapi.CmdOrderUserCancel { // 全额退款处理
messageType := int(utils.MustInterface2Int64(msg.Body["type"]))
if int(utils.MustInterface2Int64(msg.Body["cancel_type"])) == ebaiapi.OrderUserCancelTypeAfterSale &&
(messageType == ebaiapi.OrderUserCancelCSAgreed || messageType == ebaiapi.OrderUserCancelMerchantAgreed) {
afsOrderID := GetOrderIDFromMsg(msg)
// 获得退款订单ID去本地数据库拿饿百消息推送只给了订单号但是没有查询全额退款的接口只有部分退款才可以查询
orderFinancial, err := partner.CurOrderManager.LoadOrderFinancial(afsOrderID, model.VendorIDEBAI)
if err == nil {
globals.SugarLogger.Debug(utils.Format4Output(orderFinancial, false))
err = partner.CurOrderManager.SaveAfsOrderFinancialInfo(CurPurchaseHandler.OrderFinancialDetail2Refund(orderFinancial, msg))
} else {
globals.SugarLogger.Warnf("ebai OnFinancialMsg, afsOrderID:%s is not found from partner.CurOrderManager.LoadOrderFinancial", afsOrderID)
}
}
} else if msg.Cmd == ebaiapi.CmdOrderDeliveryStatus { // 转自送调整
if utils.Int64ToStr(utils.MustInterface2Int64(msg.Body["status"])) == ebaiapi.WaybillStatusSelfDelivery {
vendorOrderID := GetOrderIDFromMsg(msg)
orderMap, err := api.EbaiAPI.OrderGet(vendorOrderID)
if err == nil {
err = CurPurchaseHandler.OnOrderDetail(orderMap, partner.UpdatedPeration)
}
}
}
return api.EbaiAPI.Err2CallbackResponse(msg.Cmd, err, msg.Cmd)
}
func (p *PurchaseHandler) OrderFinancialDetail2Refund(orderFinancial *model.OrderFinancial, msg *ebaiapi.CallbackMsg) (afsOrder *model.AfsOrder) {
afsOrder = &model.AfsOrder{
VendorID: model.VendorIDEBAI,
AfsOrderID: GetOrderIDFromMsg(msg),
VendorOrderID: GetOrderIDFromMsg(msg),
AfsCreatedAt: utils.Timestamp2Time(msg.Timestamp),
// BoxMoney: orderFinancial.BoxMoney, // 饿百的餐盒费已经拆分到单条Sku里面退款时直接计算用户支付sku金额就好了
// SkuBoxMoney: orderFinancial.SkuBoxMoney,
FreightUserMoney: orderFinancial.FreightMoney,
SkuUserMoney: orderFinancial.ActualPayMoney - orderFinancial.FreightMoney,
PmSubsidyMoney: orderFinancial.PmSubsidyMoney,
}
// if msg.Body["timestamp"] != nil {
// afsOrder.AfsCreateAt = utils.Timestamp2Time(utils.Str2Int64(utils.Interface2String(msg.Body["timestamp"])))
// } else {
// globals.SugarLogger.Warnf("ebai OrderFinancialDetail2Refund timestamp is not found in afsOrder:%s", afsOrder.AfsOrderID)
// afsOrder.AfsCreateAt = time.Now()
// }
order, err := partner.CurOrderManager.LoadOrder(afsOrder.VendorOrderID, afsOrder.VendorID)
globals.SugarLogger.Debug(utils.Format4Output(order, false))
if err == nil {
afsOrder.JxStoreID = order.JxStoreID
afsOrder.VendorStoreID = order.VendorStoreID
afsOrder.StoreID = order.StoreID
} else {
globals.SugarLogger.Warnf("ebai AfsOrderDetail2Financial, afsOrderID:%s is not found from partner.CurOrderManager.LoadOrder", afsOrder.VendorOrderID)
err = nil
}
for _, sku := range orderFinancial.Skus {
orderSkuFinancial := &model.OrderSkuFinancial{
VendorID: sku.VendorID,
VendorOrderID: sku.VendorOrderID,
AfsOrderID: sku.VendorOrderID,
// ConfirmTime: afsOrder.AfsCreateAt,
VendorStoreID: afsOrder.VendorStoreID,
StoreID: afsOrder.StoreID,
JxStoreID: afsOrder.JxStoreID,
VendorSkuID: sku.VendorSkuID,
SkuID: sku.SkuID,
PromotionType: sku.PromotionType,
Name: sku.Name,
ShopPrice: sku.ShopPrice,
SalePrice: sku.SalePrice,
Count: sku.Count,
SkuBoxMoney: sku.SkuBoxMoney,
UserMoney: sku.UserMoney,
PmSubsidyMoney: sku.PmSubsidyMoney,
IsAfsOrder: 1,
}
afsOrder.Skus = append(afsOrder.Skus, orderSkuFinancial)
}
return afsOrder
}
func (p *PurchaseHandler) AfsOrderDetail2Financial(orderData map[string]interface{}) (afsOrder *model.AfsOrder) {
afsOrder = &model.AfsOrder{
VendorID: model.VendorIDEBAI,
AfsOrderID: GetOrderIDFromMap(orderData),
VendorOrderID: GetOrderIDFromMap(orderData),
}
order, err := partner.CurOrderManager.LoadOrder(afsOrder.VendorOrderID, afsOrder.VendorID)
if err == nil {
afsOrder.JxStoreID = order.JxStoreID
} else {
globals.SugarLogger.Warnf("ebai AfsOrderDetail2Financial, afsOrderID:%s is not found from partner.CurOrderManager.LoadOrder", afsOrder.VendorOrderID)
err = nil
}
// 部分退款订单,第三方平台佣金会变化,金额为 orderData["commission"],是否将该字段更新到正向订单结算表中
// 不作更新的话,商户可以得到的钱会少几毛钱,最终京西受益
// 如果要更新,总佣金,京西佣金是否都要更新,而其它一系列连锁反应,是否需要考虑更新
// 或者换个思路,不考虑变更之前的正向订单,在佣金上入手,退款金额减去佣金减少的部分
orderFinancial, err := partner.CurOrderManager.LoadOrderFinancial(afsOrder.VendorOrderID, model.VendorIDEBAI)
if err == nil {
afsOrder.PmRefundMoney = orderFinancial.PmMoney - utils.MustInterface2Int64(orderData["commission"])
} else {
// 此处应该报错
// globals.SugarLogger.Warnf("ebai AfsOrderDetail2Financial, afsOrderID:%s is not found from partner.CurOrderManager.LoadOrderFinancial", afsOrder.VendorOrderID)
err = nil
}
if orderData["refund_detail"] != nil {
refundDetail := orderData["refund_detail"].([]interface{})
for _, refundInfo := range refundDetail {
xMap := refundInfo.(map[string]interface{})
orderSkuFinancial := &model.OrderSkuFinancial{
VendorID: model.VendorIDEBAI,
AfsOrderID: afsOrder.AfsOrderID,
VendorOrderID: afsOrder.VendorOrderID,
// ConfirmTime: getTimeFromInterface(xMap["apply_time"]),
VendorSkuID: utils.Interface2String(xMap["sku_id"]),
SkuID: int(utils.Str2Int64WithDefault(utils.Interface2String(xMap["custom_sku_id"]), 0)),
Name: utils.Interface2String(xMap["name"]),
UserMoney: utils.MustInterface2Int64(xMap["total_refund"]),
PmSubsidyMoney: utils.MustInterface2Int64(xMap["shop_ele_refund"]),
IsAfsOrder: 1,
}
afsOrder.Skus = append(afsOrder.Skus, orderSkuFinancial)
afsOrder.SkuUserMoney += orderSkuFinancial.UserMoney
afsOrder.PmSubsidyMoney += orderSkuFinancial.PmSubsidyMoney
}
if len(refundDetail) > 0 {
afsOrder.AfsCreatedAt = getTimeFromInterface(refundDetail[0].(map[string]interface{})["apply_time"])
} else {
globals.SugarLogger.Warnf("ebai AfsOrderDetail2Financial, orderID:%s have no refund_detail", afsOrder.VendorOrderID)
}
} else {
globals.SugarLogger.Warnf("ebai AfsOrderDetail2Financial, orderID:% refund_detail is nil", afsOrder.VendorOrderID)
}
return afsOrder
}
// 存储饿百正向订单结账信息
func (p *PurchaseHandler) OnOrderDetail(result map[string]interface{}, operation string) (err error) {
err = partner.CurOrderManager.SaveOrderFinancialInfo(p.OrderDetail2Financial(result), operation)
return err
}
// func (p *PurchaseHandler) GetTrueEbaiOrder(result1 map[string]interface{}) (result2 map[string]interface{}) {
// order := result1["order"].(map[string]interface{})
// if utils.MustInterface2Int64(order["down_flag"]) == 1 {
// result, err := api.EbaiAPI.OrderGet(GetOrderIDFromMap(order))
// if err == nil {
// return p.GetTrueEbaiOrder(result)
// }
// }
// return result1
// }
func (p *PurchaseHandler) OrderDetail2Financial(result map[string]interface{}) (orderFinancial *model.OrderFinancial) {
orderFinancial = &model.OrderFinancial{
VendorID: model.VendorIDEBAI,
}
order1 := result["order"].(map[string]interface{})
orderFinancial.VendorOrderID = GetOrderIDFromMap(order1)
orderFinancial.VendorOrderID2 = utils.Interface2String(order1["eleme_order_id"])
// orderFinancial.DeliveryConfirmTime = getTimeFromInterface(order1["finished_time"])
orderFinancial.TotalDiscountMoney = utils.MustInterface2Int64(order1["discount_fee"])
orderFinancial.ReceivableFreight = utils.MustInterface2Int64(order1["send_fee"])
orderFinancial.DownFlag = int8(utils.MustInterface2Int64(order1["down_flag"]))
if int(getInt64FromInterface(order1["delivery_party"])) == ebaiapi.DeliveryPartyFengElmSelf {
orderFinancial.SelfDeliveryDiscountMoney = orderFinancial.ReceivableFreight
orderFinancial.DistanceFreightMoney = 0
// 通过本地数据库去取是否转美团/达达,并计算运费
// wayBill, err := partner.CurOrderManager.LoadWaybill(orderFinancial.VendorOrderID, orderFinancial.VendorID)
// if err == nil {
// orderFinancial.JxFreightMoney = wayBill.DesiredFee
// }
}
orderFinancial.BoxMoney = utils.ForceInterface2Int64(order1["package_fee"])
orderFinancial.ActualPayMoney = utils.ForceInterface2Int64(order1["user_fee"])
orderFinancial.PmMoney = utils.ForceInterface2Int64(order1["commission"])
orderFinancial.ShopMoney = utils.ForceInterface2Int64(order1["shop_fee"])
order, err := partner.CurOrderManager.LoadOrder(orderFinancial.VendorOrderID, orderFinancial.VendorID)
storeID := 0
jxStoreID := 0
if err == nil {
storeID = order.StoreID
jxStoreID = order.JxStoreID
skus := order.Skus
if skus != nil {
for _, x := range skus {
orderFinancial.ShopPriceMoney += x.ShopPrice * int64(x.Count)
}
}
} else {
globals.SugarLogger.Warnf("ebai OrderDetail2Financial, orderID:%s is not found from partner.CurOrderManager.LoadOrder", orderFinancial.VendorOrderID)
err = nil
}
shop := result["shop"].(map[string]interface{})
if result["products"] != nil {
products := result["products"].([]interface{})
for _, x := range products {
for _, y := range x.([]interface{}) {
product := y.(map[string]interface{})
orderSkuFinancial := &model.OrderSkuFinancial{
VendorID: orderFinancial.VendorID,
VendorOrderID: orderFinancial.VendorOrderID,
// OrderFinancialID: orderFinancial.VendorOrderID,
// ConfirmTime: getTimeFromInterface(order1["create_time"]),
VendorStoreID: utils.Interface2String(shop["baidu_shop_id"]),
StoreID: storeID,
JxStoreID: jxStoreID,
VendorSkuID: utils.Interface2String(product["baidu_product_id"]),
SkuID: int(utils.Str2Int64WithDefault(utils.Interface2String(product["custom_sku_id"]), 0)),
Name: utils.Interface2String(product["product_name"]),
SalePrice: utils.MustInterface2Int64(product["product_price"]),
Count: int(utils.MustInterface2Int64(product["product_amount"])),
SkuBoxMoney: utils.MustInterface2Int64(product["package_fee"]),
IsAfsOrder: 0,
}
orderFinancial.Skus = append(orderFinancial.Skus, orderSkuFinancial)
orderFinancial.SalePriceMoney += orderSkuFinancial.SalePrice * int64(orderSkuFinancial.Count)
orderFinancial.SkuBoxMoney += orderSkuFinancial.SkuBoxMoney
orderFinancial.BoxMoney -= orderSkuFinancial.SkuBoxMoney
}
}
}
if result["discount"] != nil {
discount := result["discount"].([]interface{})
for _, x := range discount {
xMap := x.(map[string]interface{})
discountPrice := utils.MustInterface2Int64(xMap["fee"])
orderFinancial.DiscountMoney += discountPrice
orderFinancial.PmSubsidyMoney += utils.MustInterface2Int64(xMap["baidu_rate"]) // 平台承担补贴
activity := &model.OrderDiscountFinancial{
VendorID: orderFinancial.VendorID,
VendorOrderID: orderFinancial.VendorOrderID,
// ActivityName: utils.Interface2String(xMap["desc"]),
// ActivityMoney: discountPrice,
VendorActivityID: utils.Interface2String(xMap["activity_id"]),
Type: utils.Interface2String(xMap["type"]),
}
orderFinancial.Discounts = append(orderFinancial.Discounts, activity)
// 通过活动Id去取京西活动补贴
// orderFinancial.JxSubsidyMoney +=
}
}
orderFinancial.FreightDiscountMoney = orderFinancial.TotalDiscountMoney - orderFinancial.DiscountMoney
return orderFinancial
}
func getInt64FromInterface(strOrNum interface{}) int64 {
var resultNum int64
if resultStr, ok := strOrNum.(string); ok {
resultNum = utils.Str2Int64WithDefault(resultStr, 0)
} else {
resultNum = utils.Interface2Int64WithDefault(strOrNum, 0)
}
return resultNum
}

View File

@@ -1,40 +0,0 @@
package ebai
import (
"encoding/json"
"fmt"
"testing"
"time"
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals/api"
)
func TestOnFinancialMsg(t *testing.T) {
msg := &ebaiapi.CallbackMsg{
Timestamp: time.Now().Unix(),
Body: make(map[string]interface{}),
}
msg.Body["order_id"] = "1554939646172038357"
// 部分退款
msg.Cmd = "order.partrefund.push"
msg.Body["status"] = json.Number("20")
// 全单退款
// msg.Cmd = "order.user.cancel"
// msg.Body["type"] = json.Number("40")
// msg.Body["cancel_type"] = json.Number("2")
res := CurPurchaseHandler.onAfsOrderMsg(msg)
fmt.Println(res)
}
func TestOnOrderDetail(t *testing.T) {
orderID := "1554939646172038357"
result, err := api.EbaiAPI.OrderGet(orderID)
if err == nil {
new(PurchaseHandler).OnOrderDetail(result, partner.CreatedPeration)
}
}

View File

@@ -1 +0,0 @@
package ebai

View File

@@ -1,722 +0,0 @@
package ebai
import (
"fmt"
"math"
"strings"
"time"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
const (
// acceptOrderDelay = 180 * time.Second
// pickupOrderDelay = 260 * time.Second
pickupOrderDelay = 1 * time.Minute
callDeliveryDelay = 10 * time.Minute
callDeliveryDelayGap = 30
fakeAcceptOrder = "fake_accept_order"
fakeOrderAdjustFinished = "fake_order_adjust_finished"
fakeOrderCanceled = "fake_order_canceled"
)
// 饿百的接单会直接召唤配送,为了统一将饿百的接单影射成拣货完成,然后模拟一个接单消息
var (
VendorStatus2StatusMap = map[string]int{
ebaiapi.CmdOrderCreate: model.OrderStatusWaitAccepted,
ebaiapi.OrderStatusNew: model.OrderStatusWaitAccepted,
fakeAcceptOrder: model.OrderStatusAccepted,
ebaiapi.OrderStatusAccepted: model.OrderStatusFinishedPickup,
ebaiapi.OrderStatusCourierAccepted: model.OrderStatusDelivering,
ebaiapi.OrderStatusCourierPickedup: model.OrderStatusDelivering,
ebaiapi.OrderStatusFinished: model.OrderStatusFinished,
ebaiapi.OrderStatusCanceled: model.OrderStatusCanceled,
fakeOrderAdjustFinished: model.OrderStatusAdjust,
fakeOrderCanceled: model.OrderStatusCanceled,
}
skuActTypeMap = map[string]int{
ebaiapi.OrderSkuDiscountTypeZhe: 1,
ebaiapi.OrderSkuDiscountTypeReduce: 1,
ebaiapi.OrderSkuDiscountTypeTe: 1,
}
deliveryTypeMap = map[int]string{
ebaiapi.DeliveryPartyFengElmSelf: model.OrderDeliveryTypeStoreSelf,
}
)
func mapDeliveryType(ebaiDeliveryParty int, businessType int) (deliveryType string) {
if businessType == ebaiapi.DeliveryBusinessTypeZT {
return model.OrderDeliveryTypeSelfTake
} else {
deliveryType = deliveryTypeMap[ebaiDeliveryParty]
if deliveryType == "" {
deliveryType = model.OrderDeliveryTypePlatform
}
}
return deliveryType
}
func (p *PurchaseHandler) getStatusFromVendorStatus(vendorStatus string) int {
if status, ok := VendorStatus2StatusMap[vendorStatus]; ok {
return status
}
return model.OrderStatusUnknown
}
func (p *PurchaseHandler) GetOrder(vendorOrgCode, vendorOrderID string) (order *model.GoodsOrder, err error) {
order, _, err = p.getOrder(vendorOrderID)
return order, err
}
func (p *PurchaseHandler) GetOrderStatus(vendorOrgCode, vendorOrderID string) (status int, err error) {
status, err = api.EbaiAPI.OrderStatusGet(vendorOrderID)
if err == nil {
status = p.getStatusFromVendorStatus(utils.Int2Str(status))
}
return status, err
}
func (p *PurchaseHandler) getOrder(vendorOrderID string) (order *model.GoodsOrder, orderMap map[string]interface{}, err error) {
for i := 0; i < 2; i++ {
orderMap, err = api.EbaiAPI.OrderGet(vendorOrderID)
if err == nil {
order = p.Map2Order(orderMap)
// 饿百订单有时会出现取不到baidu_shop_id的情况重试
if order.VendorStoreID != "" {
break
}
}
time.Sleep(100 * time.Millisecond)
}
return order, orderMap, err
}
func (p *PurchaseHandler) GetOrder4PartRefund(vendorOrderID string) (order *model.GoodsOrder, err error) {
taskIDs := []int{1, 2}
var (
err1, err2 error
result1, result2 map[string]interface{}
)
task := tasksch.NewParallelTask("GetOrder4PartRefund", nil, jxcontext.AdminCtx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
taskID := batchItemList[0].(int)
if taskID == 1 {
result1, err1 = api.EbaiAPI.OrderGet(vendorOrderID)
} else if taskID == 2 {
result2, err2 = api.EbaiAPI.OrderPartRefundGet(vendorOrderID)
}
return nil, nil
}, taskIDs)
task.Run()
task.GetResult(0)
if err1 == nil {
order = p.Map2Order(result1)
if err2 == nil {
order.Skus = p.partRefund2OrderDetailSkuList(utils.Interface2String(result2["order_id"]), result2["order_detail"])
giftSkus, discountMoney := getZengSkus(vendorOrderID, result1)
order.DiscountMoney = discountMoney
order.Skus = append(order.Skus, giftSkus...)
order.ActualPayPrice = utils.MustInterface2Int64(result2["user_fee"])
order.TotalShopMoney = utils.MustInterface2Int64(result2["shop_fee"])
jxutils.RefreshOrderSkuRelated(order)
} else if err2Ext, ok := err2.(*utils.ErrorWithCode); !ok || err2Ext.IntCode() != ebaiapi.ErrOrderIsNotPartRefund {
err = err2
}
} else {
err = err1
}
return order, err
}
func getZengSkus(orderID string, orderMan map[string]interface{}) (skus []*model.OrderSku, discountMoney int64) {
discounts, _ := orderMan["discount"].([]interface{})
for _, v := range discounts {
discount := v.(map[string]interface{})
discountType := utils.Interface2String(discount["type"])
if discountType == ebaiapi.OrderSkuDiscountTypeZeng {
sku := &model.OrderSku{
VendorOrderID: orderID,
VendorID: model.VendorIDEBAI,
Count: 1,
SkuID: 0,
VendorSkuID: "",
SkuName: utils.Interface2String(discount["desc"]),
VendorPrice: 0,
}
skus = append(skus, sku)
}
discountMoney += utils.Interface2Int64WithDefault(discount["fee"], 0)
}
return skus, discountMoney
}
func (p *PurchaseHandler) partRefund2OrderDetailSkuList(orderID string, orderDetail2 interface{}) (skuList []*model.OrderSku) {
orderDetail := orderDetail2.([]interface{})
for _, product2 := range orderDetail {
product := product2.(map[string]interface{})
skuName := product["name"].(string)
_, _, _, specUnit, _, specQuality := jxutils.SplitSkuName(skuName)
number := int(utils.MustInterface2Int64(product["number"]))
sku := &model.OrderSku{
VendorOrderID: orderID,
VendorID: model.VendorIDEBAI,
Count: number,
SkuID: int(utils.Str2Int64WithDefault(utils.Interface2String(product[ebaiapi.KeyCustomSkuID]), 0)),
VendorSkuID: utils.Interface2String(product[ebaiapi.KeySkuID]),
SkuName: skuName,
// Weight: int(utils.Interface2Int64WithDefault(product["total_weight"], 0)) / number, // 退单这里的total_weight有BUG这里的total_weight还是没有退单时的值
VendorPrice: utils.MustInterface2Int64(product["product_price"]),
}
sku.SalePrice, _, sku.StoreSubName = getSkuSalePrice(product)
if sku.Weight == 0 {
sku.Weight = jxutils.FormatSkuWeight(specQuality, specUnit) // 订单信息里没有重量,只有名字里尝试找
}
skuList = append(skuList, sku)
}
return skuList
}
func getExpectedDeliveredTime(orderMap map[string]interface{}) (expectedTime time.Time) {
expectedTime = getTimeFromInterface(orderMap["latest_send_time"])
if utils.IsTimeZero(expectedTime) {
expectedTime = getTimeFromInterface(orderMap["send_time"])
}
return expectedTime
}
func (p *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *model.GoodsOrder) {
result := orderData
shopMap := result["shop"].(map[string]interface{})
orderMap := result["order"].(map[string]interface{})
userMap := result["user"].(map[string]interface{})
vendorOrderID := orderMap["order_id"].(string)
order = &model.GoodsOrder{
VendorOrderID: vendorOrderID,
VendorOrderID2: utils.Interface2String(orderMap["eleme_order_id"]),
VendorID: model.VendorIDEBAI,
VendorStoreID: utils.Interface2String(shopMap["baidu_shop_id"]),
StoreID: int(utils.Str2Int64WithDefault(utils.Interface2String(shopMap["id"]), 0)),
StoreName: utils.Interface2String(shopMap["name"]),
VendorUserID: utils.Interface2String(userMap["user_id"]),
ConsigneeName: utils.Interface2String(userMap["name"]),
ConsigneeMobile: jxutils.FormalizeMobile(utils.Interface2String(userMap["phone"])),
ConsigneeAddress: utils.Interface2String(userMap["address"]),
CoordinateType: model.CoordinateTypeMars,
BuyerComment: utils.TrimBlankChar(utils.Interface2String(orderMap["remark"])),
ExpectedDeliveredTime: getExpectedDeliveredTime(orderMap),
PickDeadline: utils.DefaultTimeValue,
VendorStatus: utils.Int64ToStr(utils.MustInterface2Int64(orderMap["status"])),
OrderSeq: int(utils.ForceInterface2Int64(orderMap["order_index"])),
StatusTime: getTimeFromInterface(orderMap["create_time"]),
OrderCreatedAt: getTimeFromInterface(orderMap["create_time"]),
// OrderFinishedAt: getTimeFromInterface(orderMap["finished_time"]),
OriginalData: string(utils.MustMarshal(result)),
ActualPayPrice: utils.ForceInterface2Int64(orderMap["user_fee"]),
BaseFreightMoney: utils.ForceInterface2Int64(orderMap["send_fee"]),
TotalShopMoney: utils.ForceInterface2Int64(orderMap["shop_fee"]),
DeliveryType: mapDeliveryType(int(utils.ForceInterface2Int64(orderMap["delivery_party"])), int(utils.ForceInterface2Int64(orderMap["business_type"]))),
InvoiceTitle: utils.Interface2String(orderMap["invoice_title"]),
InvoiceTaxerID: utils.Interface2String(orderMap["taxer_id"]),
InvoiceEmail: jxutils.GetOneEmailFromStr(utils.Interface2String(orderMap["remark"])),
VendorOrgCode: utils.Interface2String(result["source"]),
}
finishTime := getTimeFromInterface(orderMap["finished_time"])
if finishTime == utils.ZeroTimeValue {
order.OrderFinishedAt = utils.DefaultTimeValue
} else {
order.OrderFinishedAt = finishTime
}
if utils.IsTimeZero(order.PickDeadline) && !utils.IsTimeZero(order.StatusTime) {
order.PickDeadline = order.StatusTime.Add(pickupOrderDelay) // 饿百要求在5分钟内拣货不然订单会被取消
}
if order.ConsigneeMobile == "" {
if mobileInfo, err := api.EbaiAPI.OrderPrivateInfo(vendorOrderID); err == nil {
order.ConsigneeMobile = jxutils.FormalizeMobile(mobileInfo.ShortNumber)
}
}
if order.StoreID > math.MaxInt32 {
order.StoreID = 0
}
order.Status = p.getStatusFromVendorStatus(order.VendorStatus)
if utils.MustInterface2Int64(orderMap["send_immediately"]) == 1 {
order.BusinessType = model.BusinessTypeImmediate
} else {
order.BusinessType = model.BusinessTypeDingshida
if utils.IsTimeZero(order.ExpectedDeliveredTime) {
order.ExpectedDeliveredTime = getTimeFromInterface(orderMap["latest_send_time"])
}
}
deliveryGeo := userMap["coord_amap"].(map[string]interface{})
originalLng := utils.Interface2Float64WithDefault(deliveryGeo["longitude"], 0.0) // 饿百的订单在过一段时间后,经纬度信息会变成字符串"**"
originalLat := utils.Interface2Float64WithDefault(deliveryGeo["latitude"], 0.0)
// lng, lat, err2 := api.AutonaviAPI.CoordinateConvert(originalLng, originalLat, autonavi.CoordSysBaidu)
// if err2 == nil {
// originalLng = lng
// originalLat = lat
// order.CoordinateType = model.CoordinateTypeMars
// }
order.ConsigneeLng = jxutils.StandardCoordinate2Int(originalLng)
order.ConsigneeLat = jxutils.StandardCoordinate2Int(originalLat)
products := result["products"].([]interface{})[0].([]interface{})
for _, product2 := range products {
product := product2.(map[string]interface{})
skuName := product["product_name"].(string)
_, _, _, specUnit, _, specQuality := jxutils.SplitSkuName(skuName)
productAmount := int(utils.MustInterface2Int64(product["product_amount"]))
sku := &model.OrderSku{
VendorOrderID: order.VendorOrderID,
VendorID: model.VendorIDEBAI,
Count: productAmount,
SkuID: int(utils.Str2Int64WithDefault(utils.Interface2String(product[ebaiapi.KeyCustomSkuID]), 0)),
VendorSkuID: utils.Interface2String(product["baidu_product_id"]),
SkuName: skuName,
Weight: int(utils.Interface2Int64WithDefault(product["total_weight"], 0)) / productAmount,
VendorPrice: utils.MustInterface2Int64(product["product_price"]),
}
var baiduRate int64
sku.SalePrice, baiduRate, sku.StoreSubName = getSkuSalePrice(product)
order.PmSubsidyMoney += baiduRate
if sku.Weight == 0 {
sku.Weight = jxutils.FormatSkuWeight(specQuality, specUnit) // 订单信息里没有重量,只有名字里尝试找
}
// if product["isGift"].(bool) {
// sku.SkuType = 1
// }
order.Skus = append(order.Skus, sku)
}
giftSkus, discountMoney := getZengSkus(vendorOrderID, orderData)
order.DiscountMoney = discountMoney
order.Skus = append(order.Skus, giftSkus...)
jxutils.RefreshOrderSkuRelated(order)
return order
}
func getSkuSalePrice(product map[string]interface{}) (salePrice, baiduRate int64, vendorActType string) {
var product2 *ebaiapi.OrderProductInfo
if err := utils.Map2StructByJson(product, &product2, true); err != nil {
return utils.MustInterface2Int64(product["product_price"]), 0, ""
}
return getSkuSalePrice2(product2)
}
func getSkuSalePrice2(product *ebaiapi.OrderProductInfo) (salePrice, baiduRate int64, vendorActType string) {
salePrice = int64(product.ProductPrice)
if product.ProductSubsidy != nil {
for _, v := range product.ProductSubsidy.DiscountDetail {
if skuActTypeMap[v.Type] == 1 {
skuCount := product.ProductAmount
if skuCount == 0 {
skuCount = product.Number
}
salePrice -= int64(math.Round(float64(v.BaiduRate+v.ShopRate) / float64(skuCount))) // 饿百同一SKU的优惠与非优惠没有拆开平均摊销处理
vendorActType = v.Type
}
baiduRate += int64(v.BaiduRate)
}
}
return salePrice, baiduRate, vendorActType
}
func (p *PurchaseHandler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) {
globals.SugarLogger.Debugf("ebai AcceptOrRefuseOrder orderID:%s, isAcceptIt:%t", order.VendorOrderID, isAcceptIt)
if isAcceptIt {
if globals.EnableEbaiStoreWrite {
err = api.EbaiAPI.OrderConfirm(order.VendorOrderID)
utils.AfterFuncWithRecover(time.Minute, func() {
err = api.EbaiAPI.OrderPickComplete(order.VendorOrderID)
})
}
p.postFakeMsg(order.VendorOrderID, fakeAcceptOrder)
} else {
if globals.EnableEbaiStoreWrite {
err = api.EbaiAPI.OrderCancel(order.VendorOrderID, ebaiapi.CancelTypeCustom, "bu")
}
}
return err
}
func (p *PurchaseHandler) PickupGoods(order *model.GoodsOrder, isSelfDelivery bool, userName string) (err error) {
globals.SugarLogger.Debugf("ebai PickupGoods orderID:%s, isSelfDelivery:%t", order.VendorOrderID, isSelfDelivery)
if globals.EnableEbaiStoreWrite {
// err = api.EbaiAPI.OrderPickComplete(order.VendorOrderID)
}
if err == nil {
p.postFakeMsg(order.VendorOrderID, ebaiapi.OrderStatusAccepted)
}
return err
}
func (p *PurchaseHandler) AcceptOrRefuseFailedGetOrder(ctx *jxcontext.Context, order *model.GoodsOrder, isAcceptIt bool) (err error) {
return err
}
func (p *PurchaseHandler) CallCourier(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 拣货失败后再次招唤平台配送
return err
}
func (p *PurchaseHandler) ConfirmReceiveGoods(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 投递失败后确认收到退货
return err
}
// 将订单从购物平台配送转为自送
func (p *PurchaseHandler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) {
globals.SugarLogger.Debugf("ebai Swtich2SelfDeliver orderID:%s", order.VendorOrderID)
if globals.EnableEbaiStoreWrite {
if err = api.EbaiAPI.OrderSwitchselfdelivery(order.VendorOrderID); err != nil {
if utils.IsErrMatch(err, "301251", nil) {
if deliveryStatus, err2 := api.EbaiAPI.OrderDeliveryGet(order.VendorOrderID); err2 == nil {
deliveryStatus := utils.Int64ToStr(utils.MustInterface2Int64(deliveryStatus["status"]))
if deliveryStatus == ebaiapi.WaybillStatusSelfDelivery {
err = nil
} else if deliveryStatus == ebaiapi.WaybillStatusDeliveryCancled {
p.trySyncCancelStatus(order.VendorOrderID)
}
}
}
}
}
if err == nil {
// 饿百不会发送配送中,模拟发送
p.postFakeMsg(order.VendorOrderID, ebaiapi.OrderStatusCourierAccepted)
}
return err
}
func (p *PurchaseHandler) trySyncCancelStatus(vendorOrderID string) (err error) {
orderInfo, err := api.EbaiAPI.OrderGet2(vendorOrderID)
if err == nil {
if utils.Int2Str(orderInfo.Order.Status) == ebaiapi.OrderStatusCanceled {
p.postFakeMsg(vendorOrderID, fakeOrderCanceled)
}
}
return err
}
// 将订单从购物平台配送转为自送后又送达
func (p *PurchaseHandler) Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) {
globals.SugarLogger.Debugf("ebai Swtich2SelfDelivered orderID:%s", order.VendorOrderID)
// todo 饿百转商家自送后,没有确认送达的概念,空操作
return err
}
// 完全自送的门店表示开始配送
func (p *PurchaseHandler) SelfDeliverDelivering(order *model.GoodsOrder, userName string) (err error) {
globals.SugarLogger.Debugf("ebai SelfDeliverDelivering orderID:%s", order.VendorOrderID)
if globals.EnableEbaiStoreWrite {
err = api.EbaiAPI.OrderSendOut(order.VendorOrderID, userName)
}
if err == nil {
// 饿百不会发送配送中,模拟发送
p.postFakeMsg(order.VendorOrderID, ebaiapi.OrderStatusCourierAccepted)
}
return err
}
// 完全自送的门店表示配送完成
func (p *PurchaseHandler) SelfDeliverDelivered(order *model.GoodsOrder, userName string) (err error) {
globals.SugarLogger.Debugf("ebai SelfDeliverDelivered orderID:%s", order.VendorOrderID)
if globals.EnableEbaiStoreWrite {
err = api.EbaiAPI.OrderComplete(order.VendorOrderID, userName)
}
return err
}
//
func (c *PurchaseHandler) onOrderMsg(msg *ebaiapi.CallbackMsg) (retVal *ebaiapi.CallbackResponse) {
if c.isAfsMsg(msg) {
retVal = c.onAfsOrderMsg(msg)
} else {
status := c.callbackMsg2Status(msg)
if partner.CurOrderManager.GetStatusDuplicatedCount(status) > 0 {
return nil
}
if ebaiapi.CmdOrderCreate == msg.Cmd {
retVal = c.onOrderNew(msg, status)
} else {
var err error
if status != nil {
if status.Status == model.OrderStatusAdjust {
var order *model.GoodsOrder
if order, err = c.GetOrder4PartRefund(GetOrderIDFromMsg(msg)); err == nil {
err = partner.CurOrderManager.OnOrderAdjust(order, status)
}
} else {
// 处理饿百降级订单的情况
// 是否降级;1:是,0:否;极少数订单因网络或信息交互异常,导致订单部分字段(如订单金额)生成延迟,此时订单会被标记为“已降级”状态,需开发者重新调用查看订单详情接口获取完整订单数据。
// toto sku是否也需要处理
if status.Status == model.OrderStatusDelivering || status.Status == model.OrderStatusFinished {
if order, err2 := partner.CurOrderManager.LoadOrder(status.VendorOrderID, status.VendorID); err2 == nil {
if order.TotalShopMoney == 0 {
if order2, err2 := c.GetOrder(msg.Source, status.VendorOrderID); err2 == nil {
order.TotalShopMoney = order2.TotalShopMoney
order.PmSubsidyMoney = order2.PmSubsidyMoney
partner.CurOrderManager.UpdateOrderFields(order, []string{"TotalShopMoney", "PmSubsidyMoney"})
}
}
}
}
err = partner.CurOrderManager.OnOrderStatusChanged(msg.Source, status)
}
}
retVal = api.EbaiAPI.Err2CallbackResponse(msg.Cmd, err, nil)
}
}
return retVal
}
func (c *PurchaseHandler) onOrderNew(msg *ebaiapi.CallbackMsg, orderStatus *model.OrderStatus) (response *ebaiapi.CallbackResponse) {
vendorOrderID := GetOrderIDFromMsg(msg)
order, orderMap, err := c.getOrder(vendorOrderID)
if err == nil {
// 饿百订单有时会出现取不到baidu_shop_id的情况返回错误让服务器重试
if order.VendorStoreID == "" {
return api.EbaiAPI.Err2CallbackResponse(msg.Cmd, fmt.Errorf("订单%s的baidu_shop_id为空", order.VendorOrderID), "")
}
if err = partner.CurOrderManager.OnOrderNew(order, orderStatus); err == nil {
utils.CallFuncAsync(func() {
c.OnOrderDetail(orderMap, partner.CreatedPeration)
})
}
}
return api.EbaiAPI.Err2CallbackResponse(msg.Cmd, err, map[string]interface{}{
"source_order_id": vendorOrderID,
})
}
func (c *PurchaseHandler) callbackMsg2Status(msg *ebaiapi.CallbackMsg) (orderStatus *model.OrderStatus) {
orderID := GetOrderIDFromMsg(msg)
orderStatus = &model.OrderStatus{
VendorOrderID: orderID,
VendorID: model.VendorIDEBAI,
OrderType: model.OrderTypeOrder,
RefVendorOrderID: orderID,
RefVendorID: model.VendorIDEBAI,
StatusTime: utils.Timestamp2Time(msg.Timestamp),
VendorStatus: msg.Cmd,
}
if msg.Cmd == ebaiapi.CmdOrderUserCancel {
msgType := int(utils.MustInterface2Int64(msg.Body["type"]))
cancelType := int(utils.MustInterface2Int64(msg.Body["cancel_type"]))
orderStatus.Remark = buildFullReason(utils.Interface2String(msg.Body["cancel_reason"]), utils.Interface2String(msg.Body["addition_reason"]))
orderStatus.VendorStatus = msg.Cmd + "-" + utils.Int2Str(msgType)
if cancelType == ebaiapi.OrderUserCancelTypeBeforeSale {
if msgType == ebaiapi.OrderUserCancelApply /* || msgType == ebaiapi.OrderUserCancelCSIntervene */ {
orderStatus.Status = model.OrderStatusApplyCancel
} else if msgType == ebaiapi.OrderUserCancelCSRefused ||
msgType == ebaiapi.OrderUserCancelMerchantRefused {
orderStatus.Status = model.OrderStatusVendorRejectCancel
} else if msgType == ebaiapi.OrderUserCancelInvalid {
orderStatus.Status = model.OrderStatusUndoApplyCancel
} else if msgType == ebaiapi.OrderUserCancelCSAgreed ||
msgType == ebaiapi.OrderUserCancelMerchantAgreed {
orderStatus.Status = model.OrderStatusVendorAgreeCancel
}
}
} else if msg.Cmd == ebaiapi.CmdOrderPartRefund {
msgType := int(utils.MustInterface2Int64(msg.Body["type"]))
status := int(utils.MustInterface2Int64(msg.Body["status"]))
orderStatus.Remark = buildFullReason(utils.Interface2String(msg.Body["reason"]), utils.Interface2String(msg.Body["addition_reason"]))
if msgType == ebaiapi.OrderPartRefuncTypeMerchant && status == ebaiapi.OrderPartRefundSuccess {
orderStatus.VendorStatus = fakeOrderAdjustFinished
}
} else if status, ok := msg.Body["status"]; ok {
if vendorStatus, ok := status.(string); ok {
orderStatus.VendorStatus = vendorStatus
} else {
orderStatus.VendorStatus = utils.Int64ToStr(utils.MustInterface2Int64(status))
}
orderStatus.Remark = utils.Interface2String(msg.Body["reason"])
}
if orderStatus.Status == 0 {
orderStatus.Status = c.getStatusFromVendorStatus(orderStatus.VendorStatus)
}
return orderStatus
}
func buildFullReason(reason, addReason string) (fullReason string) {
fullReason = reason
if addReason != "" {
fullReason += ",额外原因:" + addReason
}
return fullReason
}
func (c *PurchaseHandler) GetStatusActionTimeout(order *model.GoodsOrder, statusType, status int) (params *partner.StatusActionParams) {
if statusType == scheduler.TimerStatusTypeOrder && status == model.OrderStatusAccepted {
params = &partner.StatusActionParams{ // PickDeadline没有设置时才有效饿百要求在5分钟内拣货不然订单会被取消
Timeout: pickupOrderDelay,
}
} else if statusType == scheduler.TimerStatusTypeOrder && status == model.OrderStatusFinishedPickup {
params = &partner.StatusActionParams{ // 立即达订单有效,自配送延时召唤配送
Timeout: callDeliveryDelay,
TimeoutGap: callDeliveryDelayGap,
}
}
return params
}
func (c *PurchaseHandler) getOrderStoreDeliveryType(order *model.GoodsOrder) (deliveryType int) {
sql := `
SELECT *
FROM store_map t1
WHERE t1.vendor_store_id = ?
AND t1.vendor_id = ?
AND t1.deleted_at = ?
`
db := dao.GetDB()
var storeMap *model.StoreMap
if err := dao.GetRow(db, &storeMap, sql, order.VendorStoreID, model.VendorIDEBAI, utils.DefaultTimeValue); err == nil {
return int(storeMap.DeliveryType)
} else if !dao.IsNoRowsError(err) {
globals.SugarLogger.Warnf("getOrderStoreDeliveryType orderID:%s failed with error:%v", order.VendorOrderID, err)
}
return scheduler.StoreDeliveryTypeByPlatform
}
func (c *PurchaseHandler) postFakeMsg(vendorOrderID, vendorStatus string) {
msg := &ebaiapi.CallbackMsg{
Cmd: ebaiapi.CmdOrderStatus,
Timestamp: time.Now().Unix(),
Body: map[string]interface{}{
"status": vendorStatus,
"order_id": vendorOrderID,
},
}
utils.CallFuncAsync(func() {
OnCallbackMsg(msg)
})
}
func getTimeFromInterface(timeValue interface{}) time.Time {
var timeStamp int64
if timeStr, ok := timeValue.(string); ok {
timeStamp = utils.Str2Int64WithDefault(timeStr, 0)
} else {
timeStamp = utils.Interface2Int64WithDefault(timeValue, 0)
}
if timeStamp < 1538103149 { // 立即达订单给的是1而不是空01538103149不是特殊值只是一个任意之前的时间这样写可以处理
return utils.DefaultTimeValue
}
return utils.Timestamp2Time(timeStamp)
}
func (c *PurchaseHandler) GetOrderRealMobile(ctx *jxcontext.Context, order *model.GoodsOrder) (mobile string, err error) {
mobile, err = api.EbaiAPI.GetRealMobile4Order(order.VendorOrderID)
return mobile, err
}
func (c *PurchaseHandler) AgreeOrRefuseCancel(ctx *jxcontext.Context, order *model.GoodsOrder, isAgree bool, reason string) (err error) {
if globals.EnableEbaiStoreWrite {
if isAgree {
err = api.EbaiAPI.OrderAgreeRefund(order.VendorOrderID)
} else {
err = api.EbaiAPI.OrderDisagreeRefund(order.VendorOrderID, reason)
}
}
return err
}
func (c *PurchaseHandler) CancelOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
if globals.EnableEbaiStoreWrite {
err = api.EbaiAPI.OrderCancel(order.VendorOrderID, ebaiapi.CancelTypeCustom, reason)
}
return err
}
func (c *PurchaseHandler) AdjustOrder(ctx *jxcontext.Context, order *model.GoodsOrder, removedSkuList []*model.OrderSku, reason string) (err error) {
// 饿百必须要确认订单后才能调整单
if order.Status < model.OrderStatusFinishedPickup {
err = c.PickupGoods(order, false, ctx.GetUserName())
}
if err == nil {
var skuList []*ebaiapi.RefundSku
for _, sku := range removedSkuList {
skuList = append(skuList, &ebaiapi.RefundSku{
CustomeSkuID: utils.Int2Str(jxutils.GetSkuIDFromOrderSku(sku)),
Number: utils.Int2Str(sku.Count),
})
}
if globals.EnableEbaiStoreWrite {
err = api.EbaiAPI.OrderPartRefund(order.VendorOrderID, skuList)
}
}
return err
}
func (c *PurchaseHandler) ListOrders(ctx *jxcontext.Context, vendorOrgCode string, parentTask tasksch.ITask, queryDate time.Time, vendorStoreID string) (vendorOrderIDs []string, err error) {
if utils.IsTimeZero(queryDate) {
return nil, fmt.Errorf("queryDate必须指定")
}
fromDate := utils.Time2Date(queryDate)
toDate := fromDate.Add(24*time.Hour - 1)
var vendorStoreIDs []string
if vendorStoreID == "" {
vendorStoreIDs, err = c.GetAllStoresVendorID(ctx, "")
if err != nil {
return nil, err
}
} else {
vendorStoreIDs = []string{vendorStoreID}
}
task := tasksch.NewParallelTask("ebai ListOrders", nil, ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
vendorStoreID := batchItemList[0].(string)
orderList, err := api.EbaiAPI.OrderListAll("", utils.Str2Int64(vendorStoreID), fromDate.Unix(), toDate.Unix(), 0)
if err == nil {
retVal = orderList
}
return retVal, err
}, vendorStoreIDs)
tasksch.HandleTask(task, parentTask, true).Run()
orderList, err := task.GetResult(0)
if err == nil && len(orderList) > 0 {
vendorOrderIDs = make([]string, len(orderList))
for k, v := range orderList {
orderInfo := v.(*ebaiapi.ListOrderItemInfo)
vendorOrderIDs[k] = orderInfo.OrderID
}
}
return vendorOrderIDs, err
}
func (c *PurchaseHandler) GetWaybillTip(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID, vendorOrderID, vendorWaybillID, vendorWaybillID2 string) (tipFee int64, err error) {
orderInfo, err := api.EbaiAPI.GetStoreOrderInfo(vendorOrderID)
if err == nil {
if orderBasic, _ := orderInfo["order_basic"].(map[string]interface{}); orderBasic != nil {
tipFee = jxutils.StandardPrice2Int(utils.Interface2Float64WithDefault(orderBasic["delivery_tip_amount"], 0))
}
}
return tipFee, err
}
func (c *PurchaseHandler) UpdateWaybillTip(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID, vendorOrderID, vendorWaybillID, vendorWaybillID2, cityCode string, tipFee int64) (err error) {
if globals.EnableEbaiStoreWrite {
err = api.EbaiAPI.ModifyTip4OrderWaybill(vendorOrderID, "", jxutils.IntPrice2Standard(tipFee), 0)
if err != nil {
if strings.Contains(err.Error(), "HTTP code is not 200") {
return fmt.Errorf("饿百此订单暂不支持加小费!")
}
}
}
return err
}

View File

@@ -1,227 +0,0 @@
package ebai
import (
"fmt"
"strings"
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
var (
AfsVendorStatus2Status4PartRefundMap = map[int]int{
ebaiapi.OrderPartRefundApply: model.AfsOrderStatusWait4Approve,
ebaiapi.OrderPartRefundSuccess: model.AfsOrderStatusFinished,
ebaiapi.OrderPartRefundUserApplyArbitration: model.OrderStatusUnknown, // 是否是中间状态
ebaiapi.OrderPartRefundFailed: model.AfsOrderStatusFailed,
ebaiapi.OrderPartRefundMerchantRefused: model.AfsOrderStatusFailed, // 是否是中间状态
}
AfsVendorStatus2Status4UserCancel = map[int]int{
ebaiapi.OrderUserCancelApply: model.AfsOrderStatusWait4Approve,
ebaiapi.OrderUserCancelCSIntervene: model.OrderStatusUnknown,
ebaiapi.OrderUserCancelCSRefused: model.AfsOrderStatusFailed,
ebaiapi.OrderUserCancelCSAgreed: model.AfsOrderStatusFinished,
ebaiapi.OrderUserCancelMerchantRefused: model.AfsOrderStatusFailed,
ebaiapi.OrderUserCancelMerchantAgreed: model.AfsOrderStatusFinished,
ebaiapi.OrderUserCancelInvalid: model.AfsOrderStatusFailed,
}
)
func (c *PurchaseHandler) isAfsMsg(msg *ebaiapi.CallbackMsg) bool {
if msg.Cmd == ebaiapi.CmdOrderPartRefund {
msgType := int(utils.MustInterface2Int64(msg.Body["type"]))
return msgType == ebaiapi.OrderPartRefuncTypeCustomer
} else if msg.Cmd == ebaiapi.CmdOrderUserCancel {
cancelType := int(utils.MustInterface2Int64(msg.Body["cancel_type"]))
return cancelType == ebaiapi.OrderUserCancelTypeAfterSale
}
return false
}
func (c *PurchaseHandler) OnAfsOrderMsg(msg *ebaiapi.CallbackMsg) (retVal *ebaiapi.CallbackResponse) {
jxutils.CallMsgHandlerAsync(func() {
retVal = c.onAfsOrderMsg(msg)
}, jxutils.ComposeUniversalOrderID(GetOrderIDFromMsg(msg), model.VendorIDEBAI))
return retVal
}
func (c *PurchaseHandler) onAfsOrderMsg(msg *ebaiapi.CallbackMsg) (retVal *ebaiapi.CallbackResponse) {
if orderStatus := c.callbackAfsMsg2Status(msg); orderStatus != nil {
var err error
if orderStatus.Status == model.AfsOrderStatusWait4Approve || orderStatus.Status == model.AfsOrderStatusNew {
var afsOrder *model.AfsOrder
if msg.Cmd == ebaiapi.CmdOrderPartRefund {
partRefundData := msg.Data.(*ebaiapi.CBPartRefundInfo)
afsOrder = &model.AfsOrder{
VendorID: model.VendorIDEBAI,
AfsOrderID: orderStatus.VendorOrderID,
VendorOrderID: orderStatus.RefVendorOrderID,
VendorStoreID: "",
StoreID: 0,
AfsCreatedAt: utils.Timestamp2Time(msg.Timestamp),
VendorAppealType: "",
AppealType: model.AfsAppealTypeRefund,
VendorReasonType: partRefundData.ReasonType,
ReasonType: c.convertAfsReasonType(partRefundData.ReasonType),
ReasonDesc: utils.LimitUTF8StringLen(buildFullReason(partRefundData.Reason, partRefundData.AdditionReason), 1024),
ReasonImgList: utils.LimitUTF8StringLen(strings.Join(partRefundData.Photos, ","), 1024),
RefundType: model.AfsTypePartRefund,
VendorOrgCode: msg.Source,
// FreightUserMoney: afsInfo.OrderFreightMoney,
// AfsFreightMoney: afsInfo.AfsFreight,
// BoxMoney: afsInfo.PackagingMoney,
// TongchengFreightMoney: afsInfo.TongchengFreightMoney,
// SkuBoxMoney: afsInfo.MealBoxMoney,
}
for _, sku := range partRefundData.RefundProducts {
orderSku := &model.OrderSkuFinancial{
// VendorID: model.VendorIDEBAI,
// AfsOrderID: afsOrder.AfsOrderID,
// VendorOrderID: afsOrder.VendorOrderID,
// VendorStoreID: afsOrder.VendorStoreID,
// StoreID: afsOrder.StoreID,
// IsAfsOrder: 1,
Count: sku.Number,
// ConfirmTime: afsOrder.AfsCreateAt,
VendorSkuID: sku.SkuID,
SkuID: int(utils.Str2Int64WithDefault(sku.CustomSkuID, 0)),
Name: sku.Name,
UserMoney: sku.TotalRefund,
PmSkuSubsidyMoney: sku.ShopEleRefund,
}
afsOrder.SkuUserMoney += orderSku.UserMoney
afsOrder.PmSubsidyMoney += orderSku.PmSubsidyMoney
afsOrder.Skus = append(afsOrder.Skus, orderSku)
}
} else if msg.Cmd == ebaiapi.CmdOrderUserCancel {
if afsOrder = c.createAfsOrder(msg); afsOrder != nil {
// if orderFinancial, err2 := partner.CurOrderManager.LoadOrderFinancial(orderStatus.RefVendorOrderID, model.VendorIDEBAI); err2 == nil {
// afsOrder = c.OrderFinancialDetail2Refund(orderFinancial, msg)
cancelData := msg.Data.(*ebaiapi.CBUserCancelInfo)
afsOrder.AfsOrderID = orderStatus.VendorOrderID
afsOrder.RefundType = model.AfsTypeFullRefund
afsOrder.AppealType = model.AfsAppealTypeRefund
afsOrder.VendorReasonType = ""
afsOrder.ReasonType = model.AfsReasonNotOthers
afsOrder.ReasonDesc = utils.LimitUTF8StringLen(buildFullReason(cancelData.CancelReason, cancelData.AdditionReason), 1024)
afsOrder.ReasonImgList = utils.LimitUTF8StringLen(strings.Join(cancelData.Pictures, ","), 1024)
}
}
if afsOrder != nil {
err = partner.CurOrderManager.OnAfsOrderNew(afsOrder, orderStatus)
}
} else {
err = partner.CurOrderManager.OnAfsOrderStatusChanged(orderStatus)
}
retVal = api.EbaiAPI.Err2CallbackResponse(msg.Cmd, err, nil)
}
return retVal
}
func (p *PurchaseHandler) createAfsOrder(msg *ebaiapi.CallbackMsg) (afsOrder *model.AfsOrder) {
cancelData := msg.Data.(*ebaiapi.CBUserCancelInfo)
afsOrder, err := partner.CurOrderManager.CreateAfsOrderFromOrder(utils.Int64ToStr(cancelData.OrderID), model.VendorIDEBAI)
if err == nil {
afsOrder.AfsOrderID = afsOrder.VendorOrderID
afsOrder.AfsCreatedAt = utils.Timestamp2Time(msg.Timestamp)
} else {
afsOrder = nil
}
return afsOrder
}
func (c *PurchaseHandler) convertAfsReasonType(vendorReasonType string) int8 {
return model.AfsReasonNotOthers
}
func (c *PurchaseHandler) GetAfsStatusFromVendorStatus4PartRefund(vendorStatus int) int {
return AfsVendorStatus2Status4PartRefundMap[vendorStatus]
}
func (c *PurchaseHandler) GetAfsStatusFromVendorStatus4UserCancel(vendorStatus int) int {
return AfsVendorStatus2Status4UserCancel[vendorStatus]
}
func (c *PurchaseHandler) callbackAfsMsg2Status(msg *ebaiapi.CallbackMsg) (orderStatus *model.OrderStatus) {
if msg.Cmd == ebaiapi.CmdOrderPartRefund {
partRefundData := msg.Data.(*ebaiapi.CBPartRefundInfo)
orderStatus = &model.OrderStatus{
VendorOrderID: partRefundData.RefundID, // 是售后单ID不是订单ID订单ID在RefVendorOrderID中
VendorID: model.VendorIDEBAI,
OrderType: model.OrderTypeAfsOrder,
RefVendorOrderID: utils.Int64ToStr(partRefundData.OrderID),
RefVendorID: model.VendorIDEBAI,
VendorStatus: utils.Int2Str(partRefundData.Status),
Status: c.GetAfsStatusFromVendorStatus4PartRefund(partRefundData.Status),
StatusTime: utils.Timestamp2Time(msg.Timestamp),
Remark: buildFullReason(partRefundData.Reason, partRefundData.AdditionReason),
}
if orderStatus.Status == model.AfsOrderStatusWait4Approve && partRefundData.Type != ebaiapi.OrderPartRefuncTypeCustomer {
orderStatus.Status = model.AfsOrderStatusNew
}
} else if msg.Cmd == ebaiapi.CmdOrderUserCancel {
cancelData := msg.Data.(*ebaiapi.CBUserCancelInfo)
orderStatus = &model.OrderStatus{
VendorOrderID: utils.Int64ToStr(cancelData.OrderID), // 是售后单ID不是订单ID订单ID在RefVendorOrderID中
VendorID: model.VendorIDEBAI,
OrderType: model.OrderTypeAfsOrder,
RefVendorOrderID: utils.Int64ToStr(cancelData.OrderID),
RefVendorID: model.VendorIDEBAI,
VendorStatus: utils.Int2Str(cancelData.Type),
Status: c.GetAfsStatusFromVendorStatus4UserCancel(cancelData.Type),
StatusTime: utils.Timestamp2Time(msg.Timestamp),
Remark: buildFullReason(cancelData.CancelReason, cancelData.AdditionReason),
}
}
return orderStatus
}
// 审核售后单申请
func (c *PurchaseHandler) AgreeOrRefuseRefund(ctx *jxcontext.Context, order *model.AfsOrder, approveType int, reason string) (err error) {
if globals.EnableEbaiStoreWrite {
if approveType == partner.AfsApproveTypeRefused {
err = api.EbaiAPI.OrderDisagreeRefund(order.VendorOrderID, reason)
} else {
err = api.EbaiAPI.OrderAgreeRefund(order.VendorOrderID)
}
}
return err
}
// 确认收到退货
func (c *PurchaseHandler) ConfirmReceivedReturnGoods(ctx *jxcontext.Context, order *model.AfsOrder) (err error) {
err = fmt.Errorf("内部错误,饿百平台不支持确认收到退货操作")
return err
}
// 发起全款退款
func (c *PurchaseHandler) RefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
return c.PartRefundOrder(ctx, order, order.Skus, reason)
}
// 发起部分退款
func (c *PurchaseHandler) PartRefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, refundSkuList []*model.OrderSku, reason string) (err error) {
if globals.EnableEbaiStoreWrite {
err = api.EbaiAPI.OrderPartRefund(order.VendorOrderID, orderSkus2AfsSkus(refundSkuList))
}
return err
}
func orderSkus2AfsSkus(refundSkuList []*model.OrderSku) (removeSkuList []*ebaiapi.RefundSku) {
for _, v := range refundSkuList {
refundSku := &ebaiapi.RefundSku{
CustomeSkuID: utils.Int2Str(v.SkuID),
Number: utils.Int2Str(v.Count),
}
removeSkuList = append(removeSkuList, refundSku)
}
return removeSkuList
}

View File

@@ -1,102 +0,0 @@
package ebai
import (
"time"
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
// 饿百的评价不是一点一点出来的,而是一下把前一天的全部崩出来。。。
const (
RefreshCommentTime = 84 * time.Hour
RefreshCommentTimeInterval = 60 * time.Minute
EBAI_BAD_COMMENTS_MAX_MODIFY_TIME = 24 // 小时
)
func (c *PurchaseHandler) StartRefreshComment() {
utils.AfterFuncWithRecover(5*time.Second, func() {
c.refreshCommentOnce()
})
}
func (c *PurchaseHandler) refreshCommentOnce() {
c.RefreshComment(time.Now().Add(-RefreshCommentTime), time.Now())
utils.AfterFuncWithRecover(RefreshCommentTimeInterval, func() {
c.refreshCommentOnce()
})
}
func (c *PurchaseHandler) RefreshComment(fromTime, toTime time.Time) (err error) {
globals.SugarLogger.Debugf("RefreshComment fromTime:%s, toTime:%s", utils.Time2Str(fromTime), utils.Time2Str(toTime))
var orderCommentList []*model.OrderComment
stepGap := 24 * time.Hour
stepFromTime := fromTime
for {
stepToTime := stepFromTime.Add(stepGap - time.Second)
if stepToTime.Sub(toTime) > 0 {
stepToTime = toTime
}
if stepToTime.Sub(stepFromTime) == 0 {
break
}
resultList, err2 := api.EbaiAPI.GetEleCommentList(stepFromTime, stepToTime, "", "", ebaiapi.ReplyStatusAll, ebaiapi.CommentLevelAll, ebaiapi.CommentContentAll)
if err = err2; err == nil {
for _, result := range resultList {
orderComment := &model.OrderComment{
VendorOrderID: utils.Interface2String(result["order_id"]),
VendorID: model.VendorIDELM,
UserCommentID: utils.Int64ToStr(utils.MustInterface2Int64(result["comment_id"])),
// VendorStoreID: utils.Int64ToStr(utils.MustInterface2Int64(result["shop_id"])), // 这个shop_id是饿了么ID不是饿百ID
TagList: "",
Score: int8(utils.MustInterface2Int64(result["service_rating"])),
Content: utils.Interface2String(result["content"]),
CommentCreatedAt: utils.Str2Time(utils.Interface2String(result["create_time"])),
IsReplied: int8(1 - utils.MustInterface2Int64(result["can_reply"])),
ModifyDuration: EBAI_BAD_COMMENTS_MAX_MODIFY_TIME,
OriginalMsg: string(utils.MustMarshal(result)),
}
// 直接得到的订单是饿了么的,尝试统一成饿百
if order, err := partner.CurOrderManager.LoadOrder2(orderComment.VendorOrderID, model.VendorIDEBAI); err == nil {
orderComment.VendorOrderID = order.VendorOrderID
orderComment.VendorOrderID2 = order.VendorOrderID2
orderComment.VendorID = model.VendorIDEBAI
orderComment.VendorStoreID = order.VendorStoreID
orderComment.StoreID = jxutils.GetSaleStoreIDFromOrder(order)
orderComment.ConsigneeMobile = order.ConsigneeMobile
} else {
globals.SugarLogger.Infof("RefreshComment, load orderID:%s failed", orderComment.VendorOrderID)
}
orderCommentList = append(orderCommentList, orderComment)
}
} else {
// globals.SugarLogger.Warnf("RefreshComment stepFromTime:%s, stepToTime:%s failed with error:%v", utils.Time2Str(stepFromTime), utils.Time2Str(stepToTime), err)
// break //?
}
if stepToTime.Sub(toTime) == 0 {
break
}
stepFromTime = stepToTime.Add(time.Second)
}
if err == nil && len(orderCommentList) > 0 {
err = partner.CurOrderManager.OnOrderComments(orderCommentList)
}
return err
}
func (c *PurchaseHandler) ReplyOrderComment(ctx *jxcontext.Context, vendorOrgCode string,orderComment *model.OrderComment, replyComment string) (err error) {
if orderComment.VendorStoreID != "" && orderComment.UserCommentID != "" {
if globals.EnableEbaiStoreWrite {
err = api.EbaiAPI.OrderRatesReply("", utils.Str2Int64(orderComment.VendorStoreID), orderComment.UserCommentID, replyComment)
}
}
return err
}

View File

@@ -1,27 +0,0 @@
package ebai
import (
"testing"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/baseapi/utils"
)
func TestGetOrder4PartRefund(t *testing.T) {
order, err := CurPurchaseHandler.GetOrder4PartRefund("1556529608021993938")
if err != nil {
t.Fatal(err.Error())
} else {
t.Log(utils.Format4Output(order, false))
}
}
func TestListOrders(t *testing.T) {
order, err := CurPurchaseHandler.ListOrders(jxcontext.AdminCtx, "", nil, utils.GetCurDate(), "")
if err != nil {
t.Fatal(err.Error())
} else {
t.Log(utils.Format4Output(order, false))
}
}

View File

@@ -1,552 +0,0 @@
package ebai
import (
"fmt"
"strings"
"git.rosy.net.cn/baseapi/platformapi/autonavi"
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
"git.rosy.net.cn/jx-callback/business/jxutils"
"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"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
type tEbaiStoreInfo struct {
model.Store
VendorOrgCode string `orm:"size(32)" json:"vendorOrgCode"` // 同一平台下不同的商户代码,如果只有一个,可以为空
VendorStoreID string `orm:"column(vendor_store_id)"`
RealLastOperator string
EbaiStoreStatus int
SyncStatus int
ProvinceID int `orm:"column(province_id)"`
CityID int `orm:"column(city_id)"`
DistrictID int `orm:"column(district_id)"`
VendorStoreName string
}
func (p *PurchaseHandler) CreateStore(db *dao.DaoDB, storeID int, userName string) (vendorStoreID string, err error) {
var store tEbaiStoreInfo
sql := `
SELECT t1.*, t2.status ebai_store_status, t2.vendor_store_id,
IF(t1.updated_at > t2.updated_at, t1.last_operator, t2.last_operator) real_last_operator, t2.sync_status,
province.ebai_code province_id, city.ebai_code city_id, district.ebai_code district_id
FROM store t1
LEFT JOIN store_map t2 ON t1.id = t2.store_id AND t2.vendor_id = ? AND t2.deleted_at = ?
JOIN place district ON t1.district_code = district.code
JOIN place city ON t1.city_code = city.code
JOIN place province ON city.parent_code = province.code
WHERE t1.id = ? AND t2.id IS NULL;
`
if err = dao.GetRow(db, &store, sql, model.VendorIDEBAI, utils.DefaultTimeValue, storeID); err == nil {
params := genStoreMapFromStore(&store)
params["shop_id"] = store.ID
params["business_form_id"] = "179"
params["service_phone"] = store.Tel1
params["invoice_support"] = 2
params["package_box_price"] = 0
params["encrypt"] = ""
params["category1"] = ""
params["category2"] = ""
params["category3"] = ""
if globals.EnableEbaiStoreWrite {
intVendorStoreID, err2 := api.EbaiAPI.ShopCreate(params)
if err = err2; err == nil {
return utils.Int64ToStr(intVendorStoreID), err
}
} else {
return utils.Int64ToStr(jxutils.GenFakeID()), nil
}
}
return "", err
}
// 2019-07-26 疑似饿百将门店返回的坐标类型从float64改为string了
func getCoordintate(data interface{}) float64 {
if str, ok := data.(string); ok {
return utils.Str2Float64WithDefault(str, 0)
}
return utils.MustInterface2Float64(data)
}
func (p *PurchaseHandler) ReadStore(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID string) (*dao.StoreDetail, error) {
baiduShopID := utils.Str2Int64WithDefault(vendorStoreID, 0)
if baiduShopID == 0 {
return nil, fmt.Errorf("饿百门店ID:%s非法应该是一个整数", vendorStoreID)
}
result, err := api.EbaiAPI.ShopGet("", baiduShopID)
if err == nil {
// globals.SugarLogger.Debug(utils.Format4Output(result, false))
retVal := &dao.StoreDetail{
Store: model.Store{
Address: utils.Interface2String(result["address"]),
Tel1: utils.Interface2String(result["phone"]),
},
}
retVal.OriginalName = utils.Interface2String(result["name"])
_, retVal.Name = jxutils.SplitStoreName(retVal.OriginalName, partner.StoreNameSeparator, globals.StoreNameEbai)
retVal.DeliveryType = EbaiDeliveryType2Jx(utils.Interface2String(result["delivery_type"]))
retVal.SetOpTime(ebaiOpTime2Jx(result["business_time"]))
retVal.Status, _ = p.GetStoreStatus(ctx, vendorOrgCode, 0, vendorStoreID)
tel2 := utils.Interface2String(result["ivr_phone"])
if tel2 != "" && tel2 != retVal.Tel1 {
retVal.Tel2 = tel2
}
lng := getCoordintate(result["longitude"])
lat := getCoordintate(result["latitude"])
if utils.Interface2String(result["coord_type"]) == ebaiapi.CoordTypeBaidu {
var err2 error
if lng, lat, err2 = api.AutonaviAPI.CoordinateConvert(lng, lat, autonavi.CoordSysBaidu); err2 != nil {
return nil, err2
}
}
retVal.Lng = jxutils.StandardCoordinate2Int(lng)
retVal.Lat = jxutils.StandardCoordinate2Int(lat)
db := dao.GetDB()
if city, err2 := dao.GetPlaceByName(db, utils.Interface2String(result["city"]), model.PlaceLevelCity, 0); err2 == nil {
retVal.CityCode = city.Code
retVal.CityName = utils.Interface2String(result["city"])
districtName := utils.Interface2String(result["county"])
if retVal.CityCode != 0 && districtName != "" {
if district, err2 := dao.GetPlaceByName(db, utils.Interface2String(result["county"]), model.PlaceLevelDistrict, city.Code); err2 == nil {
retVal.DistrictCode = district.Code
}
}
}
if retVal.DistrictCode == 0 {
retVal.DistrictCode = api.AutonaviAPI.GetCoordinateDistrictCode(lng, lat)
if retVal.CityCode == 0 {
if district, err := dao.GetPlaceByCode(db, retVal.DistrictCode); err == nil {
retVal.CityCode = district.ParentCode
}
}
}
retVal.VendorStoreID = vendorStoreID
retVal.ID = int(utils.Str2Int64WithDefault(utils.Interface2String(result["shop_id"]), 0))
retVal.DeliveryRangeType = model.DeliveryRangeTypePolygon
retVal.DeliveryRange = EbaiDeliveryRegion2Jx(result["delivery_region"])
return retVal, nil
}
return nil, err
}
func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName string) (err error) {
globals.SugarLogger.Debugf("ebai UpdateStore storeID:%d, userName:%s", storeID, userName)
var stores []*tEbaiStoreInfo
sql := `
SELECT
t1.*,
t2.status ebai_store_status, t2.vendor_store_id, t2.vendor_org_code,
IF(t1.updated_at > t2.updated_at, t1.last_operator, t2.last_operator) real_last_operator, t2.sync_status, t2.vendor_store_name
FROM store t1
JOIN store_map t2 ON t1.id = t2.store_id AND t2.vendor_id = ? AND (t2.deleted_at = ?)
WHERE t1.id = ?
ORDER BY t2.updated_at
`
if err = dao.GetRows(db, &stores, sql, model.VendorIDEBAI, utils.DefaultTimeValue, storeID); err == nil {
for _, store := range stores {
if globals.EnableEbaiStoreWrite {
shopID := 0
if store.SyncStatus&model.SyncFlagDeletedMask == 0 {
shopID = store.ID
}
store2, err2 := p.ReadStore(jxcontext.AdminCtx, store.VendorOrgCode, store.VendorStoreID)
// globals.SugarLogger.Debugf("ebai UpdateStore2 store2:%s, err2:%v", utils.Format4Output(store2, true), err2)
if err = err2; err == nil {
if store2.ID == store.ID {
shopID = -1
}
}
if err == nil {
if shopID > 0 {
err = p.UpdateStoreCustomID(jxcontext.AdminCtx, "", store.VendorStoreID, int64(shopID))
} else if shopID == 0 {
// todo remove out shop id
}
}
if err == nil {
if store.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagStoreStatus) != 0 {
mergeStatus := jxutils.MergeStoreStatus(store.Status, store.EbaiStoreStatus)
if err = p.UpdateStoreStatus(jxcontext.AdminCtx, store.VendorOrgCode, storeID, store.VendorStoreID, mergeStatus); err != nil {
return err
}
}
params := genStoreMapFromStore(store)
if err = api.EbaiAPI.ShopUpdate(params); err == nil {
if store.PromoteInfo != "" {
err = api.EbaiAPI.ShopAnnouncementSet("", utils.Str2Int64(store.VendorStoreID), store.PromoteInfo)
}
}
}
}
}
}
return err
}
func isStoreStatusSame(status1, status2 int) bool {
if status1 == model.StoreStatusHaveRest {
status1 = model.StoreStatusClosed
}
if status2 == model.StoreStatusHaveRest {
status2 = model.StoreStatusClosed
}
return status1 == status2
}
func (p *PurchaseHandler) RefreshAllStoresID(ctx *jxcontext.Context, parentTask tasksch.ITask, isAsync bool) (hint string, err error) {
globals.SugarLogger.Debugf("ebai RefreshAllStoresID")
const batchSize = 50
const stepCount = 3
var stores []*tEbaiStoreInfo
db := dao.GetDB()
rootTask := tasksch.NewSeqTask("ebai RefreshAllStoresID", ctx,
func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
switch step {
case 0:
err = dao.GetRows(db, &stores, `
SELECT t1.*, t2.vendor_store_id
FROM store t1
JOIN store_map t2 ON t1.id = t2.store_id AND t2.deleted_at = ? AND t2.vendor_id = ?
WHERE t1.deleted_at = ?
`, utils.DefaultTimeValue, model.VendorIDEBAI, utils.DefaultTimeValue)
default:
taskName := "ebai RefreshAllStoresID update to custom id"
if step != stepCount-1 {
taskName = "ebai RefreshAllStoresID update to uuid"
}
task1 := tasksch.NewParallelTask(taskName, tasksch.NewParallelConfig().SetBatchSize(batchSize), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
baiduShopIDs := make([]string, len(batchItemList))
shopIDs := make([]string, len(batchItemList))
for k, v := range batchItemList {
store := v.(*tEbaiStoreInfo)
baiduShopIDs[k] = store.VendorStoreID
shopIDs[k] = utils.Int2Str(store.ID)
if step != stepCount-1 {
shopIDs[k] = utils.GetUUID()
}
}
if globals.EnableEbaiStoreWrite {
err = api.EbaiAPI.ShopIDBatchUpdate(baiduShopIDs, shopIDs)
}
return nil, err
}, stores)
task.AddChild(task1).Run()
_, err = task1.GetResult(0)
}
return nil, err
}, stepCount)
tasksch.HandleTask(rootTask, parentTask, false).Run()
if !isAsync {
_, err = rootTask.GetResult(0)
}
return rootTask.ID, err
}
// todo 此函数只考虑了在饿了么侧开店的情况
func EbaiDeliveryType2Jx(deliveryType string) int8 {
spIndex := strings.Index(deliveryType, "|")
elmDeliveryType := utils.Str2Int64(deliveryType[:spIndex])
switch elmDeliveryType {
case ebaiapi.DeliveryTypeElmFengNiaoZS,
ebaiapi.DeliveryTypeElmFengNiaoZSKA,
ebaiapi.DeliveryTypeElmFengNiaoKS,
ebaiapi.DeliveryTypeElmNewRetail,
ebaiapi.DeliveryTypeElmEPeiSong,
ebaiapi.DeliveryTypeElmFengNiaoHybrid,
ebaiapi.DeliveryTypeElmFengNiaoNiubee:
return scheduler.StoreDeliveryTypeByPlatform
case ebaiapi.DeliveryTypeElmXingHuoZBTrial,
ebaiapi.DeliveryTypeElmXingHuoZB,
ebaiapi.DeliveryTypeElmXingHuoZBKA:
return scheduler.StoreDeliveryTypeCrowdSourcing
case ebaiapi.DeliveryTypeElmNone,
ebaiapi.DeliveryTypeElmXingHuoTrial,
ebaiapi.DeliveryTypeElmXingHuo,
ebaiapi.DeliveryTypeElmEBase,
ebaiapi.DeliveryTypeElmXingHuoKA:
return scheduler.StoreDeliveryTypeByStore
default:
return scheduler.StoreDeliveryTypeCrowdSourcing
}
}
func EbaiDeliveryRegion2Jx(deliveryRegion interface{}) string {
realDeliveryRegion := deliveryRegion.([]interface{})
if len(realDeliveryRegion) > 0 {
region := deliveryRegion.([]interface{})[0].(map[string]interface{})["region"].([]interface{})[0].([]interface{})
coords := make([]string, len(region))
for k, v := range region {
mapV := v.(map[string]interface{})
coords[k] = fmt.Sprintf("%.6f,%.6f", utils.MustInterface2Float64(mapV["longitude"]), utils.MustInterface2Float64(mapV["latitude"]))
}
return strings.Join(coords, ";")
}
return ""
}
func JxDeliveryRegion2Ebai(store *model.Store) (deliveryRegion interface{}) {
rangeStr := strings.Trim(store.DeliveryRange, ";")
if store.DeliveryRangeType == model.DeliveryRangeTypeRadius {
if utils.Str2Int64WithDefault(store.DeliveryRange, 0) > 100 { // todo 如果小于100米表示禁用不更新
rangeStr = jxutils.GetPolygonFromCircleStr(jxutils.IntCoordinate2Standard(store.Lng), jxutils.IntCoordinate2Standard(store.Lat), utils.Str2Float64(store.DeliveryRange), 8)
} else {
rangeStr = ""
}
}
rangeStr = "" // todo 暂时禁止同步配送区域
if rangeStr != "" {
pointPairs := strings.Split(rangeStr, ";")
region := make([]map[string]interface{}, 0)
for _, v := range pointPairs {
pointPair := strings.Split(v, ",")
if len(pointPair) == 2 {
region = append(region, map[string]interface{}{
"longitude": utils.Str2Float64(pointPair[0]),
"latitude": utils.Str2Float64(pointPair[1]),
})
}
}
deliveryRegion = []interface{}{
map[string]interface{}{
"name": "主要配送区",
"delivery_fee": 600,
"delivery_time": "60",
"min_buy_free": "0",
"min_order_price": "0",
"region": []interface{}{
region,
},
},
}
}
return deliveryRegion
}
func fillOpTimeParams(params map[string]interface{}, opTimeList []int16) map[string]interface{} {
if params == nil {
params = make(map[string]interface{})
}
var pairList []map[string]string
opTimeListLen := len(opTimeList)
if opTimeListLen > 4 {
opTimeListLen = 4
}
opTimeListLen = opTimeListLen / 2 * 2
for k := 0; k < len(opTimeList); k += 2 {
if opTimeList[k] != 0 {
pairList = append(pairList, map[string]string{
"start": jxutils.JxOperationTime2StrTime(opTimeList[k]),
"end": jxutils.JxOperationTime2StrTime(opTimeList[k+1]),
})
} else {
break
}
}
params["business_time"] = pairList
return params
}
func ebaiOpTime2Jx(businessTime interface{}) (opTimeList []int16) {
businessTimeList, _ := businessTime.([]interface{})
for _, v := range businessTimeList {
vMap := v.(map[string]interface{})
opTimeList = append(opTimeList, jxutils.StrTime2JxOperationTime(utils.Interface2String(vMap["start"])+":00", 700),
jxutils.StrTime2JxOperationTime(utils.Interface2String(vMap["end"])+":00", 2000))
}
return opTimeList
}
func genStoreMapFromStore(store *tEbaiStoreInfo) map[string]interface{} {
params := fillOpTimeParams(nil, store.GetOpTimeList())
// tel := store.Tel1
// if tel == "" {
// tel = store.Tel2
// }
// if tel != "" {
// // params["phone"] = tel // 外卖客服联系电话,这个有时能修改,有时不能修改,暂时统一不改
// params["ivr_phone"] = tel // 订单提醒电话
// }
phone := ""
if store.MarketManPhone != "" {
phone = store.MarketManPhone
} else {
phone = model.VendorStoreTel
}
params["ivr_phone"] = phone //统一改为这个电话
if store.VendorStoreID != "" {
params["baidu_shop_id"] = store.VendorStoreID
}
if false { //store.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagStoreName) != 0 {
if store.VendorStoreName != "" {
params["name"] = store.VendorStoreName
} else {
params["name"] = jxutils.ComposeStoreName(store.Name, model.VendorIDEBAI)
}
}
boxFee, _ := dao.GetSysConfigAsInt64(dao.GetDB(), model.ConfigSysEbaiBoxFee)
params["package_box_price"] = jxutils.IntPrice2Standard(boxFee)
params["service_phone"] = store.Tel1
params["address"] = store.Address
// todo 饿百 开店审核通过后不允许修改商户信息
if store.SyncStatus&(model.SyncFlagNewMask /*|model.SyncFlagStoreAddress*/) != 0 {
// todo 这里应该要做坐标转换吧
params["longitude"] = jxutils.IntCoordinate2Standard(store.Lng)
params["latitude"] = jxutils.IntCoordinate2Standard(store.Lat)
params["coord_type"] = ebaiapi.CoordTypeAutonavi
// if deliveryRegion := JxDeliveryRegion2Ebai(&store.Store); deliveryRegion != nil {
// params["delivery_region"] = deliveryRegion
// }
if store.ProvinceID != 0 {
params["province"] = store.ProvinceID
}
if store.CityID != 0 {
params["city"] = store.CityID
}
if store.DistrictID != 0 {
params["county"] = store.DistrictID
}
}
return params
}
func (p *PurchaseHandler) GetStoreStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string) (storeStatus int, err error) {
ebaiStatus, err := api.EbaiAPI.ShopBusStatusGet("", utils.Str2Int64(vendorStoreID), ebaiapi.PlatformFlagElm)
if err == nil {
storeStatus = EbaiBusStatus2JxStatus(ebaiStatus)
}
return storeStatus, err
}
func (c *PurchaseHandler) onShopMsgPush(msg *ebaiapi.CallbackMsg) (response *ebaiapi.CallbackResponse) {
var err error
vendorStoreID := utils.Interface2String(msg.Body["baidu_shop_id"])
storeID := int(utils.Interface2Int64WithDefault(msg.Body["shop_id"], 0))
storeStatus := model.StoreStatusOpened
switch utils.Interface2String(msg.Body["msg_type"]) {
case "online", "offline":
storeStatus, err = c.GetStoreStatus(jxcontext.AdminCtx, "", storeID, vendorStoreID)
case "shop_open", "shop_pause", "shop_close":
if int(utils.ForceInterface2Int64(msg.Body["business_ele"])) == 1 {
storeStatus = model.StoreStatusOpened
} else {
storeStatus = model.StoreStatusClosed
}
}
if err == nil {
err = partner.CurStoreManager.OnStoreStatusChanged(vendorStoreID, model.VendorIDEBAI, storeStatus)
}
return api.EbaiAPI.Err2CallbackResponse(msg.Cmd, err, nil)
}
func (c *PurchaseHandler) GetShopHealthInfo(vendorShopID string) (shopHealthInfo map[string]interface{}, err error) {
result, err := api.EbaiAPI.GetShopHealthByDetail(utils.Str2Int64(vendorShopID))
if err == nil {
shopHealthInfo = utils.Struct2FlatMap(result)
}
return shopHealthInfo, err
}
func (p *PurchaseHandler) EnableAutoAcceptOrder(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, isSetEnable bool) (err error) {
return err
}
func (c *PurchaseHandler) UpdateStoreStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, status int) (err error) {
if globals.EnableEbaiStoreWrite {
if status == model.StoreStatusOpened {
err = api.EbaiAPI.ShopOpen("", utils.Str2Int64(vendorStoreID))
} else if status == model.StoreStatusHaveRest || status == model.StoreStatusClosed {
err = api.EbaiAPI.ShopClose("", utils.Str2Int64(vendorStoreID))
} else if status == model.StoreStatusDisabled {
err = api.EbaiAPI.ShopClose("", utils.Str2Int64(vendorStoreID))
// err = api.EbaiAPI.ShopOffline("", utils.Str2Int64(vendorStoreID))
}
if err != nil {
if remoteStatus, err2 := c.GetStoreStatus(ctx, vendorOrgCode, storeID, vendorStoreID); err2 == nil && remoteStatus == status {
err = nil
} else if intErr, ok := err.(*utils.ErrorWithCode); ok && intErr.IntCode() == 201100 || intErr.IntCode() == 201101 { // 兼容假错误:商户开业饿了么侧成功
err = nil
}
}
}
return err
}
func (c *PurchaseHandler) UpdateStoreOpTime(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, opTimeList []int16) (err error) {
params := map[string]interface{}{
ebaiapi.KeyBaiduShopID: vendorStoreID,
}
fillOpTimeParams(params, opTimeList)
if globals.EnableEbaiStoreWrite {
api.EbaiAPI.ShopUpdate(params)
}
return err
}
func (c *PurchaseHandler) GetAllStoresVendorID(ctx *jxcontext.Context, vendorOrgCode string) (vendorStoreIDs []string, err error) {
shopList, err := api.EbaiAPI.ShopList(ebaiapi.SysStatusAll)
if err == nil && len(shopList) > 0 {
vendorStoreIDs = make([]string, len(shopList))
for k, v := range shopList {
vendorStoreIDs[k] = utils.Int64ToStr(v.BaiduShopID)
}
}
return vendorStoreIDs, err
}
func (c *PurchaseHandler) UpdateStoreCustomID(ctx *jxcontext.Context, vendorOrgCode string, vendorStoreID string, storeID int64) (err error) {
if globals.EnableJdStoreWrite {
err = api.EbaiAPI.ShopIDBatchUpdate([]string{vendorStoreID}, []string{utils.Int64ToStr(storeID)})
}
return err
}
func (c *PurchaseHandler) GetShopListByPage(status, proxy_business_state int) (shopList []*ebaiapi.ShopList, err error) {
var (
pageCount = 500
pageNum = 1
)
for {
shopListPage, _, err2 := api.EbaiAPI.GetShopListByPage(status, proxy_business_state, pageCount, pageNum)
err = err2
shopList = append(shopList, shopListPage...)
if len(shopList) < pageCount {
break
}
pageNum++
}
return shopList, err
}
func (c *PurchaseHandler) GetShopIDsByPage() (vendorStoreIDs []string, err error) {
shopList, err := c.GetShopListByPage(ebaiapi.ShopStatusOnLine, ebaiapi.ProxyBusinessState)
for _, v := range shopList {
vendorStoreIDs = append(vendorStoreIDs, v.Wid)
}
return vendorStoreIDs, err
}
func (p *PurchaseHandler) CreateStore2(db *dao.DaoDB, storeID int, userName string) (vendorStoreID string, err error) {
return vendorStoreID, err
}
func (p *PurchaseHandler) DeleteStore(db *dao.DaoDB, storeID int, userName string) (err error) {
return err
}

View File

@@ -1,596 +0,0 @@
package ebai
import (
"regexp"
"strings"
"time"
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"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"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/business/partner/putils"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
const (
defVendorCatID = 201222934 // 其他蔬菜
)
var (
sensitiveWordRegexp = regexp.MustCompile(`商品名称中含有敏感词(\[.*\])`)
categoryCheck = map[int]string{
175: "赠品专区",
18: "烧烤吧台",
}
//果园果切的饿百分类ID
gygqVendorCatID = map[int]int{
201227732: 1,
201220933: 1,
201223525: 1,
201220334: 1,
}
)
func (p *PurchaseHandler) GetStoreSkusBatchSize(funcID int) (batchSize int) {
switch funcID {
case partner.FuncUpdateStoreSkusStock, partner.FuncUpdateStoreSkusStatus, partner.FuncUpdateStoreSkusPrice, partner.FuncDeleteStoreSkus:
batchSize = ebaiapi.MaxStoreSkuBatchSize
case partner.FuncCreateStoreSkus, partner.FuncUpdateStoreSkus:
batchSize = 1
case partner.FuncGetStoreSkusFullInfo:
batchSize = 1
case partner.FuncCreateActs, partner.FuncCancelActs:
batchSize = 1
}
return batchSize
}
// 门店分类
func (p *PurchaseHandler) GetStoreAllCategories(ctx *jxcontext.Context, storeID int, vendorStoreID string) (cats []*partner.BareCategoryInfo, err error) {
remoteCats, err := api.EbaiAPI.ShopCategoryGet(utils.Int2Str(storeID))
if err == nil {
cats = convertVendorCatList(remoteCats)
}
return cats, err
}
func convertVendorCatList(remoteCats []*ebaiapi.CategoryInfo) (cats []*partner.BareCategoryInfo) {
for _, rCat := range remoteCats {
cat := &partner.BareCategoryInfo{
VendorCatID: utils.Int64ToStr(rCat.CategoryID),
Name: rCat.Name,
Level: rCat.Level,
Seq: jxCatSeq2Ebai(rCat.Rank),
Children: convertVendorCatList(rCat.Children),
}
cats = append(cats, cat)
}
return cats
}
func (p *PurchaseHandler) IsErrCategoryExist(err error) (isExist bool) {
return ebaiapi.IsErrCategoryExist(err)
}
func (p *PurchaseHandler) IsErrCategoryNotExist(err error) (isNotExist bool) {
return ebaiapi.IsErrCategoryNotExist(err)
}
func getCheckExdStoreNameAndSeq(storeID int, storeCat *dao.SkuStoreCatInfo) (name string, seq int, isCheck bool) {
store, err := dao.GetStoreDetail(dao.GetDB(), storeID, model.VendorIDEBAI)
if err != nil || store == nil {
return storeCat.Name, storeCat.Seq, false
}
if strings.Contains(store.Name, model.ExdStoreName) {
if categoryCheck[storeCat.ID] != "" {
return storeCat.ExdName, storeCat.ExdSeq, true
} else {
return storeCat.ExdName, storeCat.ExdSeq, false
}
} else {
return storeCat.Name, storeCat.Seq, false
}
return name, seq, false
}
func (p *PurchaseHandler) CreateStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeCat *dao.SkuStoreCatInfo) (err error) {
var vendorCatID int64
if globals.EnableEbaiStoreWrite {
if catName, catSeq, isCheck := getCheckExdStoreNameAndSeq(storeID, storeCat); !isCheck {
vendorCatID, err = api.EbaiAPI.ShopCategoryCreate(utils.Int2Str(storeID), utils.Str2Int64WithDefault(storeCat.ParentVendorCatID, 0), formatCatName(catName), jxCatSeq2Ebai(catSeq))
}
} else {
vendorCatID = jxutils.GenFakeID()
}
storeCat.VendorCatID = utils.Int64ToStr(vendorCatID)
return err
}
func (p *PurchaseHandler) UpdateStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeCat *dao.SkuStoreCatInfo) (err error) {
if globals.EnableEbaiStoreWrite {
if catName, catSeq, isCheck := getCheckExdStoreNameAndSeq(storeID, storeCat); !isCheck {
err = api.EbaiAPI.ShopCategoryUpdate(utils.Int2Str(storeID), utils.Str2Int64WithDefault(storeCat.VendorCatID, 0), formatCatName(catName), jxCatSeq2Ebai(catSeq))
}
// todo, 饿百将一个分类重复改名也会报分类名重复错特殊处理一下不过因为GetStoreCategory其实会拉取所有的门店分类是比较耗时的操作
if utils.IsErrMatch(err, "1", []string{"分类名称已经存在"}) {
if cat, err2 := p.GetStoreCategory(ctx, storeID, vendorStoreID, storeCat.Name); err2 == nil {
if cat.VendorCatID == storeCat.VendorCatID {
err = nil
}
}
}
}
return err
}
func (p *PurchaseHandler) DeleteStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID, vendorCatID string, level int) (err error) {
if globals.EnableEbaiStoreWrite {
err = api.EbaiAPI.ShopCategoryDelete(utils.Int2Str(storeID), utils.Str2Int64WithDefault(vendorCatID, 0))
}
return err
}
// 门店商品
// 多门店平台不需要实现这个接口
func (p *PurchaseHandler) IsErrSkuExist(err error) (isExist bool) {
return ebaiapi.IsErrSkuExist(err)
}
func (p *PurchaseHandler) IsErrSkuNotExist(err error) (isNotExist bool) {
return ebaiapi.IsErrSkuNotExist(err)
}
func (p *PurchaseHandler) updateStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*dao.StoreSkuSyncInfo, isNeedMapCat bool) (failedList []*partner.StoreSkuInfoWithErr, err error) {
storeSku := storeSkuList[0]
strStoreID := utils.Int2Str(storeID)
isExd := false
if strings.Contains(storeSku.StoreName, model.ExdStoreName) {
isExd = true
}
params := genSkuParamsFromStoreSkuInfo2(storeSku, false, isExd)
if globals.EnableEbaiStoreWrite {
_, err = api.EbaiAPI.SkuUpdate(ctx.GetTrackInfo(), strStoreID, utils.Str2Int64(storeSku.VendorSkuID), params)
if err != nil {
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDEBAI], "更新商品基础信息")
}
if isNeedMapCat && !isExd {
utils.CallFuncAsync(func() {
api.EbaiAPI.SkuShopCategoryMap(strStoreID, utils.Str2Int64(storeSku.VendorSkuID), "", utils.Str2Int64(storeSku.VendorCatID), genSkuCatRank(storeSku))
})
}
err = nil
}
return failedList, err
}
func (p *PurchaseHandler) UpdateStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*dao.StoreSkuSyncInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
return p.updateStoreSkus(ctx, storeID, vendorStoreID, storeSkuList, true)
}
// 对于多门店平台来说storeSkuList中只有SkuID与VendorSkuID有意义
func (p *PurchaseHandler) CreateStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*dao.StoreSkuSyncInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
storeSku := storeSkuList[0]
var (
vendorSkuID int64
isExd bool = false
customSkuID int64
)
if strings.Contains(storeSku.StoreName, model.ExdStoreName) {
isExd = true
if storeSku.ExdSkuID == "" {
customSkuID = 0
} else {
customSkuID = utils.Str2Int64(storeSku.ExdSkuID)
}
} else {
isExd = false
customSkuID = int64(storeSku.SkuID)
}
params := genSkuParamsFromStoreSkuInfo2(storeSku, true, isExd)
if globals.EnableEbaiStoreWrite {
strStoreID := utils.Int2Str(storeID)
if vendorSkuID, err = api.EbaiAPI.SkuCreate(ctx.GetTrackInfo(), strStoreID, customSkuID, params); err == nil && !isExd {
utils.AfterFuncWithRecover(5*time.Second, func() {
api.EbaiAPI.SkuShopCategoryMap(strStoreID, vendorSkuID, "", utils.Str2Int64(storeSku.VendorCatID), genSkuCatRank(storeSku))
// 饿百平台有BUG会导致新建一个之前删除的商品时信息不会及时更新强制刷新一下
// 比如门店100887, skuID33805订单1577176719141226065
p.updateStoreSkus(ctx, storeID, vendorStoreID, storeSkuList, false)
})
} else {
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDEBAI], "创建商品")
}
} else {
vendorSkuID = jxutils.GenFakeID()
}
err = nil
storeSku.VendorSkuID = utils.Int64ToStr(vendorSkuID)
return failedList, err
}
func getFailedVendorSkuIDsFromOpResult(opResult *ebaiapi.BatchOpResult) (skuIDs []string) {
if opResult != nil {
for _, v := range opResult.FailedList {
skuIDs = append(skuIDs, utils.Int64ToStr(v.SkuID))
}
}
return skuIDs
}
func (p *PurchaseHandler) DeleteStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
if globals.EnableEbaiStoreWrite {
opResult, err2 := api.EbaiAPI.SkuDelete(ctx.GetTrackInfo(), utils.Int2Str(storeID), partner.BareStoreSkuInfoList(storeSkuList).GetVendorSkuIDIntList(), nil)
if err = err2; err2 != nil && opResult != nil {
// if len(storeSkuList) > len(opResult.FailedList) {
failedList = SelectStoreSkuListByOpResult(storeSkuList, opResult, storeID, model.VendorChineseNames[model.VendorIDEBAI], "删除商品")
// successList = putils.UnselectStoreSkuListByVendorSkuIDs(storeSkuList, getFailedVendorSkuIDsFromOpResult(opResult))
// }
}
err = nil
}
return failedList, err
}
func (p *PurchaseHandler) UpdateStoreSkusStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo, status int) (failedList []*partner.StoreSkuInfoWithErr, err error) {
vendorSkuIDs := partner.BareStoreSkuInfoList(storeSkuList).GetVendorSkuIDIntList()
if globals.EnableEbaiStoreWrite {
var opResult *ebaiapi.BatchOpResult
if status == model.SkuStatusNormal {
if len(vendorSkuIDs) > 1 {
opResult, err = api.EbaiAPI.SkuOnline(ctx.GetTrackInfo(), utils.Int2Str(storeID), vendorSkuIDs, nil, nil)
} else if len(vendorSkuIDs) == 1 {
err = api.EbaiAPI.SkuOnlineOne(ctx.GetTrackInfo(), utils.Int2Str(storeID), vendorSkuIDs[0], "", "")
if err != nil {
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDEBAI], "更新商品状态")
}
return failedList, err
}
} else {
if len(vendorSkuIDs) > 1 {
opResult, err = api.EbaiAPI.SkuOffline(ctx.GetTrackInfo(), utils.Int2Str(storeID), vendorSkuIDs, nil, nil)
} else if len(vendorSkuIDs) == 1 {
err = api.EbaiAPI.SkuOfflineOne(ctx.GetTrackInfo(), utils.Int2Str(storeID), vendorSkuIDs[0], "", "")
if err != nil {
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDEBAI], "更新商品状态")
}
return failedList, err
}
}
if err != nil && opResult != nil {
failedList = SelectStoreSkuListByOpResult(storeSkuList, opResult, storeID, model.VendorChineseNames[model.VendorIDEBAI], "更新商品状态")
// failedList = putils.UnselectStoreSkuListByVendorSkuIDs(storeSkuList, getFailedVendorSkuIDsFromOpResult(opResult))
}
err = nil
}
return failedList, err
}
func StoreSkuInfoList2Ebai(storeSkuList []*partner.StoreSkuInfo) (outList ebaiapi.ShopSkuInfoList) {
outList = make(ebaiapi.ShopSkuInfoList, len(storeSkuList))
for k, v := range storeSkuList {
outList[k] = &ebaiapi.ShopSkuInfo{
SkuID: utils.Str2Int64WithDefault(v.VendorSkuID, 0),
// CustomSkuID: utils.Int2Str(v.SkuID),
SalePrice: v.VendorPrice,
Stock: v.Stock,
}
}
return outList
}
func (p *PurchaseHandler) UpdateStoreSkusPrice(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
if globals.EnableEbaiStoreWrite {
if len(storeSkuList) > 1 {
opResult, err2 := api.EbaiAPI.SkuPriceUpdateBatch(ctx.GetTrackInfo(), utils.Int2Str(storeID), StoreSkuInfoList2Ebai(storeSkuList), ebaiapi.SkuIDTypeSkuID)
if err = err2; err != nil && opResult != nil {
failedList = SelectStoreSkuListByOpResult(storeSkuList, opResult, storeID, model.VendorChineseNames[model.VendorIDEBAI], "更新商品价格")
}
} else if len(storeSkuList) == 1 {
_, err := api.EbaiAPI.SkuPriceUpdateOne(ctx.GetTrackInfo(), utils.Int2Str(storeID), StoreSkuInfoList2Ebai(storeSkuList)[0])
if err != nil {
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDEBAI], "更新商品价格")
}
}
err = nil
}
return failedList, err
}
func (p *PurchaseHandler) UpdateStoreSkusStock(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
if globals.EnableEbaiStoreWrite {
if len(storeSkuList) > 1 {
opResult, err2 := api.EbaiAPI.SkuStockUpdateBatch(ctx.GetTrackInfo(), utils.Int2Str(storeID), StoreSkuInfoList2Ebai(storeSkuList), ebaiapi.SkuIDTypeSkuID)
if err = err2; err != nil && opResult != nil {
failedList = SelectStoreSkuListByOpResult(storeSkuList, opResult, storeID, model.VendorChineseNames[model.VendorIDEBAI], "更新商品库存")
// successList = putils.UnselectStoreSkuListByVendorSkuIDs(storeSkuList, getFailedVendorSkuIDsFromOpResult(opResult))
}
} else if len(storeSkuList) == 1 {
err = api.EbaiAPI.SkuStockUpdateOne(ctx.GetTrackInfo(), utils.Int2Str(storeID), StoreSkuInfoList2Ebai(storeSkuList)[0])
if err != nil {
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDEBAI], "更新商品库存")
}
}
err = nil
}
return failedList, err
}
func genSkuParamsFromStoreSkuInfo2(storeSku *dao.StoreSkuSyncInfo, isCreate, isExd bool) (params map[string]interface{}) {
var img string
if storeSku.ImgMix != "" {
img = storeSku.ImgMix
} else {
img = storeSku.Img
}
photos := []map[string]interface{}{
map[string]interface{}{
"is_master": true,
"url": img,
},
}
if storeSku.Img2 != "" {
photos = append(photos, map[string]interface{}{
"is_master": false,
"url": storeSku.Img2,
})
}
if storeSku.Img3 != "" {
photos = append(photos, map[string]interface{}{
"is_master": false,
"url": storeSku.Img3,
})
}
params = map[string]interface{}{
// "name": utils.LimitMixedStringLen(storeSku.SkuName, ebaiapi.MaxSkuNameByteCount),
"left_num": model.MaxStoreSkuStockQty,
// "category_id": utils.Str2Int64(storeSku.VendorCatID),
"predict_cat": 0, // 不使用推荐类目
// "cat3_id": getEbaiCat(storeSku.VendorVendorCatID),
"weight": storeSku.Weight,
"photos": photos,
"preparation_time": storeSku.PreparationTime,
}
if !isExd {
params["category_id"] = utils.Str2Int64(storeSku.VendorCatID)
params["name"] = utils.LimitMixedStringLen(storeSku.SkuName, ebaiapi.MaxSkuNameByteCount)
params["cat3_id"] = getEbaiCat(storeSku.VendorVendorCatID)
} else {
params["upc"] = storeSku.Upc
params["name"] = storeSku.Name
params["cat3_id"] = storeSku.ExdCategoryThirdID
params["category_id"] = utils.Str2Int64WithDefault(storeSku.VendorCatID, 0)
}
//证明是果园的几个果切分类,需要填加工服务
if gygqVendorCatID[int(storeSku.VendorVendorCatID)] == 1 {
params["process_type"] = model.YES
processDetail := []map[string]interface{}{
map[string]interface{}{
"type": "去皮",
"time": 2,
},
map[string]interface{}{
"type": "不加工",
"time": 0,
},
}
params["process_detail"] = processDetail
}
if storeSku.DescImg != "" {
params["rtf"] = storeSku.DescImg
}
if isCreate /*storeSku.SkuSyncStatus&(model.SyncFlagPriceMask| model.SyncFlagNewMask) != 0 */ {
params["sale_price"] = storeSku.VendorPrice
}
if storeSku.SkuSyncStatus&(model.SyncFlagSaleMask|model.SyncFlagNewMask) != 0 {
params["status"] = jxSkuStatus2Ebai(storeSku.MergedStatus)
}
// todo 饿百如果给的UPC是空要报错但如果我要删除UPC怎么弄
// if storeSku.Upc != "" {
// params["upc"] = storeSku.Upc
// }
return params
}
func ebaiSkuStatus2Jx(ebaiSkuStatus int) (jxSkuStatus int) {
if ebaiSkuStatus == ebaiapi.SkuStatusOnline {
jxSkuStatus = model.SkuStatusNormal
} else if ebaiSkuStatus == ebaiapi.SkuStatusOffline {
jxSkuStatus = model.SkuStatusDontSale
} else if ebaiSkuStatus == ebaiapi.SkuStatusOnline {
jxSkuStatus = model.SkuStatusDeleted
}
return jxSkuStatus
}
func jxSkuStatus2Ebai(status int) int {
if status <= 0 {
return ebaiapi.SkuStatusOffline
}
return ebaiapi.SkuStatusOnline
}
func getEbaiCat(catID int64) int64 {
if catID == 0 {
return defVendorCatID
}
return catID
}
// 饿百的排序是从大到小
func genSkuCatRank(storeSku *dao.StoreSkuSyncInfo) int {
return int(ebaiapi.MaxSkuCatRank - storeSku.GetSeq())
}
// 饿百的排序是从大到小
func jxCatSeq2Ebai(seq int) int {
return ebaiapi.MaxCatCatRank - seq
}
func formatCatName(name string) string {
return utils.LimitUTF8StringLen(name, ebaiapi.MaxCategoryNameLen)
}
func (p *PurchaseHandler) GetStoreSkusFullInfo(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (skuNameList []*partner.SkuNameInfo, err error) {
params := &ebaiapi.SkuListParams{
PageSize: ebaiapi.MaxSkuListPageSize,
}
if len(storeSkuList) == 1 {
if storeSkuList[0].SkuID > 0 {
params.CustomSkuID = utils.Int2Str(storeSkuList[0].SkuID)
}
if storeSkuList[0].VendorSkuID != "" {
params.SkuID = utils.Str2Int64WithDefault(storeSkuList[0].VendorSkuID, 0)
}
}
page1, err := api.EbaiAPI.SkuList(utils.Int2Str(storeID), params)
if err == nil {
skuNameList = append(skuNameList, vendorSkuList2Jx(page1.List)...)
if page1.Pages > 1 {
pages := make([]int, page1.Pages-1)
for i := 2; i <= page1.Pages; i++ {
pages[i-2] = i
}
task := tasksch.NewParallelTask("ebai GetStoreSkusFullInfo", nil, ctx,
func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
callParams := &ebaiapi.SkuListParams{
PageSize: ebaiapi.MaxSkuListPageSize,
Page: batchItemList[0].(int),
}
pageSku, err2 := api.EbaiAPI.SkuList(utils.Int2Str(storeID), callParams)
if err2 == nil {
return pageSku.List, err2
}
return nil, err2
}, pages)
tasksch.HandleTask(task, parentTask, true).Run()
result, err2 := task.GetResult(0)
if err = err2; err == nil {
for _, v := range result {
skuNameList = append(skuNameList, vendorSku2Jx(v.(*ebaiapi.SkuInfo)))
}
}
}
}
return skuNameList, err
}
func vendorSku2Jx(vendorSku *ebaiapi.SkuInfo) (skuName *partner.SkuNameInfo) {
prefix, name, comment, specUnit, unit, specQuality := jxutils.SplitSkuName(vendorSku.Name)
weight := vendorSku.Weight
if weight <= 0 {
weight = jxutils.FormatSkuWeight(specQuality, specUnit)
}
skuID := int(utils.Str2Int64WithDefault(vendorSku.CustomSkuID, 0))
vendorSkuID := utils.Int64ToStr(vendorSku.SkuID)
skuName = &partner.SkuNameInfo{
NameID: skuID,
VendorNameID: vendorSkuID,
Prefix: prefix,
Name: name,
Unit: unit,
SkuList: []*partner.SkuInfo{
&partner.SkuInfo{
StoreSkuInfo: partner.StoreSkuInfo{
VendorSkuID: vendorSkuID,
SkuID: skuID,
Stock: vendorSku.LeftNum,
VendorPrice: vendorSku.SalePrice,
Status: ebaiSkuStatus2Jx(vendorSku.Status),
},
SkuName: vendorSku.Name,
Comment: comment,
SpecQuality: float64(specQuality),
SpecUnit: specUnit,
Weight: weight,
},
},
}
for _, v := range vendorSku.Photos {
skuName.PictureList = append(skuName.PictureList, v.URL)
}
// todo, 看起来饿百只返回了最低一级的商家分类信息
for _, v := range vendorSku.CustomCatList {
skuName.VendorCatIDList = append(skuName.VendorCatIDList, v.CustomCatID)
}
return skuName
}
func vendorSkuList2Jx(vendorSkuList []*ebaiapi.SkuInfo) (skuNameList []*partner.SkuNameInfo) {
for _, vendorSku := range vendorSkuList {
skuNameList = append(skuNameList, vendorSku2Jx(vendorSku))
}
return skuNameList
}
func (p *PurchaseHandler) GetSensitiveWordRegexp() *regexp.Regexp {
return sensitiveWordRegexp
}
//饿百api返回
func SelectStoreSkuListByOpResult(storeSkuList []*partner.StoreSkuInfo, opResult *ebaiapi.BatchOpResult, storeID int, vendorName string, syncType string) (selectedStoreSkuList []*partner.StoreSkuInfoWithErr) {
opResultMap := make(map[int64]string)
if len(opResult.FailedList) > 0 {
for _, v := range opResult.FailedList {
if !(syncType == "删除商品" && ebaiapi.IsMsgSkuNotExist(v.ErrorMsg)) {
opResultMap[v.SkuID] = v.ErrorMsg
}
}
for _, v := range storeSkuList {
if opResultMap[utils.Str2Int64(v.VendorSkuID)] != "" {
opFailed := &partner.StoreSkuInfoWithErr{
StoreSkuInfo: v,
ErrMsg: opResultMap[utils.Str2Int64(v.VendorSkuID)],
StoreID: storeID,
VendoreName: vendorName,
SyncType: syncType,
}
selectedStoreSkuList = append(selectedStoreSkuList, opFailed)
}
}
}
return selectedStoreSkuList
}
func (p *PurchaseHandler) CreateStoreSkusAct(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
for _, v := range storeSkuList {
if vendorActID, err2 := createOneShopAct(putils.GetFixDirectDownAct(vendorOrgCode, storeID, v.SkuID), utils.Int2Str(storeID), putils.StoreSku2ActStoreSku(model.SyncFlagNewMask, vendorStoreID, []*partner.StoreSkuInfo{v})); err2 != nil {
failedList = append(failedList, &partner.StoreSkuInfoWithErr{
StoreSkuInfo: v,
VendoreID: model.VendorIDEBAI,
StoreID: storeID,
ErrMsg: err2.Error(),
})
} else {
v.VendorActID = vendorActID
}
}
return failedList, err
}
func (p *PurchaseHandler) CancelActs(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
for _, v := range storeSkuList {
if err2 := ActivityDisable(utils.Str2Int64(v.VendorActID), utils.Int2Str(storeID), 0, 0); err2 != nil {
failedList = append(failedList, &partner.StoreSkuInfoWithErr{
StoreSkuInfo: v,
VendoreID: model.VendorIDJD,
StoreID: storeID,
ErrMsg: err2.Error(),
})
}
}
return failedList, err
}
func (p *PurchaseHandler) UpdateStoreSkusSpecTag(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (err error) {
return err
}

View File

@@ -1,46 +0,0 @@
package ebai
import (
"testing"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
)
func TestGetStoreSkusFullInfo(t *testing.T) {
skuNameList, err := CurPurchaseHandler.GetStoreSkusFullInfo(jxcontext.AdminCtx, nil, testShopID, testShopBaiduID, []*partner.StoreSkuInfo{
&partner.StoreSkuInfo{
SkuID: 4256,
},
})
if err != nil {
t.Fatal(err.Error())
}
t.Log(utils.Format4Output(skuNameList, false))
t.Log(len(skuNameList))
}
func TestGetStoreSkusBareInfo(t *testing.T) {
storeSkuList, err := CurPurchaseHandler.GetStoreSkusBareInfo(jxcontext.AdminCtx, "", nil, testShopID, testShopBaiduID, nil)
if err != nil {
t.Fatal(err.Error())
}
t.Log(utils.Format4Output(storeSkuList, false))
t.Log(len(storeSkuList))
}
func TestDeleteStoreAllSkus(t *testing.T) {
err := CurPurchaseHandler.DeleteStoreAllSkus(jxcontext.AdminCtx, nil, testShopID, testShopBaiduID, true)
if err != nil {
t.Fatal(err)
}
}
func TestDeleteStoreAllCategories(t *testing.T) {
err := CurPurchaseHandler.DeleteStoreAllCategories(jxcontext.AdminCtx, nil, testShopID, testShopBaiduID, true)
if err != nil {
t.Fatal(err)
}
}

View File

@@ -1,57 +0,0 @@
package ebai
import (
"testing"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
)
// func TestSyncStoresSkus(t *testing.T) {
// skus := make([]int, 100)
// for i := 0; i < 100; i++ {
// skus[i] = i + 1
// }
// _, err := CurPurchaseHandler.SyncStoreSkus(jxcontext.AdminCtx, nil, testShopID, skus, false, false)
// if err != nil {
// t.Fatal(err.Error())
// }
// time.Sleep(4 * time.Second)
// }
// func TestSyncOneStoreCategoriesFromRemote2Local(t *testing.T) {
// db := dao.GetDB()
// err := CurPurchaseHandler.SyncLocalStoreCategory(db, testShopID, "autotest")
// if err != nil {
// t.Fatal(err.Error())
// }
// }
// func TestSyncOneStoreCategoriesFromLocal2Remote(t *testing.T) {
// _, err := CurPurchaseHandler.SyncStoreCategory(jxcontext.AdminCtx, nil, testShopID, false)
// if err != nil {
// t.Fatal(err.Error())
// }
// }
func TestGetAllRemoteSkus(t *testing.T) {
result, err := CurPurchaseHandler.GetStoreSkusFullInfo(jxcontext.AdminCtx, nil, testShopID, testShopBaiduID, nil)
if err != nil {
t.Fatal(err.Error())
} else {
t.Log(len(result))
}
}
func TestDeleteRemoteSkus(t *testing.T) {
err := CurPurchaseHandler.DeleteStoreAllSkus(jxcontext.AdminCtx, nil, testShopID, testShopBaiduID, true)
if err != nil {
t.Fatal(err.Error())
}
}
func TestDeleteRemoteCategories(t *testing.T) {
err := new(PurchaseHandler).DeleteStoreAllCategories(jxcontext.AdminCtx, nil, testShopID, testShopBaiduID, true)
if err != nil {
t.Fatal(err.Error())
}
}

View File

@@ -1,34 +0,0 @@
package ebai
import (
"testing"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/model/dao"
)
func TestReadStore(t *testing.T) {
result, err := CurPurchaseHandler.ReadStore(jxcontext.AdminCtx, "", testShopBaiduID)
if err != nil {
t.Fatal(err.Error())
}
t.Log(utils.Format4Output(result, false))
}
func TestUpdateStore(t *testing.T) {
db := dao.GetDB()
err := CurPurchaseHandler.UpdateStore(db, testShopID, "autotest")
if err != nil {
t.Fatal(err.Error())
}
}
func TestCreateStore(t *testing.T) {
db := dao.GetDB()
_, err := CurPurchaseHandler.CreateStore(db, 1, "autotest")
if err != nil {
t.Fatal(err.Error())
}
}

View File

@@ -1,88 +0,0 @@
package ebai
import (
"time"
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
const (
timeout4WaybillCancel = 10 * time.Minute // 饿百发送运单取消消息10分钟后如果没有转自送就要取消订单且不再发送订单取消消息
)
var (
VendorWaybillStatus2StatusMap = map[string]int{
ebaiapi.WaybillStatusNew: model.WaybillStatusUnknown,
ebaiapi.WaybillStatusRequestDelivery: model.WaybillStatusUnknown,
ebaiapi.WaybillStatusWait4Courier: model.WaybillStatusNew,
ebaiapi.WaybillStatusCourierAccepted: model.WaybillStatusAccepted,
ebaiapi.WaybillStatusCourierPickedup: model.WaybillStatusDelivering,
ebaiapi.WaybillStatusDeliveryCancled: model.WaybillStatusCanceled,
ebaiapi.WaybillStatusFinished: model.WaybillStatusDelivered,
// ebaiapi.WaybillStatusExceptional: model.WaybillStatusCanceled, // 饿百的配送异常不应该当成取消来处理比如1568651453228834871
ebaiapi.WaybillStatusSelfDelivery: model.WaybillStatusUnknown,
ebaiapi.WaybillStatusDontDeliver: model.WaybillStatusCanceled,
ebaiapi.WaybillStatusDeliveryRejected: model.WaybillStatusCanceled,
ebaiapi.WaybillStatusCourierArrived: model.WaybillStatusCourierArrived,
}
)
func (p *PurchaseHandler) GetWaybillStatusFromVendorStatus(vendorStatus string) int {
if status, ok := VendorWaybillStatus2StatusMap[vendorStatus]; ok {
return status
}
return model.WaybillStatusUnknown
}
func (c *PurchaseHandler) onWaybillMsg(msg *ebaiapi.CallbackMsg) (retVal *ebaiapi.CallbackResponse) {
order := c.callbackMsg2Waybill(msg)
globals.SugarLogger.Debugf("ebai onWaybillMsg orderID:%s", order.VendorOrderID)
if order.Status == model.WaybillStatusNew || order.Status == model.WaybillStatusAccepted { // 饿百新运单事件要查询快递员信息,因为可能事件错序
if result, err := api.EbaiAPI.OrderDeliveryGet(order.VendorOrderID); err != nil {
globals.SugarLogger.Warnf("ebai onWaybillMsg orderID:%s OrderDeliveryGet failed with error:%v", order.VendorOrderID, err)
return api.EbaiAPI.Err2CallbackResponse(msg.Cmd, err, order.VendorOrderID)
} else {
order.CourierName = utils.Interface2String(result["name"])
order.CourierMobile = utils.Interface2String(result["phone"])
}
if order.Status == model.WaybillStatusNew {
order2, _ := partner.CurOrderManager.LoadOrder(order.VendorOrderID, order.WaybillVendorID)
if order2.Status == model.OrderStatusWaitAccepted {
order2.Status = model.OrderStatusNew
scheduler.CurrentScheduler.OnOrderNew(order2, false)
}
}
} else if order.Status == model.WaybillStatusCanceled {
utils.AfterFuncWithRecover(timeout4WaybillCancel, func() {
if localOrder, err2 := partner.CurOrderManager.LoadOrder(order.VendorOrderID, model.VendorIDEBAI); err2 == nil {
if localOrder.Status < model.OrderStatusEndBegin {
c.trySyncCancelStatus(order.VendorOrderID)
}
}
})
}
return api.EbaiAPI.Err2CallbackResponse(msg.Cmd, partner.CurOrderManager.OnWaybillStatusChanged(order), order.VendorStatus)
}
func (c *PurchaseHandler) callbackMsg2Waybill(msg *ebaiapi.CallbackMsg) (retVal *model.Waybill) {
vendorStatus := utils.Int64ToStr(utils.MustInterface2Int64(msg.Body["status"]))
orderID := GetOrderIDFromMsg(msg)
retVal = &model.Waybill{
VendorOrderID: orderID,
OrderVendorID: model.VendorIDEBAI,
VendorWaybillID: orderID,
WaybillVendorID: model.VendorIDEBAI,
Status: c.GetWaybillStatusFromVendorStatus(vendorStatus),
VendorStatus: vendorStatus,
StatusTime: utils.Timestamp2Time(msg.Timestamp),
VendorOrgCode: msg.Source,
}
return retVal
}

View File

@@ -1,11 +0,0 @@
package elm
import (
"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"
)
func (c *PurchaseHandler) SyncAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actOrderRules []*model.ActOrderRule, actStoreSkuList []*model.ActStoreSku2) (err error) {
return nil
}

View File

@@ -1,101 +0,0 @@
package elm
import (
"fmt"
"git.rosy.net.cn/baseapi/platformapi/elmapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals/api"
)
var (
curPurchaseHandler *PurchaseHandler
)
type PurchaseHandler struct {
partner.BasePurchasePlatform
}
func init() {
if api.ElmAPI != nil {
curPurchaseHandler = new(PurchaseHandler)
// partner.RegisterPurchasePlatform(curPurchaseHandler)
}
}
func (c *PurchaseHandler) GetVendorID() int {
return model.VendorIDELM
}
func OnCallbackMsg(msg *elmapi.CallbackMsg) (retVal *elmapi.CallbackResponse) {
if curPurchaseHandler != nil {
retVal = curPurchaseHandler.OnCallbackMsg(msg)
}
return retVal
}
func (c *PurchaseHandler) OnCallbackMsg(msg *elmapi.CallbackMsg) (retVal *elmapi.CallbackResponse) {
if msg.Type == elmapi.MsgTypeOrderValid {
innerMsg := make(map[string]interface{})
err := utils.UnmarshalUseNumber([]byte(msg.Message), &innerMsg)
if err != nil {
retVal = elmapi.Err2CallbackResponse(err, "")
} else {
innerMsg["msgType"] = msg.Type
retVal = c.OnOrderNewMsg(innerMsg)
}
} else if msg.Type > elmapi.MsgTypeOrderValid && msg.Type < elmapi.MsgTypeUserApplyCancel {
var innerMsg elmapi.CallbackOrderStatusMsg
err := utils.UnmarshalUseNumber([]byte(msg.Message), &innerMsg)
if err != nil {
retVal = elmapi.Err2CallbackResponse(err, "")
} else {
innerMsg.MsgType = msg.Type
retVal = c.OnOrderStatusMsg(&innerMsg)
}
} else if msg.Type >= elmapi.MsgTypeUserApplyCancel && msg.Type < elmapi.MsgTypeUserUrgeOrder {
var innerMsg elmapi.CallbackOrderCancelRefundMsg
err := utils.UnmarshalUseNumber([]byte(msg.Message), &innerMsg)
if err != nil {
retVal = elmapi.Err2CallbackResponse(err, "")
} else {
innerMsg.MsgType = msg.Type
retVal = c.OnOrderCancelRefundMsg(&innerMsg)
}
} else if msg.Type == elmapi.MsgTypeUserUrgeOrder {
var innerMsg elmapi.CallbackOrderUrgeMsg
err := utils.UnmarshalUseNumber([]byte(msg.Message), &innerMsg)
if err != nil {
retVal = elmapi.Err2CallbackResponse(err, "")
} else {
innerMsg.MsgType = msg.Type
jxutils.CallMsgHandler(func() {
retVal = c.onOrderUserUrgeOrder(&innerMsg)
}, jxutils.ComposeUniversalOrderID(innerMsg.OrderID, model.VendorIDELM))
}
} else if msg.Type >= elmapi.MsgTypeWaybillWait4DeliveryVendor && msg.Type <= elmapi.MsgTypeRejectedSystemError {
var innerMsg elmapi.CallbackWaybillStatusMsg
err := utils.UnmarshalUseNumber([]byte(msg.Message), &innerMsg)
if err != nil {
retVal = elmapi.Err2CallbackResponse(err, "")
} else {
innerMsg.MsgType = msg.Type
retVal = c.OnWaybillStatusMsg(&innerMsg)
}
} else {
retVal = elmapi.SuccessResponse
}
return retVal
}
func (p *PurchaseHandler) UploadImg(ctx *jxcontext.Context, vendorOrgCode, imgURL string, imgData []byte, imgName string, imgType int) (imgHint string, err error) {
return imgHint, err
}
func (p *PurchaseHandler) GetVendorCategories(ctx *jxcontext.Context) (vendorCats []*model.SkuVendorCategory, err error) {
return nil, fmt.Errorf("平台%s不支持此操作", jxutils.GetVendorName(model.VendorIDELM))
}

View File

@@ -1,334 +0,0 @@
package elm
import (
"errors"
"fmt"
"math"
"strings"
"time"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
"git.rosy.net.cn/baseapi/platformapi/elmapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/partner"
)
const (
acceptOrderDelay = 270 * time.Second
fakePickedUp = "fakefinishedpickup"
)
var (
VendorStatus2StatusMap = map[string]int{
elmapi.OrderStatusUnprocessed: model.OrderStatusNew,
elmapi.OrderStatusValid: model.OrderStatusAccepted,
elmapi.OrderStatusPending: model.OrderStatusNew,
// elmapi.OrderStatusRefunding: model.OrderStatusApplyRefund,
elmapi.OrderStatusInvalid: model.OrderStatusCanceled,
elmapi.OrderStatusSettled: model.OrderStatusFinished,
}
)
func (c *PurchaseHandler) OnOrderStatusMsg(msg *elmapi.CallbackOrderStatusMsg) (retVal *elmapi.CallbackResponse) {
jxutils.CallMsgHandler(func() {
retVal = c.onOrderStatusMsg(msg)
}, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDELM))
return retVal
}
func (c *PurchaseHandler) OnOrderNewMsg(msg map[string]interface{}) (retVal *elmapi.CallbackResponse) {
jxutils.CallMsgHandler(func() {
retVal = c.onOrderNew(msg)
}, jxutils.ComposeUniversalOrderID(msg["orderId"].(string), model.VendorIDELM))
return retVal
}
func (c *PurchaseHandler) OnOrderCancelRefundMsg(msg *elmapi.CallbackOrderCancelRefundMsg) (retVal *elmapi.CallbackResponse) {
jxutils.CallMsgHandler(func() {
retVal = c.onOrderCancelRefundMsg(msg)
}, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDELM))
return retVal
}
func (c *PurchaseHandler) orderStatusMsg2Status(msg *elmapi.CallbackOrderStatusMsg) *model.OrderStatus {
orderStatus := &model.OrderStatus{
VendorOrderID: msg.OrderID,
VendorID: model.VendorIDELM,
OrderType: model.OrderTypeOrder,
RefVendorOrderID: msg.OrderID,
RefVendorID: model.VendorIDELM,
VendorStatus: c.stateAndType2Str(msg.State, msg.MsgType),
StatusTime: utils.Timestamp2Time(msg.UpdateTime),
}
return orderStatus
}
func (c *PurchaseHandler) cancelRefundMsg2Status(msg *elmapi.CallbackOrderCancelRefundMsg) *model.OrderStatus {
orderStatus := &model.OrderStatus{
VendorOrderID: msg.OrderID,
VendorID: model.VendorIDELM,
OrderType: model.OrderTypeOrder,
RefVendorOrderID: msg.OrderID,
RefVendorID: model.VendorIDELM,
VendorStatus: c.stateAndType2Str(msg.RefundStatus, msg.MsgType),
StatusTime: utils.Timestamp2Time(msg.UpdateTime),
}
return orderStatus
}
func (c *PurchaseHandler) onOrderStatusMsg(msg *elmapi.CallbackOrderStatusMsg) (retVal *elmapi.CallbackResponse) {
status := c.orderStatusMsg2Status(msg)
switch msg.MsgType {
case elmapi.MsgTypeOrderAccepted:
status.Status = model.OrderStatusAccepted
case elmapi.MsgTypeOrderCanceled, elmapi.MsgTypeOrderInvalid, elmapi.MsgTypeOrderForceInvalid:
status.Status = model.OrderStatusCanceled
case elmapi.MsgTypeOrderFinished:
status.Status = model.OrderStatusFinished
default:
globals.SugarLogger.Warnf("onOrderStatusMsg elm msg:%v not handled", msg)
return elmapi.SuccessResponse
}
err := partner.CurOrderManager.OnOrderStatusChanged("", status)
// 直接跳到拣货完成
if msg.MsgType == elmapi.MsgTypeOrderAccepted {
status.Status = model.OrderStatusFinishedPickup
status.VendorStatus = fakePickedUp
err = partner.CurOrderManager.OnOrderStatusChanged("", status)
}
// if globals.HandleLegacyJxOrder && err == nil {
// c.legacyElmOrderStatusChanged(status)
// }
return elmapi.Err2CallbackResponse(err, status.VendorStatus)
}
func (c *PurchaseHandler) onOrderCancelRefundMsg(msg *elmapi.CallbackOrderCancelRefundMsg) (retVal *elmapi.CallbackResponse) {
status := c.cancelRefundMsg2Status(msg)
switch msg.MsgType {
case elmapi.MsgTypeUserApplyCancel:
status.Status = model.OrderStatusApplyCancel
case elmapi.MsgTypeUserApplyRefund:
// status.Status = model.OrderStatusApplyRefund
default:
status.Status = model.OrderStatusUnknown
}
return elmapi.Err2CallbackResponse(partner.CurOrderManager.OnOrderStatusChanged("", status), status.VendorStatus)
}
func (c *PurchaseHandler) GetOrder(vendorOrgCode, orderID string) (order *model.GoodsOrder, err error) {
result, err := api.ElmAPI.GetOrder(orderID)
if err == nil {
order = c.Map2Order(result)
}
return order, err
}
func (c *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *model.GoodsOrder) {
result := orderData
orderID := result["id"].(string)
phoneList := result["phoneList"].([]interface{})
consigneeMobile := ""
if len(phoneList) > 0 {
consigneeMobile = utils.Interface2String(phoneList[0])
}
// globals.SugarLogger.Debug(result)
order = &model.GoodsOrder{
VendorOrderID: orderID,
VendorID: model.VendorIDELM,
VendorStoreID: utils.Int64ToStr(utils.MustInterface2Int64(result["shopId"])),
StoreID: int(utils.Str2Int64WithDefault(utils.Interface2String(result["openId"]), 0)),
StoreName: result["shopName"].(string),
ConsigneeName: result["consignee"].(string),
ConsigneeMobile: jxutils.FormalizeMobile(consigneeMobile),
ConsigneeAddress: result["address"].(string),
BuyerComment: utils.TrimBlankChar(utils.Interface2String(result["description"])),
ExpectedDeliveredTime: utils.Str2TimeWithDefault(utils.Interface2String(result["deliverTime"]), utils.DefaultTimeValue),
PickDeadline: utils.DefaultTimeValue,
VendorStatus: utils.Interface2String(result["status"]), // 取订单的原始status不合并消息类型因为当前消息类型没有意义
OrderSeq: int(utils.MustInterface2Int64(result["daySn"])),
StatusTime: utils.Str2Time(result["activeAt"].(string)),
OriginalData: string(utils.MustMarshal(result)),
ActualPayPrice: jxutils.StandardPrice2Int(utils.MustInterface2Float64(result["totalPrice"])),
Skus: []*model.OrderSku{},
}
order.Status = c.getStatusFromVendorStatus(order.VendorStatus)
if result["book"].(bool) {
order.BusinessType = model.BusinessTypeDingshida
} else {
order.BusinessType = model.BusinessTypeImmediate
}
deliveryGeo := strings.Split(utils.Interface2String(result["deliveryGeo"]), ",")
if len(deliveryGeo) == 2 {
order.CoordinateType = model.CoordinateTypeMars
order.ConsigneeLng = jxutils.StandardCoordinate2Int(utils.Str2Float64(deliveryGeo[0]))
order.ConsigneeLat = jxutils.StandardCoordinate2Int(utils.Str2Float64(deliveryGeo[1]))
}
for _, group2 := range result["groups"].([]interface{}) {
group := group2.(map[string]interface{})
for _, product2 := range group["items"].([]interface{}) {
product := product2.(map[string]interface{})
sku := &model.OrderSku{
VendorOrderID: orderID,
VendorID: model.VendorIDELM,
Count: int(utils.MustInterface2Int64(product["quantity"])),
SkuID: int(utils.Str2Int64WithDefault(utils.Interface2String(product["extendCode"]), 0)),
VendorSkuID: utils.Int64ToStr(utils.Interface2Int64WithDefault(product["vfoodId"], 0)),
SkuName: product["name"].(string),
SalePrice: jxutils.StandardPrice2Int(utils.MustInterface2Float64(product["price"])),
Weight: int(math.Round(utils.Interface2Float64WithDefault(product["weight"], 0.0))),
}
if dao.IsVendorThingIDEmpty(sku.VendorSkuID) {
sku.VendorSkuID = utils.Int64ToStr(utils.MustInterface2Int64(product["id"])) // 2018-09-28日饿了么迁移到饿百后这个字段发生了变化
}
order.Skus = append(order.Skus, sku)
}
}
jxutils.RefreshOrderSkuRelated(order)
return order
}
//
func (c *PurchaseHandler) onOrderNew(msg map[string]interface{}) (response *elmapi.CallbackResponse) {
// todo 这里应该可以直接用msg里的内容而不用再次去查
order, err := c.GetOrder("", msg["orderId"].(string))
if err == nil {
order.VendorStatus = c.stateAndType2Str(order.VendorStatus, elmapi.MsgTypeOrderValid)
err = partner.CurOrderManager.OnOrderNew(order, nil)
// if globals.HandleLegacyJxOrder && err == nil {
// c.legacyWriteElmOrder(order)
// }
}
return elmapi.Err2CallbackResponse(err, "elm onOrderNew")
}
func (c *PurchaseHandler) onOrderUserUrgeOrder(msg *elmapi.CallbackOrderUrgeMsg) *elmapi.CallbackResponse {
status := &model.OrderStatus{
VendorOrderID: msg.OrderID,
VendorID: model.VendorIDELM,
OrderType: model.OrderTypeOrder,
RefVendorOrderID: msg.OrderID,
RefVendorID: model.VendorIDELM,
Status: model.OrderStatusApplyUrgeOrder,
VendorStatus: utils.Int2Str(msg.MsgType),
StatusTime: utils.Timestamp2Time(msg.UpdateTime),
}
c.ClientUrgeOrder(msg.OrderID)
return elmapi.Err2CallbackResponse(partner.CurOrderManager.OnOrderStatusChanged("", status), status.VendorStatus)
}
func (c *PurchaseHandler) stateAndType2Str(state string, msgType int) string {
return fmt.Sprintf("%s-%d", state, msgType)
}
func (c *PurchaseHandler) spliltCompositeState(compositeState string) (state string, msgType int) {
index := strings.Index(compositeState, "-")
if index >= 0 {
msgType = int(utils.Str2Int64(compositeState[index+1:]))
if msgType == 0 {
globals.SugarLogger.Debug(compositeState)
}
return compositeState[:index], msgType
}
return compositeState, 0
}
// IPurchasePlatformHandler
func (c *PurchaseHandler) getStatusFromVendorStatus(vendorStatus string) int {
state, _ := c.spliltCompositeState(vendorStatus)
if status, ok := VendorStatus2StatusMap[state]; ok {
return status
}
return model.OrderStatusUnknown
}
func (c *PurchaseHandler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) {
globals.SugarLogger.Debugf("elm AcceptOrRefuseOrder orderID:%s", order.VendorOrderID)
// if globals.EnableElmStoreWrite {
// if isAcceptIt {
// err = api.ElmAPI.ConfirmOrder(order.VendorOrderID)
// } else {
// err = api.ElmAPI.CancelOrder(order.VendorOrderID, elmapi.CancelOrderTypeOthers, "")
// }
// }
return err
}
// 饿了么没有拣货这个状态,直接返回成功
// 真实流程中也不会调用这个方法,因为接收订单后状态会直接转移到已拣货
func (c *PurchaseHandler) PickupGoods(order *model.GoodsOrder, isSelfDelivery bool, userName string) (err error) {
return nil
}
func (p *PurchaseHandler) AcceptOrRefuseFailedGetOrder(ctx *jxcontext.Context, order *model.GoodsOrder, isAcceptIt bool) (err error) {
return err
}
func (p *PurchaseHandler) CallCourier(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 拣货失败后再次招唤平台配送
return err
}
func (p *PurchaseHandler) ConfirmReceiveGoods(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 投递失败后确认收到退货
return err
}
func (c *PurchaseHandler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) {
// if globals.EnableElmStoreWrite {
// err = api.ElmAPI.DeliveryBySelfLite(order.VendorOrderID)
// }
return err
}
// 饿了么转商家自送后,没有确认送达的概念,空操作
func (c *PurchaseHandler) Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) {
return nil
}
func (c *PurchaseHandler) SelfDeliverDelivering(order *model.GoodsOrder, userName string) (err error) {
// if globals.EnableElmStoreWrite {
// err = api.ElmAPI.StartDeliveryBySelf(order.VendorOrderID, order.ConsigneeMobile)
// }
return err
}
func (c *PurchaseHandler) SelfDeliverDelivered(order *model.GoodsOrder, userName string) (err error) {
// if globals.EnableElmStoreWrite {
// err = api.ElmAPI.CompleteDeliveryBySelf(order.VendorOrderID, order.ConsigneeMobile)
// }
return err
}
func (c *PurchaseHandler) GetStatusActionTimeout(order *model.GoodsOrder, statusType, status int) (params *partner.StatusActionParams) {
if statusType == scheduler.TimerStatusTypeOrder && status == model.OrderStatusNew {
params = &partner.StatusActionParams{ // 饿了么开了专送店的订单没有拣货状态,接单后就为拣货完成,所以要延迟接单,否则门店来不及备货
Timeout: acceptOrderDelay,
}
}
return params
}
func (c *PurchaseHandler) GetOrderRealMobile(ctx *jxcontext.Context, order *model.GoodsOrder) (mobile string, err error) {
err = errors.New("饿了么还未实现GetOrderRealMobile")
return mobile, err
}
func (c *PurchaseHandler) AgreeOrRefuseCancel(ctx *jxcontext.Context, order *model.GoodsOrder, isAgree bool, reason string) (err error) {
return err
}
func (c *PurchaseHandler) CancelOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
return err
}
func (c *PurchaseHandler) AdjustOrder(ctx *jxcontext.Context, order *model.GoodsOrder, removedSkuList []*model.OrderSku, reason string) (err error) {
return err
}

View File

@@ -1,28 +0,0 @@
package elm
import (
"fmt"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
)
// 审核售后单申请
func (c *PurchaseHandler) AgreeOrRefuseRefund(ctx *jxcontext.Context, order *model.AfsOrder, approveType int, reason string) (err error) {
return err
}
// 确认收到退货
func (c *PurchaseHandler) ConfirmReceivedReturnGoods(ctx *jxcontext.Context, order *model.AfsOrder) (err error) {
return err
}
// 发起全款退款
func (c *PurchaseHandler) RefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
return fmt.Errorf("饿了么不支持全款退款")
}
// 发起部分退款
func (c *PurchaseHandler) PartRefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, refundSkuList []*model.OrderSku, reason string) (err error) {
return fmt.Errorf("饿了么不支持部分退款")
}

View File

@@ -1,10 +0,0 @@
package elm
import (
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
)
func (c *PurchaseHandler) ReplyOrderComment(ctx *jxcontext.Context, vendorOrgCode string, orderComment *model.OrderComment, replyComment string) (err error) {
return err
}

View File

@@ -1,52 +0,0 @@
package elm
import (
aliyunsmsclient "github.com/KenmyZhang/aliyun-communicate"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
)
const (
ELM_SMS_REMINDERS_DAIPEISHONG_TEMPLATECODE = "SMS_175573181" //饿了么待配送模板ID
ELM_SMS_REMINDERS_PEISHOGNZHONG_TEMPLATECODE = "SMS_175583155" //饿了么配送中模板ID
)
func (c *PurchaseHandler) ClientUrgeOrder(orderID string) (err error) {
utils.CallFuncAsync(func() {
var err error
globals.SugarLogger.Debugf("ClientUrgeOrder orderID:%s", orderID)
order, err2 := partner.CurOrderManager.LoadOrder(orderID, model.VendorIDELM)
if err = err2; err == nil {
templateCode := ""
var templateParams map[string]interface{}
if order.Status == model.OrderStatusFinishedPickup {
templateCode = ELM_SMS_REMINDERS_DAIPEISHONG_TEMPLATECODE
templateParams = map[string]interface{}{
"name": order.ConsigneeName,
}
} else if order.Status == model.OrderStatusDelivering {
bill, err2 := partner.CurOrderManager.LoadWaybill(order.VendorWaybillID, order.WaybillVendorID)
if err = err2; err == nil {
templateCode = ELM_SMS_REMINDERS_PEISHOGNZHONG_TEMPLATECODE
templateParams = map[string]interface{}{
"name": order.ConsigneeName,
"number": bill.CourierMobile,
}
}
}
if templateCode != "" {
smsClient := aliyunsmsclient.New("http://dysmsapi.aliyuncs.com/")
if globals.ReallyCallPlatformAPI {
_, err = smsClient.Execute(globals.AliKey, globals.AliSecret, order.ConsigneeMobile, globals.SMSSignName, templateCode, string(utils.MustMarshal(templateParams)))
}
}
}
if err != nil {
globals.SugarLogger.Warnf("ClientUrgeOrder orderID:%s failed with error:%v", orderID, err)
}
})
return err
}

View File

@@ -1,23 +0,0 @@
package elm
import (
"testing"
_ "git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
"git.rosy.net.cn/jx-callback/globals/testinit"
)
func init() {
testinit.Init()
}
func TestGetOrder(t *testing.T) {
orderID := "3025427524410871880"
order, err := new(PurchaseHandler).GetOrder("", orderID)
if err != nil {
t.Fatal(err.Error())
}
if order.VendorOrderID != orderID {
t.Fatal(err.Error())
}
}

View File

@@ -1,25 +0,0 @@
package elm
import (
"errors"
"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/dao"
)
func (p *PurchaseHandler) ReadStore(ctx *jxcontext.Context, vendorOrgCode string, vendorStoreID string) (*dao.StoreDetail, error) {
return nil, errors.New("饿了么还没实现")
}
func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName string) error {
return nil
}
func (p *PurchaseHandler) RefreshAllStoresID(ctx *jxcontext.Context, parentTask tasksch.ITask, isAsync bool) (hint string, err error) {
return hint, err
}
func (p *PurchaseHandler) GetStoreStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string) (storeStatus int, err error) {
return storeStatus, err
}

View File

@@ -1,67 +0,0 @@
package elm
import (
"fmt"
"git.rosy.net.cn/baseapi/platformapi/elmapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals/api"
)
func (c *PurchaseHandler) OnWaybillStatusMsg(msg *elmapi.CallbackWaybillStatusMsg) (retVal *elmapi.CallbackResponse) {
jxutils.CallMsgHandler(func() {
retVal = c.onWaybillStatusMsg(msg)
}, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDELM))
return retVal
}
func (c *PurchaseHandler) onWaybillStatusMsg(msg *elmapi.CallbackWaybillStatusMsg) (retVal *elmapi.CallbackResponse) {
order := c.callbackMsg2Waybill(msg)
if msg.MsgType == elmapi.MsgTypeWaybillWait4Courier { //MsgTypeWaybillWait4Courier事件与JD的新运单事件的时间机制更相似
order.Status = model.WaybillStatusNew
} else if msg.MsgType == elmapi.MsgTypeWaybillPickingUp {
if result, err := api.ElmAPI.GetOrder(msg.OrderID); err == nil {
order.DesiredFee = jxutils.StandardPrice2Int(utils.Interface2Float64WithDefault(result["deliverFee"], 0.0) +
utils.Interface2Float64WithDefault(result["vipDeliveryFeeDiscount"], 0.0))
}
order.Status = model.WaybillStatusAccepted
} else if msg.MsgType == elmapi.MsgTypeWaybillCourierArrived {
order.Status = model.WaybillStatusCourierArrived
} else if msg.MsgType == elmapi.MsgTypeWaybillDelivering {
order.Status = model.WaybillStatusDelivering
} else if msg.MsgType == elmapi.MsgTypeWaybillDelivered {
order.Status = model.WaybillStatusDelivered
} else if msg.MsgType >= elmapi.MsgTypeWaybillCanceledByMerchant && msg.MsgType <= elmapi.MsgTypeWaybillCanceledBySystem {
order.Status = model.WaybillStatusCanceled
} else if msg.MsgType >= elmapi.MsgTypeWaybillFailedCallLate &&
msg.MsgType <= elmapi.MsgTypeRejectedSystemError &&
msg.MsgType != elmapi.MsgTypeDeiverBySelf {
order.Status = model.WaybillStatusFailed
} else {
// MsgTypeWaybillWait4DeliveryVendor
// MsgTypeDeiverBySelf
order.Status = model.WaybillStatusUnknown
}
return elmapi.Err2CallbackResponse(partner.CurOrderManager.OnWaybillStatusChanged(order), order.VendorStatus)
}
func (c *PurchaseHandler) callbackMsg2Waybill(msg *elmapi.CallbackWaybillStatusMsg) (retVal *model.Waybill) {
retVal = &model.Waybill{
VendorOrderID: msg.OrderID,
OrderVendorID: model.VendorIDELM,
VendorWaybillID: msg.OrderID,
WaybillVendorID: model.VendorIDELM,
CourierName: msg.Name,
CourierMobile: msg.Phone,
VendorStatus: c.composeState(msg.State, msg.SubState, msg.MsgType),
StatusTime: utils.Timestamp2Time(msg.UpdateAt / 1000),
}
return retVal
}
func (c *PurchaseHandler) composeState(state, subState string, msgType int) string {
return fmt.Sprintf("%s-%d", state, msgType)
}

View File

@@ -1,422 +0,0 @@
package jd
import (
"fmt"
"time"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/baseapi/platformapi/jdapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/baseapi/utils/errlist"
"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"
)
const (
actMapDuration = 2 * time.Hour
)
type LogicUpdateInfo struct {
Item interface{}
KVs map[string]interface{}
Condition map[string]interface{}
}
var (
jdSkuActStatusMap = map[int]int{
jdapi.PromotionStateNotConfirm: model.ActStatusNA,
jdapi.PromotionStateConfirmed: model.ActStatusCreated,
jdapi.PromotionStateCanceled: model.ActStatusCanceled,
jdapi.PromotionStateEnded: model.ActStatusEnded,
}
actMap jxutils.SyncMapWithTimeout
)
// 是否按单一门店商品维度创建活动
func isCreateTypeSingleStoreSku() bool {
return false
// return !globals.IsProductEnv()
}
func splitPromotionSku(skus []*jdapi.PromotionSku, maxCount int) (skusList [][]*jdapi.PromotionSku) {
for {
skusLen := len(skus)
if skusLen <= maxCount {
skusList = append(skusList, skus)
break
}
skusList = append(skusList, skus[:maxCount])
skus = skus[maxCount:]
}
return skusList
}
func jdSkuActType2Jx(actType int) int {
if actType == jdapi.PromotionTypeDirectDown {
return model.ActSkuDirectDown
} else if actType == jdapi.PromotionTypeSeckill || actType == jdapi.PromotionTypeLimitedTime {
return model.ActSkuSecKill
}
return 0
}
func jdSkuActStatus2Jx(jdActState int) int {
return jdSkuActStatusMap[jdActState]
}
func CreatePromotionInfos(vendorOrgCode string, promotionType int, name string, beginDate, endDate time.Time, outInfoId, advertising, traceId string) (infoId int64, err error) {
if globals.EnableJdStoreWrite {
if promotionType == model.ActSkuDirectDown {
infoId, err = getAPI(vendorOrgCode).CreatePromotionInfosSingle(name, beginDate, endDate, outInfoId, advertising, traceId)
} else {
infoId, err = getAPI(vendorOrgCode).CreatePromotionInfosLimitTime(name, beginDate, endDate, outInfoId, advertising, traceId)
}
} else {
infoId = jxutils.GenFakeID()
}
if err == nil {
actMap.StoreWithTimeout(infoId, 1, actMapDuration)
}
return infoId, err
}
func CreatePromotionRules(vendorOrgCode string, promotionType int, infoId int64, outInfoId string, limitDevice, limitPin, limitCount, limitDaily int, traceId string) (err error) {
if globals.EnableJdStoreWrite {
if promotionType == model.ActSkuDirectDown {
err = getAPI(vendorOrgCode).CreatePromotionRulesSingle(infoId, outInfoId, limitDevice, limitPin, limitCount, limitDaily, traceId)
} else {
err = getAPI(vendorOrgCode).CreatePromotionRulesLimitTime(infoId, outInfoId, limitDevice, limitPin, limitCount, limitDaily, traceId)
}
}
return err
}
func CreatePromotionSku(vendorOrgCode string, promotionType int, infoId int64, outInfoId string, skus []*jdapi.PromotionSku, traceId string) (skusResult []*jdapi.PromotionSku, err error) {
if globals.EnableJdStoreWrite {
for _, batchSkus := range splitPromotionSku(skus, jdapi.MaxPromotionSkuCount) {
var tmpSkusResult []*jdapi.PromotionSku
var tmpErr error
if promotionType == model.ActSkuDirectDown {
tmpSkusResult, tmpErr = getAPI(vendorOrgCode).CreatePromotionSkuSingle(infoId, outInfoId, batchSkus, traceId)
} else {
tmpSkusResult, tmpErr = getAPI(vendorOrgCode).CreatePromotionSkuLimitTime(infoId, outInfoId, batchSkus, traceId)
}
if err = tmpErr; err != nil {
break
}
skusResult = append(skusResult, tmpSkusResult...)
}
}
return skusResult, err
}
func CancelPromotionSku(vendorOrgCode string, promotionType int, infoId int64, outInfoId string, skus []*jdapi.PromotionSku, traceId string) (err error) {
if globals.EnableJdStoreWrite {
for _, batchSkus := range splitPromotionSku(skus, jdapi.MaxPromotionSkuCount) {
var tmpErr error
if promotionType == model.ActSkuDirectDown {
tmpErr = getAPI(vendorOrgCode).CancelPromotionSkuSingle(infoId, outInfoId, batchSkus, traceId)
} else {
tmpErr = getAPI(vendorOrgCode).CancelPromotionSkuLimitTime(infoId, outInfoId, batchSkus, traceId)
}
if err = tmpErr; err != nil {
break
}
}
}
return err
}
func ConfirmPromotion(vendorOrgCode string, promotionType int, infoId int64, outInfoId, traceId string) (err error) {
if globals.EnableJdStoreWrite {
if promotionType == model.ActSkuDirectDown {
return getAPI(vendorOrgCode).ConfirmPromotionSingle(infoId, outInfoId, traceId)
} else {
return getAPI(vendorOrgCode).ConfirmPromotionLimitTime(infoId, outInfoId, traceId)
}
}
return err
}
func CancelPromotion(vendorOrgCode string, promotionType int, infoId int64, outInfoId, traceId string) (err error) {
if globals.EnableJdStoreWrite {
if promotionType == model.ActSkuDirectDown {
err = getAPI(vendorOrgCode).CancelPromotionSingle(infoId, outInfoId, traceId)
} else {
err = getAPI(vendorOrgCode).CancelPromotionLimitTime(infoId, outInfoId, traceId)
}
}
return err
}
func AdjustPromotionTime(vendorOrgCode string, promotionType int, infoId int64, outInfoId string, endDate time.Time, traceId string) (err error) {
if globals.EnableJdStoreWrite {
if promotionType == model.ActSkuDirectDown {
err = getAPI(vendorOrgCode).AdjustPromotionTimeSingle(infoId, outInfoId, endDate, traceId)
} else {
err = getAPI(vendorOrgCode).AdjustPromotionTimeLimitTime(infoId, outInfoId, endDate, traceId)
}
}
return err
}
func AdjustPromotionSku(vendorOrgCode string, promotionType int, infoId int64, outInfoId string, skus []*jdapi.PromotionSku, traceId string) (skusResult []*jdapi.PromotionSku, err error) {
if globals.EnableJdStoreWrite {
if promotionType == model.ActSkuDirectDown {
skusResult, err = getAPI(vendorOrgCode).AdjustPromotionSkuSingle(infoId, outInfoId, skus, traceId)
} else {
skusResult, err = getAPI(vendorOrgCode).AdjustPromotionSkuLimitTime(infoId, outInfoId, skus, traceId)
}
}
return skusResult, err
}
func storeSku2Jd(actStoreSku []*model.ActStoreSku2, handler func(syncStatus int8) bool) (jdActStoreSku []*jdapi.PromotionSku) {
for _, v := range actStoreSku {
if handler(v.SyncStatus) {
if v.VendorStoreID != "" && v.VendorSkuID != "" {
jdActStoreSku = append(jdActStoreSku, &jdapi.PromotionSku{
StationNo: utils.Str2Int64(v.VendorStoreID),
SkuID: utils.Str2Int64(v.VendorSkuID),
PromotionPrice: v.ActualActPrice,
LimitSkuCount: v.Stock,
})
}
}
}
return jdActStoreSku
}
func createSkuAct(ctx *jxcontext.Context, act *model.Act2, actStoreSku []*model.ActStoreSku2) (vendorActID string, err error) {
traceInfo := ctx.GetTrackInfo()
outInfoID := ""
if act.VendorActID == "" {
outInfoID = utils.Int2Str(act.ID)
}
infoID, err2 := CreatePromotionInfos(act.VendorOrgCode, act.Type, act.GetRealActName(), act.BeginAt, act.EndAt, outInfoID, act.Advertising, traceInfo)
if err = err2; err == nil {
vendorActID = utils.Int64ToStr(infoID)
if err = CreatePromotionRules(act.VendorOrgCode, act.Type, infoID, "", act.LimitUser, act.LimitUser, act.LimitCount, 1, traceInfo); err == nil {
if _, err = CreatePromotionSku(act.VendorOrgCode, act.Type, infoID, utils.Int2Str(act.ID), storeSku2Jd(actStoreSku, model.IsSyncStatusNeedCreate), traceInfo); err == nil {
if err = ConfirmPromotion(act.VendorOrgCode, act.Type, infoID, "", traceInfo); err == nil {
for _, v := range actStoreSku {
v.VendorActID = vendorActID
}
}
}
}
if err != nil {
CancelPromotion(act.VendorOrgCode, act.Type, infoID, "", traceInfo)
}
}
return vendorActID, err
}
func proxyCreateSkuAct(ctx *jxcontext.Context, act *model.Act2, actStoreSku []*model.ActStoreSku2) (vendorActID string, err error) {
if isCreateTypeSingleStoreSku() && len(actStoreSku) > 1 {
errList := errlist.New()
vendorActID := act.VendorActID
act.VendorActID = "placeholder"
for _, v := range actStoreSku {
_, err := createSkuAct(ctx, act, []*model.ActStoreSku2{v})
errList.AddErr(err)
}
act.VendorActID = vendorActID
err = errList.GetErrListAsOne()
} else {
vendorActID, err = createSkuAct(ctx, act, actStoreSku)
}
return vendorActID, err
}
func cancelSkuActSkus(ctx *jxcontext.Context, act *model.Act2, vendorActID string, actStoreSku []*model.ActStoreSku2) (err error) {
if vendorActID != "" {
if skuList := storeSku2Jd(actStoreSku, model.IsSyncStatusNeedDelete); len(skuList) > 0 {
err = CancelPromotionSku(act.VendorOrgCode, act.Type, utils.Str2Int64(vendorActID), "", skuList, ctx.GetTrackInfo())
}
}
return err
}
func cancelSkuAct(ctx *jxcontext.Context, act *model.Act2, vendorActID string) (err error) {
if vendorActID != "" {
err = CancelPromotion(act.VendorOrgCode, act.Type, utils.Str2Int64(vendorActID), "", ctx.GetTrackInfo())
}
return err
}
func (c *PurchaseHandler) SyncAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actOrderRules []*model.ActOrderRule, actStoreSkuList []*model.ActStoreSku2) (err error) {
globals.SugarLogger.Debugf("jd SyncAct, actID:%d", act.ID)
vendorActInfoMap := make(map[string][]*model.ActStoreSku2)
deleteActInfoMap := make(map[string][]*model.ActStoreSku2)
var actStoreSkuList4Create []*model.ActStoreSku2
var updateItems []*dao.KVUpdateItem
actStoreSkuMap := partner.SplitActStoreSku(actStoreSkuList)
actSkuCount := 0
toDelActSkuCount := 0
for storeID := range actStoreSkuMap {
for _, actStoreSku := range actStoreSkuMap[storeID] {
vendorActID := actStoreSku.VendorActID
if vendorActID == "" {
vendorActID = act.VendorActID
}
actSkuCount++
vendorActInfoMap[vendorActID] = append(vendorActInfoMap[vendorActID], actStoreSku)
if model.IsSyncStatusDelete(actStoreSku.SyncStatus) {
toDelActSkuCount++
deleteActInfoMap[vendorActID] = append(deleteActInfoMap[vendorActID], actStoreSku)
} else if model.IsSyncStatusNew(actStoreSku.SyncStatus) {
actStoreSkuList4Create = append(actStoreSkuList4Create, actStoreSku)
}
}
}
// 如果是全删,直接添加删除(即取消)标志
if actSkuCount == toDelActSkuCount {
act.SyncStatus |= model.SyncFlagDeletedMask
}
db := dao.GetDB()
err = func() (err error) {
if model.IsSyncStatusDelete(act.SyncStatus) {
errList := errlist.New()
for vendorActID := range vendorActInfoMap {
if vendorActID != "" {
if err = cancelSkuAct(ctx, act, vendorActID); err == nil {
updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, vendorActInfoMap[vendorActID], model.SyncFlagModifiedMask)...)
} else {
errList.AddErr(err)
}
}
}
if err = errList.GetErrListAsOne(); err == nil {
updateItems = append(updateItems, partner.Act2Update(ctx, act, model.SyncFlagModifiedMask))
}
} else if model.IsSyncStatusNew(act.SyncStatus) {
if act.VendorActID, err = proxyCreateSkuAct(ctx, act, actStoreSkuList4Create); err == nil {
updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, actStoreSkuList4Create, model.SyncFlagNewMask)...)
updateItems = append(updateItems, partner.Act2Update(ctx, act, model.SyncFlagNewMask))
} else {
if act.VendorActID != "" {
actMap := partner.Act2ActMap(act)
dao.UpdateEntity(db, actMap, model.FieldVendorActID)
}
}
} else if model.IsSyncStatusUpdate(act.SyncStatus) {
errList := errlist.New()
if len(actStoreSkuList4Create) > 0 {
if _, err = proxyCreateSkuAct(ctx, act, actStoreSkuList4Create); err == nil {
updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, actStoreSkuList4Create, model.SyncFlagNewMask)...)
} else {
errList.AddErr(err)
}
}
for vendorActID := range deleteActInfoMap {
if vendorActID != "" {
if len(vendorActInfoMap[vendorActID]) == len(deleteActInfoMap[vendorActID]) {
err = cancelSkuAct(ctx, act, vendorActID)
} else {
err = cancelSkuActSkus(ctx, act, vendorActID, deleteActInfoMap[vendorActID])
}
if err == nil {
updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, deleteActInfoMap[vendorActID], model.SyncFlagDeletedMask)...)
} else {
errList.AddErr(err)
}
} else {
updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, deleteActInfoMap[vendorActID], model.SyncFlagDeletedMask)...)
}
}
if err = errList.GetErrListAsOne(); err == nil {
updateItems = append(updateItems, partner.Act2Update(ctx, act, model.SyncFlagModifiedMask))
}
}
return err
}()
// globals.SugarLogger.Debug(utils.Format4Output(updateItems, false))
_, err2 := dao.BatchUpdateActEntity(db, model.IsSyncStatusDelete(act.SyncStatus), updateItems)
if err == nil {
err = err2
}
return err
}
func OnActMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
jxutils.CallMsgHandler(func() {
retVal = CurPurchaseHandler.onActMsg(msg)
}, jxutils.ComposeUniversalOrderID(msg.BillID, model.VendorIDJD))
return retVal
}
func (c *PurchaseHandler) onActMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
if msg.StatusID == jdapi.PromotionStatusSingleOK || msg.StatusID == jdapi.PromotionStatusLimitTimeOK {
promotionID := msg.BillID
intPromotionID := utils.Str2Int64(promotionID)
if _, ok := actMap.Load(intPromotionID); !ok {
utils.CallFuncAsync(func() {
if !partner.CurActManager.IsVendorActExist(jxcontext.AdminCtx, promotionID, model.VendorIDJD) {
act, actStoreSkuList, err := getActFromJD(AppKey2OrgCode(msg.AppKey), promotionID)
if err == nil && len(actStoreSkuList) > 0 {
_, err = partner.CurActManager.CreateActFromVendor(jxcontext.AdminCtx, act, actStoreSkuList)
}
if err != nil {
retVal = jdapi.Err2CallbackResponse(err, promotionID)
}
}
})
} else {
actMap.Delete(intPromotionID)
}
}
return retVal
}
func getActFromJD(vendorOrgCode, promotionID string) (act *model.Act2, actStoreSkuList []*model.ActStoreSku2, err error) {
result, err := getAPI(vendorOrgCode).QueryPromotionInfo(utils.Str2Int64(promotionID))
if err == nil && len(result.SkuResultList) > 0 {
act = &model.Act2{
Act: model.Act{
Name: fmt.Sprintf("%s-%d", result.Source, result.PromotionInfoID),
Type: jdSkuActType2Jx(result.PromotionType),
Status: jdSkuActStatus2Jx(result.PromotionState),
BeginAt: result.SkuResultList[0].BeginTime.GoTime(),
EndAt: result.SkuResultList[0].EndTime.GoTime(),
Source: result.Source,
CreateType: model.ActCreateTypeCallback,
PricePercentage: 0,
LimitDaily: result.SkuResultList[0].LimitDaily,
LimitCount: 1,
},
VendorID: model.VendorIDJD,
VendorOrgCode: vendorOrgCode,
VendorActID: promotionID,
}
if utils.IsTimeZero(act.BeginAt) {
act.BeginAt = result.BeginTime.GoTime()
}
if utils.IsTimeZero(act.EndAt) {
act.EndAt = result.EndTime.GoTime().Add(24*time.Hour - 1*time.Second)
}
if result.SkuResultList[0].LimitPin == 1 || result.SkuResultList[0].LimitDevice == 1 {
act.LimitUser = 1
}
for _, v := range result.SkuResultList {
if v.PromotionState != jdapi.PromotionStateCanceled {
actStoreSkuList = append(actStoreSkuList, &model.ActStoreSku2{
VendorStoreID: utils.Int64ToStr(v.StationNo),
VendorSkuID: utils.Int64ToStr(v.SkuID),
ActualActPrice: int64(v.PromotionPrice),
})
}
}
}
return act, actStoreSkuList, err
}

View File

@@ -1,33 +0,0 @@
package jd
import (
"git.rosy.net.cn/baseapi/platformapi/jdapi"
)
func OnOrderMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
if CurPurchaseHandler != nil {
retVal = CurPurchaseHandler.OnOrderMsg(AppKey2OrgCode(msg.AppKey), msg)
}
return retVal
}
func OnWaybillMsg(msg *jdapi.CallbackDeliveryStatusMsg) (retVal *jdapi.CallbackResponse) {
if CurPurchaseHandler != nil {
retVal = CurPurchaseHandler.OnWaybillMsg(AppKey2OrgCode(msg.AppKey), msg)
}
return retVal
}
func OnStoreMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
if CurPurchaseHandler != nil {
retVal = CurPurchaseHandler.OnStoreMsg(AppKey2OrgCode(msg.AppKey), msg)
}
return retVal
}
func OnOrderInfoChangeMsg(msg *jdapi.CallbackOrderInfoChangeMsg) (retVal *jdapi.CallbackResponse) {
if CurPurchaseHandler != nil {
retVal = CurPurchaseHandler.OnOrderInfoChangeMsg(AppKey2OrgCode(msg.AppKey), msg)
}
return retVal
}

View File

@@ -1,244 +0,0 @@
package jd
import (
"math"
"git.rosy.net.cn/baseapi/platformapi/jdapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
)
func (p *PurchaseHandler) OnFinancialMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
utils.CallFuncAsync(func() {
retVal = p.onFinancialMsg(msg)
})
return retVal
}
// 京东正向/退款订单类型处理--存储
func (p *PurchaseHandler) onFinancialMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
var err error
a := getAPI(AppKey2OrgCode(msg.AppKey))
// if msg.StatusID == jdapi.OrderStatusPayFinishedSettle || msg.StatusID == jdapi.OrderStatusTipChanged || msg.StatusID == jdapi.OrderStatusSwitch2SelfSettle { // 如果是正向单
if msg.StatusID == jdapi.OrderStatusPayFinishedSettle || msg.StatusID == jdapi.OrderStatusTipChanged || msg.StatusID == jdapi.OrderStatusAdjustSettle || msg.StatusID == jdapi.OrderStatusSwitch2SelfSettle { // 如果是正向单
order, err2 := partner.CurOrderManager.LoadOrder(msg.BillID, model.VendorIDJD)
if err = err2; err == nil {
orderData, err2 := a.QuerySingleOrder(msg.BillID)
if err = err2; err == nil {
orderFinancial, err2 := CurPurchaseHandler.OrderDetail2Financial(a, orderData, false, order)
if err = err2; err == nil {
if msg.StatusID == jdapi.OrderStatusPayFinishedSettle {
err = partner.CurOrderManager.SaveOrderFinancialInfo(orderFinancial, partner.CreatedPeration)
} else {
err = partner.CurOrderManager.SaveOrderFinancialInfo(orderFinancial, partner.UpdatedPeration)
}
}
}
} else {
err = nil
}
} else if msg.StatusID == jdapi.AfsServiceStateRefundSuccess || msg.StatusID == jdapi.AfsServiceStateReturnGoodsSuccess { // 如果是退款单
orderData, err2 := a.GetAfsService(msg.BillID)
if err = err2; err == nil {
err = partner.CurOrderManager.SaveAfsOrderFinancialInfo(CurPurchaseHandler.AfsOrderDetail2Financial(orderData))
}
}
return jdapi.Err2CallbackResponse(nil, "jd OnFinancialMsg") // todo 强制返回成功
}
// 处理京东正向订单信息
func (p *PurchaseHandler) OrderDetail2Financial(a *jdapi.API, orderData map[string]interface{}, isFromOrderDetail bool, order *model.GoodsOrder) (orderFinancial *model.OrderFinancial, err error) {
orderFinancial = &model.OrderFinancial{
VendorID: model.VendorIDJD,
VendorOrderID: utils.Int64ToStr(utils.MustInterface2Int64(orderData["orderId"])),
ReceivableFreight: utils.MustInterface2Int64(orderData["orderReceivableFreight"]),
FreightMoney: utils.MustInterface2Int64(orderData["orderFreightMoney"]),
ActualPayMoney: utils.MustInterface2Int64(orderData["orderBuyerPayableMoney"]),
DiscountMoney: utils.MustInterface2Int64(orderData["orderDiscountMoney"]),
DistanceFreightMoney: utils.MustInterface2Int64(orderData["merchantPaymentDistanceFreightMoney"]),
FreightTipsMoney: utils.MustInterface2Int64(orderData["tips"]),
PointsDeductionMoney: utils.MustInterface2Int64(orderData["platformPointsDeductionMoney"]),
// BoxMoney: utils.MustInterface2Int64(orderData["packagingMoney"]), // 京东包装(塑料袋)由京东提供,相应钱款也归京东,不记录/记录之后优化算法
}
skus := order.Skus
if skus != nil {
for _, x := range skus {
orderFinancial.ShopPriceMoney += x.ShopPrice * int64(x.Count)
}
}
if orderData["product"] != nil {
product := orderData["product"].([]interface{})
for _, x := range product {
xMap := x.(map[string]interface{})
orderSkuFinancial := &model.OrderSkuFinancial{
VendorID: orderFinancial.VendorID,
VendorOrderID: orderFinancial.VendorOrderID,
// OrderFinancialID: orderFinancial.VendorOrderID,
// ConfirmTime: utils.Str2Time(utils.Interface2String(orderData["orderStartTime"])),
VendorStoreID: utils.Interface2String(orderData["deliveryStationNo"]),
StoreID: int(utils.Str2Int64WithDefault(utils.Interface2String(orderData["deliveryStationNoIsv"]), 0)),
JxStoreID: order.JxStoreID,
VendorSkuID: utils.Int64ToStr(utils.MustInterface2Int64(xMap["skuId"])),
// SkuID: int(utils.Str2Int64(utils.Interface2String(xMap["skuIdIsv"]))),
PromotionType: int(utils.MustInterface2Int64(xMap["promotionType"])),
Name: utils.Interface2String(xMap["skuName"]),
ShopPrice: utils.MustInterface2Int64(xMap["skuStorePrice"]),
SalePrice: utils.MustInterface2Int64(xMap["skuJdPrice"]),
Count: int(utils.MustInterface2Int64(xMap["skuCount"])),
IsAfsOrder: 0,
// MealBoxMoney: utils.MustInterface2Int64(xMap["canteenMoney"]), // 京东的目前不考虑结算餐盒费,因为都归京东所有
}
// PromotionType 是一个关键数据可能某商品活动限购用户超出限购数量超出部分不享受优惠那么除了要在活动表根据skuId,活动起止日期活动城市来查询还需要判断活动类型PromotionType
// 平台/京西单条sku补贴金额应该去京西后台活动库去取活动里针对单条SKU如果京东/京西有补贴,应该有记录
// orderSkuFinancial.PmSubsidyMoneyForSku =
// orderSkuFinancial.JxSubsidyMoneyForSku =
// orderFinancial.JxSubsidyMoneyToSku += orderSkuFinancial.JxSubsidyMoneyForSku
// orderFinancial.JxSubsidyMoney += orderSkuFinancial.JxSubsidyMoneyForSku
orderFinancial.SalePriceMoney += orderSkuFinancial.SalePrice * int64(orderSkuFinancial.Count)
orderSkuFinancial.SkuID = int(utils.Str2Int64WithDefault(utils.Interface2String(xMap["skuIdIsv"]), 0))
if orderSkuFinancial.SkuID > math.MaxInt32 {
orderSkuFinancial.SkuID = orderSkuFinancial.JxSkuID
}
orderFinancial.Skus = append(orderFinancial.Skus, orderSkuFinancial)
}
}
// orderFinancial.DeliveryConfirmTime = utils.Str2TimeWithDefault(utils.Interface2String(orderData["deliveryConfirmTime"]), utils.DefaultTimeValue)
if int(utils.Str2Int64WithDefault(utils.Interface2String(orderData["deliveryCarrierNo"]), 0)) == jdapi.CarrierNoSelfDelivery {
// 如果为自配送,自配送补贴=订单初始运费,远距离费=0
orderFinancial.SelfDeliveryDiscountMoney = utils.MustInterface2Int64(orderData["orderReceivableFreight"])
orderFinancial.DistanceFreightMoney = 0
orderFinancial.FreightTipsMoney = 0
// 通过本地数据库去取是否转美团/达达,并计算运费
// wayBill, err2 := partner.CurOrderManager.LoadWaybill(orderFinancial.VendorOrderID, orderFinancial.VendorID)
// if err = err2; err == nil {
// orderFinancial.JxFreightMoney = wayBill.DesiredFee
// }
}
if orderData["discount"] != nil {
discount := orderData["discount"].([]interface{})
for _, x := range discount {
xMap := x.(map[string]interface{})
discountPrice := utils.MustInterface2Int64(xMap["discountPrice"])
discountType := int(utils.MustInterface2Int64(xMap["discountType"]))
if discountType == jdapi.FreightDiscountTypeByShop {
orderFinancial.FreightDiscountMoney = discountPrice
} else if discountType == jdapi.FreightDiscountTypeByVip || discountType == jdapi.FreightDiscountTypeByActivity {
orderFinancial.PmFreightDiscountMoney = discountPrice
} else if discountType == jdapi.FreightDiscountTypeByCoupons {
if xMap["platPayMoney"] == nil {
orderFinancial.PmFreightDiscountMoney = discountPrice
} else {
orderFinancial.PmFreightDiscountMoney = int64(utils.MustInterface2Float64(xMap["platPayMoney"]))
orderFinancial.FreightDiscountMoney = discountPrice - orderFinancial.PmFreightDiscountMoney
}
}
orderFinancial.TotalDiscountMoney += discountPrice
if xMap["orderShareRatioData"] != nil {
orderShareRatioData, _ := utils.HTTPBody2Values([]byte(utils.Interface2String(xMap["orderShareRatioData"])), false)
if promotionID := orderShareRatioData.Get("promotionId"); promotionID != "" {
activity := &model.OrderDiscountFinancial{
VendorID: orderFinancial.VendorID,
VendorOrderID: orderFinancial.VendorOrderID,
VendorActivityID: promotionID, // utils.Interface2String(orderShareRatioData["promotionId"][0]),
Type: utils.Int64ToStr(int64(discountType)),
// ActivityName: utils.Interface2String(xMap["discountName"]),
// ActivityMoney: discountPrice,
// Remark: utils.Interface2String(xMap["orderShareRatioData"]),
}
orderFinancial.Discounts = append(orderFinancial.Discounts, activity)
// 通过活动Id去取京西活动补贴
// orderFinancial.JxSubsidyMoney +=
}
}
}
// globals.SugarLogger.Debug(utils.Format4Output(orderFinancial.Discounts, false))
}
order1, err2 := a.OrderShoudSettlementService(orderFinancial.VendorOrderID)
if err = err2; err == nil {
orderFinancial.ShopMoney = utils.Interface2Int64WithDefault(order1["settlementAmount"], 0)
orderFinancial.PmMoney += utils.Interface2Int64WithDefault(order1["goodsCommission"], 0)
orderFinancial.PmMoney += utils.Interface2Int64WithDefault(order1["freightCommission"], 0)
orderFinancial.PmMoney += utils.Interface2Int64WithDefault(order1["packageCommission"], 0)
orderFinancial.PmMoney += utils.Interface2Int64WithDefault(order1["guaranteedCommission"], 0)
orderFinancial.PmSkuSubsidyMoney = utils.Interface2Int64WithDefault(order1["platSkuGoodsDiscountMoney"], 0)
orderFinancial.PmSubsidyMoney = utils.Interface2Int64WithDefault(order1["platOrderGoodsDiscountMoney"], 0) + orderFinancial.PmSkuSubsidyMoney
}
return orderFinancial, err
}
// 处理京东售后订单结账信息
func (p *PurchaseHandler) AfsOrderDetail2Financial(orderData map[string]interface{}) (afsOrder *model.AfsOrder) {
afsOrder = &model.AfsOrder{
VendorID: model.VendorIDJD,
AfsOrderID: utils.Interface2String(orderData["afsServiceOrder"]),
VendorOrderID: utils.Interface2String(orderData["orderId"]),
VendorStoreID: utils.Interface2String(orderData["stationId"]),
StoreID: int(utils.Str2Int64WithDefault(utils.Interface2String(orderData["stationNumOutSystem"]), 0)),
AfsCreatedAt: utils.Timestamp2Time(utils.MustInterface2Int64(orderData["updateTime"].(map[string]interface{})["time"]) / 1000),
FreightUserMoney: utils.MustInterface2Int64(orderData["orderFreightMoney"]),
AfsFreightMoney: utils.MustInterface2Int64(orderData["afsFreight"]),
BoxMoney: utils.MustInterface2Int64(orderData["packagingMoney"]),
TongchengFreightMoney: utils.MustInterface2Int64(orderData["tongchengFreightMoney"]),
SkuBoxMoney: utils.MustInterface2Int64(orderData["mealBoxMoney"]),
VendorOrgCode: utils.Interface2String(orderData["venderId"]),
}
order, err := partner.CurOrderManager.LoadOrder(afsOrder.VendorOrderID, afsOrder.VendorID)
if err == nil {
afsOrder.JxStoreID = order.JxStoreID
} else {
globals.SugarLogger.Warnf("jd AfsOrderDetail2Financial, afsOrderID:%s is not found from partner.CurOrderManager.LoadOrder", afsOrder.VendorOrderID)
}
if orderData["afsDetailList"] != nil {
refundDetail := orderData["afsDetailList"].([]interface{})
for _, x := range refundDetail {
xMap := x.(map[string]interface{})
orderSku := &model.OrderSkuFinancial{
VendorID: model.VendorIDJD,
AfsOrderID: afsOrder.AfsOrderID,
VendorOrderID: afsOrder.VendorOrderID,
VendorStoreID: afsOrder.VendorStoreID,
StoreID: afsOrder.StoreID,
// ConfirmTime: afsOrder.AfsCreateAt,
VendorSkuID: utils.Int64ToStr(utils.MustInterface2Int64(xMap["wareId"])),
SkuID: int(utils.Str2Int64WithDefault(utils.Interface2String(xMap["skuIdIsv"]), 0)),
Name: utils.Interface2String(xMap["wareName"]),
UserMoney: utils.MustInterface2Int64(xMap["afsMoney"]),
PmSkuSubsidyMoney: utils.MustInterface2Int64(xMap["platPayMoney"]),
IsAfsOrder: 1,
}
afsOrder.PmSkuSubsidyMoney += orderSku.PmSkuSubsidyMoney
orderSku.PmSubsidyMoney += orderSku.PmSkuSubsidyMoney
if xMap["afsSkuDiscountList"] != nil {
afsSkuDiscountList := xMap["afsSkuDiscountList"].([]interface{})
for _, y := range afsSkuDiscountList {
orderSku.PmSubsidyMoney += utils.MustInterface2Int64(y.(map[string]interface{})["platPayMoney"])
}
}
afsOrder.SkuUserMoney += orderSku.UserMoney
afsOrder.PmSubsidyMoney += orderSku.PmSubsidyMoney
afsOrder.Skus = append(afsOrder.Skus, orderSku)
}
if len(refundDetail) <= 0 {
globals.SugarLogger.Warnf("jd AfsOrderDetail2Financial, orderID:%s have no refund_detail", afsOrder.VendorOrderID)
}
} else {
globals.SugarLogger.Warnf("jd AfsOrderDetail2Financial, orderID:% refund_detail is nil", afsOrder.VendorOrderID)
}
return afsOrder
}
func (p *PurchaseHandler) OnOrderDetail(a *jdapi.API, orderDetail map[string]interface{}, peration string) (err error) {
order, err := partner.CurOrderManager.LoadOrder(utils.Int64ToStr(utils.MustInterface2Int64(orderDetail["orderId"])), model.VendorIDJD)
if err == nil {
orderFinancial, err2 := CurPurchaseHandler.OrderDetail2Financial(a, orderDetail, true, order)
if err = err2; err == nil {
err = partner.CurOrderManager.SaveOrderFinancialInfo(orderFinancial, peration)
}
}
return err
}

View File

@@ -1,17 +0,0 @@
package jd
import (
"fmt"
"testing"
"git.rosy.net.cn/baseapi/platformapi/jdapi"
)
func TestOnFinancialMsg(t *testing.T) {
msg := &jdapi.CallbackOrderMsg{
BillID: "907315020000322",
StatusID: "330902",
}
res := CurPurchaseHandler.onFinancialMsg(msg)
fmt.Println(res)
}

View File

@@ -1,86 +0,0 @@
package jd
import (
"git.rosy.net.cn/baseapi/platformapi/jdapi"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
)
type PurchaseHandler struct {
partner.BasePurchasePlatform
}
var (
CurPurchaseHandler *PurchaseHandler
)
func init() {
globals.SugarLogger.Debug("init jd")
CurPurchaseHandler = new(PurchaseHandler)
partner.RegisterPurchasePlatform(CurPurchaseHandler)
}
func getAPI(appOrgCode string) (apiObj *jdapi.API) {
if appOrgCode == "" {
globals.SugarLogger.Warnf("getAPI appOrgCode is empty")
}
return partner.CurAPIManager.GetAPI(model.VendorIDJD, appOrgCode).(*jdapi.API)
}
func GetAPI(appOrgCode string) (apiObj *jdapi.API) {
return getAPI(appOrgCode)
}
func AppKey2OrgCode(appKey string) (vendorOrgCode string) {
apiList := partner.CurAPIManager.GetAppOrgCodeList(model.VendorIDJD)
for _, v := range apiList {
jdAPI := partner.CurAPIManager.GetAPI(model.VendorIDJD, v).(*jdapi.API)
if jdAPI.GetAppKey() == appKey {
vendorOrgCode = v
break
}
}
if vendorOrgCode == "" {
globals.SugarLogger.Warnf("AppKey2OrgCode appKey:%s get empty vendorOrgCode", appKey)
}
return vendorOrgCode
}
func (c *PurchaseHandler) GetVendorID() int {
return model.VendorIDJD
}
func JdOperationTime2JxOperationTime(value1 int) int16 {
value := int16(value1)
return (value/2)*100 + (value%2)*30
}
func JxOperationTime2JdOperationTime(value int16) int16 {
return (value/100)*2 + (value%100)/30
}
func JdStoreStatus2JxStatus(yn, closeStatus int) int {
if yn == 1 {
return model.StoreStatusDisabled
} else if closeStatus == 1 {
return model.StoreStatusClosed
}
return model.StoreStatusOpened
}
func JxStoreStatus2JdStatus(status int) (yn, closeStatus int) {
switch status {
case model.StoreStatusDisabled:
return 1, 1
case model.StoreStatusHaveRest, model.StoreStatusClosed:
return 0, 1
default:
return 0, 0
}
}
func (p *PurchaseHandler) UploadImg(ctx *jxcontext.Context, vendorOrgCode, imgURL string, imgData []byte, imgName string, imgType int) (imgHint string, err error) {
return imgHint, err
}

View File

@@ -1,11 +0,0 @@
package jd
import (
_ "git.rosy.net.cn/jx-callback/globals/api/apimanager"
"git.rosy.net.cn/jx-callback/globals/testinit"
)
func init() {
testinit.Init()
}

View File

@@ -1 +0,0 @@
package jd

View File

@@ -1,617 +0,0 @@
package jd
import (
"fmt"
"regexp"
"strings"
"time"
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/baseapi/platformapi/autonavi"
"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/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
var (
VendorStatus2StatusMap = map[string]int{
jdapi.OrderStatusPurchased: model.OrderStatusNew,
jdapi.OrderStatusWaitOutStore: model.OrderStatusAccepted,
jdapi.StatusIDWaitOutStore: model.OrderStatusAccepted,
jdapi.OrderStatusFinishedPickup: model.OrderStatusFinishedPickup,
jdapi.OrderStatusDelivering: model.OrderStatusDelivering,
jdapi.OrderStatusDelivered: model.OrderStatusFinished,
jdapi.OrderStatusFinished: model.OrderStatusFinished, // todo 这个状态不是真正都完成的意思?
jdapi.OrderStatusCanceled: model.OrderStatusCanceled,
jdapi.OrderStatusAdjust: model.OrderStatusAdjust,
jdapi.OrderStatusUserApplyCancel: model.OrderStatusApplyCancel,
jdapi.OrderStatusLocked: model.OrderStatusLocked,
jdapi.OrderStatusUnlocked: model.OrderStatusUnlocked,
jdapi.OrderStatusVenderAgreeCancel: model.OrderStatusVendorAgreeCancel,
jdapi.OrderStatusVenderRejectCancel: model.OrderStatusVendorRejectCancel,
jdapi.CallbackMsgOrderAddTips: model.OrderStatusWaybillTipChanged,
}
deliveryTypeMap = map[int]string{
jdapi.CarrierNoCrowdSourcing: model.OrderDeliveryTypePlatform,
jdapi.CarrierNoSelfDelivery: model.OrderDeliveryTypeStoreSelf,
jdapi.CarrierNoSelfTake: model.OrderDeliveryTypeSelfTake,
}
selfTakeCodeReg = regexp.MustCompile(`等待用户凭提货码(\d+)于`)
afsMsgMap = map[string]bool{
jdapi.CallbackMsgNewApplyAfterSaleBill: true,
jdapi.CallbackMsgUpdateApplyAfterSaleBill: true,
jdapi.CallbackMsgNewAfterSaleBill: true,
jdapi.CallbackMsgAfterSaleBillStatus: true,
}
)
func (c *PurchaseHandler) OnOrderMsg(vendorOrgCode string, msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
jxutils.CallMsgHandler(func() {
retVal = c.onOrderMsg(vendorOrgCode, msg)
}, jxutils.ComposeUniversalOrderID(msg.BillID, model.VendorIDJD))
return retVal
}
func (c *PurchaseHandler) updateOrderFinancialInfo(a *jdapi.API, orderID string) (err error) {
order := &model.GoodsOrder{
VendorOrderID: orderID,
VendorID: model.VendorIDJD,
}
orderSettlement, err := a.OrderShoudSettlementService2(orderID)
if err == nil {
if orderSettlement != nil {
updateOrderBySettleMent(order, orderSettlement)
globals.SugarLogger.Debugf("updateOrderBySettleMent: %v , %v", order.NewEarningPrice, order.TotalShopMoney)
err = partner.CurOrderManager.UpdateOrderFields(order, []string{ /*"WaybillTipMoney", */ "TotalShopMoney", "PmSubsidyMoney", "NewEarningPrice"})
}
}
return err
}
func (c *PurchaseHandler) onOrderMsg(vendorOrgCode string, msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
a := getAPI(vendorOrgCode)
if afsMsgMap[msg.MsgURL] {
retVal = c.OnAfsOrderMsg(a, msg)
} else {
status := c.callbackMsg2Status(msg)
if jdapi.StatusIDNewOrder == msg.StatusID {
status.Status = model.OrderStatusNew // 因为京东将事件32000与状态32000混用事件32000可能是新订单也可能是已接单统一当成新订单处理
}
if partner.CurOrderManager.GetStatusDuplicatedCount(status) > 0 {
return nil
}
if msg.MsgURL == jdapi.CallbackMsgOrderAccounting {
retVal = c.OnFinancialMsg(msg)
retVal = jdapi.Err2CallbackResponse(c.updateOrderFinancialInfo(a, msg.BillID), status.VendorStatus)
} else {
// 新订单事件,与订单状态有点冲突
if jdapi.StatusIDNewOrder == msg.StatusID {
retVal = c.onOrderNew(a, msg, status)
} else if jdapi.OrderStatusAdjust == msg.StatusID {
retVal = c.onOrderAdjust(a, msg, status)
} else {
if msg.StatusID == jdapi.OrderStatusAddComment || msg.StatusID == jdapi.OrderStatusModifyComment {
utils.CallFuncAsync(func() {
c.onOrderComment2(a, msg)
})
}
// if msg.StatusID == jdapi.OrderStatusVenderAgreeCancel {
// order := &model.GoodsOrder{
// VendorOrgCode: vendorOrgCode,
// VendorOrderID: msg.BillID,
// }
// err2 := c.PickupGoods(order, false, jxcontext.AdminCtx.GetUserName())
// if err2 != nil {
// globals.SugarLogger.Warnf("京东取消拣货:%v", err2)
// }
// }
err := partner.CurOrderManager.OnOrderStatusChanged(vendorOrgCode, status)
retVal = jdapi.Err2CallbackResponse(err, status.VendorStatus)
}
}
}
return retVal
}
func (c *PurchaseHandler) OnOrderInfoChangeMsg(vendorOrgCode string, msg *jdapi.CallbackOrderInfoChangeMsg) (retVal *jdapi.CallbackResponse) {
jxutils.CallMsgHandler(func() {
retVal = c.onOrderInfoChangeMsg(vendorOrgCode, msg)
}, jxutils.ComposeUniversalOrderID(msg.BillID, model.VendorIDJD))
return retVal
}
func (c *PurchaseHandler) onOrderInfoChangeMsg(vendorOrgCode string, msg *jdapi.CallbackOrderInfoChangeMsg) (retVal *jdapi.CallbackResponse) {
db := dao.GetDB()
order, err := dao.GetSimpleOrder(db, msg.BillID)
if err == nil {
globals.SugarLogger.Debugf("onOrderInfoChangeMsg msg:%v", utils.Format4Output(msg, false))
if msg.BuyerFullAddress != "" {
order.ConsigneeAddress = msg.BuyerFullAddress
}
if msg.BuyerFullName != "" {
order.ConsigneeName = msg.BuyerFullName
}
if msg.BuyerMobile != "" {
order.ConsigneeMobile = msg.BuyerMobile
}
if msg.BuyerLat != "" {
order.ConsigneeLat = jxutils.StandardCoordinate2Int(utils.Str2Float64(msg.BuyerLat))
}
if msg.BuyerLng != "" {
order.ConsigneeLng = jxutils.StandardCoordinate2Int(utils.Str2Float64(msg.BuyerLng))
}
if msg.OrderBuyerRemark != "" {
order.BuyerComment = msg.OrderBuyerRemark
}
_, err = dao.UpdateEntity(db, order, "ConsigneeAddress", "ConsigneeName", "ConsigneeMobile", "ConsigneeLat", "ConsigneeLng", "BuyerComment")
weixinmsg.NotifyOrderChanged(order)
}
return jdapi.SuccessResponse
}
func updateOrderBySettleMent(order *model.GoodsOrder, orderSettlement *jdapi.OrderSettlementInfo) {
if orderSettlement != nil {
order.TotalShopMoney = orderSettlement.SettlementAmount
order.PmSubsidyMoney = orderSettlement.PlatOrderGoodsDiscountMoney + orderSettlement.PlatSkuGoodsDiscountMoney
if order.TotalShopMoney > 0 {
if jxutils.GetSaleStoreIDFromOrder(order) != 0 {
storeDetail, err := partner.CurOrderManager.LoadStoreDetail(jxutils.GetSaleStoreIDFromOrder(order), order.VendorID)
if storeDetail != nil && err == nil {
jxutils.RefreshOrderEarningPrice2(order, storeDetail.PayPercentage)
}
} else {
order2, err := partner.CurOrderManager.LoadOrder(order.VendorOrderID, order.VendorID)
if order2 != nil && err == nil {
storeDetail, err := partner.CurOrderManager.LoadStoreDetail(jxutils.GetSaleStoreIDFromOrder(order2), order.VendorID)
if storeDetail != nil && err == nil {
jxutils.RefreshOrderEarningPrice2(order, storeDetail.PayPercentage)
}
}
}
} else {
order.NewEarningPrice = order.EarningPrice
}
}
}
func (c *PurchaseHandler) getOrder(a *jdapi.API, orderID string) (order *model.GoodsOrder, orderMap map[string]interface{}, err error) {
globals.SugarLogger.Debugf("jd getOrder orderID:%s", orderID)
var (
realMobile string
orderSettlement *jdapi.OrderSettlementInfo
)
task := tasksch.NewParallelTask("jd getOrder", tasksch.NewParallelConfig().SetIsContinueWhenError(true), jxcontext.AdminCtx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
taskIndex := batchItemList[0].(int)
switch taskIndex {
case 0:
orderMap, err = a.QuerySingleOrder(orderID)
if err == nil {
order = c.Map2Order(orderMap)
realMobile, _ = a.GetRealMobile4Order(orderID, order.VendorStoreID)
if realMobile != "" {
order.ConsigneeMobile2 = jxutils.FormalizeMobile(realMobile)
}
}
case 1:
orderSettlement, _ = a.OrderShoudSettlementService2(orderID)
}
return nil, err
}, []int{0, 1})
task.Run()
_, err = task.GetResult(0)
if order != nil && orderSettlement != nil {
updateOrderBySettleMent(order, orderSettlement)
err = partner.CurOrderManager.UpdateOrderFields(order, []string{"NewEarningPrice"})
}
return order, orderMap, err
}
func (c *PurchaseHandler) GetOrder(vendorOrgCode, orderID string) (order *model.GoodsOrder, err error) {
order, _, err = c.getOrder(getAPI(vendorOrgCode), orderID)
return order, err
}
func (p *PurchaseHandler) GetOrderStatus(vendorOrgCode, vendorOrderID string) (status int, err error) {
order, err := getAPI(vendorOrgCode).QuerySingleOrder2(vendorOrderID)
if err == nil {
status = getStatusFromVendorStatus(utils.Int2Str(order.OrderStatus))
}
return status, err
}
func (c *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *model.GoodsOrder) {
return Map2Order(orderData)
}
func Map2Order(orderData map[string]interface{}) (order *model.GoodsOrder) {
result := orderData
orderID := utils.Int64ToStr(utils.MustInterface2Int64(result["orderId"]))
globals.SugarLogger.Debugf("jd Map2Order orderID:%s", orderID)
const defaultStatusTimeField = "orderPurchaseTime"
statusTimeField := defaultStatusTimeField
if result[statusTimeField] == nil { // 814560888003021 orderPurchaseTime为空
statusTimeField = "orderStartTime"
}
order = &model.GoodsOrder{
VendorOrderID: orderID,
VendorID: model.VendorIDJD,
VendorStoreID: utils.Interface2String(result["produceStationNo"]),
StoreID: int(utils.Str2Int64WithDefault(utils.Interface2String(result["produceStationNoIsv"]), 0)),
StoreName: utils.Interface2String(result["produceStationName"]),
VendorUserID: utils.Interface2String(result["buyerPin"]),
ConsigneeName: utils.Interface2String(result["buyerFullName"]),
ConsigneeMobile: jxutils.FormalizeMobile(utils.Interface2String(result["buyerMobile"])),
ConsigneeAddress: utils.Interface2String(result["buyerFullAddress"]),
CoordinateType: model.CoordinateTypeMars,
BuyerComment: utils.TrimBlankChar(utils.Interface2String(result["orderBuyerRemark"])),
ExpectedDeliveredTime: utils.Str2TimeWithDefault(utils.Interface2String(result["orderPreEndDeliveryTime"]), utils.DefaultTimeValue),
PickDeadline: utils.Str2TimeWithDefault(utils.Interface2String(result["pickDeadline"]), utils.DefaultTimeValue), // 813951615000022 pickDeadline为空
VendorStatus: utils.Int64ToStr(utils.MustInterface2Int64(result["orderStatus"])),
OrderSeq: int(utils.MustInterface2Int64(result["orderNum"])),
StatusTime: utils.Str2Time(result[statusTimeField].(string)),
OrderCreatedAt: utils.Str2Time(result[statusTimeField].(string)),
// OrderFinishedAt: utils.Str2Time(result["orderStatusTime"].(string)),
OriginalData: string(utils.MustMarshal(result)),
ActualPayPrice: utils.MustInterface2Int64(result["orderBuyerPayableMoney"]),
BaseFreightMoney: utils.Interface2Int64WithDefault(result["orderBaseFreightMoney"], 0),
DistanceFreightMoney: utils.Interface2Int64WithDefault(result["merchantPaymentDistanceFreightMoney"], 0),
DeliveryType: deliveryTypeMap[int(utils.Str2Int64WithDefault(utils.Interface2String(result["deliveryCarrierNo"]), 0))],
VendorOrgCode: utils.Interface2String(result["orgCode"]),
}
if orderInvoice, ok := result["orderInvoice"].(map[string]interface{}); ok && orderInvoice != nil {
order.InvoiceTitle = utils.Interface2String(orderInvoice["invoiceTitle"])
order.InvoiceTaxerID = utils.Interface2String(orderInvoice["invoiceDutyNo"])
order.InvoiceEmail = utils.Interface2String(orderInvoice["invoiceMail"])
}
order.Status = getStatusFromVendorStatus(order.VendorStatus)
businessTage := utils.Interface2String(result["businessTag"])
if strings.Index(businessTage, "dj_aging_immediately") >= 0 {
order.BusinessType = model.BusinessTypeImmediate
} else {
order.BusinessType = model.BusinessTypeDingshida
}
coordinateType := utils.Interface2Int64WithDefault(result["buyerCoordType"], 1)
originalLng := utils.MustInterface2Float64(result["buyerLng"])
originalLat := utils.MustInterface2Float64(result["buyerLat"])
if coordinateType == 1 {
lng, lat, err2 := api.AutonaviAPI.CoordinateConvert(originalLng, originalLat, autonavi.CoordSysGPS)
if err2 == nil {
originalLng = lng
originalLat = lat
} else {
// 如果没有转成功,保留原始数据
order.CoordinateType = model.CoordinateTypeGPS
}
}
order.ConsigneeLng = jxutils.StandardCoordinate2Int(originalLng)
order.ConsigneeLat = jxutils.StandardCoordinate2Int(originalLat)
discounts, _ := result["discount"].([]interface{})
for _, v := range discounts {
discount := v.(map[string]interface{})
order.DiscountMoney += utils.Interface2Int64WithDefault(discount["discountPrice"], 0)
}
for _, product2 := range result["product"].([]interface{}) {
product := product2.(map[string]interface{})
sku := &model.OrderSku{
VendorOrderID: orderID,
VendorID: model.VendorIDJD,
Count: int(utils.MustInterface2Int64(product["skuCount"])),
SkuID: int(utils.Str2Int64WithDefault(utils.Interface2String(product["skuIdIsv"]), 0)),
VendorSkuID: utils.Int64ToStr(utils.MustInterface2Int64(product["skuId"])),
SkuName: product["skuName"].(string),
Weight: jxutils.FloatWeight2Int(float32(utils.MustInterface2Float64(product["skuWeight"]))),
VendorPrice: utils.MustInterface2Int64(product["skuStorePrice"]),
SalePrice: utils.MustInterface2Int64(product["skuJdPrice"]),
}
if jdPromotionType := int(utils.MustInterface2Int64(product["promotionType"])); jdPromotionType != 0 && jdPromotionType != jdapi.PromotionTypeNormal {
sku.StoreSubName = utils.Int2Str(jdPromotionType)
}
if skuCostumeProperty, ok := product["skuCostumeProperty"]; ok {
sku.SkuName += skuCostumeProperty.(string)
}
if isGift, ok := product["isGift"].(bool); ok && isGift {
sku.SkuType = 1
}
order.Skus = append(order.Skus, sku)
}
jxutils.RefreshOrderSkuRelated(order)
return order
}
//
func (c *PurchaseHandler) onOrderNew(a *jdapi.API, msg *jdapi.CallbackOrderMsg, orderStatus *model.OrderStatus) (response *jdapi.CallbackResponse) {
globals.SugarLogger.Debugf("onOrderNew orderID:%s", msg.BillID)
order, orderMap, err := c.getOrder(a, msg.BillID)
if err == nil {
globals.SugarLogger.Debugf("onOrderNew2 orderID:%s", msg.BillID)
if err = partner.CurOrderManager.OnOrderNew(order, orderStatus); err == nil {
utils.CallFuncAsync(func() {
c.OnOrderDetail(a, orderMap, partner.CreatedPeration)
})
}
}
return jdapi.Err2CallbackResponse(err, "jd onOrderNew")
}
func (c *PurchaseHandler) onOrderAdjust(a *jdapi.API, msg *jdapi.CallbackOrderMsg, orderStatus *model.OrderStatus) *jdapi.CallbackResponse {
order, orderMap, err := c.getOrder(a, msg.BillID)
if err == nil {
err = partner.CurOrderManager.OnOrderAdjust(order, orderStatus)
if err == nil {
utils.CallFuncAsync(func() {
c.OnOrderDetail(a, orderMap, partner.UpdatedPeration)
})
}
}
return jdapi.Err2CallbackResponse(err, "jd onOrderAdjust")
}
func (c *PurchaseHandler) callbackMsg2Status(msg *jdapi.CallbackOrderMsg) *model.OrderStatus {
orderStatus := &model.OrderStatus{
VendorOrderID: msg.BillID,
VendorID: model.VendorIDJD,
OrderType: model.OrderTypeOrder,
RefVendorOrderID: msg.BillID,
RefVendorID: model.VendorIDJD,
VendorStatus: msg.StatusID,
StatusTime: utils.Str2Time(msg.Timestamp),
Remark: msg.Remark,
}
if msg.MsgURL == jdapi.CallbackMsgOrderAddTips {
orderStatus.VendorStatus = jdapi.CallbackMsgOrderAddTips
}
orderStatus.Status = getStatusFromVendorStatus(orderStatus.VendorStatus)
return orderStatus
}
func (c *PurchaseHandler) postFakeMsg(vendorOrgCode, vendorOrderID, vendorStatus string) {
msg := &jdapi.CallbackOrderMsg{
CallbackMsg: &jdapi.CallbackMsg{
AppKey: getAPI(vendorOrgCode).GetAppKey(),
},
BillID: vendorOrderID,
StatusID: vendorStatus,
Timestamp: utils.Time2Str(time.Now()),
}
utils.CallFuncAsync(func() {
OnOrderMsg(msg)
})
}
// IPurchasePlatformHandler
func getStatusFromVendorStatus(vendorStatus string) int {
if status, ok := VendorStatus2StatusMap[vendorStatus]; ok {
return status
}
return model.OrderStatusUnknown
}
func (c *PurchaseHandler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) {
globals.SugarLogger.Debugf("jd AcceptOrRefuseOrder orderID:%s, isAcceptIt:%t", order.VendorOrderID, isAcceptIt)
if globals.EnableJdStoreWrite {
err = getAPI(order.VendorOrgCode).OrderAcceptOperate(order.VendorOrderID, isAcceptIt, userName)
if isAcceptIt && err == nil {
c.postFakeMsg(order.VendorOrgCode, order.VendorOrderID, jdapi.StatusIDWaitOutStore)
}
} else {
if isAcceptIt {
c.postFakeMsg(order.VendorOrgCode, order.VendorOrderID, jdapi.StatusIDWaitOutStore)
} else {
c.postFakeMsg(order.VendorOrgCode, order.VendorOrderID, jdapi.OrderStatusCanceled)
}
}
return err
}
func (c *PurchaseHandler) PickupGoods(order *model.GoodsOrder, isSelfDelivery bool, userName string) (err error) {
globals.SugarLogger.Debugf("jd PickupGoods orderID:%s, isSelfDelivery:%t", order.VendorOrderID, isSelfDelivery)
if !isSelfDelivery && globals.EnableJdStoreWrite {
_, err = getAPI(order.VendorOrgCode).OrderJDZBDelivery(order.VendorOrderID, userName)
} else {
c.postFakeMsg(order.VendorOrgCode, order.VendorOrderID, jdapi.OrderStatusFinishedPickup)
}
if err == nil {
orderSettlement, _ := getAPI(order.VendorOrgCode).OrderShoudSettlementService2(order.VendorOrderID)
updateOrderBySettleMent(order, orderSettlement)
globals.SugarLogger.Debugf("jd PickupGoods, %v", order.NewEarningPrice)
err = partner.CurOrderManager.UpdateOrderFields(order, []string{"NewEarningPrice"})
}
return err
}
func (p *PurchaseHandler) AcceptOrRefuseFailedGetOrder(ctx *jxcontext.Context, order *model.GoodsOrder, isAcceptIt bool) (err error) {
if globals.EnableJdStoreWrite {
err = getAPI(order.VendorOrgCode).ReceiveFailedAudit(order.VendorOrderID, isAcceptIt, ctx.GetUserName(), "")
}
return err
}
func (p *PurchaseHandler) CallCourier(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 拣货失败后再次招唤平台配送
if globals.EnableJdStoreWrite {
err = getAPI(order.VendorOrgCode).UrgeDispatching(order.VendorOrderID, ctx.GetUserName())
}
return err
}
func (p *PurchaseHandler) ConfirmReceiveGoods(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 投递失败后确认收到退货
if globals.EnableJdStoreWrite {
err = getAPI(order.VendorOrgCode).ConfirmReceiveGoods(order.VendorOrderID)
}
return err
}
func (c *PurchaseHandler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) {
globals.SugarLogger.Debugf("jd Swtich2SelfDeliver orderID:%s", order.VendorOrderID)
if globals.EnableJdStoreWrite {
_, err = getAPI(order.VendorOrgCode).ModifySellerDelivery(order.VendorOrderID, userName)
if err != nil {
if errWithCode, ok := err.(*utils.ErrorWithCode); ok && errWithCode.Level() == 1 {
globals.SugarLogger.Infof("Swtich2SelfDeliver failed with error:%v try get current status", err)
if order2, err2 := c.GetOrder(order.VendorOrgCode, order.VendorOrderID); err2 == nil {
var mapData map[string]interface{}
if err2 = utils.UnmarshalUseNumber([]byte(order2.OriginalData), &mapData); err2 == nil {
if utils.Interface2String(mapData["deliveryCarrierNo"]) == "2938" { // 当前已经是自送状态了
err = nil
}
}
}
}
}
}
return err
}
func (c *PurchaseHandler) Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) {
globals.SugarLogger.Debugf("jd Swtich2SelfDelivered orderID:%s", order.VendorOrderID)
if globals.EnableJdStoreWrite {
_, err = getAPI(order.VendorOrgCode).DeliveryEndOrder(order.VendorOrderID, userName)
}
return err
}
func (c *PurchaseHandler) SelfDeliverDelivering(order *model.GoodsOrder, userName string) (err error) {
globals.SugarLogger.Debugf("jd SelfDeliverDelivering orderID:%s", order.VendorOrderID)
if globals.EnableJdStoreWrite {
_, err = getAPI(order.VendorOrgCode).OrderSerllerDelivery(order.VendorOrderID, userName)
}
return err
}
// 京东送达接口都是一样的
func (c *PurchaseHandler) SelfDeliverDelivered(order *model.GoodsOrder, userName string) (err error) {
globals.SugarLogger.Debugf("jd SelfDeliverDelivered orderID:%s", order.VendorOrderID)
if globals.EnableJdStoreWrite {
err = c.Swtich2SelfDelivered(order, userName)
}
return err
}
func (c *PurchaseHandler) GetOrderRealMobile(ctx *jxcontext.Context, order *model.GoodsOrder) (mobile string, err error) {
mobile, err = getAPI(order.VendorOrgCode).GetRealMobile4Order(order.VendorOrderID, order.VendorStoreID)
return mobile, err
}
func (c *PurchaseHandler) AgreeOrRefuseCancel(ctx *jxcontext.Context, order *model.GoodsOrder, isAgree bool, reason string) (err error) {
if globals.EnableJdStoreWrite {
err = getAPI(order.VendorOrgCode).OrderCancelOperate(order.VendorOrderID, isAgree, ctx.GetUserName(), reason)
}
return err
}
func (c *PurchaseHandler) CancelOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
if globals.EnableJdStoreWrite {
err1 := c.Swtich2SelfDeliver(order, ctx.GetUserName())
if err = getAPI(order.VendorOrgCode).CancelAndRefund(order.VendorOrderID, ctx.GetUserName(), reason); err != nil {
if err1 != nil {
err = fmt.Errorf("取消订单失败,京东取消订单是要先转为自送再处理,转自送失败:%v", err1)
}
}
}
return err
}
func (c *PurchaseHandler) AdjustOrder(ctx *jxcontext.Context, order *model.GoodsOrder, removedSkuList []*model.OrderSku, reason string) (err error) {
order = jxutils.RemoveSkuFromOrder(order, removedSkuList)
var oaosAdjustDTOList []*jdapi.OAOSAdjustDTO
dtoMap := make(map[int]*jdapi.OAOSAdjustDTO)
for _, sku := range order.Skus {
skuID := jxutils.GetSkuIDFromOrderSku(sku)
if dtoMap[skuID] == nil {
dtoMap[skuID] = &jdapi.OAOSAdjustDTO{
OutSkuID: utils.Int2Str(skuID),
SkuCount: sku.Count,
}
oaosAdjustDTOList = append(oaosAdjustDTOList, dtoMap[skuID])
} else {
dtoMap[skuID].SkuCount += sku.Count
}
}
if globals.EnableJdStoreWrite {
err = getAPI(order.VendorOrgCode).AdjustOrder(order.VendorOrderID, ctx.GetUserName(), reason, oaosAdjustDTOList)
}
return err
}
func (c *PurchaseHandler) ListOrders(ctx *jxcontext.Context, vendorOrgCode string, parentTask tasksch.ITask, queryDate time.Time, vendorStoreID string) (vendorOrderIDs []string, err error) {
if utils.IsTimeZero(queryDate) {
return nil, fmt.Errorf("queryDate必须指定")
}
fromDate := utils.Time2Date(queryDate)
toDate := fromDate.Add(24*time.Hour - 1)
queryParam := &jdapi.OrderQueryParam{
OrderPurchaseTimeBegin: utils.Time2Str(fromDate),
OrderPurchaseTimeEnd: utils.Time2Str(toDate),
PageNo: jdapi.AllPage,
}
if vendorStoreID != "" {
queryParam.DeliveryStationNo = vendorStoreID
}
orderList, _, err := getAPI(vendorOrgCode).OrderQuery2(queryParam)
if err == nil {
vendorOrderIDs = make([]string, len(orderList))
for k, v := range orderList {
vendorOrderIDs[k] = utils.Int64ToStr(v.OrderID)
}
}
return vendorOrderIDs, err
}
func (c *PurchaseHandler) GetWaybillTip(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID, vendorOrderID, vendorWaybillID, vendorWaybillID2 string) (tipFee int64, err error) {
orderInfo, err := getAPI(vendorOrgCode).QuerySingleOrder2(vendorOrderID)
if err == nil {
tipFee = int64(orderInfo.Tips)
}
return tipFee, err
}
func (c *PurchaseHandler) UpdateWaybillTip(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID, vendorOrderID, vendorWaybillID, vendorWaybillID2, cityCode string, tipFee int64) (err error) {
curTipFee, err := c.GetWaybillTip(ctx, vendorOrgCode, vendorStoreID, vendorOrderID, vendorWaybillID, vendorWaybillID2)
if err == nil {
if tipFee2Add := tipFee - curTipFee; tipFee2Add > 0 {
if globals.EnableJdStoreWrite {
err = getAPI(vendorOrgCode).OrderAddTips(vendorOrderID, int(tipFee2Add), ctx.GetUserName())
}
}
}
return err
}
func (c *PurchaseHandler) GetSelfTakeCode(ctx *jxcontext.Context, order *model.GoodsOrder) (selfTakeCode string, err error) {
orderTrackList, err := getAPI(order.VendorOrgCode).GetByOrderNoForOaos(order.VendorOrderID)
if err == nil {
for _, v := range orderTrackList {
if v.TagCode == 180 {
searchResult := selfTakeCodeReg.FindStringSubmatch(v.MsgContent)
if searchResult != nil && len(searchResult[1]) > 0 {
selfTakeCode = searchResult[1]
}
break
}
}
}
return selfTakeCode, err
}
func (c *PurchaseHandler) ConfirmSelfTake(ctx *jxcontext.Context, order *model.GoodsOrder, selfTakeCode string) (err error) {
if globals.EnableJdStoreWrite {
err = getAPI(order.VendorOrgCode).CheckSelfPickCode(selfTakeCode, order.VendorOrderID, ctx.GetUserName())
}
return err
}

View File

@@ -1,225 +0,0 @@
package jd
import (
"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/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
)
var (
AfsVendorStatus2StatusMap = map[string]int{
jdapi.AfsServiceStateWaiting4Audit: model.AfsOrderStatusWait4Approve, // 需要审核
jdapi.AfsServiceStateWaiting4CSFeedback: model.AfsOrderStatusNew,
jdapi.AfsServiceStateRefundProcessing: model.AfsOrderStatusNew,
jdapi.AfsServiceStateWaiting4DirectCompensate: model.AfsOrderStatusNew,
jdapi.AfsServiceStateWaiting4ReturnGoods: model.AfsOrderStatusNew,
jdapi.AfsServiceStateWaiting4MerchantReceiveGoods: model.AfsOrderStatusWait4ReceiveGoods,
jdapi.AfsServiceStateRefundSuccess: model.AfsOrderStatusFinished,
jdapi.AfsServiceStateSolved: model.AfsOrderStatusFinished,
jdapi.AfsServiceStateDirectCompensateSuccess: model.AfsOrderStatusFinished,
jdapi.AfsServiceStateReturnGoodsSuccess: model.AfsOrderStatusFinished,
jdapi.AfsServiceStateRefundFailed: model.AfsOrderStatusFailed,
jdapi.AfsServiceStateAuditRefused: model.AfsOrderStatusFailed,
jdapi.AfsServiceStateUserCanceled: model.AfsOrderStatusFailed,
jdapi.AfsServiceStateMerchantFailedReceiveGoods: model.AfsOrderStatusFailed,
jdapi.AfsServiceStateDirectCompensateFailed: model.AfsOrderStatusFailed,
jdapi.AfsServiceStateReturnGoodsFailed: model.AfsOrderStatusFailed,
}
afsReasonTypeMap = map[int]int8{
jdapi.AfsReasonTypeGoodsQuality: model.AfsReasonTypeGoodsQuality,
jdapi.AfsReasonTypeWrongGoods: model.AfsReasonTypeWrongGoods,
jdapi.AfsReasonTypeMissingGoods: model.AfsReasonTypeMissingGoods,
jdapi.AfsReasonTypeNoGoods: model.AfsReasonTypeNoGoods,
jdapi.AfsReasonTypeDamagedGoods: model.AfsReasonTypeDamagedGoods,
jdapi.AfsReasonTypeGoodsQuantity: model.AfsReasonTypeGoodsQuantity,
jdapi.AfsReasonTypeGoodsAbsent: model.AfsReasonTypeGoodsAbsent,
jdapi.AfsReasonTypeGoodsSizeNoSame: model.AfsReasonTypeGoodsNoSame,
jdapi.AfsReasonTypeGoodsColorNoSame: model.AfsReasonTypeGoodsNoSame,
jdapi.AfsReasonWrongPurchase: model.AfsReasonWrongPurchase,
jdapi.AfsReasonNotReceivedIntime: model.AfsReasonNotReceivedIntime,
}
afsAppealTypeMap = map[string]int8{
jdapi.AfsDealTypeRefund: model.AfsAppealTypeRefund,
jdapi.AfsDealTypeReturnGoodsRefund: model.AfsAppealTypeReturnAndRefund,
jdapi.AfsDealTypeDirectCompensate: model.AfsAppealTypeNewGoods,
}
afsApproveTypeMap = map[int]int{
partner.AfsApproveTypeRefund: jdapi.AfsApproveTypeRefund,
partner.AfsApproveTypeReturnGoods: jdapi.AfsApproveTypeReturnGoods,
partner.AfsApproveTypeRefused: jdapi.AfsApproveTypeRefused,
}
)
func (c *PurchaseHandler) OnAfsOrderMsg(a *jdapi.API, msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
jxutils.CallMsgHandlerAsync(func() {
retVal = c.onAfsOrderMsg(a, msg)
}, jxutils.ComposeUniversalOrderID(msg.BillID, model.VendorIDJD))
return retVal
}
func (c *PurchaseHandler) onAfsOrderMsg(a *jdapi.API, msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
afsInfo, err := a.GetAfsService2(msg.BillID)
if err == nil {
status := c.callbackAfsMsg2Status(msg, afsInfo)
if partner.CurOrderManager.GetStatusDuplicatedCount(status) > 0 {
return nil
}
if status.Status == model.AfsOrderStatusWait4Approve || status.Status == model.AfsOrderStatusNew {
afsOrder := c.buildAfsOrder(afsInfo)
err = partner.CurOrderManager.OnAfsOrderNew(afsOrder, status)
} else {
err = partner.CurOrderManager.OnAfsOrderStatusChanged(status)
}
retVal = jdapi.Err2CallbackResponse(err, status.VendorStatus)
}
return retVal
}
func (c *PurchaseHandler) callbackAfsMsg2Status(msg *jdapi.CallbackOrderMsg, afsInfo *jdapi.AfsServiceResponse) *model.OrderStatus {
orderStatus := &model.OrderStatus{
VendorOrderID: msg.BillID, // 是售后单ID不是订单ID订单ID在RefVendorOrderID中
VendorID: model.VendorIDJD,
OrderType: model.OrderTypeAfsOrder,
RefVendorOrderID: afsInfo.OrderID,
RefVendorID: model.VendorIDJD,
VendorStatus: msg.StatusID,
Status: c.GetAfsStatusFromVendorStatus(msg.StatusID),
StatusTime: utils.Str2Time(msg.Timestamp),
Remark: msg.Remark,
}
return orderStatus
}
func (c *PurchaseHandler) GetAfsStatusFromVendorStatus(vendorStatus string) int {
if status, ok := AfsVendorStatus2StatusMap[vendorStatus]; ok {
return status
}
return model.OrderStatusUnknown
}
func (c *PurchaseHandler) convertAfsReasonType(vendorReasonType int) int8 {
if status, ok := afsReasonTypeMap[vendorReasonType]; ok {
return status
}
return model.AfsReasonNotOthers
}
func (c *PurchaseHandler) convertAfsAppealType(vendorAppealType string) int8 {
if status, ok := afsAppealTypeMap[vendorAppealType]; ok {
return status
}
globals.SugarLogger.Warnf("jd convertAfsAppealType unknown vendorAppealType:%d", vendorAppealType)
return 0
}
func (c *PurchaseHandler) buildAfsOrder(afsInfo *jdapi.AfsServiceResponse) (afsOrder *model.AfsOrder) {
afsOrder = &model.AfsOrder{
VendorID: model.VendorIDJD,
AfsOrderID: afsInfo.AfsServiceOrder,
VendorOrderID: afsInfo.OrderID,
VendorStoreID: afsInfo.StationID,
StoreID: int(utils.Str2Int64WithDefault(afsInfo.StationNumOutSystem, 0)),
AfsCreatedAt: afsInfo.CreateTime.GoTime(),
FreightUserMoney: afsInfo.OrderFreightMoney,
AfsFreightMoney: afsInfo.AfsFreight,
BoxMoney: afsInfo.PackagingMoney,
TongchengFreightMoney: afsInfo.TongchengFreightMoney,
SkuBoxMoney: afsInfo.MealBoxMoney,
VendorStatus: utils.Int2Str(afsInfo.AfsServiceState),
VendorReasonType: utils.Int2Str(afsInfo.QuestionTypeCid),
ReasonType: c.convertAfsReasonType(afsInfo.QuestionTypeCid),
ReasonDesc: utils.LimitUTF8StringLen(afsInfo.QuestionDesc, 1024),
ReasonImgList: utils.LimitUTF8StringLen(jdapi.ProcessQuestionPic(afsInfo.QuestionPic), 1024),
VendorAppealType: afsInfo.ApplyDeal,
AppealType: c.convertAfsAppealType(afsInfo.ApplyDeal),
VendorOrgCode: afsInfo.VenderID,
}
afsOrder.Status = c.GetAfsStatusFromVendorStatus(afsOrder.VendorStatus)
for _, x := range afsInfo.AfsDetailList {
orderSku := &model.OrderSkuFinancial{
// VendorID: model.VendorIDJD,
// AfsOrderID: afsOrder.AfsOrderID,
// VendorOrderID: afsOrder.VendorOrderID,
// VendorStoreID: afsOrder.VendorStoreID,
// StoreID: afsOrder.StoreID,
// IsAfsOrder: 1,
Count: x.SkuCount,
// ConfirmTime: afsOrder.AfsCreateAt,
VendorSkuID: utils.Int64ToStr(x.WareID),
SkuID: int(utils.Str2Int64WithDefault(x.SkuIDIsv, 0)),
Name: x.WareName,
UserMoney: x.AfsMoney,
PmSkuSubsidyMoney: x.PlatPayMoney,
}
if x.PromotionType != 0 && x.PromotionType != jdapi.PromotionTypeNormal {
orderSku.StoreSubName = utils.Int2Str(x.PromotionType)
}
afsOrder.PmSkuSubsidyMoney += orderSku.PmSkuSubsidyMoney
orderSku.PmSubsidyMoney += orderSku.PmSkuSubsidyMoney
for _, y := range x.AfsSkuDiscountList {
orderSku.PmSubsidyMoney += y.PlatPayMoney
}
afsOrder.SkuUserMoney += orderSku.UserMoney
afsOrder.PmSubsidyMoney += orderSku.PmSubsidyMoney
afsOrder.Skus = append(afsOrder.Skus, orderSku)
}
return afsOrder
}
// 审核售后单申请
func (c *PurchaseHandler) AgreeOrRefuseRefund(ctx *jxcontext.Context, order *model.AfsOrder, approveType int, reason string) (err error) {
if globals.EnableJdStoreWrite {
err = getAPI(order.VendorOrgCode).AfsOpenApprove(order.AfsOrderID, afsApproveTypeMap[approveType], reason, ctx.GetUserName())
}
return err
}
// 确认收到退货
func (c *PurchaseHandler) ConfirmReceivedReturnGoods(ctx *jxcontext.Context, order *model.AfsOrder) (err error) {
if globals.EnableJdStoreWrite {
err = getAPI(order.VendorOrgCode).ConfirmReceipt(order.AfsOrderID, ctx.GetUserName())
}
return err
}
func orderSkus2AfsSkus(refundSkuList []*model.OrderSku) (list []*jdapi.VenderAfsSkuDTO) {
for _, v := range refundSkuList {
actType := int(utils.Str2Int64WithDefault(v.StoreSubName, 0))
if actType == 0 { //!(actType == jdapi.PromotionTypeOverflowGiveGift || actType == jdapi.PromotionTypeBuyGiveGift) {
actType = 1
}
list = append(list, &jdapi.VenderAfsSkuDTO{
SkuID: utils.Str2Int64(v.VendorSkuID),
SkuCount: v.Count,
PromotionType: actType,
})
}
return list
}
// 发起全款退款
func (c *PurchaseHandler) RefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
return c.PartRefundOrder(ctx, order, order.Skus, reason)
}
// 发起部分退款
func (c *PurchaseHandler) PartRefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, refundSkuList []*model.OrderSku, reason string) (err error) {
if globals.EnableJdStoreWrite {
_, err = getAPI(order.VendorOrgCode).AfsSubmit(order.VendorOrderID, ctx.GetUserName(), utils.Int2Str(jdapi.AfsReasonTypeWrongGoods), reason, "", order.ConsigneeName, order.ConsigneeMobile, order.ConsigneeAddress, orderSkus2AfsSkus(refundSkuList))
}
return err
}

View File

@@ -1,51 +0,0 @@
package jd
import (
"git.rosy.net.cn/baseapi/platformapi/jdapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
)
const (
JDDJ_BAD_COMMENTS_MAX_MODIFY_TIME = 72 // 小时
)
func (c *PurchaseHandler) onOrderComment2(a *jdapi.API, msg *jdapi.CallbackOrderMsg) (err error) {
intOrderID := utils.Str2Int64(msg.BillID)
result, err := a.GetCommentByOrderId2(intOrderID)
if err == nil {
globals.SugarLogger.Debugf("onOrderComment comment:%s", utils.Format4Output(result, true))
orderCommend := &model.OrderComment{
VendorOrderID: utils.Int64ToStr(result.OrderID),
VendorID: model.VendorIDJD,
UserCommentID: "",
VendorStoreID: utils.Int64ToStr(result.StoreID),
TagList: string(utils.MustMarshal(result.VenderTags)),
Score: int8(result.Score4),
Content: result.Score4Content,
ModifyDuration: JDDJ_BAD_COMMENTS_MAX_MODIFY_TIME,
OriginalMsg: string(utils.MustMarshal(result)),
}
if result.CreateTime != nil {
orderCommend.CommentCreatedAt = result.CreateTime.GoTime()
}
if result.OrgCommentContent != "" {
orderCommend.IsReplied = 1
}
err = partner.CurOrderManager.OnOrderComments([]*model.OrderComment{orderCommend})
}
if err != nil {
globals.SugarLogger.Warnf("onOrderComment orderID:%s failed with error:%v", msg.BillID, err)
}
return err
}
func (c *PurchaseHandler) ReplyOrderComment(ctx *jxcontext.Context, vendorOrgCode string, orderComment *model.OrderComment, replyComment string) (err error) {
if globals.EnableJdStoreWrite {
err = getAPI(vendorOrgCode).OrgReplyComment(utils.Str2Int64(orderComment.VendorOrderID), orderComment.VendorStoreID, replyComment, ctx.GetUserName())
}
return err
}

View File

@@ -1,61 +0,0 @@
package jd
import (
"testing"
"time"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
_ "git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
)
func TestSwitch2SelfDeliver(t *testing.T) {
orderID := "817540316000041"
if order, err := partner.CurOrderManager.LoadOrder(orderID, model.VendorIDJD); err == nil {
// globals.SugarLogger.Debug(order)
if err = CurPurchaseHandler.Swtich2SelfDeliver(order, ""); err == nil {
} else {
t.Fatal(err.Error())
}
} else {
t.Fatal(err.Error())
}
}
func TestGetOrder(t *testing.T) {
_, err := CurPurchaseHandler.GetOrder("", "815536199000222")
if err != nil {
t.Fatal(err.Error())
}
}
func TestGetOrderStatus(t *testing.T) {
status, err := CurPurchaseHandler.GetOrderStatus("", "929203144000041")
if err != nil {
t.Fatal(err.Error())
}
t.Log(status)
}
func TestListOrders(t *testing.T) {
result, err := CurPurchaseHandler.ListOrders(jxcontext.AdminCtx, "", nil, time.Now(), "")
if err != nil {
t.Fatal(err.Error())
}
t.Log(utils.Format4Output(result, false))
}
func TestGetSelfTakeCode(t *testing.T) {
order, err := partner.CurOrderManager.LoadOrder("921160248000222", model.VendorIDJD)
if err != nil {
t.Fatal(err)
}
selfTakeCode, err := CurPurchaseHandler.GetSelfTakeCode(jxcontext.AdminCtx, order)
if err != nil {
t.Fatal(err.Error())
}
t.Log(selfTakeCode)
}

View File

@@ -1,480 +0,0 @@
package jd
// 这里函数取得的信息除了与自身实体相关的ID比如PARENT ID都已经转换成了本地ID了
// type tSkuInfoExt struct {
// model.SkuName
// JdCatID int64 `orm:"column(jd_cat_id)"` // 商家类别
// JdCategoryID int `orm:"column(jd_category_id)"` // 到家类别
// SkuCatID int64 `orm:"column(sku_cat_id)"` // 商家特殊类别
// Comment string `orm:"size(255)" json:"comment"`
// }
// var (
// skuAddParamsKeyMap = map[string]int{
// jdapi.KeyUpcCode: 1,
// }
// )
// func (p *PurchaseHandler) CreateCategory(db *dao.DaoDB, cat *model.SkuCategory, userName string) (err error) {
// var jdPid int64
// if cat.ParentID != 0 {
// pCat := &model.SkuCategory{}
// pCat.ID = cat.ParentID
// if err = dao.GetEntity(db, pCat); err == nil {
// jdPid = pCat.JdID
// } else {
// return err
// }
// }
// if globals.EnableJdStoreWrite {
// result, err2 := getAPI("").AddShopCategory(jdPid, cat.Name, int(cat.Level), cat.Seq, userName)
// if err = err2; err == nil {
// if jdID := utils.Str2Int64WithDefault(result, 0); jdID != 0 {
// cat.JdID = jdID
// }
// }
// } else {
// cat.JdID = jxutils.GenFakeID()
// }
// return err
// }
// func (p *PurchaseHandler) UpdateCategory(db *dao.DaoDB, cat *model.SkuCategory, userName string) error {
// if globals.EnableJdStoreWrite {
// return getAPI("").UpdateShopCategory(cat.JdID, cat.Name)
// }
// return nil
// }
// func (p *PurchaseHandler) DeleteCategory(db *dao.DaoDB, cat *model.SkuCategory, userName string) error {
// if globals.EnableJdStoreWrite {
// return getAPI("").DelShopCategory(cat.JdID)
// }
// return nil
// }
// func (p *PurchaseHandler) ReorderCategories(db *dao.DaoDB, parentCatID int, userName string) (err error) {
// var parentJDID int64
// if parentCatID != 0 {
// cat := &model.SkuCategory{}
// cat.ID = parentCatID
// if err = dao.GetEntity(db, cat); err != nil {
// return err
// }
// parentJDID = cat.JdID
// }
// var cats []*model.SkuCategory
// if err = dao.GetRows(db, &cats, `
// SELECT *
// FROM sku_category
// WHERE parent_id = ? AND deleted_at = ?
// ORDER BY seq`, parentCatID, utils.DefaultTimeValue); err == nil {
// jdCatIDs := make([]int64, len(cats))
// for k, v := range cats {
// jdCatIDs[k] = v.JdID
// }
// if globals.EnableJdStoreWrite {
// err = getAPI("").ChangeShopCategoryOrder(parentJDID, jdCatIDs)
// }
// }
// return err
// }
// func (p *PurchaseHandler) cuSku(db *dao.DaoDB, sku *model.Sku, handler func(skuExt *tSkuInfoExt, price int, skuName string, shopCategories []int64, addParams map[string]interface{}) (string, error)) (err error) {
// var skuInfoExt tSkuInfoExt
// err = dao.GetRow(nil, &skuInfoExt, `
// SELECT
// t2.*, IF(t2.jd_category_id > 0, t2.jd_category_id, t3.jd_category_id) jd_category_id,
// t3.jd_id jd_cat_id,
// t4.jd_id sku_cat_id
// FROM sku t1
// JOIN sku_name t2 ON t1.name_id = t2.id
// JOIN sku_category t3 ON t2.category_id = t3.id
// LEFT JOIN sku_category t4 ON t1.category_id = t4.id
// WHERE t1.id = ?
// `, sku.ID)
// if err == nil {
// shopCategories := []int64{skuInfoExt.JdCatID}
// // SPU只支持SPU的商家分类不支持单独SKU的去除SKU的分类
// // if skuInfoExt.SkuCatID != 0 {
// // shopCategories = append(shopCategories, skuInfoExt.SkuCatID)
// // }
// if skuInfoExt.JdCategoryID == 0 {
// skuInfoExt.JdCategoryID = getDefJdCategoryID()
// }
// if skuInfoExt.BrandID == 0 {
// skuInfoExt.BrandID = DefBrandID
// }
// addParams := map[string]interface{}{}
// if skuInfoExt.IsGlobal == 0 { //如果不是全国可售,要查可售区域
// sellPlaces, err2 := dao.GetSellCities(db, skuInfoExt.ID, model.VendorIDJD)
// if err = err2; err == nil && len(sellPlaces) > 0 {
// sellCites := make([]int, len(sellPlaces))
// for k, v := range sellPlaces {
// sellCites[k] = v.JdCode
// }
// addParams["sellCities"] = sellCites
// }
// }
// if addParams["sellCities"] == nil {
// addParams["sellCities"] = []int{0}
// }
// if skuInfoExt.DescImg != "" {
// addParams[jdapi.KeyProductDesc] = fmt.Sprintf(`<img src="%s" alt="一张图片" />`, skuInfoExt.DescImg)
// addParams[jdapi.KeyIfViewDesc] = 0
// } else {
// addParams[jdapi.KeyIfViewDesc] = 1
// }
// if err == nil {
// skuName := jxutils.ComposeSkuName(skuInfoExt.Prefix, skuInfoExt.Name, sku.Comment, skuInfoExt.Unit, sku.SpecQuality, sku.SpecUnit, jdapi.MaxSkuNameCharCount)
// skuPrice := jxutils.CaculateSkuPrice(skuInfoExt.Price, sku.SpecQuality, sku.SpecUnit, skuInfoExt.Unit)
// if skuInfoExt.Upc != "" {
// addParams[jdapi.KeyUpcCode] = skuInfoExt.Upc
// }
// result, err2 := handler(&skuInfoExt, skuPrice, skuName, shopCategories, addParams)
// if err = err2; err == nil {
// if jdID := utils.Str2Int64WithDefault(result, 0); jdID != 0 {
// sku.JdID = jdID
// }
// }
// }
// }
// return err
// }
// func (p *PurchaseHandler) CreateSku(db *dao.DaoDB, sku *model.Sku, userName string) (err error) {
// return p.cuSku(db, sku, func(skuExt *tSkuInfoExt, price int, skuName string, shopCategories []int64, addParams map[string]interface{}) (vendorSkuID string, err error) {
// if skuExt.IsSpu == 0 {
// if globals.EnableJdStoreWrite {
// vendorSkuID, err = getAPI("").AddSku(utils.Int2Str(sku.ID), skuExt.JdCategoryID, shopCategories, skuExt.BrandID, skuName, price, jxutils.IntWeight2Float(sku.Weight), jxutils.BatchString2Slice(skuExt.Img, skuExt.Img2), jxStatus2jdStatus(sku.Status), true, addParams)
// if err != nil {
// if jdSkuID := jdapi.GetJdSkuIDFromError(err); jdSkuID > 0 {
// vendorSkuID = utils.Int64ToStr(jdSkuID)
// err = nil
// }
// }
// } else {
// vendorSkuID = utils.Int64ToStr(jxutils.GenFakeID())
// }
// } else {
// vendorSkuID, err = p.syncSkuNameAsSpu(db, sku, skuExt, price, skuName, shopCategories, addParams)
// }
// return vendorSkuID, err
// })
// }
// // func (p *PurchaseHandler) ReadSku(ctx *jxcontext.Context, vendorOrgCode, vendorSkuID string) (skuNameExt *model.SkuNameExt, err error) {
// // jdSkuID := utils.Str2Int64(vendorSkuID)
// // a := getAPI(vendorOrgCode)
// // skuList, _, err := a.QuerySkuInfos(&jdapi.QuerySkuParam{
// // SkuID: jdSkuID,
// // })
// // if err == nil {
// // if len(skuList) >= 1 {
// // skuNameExt = &model.SkuNameExt{}
// // if imgList, err2 := a.QueryListBySkuIds(&jdapi.QueryListBySkuIdsParam{
// // SkuIDs: []int64{jdSkuID},
// // }); err2 == nil && len(imgList) > 0 {
// // skuNameExt.Img = imgList[0].SourceImgURL
// // }
// // sku := skuList[0]
// // prefix, name, comment, specUnit, unit, specQuality := jxutils.SplitSkuName(sku.SkuName)
// // if name == "" {
// // name = sku.SkuName
// // unit = "份"
// // specUnit = "g"
// // }
// // skuNameExt.Prefix = prefix
// // skuNameExt.Name = name
// // skuNameExt.Unit = unit
// // skuNameExt.Price = sku.SkuPrice
// // skuNameExt.Skus = []*model.SkuWithVendor{
// // &model.SkuWithVendor{
// // Sku: &model.Sku{
// // SpecQuality: specQuality,
// // SpecUnit: specUnit,
// // Weight: jxutils.FloatWeight2Int(float32(sku.Weight)),
// // JdID: sku.SkuID,
// // Status: jdStatus2jxStatus(sku.FixedStatus),
// // Comment: comment,
// // },
// // },
// // }
// // skuNameExt.Skus[0].ID = int(utils.Str2Int64(sku.OutSkuID))
// // db := dao.GetDB()
// // shopCategories := sku.ShopCategories
// // if len(shopCategories) > 0 {
// // skuCat := &model.SkuCategory{}
// // skuCat.JdID = shopCategories[0]
// // if dao.GetEntity(db, skuCat, "JdID") == nil {
// // skuNameExt.CategoryID = skuCat.ID
// // }
// // }
// // sellCities := sku.SellCities
// // for _, v := range sellCities {
// // if v == 0 {
// // skuNameExt.IsGlobal = 1
// // }
// // }
// // if len(sellCities) == 0 || skuNameExt.IsGlobal == 1 {
// // skuNameExt.IsGlobal = 1
// // } else {
// // var places []*model.Place
// // if err = dao.GetRows(db, &places, "SELECT * FROM place WHERE jd_code IN ("+dao.GenQuestionMarks(len(sellCities))+") AND level = 2", sellCities); err == nil {
// // skuNameExt.Places = make([]int, len(places))
// // for k, v := range places {
// // skuNameExt.Places[k] = v.Code
// // }
// // }
// // }
// // } else {
// // err = partner.ErrCanNotFindItem
// // }
// // }
// // return skuNameExt, err
// // }
// func (p *PurchaseHandler) UpdateSku(db *dao.DaoDB, sku *model.Sku, userName string) (err error) {
// return p.cuSku(db, sku, func(skuExt *tSkuInfoExt, price int, skuName string, shopCategories []int64, addParams map[string]interface{}) (vendorSkuID string, err error) {
// params := utils.MergeMaps(addParams)
// params[jdapi.KeyCategoryId] = skuExt.JdCategoryID
// params[jdapi.KeyShopCategories] = shopCategories
// params[jdapi.KeyBrandId] = skuExt.BrandID
// params[jdapi.KeySkuName] = skuName
// params[jdapi.KeyWeight] = jxutils.IntWeight2Float(sku.Weight)
// params[jdapi.KeyImages] = jxutils.BatchString2Slice(skuExt.Img, skuExt.Img2)
// params[jdapi.KeyFixedStatus] = jxStatus2jdStatus(sku.Status)
// if skuExt.IsSpu == 0 {
// if globals.EnableJdStoreWrite {
// vendorSkuID, err = getAPI("").UpdateSku(utils.Int2Str(sku.ID), params)
// }
// } else {
// vendorSkuID, err = p.syncSkuNameAsSpu(db, sku, skuExt, price, skuName, shopCategories, addParams)
// }
// return vendorSkuID, err
// })
// }
// func (p *PurchaseHandler) DeleteSku(db *dao.DaoDB, sku *model.Sku, userName string) (err error) {
// params := map[string]interface{}{
// jdapi.KeyFixedStatus: jdapi.SkuFixedStatusDeleted,
// }
// sql := `
// SELECT t2.*
// FROM sku t1
// JOIN sku_name t2 ON t1.name_id = t2.id
// WHERE t1.id = ?
// `
// var skuExt tSkuInfoExt
// err = dao.GetRow(db, &skuExt, sql, sku.ID)
// if err == nil {
// if skuExt.IsSpu == 0 {
// if globals.EnableJdStoreWrite {
// _, err = getAPI("").UpdateSku(utils.Int2Str(sku.ID), params)
// }
// } else {
// _, err = p.syncSkuNameAsSpu(db, sku, &skuExt, 0, "", nil, nil)
// }
// }
// return err
// }
// // func (p *PurchaseHandler) RefreshAllSkusID(ctx *jxcontext.Context, parentTask tasksch.ITask, isAsync bool) (hint string, err error) {
// // globals.SugarLogger.Debugf("jd RefreshAllSkusID")
// // db := dao.GetDB()
// // var skuPairs []*jdapi.SkuIDPair
// // const stepCount = 2
// // rootTask := tasksch.NewSeqTask("jd RefreshAllSkusID", ctx,
// // func(rootTask *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
// // switch step {
// // case 0:
// // err = dao.GetRows(db, &skuPairs, `
// // SELECT t1.id out_sku_id, t1.jd_id sku_id
// // FROM sku t1
// // WHERE t1.deleted_at = ?
// // `, utils.DefaultTimeValue)
// // default:
// // taskName := "RefreshAllSkusID update id"
// // if step != stepCount-1 {
// // taskName = "RefreshAllSkusID update uuid"
// // }
// // task1 := tasksch.NewParallelTask(taskName, tasksch.NewParallelConfig().SetIsContinueWhenError(true).SetBatchSize(jdapi.MaxBatchSize4BatchUpdateOutSkuId), ctx,
// // func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
// // skuPairs := make([]*jdapi.SkuIDPair, len(batchItemList))
// // for k, v := range batchItemList {
// // pair := v.(*jdapi.SkuIDPair)
// // skuPairs[k] = &jdapi.SkuIDPair{
// // SkuId: pair.SkuId,
// // OutSkuId: pair.OutSkuId,
// // }
// // if step != stepCount-1 {
// // skuPairs[k].OutSkuId = utils.GetUUID()
// // }
// // }
// // globals.SugarLogger.Debug(utils.Format4Output(skuPairs, false))
// // if globals.EnableJdStoreWrite {
// // _, err = getAPI("").BatchUpdateOutSkuId(skuPairs)
// // }
// // return nil, err
// // }, skuPairs)
// // rootTask.AddChild(task1).Run()
// // _, err = task1.GetResult(0)
// // }
// // return nil, err
// // }, stepCount)
// // tasksch.HandleTask(rootTask, parentTask, false).Run()
// // if !isAsync {
// // _, err = rootTask.GetResult(0)
// // }
// // return rootTask.ID, err
// // }
// func splitAddParams(addParams map[string]interface{}) (spuAddParams, skuAddParams map[string]interface{}) {
// if addParams != nil {
// spuAddParams = make(map[string]interface{})
// skuAddParams = make(map[string]interface{})
// for key := range addParams {
// if skuAddParamsKeyMap[key] == 1 {
// skuAddParams[key] = addParams[key]
// } else {
// spuAddParams[key] = addParams[key]
// }
// }
// }
// return spuAddParams, skuAddParams
// }
// // 这个处理JD SPU补丁形式
// func (p *PurchaseHandler) syncSkuNameAsSpu(db *dao.DaoDB, sku *model.Sku, skuExt *tSkuInfoExt, price int, skuName string, shopCategories []int64, addParams map[string]interface{}) (vendorSkuID string, err error) {
// // SPU的SKU NAME不需要规格信息
// skuName = jxutils.ComposeSkuName(skuExt.Prefix, skuExt.Name, sku.Comment, "", 0, "", 0)
// skuNameJdID := skuExt.JdID
// globals.SugarLogger.Debugf("syncSkuNameAsSpu1 sku.id=%d, bareSkuName:%s, skuName:%s, skuNameJdID:%d", sku.ID, skuExt.Name, skuName, skuNameJdID)
// spuAddParams, skuAddParams := splitAddParams(addParams)
// if !jxutils.IsEmptyID(skuNameJdID) && sku.JdSyncStatus&model.SyncFlagDeletedMask != 0 { // 删除SKU
// if globals.EnableJdStoreWrite {
// err = getAPI("").UpdateSkuBaseInfo(utils.Int2Str(skuExt.ID), utils.Int2Str(sku.ID), utils.Params2Map(jdapi.KeyFixedStatus, jdapi.SkuFixedStatusDeleted))
// }
// }
// if err == nil {
// updateFields := []string{}
// if skuExt.JdSyncStatus&model.SyncFlagDeletedMask != 0 {
// sql := `
// SELECT COUNT(*) ct
// FROM sku t1
// WHERE t1.name_id = ? AND (t1.status <> ? OR t1.jd_sync_status <> 0)
// `
// var count struct {
// Ct int
// }
// if err = dao.GetRow(db, &count, sql, sku.NameID, model.SkuStatusDeleted); err != nil {
// return "", err
// }
// if count.Ct <= 1 && sku.JdSyncStatus&model.SyncFlagDeletedMask != 0 { // 1就是最后删的那个
// updateFields = append(updateFields, model.FieldJdSyncStatus)
// if globals.EnableJdStoreWrite {
// if err = getAPI("").UpdateSpu(utils.Int2Str(skuExt.ID), utils.Params2Map(jdapi.KeyFixedStatus, jdapi.SkuFixedStatusOffline)); err == nil {
// err = getAPI("").UpdateSpu(utils.Int2Str(skuExt.ID), utils.Params2Map(jdapi.KeyFixedStatus, jdapi.SkuFixedStatusDeleted))
// }
// }
// }
// } else if skuExt.JdSyncStatus&model.SyncFlagNewMask != 0 && jxutils.IsEmptyID(skuNameJdID) {
// if globals.EnableJdStoreWrite {
// spuName := jxutils.ComposeSpuName(skuExt.Prefix, skuExt.Name, 0)
// skus := []map[string]interface{}{
// map[string]interface{}{
// jdapi.KeyOutSkuId: utils.Int2Str(sku.ID),
// jdapi.KeySkuName: skuName,
// jdapi.KeyFixedStatus: jxStatus2jdStatus(sku.Status),
// jdapi.KeySkuPrice: price,
// jdapi.KeyWeight: jxutils.IntWeight2Float(sku.Weight),
// jdapi.KeyIsSale: true,
// jdapi.FakeKeySpecAttr: composeSkuSpec(sku.SpecQuality, sku.SpecUnit, skuExt.Unit),
// },
// }
// skus[0] = utils.MergeMaps(skus[0], skuAddParams)
// updateFields = append(updateFields, model.FieldJdSyncStatus)
// if globals.EnableJdStoreWrite {
// vendorSpuID, skuPairs, err2 := getAPI("").AddSpu(utils.Int2Str(skuExt.ID), skuExt.JdCategoryID, shopCategories, skuExt.BrandID, spuName, []string{skuExt.Img}, jxStatus2jdStatus(skuExt.Status), spuAddParams, skus)
// if err = err2; err == nil {
// skuExt.JdID = vendorSpuID
// // skuNameJdID = skuExt.JdID // 这个是故意去掉的这样之后的首次SKU修改操作就会被忽略下一条语句也就可以不用了
// // sku.JdSyncStatus &= ^model.SyncFlagNewMask
// vendorSkuID = utils.Int64ToStr(skuPairs[0].SkuId)
// updateFields = append(updateFields, model.FieldJdID)
// }
// }
// }
// } else if skuExt.JdSyncStatus&model.SyncFlagModifiedMask != 0 {
// params := utils.MergeMaps(map[string]interface{}{
// jdapi.KeySpuName: jxutils.ComposeSpuName(skuExt.Prefix, skuExt.Name, 0),
// jdapi.KeyShopCategories: shopCategories,
// jdapi.KeyCategoryId: skuExt.JdCategoryID,
// jdapi.KeyBrandId: skuExt.BrandID,
// jdapi.KeyImages: []string{skuExt.Img},
// jdapi.KeyFixedStatus: jxStatus2jdStatus(skuExt.Status),
// }, spuAddParams)
// updateFields = append(updateFields, model.FieldJdSyncStatus)
// if globals.EnableJdStoreWrite {
// err = getAPI("").UpdateSpu(utils.Int2Str(skuExt.ID), params)
// }
// }
// if err == nil {
// if skuExt.JdSyncStatus != 0 && len(updateFields) > 0 {
// skuExt.JdSyncStatus = 0
// _, err = dao.UpdateEntity(db, &skuExt.SkuName, updateFields...)
// globals.SugarLogger.Debugf("syncSkuNameAsSpu4 sku.id=%d, skuName:%s, skuName:%s", sku.ID, skuExt.Name, utils.Format4Output(&skuExt.SkuName, false))
// }
// }
// }
// if err == nil && !jxutils.IsEmptyID(skuNameJdID) {
// if sku.JdSyncStatus&model.SyncFlagNewMask != 0 { // 非首次新增SKU
// if globals.EnableJdStoreWrite {
// vendorSkuID2, err2 := getAPI("").AppendSku(utils.Int2Str(skuExt.ID), utils.Int2Str(sku.ID), skuName, price, jxutils.IntWeight2Float(sku.Weight), []string{skuExt.Img}, jxStatus2jdStatus(sku.Status), true, composeSkuSpec(sku.SpecQuality, sku.SpecUnit, skuExt.Unit), skuAddParams)
// if err = err2; err == nil {
// vendorSkuID = utils.Int64ToStr(vendorSkuID2)
// }
// }
// } else if sku.JdSyncStatus&model.SyncFlagModifiedMask != 0 {
// params := make(map[string]interface{})
// params[jdapi.KeySkuName] = skuName
// params[jdapi.KeyImages] = []string{skuExt.Img}
// params[jdapi.KeyFixedStatus] = jxStatus2jdStatus(sku.Status)
// params[jdapi.KeyWeight] = jxutils.IntWeight2Float(sku.Weight)
// params[jdapi.KeySkuPrice] = price
// if globals.EnableJdStoreWrite {
// err = getAPI("").UpdateSkuBaseInfo(utils.Int2Str(skuExt.ID), utils.Int2Str(sku.ID), utils.MergeMaps(params, skuAddParams))
// if sku.JdSyncStatus&model.SyncFlagSpecMask != 0 {
// skuIndex := sku.SkuIndex
// if skuIndex > 0 {
// saleAttrValue := composeSkuSpec(sku.SpecQuality, sku.SpecUnit, skuExt.Unit)
// globals.SugarLogger.Debugf("syncSkuNameAsSpu outSuperId:%d, saleAttrId:%d, saleAttrValueId:%d, saleAttrValueName:%s", skuExt.ID, jdapi.SaleAttrIDBase, jdapi.SaleAttrValueIDBase+skuIndex-1, saleAttrValue)
// err = getAPI("").UpdateSpuSaleAttr(utils.Int2Str(skuExt.ID), utils.Int2Str(jdapi.SaleAttrIDBase), "", utils.Int2Str(jdapi.SaleAttrValueIDBase+skuIndex-1), saleAttrValue)
// }
// }
// }
// }
// if err == nil {
// sku.JdSyncStatus = 0
// }
// }
// return vendorSkuID, err
// }
// func composeSkuSpec(specQuality float32, specUnit, unit string) string {
// prefix := ""
// if unit == model.SpecialUnit {
// prefix = "约"
// }
// value := prefix + jxutils.ComposeSkuSpec(specQuality, specUnit)
// suffix := "/" + unit
// if utf8.RuneCountInString(value) <= 8-utf8.RuneCountInString(suffix) {
// value += suffix
// }
// return value
// }

View File

@@ -1,485 +0,0 @@
package jd
import (
"fmt"
"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/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"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
"github.com/astaxie/beego"
)
const (
DefBrandID = 35247
DefJdCategoryID = 20362
DefJdCategoryID4Jxgy = 22410 // 其他国产水果
)
func getDefJdCategoryID() int {
if beego.BConfig.RunMode == "jxgy" {
return DefJdCategoryID4Jxgy
}
return DefJdCategoryID
}
func jdCat2Jx(jdCat *jdapi.CategoryInfo) (jxCat *partner.BareCategoryInfo) {
return &partner.BareCategoryInfo{
VendorCatID: utils.Int64ToStr(jdCat.Id),
Level: jdCat.Level,
Name: jdCat.Name,
Seq: jdCat.Sort,
}
}
func (p *PurchaseHandler) GetAllCategories(ctx *jxcontext.Context, vendorOrgCode string) (cats []*partner.BareCategoryInfo, err error) {
result, err := getAPI(vendorOrgCode).QueryCategoriesByOrgCode()
if err == nil {
catMap := make(map[int64]*partner.BareCategoryInfo)
level := 1
for {
processedCount := 0
for _, jdCat := range result {
if jdCat.Level == level {
processedCount++
jxCat := jdCat2Jx(jdCat)
if level == 1 {
cats = append(cats, jxCat)
} else {
parentCat := catMap[jdCat.ParentId]
if parentCat != nil {
parentCat.Children = append(parentCat.Children, jxCat)
}
}
catMap[jdCat.Id] = jxCat
}
}
if processedCount == 0 {
break
}
level++
}
}
return cats, err
}
func (p *PurchaseHandler) CreateCategory2(ctx *jxcontext.Context, cat *dao.SkuStoreCatInfo) (err error) {
globals.SugarLogger.Debugf("CreateCategory2 cat:%s", utils.Format4Output(cat, true))
parentID := int64(0)
if cat.Level != 1 {
parentID = utils.Str2Int64(cat.ParentVendorCatID)
}
if globals.EnableJdStoreWrite {
result, err2 := getAPI(cat.VendorOrgCode).AddShopCategory(parentID, cat.Name, int(cat.Level), cat.Seq, ctx.GetUserName())
if err = err2; err == nil {
if jdID := utils.Str2Int64WithDefault(result, 0); jdID != 0 {
cat.VendorCatID = utils.Int64ToStr(jdID)
}
}
} else {
cat.VendorCatID = utils.Int64ToStr(jxutils.GenFakeID())
}
return err
}
func (p *PurchaseHandler) UpdateCategory2(ctx *jxcontext.Context, cat *dao.SkuStoreCatInfo) (err error) {
globals.SugarLogger.Debugf("UpdateCategory2 cat:%s", utils.Format4Output(cat, true))
if globals.EnableJdStoreWrite {
err = getAPI(cat.VendorOrgCode).UpdateShopCategory(utils.Str2Int64(cat.VendorCatID), cat.Name)
}
return err
}
func (p *PurchaseHandler) DeleteCategory2(ctx *jxcontext.Context, vendorOrgCode, vendorCatID string) (err error) {
globals.SugarLogger.Debugf("DeleteCategory2 vendorOrgCode:%s, vendorCatID:%s", vendorOrgCode, vendorCatID)
if globals.EnableJdStoreWrite {
err = getAPI(vendorOrgCode).DelShopCategory(utils.Str2Int64(vendorCatID))
}
return err
}
func (p *PurchaseHandler) ReorderCategories2(ctx *jxcontext.Context, vendorOrgCode, vendorParentCatID string, vendorCatIDList []string) (err error) {
if globals.EnableJdStoreWrite {
err = getAPI(vendorOrgCode).ChangeShopCategoryOrder(utils.Str2Int64WithDefault(vendorParentCatID, 0), utils.StringSlice2Int64(vendorCatIDList))
}
return err
}
func (p *PurchaseHandler) getVendorCategories(level int, pid int64) (vendorCats []*model.SkuVendorCategory, err error) {
// 得到平台的分类,不需要指定分账号
cats, err := api.JdAPI.QueryChildCategoriesForOP(pid)
if err != nil {
return nil, err
}
for _, v := range cats {
if v.Status == 1 {
cat := &model.SkuVendorCategory{
VendorID: model.VendorIDJD,
Name: v.Name,
Level: level,
VendorCategoryID: utils.Int64ToStr(v.Id),
}
if level > 1 {
cat.ParentID = utils.Int64ToStr(v.ParentId)
if level == 3 {
cat.IsLeaf = 1
}
}
vendorCats = append(vendorCats, cat)
if level < 3 {
childVendorCats, err2 := p.getVendorCategories(level+1, v.Id)
if err2 == nil && len(childVendorCats) > 0 {
vendorCats = append(vendorCats, childVendorCats...)
} else {
cat.IsLeaf = 1
}
}
}
}
return vendorCats, nil
}
func (p *PurchaseHandler) GetVendorCategories(ctx *jxcontext.Context) (vendorCats []*model.SkuVendorCategory, err error) {
vendorCats, err = p.getVendorCategories(1, 0)
return vendorCats, err
}
func skuInfo2Param(ctx *jxcontext.Context, sku *dao.StoreSkuSyncInfo) (param *jdapi.OpSkuParam) {
param = &jdapi.OpSkuParam{
TraceID: ctx.GetTrackInfo(),
OutSkuID: utils.Int2Str(sku.SkuID),
ShopCategories: []int64{utils.Str2Int64(sku.VendorCatID)},
CategoryID: sku.VendorVendorCatID,
BrandID: DefBrandID,
SkuName: utils.LimitUTF8StringLen(sku.SkuName, jdapi.MaxSkuNameCharCount),
SkuPrice: int(sku.Price),
Weight: float64(jxutils.IntWeight2Float(sku.Weight)),
FixedStatus: jxStatus2jdStatus(sku.MergedStatus),
IsSale: jdapi.IsSaleNo, // todo ?
Upc: sku.Upc,
// Images: jxutils.BatchString2Slice(sku.Img, sku.Img2),
}
if sku.ImgMix != "" {
param.Images = jxutils.BatchString2Slice(sku.ImgMix, sku.Img2)
} else {
param.Images = jxutils.BatchString2Slice(sku.Img, sku.Img2)
}
if param.CategoryID == 0 {
param.CategoryID = int64(getDefJdCategoryID())
}
// 京东强制要求upc的商品如果没有设置upc自动生成一个假的
if param.Upc == "" && isSkuMustHaveUpc(sku.Unit, param.CategoryID) {
param.Upc = jxutils.GenFakeUPC(sku.SkuID)
}
if sku.IsGlobal == 0 && len(sku.SellCities) > 0 {
param.SellCities = utils.StringSlice2Int64(sku.SellCities)
}
if sku.DescImg != "" {
param.ProductDesc = fmt.Sprintf(`<img src="%s" alt="一张图片" />`, sku.DescImg)
}
return param
}
func (p *PurchaseHandler) CreateSku2(ctx *jxcontext.Context, sku *dao.StoreSkuSyncInfo) (err error) {
globals.SugarLogger.Debugf("CreateSku2 sku:%s", utils.Format4Output(sku, true))
param := skuInfo2Param(ctx, sku)
if globals.EnableJdStoreWrite {
sku.VendorSkuID, err = getAPI(sku.VendorOrgCode).AddSku2(param)
} else {
sku.VendorSkuID = utils.Int64ToStr(jxutils.GenFakeID())
}
return err
}
func (p *PurchaseHandler) UpdateSku2(ctx *jxcontext.Context, sku *dao.StoreSkuSyncInfo) (err error) {
globals.SugarLogger.Debugf("UpdateSku2 sku:%s", utils.Format4Output(sku, true))
param := skuInfo2Param(ctx, sku)
if globals.EnableJdStoreWrite {
_, err = getAPI(sku.VendorOrgCode).UpdateSku2(param)
}
return err
}
func (p *PurchaseHandler) DeleteSku2(ctx *jxcontext.Context, vendorOrgCode string, sku *partner.StoreSkuInfo) (err error) {
globals.SugarLogger.Debugf("DeleteSku2 vendorOrgCode:%s, sku:%s", vendorOrgCode, utils.Format4Output(sku, true))
// 京东到家只能通过商家ID删除SKU如果没有的话先绑定再删除
if sku.SkuID == 0 {
skuPairList := []*jdapi.SkuIDPair{
&jdapi.SkuIDPair{
SkuId: utils.Str2Int64(sku.VendorSkuID),
OutSkuId: sku.VendorSkuID,
},
}
if globals.EnableJdStoreWrite {
_, err = getAPI(vendorOrgCode).BatchUpdateOutSkuId(skuPairList)
if err != nil {
return err
}
sku.SkuID = int(utils.Str2Int64(sku.VendorSkuID))
}
}
param := &jdapi.OpSkuParam{
TraceID: ctx.GetTrackInfo(),
OutSkuID: utils.Int2Str(sku.SkuID),
FixedStatus: jdapi.SkuFixedStatusDeleted,
}
if globals.EnableJdStoreWrite {
_, err = getAPI(vendorOrgCode).UpdateSku2(param)
}
return err
}
func (p *PurchaseHandler) GetSkus(ctx *jxcontext.Context, vendorOrgCode string, skuID int, vendorSkuID string) (skuNameList []*partner.SkuNameInfo, err error) {
param := &jdapi.QuerySkuParam{
SkuID: utils.Str2Int64WithDefault(vendorSkuID, 0),
IsFilterDel: jdapi.IsFilterDelTrue,
PageNo: 1,
PageSize: jdapi.MaxSkuIDsCount4QueryListBySkuIds, // 为了同时取图这个值不要大于jdapi.MaxSkuIDsCount4QueryListBySkuIds
}
for {
skuList, _, err2 := getAPI(vendorOrgCode).QuerySkuInfos(param)
if err = err2; err != nil {
return nil, err
}
if len(skuList) > 0 {
batchSkuNameList := make([]*partner.SkuNameInfo, len(skuList))
for k, v := range skuList {
batchSkuNameList[k] = vendorSku2Jx(v)
}
setSkuNameListPic(vendorOrgCode, batchSkuNameList)
skuNameList = append(skuNameList, batchSkuNameList...)
}
if len(skuList) < param.PageSize {
break
}
param.PageNo++
}
return skuNameList, err
}
func setSkuNameListPic(vendorOrgCode string, skuNameList []*partner.SkuNameInfo) []*partner.SkuNameInfo {
jdSkuIDs := make([]int64, len(skuNameList))
for k, v := range skuNameList {
jdSkuIDs[k] = utils.Str2Int64(v.SkuList[0].VendorSkuID)
}
imgMap := make(map[int64]*jdapi.ImgHandleQueryResult)
if imgList, err2 := getAPI(vendorOrgCode).QueryListBySkuIds(&jdapi.QueryListBySkuIdsParam{
SkuIDs: jdSkuIDs,
}); err2 == nil {
for _, v := range imgList {
if v.ImgType == jdapi.ImgTypeMain {
imgResult := imgMap[v.SkuID]
if imgResult == nil || imgResult.IsMain < v.IsMain {
imgMap[v.SkuID] = v
}
}
}
}
// 使用扒页面方式获取商品图片
if false {
var leftJdSkuIDs []int64
for _, v := range jdSkuIDs {
if imgMap[v] == nil {
leftJdSkuIDs = append(leftJdSkuIDs, v)
}
}
task := tasksch.NewParallelTask("jd setSkuNameListPic", nil, jxcontext.AdminCtx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
jdSkuID := batchItemList[0].(int64)
imgList, err := getAPI(vendorOrgCode).GetSkuPageImageInfo(jdSkuID)
if err == nil && len(imgList) > 0 {
retVal = [][]string{
[]string{utils.Int64ToStr(jdSkuID), imgList[0].Big},
}
}
return retVal, err
}, leftJdSkuIDs)
task.Run()
if resultList, err := task.GetResult(0); err == nil {
for _, v := range resultList {
strList := v.([]string)
imgMap[utils.Str2Int64(strList[0])] = &jdapi.ImgHandleQueryResult{
SourceImgURL: strList[1],
}
}
}
}
// 设置商品图片
for _, v := range skuNameList {
if imgResult := imgMap[utils.Str2Int64(v.SkuList[0].VendorSkuID)]; imgResult != nil {
v.PictureList = []string{imgResult.SourceImgURL}
}
}
return skuNameList
}
func vendorSku2Jx(vendorSku *jdapi.SkuMain) (skuName *partner.SkuNameInfo) {
prefix, name, comment, specUnit, unit, specQuality := jxutils.SplitSkuName(vendorSku.SkuName)
weight := int(vendorSku.Weight * 1000)
if weight <= 0 {
weight = jxutils.FormatSkuWeight(specQuality, specUnit)
}
skuID := int(utils.Str2Int64WithDefault(vendorSku.OutSkuID, 0))
vendorSkuID := utils.Int64ToStr(vendorSku.SkuID)
skuName = &partner.SkuNameInfo{
NameID: skuID,
VendorNameID: vendorSkuID,
VendorCatIDList: []string{utils.Int64ToStr(vendorSku.CategoryID)},
Prefix: prefix,
Name: name,
Unit: unit,
SkuList: []*partner.SkuInfo{
&partner.SkuInfo{
StoreSkuInfo: partner.StoreSkuInfo{
VendorSkuID: vendorSkuID,
SkuID: skuID,
VendorPrice: int64(vendorSku.SkuPrice),
Status: jdStatus2jxStatus(vendorSku.FixedStatus),
},
SkuName: vendorSku.SkuName,
Comment: comment,
SpecQuality: float64(specQuality),
SpecUnit: specUnit,
Weight: weight,
},
},
}
return skuName
}
func jdStatus2jxStatus(jdStatus int) (jxStatus int) {
switch jdStatus {
case jdapi.SkuFixedStatusOnline:
jxStatus = model.SkuStatusNormal
case jdapi.SkuFixedStatusOffline:
jxStatus = model.SkuStatusDontSale
case jdapi.SkuFixedStatusDeleted:
jxStatus = model.SkuStatusDeleted
}
return jxStatus
}
func jxStatus2jdStatus(jxStatus int) (jdStatus int) {
switch jxStatus {
case model.SkuStatusNormal:
jdStatus = jdapi.SkuFixedStatusOnline
case model.SkuStatusDontSale:
jdStatus = jdapi.SkuFixedStatusOffline
case model.SkuStatusDeleted:
jdStatus = jdapi.SkuFixedStatusDeleted
}
return jdStatus
}
func isSkuMustHaveUpc(unit string, vendorVendorCatID int64) bool {
return unit != model.SpecialUnit || !upcLessMap[vendorVendorCatID]
}
var (
upcLessMap = map[int64]bool{
20250: true,
20252: true,
20258: true,
20259: true,
20261: true,
20262: true,
20263: true,
20264: true,
20265: true,
20266: true,
20267: true,
22822: true,
20269: true,
20270: true,
20271: true,
20272: true,
20273: true,
20275: true,
20276: true,
20277: true,
20278: true,
20279: true,
20281: true,
20282: true,
20283: true,
20285: true,
20286: true,
20287: true,
22821: true,
20289: true,
20290: true,
23018: true,
20354: true,
20355: true,
20357: true,
20359: true,
23019: true,
20294: true,
20295: true,
20296: true,
20297: true,
20298: true,
20299: true,
20300: true,
20302: true,
20303: true,
20304: true,
22840: true,
22841: true,
20317: true,
20320: true,
20321: true,
20323: true,
20325: true,
20326: true,
20328: true,
20329: true,
20331: true,
20335: true,
20337: true,
20338: true,
20339: true,
22842: true,
22843: true,
23020: true,
20309: true,
20310: true,
20311: true,
20312: true,
20313: true,
20314: true,
20315: true,
22410: true,
23050: true,
20319: true,
20322: true,
20330: true,
20332: true,
20334: true,
20336: true,
20340: true,
20342: true,
23049: true,
20356: true,
20358: true,
20360: true,
20361: true,
20362: true,
20364: true,
}
)

View File

@@ -1,61 +0,0 @@
package jd
import (
"testing"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
)
func TestCreateSku(t *testing.T) {
// t.Log(beego.BConfig.RunMode)
skuID := 21741
sku := &model.Sku{}
sku.ID = skuID
dao.GetEntity(nil, sku)
t.Log(sku)
// err := CurPurchaseHandler.CreateSku(sku)
// if err != nil {
// t.Fatal(err.Error())
// }
}
func TestGetAllCategories(t *testing.T) {
result, err := CurPurchaseHandler.GetAllCategories(jxcontext.AdminCtx, "")
if err != nil || len(result) == 0 {
t.Fatal(err.Error())
}
t.Log(utils.Format4Output(result, false))
}
// func TestReadSku(t *testing.T) {
// skuName, err := CurPurchaseHandler.ReadSku(jxcontext.AdminCtx, "", "2005582952")
// t.Log(utils.Format4Output(skuName, false))
// if err != nil {
// t.Fatal(err.Error())
// }
// if skuName.Name != "味事达酱香鲜特级酿造酱油" || skuName.Skus[0].SpecUnit != "ml" {
// t.Fatal("ReadSku return data wrong")
// t.Log(string(utils.MustMarshal(skuName)))
// }
// }
func TestGetVendorCategories(t *testing.T) {
catList, err := CurPurchaseHandler.GetVendorCategories(jxcontext.AdminCtx)
if err != nil {
t.Fatal(err.Error())
}
t.Log(utils.Format4Output(catList, false))
}
func TestGetSkus(t *testing.T) {
skuNameList, err := CurPurchaseHandler.GetSkus(jxcontext.AdminCtx, "", 0, "2023747677")
t.Log(utils.Format4Output(skuNameList, false))
t.Log(len(skuNameList))
if err != nil {
t.Fatal(err.Error())
}
}

View File

@@ -1,520 +0,0 @@
package jd
import (
"fmt"
"strings"
"time"
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
"git.rosy.net.cn/jx-callback/business/jxutils"
"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/dao"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/baseapi/platformapi/jdapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/baseapi/utils/errlist"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/globals/api"
)
type tJdStoreInfo struct {
model.Store
VendorOrgCode string `orm:"size(32)" json:"vendorOrgCode"` // 同一平台下不同的商户代码,如果只有一个,可以为空
FreightDeductionPack string `orm:"size(32)" json:"freightDeductionPack"` //
JdCityCode int
JdDistrictCode int
JdStoreStatus int
VendorStoreID string `orm:"column(vendor_store_id)"`
RealLastOperator string
SyncStatus int
VendorStoreName string
}
var (
specialDistrictMap = map[int]int{
13989: 310032,
}
)
func (p *PurchaseHandler) ReadStore(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID string) (*dao.StoreDetail, error) {
a := getAPI(vendorOrgCode)
result, err := a.GetStoreInfoByStationNo2(vendorStoreID)
if err == nil {
retVal := &dao.StoreDetail{
Store: model.Store{
Address: result.StationAddress,
OpenTime1: JdOperationTime2JxOperationTime(result.ServiceTimeStart1),
CloseTime1: JdOperationTime2JxOperationTime(result.ServiceTimeEnd1),
OpenTime2: JdOperationTime2JxOperationTime(result.ServiceTimeStart2),
CloseTime2: JdOperationTime2JxOperationTime(result.ServiceTimeEnd2),
Status: JdStoreStatus2JxStatus(int(result.Yn), result.CloseStatus),
Tel1: result.Phone,
},
}
if result.IsAutoOrder == 0 {
retVal.IsAutoOrder = 1
} else {
retVal.IsAutoOrder = -1
}
retVal.OriginalName = result.StationName
_, retVal.Name = jxutils.SplitStoreName(retVal.OriginalName, partner.StoreNameSeparator, globals.StoreName)
retVal.DeliveryType = JdDeliveryType2Jx(result.CarrierNo)
tel2 := result.Mobile
if tel2 != "" && tel2 != retVal.Tel1 {
retVal.Tel2 = tel2
}
lng := result.Lng
lat := result.Lat
retVal.Lng = jxutils.StandardCoordinate2Int(lng)
retVal.Lat = jxutils.StandardCoordinate2Int(lat)
db := dao.GetDB()
cityCode := result.City
if cityCode != 0 {
if place, err2 := dao.GetPlaceByJdCode(db, cityCode); err2 == nil {
if place.Level == model.PlaceLevelCity {
retVal.CityCode = place.Code
retVal.CityName = utils.Interface2String(result.CityName)
districtName := result.CountyName // 京东的市区号码与通用数据完全无法关联,只有通过名字来关联
if retVal.CityCode != 0 && districtName != "" {
if district, err2 := dao.GetPlaceByName(db, districtName, 3, place.Code); err2 == nil {
retVal.DistrictCode = district.Code
}
}
} else if place.Level == model.PlaceLevelDistrict {
retVal.CityCode = place.ParentCode
retVal.DistrictCode = place.Code
} else {
globals.SugarLogger.Warnf("门店:%s的城市码:%d异常", vendorStoreID, cityCode)
}
}
}
if retVal.DistrictCode == 0 {
retVal.DistrictCode = api.AutonaviAPI.GetCoordinateDistrictCode(lng, lat)
if retVal.CityCode == 0 {
if district, err := dao.GetPlaceByCode(db, retVal.DistrictCode); err == nil {
retVal.CityCode = district.ParentCode
}
}
}
retVal.VendorStoreID = vendorStoreID
retVal.ID = int(utils.Str2Int64WithDefault(result.OutSystemID, 0))
deliveryRange, err2 := a.GetDeliveryRangeByStationNo2(vendorStoreID)
if err = err2; err == nil {
retVal.DeliveryRangeType = int8(deliveryRange.DeliveryRangeType)
if retVal.DeliveryRangeType == model.DeliveryRangeTypePolygon {
retVal.DeliveryRange = strings.Trim(deliveryRange.DeliveryRange, ";")
} else {
retVal.DeliveryRange = utils.Int2Str(deliveryRange.DeliveryRangeRadius)
}
return retVal, nil
}
}
return nil, err
}
// stoerIDs为nil表示所有
func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName string) (err error) {
var stores []*tJdStoreInfo
sql := `
SELECT
t1.*, city.jd_code jd_city_code, district.jd_code jd_district_code,
t2.status jd_store_status, t2.vendor_store_id, IF(t1.updated_at > t2.updated_at, t1.last_operator,
t2.last_operator) real_last_operator,
t2.sync_status, t2.freight_deduction_pack, t2.vendor_org_code, t2.vendor_store_name
FROM store t1
JOIN store_map t2 ON t1.id = t2.store_id AND t2.vendor_id = ? AND (t2.deleted_at = ?)
LEFT JOIN place city ON t1.city_code = city.code
LEFT JOIN place district ON t1.district_code = district.code
WHERE t1.id = ?
ORDER BY t2.updated_at
`
if err = dao.GetRows(db, &stores, sql, model.VendorIDJD, utils.DefaultTimeValue, storeID); err == nil {
for _, store := range stores {
a := getAPI(store.VendorOrgCode)
// phone := ""
// if store.MarketManPhone != "" {
// phone = store.MarketManPhone
// } else {
// phone = model.VendorStoreTel
// }
storeParams := &jdapi.OpStoreParams{
StationNo: store.VendorStoreID,
Operator: userName,
Phone: store.Tel1,
Mobile: store.Tel1,
}
if store.SyncStatus&model.SyncFlagDeletedMask == 0 {
storeParams.OutSystemID = utils.Int2Str(int(store.ID))
} else {
storeParams.OutSystemID = store.VendorStoreID
}
if store.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagStoreName) != 0 {
if store.VendorStoreName != "" {
storeParams.StationName = store.VendorStoreName
} else {
storeParams.StationName = jxutils.ComposeStoreName(store.Name, model.VendorIDJD)
}
storeParams.StationName = utils.LimitUTF8StringLen(storeParams.StationName, jdapi.MaxStoreNameLen)
}
if store.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagStoreAddress) != 0 {
storeParams.StationAddress = store.Address
storeParams.CoordinateType = jdapi.CoordinateTypeAutonavi // 一直用高德
storeParams.Lng = jxutils.IntCoordinate2Standard(store.Lng)
storeParams.Lat = jxutils.IntCoordinate2Standard(store.Lat)
if store.JdCityCode != 0 {
storeParams.City = store.JdCityCode
}
if store.JdDistrictCode != 0 {
storeParams.County = store.JdDistrictCode
//TODO 彭州市做特殊处理 2020-05-25
if store.JdDistrictCode == 49318 {
storeParams.City = 49318
storeParams.County = 310045
}
}
// storeParams.DeliveryRangeType = store.DeliveryRangeType
// if store.DeliveryRangeType == model.DeliveryRangeTypePolygon {
// storeParams.CoordinatePoints = store.DeliveryRange
// } else {
// storeParams.DeliveryRangeRadius = int(utils.Str2Int64WithDefault(store.DeliveryRange, 0))
// }
}
if specialDistrictMap[storeParams.County] != 0 {
storeParams.City = storeParams.County
storeParams.County = specialDistrictMap[storeParams.County]
}
storeParams.StoreNotice = store.PromoteInfo
modifyCloseStatus := false
if store.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagDeletedMask|model.SyncFlagStoreStatus) != 0 {
modifyCloseStatus = true
_, storeParams.CloseStatus = JxStoreStatus2JdStatus(jxutils.MergeStoreStatus(store.Status, store.JdStoreStatus))
}
fillOpTimeParams(storeParams, store.GetOpTimeList())
// globals.SugarLogger.Debug(utils.Format4Output(storeParams, false))
errList := errlist.New()
if globals.EnableJdStoreWrite {
errList.AddErr(a.UpdateStoreInfo4Open2(storeParams, modifyCloseStatus))
}
if store.FreightDeductionPack != "" {
storeDetail, err2 := dao.GetStoreDetail(db, store.ID, model.VendorIDJD)
if err2 == nil {
if storeDetail.FreightDeductionPackObj != nil {
freightParams := &jdapi.UpdateStoreFreightParam{
StationNo: store.VendorStoreID,
UserPin: userName,
OpenDistanceFreight: true,
StartCharge: int64(storeDetail.FreightDeductionPackObj.StartPrice),
}
if len(storeDetail.FreightDeductionPackObj.FreightDeductionList) > 0 {
for _, v := range storeDetail.FreightDeductionPackObj.FreightDeductionList {
if v.DeductFreight > 0 {
freightParams.FreeFreightInfoList = append(freightParams.FreeFreightInfoList, &jdapi.FreeFreightInfo{
FullFreeMoney: int64(v.BeginPrice),
FreeType: jdapi.FreightFreeTypePartBase,
FreeMoney: int64(v.DeductFreight),
FreeFreightTimes: []*jdapi.FreeFreightTime{
&jdapi.FreeFreightTime{
FreeBeginTime: utils.Time2Str(time.Now()),
FreeEndTime: utils.Time2Str(time.Now().Add(24 * time.Hour * 365 * 2)),
},
},
})
break // 京东只能设置一个满减,之前理解有误
}
}
}
freightParams.IsFullFree = len(freightParams.FreeFreightInfoList) > 0
// globals.SugarLogger.Debug(utils.Format4Output(freightParams, false))
if globals.EnableJdStoreWrite {
errList.AddErr(a.UpdateStoreFreightConfigNew(freightParams))
}
}
}
}
err = errList.GetErrListAsOne()
}
}
return err
}
func (p *PurchaseHandler) RefreshAllStoresID(ctx *jxcontext.Context, parentTask tasksch.ITask, isAsync bool) (hint string, err error) {
globals.SugarLogger.Debugf("jd RefreshAllStoresID")
const stepCount = 3
var stores []*tJdStoreInfo
db := dao.GetDB()
rootTask := tasksch.NewSeqTask("jd RefreshAllStoresID", ctx,
func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
switch step {
case 0:
err = dao.GetRows(db, &stores, `
SELECT t1.*, t2.vendor_store_id
FROM store t1
JOIN store_map t2 ON t1.id = t2.store_id AND t2.deleted_at = ? AND t2.vendor_id = ?
WHERE t1.deleted_at = ?
`, utils.DefaultTimeValue, model.VendorIDJD, utils.DefaultTimeValue)
default:
taskName := "jd RefreshAllStoresID update outSystemId"
if step != stepCount-1 {
taskName = "jd RefreshAllStoresID update to uuid"
}
task1 := tasksch.NewParallelTask(taskName, nil, ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
store := batchItemList[0].(*tJdStoreInfo)
storeParams := &jdapi.OpStoreParams{
StationNo: store.VendorStoreID,
Operator: ctx.GetUserName(),
OutSystemID: utils.Int2Str(int(store.ID)),
}
if step != stepCount-1 {
storeParams.OutSystemID = store.VendorStoreID
}
if globals.EnableJdStoreWrite {
err = getAPI(store.VendorOrgCode).UpdateStoreInfo4Open2(storeParams, false)
}
return nil, err
}, stores)
task.AddChild(task1).Run()
_, err = task1.GetResult(0)
}
return nil, err
}, stepCount)
tasksch.HandleTask(rootTask, parentTask, false).Run()
if !isAsync {
_, err = rootTask.GetResult(0)
}
return rootTask.ID, err
}
func JdDeliveryType2Jx(deliveryType int) int8 {
if deliveryType == jdapi.CarrierNoSelfDelivery {
return scheduler.StoreDeliveryTypeByStore
} else if deliveryType == jdapi.CarrierNoCrowdSourcing {
return scheduler.StoreDeliveryTypeCrowdSourcing
}
return scheduler.StoreDeliveryTypeByPlatform
}
func (p *PurchaseHandler) GetStoreStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string) (storeStatus int, err error) {
result, err := getAPI(vendorOrgCode).GetStoreInfoByStationNo2(vendorStoreID)
if err == nil {
storeStatus = JdStoreStatus2JxStatus(int(result.Yn), result.CloseStatus)
}
return storeStatus, err
}
// 当前京东的storeCrud消息不会在门店状态改变时发送所以意义不大先放在这里
func (c *PurchaseHandler) OnStoreMsg(vendorOrgCode string, msg *jdapi.CallbackOrderMsg) (response *jdapi.CallbackResponse) {
var err error
// if msg.StatusID == jdapi.StatusIDUpdateStore {
// var storeStatus int
// vendorStoreID := msg.BillID
// if storeStatus, err = c.GetStoreStatus(jxcontext.AdminCtx, vendorStoreID); err == nil {
// err = partner.CurStoreManager.OnStoreStatusChanged(vendorStoreID, model.VendorIDJD, storeStatus)
// } else {
// // 可能在门店删除的情况下会出查不到门店的错误
// if errExt, ok := err.(*utils.ErrorWithCode); ok && errExt.IntCode() == 4 {
// err = nil
// }
// }
// }
return jdapi.Err2CallbackResponse(err, "")
}
func (p *PurchaseHandler) EnableAutoAcceptOrder(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, isSetEnable bool) (err error) {
_, err = getAPI(vendorOrgCode).UpdateStoreConfig4Open(vendorStoreID, isSetEnable)
return err
}
func (c *PurchaseHandler) UpdateStoreStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, status int) (err error) {
_, closeStatus := JxStoreStatus2JdStatus(status)
if globals.EnableJdStoreWrite {
err = getAPI(vendorOrgCode).UpdateStoreInfo4Open2(&jdapi.OpStoreParams{
StationNo: vendorStoreID,
Operator: ctx.GetUserName(),
CloseStatus: closeStatus,
}, true)
}
return err
}
func fillOpTimeParams(params *jdapi.OpStoreParams, opTimeList []int16) {
index := 1
opTimeListLen := len(opTimeList)
if opTimeListLen > 4 {
opTimeListLen = 4
}
opTimeListLen = opTimeListLen / 2 * 2
for k := 0; k < len(opTimeList); k += 2 {
if opTimeList[k] != 0 {
if index == 1 {
params.ServiceTimeStart1 = int(JxOperationTime2JdOperationTime(int16(opTimeList[k])))
params.ServiceTimeEnd1 = int(JxOperationTime2JdOperationTime(int16(opTimeList[k+1])))
} else {
params.ServiceTimeStart2 = int(JxOperationTime2JdOperationTime(int16(opTimeList[k])))
params.ServiceTimeEnd2 = int(JxOperationTime2JdOperationTime(int16(opTimeList[k+1])))
}
} else {
break
}
index++
}
}
func (c *PurchaseHandler) UpdateStoreOpTime(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, opTimeList []int16) (err error) {
params := &jdapi.OpStoreParams{
StationNo: vendorStoreID,
Operator: ctx.GetUserName(),
}
fillOpTimeParams(params, opTimeList)
if globals.EnableJdStoreWrite {
err = getAPI(vendorOrgCode).UpdateStoreInfo4Open2(params, false)
}
return err
}
func (c *PurchaseHandler) GetAllStoresVendorID(ctx *jxcontext.Context, vendorOrgCode string) (vendorStoreIDs []string, err error) {
vendorStoreIDs, err = getAPI(vendorOrgCode).GetStationsByVenderId()
return vendorStoreIDs, err
}
func (c *PurchaseHandler) storeUploadImgByURL(vendorOrgCode, inImgURL string) (imgURL string, err error) {
if globals.EnableJdStoreWrite {
if vendorOrgCode == globals.JdOrgCode {
imgURL, err = api.JdPageAPI.StoreUploadImgByURL(inImgURL)
} else {
imgURL, err = getAPI(vendorOrgCode).StoreUploadImgByURL(inImgURL)
}
} else {
imgURL = utils.GetUUID()
}
return imgURL, err
}
func addStoreInfo2Err(err error, storeID int) error {
if err != nil {
errExt, _ := err.(*utils.ErrorWithCode)
if errExt == nil {
errExt = utils.NewErrorCode(err.Error(), "999")
}
errExt.AddPrefixMsg(fmt.Sprintf("门店%d", storeID))
err = errExt
}
return err
}
func (c *PurchaseHandler) SyncQualify(ctx *jxcontext.Context, storeDetail *dao.StoreDetail) (err error) {
if storeDetail.LicenceCode == "" || storeDetail.Licence == "" {
return addStoreInfo2Err(fmt.Errorf("营业执照信息不全"), storeDetail.ID)
}
if storeDetail.IDCode == "" || storeDetail.IDCardFront == "" || storeDetail.IDCardBack == "" || storeDetail.IDValid == "" {
return addStoreInfo2Err(fmt.Errorf("个人信息不全"), storeDetail.ID)
}
var qualifyList []*jdapi.QualifyItem
licenceDetail, err := api.JdPageAPI.GetCorporationInfo(storeDetail.VendorStoreID, storeDetail.LicenceCode)
if err != nil {
return addStoreInfo2Err(err, storeDetail.ID)
}
licenceURL, err := c.storeUploadImgByURL(storeDetail.VendorOrgCode, storeDetail.Licence)
if err != nil {
return addStoreInfo2Err(err, storeDetail.ID)
}
expireStart, err := utils.TryStr2Time(licenceDetail.StartDate)
if err != nil {
return addStoreInfo2Err(fmt.Errorf("执照有效开始时间:%s非法请手动处理", licenceDetail.StartDate), storeDetail.ID)
}
qualifyList = append(qualifyList, &jdapi.QualifyItem{
QualifyType: jdapi.QualifyTypeCompany,
QualifyURL: licenceURL,
QualifyExpireStart: utils.Time2Str(expireStart),
QualifyExpireForever: 0,
QualifyName: licenceDetail.OperName,
LicenceType: "-1",
QualifyNumber: storeDetail.LicenceCode,
QualifyAddress: licenceDetail.Address,
LicenceName: licenceDetail.Name,
EconKind: licenceDetail.EconKind,
Scope: licenceDetail.Scope,
})
idFrondURL, err := c.storeUploadImgByURL(storeDetail.VendorOrgCode, storeDetail.IDCardFront)
if err != nil {
return addStoreInfo2Err(err, storeDetail.ID)
}
// 个体经营,个体工商户
if storeDetail.LicenceType == 0 { // 个人
personQualify := &jdapi.QualifyItem{
QualifyType: jdapi.QualifyTypePerson,
QualifyURL: idFrondURL,
QualifyExpireStart: utils.Time2Str(utils.Str2Time(storeDetail.IDValid)),
QualifyExpireForever: 0,
QualifyNumber: storeDetail.IDCode,
QualifyOwner: storeDetail.LicenceOwnerName,
}
if storeDetail.IDExpire != "" {
personQualify.QualifyExpireForever = 1
personQualify.QualifyExpireEnd = utils.Time2Str(utils.Str2Time(storeDetail.IDExpire))
}
qualifyList = append(qualifyList, personQualify)
} else {
addInfo := &jdapi.QualifyItem{
QualifyType: jdapi.QualifyTypeAddInfo,
QualifyURL: idFrondURL,
QualifyExpireStart: utils.Time2Str(utils.Str2Time(storeDetail.IDValid)),
QualifyExpireForever: 0,
}
if storeDetail.IDExpire != "" {
addInfo.QualifyExpireForever = 1
addInfo.QualifyExpireEnd = utils.Time2Str(utils.Str2Time(storeDetail.IDExpire))
}
qualifyList = append(qualifyList, addInfo)
}
if storeDetail.IDExpire == "" {
idBackURL, err := c.storeUploadImgByURL(storeDetail.VendorOrgCode, storeDetail.IDCardBack)
if err != nil {
return addStoreInfo2Err(err, storeDetail.ID)
}
qualifyList = append(qualifyList, &jdapi.QualifyItem{
QualifyType: jdapi.QualifyTypeAddInfo,
QualifyURL: idBackURL,
QualifyExpireStart: utils.Time2Str(utils.Str2Time(storeDetail.IDValid)),
QualifyExpireForever: 0,
})
}
globals.SugarLogger.Debug(utils.Format4Output(qualifyList, false))
if globals.EnableJdStoreWrite {
globals.SugarLogger.Debugf("SaveQualifyTest4,[%v]", utils.Format4Output(qualifyList, false))
err = api.JdPageAPI.SaveQualify(storeDetail.VendorStoreID, jdapi.SaveQualifyActionTypeCommit, qualifyList)
// err = api.JdPageAPI.SaveQualify(storeDetail.VendorStoreID, jdapi.SaveQualifyActionTypeSave, qualifyList)
}
return addStoreInfo2Err(err, storeDetail.ID)
}
func (c *PurchaseHandler) UpdateStoreCustomID(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID string, storeID int64) (err error) {
if globals.EnableJdStoreWrite {
err = getAPI(vendorOrgCode).UpdateStoreInfo4Open2(
&jdapi.OpStoreParams{
StationNo: vendorStoreID,
Operator: ctx.GetUserName(),
OutSystemID: utils.Int2Str(int(storeID)),
}, false)
}
return err
}
func (p *PurchaseHandler) CreateStore2(db *dao.DaoDB, storeID int, userName string) (vendorStoreID string, err error) {
return vendorStoreID, err
}
func (p *PurchaseHandler) DeleteStore(db *dao.DaoDB, storeID int, userName string) (err error) {
return err
}

View File

@@ -1,300 +0,0 @@
package jd
import (
"git.rosy.net.cn/baseapi/platformapi/jdapi"
"git.rosy.net.cn/baseapi/utils"
"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"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/business/partner/putils"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api/apimanager"
)
func (p *PurchaseHandler) GetStoreSkusBatchSize(funcID int) (batchSize int) {
switch funcID {
case partner.FuncUpdateStoreSkusStock, partner.FuncUpdateStoreSkusStatus, partner.FuncUpdateStoreSkusPrice:
batchSize = jdapi.MaxStoreSkuBatchSize
case partner.FuncCreateActs, partner.FuncCancelActs:
batchSize = 1
}
return batchSize
}
func (p *PurchaseHandler) getStoreSkusBareInfoLimitSize(ctx *jxcontext.Context, vendorOrgCode string, parentTask tasksch.ITask, storeID int, vendorStoreID string, inStoreSkuList []*partner.StoreSkuInfo) (outStoreSkuList []*partner.StoreSkuInfo, err error) {
var batchSkuInfoList []*jdapi.BaseStockCenterRequest
batchSkuList := partner.BareStoreSkuInfoList(inStoreSkuList).GetVendorSkuIDIntList()
for _, v := range inStoreSkuList {
if !dao.IsVendorThingIDEmpty(v.VendorSkuID) {
batchSkuInfoList = append(batchSkuInfoList, &jdapi.BaseStockCenterRequest{
StationNo: vendorStoreID,
SkuId: utils.Str2Int64(v.VendorSkuID),
})
}
}
if len(batchSkuInfoList) > 0 {
var stockInfo []*jdapi.QueryStockResponse
var priceInfo []*jdapi.StorePriceInfo
task := tasksch.NewParallelTask("获取京东到家平台门店商品信息", tasksch.NewParallelConfig().SetParallelCount(2), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
subTaskID := batchItemList[0].(int)
if subTaskID == 0 {
stockInfo, err = getAPI(vendorOrgCode).QueryOpenUseable(batchSkuInfoList)
} else {
priceInfo, err = getAPI(vendorOrgCode).GetStationInfoList(vendorStoreID, batchSkuList)
}
return nil, err
}, []int{0, 1})
tasksch.HandleTask(task, parentTask, false).Run()
_, err = task.GetResult(0)
if err == nil {
storeSkuMap := putils.StoreSkuList2MapByVendorSkuID(inStoreSkuList)
for _, v := range stockInfo {
sku := storeSkuMap[utils.Int64ToStr(v.SkuID)]
sku.Status = jdStoreSkuStatus2Jx(v.Vendibility)
sku.Stock = v.UsableQty
if sku.Stock > 0 {
outStoreSkuList = append(outStoreSkuList, sku)
}
}
for _, v := range priceInfo {
sku := storeSkuMap[utils.Int64ToStr(v.SkuID)]
sku.VendorPrice = v.Price
}
}
}
return outStoreSkuList, err
}
func (p *PurchaseHandler) GetStoreSkusBareInfo(ctx *jxcontext.Context, vendorOrgCode string, parentTask tasksch.ITask, storeID int, vendorStoreID string, inStoreSkuList []*partner.StoreSkuInfo) (outStoreSkuList []*partner.StoreSkuInfo, err error) {
result, err := putils.FreeBatchStoreSkuInfo("获取门店商品信息", func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) {
list, err := p.getStoreSkusBareInfoLimitSize(ctx, vendorOrgCode, task, storeID, vendorStoreID, batchedStoreSkuList)
if err == nil {
result = list
}
return result, len(list), err
}, ctx, parentTask, inStoreSkuList, jdapi.MaxStoreSkuBatchSize, true)
for _, v := range result {
outStoreSkuList = append(outStoreSkuList, v.(*partner.StoreSkuInfo))
}
return outStoreSkuList, err
}
func jdStoreSkuStatus2Jx(jdStoreSkuStatus int) (jxSkuStatus int) {
if jdStoreSkuStatus == 0 {
jxSkuStatus = model.SkuStatusNormal
} else {
jxSkuStatus = model.SkuStatusDontSale
}
return jxSkuStatus
}
func jxStoreSkuStatus2Jd(jxStoreSkuStatus int) (isSale bool) {
return jxStoreSkuStatus == model.SkuStatusNormal
}
func isErrPartialFailed(err error) bool {
if errExt, ok := err.(*utils.ErrorWithCode); ok && errExt.Code() == jdapi.ResponseInnerCodePartialFailed {
return true
}
return false
}
func getStrOutSkuIDs(l []*jdapi.StoreSkuBatchUpdateResponse, isSuccess bool) (outSkuIDs []string) {
for _, v := range l {
if isSuccess && jdapi.IsCodeSuccess(v.Code) {
outSkuIDs = append(outSkuIDs, v.OutSkuID)
} else if !isSuccess && !jdapi.IsCodeSuccess(v.Code) {
outSkuIDs = append(outSkuIDs, v.OutSkuID)
}
}
return outSkuIDs
}
func (p *PurchaseHandler) UpdateStoreSkusStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo, status int) (failedList []*partner.StoreSkuInfoWithErr, err error) {
var skuVendibilityList []*jdapi.StockVendibility
jdStatus := jxStoreSkuStatus2Jd(status)
for _, v := range storeSkuList {
skuVendibilityList = append(skuVendibilityList, &jdapi.StockVendibility{
OutSkuId: utils.Int2Str(v.SkuID),
DoSale: jdStatus,
})
}
if globals.EnableJdStoreWrite {
var responseList []*jdapi.StoreSkuBatchUpdateResponse
var err2 error
if vendorOrgCode != apimanager.FakeJdOrgCode {
responseList, err2 = getAPI(vendorOrgCode).BatchUpdateVendibility(ctx.GetTrackInfo(), "", vendorStoreID, skuVendibilityList, ctx.GetUserName())
} else {
responseList, err2 = getAPI(vendorOrgCode).FakeBatchUpdateVendibility(ctx.GetTrackInfo(), "", vendorStoreID, skuVendibilityList, ctx.GetUserName())
}
if err = err2; err != nil {
failedList = SelectStoreSkuListByResponseList(storeSkuList, responseList, storeID, model.VendorChineseNames[model.VendorIDJD], "更新商品状态")
// successList = putils.UnselectStoreSkuListBySkuIDs(storeSkuList, utils.StringSlice2Int(getStrOutSkuIDs(responseList, false)))
}
}
err = nil
return failedList, err
}
func (p *PurchaseHandler) UpdateStoreSkusPrice(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
if len(storeSkuList) == 1 && vendorOrgCode != apimanager.FakeJdOrgCode {
if globals.EnableJdStoreWrite {
_, err = getAPI(vendorOrgCode).UpdateStationPrice(ctx.GetTrackInfo(), utils.Str2Int64WithDefault(storeSkuList[0].VendorSkuID, 0), vendorStoreID, int(storeSkuList[0].VendorPrice))
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDJD], "更新商品价格")
}
} else {
var skuPriceInfoList []*jdapi.SkuPriceInfo
for _, v := range storeSkuList {
skuPriceInfoList = append(skuPriceInfoList, &jdapi.SkuPriceInfo{
OutSkuId: utils.Int2Str(v.SkuID),
Price: int(v.VendorPrice),
})
}
if globals.EnableJdStoreWrite {
var responseList []*jdapi.StoreSkuBatchUpdateResponse
var err2 error
if vendorOrgCode != apimanager.FakeJdOrgCode {
responseList, err2 = getAPI(vendorOrgCode).UpdateVendorStationPrice(ctx.GetTrackInfo(), "", vendorStoreID, skuPriceInfoList)
} else {
responseList, err2 = getAPI(vendorOrgCode).FakeUpdateVendorStationPrice(ctx.GetTrackInfo(), "", vendorStoreID, skuPriceInfoList)
}
if err = err2; err != nil {
failedList = SelectStoreSkuListByResponseList(storeSkuList, responseList, storeID, model.VendorChineseNames[model.VendorIDJD], "更新商品价格")
}
}
}
err = nil
return failedList, err
}
func (p *PurchaseHandler) UpdateStoreSkusStock(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
if len(storeSkuList) == 1 && vendorOrgCode != apimanager.FakeJdOrgCode {
if globals.EnableJdStoreWrite {
err = getAPI(vendorOrgCode).UpdateCurrentQty(ctx.GetTrackInfo(), vendorStoreID, utils.Str2Int64WithDefault(storeSkuList[0].VendorSkuID, 0), storeSkuList[0].Stock)
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDJD], "更新商品库存")
}
} else {
var skuStockList []*jdapi.SkuStock
for _, v := range storeSkuList {
skuStockList = append(skuStockList, &jdapi.SkuStock{
OutSkuId: utils.Int2Str(v.SkuID),
StockQty: v.Stock,
})
}
if globals.EnableJdStoreWrite {
var responseList []*jdapi.StoreSkuBatchUpdateResponse
var err2 error
if vendorOrgCode != apimanager.FakeJdOrgCode {
responseList, err2 = getAPI(vendorOrgCode).BatchUpdateCurrentQtys(ctx.GetTrackInfo(), "", vendorStoreID, skuStockList, ctx.GetUserName())
} else {
responseList, err2 = getAPI(vendorOrgCode).FakeBatchUpdateCurrentQtys(ctx.GetTrackInfo(), "", vendorStoreID, skuStockList, ctx.GetUserName())
}
if err = err2; err != nil {
failedList = SelectStoreSkuListByResponseList(storeSkuList, responseList, storeID, model.VendorChineseNames[model.VendorIDJD], "更新商品库存")
// successList = putils.UnselectStoreSkuListBySkuIDs(storeSkuList, utils.StringSlice2Int(getStrOutSkuIDs(responseList, false)))
}
}
}
err = nil
return failedList, err
}
func (p *PurchaseHandler) SyncStoreProducts(ctx *jxcontext.Context, vendorOrgCode string, parentTask tasksch.ITask, storeID int, skuIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) {
globals.SugarLogger.Debugf("jd SyncStoreProducts, storeID:%d", storeID)
db := dao.GetDB()
storeDetail, err := dao.GetStoreDetail(db, storeID, model.VendorIDJD)
if err != nil {
return "", err
}
storeSkuList, err := dao.GetStoreSkus2(db, model.VendorIDJD, storeID, skuIDs, false)
if err != nil {
return "", err
}
task := tasksch.NewParallelTask("SyncStoreProducts京东", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
storeSku := batchItemList[0].(*dao.StoreSkuSyncInfo)
if storeSku.VendorSkuID != "" && storeSku.StoreSkuStatus == model.SkuStatusNormal {
if globals.EnableJdStoreWrite {
synchronized, err2 := getAPI(vendorOrgCode).SyncProduct(storeDetail.VendorStoreID, storeSku.VendorSkuID)
if err = err2; err == nil && synchronized {
retVal = []int{1}
}
} else {
retVal = []int{1}
}
}
return retVal, err
}, storeSkuList)
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
}
//京东api返回
func SelectStoreSkuListByResponseList(storeSkuList []*partner.StoreSkuInfo, responseList []*jdapi.StoreSkuBatchUpdateResponse, storeID int, vendorName, syncType string) (selectedStoreSkuList []*partner.StoreSkuInfoWithErr) {
responseMap := make(map[string]string)
if len(responseList) > 0 {
for _, v := range responseList {
if v.Code != "0" {
responseMap[v.OutSkuID] = v.Msg
}
}
for _, v := range storeSkuList {
if responseMap[utils.Int2Str(v.SkuID)] != "" {
respFailed := &partner.StoreSkuInfoWithErr{
StoreSkuInfo: v,
ErrMsg: responseMap[utils.Int2Str(v.SkuID)],
StoreID: storeID,
VendoreName: vendorName,
SyncType: syncType,
}
selectedStoreSkuList = append(selectedStoreSkuList, respFailed)
}
}
}
return selectedStoreSkuList
}
func (p *PurchaseHandler) CreateStoreSkusAct(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
for _, v := range storeSkuList {
if vendorActID, err2 := createSkuAct(ctx, putils.GetFixDirectDownAct(vendorOrgCode, storeID, v.SkuID), putils.StoreSku2ActStoreSku(model.SyncFlagNewMask, vendorStoreID, []*partner.StoreSkuInfo{v})); err2 != nil {
failedList = append(failedList, &partner.StoreSkuInfoWithErr{
StoreSkuInfo: v,
VendoreID: model.VendorIDJD,
StoreID: storeID,
ErrMsg: err2.Error(),
})
} else {
v.VendorActID = vendorActID
}
}
return failedList, err
}
func (p *PurchaseHandler) CancelActs(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
for _, v := range storeSkuList {
if err2 := cancelSkuAct(ctx, putils.GetFixDirectDownAct(vendorOrgCode, storeID, v.SkuID), v.VendorActID); err2 != nil {
failedList = append(failedList, &partner.StoreSkuInfoWithErr{
StoreSkuInfo: v,
VendoreID: model.VendorIDJD,
StoreID: storeID,
ErrMsg: err2.Error(),
})
}
}
return failedList, err
}
func (p *PurchaseHandler) UpdateStoreSkusSpecTag(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (err error) {
return err
}

View File

@@ -1,40 +0,0 @@
package jd
import (
"testing"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/business/partner/putils"
)
func TestGetStoreSkusBareInfo(t *testing.T) {
// list := []*partner.StoreSkuInfo{
// &partner.StoreSkuInfo{
// SkuID: 2212,
// VendorSkuID: "2019458103",
// },
// }
// for i := 0; i < 30-1; i++ {
// list = append(list, list[0])
// }
skuNameList, err := CurPurchaseHandler.GetSkus(jxcontext.AdminCtx, "", 0, "")
if err != nil {
t.Fatal(err)
}
list := putils.StoreSkuFullList2Bare(skuNameList)
storeSkuList, err := CurPurchaseHandler.GetStoreSkusBareInfo(jxcontext.AdminCtx, "", nil, 2, "11053496", list)
if err != nil {
t.Fatal(err.Error())
}
var focusedStoreSkuList []*partner.StoreSkuInfo
for _, v := range storeSkuList {
if v.Stock > 0 {
focusedStoreSkuList = append(focusedStoreSkuList, v)
}
}
t.Log(utils.Format4Output(focusedStoreSkuList, false))
t.Log(len(focusedStoreSkuList))
}

View File

@@ -1,95 +0,0 @@
package jd
import (
"strings"
"testing"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/model/dao"
)
const (
TestStoreNo = 100164
TestJdStoreNo = "11736989"
)
func TestReadStore(t *testing.T) {
result, err := new(PurchaseHandler).ReadStore(jxcontext.AdminCtx, "", TestJdStoreNo)
if err != nil {
t.Fatal(err.Error())
}
t.Log(utils.Format4Output(result, false))
}
func TestUpdateStore(t *testing.T) {
handler := new(PurchaseHandler)
result, err := handler.ReadStore(jxcontext.AdminCtx, "", TestJdStoreNo)
// result := &model.Store{}
// result.ID = 100164
// err := dao.GetEntity(nil, result)
db := dao.GetDB()
if err != nil {
t.Fatal(err.Error())
}
result.Name += "h"
newName := result.Name
err = handler.UpdateStore(db, TestStoreNo, "autotest")
if err != nil {
t.Fatal(err.Error())
}
// same
result, err = handler.ReadStore(jxcontext.AdminCtx, "", TestJdStoreNo)
if result.Name != newName {
t.Fatalf("result is not same, desired newName:%s, newName:%s", newName, result.Name)
}
// restore
result.Name = strings.Trim(result.Name, "h")
err = handler.UpdateStore(db, TestStoreNo, "autotest")
if err != nil {
t.Fatal(err.Error())
}
}
func TestUpdateStore2(t *testing.T) {
handler := new(PurchaseHandler)
// result := &model.Store{}
// result.ID = 100164
// err := dao.GetEntity(nil, result)
db := dao.GetDB()
// restore
err := handler.UpdateStore(db, 1, "autotest")
if err != nil {
t.Fatal(err.Error())
}
}
// func TestCoordRangeConversion(t *testing.T) {
// jxRange := "108841759,34332892;108842271,34330820;108846013,34331422;108846110,34333189;108847722,34331853;108856703,34331729;108866149,34327507;108873423,34320980;108877737,34312856;108877727,34299624;108870105,34287988;108855137,34290911;108867884,34286298;108858260,34281316;108854162,34283490;108853803,34280145;108846110,34279291;108830587,34282539;108818806,34291500;108814493,34299624;108813596,34308465;108818797,34320980;108830582,34329941;108841759,34332892"
// jdRange := "108.841759,34.332892;108.842271,34.330820;108.846013,34.331422;108.846110,34.333189;108.847722,34.331853;108.856703,34.331729;108.866149,34.327507;108.873423,34.320980;108.877737,34.312856;108.877727,34.299624;108.870105,34.287988;108.855137,34.290911;108.867884,34.286298;108.858260,34.281316;108.854162,34.283490;108.853803,34.280145;108.846110,34.279291;108.830587,34.282539;108.818806,34.291500;108.814493,34.299624;108.813596,34.308465;108.818797,34.320980;108.830582,34.329941;108.841759,34.332892"
// if JdRange2JxRange(jdRange) != jxRange {
// t.Fatal("result doesn't match")
// }
// if JxRange2JdRange(jxRange) != jdRange {
// t.Fatal("result doesn't match")
// }
// }
func TestSyncQualify(t *testing.T) {
storeDetail, err := dao.GetStoreDetail(dao.GetDB(), 102610, model.VendorIDJD)
if err != nil {
t.Fatal(err.Error())
}
err = CurPurchaseHandler.SyncQualify(jxcontext.AdminCtx, storeDetail)
if err != nil {
t.Fatal(err.Error())
}
}

View File

@@ -1,70 +0,0 @@
package jd
import (
"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/model"
"git.rosy.net.cn/jx-callback/business/partner"
)
func (c *PurchaseHandler) OnWaybillMsg(vendorOrgCode string, msg *jdapi.CallbackDeliveryStatusMsg) (retVal *jdapi.CallbackResponse) {
jxutils.CallMsgHandler(func() {
retVal = c.onWaybillMsg(vendorOrgCode, msg)
}, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDJD))
return retVal
}
func (c *PurchaseHandler) onWaybillMsg(vendorOrgCode string, msg *jdapi.CallbackDeliveryStatusMsg) (retVal *jdapi.CallbackResponse) {
order := c.callbackMsg2Waybill(msg)
switch msg.DeliveryStatus {
case jdapi.DeliveryStatusWait4Grap:
order.Status = model.WaybillStatusNew
case jdapi.DeliveryStatusAccepted, jdapi.DeliveryStatusCourierChaged: // 将更换配送员也当成接单消息
// todo 性能问题,暂时取消调用
// if result, err := getAPI(vendorOrgCode).QuerySingleOrder(msg.OrderID); err == nil {
// // 默认配送费=订单应付运费(orderReceivableFreight)
// //订单应付运费为未优惠前应付运费(满免优惠运费优惠券VIP免基础运费用户小费)ps用户小费是用户给配送员的小费
// order.DesiredFee = utils.Interface2Int64WithDefault(result["orderReceivableFreight"], 0) +
// utils.Interface2Int64WithDefault(result["merchantPaymentDistanceFreightMoney"], 0) +
// utils.Interface2Int64WithDefault(result["tips"], 0)
// }
order.Status = model.WaybillStatusAccepted
case jdapi.DeliveryStatusCourierCanceled:
order.Status = model.WaybillStatusAcceptCanceled
case jdapi.DeliveryStatusCourierArrived:
order.Status = model.WaybillStatusCourierArrived
case jdapi.DeliveryStatusFailedGetGoodsWaiting:
order.Status = model.WaybillStatusApplyFailedGetGoods
case jdapi.DeliveryStatusFailedGetGoodsRejected:
order.Status = model.WaybillStatusRefuseFailedGetGoods
case jdapi.DeliveryStatusFailedGetGoods:
order.Status = model.WaybillStatusAgreeFailedGetGoods
case jdapi.DeliveryStatusGotGoods:
order.Status = model.WaybillStatusDelivering
case jdapi.DeliveryStatusFailedDelivery:
order.Status = model.WaybillStatusDeliverFailed
case jdapi.DeliveryStatusFinished:
order.Status = model.WaybillStatusDelivered
default:
order.Status = model.WaybillStatusUnknown
}
return jdapi.Err2CallbackResponse(partner.CurOrderManager.OnWaybillStatusChanged(order), order.VendorStatus)
}
func (c *PurchaseHandler) callbackMsg2Waybill(msg *jdapi.CallbackDeliveryStatusMsg) (retVal *model.Waybill) {
retVal = &model.Waybill{
VendorOrderID: msg.OrderID,
OrderVendorID: model.VendorIDJD,
VendorWaybillID: msg.OrderID,
WaybillVendorID: model.VendorIDJD,
CourierName: msg.DeliveryManName,
CourierMobile: msg.DeliveryManPhone,
VendorStatus: msg.DeliveryStatus,
StatusTime: utils.Str2Time(msg.DeliveryStatusTime),
Remark: msg.Remark,
VendorOrgCode: AppKey2OrgCode(msg.AppKey),
}
return retVal
}

View File

@@ -1,11 +0,0 @@
package jdshop
import (
"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"
)
func (c *PurchaseHandler) SyncAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actOrderRules []*model.ActOrderRule, actStoreSkuList []*model.ActStoreSku2) (err error) {
return err
}

View File

@@ -1,314 +0,0 @@
package jdshop
import (
"bytes"
"encoding/base64"
"encoding/hex"
"fmt"
"math"
"strings"
"time"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
"git.rosy.net.cn/baseapi/platformapi/jcqapi"
"git.rosy.net.cn/baseapi/platformapi/jdshopapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxstore/common"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/ddmsg"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
func OnCallbackMsg(msg *jdshopapi.CallBackResult) (err error) {
msgType := msg.MsgType
switch msgType {
case jcqapi.TopicOrderPay:
utils.CallFuncAsync(func() {
SaveJdsOrders(msg)
})
case jcqapi.TopicOrderCancel:
utils.CallFuncAsync(func() {
order := getRealOrderID(msg.OrderID)
if order != nil {
if order.Status != model.OrderStatusCanceled {
CurPurchaseHandler.CancelOrder(jxcontext.AdminCtx, order, "系统取消")
}
}
})
case jcqapi.TopicOrderOut:
utils.CallFuncAsync(func() {
globals.SugarLogger.Debugf("jdsOrderOut", utils.Format4Output(msg, false))
orders := getAllRealOrderID(msg.OrderID)
if len(orders) > 0 {
for _, order := range orders {
if order.ActualPayPrice == 0 {
if jxutils.StandardPrice2Int(utils.Str2Float64(msg.OrderPayment)) == 0 {
order.ActualPayPrice = jxutils.StandardPrice2Int(utils.Str2Float64(msg.OrderTotalPrice) + utils.Str2Float64(msg.FreightPrice) - utils.Str2Float64(msg.SellerDiscount))
} else {
order.ActualPayPrice = jxutils.StandardPrice2Int(utils.Str2Float64(msg.OrderPayment))
}
order.TotalShopMoney = utils.Float64TwoInt64(float64(order.ActualPayPrice) * jdshopapi.JdsPayPercentage)
partner.CurOrderManager.UpdateOrderFields(order, []string{"ActualPayPrice", "TotalShopMoney"})
}
}
}
})
default:
return fmt.Errorf("暂不支持的topic类型topic: %v", msgType)
}
return err
}
func SaveJdsOrders(msg *jdshopapi.CallBackResult) (err error) {
order, err := result2Orders(msg)
if err != nil || order == nil {
return err
}
partner.CurOrderManager.OnOrderNew(order, model.Order2Status(order))
noticeMsg := fmt.Sprintf("京东商城新订单,订单号:[%v] ,将要发到的门店id[%v] , 门店名:[%v]", order.VendorOrderID, order.StoreID, order.StoreName)
if order.OrderType == model.OrderTypeAddressErr {
noticeMsg += " 此订单地址有问题,需要矫正坐标!"
}
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, "DDC5657B43EE11E9A9FF525400E86DC0", "京东商城来新订单了!", noticeMsg)
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, "1439B3E07D3911EA881A525400E86DC0", "京东商城来新订单了!", noticeMsg)
return err
}
func result2Orders(msg *jdshopapi.CallBackResult) (order *model.GoodsOrder, err error) {
//有可能是库里已经有这个订单了
orderE, err := partner.CurOrderManager.LoadOrder(msg.OrderID+"000001", model.VendorIDJDShop)
if orderE != nil {
return order, fmt.Errorf("已经存在此订单!")
}
order = &model.GoodsOrder{
VendorOrderID2: msg.OrderID,
VendorOrderID: msg.OrderID + "000001",
VendorID: model.VendorIDJDShop,
BaseFreightMoney: jxutils.StandardPrice2Int(utils.Str2Float64(msg.FreightPrice)),
VendorStatus: msg.OrderState,
VendorUserID: msg.Pin,
BuyerComment: msg.OrderRemark,
PickDeadline: utils.DefaultTimeValue,
OriginalData: string(utils.MustMarshal(msg)),
OrderCreatedAt: utils.Str2Time(msg.OrderStartTime),
ConsigneeAddress: Decrypt(msg.ConsigneeInfo.FullAddress),
ConsigneeName: Decrypt(msg.ConsigneeInfo.Fullname),
ConsigneeMobile: Decrypt(msg.ConsigneeInfo.Mobile),
ConsigneeMobile2: Decrypt(msg.ConsigneeInfo.Telephone),
ActualPayPrice: jxutils.StandardPrice2Int(utils.Str2Float64(msg.OrderPayment)),
Status: model.OrderStatusNew,
TotalShopMoney: utils.Float64TwoInt64(math.Round(float64(jxutils.StandardPrice2Int(utils.Str2Float64(msg.OrderPayment))) * jdshopapi.JdsPayPercentage)),
DeliveryType: model.OrderDeliveryTypeStoreSelf,
StatusTime: utils.Str2Time(msg.OrderStartTime),
OrderSeq: 0,
}
if order.TotalShopMoney < 100 {
order.TotalShopMoney = 100
}
if order.ConsigneeAddress != "" {
lng, lat, err2 := api.AutonaviAPI.GetCoordinateFromAddressByPage(order.ConsigneeAddress)
if err = err2; err != nil {
globals.SugarLogger.Infof("高德page err: %v", err)
}
lng2, lat2, _ := api.AutonaviAPI.GetCoordinateFromAddress(order.ConsigneeAddress, "")
distance := jxutils.EarthDistance(lng, lat, lng2, lat2)
if distance > 1 {
order.OrderType = model.OrderTypeAddressErr
}
if err == nil && lng != 0 && lat != 0 {
order.ConsigneeLng = jxutils.StandardCoordinate2Int(lng)
order.ConsigneeLat = jxutils.StandardCoordinate2Int(lat)
} else {
order.ConsigneeLng = jxutils.StandardCoordinate2Int(lng2)
order.ConsigneeLat = jxutils.StandardCoordinate2Int(lat2)
}
order.CoordinateType = model.CoordinateTypeMars
}
for _, v := range msg.ItemInfoList {
sku := &model.OrderSku{
VendorID: model.VendorIDJDShop,
VendorOrderID: order.VendorOrderID,
Count: utils.Str2Int(v.ItemTotal),
VendorSkuID: v.SkuID,
SkuName: v.SkuName,
VendorPrice: jxutils.StandardPrice2Int(utils.Str2Float64(v.JdPrice)),
SalePrice: jxutils.StandardPrice2Int(utils.Str2Float64(v.JdPrice)),
// SkuID: utils.Str2Int(v.OuterSkuID),
}
if v.OuterSkuID != "" {
sku.SkuID = utils.Str2Int(v.OuterSkuID)
}
_, _, _, specUnit, _, specQuality := jxutils.SplitSkuName(v.SkuName)
sku.Weight = jxutils.FormatSkuWeight(specQuality, specUnit)
order.Skus = append(order.Skus, sku)
}
storeList, err := common.GetStoreListByLocation(jxcontext.AdminCtx, jxutils.IntCoordinate2Standard(order.ConsigneeLng), jxutils.IntCoordinate2Standard(order.ConsigneeLat), 3000, false, true)
if err != nil {
globals.SugarLogger.Debugf("jds GetStoreListByLocation error: %v", err.Error())
return order, err
}
if len(storeList) > 0 {
for _, store := range storeList {
order.StoreID = store.ID
order.JxStoreID = store.ID
order.StoreName = store.Name
globals.SugarLogger.Debugf("jds GetStoreListByLocation, orderID: %v storeID :%v", order.VendorOrderID, order.StoreID)
//结算类型
storeDetail, _ := dao.GetStoreDetail(dao.GetDB(), order.StoreID, model.VendorIDJDShop)
if storeDetail != nil {
if storeDetail.PayPercentage < 50 {
order.EarningType = model.EarningTypePoints
} else {
order.EarningType = model.EarningTypeQuote
}
}
var (
shopPriceSum int
saleNormalSum int
)
for _, sku := range order.Skus {
storeSkuList, _ := dao.GetStoresSkusInfo(dao.GetDB(), []int{order.StoreID}, []int{sku.SkuID})
if len(storeSkuList) > 0 {
if storeSkuList[0].Status == model.StoreSkuBindStatusNormal {
saleNormalSum += 1
}
shopPriceSum += storeSkuList[0].Price * sku.Count
}
}
//可售数小于一半就不行
if math.Mod(float64(len(order.Skus)), float64(2)) == 0 {
if saleNormalSum < len(order.Skus)/2 {
buildOrderTo102919(order)
continue
} else {
if order.EarningType == model.EarningTypeQuote && shopPriceSum+700 > int(order.TotalShopMoney) {
buildOrderTo102919(order)
continue
}
}
} else {
if saleNormalSum <= len(order.Skus)/2 {
buildOrderTo102919(order)
continue
} else {
if order.EarningType == model.EarningTypeQuote && shopPriceSum+700 > int(order.TotalShopMoney) {
buildOrderTo102919(order)
continue
}
}
}
break
}
} else {
buildOrderTo102919(order)
}
storeMaps, _ := dao.GetStoresMapList(dao.GetDB(), []int{model.VendorIDJDShop}, []int{order.StoreID}, nil, model.StoreStatusAll, model.StoreIsSyncAll, "", "")
if len(storeMaps) > 0 {
order.VendorStoreID = storeMaps[0].VendorStoreID
}
// 如果是暂停表示是预订单g
if msg.OrderState == jdshopapi.OrderStatusPause || msg.OrderState == jdshopapi.OrderStatusPopPause {
order.BusinessType = model.BusinessTypeDingshida
if time2, err := api.JdShopAPI.GetOrderExtInfoByOrderId(order.VendorOrderID2); err == nil {
if time2 == "" {
order.ExpectedDeliveredTime = order.OrderCreatedAt.Add(time.Hour)
} else {
order.ExpectedDeliveredTime = utils.Str2Time(time2).Add(-time.Minute * 30)
}
}
order.PickDeadline = order.ExpectedDeliveredTime.Add(-time.Hour)
} else if msg.OrderState == jdshopapi.OrderStatusWait {
order.ExpectedDeliveredTime = order.OrderCreatedAt.Add(time.Hour)
order.BusinessType = model.BusinessTypeImmediate
} else {
globals.SugarLogger.Debugf("暂不支持的京东商城订单类型type: %v", msg.OrderState)
return nil, err
}
if msg.IDSopShipmenttype == jdshopapi.IdSopShipmenttypeTC {
if time2, err := api.JdShopAPI.GetOrderExtInfoByOrderId(order.VendorOrderID2); err == nil {
order.BusinessType = model.BusinessTypeDingshida
order.ExpectedDeliveredTime = utils.Str2Time(time2).Add(-time.Minute * 30)
}
}
setJdsOrderSeq(order)
if order.OrderType == model.OrderTypeAddressErr {
buildOrderTo102919(order)
}
return order, err
}
func buildOrderTo102919(order *model.GoodsOrder) {
order.StoreID = 102919
order.JxStoreID = 102919
order.StoreName = "商城模板(成都发货)"
order.VendorStoreID = model.JdShopMainVendorStoreID
order.DeliveryFlag = model.OrderDeliveryFlagMaskScheduleDisabled
}
func setJdsOrderSeq(order *model.GoodsOrder) (err error) {
type tCount struct {
Count int `json:"count"`
}
var count = &tCount{}
sql := `
SELECT count(*) count FROM goods_order WHERE store_id = ? AND order_create_at >= ? AND order_create_at <= ? AND vendor_id = ?
`
sqlParams := []interface{}{
order.StoreID, utils.Time2Date(time.Now()), utils.Time2Date(time.Now().AddDate(0, 0, 1)), order.VendorID,
}
err = dao.GetRow(dao.GetDB(), &count, sql, sqlParams)
order.OrderSeq = count.Count + 1
return err
}
func Decrypt(p string) (result string) {
if p == "" {
return ""
}
data, _ := base64.StdEncoding.DecodeString(strings.ReplaceAll(p, " ", "+"))
key := GetKey(hex.EncodeToString(data)[4:36])
globals.SugarLogger.Debugf("Decrypt keys : %v", key)
data2, _ := base64.StdEncoding.DecodeString(key)
b := bytes.NewBuffer(data)
b.Next(18)
iv := make([]byte, 16)
b.Read(iv)
main := make([]byte, len(data)-18-16)
b.Read(main)
decryptedData, _ := utils.AESCBCDecpryt(main, data2[:16], iv)
return string(decryptedData)
}
func getRealOrderID(orderID string) (order *model.GoodsOrder) {
var (
db = dao.GetDB()
)
sql := `
SELECT * FROM goods_order WHERE vendor_order_id2 = ? ORDER BY vendor_order_id DESC LIMIT 1
`
sqlParams := []interface{}{
orderID,
}
dao.GetRow(db, &order, sql, sqlParams)
return order
}
func getAllRealOrderID(orderID string) (orders []*model.GoodsOrder) {
var (
db = dao.GetDB()
)
sql := `
SELECT * FROM goods_order WHERE vendor_order_id2 = ?
`
sqlParams := []interface{}{
orderID,
}
dao.GetRows(db, &orders, sql, sqlParams)
return orders
}

View File

@@ -1,69 +0,0 @@
package jdshop
import (
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/business/partner/putils"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
var (
CurPurchaseHandler *PurchaseHandler
)
type PurchaseHandler struct {
partner.BasePurchasePlatform
putils.DefSingleStorePlatform
}
func init() {
if api.JdShopAPI != nil {
CurPurchaseHandler = New()
partner.RegisterPurchasePlatform(CurPurchaseHandler)
}
}
func New() (obj *PurchaseHandler) {
obj = new(PurchaseHandler)
obj.ISingleStoreStoreSkuHandler = obj
return obj
}
func (p *PurchaseHandler) GetVendorID() int {
return model.VendorIDJDShop
}
func (p *PurchaseHandler) UploadImg(ctx *jxcontext.Context, vendorOrgCode, imgURL string, imgData []byte, imgName string, imgType int) (imgHint string, err error) {
if globals.EnableJdShopWrite {
if imgType > model.ImgTypeLocal {
result, err := api.JdShopAPI.UploadPicture(imgData, 0, imgName)
if err == nil {
imgHint = result.PictureURL
}
}
} else {
imgHint = utils.GetUpperUUID()
}
return imgHint, err
}
func (p *PurchaseHandler) GetVendorCategories(ctx *jxcontext.Context) (vendorCats []*model.SkuVendorCategory, err error) {
result, err := api.JdShopAPI.FindVendorCategories()
for _, v := range result {
cat := &model.SkuVendorCategory{
VendorID: model.VendorIDJDShop,
Name: v.Name,
Level: v.Lev,
VendorCategoryID: utils.Int2Str(v.ID),
}
if v.Lev > 1 {
cat.ParentID = utils.Int2Str(v.Fid)
cat.IsLeaf = 1
}
vendorCats = append(vendorCats, cat)
}
return vendorCats, err
}

View File

@@ -1,51 +0,0 @@
package jdshop
import (
"encoding/base64"
"encoding/hex"
"encoding/json"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
var (
KeyList []*Key
)
type Key struct {
ID string `json:"id"`
KeyExp int64 `json:"key_exp"`
KeyStatus int `json:"key_status"`
KeyDigest string `json:"key_digest"`
KeyType string `json:"key_type"`
KeyString string `json:"key_string"`
KeyEffective int64 `json:"key_effective"`
Version int `json:"version"`
}
func InitKey() {
keyResult, err := api.JdShopAPI.KeyGet()
if err != nil {
return
}
for _, v := range keyResult.Response.ServiceKeyList[0].Keys {
data, _ := json.Marshal(v)
vv := &Key{}
err = json.Unmarshal(data, &vv)
KeyList = append(KeyList, vv)
}
globals.SugarLogger.Debugf("jdshop key refreshed..")
}
func GetKey(keySign string) (key string) {
for _, v := range KeyList {
data, _ := base64.StdEncoding.DecodeString(v.ID)
if keySign == hex.EncodeToString(data) {
return v.KeyString
}
}
globals.SugarLogger.Debugf("no key can equal..")
return key
}

View File

@@ -1,243 +0,0 @@
package jdshop
import (
"fmt"
"net/http"
"strings"
"time"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/baseapi"
"git.rosy.net.cn/baseapi/platformapi"
"git.rosy.net.cn/baseapi/platformapi/jdshopapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals/api"
)
func (p *PurchaseHandler) AcceptOrRefuseFailedGetOrder(ctx *jxcontext.Context, order *model.GoodsOrder, isAcceptIt bool) (err error) {
return err
}
func (p *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *model.GoodsOrder) {
result := &jdshopapi.AllOrdersResult{}
utils.Map2StructByJson(orderData, &result, false)
jdsOrder := result.OrderList[0]
order = &model.GoodsOrder{
VendorOrderID: utils.Int64ToStr(jdsOrder.OrderID),
VendorID: model.VendorIDJDShop,
BaseFreightMoney: jxutils.StandardPrice2Int(jdsOrder.Freight),
VendorStatus: utils.Int2Str(jdsOrder.OrderStatus),
VendorUserID: jdsOrder.UserPin,
BuyerComment: jdsOrder.UserRemark,
PickDeadline: utils.DefaultTimeValue,
OriginalData: string(utils.MustMarshal(jdsOrder)),
}
return order
}
func (p *PurchaseHandler) GetOrder(vendorOrgCode, vendorOrderID string) (order *model.GoodsOrder, err error) {
resultOrders, err := api.JdShopAPI.AllOrders(&jdshopapi.AllOrdersParam{
OrderID: vendorOrderID,
Current: 1,
PageSize: 1,
})
return p.Map2Order(utils.Struct2FlatMap(resultOrders)), err
}
func (p *PurchaseHandler) GetOrderStatus(vendorOrgCode, vendorOrderID string) (status int, err error) {
jdsOrder, err := GetJdsOrder(vendorOrderID)
return status2Jxstatus(jdsOrder.OrderState), err
}
func (p *PurchaseHandler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) {
var status int
if isAcceptIt {
status = model.OrderStatusAccepted
} else {
status = model.OrderStatusCanceled
}
return ChangeOrderStatus(order.VendorOrderID, status, "")
}
func (p *PurchaseHandler) PickupGoods(order *model.GoodsOrder, isSelfDelivery bool, userName string) (err error) {
status, err := p.GetOrderStatus("", order.VendorOrderID2)
//说明此时该订单在平台上已经取消了
if status == model.OrderStatusCanceled {
err = ChangeOrderStatus(order.VendorOrderID, model.OrderStatusCanceled, "订单在京东商城已被取消!")
} else {
err = ChangeOrderStatus(order.VendorOrderID, model.OrderStatusFinishedPickup, "自动拣货完成")
err = p.OrderExport(jxcontext.AdminCtx, order.VendorOrderID, order.VendorOrderID, true)
}
return err
}
func (p *PurchaseHandler) CallCourier(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) {
return err
} // 取货失败后再次招唤平台配送
func (p *PurchaseHandler) ConfirmReceiveGoods(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) {
return err
} // 投递失败后确认收到退货
func (p *PurchaseHandler) CanSwitch2SelfDeliver(order *model.GoodsOrder) (isCan bool, err error) {
return isCan, err
}
func (p *PurchaseHandler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) {
return err
}
func (p *PurchaseHandler) Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) {
return err
}
func (p *PurchaseHandler) SelfDeliverDelivering(order *model.GoodsOrder, userName string) (err error) {
ChangeOrderStatus(order.VendorOrderID, model.OrderStatusDelivering, "")
return err
}
func (p *PurchaseHandler) SelfDeliverDelivered(order *model.GoodsOrder, userName string) (err error) {
ChangeOrderStatus(order.VendorOrderID, model.OrderStatusFinished, "")
return err
}
func (p *PurchaseHandler) GetOrderRealMobile(ctx *jxcontext.Context, order *model.GoodsOrder) (mobile string, err error) {
return mobile, err
}
func (p *PurchaseHandler) ReplyOrderComment(ctx *jxcontext.Context, vendorOrgCode string, orderComment *model.OrderComment, replyComment string) (err error) {
return err
}
func (p *PurchaseHandler) AgreeOrRefuseCancel(ctx *jxcontext.Context, order *model.GoodsOrder, isAgree bool, reason string) (err error) {
return err
}
func (p *PurchaseHandler) CancelOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
ChangeOrderStatus(order.VendorOrderID, model.OrderStatusCanceled, reason)
if order.EclpOutID != "" {
_, err = api.JdEclpAPI.CancelOrder(order.EclpOutID)
}
return err
}
func (p *PurchaseHandler) AdjustOrder(ctx *jxcontext.Context, order *model.GoodsOrder, removedSkuList []*model.OrderSku, reason string) (err error) {
var (
db = dao.GetDB()
diffShopPrice int64
diffSalePrice int64
)
if order.Status >= model.OrderStatusDelivering {
return fmt.Errorf("配送中以后的订单无法进行售前退款!")
}
//1、删除原order_sku 中售前调整的商品
for _, sku := range removedSkuList {
sql := `DELETE FROM order_sku WHERE vendor_order_id = ? AND vendor_id = ? AND sku_id = ?`
sqlParams := []interface{}{order.VendorOrderID, order.VendorID, sku.SkuID}
dao.ExecuteSQL(db, sql, sqlParams)
diffShopPrice += sku.ShopPrice
diffSalePrice += sku.SalePrice
}
//2、修改goods_order 中的shopprice,若是扣点的订单还要改new_earning_price和total_shop_money
order.AdjustCount += 1
order.ShopPrice = order.ShopPrice - diffShopPrice
if order.EarningType == model.EarningTypePoints {
order.TotalShopMoney = utils.Float64TwoInt64(float64(float64(order.TotalShopMoney)/jdshopapi.JdsPayPercentage-float64(diffSalePrice)) * jdshopapi.JdsPayPercentage)
jxutils.RefreshOrderEarningPrice2(order, order.OrderPayPercentage)
partner.CurOrderManager.UpdateOrderFields(order, []string{"TotalShopMoney", "NewEarningPrice"})
}
partner.CurOrderManager.UpdateOrderFields(order, []string{"AdjustCount", "ShopPrice"})
return err
}
func (p *PurchaseHandler) GetJdsOrders(ctx *jxcontext.Context, orderCreatedStart, orderCreatedEnd string, current, pageSize int) (orderResult *jdshopapi.AllOrdersResult, err error) {
orderResult, err = api.JdShopAPI.AllOrders(&jdshopapi.AllOrdersParam{
Current: current,
PageSize: pageSize,
OrderCreateDateRange: []string{orderCreatedStart, orderCreatedEnd},
})
return orderResult, err
}
func ChangeOrderStatus(vendorOrderID string, status int, remark string) (err error) {
orderStatus := &model.OrderStatus{
VendorOrderID: vendorOrderID,
VendorID: model.VendorIDJDShop,
OrderType: model.OrderTypeOrder,
RefVendorOrderID: vendorOrderID,
RefVendorID: model.VendorIDJDShop,
VendorStatus: utils.Int2Str(status),
Status: status,
StatusTime: time.Now(),
Remark: remark,
}
jxutils.CallMsgHandlerAsync(func() {
err = partner.CurOrderManager.OnOrderStatusChanged("", orderStatus)
}, jxutils.ComposeUniversalOrderID(vendorOrderID, model.VendorIDJDShop))
return err
}
func (p *PurchaseHandler) OrderExport(ctx *jxcontext.Context, vendorOrderID, vendorWaybillID string, isAuto bool) (err error) {
companyID := jdshopapi.JdsDeliveryCompany3rd
//表示是门店手动发京东
if !isAuto {
companyID = jdshopapi.JdsDeliveryCompanyJD
}
err = api.JdShopAPI.OrderShipment(utils.Str2Int64(vendorOrderID[:12]), companyID, vendorWaybillID)
return err
}
func (p *PurchaseHandler) OrderTransfer(ctx *jxcontext.Context, vendorOrderID, vendorWaybillID string, isAuto bool) (err error) {
companyID := jdshopapi.JdsDeliveryCompany3rd
//表示是门店手动发京东
if !isAuto {
companyID = jdshopapi.JdsDeliveryCompanyJD
}
err = api.JdShopAPI.UpdateWaybill(vendorOrderID[:12], companyID, vendorOrderID)
return err
}
func status2Jxstatus(status string) (statusJx int) {
if status == jdshopapi.OrderStatusPopPause || status == jdshopapi.OrderStatusPause {
statusJx = model.OrderStatusNew
} else if status == jdshopapi.OrderStatusWait {
statusJx = model.OrderStatusAccepted
} else if status == jdshopapi.OrderStatusCancel {
statusJx = model.OrderStatusCanceled
}
return statusJx
}
const (
ProdURL = "http://116.196.82.188:8080/v2/"
)
func apiToYd(url string, params map[string]interface{}) (retVal map[string]interface{}, err error) {
cl := &http.Client{}
err = platformapi.AccessPlatformAPIWithRetry(cl,
func() *http.Request {
request, _ := http.NewRequest(http.MethodPost, ProdURL+url, strings.NewReader(utils.Map2URLValues(params).Encode()))
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
return request
},
nil,
func(response *http.Response, bodyStr string, jsonResult1 map[string]interface{}) (errLevel string, err error) {
if jsonResult1 == nil {
return platformapi.ErrLevelRecoverableErr, fmt.Errorf("mapData is nil")
}
if err == nil {
if jsonResult1["code"] != nil {
if utils.Interface2Int64WithDefault(jsonResult1["code"], 0) != 0 {
errLevel = platformapi.ErrLevelGeneralFail
err = utils.NewErrorCode(jsonResult1["desc"].(string), jsonResult1["code"].(string))
baseapi.SugarLogger.Debugf("yd AccessAPI failed, jsonResult1:%s", utils.Format4Output(jsonResult1, true))
}
}
retVal = jsonResult1
}
return errLevel, err
})
return retVal, err
}
func GetJdsOrder(vendorOrderID string) (jdsOrder *jdshopapi.GetOrderResult, err error) {
params := make(map[string]interface{})
params["orderID"] = vendorOrderID
params["token"] = jdshopapi.JdsYdToken
result, err := apiToYd("order/GetJdsOrder", params)
jdsOrder2 := &jdshopapi.GetOrderResult{}
err = utils.UnmarshalUseNumber([]byte(strings.ReplaceAll(result["data"].(string), "\\", "")), &jdsOrder2)
return jdsOrder2, err
}

View File

@@ -1,134 +0,0 @@
package jdshop
import (
"crypto/md5"
"fmt"
"math"
"time"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
)
func (c *PurchaseHandler) AgreeOrRefuseRefund(ctx *jxcontext.Context, afsOrder *model.AfsOrder, approveType int, reason string) (err error) {
var status int
if approveType == partner.AfsApproveTypeRefused {
status = model.AfsOrderStatusFailed
} else {
status = model.AfsOrderStatusFinished
}
orderStatus := &model.OrderStatus{
VendorOrderID: afsOrder.AfsOrderID, // 是售后单ID不是订单ID订单ID在RefVendorOrderID中
VendorID: afsOrder.VendorID,
OrderType: model.OrderTypeAfsOrder,
RefVendorOrderID: afsOrder.VendorOrderID,
RefVendorID: afsOrder.VendorID,
VendorStatus: utils.Int2Str(status),
Status: status,
StatusTime: time.Now(),
Remark: reason,
}
partner.CurOrderManager.OnAfsOrderStatusChanged(orderStatus)
return err
}
// 确认收到退货
func (c *PurchaseHandler) ConfirmReceivedReturnGoods(ctx *jxcontext.Context, order *model.AfsOrder) (err error) {
err = fmt.Errorf("京东商城当前不支持ConfirmReceivedReturnGoods")
return err
}
// 发起全款退款
func (c *PurchaseHandler) RefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
err = c.PartRefundOrder(ctx, order, order.Skus, reason)
return err
}
// 发起部分退款
func (c *PurchaseHandler) PartRefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, refundSkuList []*model.OrderSku, reason string) (err error) {
globals.SugarLogger.Debugf("PartRefundOrder jdshop, orderID :%v", order.VendorOrderID)
var (
skuMap = make(map[int]*model.OrderSku)
salePrice int64
db = dao.GetDB()
)
for _, sku := range order.Skus {
skuMap[sku.SkuID] = sku
}
orderStatus := buildOrderStatus(ctx, order, reason)
afsOrder := &model.AfsOrder{
VendorID: order.VendorID,
AfsOrderID: orderStatus.VendorOrderID,
VendorOrderID: orderStatus.RefVendorOrderID,
// VendorStoreID: order.VendorStoreID,
// StoreID: jxutils.GetSaleStoreIDFromOrder(order),
AfsCreatedAt: time.Now(),
VendorAppealType: "",
AppealType: model.AfsAppealTypeRefund,
VendorReasonType: utils.Int2Str(model.AfsReasonNotOthers),
ReasonType: model.AfsReasonNotOthers,
ReasonDesc: utils.LimitUTF8StringLen(reason, 1024),
ReasonImgList: "",
RefundType: model.AfsTypePartRefund,
VendorOrgCode: "",
}
for _, sku := range refundSkuList {
orderSku := &model.OrderSkuFinancial{
Count: sku.Count,
VendorSkuID: utils.Int2Str(sku.SkuID),
SkuID: sku.SkuID,
}
storeSkus, _ := dao.GetStoresSkusInfo(db, []int{model.JdShopMainStoreID}, []int{sku.SkuID})
if len(storeSkus) > 0 {
orderSku.VendorSkuID = utils.Int64ToStr(storeSkus[0].JdsID)
}
if skuMap[sku.SkuID] != nil {
orderSku.Name = skuMap[sku.SkuID].SkuName
orderSku.UserMoney = skuMap[sku.SkuID].SalePrice * int64(sku.Count)
salePrice += skuMap[sku.SkuID].SalePrice * int64(sku.Count)
}
afsOrder.SkuUserMoney += orderSku.UserMoney
afsOrder.Skus = append(afsOrder.Skus, orderSku)
}
err = partner.CurOrderManager.OnAfsOrderNew(afsOrder, orderStatus)
return err
}
func buildOrderStatus(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (orderStatus *model.OrderStatus) {
orderStatus = &model.OrderStatus{
VendorOrderID: utils.Int64ToStr(GenAfsOrderNo(ctx)), // 是售后单ID不是订单ID订单ID在RefVendorOrderID中
VendorID: order.VendorID,
OrderType: model.OrderTypeAfsOrder,
RefVendorOrderID: order.VendorOrderID,
RefVendorID: order.VendorID,
VendorStatus: utils.Int2Str(model.AfsOrderStatusWait4Approve),
Status: model.AfsOrderStatusWait4Approve,
StatusTime: time.Now(),
Remark: reason,
}
orderStatus.Status = model.AfsOrderStatusWait4Approve
return orderStatus
}
func GenAfsOrderNo(ctx *jxcontext.Context) (orderNo int64) {
const prefix = 70
const randPartNum = 100
orderNoBeginTimestamp := utils.Str2Time("2010-01-01 00:00:00").Unix()
orderNo = time.Now().Unix() - orderNoBeginTimestamp
orderNo = orderNo * randPartNum
md5Bytes := md5.Sum([]byte(utils.GetUUID()))
randPart := 0
for k, v := range md5Bytes {
randPart += int(v) << ((k % 3) * 8)
}
orderNo += int64(randPart % randPartNum)
orderNo += int64(math.Pow10(int(math.Log10(float64(orderNo)))+1)) * prefix
return orderNo
}

View File

@@ -1,5 +0,0 @@
package jdshop
func (c *PurchaseHandler) StartRefreshComment() {
}

View File

@@ -1,204 +0,0 @@
package jdshop
import (
"encoding/base64"
"encoding/json"
"fmt"
"strings"
"git.rosy.net.cn/baseapi/platformapi/jdshopapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"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"
"git.rosy.net.cn/jx-callback/globals/api"
)
func (p *PurchaseHandler) ReadStore(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID string) (storeDetail *dao.StoreDetail, err error) {
// result, err := api.JdShopAPI.NewInfoList(utils.Str2Int64(vendorStoreID))
// storeDetail.VendorStoreID = vendorStoreID
// storeDetail.Status = JdsStatus2jxStatus(result.StoreStatus)
result2, err := api.JdShopAPI.QueryEntityStore(utils.Str2Int64(vendorStoreID))
if result2 == nil {
return storeDetail, fmt.Errorf("未查询到该平台门店平台门店ID[%v]", vendorStoreID)
}
storeDetail = &dao.StoreDetail{}
storeDetail.ID = utils.Str2Int(result2.ExStoreID)
storeDetail.Name = result2.StoreName
storeDetail.Address = result2.Address
storeDetail.Tel1 = result2.Phone
storeDetail.DistrictCode = result2.AddrCode
zbs := strings.Split(result2.Coordinate, ",")
storeDetail.Lat = jxutils.StandardCoordinate2Int(utils.Str2Float64(zbs[0]))
storeDetail.Lng = jxutils.StandardCoordinate2Int(utils.Str2Float64(zbs[1]))
return storeDetail, err
}
// stoerIDs为nil表示所有
func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName string) (err error) {
store, err := dao.GetStoreDetail(db, storeID, model.VendorIDJDShop)
if err != nil {
return err
}
data, _, err := jxutils.DownloadFileByURL(jdshopapi.JdsStoreImg)
timeMap := map[string]string{
"businessBeginTime": int2TimeStr(int(store.OpenTime1)),
"businessEndTime": int2TimeStr(int(store.CloseTime1)),
}
timeJSON, _ := json.Marshal(timeMap)
updateEntityStoreParam := &jdshopapi.UpdateEntityStoreParam{
StoreID: utils.Str2Int(store.VendorStoreID),
Name: store.Name,
AddCode: store.JdsCode,
AddCodeName: store.DistrictName,
AddName: store.ProvinceName + store.CityName + store.DistrictName + "@!" + store.Address,
Coordinate: utils.Float64ToStr(jxutils.IntCoordinate2Standard(store.Lat)) + "," + utils.Float64ToStr(jxutils.IntCoordinate2Standard(store.Lng)),
Phone: store.Tel1,
ExtendJSON: string(timeJSON),
ImageFile: base64.StdEncoding.EncodeToString(data),
CustomerID: utils.Int2Str(store.ID),
}
if store.JdsStreetCode != 0 {
updateEntityStoreParam.AddCode = store.JdsStreetCode
}
if updateEntityStoreParam.AddCode == 0 {
updateEntityStoreParam.AddCode = store.JdCode
}
err = api.JdShopAPI.UpdateEntityStore(updateEntityStoreParam)
if err == nil {
// if store.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagStoreStatus) != 0 {
// mergeStatus := jxutils.MergeStoreStatus(store.Status, store.VendorStatus)
// err = api.JdShopAPI.UpdateStoreStatus(utils.Str2Int(store.VendorStoreID), jxStatus2JdsStatus(mergeStatus))
// }
}
return err
}
func (p *PurchaseHandler) CreateStore2(db *dao.DaoDB, storeID int, userName string) (vendorStoreID string, err error) {
store, err := dao.GetStoreDetail(db, storeID, model.VendorIDJDShop)
if err != nil {
return vendorStoreID, err
}
data, _, err := jxutils.DownloadFileByURL(jdshopapi.JdsStoreImg)
timeMap := map[string]string{
"businessBeginTime": int2TimeStr(int(store.OpenTime1)),
"businessEndTime": int2TimeStr(int(store.CloseTime1)),
}
timeJSON, _ := json.Marshal(timeMap)
createEntityStoreParam := &jdshopapi.CreateEntityStoreParam{
Name: store.Name,
AddCode: store.JdsCode,
AddCodeName: store.DistrictName,
AddName: store.ProvinceName + store.CityName + store.DistrictName + "@!" + store.Address,
Coordinate: utils.Float64ToStr(jxutils.IntCoordinate2Standard(store.Lat)) + "," + utils.Float64ToStr(jxutils.IntCoordinate2Standard(store.Lng)),
Phone: store.Tel1,
ExtendJSON: string(timeJSON),
ImageFile: base64.StdEncoding.EncodeToString(data),
CategoryName: jdshopapi.JdsStoreCategoryName,
CustomerID: utils.Int2Str(store.ID),
}
if store.JdsStreetCode != 0 {
createEntityStoreParam.AddCode = store.JdsStreetCode
}
if createEntityStoreParam.AddCode == 0 {
createEntityStoreParam.AddCode = store.JdCode
}
//证明这个店可能隶属直辖市或者东莞
if model.ZXCityCodeMap[store.CityCode] != "" {
result, _ := api.AutonaviAPI.GetCoordinateAreaInfo(jxutils.IntCoordinate2Standard(store.Lng), jxutils.IntCoordinate2Standard(store.Lat))
if result["regeocode"] != nil {
street := result["regeocode"].(map[string]interface{})["addressComponent"].(map[string]interface{})["township"].(string)
if street != "" {
result1, _ := api.JdShopAPI.GetProvince()
for _, v := range result1 {
if strings.Contains(store.CityName, v.AreaName) {
result2, _ := api.JdShopAPI.GetCity(v.AreaID)
for _, vv := range result2 {
if strings.Contains(store.DistrictName, vv.AreaName) {
result3, _ := api.JdShopAPI.GetCounty(vv.AreaID)
for _, vvv := range result3 {
if street == vvv.AreaName {
createEntityStoreParam.AddCode = vvv.AreaID
break
}
}
}
}
}
}
}
}
}
vendorStoreID, err = api.JdShopAPI.CreateEntityStore(createEntityStoreParam)
return vendorStoreID, err
}
func (p *PurchaseHandler) DeleteStore(db *dao.DaoDB, storeID int, userName string) (err error) {
// store, err := dao.GetStoreDetail(db, storeID, model.VendorIDJDShop)
// if err != nil {
// return err
// }
// err = api.JdShopAPI.DeleteStoresByID(utils.Str2Int64(store.VendorStoreID))
return err
}
func (p *PurchaseHandler) RefreshAllStoresID(ctx *jxcontext.Context, parentTask tasksch.ITask, isAsync bool) (hint string, err error) {
return hint, err
}
func (p *PurchaseHandler) GetStoreStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string) (storeStatus int, err error) {
return storeStatus, err
}
func (p *PurchaseHandler) EnableAutoAcceptOrder(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, isSetEnable bool) (err error) {
return err
}
func (c *PurchaseHandler) UpdateStoreStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, status int) (err error) {
return err
}
func (c *PurchaseHandler) UpdateStoreOpTime(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, opTimeList []int16) (err error) {
return err
}
func (c *PurchaseHandler) GetAllStoresVendorID(ctx *jxcontext.Context, vendorOrgCode string) (vendorStoreIDs []string, err error) {
return vendorStoreIDs, err
}
func (c *PurchaseHandler) UpdateStoreCustomID(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID string, storeID int64) (err error) {
return err
}
func int2TimeStr(time int) (str string) {
str += utils.Int2Str(time / 1000)
str += utils.Int2Str(time % 1000 / 100)
str += ":"
str += utils.Int2Str(time % 100 / 10)
str += utils.Int2Str(time % 10)
return str
}
func jxStatus2JdsStatus(status int) (result int) {
if status == model.StoreStatusOpened {
result = jdshopapi.JdsStoreStatusOnline
} else if status == model.StoreStatusHaveRest || status == model.StoreStatusClosed {
result = jdshopapi.JdsStoreStatusRest
} else {
result = jdshopapi.JdsStoreStatusDisable
}
return result
}
func JdsStatus2jxStatus(status int) (result int) {
if status == jdshopapi.JdsStoreStatusOnline {
result = model.StoreStatusOpened
} else if status == jdshopapi.JdsStoreStatusRest {
result = model.StoreStatusClosed
} else {
result = model.StoreStatusDisabled
}
return result
}

View File

@@ -1,896 +0,0 @@
package jdshop
import (
"fmt"
"math"
"regexp"
"strings"
"time"
"git.rosy.net.cn/baseapi/platformapi/jdshopapi"
"git.rosy.net.cn/jx-callback/globals/api"
"git.rosy.net.cn/baseapi/platformapi/yinbaoapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"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"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/business/partner/putils"
"git.rosy.net.cn/jx-callback/globals"
)
const (
deleteErr1 = "已经删除的不能直接下架"
deleteErr2 = "SKU"
deleteErr3 = "已删除"
)
var (
sensitiveWordRegexp = regexp.MustCompile(`商品名称中含有敏感词(\[.*\])`)
)
func (p *PurchaseHandler) CreateStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*dao.StoreSkuSyncInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
if globals.EnableJdShopWrite && vendorStoreID == model.JdShopMainVendorStoreID {
for _, v := range storeSkuList {
//判断京东商城上是否有这个商品了,如果有就是添加规格而不是创建商品
name := filterSensitiveWord(v.Name)
flag := false
result, err := api.JdShopAPI.SearchWare4Valid(name, 1, 100)
if err != nil {
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDJDShop], "创建商品")
return failedList, err
}
for _, v := range result.Data {
if v.Title == name {
flag = true
break
}
}
if result.TotalItem > 0 && len(result.Data) > 0 && flag {
for _, vv := range v.StoreSkuSyncInfoJds {
v.JdsWareID = result.Data[0].WareID
vv.JdsWareID = result.Data[0].WareID
updateSkusParam, err := buildUpdateSkusParam(v, vv, true)
if err != nil {
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDJDShop], "创建商品")
return failedList, err
}
vendorSkuID, err := api.JdShopAPI.UpdateSkus(updateSkusParam)
if err != nil {
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDJDShop], "创建商品")
return failedList, err
}
vv.VendorSkuID = vendorSkuID
}
} else {
createSkuParamWare, createSkuParamSkus, err := buildCreateWareParam(v)
if err != nil {
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDJDShop], "创建商品")
return failedList, err
}
createSkuResult, err := api.JdShopAPI.CreateWare(createSkuParamWare, createSkuParamSkus)
if err != nil {
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDJDShop], "创建商品")
return failedList, err
} else {
//追加商品透图
imageURL := ""
img := v.Img
if img != "" {
suffix := img[strings.LastIndex(img, "."):]
if suffix != ".png" {
if resBinary, _, _ := jxutils.DownloadFileByURL(img + model.SkuNameImgToPng); err == nil {
downloadURL, _ := jxutils.UploadExportContent(resBinary, utils.Int64ToStr(time.Now().Unix()))
imageURL, _ = uploadImg(downloadURL, name, "tou")
}
} else {
imageURL, _ = uploadImg(img, name, "tou")
}
}
api.JdShopAPI.TransparentImageAdd(createSkuResult.WareID, imageURL)
}
var paramAttrs = make(map[string]*jdshopapi.CreateSkuParamSkus)
var resultAttrs = make(map[string]int64)
for _, vv := range createSkuParamSkus {
for _, vvv := range vv.SaleAttrs {
paramAttrs[vvv.AttrValues[0]] = vv
}
}
for _, vv1 := range createSkuResult.Skus {
for _, vvv1 := range vv1.SaleAttrs {
if paramAttrs[vvv1.AttrValues[0]] != nil {
resultAttrs[paramAttrs[vvv1.AttrValues[0]].OuterID] = vv1.SkuID
}
}
}
for _, vv2 := range v.StoreSkuSyncInfoJds {
vv2.JdsWareID = createSkuResult.WareID
if resultAttrs[utils.Int2Str(vv2.SkuID)] != 0 {
vv2.VendorSkuID = utils.Int64ToStr(resultAttrs[utils.Int2Str(vv2.SkuID)])
}
}
}
}
}
return failedList, err
}
func (p *PurchaseHandler) UpdateStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*dao.StoreSkuSyncInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
if globals.EnableJdShopWrite && vendorStoreID == model.JdShopMainVendorStoreID {
for _, v := range storeSkuList {
name := filterSensitiveWord(v.Name)
updateWareParam := &jdshopapi.UpdateWareParam{
WareID: v.JdsWareID,
Title: name,
VenderID: jdshopapi.VenderID,
// PromiseID: jdshopapi.JdsPromiseID,
ShopCategorys: []int{utils.Str2Int(v.VendorCatID)},
JdPrice: jxutils.IntPrice2Standard(v.UnitPrice),
}
if v.VendorVendorCatID != jdshopapi.JdsOtherMeatCatID {
updateWareParam.PromiseID = jdshopapi.JdsPromiseID
}
var desc string
if v.DescImg != "" {
pic3, err2 := uploadImg2(v.DescImg, name, "desc")
err = err2
desc = `<p><img src="` + jdshopapi.JdsImgURL + pic3 + `" style="width: auto; height: auto; max-width: 100%;"><br></p><p><br></p>`
} else {
desc = `<p><br></p><p><br></p>`
}
updateWareParam.Introduction = desc
updateWareParam.MobileDesc = desc
img := ""
if v.ImgMix != "" {
img = v.ImgMix
} else {
img = v.Img
}
if img != "" {
pic1, err2 := uploadImg2(img, name, "1")
err = err2
err = api.JdShopAPI.ImageUpdate(v.JdsWareID, 1, pic1)
if v.Img2 != "" {
pic2, err2 := uploadImg2(v.Img2, name, "2")
err = err2
err = api.JdShopAPI.ImageUpdate(v.JdsWareID, 2, pic2)
} else {
err = api.JdShopAPI.ImageUpdate(v.JdsWareID, 2, pic1)
}
err = api.JdShopAPI.ImageUpdate(v.JdsWareID, 3, pic1)
}
var features = []*jdshopapi.CreateSkuParamFeatures{
&jdshopapi.CreateSkuParamFeatures{
Key: "is7ToReturn", //不支持7天无理由退货
Value: "0",
},
&jdshopapi.CreateSkuParamFeatures{
Key: "tssp", //支持自提
Value: "",
},
// &jdshopapi.CreateSkuParamFeatures{
// Key: "fdms", //分单?
// Value: "1",
// },
}
updateWareParam.Features = features
err = api.JdShopAPI.UpdateWare(updateWareParam)
if err == nil {
//追加商品透图
imageURL := ""
img := v.Img
if img != "" {
suffix := img[strings.LastIndex(img, "."):]
if suffix != ".png" {
if resBinary, _, err := jxutils.DownloadFileByURL(img + model.SkuNameImgToPng); err == nil {
downloadURL, err2 := jxutils.UploadExportContent(resBinary, utils.Int64ToStr(time.Now().Unix()))
err = err2
imageURL, err = uploadImg(downloadURL, name, "tou")
}
} else {
imageURL, err = uploadImg(img, name, "tou")
}
}
api.JdShopAPI.TransparentImageAdd(v.JdsWareID, imageURL)
}
for _, vv := range v.StoreSkuSyncInfoJds {
updateSkusParam, err := buildUpdateSkusParam(v, vv, false)
if err != nil {
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDJDShop], "更新商品基础信息")
return failedList, err
}
_, err = api.JdShopAPI.UpdateSkus(updateSkusParam)
}
}
if err != nil {
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDJDShop], "更新商品基础信息")
}
}
return failedList, err
}
func (p *PurchaseHandler) DeleteStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
if globals.EnableJdShopWrite && vendorStoreID == model.JdShopMainVendorStoreID {
for _, v := range storeSkuList {
if v.IsDeletedBySku {
err = api.JdShopAPI.DeleteSku(utils.Str2Int64(v.VendorSkuID))
} else {
err = api.JdShopAPI.UpOrDown(utils.Str2Int64(v.VendorSkuID2), 2)
if err == nil {
err = api.JdShopAPI.DeleteWare(utils.Str2Int(v.VendorSkuID2))
}
}
if err != nil {
failedList = append(failedList, putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDJDShop], "删除商品")...)
}
}
}
return failedList, err
}
func (p *PurchaseHandler) GetStoreSkusFullInfo(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (skuNameList []*partner.SkuNameInfo, err error) {
var (
pageNo = 1
pageSize = 20
)
_, totalCount, err := api.JdShopAPI.SearchSkuList(pageNo, pageSize)
for ; pageNo <= totalCount/pageSize+1; pageNo++ {
result, _, err := api.JdShopAPI.SearchSkuList(pageNo, pageSize)
if err == nil {
for _, v := range result {
if skuName := vendorSku2Jx(v); skuName != nil {
skuNameList = append(skuNameList, skuName)
}
}
}
}
return skuNameList, err
}
func (p *PurchaseHandler) UpdateStoreSkusStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo, status int) (failedList []*partner.StoreSkuInfoWithErr, err error) {
if globals.EnableJdShopWrite {
var stock = 0
for _, v := range storeSkuList {
if storeID == model.JdShopMainStoreID {
if status == model.SkuStatusNormal {
stock = 9999
}
if v.JdsStockSwitch == model.NO {
stock = 0
}
err = api.JdShopAPI.UpdateSkuStock(utils.Str2Int(v.VendorSkuID), stock)
} else {
storeSkus, err2 := dao.GetStoresSkusInfo(dao.GetDB(), []int{model.JdShopMainStoreID}, []int{v.SkuID})
err = err2
if len(storeSkus) > 0 {
if storeSkus[0].JdsID != 0 && vendorStoreID != "" {
if storeSkus[0].Status == model.SkuStatusNormal {
stock = 9999
}
err = api.JdShopAPI.UpdateSkuSiteStock(storeSkus[0].JdsID, stock, utils.Str2Int(vendorStoreID))
}
}
}
}
if err != nil {
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDJDShop], "修改商品库存")
}
}
return failedList, err
}
func (p *PurchaseHandler) UpdateStoreSkusPrice(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
if globals.EnableJdShopWrite && vendorStoreID == model.JdShopMainVendorStoreID {
for _, v := range storeSkuList {
err = api.JdShopAPI.UpdateSkuJdPrice(utils.Str2Int(v.VendorSkuID), jxutils.IntPrice2Standard(v.VendorPrice))
if err != nil {
failedList = append(failedList, putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDJDShop], "修改商品价格")...)
}
}
}
return failedList, err
}
func (p *PurchaseHandler) UpdateStoreSkusStock(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
if globals.EnableJdShopWrite {
}
return failedList, err
}
func (p *PurchaseHandler) GetStoreAllCategories(ctx *jxcontext.Context, storeID int, vendorStoreID string) (cats []*partner.BareCategoryInfo, err error) {
result, err := api.JdShopAPI.FindShopCategories()
for _, v := range result {
var cat = &partner.BareCategoryInfo{
VendorCatID: utils.Int64ToStr(v.CID),
Name: v.Name,
}
if v.ParentCID == 0 {
cat.Level = 1
} else {
cat.Level = 2
}
cats = append(cats, cat)
}
return cats, err
}
func (p *PurchaseHandler) CreateStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeCat *dao.SkuStoreCatInfo) (err error) {
if globals.EnableJdShopWrite && vendorStoreID == model.JdShopMainVendorStoreID {
status, err2 := updateOrCreateCategories(storeCat, true)
err = err2
if status == -1 {
return fmt.Errorf("京东商城店内分类创建失败!")
}
if err != nil {
return err
}
time.Sleep(time.Second * 2)
// flag := false
// for {
result, err := api.JdShopAPI.FindShopCategories()
if err != nil {
return err
}
for _, v := range result {
if v.Name == storeCat.Name {
storeCat.VendorCatID = utils.Int64ToStr(v.CID)
// flag = true
break
}
}
if storeCat.VendorCatID == "" {
return fmt.Errorf("京东商城店内分类创建可能失败了storeID: %v", storeID)
}
// if flag {
// break
// }
// }
}
return err
}
func (p *PurchaseHandler) UpdateStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeCat *dao.SkuStoreCatInfo) (err error) {
if globals.EnableJdShopWrite && vendorStoreID == model.JdShopMainVendorStoreID {
status, err2 := updateOrCreateCategories(storeCat, false)
err = err2
if status == -1 {
return fmt.Errorf("京东商城店内分类更新失败!")
}
}
return err
}
func (p *PurchaseHandler) DeleteStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID, vendorCatID string, level int) (err error) {
if globals.EnableJdShopWrite && vendorStoreID == model.JdShopMainVendorStoreID {
_, err = api.JdShopAPI.DeleteShopCategory(utils.Str2Int64(vendorCatID))
}
return err
}
func (p *PurchaseHandler) IsErrSkuExist(err error) (isExist bool) {
return false
}
func (p *PurchaseHandler) IsErrCategoryExist(err error) (isExist bool) {
return false
}
func (p *PurchaseHandler) IsErrCategoryNotExist(err error) (isNotExist bool) {
return false
}
func (p *PurchaseHandler) GetStoreSkusBatchSize(funcID int) (batchSize int) {
return 1
}
func (p *PurchaseHandler) GetSensitiveWordRegexp() *regexp.Regexp {
return sensitiveWordRegexp
}
func (p *PurchaseHandler) IsErrSkuNotExist(err error) (isNotExist bool) {
if strings.Contains(err.Error(), deleteErr1) || (strings.Contains(err.Error(), deleteErr2) && strings.Contains(err.Error(), deleteErr3)) {
return true
}
return false
}
func ybSkuStatus2Jx(ybStatus int) (jxSkuStatus int) {
if ybStatus == yinbaoapi.SkuStatusEnable {
jxSkuStatus = model.SkuStatusNormal
} else if ybStatus == yinbaoapi.SkuStatusDisabled {
jxSkuStatus = model.SkuStatusDontSale
} else if ybStatus == yinbaoapi.SkuStatusDeleted {
jxSkuStatus = model.SkuStatusDeleted
}
return jxSkuStatus
}
func vendorSku2Jx(result *jdshopapi.SearchSkuListResult) (skuName *partner.SkuNameInfo) {
if result == nil {
globals.SugarLogger.Warnf("vendorSku2Jx, strange result:%s", utils.Format4Output(result, true))
return nil
}
skuName = &partner.SkuNameInfo{
VendorNameID: utils.Int64ToStr(result.WareID),
SkuList: []*partner.SkuInfo{
&partner.SkuInfo{
StoreSkuInfo: partner.StoreSkuInfo{
SkuID: utils.Str2Int(result.OuterID),
VendorSkuID: utils.Int64ToStr(result.SkuID),
VendorNameID: utils.Int64ToStr(result.WareID),
Stock: result.StockNum,
VendorPrice: utils.Float64TwoInt64(result.JdPrice * 100),
},
Comment: result.SaleAttrs[0].AttrValueAlias[0],
},
},
}
return skuName
}
func updateOrCreateCategories(storeCat *dao.SkuStoreCatInfo, isCreate bool) (status int64, err error) {
var createShopCategoryParams []*jdshopapi.CreateShopCategoryParam
result, err := api.JdShopAPI.FindShopCategories()
if err != nil {
return -1, err
}
for _, v := range result {
createShopCategoryParam := &jdshopapi.CreateShopCategoryParam{
HomeShow: "0",
ID: utils.Int64ToStr(v.CID),
Open: "",
OrderNo: utils.Int2Str(v.OrderNo),
ParentID: utils.Int64ToStr(v.ParentCID),
Title: v.Name,
Type: jdshopapi.UpdateCatType,
}
createShopCategoryParams = append(createShopCategoryParams, createShopCategoryParam)
}
createShopCategoryParam2 := &jdshopapi.CreateShopCategoryParam{
HomeShow: "0",
Open: "",
OrderNo: utils.Int2Str(storeCat.Seq),
ParentID: storeCat.ParentVendorCatID,
Title: storeCat.Name,
}
if isCreate {
createShopCategoryParam2.Type = jdshopapi.CreateCatType
createShopCategoryParam2.ID = "1"
createShopCategoryParams = append(createShopCategoryParams, createShopCategoryParam2)
} else {
for _, v := range createShopCategoryParams {
if v.ID == storeCat.VendorCatID {
v.Title = createShopCategoryParam2.Title
v.OrderNo = createShopCategoryParam2.OrderNo
}
}
}
status, err = api.JdShopAPI.CreateShopCategory(createShopCategoryParams)
return status, err
}
func buildCreateWareParam(storeSku *dao.StoreSkuSyncInfo) (createSkuParamWare *jdshopapi.CreateSkuParamWare, createSkuParamSkus []*jdshopapi.CreateSkuParamSkus, err error) {
var (
images []*jdshopapi.CreateSkuParamImages
vendorCatID int
)
if storeSku.VendorCatID == "0" {
resultCat, _ := api.JdShopAPI.FindShopCategories()
for _, v := range resultCat {
if v.Name == storeSku.CategoryName {
vendorCatID = int(v.CID)
break
}
}
} else {
vendorCatID = utils.Str2Int(storeSku.VendorCatID)
}
name := filterSensitiveWord(storeSku.Name)
createSkuParamWare = &jdshopapi.CreateSkuParamWare{
Title: name,
ShopCategorys: []int{vendorCatID},
CategoryID: int(storeSku.VendorVendorCatID),
BrandID: jdshopapi.JxBrandId,
// TransportID: jdshopapi.TransportID,
WareStatus: 8, //上架待审核
OuterID: utils.Int2Str(storeSku.NameID),
VenderID: jdshopapi.VenderID,
Length: 100,
Width: 100,
Height: 100,
Weight: 0.5,
JdPrice: jxutils.IntPrice2Standard(storeSku.UnitPrice),
// MarketPrice: jxutils.IntPrice2Standard(storeSku.UnitPrice),
// PromiseID: jdshopapi.JdsPromiseID,
}
if storeSku.VendorVendorCatID != jdshopapi.JdsOtherMeatCatID {
createSkuParamWare.PromiseID = jdshopapi.JdsPromiseID
}
if storeSku.VendorVendorCatID == jdshopapi.JdsBeefCatID {
createSkuParamWare.MultiCategoryID = jdshopapi.JdsBeefLastCatID
}
//上传京东图片
//规则,有两张就传两张,没有就重复传一张
pic1, err := uploadImg(storeSku.Img, name, "1")
img1 := &jdshopapi.CreateSkuParamImages{
ColorID: "0000000000",
ImgIndex: 1,
ImgURL: pic1,
}
img2 := &jdshopapi.CreateSkuParamImages{
ColorID: "0000000000",
ImgIndex: 2,
}
if storeSku.Img2 == "" {
img2.ImgURL = pic1
} else {
pic2, err2 := uploadImg(storeSku.Img, name, "2")
err = err2
img2.ImgURL = pic2
}
img3 := &jdshopapi.CreateSkuParamImages{
ColorID: "0000000000",
ImgIndex: 3,
ImgURL: pic1,
}
images = append(images, img1)
images = append(images, img2)
images = append(images, img3)
createSkuParamWare.Images = images
//商品详情拼接
var desc string
if storeSku.DescImg != "" {
pic3, err2 := uploadImg(storeSku.DescImg, name, "desc")
err = err2
desc = `<p><img src="` + jdshopapi.JdsImgURL + pic3 + `" style="width: auto; height: auto; max-width: 100%;"><br></p><p><br></p>`
} else {
desc = `<p><br></p><p><br></p>`
}
createSkuParamWare.MobileDesc = desc
createSkuParamWare.Introduction = desc
//设置商品属性值
var (
attrIDs = make(map[string]int) //贮存方式,净含量,保质期IDs
zctjValueID int64 //贮存条件冷藏0-4的id
gcjkValueID int64 //国产进口的id
lbValueID int64 //类别的ID
bcztValueID int64 //保存状态ID
rmsjValueID int64 //热卖时间ID
attrsProp []*jdshopapi.CreateSkuParamAttrs
)
attrs, err := api.JdShopAPI.FindAttrs(int(storeSku.VendorVendorCatID))
for _, v := range attrs {
if v.Name == "保质期" {
attrIDs[v.Name] = v.ID
} else if v.Name == "贮存条件" {
attrIDs[v.Name] = v.ID
} else if v.Name == "净含量" {
attrIDs[v.Name] = v.ID
} else if v.Name == "规格" {
attrIDs[v.Name] = v.ID
} else if v.Name == "国产/进口" {
attrIDs[v.Name] = v.ID
} else if v.Name == "类别" {
attrIDs[v.Name] = v.ID
} else if v.Name == "保存状态" {
attrIDs[v.Name] = v.ID
} else if v.Name == "热卖时间" {
attrIDs[v.Name] = v.ID
}
}
values, _, err := api.JdShopAPI.FindValuesByAttrId(attrIDs["贮存条件"])
for _, v := range values {
if v.Name == "冷藏 0-4℃" {
zctjValueID = v.ID
}
}
if attrIDs["国产/进口"] != 0 {
values2, _, err2 := api.JdShopAPI.FindValuesByAttrId(attrIDs["国产/进口"])
err = err2
for _, v := range values2 {
if v.Name == "国产" {
gcjkValueID = v.ID
}
}
attrgcjk := &jdshopapi.CreateSkuParamAttrs{
AttrID: utils.Int2Str(attrIDs["国产/进口"]),
AttrValues: []string{utils.Int64ToStr(gcjkValueID)},
}
attrsProp = append(attrsProp, attrgcjk)
}
if attrIDs["保存状态"] != 0 {
values2, _, err2 := api.JdShopAPI.FindValuesByAttrId(attrIDs["保存状态"])
err = err2
for _, v := range values2 {
if v.Name == "冷藏" || v.Name == "活鲜" {
bcztValueID = v.ID
}
}
attrbczt := &jdshopapi.CreateSkuParamAttrs{
AttrID: utils.Int2Str(attrIDs["保存状态"]),
AttrValues: []string{utils.Int64ToStr(bcztValueID)},
}
attrsProp = append(attrsProp, attrbczt)
}
if attrIDs["热卖时间"] != 0 {
values2, _, err2 := api.JdShopAPI.FindValuesByAttrId(attrIDs["热卖时间"])
err = err2
for _, v := range values2 {
if v.Name == "12月" {
rmsjValueID = v.ID
}
}
attrrmsj := &jdshopapi.CreateSkuParamAttrs{
AttrID: utils.Int2Str(attrIDs["热卖时间"]),
AttrValues: []string{utils.Int64ToStr(rmsjValueID)},
}
attrsProp = append(attrsProp, attrrmsj)
}
if storeSku.VendorVendorCatID == jdshopapi.JdsBeefCatID {
var exValueID int64
values2, _, err2 := api.JdShopAPI.FindValuesByAttrId(150390)
err = err2
for _, v := range values2 {
if v.Name == "其它" {
exValueID = v.ID
}
}
attrex := &jdshopapi.CreateSkuParamAttrs{
AttrID: utils.Int2Str(150390),
AttrValues: []string{utils.Int64ToStr(exValueID)},
}
attrsProp = append(attrsProp, attrex)
}
attrZctj := &jdshopapi.CreateSkuParamAttrs{
AttrID: utils.Int2Str(attrIDs["贮存条件"]),
AttrValues: []string{utils.Int64ToStr(zctjValueID)},
}
attrJhl := &jdshopapi.CreateSkuParamAttrs{
AttrID: utils.Int2Str(attrIDs["净含量"]),
AttrValues: []string{"0.5"},
}
attrBzq := &jdshopapi.CreateSkuParamAttrs{
AttrID: utils.Int2Str(attrIDs["保质期"]),
AttrValues: []string{"5"},
}
attrsProp = append(attrsProp, attrZctj)
attrsProp = append(attrsProp, attrJhl)
attrsProp = append(attrsProp, attrBzq)
createSkuParamWare.MultiCateProps = attrsProp
var features = []*jdshopapi.CreateSkuParamFeatures{
&jdshopapi.CreateSkuParamFeatures{
Key: "is7ToReturn", //不支持7天无理由退货
Value: "0",
},
&jdshopapi.CreateSkuParamFeatures{
Key: "tssp", //支持自提
Value: "",
},
// &jdshopapi.CreateSkuParamFeatures{
// Key: "fdms", //分单?
// Value: "1",
// },
}
createSkuParamWare.Features = features
//组合sku
var vendorPrice int64 = 0
for _, v := range storeSku.StoreSkuSyncInfoJds {
var (
ggValueID int64 //规格的属性id
attrsPropSku []*jdshopapi.CreateSkuParamAttrs
multiPropSku []*jdshopapi.CreateSkuParamAttrs
specQuality string
)
valuesSku, maxNo, _ := api.JdShopAPI.FindValuesByAttrId(attrIDs["规格"])
if v.SpecUnit == model.SpecUnitNames[1] || v.SpecUnit == model.SpecUnitNames[2] {
specQuality = strings.TrimRight(fmt.Sprintf("%.2f", float64(v.SpecQuality)), "0.") + v.SpecUnit
} else {
specQuality = utils.Float64ToStr(float64(v.SpecQuality)) + v.SpecUnit
}
if v.Comment != "" {
specQuality = v.Comment
}
for _, v := range valuesSku {
if v.Name == specQuality {
ggValueID = v.ID
}
}
if ggValueID == 0 { //说明没有建这个规格,要建上
catID, _ := api.JdShopAPI.SaveVenderAttrValue(specQuality, attrIDs["规格"], int(storeSku.VendorVendorCatID), maxNo+1)
ggValueID = catID
}
attrSku := &jdshopapi.CreateSkuParamAttrs{
AttrID: utils.Int2Str(attrIDs["规格"]),
AttrValues: []string{utils.Int64ToStr(ggValueID)},
}
attrsPropSku = append(attrsPropSku, attrSku)
sku := &jdshopapi.CreateSkuParamSkus{
JdPrice: jxutils.IntPrice2Standard(v.VendorPrice),
// StockNum: 9999,
Type: "com.jd.pop.ware.ic.api.domain.sku",
Type2: "com.jd.pop.ware.ic.api.domain.Sku",
OuterID: utils.Int2Str(v.SkuID),
}
sku.SaleAttrs = attrsPropSku
if attrIDs["类别"] != 0 {
values2, _, err2 := api.JdShopAPI.FindValuesByAttrId(attrIDs["类别"])
err = err2
lbValueID = values2[len(values2)-1].ID
attrlb := &jdshopapi.CreateSkuParamAttrs{
AttrID: utils.Int2Str(attrIDs["类别"]),
AttrValues: []string{utils.Int64ToStr(lbValueID)},
}
multiPropSku = append(multiPropSku, attrlb)
}
sku.MultiCateProps = multiPropSku
createSkuParamSkus = append(createSkuParamSkus, sku)
if v.VendorPrice > vendorPrice {
vendorPrice = v.VendorPrice
}
if v.Status == model.SkuStatusNormal {
sku.StockNum = 9999
} else {
sku.StockNum = 0
}
}
//市场价固定500
createSkuParamWare.MarketPrice = 500
return createSkuParamWare, createSkuParamSkus, err
}
//京东商城上传图片,若平台上已经有了这个图就直接拿来用了
func uploadImg(img, name, index string) (imgURL string, err error) {
result, err := api.JdShopAPI.QueryPicture(name + index)
if len(result) > 0 {
imgURL = result[0].PictureURL
} else {
data, _, err := jxutils.DownloadFileByURL(img)
if err != nil {
return imgURL, err
}
uploadResult, err := api.JdShopAPI.UploadPicture(data, 0, name+index)
if err != nil {
return imgURL, err
}
imgURL = uploadResult.PictureURL
}
return imgURL, err
}
func uploadImg2(img, name, index string) (imgURL string, err error) {
data, _, err := jxutils.DownloadFileByURL(img)
if err != nil {
return imgURL, err
}
uploadResult, err := api.JdShopAPI.UploadPicture(data, 0, name+index)
if err != nil {
return imgURL, err
}
imgURL = uploadResult.PictureURL
return imgURL, err
}
func filterSensitiveWord(name string) (result string) {
for _, v := range jdshopapi.SensitiveWordMap {
if strings.Contains(name, v) {
return strings.ReplaceAll(name, v, "")
}
}
return name
}
func buildUpdateSkusParam(storeSku *dao.StoreSkuSyncInfo, v *dao.StoreSkuSyncInfo, isCreate bool) (updateSkusParam *jdshopapi.UpdateSkusParam, err error) {
var (
ggValueID int64 //规格的属性id
attrsPropSku []*jdshopapi.CreateSkuParamAttrs
skus []*jdshopapi.UpdateSkusParamSkus
multiPropSku []*jdshopapi.CreateSkuParamAttrs
specQuality string
)
updateSkusParam = &jdshopapi.UpdateSkusParam{
WareID: storeSku.JdsWareID,
}
sku := &jdshopapi.UpdateSkusParamSkus{
WareID: storeSku.JdsWareID,
JdPrice: jxutils.IntPrice2Standard(v.VendorPrice),
Type: "com.jd.pop.ware.ic.api.domain.sku",
Type2: "com.jd.pop.ware.ic.api.domain.Sku",
OuterID: utils.Int2Str(v.SkuID),
}
//库存设置
if v.StoreSkuStatus == model.SkuStatusNormal {
sku.StockNum = "9999"
} else {
sku.StockNum = "0"
}
//规格类别设置
attrIDs := make(map[string]int)
attrs, err := api.JdShopAPI.FindAttrs(int(storeSku.VendorVendorCatID))
for _, v := range attrs {
if v.Name == "规格" {
attrIDs[v.Name] = v.ID
} else if v.Name == "类别" {
attrIDs[v.Name] = v.ID
}
}
if attrIDs["类别"] != 0 {
values2, _, err2 := api.JdShopAPI.FindValuesByAttrId(attrIDs["类别"])
err = err2
lbValueID := values2[len(values2)-1].ID
attrlb := &jdshopapi.CreateSkuParamAttrs{
AttrID: utils.Int2Str(attrIDs["类别"]),
AttrValues: []string{utils.Int64ToStr(lbValueID)},
}
multiPropSku = append(multiPropSku, attrlb)
}
sku.MultiCateProps = multiPropSku
if v.SpecUnit == model.SpecUnitNames[1] || v.SpecUnit == model.SpecUnitNames[2] {
if math.Mod(float64(v.SpecQuality), 10) != 0 {
specQuality = strings.TrimRight(fmt.Sprintf("%.2f", float64(v.SpecQuality)), "0.") + v.SpecUnit
} else {
specQuality = utils.Float64ToStr(float64(v.SpecQuality)) + v.SpecUnit
}
} else {
specQuality = utils.Float64ToStr(float64(v.SpecQuality)) + v.SpecUnit
}
valuesSku, maxNo, _ := api.JdShopAPI.FindValuesByAttrId(attrIDs["规格"])
if isCreate {
for _, vv := range valuesSku {
if vv.Name == specQuality {
ggValueID = vv.ID
break
}
}
if ggValueID == 0 { //说明没有建这个规格,要建上
catID, _ := api.JdShopAPI.SaveVenderAttrValue(specQuality, attrIDs["规格"], int(storeSku.VendorVendorCatID), maxNo+1)
ggValueID = catID
}
attrSku := &jdshopapi.CreateSkuParamAttrs{
AttrID: utils.Int2Str(attrIDs["规格"]),
AttrValues: []string{utils.Int64ToStr(ggValueID)},
}
attrsPropSku = append(attrsPropSku, attrSku)
sku.SaleAttrs = attrsPropSku
} else {
vendorSku, err2 := api.JdShopAPI.FindSkuById(utils.Str2Int64(v.VendorSkuID))
err = err2
vendorAttrValue := vendorSku.SaleAttrs[0].AttrValueAlias[0]
if v.Comment != "" {
specQuality = v.Comment
}
if v.Comment != vendorAttrValue {
err = api.JdShopAPI.UpdateWareSaleAttrvalueAlias(&jdshopapi.UpdateWareSaleAttrvalueAliasParam{
WareID: v.JdsWareID,
Props: []*jdshopapi.CreateSkuParamAttrs2{
&jdshopapi.CreateSkuParamAttrs2{
AttrID: vendorSku.SaleAttrs[0].AttrID,
AttrValues: []string{vendorSku.SaleAttrs[0].AttrValues[0]},
AttrValueAlias: []string{specQuality},
Type: "com.jd.pop.ware.ic.api.domain.prop",
Type2: "com.jd.pop.ware.ic.api.domain.Prop",
},
},
})
sku.SkuID = utils.Str2Int64(v.VendorSkuID)
}
attrSku := &jdshopapi.CreateSkuParamAttrs{
AttrID: vendorSku.SaleAttrs[0].AttrID,
AttrValues: []string{vendorSku.SaleAttrs[0].AttrValues[0]},
}
attrsPropSku = append(attrsPropSku, attrSku)
sku.SaleAttrs = attrsPropSku
}
skus = append(skus, sku)
updateSkusParam.Skus = skus
return updateSkusParam, err
}

View File

@@ -1,11 +0,0 @@
package jx
import (
"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"
)
func (c *PurchaseHandler) SyncAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actOrderRules []*model.ActOrderRule, actStoreSkuList []*model.ActStoreSku2) (err error) {
return err
}

View File

@@ -1,34 +0,0 @@
package jx
import (
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
)
type PurchaseHandler struct {
partner.BasePurchasePlatform
}
var (
CurPurchaseHandler *PurchaseHandler
)
func init() {
globals.SugarLogger.Debug("init jx")
if true {
CurPurchaseHandler = new(PurchaseHandler)
// 不能注册京西
// partner.RegisterPurchasePlatform(CurPurchaseHandler)
partner.RegisterPurchaseOrderHandler(CurPurchaseHandler.GetVendorID(), CurPurchaseHandler)
}
}
func (c *PurchaseHandler) GetVendorID() int {
return model.VendorIDJX
}
func (p *PurchaseHandler) UploadImg(ctx *jxcontext.Context, vendorOrgCode, imgURL string, imgData []byte, imgName string, imgType int) (imgHint string, err error) {
return imgHint, err
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,26 +0,0 @@
package localjx
import (
"testing"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/globals/testinit"
)
func init() {
testinit.Init()
}
func TestGenOrderNo(t *testing.T) {
orderNo := GenOrderNo(jxcontext.AdminCtx)
t.Log(orderNo)
}
func TestGetAvailableDeliverTime(t *testing.T) {
timeInfo, err := GetAvailableDeliverTime(jxcontext.AdminCtx, 100118)
if err != nil {
t.Fatal(err)
}
t.Log(utils.Format4Output(timeInfo, false))
}

View File

@@ -1,182 +0,0 @@
package localjx
import (
"encoding/json"
"strings"
"time"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/baseapi/platformapi/tonglianpayapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/auth2/authprovider/weixin"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals/api"
)
func pay4OrderByTL(ctx *jxcontext.Context, order *model.GoodsOrder, payType int, vendorPayType string) (orderPay *model.OrderPay, err error) {
// if order.FromStoreID != 0 {
// result, _ := orderman.GetMatterStoreOrderCount(nil, order.FromStoreID)
// if !result.Flag {
// return nil, fmt.Errorf("该门店[%v]已在一周内申请过物料,请勿重复申请!", order.FromStoreID)
// }
// }
payCreatedAt := time.Now()
param := &tonglianpayapi.CreateUnitorderOrderParam{
Trxamt: int(order.ActualPayPrice),
NotifyUrl: globals.TLPayNotifyURL,
Reqsn: order.VendorOrderID,
PayType: vendorPayType,
}
//暂时做兼容处理
if vendorPayType == "JSAPI" {
param.PayType = tonglianpayapi.PayTypeWxXcx
}
if vendorPayType == tonglianpayapi.PayTypeWxXcx {
if authInfo, err := ctx.GetV2AuthInfo(); err == nil && authInfo.GetAuthType() == weixin.AuthTypeMini {
param.Acct = authInfo.GetAuthID()
}
}
if vendorPayType == tonglianpayapi.PayTypeH5 {
param2 := &tonglianpayapi.CreateH5UnitorderOrderParam{
Trxamt: int(order.ActualPayPrice),
NotifyUrl: globals.TLPayNotifyURL,
Body: "京西菜市",
Charset: "UTF-8",
}
err = api.TLpayAPI.CreateH5UnitorderOrder(param2)
} else {
result, err := api.TLpayAPI.CreateUnitorderOrder(param)
if err == nil {
var result2 tonglianpayapi.PayInfo
json.Unmarshal([]byte(result.PayInfo), &result2)
prePayID := result2.Package[strings.LastIndex(result2.Package, "=")+1 : len(result2.Package)]
orderPay = &model.OrderPay{
PayOrderID: param.Reqsn,
PayType: payType,
VendorPayType: vendorPayType,
TransactionID: result.TrxID,
VendorOrderID: order.VendorOrderID,
VendorID: order.VendorID,
Status: 0,
PayCreatedAt: payCreatedAt,
PrepayID: prePayID,
CodeURL: utils.LimitUTF8StringLen(result.PayInfo, 3200),
TotalFee: int(order.ActualPayPrice),
}
}
}
return orderPay, err
}
func OnTLPayCallback(call *tonglianpayapi.CallBackResult) (err error) {
globals.SugarLogger.Debugf("OnTLPayCallback msg:%s", utils.Format4Output(call, true))
switch call.TrxCode {
case tonglianpayapi.MsgTypePay:
err = onTLpayFinished(call)
case tonglianpayapi.MsgTypeRefund:
err = onTLpayRefund(call)
}
return err
}
func onTLpayFinished(call *tonglianpayapi.CallBackResult) (err error) {
orderPay := &model.OrderPay{
PayOrderID: call.CusorderID,
// PayType: model.PayTypeTL,
}
orderPay.DeletedAt = utils.DefaultTimeValue
db := dao.GetDB()
if err = dao.GetEntity(db, orderPay, "PayOrderID", "DeletedAt"); err == nil {
if orderPay.Status != 0 {
globals.SugarLogger.Debugf("already pay msg:%s, err:%v", utils.Format4Output(call, true), err)
return err
}
loc, _ := time.LoadLocation("Local")
t1, _ := time.ParseInLocation("20060102150405", call.PayTime, loc)
orderPay.PayFinishedAt = utils.Time2Pointer(t1)
// orderPay.TransactionID = call.ChnlTrxID
orderPay.OriginalData = utils.Format4Output(call, true)
if call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
orderPay.Status = model.PayStatusYes
} else {
orderPay.Status = model.PayStatusFailed
}
dao.UpdateEntity(db, orderPay)
if call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
err = OnPayFinished(orderPay)
}
} else {
globals.SugarLogger.Debugf("onTLpayFinished msg:%s, err:%v", utils.Format4Output(call, true), err)
}
return err
}
func onTLpayRefund(call *tonglianpayapi.CallBackResult) (err error) {
orderPayRefund := &model.OrderPayRefund{
RefundID: call.CusorderID,
}
db := dao.GetDB()
if err = dao.GetEntity(db, orderPayRefund, "RefundID"); err == nil {
if call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
orderPayRefund.Status = model.RefundStatusYes
} else {
orderPayRefund.Status = model.RefundStatusFailed
}
orderPayRefund.OriginalData = utils.Format4Output(call, true)
dao.UpdateEntity(db, orderPayRefund)
} else if dao.IsNoRowsError(err) {
globals.SugarLogger.Warnf("收到异常的退款事件, call:%s", utils.Format4Output(call, true))
}
orderPay := &model.OrderPay{
VendorOrderID: orderPayRefund.VendorOrderID,
VendorID: jxutils.GetPossibleVendorIDFromVendorOrderID(orderPayRefund.VendorOrderID),
PayType: model.PayTypeWX,
Status: model.PayStatusYes,
}
orderPay.DeletedAt = utils.DefaultTimeValue
if err = dao.GetEntity(db, orderPay, "VendorOrderID", "VendorID", "PayType", "Status", "DeletedAt"); err == nil {
orderPay.Status = model.PayStatusRefund
dao.UpdateEntity(db, orderPay)
}
return err
}
func RefundOrderByTL(ctx *jxcontext.Context, orderPay *model.OrderPay, refundID string, refundFee int, refundDesc string) (orderPayRefund *model.OrderPayRefund, err error) {
result, err := api.TLpayAPI.PayRefund(&tonglianpayapi.PayRefundParam{
Trxamt: refundFee,
Reqsn: utils.GetUUID(),
Remark: refundDesc,
OldTrxID: orderPay.TransactionID,
})
if err == nil {
orderPayRefund = &model.OrderPayRefund{
RefundID: refundID,
VendorRefundID: result.TrxID,
VendorOrderID: orderPay.VendorOrderID,
VendorID: orderPay.VendorID,
Status: model.RefundStatusNo,
TransactionID: orderPay.TransactionID,
RefundFee: refundFee,
RefundCreatedAt: time.Now(),
}
dao.WrapAddIDCULDEntity(orderPayRefund, ctx.GetUserName())
db := dao.GetDB()
if result.TrxStatus == tonglianpayapi.TrxStatusSuccess {
orderPayRefund.Status = model.RefundStatusYes
} else {
orderPayRefund.Status = model.RefundStatusFailed
}
orderPayRefund.OriginalData = utils.Format4Output(result, true)
dao.CreateEntity(db, orderPayRefund)
orderPay.Status = model.PayStatusRefund
dao.UpdateEntity(db, orderPay)
}
return orderPayRefund, err
}

View File

@@ -1,65 +0,0 @@
package localjx
import (
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals/api"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
)
type GetJxShopUsersResult struct {
model.User
BuyCount int `json:"buyCount"`
ActualPayPrice int `json:"actualPayPrice"`
GoodCommentCount int `json:"goodCommentCount"`
BadCommentCount int `json:"badCommentCount"`
UserMembers []*model.UserMember `json:"userMembers"`
}
func GetJxShopUsers(ctx *jxcontext.Context, keyword string, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
var (
requestList []*GetJxShopUsersResult
db = dao.GetDB()
)
sql := `
SELECT SQL_CALC_FOUND_ROWS DISTINCT a.*, b.buy_count, b.actual_pay_price
FROM user a,
(SELECT a.user_id, COUNT(*) buy_count, SUM(c.actual_pay_price) actual_pay_price
FROM user a
JOIN auth_bind b ON b.user_id = a.user_id AND b.deleted_at = ? AND b.type_id = ?
JOIN goods_order c ON c.user_id = a.user_id AND c.status <> ? AND c.store_id <> ?
WHERE a.deleted_at = ?
GROUP BY 1) b
WHERE a.user_id = b.user_id
`
sqlParams := []interface{}{
utils.DefaultTimeValue, api.WeixinMiniAppID2,
model.OrderStatusCanceled, model.MatterStoreID,
utils.DefaultTimeValue,
}
if keyword != "" {
sql += " AND (a.user_id LIKE ? OR a.name LIKE ? OR a.mobile LIKE ? OR a.user_id2 LIKE ?)"
sqlParams = append(sqlParams, "%"+keyword+"%", "%"+keyword+"%", "%"+keyword+"%", "%"+keyword+"%")
}
sql += "LIMIT ? OFFSET ?"
pageSize = jxutils.FormalizePageSize(pageSize)
sqlParams = append(sqlParams, pageSize, offset)
dao.Begin(db)
defer dao.Commit(db)
if err = dao.GetRows(db, &requestList, sql, sqlParams...); err == nil {
pagedInfo = &model.PagedInfo{
TotalCount: dao.GetLastTotalRowCount(db),
// Data: requestList,
}
for _, v := range requestList {
userMembers, _ := dao.GetUserMember(db, v.UserID, "", model.MemberTypeDiscountCard, model.YES)
v.UserMembers = userMembers
}
pagedInfo.Data = requestList
}
return pagedInfo, err
}

View File

@@ -1,152 +0,0 @@
package localjx
import (
"fmt"
"time"
"git.rosy.net.cn/baseapi/platformapi/wxpayapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/auth2/authprovider/weixin"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"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"
)
func vendorPayType2WxpayType(vendorPayType string) string {
return vendorPayType
}
func getOrderBrief(order *model.GoodsOrder) string {
return fmt.Sprintf("%s等共%d件商品", order.Skus[0].SkuName, order.GoodsCount)
}
func pay4OrderByWX(ctx *jxcontext.Context, order *model.GoodsOrder, vendorPayType string) (orderPay *model.OrderPay, err error) {
payCreatedAt := time.Now()
param := &wxpayapi.CreateOrderParam{
OutTradeNo: utils.Int64ToStr(GenPayOrderID(order)),
Body: getOrderBrief(order),
NotifyURL: globals.WxpayNotifyURL,
SpbillCreateIP: ctx.GetRealRemoteIP(),
TradeType: vendorPayType2WxpayType(vendorPayType),
TotalFee: int(order.ActualPayPrice),
TimeStart: wxpayapi.Time2PayTime(payCreatedAt),
// TimeExpire: wxpayapi.Time2PayTime(payCreatedAt.Add(PayWaitingTime)),
ProfitSharing: wxpayapi.OptYes,
}
if authInfo, err := ctx.GetV2AuthInfo(); err == nil && authInfo.GetAuthType() == weixin.AuthTypeMini {
param.OpenID = authInfo.GetAuthID()
}
result, err := api.WxpayAPI.CreateUnifiedOrder(param)
if err == nil {
orderPay = &model.OrderPay{
PayOrderID: param.OutTradeNo,
PayType: model.PayTypeWX,
VendorPayType: vendorPayType,
VendorOrderID: order.VendorOrderID,
VendorID: order.VendorID,
Status: 0,
PayCreatedAt: payCreatedAt,
PrepayID: result.PrepayID,
CodeURL: result.CodeURL,
TotalFee: int(order.ActualPayPrice),
}
}
return orderPay, err
}
func OnWxPayCallback(msg *wxpayapi.CallbackMsg) (err error) {
globals.SugarLogger.Debugf("OnWxPayCallback msg:%s", utils.Format4Output(msg, true))
switch msg.MsgType {
case wxpayapi.MsgTypePay:
err = onWxpayFinished(msg.Data.(*wxpayapi.PayResultMsg))
case wxpayapi.MsgTypeRefund:
err = onWxpayRefund(msg.Data.(*wxpayapi.RefundResultMsg))
}
return err
}
func onWxpayFinished(msg *wxpayapi.PayResultMsg) (err error) {
orderPay := &model.OrderPay{
PayOrderID: msg.OutTradeNo,
PayType: model.PayTypeWX,
}
orderPay.DeletedAt = utils.DefaultTimeValue
db := dao.GetDB()
if err = dao.GetEntity(db, orderPay, "PayOrderID", "PayType", "DeletedAt"); err == nil {
orderPay.PayFinishedAt = utils.Time2Pointer(wxpayapi.PayTime2Time(msg.TimeEnd))
orderPay.TransactionID = msg.TransactionID
orderPay.OriginalData = utils.Format4Output(msg, true)
if msg.ResultCode == wxpayapi.ResponseCodeSuccess {
orderPay.Status = model.PayStatusYes
} else {
orderPay.Status = model.PayStatusFailed
}
dao.UpdateEntity(db, orderPay)
if msg.ResultCode == wxpayapi.ResponseCodeSuccess {
err = OnPayFinished(orderPay)
}
} else {
globals.SugarLogger.Debugf("onWxpayFinished msg:%s, err:%v", utils.Format4Output(msg, true), err)
}
return err
}
func onWxpayRefund(msg *wxpayapi.RefundResultMsg) (err error) {
orderPayRefund := &model.OrderPayRefund{
RefundID: msg.ReqInfoObj.OutRefundNo,
}
db := dao.GetDB()
if err = dao.GetEntity(db, orderPayRefund, "RefundID"); err == nil {
if msg.ResultCode == wxpayapi.ResponseCodeSuccess {
orderPayRefund.Status = model.RefundStatusYes
} else {
orderPayRefund.Status = model.RefundStatusFailed
}
orderPayRefund.OriginalData = utils.Format4Output(msg, true)
dao.UpdateEntity(db, orderPayRefund)
} else if dao.IsNoRowsError(err) {
globals.SugarLogger.Warnf("收到异常的退款事件, msg:%s", utils.Format4Output(msg, true))
}
orderPay := &model.OrderPay{
VendorOrderID: orderPayRefund.VendorOrderID,
VendorID: jxutils.GetPossibleVendorIDFromVendorOrderID(orderPayRefund.VendorOrderID),
PayType: model.PayTypeWX,
Status: model.PayStatusYes,
}
orderPay.DeletedAt = utils.DefaultTimeValue
if err = dao.GetEntity(db, orderPay, "VendorOrderID", "VendorID", "PayType", "Status", "DeletedAt"); err == nil {
orderPay.Status = model.PayStatusRefund
dao.UpdateEntity(db, orderPay)
}
return err
}
func refundOrderByWX(ctx *jxcontext.Context, orderPay *model.OrderPay, refundID string, refundFee int, refundDesc string) (orderPayRefund *model.OrderPayRefund, err error) {
result, err := api.WxpayAPI.PayRefund(&wxpayapi.PayRefundParam{
OutTradeNo: orderPay.VendorOrderID,
NotifyURL: globals.WxpayNotifyURL,
OutRefundNo: refundID,
TotalFee: orderPay.TotalFee,
RefundFee: refundFee,
RefundDesc: wxpayapi.CData(refundDesc),
})
if err == nil {
orderPayRefund = &model.OrderPayRefund{
RefundID: refundID,
VendorRefundID: result.RefundID,
VendorOrderID: orderPay.VendorOrderID,
VendorID: orderPay.VendorID,
Status: model.RefundStatusNo,
TransactionID: orderPay.TransactionID,
RefundFee: orderPay.TotalFee,
RefundCreatedAt: time.Now(),
}
}
return orderPayRefund, err
}

View File

@@ -1,134 +0,0 @@
package jx
import (
"time"
"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/partner"
"git.rosy.net.cn/jx-callback/business/partner/purchase/jx/localjx"
"git.rosy.net.cn/jx-callback/business/partner/purchase/jx/phpjx"
)
func (c *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *model.GoodsOrder) {
return order
}
func (c *PurchaseHandler) GetOrder(vendorOrgCode, orderID string) (order *model.GoodsOrder, err error) {
order, err = partner.CurOrderManager.LoadOrder(orderID, model.VendorIDJX)
return order, err
}
func (p *PurchaseHandler) GetOrderStatus(vendorOrgCode, vendorOrderID string) (status int, err error) {
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, model.VendorIDJX)
if err == nil {
status = order.Status
}
return status, err
}
func (c *PurchaseHandler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) {
var status int
if isAcceptIt {
status = model.OrderStatusAccepted
} else {
status = model.OrderStatusCanceled
}
if model.IsOrderJXTemp(order) {
err = phpjx.NotifyOrderStatusChanged(order, status)
} else {
err = localjx.AcceptOrRefuseOrder(order, isAcceptIt, userName)
}
return err
}
func (c *PurchaseHandler) PickupGoods(order *model.GoodsOrder, isSelfDelivery bool, userName string) (err error) {
if model.IsOrderJXTemp(order) {
err = phpjx.NotifyOrderStatusChanged(order, model.OrderStatusFinishedPickup)
} else {
err = localjx.PickupGoods(order, isSelfDelivery, userName)
}
return err
}
func (p *PurchaseHandler) AcceptOrRefuseFailedGetOrder(ctx *jxcontext.Context, order *model.GoodsOrder, isAcceptIt bool) (err error) {
return err
}
func (p *PurchaseHandler) CallCourier(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 拣货失败后再次招唤平台配送
return err
}
func (p *PurchaseHandler) ConfirmReceiveGoods(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 投递失败后确认收到退货
return err
}
func (c *PurchaseHandler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) {
return err
}
func (c *PurchaseHandler) Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) {
return err
}
func (c *PurchaseHandler) SelfDeliverDelivering(order *model.GoodsOrder, userName string) (err error) {
if model.IsOrderJXTemp(order) {
err = phpjx.NotifyOrderStatusChanged(order, model.OrderStatusDelivering)
} else {
err = localjx.SelfDeliverDelivering(order, userName)
}
return err
}
func (c *PurchaseHandler) SelfDeliverDelivered(order *model.GoodsOrder, userName string) (err error) {
if model.IsOrderJXTemp(order) {
err = phpjx.NotifyOrderStatusChanged(order, model.OrderStatusFinished)
} else {
err = localjx.SelfDeliverDelivered(order, userName)
}
return err
}
func (c *PurchaseHandler) GetOrderRealMobile(ctx *jxcontext.Context, order *model.GoodsOrder) (mobile string, err error) {
return mobile, err
}
func (c *PurchaseHandler) AgreeOrRefuseCancel(ctx *jxcontext.Context, order *model.GoodsOrder, isAgree bool, reason string) (err error) {
if model.IsOrderJXTemp(order) {
} else {
err = localjx.AgreeOrRefuseCancel(ctx, order, isAgree, reason)
}
return err
}
func (c *PurchaseHandler) CancelOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
if model.IsOrderJXTemp(order) {
err = phpjx.NotifyOrderStatusChanged(order, model.OrderStatusCanceled)
} else {
err = localjx.CancelOrder(ctx, order, reason)
}
return err
}
func (c *PurchaseHandler) AdjustOrder(ctx *jxcontext.Context, order *model.GoodsOrder, removedSkuList []*model.OrderSku, reason string) (err error) {
if model.IsOrderJXTemp(order) {
} else {
err = localjx.AdjustOrder(ctx, order, removedSkuList, reason)
}
return err
}
func (c *PurchaseHandler) ListOrders(ctx *jxcontext.Context, vendorOrgCode string, parentTask tasksch.ITask, queryDate time.Time, vendorStoreID string) (vendorOrderIDs []string, err error) {
return vendorOrderIDs, err
}
func (c *PurchaseHandler) ConfirmSelfTake(ctx *jxcontext.Context, vendorOrderID, selfTakeCode string) (err error) {
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, model.VendorIDJX)
if err == nil {
if model.IsOrderJXTemp(order) {
err = phpjx.NotifyOrderStatusChanged(order, model.OrderStatusFinished)
}
}
return err
}

View File

@@ -1,170 +0,0 @@
package jx
import (
"fmt"
"strings"
"time"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals/api"
"git.rosy.net.cn/jx-callback/business/partner/purchase/jx/localjx"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
)
// 审核售后单申请
func (c *PurchaseHandler) AgreeOrRefuseRefund(ctx *jxcontext.Context, order *model.AfsOrder, approveType int, reason string) (err error) {
var status int
if approveType == partner.AfsApproveTypeRefused {
status = model.AfsOrderStatusFailed
} else {
status = model.AfsOrderStatusFinished
}
orderStatus := &model.OrderStatus{
VendorOrderID: order.AfsOrderID, // 是售后单ID不是订单ID订单ID在RefVendorOrderID中
VendorID: order.VendorID,
OrderType: model.OrderTypeAfsOrder,
RefVendorOrderID: order.VendorOrderID,
RefVendorID: order.VendorID,
VendorStatus: utils.Int2Str(status),
Status: status,
StatusTime: time.Now(),
Remark: reason,
}
if status == model.AfsOrderStatusFinished {
orderPays, err := dao.GetOrderPayList(dao.GetDB(), order.VendorOrderID, order.VendorID)
if err == nil {
_, err = localjx.RefundOrderByTL(ctx, orderPays[0], order.VendorOrderID, int(order.SkuUserMoney), reason)
if err != nil {
return err
} else {
partner.CurOrderManager.OnAfsOrderStatusChanged(orderStatus)
}
}
} else {
partner.CurOrderManager.OnAfsOrderStatusChanged(orderStatus)
}
return err
}
// 确认收到退货
func (c *PurchaseHandler) ConfirmReceivedReturnGoods(ctx *jxcontext.Context, order *model.AfsOrder) (err error) {
err = fmt.Errorf("京西商城当前不支持ConfirmReceivedReturnGoods")
return err
}
// 发起全款退款
func (c *PurchaseHandler) RefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
err = c.PartRefundOrder(ctx, order, order.Skus, reason)
return err
}
// 发起部分退款
func (c *PurchaseHandler) PartRefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, refundSkuList []*model.OrderSku, reason string) (err error) {
globals.SugarLogger.Debugf("PartRefundOrder jx, orderID :%v", order.VendorOrderID)
var (
skuMap = make(map[int]*model.OrderSku)
appID = ""
salePrice int64
db = dao.GetDB()
)
if time.Now().Sub(order.OrderCreatedAt) > 24*time.Hour {
return fmt.Errorf("已超过售后申请时间,如有疑问请联系门店!")
}
referer := ctx.GetRequest().Referer()
index := strings.Index(referer, "//")
if index > 0 {
list := strings.Split(referer[index+2:], "/")
if len(list) >= 2 {
appID = list[1]
}
}
for _, sku := range order.Skus {
skuMap[sku.SkuID] = sku
}
orderStatus := buildOrderStatus(ctx, order, reason, isJxShop(appID))
afsOrder := &model.AfsOrder{
VendorID: order.VendorID,
AfsOrderID: orderStatus.VendorOrderID,
VendorOrderID: orderStatus.RefVendorOrderID,
VendorStoreID: order.VendorStoreID,
StoreID: order.StoreID,
AfsCreatedAt: time.Now(),
VendorAppealType: "",
AppealType: model.AfsAppealTypeRefund,
VendorReasonType: utils.Int2Str(model.AfsReasonNotOthers),
ReasonType: model.AfsReasonNotOthers,
ReasonDesc: utils.LimitUTF8StringLen(reason, 1024),
ReasonImgList: "",
RefundType: model.AfsTypePartRefund,
VendorOrgCode: "",
}
for _, sku := range refundSkuList {
orderSku := &model.OrderSkuFinancial{
Count: sku.Count,
VendorSkuID: utils.Int2Str(sku.SkuID),
SkuID: sku.SkuID,
}
if skuMap[sku.SkuID] != nil {
orderSku.Name = skuMap[sku.SkuID].SkuName
orderSku.UserMoney = skuMap[sku.SkuID].SalePrice * int64(sku.Count)
salePrice += skuMap[sku.SkuID].SalePrice * int64(sku.Count)
}
afsOrder.SkuUserMoney += orderSku.UserMoney
afsOrder.Skus = append(afsOrder.Skus, orderSku)
}
if !isJxShop(appID) {
orderPays, err := dao.GetOrderPayList(db, order.VendorOrderID, order.VendorID)
if err == nil {
_, err = localjx.RefundOrderByTL(ctx, orderPays[0], order.VendorOrderID, int(salePrice), reason)
if err != nil {
return err
} else {
if afsOrder != nil {
err = partner.CurOrderManager.OnAfsOrderNew(afsOrder, orderStatus)
}
}
}
} else {
err = partner.CurOrderManager.OnAfsOrderNew(afsOrder, orderStatus)
}
return err
}
func buildOrderStatus(ctx *jxcontext.Context, order *model.GoodsOrder, reason string, isJxShop bool) (orderStatus *model.OrderStatus) {
orderStatus = &model.OrderStatus{
VendorOrderID: utils.Int64ToStr(jxutils.GenAfsOrderNo()), // 是售后单ID不是订单ID订单ID在RefVendorOrderID中
VendorID: order.VendorID,
OrderType: model.OrderTypeAfsOrder,
RefVendorOrderID: order.VendorOrderID,
RefVendorID: order.VendorID,
VendorStatus: utils.Int2Str(model.AfsOrderStatusWait4Approve),
// Status: model.AfsOrderStatusWait4Approve,
StatusTime: time.Now(),
Remark: reason,
}
if isJxShop {
orderStatus.Status = model.AfsOrderStatusWait4Approve
} else {
orderStatus.Status = model.AfsOrderStatusFinished
}
return orderStatus
}
func isJxShop(appID string) bool {
if appID == api.WeixinMiniAppID2 {
return true
}
return false
}

View File

@@ -1,10 +0,0 @@
package jx
import (
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
)
func (c *PurchaseHandler) ReplyOrderComment(ctx *jxcontext.Context, vendorOrgCode string, orderComment *model.OrderComment, replyComment string) (err error) {
return err
}

View File

@@ -1,55 +0,0 @@
package phpjx
import (
"fmt"
"time"
"git.rosy.net.cn/baseapi/utils"
)
const (
appKey = "4A86853D-E4B6-454E-940A-B68ECDA2B73E"
MsgTypeOrder = "order"
MsgTypeAfsOrder = "afsOrder"
)
type CallbackResponse struct {
Code int `json:"code"`
Data string `json:"data"`
}
type CallbackMsg struct {
AppKey string `json:"appKey"`
MsgType string `json:"msgType"`
SubMsgType string `json:"subMsgType"`
ThingID string `json:"thingID"`
ThingID2 string `json:"thingID2"`
Data string `json:"data"`
Timestamp int64 `json:"timestamp"`
}
func OnCallbackMsg(msg *CallbackMsg) (retVal, errCode string, err error) {
if msg.AppKey != appKey {
return retVal, errCode, fmt.Errorf("无效的AppKey:%s", msg.AppKey)
}
if msg.MsgType == MsgTypeOrder {
retVal, errCode, err = OnOrderMsg(msg)
} else if msg.MsgType == MsgTypeAfsOrder {
err = OnAfsOrderMsg(msg)
}
return retVal, errCode, err
}
func postFakeMsg(orderNo string, status int) {
msg := &CallbackMsg{
AppKey: appKey,
MsgType: MsgTypeOrder,
SubMsgType: utils.Int2Str(status),
ThingID: orderNo,
Timestamp: time.Now().Unix(),
}
utils.CallFuncAsync(func() {
OnCallbackMsg(msg)
})
}

View File

@@ -1,52 +0,0 @@
package phpjx
import (
"testing"
_ "git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals/testinit"
)
func init() {
testinit.Init()
}
func TestBuildNewJxOrder(t *testing.T) {
order, err := partner.CurOrderManager.LoadOrder("920931913000041", model.VendorIDJD)
if err != nil {
t.Fatal(err)
}
order.VendorID = model.VendorIDJX
order.VendorStoreID = utils.Int2Str(order.StoreID)
for _, sku := range order.Skus {
sku.VendorID = model.VendorIDJX
sku.VendorSkuID = utils.Int2Str(sku.SkuID)
}
order2 := &Data4Neworder{
GoodsOrder: *order,
Skus: order.Skus,
}
msg := &CallbackMsg{
AppKey: appKey,
MsgType: MsgTypeOrder,
SubMsgType: utils.Int2Str(model.OrderStatusNew),
ThingID: order.VendorOrderID,
Data: utils.Format4Output(order2, true),
}
t.Logf("\n%s", msg.AppKey)
t.Logf("\n%s", msg.MsgType)
t.Logf("\n%s", msg.SubMsgType)
t.Logf("\n%s", msg.ThingID)
t.Logf("\n%s", msg.Data)
var order3 *model.GoodsOrder
err = utils.UnmarshalUseNumber([]byte(msg.Data), &order3)
if err != nil {
t.Fatal(err)
}
t.Log(order3.OrderCreatedAt)
}

View File

@@ -1,99 +0,0 @@
package phpjx
import (
"fmt"
"net/http"
"strings"
"git.rosy.net.cn/baseapi"
"git.rosy.net.cn/baseapi/platformapi"
"git.rosy.net.cn/baseapi/utils"
)
type API struct {
token string
appKey string
appSecret string
client *http.Client
config *platformapi.APIConfig
}
const (
ResponseCodeSuccess = 200
)
const (
prodURL = "https://www.jingxicaishi.com/index.php/Weimendian/index"
)
var (
exceedLimitCodes = map[int]int{}
canRetryCodes = map[int]int{}
)
var (
jxAPI *API
)
func NewAPI(token, appKey, appSecret string, config ...*platformapi.APIConfig) *API {
curConfig := platformapi.DefAPIConfig
if len(config) > 0 {
curConfig = *config[0]
}
return &API{
token: token,
appKey: appKey,
appSecret: appSecret,
client: &http.Client{Timeout: curConfig.ClientTimeout},
config: &curConfig,
}
}
func init() {
jxAPI = NewAPI("", "", "")
}
func (a *API) AccessAPI(apiStr string, jxParams map[string]interface{}, traceInfo string) (retVal map[string]interface{}, err error) {
err = platformapi.AccessPlatformAPIWithRetry(a.client,
func() *http.Request {
params := utils.MergeMaps(jxParams, map[string]interface{}{
"timestamp": utils.GetCurTimeStr(),
})
var request *http.Request
if false {
} else {
fullURL := prodURL + "/" + apiStr
// baseapi.SugarLogger.Debug(utils.Map2URLValues(params).Encode())
request, _ = http.NewRequest(http.MethodPost, fullURL, strings.NewReader(utils.Map2URLValues(params).Encode()))
request.Header.Set("charset", "UTF-8")
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
}
if traceInfo != "" {
request.Header.Set(platformapi.KeyTrackInfo, traceInfo)
}
// request.Close = true //todo 为了性能考虑还是不要关闭
return request
},
a.config,
func(response *http.Response, bodyStr string, jsonResult1 map[string]interface{}) (errLevel string, err error) {
if jsonResult1 == nil {
return platformapi.ErrLevelRecoverableErr, fmt.Errorf("mapData is nil")
}
code := int(utils.Interface2Int64WithDefault(jsonResult1["code"], 0))
if code == ResponseCodeSuccess {
retVal = jsonResult1
return platformapi.ErrLevelSuccess, nil
}
newErr := utils.NewErrorIntCode(jsonResult1["msg"].(string), code)
if _, ok := exceedLimitCodes[code]; ok {
return platformapi.ErrLevelExceedLimit, newErr
} else if _, ok := canRetryCodes[code]; ok {
return platformapi.ErrLevelRecoverableErr, newErr
} else {
baseapi.SugarLogger.Debugf("jx AccessAPI failed, jsonResult1:%s", utils.Format4Output(jsonResult1, true))
return platformapi.ErrLevelCodeIsNotOK, newErr
}
})
return retVal, err
}

View File

@@ -1,45 +0,0 @@
package phpjx
import (
"git.rosy.net.cn/jx-callback/business/model"
)
var (
orderStatusMap = map[int]int{
model.OrderStatusFinishedPickup: 7,
model.OrderStatusDelivering: 8,
// 4,
model.OrderStatusFinished: 3,
model.OrderStatusCanceled: 3,
}
)
func translateOrderStatus(status int) (outStatus int) {
return status //orderStatusMap[status]
}
func (a *API) NotifyOrderStatusChanged(order *model.GoodsOrder) (err error) {
status := translateOrderStatus(order.Status)
if status > 0 {
_, err = a.AccessAPI("orderChangeStatus", map[string]interface{}{
"orderid": order.VendorOrderID,
"status": status,
"data": "", //string(utils.MustMarshal(order)),
}, "")
}
return err
}
func (a *API) NotifyAfsOrderStatusChanged(afsOrder *model.AfsOrder) (err error) {
status := translateOrderStatus(afsOrder.Status)
if status > 0 {
_, err = a.AccessAPI("afsOrderChangeStatus", map[string]interface{}{
"orderid": afsOrder.VendorOrderID,
"afsOrderID": afsOrder.AfsOrderID,
"status": status,
"data": "", //string(utils.MustMarshal(order)),
}, "")
}
return err
}

View File

@@ -1,21 +0,0 @@
package phpjx
import (
"testing"
_ "git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
)
func TestNotifyOrderStatusChanged(t *testing.T) {
order, err := partner.CurOrderManager.LoadOrder("920931913000041", model.VendorIDJX)
if err != nil {
t.Fatal(err)
}
err = jxAPI.NotifyOrderStatusChanged(order)
if err != nil {
t.Fatal(err)
}
}

View File

@@ -1,84 +0,0 @@
package phpjx
import (
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
)
func NotifyOrderStatusChanged(order *model.GoodsOrder, status int) (err error) {
orderMsg := *order
orderMsg.Status = status
if err = jxAPI.NotifyOrderStatusChanged(&orderMsg); err == nil {
postFakeMsg(orderMsg.VendorOrderID, orderMsg.Status)
}
return err
}
type Data4Neworder struct {
model.GoodsOrder
Skus []*model.OrderSku `json:"skus"`
}
func OnOrderMsg(msg *CallbackMsg) (retVal, errCode string, err error) {
jxutils.CallMsgHandler(func() {
retVal, errCode, err = onOrderMsg(msg)
}, jxutils.ComposeUniversalOrderID(msg.ThingID, model.VendorIDJX))
return retVal, errCode, err
}
func onOrderMsg(msg *CallbackMsg) (retVal, errCode string, err error) {
subMsgType := int(utils.Str2Int64WithDefault(msg.SubMsgType, 0))
if subMsgType == model.OrderStatusNew || subMsgType == model.OrderStatusAdjust {
var order *Data4Neworder
if err = utils.UnmarshalUseNumber([]byte(msg.Data), &order); err == nil {
if order.VendorStatus == "" {
order.VendorStatus = utils.Int2Str(order.Status)
}
retVal, errCode, err = onOrderNew(msg, subMsgType, order)
}
} else {
status := callbackMsg2Status(msg)
err = partner.CurOrderManager.OnOrderStatusChanged("", status)
}
return retVal, errCode, err
}
func callbackMsg2Status(msg *CallbackMsg) *model.OrderStatus {
orderStatus := &model.OrderStatus{
VendorOrderID: msg.ThingID,
VendorID: model.VendorIDJX,
OrderType: model.OrderTypeOrder,
RefVendorOrderID: msg.ThingID,
RefVendorID: model.VendorIDJX,
VendorStatus: msg.SubMsgType,
Status: int(utils.Str2Int64WithDefault(msg.SubMsgType, 0)),
StatusTime: utils.Timestamp2Time(msg.Timestamp),
Remark: "",
}
return orderStatus
}
func onOrderNew(msg *CallbackMsg, subMsgType int, order *Data4Neworder) (retVal, errCode string, err error) {
globals.SugarLogger.Debugf("onOrderNew orderID:%s", msg.ThingID)
order.StoreID = int(utils.Str2Int64WithDefault(order.VendorStoreID, 0))
if order.DeliveryType == "" {
order.DeliveryType = model.OrderDeliveryTypeStoreSelf
}
order.GoodsOrder.Skus = order.Skus
order.VendorID = model.VendorIDJX
order.Flag = model.OrderFlagMaskTempJX
for _, v := range order.GoodsOrder.Skus {
v.SkuID = int(utils.Str2Int64WithDefault(v.VendorSkuID, 0))
}
jxutils.RefreshOrderSkuRelated(&order.GoodsOrder)
orderStatus := model.Order2Status(&order.GoodsOrder)
if subMsgType == model.OrderStatusNew {
err = partner.CurOrderManager.OnOrderNew(&order.GoodsOrder, orderStatus)
} else if subMsgType == model.OrderStatusAdjust {
err = partner.CurOrderManager.OnOrderAdjust(&order.GoodsOrder, orderStatus)
}
return retVal, errCode, err
}

View File

@@ -1,130 +0,0 @@
package phpjx
import (
"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/model"
"git.rosy.net.cn/jx-callback/business/partner"
)
type Data4AfsOrderSku struct {
VendorSkuID string `orm:"column(vendor_sku_id);size(48)" json:"vendorSkuID"` // 平台skuid
PromotionType int `json:"promotionType"` // 商品级别促销类型 (1、无优惠;2、秒杀(已经下线);3、单品直降;4、限时抢购;1202、加价购;1203、满赠(标识商品);6、买赠(买A送B标识B);9999、表示一个普通商品参与捆绑促销设置的捆绑类型;9998、表示一个商品参与了捆绑促销并且还参与了其他促销类型;9997、表示一个商品参与了捆绑促销但是金额拆分不尽,9996:组合购,8001:轻松购会员价,8:第二件N折,9:拼团促销)
Name string `orm:"size(255)" json:"name"` // 商品名
SalePrice int64 `json:"salePrice"` // 售卖价
Count int `json:"count"` // 订单下单数量
}
type Data4AfsOrder struct {
VendorOrderID string `orm:"column(vendor_order_id);size(48)" json:"vendorOrderID"` // 关联原始订单ID
AfsOrderID string `orm:"column(afs_order_id);size(48)" json:"afsOrderID"` // 售后订单ID
AfsCreatedAt time.Time `orm:"type(datetime);null;index" json:"afsCreatedAt"` // 售后单生成时间
VendorStoreID string `orm:"column(vendor_store_id);size(48)" json:"vendorStoreID"` // 外部系统里记录的storeid
VendorStatus string `orm:"size(255)" json:"vendorStatus"`
VendorReasonType string `orm:"size(255)" json:"vendorReasonType"` // 原始售后原因
ReasonDesc string `orm:"size(1024)" json:"reasonDesc"` // 售后原因描述
ReasonImgList string `orm:"size(1024)" json:"reasonImgList"` // 售后描述图片
VendorAppealType string `orm:"size(255)" json:"vendorAppealType"` // 原始售后方式
Skus []*Data4AfsOrderSku
}
func OnAfsOrderMsg(msg *CallbackMsg) (err error) {
jxutils.CallMsgHandlerAsync(func() {
err = onAfsOrderMsg(msg)
}, jxutils.ComposeUniversalOrderID(msg.ThingID, model.VendorIDJX))
return err
}
func buildAfsOrder(msg *CallbackMsg) (outAfsOrder *model.AfsOrder, err error) {
var afsOrder *Data4AfsOrder
if err = utils.UnmarshalUseNumber([]byte(msg.Data), &afsOrder); err == nil {
outAfsOrder = &model.AfsOrder{
VendorID: model.VendorIDJX,
AfsOrderID: afsOrder.AfsOrderID,
VendorOrderID: afsOrder.VendorOrderID,
VendorStoreID: afsOrder.VendorStoreID,
StoreID: int(utils.Str2Int64WithDefault(afsOrder.VendorStoreID, 0)),
AfsCreatedAt: afsOrder.AfsCreatedAt,
VendorStatus: afsOrder.VendorStatus,
VendorReasonType: afsOrder.VendorReasonType,
ReasonType: int8(utils.Str2Int64WithDefault(afsOrder.VendorReasonType, 0)),
ReasonDesc: utils.LimitUTF8StringLen(afsOrder.ReasonDesc, 1024),
ReasonImgList: afsOrder.ReasonImgList,
VendorAppealType: afsOrder.VendorAppealType,
AppealType: int8(utils.Str2Int64WithDefault(afsOrder.VendorAppealType, 0)),
Flag: model.OrderFlagMaskTempJX,
}
outAfsOrder.Status = int(utils.Str2Int64WithDefault(afsOrder.VendorStatus, 0))
for _, x := range afsOrder.Skus {
orderSku := &model.OrderSkuFinancial{
Count: x.Count,
VendorSkuID: x.VendorSkuID,
SkuID: int(utils.Str2Int64WithDefault(x.VendorSkuID, 0)),
Name: x.Name,
}
if x.PromotionType != 0 && x.PromotionType != jdapi.PromotionTypeNormal {
orderSku.StoreSubName = utils.Int2Str(x.PromotionType)
}
outAfsOrder.Skus = append(outAfsOrder.Skus, orderSku)
}
}
return outAfsOrder, err
}
func callbackAfsMsg2Status(msg *CallbackMsg) *model.OrderStatus {
orderStatus := &model.OrderStatus{
VendorOrderID: msg.ThingID2, // 是售后单ID不是订单ID订单ID在RefVendorOrderID中
VendorID: model.VendorIDJX,
OrderType: model.OrderTypeAfsOrder,
RefVendorOrderID: msg.ThingID,
RefVendorID: model.VendorIDJX,
VendorStatus: msg.SubMsgType,
Status: int(utils.Str2Int64WithDefault(msg.SubMsgType, 0)),
StatusTime: utils.Timestamp2Time(msg.Timestamp),
Remark: "",
}
return orderStatus
}
func onAfsOrderMsg(msg *CallbackMsg) (err error) {
subMsgType := int(utils.Str2Int64WithDefault(msg.SubMsgType, 0))
status := callbackAfsMsg2Status(msg)
if subMsgType == model.AfsOrderStatusWait4Approve || subMsgType == model.AfsOrderStatusNew {
afsOrder, err2 := buildAfsOrder(msg)
if err = err2; err == nil {
err = partner.CurOrderManager.OnAfsOrderNew(afsOrder, status)
}
} else {
err = partner.CurOrderManager.OnOrderStatusChanged("", status)
}
return err
}
func postFakeAfsMsg(orderNo, afsOrderID string, status int) {
msg := &CallbackMsg{
AppKey: appKey,
MsgType: MsgTypeAfsOrder,
SubMsgType: utils.Int2Str(status),
ThingID: orderNo,
ThingID2: afsOrderID,
Timestamp: time.Now().Unix(),
}
utils.CallFuncAsync(func() {
OnCallbackMsg(msg)
})
}
func NotifyAfsOrderStatusChanged(order *model.AfsOrder, status int) (err error) {
orderMsg := *order
orderMsg.Status = status
if err = jxAPI.NotifyAfsOrderStatusChanged(&orderMsg); err == nil {
postFakeAfsMsg(orderMsg.VendorOrderID, orderMsg.AfsOrderID, orderMsg.Status)
}
return err
}

View File

@@ -1,82 +0,0 @@
package jx
// 这里函数取得的信息除了与自身实体相关的ID比如PARENT ID都已经转换成了本地ID了
import (
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/partner"
)
// func (p *PurchaseHandler) CreateCategory(db *dao.DaoDB, cat *model.SkuCategory, userName string) (err error) {
// return err
// }
func (p *PurchaseHandler) GetAllCategories(ctx *jxcontext.Context, vendorOrgCode string) (cats []*partner.BareCategoryInfo, err error) {
return cats, err
}
// func (p *PurchaseHandler) UpdateCategory(db *dao.DaoDB, cat *model.SkuCategory, userName string) error {
// return nil
// }
// func (p *PurchaseHandler) DeleteCategory(db *dao.DaoDB, cat *model.SkuCategory, userName string) error {
// return nil
// }
// func (p *PurchaseHandler) ReorderCategories(db *dao.DaoDB, parentCatID int, userName string) (err error) {
// return err
// }
func (p *PurchaseHandler) CreateCategory2(ctx *jxcontext.Context, cat *dao.SkuStoreCatInfo) (err error) {
return err
}
func (p *PurchaseHandler) UpdateCategory2(ctx *jxcontext.Context, cat *dao.SkuStoreCatInfo) (err error) {
return err
}
func (p *PurchaseHandler) DeleteCategory2(ctx *jxcontext.Context, vendorOrgCode, vendorCatID string) (err error) {
return err
}
func (p *PurchaseHandler) ReorderCategories2(ctx *jxcontext.Context, vendorOrgCode, vendorParentCatID string, vendorCatIDList []string) (err error) {
return err
}
// func (p *PurchaseHandler) CreateSku(db *dao.DaoDB, sku *model.Sku, userName string) (err error) {
// return err
// }
// func (p *PurchaseHandler) ReadSku(ctx *jxcontext.Context, vendorOrgCode, vendorSkuID string) (skuNameExt *model.SkuNameExt, err error) {
// return skuNameExt, err
// }
// func (p *PurchaseHandler) UpdateSku(db *dao.DaoDB, sku *model.Sku, userName string) (err error) {
// return err
// }
// func (p *PurchaseHandler) DeleteSku(db *dao.DaoDB, sku *model.Sku, userName string) (err error) {
// return err
// }
func (p *PurchaseHandler) CreateSku2(ctx *jxcontext.Context, sku *dao.StoreSkuSyncInfo) (err error) {
return err
}
func (p *PurchaseHandler) UpdateSku2(ctx *jxcontext.Context, sku *dao.StoreSkuSyncInfo) (err error) {
return err
}
func (p *PurchaseHandler) DeleteSku2(ctx *jxcontext.Context, vendorOrgCode string, sku *partner.StoreSkuInfo) (err error) {
return err
}
func (p *PurchaseHandler) GetVendorCategories(ctx *jxcontext.Context) (vendorCats []*model.SkuVendorCategory, err error) {
return vendorCats, err
}
func (p *PurchaseHandler) GetSkus(ctx *jxcontext.Context, vendorOrgCode string, skuID int, vendorSkuID string) (skuNameList []*partner.SkuNameInfo, err error) {
return skuNameList, err
}

View File

@@ -1,44 +0,0 @@
package jx
import (
"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/dao"
)
func (p *PurchaseHandler) ReadStore(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID string) (storeDetail *dao.StoreDetail, err error) {
return storeDetail, err
}
// stoerIDs为nil表示所有
func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName string) (err error) {
return err
}
func (p *PurchaseHandler) RefreshAllStoresID(ctx *jxcontext.Context, parentTask tasksch.ITask, isAsync bool) (hint string, err error) {
return hint, err
}
func (p *PurchaseHandler) GetStoreStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string) (storeStatus int, err error) {
return storeStatus, err
}
func (p *PurchaseHandler) EnableAutoAcceptOrder(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, isSetEnable bool) (err error) {
return err
}
func (c *PurchaseHandler) UpdateStoreStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, status int) (err error) {
return err
}
func (c *PurchaseHandler) UpdateStoreOpTime(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, opTimeList []int16) (err error) {
return err
}
func (c *PurchaseHandler) GetAllStoresVendorID(ctx *jxcontext.Context, vendorOrgCode string) (vendorStoreIDs []string, err error) {
return vendorStoreIDs, err
}
func (c *PurchaseHandler) UpdateStoreCustomID(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID string, storeID int64) (err error) {
return err
}

View File

@@ -1,36 +0,0 @@
package jx
import (
"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/partner"
)
func (p *PurchaseHandler) GetStoreSkusBatchSize(funcID int) (batchSize int) {
batchSize = 1
return batchSize
}
func (p *PurchaseHandler) GetStoreSkusBareInfo(ctx *jxcontext.Context, vendorOrgCode string, parentTask tasksch.ITask, storeID int, vendorStoreID string, inStoreSkuList []*partner.StoreSkuInfo) (outStoreSkuList []*partner.StoreSkuInfo, err error) {
return outStoreSkuList, err
}
func (p *PurchaseHandler) UpdateStoreSkusStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo, status int) (successList []*partner.StoreSkuInfo, err error) {
return successList, err
}
func (p *PurchaseHandler) UpdateStoreSkusPrice(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (successList []*partner.StoreSkuInfo, err error) {
return successList, err
}
func (p *PurchaseHandler) UpdateStoreSkusStock(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (successList []*partner.StoreSkuInfo, err error) {
return successList, err
}
func (p *PurchaseHandler) CreateStoreSkusAct(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
return failedList, err
}
func (p *PurchaseHandler) CancelActs(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
return failedList, err
}

View File

@@ -1,260 +0,0 @@
package mtwm
import (
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"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"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/business/partner/putils"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
func jxActType2Mtwm(actType int) int {
if actType == model.ActSkuDirectDown {
actType = mtwmapi.RetailActTypeDirectDown
} else if actType == model.ActSkuSecKill {
actType = mtwmapi.RetailActTypeSecKill
} else {
actType = 0
}
return actType
}
func actOrderRules2Mtwm(actOrderRules []*model.ActOrderRule) (actDetails []*mtwmapi.FullDiscountActDetail) {
for _, v := range actOrderRules {
actDetails = append(actDetails, &mtwmapi.FullDiscountActDetail{
OriginalPrice: jxutils.IntPrice2Standard(v.SalePrice),
ActPrice: jxutils.IntPrice2Standard(v.DeductPrice),
})
}
return actDetails
}
func storeSku2ActData(act *model.Act2, actStoreSku []*model.ActStoreSku2, handler func(int8) bool) (actData []*mtwmapi.RetailDiscountActData) {
orderLimit := 1
if act.LimitCount > 0 {
orderLimit = act.LimitCount
}
for _, v := range actStoreSku {
if handler == nil || handler(v.SyncStatus) {
dayLimit := -1
if v.Stock > 0 {
dayLimit = v.Stock
}
actData = append(actData, &mtwmapi.RetailDiscountActData{
AppFoodCode: utils.Int2Str(v.SkuID),
// UserType: 0,
StartTime: act.BeginAt.Unix(),
EndTime: act.EndAt.Unix(),
OrderLimit: orderLimit,
DayLimit: dayLimit,
// Period: "",
// WeeksTime: "",
SettingType: mtwmapi.SettingTypeAsPrice,
ActPrice: jxutils.IntPrice2Standard(v.ActualActPrice),
// DiscountCoefficient: 0,
// Sequence: int(v.ActPrice), // 此字段不允许重复
// ItemID: utils.Str2Int64WithDefault(v.VendorActID, 0),
})
}
}
return actData
}
func storeSku2ActData4Delete(actStoreSku []*model.ActStoreSku2, handler func(int8) bool) (actIDList []string) {
for _, v := range actStoreSku {
if handler == nil || handler(v.SyncStatus) {
if v.VendorActID != "" {
actIDList = append(actIDList, v.VendorActID)
}
}
}
return actIDList
}
func isCreateOrUpdate(syncStatus int8) bool {
return model.IsSyncStatusNeedCreate(syncStatus) || model.IsSyncStatusNeedUpdate(syncStatus)
}
func createOneShopAct(act *model.Act2, vendorStoreID string, actStoreSku []*model.ActStoreSku2) (failedList []*partner.StoreSkuInfoWithErr, err error) {
actData := storeSku2ActData(act, actStoreSku, isCreateOrUpdate)
if len(actData) > 0 {
if globals.EnableMtwmStoreWrite {
actResult, faileInfoList, err2 := api.MtwmAPI.RetailDiscountBatchSave2(vendorStoreID, jxActType2Mtwm(act.Type), actData)
err = err2
// 忽略错误都放在failedList里
// if err != nil {
// return nil, err
// }
// globals.SugarLogger.Debugf("mtwm createOneShopAct actResult:%s, faileInfoList:%s err2:%v", utils.Format4Output(actResult, true), utils.Format4Output(faileInfoList, true), err2)
actStoreSkuMap := make(map[int]*model.ActStoreSku2)
for _, v := range actStoreSku {
actStoreSkuMap[v.SkuID] = v
}
for _, v := range actResult {
if v2 := actStoreSkuMap[int(utils.Str2Int64WithDefault(v.AppFoodCode, 0))]; v2 != nil {
v2.VendorActID = utils.Int64ToStr(v.ActID)
}
}
for _, v := range faileInfoList {
if v2 := actStoreSkuMap[int(utils.Str2Int64WithDefault(v.AppFoodCode, 0))]; v2 != nil {
failedList = append(failedList, &partner.StoreSkuInfoWithErr{
StoreSkuInfo: &partner.StoreSkuInfo{
SkuID: v2.SkuID,
},
VendoreID: model.VendorIDMTWM,
StoreID: int(utils.Str2Int64WithDefault(vendorStoreID, 0)),
ErrMsg: v.ErrorMsg,
})
}
}
} else {
for _, v := range actStoreSku {
v.VendorActID = utils.Int64ToStr(jxutils.GenFakeID())
}
}
}
return failedList, err
}
func cancelOneShopAct(act *model.Act2, vendorStoreID string, actStoreSku []*model.ActStoreSku2) (failedList []*partner.StoreSkuInfoWithErr, err error) {
if list := storeSku2ActData4Delete(actStoreSku, nil /*model.IsSyncStatusNeedDelete*/); len(list) > 0 {
if globals.EnableMtwmStoreWrite {
failedList2, err2 := api.MtwmAPI.RetailDiscountDelete2(vendorStoreID, jxActType2Mtwm(act.Type), list)
actStoreSkuMap := make(map[string]*model.ActStoreSku2)
for _, v := range actStoreSku {
actStoreSkuMap[v.VendorActID] = v
}
for _, v := range failedList2 {
if !mtwmapi.CanDeleteActErrMsgIgnore(v.ErrorMsg) {
failedList = append(failedList, &partner.StoreSkuInfoWithErr{
StoreSkuInfo: &partner.StoreSkuInfo{
SkuID: actStoreSkuMap[utils.Int64ToStr(v.ActID)].SkuID,
},
StoreID: int(utils.Str2Int64WithDefault(vendorStoreID, 0)),
ErrMsg: v.ErrorMsg,
VendoreID: model.VendorIDMTWM,
})
}
}
err = err2
err = nil // 强制不返回错误,使用部分错误
}
}
return failedList, err
}
func getActStoreSkuFromTaskResult(taskReslt []interface{}) (list []*model.ActStoreSku2) {
for _, v := range taskReslt {
actStoreSkuList := v.([]*model.ActStoreSku2)
list = append(list, actStoreSkuList...)
}
return list
}
func createSkuAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actStoreSku []*model.ActStoreSku2) (createdList []*model.ActStoreSku2, err error) {
globals.SugarLogger.Debugf("mtwm createSkuAct")
actStoreSkuListList := partner.SplitActStoreSku2List(actStoreSku)
task := tasksch.NewParallelTask("mtwm createSkuAct", nil, ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
list := batchItemList[0].([]*model.ActStoreSku2)
failedList, err2 := createOneShopAct(act, list[0].VendorStoreID, list)
if err = err2; err2 == nil {
if len(failedList) > 0 {
failedMap := putils.StoreSkuInfoWithErrList2MapBySku(failedList)
list = []*model.ActStoreSku2{}
for _, v := range actStoreSku {
if failedMap[v.SkuID] == nil {
list = append(list, v)
}
}
list = []*model.ActStoreSku2{}
}
retVal = []interface{}{list}
}
return retVal, err
}, actStoreSkuListList)
tasksch.HandleTask(task, parentTask, true).Run()
result, err := task.GetResult(0)
return getActStoreSkuFromTaskResult(result), err
}
func cancelSkuAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actStoreSku []*model.ActStoreSku2) (canceledList []*model.ActStoreSku2, err error) {
globals.SugarLogger.Debugf("mtwm cancelSkuAct")
actStoreSkuListList := partner.SplitActStoreSku2List(actStoreSku)
task := tasksch.NewParallelTask("mtwm cancelSkuAct", nil, ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
actStoreSkuList := batchItemList[0].([]*model.ActStoreSku2)
if _, err = cancelOneShopAct(act, actStoreSkuList[0].VendorStoreID, actStoreSkuList); err == nil {
retVal = []interface{}{actStoreSkuList}
}
return retVal, err
}, actStoreSkuListList)
tasksch.HandleTask(task, parentTask, true).Run()
result, err := task.GetResult(0)
return getActStoreSkuFromTaskResult(result), err
}
func (c *PurchaseHandler) SyncAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actOrderRules []*model.ActOrderRule, actStoreSkuList []*model.ActStoreSku2) (err error) {
globals.SugarLogger.Debugf("mtwm SyncAct, actID:%d", act.ID)
var actStoreSkuList4Create, actStoreSkuList4Delete []*model.ActStoreSku2
var updateItems []*dao.KVUpdateItem
actStoreSkuMap := partner.SplitActStoreSku(actStoreSkuList)
for storeID := range actStoreSkuMap {
for _, actStoreSku := range actStoreSkuMap[storeID] {
if model.IsSyncStatusDelete(actStoreSku.SyncStatus) {
actStoreSkuList4Delete = append(actStoreSkuList4Delete, actStoreSku)
} else if model.IsSyncStatusNew(actStoreSku.SyncStatus) {
actStoreSkuList4Create = append(actStoreSkuList4Create, actStoreSku)
}
}
}
err = func() (err error) {
if model.IsSyncStatusDelete(act.SyncStatus) {
canceledList, err2 := cancelSkuAct(ctx, nil, act, actStoreSkuList)
updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, canceledList, model.SyncFlagModifiedMask)...)
if err = err2; err == nil {
updateItems = append(updateItems, partner.Act2Update(ctx, act, model.SyncFlagModifiedMask))
}
} else if model.IsSyncStatusNew(act.SyncStatus) {
createdList, err2 := createSkuAct(ctx, nil, act, actStoreSkuList4Create)
updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, createdList, model.SyncFlagNewMask)...)
if err = err2; err == nil {
updateItems = append(updateItems, partner.Act2Update(ctx, act, model.SyncFlagNewMask))
}
} else if model.IsSyncStatusUpdate(act.SyncStatus) {
// globals.SugarLogger.Debug(utils.Format4Output(updateItems, false))
if len(actStoreSkuList4Create) > 0 {
addedList, err2 := createSkuAct(ctx, nil, act, actStoreSkuList4Create)
updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, addedList, model.SyncFlagNewMask)...)
if err = err2; err != nil {
return err
}
}
if len(actStoreSkuList4Delete) > 0 {
deletedList, err2 := cancelSkuAct(ctx, nil, act, actStoreSkuList4Delete)
updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, deletedList, model.SyncFlagDeletedMask)...)
if err = err2; err != nil {
return err
}
}
if err == nil {
updateItems = append(updateItems, partner.Act2Update(ctx, act, model.SyncFlagModifiedMask))
}
}
return err
}()
db := dao.GetDB()
_, err2 := dao.BatchUpdateActEntity(db, model.IsSyncStatusDelete(act.SyncStatus), updateItems)
if err == nil {
err = err2
}
return err
}

View File

@@ -1,38 +0,0 @@
package mtwm
import (
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/model"
)
func OnCallbackMsg(msg *mtwmapi.CallbackMsg) (response *mtwmapi.CallbackResponse) {
if CurPurchaseHandler != nil {
if msg.Cmd == mtwmapi.MsgTypeStoreStatusChanged {
response = CurPurchaseHandler.onStoreStatusChanged(msg)
} else if msg.Cmd == mtwmapi.MsgTypePrivateNumberDowngrade {
response = CurPurchaseHandler.onNumberDowngrade(msg)
} else {
if orderID := GetOrderIDFromMsg(msg); orderID != "" {
jxutils.CallMsgHandler(func() {
switch msg.Cmd {
case mtwmapi.MsgTypeWaybillStatus:
response = CurPurchaseHandler.onWaybillMsg(msg)
default:
response = CurPurchaseHandler.onOrderMsg(msg)
}
}, jxutils.ComposeUniversalOrderID(orderID, model.VendorIDMTWM))
}
/*if msg.Cmd == mtwmapi.MsgTypeOrderRefund || msg.Cmd == mtwmapi.MsgTypeOrderPartialRefund {
utils.CallFuncAsync(func() {
OnFinancialMsg(msg)
})
} */
}
}
return response
}
func GetOrderIDFromMsg(msg *mtwmapi.CallbackMsg) string {
return msg.FormData.Get(mtwmapi.KeyOrderID)
}

View File

@@ -1,252 +0,0 @@
package mtwm
import (
"net/url"
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
)
const (
PublicWelfareDonation = 1 // 美团公益捐款金额现阶段是每单一分钱
)
// 存储美团退款订单结账信息
func OnFinancialMsg(msg *mtwmapi.CallbackMsg) (err error) {
if msg.Cmd == mtwmapi.MsgTypeOrderPartialRefund { // 部分退款处理
orderData := msg.FormData
if orderData.Get("notify_type") == mtwmapi.NotifyTypeSuccess {
err = partner.CurOrderManager.SaveAfsOrderFinancialInfo(CurPurchaseHandler.AfsOrderDetail2Financial(orderData))
}
}
if msg.Cmd == mtwmapi.MsgTypeOrderRefund { // todo 全额退款处理
orderData := msg.FormData
if orderData.Get("notify_type") == mtwmapi.NotifyTypeSuccess {
globals.SugarLogger.Debug(orderData.Get("order_id")) // 获得退款订单ID去本地数据库拿饿百消息推送只给了订单号也没有通过订单号查询退款信息的接口
afsOrderID := orderData.Get("order_id")
orderFinancial, err := partner.CurOrderManager.LoadOrderFinancial(afsOrderID, model.VendorIDMTWM)
if err == nil {
globals.SugarLogger.Debug(utils.Format4Output(orderFinancial, false))
err = partner.CurOrderManager.SaveAfsOrderFinancialInfo(CurPurchaseHandler.OrderFinancialDetail2Refund(orderFinancial, orderData))
} else {
globals.SugarLogger.Warnf("mtwm OnFinancialMsg, afsOrderID:%s is not found from partner.CurOrderManager.LoadOrderFinancial", afsOrderID)
}
}
}
return err
}
func (p *PurchaseHandler) OrderFinancialDetail2Refund(orderFinancial *model.OrderFinancial, orderData url.Values) (afsOrder *model.AfsOrder) {
afsOrder = &model.AfsOrder{
VendorID: model.VendorIDMTWM,
AfsOrderID: orderData.Get("refund_id"),
VendorOrderID: orderData.Get("order_id"),
AfsCreatedAt: utils.Timestamp2Time(utils.Str2Int64(orderData.Get("timestamp"))),
// BoxMoney: orderFinancial.BoxMoney,
// SkuBoxMoney: orderFinancial.SkuBoxMoney, // 美团的餐盒费已经拆到单条SKU里面去了,退款时直接计算用户支付sku金额就好了
FreightUserMoney: orderFinancial.FreightMoney,
SkuUserMoney: orderFinancial.ActualPayMoney - orderFinancial.FreightMoney,
PmSubsidyMoney: orderFinancial.PmSubsidyMoney,
}
order, err := partner.CurOrderManager.LoadOrder(afsOrder.VendorOrderID, afsOrder.VendorID)
globals.SugarLogger.Debug(utils.Format4Output(order, false))
if err == nil {
afsOrder.JxStoreID = order.JxStoreID
afsOrder.VendorStoreID = order.VendorStoreID
afsOrder.StoreID = order.StoreID
} else {
globals.SugarLogger.Warnf("mtwm AfsOrderDetail2Financial, afsOrderID:%s is not found from partner.CurOrderManager.LoadOrder", afsOrder.VendorOrderID)
err = nil
}
for _, sku := range orderFinancial.Skus {
orderSkuFinancial := &model.OrderSkuFinancial{
VendorID: sku.VendorID,
VendorOrderID: sku.VendorOrderID,
// OrderFinancialID: sku.VendorOrderID,
// ConfirmTime: afsOrder.AfsCreateAt,
VendorStoreID: afsOrder.VendorStoreID,
StoreID: afsOrder.StoreID,
JxStoreID: afsOrder.JxStoreID,
VendorSkuID: sku.VendorSkuID,
SkuID: sku.SkuID,
PromotionType: sku.PromotionType,
Name: sku.Name,
ShopPrice: sku.ShopPrice,
SalePrice: sku.SalePrice,
Count: sku.Count,
UserMoney: sku.UserMoney,
PmSubsidyMoney: sku.PmSubsidyMoney,
IsAfsOrder: 1,
}
afsOrder.Skus = append(afsOrder.Skus, orderSkuFinancial)
}
return afsOrder
}
func (p *PurchaseHandler) AfsOrderDetail2Financial(orderData url.Values) (afsOrder *model.AfsOrder) {
afsOrder = &model.AfsOrder{
VendorID: model.VendorIDMTWM,
AfsOrderID: orderData.Get("order_id"),
VendorOrderID: orderData.Get("order_id"),
AfsCreatedAt: utils.Timestamp2Time(utils.Str2Int64(orderData.Get("timestamp"))),
RefundMoney: jxutils.StandardPrice2Int(utils.Str2Float64(orderData.Get("money"))),
}
// if orderData.Get("timestamp") != "" {
// afsOrder.AfsCreateAt = utils.Timestamp2Time(utils.Str2Int64(orderData.Get("timestamp")))
// } else {
// globals.SugarLogger.Warnf("ebai OrderFinancialDetail2Refund timestamp is not found in afsOrder:%s", afsOrder.AfsOrderID)
// afsOrder.AfsCreateAt = time.Now()
// }
order, err := partner.CurOrderManager.LoadOrder(afsOrder.VendorOrderID, afsOrder.VendorID)
if err == nil {
afsOrder.JxStoreID = order.JxStoreID
} else {
globals.SugarLogger.Warnf("mtwm AfsOrderDetail2Financial, afsOrderID:%s is not found from partner.CurOrderManager.LoadOrder", afsOrder.VendorOrderID)
err = nil
}
food := orderData.Get("food")
var refundDetail []map[string]interface{}
utils.UnmarshalUseNumber([]byte(food), &refundDetail)
for _, xMap := range refundDetail {
orderSkuFinancial := &model.OrderSkuFinancial{
VendorID: model.VendorIDMTWM,
AfsOrderID: afsOrder.AfsOrderID,
VendorOrderID: afsOrder.VendorOrderID,
// ConfirmTime: afsOrder.AfsCreateAt,
VendorSkuID: utils.Interface2String(xMap["app_food_code"]),
SkuID: int(utils.Str2Int64WithDefault(utils.Interface2String(xMap["sku_id"]), 0)),
Name: utils.Interface2String(xMap["food_name"]),
UserMoney: jxutils.StandardPrice2Int(utils.MustInterface2Float64(xMap["refund_price"]))*utils.MustInterface2Int64(xMap["count"]) + jxutils.StandardPrice2Int(utils.MustInterface2Float64(xMap["box_price"]))*int64(utils.MustInterface2Float64(xMap["box_num"])),
IsAfsOrder: 1,
}
afsOrder.Skus = append(afsOrder.Skus, orderSkuFinancial)
afsOrder.SkuUserMoney += orderSkuFinancial.UserMoney
// afsOrder.PmSubsidyMoney += orderSkuFinancial.PmSubsidyMoney // 美团只给了一个扣款金额,很尴尬、、
}
afsOrder.PmSubsidyMoney += afsOrder.RefundMoney - afsOrder.SkuUserMoney
if len(refundDetail) <= 0 {
globals.SugarLogger.Warnf("mtwm AfsOrderDetail2Financial, orderID:%s have no refund_detail", afsOrder.VendorOrderID)
}
return afsOrder
}
// 存储美团正向订单结账信息
func (p *PurchaseHandler) OnOrderDetail(result map[string]interface{}, operation string) (err error) {
globals.SugarLogger.Debug(utils.Int64ToStr(utils.MustInterface2Int64(result["order_id"])))
err = partner.CurOrderManager.SaveOrderFinancialInfo(p.OrderDetail2Financial(result), operation)
return err
}
func (p *PurchaseHandler) OrderDetail2Financial(result map[string]interface{}) (orderFinancial *model.OrderFinancial) {
orderFinancial = &model.OrderFinancial{
VendorID: model.VendorIDMTWM,
VendorOrderID: utils.Int64ToStr(utils.MustInterface2Int64(result["order_id"])),
}
// orderFinancial.DeliveryConfirmTime = utils.Str2TimeWithDefault(utils.Interface2String(result["order_completed_time"]), utils.DefaultTimeValue)
order, err := partner.CurOrderManager.LoadOrder(orderFinancial.VendorOrderID, orderFinancial.VendorID)
jxStoreID := 0
if err == nil {
jxStoreID = order.JxStoreID
if order.Skus != nil {
for _, x := range order.Skus {
orderFinancial.ShopPriceMoney += x.ShopPrice * int64(x.Count)
}
}
} else {
globals.SugarLogger.Warnf("mtwm OrderDetail2Financial, orderID:%s is not found from partner.CurOrderManager.LoadOrder", orderFinancial.VendorOrderID)
err = nil
}
if result["package_bag_money"] != nil {
orderFinancial.BoxMoney = utils.MustInterface2Int64(result["package_bag_money"])
}
detail := result["detail"]
if detail != nil {
var data []map[string]interface{}
utils.UnmarshalUseNumber([]byte(utils.Interface2String(detail)), &data)
for _, x := range data {
orderSkuFinancial := &model.OrderSkuFinancial{
VendorID: orderFinancial.VendorID,
VendorOrderID: orderFinancial.VendorOrderID,
// OrderFinancialID: orderFinancial.VendorOrderID,
// ConfirmTime: utils.Str2TimeWithDefault(utils.Interface2String(result["ctime"]), utils.DefaultTimeValue),
VendorStoreID: result["app_poi_code"].(string),
StoreID: 0,
JxStoreID: jxStoreID,
VendorSkuID: utils.Interface2String(x["sku_id"]),
SkuID: int(utils.Str2Int64WithDefault(utils.Interface2String(x["sku_id"]), 0)),
Name: utils.Interface2String(x["food_name"]),
SalePrice: jxutils.StandardPrice2Int(utils.MustInterface2Float64(x["price"])),
Count: int(utils.MustInterface2Int64(x["quantity"])),
SkuBoxMoney: jxutils.StandardPrice2Int(utils.MustInterface2Float64(x["box_price"])) * jxutils.StandardPrice2Int(utils.MustInterface2Float64(x["box_num"])),
IsAfsOrder: 0,
}
orderFinancial.Skus = append(orderFinancial.Skus, orderSkuFinancial)
orderFinancial.SalePriceMoney += orderSkuFinancial.SalePrice * int64(orderSkuFinancial.Count)
orderFinancial.SkuBoxMoney += orderSkuFinancial.SkuBoxMoney
}
} else {
globals.SugarLogger.Warnf("mtwm OrderDetail2Financial, orderID:%s have no detail", orderFinancial.VendorOrderID)
}
extras := result["extras"]
if extras != nil {
var data []map[string]interface{}
utils.UnmarshalUseNumber([]byte(utils.Interface2String(extras)), &data)
for _, x := range data {
if x["rider_fee"] == nil {
activity := &model.OrderDiscountFinancial{
VendorID: orderFinancial.VendorID,
VendorOrderID: orderFinancial.VendorOrderID,
// ActivityName: utils.Interface2String(x["remark"]),
// ActivityMoney: jxutils.StandardPrice2Int(utils.MustInterface2Float64(x["reduce_fee"])),
// VendorActivityID: utils.Int64ToStr(utils.MustInterface2Int64(x["act_detail_id"])),
}
if x["act_detail_id"] != nil { // 容错处理
activity.VendorActivityID = utils.Int64ToStr(utils.MustInterface2Int64(x["act_detail_id"]))
orderFinancial.Discounts = append(orderFinancial.Discounts, activity)
}
// 通过活动Id去取京西活动补贴
// orderFinancial.JxSubsidyMoney +=
}
}
}
poiReceiveDetail := result["poi_receive_detail"]
if poiReceiveDetail != nil {
var data map[string]interface{}
utils.UnmarshalUseNumber([]byte(utils.Interface2String(poiReceiveDetail)), &data)
orderFinancial.ReceivableFreight = utils.MustInterface2Int64(data["logisticsFee"])
orderFinancial.FreightMoney = utils.MustInterface2Int64(data["logisticsFee"])
orderFinancial.ActualPayMoney = utils.MustInterface2Int64(data["onlinePayment"])
orderFinancial.PmMoney = utils.MustInterface2Int64(data["foodShareFeeChargeByPoi"])
orderFinancial.ShopMoney = utils.MustInterface2Int64(data["wmPoiReceiveCent"])
for _, x := range data["actOrderChargeByMt"].([]interface{}) {
orderFinancial.TotalDiscountMoney += utils.MustInterface2Int64(x.(map[string]interface{})["moneyCent"])
orderFinancial.PmSubsidyMoney += utils.MustInterface2Int64(x.(map[string]interface{})["moneyCent"])
}
for _, x := range data["actOrderChargeByPoi"].([]interface{}) {
orderFinancial.TotalDiscountMoney += utils.MustInterface2Int64(x.(map[string]interface{})["moneyCent"])
}
} else {
globals.SugarLogger.Warnf("mtwm OrderDetail2Financial, orderID:%s have no poi_receive_detail", orderFinancial.VendorOrderID)
}
if utils.MustInterface2Int64(result["is_third_shipping"]) == SelfDeliveryCarrierNo { // is_third_shipping int 是否是第三方配送平台配送,0表否1表是
orderFinancial.SelfDeliveryDiscountMoney = orderFinancial.ReceivableFreight
orderFinancial.DistanceFreightMoney = 0
// 通过本地数据库去取是否转美团/达达,并计算运费
// wayBill, err := partner.CurOrderManager.LoadWaybill(orderFinancial.VendorOrderID, orderFinancial.VendorID)
// if err == nil {
// orderFinancial.JxFreightMoney = wayBill.DesiredFee
// }
}
// // 美团订单单独处理部分,美团正向订单接口推送时总结算金额没有计算公益捐款一分钱,是否在这里直接提前扣除?
// // 3/18之后的订单一直都不显示公益捐款金额而且结算现在结算到了3/18之后的订单没有的已经不计算了先注释
// // 2019-04-03 10.52 询问赵mf, 此计划是必须参加的,而且是长期的,每单固定扣除一分钱
orderFinancial.DonationMoney = PublicWelfareDonation
// 不应该对第三方结账金额做更改,就算有异常,也要保留异常,知道问题出在哪里
// orderFinancial.ShopMoney -= PublicWelfareDonation
globals.SugarLogger.Debug(orderFinancial.VendorOrderID)
return orderFinancial
}

View File

@@ -1,54 +0,0 @@
package mtwm
import (
"fmt"
"net/url"
"testing"
"time"
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/partner"
)
func TestOnFinancialMsg(t *testing.T) {
msg := &mtwmapi.CallbackMsg{
Cmd: "orderRefund",
FormData: url.Values{},
}
msg.FormData.Set("timestamp", utils.Int64ToStr(time.Now().Unix()))
msg.FormData.Set("order_id", "33762863167364867")
msg.FormData.Set("notify_type", "agree")
msg.FormData.Set("money", "23.56")
food := []map[string]interface{}{
map[string]interface{}{
"app_food_code": "123",
"food_name": "商品1",
"sku_id": "123",
"refund_price": 3.14,
"count": 2,
"box_num": 1,
"box_price": 1,
},
map[string]interface{}{
"app_food_code": "124",
"food_name": "商品2",
"sku_id": "124",
"refund_price": 3.15,
"count": 2,
"box_num": 1,
"box_price": 1,
},
}
msg.FormData.Set("food", string(utils.MustMarshal(food)))
res := CurPurchaseHandler.onAfsOrderMsg(msg)
fmt.Println(res)
}
func TestOnOrderDetail(t *testing.T) {
result := map[string]interface{}{
"app_order_code": "", "app_poi_code": "2828472", "avg_send_time": 2410, "backup_recipient_phone": "[\"13164714130_7645\"]", "caution": " 【如遇缺货】: 缺货时电话与我沟通 收餐人隐私号 13049813276_5307手机号 139****5027", "city_id": 440300, "ctime": 1555036346, "day_seq": 1, "delivery_time": 0, "detail": "[{\"app_food_code\":\"27262\",\"box_num\":0,\"box_price\":0,\"cart_id\":0,\"food_discount\":1,\"food_name\":\"红管鱿鱼约250g/份\",\"food_property\":\"\",\"price\":23.54,\"quantity\":1,\"sku_id\":\"27262\",\"spec\":\"250g\",\"unit\":\"份\"},{\"app_food_code\":\"24987\",\"box_num\":0,\"box_price\":0,\"cart_id\":0,\"food_discount\":1,\"food_name\":\"带皮猪梅花肉约250g/份\",\"food_property\":\"\",\"price\":15.84,\"quantity\":1,\"sku_id\":\"24987\",\"spec\":\"250g\",\"unit\":\"份\"},{\"app_food_code\":\"27179\",\"box_num\":0,\"box_price\":0,\"cart_id\":0,\"food_discount\":1,\"food_name\":\"[畅销]龙骨约250g/份\",\"food_property\":\"\",\"price\":18.59,\"quantity\":1,\"sku_id\":\"27179\",\"spec\":\"250g\",\"unit\":\"份\"}]", "dinners_number": 0, "expect_deliver_time": 0, "extras": "[{\"act_detail_id\":664795195,\"mt_charge\":0,\"poi_charge\":5,\"reduce_fee\":5,\"remark\":\"满46.0元减5.0元\",\"type\":2},{\"act_detail_id\":665051798,\"mt_charge\":0,\"poi_charge\":4,\"reduce_fee\":4,\"remark\":\"减配送费4.0元\",\"type\":25},{\"act_detail_id\":274839715,\"mt_charge\":0.5,\"poi_charge\":0,\"reduce_fee\":0.5,\"remark\":\"用户使用了支付红包减0.5元\",\"type\":9},{\"mt_charge\":0,\"poi_charge\":0,\"reduce_fee\":0,\"remark\":\"送30元商家代金券\",\"type\":100},{}]", "has_invoiced": 0, "invoice_title": "", "is_favorites": false, "is_poi_first_order": true, "is_pre": 0, "is_third_shipping": 0, "latitude": 22.530194, "logistics_code": "1001", "longitude": 114.08372, "order_id": 28284722536001020, "order_send_time": 1555036356, "original_price": 63.97, "package_bag_money": 0, "pay_type": 2, "pick_type": 0, "poi_receive_detail": "{\"actOrderChargeByMt\":[{\"comment\":\"活动款\",\"feeTypeDesc\":\"活动款\",\"feeTypeId\":10019,\"moneyCent\":50}],\"actOrderChargeByPoi\":[{\"comment\":\"满46.0元减5.0元\",\"feeTypeDesc\":\"活动款\",\"feeTypeId\":10019,\"moneyCent\":500},{\"comment\":\"减配送费4.0元\",\"feeTypeDesc\":\"活动款\",\"feeTypeId\":10019,\"moneyCent\":400}],\"foodShareFeeChargeByPoi\":490,\"logisticsFee\":600,\"onlinePayment\":5447,\"wmPoiReceiveCent\":4406}", "recipient_address": "汇港名苑 (南2区1005)@#广东省深圳市福田区滨河大道滨河大道3119号汇港名苑", "recipient_name": "颜(女士)", "recipient_phone": "13049813276_5307", "remark": "", "result": "ok", "shipper_phone": "", "shipping_fee": 6, "shipping_type": 0, "source_id": 3, "status": 2, "taxpayer_id": "", "total": 54.47, "utime": 1555036346, "wm_order_id_view": 28284722536001020, "wm_poi_address": "深圳市福田区南园街道南华社区滨河路2037号下小庙南区70栋101号滨河街市场", "wm_poi_id": 2828472, "wm_poi_name": "京西菜市(华强南店)", "wm_poi_phone": "13724313878",
}
err := new(PurchaseHandler).OnOrderDetail(result, partner.CreatedPeration)
fmt.Println(err)
}

View File

@@ -1,225 +0,0 @@
package mtwm
import (
"fmt"
"strings"
"sync"
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/business/partner/putils"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
var (
CurPurchaseHandler *PurchaseHandler
)
type PurchaseHandler struct {
partner.BasePurchasePlatform
putils.DefSingleStorePlatform
storeIDs []string
locker sync.RWMutex
}
func init() {
if api.MtwmAPI != nil {
CurPurchaseHandler = New()
partner.RegisterPurchasePlatform(CurPurchaseHandler)
}
}
func New() (obj *PurchaseHandler) {
obj = new(PurchaseHandler)
obj.ISingleStoreStoreSkuHandler = obj
return obj
}
func (c *PurchaseHandler) GetVendorID() int {
return model.VendorIDMTWM
}
func (p *PurchaseHandler) GetVendorCategories(ctx *jxcontext.Context) (vendorCats []*model.SkuVendorCategory, err error) {
cats, err := api.MtwmAPI.RetailGetSpTagIds()
if err != nil {
return nil, err
}
vendorCatMapList := make([]map[string]*model.SkuVendorCategory, 3)
manID := 10000
for i := 0; i < 3; i++ {
vendorCatMapList[i] = make(map[string]*model.SkuVendorCategory)
for _, v := range cats {
if v.Level == 3 {
namePathList := strings.Split(strings.Trim(v.NamePath, ","), ",")
if len(namePathList) != 3 {
panic(fmt.Sprintf("%s没有三级结构", v.NamePath))
}
name := namePathList[i]
if _, ok := vendorCatMapList[i][name]; !ok {
cat := &model.SkuVendorCategory{
VendorID: model.VendorIDMTWM,
Name: name, //utils.Interface2String(v["name"]),
Level: i + 1, //int(utils.MustInterface2Int64(v["level"])),
}
vendorCats = append(vendorCats, cat)
vendorCatMapList[i][name] = cat
if i == 2 {
cat.IsLeaf = 1
cat.VendorCategoryID = utils.Int64ToStr(v.ID)
} else {
cat.VendorCategoryID = utils.Int2Str(manID) // 非叶子结点编码没有实际使用
manID++
}
if i > 0 {
cat.ParentID = vendorCatMapList[i-1][namePathList[i-1]].VendorCategoryID
}
}
}
}
}
return vendorCats, nil
}
func rangeMtwm2JX(areaStr string) string {
var area []interface{}
if err := utils.UnmarshalUseNumber([]byte(areaStr), &area); err == nil {
if len(area) > 0 {
coordList := make([]string, len(area))
for k, v := range area {
vv := v.(map[string]interface{})
coordList[k] = fmt.Sprintf("%.6f,%.6f", jxutils.IntCoordinate2Standard(int(utils.ForceInterface2Int64(vv["x"]))), jxutils.IntCoordinate2Standard(int(utils.ForceInterface2Int64(vv["y"]))))
}
return strings.Join(coordList, ";")
}
}
return ""
}
func rangeJX2Mtwm(coords string) string {
pairs := strings.Split(strings.Trim(coords, ";"), ";")
if len(pairs) > 0 {
coordList := make([]map[string]interface{}, len(pairs))
for k, v := range pairs {
pair := strings.Split(v, ",")
coordList[k] = map[string]interface{}{
"x": jxutils.StandardCoordinate2Int(utils.Str2Float64(pair[0])),
"y": jxutils.StandardCoordinate2Int(utils.Str2Float64(pair[1])),
}
}
return string(utils.MustMarshal(coordList))
}
return ""
}
func openTimeMtwm2JX(vendorOpenTime string) (opTimeList []int16) {
timePairs := strings.Split(vendorOpenTime, ",")
for _, v := range timePairs {
times := strings.Split(v, "-")
if len(times) >= 2 {
opTimeList = append(opTimeList, jxutils.StrTime2JxOperationTime(times[0]+":00", 700), jxutils.StrTime2JxOperationTime(times[1]+":00", 2000))
}
}
return opTimeList
}
func openTimeJX2Mtwm(opTimeList []int16) string {
timesLen := len(opTimeList) / 2 * 2
var strPairs []string
for i := 0; i < timesLen; i += 2 {
if opTimeList[i] != 0 {
strPairs = append(strPairs, jxutils.JxOperationTime2StrTime(opTimeList[i])+"-"+jxutils.JxOperationTime2StrTime(opTimeList[i+1]))
} else {
break
}
}
return strings.Join(strPairs, ",")
}
func bizStatusMtwm2JX(openLevel, online int) int {
if online != mtwmapi.PoiStatusOnline {
return model.StoreStatusDisabled
} else {
if openLevel == mtwmapi.PoiOpenLevelHaveRest {
return model.StoreStatusClosed
}
}
return model.StoreStatusOpened
}
func bizStatusJX2Mtwm(status int) (openLevel, online int) {
if status == model.StoreStatusDisabled {
return mtwmapi.PoiOpenLevelHaveRest, mtwmapi.PoiStatusOnline //mtwmapi.PoiStatusOffline
} else if status == model.StoreStatusHaveRest || status == model.StoreStatusClosed {
return mtwmapi.PoiOpenLevelHaveRest, mtwmapi.PoiStatusOnline
}
return mtwmapi.PoiOpenLevelNormal, mtwmapi.PoiStatusOnline
}
func skuStatusJX2Mtwm(status int) int {
if status == model.SkuStatusNormal {
return mtwmapi.SellStatusOnline
}
return mtwmapi.SellStatusOffline
}
func (p *PurchaseHandler) UploadImg(ctx *jxcontext.Context, vendorOrgCode, imgURL string, imgData []byte, imgName string, imgType int) (imgHint string, err error) {
globals.SugarLogger.Debugf("mtwm UploadImg imgURL:%s, imgName:%s", imgURL, imgName)
poiCode4UploadImg := p.getUploadImgPoiCode()
if poiCode4UploadImg == "" {
return "", fmt.Errorf("找不到一个美团门店来上传图片")
}
if globals.EnableMtwmStoreWrite {
if imgType > model.ImgTypeLocal {
if imgData != nil {
imgHint, err = api.MtwmAPI.ImageUpload(poiCode4UploadImg, imgName, imgData)
} else {
imgHint, err = api.MtwmAPI.ImageUploadByURL(poiCode4UploadImg, imgName, imgURL)
}
}
} else {
imgHint = utils.GetUpperUUID()
}
return imgHint, err
}
func getStoreIDFromList(storeIDs []string) (poiCode string) {
if len(storeIDs) > 0 {
poiCode = storeIDs[0]
}
return poiCode
}
func (p *PurchaseHandler) getUploadImgPoiCode() (poiCode string) {
var storeIDs []string
p.locker.RLock()
storeIDs = p.storeIDs
p.locker.RUnlock()
if len(storeIDs) > 0 {
return getStoreIDFromList(storeIDs)
}
p.locker.Lock()
storeIDs = p.storeIDs
if len(storeIDs) > 0 {
p.locker.Unlock()
return getStoreIDFromList(storeIDs)
}
defer p.locker.Unlock()
storeIDs, err := api.MtwmAPI.PoiGetIDs()
if err == nil {
if len(storeIDs) > 0 {
p.storeIDs = storeIDs
poiCode = getStoreIDFromList(storeIDs)
} else {
// p.storeIDs = []string{""}
}
}
return poiCode
}

View File

@@ -1,28 +0,0 @@
package mtwm
import (
"testing"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/baseapi/utils"
_ "git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
"git.rosy.net.cn/jx-callback/globals/testinit"
)
const (
testShopVendorID = "2523687"
testShopID = 2
)
func init() {
testinit.Init()
}
func TestGetVendorCategories(t *testing.T) {
result, err := new(PurchaseHandler).GetVendorCategories(jxcontext.AdminCtx)
if err != nil {
t.Fatal(err)
}
t.Log(utils.Format4Output(result, false))
}

View File

@@ -1,797 +0,0 @@
package mtwm
import (
"errors"
"fmt"
"math"
"net/url"
"regexp"
"strings"
"time"
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"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"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
const (
FakeMsgType = "fakeMsgType"
fakeFinishedPickup = "fake_finished_pickup"
fakeUserApplyCancel = "fake_user_apply_cancel"
fakeMerchantAgreeApplyCancel = "fake_merchant_agree_apply_cancel"
fakeRefuseUserApplyCancel = "fake_refuse_user_apply_cancel"
fakeUserUndoApplyCancel = "fake_user_undo_apply_cancel"
fakeOrderAdjustFinished = "fake_order_adjust_finished"
keyVendorOrgCode = "vendorOrgCode"
)
const (
SelfDeliveryCarrierNo = 1 // 美团配送方式0-美团专送1-商家自送
)
const (
// pickupOrderDelay = 260 * time.Second
// pickupOrderDelay = 1 * time.Second
// callDeliveryDelay = 10 * time.Minute
// callDeliveryDelayGap = 30
)
var (
specPat = regexp.MustCompile(`(\d+)(.+)`)
)
var (
VendorStatus2StatusMap = map[string]int{
mtwmapi.OrderStatusUserCommitted: model.OrderStatusUnknown,
mtwmapi.OrderStatusNew: model.OrderStatusNew,
// mtwmapi.OrderStatusReceived: model.OrderStatusAccepted,
// mtwmapi.OrderStatusAccepted: model.OrderStatusFinishedPickup,
mtwmapi.OrderStatusAccepted: model.OrderStatusAccepted,
mtwmapi.OrderStatusDelivering: model.OrderStatusDelivering,
mtwmapi.OrderStatusDelivered: model.OrderStatusUnknown, // 以mtwmapi.OrderStatusFinished为结束状态这个当成一个中间状态且很少看到这个状态
mtwmapi.OrderStatusFinished: model.OrderStatusFinished,
mtwmapi.OrderStatusCanceled: model.OrderStatusCanceled,
fakeFinishedPickup: model.OrderStatusFinishedPickup,
fakeOrderAdjustFinished: model.OrderStatusAdjust,
fakeRefuseUserApplyCancel: model.OrderStatusVendorRejectCancel,
fakeUserApplyCancel: model.OrderStatusApplyCancel,
fakeUserUndoApplyCancel: model.OrderStatusUndoApplyCancel,
fakeMerchantAgreeApplyCancel: model.OrderStatusCanceled,
}
skuActTypeMap = map[int]int{
mtwmapi.ExtrasPromotionTypeTeJiaCai: 1,
mtwmapi.ExtrasPromotionTypeZheKouCai: 1,
mtwmapi.ExtrasPromotionTypeSecondHalfPrice: 1,
}
)
func (p *PurchaseHandler) getStatusFromVendorStatus(vendorStatus string) int {
if status, ok := VendorStatus2StatusMap[vendorStatus]; ok {
return status
}
return model.OrderStatusUnknown
}
func (p *PurchaseHandler) getOrder(vendorOrgCode, vendorOrderID string) (order *model.GoodsOrder, orderMap map[string]interface{}, err error) {
result, err := api.MtwmAPI.OrderGetOrderDetail(utils.Str2Int64(vendorOrderID), true)
if err == nil {
result[keyVendorOrgCode] = vendorOrgCode
order = p.Map2Order(result)
}
return order, result, err
}
func (p *PurchaseHandler) GetOrder(vendorOrgCode, vendorOrderID string) (order *model.GoodsOrder, err error) {
order, _, err = p.getOrder(vendorOrgCode, vendorOrderID)
return order, err
}
func (p *PurchaseHandler) GetOrderStatus(vendorOrgCode, vendorOrderID string) (status int, err error) {
status, err = api.MtwmAPI.OrderViewStatus(utils.Str2Int64(vendorOrderID))
if err == nil {
status = p.getStatusFromVendorStatus(utils.Int2Str(status))
}
return status, err
}
func (p *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *model.GoodsOrder) {
result := orderData
vendorOrderID := utils.Int64ToStr(utils.MustInterface2Int64(result["order_id"]))
// 因为美团外卖不能自动设置商家门店号,且只能通过商家门店号来访问门店,
// 为了在后台设置简单一致把app_poi_code直接当成平台门店号使用(即在后台设置时,平台门店号与商家门店号一样)
// 订单中wm_poi_id实际来平台门店号app_poi_code为商家门店号这样一来这两个就相同了
order = &model.GoodsOrder{
VendorOrderID: vendorOrderID,
// VendorOrderID2: utils.Int64ToStr(utils.MustInterface2Int64(result["wm_order_id_view"])),
VendorID: model.VendorIDMTWM,
VendorStoreID: result["app_poi_code"].(string),
StoreID: 0,
// VendorStoreID: utils.Int64ToStr(utils.MustInterface2Int64(result["wm_poi_id"])),
// StoreID: int(utils.Str2Int64WithDefault(utils.Interface2String(result["app_poi_code"]), 0)),
StoreName: result["wm_poi_name"].(string),
ConsigneeName: result["recipient_name"].(string),
ConsigneeMobile: jxutils.FormalizeMobile(result["recipient_phone"].(string)),
ConsigneeAddress: result["recipient_address"].(string),
CoordinateType: model.CoordinateTypeMars,
BuyerComment: utils.TrimBlankChar(utils.Interface2String(result["caution"])),
ExpectedDeliveredTime: getTimeFromTimestamp(utils.Interface2Int64WithDefault(result["delivery_time"], 0)),
PickDeadline: utils.DefaultTimeValue,
VendorStatus: utils.Int64ToStr(utils.MustInterface2Int64(result["status"])),
OrderSeq: int(utils.MustInterface2Int64(result["day_seq"])),
StatusTime: getTimeFromTimestamp(utils.MustInterface2Int64(result["ctime"])),
OrderCreatedAt: getTimeFromTimestamp(utils.MustInterface2Int64(result["ctime"])),
// OrderFinishedAt: getTimeFromTimestamp(utils.MustInterface2Int64(result["order_completed_time"])),
OriginalData: string(utils.MustMarshal(result)),
ActualPayPrice: jxutils.StandardPrice2Int(utils.MustInterface2Float64(result["total"])),
BaseFreightMoney: jxutils.StandardPrice2Int(utils.Interface2Float64WithDefault(result["shipping_fee"], 0)),
InvoiceTitle: utils.Interface2String(result["invoice_title"]),
InvoiceTaxerID: utils.Interface2String(result["taxpayer_id"]),
InvoiceEmail: jxutils.GetOneEmailFromStr(utils.Interface2String(result["caution"])),
VendorOrgCode: utils.Interface2String(result[keyVendorOrgCode]),
}
if result["order_completed_time"] != nil {
order.OrderFinishedAt = getTimeFromTimestamp(utils.MustInterface2Int64(result["order_completed_time"]))
} else {
order.OrderFinishedAt = utils.DefaultTimeValue
}
pickType := int(utils.Interface2Int64WithDefault(result["pick_type"], 0))
if pickType == mtwmapi.OrderPickTypeSelf {
order.DeliveryType = model.OrderDeliveryTypeSelfTake
} else {
logisticsCode := utils.Interface2String(result["logistics_code"])
if logisticsCode == mtwmapi.PeiSongTypeSelf {
order.DeliveryType = model.OrderDeliveryTypeStoreSelf
} else {
order.DeliveryType = model.OrderDeliveryTypePlatform
}
}
openUID := utils.Interface2Int64WithDefault(result["openUid"], 0)
if openUID > 0 {
order.VendorUserID = utils.Int64ToStr(openUID)
}
// 不设置最晚拣货时间,以缺省值为准
// if utils.IsTimeZero(order.PickDeadline) && !utils.IsTimeZero(order.StatusTime) {
// order.PickDeadline = order.StatusTime.Add(pickupOrderDelay) // 美团外卖要求在5分钟内拣货不然订单会被取消
// }
order.Status = p.getStatusFromVendorStatus(order.VendorStatus)
if utils.IsTimeZero(order.ExpectedDeliveredTime) {
order.BusinessType = model.BusinessTypeImmediate
} else {
order.BusinessType = model.BusinessTypeDingshida
}
originalLng := utils.MustInterface2Float64(result["longitude"])
originalLat := utils.MustInterface2Float64(result["latitude"])
order.ConsigneeLng = jxutils.StandardCoordinate2Int(originalLng)
order.ConsigneeLat = jxutils.StandardCoordinate2Int(originalLat)
var detail []map[string]interface{}
if err := utils.UnmarshalUseNumber([]byte(result["detail"].(string)), &detail); err != nil {
panic(fmt.Sprintf("mtwm Map2Order vendorID:%s failed with error:%v", vendorOrderID, err))
}
// 添加需要赠送的东西
if result["extras"] != nil {
var extraList []*mtwmapi.OrderExtraInfo
if err := utils.UnmarshalUseNumber([]byte(result["extras"].(string)), &extraList); err != nil {
panic(fmt.Sprintf("mtwm Map2Order vendorID:%s failed with error:%v", vendorOrderID, err))
}
for _, extra := range extraList {
order.DiscountMoney += jxutils.StandardPrice2Int(extra.ReduceFee)
if extra.Type == mtwmapi.ExtrasPromotionTypeTaoCanZeng || extra.Type == mtwmapi.ExtrasPromotionTypeManZeng {
sku := &model.OrderSku{
VendorOrderID: order.VendorOrderID,
VendorID: model.VendorIDMTWM,
Count: 1,
SkuID: 0,
VendorSkuID: "",
SkuName: extra.Remark,
Weight: 0,
SalePrice: 0,
StoreSubName: utils.Int2Str(extra.Type),
}
order.Skus = append(order.Skus, sku)
}
}
}
if poiReceiveDetailStr := utils.Interface2String(result["poi_receive_detail"]); poiReceiveDetailStr != "" {
var poiReceiveDetail *mtwmapi.PoiReceiveDetailInfo
utils.UnmarshalUseNumber([]byte(poiReceiveDetailStr), &poiReceiveDetail)
if poiReceiveDetail != nil {
order.TotalShopMoney = poiReceiveDetail.WmPoiReceiveCent
for _, v := range poiReceiveDetail.ActOrderChargeByMt {
order.PmSubsidyMoney += v.MoneyCent
}
}
}
var skuBenefitDetailMap map[string]*mtwmapi.SkuBenefitDetailInfo
if skuBenefitDetai := utils.Interface2String(result["sku_benefit_detail"]); skuBenefitDetai != "" {
skuBenefitDetailMap = make(map[string]*mtwmapi.SkuBenefitDetailInfo)
var skuBenefitDetailList []*mtwmapi.SkuBenefitDetailInfo
utils.UnmarshalUseNumber([]byte(skuBenefitDetai), &skuBenefitDetailList)
for _, v := range skuBenefitDetailList {
skuBenefitDetailMap[v.SkuID] = v
}
}
ignoreSkuMap := make(map[int]int)
// detail := result["detail"].([]interface{})
multiSkuMap := make(map[int]int)
for _, product := range detail {
// product := product2.(map[string]interface{})
skuName := product["food_name"].(string)
skuID := utils.Interface2String(product["sku_id"])
sku := &model.OrderSku{
VendorOrderID: order.VendorOrderID,
VendorID: model.VendorIDMTWM,
Count: int(utils.MustInterface2Float64(product["quantity"])),
SkuID: int(utils.Str2Int64WithDefault(skuID, 0)),
VendorSkuID: skuID,
SkuName: skuName,
Weight: getSkuWeight(product),
VendorPrice: jxutils.StandardPrice2Int(utils.MustInterface2Float64(product["price"])),
SalePrice: jxutils.StandardPrice2Int(utils.MustInterface2Float64(product["price"])),
}
if sku.Weight == 0 {
sku.Weight = 222 // 如果名字里找不到缺省给半斤左右的一个特别值
}
if skuBenefitDetailMap != nil && skuBenefitDetailMap[sku.VendorSkuID] != nil && ignoreSkuMap[sku.SkuID] == 0 /* && sku.Count == 1 */ {
for _, v := range skuBenefitDetailMap[sku.VendorSkuID].WmAppOrderActDetails {
if /*skuActTypeMap[v.Type] == 1 && */ strings.Index(v.Remark, skuName) >= 0 && sku.Count == v.Count {
if sku.SalePrice-jxutils.StandardPrice2Int(v.MtCharge+v.PoiCharge) < 0 {
continue
} else {
ignoreSkuMap[sku.SkuID] = 1
sku.SalePrice -= jxutils.StandardPrice2Int(v.MtCharge + v.PoiCharge)
}
sku.StoreSubName = utils.Int2Str(v.Type)
}
}
}
if sku.SalePrice < 0 {
sku.SalePrice = jxutils.StandardPrice2Int(utils.MustInterface2Float64(product["price"]))
}
// if product["isGift"].(bool) {
// sku.SkuType = 1
// }
order.Skus = append(order.Skus, sku)
multiSkuMap[sku.SkuID]++
}
for _, v := range order.Skus {
if multiSkuMap[v.SkuID] > 1 && v.SalePrice == v.VendorPrice {
v.IsVendorAct = model.YES
}
}
jxutils.RefreshOrderSkuRelated(order)
return order
}
func getRefundSkuDetailList(msg *mtwmapi.CallbackMsg) (skuList []*mtwmapi.RefundSkuDetail, err error) {
if false {
skuList = api.MtwmAPI.GetRefundSkuDetailFromMsg(msg)
} else {
refundOrderDetailList, err2 := api.MtwmAPI.GetOrderRefundDetail(utils.Str2Int64(GetOrderIDFromMsg(msg)), mtwmapi.RefundTypePart)
if err = err2; err == nil {
for _, v := range refundOrderDetailList {
skuList = append(skuList, v.WmAppRetailForOrderPartRefundList...)
}
}
}
globals.SugarLogger.Debugf("getRefundSkuDetailList orderID:%s skuList:%s", GetOrderIDFromMsg(msg), utils.Format4Output(skuList, true))
return skuList, err
}
func getSkuWeight(product map[string]interface{}) (weight int) {
if weight = int(utils.Interface2Int64WithDefault(product["weight"], 0)); weight == 0 {
searchResult := specPat.FindStringSubmatch(product["spec"].(string))
if len(searchResult) == 3 {
weight = jxutils.FormatSkuWeight(float32(utils.Str2Float64WithDefault(searchResult[1], 0)), utils.TrimBlankChar(searchResult[2]))
}
if weight == 0 {
_, _, _, specUnit, _, specQuality := jxutils.SplitSkuName(product["food_name"].(string))
weight = jxutils.FormatSkuWeight(specQuality, specUnit)
}
}
return weight
}
func (c *PurchaseHandler) onOrderMsg(msg *mtwmapi.CallbackMsg) (response *mtwmapi.CallbackResponse) {
var err error
if c.isAfsMsg(msg) {
response = c.OnAfsOrderMsg(msg)
} else {
status := c.callbackMsg2Status(msg)
if partner.CurOrderManager.GetStatusDuplicatedCount(status) > 0 {
return nil
}
if msg.Cmd == mtwmapi.MsgTypeNewOrder {
order, orderMap, err2 := c.getOrder(msg.AppID, GetOrderIDFromMsg(msg))
if err = err2; err == nil {
err = partner.CurOrderManager.OnOrderNew(order, c.callbackMsg2Status(msg))
if err == nil {
utils.CallFuncAsync(func() {
if msg.Cmd == mtwmapi.MsgTypeNewOrder {
c.OnOrderDetail(orderMap, partner.CreatedPeration)
} else {
c.OnOrderDetail(orderMap, partner.UpdatedPeration)
}
})
}
}
} else {
if status != nil {
if status.Status == model.OrderStatusAdjust {
var order *model.GoodsOrder
if order, err = c.GetOrder(msg.AppID, GetOrderIDFromMsg(msg)); err == nil {
skuList, err2 := getRefundSkuDetailList(msg)
if err = err2; err == nil {
var removedSkuList []*model.OrderSku
for _, mtwmSku := range skuList {
order.ActualPayPrice -= jxutils.StandardPrice2Int(mtwmSku.RefundPrice) * int64(mtwmSku.Count)
removedSkuList = append(removedSkuList, &model.OrderSku{
SkuID: int(utils.Str2Int64WithDefault(mtwmSku.SkuID, 0)),
Count: mtwmSku.Count,
})
}
order = jxutils.RemoveSkuFromOrder(order, removedSkuList)
jxutils.RefreshOrderSkuRelated(order)
err = partner.CurOrderManager.OnOrderAdjust(order, status)
}
}
} else {
if status.Status == model.OrderStatusDelivering {
// 美团订单即使时在配送状态时,如果之前没有调用过拣货完成,也会对门店指标生成影响,这里强制再调用拣货完成,且忽略错误
utils.CallFuncAsync(func() {
if globals.EnableMtwmStoreWrite {
err = api.MtwmAPI.PreparationMealComplete(utils.Str2Int64(status.VendorOrderID))
}
})
}
err = partner.CurOrderManager.OnOrderStatusChanged(msg.AppID, status)
if err == nil && msg.Cmd == mtwmapi.MsgTypeOrderFinished {
utils.CallFuncAsync(func() {
orderMap, err := api.MtwmAPI.OrderGetOrderDetail(utils.Str2Int64(GetOrderIDFromMsg(msg)), true)
if err == nil && utils.MustInterface2Int64(orderMap["is_third_shipping"]) == SelfDeliveryCarrierNo {
c.OnOrderDetail(orderMap, partner.UpdatedPeration)
}
})
}
}
}
}
}
return mtwmapi.Err2CallbackResponse(err, "")
}
func (c *PurchaseHandler) callbackMsg2Status(msg *mtwmapi.CallbackMsg) (orderStatus *model.OrderStatus) {
orderID := GetOrderIDFromMsg(msg)
vendorStatus := msg.Cmd
remark := ""
statusTime := utils.Str2Int64(msg.FormData.Get("timestamp"))
switch msg.Cmd {
case mtwmapi.MsgTypeUserUrgeOrder, mtwmapi.MsgTypeOrderModified, mtwmapi.MsgTypeOrderFinancial:
vendorStatus = msg.Cmd
case mtwmapi.MsgTypeOrderCanceled:
vendorStatus = mtwmapi.OrderStatusCanceled
remark = msg.FormData.Get("reason")
case FakeMsgType, mtwmapi.MsgTypeNewOrder, mtwmapi.MsgTypeOrderAccepted, mtwmapi.MsgTypeOrderFinished:
vendorStatus = msg.FormData.Get("status")
statusTime = utils.Str2Int64(msg.FormData.Get("utime"))
case mtwmapi.MsgTypeOrderRefund, mtwmapi.MsgTypeOrderPartialRefund:
notifyType := msg.FormData.Get("notify_type")
vendorStatus = msg.Cmd + "-" + notifyType
if true { // 已经提前判断了,到这里的都是售中
remark = msg.FormData.Get("reason")
if msg.Cmd == mtwmapi.MsgTypeOrderPartialRefund {
if notifyType == mtwmapi.NotifyTypePartyApply {
if globals.EnableMtwmStoreWrite {
// goods, err := dao.GetSimpleOrder(dao.GetDB(), orderID)
// if err == nil {
// if goods.Status < model.OrderStatusDelivering {
api.MtwmAPI.OrderRefundAgree(utils.Str2Int64(orderID), "自动确认退款")
// } else {
// api.MtwmAPI.OrderRefundReject(utils.Str2Int64(orderID), "商品配送中,请联系门店。") // todo 京东与饿百都没有售前用户提出订单调整的,自动拒绝调整单
// }
// }
}
} else if notifyType == mtwmapi.NotifyTypeSuccess {
vendorStatus = fakeOrderAdjustFinished
}
} else if msg.Cmd == mtwmapi.MsgTypeOrderRefund {
if notifyType == mtwmapi.NotifyTypeApply {
vendorStatus = fakeUserApplyCancel
} else if notifyType == mtwmapi.NotifyTypeCancelRefund || notifyType == mtwmapi.NotifyTypeCancelRefundComplaint {
vendorStatus = fakeUserUndoApplyCancel
} else if notifyType == mtwmapi.NotifyTypeReject {
vendorStatus = fakeRefuseUserApplyCancel
} else if notifyType == mtwmapi.NotifyTypeSuccess {
vendorStatus = fakeMerchantAgreeApplyCancel // todo 可能导致订单取消消息重复
}
}
}
default:
globals.SugarLogger.Errorf("mtwm unkonw msg:%s", utils.Format4Output(msg, false))
}
if vendorStatus != "" {
orderStatus = &model.OrderStatus{
VendorOrderID: orderID,
VendorID: model.VendorIDMTWM,
OrderType: model.OrderTypeOrder,
RefVendorOrderID: orderID,
RefVendorID: model.VendorIDMTWM,
VendorStatus: vendorStatus,
Status: c.getStatusFromVendorStatus(vendorStatus),
StatusTime: getTimeFromTimestamp(statusTime),
Remark: remark,
}
}
return orderStatus
}
func (c *PurchaseHandler) postFakeMsg(vendorOrderID, cmd, vendorStatus string) {
msg := &mtwmapi.CallbackMsg{
Cmd: cmd,
FormData: make(url.Values),
}
timeStr := utils.Int64ToStr(time.Now().Unix())
msg.FormData.Set(mtwmapi.KeyOrderID, vendorOrderID)
msg.FormData.Set("status", vendorStatus)
msg.FormData.Set("timestamp", timeStr)
msg.FormData.Set("utime", timeStr)
utils.CallFuncAsync(func() {
c.onOrderMsg(msg)
})
}
func (c *PurchaseHandler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) {
globals.SugarLogger.Debugf("mtwm AcceptOrRefuseOrder orderID:%s, isAcceptIt:%t", order.VendorOrderID, isAcceptIt)
if isAcceptIt {
if globals.EnableMtwmStoreWrite {
// err = api.MtwmAPI.OrderReceived(utils.Str2Int64(order.VendorOrderID))
err = api.MtwmAPI.OrderConfirm(utils.Str2Int64(order.VendorOrderID))
if err != nil {
if utils.IsErrMatch(err, utils.Int2Str(mtwmapi.ErrCodeOpFailed), []string{
"订单已经确认过了",
}) {
err = nil
} else {
globals.SugarLogger.Warnf("mtwm AcceptOrRefuseOrder orderID:%s failed with err:%v", order.VendorOrderID, err)
}
}
}
// if err == nil {
// c.postFakeMsg(order.VendorOrderID, FakeMsgType, mtwmapi.OrderStatusReceived)
// }
} else {
if globals.EnableMtwmStoreWrite {
err = c.CancelOrder(jxcontext.AdminCtx, order, "bu")
}
}
return err
}
func (c *PurchaseHandler) PickupGoods(order *model.GoodsOrder, isSelfDelivery bool, userName string) (err error) {
globals.SugarLogger.Debugf("mtwm PickupGoods orderID:%s, isSelfDelivery:%t", order.VendorOrderID, isSelfDelivery)
if !isSelfDelivery {
if globals.EnableMtwmStoreWrite {
// err = api.MtwmAPI.OrderConfirm(utils.Str2Int64(order.VendorOrderID))
err = api.MtwmAPI.PreparationMealComplete(utils.Str2Int64(order.VendorOrderID))
}
}
if err == nil {
c.postFakeMsg(order.VendorOrderID, FakeMsgType, fakeFinishedPickup)
}
return err
}
func (p *PurchaseHandler) AcceptOrRefuseFailedGetOrder(ctx *jxcontext.Context, order *model.GoodsOrder, isAcceptIt bool) (err error) {
return err
}
func (p *PurchaseHandler) CallCourier(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 拣货失败后再次招唤平台配送
return err
}
func (p *PurchaseHandler) ConfirmReceiveGoods(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 投递失败后确认收到退货
return err
}
// 美团预定单不能转商家自送
func (c *PurchaseHandler) CanSwitch2SelfDeliver(order *model.GoodsOrder) (isCan bool, err error) {
return order.BusinessType != model.BusinessTypeDingshida, nil
}
func (c *PurchaseHandler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) {
globals.SugarLogger.Debugf("mtwm Swtich2SelfDeliver orderID:%s", order.VendorOrderID)
if globals.EnableMtwmStoreWrite {
err = api.MtwmAPI.OrderLogisticsChange2Self(utils.Str2Int64(order.VendorOrderID))
}
return err
}
func (c *PurchaseHandler) Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) {
globals.SugarLogger.Debugf("mtwm Swtich2SelfDelivered orderID:%s", order.VendorOrderID)
if globals.EnableMtwmStoreWrite {
// 您好,之前的答复已经更正为,调用变更配送状态的接口,会校验门店的配送类型。美团配送的门店即便转自配后因门店配送类型是美团配送所以无法调用接口变更配送状态。可提醒顾客点击确认收货。谢谢
// 非自配送门店订单调用OrderArrived好像会报错{"data":"ng","error":{"code":1038,"msg":"只允许商家配送调用该接口"}}
// err = api.MtwmAPI.OrderArrived(utils.Str2Int64(order.VendorOrderID))
}
return err
}
func (c *PurchaseHandler) SelfDeliverDelivering(order *model.GoodsOrder, userName string) (err error) {
globals.SugarLogger.Debugf("mtwm SelfDeliverDelivering orderID:%s", order.VendorOrderID)
if globals.EnableMtwmStoreWrite {
err = api.MtwmAPI.OrderDelivering(utils.Str2Int64(order.VendorOrderID))
}
return err
}
func (c *PurchaseHandler) SelfDeliverDelivered(order *model.GoodsOrder, userName string) (err error) {
globals.SugarLogger.Debugf("mtwm SelfDeliverDelivered orderID:%s", order.VendorOrderID)
if globals.EnableMtwmStoreWrite {
err = api.MtwmAPI.OrderArrived(utils.Str2Int64(order.VendorOrderID))
}
return err
}
func getTimeFromTimestamp(timeStamp int64) time.Time {
if timeStamp < 1538103149 { // 立即达订单给的是1而不是空01538103149不是特殊值只是一个任意之前的时间这样写可以处理
return utils.DefaultTimeValue
}
return utils.Timestamp2Time(timeStamp)
}
func (c *PurchaseHandler) GetOrderRealMobile(ctx *jxcontext.Context, order *model.GoodsOrder) (mobile string, err error) {
err = errors.New("美团外卖还未实现GetOrderRealMobile")
return mobile, err
}
func (c *PurchaseHandler) AgreeOrRefuseCancel(ctx *jxcontext.Context, order *model.GoodsOrder, isAgree bool, reason string) (err error) {
if globals.EnableMtwmStoreWrite {
if isAgree {
err = api.MtwmAPI.OrderRefundAgree(utils.Str2Int64(order.VendorOrderID), reason)
} else {
err = api.MtwmAPI.OrderRefundReject(utils.Str2Int64(order.VendorOrderID), reason)
}
}
return err
}
func (c *PurchaseHandler) CancelOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
if globals.EnableMtwmStoreWrite {
if err = api.MtwmAPI.OrderCancel(utils.Str2Int64(order.VendorOrderID), reason, mtwmapi.CancelReasonOther); err == nil {
// 调用开放平台接口取消订单,不推送取消订单消息和退款消息。
c.postFakeMsg(order.VendorOrderID, mtwmapi.MsgTypeOrderCanceled, mtwmapi.OrderStatusCanceled)
}
}
return err
}
func (c *PurchaseHandler) AdjustOrder(ctx *jxcontext.Context, order *model.GoodsOrder, removedSkuList []*model.OrderSku, reason string) (err error) {
// 美团外卖必须要确认订单后才能调整单
if order.Status < model.OrderStatusFinishedPickup {
err = c.PickupGoods(order, false, ctx.GetUserName())
}
if err == nil {
var skuList []*mtwmapi.RefundSku
for _, sku := range removedSkuList {
skuID := utils.Int2Str(jxutils.GetSkuIDFromOrderSku(sku))
skuList = append(skuList, &mtwmapi.RefundSku{
AppFoodCode: skuID,
SkuID: skuID,
Count: sku.Count,
})
}
if globals.EnableMtwmStoreWrite {
err = api.MtwmAPI.OrderApplyPartRefund(utils.Str2Int64(order.VendorOrderID), reason, skuList)
}
}
return err
}
func (c *PurchaseHandler) ListOrders(ctx *jxcontext.Context, vendorOrgCode string, parentTask tasksch.ITask, queryDate time.Time, vendorStoreID string) (vendorOrderIDs []string, err error) {
if utils.IsTimeZero(queryDate) {
return nil, fmt.Errorf("queryDate必须指定")
}
queryDate = utils.Time2Date(queryDate)
var vendorStoreIDs []string
if vendorStoreID == "" {
vendorStoreIDs, err = c.GetAllStoresVendorID(ctx, "")
if err != nil {
return nil, err
}
} else {
vendorStoreIDs = []string{vendorStoreID}
}
task := tasksch.NewParallelTask("mtwm ListOrders", nil, ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
vendorStoreID := batchItemList[0].(string)
var orderIDs []string
seqStart := 1
i := 0
for {
batchSize := int(math.Min(math.Pow(2, float64(i*3)), float64(mtwmapi.MaxGap4GetOrderIdByDaySeq)))
seqEnd := seqStart + batchSize - 1
var tmpOrderIDs []int64
if seqStart == seqEnd {
if vendorOderID, err2 := api.MtwmAPI.GetOrderIdByDaySeqSingle(vendorStoreID, queryDate, seqStart); err2 == nil {
tmpOrderIDs = []int64{vendorOderID}
}
} else {
tmpOrderIDs, err = api.MtwmAPI.GetOrderIdByDaySeq(vendorStoreID, queryDate, seqStart, seqEnd)
}
if len(tmpOrderIDs) > 0 {
for _, v := range tmpOrderIDs {
orderIDs = append(orderIDs, utils.Int64ToStr(v))
}
}
if err != nil || len(tmpOrderIDs) < batchSize {
err = nil
break
}
seqStart = seqEnd + 1
i++
}
retVal = orderIDs
return retVal, nil
}, vendorStoreIDs)
tasksch.HandleTask(task, parentTask, true).Run()
orderList, err := task.GetResult(0)
if err == nil && len(orderList) > 0 {
vendorOrderIDs = make([]string, len(orderList))
for k, v := range orderList {
vendorOrderIDs[k] = v.(string)
}
}
return vendorOrderIDs, err
}
// func (c *PurchaseHandler) UpdateWaybillTip(ctx *jxcontext.Context, order *model.GoodsOrder, tipFee int64) (err error) {
// if globals.EnableMtwmStoreWrite {
// err = api.MtwmAPI.OrderUpdateTip(utils.Str2Int64(order.VendorOrderID), jxutils.IntPrice2Standard(tipFee))
// }
// return err
// }
func (p *PurchaseHandler) GetOrderConsigneeNumber(ctx *jxcontext.Context, storeID int, vendorStoreID string) (numberList []*partner.OrderPhoneNumberInfo, err error) {
offset := 0
for {
result, err2 := api.MtwmAPI.OrderBatchPullPhoneNumber(vendorStoreID, offset, mtwmapi.MaxBatchPullPhoneNumberLimit)
if err = err2; err == nil {
for _, v := range result {
v2 := &partner.OrderPhoneNumberInfo{
VendorOrderID: utils.Int64ToStr(v.OrderID),
PhoneNumber: v.RealPhoneNumber,
}
if v2.PhoneNumber == "" {
v2.PhoneNumber = v.RealOrderPhoneNumber
}
numberList = append(numberList, v2)
}
if len(result) <= mtwmapi.MaxBatchPullPhoneNumberLimit {
break
}
offset += mtwmapi.MaxBatchPullPhoneNumberLimit
} else {
break
}
}
return numberList, err
}
func (p *PurchaseHandler) GetOrderCourierNumber(ctx *jxcontext.Context, storeID int, vendorStoreID string) (numberList []*partner.OrderPhoneNumberInfo, err error) {
offset := 0
for {
result, err2 := api.MtwmAPI.OrderGetRiderInfoPhoneNumber(vendorStoreID, offset, mtwmapi.MaxBatchPullPhoneNumberLimit)
if err = err2; err == nil {
for _, v := range result {
numberList = append(numberList, &partner.OrderPhoneNumberInfo{
VendorOrderID: utils.Int64ToStr(v.OrderID),
PhoneNumber: v.RiderRealPhoneNumber,
})
}
if len(result) <= mtwmapi.MaxBatchPullPhoneNumberLimit {
break
}
offset += mtwmapi.MaxBatchPullPhoneNumberLimit
} else {
break
}
}
return numberList, err
}
func (p *PurchaseHandler) onNumberDowngrade(msg *mtwmapi.CallbackMsg) (response *mtwmapi.CallbackResponse) {
userNumberMap := make(map[string]*partner.OrderPhoneNumberInfo)
courierNumberMap := make(map[string]*partner.OrderPhoneNumberInfo)
orderMap := make(map[string]int)
ctx := jxcontext.AdminCtx
task := tasksch.NewParallelTask("美团外卖平台处理隐私号降级通知", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(true), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
step := batchItemList[0].(int)
switch step {
case 0:
userNumberList, err2 := p.GetOrderConsigneeNumber(ctx, 0, "")
if err = err2; err == nil {
for _, v := range userNumberList {
userNumberMap[v.VendorOrderID] = v
orderMap[v.VendorOrderID] = 1
}
}
case 1:
courierNumberList, err2 := p.GetOrderCourierNumber(ctx, 0, "")
if err = err2; err == nil {
for _, v := range courierNumberList {
courierNumberMap[v.VendorOrderID] = v
orderMap[v.VendorOrderID] = 1
}
}
case 2:
orderList := jxutils.StringMap2List(orderMap)
if len(orderList) > 0 {
updateTask := tasksch.NewParallelTask("美团外卖平台处理隐私号降级通知/处理订单", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(true), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
vendorOrderID := batchItemList[0].(string)
db := dao.GetDB()
if userNumberMap[vendorOrderID] != nil {
_, err = dao.UpdateEntityByKV(db, &model.GoodsOrder{}, map[string]interface{}{
"ConsigneeMobile": userNumberMap[vendorOrderID].PhoneNumber,
"ConsigneeMobile2": userNumberMap[vendorOrderID].PhoneNumber,
}, map[string]interface{}{
model.FieldVendorOrderID: vendorOrderID,
model.FieldVendorID: model.VendorIDMTWM,
})
}
if courierNumberMap[vendorOrderID] != nil {
_, err = dao.UpdateEntityByKV(db, &model.Waybill{}, map[string]interface{}{
"CourierMobile": courierNumberMap[vendorOrderID].PhoneNumber,
}, map[string]interface{}{
"VendorWaybillID": vendorOrderID,
"WaybillVendorID": model.VendorIDMTWM,
})
}
return retVal, err
}, orderList)
tasksch.HandleTask(updateTask, task, true).Run()
_, err = updateTask.GetResult(0)
}
}
return retVal, err
}, []int{0, 1, 2})
tasksch.HandleTask(task, nil, true).Run()
return response
}
func (c *PurchaseHandler) GetWaybillTip(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID, vendorOrderID, vendorWaybillID, vendorWaybillID2 string) (tipFee int64, err error) {
orderInfo, err := api.MtwmAPI.GetDistributeOrderDetail(vendorOrderID, vendorStoreID)
if err == nil {
tipFee = jxutils.StandardPrice2Int(orderInfo.TipAmount)
}
return tipFee, err
}
func (c *PurchaseHandler) UpdateWaybillTip(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID, vendorOrderID, vendorWaybillID, vendorWaybillID2, cityCode string, tipFee int64) (err error) {
if globals.EnableMtwmStoreWrite {
err = api.MtwmAPI.OrderModityTips(vendorOrderID, vendorStoreID, jxutils.IntPrice2Standard(tipFee))
}
return err
}

View File

@@ -1,213 +0,0 @@
package mtwm
import (
"fmt"
"net/url"
"strings"
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
var (
// AfsVendorStatus2StatusMap = map[int]int{
// mtwmapi.ResTypePending: model.AfsOrderStatusWait4Approve,
// mtwmapi.ResTypeMerchantRefused: model.AfsOrderStatusFailed,
// mtwmapi.ResTypeMerchantAgreed: model.AfsOrderStatusFinished,
// mtwmapi.ResTypeCSRefused: model.AfsOrderStatusFailed,
// mtwmapi.ResTypeCSAgreed: model.AfsOrderStatusFinished,
// mtwmapi.ResTypeTimeoutAutoAgreed: model.AfsOrderStatusFinished,
// mtwmapi.ResTypeAutoAgreed: model.AfsOrderStatusFinished,
// mtwmapi.ResTypeUserCancelApply: model.AfsOrderStatusFailed,
// mtwmapi.ResTypeUserCancelComplain: model.AfsOrderStatusFailed,
// }
AfsVendorStatus2StatusMap = map[string]int{
mtwmapi.NotifyTypeApply: model.AfsOrderStatusWait4Approve,
mtwmapi.NotifyTypePartyApply: model.AfsOrderStatusWait4Approve,
mtwmapi.NotifyTypeSuccess: model.AfsOrderStatusFinished,
mtwmapi.NotifyTypeReject: model.AfsOrderStatusFailed,
mtwmapi.NotifyTypeCancelRefund: model.AfsOrderStatusFailed,
mtwmapi.NotifyTypeCancelRefundComplaint: model.AfsOrderStatusFailed,
}
)
func (c *PurchaseHandler) isAfsMsg(msg *mtwmapi.CallbackMsg) bool {
if msg.Cmd == mtwmapi.MsgTypeOrderRefund || msg.Cmd == mtwmapi.MsgTypeOrderPartialRefund {
// refundData := msg.Data.(*mtwmapi.CallbackRefundInfo)
orderID := utils.Str2Int64(GetOrderIDFromMsg(msg))
status, err := api.MtwmAPI.OrderViewStatus(orderID)
if err == nil {
return utils.Int2Str(status) == mtwmapi.OrderStatusFinished
}
globals.SugarLogger.Warnf("mtwm isAfsMsg OrderGetOrderDetail2 orderID:%d failed with error:%v", orderID, err)
}
return false
}
func (c *PurchaseHandler) OnAfsOrderMsg(msg *mtwmapi.CallbackMsg) (retVal *mtwmapi.CallbackResponse) {
jxutils.CallMsgHandlerAsync(func() {
retVal = c.onAfsOrderMsg(msg)
}, jxutils.ComposeUniversalOrderID(GetOrderIDFromMsg(msg), model.VendorIDEBAI))
return retVal
}
// todo 对于退款与部分退款order.go与这个文件中对于状态的处理不一致
func (c *PurchaseHandler) onAfsOrderMsg(msg *mtwmapi.CallbackMsg) (retVal *mtwmapi.CallbackResponse) {
var err error
orderStatus := c.callbackAfsMsg2Status(msg)
needCallNew := orderStatus.Status == model.AfsOrderStatusWait4Approve || orderStatus.Status == model.AfsOrderStatusNew
if !needCallNew {
_, err := partner.CurOrderManager.LoadAfsOrder(orderStatus.VendorOrderID, orderStatus.VendorID)
if err != nil {
if dao.IsNoRowsError(err) {
needCallNew = true
} else {
return mtwmapi.Err2CallbackResponse(err, "")
}
}
}
if needCallNew {
var afsOrder *model.AfsOrder
refundData := msg.Data.(*mtwmapi.CallbackRefundInfo)
if msg.Cmd == mtwmapi.MsgTypeOrderPartialRefund {
afsOrder = &model.AfsOrder{
VendorID: model.VendorIDMTWM,
AfsOrderID: orderStatus.VendorOrderID,
VendorOrderID: orderStatus.RefVendorOrderID,
VendorStoreID: "",
StoreID: 0,
AfsCreatedAt: utils.Timestamp2Time(refundData.Timestamp),
VendorAppealType: "",
AppealType: model.AfsAppealTypeRefund,
VendorReasonType: "",
ReasonType: model.AfsReasonNotOthers,
ReasonDesc: utils.LimitUTF8StringLen(refundData.Reason, 1024),
ReasonImgList: utils.LimitUTF8StringLen(strings.Join(refundData.PictureList, ","), 1024),
RefundType: model.AfsTypePartRefund,
VendorOrgCode: msg.AppID,
// FreightUserMoney: afsInfo.OrderFreightMoney,
// AfsFreightMoney: afsInfo.AfsFreight,
// BoxMoney: afsInfo.PackagingMoney,
// TongchengFreightMoney: afsInfo.TongchengFreightMoney,
// SkuBoxMoney: afsInfo.MealBoxMoney,
}
for _, sku := range refundData.FoodList {
orderSku := &model.OrderSkuFinancial{
// VendorID: model.VendorIDMTWM,
// AfsOrderID: afsOrder.AfsOrderID,
// VendorOrderID: afsOrder.VendorOrderID,
// VendorStoreID: afsOrder.VendorStoreID,
// StoreID: afsOrder.StoreID,
// IsAfsOrder: 1,
Count: sku.Count,
// ConfirmTime: afsOrder.AfsCreateAt,
VendorSkuID: sku.SkuID,
SkuID: int(utils.Str2Int64WithDefault(sku.SkuID, 0)),
Name: sku.FoodName,
UserMoney: jxutils.StandardPrice2Int(sku.RefundPrice)*int64(sku.Count) + jxutils.StandardPrice2Int(sku.BoxPrice)*int64(sku.BoxNum),
}
afsOrder.SkuUserMoney += orderSku.UserMoney
afsOrder.Skus = append(afsOrder.Skus, orderSku)
}
afsOrder.PmSubsidyMoney += afsOrder.RefundMoney - afsOrder.SkuUserMoney
} else {
if afsOrder = c.createAfsOrder(msg.FormData); afsOrder != nil {
// if orderFinancial, err2 := partner.CurOrderManager.LoadOrderFinancial(orderStatus.RefVendorOrderID, model.VendorIDMTWM); err2 == nil {
// afsOrder = c.OrderFinancialDetail2Refund(orderFinancial, msg.FormData)
afsOrder.AfsOrderID = orderStatus.VendorOrderID
afsOrder.RefundType = model.AfsTypeFullRefund
afsOrder.AppealType = model.AfsAppealTypeRefund
afsOrder.VendorReasonType = ""
afsOrder.ReasonType = model.AfsReasonNotOthers
afsOrder.ReasonDesc = utils.LimitUTF8StringLen(refundData.Reason, 1024)
afsOrder.ReasonImgList = utils.LimitUTF8StringLen(strings.Join(refundData.PictureList, ","), 1024)
}
}
if afsOrder != nil {
err = partner.CurOrderManager.OnAfsOrderNew(afsOrder, orderStatus)
}
} else {
err = partner.CurOrderManager.OnAfsOrderStatusChanged(orderStatus)
}
return mtwmapi.Err2CallbackResponse(err, "")
}
func (p *PurchaseHandler) createAfsOrder(orderData url.Values) (afsOrder *model.AfsOrder) {
afsOrder, err := partner.CurOrderManager.CreateAfsOrderFromOrder(orderData.Get("order_id"), model.VendorIDMTWM)
if err == nil {
afsOrder.AfsOrderID = orderData.Get("refund_id")
afsOrder.AfsCreatedAt = utils.Timestamp2Time(utils.Str2Int64(orderData.Get("timestamp")))
if afsOrder.AfsOrderID == "" {
afsOrder.AfsOrderID = afsOrder.VendorOrderID
}
} else {
afsOrder = nil
}
return afsOrder
}
func (c *PurchaseHandler) callbackAfsMsg2Status(msg *mtwmapi.CallbackMsg) (orderStatus *model.OrderStatus) {
refundData := msg.Data.(*mtwmapi.CallbackRefundInfo)
orderStatus = &model.OrderStatus{
VendorID: model.VendorIDMTWM,
OrderType: model.OrderTypeAfsOrder,
RefVendorOrderID: utils.Int64ToStr(refundData.OrderID),
RefVendorID: model.VendorIDMTWM,
VendorStatus: fmt.Sprintf("%s:%d", refundData.NotifyType, refundData.ResType),
Status: c.GetAfsStatusFromVendorStatus(refundData.ResType, refundData.NotifyType),
StatusTime: utils.Timestamp2Time(refundData.Timestamp),
Remark: refundData.Reason,
}
if refundData.RefundID > 0 {
orderStatus.VendorOrderID = utils.Int64ToStr(refundData.RefundID)
} else {
orderStatus.VendorOrderID = orderStatus.RefVendorOrderID
}
return orderStatus
}
func (c *PurchaseHandler) GetAfsStatusFromVendorStatus(resType int, notifyType string) int {
status := AfsVendorStatus2StatusMap[notifyType]
if status == model.AfsOrderStatusWait4Approve && resType != mtwmapi.ResTypePending {
status = model.AfsOrderStatusNew
}
return status
}
// 审核售后单申请
func (c *PurchaseHandler) AgreeOrRefuseRefund(ctx *jxcontext.Context, order *model.AfsOrder, approveType int, reason string) (err error) {
if globals.EnableMtwmStoreWrite {
if approveType == partner.AfsApproveTypeRefused {
err = api.MtwmAPI.OrderRefundReject(utils.Str2Int64(order.VendorOrderID), reason)
} else {
err = api.MtwmAPI.OrderRefundAgree(utils.Str2Int64(order.VendorOrderID), reason)
}
}
return err
}
// 确认收到退货
func (c *PurchaseHandler) ConfirmReceivedReturnGoods(ctx *jxcontext.Context, order *model.AfsOrder) (err error) {
err = fmt.Errorf("内部错误,美团外卖平台不支持确认收到退货操作")
return err
}
// 发起全款退款
func (c *PurchaseHandler) RefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
return fmt.Errorf("%s不支持售后全额退款请让买家发起退款", model.VendorChineseNames[model.VendorIDMTWM])
}
// 发起部分退款
func (c *PurchaseHandler) PartRefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, refundSkuList []*model.OrderSku, reason string) (err error) {
return c.AdjustOrder(ctx, order, refundSkuList, reason)
}

View File

@@ -1,112 +0,0 @@
package mtwm
import (
"strings"
"time"
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"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"
)
const (
RefreshCommentTime = 7 * 24 * time.Hour // 此值必须大于24小时
RefreshCommentTimeInterval = 60 * time.Minute
BAD_COMMENTS_MAX_MODIFY_TIME = 24 * 6 // 小时
)
func (c *PurchaseHandler) StartRefreshComment() {
utils.AfterFuncWithRecover(5*time.Second, func() {
c.refreshCommentOnce()
})
}
func (c *PurchaseHandler) refreshCommentOnce() {
c.RefreshComment(time.Now().Add(-RefreshCommentTime), time.Now())
utils.AfterFuncWithRecover(RefreshCommentTimeInterval, func() {
c.refreshCommentOnce()
})
}
func formalizeTagList(mtwmTagList string) (outTagList string) {
if mtwmTagList != "" {
outTagList = string(utils.Format4Output(strings.Split(mtwmTagList, ","), true))
}
return outTagList
}
func (c *PurchaseHandler) RefreshComment(fromTime, toTime time.Time) (err error) {
storeMapList, err2 := dao.GetStoresMapList(dao.GetDB(), []int{model.VendorIDMTWM}, nil, nil, model.StoreStatusAll, model.StoreIsSyncYes, "", "")
if err = err2; err != nil {
return err
}
task := tasksch.NewParallelTask("mtwm RefreshComment", nil, jxcontext.AdminCtx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
storeMap := batchItemList[0].(*model.StoreMap)
endDateStr := time.Now().Add(-24 * time.Hour).Format("20060102")
startDateStr := time.Now().Add(-RefreshCommentTime).Format("20060102")
commentList, err2 := api.MtwmAPI.CommentQuery(storeMap.VendorStoreID, startDateStr, endDateStr, 0, 0, mtwmapi.CommentReplyStatusAll)
var orderCommentList []*model.OrderComment
if err = err2; err != nil {
return nil, err
}
for _, mtwmComment := range commentList {
createdTime, err := utils.TryStr2Time(mtwmComment.CommentTime)
if err == nil {
orderComment := &model.OrderComment{
VendorOrderID: utils.Int64ToStr(mtwmComment.CommentID), // 美团评价不能得到订单号以评价ID代替
VendorID: model.VendorIDMTWM,
UserCommentID: utils.Int64ToStr(mtwmComment.CommentID),
VendorStoreID: storeMap.VendorStoreID,
TagList: formalizeTagList(mtwmComment.CommentLables),
Score: int8(mtwmComment.FoodCommentScore),
ModifyDuration: BAD_COMMENTS_MAX_MODIFY_TIME,
OriginalMsg: string(utils.MustMarshal(mtwmComment)),
IsReplied: int8(mtwmComment.ReplyStatus),
}
if orderComment.IsReplied == 0 {
orderComment.Content = mtwmComment.CommentContent
orderComment.CommentCreatedAt = createdTime
} else {
orderComment.Content = mtwmComment.AddComment
if updatedTime, err := utils.TryStr2Time(mtwmComment.CommentTime); err == nil {
orderComment.CommentCreatedAt = updatedTime
}
}
orderCommentList = append(orderCommentList, orderComment)
}
}
return orderCommentList, nil
}, storeMapList)
task.Run()
resultList, err2 := task.GetResult(0)
if err = err2; err != nil {
return err
}
var orderCommentList []*model.OrderComment
for _, result := range resultList {
orderComment := result.(*model.OrderComment)
orderCommentList = append(orderCommentList, orderComment)
}
if len(orderCommentList) > 0 {
err = partner.CurOrderManager.OnOrderComments(orderCommentList)
}
return err
}
func (c *PurchaseHandler) ReplyOrderComment(ctx *jxcontext.Context, vendorOrgCode string, orderComment *model.OrderComment, replyComment string) (err error) {
globals.SugarLogger.Debugf("mtwm ReplyOrderComment, orderComment:%s, replyComment:%s", utils.Format4Output(orderComment, true), replyComment)
if globals.EnableMtwmStoreWrite {
err = api.MtwmAPI.CommentAddReply(orderComment.VendorStoreID, utils.Str2Int64(orderComment.UserCommentID), replyComment)
}
return err
}

View File

@@ -1,35 +0,0 @@
package mtwm
import (
"testing"
"time"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/baseapi/utils"
_ "git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
)
func TestGetOrder(t *testing.T) {
result, err := CurPurchaseHandler.GetOrder("", "33437032333978492")
if err != nil {
t.Fatal(err)
}
t.Log(utils.Format4Output(result, false))
}
func TestGetOrderStatus(t *testing.T) {
result, err := CurPurchaseHandler.GetOrderStatus("", "71884881906304496")
if err != nil {
t.Fatal(err)
}
t.Log(utils.Format4Output(result, false))
}
func TestListOrders(t *testing.T) {
result, err := CurPurchaseHandler.ListOrders(jxcontext.AdminCtx, "", nil, time.Now(), "4626746")
if err != nil {
t.Fatal(err)
}
t.Log(utils.Format4Output(result, false))
}

View File

@@ -1,317 +0,0 @@
package mtwm
import (
"errors"
"math"
"regexp"
"strings"
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/baseapi/utils/errlist"
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
"git.rosy.net.cn/jx-callback/business/jxutils"
"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"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
var (
opTimeErrReg = regexp.MustCompile(`当前配送营业时间为:([\d:~,]*)`)
)
type tEbaiStoreInfo struct {
model.Store
VendorStoreID string `orm:"column(vendor_store_id)"`
RealLastOperator string
EbaiStoreStatus int
SyncStatus int
ProvinceID int `orm:"column(province_id)"`
CityID int `orm:"column(city_id)"`
DistrictID int `orm:"column(district_id)"`
}
func (p *PurchaseHandler) ReadStore(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID string) (retVal *dao.StoreDetail, err error) {
result, err := api.MtwmAPI.PoiGet(vendorStoreID)
if err == nil {
// globals.SugarLogger.Debug(utils.Format4Output(result, false))
retVal = &dao.StoreDetail{
Store: model.Store{
Address: result.Address,
Tel1: result.Phone,
},
}
retVal.OriginalName = result.Name
_, retVal.Name = jxutils.SplitStoreName(retVal.OriginalName, partner.StoreNameSeparator, globals.StoreNameMtwm)
retVal.SetOpTime(openTimeMtwm2JX(result.ShippingTime))
retVal.Status = bizStatusMtwm2JX(result.OpenLevel, result.IsOnline)
tel2 := result.StandbyTel
if tel2 != "" && tel2 != retVal.Tel1 {
retVal.Tel2 = tel2
}
retVal.Lng = int(result.Longitude)
retVal.Lat = int(result.Latitude)
lng := jxutils.IntCoordinate2Standard(retVal.Lng)
lat := jxutils.IntCoordinate2Standard(retVal.Lat)
db := dao.GetDB()
retVal.DistrictCode = api.AutonaviAPI.GetCoordinateDistrictCode(lng, lat)
city, err := dao.GetPlaceByCode(db, result.CityID)
retVal.CityName = city.Name
retVal.CityCode = result.CityID
poiCode := result.AppPoiCode
retVal.VendorStoreID = vendorStoreID
retVal.ID = int(utils.Str2Int64WithDefault(poiCode, 0))
retVal.DeliveryRangeType = model.DeliveryRangeTypePolygon
var deliveryRangeInfo []map[string]interface{}
deliveryRangeInfo, err = api.MtwmAPI.ShippingFetch(poiCode)
if err != nil {
deliveryRangeInfo, err = api.MtwmAPI.ShippingList(poiCode)
}
if err == nil {
if len(deliveryRangeInfo) > 0 {
retVal.DeliveryRange = rangeMtwm2JX(deliveryRangeInfo[0]["area"].(string))
logisticsCode := utils.Interface2String(deliveryRangeInfo[0]["logistics_code"])
if logisticsCode == "" || logisticsCode == mtwmapi.PeiSongTypeSelf {
retVal.DeliveryType = scheduler.StoreDeliveryTypeByStore
} else {
retVal.DeliveryType = scheduler.StoreDeliveryTypeByPlatform
}
}
}
return retVal, nil
}
return nil, err
}
func (p *PurchaseHandler) CreateStore(db *dao.DaoDB, storeID int, userName string) (err error) {
return p.UpdateStore(db, storeID, userName)
}
func (p *PurchaseHandler) CreateStore2(db *dao.DaoDB, storeID int, userName string) (vendorStoreID string, err error) {
return vendorStoreID, err
}
func (p *PurchaseHandler) DeleteStore(db *dao.DaoDB, storeID int, userName string) (err error) {
return err
}
func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName string) (err error) {
var name string
if db == nil {
db = dao.GetDB()
}
storeDetail, err := dao.GetStoreDetail(db, storeID, model.VendorIDMTWM)
if err != nil {
return err
}
errList := errlist.New()
remoteStoreInfo, err := api.MtwmAPI.PoiGet(storeDetail.VendorStoreID)
if err != nil {
return err
}
mergedStoreStatus := jxutils.MergeStoreStatus(storeDetail.Status, storeDetail.VendorStatus)
name = remoteStoreInfo.Name
if storeDetail.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagStoreName) != 0 {
if storeDetail.VendorStoreName != "" {
name = storeDetail.VendorStoreName
}
// else {
// name = jxutils.ComposeStoreName(storeDetail.Store.Name, model.VendorIDMTWM)
// }
}
// openLevel, isOnline := bizStatusJX2Mtwm(mergedStoreStatus)
//TODO 美团暂时不用那个电话
phone := storeDetail.Tel1
// if storeDetail.MarketManPhone != "" {
// phone = storeDetail.MarketManPhone
// } else {
// phone = model.VendorStoreTel
// }
params := map[string]interface{}{
"name": name, //jxutils.ComposeStoreName(storeDetail.Store.Name, model.VendorIDMTWM),
"address": storeDetail.Address, // 美团好像地址也不能改的?
"longitude": jxutils.IntCoordinate2Standard(int(remoteStoreInfo.Longitude)),
"latitude": jxutils.IntCoordinate2Standard(int(remoteStoreInfo.Latitude)),
"phone": phone,
"shipping_fee": remoteStoreInfo.ShippingFee,
"shipping_time": remoteStoreInfo.ShippingTime,
"open_level": remoteStoreInfo.OpenLevel,
"is_online": remoteStoreInfo.IsOnline,
"third_tag_name": remoteStoreInfo.ThirdTagName,
"promotion_info": storeDetail.PromoteInfo,
}
// globals.SugarLogger.Debug(utils.Format4Output(params, false))
if globals.EnableMtwmStoreWrite {
errList.AddErr(api.MtwmAPI.PoiSave(storeDetail.VendorStoreID, params))
}
// PoiSave有时会报错商家已接入美团配送不可修改门店配送相关信息这里放弃信息修改
// if err != nil {
// if utils.IsErrMatch(err, utils.Int2Str(mtwmapi.ErrCodeCanNotModifyStoreDeliveryInfo), nil) {
// globals.SugarLogger.Infof("mtwm UpdateStore vendorStoreID:%s, params:%s failed with err:%v", storeDetail.VendorStoreID, utils.Format4Output(params, true), err)
// if storeDetail.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagStoreStatus) != 0 {
// err = p.UpdateStoreStatus(jxcontext.AdminCtx, storeDetail.VendorOrgCode, storeID, storeDetail.VendorStoreID, mergedStoreStatus)
// } else {
// err = nil
// }
// }
// errList.AddErr(err)
// }
if storeDetail.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagStoreStatus) != 0 {
errList.AddErr(p.UpdateStoreStatus(jxcontext.AdminCtx, storeDetail.VendorOrgCode, storeID, storeDetail.VendorStoreID, mergedStoreStatus))
}
errList.AddErr(p.UpdateStoreOpTime(jxcontext.AdminCtx, storeDetail.VendorOrgCode, storeID, storeDetail.VendorStoreID, storeDetail.GetOpTimeList()))
errList.AddErr(p.UpdateStoreBoxFee(jxcontext.AdminCtx, storeDetail.VendorOrgCode, storeID, storeDetail.VendorStoreID))
return errList.GetErrListAsOne()
}
func (p *PurchaseHandler) RefreshAllStoresID(ctx *jxcontext.Context, parentTask tasksch.ITask, isAsync bool) (hint string, err error) {
return "", errors.New("美团外卖不支持此操作")
}
func (p *PurchaseHandler) onStoreStatusChanged(msg *mtwmapi.CallbackMsg) (response *mtwmapi.CallbackResponse) {
var err error
poiStatus := int(utils.Str2Int64(msg.FormData.Get("poi_status")))
vendorStoreID := msg.FormData.Get("app_poi_code")
storeStatus := 0
if poiStatus == mtwmapi.MsgPoiStatusOpened {
storeStatus = model.StoreStatusOpened
} else if poiStatus == mtwmapi.MsgPoiStatusClosed {
storeStatus = model.StoreStatusClosed
} else if poiStatus == mtwmapi.MsgPoiStatusOffline {
storeStatus = model.StoreStatusDisabled
} else {
storeStatus, err = p.GetStoreStatus(jxcontext.AdminCtx, "", 0, vendorStoreID)
}
if err == nil {
err = partner.CurStoreManager.OnStoreStatusChanged(vendorStoreID, model.VendorIDMTWM, storeStatus)
}
response = mtwmapi.Err2CallbackResponse(err, "")
return response
}
func (p *PurchaseHandler) GetStoreStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string) (storeStatus int, err error) {
result, err := api.MtwmAPI.PoiGet(vendorStoreID)
if err == nil {
return bizStatusMtwm2JX(result.OpenLevel, result.IsOnline), nil
}
return 0, err
}
func (p *PurchaseHandler) EnableAutoAcceptOrder(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, isSetEnable bool) (err error) {
return err
}
func (c *PurchaseHandler) UpdateStoreStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, status int) (err error) {
openLevel, isOnline := bizStatusJX2Mtwm(status)
if globals.EnableMtwmStoreWrite {
if isOnline != mtwmapi.PoiStatusOnline {
err = api.MtwmAPI.PoiOffline(vendorStoreID)
} else {
if err = api.MtwmAPI.PoiOnline(vendorStoreID); err == nil { // 这个函数成功返回也并不表示上线成功。。。
remoteStoreInfo, err2 := api.MtwmAPI.PoiGet(vendorStoreID)
if err = err2; err != nil {
return err
}
if remoteStoreInfo.IsOnline == mtwmapi.PoiStatusOnline {
if openLevel == mtwmapi.PoiOpenLevelHaveRest {
err = api.MtwmAPI.PoiClose(vendorStoreID)
} else {
err = api.MtwmAPI.PoiOpen(vendorStoreID)
}
} else {
err = errors.New("门店还未上线,不能修改营业状态")
}
}
}
}
return err
}
func errOpStr2Int16(str string) []int16 {
list := strings.Split(str, "~")
if len(list) >= 2 {
return []int16{jxutils.StrTime2JxOperationTime(list[0]+":00", 0), jxutils.StrTime2JxOperationTime(list[1]+":00", 2359)}
}
return nil
}
func getOpTimeListFromErr(err error) (opTimeList []int16) {
if errExt, ok := err.(*utils.ErrorWithCode); ok && errExt.IntCode() == mtwmapi.ErrCodeOpFailed {
if result := opTimeErrReg.FindStringSubmatch(errExt.ErrMsg()); len(result) >= 2 {
timeStrList := strings.Split(result[1], ",")
for _, v := range timeStrList {
v = utils.TrimBlankChar(v)
if len(v) == len("00:00~02:00") {
opTimeList = append(opTimeList, errOpStr2Int16(v)...)
}
}
}
}
return opTimeList
}
// 此函数只是简单实现,不支持区间切分,只做单一区间限制
func constrainOpTimeList(opTimeList, validOpTimeList []int16) (newOpTimeList []int16) {
for k := 0; k < len(opTimeList); k += 2 {
beginTime := opTimeList[k]
endTime := opTimeList[k+1]
for k2 := 0; k2 < len(validOpTimeList); k2 += 2 {
beginTime2 := validOpTimeList[k2]
endTime2 := validOpTimeList[k2+1]
if beginTime >= beginTime2 && beginTime <= endTime2 {
newOpTimeList = append(newOpTimeList, beginTime)
newOpTimeList = append(newOpTimeList, int16(math.Min(float64(endTime), float64(endTime2))))
} else if beginTime2 >= beginTime && beginTime2 <= endTime {
newOpTimeList = append(newOpTimeList, beginTime2)
newOpTimeList = append(newOpTimeList, int16(math.Min(float64(endTime), float64(endTime2))))
}
}
}
return newOpTimeList
}
func (c *PurchaseHandler) UpdateStoreOpTime(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, opTimeList []int16) (err error) {
shippingTime := openTimeJX2Mtwm(opTimeList)
if globals.EnableMtwmStoreWrite {
err = api.MtwmAPI.PoiShipTimeUpdate(vendorStoreID, shippingTime)
if err != nil {
shippingTime = ""
if validOpTimeList := getOpTimeListFromErr(err); len(validOpTimeList) > 0 {
shippingTime = openTimeJX2Mtwm(constrainOpTimeList(opTimeList, validOpTimeList))
}
if shippingTime != "" {
err = api.MtwmAPI.PoiShipTimeUpdate(vendorStoreID, shippingTime)
}
}
}
return err
}
func (c *PurchaseHandler) GetAllStoresVendorID(ctx *jxcontext.Context, vendorOrgCode string) (vendorStoreIDs []string, err error) {
vendorStoreIDs, err = api.MtwmAPI.PoiGetIDs()
return vendorStoreIDs, err
}
func (c *PurchaseHandler) UpdateStoreCustomID(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID string, storeID int64) (err error) {
return err
}
func (c *PurchaseHandler) UpdateStoreBoxFee(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string) (err error) {
boxFee, err := dao.GetSysConfigAsInt64(dao.GetDB(), model.ConfigSysMtwmBoxFee)
if err == nil {
if globals.EnableMtwmStoreWrite && globals.IsProductEnv() {
err = api.MtwmAPI.PackagePriceUpdate(vendorStoreID, 1, int(boxFee))
}
}
return err
}

View File

@@ -1,676 +0,0 @@
package mtwm
import (
"encoding/json"
"regexp"
"strings"
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"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"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/business/partner/putils"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
const (
updateTypeStock = iota
updateTypeStatus
updateTypePrice
)
const (
defVendorCatID = 200001903 // 生菜
specialStoreID = "8171010"
// specialStoreID = "2523687"
)
var (
sensitiveWordRegexp = regexp.MustCompile(`包含敏感词:(\[.*\])`)
)
func (p *PurchaseHandler) GetStoreSkusBatchSize(funcID int) (batchSize int) {
switch funcID {
case partner.FuncUpdateStoreSkusStock, partner.FuncUpdateStoreSkusStatus, partner.FuncUpdateStoreSkusPrice:
batchSize = mtwmapi.MaxStoreSkuBatchSize
case partner.FuncDeleteStoreSkus:
batchSize = mtwmapi.MaxBatchDeleteSize
case partner.FuncCreateStoreSkus:
batchSize = 1 // 可考虑用批量操作
case partner.FuncUpdateStoreSkus:
batchSize = 1 // mtwmapi.MaxStoreSkuBatchSize
case partner.FuncGetStoreSkusFullInfo:
batchSize = 1
case partner.FuncCreateActs:
batchSize = mtwmapi.MaxRetailDiscountCreateBatchSize
case partner.FuncCancelActs:
batchSize = mtwmapi.MaxRetailDiscountDeleteBatchSize
}
return batchSize
}
// 门店分类
func (p *PurchaseHandler) GetStoreAllCategories(ctx *jxcontext.Context, storeID int, vendorStoreID string) (cats []*partner.BareCategoryInfo, err error) {
remoteCats, err := api.MtwmAPI.RetailCatList(vendorStoreID)
if err == nil {
cats = convertVendorCatList(remoteCats)
}
return cats, err
}
func convertVendorCatList(remoteCats []*mtwmapi.RetailCategoryInfo) (cats []*partner.BareCategoryInfo) {
for _, rCat := range remoteCats {
cat := &partner.BareCategoryInfo{
VendorCatID: rCat.Code,
Name: rCat.Name,
Level: rCat.Level,
Seq: rCat.Sequence,
Children: convertVendorCatList(rCat.Children),
}
if cat.VendorCatID == "" {
cat.VendorCatID = rCat.Name
}
cats = append(cats, cat)
}
return cats
}
func (p *PurchaseHandler) IsErrCategoryExist(err error) (isExist bool) {
return mtwmapi.IsErrCategoryExist(err)
}
func (p *PurchaseHandler) IsErrCategoryNotExist(err error) (isNotExist bool) {
return mtwmapi.IsErrCategoryNotExist(err)
}
func catCode2Str(catCode int) (catCodeStr string) {
if catCode > 0 {
catCodeStr = utils.Int2Str(catCode)
}
return catCodeStr
}
func tryCatName2Code(originName string) (catCodeStr string) {
if intValue := utils.Str2Int64WithDefault(originName, 0); intValue > 0 {
catCodeStr = utils.Int64ToStr(intValue)
if catCodeStr != originName {
catCodeStr = ""
}
}
return catCodeStr
}
func (p *PurchaseHandler) CreateStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeCat *dao.SkuStoreCatInfo) (err error) {
level := 1
if storeCat.ParentCatName != "" {
level = 2
}
originName := ""
catName := storeCat.Name
catCode := storeCat.ID
subCatName := ""
subCatCode := 0
if storeCat.CatSyncStatus&model.SyncFlagNewMask == 0 {
// 修改一级分类
originName = storeCat.VendorCatID
}
if level == 2 { // 二级分类
// 创建二级分类
originName = storeCat.ParentVendorCatID
catName = storeCat.ParentCatName
catCode = storeCat.ParentID
subCatName = storeCat.Name
subCatCode = storeCat.ID
if storeCat.CatSyncStatus&model.SyncFlagNewMask == 0 {
// 修改二级分类
originName = storeCat.VendorCatID
catName = storeCat.Name
catCode = storeCat.ID
subCatName = ""
subCatCode = 0
}
}
if catName == "" {
panic("catName is empty")
}
catName = utils.FilterEmoji(catName)
subCatName = utils.FilterEmoji(subCatName)
globals.SugarLogger.Debugf("mtwm CreateStoreCategory vendorStoreID:%s, originName:%s, catCode:%d, catName:%s, subCatCode:%d, subCatName:%s, seq:%d",
vendorStoreID, originName, catCode, catName, subCatCode, subCatName, storeCat.Seq)
if globals.EnableMtwmStoreWrite {
// err = api.MtwmAPI.RetailCatUpdate2(vendorStoreID, tryCatName2Code(originName), originName, catCode2Str(catCode), catName, catCode2Str(subCatCode), subCatName, storeCat.Seq)
param4Update := &mtwmapi.Param4UpdateCat{
CategoryCodeOrigin: tryCatName2Code(originName),
CategoryNameOrigin: originName,
CategoryCode: catCode2Str(catCode),
SecondaryCategoryCode: catCode2Str(subCatCode),
SecondaryCategoryName: subCatName,
Sequence: storeCat.Seq,
}
err = api.MtwmAPI.RetailCatUpdate(vendorStoreID, catName, param4Update)
if storeCat.CatSyncStatus&model.SyncFlagNewMask == 0 && // 修改分类名,但分类不存在
p.IsErrCategoryNotExist(err) && originName != "" {
storeCat.CatSyncStatus |= model.SyncFlagNewMask
err = p.CreateStoreCategory(ctx, storeID, vendorStoreID, storeCat)
}
}
if err == nil {
// storeCat.VendorCatID = utils.FilterEmoji(storeCat.Name)
storeCat.VendorCatID = utils.Int2Str(storeCat.ID)
}
return err
}
func (p *PurchaseHandler) UpdateStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeCat *dao.SkuStoreCatInfo) (err error) {
return p.CreateStoreCategory(ctx, storeID, vendorStoreID, storeCat)
}
func (p *PurchaseHandler) DeleteStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID, vendorCatID string, level int) (err error) {
if false {
if globals.EnableMtwmStoreWrite {
err = api.MtwmAPI.RetailCatDelete(vendorStoreID, tryCatName2Code(vendorCatID), vendorCatID)
}
} else {
var catCodes []string
if catCode := tryCatName2Code(vendorCatID); catCode != "" {
catCodes = []string{catCode}
}
if globals.EnableMtwmStoreWrite {
if level == 1 {
err = api.MtwmAPI.RetailCatSkuBatchDelete2(ctx.GetTrackInfo(), vendorStoreID, catCodes, []string{vendorCatID}, nil, nil, nil)
} else {
err = api.MtwmAPI.RetailCatSkuBatchDelete2(ctx.GetTrackInfo(), vendorStoreID, nil, nil, catCodes, []string{vendorCatID}, nil)
}
}
}
return err
}
// 门店商品
// 多门店平台不需要实现这个接口
func (p *PurchaseHandler) IsErrSkuExist(err error) (isExist bool) {
return false
}
func (p *PurchaseHandler) IsErrSkuNotExist(err error) (isNotExist bool) {
return mtwmapi.IsErrSkuNotExist(err)
}
// func duplicateStoreSkuList(storeSkuList []*dao.StoreSkuSyncInfo, index int) (newStoreSkuList []*dao.StoreSkuSyncInfo) {
// newStoreSkuList = make([]*dao.StoreSkuSyncInfo, len(storeSkuList))
// for k, v := range storeSkuList {
// tmp := *v
// tmp.SkuName = fmt.Sprintf("%s.%d", tmp.SkuName, index)
// tmp.SkuID = index*1000000 + tmp.SkuID
// newStoreSkuList[k] = &tmp
// }
// return newStoreSkuList
// }
func (p *PurchaseHandler) UpdateStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*dao.StoreSkuSyncInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
failedList, err = p.createOrUpdateStoreSkus(ctx, storeID, vendorStoreID, storeSkuList, false)
// if err == nil && vendorStoreID == specialStoreID {
// for i := 0; i < 2; i++ {
// p.createOrUpdateStoreSkus(ctx, storeID, vendorStoreID, duplicateStoreSkuList(storeSkuList, i+1), true)
// }
// }
return failedList, err
}
func (p *PurchaseHandler) CreateStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*dao.StoreSkuSyncInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
failedList, err = p.createOrUpdateStoreSkus(ctx, storeID, vendorStoreID, storeSkuList, true)
// if err == nil && vendorStoreID == specialStoreID {
// for i := 0; i < 2; i++ {
// p.createOrUpdateStoreSkus(ctx, storeID, vendorStoreID, duplicateStoreSkuList(storeSkuList, i+1), true)
// }
// }
return failedList, err
}
// 对于多门店平台来说storeSkuList中只有SkuID与VendorSkuID有意义
func (p *PurchaseHandler) createOrUpdateStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*dao.StoreSkuSyncInfo, isCreate bool) (failedList []*partner.StoreSkuInfoWithErr, err error) {
var syncType string
foodDataList := make([]map[string]interface{}, len(storeSkuList))
if isCreate {
syncType = "创建商品"
} else {
syncType = "更新商品"
}
for i, storeSku := range storeSkuList {
isNeedUpdatePrice := isCreate //storeSku.SkuSyncStatus&(model.SyncFlagPriceMask|model.SyncFlagNewMask) != 0
foodData := make(map[string]interface{})
foodDataList[i] = foodData
foodData[mtwmapi.KeyAppFoodCode] = utils.Int2Str(storeSku.SkuID)
skus := []map[string]interface{}{
map[string]interface{}{
"sku_id": foodData[mtwmapi.KeyAppFoodCode],
},
}
foodData["skus"] = skus
foodData["name"] = utils.LimitUTF8StringLen(utils.FilterEmoji(storeSku.SkuName), mtwmapi.MaxSkuNameCharCount)
foodData["description"] = storeSku.Comment
if isNeedUpdatePrice {
foodData["price"] = jxutils.IntPrice2Standard(storeSku.VendorPrice)
}
if storeSku.MinOrderCount != 0 {
foodData["min_order_count"] = storeSku.MinOrderCount
} else {
foodData["min_order_count"] = 1
}
foodData["unit"] = storeSku.Unit
attr := switchAttr(storeSku.VendorVendorCatID)
if attr != "" {
foodData["common_attr_value"] = attr
}
catCode := tryCatName2Code(storeSku.VendorCatID)
if catCode != "" {
foodData["category_code"] = catCode
} else {
foodData["category_name"] = storeSku.VendorCatID
}
foodData["is_sold_out"] = skuStatusJX2Mtwm(storeSku.MergedStatus)
if true { // vendorStoreID == specialStoreID {
img2 := storeSku.Img2
if img2 == "" {
img2 = storeSku.Img
}
if storeSku.ImgMix != "" {
foodData["picture"] = strings.Join(jxutils.BatchString2Slice(storeSku.ImgMix, img2, storeSku.ImgMix, storeSku.ImgMix, storeSku.ImgMix), ",")
} else {
foodData["picture"] = strings.Join(jxutils.BatchString2Slice(storeSku.Img, img2, storeSku.Img, storeSku.Img, storeSku.Img), ",")
}
} else {
foodData["picture"] = strings.Join(jxutils.BatchString2Slice(storeSku.Img, storeSku.Img2), ",")
}
if storeSku.DescImg != "" {
foodData["picture_contents"] = storeSku.DescImg
}
foodData["sequence"] = storeSku.GetSeq()
if storeSku.VendorVendorCatID != 0 {
foodData["tag_id"] = utils.Int64ToStr(storeSku.VendorVendorCatID)
} else {
// foodData["tag_id"] = utils.Int64ToStr(defVendorCatID)
}
skus[0]["spec"] = jxutils.ComposeSkuSpec(storeSku.SpecQuality, storeSku.SpecUnit)
if isNeedUpdatePrice {
skus[0]["price"] = foodData["price"]
}
skus[0]["stock"] = stockCount2Mtwm(model.MaxStoreSkuStockQty)
if storeSku.Upc != "" {
skus[0]["upc"] = storeSku.Upc
}
skus[0]["ladder_box_num"] = storeSku.LadderBoxNum
skus[0]["ladder_box_price"] = jxutils.IntPrice2Standard(int64(storeSku.LadderBoxPrice))
if foodData["tag_id"] != nil {
skus[0]["weight"] = storeSku.Weight // weight字段仅限服饰鞋帽、美妆、日用品、母婴、生鲜果蔬、生活超市下的便利店/超市门店品类的商家使用
}
}
if globals.EnableMtwmStoreWrite {
if len(foodDataList) == 1 {
foodDataList[0]["skus"] = string(utils.MustMarshal(foodDataList[0]["skus"]))
err = api.MtwmAPI.RetailInitData(ctx.GetTrackInfo(), vendorStoreID, utils.Int2Str(storeSkuList[0].SkuID), foodDataList[0])
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDMTWM], syncType)
} else if len(foodDataList) > 0 {
failedFoodList, err2 := api.MtwmAPI.RetailBatchInitData(ctx.GetTrackInfo(), vendorStoreID, foodDataList)
if err = err2; err == nil {
if err = putils.GenPartialFailedErr(failedFoodList, len(failedFoodList)); err != nil {
failedList = SelectStoreSkuListByFoodList(storeSkuList, failedFoodList, storeID, model.VendorChineseNames[model.VendorIDMTWM], syncType)
// successList = putils.UnselectStoreSkuSyncListByVendorSkuIDs(storeSkuList, getAppFoodCodeList(failedFoodList))
}
} else if err2 != nil && len(failedFoodList) == 0 {
if errExt, ok := err2.(*utils.ErrorWithCode); ok {
err = utils.UnmarshalUseNumber([]byte(errExt.ErrMsg()), &failedFoodList)
failedList = SelectStoreSkuListByFoodList(storeSkuList, failedFoodList, storeID, model.VendorChineseNames[model.VendorIDMTWM], syncType)
}
err = nil
}
}
}
for _, storeSku := range storeSkuList {
storeSku.VendorSkuID = utils.Int2Str(storeSku.SkuID)
}
return failedList, err
}
func getAppFoodCodeList(l []*mtwmapi.AppFoodResult) (vendorSkuIDs []string) {
if len(l) > 0 {
vendorSkuIDs = make([]string, len(l))
for k, v := range l {
vendorSkuIDs[k] = v.AppFoodCode
}
}
return vendorSkuIDs
}
func (p *PurchaseHandler) DeleteStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
if globals.EnableMtwmStoreWrite {
if len(storeSkuList) == 1 {
err = api.MtwmAPI.RetailDelete(ctx.GetTrackInfo(), vendorStoreID, storeSkuList[0].VendorSkuID)
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDMTWM], "删除商品")
} else {
// todo 部分失败
err = api.MtwmAPI.RetailCatSkuBatchDelete2(ctx.GetTrackInfo(), vendorStoreID, nil, nil, nil, nil, partner.BareStoreSkuInfoList(storeSkuList).GetVendorSkuIDList())
if err != nil {
if errExt, ok := err.(*utils.ErrorWithCode); ok {
myMap := make(map[string][]*mtwmapi.AppFoodResult)
json.Unmarshal([]byte(errExt.ErrMsg()), &myMap)
failedList = SelectStoreSkuListByFoodList(storeSkuList, myMap["retail_error_list"], storeID, model.VendorChineseNames[model.VendorIDMTWM], "批量删除商品")
}
}
err = nil
}
}
return failedList, err
}
func switchAttr(vendorCatID int64) (attrs string) {
switch vendorCatID {
case 200002727:
return mtwmapi.MtwmSkuAttr200002727
case 200001555:
return mtwmapi.MtwmSkuAttr200001555
case 200002728:
return mtwmapi.MtwmSkuAttr200002728
case 200001519, 200000592:
return mtwmapi.MtwmSkuAttr200000592
case 200002704, 200002731:
return mtwmapi.MtwmSkuAttr200002731
case 200002716:
return mtwmapi.MtwmSkuAttr200002716
case 200002667, 200002713, 200002670:
return mtwmapi.MtwmSkuAttr200002670
case 200002680:
return mtwmapi.MtwmSkuAttr200002680
default:
return ""
}
return attrs
}
func stockCount2Mtwm(stock int) (mtwmStock string) {
return utils.Int2Str(stock)
}
func storeSku2Mtwm(storeSkuList []*partner.StoreSkuInfo, updateType int) (skuList []*mtwmapi.BareStoreFoodInfo) {
for _, storeSku := range storeSkuList {
skuInfo := &mtwmapi.BareStoreFoodInfo{
AppFoodCode: storeSku.VendorSkuID,
Skus: []*mtwmapi.BareStoreSkuInfo{
&mtwmapi.BareStoreSkuInfo{
SkuID: storeSku.VendorSkuID,
},
},
}
if updateType == updateTypeStock {
skuInfo.Skus[0].Stock = stockCount2Mtwm(storeSku.Stock)
} else if updateType == updateTypePrice {
skuInfo.Skus[0].Price = jxutils.IntPrice2StandardString(storeSku.VendorPrice)
} else {
skuInfo.Skus = nil
}
skuList = append(skuList, skuInfo)
}
return skuList
}
func (p *PurchaseHandler) UpdateStoreSkusStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo, status int) (failedList []*partner.StoreSkuInfoWithErr, err error) {
skuList := storeSku2Mtwm(storeSkuList, updateTypeStatus)
mtwmStatus := skuStatusJX2Mtwm(status)
if globals.EnableMtwmStoreWrite {
failedFoodList, err2 := api.MtwmAPI.RetailSellStatus(ctx.GetTrackInfo(), vendorStoreID, skuList, mtwmStatus)
if err = err2; err == nil {
if len(failedFoodList) > 0 {
failedList = SelectStoreSkuListByFoodList(storeSkuList, failedFoodList, storeID, model.VendorChineseNames[model.VendorIDMTWM], "更新商品状态")
// successList = putils.UnselectStoreSkuListByVendorSkuIDs(storeSkuList, getAppFoodCodeList(failedFoodList))
}
} else if err2 != nil && len(failedFoodList) == 0 {
if errExt, ok := err2.(*utils.ErrorWithCode); ok {
err = utils.UnmarshalUseNumber([]byte(errExt.ErrMsg()), &failedFoodList)
failedList = SelectStoreSkuListByFoodList(storeSkuList, failedFoodList, storeID, model.VendorChineseNames[model.VendorIDMTWM], "更新商品状态")
}
err = nil
}
}
return failedList, err
}
func (p *PurchaseHandler) UpdateStoreSkusPrice(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
priceList := storeSku2Mtwm(storeSkuList, updateTypePrice)
if globals.EnableMtwmStoreWrite {
failedFoodList, err2 := api.MtwmAPI.RetailSkuPrice(ctx.GetTrackInfo(), vendorStoreID, priceList)
if err = err2; err == nil {
if len(failedFoodList) > 0 {
failedList = SelectStoreSkuListByFoodList(storeSkuList, failedFoodList, storeID, model.VendorChineseNames[model.VendorIDMTWM], "更新商品价格")
}
} else if err2 != nil && len(failedFoodList) == 0 {
if errExt, ok := err2.(*utils.ErrorWithCode); ok {
err = utils.UnmarshalUseNumber([]byte(errExt.ErrMsg()), &failedFoodList)
failedList = SelectStoreSkuListByFoodList(storeSkuList, failedFoodList, storeID, model.VendorChineseNames[model.VendorIDMTWM], "更新商品价格")
}
err = nil
}
}
return failedList, err
}
func (p *PurchaseHandler) UpdateStoreSkusStock(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
stockList := storeSku2Mtwm(storeSkuList, updateTypeStock)
if globals.EnableMtwmStoreWrite {
failedFoodList, err2 := api.MtwmAPI.RetailSkuStock(ctx.GetTrackInfo(), vendorStoreID, stockList)
if err = err2; err == nil {
if len(failedFoodList) > 0 {
failedList = SelectStoreSkuListByFoodList(storeSkuList, failedFoodList, storeID, model.VendorChineseNames[model.VendorIDMTWM], "更新商品库存")
}
//if err = putils.GenPartialFailedErr(failedFoodList, len(failedFoodList)); err != nil {
// successList = putils.UnselectStoreSkuListByVendorSkuIDs(storeSkuList, getAppFoodCodeList(failedFoodList))
// }
} else if err2 != nil && len(failedFoodList) == 0 {
if errExt, ok := err2.(*utils.ErrorWithCode); ok {
err = utils.UnmarshalUseNumber([]byte(errExt.ErrMsg()), &failedFoodList)
failedList = SelectStoreSkuListByFoodList(storeSkuList, failedFoodList, storeID, model.VendorChineseNames[model.VendorIDMTWM], "更新商品库存")
}
err = nil
}
}
return failedList, err
}
func mtwmSkuStatus2Jx(mtwmSkuStatus int) (jxSkuStatus int) {
if mtwmSkuStatus == mtwmapi.SellStatusOnline {
jxSkuStatus = model.SkuStatusNormal
} else {
jxSkuStatus = model.SkuStatusDontSale
}
return jxSkuStatus
}
func (p *PurchaseHandler) GetStoreSkusFullInfo(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (skuNameList []*partner.SkuNameInfo, err error) {
if len(storeSkuList) == 1 {
skuInfo, err := api.MtwmAPI.RetailGet(vendorStoreID, utils.Int2Str(storeSkuList[0].SkuID))
if err != nil {
return nil, err
}
if skuName := vendorSku2Jx(skuInfo); skuName != nil {
skuNameList = append(skuNameList, skuName)
}
} else {
var storeSkuMap map[string]*partner.StoreSkuInfo
if storeSkuList != nil {
storeSkuMap = putils.StoreSkuList2MapByVendorSkuID(storeSkuList)
}
for {
// todo 待优化获取速度
result, err := api.MtwmAPI.RetailList(vendorStoreID, len(skuNameList), mtwmapi.GeneralMaxLimit)
if err != nil {
return nil, err
}
if storeSkuMap == nil {
skuNameList = append(skuNameList, vendorSkuList2Jx(result)...)
} else {
for _, v := range result {
if storeSkuMap[v.AppFoodCode] != nil {
if skuName := vendorSku2Jx(v); skuName != nil {
skuNameList = append(skuNameList, skuName)
}
}
}
}
if len(result) < mtwmapi.GeneralMaxLimit {
break
}
}
}
return skuNameList, err
}
func vendorSku2Jx(appFood *mtwmapi.AppFood) (skuName *partner.SkuNameInfo) {
if len(appFood.SkuList) == 0 {
globals.SugarLogger.Warnf("vendorSku2Jx, strange appFood:%s", utils.Format4Output(appFood, true))
return nil
}
prefix, name, comment, specUnit, unit, specQuality := jxutils.SplitSkuName(appFood.Name)
vendorSku := appFood.SkuList[0]
weight := int(utils.Str2Int64WithDefault(vendorSku.Weight, 0))
if weight <= 0 {
weight = jxutils.FormatSkuWeight(specQuality, specUnit)
}
skuID := int(utils.Str2Int64WithDefault(vendorSku.SkuID, 0))
skuName = &partner.SkuNameInfo{
NameID: int(utils.Str2Int64WithDefault(appFood.AppFoodCode, 0)),
VendorNameID: appFood.AppFoodCode,
Prefix: prefix,
Name: name,
Unit: unit,
SkuList: []*partner.SkuInfo{
&partner.SkuInfo{
StoreSkuInfo: partner.StoreSkuInfo{
VendorSkuID: vendorSku.SkuID,
SkuID: skuID,
IsSpecialty: appFood.IsSpecialty,
Stock: int(utils.Str2Int64WithDefault(vendorSku.Stock, partner.UnlimitedStoreSkuStock)),
VendorPrice: jxutils.StandardPrice2Int(utils.Str2Float64WithDefault(vendorSku.Price, 0)),
Status: mtwmSkuStatus2Jx(appFood.IsSoldOut),
},
SkuName: appFood.Name,
Comment: comment,
SpecQuality: float64(specQuality),
SpecUnit: specUnit,
Weight: weight,
},
},
PictureList: appFood.PictureList,
}
if appFood.CategoryName != "" {
// todo, 因为当前我们用的是分类名操作这种方式所以要返回分类名而不是分类code
skuName.VendorCatIDList = []string{appFood.CategoryName}
if appFood.SecondaryCategoryName != "" {
skuName.VendorCatIDList = append(skuName.VendorCatIDList, appFood.SecondaryCategoryName)
}
}
return skuName
}
func vendorSkuList2Jx(appFoodList []*mtwmapi.AppFood) (skuNameList []*partner.SkuNameInfo) {
for _, appFood := range appFoodList {
if skuName := vendorSku2Jx(appFood); skuName != nil {
skuNameList = append(skuNameList, skuName)
}
}
return skuNameList
}
func (p *PurchaseHandler) GetSensitiveWordRegexp() *regexp.Regexp {
return sensitiveWordRegexp
}
//美团api返回
func SelectStoreSkuListByFoodList(storeSkuList interface{}, foodList []*mtwmapi.AppFoodResult, storeID int, vendorName, syncType string) (selectedStoreSkuList []*partner.StoreSkuInfoWithErr) {
foodMap := make(map[string]string)
if len(foodList) > 0 {
for _, v := range foodList {
foodMap[v.AppFoodCode] = v.ErrorMsg
}
if storeSkuLists, ok := storeSkuList.([]*partner.StoreSkuInfo); ok {
for _, v := range storeSkuLists {
if foodMap[v.VendorSkuID] != "" {
foodFailed := &partner.StoreSkuInfoWithErr{
StoreSkuInfo: v,
ErrMsg: foodMap[v.VendorSkuID],
StoreID: storeID,
VendoreName: vendorName,
SyncType: syncType,
}
selectedStoreSkuList = append(selectedStoreSkuList, foodFailed)
}
}
}
if storeSkuLists, ok := storeSkuList.([]*dao.StoreSkuSyncInfo); ok {
for _, v := range storeSkuLists {
if foodMap[v.VendorSkuID] != "" {
storeSkuInfo := &partner.StoreSkuInfo{
SkuID: v.SkuID,
VendorSkuID: v.VendorSkuID,
NameID: v.NameID,
VendorNameID: v.VendorNameID,
VendorPrice: v.VendorPrice,
Status: v.Status,
}
foodFailed := &partner.StoreSkuInfoWithErr{
StoreSkuInfo: storeSkuInfo,
ErrMsg: foodMap[v.VendorSkuID],
StoreID: storeID,
VendoreName: vendorName,
SyncType: syncType,
}
selectedStoreSkuList = append(selectedStoreSkuList, foodFailed)
}
}
}
}
return selectedStoreSkuList
}
func (p *PurchaseHandler) CreateStoreSkusAct(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
actStoreSkuList := putils.StoreSku2ActStoreSku(model.SyncFlagNewMask, vendorStoreID, storeSkuList)
failedList, err = createOneShopAct(putils.GetFixDirectDownAct(vendorOrgCode, storeID, 0), vendorStoreID, actStoreSkuList)
storeSkuMap := putils.StoreSkuList2MapBySkuID(storeSkuList)
for _, v := range actStoreSkuList {
storeSkuMap[v.SkuID].VendorActID = v.VendorActID
}
return failedList, err
}
func (p *PurchaseHandler) CancelActs(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
return cancelOneShopAct(putils.GetFixDirectDownAct(vendorOrgCode, storeID, 0), vendorStoreID, putils.StoreSku2ActStoreSku(model.SyncFlagDeletedMask, vendorStoreID, storeSkuList))
}
func (p *PurchaseHandler) UpdateStoreSkusSpecTag(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (err error) {
var foodDataList = []map[string]interface{}{}
for _, v := range storeSkuList {
var foodData = make(map[string]interface{})
if v.IsSpecialty != 0 && v.IsSpecialty == -1 {
v.IsSpecialty = 0
}
foodData["is_specialty"] = v.IsSpecialty
foodData["app_food_code"] = v.SkuID
foodDataList = append(foodDataList, foodData)
}
if globals.EnableMtwmStoreWrite {
if len(foodDataList) == 1 {
err = api.MtwmAPI.RetailInitData(ctx.GetTrackInfo(), vendorStoreID, utils.Int2Str(storeSkuList[0].SkuID), foodDataList[0])
} else if len(foodDataList) > 0 {
_, err = api.MtwmAPI.RetailBatchInitData(ctx.GetTrackInfo(), vendorStoreID, foodDataList)
}
}
return err
}

View File

@@ -1,64 +0,0 @@
package mtwm
import (
"testing"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/partner"
// _ "git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
)
func TestGetStoreSkusFullInfo(t *testing.T) {
skuNameList, err := CurPurchaseHandler.GetStoreSkusFullInfo(jxcontext.AdminCtx, nil, 2, "2523687", nil)
if err != nil {
t.Fatal(err)
}
t.Log(utils.Format4Output(skuNameList, false))
t.Log(len(skuNameList))
}
func TestGetStoreSkusBareInfo(t *testing.T) {
storeSkuList, err := CurPurchaseHandler.GetStoreSkusBareInfo(jxcontext.AdminCtx, "", nil, 2, "2523687", []*partner.StoreSkuInfo{
&partner.StoreSkuInfo{
SkuID: 969,
},
&partner.StoreSkuInfo{
SkuID: 1306,
},
})
if err != nil {
t.Fatal(err.Error())
}
t.Log(utils.Format4Output(storeSkuList, false))
t.Log(len(storeSkuList))
}
func TestDeleteStoreAllSkus(t *testing.T) {
err := CurPurchaseHandler.DeleteStoreAllSkus(jxcontext.AdminCtx, nil, 2, "2523687", true)
if err != nil {
t.Fatal(err)
}
}
func TestDeleteStoreAllCategories(t *testing.T) {
err := CurPurchaseHandler.DeleteStoreAllCategories(jxcontext.AdminCtx, nil, 2, "2523687", true)
if err != nil {
t.Fatal(err)
}
}
func TestGetStoreCategory(t *testing.T) {
_, err := CurPurchaseHandler.GetStoreCategory(jxcontext.AdminCtx, 2, "2523687", "不存在的分类")
if err == nil {
t.Fatal("应该找不到这个分类")
}
catName := "小月饼"
cat, err := CurPurchaseHandler.GetStoreCategory(jxcontext.AdminCtx, 2, "2523687", catName)
if err != nil {
t.Fatal(err)
} else if cat.Name != catName {
t.Fatal("没有找到正确的商家分类")
}
t.Log(utils.Format4Output(cat, false))
}

View File

@@ -1,46 +0,0 @@
package mtwm
import (
"testing"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
// _ "git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
)
// func TestSyncStoreCategory(t *testing.T) {
// hint, err := CurPurchaseHandler.SyncStoreCategory(jxcontext.AdminCtx, nil, testShopID, false)
// if err != nil {
// t.Fatal(err)
// }
// t.Log(hint)
// }
// func TestSyncLocalStoreCategory(t *testing.T) {
// hint, err := CurPurchaseHandler.SyncLocalStoreCategory(jxcontext.AdminCtx, nil, testShopID, true, nil)
// if err != nil {
// t.Fatal(err)
// }
// t.Log(hint)
// }
// func TestSyncStoreSkus(t *testing.T) {
// hint, err := CurPurchaseHandler.SyncStoreSkus(jxcontext.AdminCtx, nil, testShopID, nil, false, true)
// if err != nil {
// t.Fatal(err)
// }
// t.Log(hint)
// }
func TestDeleteRemoteSkus(t *testing.T) {
err := CurPurchaseHandler.DeleteStoreAllSkus(jxcontext.AdminCtx, nil, testShopID, testShopVendorID, true)
if err != nil {
t.Fatal(err)
}
}
func TestDeleteRemoteCategories(t *testing.T) {
err := CurPurchaseHandler.DeleteStoreAllCategories(jxcontext.AdminCtx, nil, testShopID, testShopVendorID, true)
if err != nil {
t.Fatal(err)
}
}

View File

@@ -1,45 +0,0 @@
package mtwm
import (
"testing"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
"git.rosy.net.cn/baseapi/utils"
// _ "git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
)
func TestReadStore(t *testing.T) {
store, err := CurPurchaseHandler.ReadStore(jxcontext.AdminCtx, "", "4351018")
if err != nil {
t.Fatal(err)
}
t.Log(utils.Format4Output(store, false))
}
func TestUpdateStore(t *testing.T) {
err := CurPurchaseHandler.UpdateStore(nil, 100002, "test")
if err != nil {
t.Fatal(err)
}
}
func TestConstrainOpTimeList(t *testing.T) {
timeList := constrainOpTimeList([]int16{830, 1800}, []int16{
0,
200,
930,
1700,
})
t.Log(utils.Format4Output(timeList, false))
if timeList[0] != 930 || timeList[1] != 1700 {
t.Fatal("constrainOpTimeList failed")
}
}
func TestGetOpTimeListFromErr(t *testing.T) {
err := utils.NewErrorIntCode("当前配送营业时间为:07:00~24:00", mtwmapi.ErrCodeOpFailed)
list := getOpTimeListFromErr(err)
t.Log(list)
}

View File

@@ -1,56 +0,0 @@
package mtwm
import (
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
)
var (
VendorWaybillStatus2StatusMap = map[string]int{
mtwmapi.WaybillStatusWait4Delivery: model.WaybillStatusNew,
mtwmapi.WaybillStatusPending: model.WaybillStatusPending,
mtwmapi.WaybillStatusAccepted: model.WaybillStatusAccepted,
mtwmapi.WaybillStatusCourierArrived: model.WaybillStatusCourierArrived,
mtwmapi.WaybillStatusPickedup: model.WaybillStatusDelivering,
mtwmapi.WaybillStatusDelivered: model.WaybillStatusDelivered,
mtwmapi.WaybillStatusCanceled: model.WaybillStatusCanceled,
}
)
func (p *PurchaseHandler) GetWaybillStatusFromVendorStatus(vendorStatus string) int {
if status, ok := VendorWaybillStatus2StatusMap[vendorStatus]; ok {
return status
}
return model.WaybillStatusUnknown
}
func (c *PurchaseHandler) onWaybillMsg(msg *mtwmapi.CallbackMsg) (response *mtwmapi.CallbackResponse) {
waybill := c.callbackMsg2Waybill(msg)
err := partner.CurOrderManager.OnWaybillStatusChanged(waybill)
if err == nil && waybill.Status == model.WaybillStatusDelivering {
c.postFakeMsg(waybill.VendorOrderID, FakeMsgType, mtwmapi.OrderStatusDelivering)
}
return mtwmapi.Err2CallbackResponse(err, "")
}
func (c *PurchaseHandler) callbackMsg2Waybill(msg *mtwmapi.CallbackMsg) (retVal *model.Waybill) {
orderID := GetOrderIDFromMsg(msg)
vendorStatus := msg.FormData.Get("logistics_status")
retVal = &model.Waybill{
VendorOrderID: orderID,
OrderVendorID: model.VendorIDMTWM,
VendorWaybillID: orderID,
WaybillVendorID: model.VendorIDMTWM,
CourierName: msg.FormData.Get("dispatcher_name"),
CourierMobile: msg.FormData.Get("dispatcher_mobile"),
VendorStatus: vendorStatus,
Status: c.GetWaybillStatusFromVendorStatus(vendorStatus),
StatusTime: getTimeFromTimestamp(utils.Str2Int64(msg.FormData.Get("time"))),
Remark: "",
VendorOrgCode: msg.AppID,
}
return retVal
}

View File

@@ -1,11 +0,0 @@
package wsc
import (
"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"
)
func (c *PurchaseHandler) SyncAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actOrderRules []*model.ActOrderRule, actStoreSkuList []*model.ActStoreSku2) (err error) {
return nil
}

View File

@@ -1,18 +0,0 @@
package wsc
import (
"git.rosy.net.cn/baseapi/platformapi/weimobapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/model"
)
func OnCallbackMsg(msg *weimobapi.CallbackMsg) (response *weimobapi.CallbackResponse) {
if curPurchaseHandler != nil {
orderID := utils.Int64ToStr(msg.OrderNo)
jxutils.CallMsgHandler(func() {
response = curPurchaseHandler.onOrderMsg(msg)
}, jxutils.ComposeUniversalOrderID(orderID, model.VendorIDWSC))
}
return response
}

View File

@@ -1,309 +0,0 @@
package wsc
import (
"errors"
"fmt"
"time"
"git.rosy.net.cn/baseapi/platformapi/weimobapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/business/partner/delivery/dada"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
const (
FakeOrderStatusAccepted = "fakeaccepted"
FakeOrderStatusFinishedPickup = "fakefinishedpickup"
)
const (
maxAddFee = 300 // 最大增加费用,单位为分,超过不发三方配送了
)
var (
VendorStatus2StatusMap = map[string]int{
utils.Int2Str(weimobapi.OrderStatusWait4Pay): model.OrderStatusWait4Pay,
utils.Int2Str(weimobapi.OrderStatusPayed): model.OrderStatusNew,
FakeOrderStatusAccepted: model.OrderStatusAccepted,
FakeOrderStatusFinishedPickup: model.OrderStatusFinishedPickup,
utils.Int2Str(weimobapi.OrderStatusDelivering): model.OrderStatusDelivering,
utils.Int2Str(weimobapi.OrderStatusFinished): model.OrderStatusFinished,
utils.Int2Str(weimobapi.OrderStatusCanceled): model.OrderStatusCanceled,
weimobapi.MsgEventCreateRights: model.OrderStatusLocked,
}
)
func (p *PurchaseHandler) onOrderMsg(msg *weimobapi.CallbackMsg) (response *weimobapi.CallbackResponse) {
var (
err error
status *model.OrderStatus
orderMapData map[string]interface{}
)
if msg.IsFake || weimobapi.MsgEventCreateOrder == msg.Event || weimobapi.MsgEventOrderStatusChange == msg.Event {
orderMapData, err = api.WeimobAPI.QueryOrderDetail(msg.OrderNo, false)
if err == nil {
status = p.callbackMsg2Status(msg, orderMapData)
if msg.Event == weimobapi.MsgEventCreateOrder || status.Status == model.OrderStatusNew {
order := p.Map2Order(orderMapData)
order.StatusTime = msg.StatusTime
err = partner.CurOrderManager.OnOrderNew(order, status)
} else {
err = partner.CurOrderManager.OnOrderStatusChanged("", status)
}
}
}
return weimobapi.Err2CallbackResponse(err, "")
}
func (p *PurchaseHandler) callbackMsg2Status(msg *weimobapi.CallbackMsg, orderMapData map[string]interface{}) (orderStatus *model.OrderStatus) {
orderID := utils.Int64ToStr(msg.OrderNo)
var vendorStatus string
if msg.IsFake {
vendorStatus = msg.Event
} else {
if msg.Event == weimobapi.MsgEventCreateRights {
vendorStatus = msg.Event
} else {
vendorStatus = p.getOrderStatus(orderMapData)
}
}
orderStatus = &model.OrderStatus{
VendorOrderID: orderID,
VendorID: model.VendorIDWSC,
OrderType: model.OrderTypeOrder,
RefVendorOrderID: orderID,
RefVendorID: model.VendorIDWSC,
VendorStatus: vendorStatus,
Status: p.getStatusFromVendorStatus(vendorStatus),
StatusTime: msg.StatusTime,
Remark: "",
}
return orderStatus
}
func (p *PurchaseHandler) getOrderStatus(orderMapData map[string]interface{}) (status string) {
return utils.Int64ToStr(utils.MustInterface2Int64(orderMapData["orderStatus"]))
}
func (p *PurchaseHandler) getStatusFromVendorStatus(vendorStatus string) int {
if status, ok := VendorStatus2StatusMap[vendorStatus]; ok {
return status
}
return model.OrderStatusUnknown
}
func (p *PurchaseHandler) GetOrder(vendorOrgCode, vendorOrderID string) (order *model.GoodsOrder, err error) {
globals.SugarLogger.Debugf("wsc GetOrder orderID:%s", vendorOrderID)
result, err := api.WeimobAPI.QueryOrderDetail(utils.Str2Int64(vendorOrderID), false)
if err != nil {
return nil, err
}
order = p.Map2Order(result)
return order, err
}
func (p *PurchaseHandler) GetOrderStatus(vendorOrgCode, vendorOrderID string) (status int, err error) {
return 0, fmt.Errorf("未实现")
}
func (p *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *model.GoodsOrder) {
result := orderData
vendorOrderID := utils.Int64ToStr(utils.MustInterface2Int64(result["orderNo"]))
deliveryDetail := result["deliveryDetail"].(map[string]interface{})
logisticsDeliveryDetail, _ := deliveryDetail["logisticsDeliveryDetail"].(map[string]interface{})
// paymentInfo := result["paymentInfo"].(map[string]interface{})
order = &model.GoodsOrder{
VendorOrderID: vendorOrderID,
VendorID: model.VendorIDWSC,
VendorStoreID: utils.Int64ToStr(utils.MustInterface2Int64(result["processStoreId"])), // 这个不是通常意义上的vendor store id
// StoreID
BuyerComment: utils.Interface2String(result["buyerRemark"]),
ExpectedDeliveredTime: utils.DefaultTimeValue,
PickDeadline: utils.DefaultTimeValue,
VendorStatus: utils.Int64ToStr(utils.MustInterface2Int64(result["orderStatus"])),
StatusTime: utils.Timestamp2Time(utils.MustInterface2Int64(result["createTime"]) / 1000),
OrderCreatedAt: utils.Timestamp2Time(utils.MustInterface2Int64(result["createTime"]) / 1000),
OriginalData: string(utils.MustMarshal(result)),
ActualPayPrice: jxutils.StandardPrice2Int(utils.MustInterface2Float64(result["totalAmount"])),
BusinessType: model.BusinessTypeImmediate,
}
if logisticsDeliveryDetail != nil {
order.StoreName = utils.Interface2String(logisticsDeliveryDetail["processStoreTitle"])
order.ConsigneeName = utils.Interface2String(logisticsDeliveryDetail["receiverName"])
order.ConsigneeMobile = utils.Interface2String(logisticsDeliveryDetail["receiverMobile"])
order.ConsigneeAddress = utils.Interface2String(logisticsDeliveryDetail["receiverAddress"])
order.ConsigneeLng = jxutils.StandardCoordinate2Int(utils.Str2Float64(utils.Interface2String(logisticsDeliveryDetail["receiverLongitude"])))
order.ConsigneeLat = jxutils.StandardCoordinate2Int(utils.Str2Float64(utils.Interface2String(logisticsDeliveryDetail["receiverLatitude"])))
order.CoordinateType = model.CoordinateTypeMars
// if expectDeliveryTimeStr, ok := logisticsDeliveryDetail["expectDeliveryTime"].(string); ok {
// if expectDeliveryTimeStr =
// }
} else {
selfPickupDetail, _ := deliveryDetail["selfPickupDetail"].(map[string]interface{})
if selfPickupDetail != nil {
order.StoreName = utils.Interface2String(selfPickupDetail["selfPickupSiteName"])
}
}
order.Status = p.getStatusFromVendorStatus(order.VendorStatus)
itemList := result["itemList"].([]interface{})
for _, v := range itemList {
item := v.(map[string]interface{})
skuName := utils.Interface2String(item["goodsTitle"])
_, _, _, specUnit, _, specQuality := jxutils.SplitSkuName(skuName)
sku := &model.OrderSku{
VendorOrderID: vendorOrderID,
VendorID: model.VendorIDWSC,
Count: int(utils.MustInterface2Int64(item["skuNum"])),
SkuID: int(utils.Str2Int64WithDefault(utils.Interface2String(item["skuCode"]), 0)),
VendorSkuID: utils.Int64ToStr(utils.MustInterface2Int64(item["skuId"])),
SkuName: skuName,
Weight: jxutils.FormatSkuWeight(specQuality, specUnit), // 订单信息里没有重量,只有名字里尝试找
SalePrice: jxutils.StandardPrice2Int(utils.MustInterface2Float64(item["price"])),
}
order.Skus = append(order.Skus, sku)
}
jxutils.RefreshOrderSkuRelated(order)
if logisticsDeliveryDetail != nil {
p.arrangeSaleStore(order, utils.Interface2String(logisticsDeliveryDetail["receiverCity"]), utils.Interface2String(logisticsDeliveryDetail["receiverProvince"]))
}
p.setStoreOrderSeq(order)
globals.SugarLogger.Debug(utils.Format4Output(order, false))
return order
}
func (p *PurchaseHandler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) {
globals.SugarLogger.Debugf("wsc AcceptOrRefuseOrder orderID:%s, isAcceptIt:%t", order.VendorOrderID, isAcceptIt)
if !isAcceptIt {
if globals.EnableWscStoreWrite {
err = api.WeimobAPI.CancelOrder(utils.Str2Int64(order.VendorOrderID), "")
}
} else {
if jxutils.GetSaleStoreIDFromOrder(order) != 0 {
// 微商城没有确认,只有取消,模拟接受
p.postFakeMsg(utils.Str2Int64(order.VendorOrderID), FakeOrderStatusAccepted)
} else {
globals.SugarLogger.Debugf("weimob AcceptOrRefuseOrder orderID:%s can not find sale store", order.VendorOrderID)
if globals.EnableWscStoreWrite {
err = api.WeimobAPI.CancelOrder(utils.Str2Int64(order.VendorOrderID), "没有找到合适的配送店")
}
}
}
return err
}
func (p *PurchaseHandler) PickupGoods(order *model.GoodsOrder, isSelfDelivery bool, userName string) (err error) {
globals.SugarLogger.Debugf("wsc PickupGoods orderID:%s, isSelfDelivery:%t", order.VendorOrderID, isSelfDelivery)
if globals.EnableWscStoreWrite && !isSelfDelivery {
_, err = dada.CurDeliveryHandler.CreateWaybill(order, 0)
}
// 微商城没有拣货完成,模拟
p.postFakeMsg(utils.Str2Int64(order.VendorOrderID), FakeOrderStatusFinishedPickup)
return err
}
func (p *PurchaseHandler) AcceptOrRefuseFailedGetOrder(ctx *jxcontext.Context, order *model.GoodsOrder, isAcceptIt bool) (err error) {
return err
}
func (p *PurchaseHandler) CallCourier(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 拣货失败后再次招唤平台配送
return err
}
func (p *PurchaseHandler) ConfirmReceiveGoods(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 投递失败后确认收到退货
return err
}
// 将订单从购物平台配送转为自送
func (p *PurchaseHandler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) {
globals.SugarLogger.Debugf("wsc Swtich2SelfDeliver orderID:%s", order.VendorOrderID)
if globals.EnableWscStoreWrite {
err = api.WeimobAPI.DeliveryOrder(&weimobapi.DeliveryOrder{
OrderNo: utils.Str2Int64(order.VendorOrderID),
})
}
return err
}
// 将订单从购物平台配送转为自送后又送达
func (p *PurchaseHandler) Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) {
globals.SugarLogger.Debugf("wsc Swtich2SelfDelivered orderID:%s", order.VendorOrderID)
return err
}
// 完全自送的门店表示开始配送
func (p *PurchaseHandler) SelfDeliverDelivering(order *model.GoodsOrder, userName string) (err error) {
globals.SugarLogger.Debugf("wsc SelfDeliverDelivering orderID:%s", order.VendorOrderID)
if globals.EnableWscStoreWrite {
err = api.WeimobAPI.DeliveryOrder(&weimobapi.DeliveryOrder{
OrderNo: utils.Str2Int64(order.VendorOrderID),
})
}
return err
}
// 完全自送的门店表示配送完成
func (p *PurchaseHandler) SelfDeliverDelivered(order *model.GoodsOrder, userName string) (err error) {
globals.SugarLogger.Debugf("wsc SelfDeliverDelivered orderID:%s", order.VendorOrderID)
return err
}
func (p *PurchaseHandler) postFakeMsg(orderNo int64, fakeStatus string) {
msg := &weimobapi.CallbackMsg{
IsFake: true,
Event: fakeStatus,
OrderNo: orderNo,
StatusTime: time.Now(),
}
utils.CallFuncAsync(func() {
OnCallbackMsg(msg)
})
}
func (p *PurchaseHandler) arrangeSaleStore(order *model.GoodsOrder, cityName, provinceName string) {
}
func (p *PurchaseHandler) setStoreOrderSeq(order *model.GoodsOrder) {
if order.StoreID > 0 {
year, month, day := order.StatusTime.Date()
dateBegin := time.Date(year, month, day, 0, 0, 0, 0, order.StatusTime.Location())
// dateEnd := date1.Add(time.Hour * 24)
sql := `
SELECT COUNT(*) ct
FROM goods_order t1
WHERE t1.store_id = ? AND t1.order_created_at >= ? AND t1.vendor_id = ?
`
var count int
db := dao.GetDB()
if err := dao.GetRow(db, &count, sql, order.StoreID, dateBegin, model.VendorIDWSC); err == nil {
order.OrderSeq = count + 1
globals.SugarLogger.Debugf("setStoreOrderSeq orderID:%s, dateBegin:%s, orderSeq:%d", order.VendorOrderID, utils.Time2Str(dateBegin), order.OrderSeq)
} else {
globals.SugarLogger.Errorf("setStoreOrderSeq orderID:%s failed with error:%v", order.VendorOrderID, err)
}
}
}
func (c *PurchaseHandler) GetOrderRealMobile(ctx *jxcontext.Context, order *model.GoodsOrder) (mobile string, err error) {
err = errors.New("微盟微商城还未实现GetOrderRealMobile")
return mobile, err
}
func (c *PurchaseHandler) AgreeOrRefuseCancel(ctx *jxcontext.Context, order *model.GoodsOrder, isAgree bool, reason string) (err error) {
return err
}
func (c *PurchaseHandler) CancelOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
return err
}
func (c *PurchaseHandler) AdjustOrder(ctx *jxcontext.Context, order *model.GoodsOrder, removedSkuList []*model.OrderSku, reason string) (err error) {
return err
}

View File

@@ -1,28 +0,0 @@
package wsc
import (
"fmt"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
)
// 审核售后单申请
func (c *PurchaseHandler) AgreeOrRefuseRefund(ctx *jxcontext.Context, order *model.AfsOrder, approveType int, reason string) (err error) {
return err
}
// 确认收到退货
func (c *PurchaseHandler) ConfirmReceivedReturnGoods(ctx *jxcontext.Context, order *model.AfsOrder) (err error) {
return err
}
// 发起全款退款
func (c *PurchaseHandler) RefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
return fmt.Errorf("微商城不支持全款退款")
}
// 发起部分退款
func (c *PurchaseHandler) PartRefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, refundSkuList []*model.OrderSku, reason string) (err error) {
return fmt.Errorf("微商城不支持部分退款")
}

View File

@@ -1,10 +0,0 @@
package wsc
import (
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
)
func (c *PurchaseHandler) ReplyOrderComment(ctx *jxcontext.Context, vendorOrgCode string, orderComment *model.OrderComment, replyComment string) (err error) {
return err
}

View File

@@ -1,25 +0,0 @@
package wsc
import (
"errors"
"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/dao"
)
func (p *PurchaseHandler) ReadStore(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID string) (*dao.StoreDetail, error) {
return nil, errors.New("微盟微商城还没实现")
}
func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName string) error {
return nil
}
func (p *PurchaseHandler) RefreshAllStoresID(ctx *jxcontext.Context, parentTask tasksch.ITask, isAsync bool) (hint string, err error) {
return hint, err
}
func (p *PurchaseHandler) GetStoreStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string) (storeStatus int, err error) {
return 0, err
}

Some files were not shown because too many files have changed in this diff Show More