From 97a83f1c2fc6529857ecbf6302fd8f786ea75841 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=B9=E5=AE=97=E6=A5=A0?= Date: Wed, 31 Aug 2022 16:47:41 +0800 Subject: [PATCH] 1 --- business/jxutils/tasks/configrefresh.go | 48 ++++ business/model/api_config.go | 1 + business/partner/purchase/tiktok_store/act.go | 270 +++++++++++++++++ .../partner/purchase/tiktok_store/callback.go | 25 ++ .../purchase/tiktok_store/financial.go | 252 ++++++++++++++++ .../purchase/tiktok_store/interface_call.go | 267 +++++++++++++++++ .../partner/purchase/tiktok_store/tiktok.go | 272 ++++++++++++++++++ controllers/tiktok_store.go | 22 ++ globals/api/api.go | 14 +- main.go | 4 + routers/router.go | 1 + 11 files changed, 1170 insertions(+), 6 deletions(-) create mode 100644 business/partner/purchase/tiktok_store/act.go create mode 100644 business/partner/purchase/tiktok_store/callback.go create mode 100644 business/partner/purchase/tiktok_store/financial.go create mode 100644 business/partner/purchase/tiktok_store/interface_call.go create mode 100644 business/partner/purchase/tiktok_store/tiktok.go create mode 100644 controllers/tiktok_store.go diff --git a/business/jxutils/tasks/configrefresh.go b/business/jxutils/tasks/configrefresh.go index 1749cb265..580452ce9 100644 --- a/business/jxutils/tasks/configrefresh.go +++ b/business/jxutils/tasks/configrefresh.go @@ -30,6 +30,7 @@ const ( yilianyunTokenExpires = 30 * 24 * 3600 * time.Second pushTokenExpires = 7200 * time.Second fnTokenExpires = 1 * time.Hour + tiktokTokenExpires = 14 * 24 * 3600 * time.Second maxRefreshGap = 5 * 60 * time.Second errRefreshGap = 10 * time.Second @@ -470,3 +471,50 @@ func getWeimobTokenFromRemote(oldToken string) (tokenInfo *syseventhub.TokenInfo } return tokenInfo } + +// RefreshTiktokToken 刷新抖店token +func RefreshTiktokToken() (err error) { + if api.TiktokStore != nil { + err = RefreshConfig("tiktok", tiktokTokenExpires, func() (token string, expireTimeStr string, refreshToken string) { + curConfig := &legacymodel.Config{ + Thirdparty: "tiktok", + } + if err := orm.NewOrm().Read(curConfig, "Thirdparty"); err != nil { + globals.SugarLogger.Errorf("RefreshTiktokToken RefreshToken failed with error:%v", err) + } + if curConfig.RefreshToken == "" { + if tokenInfo, err := api.TiktokStore.CreateToken(curConfig.Token); err != nil { + globals.SugarLogger.Errorf("tiktok store get token err:%v", err) + } else { + token = tokenInfo.AccessToken + refreshToken = tokenInfo.RefreshToken + expireTimeStr = time.Unix(tokenInfo.ExpiresIn, 0).Format("2006-01-02 15:04:05") + } + } else { + expireIn, _ := time.Parse("2006-01-02 15:04:05", curConfig.Date) + if expireIn.Unix() < time.Now().Unix() { + api.TiktokStore.SetToken(curConfig.Token) + api.TiktokStore.SetRefreshToken(curConfig.RefreshToken) + if tokenInfo, err := api.TiktokStore.RefreshToken(); err == nil { + token = tokenInfo.AccessToken + refreshToken = tokenInfo.RefreshToken + expireTimeStr = time.Unix(tokenInfo.ExpiresIn, 0).Format("2006-01-02 15:04:05") + } else { + globals.SugarLogger.Errorf("RefreshTiktokToken RefreshToken failed with error:%v", err) + } + } + } + + sql := `UPDATE config SET token = ?,refresh_token = ?,data = ? WHERE thirdparty = ?` + dao.ExecuteSQL(dao.GetDB(), sql, []interface{}{ + token, refreshToken, expireTimeStr, "tiktok", + }) + return token, expireTimeStr, refreshToken + }, func(value, v2 string) { + globals.SugarLogger.Debugf("RefreshFnToken setter value:[%s],[%s]", value, v2) + api.TiktokStore.SetToken(value) + api.TiktokStore.SetRefreshToken(v2) + }) + } + return err +} diff --git a/business/model/api_config.go b/business/model/api_config.go index 1cb737a01..ee5541af1 100644 --- a/business/model/api_config.go +++ b/business/model/api_config.go @@ -22,6 +22,7 @@ const ( VendorIDJX = 9 // 这是一个假的京西VendorID VendorGoMei = 12 // 国美 VendorIDTT = 13 // 抖音平台小程序 + VendorIDDD = 14 // 抖店 VendorIDWXPay = 51 // 微信支付 diff --git a/business/partner/purchase/tiktok_store/act.go b/business/partner/purchase/tiktok_store/act.go new file mode 100644 index 000000000..438cc880c --- /dev/null +++ b/business/partner/purchase/tiktok_store/act.go @@ -0,0 +1,270 @@ +package tiktok_store + +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 +} + +func (c *PurchaseHandler) GetActAmple(ctx *jxcontext.Context, vendorStoreID, vendorOrgCode string) (ample int, err error) { + for _, v := range mtwmapi.ActTypeList { + //1表示进行中 + if actList, err := getAPI(vendorOrgCode, 0, vendorStoreID).GetByAppPoiCodeAndType(vendorOrgCode, 1, v); err == nil { + ample += len(actList) + } + } + return ample, err +} diff --git a/business/partner/purchase/tiktok_store/callback.go b/business/partner/purchase/tiktok_store/callback.go new file mode 100644 index 000000000..8869a6a61 --- /dev/null +++ b/business/partner/purchase/tiktok_store/callback.go @@ -0,0 +1,25 @@ +package tiktok_store + +import ( + "git.rosy.net.cn/baseapi/platformapi/mtwmapi" + tiktokShop "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/tiktok_api" +) + +// 美团回调接口 +func OnCallbackMsg(msg *tiktokShop.CreateOrderCallback) (tiktokShop *mtwmapi.CallbackResponse) { + if CurPurchaseHandler != nil { + switch msg.Tag { + case tiktokShop.CallbackMsgTagId: + + } + } + return response +} + +func GetOrderIDFromMsg(msg *mtwmapi.CallbackMsg) string { + return msg.FormData.Get(mtwmapi.KeyOrderID) +} + +func GetVendorStoreIDFromMsg(msg *mtwmapi.CallbackMsg) string { + return msg.FormData.Get(mtwmapi.KeyAppPoiCode) +} diff --git a/business/partner/purchase/tiktok_store/financial.go b/business/partner/purchase/tiktok_store/financial.go new file mode 100644 index 000000000..b5c597fc2 --- /dev/null +++ b/business/partner/purchase/tiktok_store/financial.go @@ -0,0 +1,252 @@ +package tiktok_store + +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 +} diff --git a/business/partner/purchase/tiktok_store/interface_call.go b/business/partner/purchase/tiktok_store/interface_call.go new file mode 100644 index 000000000..c7e38bd05 --- /dev/null +++ b/business/partner/purchase/tiktok_store/interface_call.go @@ -0,0 +1,267 @@ +package tiktok_store + +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" + "git.rosy.net.cn/jx-callback/business/model/dao" + "git.rosy.net.cn/jx-callback/business/partner" + "regexp" + "time" +) + +func (c *PurchaseHandler) GetStoreSkusBatchSize(funcID int) int { return 0 } + +func (c *PurchaseHandler) ListOrders(ctx *jxcontext.Context, vendorOrgCode string, parentTask tasksch.ITask, queryDate time.Time, vendorStoreID string) (vendorOrderIDs []string, err error) { + return nil, err +} + +// 此接口要求实现为不限制批处理大小的 +func (c *PurchaseHandler) GetStoreSkusBareInfo(ctx *jxcontext.Context, vendorOrgCode string, parentTask tasksch.ITask, storeID int, vendorStoreID string, inStoreSkuList []*partner.StoreSkuInfo) (outStoreSkuList []*partner.StoreSkuInfo, err error) { + return nil, err +} +func (c *PurchaseHandler) UpdateStoreSkusStock(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) { + return nil, err +} +func (c *PurchaseHandler) UpdateStoreSkusStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo, status int) (failedList []*partner.StoreSkuInfoWithErr, err error) { + return nil, err +} +func (c *PurchaseHandler) UpdateStoreSkusPrice(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) { + return nil, err +} + +func (c *PurchaseHandler) CreateStoreSkusAct(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) { + return nil, err +} +func (c *PurchaseHandler) CancelActs(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) { + return nil, err +} +func (c *PurchaseHandler) UpdateStoreSkusSpecTag(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (err error) { + return err +} +func (c *PurchaseHandler) GetStoreSkusFullInfo(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (outSkuNameList []*partner.SkuNameInfo, err error) { + return nil, err +} +func (c *PurchaseHandler) CreateStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*dao.StoreSkuSyncInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) { + return nil, err +} +func (c *PurchaseHandler) UpdateStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*dao.StoreSkuSyncInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) { + return nil, err +} +func (c *PurchaseHandler) DeleteStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) { + return nil, err +} +func (c *PurchaseHandler) DeleteStoreAllSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, vendorStoreID string, isContinueWhenError bool) (err error) { + return err +} +func (c *PurchaseHandler) IsErrSkuExist(err error) (isExist bool) { return true } +func (c *PurchaseHandler) IsErrSkuNotExist(err error) (isNotExist bool) { return true } + +func (c *PurchaseHandler) GetStoreAllCategories(ctx *jxcontext.Context, storeID int, vendorStoreID string) (cats []*partner.BareCategoryInfo, err error) { + return nil, err +} +func (c *PurchaseHandler) GetStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID, catName string) (cat *partner.BareCategoryInfo, err error) { + return nil, err +} +func (c *PurchaseHandler) CreateStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeCat *dao.SkuStoreCatInfo) (err error) { + return err +} +func (c *PurchaseHandler) UpdateStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeCat *dao.SkuStoreCatInfo) (err error) { + return err +} +func (c *PurchaseHandler) DeleteStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID, vendorCatID string, level int) (err error) { + return err +} +func (c *PurchaseHandler) DeleteStoreAllCategories(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, vendorStoreID string, isContinueWhenError bool) (err error) { + return err +} + +func (c *PurchaseHandler) IsErrCategoryExist(err error) (isExist bool) { return true } +func (c *PurchaseHandler) IsErrCategoryNotExist(err error) (isNotExist bool) { return true } + +func (c *PurchaseHandler) GetSensitiveWordRegexp() *regexp.Regexp { return nil } + +func (c *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *model.GoodsOrder) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) GetOrder(vendorOrgCode, vendorOrderID, vendorStoreID string) (order *model.GoodsOrder, err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) GetOrderStatus(vendorOrgCode, vendorOrderID string) (status int, err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) PickupGoods(order *model.GoodsOrder, isSelfDelivery bool, userName string) (err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) AcceptOrRefuseFailedGetOrder(ctx *jxcontext.Context, order *model.GoodsOrder, isAcceptIt bool) (err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) CallCourier(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) ConfirmReceiveGoods(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) SelfDeliverDelivering(order *model.GoodsOrder, userName string) (err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) GetCancelDeliveryReason(order *model.GoodsOrder) (string, error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) CancelLogisticsByWmOrderId(order *model.GoodsOrder, reasonCode, detailContent, appPoiCode, orderId string) error { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) OrderLogisticsStatus(orderId int64) (int64, error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) SelfDeliverDelivered(order *model.GoodsOrder, userName string) (err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) GetOrderRealMobile(ctx *jxcontext.Context, order *model.GoodsOrder) (mobile string, err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) ReplyOrderComment(ctx *jxcontext.Context, vendorOrgCode string, orderComment *model.OrderComment, replyComment string) (err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) AgreeOrRefuseCancel(ctx *jxcontext.Context, order *model.GoodsOrder, isAgree bool, reason string) (err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) CancelOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) AdjustOrder(ctx *jxcontext.Context, order *model.GoodsOrder, removedSkuList []*model.OrderSku, reason string) (err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) RefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) PartRefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, refundSkuList []*model.OrderSku, reason string) (err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) AgreeOrRefuseRefund(ctx *jxcontext.Context, order *model.AfsOrder, approveType int, reason string) (err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) ConfirmReceivedReturnGoods(ctx *jxcontext.Context, order *model.AfsOrder) (err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) GetSelfTakeCode(ctx *jxcontext.Context, order *model.GoodsOrder) (code string, err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) ConfirmSelfTake(ctx *jxcontext.Context, order *model.GoodsOrder, selfTakeCode string) (err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) GetOrderAfsInfo(ctx *jxcontext.Context, vendorOrderID, afsOrderID string) (orderAfsInfo *partner.OrderAfsInfo, err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) ComplaintRider(vendorOrderId string, resonID int, resonContent string) (err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) GetOrderRider(vendorOrgCode, vendorStoreID string, param map[string]interface{}) (err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) ReadStore(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID, vendorStoreName string) (store *dao.StoreDetail, err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName string) (err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) CreateStore2(db *dao.DaoDB, storeID int, userName string, params map[string]interface{}, storeDetail *dao.StoreDetail) (vendorStoreID string, err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) DeleteStore(db *dao.DaoDB, storeID int, userName string) (err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) GetStoreStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string) (storeStatus int, err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) UpdateStoreCustomID(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID string, storeID int64) (err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) RefreshAllStoresID(ctx *jxcontext.Context, parentTask tasksch.ITask, isAsync bool) (hint string, err error) { + //TODO implement me + panic("implement me") +} + +func (c *PurchaseHandler) UpdateStoreLineStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, lineStatus int) (err error) { + //TODO implement me + panic("implement me") +} diff --git a/business/partner/purchase/tiktok_store/tiktok.go b/business/partner/purchase/tiktok_store/tiktok.go new file mode 100644 index 000000000..0c5167b7b --- /dev/null +++ b/business/partner/purchase/tiktok_store/tiktok.go @@ -0,0 +1,272 @@ +package tiktok_store + +import ( + "fmt" + "strings" + "sync" + + "git.rosy.net.cn/jx-callback/business/model/dao" + + "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 || api.Mtwm2API != 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.VendorIDDD +} + +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 +} + +func GetAPI(appOrgCode string, storeID int, vendorStoreID string) (apiObj *mtwmapi.API) { + if appOrgCode == "" { + globals.SugarLogger.Debugf("getAPI appOrgCode is empty") + } + apiObj = partner.CurAPIManager.GetAPI(model.VendorIDMTWM, appOrgCode).(*mtwmapi.API) + if appOrgCode == globals.Mtwm2Code { + var storeDetail *dao.StoreDetail + if storeID != 0 { + storeDetail, _ = dao.GetStoreDetail(dao.GetDB(), storeID, model.VendorIDMTWM, appOrgCode) + } else if vendorStoreID != "" { + storeDetail, _ = dao.GetStoreDetailByVendorStoreID(dao.GetDB(), vendorStoreID, model.VendorIDMTWM, appOrgCode) + } + if storeDetail != nil { + apiObj.SetToken(storeDetail.MtwmToken) + } + } + return apiObj +} + +func getAPI(appOrgCode string, storeID int, vendorStoreID string) (apiObj *mtwmapi.API) { + if appOrgCode == "" { + globals.SugarLogger.Debugf("getAPI appOrgCode is empty") + } + apiObj = partner.CurAPIManager.GetAPI(model.VendorIDMTWM, appOrgCode).(*mtwmapi.API) + if appOrgCode == globals.Mtwm2Code { + var storeDetail *dao.StoreDetail + if storeID != 0 { + storeDetail, _ = dao.GetStoreDetail(dao.GetDB(), storeID, model.VendorIDMTWM, appOrgCode) + } else if vendorStoreID != "" { + storeDetail, _ = dao.GetStoreDetailByVendorStoreID(dao.GetDB(), vendorStoreID, model.VendorIDMTWM, appOrgCode) + } + if storeDetail != nil { + apiObj.SetToken(storeDetail.MtwmToken) + } + } + return apiObj +} + +func getAPIWithoutToken(appOrgCode string) (apiObj *mtwmapi.API) { + if appOrgCode == "" { + globals.SugarLogger.Warnf("getAPI appOrgCode is empty") + } + return partner.CurAPIManager.GetAPI(model.VendorIDMTWM, appOrgCode).(*mtwmapi.API) +} diff --git a/controllers/tiktok_store.go b/controllers/tiktok_store.go new file mode 100644 index 000000000..a3e4a4b13 --- /dev/null +++ b/controllers/tiktok_store.go @@ -0,0 +1,22 @@ +package controllers + +import ( + "git.rosy.net.cn/jx-callback/business/partner/purchase/tiktok_store" + "git.rosy.net.cn/jx-callback/globals/api" + "github.com/astaxie/beego/server/web" +) + +type TiktokController struct { + web.Controller +} + +// CallbackTiktok 抖店用户下单订单推送 (tiktokStore) +func (t *TiktokController) CallbackTiktok() { + data, resp := api.TiktokStore.CreateOrderCallback(t.Ctx.Request) + if resp.Code == 200 { + // 业务处理 + tiktok_store.OnCallbackMsg(data) + } + t.Data["json"] = resp + t.ServeJSON() +} diff --git a/globals/api/api.go b/globals/api/api.go index 337e15f11..fea5675c9 100644 --- a/globals/api/api.go +++ b/globals/api/api.go @@ -6,6 +6,7 @@ import ( "git.rosy.net.cn/baseapi/platformapi/jxprintapi" "git.rosy.net.cn/baseapi/platformapi/qywxapi" "git.rosy.net.cn/baseapi/platformapi/tiktok" + tiktokShop "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/tiktok_api" "time" "git.rosy.net.cn/baseapi/platformapi/fnpsapi" @@ -112,12 +113,12 @@ var ( Cacher cache.ICacher SMSClient *aliyunsmsclient.SmsClient - TiktokApi *tiktok.API // 抖音api - TiktokJXDJApi *tiktok.API //抖音京西到家api - TiktokApiID string //抖音商城ID - TiktokJXDJApiID string //抖音京西到家ID - GuoMeiApi *gomei.API // 国美api - + TiktokApi *tiktok.API // 抖音api + TiktokJXDJApi *tiktok.API //抖音京西到家api + TiktokApiID string //抖音商城ID + TiktokJXDJApiID string //抖音京西到家ID + GuoMeiApi *gomei.API // 国美api + TiktokStore *tiktokShop.Api EnterpriseChatHeadApi *enterprise.API // 企业微信api EnterpriseChatMin *enterprise.API // 企业微信小程序api ) @@ -308,6 +309,7 @@ func Init() { if TiktokJXDJApiID = beego.AppConfig.DefaultString("TiktokJXDJApiID", ""); TiktokJXDJApiID != "" { TiktokJXDJApi = tiktok.New(beego.AppConfig.DefaultString("tiktokJXDJSecret", ""), beego.AppConfig.DefaultString("TiktokJXDJApiID", "")) } + TiktokStore = tiktokShop.New(beego.AppConfig.DefaultString("key", ""), beego.AppConfig.DefaultString("sercret", ""), "") // 国美aip GuoMeiApi = gomei.New(beego.AppConfig.DefaultString("gomeiAppKey", ""), beego.AppConfig.DefaultString("gomeiAppSecret", ""), "") EnterpriseChatHeadApi = enterprise.New("ww9a156bfa070e1857", "0jBdCjSmoFiOoHIXyeCK9VbGQ82fVNJZ8uMl6JNN7X4") // 通讯录 diff --git a/main.go b/main.go index d7c9d3988..57710d566 100644 --- a/main.go +++ b/main.go @@ -162,6 +162,10 @@ func main() { globals.SugarLogger.Errorf("RefreshFnToken failed with error:%s", err) return } + if err := tasks.RefreshTiktokToken(); err != nil { + globals.SugarLogger.Errorf("RefreshTiktokToken failed with error:%s", err) + return + } if err := tasks.RefreshQywxToken(); err != nil { globals.SugarLogger.Errorf("RefreshQywxToken failed with error:%s", err) return diff --git a/routers/router.go b/routers/router.go index 319e175bc..e1cb85fa8 100644 --- a/routers/router.go +++ b/routers/router.go @@ -184,6 +184,7 @@ func init() { web.AutoRouter(&controllers.TicTocController{}) web.AutoRouter(&controllers.EnterpriseController{}) + web.AutoRouter(&controllers.TiktokController{}) // 如下都是用于检测存活的空接口 web.Any("/", func(ctx *beecontext.Context) { ctx.WriteString("pong\n")