diff --git a/business/jxcallback/orderman/order.go b/business/jxcallback/orderman/order.go index 82e66354e..aae59e8d4 100644 --- a/business/jxcallback/orderman/order.go +++ b/business/jxcallback/orderman/order.go @@ -31,29 +31,6 @@ type tStoreSkuBindAndVendorSkuID struct { func init() { } -func (c *OrderManager) LoadPendingOrders() []*model.GoodsOrder { - db := orm.NewOrm() - var orders []*model.GoodsOrder - tillTime := time.Now().Add(-pendingOrderGapMax) - _, err := db.Raw(` - SELECT * - FROM goods_order - WHERE order_created_at >= ? - AND status < ? - `, tillTime, model.OrderStatusEndBegin).QueryRows(&orders) - if err != nil { - globals.SugarLogger.Warnf("LoadPendingOrders load pending orders error:%v", err) - return nil - } - for _, order := range orders { - utils.CallFuncLogError(func() error { - _, err = db.QueryTable("order_sku").Filter("vendor_order_id", order.VendorOrderID).Filter("vendor_id", order.VendorID).All(&order.Skus) - return err - }, "LoadPendingOrders order:%v", order) - } - return orders -} - // msgVendorStatus的意思是事件本身的类型,类似有时收到NewOrder事件去取,订单状态不一定就是New的 // OnOrderAdjust也类似,而OrderStatus要记录的是消息,所以添加这个 func (c *OrderManager) OnOrderNew(order *model.GoodsOrder, orderStatus *model.OrderStatus) (err error) { @@ -97,6 +74,7 @@ func (c *OrderManager) OnOrderNew(order *model.GoodsOrder, orderStatus *model.Or // todo 调整单的处理可能还需要再细化一点,当前只是简单的删除重建 func (c *OrderManager) OnOrderAdjust(order *model.GoodsOrder, orderStatus *model.OrderStatus) (err error) { + globals.SugarLogger.Debugf("OnOrderAdjust orderID:%s, status:%d", order.VendorOrderID, order.Status) if order.ConsigneeMobile2 == "" && jxutils.IsStringLikeMobile(order.ConsigneeMobile) { order.ConsigneeMobile2 = order.ConsigneeMobile } @@ -185,6 +163,33 @@ func (c *OrderManager) OnOrderStatusChanged(vendorOrgCode string, orderStatus *m isDuplicated, order, err := c.addOrderStatus(orderStatus, db) if err == nil { dao.Commit(db) + if orderStatus.Status == model.OrderStatusWaybillTipChanged { + if order, err2 := c.LoadOrder(orderStatus.VendorOrderID, orderStatus.VendorID); err2 == nil { + if handler := partner.GetWaybillTipUpdater(orderStatus.RefVendorID); handler != nil { + tipFee, err2 := handler.GetWaybillTip(jxcontext.AdminCtx, vendorOrgCode, order.VendorStoreID, orderStatus.RefVendorOrderID, orderStatus.VendorOrderID, "") + if err2 == nil { + order.WaybillTipMoney = tipFee + c.UpdateOrderFields(order, []string{"WaybillTipMoney"}) + } + } + } + } else if orderStatus.Status == model.OrderStatusFinished { + if order, err2 := c.LoadOrder(orderStatus.VendorOrderID, orderStatus.VendorID); err2 == nil { + // 当前只针对三方运单更新配送费信息 + if order.WaybillVendorID >= 0 && order.VendorWaybillID != "" && order.WaybillVendorID != order.VendorID { + if waybill, err2 := c.LoadWaybill(order.VendorWaybillID, order.WaybillVendorID); err2 == nil { + if handler := partner.GetWaybillTipUpdater(waybill.WaybillVendorID); handler != nil { + tipFee, err2 := handler.GetWaybillTip(jxcontext.AdminCtx, waybill.VendorOrgCode, "", order.VendorOrderID, waybill.VendorWaybillID, waybill.VendorWaybillID2) + if err2 == nil && waybill.TipFee != tipFee { + waybill.ActualFee += tipFee - waybill.TipFee + waybill.TipFee = tipFee + dao.UpdateEntity(db, waybill, "TipFee", "ActualFee") + } + } + } + } + } + } if !isDuplicated { if order != nil { order.Skus = c.loadOrderSku(db, order.VendorOrderID, order.VendorID) @@ -234,7 +239,7 @@ func setFakeOrderFlag(db *dao.DaoDB, order *model.GoodsOrder) { } func (c *OrderManager) SaveOrder(order *model.GoodsOrder, isAdjust bool, db *dao.DaoDB) (isDuplicated bool, err error) { - globals.SugarLogger.Debugf("SaveOrder orderID:%s, VendorStoreID:%s", order.VendorOrderID, order.VendorStoreID) + globals.SugarLogger.Debugf("SaveOrder orderID:%s, VendorStoreID:%s, status:%d", order.VendorOrderID, order.VendorStoreID, order.Status) // 忽略查找JX信息错误 c.updateOrderOtherInfo(order, db) order.ID = 0 @@ -259,7 +264,7 @@ func (c *OrderManager) SaveOrder(order *model.GoodsOrder, isAdjust bool, db *dao if dao.GetRow(db, orderStatus, ` SELECT * FROM order_status - WHERE order_type = ? AND vendor_order_id = ? AND vendor_id = ? + WHERE order_type = ? AND vendor_order_id = ? AND vendor_id = ? AND status > 0 ORDER BY status_time DESC LIMIT 1 `, model.OrderTypeOrder, order.VendorOrderID, order.VendorID) == nil { @@ -394,7 +399,7 @@ func updateSingleOrderEarningPrice(order *model.GoodsOrder, db *dao.DaoDB) { skuIDMap[v.SkuID] = 1 } if len(skuIDMap) > 0 { - actStoreSkuList, err := dao.GetEffectiveActStoreSkuInfo(db, 0, []int{order.VendorID}, []int{jxStoreID}, jxutils.IntMap2List(skuIDMap), order.OrderCreatedAt, order.OrderCreatedAt) + actStoreSkuList, err := dao.GetEffectiveActStoreSkuInfo(db, 0, []int{order.VendorID}, model.ActTypeAll, []int{jxStoreID}, jxutils.IntMap2List(skuIDMap), order.OrderCreatedAt, order.OrderCreatedAt) if err != nil { globals.SugarLogger.Errorf("updateOrderSkuOtherInfo can not get sku promotion info for error:%v", err) } diff --git a/business/jxcallback/orderman/order_afs.go b/business/jxcallback/orderman/order_afs.go index f65bd0dba..776050f21 100644 --- a/business/jxcallback/orderman/order_afs.go +++ b/business/jxcallback/orderman/order_afs.go @@ -273,7 +273,7 @@ func (c *OrderManager) updateAfsOrderSkuOtherInfo(db *dao.DaoDB, order *model.Af var actStoreSkuMap *jxutils.ActStoreSkuMap if len(skuIDMap) > 0 { if order2, err2 := c.LoadOrder(order.VendorOrderID, order.VendorID); err2 == nil { - actStoreSkuList, err := dao.GetEffectiveActStoreSkuInfo(db, 0, []int{order.VendorID}, []int{jxStoreID}, jxutils.IntMap2List(skuIDMap), order2.OrderCreatedAt, order2.OrderCreatedAt) + actStoreSkuList, err := dao.GetEffectiveActStoreSkuInfo(db, 0, []int{order.VendorID}, model.ActTypeAll, []int{jxStoreID}, jxutils.IntMap2List(skuIDMap), order2.OrderCreatedAt, order2.OrderCreatedAt) if err != nil { globals.SugarLogger.Errorf("updateAfsOrderSkuOtherInfo can not get sku promotion info for error:%v", err) return err diff --git a/business/jxcallback/orderman/order_comment.go b/business/jxcallback/orderman/order_comment.go index 5bdd9ed26..079ed953d 100644 --- a/business/jxcallback/orderman/order_comment.go +++ b/business/jxcallback/orderman/order_comment.go @@ -85,7 +85,10 @@ func (c *OrderManager) OnOrderComments(orderCommentList []*model.OrderComment) ( isNewComment = true if orderComment.IsReplied == 0 && time.Now().Sub(orderComment.CommentCreatedAt) < time.Duration(orderComment.ModifyDuration)*time.Hour { if storeDetail, err2 := dao.GetStoreDetail(db, orderComment.StoreID, orderComment.VendorID); err2 == nil { - c.replyOrderComment(storeDetail.VendorOrgCode, orderComment) + if storeDetail.AutoReplyType == model.AutoReplyAll || + orderComment.Score > JX_BAD_COMMENTS_MAX_LEVEL && storeDetail.AutoReplyType == model.AutoReplyGoodComment { + c.replyOrderComment(storeDetail.VendorOrgCode, orderComment) + } } } } diff --git a/business/jxcallback/orderman/orderman.go b/business/jxcallback/orderman/orderman.go index c907ed479..f66f1528a 100644 --- a/business/jxcallback/orderman/orderman.go +++ b/business/jxcallback/orderman/orderman.go @@ -115,8 +115,11 @@ func (c *OrderManager) GetStatusDuplicatedCount(status *model.OrderStatus) (dupl // todo 最好还是改成全事件回放算了 func LoadPendingOrders() { - orders := FixedOrderManager.LoadPendingOrders() - globals.SugarLogger.Infof("LoadPendingOrders orders count:%d", len(orders)) + orders, err := dao.LoadPendingOrders(dao.GetDB(), time.Now().Add(-pendingOrderGapMax), model.OrderStatusEndBegin) + globals.SugarLogger.Infof("LoadPendingOrders orders count:%d, err:%v", len(orders), err) + if err != nil { + return + } ordersCount := len(orders) if ordersCount > 0 { diff --git a/business/jxcallback/orderman/orderman_ext.go b/business/jxcallback/orderman/orderman_ext.go index 39c6b15d3..175b1584d 100644 --- a/business/jxcallback/orderman/orderman_ext.go +++ b/business/jxcallback/orderman/orderman_ext.go @@ -23,6 +23,9 @@ import ( const ( maxLastHours = 7 * 24 // 最多只能查询7天内的订单数据 defLastHours = 2 * 24 // 缺省是两天内的订单 + + orderSubTimeImmediatelyArrive = 8 + orderSubTimeDelayArrive = 5 ) type tWaybillExt struct { @@ -96,8 +99,7 @@ func (c *OrderManager) GetOrderSkuInfo(ctx *jxcontext.Context, vendorOrderID str t1.sku_name, IF(t1.shop_price = 0, t1.sale_price, t1.shop_price) shop_price, t1.sale_price, - t1.earning_price, - CAST(IF(t1.earning_price <> 0, t1.earning_price, IF(t1.shop_price <> 0 && t1.shop_price < t1.sale_price, t1.shop_price, t1.sale_price) * IF(t5.pay_percentage > 0, t5.pay_percentage, ?) / 100) AS SIGNED) real_earning_price, + CAST(IF(t1.earning_price <> 0, t1.earning_price, IF(t1.shop_price <> 0 && t1.shop_price < t1.sale_price, t1.shop_price, t1.sale_price) * IF(t5.pay_percentage > 0, t5.pay_percentage, ?) / 100) AS SIGNED) earning_price, t1.weight, t1.sku_type, t1.promotion_type, @@ -159,7 +161,7 @@ func (c *OrderManager) GetOrderInfo(ctx *jxcontext.Context, vendorOrderID string return nil, err } -func (c *OrderManager) GetOrderWaybillInfo(ctx *jxcontext.Context, vendorOrderID string, vendorID int, isNotEnded bool) (bills []*model.Waybill, err error) { +func (c *OrderManager) GetOrderWaybillInfo(ctx *jxcontext.Context, vendorOrderID string, vendorID int, isNotEnded, isGetPos bool) (bills []*model.WaybillExt, err error) { globals.SugarLogger.Debugf("GetOrderWaybillInfo orderID:%s", vendorOrderID) db := dao.GetDB() sql := ` @@ -176,7 +178,26 @@ func (c *OrderManager) GetOrderWaybillInfo(ctx *jxcontext.Context, vendorOrderID sqlParams = append(sqlParams, model.OrderStatusEndBegin) } err = dao.GetRows(db, &bills, sql, sqlParams...) - globals.SugarLogger.Infof("GetOrderWaybillInfo orderID:%s failed with error:%v", vendorOrderID, err) + if err == nil && isGetPos { + var taskBills []*model.WaybillExt + for _, v := range bills { + if v.Status >= model.WaybillStatusAccepted && v.Status <= model.WaybillStatusDelivering { + if handler := partner.GetRidderPositionGetter(v.WaybillVendorID); handler != nil { + taskBills = append(taskBills, v) + } + } + } + if len(taskBills) > 0 { + task := tasksch.NewParallelTask("GetOrderWaybillInfo", nil, ctx, + func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { + waybill := batchItemList[0].(*model.WaybillExt) + waybill.Lng, waybill.Lat, err = partner.GetRidderPositionGetter(waybill.WaybillVendorID).GetRidderPosition(ctx, waybill.VendorOrderID, waybill.VendorOrderID, waybill.VendorWaybillID, waybill.VendorWaybillID2) + return nil, err + }, taskBills) + tasksch.HandleTask(task, nil, false).Run() + task.GetResult(0) + } + } return bills, err } @@ -937,6 +958,7 @@ func (c *OrderManager) AmendMissingOrders(ctx *jxcontext.Context, vendorIDs []in } if len(dateVendorList) > 0 { var missingOrderList []*tOrderVendorPair + var updateOrderStatusList []*model.GoodsOrder db := dao.GetDB() vendorStoreIDMap := make(map[int]string) if storeID > 0 { @@ -987,8 +1009,21 @@ func (c *OrderManager) AmendMissingOrders(ctx *jxcontext.Context, vendorIDs []in for _, v := range orderList { pair := v.(*tOrderVendorPair) - if localOrderMap[jxutils.ComposeUniversalOrderID(pair.VendorOrderID, pair.VendorID)] == nil { + goodsOrder := localOrderMap[jxutils.ComposeUniversalOrderID(pair.VendorOrderID, pair.VendorID)] + if goodsOrder == nil { missingOrderList = append(missingOrderList, pair) + } else { + if !model.IsOrderFinalStatus(goodsOrder.Status) { + if goodsOrder.BusinessType == model.BusinessTypeImmediate { + if time.Now().Sub(goodsOrder.CreatedAt).Hours() >= orderSubTimeImmediatelyArrive { + updateOrderStatusList = append(updateOrderStatusList, goodsOrder) + } + } else { + if time.Now().Sub(goodsOrder.ExpectedDeliveredTime).Hours() >= orderSubTimeDelayArrive { + updateOrderStatusList = append(updateOrderStatusList, goodsOrder) + } + } + } } } case 1: @@ -1008,9 +1043,26 @@ func (c *OrderManager) AmendMissingOrders(ctx *jxcontext.Context, vendorIDs []in }, missingOrderList) tasksch.HandleTask(task2, task, true).Run() result, err = task2.GetResult(0) + case 2: + task3 := tasksch.NewParallelTask("AmendMissingOrders UpdateOrders", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx, + func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { + goodsOrder := batchItemList[0].(*model.GoodsOrder) + if handler := partner.GetPurchaseOrderHandlerFromVendorID(goodsOrder.VendorID); handler != nil { + status, err2 := handler.GetOrderStatus(goodsOrder.VendorOrgCode, goodsOrder.VendorOrderID) + if err = err2; err == nil { + if model.IsOrderFinalStatus(status) { + goodsOrder.Status = status + _, err = dao.UpdateEntity(db, goodsOrder, "Status") + } + } + } + return retVal, err + }, updateOrderStatusList) + tasksch.HandleTask(task3, task, true).Run() + _, err = task3.GetResult(0) } return result, err - }, 2) + }, 3) tasksch.HandleTask(task, nil, true).Run() if !isAsync { result, err2 := task.GetResult(0) diff --git a/business/jxcallback/orderman/waybill.go b/business/jxcallback/orderman/waybill.go index 1e9cba812..43b93b567 100644 --- a/business/jxcallback/orderman/waybill.go +++ b/business/jxcallback/orderman/waybill.go @@ -1,11 +1,17 @@ package orderman import ( + "fmt" "time" + "git.rosy.net.cn/jx-callback/business/partner" + + "git.rosy.net.cn/baseapi/platformapi/dadaapi" + "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/globals" @@ -19,6 +25,17 @@ var ( model.WaybillStatusRefuseFailedGetGoods: model.OrderStatusRefuseFailedGetGoods, model.WaybillStatusDeliverFailed: model.OrderStatusDeliverFailed, } + complaintReasonsMap = map[int]string{ + 1: "骑手态度恶劣", + 2: "骑手接单后未取货", + 3: "骑手取货太慢", + 4: "骑手送货太慢", + 5: "货品未送达", + 6: "货品有损坏", + 7: "骑手违规收取顾客其他费用", + 69: "骑手恶意取消订单", + 71: "骑手提前点击取货/送达", + } ) func (w *OrderManager) LoadPendingWaybills() []*model.Waybill { @@ -85,6 +102,9 @@ func (w *OrderManager) onWaybillNew(bill2 *model.Waybill, db *dao.DaoDB) (isDupl func (w *OrderManager) OnWaybillStatusChanged(bill *model.Waybill) (err error) { var isDuplicated bool + if bill.ActualFee == 0 { + bill.ActualFee = bill.DesiredFee + bill.TipFee + } bill.CourierMobile = jxutils.FormalizeMobile(bill.CourierMobile) db := dao.GetDB() dao.Begin(db) @@ -220,3 +240,26 @@ func (c *OrderManager) LoadWaybill(vendorWaybillID string, waybillVendorID int) } return bill, err } + +func GetComplaintReasons() (complaintReasonList []*dadaapi.ComplaintReason) { + for k, v := range complaintReasonsMap { + complaintReason := &dadaapi.ComplaintReason{ + ID: k, + Reason: v, + } + complaintReasonList = append(complaintReasonList, complaintReason) + } + return complaintReasonList +} + +func ComplaintRider(ctx *jxcontext.Context, vendorOrderID string, vendorID, waybillVendorID, complaintID int) (err error) { + db := dao.GetDB() + p := partner.GetDeliveryPlatformFromVendorID(waybillVendorID).Handler + wayBillList, err := dao.GetWayBillByOrderID(db, model.OrderStatusFinished, vendorID, waybillVendorID, vendorOrderID) + if err == nil && len(wayBillList) > 0 { + err = p.ComplaintRider(wayBillList[0], complaintID, complaintReasonsMap[complaintID]) + } else { + return fmt.Errorf("未查询到到相关订单,订单状态要求必须是完成!订单号:[%v] ,厂商:[%v],运送厂商:[%v]", vendorOrderID, vendorID, waybillVendorID) + } + return err +} diff --git a/business/jxcallback/scheduler/basesch/basesch.go b/business/jxcallback/scheduler/basesch/basesch.go index 72a09852d..1f623cd4f 100644 --- a/business/jxcallback/scheduler/basesch/basesch.go +++ b/business/jxcallback/scheduler/basesch/basesch.go @@ -37,8 +37,14 @@ func (c *BaseScheduler) PickupGoods(order *model.GoodsOrder, isSelfDelivery bool globals.SugarLogger.Infof("PickupGoods orderID:%s", order.VendorOrderID) if /*order.LockStatus == model.OrderStatusUnknown && */ order.Status == model.OrderStatusAccepted { if c.IsReallyCallPlatformAPI { - err = utils.CallFuncLogErrorWithInfo(func() error { - return partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).PickupGoods(order, isSelfDelivery, userName) + handler := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID) + err = utils.CallFuncLogErrorWithInfo(func() (err error) { + if err = handler.PickupGoods(order, isSelfDelivery, userName); err != nil { + if status, err2 := handler.GetOrderStatus(order.VendorOrgCode, order.VendorOrderID); err2 == nil && status >= model.OrderStatusFinished { + err = nil + } + } + return err }, "PickupGoods orderID:%s", order.VendorOrderID) } } else { diff --git a/business/jxcallback/scheduler/basesch/basesch_ext.go b/business/jxcallback/scheduler/basesch/basesch_ext.go index 31d20b865..ed6afc1d4 100644 --- a/business/jxcallback/scheduler/basesch/basesch_ext.go +++ b/business/jxcallback/scheduler/basesch/basesch_ext.go @@ -236,6 +236,69 @@ func (c *BaseScheduler) ConfirmSelfTake(ctx *jxcontext.Context, vendorOrderID st return err } +func (c *BaseScheduler) SetOrderWaybillTip(ctx *jxcontext.Context, vendorOrderID string, vendorID int, tipFee int64) (err error) { + order, err2 := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID) + if err = err2; err == nil { + err = c.SetOrderWaybillTipByOrder(ctx, order, tipFee) + } + return err +} + +func isWaybillCanAddTip(waybill *model.Waybill) (isCan bool) { + isCan = waybill.Status >= model.WaybillStatusNew && waybill.Status < model.WaybillStatusAccepted && partner.GetWaybillTipUpdater(waybill.WaybillVendorID) != nil + return isCan +} + +func (c *BaseScheduler) SetOrderWaybillTipByOrder(ctx *jxcontext.Context, order *model.GoodsOrder, tipFee int64) (err error) { + roundTipFee := tipFee / 100 * 100 + if roundTipFee != tipFee { + return fmt.Errorf("小费必须是1元的整数倍") + } + if order.WaybillTipMoney >= tipFee { + return fmt.Errorf("当前小费已经是%s元,想要设置%s元", jxutils.IntPrice2StandardString(order.WaybillTipMoney), jxutils.IntPrice2StandardString(tipFee)) + } + + db := dao.GetDB() + storeDetail, err2 := dao.GetStoreDetail(db, jxutils.GetSaleStoreIDFromOrder(order), order.VendorID) + if err = err2; err != nil { + return err + } + + // 如果平台支持设置配送小费,必须要成功设置 + if handler := partner.GetWaybillTipUpdater(order.VendorID); handler != nil { + if err = handler.UpdateWaybillTip(ctx, order.VendorOrgCode, order.VendorStoreID, order.VendorOrderID, "", "", utils.Int2Str(storeDetail.CityCode), tipFee); err != nil { + return err + } + } + order.WaybillTipMoney = tipFee + partner.CurOrderManager.UpdateOrderFields(order, []string{"WaybillTipMoney"}) + + waybills, err := dao.GetWayBillByOrderID(db, 0, order.VendorID, 0, order.VendorOrderID) + if err == nil { + var waybills2 []*model.Waybill + for _, v := range waybills { + // 必须是三方配送 + if !model.IsWaybillPlatformOwn(v) && isWaybillCanAddTip(v) { + waybills2 = append(waybills2, v) + } + } + if len(waybills2) > 0 { + task := tasksch.NewParallelTask("SetOrderWaybillTipByOrder", nil, ctx, + func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { + waybill := batchItemList[0].(*model.Waybill) + handler := partner.GetWaybillTipUpdater(waybill.WaybillVendorID) + if err == nil { + err = handler.UpdateWaybillTip(ctx, waybill.VendorOrgCode, storeDetail.VendorStoreID, waybill.VendorOrderID, waybill.VendorWaybillID, waybill.VendorWaybillID2, utils.Int2Str(storeDetail.CityCode), tipFee) + } + return nil, err + }, waybills2) + tasksch.HandleTask(task, nil, false).Run() + _, err = task.GetResult(0) + } + } + return err +} + func (c *BaseScheduler) confirmSelfTake(ctx *jxcontext.Context, order *model.GoodsOrder, selfTakeCode string) (err error) { globals.SugarLogger.Debugf("confirmSelfTake orderID:%s, selfTakeCode:%s", order.VendorOrderID, selfTakeCode) if order.VendorID == model.VendorIDJD { diff --git a/business/jxcallback/scheduler/defsch/defsch.go b/business/jxcallback/scheduler/defsch/defsch.go index 1d757083c..fa5e9cc67 100644 --- a/business/jxcallback/scheduler/defsch/defsch.go +++ b/business/jxcallback/scheduler/defsch/defsch.go @@ -6,11 +6,14 @@ import ( "sync" "time" + "git.rosy.net.cn/jx-callback/business/jxutils/ddmsg" + "git.rosy.net.cn/jx-callback/business/jxutils/jxcontext" "git.rosy.net.cn/jx-callback/business/jxutils/netprinter" "git.rosy.net.cn/jx-callback/business/jxutils/smsmsg" "git.rosy.net.cn/jx-callback/business/msghub" + "git.rosy.net.cn/baseapi/platformapi/dingdingapi" "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/business/jxcallback/scheduler" "git.rosy.net.cn/jx-callback/business/jxcallback/scheduler/basesch" @@ -157,6 +160,7 @@ func (s *WatchOrderInfo) updateOrderStoreFeature(order *model.GoodsOrder) (err e s.autoPickupTimeoutMinute = int(storeDetail.AutoPickup) s.isDeliveryCompetition = storeDetail.DeliveryCompetition != 0 } + globals.SugarLogger.Debugf("updateOrderStoreFeature2 orderID:%s, isDeliveryCompetition:%t", order.VendorOrderID, s.isDeliveryCompetition) return err } @@ -175,7 +179,7 @@ func (w *WatchOrderInfo) StopTimer(statusType, vendorID, status int) { for _, timerInfo := range w.timerList { if (statusType == -1 || statusType == timerInfo.statusType) && (vendorID == -1 || vendorID == timerInfo.vendorID) && - (status == -1 || status <= timerInfo.status) { + (status == -1 || status >= timerInfo.status) { if timerInfo.timer != nil { timerInfo.timer.Stop() timerInfo.timer = nil @@ -187,6 +191,10 @@ func (w *WatchOrderInfo) StopTimer(statusType, vendorID, status int) { w.timerList = newTimerList } +func (w *WatchOrderInfo) AddTimer(timerInfo *tTimerInfo) { + w.timerList = append(w.timerList, timerInfo) +} + func (w *WatchOrderInfo) GetCreateWaybillTimeout() (timeoutSecond int) { // if w.timerStatusType == scheduler.TimerStatusTypeWaybill && w.timerStatus == model.WaybillStatusNew { // timeoutSecond = int(w.timerTime.Sub(time.Now()) / time.Second) @@ -267,7 +275,7 @@ func init() { return nil }, ShouldSetTimer: func(savedOrderInfo *WatchOrderInfo, bill *model.Waybill) bool { - return savedOrderInfo.autoPickupTimeoutMinute > 0 + return savedOrderInfo.autoPickupTimeoutMinute > 0 && savedOrderInfo.order.Status < model.OrderStatusFinishedPickup }, }, model.OrderStatusFinishedPickup: &StatusActionConfig{ @@ -304,7 +312,6 @@ func init() { order.VendorID == bill.WaybillVendorID && savedOrderInfo.isDeliveryCompetition && model.IsOrderDeliveryByPlatform(order) && - order.DeliveryType != model.OrderDeliveryTypeSelfTake && isOrderCanSwitch2SelfDeliver(order) && (order.Status >= model.OrderStatusFinishedPickup && order.Status < model.OrderStatusEndBegin) }, @@ -325,9 +332,8 @@ func init() { order.VendorID == bill.WaybillVendorID && savedOrderInfo.isDeliveryCompetition && model.IsOrderDeliveryByPlatform(order) && - order.DeliveryType != model.OrderDeliveryTypeSelfTake && isOrderCanSwitch2SelfDeliver(order) && - (order.Status >= model.OrderStatusFinishedPickup && order.Status < model.OrderStatusEndBegin) + (order.Status >= model.OrderStatusAccepted && order.Status < model.OrderStatusEndBegin) // 运单与订单时间有错序的情况,放开订单条件至OrderStatusAccepted }, }, //*/ @@ -453,24 +459,35 @@ func (s *DefScheduler) OnWaybillStatusChanged(bill *model.Waybill, isPending boo if !isPending { if order.Status > model.OrderStatusEndBegin { s.ProxyCancelWaybill(order, bill, partner.CancelWaybillReasonNotAcceptIntime, partner.CancelWaybillReasonStrNotAcceptIntime) - } else if model.IsOrderHaveWaybill(order) { - globals.SugarLogger.Debugf("OnWaybillStatusChanged multiple waybill created, bill:%v", bill) - if model.IsWaybillPlatformOwn(bill) { // 是购物平台运单 - if !model.IsOrderHaveOwnWaybill(order) { // 既有运单不是购物平台运单 - globals.SugarLogger.Infof("OnWaybillStatusChanged bill:%v purchase platform bill came later than others, strange!!!", bill) - oldBill := savedOrderInfo.waybills[order.WaybillVendorID] - if oldBill != nil { - s.ProxyCancelWaybill(order, oldBill, partner.CancelWaybillReasonNotAcceptIntime, partner.CancelWaybillReasonStrNotAcceptIntime) - } else { - globals.SugarLogger.Warnf("OnWaybillStatusChanged bill:%v, oldBill is null, strange!!!", bill) + } else { + needAddTip := order.WaybillTipMoney > 0 && !model.IsWaybillPlatformOwn(bill) + if model.IsOrderHaveWaybill(order) { + globals.SugarLogger.Debugf("OnWaybillStatusChanged multiple waybill created, bill:%v", bill) + if model.IsWaybillPlatformOwn(bill) { // 是购物平台运单 + if !model.IsOrderHaveOwnWaybill(order) { // 既有运单不是购物平台运单 + globals.SugarLogger.Infof("OnWaybillStatusChanged bill:%v purchase platform bill came later than others, strange!!!", bill) + oldBill := savedOrderInfo.waybills[order.WaybillVendorID] + if oldBill != nil { + s.ProxyCancelWaybill(order, oldBill, partner.CancelWaybillReasonNotAcceptIntime, partner.CancelWaybillReasonStrNotAcceptIntime) + } else { + globals.SugarLogger.Warnf("OnWaybillStatusChanged bill:%v, oldBill is null, strange!!!", bill) + } + } + s.updateOrderByBill(order, nil, false) + if time.Now().Sub(order.OrderCreatedAt) < 2*time.Minute { // 京东一些门店设置成了接单即拣货完成,这种情况下自动调用拣货完成 + s.autoPickupGood(savedOrderInfo) + } + } else { + needAddTip = false + s.ProxyCancelWaybill(order, bill, partner.CancelWaybillReasonNotAcceptIntime, partner.CancelWaybillReasonStrNotAcceptIntime) + } + } + if needAddTip { + if handler := partner.GetWaybillTipUpdater(bill.WaybillVendorID); handler != nil { + if storeDetail, err2 := dao.GetStoreDetail(dao.GetDB(), jxutils.GetSaleStoreIDFromOrder(order), order.VendorID); err2 == nil { + handler.UpdateWaybillTip(jxcontext.AdminCtx, order.VendorOrgCode, order.VendorStoreID, order.VendorOrderID, bill.VendorWaybillID, bill.VendorWaybillID2, utils.Int2Str(storeDetail.CityCode), order.WaybillTipMoney) } } - s.updateOrderByBill(order, nil, false) - if time.Now().Sub(order.OrderCreatedAt) < 2*time.Minute { // 京东一些门店设置成了接单即拣货完成,这种情况下自动调用拣货完成 - s.autoPickupGood(savedOrderInfo) - } - } else { - s.ProxyCancelWaybill(order, bill, partner.CancelWaybillReasonNotAcceptIntime, partner.CancelWaybillReasonStrNotAcceptIntime) } } flag2Clear := model.WaybillVendorID2Mask(bill.WaybillVendorID) @@ -840,6 +857,7 @@ func (s *DefScheduler) resetTimer(savedOrderInfo *WatchOrderInfo, bill *model.Wa ts.StopTimer(statusType, vendorID, status) }, jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID)) }) + savedOrderInfo.AddTimer(timerInfo) } globals.SugarLogger.Debugf("resetTimer, orderID:%s, statusType:%d, status:%d, timeout:%v", order.VendorOrderID, statusType, status, timeout) } else { @@ -1184,29 +1202,41 @@ func (s *DefScheduler) watchOrderWaybills(savedOrderInfo *WatchOrderInfo) { savedOrderInfo.SetOrder(order) if isNeedWatch3rdWaybill(order) { if isNeedWatchWaybillTip(order) { + // tipFee := getWaybillTip(order) + // if tipFee > order.WaybillTipMoney { + // vendorStatus := fmt.Sprintf("应设置小费:%s", jxutils.IntPrice2StandardCurrencyString(tipFee)) + // remark := "" + // if false { + // err = s.SetOrderWaybillTipByOrder(jxcontext.AdminCtx, order, tipFee) + // if err == nil { + // vendorStatus += "成功" + // } else { + // vendorStatus += "失败" + // remark = fmt.Sprint(err) + // } + // } else { + // vendorStatus += "空操作" + // } + // partner.CurOrderManager.OnOrderMsg(order, vendorStatus, remark) + // } if handler, ok := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).(partner.IAddWaybillTip); ok && handler != nil { var remark string tipFee := getWaybillTip(order) vendorStatus := fmt.Sprintf("设置小费:%s", jxutils.IntPrice2StandardCurrencyString(tipFee)) - if curTipFee, err := handler.GetWaybillTip(jxcontext.AdminCtx, order); err == nil { - tipFee2Add := tipFee - curTipFee - vendorStatus += fmt.Sprintf(", 本次添加:%s", jxutils.IntPrice2StandardCurrencyString(tipFee2Add)) - if false { //tipFee2Add > 0 { - err := handler.AddWaybillTip(jxcontext.AdminCtx, order, tipFee2Add) - if err == nil { - vendorStatus += "成功" - order.WaybillTipMoney += tipFee2Add - partner.CurOrderManager.UpdateOrderFields(order, []string{"WaybillTipMoney"}) - } else { - vendorStatus += "失败" - remark = fmt.Sprint(err) - } + tipFee2Add := tipFee - order.WaybillTipMoney + vendorStatus += fmt.Sprintf(", 本次添加:%s", jxutils.IntPrice2StandardCurrencyString(tipFee2Add)) + if false { //tipFee2Add > 0 { + err := handler.UpdateWaybillTip(jxcontext.AdminCtx, order.VendorOrgCode, order.VendorStoreID, order.VendorOrderID, order.VendorOrderID, "", "", tipFee) + if err == nil { + vendorStatus += "成功" + order.WaybillTipMoney = tipFee + partner.CurOrderManager.UpdateOrderFields(order, []string{"WaybillTipMoney"}) } else { - vendorStatus += "空操作" + vendorStatus += "失败" + remark = fmt.Sprint(err) } } else { - vendorStatus += "失败" - remark = fmt.Sprint(err) + vendorStatus += "空操作" } partner.CurOrderManager.OnOrderMsg(order, vendorStatus, remark) } @@ -1251,18 +1281,35 @@ func OnDefSchConfChanged(key, value string) { } } +func setFakeActualPayPrice(order *model.GoodsOrder) (newOrder *model.GoodsOrder) { + orderCopy := *order + storeDetail, err := dao.GetStoreDetail(dao.GetDB(), order.JxStoreID, order.VendorID) + if err == nil { + if storeDetail.PayPercentage < 50 { + orderCopy.ActualPayPrice = order.TotalShopMoney * (100 - int64(storeDetail.PayPercentage/2)) * 100 + } else { + orderCopy.ActualPayPrice = order.EarningPrice + } + } + newOrder = &orderCopy + return newOrder +} + func (s *DefScheduler) notifyNewOrder(order *model.GoodsOrder) { if order.Flag&model.OrderFlagMaskFake == 0 { utils.CallFuncAsync(func() { + order = setFakeActualPayPrice(order) netprinter.PrintOrderByOrder(jxcontext.AdminCtx, order) weixinmsg.NotifyNewOrder(order) smsmsg.NotifyNewOrder(order) + OrderProfitWarning(order) }) } } func (s *DefScheduler) notifyUserApplyCancel(order *model.GoodsOrder, cancelReason string) { utils.CallFuncAsync(func() { + order = setFakeActualPayPrice(order) weixinmsg.NotifyUserApplyCancel(order, cancelReason) }) } @@ -1270,6 +1317,7 @@ func (s *DefScheduler) notifyUserApplyCancel(order *model.GoodsOrder, cancelReas func (s *DefScheduler) notifyOrderCanceled(order *model.GoodsOrder) { if order.Flag&model.OrderFlagMaskFake == 0 { utils.CallFuncAsync(func() { + order = setFakeActualPayPrice(order) weixinmsg.NotifyOrderCanceled(order) smsmsg.NotifyOrderCanceled(order) }) @@ -1291,3 +1339,46 @@ func isOrderCanSwitch2SelfDeliver(order *model.GoodsOrder) (isCan bool) { } return isCan } + +//订单预计利润若低于0,则向门店运营负责人发送钉钉消息 +func OrderProfitWarning(order *model.GoodsOrder) { + var ( + operatorName string + operatorPhone string + noticeMsg string + profit float64 + storeID int + ) + db := dao.GetDB() + if order == nil { + return + } + if order.TotalShopMoney == 0 { + globals.SugarLogger.Debugf("OrderProfitWarning TotalShopMoney=0 orderID:%s", order.VendorOrderID) + return + } + storeID = jxutils.GetShowStoreIDFromOrder(order) + storeDetail, err := dao.GetStoreDetail(db, storeID, order.VendorID) + if storeDetail != nil && err == nil { + payPercentage := storeDetail.PayPercentage + if payPercentage >= 50 { + profit = utils.Str2Float64(utils.Int64ToStr(order.TotalShopMoney-order.EarningPrice-order.DistanceFreightMoney-order.WaybillTipMoney)) / 100 + } else { + profit = utils.Str2Float64(utils.Int64ToStr(order.TotalShopMoney*int64(payPercentage)/200)) / 100 + } + if profit < 0 { + if storeDetail.OperatorPhone != "" { + operatorName = storeDetail.OperatorName + operatorPhone = storeDetail.OperatorPhone + } else if storeDetail.OperatorPhone2 != "" { + operatorName = storeDetail.OperatorName2 + operatorPhone = storeDetail.OperatorPhone2 + } + noticeMsg = fmt.Sprintf("利润 :[%v],运营负责人:[%v],门店ID:[%v],平台门店ID[%v],门店名:[%v],订单号(点击进入详情):%v", profit, operatorName, order.StoreID, order.VendorStoreID, order.StoreName, globals.BackstageHost+"/#/ordermanager/"+order.VendorOrderID) + user, err := dao.GetUserByID(db, "mobile", operatorPhone) + if user != nil && err == nil { + ddmsg.SendUserMessage(dingdingapi.MsgTyeText, user.UserID, "警告!此订单利润低于0", noticeMsg) + } + } + } +} diff --git a/business/jxcallback/scheduler/defsch/defsch_ext.go b/business/jxcallback/scheduler/defsch/defsch_ext.go index 0681eb9e8..9acf53a29 100644 --- a/business/jxcallback/scheduler/defsch/defsch_ext.go +++ b/business/jxcallback/scheduler/defsch/defsch_ext.go @@ -214,13 +214,13 @@ func (s *DefScheduler) QueryOrderWaybillFeeInfoEx(ctx *jxcontext.Context, vendor if err != nil { return nil, err } - waybillList, err := partner.CurOrderManager.GetOrderWaybillInfo(ctx, vendorOrderID, vendorID, true) + waybillList, err := partner.CurOrderManager.GetOrderWaybillInfo(ctx, vendorOrderID, vendorID, true, false) if err != nil { return nil, err } waybillMap := make(map[int]*model.Waybill) for _, bill := range waybillList { - waybillMap[bill.WaybillVendorID] = bill + waybillMap[bill.WaybillVendorID] = &bill.Waybill } deliveryFeeMap = make(map[int]*partner.WaybillFeeInfo) @@ -238,7 +238,7 @@ func (s *DefScheduler) QueryOrderWaybillFeeInfoEx(ctx *jxcontext.Context, vendor if storeCourier.Status != model.StoreStatusOpened { feeInfo = &partner.WaybillFeeInfo{ ErrCode: partner.WaybillFeeErrCodeCourierNotOpen, - ErrStr: fmt.Sprintf("%d配送门店没有启用", storeCourier.VendorID), + ErrStr: fmt.Sprintf("暂未开通,联系运营"), } } else { if handler := partner.GetDeliveryPlatformFromVendorID(storeCourier.VendorID); handler != nil { diff --git a/business/jxstore/act/act.go b/business/jxstore/act/act.go index 4de287908..a1ca25b47 100644 --- a/business/jxstore/act/act.go +++ b/business/jxstore/act/act.go @@ -113,7 +113,7 @@ func ActStoreSkuParam2Model(ctx *jxcontext.Context, db *dao.DaoDB, act *model.Ac skuIDs := jxutils.IntMap2List(skuIDMap) // 判断活动是否重叠的检查,当前忽略京东平台及所有结算信息 if !(len(vendorIDs) == 1 && vendorIDs[0] == model.VendorIDJD || act.Type == model.ActSkuFake) { - effectActStoreSkuList, err := dao.GetEffectiveActStoreSkuInfo(db, 0, vendorIDs, storeIDs, skuIDs, act.BeginAt, act.EndAt) + effectActStoreSkuList, err := dao.GetEffectiveActStoreSkuInfo(db, 0, vendorIDs, act.Type, storeIDs, skuIDs, act.BeginAt, act.EndAt) if err != nil { globals.SugarLogger.Errorf("GetEffectiveActStoreSkuInfo can not get sku promotion info for error:%v", err) return nil, nil, nil, err @@ -138,62 +138,64 @@ func ActStoreSkuParam2Model(ctx *jxcontext.Context, db *dao.DaoDB, act *model.Ac for _, vendorID := range vendorIDs { storeDetail, err2 := dao.GetStoreDetail(db, storeID, vendorID) if err = err2; err == nil { - if storeDetail.IsSync != 0 && storeDetail.Status != model.StoreStatusDisabled && storeDetail.VendorStatus != model.StoreStatusDisabled { - for _, v := range oneStoreSkuParam { - validVendorMap[vendorID] = 1 - validSkuMap[v.SkuID] = 1 - v.ActID = act.ID - actSkuMap := &model.ActStoreSkuMap{ - ActID: act.ID, - StoreID: storeID, - SkuID: v.SkuID, - VendorID: vendorID, - } - v.OriginalPrice = actSkuMap.VendorPrice - storeSkuInfo := storeSkuMap[jxutils.Combine2Int(v.StoreID, v.SkuID)] - if storeSkuInfo != nil { - jxPrice := storeSkuInfo.Price - actSkuMap.VendorPrice = int64(getVendorPriceFromStoreSkuBind(storeSkuInfo, vendorID)) - v.OriginalPrice = int64(jxPrice) - } - var err2 error - if act.Type != model.ActSkuFake { // 非结算,要计算实际活动价格 - if storeSkuInfo == nil { - v.ErrMsg = fmt.Sprintf("门店:%d没有关注商品:%d", v.StoreID, v.SkuID) - wrongSkuList = append(wrongSkuList, v) - continue + if storeDetail.IsSync != 0 { + if act.Type == model.ActSkuFake || + storeDetail.Status != model.StoreStatusDisabled && storeDetail.VendorStatus != model.StoreStatusDisabled { + for _, v := range oneStoreSkuParam { + validVendorMap[vendorID] = 1 + validSkuMap[v.SkuID] = 1 + v.ActID = act.ID + actSkuMap := &model.ActStoreSkuMap{ + ActID: act.ID, + StoreID: storeID, + SkuID: v.SkuID, + VendorID: vendorID, } - if !(vendorID == model.VendorIDJX || act.Type == model.ActSkuFake) { - actSkuMap.SyncStatus = model.SyncFlagNewMask + storeSkuInfo := storeSkuMap[jxutils.Combine2Int(v.StoreID, v.SkuID)] + if storeSkuInfo != nil { + jxPrice := storeSkuInfo.Price + actSkuMap.VendorPrice = int64(getVendorPriceFromStoreSkuBind(storeSkuInfo, vendorID)) + v.OriginalPrice = int64(jxPrice) } - if v.ActPrice != 0 { - actSkuMap.ActualActPrice = v.ActPrice - } else { - percentage := act.PricePercentage - if v.PricePercentage != 0 { - percentage = v.PricePercentage + var err2 error + if act.Type != model.ActSkuFake { // 非结算,要计算实际活动价格 + if storeSkuInfo == nil { + v.ErrMsg = fmt.Sprintf("门店:%d没有关注商品:%d", v.StoreID, v.SkuID) + wrongSkuList = append(wrongSkuList, v) + continue } - actSkuMap.ActualActPrice = int64(jxutils.CaculateSkuVendorPrice(int(actSkuMap.VendorPrice), percentage, 0)) - if actSkuMap.ActualActPrice > 10 { - actSkuMap.ActualActPrice = int64(math.Floor(float64(actSkuMap.ActualActPrice)/10) * 10) + if !(vendorID == model.VendorIDJX || act.Type == model.ActSkuFake) { + actSkuMap.SyncStatus = model.SyncFlagNewMask + } + if v.ActPrice != 0 { + actSkuMap.ActualActPrice = v.ActPrice + } else { + percentage := act.PricePercentage + if v.PricePercentage != 0 { + percentage = v.PricePercentage + } + actSkuMap.ActualActPrice = int64(jxutils.CaculateSkuVendorPrice(int(actSkuMap.VendorPrice), percentage, 0)) + if actSkuMap.ActualActPrice > 10 { + actSkuMap.ActualActPrice = int64(math.Floor(float64(actSkuMap.ActualActPrice)/10) * 10) + } + } + if actSkuMap.ActualActPrice <= 0 { + actSkuMap.ActualActPrice = 1 + } + if err2 = checkDiscountValidation(vendorIDs, act.Type, float64(actSkuMap.ActualActPrice)*100/float64(actSkuMap.VendorPrice)); err2 != nil { + v.ErrMsg = err2.Error() + v.ActualActPrice = actSkuMap.ActualActPrice + v.VendorPrice = actSkuMap.VendorPrice + wrongSkuList = append(wrongSkuList, v) } } - if actSkuMap.ActualActPrice <= 0 { - actSkuMap.ActualActPrice = 1 - } - if err2 = checkDiscountValidation(vendorIDs, act.Type, float64(actSkuMap.ActualActPrice)*100/float64(actSkuMap.VendorPrice)); err2 != nil { - v.ErrMsg = err2.Error() - v.ActualActPrice = actSkuMap.ActualActPrice - v.VendorPrice = actSkuMap.VendorPrice - wrongSkuList = append(wrongSkuList, v) + if err2 == nil { + dao.WrapAddIDCULDEntity(actSkuMap, ctx.GetUserName()) + actStoreSkuMapList = append(actStoreSkuMapList, actSkuMap) } } - if err2 == nil { - dao.WrapAddIDCULDEntity(actSkuMap, ctx.GetUserName()) - actStoreSkuMapList = append(actStoreSkuMapList, actSkuMap) - } + wholeValidVendorMap[vendorID] = 1 } - wholeValidVendorMap[vendorID] = 1 } } else if !dao.IsNoRowsError(err) { return nil, nil, nil, err @@ -318,8 +320,12 @@ func checkDiscountValidation(vendorIDs []int, actType int, pricePercentage float } else if len(vendorIDs) > 0 && vendorIDs[0] == model.VendorIDMTWM && pricePercentageMin < minDiscount4SkuDirectDownMTWM { err = fmt.Errorf("美团平台%s活动折扣必须大于:%d", model.ActTypeName[actType], minDiscount4SkuDirectDownMTWM) } - } else if actType == model.ActSkuSecKill && pricePercentageMax > maxDiscount4SkuSecKill { - err = fmt.Errorf("%s活动折扣必须小于:%d", model.ActTypeName[actType], maxDiscount4SkuSecKill) + } else if actType == model.ActSkuSecKill { + if len(vendorIDs) > 0 && vendorIDs[0] == model.VendorIDMTWM && pricePercentageMax > minDiscount4SkuDirectDownMTWM { + err = fmt.Errorf("美团平台%s活动折扣必须小于:%d", model.ActTypeName[actType], minDiscount4SkuDirectDownMTWM) + } else if pricePercentageMax > maxDiscount4SkuSecKill { + err = fmt.Errorf("%s活动折扣必须小于:%d", model.ActTypeName[actType], maxDiscount4SkuSecKill) + } } return err } @@ -341,8 +347,6 @@ func checkActValidation(act *model.Act, vendorIDs []int) (err error) { errList.AddErr(fmt.Errorf("必须指定缺省活动折扣")) } else if err = checkDiscountValidation(vendorIDs, act.Type, float64(act.PricePercentage)); err != nil { errList.AddErr(err) - } else if act.Type == model.ActSkuSecKill && vendorIDMap[model.VendorIDMTWM] == 1 { - errList.AddErr(fmt.Errorf("%s平台不支持%s活动", model.VendorChineseNames[model.VendorIDMTWM], model.ActTypeName[model.ActSkuSecKill])) } } else if act.Type == model.ActSkuFake { @@ -611,7 +615,7 @@ func GetActStoreSkuInfo(ctx *jxcontext.Context, actID int, vendorIDs []int, keyw return nil, err } for _, v := range actStoreSkuList { - v.SkuName = jxutils.ComposeSkuName(v.Prefix, v.SkuNameName, v.Comment, v.Unit, v.SpecQuality, v.SpecUnit, 0) + v.SkuName = jxutils.ComposeSkuName(v.Prefix, v.SkuNameName, v.Comment, v.Unit, v.SpecQuality, v.SpecUnit, 0, v.ExPrefix, v.ExPrefixBegin, v.ExPrefixEnd) } if pageSize > 0 && pageSize != model.UnlimitedPageSize { pagedInfo := &model.PagedInfo{ @@ -760,7 +764,7 @@ func SyncAct(ctx *jxcontext.Context, parentTask tasksch.ITask, actID int, vendor if vendorIDs == nil { vendorIDs = partner.GetVendorIDsFromActMap(actMap) } - if len(vendorIDs) == 0 || actMap[vendorIDs[0]].Type == model.ActSkuFake { + if len(vendorIDs) == 0 || vendorIDs[0] == model.VendorIDJX || actMap[vendorIDs[0]].Type == model.ActSkuFake { return "", nil } task := tasksch.NewParallelTask("SyncAct", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx, @@ -888,16 +892,15 @@ func RefreshPageActs(ctx *jxcontext.Context, vendorIDs []int, createdFrom time.T return hint, err } -func DeleteSkusFromAct(ctx *jxcontext.Context, vendorID int, skuIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) { +func DeleteSkusFromAct(ctx *jxcontext.Context, vendorID int, actTypes, skuIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) { db := dao.GetDB() actMap := make(map[int]*model.Act) for _, skuID := range skuIDs { - pagedInfo, err2 := dao.QueryActs(db, 0, 0, -1, -1, "", vendorID, []int{model.ActStatusCreated}, []int{model.ActSkuDirectDown, model.ActSkuSecKill}, nil, 0, skuID, 0, + pagedInfo, err2 := dao.QueryActs(db, 0, 0, -1, -1, "", vendorID, []int{model.ActStatusCreated}, actTypes, nil, 0, skuID, 0, utils.DefaultTimeValue, utils.DefaultTimeValue, time.Now().Add(-24*30*3*time.Hour), utils.DefaultTimeValue) if err = err2; err != nil { return "", err } - // globals.SugarLogger.Debug(utils.Format4Output(pagedInfo, false)) for _, v := range pagedInfo.Data { actMap[v.Act.ID] = &v.Act } @@ -951,7 +954,7 @@ func DeleteSkusFromAct(ctx *jxcontext.Context, vendorID int, skuIDs []int, isAsy return hint, err } -func ForceUpdateVendorPrice(ctx *jxcontext.Context, vendorID int, actType int, storeSkuList []*ActStoreSkuParam, isAsync bool) (hint string, err error) { +func ForceUpdateVendorPrice(ctx *jxcontext.Context, vendorID int, actType int, storeSkuList []*ActStoreSkuParam, lockTime time.Time, isAsync bool) (hint string, err error) { var wrongSkuList []*ActStoreSkuParam var storeSkuBindList []*model.StoreSkuBind @@ -985,13 +988,15 @@ func ForceUpdateVendorPrice(ctx *jxcontext.Context, vendorID int, actType int, s } } if storeSkuBind != nil { - dao.SetStoreSkuBindVendorPrice(storeSkuBind, vendorID, vendorPrice) + dao.SetStoreSkuBindVendorPrice(storeSkuBind, vendorID, vendorPrice, lockTime) if vendorID != model.VendorIDJX { dao.SetStoreSkuBindSyncStatus(storeSkuBind, vendorID, dao.GetStoreSkuBindSyncStatus(storeSkuBind, vendorID)|model.SyncFlagPriceMask) } storeSkuBind.LastOperator = ctx.GetUserName() storeSkuBindList = append(storeSkuBindList, storeSkuBind) } + } else if dao.IsNoRowsError(err) { // 忽略不存在错 + err = nil } else { errList.AddErr(fmt.Errorf("获取门店:%d商品:%d出错:%s", v.StoreID, v.SkuID, err)) } diff --git a/business/jxstore/cms/cms.go b/business/jxstore/cms/cms.go index 59f0ecda8..68258f6cb 100644 --- a/business/jxstore/cms/cms.go +++ b/business/jxstore/cms/cms.go @@ -100,6 +100,8 @@ func InitServiceInfo(version string, buildTime time.Time, gitCommit string) { "storePriceTypeName": model.StorePriceTypeName, "payStatusName": model.PayStatusName, "refundStatusName": model.RefundStatusName, + "autoReplyTypeName": model.AutoReplyTypeName, + "complaintReasons": model.ComplaintReasons, }, } } diff --git a/business/jxstore/cms/sku.go b/business/jxstore/cms/sku.go index 202d80a75..69bb3ca00 100644 --- a/business/jxstore/cms/sku.go +++ b/business/jxstore/cms/sku.go @@ -7,6 +7,12 @@ import ( "strings" "time" + "git.rosy.net.cn/jx-callback/business/jxutils/tasksch" + + "git.rosy.net.cn/baseapi/platformapi/jdapi" + + "git.rosy.net.cn/jx-callback/globals/api" + "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/baseapi/utils/errlist" "git.rosy.net.cn/jx-callback/business/jxutils" @@ -54,7 +60,7 @@ func GetVendorCategories(ctx *jxcontext.Context, vendorID int, parentID string) // parentID 为-1表示所有 func GetCategories(ctx *jxcontext.Context, parentID int) (catList []*dao.SkuCategoryWithVendor, err error) { db := dao.GetDB() - cats, err := dao.GetCategories(db, parentID, nil) + cats, err := dao.GetCategories(db, parentID, 0, nil) if err == nil { var ids []int for _, v := range cats { @@ -516,7 +522,10 @@ func GetSkuNames(ctx *jxcontext.Context, keyword string, isBySku bool, params ma t1.status, t1.is_spu, t1.desc_img, - t1.upc` + t1.upc, + t1.ex_prefix, + t1.ex_prefix_begin, + t1.ex_prefix_end` if isBySku { sql += `, t2.id` @@ -545,6 +554,9 @@ func GetSkuNames(ctx *jxcontext.Context, keyword string, isBySku bool, params ma t1.upc, t1.jd_id, t1.jd_sync_status, + t1.ex_prefix, + t1.ex_prefix_begin, + t1.ex_prefix_end, CONCAT("[", GROUP_CONCAT(DISTINCT CONCAT('{"id":', t2.id, ',"comment":"', t2.comment, '","status":', t2.status, ',"createdAt":"', CONCAT(REPLACE(t2.created_at," ","T"),"+08:00"), '","updatedAt":"', CONCAT(REPLACE(t2.updated_at," ","T"),"+08:00"), '","lastOperator":"', t2.last_operator, '","specQuality":', t2.spec_quality, ',"specUnit":"', t2.spec_unit, @@ -575,6 +587,7 @@ func GetSkuNames(ctx *jxcontext.Context, keyword string, isBySku bool, params ma var skuIDs []int for _, skuName := range skuNamesInfo.SkuNames { + skuName.FullName = jxutils.ComposeSkuName(skuName.Prefix, skuName.Name, "", "", 0, "", 0, skuName.ExPrefix, skuName.ExPrefixBegin, skuName.ExPrefixEnd) if skuName.SkusStr != "" { if err = utils.UnmarshalUseNumber([]byte(skuName.SkusStr), &skuName.Skus); err != nil { dao.Rollback(db) @@ -646,17 +659,14 @@ func AddSkuName(ctx *jxcontext.Context, skuNameExt *model.SkuNameExt, userName s if hasSensitiveWord, err := CheckHasSensitiveWord(skuNameExt.Name); hasSensitiveWord { return nil, err } + upc := utils.Pointer2String(skuNameExt.Upc) + if upc == "" { + skuNameExt.Upc = nil + } else if !jxutils.IsUpcValid(upc) { + return nil, fmt.Errorf("upc:%s不合法,请仔细检查", upc) + } db := dao.GetDB() - if skuNameExt.Upc != "" { - err = dao.GetEntity(db, &skuNameExt.SkuName, "Upc") - if err == nil { - return nil, fmt.Errorf("UPC:%s重复", skuNameExt.Upc) - } else if !dao.IsNoRowsError(err) { - return nil, err - } - err = nil - } skuNameExt.SkuName.Status = model.SkuStatusNormal if skuNameExt.IsSpu == 1 { return nil, fmt.Errorf("不允许创建多规格商品") @@ -776,19 +786,14 @@ func UpdateSkuName(ctx *jxcontext.Context, nameID int, payload map[string]interf valid = utils.RemoveGeneralMapKeys(valid, model.FieldSpecQuality, model.FieldSpecUnit) _, hasPlaces := payload["places"] if len(valid) > 0 || hasPlaces { - globals.SugarLogger.Debugf("UpdateSkuName valid:%s", utils.Format4Output(valid, false)) - if upc, _ := valid["upc"].(string); upc != "" { - skuName := &model.SkuName{ - Upc: upc, + if valid["Upc"] != nil { + if upc, _ := valid["Upc"].(string); upc == "" { + valid["Upc"] = nil + } else if !jxutils.IsUpcValid(upc) { + return 0, fmt.Errorf("upc:%s不合法,请仔细检查", upc) } - err = dao.GetEntity(db, skuName, "Upc") - if err == nil { - return 0, fmt.Errorf("UPC:%s重复", upc) - } else if !dao.IsNoRowsError(err) { - return 0, err - } - err = nil } + globals.SugarLogger.Debugf("UpdateSkuName valid:%s", utils.Format4Output(valid, false)) for _, imgName := range []string{"img", "img2"} { if valid[imgName] != nil { if imgStr := utils.Interface2String(valid[imgName]); imgStr != "" { @@ -846,7 +851,6 @@ func UpdateSkuName(ctx *jxcontext.Context, nameID int, payload map[string]interf } } } - skuList, err2 := dao.GetSkus(db, nil, []int{nameID}, nil, nil) if err = err2; err == nil { for _, v := range skuList { @@ -865,7 +869,6 @@ func UpdateSkuName(ctx *jxcontext.Context, nameID int, payload map[string]interf } } } - skuIDs, err2 := dao.GetSkuIDByNames(db, []int{nameID}) if err = err2; err != nil { dao.Rollback(db) @@ -1289,3 +1292,146 @@ func SortCategorySkus(ctx *jxcontext.Context, catID int, skuIDList []int) (err e } return err } + +func GetJdUpcCodeByName(ctx *jxcontext.Context, name, upcCode string) (productInfos []*jdapi.ProductInfo, err error) { + var ( + pageNo = 5 + pageSize = 30 + pageNoList []int + ) + if name == "" && upcCode == "" { + return nil, fmt.Errorf("至少输入一个条件查询,商品名或者upc码!") + } + for i := 1; i < pageNo+1; i++ { + pageNoList = append(pageNoList, i) + } + task := tasksch.NewParallelTask("获取京东商品", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx, + func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { + pageNum := batchItemList[0].(int) + productInfo, err := api.JdAPI.GetJdUpcCodeByName(name, upcCode, pageNum, pageSize) + if err != nil { + return retVal, err + } + for _, v := range productInfo { + _, name, _, specUnit, _, specQuality := jxutils.SplitSkuName(v.OriginalName) + v.Name = name + v.SpecQuality = specQuality + v.SpecUnit = specUnit + } + retVal = productInfo + return retVal, err + }, pageNoList) + tasksch.HandleTask(task, nil, true).Run() + productInfoInterface, err := task.GetResult(0) + for _, v := range productInfoInterface { + productInfos = append(productInfos, v.(*jdapi.ProductInfo)) + } + return productInfos, err +} + +func UpdateSkuNamesExPrefix(ctx *jxcontext.Context, nameIDs []int, exPrefix, fromTime, toTime string, isAsync, isContinueWhenError bool) (hint string, err error) { + var ( + fromTimeP time.Time + toTimeP time.Time + db = dao.GetDB() + ) + if fromTime != "" { + fromTimeP = utils.Time2Date(utils.Str2Time(fromTime)) + } + if toTime != "" { + toTimeP = utils.Time2Date(utils.Str2Time(toTime)) + } + if toTimeP.Before(fromTimeP) { + return "", fmt.Errorf("结束时间不可以小于开始时间!开始时间:[%v],结束时间:[%v]", fromTimeP, toTimeP) + } + task := tasksch.NewParallelTask("批量设置商品前缀", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(isContinueWhenError), ctx, + func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { + step := batchItemList[0].(int) + now := utils.Time2Date(time.Now()) + switch step { + case 0: + task := tasksch.NewParallelTask("批量设置商品前缀", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx, + func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { + nameID := batchItemList[0].(int) + payload := map[string]interface{}{ + "exPrefix": exPrefix, + "exPrefixBegin": fromTimeP, + "exPrefixEnd": toTimeP, + } + if now.Sub(toTimeP) <= 0 && now.Sub(fromTimeP) >= 0 { + _, err = UpdateSkuName(ctx, nameID, payload) + } else if now.Sub(fromTimeP) > 0 && now.Sub(toTimeP) > 0 { + payload["exPrefixBegin"] = nil + payload["exPrefixEnd"] = nil + _, err = UpdateSkuName(ctx, nameID, payload) + } else { + skuList, err := dao.GetSkus(db, nil, []int{nameID}, nil, nil) + if err == nil && len(skuList) > 0 { + if skuList[0].ExPrefixBegin != nil { + _, err = UpdateSkuName(ctx, nameID, payload) + CurVendorSync.SyncStoresSkus2(ctx, db, partner.GetSingleStoreVendorIDs(), nil, false, []int{skuList[0].ID}, nil, model.SyncFlagModifiedMask, true, true) + } else { + skuName := &model.SkuName{ + ExPrefix: exPrefix, + ExPrefixBegin: &fromTimeP, + ExPrefixEnd: &toTimeP, + } + skuName.ID = nameID + skuName.LastOperator = ctx.GetLoginID() + skuName.UpdatedAt = time.Now() + dao.Begin(db) + defer func() { + if r := recover(); r != nil { + dao.Rollback(db) + panic(r) + } + }() + _, err = dao.UpdateEntity(db, skuName, "ExPrefix", "ExPrefixBegin", "ExPrefixEnd", "LastOperator", "UpdatedAt") + dao.Commit(db) + } + } + } + return retVal, err + }, nameIDs) + tasksch.HandleTask(task, nil, true).Run() + _, err = task.GetResult(0) + case 1: + if (now.Sub(toTimeP) <= 0 && now.Sub(fromTimeP) >= 0) || (now.Sub(fromTimeP) > 0 && now.Sub(toTimeP) > 0) { + var skuIDs []int + skuList, err2 := dao.GetSkus(db, nil, nameIDs, nil, nil) + if err = err2; err == nil { + if len(skuList) > 0 { + for _, v := range skuList { + skuIDs = append(skuIDs, v.ID) + } + CurVendorSync.SyncStoresSkus2(ctx, db, partner.GetSingleStoreVendorIDs(), nil, false, skuIDs, nil, model.SyncFlagModifiedMask, true, true) + } + } + } + } + return retVal, err + }, []int{0, 1}) + tasksch.HandleTask(task, nil, true).Run() + if !isAsync { + _, err = task.GetResult(0) + hint = "1" + } else { + hint = task.GetID() + } + return hint, err +} + +func SetSingleStoreSkuSyncModifyStatus(db *dao.DaoDB, vendorIDs []int) (err error) { + _, err = dao.UpdateStoreSkuBindSyncStatusForExPrefix(db, vendorIDs) + return err +} + +func SetMultiStoreSkuSyncModifyStatus(db *dao.DaoDB, vendorIDs []int) (err error) { + _, err = dao.UpdateSkuSyncStatusForExPrefix(db, vendorIDs) + return err +} + +func DeleteSkuNameExPrefixOverdue(db *dao.DaoDB) (err error) { + _, err = dao.DeleteSkuNameExPrefixOverdue(db) + return err +} diff --git a/business/jxstore/cms/store.go b/business/jxstore/cms/store.go index 44e86dcac..ee40f141a 100644 --- a/business/jxstore/cms/store.go +++ b/business/jxstore/cms/store.go @@ -11,6 +11,7 @@ import ( "strconv" "strings" "time" + "unicode/utf8" "github.com/360EntSecGroup-Skylar/excelize" @@ -145,6 +146,11 @@ type VendorStoreExcel struct { OperatorName2 string `json:"运营负责人2"` } +type JdStoreLevelExt struct { + Level string `json:"level` + PageNo int `json:"pageNo"` +} + var ( ErrMissingInput = errors.New("没有有效的输入参数") ErrCanNotFindVendor = errors.New("vendorID参数不合法") @@ -167,6 +173,7 @@ var ( "deliveryRangeType": 1, "deliveryRange": 1, "status": 1, + "promoteInfo": 1, } WatchVendorStoreTimeList = []string{ @@ -204,6 +211,7 @@ var ( "18328080405": "18328080405", //肖娜娜的手机 "13350726500": "13350726500", //谭翔心 "15928865396": "15928865396", //何佳梦 + "18048531223": "18048531223", //石老板 } ) @@ -830,6 +838,10 @@ func UpdateStore(ctx *jxcontext.Context, storeID int, payload map[string]interfa } } + if valid["promoteInfo"] != nil { + valid["promoteInfo"] = strings.ReplaceAll(valid["promoteInfo"].(string), "{phone}", store.Tel1) + } + for k, _ := range valid { if roleMap[k] != "" { if authInfo, err := ctx.GetV2AuthInfo(); err == nil { @@ -1042,6 +1054,7 @@ func AddStoreVendorMap(ctx *jxcontext.Context, db *dao.DaoDB, vendorID int, vend userName := ctx.GetUserName() storeMap.StoreID = storeID storeMap.VendorID = vendorID + storeMap.VendorOrgCode = vendorOrgCode storeMap.Status = model.StoreStatusOpened storeMap.DeliveryType = model.StoreDeliveryTypeByStore storeMap.SyncStatus = 0 @@ -1137,6 +1150,12 @@ func UpdateStoreVendorMap(ctx *jxcontext.Context, db *dao.DaoDB, storeID, vendor if valid["status"] != nil { syncStatus |= model.SyncFlagStoreStatus } + if vendorStoreName, ok := valid["vendorStoreName"].(string); ok { + if utf8.RuneCountInString(vendorStoreName) > jdapi.MaxStoreNameLen && vendorID == model.VendorIDJD { + return 0, fmt.Errorf("门店名称不允许超过13位!") + } + syncStatus |= model.SyncFlagStoreName + } for _, v := range [][]string{ []string{ "pricePercentagePack", @@ -1177,7 +1196,7 @@ func UpdateStoreVendorMap(ctx *jxcontext.Context, db *dao.DaoDB, storeID, vendor panic(r) } }() - if valid["status"] != nil { // 对于store vendor map,只有Status改变才需要同步到厂商 + if valid["status"] != nil || valid["vendorStoreName"] != nil { // 对于store vendor map,只有Status改变才需要同步到厂商 num, err = dao.UpdateEntityLogicallyAndUpdateSyncStatus(db, storeMap, valid, userName, map[string]interface{}{ model.FieldStoreID: storeID, model.FieldVendorID: vendorID, @@ -1210,7 +1229,7 @@ func UpdateStoreVendorMap(ctx *jxcontext.Context, db *dao.DaoDB, storeID, vendor } } dao.Commit(db) - if vendorID != model.VendorIDJX && (valid["status"] != nil || valid["freightDeductionPack"] != nil) { + if vendorID != model.VendorIDJX && (valid["status"] != nil || valid["freightDeductionPack"] != nil || valid["vendorStoreName"] != nil) { _, err = CurVendorSync.SyncStore(ctx, db, vendorID, storeID, false, userName) } } @@ -2529,13 +2548,13 @@ func StoreStatus2Chinese(status int) (str string) { } } -func GetStorePriceScore(ctx *jxcontext.Context, storeIDs []int, fromScore, toScore, sort int, snapDate string, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) { +func GetStorePriceScore(ctx *jxcontext.Context, storeIDs, vendorIDs []int, fromScore, toScore, sort int, snapDate string, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) { var snapDateParam time.Time db := dao.GetDB() if snapDate != "" { snapDateParam = utils.Str2Time(snapDate) } - storePriceScore, totalCount, err := dao.GetStorePriceScore(db, storeIDs, fromScore, toScore, sort, snapDateParam, offset, pageSize) + storePriceScore, totalCount, err := dao.GetStorePriceScore(db, storeIDs, vendorIDs, fromScore, toScore, sort, snapDateParam, offset, pageSize) pagedInfo = &model.PagedInfo{ Data: storePriceScore, TotalCount: totalCount, @@ -2543,14 +2562,10 @@ func GetStorePriceScore(ctx *jxcontext.Context, storeIDs []int, fromScore, toSco return pagedInfo, err } -func CreateStorePriceScore(ctx *jxcontext.Context, forRefresh bool) (err error) { +func CreateStorePriceScore(ctx *jxcontext.Context) (err error) { db := dao.GetDB() var snapshotAt time.Time - if forRefresh { - snapshotAt = utils.Time2Date(time.Now().AddDate(0, 0, -1)) - } else { - snapshotAt = utils.Time2Date(time.Now()) - } + snapshotAt = utils.Time2Date(time.Now().AddDate(0, 0, -1)) storePriceScoreSnapshot, err := dao.GetStorePriceScoreSnapshot(db, snapshotAt) if len(storePriceScoreSnapshot) > 0 { dao.Begin(db) @@ -2574,6 +2589,51 @@ func CreateStorePriceScore(ctx *jxcontext.Context, forRefresh bool) (err error) } } dao.Commit(db) + globals.SugarLogger.Debugf("CreateStorePriceScore") + } + return err +} + +func RefreshJdLevel(ctx *jxcontext.Context) (err error) { + db := dao.GetDB() + storeMapList, err := dao.GetStoresMapList(db, []int{model.VendorIDJD}, nil, model.StoreStatusOpened, -1, "") + if len(storeMapList) > 0 { + dao.Begin(db) + defer func() { + if r := recover(); r != nil || err != nil { + dao.Rollback(db) + if r != nil { + panic(r) + } + } + }() + task := tasksch.NewParallelTask("更新京东门店等级", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx, + func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { + v := batchItemList[0].(*model.StoreMap) + var ( + pageLimit = 5 + pageNo = 1 + level string + ) + for ; pageNo < pageLimit+1; pageNo++ { + level, err = jd.GetAPI(v.VendorOrgCode).GetJdStoreLevel(v.VendorOrgCode, v.VendorStoreID, pageNo) + if err != nil { + return retVal, err + } + if level != "" { + break + } + if pageNo == pageLimit { + level = "" + } + } + v.JdStoreLevel = level + _, err = dao.UpdateEntity(db, v, "JdStoreLevel") + return retVal, err + }, storeMapList) + tasksch.HandleTask(task, nil, true).Run() + _, err = task.GetResult(0) + dao.Commit(db) } return err } diff --git a/business/jxstore/cms/store_sku.go b/business/jxstore/cms/store_sku.go index d7e4771ab..b9dee32f5 100644 --- a/business/jxstore/cms/store_sku.go +++ b/business/jxstore/cms/store_sku.go @@ -18,6 +18,7 @@ import ( "git.rosy.net.cn/jx-callback/business/jxutils/excel" "git.rosy.net.cn/jx-callback/business/jxutils/tasksch" "git.rosy.net.cn/jx-callback/business/partner/purchase/jd" + "git.rosy.net.cn/jx-callback/globals/api/apimanager" "git.rosy.net.cn/jx-callback/business/partner" @@ -42,6 +43,13 @@ const ( CopyStoreSkuModeUpdatePrice = "updatePrice" // 增量复制价格 ) +//通用写入Excel +type ExcelParam struct { + DataList interface{} + SheetName string + TitleList []string +} + // UpdateStoreSku用,API调用时 type StoreSkuBindSkuInfo struct { SkuID int `json:"skuID"` @@ -117,6 +125,14 @@ type SheetParam struct { SkuRow int } +type DataVendorStoreSkuPrice struct { + StoreID string `json:"门店ID"` + StoreName string `json:"门店名"` + SkuID int `json:"商品ID"` + SkuName string `json:"商品名"` + VendorPrice string `json:"平台价"` +} + type DataSuccess struct { NameID int `json:"商品NameID"` Name string `json:"商品名称"` @@ -139,7 +155,7 @@ type DataLock struct { } const ( - maxStoreNameBind = 3000 // 最大门店SkuName bind个数 + maxStoreNameBind = 10000 // 最大门店SkuName bind个数 maxStoreNameBind2 = 10000 // 最大门店乘SkuName个数 AutoSaleAtStr = "22:00:00" @@ -151,7 +167,14 @@ var ( "18180948107": 1, // 徐 // "13684045763": 1, // 周 } - dataLock DataLock + dataLock DataLock + titleListVendorStoreSkuPrice = []string{ + "门店ID", + "门店名", + "商品ID", + "商品名", + "平台价", + } titleListSuccess = []string{ "商品NameID", "商品名称", @@ -319,6 +342,12 @@ func getGetStoresSkusBaseSQL(db *dao.DaoDB, storeIDs, skuIDs []int, isFocus bool sqlParams = append(sqlParams, skuID) } } + if lockTimeStr, ok := params["lockTime"].(string); ok && lockTimeStr != "" { + if timeList, err2 := jxutils.BatchStr2Time(lockTimeStr); err2 == nil { + sql += " AND (t4.jd_lock_time > ? OR t4.mtwm_lock_time > ? OR t4.ebai_lock_time > ? OR t4.jx_lock_time > ?)" + sqlParams = append(sqlParams, timeList[0], timeList[0], timeList[0], timeList[0]) + } + } if isFocus { if params["fromStatus"] != nil { fromStatus := params["fromStatus"].(int) @@ -451,6 +480,7 @@ func GetStoresSkusNew(ctx *jxcontext.Context, storeIDs, skuIDs []int, isFocus bo t4.ebai_id, t4.mtwm_id, t4.jd_sync_status, t4.ebai_sync_status, t4.mtwm_sync_status, t4.jd_price, t4.ebai_price, t4.mtwm_price, t4.jx_price, + t4.jd_lock_time, t4.ebai_lock_time, t4.mtwm_lock_time, t4.jx_lock_time, t4.status_sale_begin, t4.status_sale_end `, jdVendorIDField) + sql var tmpList []*tGetStoresSkusInfo @@ -862,9 +892,9 @@ func uniqueStoreNameBind(skuBindInfos []*StoreSkuBindInfo) (outSkuBindInfos []*S } func updateStoresSkusWithoutSync(ctx *jxcontext.Context, db *dao.DaoDB, storeIDs []int, skuBindInfos []*StoreSkuBindInfo, isScale bool) (needSyncSkus []int, err error) { - if len(storeIDs)*len(skuBindInfos) > maxStoreNameBind2 { - return nil, fmt.Errorf("门店商品信息大于%d", maxStoreNameBind2) - } + // if len(storeIDs)*len(skuBindInfos) > maxStoreNameBind2 { + // return nil, fmt.Errorf("门店商品信息大于%d", maxStoreNameBind2) + // } storeIDs = uniqueStoreIDs(storeIDs) skuBindInfos = uniqueStoreNameBind(skuBindInfos) @@ -991,11 +1021,24 @@ func updateStoresSkusWithoutSync(ctx *jxcontext.Context, db *dao.DaoDB, storeIDs setStoreSkuBindStatus(skuBind, model.SyncFlagNewMask) dao.WrapAddIDCULDEntity(skuBind, userName) globals.SugarLogger.Debug(utils.Format4Output(skuBind, false)) - if err = dao.CreateEntity(db, skuBind); err != nil { - dao.Rollback(db) - return nil, err + if deletedSku := dao.GetDeletedStoreSkuBind(db, skuBind.StoreID, skuBind.SkuID); deletedSku == nil { + if err = dao.CreateEntity(db, skuBind); err != nil { + dao.Rollback(db) + return nil, err + } + num = 1 + } else { + // 需要处理,在删除某个门店商品,同步失败的情况下,又把商品重新关注。 + // 所以统一处理成恢复删除的记录,这样避免问题 + skuBind.ID = deletedSku.ID + // vendorSkuID的赋值意义不大 + skuBind.MtwmID = deletedSku.MtwmID + skuBind.EbaiID = deletedSku.EbaiID + if num, err = dao.UpdateEntity(db, skuBind); err != nil { + dao.Rollback(db) + return nil, err + } } - num = 1 } } else { skuBind = &v.StoreSkuBind @@ -1090,12 +1133,13 @@ func updateStoresSkusWithoutSync(ctx *jxcontext.Context, db *dao.DaoDB, storeIDs return skuIDs, err } -func getSkuSaleStatus(inSkuBind *StoreSkuBindSkuInfo, skuBindInfo *StoreSkuBindInfo) int { +func getSkuSaleStatus(inSkuBind *StoreSkuBindSkuInfo, skuNameBindInfo *StoreSkuBindInfo) int { tempSale := 0 if inSkuBind != nil { tempSale = inSkuBind.IsSale - } else { - tempSale = skuBindInfo.IsSale + } + if tempSale == 0 { + tempSale = skuNameBindInfo.IsSale } if tempSale == -1 { return model.StoreSkuBindStatusDontSale @@ -2139,12 +2183,118 @@ func GetTopSkusByStoreIDs(ctx *jxcontext.Context, storeIDs []int) (storeSkuNameE return storeSkuNameExt, err } -func GetTopCategorysByStoreIDs(ctx *jxcontext.Context, storeIDs []int) (skuCategory []*model.SkuCategory, err error) { +func GetTopSkusByCityCode(ctx *jxcontext.Context, cityCode, storeID int) (skuNameAndPlaceList []*dao.SkuNameAndPlace, err error) { + db := dao.GetDB() + orderCreate := time.Now().AddDate(0, -1, 0) + skuNameAndPlace, err := dao.GetTopSkusByCityCode(db, cityCode, orderCreate) + if storeID > 0 { + var skuNameList []*model.SkuName + //未关注,不可售的商品nameID列表 + sql := ` + SELECT DISTINCT b.name_id id,1 brand_id + FROM store_sku_bind a + JOIN sku b ON a.sku_id = b.id AND b.deleted_at = ? + WHERE a.deleted_at = ? + AND a.store_id = ? + AND a.status <> ? + AND b.name_id NOT IN(SELECT DISTINCT b.name_id + FROM store_sku_bind a + JOIN sku b ON a.sku_id = b.id AND b.deleted_at = ? + WHERE a.deleted_at = ? + AND a.store_id = ? + AND a.status = ?) + UNION + SELECT DISTINCT a.name_id id,0 brand_id + FROM sku a + LEFT JOIN (SELECT DISTINCT b.name_id + FROM store_sku_bind a + JOIN sku b ON a.sku_id = b.id + WHERE a.deleted_at = ? + AND store_id = ?)b ON a.name_id = b.name_id + WHERE a.status = ? + AND a.deleted_at = ? + AND b.name_id IS NULL + ` + sqlParams := []interface{}{ + utils.DefaultTimeValue, + utils.DefaultTimeValue, + storeID, + model.StoreSkuBindStatusNormal, + utils.DefaultTimeValue, + utils.DefaultTimeValue, + storeID, + model.StoreSkuBindStatusNormal, + utils.DefaultTimeValue, + storeID, + model.StoreSkuBindStatusNormal, + utils.DefaultTimeValue, + } + err = dao.GetRows(db, &skuNameList, sql, sqlParams...) + var skuNameMap = make(map[int]*model.SkuName) + for _, v := range skuNameList { + skuNameMap[v.ID] = v + } + for _, v := range skuNameAndPlace { + if skuNameMap[v.ID] != nil { + midPrice, _ := dao.GetMidPriceByNameID(db, cityCode, v.ID, utils.Time2Date(time.Now().AddDate(0, 0, -1))) + if midPrice != 0 { + v.Price = midPrice + } + v.Type = skuNameMap[v.ID].BrandID + skuNameAndPlaceList = append(skuNameAndPlaceList, v) + } + } + } else { + skuNameAndPlaceList = append(skuNameAndPlaceList, skuNameAndPlace...) + } + i := 1 + for _, v := range skuNameAndPlaceList { + v.Sequence = i + i++ + } + if len(skuNameAndPlaceList) <= 100 { + return skuNameAndPlaceList, err + } else { + return skuNameAndPlaceList[0:100], err + } +} + +func GetTopCategoriesByStoreIDs(ctx *jxcontext.Context, storeIDs []int) (skuCategory []*model.SkuCategory, err error) { + var ( + skuCategory2 []*model.SkuCategory + skuCategoryMap = make(map[int]*model.SkuCategory) + limit = 10 + ) if len(storeIDs) == 0 { return skuCategory, err } db := dao.GetDB() - skuCategory, err = dao.GetTopCategorysByStoreIDs(db, storeIDs) + skuCategory, err = dao.GetTopCategoriesByStoreIDs(db, storeIDs, limit) + //若大于等于10个就不用做下面的操作 + if len(skuCategory) >= limit { + return skuCategory, err + } + if len(skuCategory) > 0 { + for _, v := range skuCategory { + skuCategoryMap[v.ID] = v + } + } + //推荐分类,若不满10个,则填满10个 + if (len(skuCategory) < limit && len(skuCategory) > 0) || len(skuCategory) == 0 { + skuCategory2, err = dao.GetCategories(db, -1, 1, nil) + if len(skuCategory2) > 0 { + for _, v := range skuCategory2 { + if skuCategoryMap[v.ID] == nil { + if !strings.Contains(v.Name, "赠品") { + skuCategory = append(skuCategory, v) + } + } + if len(skuCategory) >= limit { + break + } + } + } + } if err != nil { return nil, err } @@ -2155,7 +2305,7 @@ func RefershStoreSkusMidPrice(ctx *jxcontext.Context, storeIDs []int) (err error db := dao.GetDB() _, err = dao.RefershStoreSkusMidPrice(db, storeIDs) if err == nil { - CreateStorePriceScore(ctx, true) + CreateStorePriceScore(ctx) } return err } @@ -2443,3 +2593,319 @@ func IsChineseChar(str string) bool { } return false } + +func GetStoreCategories(ctx *jxcontext.Context, storeID, parentID int) (catList []*model.SkuCategory, err error) { + return dao.GetStoreSkuCategories(dao.GetDB(), storeID, parentID) +} + +func GetVendorStoreSkuPrice(ctx *jxcontext.Context, vendorIDs []int, skuID int, isAsync, isContinueWhenError bool) (hint string, err error) { + var ( + storeSkuListJD []DataVendorStoreSkuPrice + storeSkuListMT []DataVendorStoreSkuPrice + storeSkuListEB []DataVendorStoreSkuPrice + excelParamList []ExcelParam + ) + taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) { + switch step { + case 0: + for _, v := range vendorIDs { + vendorID := v + handler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IPurchasePlatformStoreSkuHandler) + handlerStore := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IStoreHandler) + for _, v := range apimanager.CurAPIManager.GetAppOrgCodeList(vendorID) { + vendorStoreIDs, err2 := handlerStore.GetAllStoresVendorID(ctx, v) + err = err2 + taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { + vendorStoreID := batchItemList[0].(string) + var ( + inStoreSkuList []*partner.StoreSkuInfo + storeDetail *dao.StoreDetail + inStoreSku = &partner.StoreSkuInfo{} + outStoreSkuList []*partner.StoreSkuInfo + ) + db := dao.GetDB() + skuNameList, err := dao.GetSkus(db, []int{skuID}, nil, nil, nil) + if err != nil { + return retVal, err + } + if partner.IsMultiStore(vendorID) { + multiHandler, _ := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IMultipleStoresHandler) + storeDetail, err = multiHandler.ReadStore(ctx, v, vendorStoreID) + if len(skuNameList) > 0 { + inStoreSku.VendorSkuID = utils.Int64ToStr(skuNameList[0].JdID) + } + } else { + singleHandler, _ := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.ISingleStoreHandler) + storeDetail, err = singleHandler.ReadStore(ctx, v, vendorStoreID) + inStoreSku.SkuID = skuID + } + inStoreSkuList = append(inStoreSkuList, inStoreSku) + storeDetail2, err := dao.GetStoreDetailByVendorStoreID(db, vendorStoreID, vendorID) + if storeDetail2 != nil { + outStoreSkuList, err = handler.GetStoreSkusBareInfo(ctx, v, task, storeDetail2.ID, vendorStoreID, inStoreSkuList) + } else { + outStoreSkuList, err = handler.GetStoreSkusBareInfo(ctx, v, task, 0, vendorStoreID, inStoreSkuList) + } + if storeDetail != nil { + if len(outStoreSkuList) == 0 { + data := DataVendorStoreSkuPrice{ + StoreID: vendorStoreID, + StoreName: storeDetail.Name, + SkuID: skuID, + SkuName: skuNameList[0].Name, + VendorPrice: "", + } + retVal = []DataVendorStoreSkuPrice{data} + } else { + data := DataVendorStoreSkuPrice{ + StoreID: vendorStoreID, + StoreName: storeDetail.Name, + SkuID: skuID, + SkuName: skuNameList[0].Name, + VendorPrice: utils.Float64ToStr(utils.Str2Float64(utils.Int64ToStr(outStoreSkuList[0].VendorPrice)) / 100), + } + retVal = []DataVendorStoreSkuPrice{data} + } + } + return retVal, err + } + taskParallel := tasksch.NewParallelTask("获取各平台所有门店某商品价格", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx, taskFunc, vendorStoreIDs) + tasksch.HandleTask(taskParallel, task, true).Run() + storeSkuList, _ := taskParallel.GetResult(0) + for _, v := range storeSkuList { + if vendorID == model.VendorIDJD { + storeSkuListJD = append(storeSkuListJD, v.(DataVendorStoreSkuPrice)) + } + if vendorID == model.VendorIDEBAI { + storeSkuListEB = append(storeSkuListEB, v.(DataVendorStoreSkuPrice)) + } + if vendorID == model.VendorIDMTWM { + storeSkuListMT = append(storeSkuListMT, v.(DataVendorStoreSkuPrice)) + } + } + } + } + excelParam1 := ExcelParam{ + DataList: storeSkuListJD, + TitleList: titleListVendorStoreSkuPrice, + SheetName: "京东平台", + } + excelParam2 := ExcelParam{ + DataList: storeSkuListEB, + TitleList: titleListVendorStoreSkuPrice, + SheetName: "饿百平台", + } + excelParam3 := ExcelParam{ + DataList: storeSkuListMT, + TitleList: titleListVendorStoreSkuPrice, + SheetName: "美团平台", + } + excelParamList = append(excelParamList, excelParam1, excelParam2, excelParam3) + case 1: + WriteToExcelNormal(task, "各平台"+utils.Int2Str(skuID)+"商品所有门店价格", excelParamList) + } + return result, err + } + taskSeq := tasksch.NewSeqTask2("获取各平台所有门店某商品价格-序列任务", ctx, isContinueWhenError, taskSeqFunc, 2) + tasksch.HandleTask(taskSeq, nil, true).Run() + if !isAsync { + _, err = taskSeq.GetResult(0) + hint = "1" + } else { + hint = taskSeq.GetID() + } + return hint, err +} + +func WriteToExcelNormal(task *tasksch.SeqTask, fileName string, excelParam []ExcelParam) (err error) { + var sheetList []*excel.Obj2ExcelSheetConfig + for _, v := range excelParam { + if v.DataList != nil { + excelConf := &excel.Obj2ExcelSheetConfig{ + Title: v.SheetName, + Data: v.DataList, + CaptionList: v.TitleList, + } + sheetList = append(sheetList, excelConf) + } + } + downloadURL, fileNameResult, err := jxutils.UploadExeclAndPushMsg(sheetList, fileName) + if err != nil { + baseapi.SugarLogger.Errorf("WriteToExcel:upload %s failed error:%v", fileNameResult, err) + } else { + noticeMsg := fmt.Sprintf("[详情点我]path=%s \n", downloadURL) + task.SetNoticeMsg(noticeMsg) + baseapi.SugarLogger.Debugf("WriteToExcel:upload %s success, downloadURL:%s", fileNameResult, downloadURL) + } + return err +} + +func FocusStoreSkusByExcel(ctx *jxcontext.Context, files []*multipart.FileHeader, isAsync, isContinueWhenError bool) (hint string, err error) { + if len(files) == 0 { + return "", errors.New("没有文件上传!") + } + fileHeader := files[0] + file, err := fileHeader.Open() + hint, err = FocusStoreSkusByExcelBin(ctx, file, isAsync, isContinueWhenError) + file.Close() + return hint, err +} + +func FocusStoreSkusByExcelBin(ctx *jxcontext.Context, reader io.Reader, isAsync, isContinueWhenError bool) (hint string, err error) { + var ( + skuMap = make(map[int]int) + skuNameMap = make(map[int]int) + skuBindInfos []*StoreSkuBindInfo + db = dao.GetDB() + storeIDs []int + skuIDs []int + ) + sheetParam := &SheetParam{ + OutSkuIDCol: 1, + SkuPriceCol: 3, + SkuRow: 1, + } + // xlsx, err := excelize.OpenFile("111.xlsx") + taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) { + switch step { + case 0: + xlsx, err := excelize.OpenReader(reader) + if err != nil { + return result, err + } + rows, _ := xlsx.GetRows(xlsx.GetSheetName(1)) + for rowNum, row := range rows { + if rowNum < sheetParam.SkuRow { + continue + } + GetCellForFocusStoreSkus(db, rowNum, row, sheetParam, skuMap) + } + case 1: + for k, _ := range skuMap { + skuIDs = append(skuIDs, k) + } + skuList, err := dao.GetSkus(db, skuIDs, nil, nil, nil) + if err != nil && len(skuList) == 0 { + return result, err + } + for _, v := range skuList { + var ( + price int + specQuality float64 + ) + if v.Unit == model.SpecialUnit { + if v.SpecUnit == model.SpecUnitNames[1] || v.SpecUnit == model.SpecUnitNames[2] { + specQuality = float64(v.SpecQuality) * 1000 + } else { + specQuality = float64(v.SpecQuality) + } + price = int(utils.Float64TwoInt64(utils.Int2Float64(model.SpecialSpecQuality) / specQuality * utils.Int2Float64(skuMap[v.ID]))) + } else { + price = skuMap[v.ID] + } + if skuNameMap[v.NameID] < price { + skuNameMap[v.NameID] = price + } + } + for k, v := range skuNameMap { + skuBindInfo := &StoreSkuBindInfo{ + NameID: k, + UnitPrice: v, + IsFocus: 1, + IsSale: 1, + } + skuBindInfos = append(skuBindInfos, skuBindInfo) + } + storeList, err := dao.GetStoreList(db, nil, nil, "") + for _, v := range storeList { + storeIDs = append(storeIDs, v.ID) + } + case 2: + UpdateStoresSkus(ctx, storeIDs, skuBindInfos, false, isAsync, isContinueWhenError) + } + return result, err + } + taskSeq := tasksch.NewSeqTask2("根据Excel中skuID批量关注商品", ctx, isContinueWhenError, taskSeqFunc, 3) + tasksch.HandleTask(taskSeq, nil, true).Run() + if !isAsync { + _, err = taskSeq.GetResult(0) + hint = "1" + } else { + hint = taskSeq.GetID() + } + return hint, err +} + +func GetCellForFocusStoreSkus(db *dao.DaoDB, rowNum int, row []string, sheetParam *SheetParam, skuMap map[int]int) { + var ( + skuID int + price int + ) + for k, cell := range row { + if k == sheetParam.OutSkuIDCol { + skuID = int(utils.Str2Int64(cell)) + } + if k == sheetParam.SkuPriceCol { + price = int(utils.Float64TwoInt64(utils.Str2Float64(cell) * 100)) + } + } + skuMap[skuID] = price +} + +func FocusStoreSkusBySku(ctx *jxcontext.Context, skuIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) { + var ( + skuBindInfos []*StoreSkuBindInfo + skuNameMap = make(map[int][]*StoreSkuBindSkuInfo) + storeIDs []int + ) + db := dao.GetDB() + skuList, err := dao.GetSkus(db, skuIDs, nil, nil, nil) + storeList, err := dao.GetStoreList(db, nil, nil, "") + taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) { + switch step { + case 0: + for _, v := range storeList { + storeIDs = append(storeIDs, v.ID) + } + for _, v := range skuList { + skuNameMap[v.NameID] = append(skuNameMap[v.NameID], &StoreSkuBindSkuInfo{ + SkuID: v.ID, + IsSale: 1, + }) + } + case 1: + taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { + store := batchItemList[0].(*model.Store) + for k, v := range skuNameMap { + midPrice, _ := dao.GetMidPriceByNameID(db, store.CityCode, k, utils.Time2Date(time.Now().AddDate(0, 0, -1))) + skuBindInfo := &StoreSkuBindInfo{ + NameID: k, + UnitPrice: midPrice, + IsFocus: 1, + Skus: v, + } + retVal = []*StoreSkuBindInfo{skuBindInfo} + } + return retVal, err + } + taskParallel := tasksch.NewParallelTask("根据skuID部分关注商品", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx, taskFunc, storeList) + tasksch.HandleTask(taskParallel, task, true).Run() + result1, _ := taskParallel.GetResult(0) + for _, v := range result1 { + skuBindInfos = append(skuBindInfos, v.(*StoreSkuBindInfo)) + } + case 2: + UpdateStoresSkus(ctx, storeIDs, skuBindInfos, false, isAsync, isContinueWhenError) + } + return result, err + } + taskSeq := tasksch.NewSeqTask2("根据skuID批量部分关注商品", ctx, isContinueWhenError, taskSeqFunc, 3) + tasksch.HandleTask(taskSeq, nil, true).Run() + if !isAsync { + _, err = taskSeq.GetResult(0) + hint = "1" + } else { + hint = taskSeq.GetID() + } + return hint, err +} diff --git a/business/jxstore/cms/store_sku_check.go b/business/jxstore/cms/store_sku_check.go index c64fa5bd8..6268288ef 100644 --- a/business/jxstore/cms/store_sku_check.go +++ b/business/jxstore/cms/store_sku_check.go @@ -340,10 +340,10 @@ func CompareJxAndVendor(vendorID int, storeIDStr, vendorStoreID, storeName strin //多规格商品不用比较数量单位 if jxSkuInfo.IsSpu == 0 { //jxSkuDetailName : 前缀 ([荐]) + 分类名(xxx水饺) + 数量单位(约..g/份) + 注释 (补充..) - jxSkuDetailName = jxutils.ComposeSkuName(jxSkuInfo.SkuName.Prefix, jxSkuInfo.SkuName.Name, jxSkuInfo.Skus[0].Comment, jxSkuInfo.SkuName.Unit, jxSkuInfo.Skus[0].SkuSpecQuality, jxSkuInfo.Skus[0].SkuSpecUnit, 0) + jxSkuDetailName = jxutils.ComposeSkuNameOriginal(jxSkuInfo.SkuName.Prefix, jxSkuInfo.SkuName.Name, jxSkuInfo.Skus[0].Comment, jxSkuInfo.SkuName.Unit, jxSkuInfo.Skus[0].SkuSpecQuality, jxSkuInfo.Skus[0].SkuSpecUnit, 0) } else { //jxSkuDetailName : 前缀 ([荐]) + 分类名(xxx水饺) + 数量单位(约..g/份) + 注释 (补充..) - jxSkuDetailName = jxutils.ComposeSkuName(jxSkuInfo.SkuName.Prefix, jxSkuInfo.SkuName.Name, jxSkuInfo.Skus[0].Comment, "", jxSkuInfo.Skus[0].SkuSpecQuality, "", 0) + jxSkuDetailName = jxutils.ComposeSkuNameOriginal(jxSkuInfo.SkuName.Prefix, jxSkuInfo.SkuName.Name, jxSkuInfo.Skus[0].Comment, "", jxSkuInfo.Skus[0].SkuSpecQuality, "", 0) } //jxSkuSaleStatus : 商品状态 ,skustatus 优先级高于 StoreSkuStatus @@ -462,9 +462,9 @@ func CompareJxAndMultiVenderDepot(ctx *jxcontext.Context, vendorMap map[int]bool var jxSkuDetailName string //多规格商品不用比较数量单位 if jxSkuInfo.IsSpu == 0 { - jxSkuDetailName = jxutils.ComposeSkuName(jxSkuInfo.Prefix, jxSkuInfo.Name, jxSkuInfo.Comment, jxSkuInfo.Unit, jxSkuInfo.SpecQuality, jxSkuInfo.SpecUnit, 0) + jxSkuDetailName = jxutils.ComposeSkuNameOriginal(jxSkuInfo.Prefix, jxSkuInfo.Name, jxSkuInfo.Comment, jxSkuInfo.Unit, jxSkuInfo.SpecQuality, jxSkuInfo.SpecUnit, 0) } else { - jxSkuDetailName = jxutils.ComposeSkuName(jxSkuInfo.Prefix, jxSkuInfo.Name, jxSkuInfo.Comment, "", jxSkuInfo.SpecQuality, "", 0) + jxSkuDetailName = jxutils.ComposeSkuNameOriginal(jxSkuInfo.Prefix, jxSkuInfo.Name, jxSkuInfo.Comment, "", jxSkuInfo.SpecQuality, "", 0) } vendorSkuInfoMap := filterVendorSkuInfoMap[skuid] diff --git a/business/jxstore/cms/sync.go b/business/jxstore/cms/sync.go index 49a8579ef..b5b71e66d 100644 --- a/business/jxstore/cms/sync.go +++ b/business/jxstore/cms/sync.go @@ -18,7 +18,6 @@ import ( "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/refutil" ) type SyncErrResult struct { @@ -80,36 +79,36 @@ var ( syncErrResultLock SyncErrResultLock ) -func (p *MultiStoreHandlerWrapper) DeleteCategory(db *dao.DaoDB, cat *model.SkuCategory, userName string) (err error) { - if jxutils.IsEmptyID(cat.JdID) { - return nil - } - return p.IMultipleStoresHandler.DeleteCategory(db, cat, userName) -} +// func (p *MultiStoreHandlerWrapper) DeleteCategory(db *dao.DaoDB, cat *model.SkuCategory, userName string) (err error) { +// if jxutils.IsEmptyID(cat.JdID) { +// return nil +// } +// return p.IMultipleStoresHandler.DeleteCategory(db, cat, userName) +// } -func (p *MultiStoreHandlerWrapper) UpdateCategory(db *dao.DaoDB, cat *model.SkuCategory, userName string) (err error) { - if jxutils.IsEmptyID(cat.JdID) { - globals.SugarLogger.Warnf("UpdateCategory fakeid cat:%s should not get here", utils.Format4Output(cat, true)) - return nil - } - return p.IMultipleStoresHandler.UpdateCategory(db, cat, userName) -} +// func (p *MultiStoreHandlerWrapper) UpdateCategory(db *dao.DaoDB, cat *model.SkuCategory, userName string) (err error) { +// if jxutils.IsEmptyID(cat.JdID) { +// globals.SugarLogger.Warnf("UpdateCategory fakeid cat:%s should not get here", utils.Format4Output(cat, true)) +// return nil +// } +// return p.IMultipleStoresHandler.UpdateCategory(db, cat, userName) +// } -func (p *MultiStoreHandlerWrapper) DeleteSku(db *dao.DaoDB, sku *model.Sku, userName string) (err error) { - globals.SugarLogger.Debugf("wrapper DeleteSku, sku:%s", utils.Format4Output(sku, false)) - if jxutils.IsEmptyID(sku.JdID) { - return nil - } - return p.IMultipleStoresHandler.DeleteSku(db, sku, userName) -} +// func (p *MultiStoreHandlerWrapper) DeleteSku(db *dao.DaoDB, sku *model.Sku, userName string) (err error) { +// globals.SugarLogger.Debugf("wrapper DeleteSku, sku:%s", utils.Format4Output(sku, false)) +// if jxutils.IsEmptyID(sku.JdID) { +// return nil +// } +// return p.IMultipleStoresHandler.DeleteSku(db, sku, userName) +// } -func (p *MultiStoreHandlerWrapper) UpdateSku(db *dao.DaoDB, sku *model.Sku, userName string) (err error) { - if jxutils.IsEmptyID(sku.JdID) { - globals.SugarLogger.Warnf("UpdateSku fakeid sku:%s should not get here", utils.Format4Output(sku, true)) - return nil - } - return p.IMultipleStoresHandler.UpdateSku(db, sku, userName) -} +// func (p *MultiStoreHandlerWrapper) UpdateSku(db *dao.DaoDB, sku *model.Sku, userName string) (err error) { +// if jxutils.IsEmptyID(sku.JdID) { +// globals.SugarLogger.Warnf("UpdateSku fakeid sku:%s should not get here", utils.Format4Output(sku, true)) +// return nil +// } +// return p.IMultipleStoresHandler.UpdateSku(db, sku, userName) +// } func (v *VendorSync) GetStoreHandler(vendorID int) partner.IPurchasePlatformHandler { return partner.GetPurchasePlatformFromVendorID(vendorID) @@ -129,95 +128,95 @@ func (v *VendorSync) GetSingleStoreHandler(vendorID int) partner.ISingleStoreHan return nil } -func (v *VendorSync) syncCategories(ctx *jxcontext.Context, parentTask tasksch.ITask, vendorID int, db *dao.DaoDB, cats []*model.SkuCategory, userName string) (err error) { - multiStoresHandler := v.GetMultiStoreHandler(vendorID) - syncStatusFieldName := dao.GetSyncStatusStructField(model.VendorNames[vendorID]) - task := tasksch.NewParallelTask(fmt.Sprintf("处理平台%s", model.VendorChineseNames[vendorID]), nil, ctx, - func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (interface{}, error) { - cat := batchItemList[0].(*model.SkuCategory) - updateFields := []string{syncStatusFieldName} - syncStatus := refutil.GetObjFieldByName(cat, syncStatusFieldName).(int8) - if (syncStatus & model.SyncFlagDeletedMask) != 0 { //删除 - if (syncStatus & model.SyncFlagNewMask) == 0 { - err = multiStoresHandler.DeleteCategory(db, cat, userName) - } - } else if (syncStatus & model.SyncFlagNewMask) != 0 { // 新增 - err = multiStoresHandler.CreateCategory(db, cat, userName) - updateFields = append(updateFields, dao.GetVendorThingIDStructField(model.VendorNames[multiStoresHandler.GetVendorID()])) - } else if (syncStatus & model.SyncFlagModifiedMask) != 0 { // 修改 - err = multiStoresHandler.UpdateCategory(db, cat, userName) - if intErr, ok := err.(*utils.ErrorWithCode); ok && intErr.IntCode() == -3 { - err = nil - } - } - if err == nil { - refutil.SetObjFieldByName(cat, syncStatusFieldName, int8(0)) - _, err = dao.UpdateEntity(db, cat, updateFields...) - } - return nil, err - }, cats) - tasksch.HandleTask(task, parentTask, false).Run() - _, err = task.GetResult(0) - return err -} +// func (v *VendorSync) syncCategories(ctx *jxcontext.Context, parentTask tasksch.ITask, vendorID int, db *dao.DaoDB, cats []*model.SkuCategory, userName string) (err error) { +// multiStoresHandler := v.GetMultiStoreHandler(vendorID) +// syncStatusFieldName := dao.GetSyncStatusStructField(model.VendorNames[vendorID]) +// task := tasksch.NewParallelTask(fmt.Sprintf("处理平台%s", model.VendorChineseNames[vendorID]), nil, ctx, +// func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (interface{}, error) { +// cat := batchItemList[0].(*model.SkuCategory) +// updateFields := []string{syncStatusFieldName} +// syncStatus := refutil.GetObjFieldByName(cat, syncStatusFieldName).(int8) +// if (syncStatus & model.SyncFlagDeletedMask) != 0 { //删除 +// if (syncStatus & model.SyncFlagNewMask) == 0 { +// err = multiStoresHandler.DeleteCategory(db, cat, userName) +// } +// } else if (syncStatus & model.SyncFlagNewMask) != 0 { // 新增 +// err = multiStoresHandler.CreateCategory(db, cat, userName) +// updateFields = append(updateFields, dao.GetVendorThingIDStructField(model.VendorNames[multiStoresHandler.GetVendorID()])) +// } else if (syncStatus & model.SyncFlagModifiedMask) != 0 { // 修改 +// err = multiStoresHandler.UpdateCategory(db, cat, userName) +// if intErr, ok := err.(*utils.ErrorWithCode); ok && intErr.IntCode() == -3 { +// err = nil +// } +// } +// if err == nil { +// refutil.SetObjFieldByName(cat, syncStatusFieldName, int8(0)) +// _, err = dao.UpdateEntity(db, cat, updateFields...) +// } +// return nil, err +// }, cats) +// tasksch.HandleTask(task, parentTask, false).Run() +// _, err = task.GetResult(0) +// return err +// } func (v *VendorSync) SyncCategory(ctx *jxcontext.Context, db *dao.DaoDB, categoryID int, isAsync bool, userName string) (hint string, err error) { - if !globals.IsUseThingMap { - return v.oldSyncCategory(ctx, db, categoryID, isAsync, userName) - } + // if !globals.IsUseThingMap { + // return v.oldSyncCategory(ctx, db, categoryID, isAsync, userName) + // } return SyncCategories(ctx, nil, nil, nil, []int{categoryID}, isAsync) } -func (v *VendorSync) oldSyncCategory(ctx *jxcontext.Context, db *dao.DaoDB, categoryID int, isAsync bool, userName string) (hint string, err error) { - globals.SugarLogger.Debug("SyncCategory") - hint, err = v.LoopMultiStoresVendors(ctx, db, fmt.Sprintf("同步分类信息:%d", categoryID), isAsync, false, - func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (interface{}, error) { - vendorInfo := batchItemList[0].(*MultiStoreVendorInfo) - var cats []*model.SkuCategory - cond := make(map[string]interface{}) - if categoryID > 0 { - cond[model.FieldID] = categoryID - } else { - cond[model.FieldLevel] = 1 - } - err := dao.GetEntitiesByKV(db, &cats, cond, true) - if err == nil { - err = v.syncCategories(ctx, t, vendorInfo.VendorID, db, cats, userName) - } - if err != nil || categoryID > 0 { - return nil, err - } - cond[model.FieldLevel] = 2 - err = dao.GetEntitiesByKV(db, &cats, cond, true) - if err == nil { - err = v.syncCategories(ctx, t, vendorInfo.VendorID, db, cats, userName) - } - return nil, err - }) - return "", err -} +// func (v *VendorSync) oldSyncCategory(ctx *jxcontext.Context, db *dao.DaoDB, categoryID int, isAsync bool, userName string) (hint string, err error) { +// globals.SugarLogger.Debug("SyncCategory") +// hint, err = v.LoopMultiStoresVendors(ctx, db, fmt.Sprintf("同步分类信息:%d", categoryID), isAsync, false, +// func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (interface{}, error) { +// vendorInfo := batchItemList[0].(*MultiStoreVendorInfo) +// var cats []*model.SkuCategory +// cond := make(map[string]interface{}) +// if categoryID > 0 { +// cond[model.FieldID] = categoryID +// } else { +// cond[model.FieldLevel] = 1 +// } +// err := dao.GetEntitiesByKV(db, &cats, cond, true) +// if err == nil { +// err = v.syncCategories(ctx, t, vendorInfo.VendorID, db, cats, userName) +// } +// if err != nil || categoryID > 0 { +// return nil, err +// } +// cond[model.FieldLevel] = 2 +// err = dao.GetEntitiesByKV(db, &cats, cond, true) +// if err == nil { +// err = v.syncCategories(ctx, t, vendorInfo.VendorID, db, cats, userName) +// } +// return nil, err +// }) +// return "", err +// } func (v *VendorSync) SyncReorderCategories(ctx *jxcontext.Context, db *dao.DaoDB, categoryID int, isAsync bool, userName string) (hint string, err error) { - if !globals.IsUseThingMap { - return v.oldSyncReorderCategories(ctx, db, categoryID, isAsync, userName) - } + // if !globals.IsUseThingMap { + // return v.oldSyncReorderCategories(ctx, db, categoryID, isAsync, userName) + // } return SyncReorderCategories(ctx, -1, isAsync) } -func (v *VendorSync) oldSyncReorderCategories(ctx *jxcontext.Context, db *dao.DaoDB, categoryID int, isAsync bool, userName string) (hint string, err error) { - hint, err = v.LoopMultiStoresVendors(ctx, db, fmt.Sprintf("分类重排序:%d", categoryID), isAsync, false, func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (interface{}, error) { - vendorInfo := batchItemList[0].(*MultiStoreVendorInfo) - multiStoresHandler := v.GetMultiStoreHandler(vendorInfo.VendorID) - err2 := multiStoresHandler.ReorderCategories(db, categoryID, userName) - if err2 == nil { - cat := &model.SkuCategory{} - _, err2 = dao.UpdateEntityByKV(db, cat, utils.Params2Map(dao.GetSyncStatusStructField(model.VendorNames[multiStoresHandler.GetVendorID()]), 0), utils.Params2Map(model.FieldParentID, categoryID)) - return nil, err2 - } - return nil, err2 - }) - return "", err -} +// func (v *VendorSync) oldSyncReorderCategories(ctx *jxcontext.Context, db *dao.DaoDB, categoryID int, isAsync bool, userName string) (hint string, err error) { +// hint, err = v.LoopMultiStoresVendors(ctx, db, fmt.Sprintf("分类重排序:%d", categoryID), isAsync, false, func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (interface{}, error) { +// vendorInfo := batchItemList[0].(*MultiStoreVendorInfo) +// multiStoresHandler := v.GetMultiStoreHandler(vendorInfo.VendorID) +// err2 := multiStoresHandler.ReorderCategories(db, categoryID, userName) +// if err2 == nil { +// cat := &model.SkuCategory{} +// _, err2 = dao.UpdateEntityByKV(db, cat, utils.Params2Map(dao.GetSyncStatusStructField(model.VendorNames[multiStoresHandler.GetVendorID()]), 0), utils.Params2Map(model.FieldParentID, categoryID)) +// return nil, err2 +// } +// return nil, err2 +// }) +// return "", err +// } func (v *VendorSync) SyncStore(ctx *jxcontext.Context, db *dao.DaoDB, vendorID, storeID int, isAsync bool, userName string) (hint string, err error) { globals.SugarLogger.Debugf("SyncStore, storeID:%d", storeID) @@ -281,109 +280,109 @@ func (v *VendorSync) SyncSku(ctx *jxcontext.Context, db *dao.DaoDB, nameID, skuI } func (v *VendorSync) SyncSkus(ctx *jxcontext.Context, db *dao.DaoDB, nameIDs []int, skuIDs []int, isAsync, isContinueWhenError bool, userName string) (hint string, err error) { - if !globals.IsUseThingMap { - return v.oldSyncSkus(ctx, db, nameIDs, skuIDs, isAsync, isContinueWhenError, userName) - } + // if !globals.IsUseThingMap { + // return v.oldSyncSkus(ctx, db, nameIDs, skuIDs, isAsync, isContinueWhenError, userName) + // } return SyncSkus(ctx, nil, nil, nil, nameIDs, skuIDs, isAsync) } -func (v *VendorSync) oldSyncSkus(ctx *jxcontext.Context, db *dao.DaoDB, nameIDs []int, skuIDs []int, isAsync, isContinueWhenError bool, userName string) (hint string, err error) { - globals.SugarLogger.Debugf("SyncSku trackInfo:%s, nameIDs:%v, skuIDs:%v, userName:%s", ctx.GetTrackInfo(), nameIDs, skuIDs, userName) - isManagedIt := !(len(nameIDs) > 0 && len(nameIDs) <= 2 || len(skuIDs) > 0 && len(skuIDs) < 8) - return v.LoopMultiStoresVendors(ctx, db, fmt.Sprintf("同步商品信息, nameIDs:%v, skuIDs:%v", nameIDs, skuIDs), isAsync, isManagedIt, - func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (interface{}, error) { - var resultList []interface{} - vendorInfo := batchItemList[0].(*MultiStoreVendorInfo) - multiStoresHandler := v.GetMultiStoreHandler(vendorInfo.VendorID) - syncStatusFieldName := dao.GetSyncStatusStructField(model.VendorNames[multiStoresHandler.GetVendorID()]) - dbField := dao.ConvertDBFieldPrefix(model.VendorNames[multiStoresHandler.GetVendorID()]) - skuMap := make(map[int]bool) - sql := fmt.Sprintf(` - SELECT DISTINCT t2.* - FROM sku t1 - JOIN sku_name t2 ON t2.id = t1.name_id - WHERE t1.%s_sync_status <> 0 - `, dbField) - sqlParams := []interface{}{} - if len(nameIDs) > 0 { - sql += " AND t1.name_id IN (" + dao.GenQuestionMarks(len(nameIDs)) + ")" - sqlParams = append(sqlParams, nameIDs) - } - if len(skuIDs) > 0 { - sql += " AND t1.id IN(" + dao.GenQuestionMarks(len(skuIDs)) + ")" - sqlParams = append(sqlParams, skuIDs) +// func (v *VendorSync) oldSyncSkus(ctx *jxcontext.Context, db *dao.DaoDB, nameIDs []int, skuIDs []int, isAsync, isContinueWhenError bool, userName string) (hint string, err error) { +// globals.SugarLogger.Debugf("SyncSku trackInfo:%s, nameIDs:%v, skuIDs:%v, userName:%s", ctx.GetTrackInfo(), nameIDs, skuIDs, userName) +// isManagedIt := !(len(nameIDs) > 0 && len(nameIDs) <= 2 || len(skuIDs) > 0 && len(skuIDs) < 8) +// return v.LoopMultiStoresVendors(ctx, db, fmt.Sprintf("同步商品信息, nameIDs:%v, skuIDs:%v", nameIDs, skuIDs), isAsync, isManagedIt, +// func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (interface{}, error) { +// var resultList []interface{} +// vendorInfo := batchItemList[0].(*MultiStoreVendorInfo) +// multiStoresHandler := v.GetMultiStoreHandler(vendorInfo.VendorID) +// syncStatusFieldName := dao.GetSyncStatusStructField(model.VendorNames[multiStoresHandler.GetVendorID()]) +// dbField := dao.ConvertDBFieldPrefix(model.VendorNames[multiStoresHandler.GetVendorID()]) +// skuMap := make(map[int]bool) +// sql := fmt.Sprintf(` +// SELECT DISTINCT t2.* +// FROM sku t1 +// JOIN sku_name t2 ON t2.id = t1.name_id +// WHERE t1.%s_sync_status <> 0 +// `, dbField) +// sqlParams := []interface{}{} +// if len(nameIDs) > 0 { +// sql += " AND t1.name_id IN (" + dao.GenQuestionMarks(len(nameIDs)) + ")" +// sqlParams = append(sqlParams, nameIDs) +// } +// if len(skuIDs) > 0 { +// sql += " AND t1.id IN(" + dao.GenQuestionMarks(len(skuIDs)) + ")" +// sqlParams = append(sqlParams, skuIDs) - } - for _, v := range skuIDs { - skuMap[v] = true - } - sql += " ORDER BY t2.id" +// } +// for _, v := range skuIDs { +// skuMap[v] = true +// } +// sql += " ORDER BY t2.id" - var skuNameList []*model.SkuName - err := dao.GetRows(db, &skuNameList, sql, sqlParams...) - if err == nil && len(skuNameList) > 0 { - // todo 同一skuName下的sku顺序处理的原因是京东SPU特殊类型必须要序列化同步才能正常处理, db可能会有多线程问题 - task := tasksch.NewParallelTask(fmt.Sprintf("处理平台%s", model.VendorChineseNames[vendorInfo.VendorID]), tasksch.NewParallelConfig().SetParallelCount(10).SetIsContinueWhenError(isContinueWhenError), ctx, - func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (interface{}, error) { - var resultList []interface{} - skuName := batchItemList[0].(*model.SkuName) - var skuList []*model.Sku - if err = dao.GetRows(db, &skuList, fmt.Sprintf(` - SELECT * - FROM sku - WHERE name_id = ? AND %s_sync_status <> 0 - ORDER BY IF(spec_unit IN('kg', 'L'), 1000, 1) * spec_quality - `, dbField), skuName.ID); err == nil && len(skuList) > 0 { - for _, sku := range skuList { - syncStatus := refutil.GetObjFieldByName(sku, syncStatusFieldName).(int8) - globals.SugarLogger.Debugf("SyncSku trackInfo2:%s, skuID:%d, syncStatus:%d", ctx.GetTrackInfo(), sku.ID, syncStatus) - if (len(skuIDs) == 0 || skuMap[sku.ID]) && (syncStatus != 0) { - updateFields := []string{syncStatusFieldName} - if syncStatus&model.SyncFlagDeletedMask != 0 { // 删除 - if syncStatus&model.SyncFlagNewMask == 0 { - err = multiStoresHandler.DeleteSku(db, sku, userName) - } - } else if syncStatus&model.SyncFlagNewMask != 0 { // 新增 - if err = multiStoresHandler.CreateSku(db, sku, userName); err == nil { - var tmpStruct struct { - MaxIndex int - } - // todo hard code 得到京东spu中sku的顺序(以方便以后修改销售属性),这个必须要每次重新从数据库取 - if dao.GetRow(db, &tmpStruct, "SELECT MAX(sku_index) max_index FROM sku WHERE name_id = ? AND jd_id > 0 AND jd_id < 4024012631406 ", sku.NameID) == nil { - sku.SkuIndex = tmpStruct.MaxIndex + 1 - updateFields = append(updateFields, "SkuIndex") - } - updateFields = append(updateFields, dao.GetVendorThingIDStructField(model.VendorNames[multiStoresHandler.GetVendorID()])) - } - } else if syncStatus&model.SyncFlagModifiedMask != 0 { // 修改 - err = multiStoresHandler.UpdateSku(db, sku, userName) - } - if err == nil { - refutil.SetObjFieldByName(sku, syncStatusFieldName, int8(0)) - if _, err = dao.UpdateEntity(db, sku, updateFields...); err != nil { - break - } else { - resultList = append(resultList, 1) - } - } - } - } - } - if err == nil { - refutil.SetObjFieldByName(skuName, syncStatusFieldName, int8(0)) - _, err = dao.UpdateEntity(db, skuName, syncStatusFieldName) - } - return resultList, err - }, skuNameList) - t.AddChild(task).Run() - result, err2 := task.GetResult(0) - if err = err2; err == nil { - resultList = append(resultList, result...) - } - } - return resultList, err - }) -} +// var skuNameList []*model.SkuName +// err := dao.GetRows(db, &skuNameList, sql, sqlParams...) +// if err == nil && len(skuNameList) > 0 { +// // todo 同一skuName下的sku顺序处理的原因是京东SPU特殊类型必须要序列化同步才能正常处理, db可能会有多线程问题 +// task := tasksch.NewParallelTask(fmt.Sprintf("处理平台%s", model.VendorChineseNames[vendorInfo.VendorID]), tasksch.NewParallelConfig().SetParallelCount(10).SetIsContinueWhenError(isContinueWhenError), ctx, +// func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (interface{}, error) { +// var resultList []interface{} +// skuName := batchItemList[0].(*model.SkuName) +// var skuList []*model.Sku +// if err = dao.GetRows(db, &skuList, fmt.Sprintf(` +// SELECT * +// FROM sku +// WHERE name_id = ? AND %s_sync_status <> 0 +// ORDER BY IF(spec_unit IN('kg', 'L'), 1000, 1) * spec_quality +// `, dbField), skuName.ID); err == nil && len(skuList) > 0 { +// for _, sku := range skuList { +// syncStatus := refutil.GetObjFieldByName(sku, syncStatusFieldName).(int8) +// globals.SugarLogger.Debugf("SyncSku trackInfo2:%s, skuID:%d, syncStatus:%d", ctx.GetTrackInfo(), sku.ID, syncStatus) +// if (len(skuIDs) == 0 || skuMap[sku.ID]) && (syncStatus != 0) { +// updateFields := []string{syncStatusFieldName} +// if syncStatus&model.SyncFlagDeletedMask != 0 { // 删除 +// if syncStatus&model.SyncFlagNewMask == 0 { +// err = multiStoresHandler.DeleteSku(db, sku, userName) +// } +// } else if syncStatus&model.SyncFlagNewMask != 0 { // 新增 +// if err = multiStoresHandler.CreateSku(db, sku, userName); err == nil { +// var tmpStruct struct { +// MaxIndex int +// } +// // todo hard code 得到京东spu中sku的顺序(以方便以后修改销售属性),这个必须要每次重新从数据库取 +// if dao.GetRow(db, &tmpStruct, "SELECT MAX(sku_index) max_index FROM sku WHERE name_id = ? AND jd_id > 0 AND jd_id < 4024012631406 ", sku.NameID) == nil { +// sku.SkuIndex = tmpStruct.MaxIndex + 1 +// updateFields = append(updateFields, "SkuIndex") +// } +// updateFields = append(updateFields, dao.GetVendorThingIDStructField(model.VendorNames[multiStoresHandler.GetVendorID()])) +// } +// } else if syncStatus&model.SyncFlagModifiedMask != 0 { // 修改 +// err = multiStoresHandler.UpdateSku(db, sku, userName) +// } +// if err == nil { +// refutil.SetObjFieldByName(sku, syncStatusFieldName, int8(0)) +// if _, err = dao.UpdateEntity(db, sku, updateFields...); err != nil { +// break +// } else { +// resultList = append(resultList, 1) +// } +// } +// } +// } +// } +// if err == nil { +// refutil.SetObjFieldByName(skuName, syncStatusFieldName, int8(0)) +// _, err = dao.UpdateEntity(db, skuName, syncStatusFieldName) +// } +// return resultList, err +// }, skuNameList) +// t.AddChild(task).Run() +// result, err2 := task.GetResult(0) +// if err = err2; err == nil { +// resultList = append(resultList, result...) +// } +// } +// return resultList, err +// }) +// } func (v *VendorSync) SyncStoresCategory(ctx *jxcontext.Context, db *dao.DaoDB, vendorIDs []int, storeIDs []int, isForce, isAsync, isContinueWhenError bool) (hint string, err error) { globals.SugarLogger.Debug("SyncStoresCategory") @@ -572,6 +571,29 @@ func (v *VendorSync) AddCreateFlagForJxStoreSku(ctx *jxcontext.Context, vendorID return hint, makeSyncError(err) } +func (v *VendorSync) AmendAndPruneStoreStuff(ctx *jxcontext.Context, vendorIDs []int, storeIDs []int, isAsync, isContinueWhenError bool, optType int, isForceUpdate bool) (hint string, err error) { + globals.SugarLogger.Debug("AmendAndPruneStoreStuff") + hint, err = v.LoopStoresMap(ctx, dao.GetDB(), fmt.Sprintf("处理京西平台商家分类与商品差异:%v", storeIDs), isAsync, true, vendorIDs, storeIDs, + func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (interface{}, error) { + loopMapInfo := batchItemList[0].(*LoopStoreMapInfo) + if len(loopMapInfo.StoreMapList) > 1 { + loopStoreTask := tasksch.NewParallelTask(fmt.Sprintf("处理平台%s", model.VendorChineseNames[loopMapInfo.VendorID]), + tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError).SetParallelCount(5), ctx, + func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { + storeMap := batchItemList[0].(*model.StoreMap) + _, err = amendAndPruneStoreStuff(ctx, task, loopMapInfo.VendorID, storeMap.StoreID, storeMap.VendorStoreID, false, isContinueWhenError, optType, isForceUpdate) + return nil, err + }, loopMapInfo.StoreMapList) + t.AddChild(loopStoreTask).Run() + _, err = loopStoreTask.GetResult(0) + } else { + _, err = amendAndPruneStoreStuff(ctx, t, loopMapInfo.VendorID, loopMapInfo.StoreMapList[0].StoreID, loopMapInfo.StoreMapList[0].VendorStoreID, false, isContinueWhenError, optType, isForceUpdate) + } + return nil, partner.AddVendorInfo2Err(err, loopMapInfo.VendorID) + }, isContinueWhenError) + return hint, makeSyncError(err) +} + func (v *VendorSync) LoopStoresMap2(ctx *jxcontext.Context, db *dao.DaoDB, taskName string, isAsync, isManageIt bool, vendorIDs []int, storeIDs []int, handler tasksch.WorkFunc, isContinueWhenError bool) (task tasksch.ITask, hint string, err error) { var storeMapList []*model.StoreMap if storeMapList, err = dao.GetStoresMapList(db, vendorIDs, storeIDs, model.StoreStatusAll, model.StoreIsSyncYes, ""); err != nil { @@ -722,7 +744,7 @@ func (v *VendorSync) ChangeStoreSkuSaleStatus(ctx *jxcontext.Context, storeID in skuIDs = append(skuIDs, v.SkuID) } vendorIDs := partner.GetPurchasePlatformVendorIDs() - dao.UpdateStoreSkuBindSyncStatus(db, vendorIDs, storeID) + dao.UpdateStoreSkuBindSyncStatusForSaleStatus(db, vendorIDs, storeID) v.SyncStoresSkus(ctx, db, vendorIDs, storeIDs, skuIDs, false, isAsync, isContinueWhenError) return err } diff --git a/business/jxstore/cms/sync2.go b/business/jxstore/cms/sync2.go index 0d28c262a..03a7fc223 100644 --- a/business/jxstore/cms/sync2.go +++ b/business/jxstore/cms/sync2.go @@ -42,7 +42,7 @@ func getMultiStoreVendorInfoList() (list []*MultiStoreVendorInfo) { func syncCategories(ctx *jxcontext.Context, db *dao.DaoDB, parentTask tasksch.ITask, catList []*dao.SkuStoreCatInfo, isAsync bool) (hint string, err error) { if len(catList) > 0 { // todo 按vendorID orgCode合并操作 - task := tasksch.NewParallelTask(fmt.Sprintf("同步分类2:%D", len(catList)), tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx, + task := tasksch.NewParallelTask(fmt.Sprintf("同步分类2:%d", len(catList)), tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { catVendorInfo := batchItemList[0].(*dao.SkuStoreCatInfo) if catVendorInfo.Level != 1 && catVendorInfo.ParentVendorCatID == "" { @@ -84,10 +84,11 @@ func syncCategories(ctx *jxcontext.Context, db *dao.DaoDB, parentTask tasksch.IT } func SyncCategories(ctx *jxcontext.Context, parentTask tasksch.ITask, vendorIDs []int, appOrgCodes []string, catIDs []int, isAsync bool) (hint string, err error) { - globals.SugarLogger.Debugf("SyncCategories catIDs:%v", catIDs) + globals.SugarLogger.Debugf("SyncCategories vendorIDs:%v, appOrgCodes:%v, catIDs:%v", vendorIDs, appOrgCodes, catIDs) db := dao.GetDB() catList, err := dao.GetSkuCategoryWithVendor(db, vendorIDs, appOrgCodes, -1, catIDs, true) if err == nil && len(catList) > 0 { + // TODO 同一平台不同账号会有影响needSyncParentIDs,暂不处理 var needSyncParentIDs []int for _, cat := range catList { if cat.Level == 2 && cat.ParentVendorCatID == "" { @@ -128,7 +129,7 @@ func SyncCategories(ctx *jxcontext.Context, parentTask tasksch.ITask, vendorIDs } func SyncSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, vendorIDs []int, appOrgCodes []string, nameIDs, skuIDs []int, isAsync bool) (hint string, err error) { - globals.SugarLogger.Debugf("SyncSkus nameIDs:%v, skuIDs:%v", nameIDs, skuIDs) + globals.SugarLogger.Debugf("SyncSkus vendorIDs:%v, appOrgCodes:%v, nameIDs:%v, skuIDs:%v", vendorIDs, appOrgCodes, nameIDs, skuIDs) db := dao.GetDB() skuList, err := dao.GetSkusWithVendor(db, vendorIDs, appOrgCodes, nameIDs, skuIDs, true) if err == nil && len(skuList) > 0 { @@ -142,7 +143,7 @@ func SyncSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, vendorIDs []int, if skuVendorInfo.BindID == 0 { return nil, fmt.Errorf("商品:%d的数据异常", skuVendorInfo.SkuID) } - skuVendorInfo.SkuName = jxutils.ComposeSkuName(skuVendorInfo.Prefix, skuVendorInfo.Name, skuVendorInfo.Comment, skuVendorInfo.Unit, skuVendorInfo.SpecQuality, skuVendorInfo.SpecUnit, 0) + skuVendorInfo.SkuName = jxutils.ComposeSkuName(skuVendorInfo.Prefix, skuVendorInfo.Name, skuVendorInfo.Comment, skuVendorInfo.Unit, skuVendorInfo.SpecQuality, skuVendorInfo.SpecUnit, 0, skuVendorInfo.ExPrefix, skuVendorInfo.ExPrefixBegin, skuVendorInfo.ExPrefixEnd) skuVendorInfo.MergedStatus = jxutils.MergeSkuStatus(skuVendorInfo.Status, skuVendorInfo.NameStatus) if multiStoresHandler, ok := partner.GetPurchasePlatformFromVendorID(skuVendorInfo.VendorID).(partner.IMultipleStoresHandler); ok { if model.IsSyncStatusDelete(skuVendorInfo.SkuSyncStatus) { //删除 diff --git a/business/jxstore/cms/sync_store_sku.go b/business/jxstore/cms/sync_store_sku.go index 4be5d6d7e..9384d0fc4 100644 --- a/business/jxstore/cms/sync_store_sku.go +++ b/business/jxstore/cms/sync_store_sku.go @@ -228,13 +228,16 @@ func calVendorPrice4StoreSku(inSku *dao.StoreSkuSyncInfo, pricePercentagePack mo func formalizeStoreSkuList(inSkuList []*dao.StoreSkuSyncInfo) []*dao.StoreSkuSyncInfo { for _, skuItem := range inSkuList { skuItem.MergedStatus = jxutils.MergeSkuStatus(skuItem.Status, skuItem.StoreSkuStatus) - skuItem.SkuName = jxutils.ComposeSkuName(skuItem.Prefix, skuItem.Name, skuItem.Comment, skuItem.Unit, skuItem.SpecQuality, skuItem.SpecUnit, 0) + skuItem.SkuName = jxutils.ComposeSkuNameSync(skuItem.Prefix, skuItem.Name, skuItem.Comment, skuItem.Unit, skuItem.SpecQuality, skuItem.SpecUnit, 0, skuItem.ExPrefix, skuItem.ExPrefixBegin, skuItem.ExPrefixEnd) } return inSkuList } func sku2Update(vendorID int, sku *dao.StoreSkuSyncInfo, syncStatus int8) (item *dao.KVUpdateItem) { kvs := map[string]interface{}{} + if !isSkuLockTimeValid(sku) { + kvs[dao.GetVendorLockTimeStructField(model.VendorNames[vendorID])] = nil + } if syncStatus&(model.SyncFlagDeletedMask|model.SyncFlagNewMask|model.SyncFlagModifiedMask) != 0 { if model.IsSyncStatusNew(syncStatus) { sku.SkuSyncStatus = 0 @@ -289,6 +292,10 @@ func updateStoreSku(db *dao.DaoDB, vendorID int, storeSkuList []*dao.StoreSkuSyn return num, err } +func isSkuLockTimeValid(sku *dao.StoreSkuSyncInfo) bool { + return sku.LockTime != nil && time.Now().Sub(*sku.LockTime) < 0 +} + func syncStoreSkuNew(ctx *jxcontext.Context, parentTask tasksch.ITask, isFull bool, vendorID, storeID int, nameIDs, skuIDs, excludeSkuIDs []int, useVendorPriceDirectly, isContinueWhenError bool) (err error) { db := dao.GetDB() storeDetail, err := dao.GetStoreDetail(db, storeID, vendorID) @@ -334,7 +341,8 @@ func syncStoreSkuNew(ctx *jxcontext.Context, parentTask tasksch.ITask, isFull bo } now := jxutils.OperationTime2HourMinuteFormat(time.Now()) for _, sku := range skus { - if !useVendorPriceDirectly { + if !useVendorPriceDirectly && + !isSkuLockTimeValid(sku) { sku.VendorPrice = 0 } sku.MergedStatus = MergeSkuSaleStatusWithStoreOpTime(sku, storeDetail, now) @@ -354,14 +362,18 @@ func syncStoreSkuNew(ctx *jxcontext.Context, parentTask tasksch.ITask, isFull bo } else if model.IsSyncStatusNew(sku.SkuSyncStatus) { calVendorPrice4StoreSku(sku, storeDetail.PricePercentagePackObj, int(storeDetail.PricePercentage)) if singleStoreHandler == nil { - sku.SkuSyncStatus |= model.SyncFlagSaleMask | model.SyncFlagPriceMask - bareSku = storeSkuSyncInfo2Bare(sku) - stockList = append(stockList, bareSku) - priceList = append(priceList, bareSku) - if sku.MergedStatus == model.SkuStatusNormal { - onlineList = append(onlineList, bareSku) + if dao.IsVendorThingIDEmpty(sku.VendorSkuID) { + // todo 多平台商品库没有正常创建,直接跳过 } else { - offlineList = append(offlineList, bareSku) + sku.SkuSyncStatus |= model.SyncFlagSaleMask | model.SyncFlagPriceMask + bareSku = storeSkuSyncInfo2Bare(sku) + stockList = append(stockList, bareSku) + priceList = append(priceList, bareSku) + if sku.MergedStatus == model.SkuStatusNormal { + onlineList = append(onlineList, bareSku) + } else { + offlineList = append(offlineList, bareSku) + } } } else { if sku.MergedStatus == model.SkuStatusNormal { @@ -703,11 +715,13 @@ func amendAndPruneStoreStuff(ctx *jxcontext.Context, parentTask tasksch.ITask, v if (opType == AmendPruneOnlyPrune || opType == AmendPruneAll) && len(sku2Delete) > 0 { _, err = putils.FreeBatchStoreSkuInfo("删除门店商品", func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) { if _, err = handler.DeleteStoreSkus(ctx, storeID, vendorStoreID, batchedStoreSkuList); err != nil { - // 如果删除失败,尝试设置不可售,假定删除批处理SIZE小于等于设置门店商品可售批处理SIZE - handler.UpdateStoreSkusStatus(ctx, storeDetail.VendorOrgCode, storeID, vendorStoreID, batchedStoreSkuList, model.SkuStatusDontSale) + if batchedStoreSkuList[0].Status == model.SkuStatusNormal { + // 如果删除失败,尝试设置不可售,假定删除批处理SIZE小于等于设置门店商品可售批处理SIZE + handler.UpdateStoreSkusStatus(ctx, storeDetail.VendorOrgCode, storeID, vendorStoreID, batchedStoreSkuList, model.SkuStatusDontSale) + } } return nil, 0, err - }, ctx, task, sku2Delete, handler.GetStoreSkusBatchSize(partner.FuncDeleteStoreSkus), isContinueWhenError) + }, ctx, task, sku2Delete, 1 /*handler.GetStoreSkusBatchSize(partner.FuncDeleteStoreSkus)*/, isContinueWhenError) } sku2Delete = nil case 2: diff --git a/business/jxstore/cms/sync_store_sku_test.go b/business/jxstore/cms/sync_store_sku_test.go index 0df67e1a0..23c8cbd6d 100644 --- a/business/jxstore/cms/sync_store_sku_test.go +++ b/business/jxstore/cms/sync_store_sku_test.go @@ -33,7 +33,7 @@ func TestFreeBatchStoreSkuInfo(t *testing.T) { } func TestGetTimeMixByInt(t *testing.T) { - var ( + const ( time1 = 1100 time2 = 2300 time3 = 1200 diff --git a/business/jxstore/misc/misc.go b/business/jxstore/misc/misc.go index 62923b4b9..8f1b302cf 100644 --- a/business/jxstore/misc/misc.go +++ b/business/jxstore/misc/misc.go @@ -9,6 +9,7 @@ import ( "git.rosy.net.cn/jx-callback/business/jxstore/report" "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/baseapi/utils/errlist" "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/business/jxstore/act" @@ -34,8 +35,11 @@ var ( dailyWorkTimeList = []string{ "20:30:00", } + priceReferTimeList = []string{ + "01:00:00", + } createStorePriceTimeList = []string{ - "23:00:00", + "02:00:00", } refreshPageActTimeList = []string{ "7:00:00", @@ -113,7 +117,7 @@ func Init() { }, 5*time.Second, 1*time.Hour) ScheduleTimerFuncByInterval(func() { - defsch.FixedScheduler.ConfirmSelfTakeOrders(jxcontext.AdminCtx, nil, time.Now().Add(-48*time.Hour), time.Now().Add(-30*time.Minute), true, true) + defsch.FixedScheduler.ConfirmSelfTakeOrders(jxcontext.AdminCtx, []int{model.VendorIDJD}, time.Now().Add(-48*time.Hour), time.Now().Add(-30*time.Minute), true, true) }, 5*time.Second, 10*time.Minute) ScheduleTimerFunc("auto enable remote store", func() { @@ -129,7 +133,7 @@ func Init() { act.RefreshPageActs(jxcontext.AdminCtx, []int{model.VendorIDEBAI}, time.Now().Add(-30*24*time.Hour), false) }, refreshPageActTimeList) ScheduleTimerFunc("UpdateActStatusByTime", func() { - dao.UpdateActStatusByTime(dao.GetDB(), time.Now().Add(-48*time.Hour)) + dao.UpdateActStatusByTime(dao.GetDB(), time.Now()) }, updateActStatusTimeList) ScheduleScoreStore() ScheduleCheckStoreAlert() @@ -138,10 +142,10 @@ func Init() { }, ChangeStoreSkuSaleStatusList) ScheduleTimerFunc("BeginSavePriceRefer", func() { report.BeginSavePriceRefer(jxcontext.AdminCtx, nil, nil) - }, createStorePriceTimeList) + }, priceReferTimeList) ScheduleTimerFunc("CreateStorePriceScore", func() { - cms.CreateStorePriceScore(jxcontext.AdminCtx, false) - }, openRemoteStoreTimeList) + cms.CreateStorePriceScore(jxcontext.AdminCtx) + }, createStorePriceTimeList) } ScheduleTimerFunc("AutoSaleStoreSku", func() { cms.AutoSaleStoreSku(jxcontext.AdminCtx, nil, false) @@ -156,20 +160,55 @@ func Init() { } } -func doDailyWork() { - globals.SugarLogger.Debug("doDailyWork") - cms.SyncStoresCourierInfo(jxcontext.AdminCtx, nil, false, true) - netprinter.RebindAllPrinters(jxcontext.AdminCtx, false, true) +func syncStoreSku() { syncFlag := model.SyncFlagPriceMask if (time.Now().Unix()/24*3600)%10 == 0 { syncFlag |= model.SyncFlagSaleMask } - // cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, dao.GetDB(), []int{model.VendorIDJD}, nil, false, nil, []int{27379}, syncFlag, true, true) - cms.CurVendorSync.FullSyncStoresSkus(jxcontext.AdminCtx, dao.GetDB(), []int{model.VendorIDJD}, nil, false, []int{27379}, true, true) + task := tasksch.NewParallelTask("同步京西与平台数据", nil, jxcontext.AdminCtx, + func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { + step := batchItemList[0].(int) + errList := errlist.New() + db := dao.GetDB() + switch step { + case 0: + errList.AddErr(cms.DeleteSkuNameExPrefixOverdue(db)) + errList.AddErr(cms.SetMultiStoreSkuSyncModifyStatus(db, partner.GetMultiStoreVendorIDs())) - SaveImportantTaskID(TaskNameSyncStoreSku, SpecialTaskID) - taskID, _ := cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, dao.GetDB(), []int{model.VendorIDEBAI, model.VendorIDMTWM}, nil, false, nil, nil, syncFlag, true, true) - SaveImportantTaskID(TaskNameSyncStoreSku, taskID) + _, err = cms.CurVendorSync.LoopMultiStoresVendors(jxcontext.AdminCtx, db, "同步多门店平台商品库", false, true, + func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { + vendorInfo := batchItemList[0].(*cms.MultiStoreVendorInfo) + _, err = cms.FullSyncVendorStuff(jxcontext.AdminCtx, task, vendorInfo.VendorID, vendorInfo.OrgCode, false, true) + return retVal, err + }) + errList.AddErr(err) + + // cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, db, partner.GetMultiStoreVendorIDs(), nil, false, nil, []int{27379}, syncFlag, true, true) + _, err = cms.CurVendorSync.FullSyncStoresSkus(jxcontext.AdminCtx, db, partner.GetMultiStoreVendorIDs(), nil, false, []int{27379}, true, true) + errList.AddErr(err) + case 1: + errList.AddErr(cms.SetSingleStoreSkuSyncModifyStatus(db, partner.GetSingleStoreVendorIDs())) + + _, err = cms.CurVendorSync.AmendAndPruneStoreStuff(jxcontext.AdminCtx, partner.GetSingleStoreVendorIDs(), nil, false, true, cms.AmendPruneAll, false) + errList.AddErr(err) + + SaveImportantTaskID(TaskNameSyncStoreSku, SpecialTaskID) + taskID, err2 := cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, db, partner.GetSingleStoreVendorIDs(), nil, false, nil, nil, syncFlag, true, true) + errList.AddErr(err2) + SaveImportantTaskID(TaskNameSyncStoreSku, taskID) + } + err = errList.GetErrListAsOne() + return retVal, err + }, []int{0, 1}) + tasksch.HandleTask(task, nil, true).Run() +} + +func doDailyWork() { + globals.SugarLogger.Debug("doDailyWork") + cms.SyncStoresCourierInfo(jxcontext.AdminCtx, nil, false, true) + netprinter.RebindAllPrinters(jxcontext.AdminCtx, false, true) + + syncStoreSku() InitEx() @@ -180,6 +219,8 @@ func doDailyWork() { //fromDate, toDate都不传默认刷新当前天5天以前的订单,只传fromDate默认刷新fromDate到当天的订单 //只传toDate默认刷新toDate到5天以前的订单 orderman.RefreshOrdersWithoutJxStoreID(jxcontext.AdminCtx, "", "", true, true) + //刷新京东门店的等级 + cms.RefreshJdLevel(jxcontext.AdminCtx) } func RefreshRealMobile(ctx *jxcontext.Context, vendorID int, fromTime, toTime time.Time, isAsync, isContinueWhenError bool) (hint string, err error) { diff --git a/business/jxstore/misc/store_score.go b/business/jxstore/misc/store_score.go index 214d9acd3..cf3752bf4 100644 --- a/business/jxstore/misc/store_score.go +++ b/business/jxstore/misc/store_score.go @@ -396,7 +396,7 @@ func ScorePromotionSku(storeInfo *cms.StoreExt) { db := dao.GetDB() beginTime := time.Now() endTime := time.Now() - actStoreSkuList, err := dao.GetEffectiveActStoreSkuInfo(db, -1, nil, []int{storeID}, nil, beginTime, endTime) + actStoreSkuList, err := dao.GetEffectiveActStoreSkuInfo(db, -1, nil, model.ActTypeAll, []int{storeID}, nil, beginTime, endTime) finalScore := 0 if err == nil && len(actStoreSkuList) > 0 { actStoreSkuMap := make(map[int]int) diff --git a/business/jxstore/misc/store_sku_sales.go b/business/jxstore/misc/store_sku_sales.go index ca0dfc7fe..2f7e677fe 100644 --- a/business/jxstore/misc/store_sku_sales.go +++ b/business/jxstore/misc/store_sku_sales.go @@ -149,7 +149,7 @@ func GetStoreSkuSalesInfo(ctx *jxcontext.Context, storeID int) (outStoreSkuSales if storeSkuInfo != nil { skuName := storeSkuInfo.SkuName skuInfo := storeSkuInfo.Skus[0] - storeSkuSales.SkuName = jxutils.ComposeSkuName(skuName.Prefix, skuName.Name, skuInfo.Comment, skuName.Unit, skuInfo.SkuSpecQuality, skuInfo.SkuSpecUnit, 0) + storeSkuSales.SkuName = jxutils.ComposeSkuName(skuName.Prefix, skuName.Name, skuInfo.Comment, skuName.Unit, skuInfo.SkuSpecQuality, skuInfo.SkuSpecUnit, 0,skuName.ExPrefix,skuName.ExPrefixBegin,skuName.ExPrefixEnd) storeSkuSales.SkuImage = storeSkuInfo.Img storeSkuSales.SkuPrice = jxutils.IntPrice2StandardCurrencyString(int64(storeSkuInfo.Skus[0].BindPrice)) } else if skuAndNameInfo != nil { @@ -159,7 +159,7 @@ func GetStoreSkuSalesInfo(ctx *jxcontext.Context, storeID int) (outStoreSkuSales storeSkuSales.SkuImage = skuNameList[0].Img prefix = skuNameList[0].Prefix } - storeSkuSales.SkuName = jxutils.ComposeSkuName(prefix, skuAndNameInfo.Name, skuAndNameInfo.Comment, skuAndNameInfo.Unit, skuAndNameInfo.SpecQuality, skuAndNameInfo.SpecUnit, 0) + storeSkuSales.SkuName = jxutils.ComposeSkuName(prefix, skuAndNameInfo.Name, skuAndNameInfo.Comment, skuAndNameInfo.Unit, skuAndNameInfo.SpecQuality, skuAndNameInfo.SpecUnit, 0,skuAndNameInfo.ExPrefix,skuAndNameInfo.ExPrefixBegin,skuAndNameInfo.ExPrefixEnd) storeSkuSales.SkuPrice = "N/A" } else { storeSkuSales.SkuName = "N/A" diff --git a/business/jxstore/report/report.go b/business/jxstore/report/report.go index f3120c702..cc78fbe71 100644 --- a/business/jxstore/report/report.go +++ b/business/jxstore/report/report.go @@ -6,6 +6,8 @@ import ( "math" "time" + "git.rosy.net.cn/jx-callback/globals" + "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/business/jxutils/jxcontext" "git.rosy.net.cn/jx-callback/business/model" @@ -52,7 +54,7 @@ func StatisticsReportForStoreSkusPrice(ctx *jxcontext.Context, cityCodes, skuIDs func BeginSavePriceRefer(ctx *jxcontext.Context, cityCodes, skuIDs []int) (err error) { db := dao.GetDB() - snapshotAt := utils.Time2Date(time.Now()) + snapshotAt := utils.Time2Date(time.Now().AddDate(0, 0, -1)) priceReferSnapshot, err := dao.GetStatisticsReportForStoreSkusPrice(db, cityCodes, skuIDs) if len(priceReferSnapshot) > 0 { dao.Begin(db) @@ -71,12 +73,12 @@ func BeginSavePriceRefer(ctx *jxcontext.Context, cityCodes, skuIDs []int) (err e for _, v := range priceReferSnapshot { dao.WrapAddIDCULDEntity(v, ctx.GetUserName()) v.SnapshotAt = snapshotAt - fmt.Println(v) if err = dao.CreateEntity(db, v); err != nil { return err } } dao.Commit(db) + globals.SugarLogger.Debugf("CreatePriceRefer") } return err } diff --git a/business/jxstore/tempop/tempop.go b/business/jxstore/tempop/tempop.go index e55bb1a69..8909c63bd 100644 --- a/business/jxstore/tempop/tempop.go +++ b/business/jxstore/tempop/tempop.go @@ -1451,7 +1451,7 @@ func BuildSkuFromEbaiStore(ctx *jxcontext.Context, baiduShopID int64, isAsync, i } price := sku.LinkID sku.LinkID = 0 - skuName := jxutils.ComposeSkuName(skuNameExt.Prefix, skuNameExt.Name, sku.Comment, skuNameExt.Unit, sku.SpecQuality, sku.SpecUnit, jdapi.MaxSkuNameCharCount) + skuName := jxutils.ComposeSkuNameOriginal(skuNameExt.Prefix, skuNameExt.Name, sku.Comment, skuNameExt.Unit, sku.SpecQuality, sku.SpecUnit, jdapi.MaxSkuNameCharCount) fixedStatus := 1 if sku.Status != model.SkuStatusNormal { fixedStatus = 2 diff --git a/business/jxutils/jxutils.go b/business/jxutils/jxutils.go index 94b79e6c8..b666a5ea3 100644 --- a/business/jxutils/jxutils.go +++ b/business/jxutils/jxutils.go @@ -327,7 +327,7 @@ func FloatWeight2Int(weight float32) int { return int(math.Round(float64(weight * 1000))) } -func ComposeSkuName(prefix, name, comment, unit string, spec_quality float32, spec_unit string, maxLen int) (skuName string) { +func ComposeSkuNameOriginal(prefix, name, comment, unit string, spec_quality float32, spec_unit string, maxLen int) (skuName string) { if prefix != "" { skuName = "[" + prefix + "]" } @@ -348,6 +348,29 @@ func ComposeSkuName(prefix, name, comment, unit string, spec_quality float32, sp return skuName } +func ComposeSkuName(prefix, name, comment, unit string, spec_quality float32, spec_unit string, maxLen int, exPrefix string, exPrefixBegin, exPrefixEnd *time.Time) (skuName string) { + if exPrefix != "" && exPrefixBegin != nil && exPrefixEnd != nil { + if utils.Time2Date(time.Now().Add(6*time.Hour)).Sub(*exPrefixBegin) >= 0 && utils.Time2Date(time.Now()).Sub(*exPrefixEnd) <= 0 { + skuName = exPrefix + } + } + skuName += ComposeSkuNameOriginal(prefix, name, comment, unit, spec_quality, spec_unit, maxLen) + return skuName +} + +func ComposeSkuNameSync(prefix, name, comment, unit string, spec_quality float32, spec_unit string, maxLen int, exPrefix string, exPrefixBegin, exPrefixEnd *time.Time) (skuName string) { + if exPrefix != "" && exPrefixBegin != nil && exPrefixEnd != nil { + if utils.Time2Date(time.Now().Add(6*time.Hour)).Sub(*exPrefixBegin) >= 0 && utils.Time2Date(time.Now()).Sub(*exPrefixEnd) <= 0 { + skuName = exPrefix + } + if utils.Time2Date(time.Now().Add(6*time.Hour)).Sub(*exPrefixEnd) > 0 { + skuName = "" + } + } + skuName += ComposeSkuNameOriginal(prefix, name, comment, unit, spec_quality, spec_unit, maxLen) + return skuName +} + func ComposeSpuName(prefix, name string, maxLen int) (spuName string) { if prefix != "" { spuName = "[" + prefix + "]" @@ -409,6 +432,31 @@ func SplitSkuName(skuName string) (prefix, name, comment, specUnit, unit string, return prefix, name, comment, specUnit, unit, specQuality } +// https://my.oschina.net/hyller/blog/700414 +func CalUpcCheckSum(upc12 int64) (checkSum int) { + var sum [2]int + for i := 0; i < 12; i++ { + base := int64(math.Pow10(i)) + sum[i%2] += int((upc12 / base) % 10) + } + sum[0] *= 3 + return (10 - (sum[0]+sum[1])%10) % 10 +} + +func IsUpcValid(upc string) bool { + if len(upc) != 13 { + return false + } + upcInt := utils.Str2Int64WithDefault(upc, 0) + checkSum := CalUpcCheckSum(upcInt / 10) + return int(utils.Str2Int64(upc[12:])) == checkSum +} + +func GenFakeUPC(skuID int) string { + id := int64(skuID) + 666600000000 + return fmt.Sprintf("%012d%d", id, CalUpcCheckSum(id)) +} + func MakeValidationMapFromSlice(validValues []string, flag int) map[string]int { retVal := make(map[string]int) for _, v := range validValues { diff --git a/business/jxutils/jxutils_act.go b/business/jxutils/jxutils_act.go index a2a97bde0..575e8f650 100644 --- a/business/jxutils/jxutils_act.go +++ b/business/jxutils/jxutils_act.go @@ -8,6 +8,7 @@ type ActStoreSkuMap struct { actStoreSkuMap map[int64]map[int]*model.ActStoreSku2 } +// isActPrice为true表示是活动,false表示是结算 func NewActStoreSkuMap(actStoreSkuList []*model.ActStoreSku2, isActPrice bool) (actMap *ActStoreSkuMap) { actMap = &ActStoreSkuMap{} actStoreSkuMap := make(map[int64]map[int]*model.ActStoreSku2) diff --git a/business/jxutils/jxutils_act_test.go b/business/jxutils/jxutils_act_test.go index 79d4d1577..9e3563557 100644 --- a/business/jxutils/jxutils_act_test.go +++ b/business/jxutils/jxutils_act_test.go @@ -2,18 +2,14 @@ package jxutils import ( "testing" - - "git.rosy.net.cn/baseapi/utils" - "git.rosy.net.cn/jx-callback/business/model" - "git.rosy.net.cn/jx-callback/business/model/dao" ) func TestGetActStoreSku(t *testing.T) { - actStoreSkuList, err := dao.GetEffectiveActStoreSkuInfo(dao.GetDB(), 0, []int{model.VendorIDMTWM}, []int{102046}, []int{25430, 30611}, - utils.Str2Time("2019-07-27 13:29:57"), utils.Str2Time("2019-07-27 13:29:57")) - if err != nil { - t.Fatal(err) - } - storeSkuMap := jxutils.NewActStoreSkuMap(actStoreSkuList, false) - t.Log(storeSkuMap.GetActStoreSku(1, 2, 3)) + // actStoreSkuList, err := dao.GetEffectiveActStoreSkuInfo(dao.GetDB(), 0, []int{model.VendorIDMTWM}, []int{102046}, []int{25430, 30611}, + // utils.Str2Time("2019-07-27 13:29:57"), utils.Str2Time("2019-07-27 13:29:57")) + // if err != nil { + // t.Fatal(err) + // } + // storeSkuMap := jxutils.NewActStoreSkuMap(actStoreSkuList, false) + // t.Log(storeSkuMap.GetActStoreSku(1, 2, 3)) } diff --git a/business/jxutils/jxutils_cms_test.go b/business/jxutils/jxutils_cms_test.go index 701e3093b..864bdd23c 100644 --- a/business/jxutils/jxutils_cms_test.go +++ b/business/jxutils/jxutils_cms_test.go @@ -2,12 +2,10 @@ package jxutils import ( "fmt" - "strings" "testing" "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/business/model" - "git.rosy.net.cn/jx-callback/business/model/dao" ) func TestSplitSlice(t *testing.T) { @@ -109,22 +107,22 @@ func TestCalcPolygonAreaAutonavi(t *testing.T) { // pointers := GetPolygonFromCircle(104.065702, 30.657488, 3000, 128) // area := CalcPolygonAreaAutonavi(pointers) // t.Logf("area:%f", area) - db := dao.GetDB() - storeList, err := dao.GetStoreList(db, nil, nil, "") - if err != nil { - t.Fatal(err) - } + // db := dao.GetDB() + // storeList, err := dao.GetStoreList(db, nil, nil, "") + // if err != nil { + // t.Fatal(err) + // } - strBuilder := &strings.Builder{} - strBuilder.WriteString("\n") - for _, v := range storeList { - if v.DeliveryRangeType == model.DeliveryRangeTypePolygon { - pointers := CoordinateStr2Points(v.DeliveryRange) - area1 := CalcPolygonAreaAutonavi(pointers) - strBuilder.WriteString(fmt.Sprintf("%d,%f\n", v.ID, area1)) - } - } - t.Log(strBuilder.String()) + // strBuilder := &strings.Builder{} + // strBuilder.WriteString("\n") + // for _, v := range storeList { + // if v.DeliveryRangeType == model.DeliveryRangeTypePolygon { + // pointers := CoordinateStr2Points(v.DeliveryRange) + // area1 := CalcPolygonAreaAutonavi(pointers) + // strBuilder.WriteString(fmt.Sprintf("%d,%f\n", v.ID, area1)) + // } + // } + // t.Log(strBuilder.String()) } func TestCaculateSkuPrice(t *testing.T) { diff --git a/business/jxutils/jxutils_test.go b/business/jxutils/jxutils_test.go index 55a78db84..d6ecd5e26 100644 --- a/business/jxutils/jxutils_test.go +++ b/business/jxutils/jxutils_test.go @@ -284,3 +284,26 @@ func TestGetOneEmailFromStr(t *testing.T) { } } } + +func TestGenFakeUPC(t *testing.T) { + for _, v := range [][]string{ + []string{ + "6666000298034", + "29803", + }, + []string{ + "6666076543212", + "7654321", + }, + } { + if str := GenFakeUPC(int(utils.Str2Int64(v[1]))); str != v[0] { + t.Errorf("%s failed, result:%s, expect:%s", v[1], str, v[0]) + } + } + if !IsUpcValid("6666076543212") { + t.Fatal("wrong1") + } + if IsUpcValid("6666076543210") { + t.Fatal("wrong2") + } +} diff --git a/business/jxutils/tasksch/task.go b/business/jxutils/tasksch/task.go index e80f8febf..b7e2f643e 100644 --- a/business/jxutils/tasksch/task.go +++ b/business/jxutils/tasksch/task.go @@ -418,12 +418,6 @@ func (t *BaseTask) MarshalJSON() ([]byte, error) { func (t *BaseTask) run(taskHandler func()) { if t.GetStatus() == TaskStatusBegin { utils.CallFuncAsync(func() { - defer func() { - if r := recover(); r != nil { - globals.SugarLogger.Errorf("panic in BaseTask.run task:%s, task detail:%s, r:%v", t.Name, utils.Format4Output(t, false), r) - } - }() - taskHandler() task := t diff --git a/business/jxutils/weixinmsg/weixinmsg.go b/business/jxutils/weixinmsg/weixinmsg.go index c23d6ec36..ab9c99af2 100644 --- a/business/jxutils/weixinmsg/weixinmsg.go +++ b/business/jxutils/weixinmsg/weixinmsg.go @@ -197,7 +197,7 @@ func getOrderDetailBrief(order *model.GoodsOrder) (brief string) { sb.WriteString(utils.Int2Str(order.Skus[0].Count)) sb.WriteString("份(") sb.WriteString(jxutils.IntPrice2StandardString(order.Skus[0].SalePrice)) - sb.WriteString("元/份)等,共支付了") + sb.WriteString("元/份)等,预计收入") sb.WriteString(jxutils.IntPrice2StandardString(order.ActualPayPrice)) sb.WriteString("元") return sb.String() diff --git a/business/model/act.go b/business/model/act.go index b4bfeee86..5ea7c0125 100644 --- a/business/model/act.go +++ b/business/model/act.go @@ -7,6 +7,7 @@ import ( ) const ( + ActTypeAll = -1 ActSkuFake = 0 // 假活动,只用于存储活动结算信息 ActSkuDirectDown = 3 // 兼容之前的 ActSkuSecKill = 4 // 兼容之前的 @@ -198,10 +199,13 @@ type ActStoreSku2 struct { SkuName string `json:"skuName"` - Prefix string `json:"-"` - SkuNameName string `orm:"column(sku_name_name)" json:"-"` - Unit string `orm:"size(8)" json:"-"` - SpecQuality float32 `json:"-"` - SpecUnit string `json:"-"` - Comment string `json:"-"` + Prefix string `json:"-"` + ExPrefix string + ExPrefixBegin *time.Time + ExPrefixEnd *time.Time + SkuNameName string `orm:"column(sku_name_name)" json:"-"` + Unit string `orm:"size(8)" json:"-"` + SpecQuality float32 `json:"-"` + SpecUnit string `json:"-"` + Comment string `json:"-"` } diff --git a/business/model/api.go b/business/model/api.go index 4e2d1c2c8..eb3580556 100644 --- a/business/model/api.go +++ b/business/model/api.go @@ -45,10 +45,10 @@ type GoodsOrderExt struct { type OrderSkuExt struct { OrderSku - NameID int `orm:"column(name_id)" json:"nameID"` - FullSkuName string `json:"fullSkuName"` - Image string `json:"image"` - RealEarningPrice int64 `json:"realEarningPrice"` // 实际单品结算给门店老板钱 + NameID int `orm:"column(name_id)" json:"nameID"` + FullSkuName string `json:"fullSkuName"` + Image string `json:"image"` + // RealEarningPrice int64 `json:"realEarningPrice"` // 实际单品结算给门店老板钱 } type GoodsOrderCountInfo struct { @@ -83,3 +83,20 @@ type OrderFinancialSkuExt struct { OrderSkuFinancial Image string `json:"image"` } + +type ProductInfo struct { + OriginalName string `json:"originalName"` + OriginalSpec string `json:"originalSpec"` + Name string `json:"name"` + Img string `json:"img"` + ImgList []string `json:"imgList"` + SpecQuality int `json:"specQuality"` + SpecUnit string `json:"specUnit"` + Unit string `json:"unit"` + Weight float32 `json:"weight"` + Price int `json:"price"` + Categories []string `json:"categories"` + ManName string `json:"manName"` // 生产商 + BrandName string `json:"brandName"` + UpcCode string `json:"upcCode"` +} diff --git a/business/model/api_config.go b/business/model/api_config.go index f5d16debd..1eb9f795c 100644 --- a/business/model/api_config.go +++ b/business/model/api_config.go @@ -18,6 +18,8 @@ const ( VendorIDPurchaseEnd = 11 VendorIDJX = 9 // 这是一个假的京西VendorID + VendorIDWXPay = 51 // 微信支付 + VendorIDDeliveryBegin = 101 VendorIDDada = 101 VendorIDMTPS = 102 diff --git a/business/model/const.go b/business/model/const.go index f9bad6472..f96a52a4e 100644 --- a/business/model/const.go +++ b/business/model/const.go @@ -33,9 +33,9 @@ var ( OrderStatusName = map[int]string{ OrderStatusMsg: "通知消息", + OrderStatusWaybillTipChanged: "小费变动", OrderStatusRefuseFailedGetGoods: "取货失败审核驳回", OrderStatusAdjust: "订单调整完成", - OrderStatusWait4Pay: "待付款", OrderStatusApplyUrgeOrder: "催单", OrderStatusUnlocked: "解锁", @@ -46,7 +46,7 @@ var ( OrderStatusUnknown: "一般事件", - OrderStatusCreated: "待支付", + OrderStatusWait4Pay: "待付款", OrderStatusNew: "新订单", OrderStatusAccepted: "待拣货", OrderStatusFinishedPickup: "待配送", @@ -86,6 +86,18 @@ var ( OrderTypeAfsOrder: "售后单", } + ComplaintReasons = map[int]string{ + ComplaintReasons1: "骑手态度恶劣", + ComplaintReasons2: "骑手接单后未取货", + ComplaintReasons3: "骑手取货太慢", + ComplaintReasons4: "骑手送货太慢", + ComplaintReasons5: "货品未送达", + ComplaintReasons6: "货品有损坏", + ComplaintReasons7: "骑手违规收取顾客其他费用", + ComplaintReasons69: "骑手恶意取消订单", + ComplaintReasons71: "骑手提前点击取货/送达", + } + MultiStoresVendorMap = map[int]int{ VendorIDJD: 1, VendorIDMTWM: 0, @@ -161,19 +173,21 @@ const ( const ( OrderStatusMsg = -100 + OrderStatusWaybillTipChanged = -80 // 订单小费变化 + OrderStatusRefuseFailedGetGoods = -70 // 取货失败审核驳回 OrderStatusAdjust = -65 // 原值-35 订单调整完成 - OrderStatusWait4Pay = -60 // 原值-30 下单待支付,微盟在这个时间发新订单事件 OrderStatusApplyUrgeOrder = -55 // 原值-15 - OrderStatusUnlocked = -25 - OrderStatusLocked = -20 - // OrderStatusApplyRefund = -10 - OrderStatusUndoApplyCancel = -10 - OrderStatusApplyCancel = -5 + OrderStatusUnlocked = -25 + OrderStatusLocked = -20 + OrderStatusUndoApplyCancel = -10 + OrderStatusVendorRejectCancel = -7 + OrderStatusVendorAgreeCancel = -6 + OrderStatusApplyCancel = -5 OrderStatusUnknown = 0 - OrderStatusCreated = 2 // 已支付 + OrderStatusWait4Pay = 2 // 原值-60 下单待支付 OrderStatusNew = 5 // 新订单,实际是已经支付 OrderStatusAccepted = 10 // 已经接单,也即待出库,待拣货 OrderStatusFinishedPickup = 15 // 拣货完成 @@ -202,6 +216,19 @@ const ( LockStatusLocked = 1 ) +//投诉原因 +const ( + ComplaintReasons1 = 1 //"骑手态度恶劣", + ComplaintReasons2 = 2 //"骑手接单后未取货" + ComplaintReasons3 = 3 //"骑手取货太慢", + ComplaintReasons4 = 4 //"骑手送货太慢", + ComplaintReasons5 = 5 //"货品未送达", + ComplaintReasons6 = 6 //"货品有损坏", + ComplaintReasons7 = 7 //"骑手违规收取顾客其他费用", + ComplaintReasons69 = 69 //"骑手恶意取消订单", + ComplaintReasons71 = 71 //"骑手提前点击取货/送达", +) + const ( WaybillStatusRefuseFailedGetGoods = -70 WaybillStatusUnknown = 0 @@ -222,6 +249,7 @@ const ( WaybillStatusDelivered = 105 // todo 这个应该改为110,与订单对应 WaybillStatusCanceled = 115 WaybillStatusFailed = 120 // 这个状态存在的意义是区分于WaybillStatusCanceled,比如达达平台在这种状态下再次创建运单的方式不一样 + WaybillStatusEndEnd = 120 ) const ( @@ -336,7 +364,7 @@ func IsOrderLockStatus(status int) bool { } func IsOrderUnlockStatus(status int) bool { - return status == OrderStatusUnlocked || status == OrderStatusUndoApplyCancel + return status == OrderStatusUnlocked || status == OrderStatusUndoApplyCancel || status == OrderStatusVendorAgreeCancel || status == OrderStatusVendorRejectCancel } func IsOrderMainStatus(status int) bool { @@ -367,3 +395,7 @@ func WaybillVendorID2Mask(vendorID int) (mask int8) { func IsAfsOrderFinalStatus(status int) bool { return status >= AfsOrderStatusFinished && status <= AfsOrderStatusFailed } + +func IsWaybillFinalStatus(status int) bool { + return status >= WaybillStatusEndBegin && status <= WaybillStatusEndEnd +} diff --git a/business/model/dao/act.go b/business/model/dao/act.go index 02800b6a4..4d15fcf8e 100644 --- a/business/model/dao/act.go +++ b/business/model/dao/act.go @@ -101,7 +101,7 @@ func GetActStoreSkuVendorList(db *DaoDB, actID int, vendorIDs, storeIDs, skuIDs END vendor_sku_id, t4.comment, t4.spec_quality, t4.spec_unit, t6.name store_name, - t7.name sku_name_name, t7.unit, t7.prefix + t7.name sku_name_name, t7.unit, t7.prefix, t7.ex_prefix, t7.ex_prefix_begin, t7.ex_prefix_end FROM act_store_sku t1 %s JOIN act_store_sku_map t2 ON t2.act_id = ? AND t2.bind_id = t1.id AND t2.deleted_at = ?`, jdVendorIDField, leftOrEmpty) sqlParams := []interface{}{ @@ -204,25 +204,25 @@ func QueryActs(db *DaoDB, actID int, offset, pageSize int, syncStatus int, keywo SELECT t1.*, t2.id map_id, t2.vendor_id, t2.vendor_act_id, t2.sync_status, t2.remark map_remark - FROM act t1 - LEFT JOIN act_map t2 ON t2.act_id = t1.id AND t2.deleted_at = ?` - sqlParams = []interface{}{utils.DefaultTimeValue} - if syncStatus >= 0 { - sql += " AND (t2.sync_status = ? OR t2.sync_status & ? <> 0)" - sqlParams = append(sqlParams, syncStatus, syncStatus) - } - } else if syncStatus >= 0 { - sql += " JOIN act_map t2 ON t2.act_id = t1.id AND t2.deleted_at = ? AND (t2.sync_status = ? OR t2.sync_status & ? <> 0)" - sqlParams = append(sqlParams, utils.DefaultTimeValue, syncStatus, syncStatus) + FROM act t1` + } + sql += " LEFT JOIN act_map t2 ON t2.act_id = t1.id AND t2.deleted_at = ?" + sqlParams = append(sqlParams, utils.DefaultTimeValue) + if syncStatus >= 0 { + sql += " AND (t2.sync_status = ? OR t2.sync_status & ? <> 0)" + sqlParams = append(sqlParams, syncStatus, syncStatus) } sql += ` WHERE t1.deleted_at = ?` + if syncStatus >= 0 { + sql += " AND t2.id IS NOT NULL" + } sqlParams = append(sqlParams, utils.DefaultTimeValue) keywordInt := int64(0) if keyword != "" { keywordLike := "%" + keyword + "%" - sql += " AND ( t1.name LIKE ? OR t1.advertising LIKE ? OR t1.remark LIKE ?" - sqlParams = append(sqlParams, keywordLike, keywordLike, keywordLike) + sql += " AND ( t1.name LIKE ? OR t1.advertising LIKE ? OR t1.remark LIKE ? OR t2.vendor_act_id LIKE ?" + sqlParams = append(sqlParams, keywordLike, keywordLike, keywordLike, keywordLike) keywordInt = utils.Str2Int64WithDefault(keyword, 0) if keywordInt > 0 { sql += ` @@ -321,9 +321,12 @@ func QueryActs(db *DaoDB, actID int, offset, pageSize int, syncStatus int, keywo t2.id map_id, t2.vendor_id, t2.vendor_org_code, t2.vendor_act_id, t2.sync_status, t2.remark map_remark FROM act t1 LEFT JOIN act_map t2 ON t2.act_id = t1.id AND t2.deleted_at = ? - WHERE t1.id IN (` + GenQuestionMarks(len(idList)) + `) - ORDER BY t1.id DESC, t2.vendor_id - ` + WHERE t1.id IN (` + GenQuestionMarks(len(idList)) + `)` + if syncStatus >= 0 { + sql += " AND t2.id IS NOT NULL" + } + sql += ` + ORDER BY t1.id DESC, t2.vendor_id` sqlParams = []interface{}{ utils.DefaultTimeValue, idList, @@ -369,7 +372,7 @@ func GetExistVendorActIDs(db *DaoDB, vendorID int) (vendorActIDs []string, err e return vendorActIDs, err } -func GetEffectiveActStoreSkuInfo(db *DaoDB, actID int, vendorIDs []int, storeIDs, skuIDs []int, beginAt, endAt time.Time) (actStoreSkuList []*model.ActStoreSku2, err error) { +func GetEffectiveActStoreSkuInfo(db *DaoDB, actID int, vendorIDs []int, actType int, storeIDs, skuIDs []int, beginAt, endAt time.Time) (actStoreSkuList []*model.ActStoreSku2, err error) { if utils.IsTimeZero(beginAt) { return nil, fmt.Errorf("GeActStoreSkuInfo必须指定活动开始时间") } @@ -406,9 +409,13 @@ func GetEffectiveActStoreSkuInfo(db *DaoDB, actID int, vendorIDs []int, storeIDs sqlParams = append(sqlParams, model.GetVendorMask(vendorIDs...), vendorIDs) } if actID > 0 { - sql = " AND t1.id = ?" + sql += " AND t1.id = ?" sqlParams = append(sqlParams, actID) } + if actType != model.ActTypeAll { + sql += " AND t1.type = ?" + sqlParams = append(sqlParams, actType) + } if len(storeIDs) > 0 { sql += " AND t2.store_id IN (" + GenQuestionMarks(len(storeIDs)) + ")" sqlParams = append(sqlParams, storeIDs) @@ -432,7 +439,7 @@ func UpdateActStatusByTime(db *DaoDB, refTime time.Time) (num int64, err error) model.ActStatusEnded, utils.DefaultTimeValue, model.ActStatusCanceled, - refTime, + utils.Time2Date(refTime), } num, err = ExecuteSQL(db, sql, sqlParams...) return num, err diff --git a/business/model/dao/act_test.go b/business/model/dao/act_test.go index 7d902cccb..be48eee2a 100644 --- a/business/model/dao/act_test.go +++ b/business/model/dao/act_test.go @@ -5,6 +5,7 @@ import ( "time" "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/model" ) func TestGetEffectiveActStoreSkuInfo(t *testing.T) { @@ -27,7 +28,7 @@ func TestGetEffectiveActStoreSkuInfo(t *testing.T) { ToTime: utils.Str2Time("2019-08-06 12:34:56"), }, } { - result, err := GetEffectiveActStoreSkuInfo(GetDB(), v.ActID, v.VendorIDs, v.StoreIDs, v.SkuIDs, v.FromTime, v.ToTime) + result, err := GetEffectiveActStoreSkuInfo(GetDB(), v.ActID, v.VendorIDs, model.ActTypeAll, v.StoreIDs, v.SkuIDs, v.FromTime, v.ToTime) if err != nil { t.Fatal(err) } diff --git a/business/model/dao/dao_order.go b/business/model/dao/dao_order.go index ebccfdc9c..7dadf5c58 100644 --- a/business/model/dao/dao_order.go +++ b/business/model/dao/dao_order.go @@ -734,7 +734,7 @@ func GetOrders(db *DaoDB, ids []int64, isIncludeSku, isIncludeFake bool, fromDat IF(t3.jx_sku_id > 0, t3.jx_sku_id, t3.sku_id) sku_id, t3.count sku_count2, t3.shop_price sku_shop_price, - t3.earning_price sku_earning_price, + IF(t3.store_sub_id = 0, 0, t3.earning_price) sku_earning_price, t3.sale_price sku_sale_price, t3.sku_name` } @@ -1015,3 +1015,88 @@ func GetPendingFakeOrders(db *DaoDB, vendorIDs []int, orderCreatedAfter, orderCr err = GetRows(db, &orderList, sql, sqlParams...) return orderList, err } + +// 不会有Skus信息 +func LoadPendingOrders(db *DaoDB, orderCreatedAfter time.Time, beforStatus int) (orderList []*model.GoodsOrder, err error) { + sql := ` + SELECT * + FROM goods_order + WHERE order_created_at >= ? + AND status < ?` + sqlParams := []interface{}{orderCreatedAfter, beforStatus} + err = GetRows(db, &orderList, sql, sqlParams...) + return orderList, err +} + +func GetWayBillByOrderID(db *DaoDB, orderStatus, vendorID, waybillVendorID int, vendorOrderID string) (wayBillList []*model.Waybill, err error) { + sql := ` + SELECT b.* + FROM goods_order a + JOIN waybill b ON IF(a.waybill_vendor_id = -1,a.vendor_order_id,a.vendor_waybill_id) = b.vendor_waybill_id AND b.order_vendor_id = a.vendor_id + WHERE a.vendor_order_id = ? + AND a.vendor_id = ? + ` + sqlParams := []interface{}{ + vendorOrderID, + vendorID, + } + if orderStatus > 0 { + sql += ` AND a.status = ?` + sqlParams = append(sqlParams, orderStatus) + } + if waybillVendorID > 0 { + sql += ` AND b.waybill_vendor_id = ?` + sqlParams = append(sqlParams, waybillVendorID) + } + err = GetRows(db, &wayBillList, sql, sqlParams...) + return wayBillList, err +} + +func GetOrdersSupplement(db *DaoDB, storIDs, vendorIDs []int, vendorOrderID string, fromTime, toTime time.Time, status, stype, offset, pageSize int) (orderSupplementFee []*model.OrderSupplementFee, totalCount int, err error) { + sql := ` + SELECT SQL_CALC_FOUND_ROWS * + FROM order_supplement_fee + WHERE 1=1 + AND deleted_at = ? + ` + sqlParams := []interface{}{ + utils.DefaultTimeValue, + } + if !utils.IsTimeZero(fromTime) { + sql += " AND supplement_time >= ?" + sqlParams = append(sqlParams, fromTime) + } + if !utils.IsTimeZero(toTime) { + sql += " AND supplement_time <= ?" + sqlParams = append(sqlParams, toTime) + } + if len(storIDs) > 0 { + sql += " AND store_id IN (" + GenQuestionMarks(len(storIDs)) + ")" + sqlParams = append(sqlParams, storIDs) + } + if len(vendorIDs) > 0 { + sql += " AND store_id IN (" + GenQuestionMarks(len(vendorIDs)) + ")" + sqlParams = append(sqlParams, vendorIDs) + } + if vendorOrderID != "" { + sql += " AND vendor_order_id = ?" + sqlParams = append(sqlParams, vendorOrderID) + } + if status >= 0 { + sql += " AND status = ?" + sqlParams = append(sqlParams, status) + } + if stype >= 0 { + sql += " AND type = ?" + sqlParams = append(sqlParams, stype) + } + sql += ` + LIMIT ? OFFSET ?` + sqlParams = append(sqlParams, pageSize, offset) + Begin(db) + defer Commit(db) + if err = GetRows(db, &orderSupplementFee, sql, sqlParams...); err == nil { + totalCount = GetLastTotalRowCount(db) + } + return orderSupplementFee, totalCount, err +} diff --git a/business/model/dao/dao_utils.go b/business/model/dao/dao_utils.go index 8a36c2adc..eaca61326 100644 --- a/business/model/dao/dao_utils.go +++ b/business/model/dao/dao_utils.go @@ -160,6 +160,10 @@ func GetCategoryIDDBField(prefix string) string { return ConvertDBFieldPrefix(prefix) + "_category_id" } +func GetVendorLockTimeStructField(prefix string) string { + return ConvertStructFieldPrefix(prefix) + "LockTime" +} + func value2Value(srcValue, dstValue reflect.Value, copyType int) { srcType := srcValue.Type() for i := 0; i < srcType.NumField(); i++ { diff --git a/business/model/dao/report.go b/business/model/dao/report.go index 125b42a21..316e5b1ed 100644 --- a/business/model/dao/report.go +++ b/business/model/dao/report.go @@ -188,10 +188,10 @@ func GetGetStatisticsReportForAfsOrders(db *DaoDB, storeIDs []int, fromDate time func GetStatisticsReportForStoreSkusPrice(db *DaoDB, cityCodes, skuIDs []int) (priceReferSnapshot []*model.PriceReferSnapshot, err error) { sql := ` SELECT b.city_code,a.sku_id, - MAX(a.price) max_price, - MIN(a.price) min_price, - ROUND(AVG(a.price)) avg_price, - ROUND(SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT((a.price/IF(b.pay_percentage=0,100,b.pay_percentage))*100 ORDER BY (a.price/IF(b.pay_percentage=0,100,b.pay_percentage))*100),',',Count(1)/2),',',-1),2) mid_price, + ROUND(MAX(a.price/IF(b.pay_percentage=0,100,b.pay_percentage)*100)) max_price, + ROUND(MIN(a.price/IF(b.pay_percentage=0,100,b.pay_percentage)*100)) min_price, + ROUND(AVG(a.price/IF(b.pay_percentage=0,100,b.pay_percentage)*100)) avg_price, + ROUND(SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT((a.price/IF(b.pay_percentage=0,100,b.pay_percentage))*100 ORDER BY (a.price/IF(b.pay_percentage=0,100,b.pay_percentage))*100),',',Count(1)/2),',',-1)) mid_price, MAX(a.jd_price) max_jd_price, MIN(a.jd_price) min_jd_price, ROUND(AVG(a.jd_price)) avg_jd_price, @@ -211,8 +211,7 @@ func GetStatisticsReportForStoreSkusPrice(db *DaoDB, cityCodes, skuIDs []int) (p t1.min_vendor_price, t1.avg_vendor_price FROM store_sku_bind a - JOIN store b ON a.store_id = b.id AND b.deleted_at = ? - JOIN sku d ON a.sku_id = d.id AND d.deleted_at = ? + JOIN store b ON a.store_id = b.id AND b.deleted_at = ? AND b.status != ? LEFT JOIN ( SELECT SUM(t1.count),t1.sku_id,MAX(t1.sale_price) max_sale_price,MIN(t1.sale_price) min_sale_price,ROUND(AVG(t1.sale_price)) avg_sale_price,MAX(t1.vendor_price) max_vendor_price,MIN(t1.vendor_price) min_vendor_price,ROUND(AVG(t1.vendor_price)) avg_vendor_price FROM order_sku t1 @@ -220,12 +219,14 @@ func GetStatisticsReportForStoreSkusPrice(db *DaoDB, cityCodes, skuIDs []int) (p GROUP BY 2 )t1 ON t1.sku_id = a.sku_id WHERE a.deleted_at = ? + AND a.status = ? ` sqlParams := []interface{}{ utils.DefaultTimeValue, - utils.DefaultTimeValue, + model.StoreStatusDisabled, time.Now().AddDate(0, -1, 0), utils.DefaultTimeValue, + model.SkuStatusNormal, } if len(skuIDs) > 0 { sql += " AND a.sku_id IN (" + GenQuestionMarks(len(skuIDs)) + ")" @@ -277,7 +278,7 @@ func GetPriceReferSnapshot(db *DaoDB, cityCodes, skuIDs []int, snapDate time.Tim err = err2 if len(skuList) > 0 { skuAndName := skuList[0] - jxSkuDetailName := jxutils.ComposeSkuName(skuAndName.Prefix, skuAndName.Name, skuAndName.Comment, skuAndName.Unit, skuAndName.SpecQuality, skuAndName.SpecUnit, 0) + jxSkuDetailName := jxutils.ComposeSkuNameOriginal(skuAndName.Prefix, skuAndName.Name, skuAndName.Comment, skuAndName.Unit, skuAndName.SpecQuality, skuAndName.SpecUnit, 0) v.SkuName = jxSkuDetailName } } diff --git a/business/model/dao/sku.go b/business/model/dao/sku.go index 3edd64d28..fb83053aa 100644 --- a/business/model/dao/sku.go +++ b/business/model/dao/sku.go @@ -8,16 +8,17 @@ import ( "git.rosy.net.cn/jx-callback/globals" ) -type tStoreSkuSyncInfo2 struct { - StoreSkuSyncInfo - VendorPlaceCode string -} - type SkuCategoryWithVendor struct { *model.SkuCategory MapList []*model.ThingMap `json:"mapList"` } +type SkuNamePlace struct { + model.Place + NameID int `orm:"column(name_id)" json:"nameID"` + SkuID int `orm:"column(sku_id)" json:"skuID"` +} + func GetSellCities(db *DaoDB, nameID int, vendorID int) (cities []*model.Place, err error) { cities = []*model.Place{} sql := ` @@ -49,7 +50,7 @@ func DeleteSkuNamePlace(db *DaoDB, nameID int, placeCodes []int) (num int64, err return ExecuteSQL(db, sql, sqlParams...) } -func GetCategories(db *DaoDB, parentID int, catIDs []int) (cats []*model.SkuCategory, err error) { +func GetCategories(db *DaoDB, parentID, level int, catIDs []int) (cats []*model.SkuCategory, err error) { sql := ` SELECT t1.* FROM sku_category t1 @@ -62,16 +63,20 @@ func GetCategories(db *DaoDB, parentID int, catIDs []int) (cats []*model.SkuCate params = append(params, parentID) } if len(catIDs) > 0 { - sql += " AND t1.id (" + GenQuestionMarks(len(catIDs)) + ")" + sql += " AND t1.id IN (" + GenQuestionMarks(len(catIDs)) + ")" params = append(params, catIDs) } + if level > 0 { + sql += " AND t1.level = ?" + params = append(params, level) + } sql += " ORDER BY t1.level, t1.seq" return cats, GetRows(db, &cats, sql, params) } func GetSkus(db *DaoDB, skuIDs, nameIDs, statuss, catIDs []int) (skuList []*model.SkuAndName, err error) { sql := ` - SELECT t1.*, t2.name, t2.unit, t2.prefix, t2.is_spu + SELECT t1.*, t2.name, t2.unit, t2.prefix, t2.is_spu, t2.ex_prefix, t2.ex_prefix_begin, t2.ex_prefix_end FROM sku t1 JOIN sku_name t2 ON t2.id = t1.name_id AND t2.deleted_at = ? ` @@ -174,6 +179,9 @@ func SetSkuSyncStatus(db *DaoDB, vendorID int, skuIDs []int, syncStatus int) (nu return ExecuteSQL(db, sql, sqlParams...) } +// todo, GetSkuCategoryWithVendor与GetSkusWithVendor, +// 如果mustDirty为true,应该是要thing_map为基表,LEFT JOIN原始实体表,否则当原始实体记录在未同步前被物理删除后,无法真正同步 + // 多门店平台使用,当前只有京东 func GetSkuCategoryWithVendor(db *DaoDB, vendorIDs []int, appOrgCodes []string, parentCatID int, catIDs []int, mustDirty bool) (catList []*SkuStoreCatInfo, err error) { sql := ` @@ -211,7 +219,7 @@ func GetSkuCategoryWithVendor(db *DaoDB, vendorIDs []int, appOrgCodes []string, ` sqlParams = append(sqlParams, model.ThingTypeCategory, utils.DefaultTimeValue) if mustDirty { - sql += " AND t1m.sync_status <> 0" + sql += " AND t1m.sync_status IS NOT NULL AND t1m.sync_status <> 0" } else { sql += " AND t1.deleted_at = ?" sqlParams = append(sqlParams, utils.DefaultTimeValue) @@ -252,9 +260,9 @@ func GetSkusWithVendor(db *DaoDB, vendorIDs []int, appOrgCodes []string, nameIDs IF(t11.resource_type IS NULL OR t11.resource_type <> ?, t2.img, '') img, IF(t12.resource_type IS NULL OR t12.resource_type <> ?, t2.img2, '') img2, t2.desc_img, - - t5.jd_code vendor_place_code, - + t2.ex_prefix, + t2.ex_prefix_begin, + t2.ex_prefix_end, t3.jd_category_id vendor_vendor_cat_id, t3m.sync_status cat_sync_status, @@ -281,15 +289,13 @@ func GetSkusWithVendor(db *DaoDB, vendorIDs []int, appOrgCodes []string, nameIDs LEFT JOIN sku_category t3 ON t3.id = t2.category_id LEFT JOIN thing_map t3m ON t3m.thing_id = t3.id AND t3m.thing_type = ? AND t3m.deleted_at = ? AND t3m.vendor_id = t1m.vendor_id AND t3m.vendor_org_code = t1m.vendor_org_code - LEFT JOIN sku_name_place_bind t4 ON t2.is_global = 0 AND t4.name_id = t1.name_id - LEFT JOIN place t5 ON t5.code = t4.place_code LEFT JOIN data_resource t11 ON t11.main_url = t2.img LEFT JOIN data_resource t12 ON t12.main_url = t2.img2 WHERE 1 = 1 ` sqlParams = append(sqlParams, model.ThingTypeCategory, utils.DefaultTimeValue) if mustDirty { - sql += " AND t1m.sync_status <> 0" + sql += " AND t1m.sync_status IS NOT NULL AND t1m.sync_status <> 0" } else { sql += " AND t1.deleted_at = ?" sqlParams = append(sqlParams, utils.DefaultTimeValue) @@ -303,19 +309,47 @@ func GetSkusWithVendor(db *DaoDB, vendorIDs []int, appOrgCodes []string, nameIDs sqlParams = append(sqlParams, skuIDs) } sql += " ORDER BY t1.seq" - - var list []*tStoreSkuSyncInfo2 - if err = GetRows(db, &list, sql, sqlParams...); err == nil { - skuMap := make(map[int]*StoreSkuSyncInfo) - for _, v := range list { - if skuMap[v.SkuID] == nil { - skuMap[v.SkuID] = &v.StoreSkuSyncInfo - skuList = append(skuList, &v.StoreSkuSyncInfo) + if err = GetRows(db, &skuList, sql, sqlParams...); err == nil { + skuPlaceList, err2 := GetSkuNamePlaces(db, nameIDs, skuIDs) + if err = err2; err == nil { + skuPlaceMap := make(map[int][]*SkuNamePlace) + for _, v := range skuPlaceList { + skuPlaceMap[v.SkuID] = append(skuPlaceMap[v.SkuID], v) } - if !IsVendorThingIDEmpty(v.VendorPlaceCode) { - skuMap[v.SkuID].SellCities = append(skuMap[v.SkuID].SellCities, v.VendorPlaceCode) + for _, v := range skuList { + if v.IsGlobal == 0 { + for _, v2 := range skuPlaceMap[v.SkuID] { + // 京东到家 + if v2.JdCode > 0 { + v.SellCities = append(v.SellCities, utils.Int2Str(v2.JdCode)) + } + } + } } } } return skuList, err } + +func GetSkuNamePlaces(db *DaoDB, nameIDs, skuIDs []int) (skuPlaceList []*SkuNamePlace, err error) { + sql := ` + SELECT + t4.*, + t2.id sku_id, t2.name_id + FROM sku t2 + JOIN sku_name_place_bind t3 ON t3.name_id = t2.name_id + JOIN place t4 ON t4.code = t3.place_code + WHERE t2.deleted_at = ? + ` + sqlParams := []interface{}{utils.DefaultTimeValue} + if len(nameIDs) > 0 { + sql += " AND t2.name_id IN (" + GenQuestionMarks(len(nameIDs)) + ")" + sqlParams = append(sqlParams, nameIDs) + } + if len(skuIDs) > 0 { + sql += " AND t2.id IN (" + GenQuestionMarks(len(skuIDs)) + ")" + sqlParams = append(sqlParams, skuIDs) + } + err = GetRows(db, &skuPlaceList, sql, sqlParams...) + return skuPlaceList, err +} diff --git a/business/model/dao/store.go b/business/model/dao/store.go index 08ac3f9ae..c1b82afea 100644 --- a/business/model/dao/store.go +++ b/business/model/dao/store.go @@ -14,10 +14,11 @@ type StoreDetail struct { VendorOrgCode string `orm:"size(32)" json:"vendorOrgCode"` // 同一平台下不同的商户代码,如果只有一个,可以为空 - VendorStoreID string `orm:"column(vendor_store_id);size(48)" json:"vendorStoreID"` - VendorStatus int `json:"vendor_status"` // 取值同Store.Status - DeliveryFee int `json:"deliveryFee"` - SyncStatus int8 `orm:"default(2)" json:"syncStatus"` + VendorStoreID string `orm:"column(vendor_store_id);size(48)" json:"vendorStoreID"` + VendorStoreName string `json:"vendorStoreName"` + VendorStatus int `json:"vendor_status"` // 取值同Store.Status + DeliveryFee int `json:"deliveryFee"` + SyncStatus int8 `orm:"default(2)" json:"syncStatus"` PricePercentage int16 `orm:"default(100)" json:"pricePercentage"` // todo 厂商价格相对于本地价格的百分比,这个字段的修改会比较特殊,因为可能需要刷新厂商价格 PricePercentagePackStr string `orm:"size(4096)" json:"-"` // @@ -38,6 +39,8 @@ type StoreDetail struct { MarketManName string `json:"marketManName"` //市场负责人 OperatorName string `json:"operatorName"` //运营负责人 OperatorName2 string `json:"operatorName2"` + + JdStoreLevel string `json:"jdStoreLevel"` //京东门店等级 } // 带快递门店信息的 @@ -60,10 +63,12 @@ type CityBrankBranch struct { } type StorePriceScore struct { - StoreID int `orm:"column(store_id)" json:"storeID"` - StoreName string `json:"storeName"` - StoreScore float64 `json:"storeScore"` - CityName string `json:"cityName"` + StoreID int `orm:"column(store_id)" json:"storeID"` + StoreName string `json:"storeName"` + StoreScore float64 `json:"storeScore"` + CityName string `json:"cityName"` + DirectDownCount int `json:"directDownCount"` + SecKillCount int `json:"secKillCount"` } type StorePriceScoreEx struct { @@ -78,8 +83,8 @@ func (s *StoreDetail) GetPricePerentage(price int) (pricePercentage int) { func getStoreDetail(db *DaoDB, storeID, vendorID int, vendorStoreID string) (storeDetail *StoreDetail, err error) { sql := ` SELECT t1.*, - t2.vendor_store_id, t2.status vendor_status, t2.delivery_fee, t2.sync_status, - t2.price_percentage, t2.auto_pickup, t2.delivery_type, t2.delivery_competition, t2.is_sync, + t2.vendor_store_id, t2.status vendor_status, t2.delivery_fee, t2.sync_status, t2.vendor_org_code, + t2.price_percentage, t2.auto_pickup, t2.delivery_type, t2.delivery_competition, t2.is_sync, t2.vendor_store_name, t3.value price_percentage_pack_str, t4.value freight_deduction_pack_str, district.name district_name, @@ -484,16 +489,39 @@ func GetStoreMapsListWithoutDisabled(db *DaoDB, vendorIDs []int, status int) (st return storeMapList, err } -func GetStorePriceScore(db *DaoDB, storeIDs []int, fromScore, toScore, sort int, snapDate time.Time, offset, pageSize int) (StorePriceScore []*StorePriceScore, totalCount int, err error) { +func GetStorePriceScore(db *DaoDB, storeIDs, vendorIDs []int, fromScore, toScore, sort int, snapDate time.Time, offset, pageSize int) (StorePriceScore []*StorePriceScore, totalCount int, err error) { sql := ` - SELECT SQL_CALC_FOUND_ROWS a.store_id,score store_score,e.name city_name,b.name store_name + SELECT SQL_CALC_FOUND_ROWS a.store_id, score store_score, e.name city_name, b.name store_name, t1.direct_down_count, t1.sec_kill_count FROM store_price_score_snapshot a JOIN store b ON b.id = a.store_id JOIN place e ON e.code = b.city_code + JOIN (SELECT a.store_id, count(d.type = ? OR NULL) direct_down_count, count(d.type = ? OR NULL) sec_kill_count + FROM store_sku_bind a + LEFT JOIN act_store_sku b ON a.store_id = b.store_id AND b.sku_id = a.sku_id + LEFT JOIN act_map c ON c.act_id = b.act_id + LEFT JOIN act d ON d.id = c.act_id + WHERE 1=1 + ` + sqlParams := []interface{}{ + model.ActSkuDirectDown, model.ActSkuSecKill, + } + if len(storeIDs) > 0 { + sql += " AND a.store_id IN(" + GenQuestionMarks(len(storeIDs)) + ")" + sqlParams = append(sqlParams, storeIDs) + } + if len(vendorIDs) > 0 { + sql += " AND c.vendor_id IN(" + GenQuestionMarks(len(vendorIDs)) + ")" + sqlParams = append(sqlParams, vendorIDs) + } + sql += ` + AND NOW() BETWEEN d.begin_at AND d.end_at + AND a.status = ? + AND a.deleted_at = ? + GROUP BY a.store_id)t1 ON t1.store_id = a.store_id WHERE 1=1 ` - sqlParams := []interface{}{} - if fromScore != 0 && toScore != 0 { + sqlParams = append(sqlParams, model.StoreSkuBindStatusNormal, utils.DefaultTimeValue) + if fromScore != 0 || toScore != 0 { sql += " AND a.score BETWEEN ? AND ?" sqlParams = append(sqlParams, fromScore, toScore) } @@ -505,10 +533,18 @@ func GetStorePriceScore(db *DaoDB, storeIDs []int, fromScore, toScore, sort int, sql += " AND a.snapshot_at = ?" sqlParams = append(sqlParams, snapDate) } - if sort == 0 { + if sort == 1 { sql += " ORDER BY a.score" - } else { + } else if sort == -1 { sql += " ORDER BY a.score DESC" + } else if sort == 2 { + sql += " ORDER BY t1.direct_down_count" + } else if sort == -2 { + sql += " ORDER BY t1.direct_down_count DESC" + } else if sort == 3 { + sql += " ORDER BY t1.sec_kill_count" + } else if sort == -3 { + sql += " ORDER BY t1.sec_kill_count DESC" } sql += " LIMIT ? OFFSET ?" sqlParams = append(sqlParams, pageSize, offset) diff --git a/business/model/dao/store_sku.go b/business/model/dao/store_sku.go index e2c7c908f..65925ece8 100644 --- a/business/model/dao/store_sku.go +++ b/business/model/dao/store_sku.go @@ -18,6 +18,7 @@ var ( model.VendorIDMTWM: "mtwm_url", model.VendorIDEBAI: "ebai_url", } + salePriceLimit = 100 ) type SkuStoreCatInfo struct { @@ -56,7 +57,10 @@ type StoreSkuSyncInfo struct { model.Sku // sku_name - Prefix string + Prefix string + ExPrefix string + ExPrefixBegin *time.Time + ExPrefixEnd *time.Time // NameID int `orm:"column(name_id)"` VendorNameID string `orm:"column(vendor_name_id)"` // 暂时无用 Name string @@ -69,7 +73,7 @@ type StoreSkuSyncInfo struct { // 平台相关的图片信息 Img string Img2 string - DescImg string // 饿百是SkuName中的DescImgEbai + DescImg string VendorVendorCatID int64 `orm:"column(vendor_vendor_cat_id)"` // 平台商品分类(叶子结点) @@ -81,7 +85,9 @@ type StoreSkuSyncInfo struct { CatSyncStatus int8 VendorCatID string `orm:"column(vendor_cat_id)"` - VendorPrice int64 + VendorPrice int64 + LockTime *time.Time + MergedStatus int SkuName string StatusSaleBegin int16 `json:"statusSaleBegin"` //商品可售时间范围 @@ -167,6 +173,11 @@ type StoreSkuExt struct { MtwmPrice int `json:"mtwmPrice"` JxPrice int `json:"jxPrice"` + JdLockTime *time.Time `orm:"null" json:"jdLockTime,omitempty"` + EbaiLockTime *time.Time `orm:"null" json:"ebaiLockTime,omitempty"` + MtwmLockTime *time.Time `orm:"null" json:"mtwmLockTime,omitempty"` + JxLockTime *time.Time `orm:"null" json:"jxLockTime,omitempty"` + AutoSaleAt time.Time `orm:"type(datetime);null" json:"autoSaleAt"` ActPrice int `json:"actPrice"` @@ -176,7 +187,7 @@ type StoreSkuExt struct { EarningPrice int `json:"earningPrice"` EarningActID int `orm:"column(earning_act_id)" json:"earningActID"` - RealEarningPrice int `json:"realEarningPrice"` + // RealEarningPrice int `json:"realEarningPrice"` StatusSaleBegin int16 `json:"statusSaleBegin"` //商品可售时间范围 StatusSaleEnd int16 `json:"statusSaleEnd"` @@ -185,6 +196,15 @@ type StoreSkuExt struct { Times int `json:"times"` } +type SkuNameAndPlace struct { + model.SkuName + CityCode int `json:"cityCode"` + CityName string `json:"cityName"` + Sequence int `json:"sequence"` + Count int `json:"count"` + Type int `json:"type"` +} + // todo 应该通过需要同步的skuid来驱动同步分类,而不是当前这种分开的逻辑 // 单门店模式厂商适用 // 从store_sku_bind中,得到所有依赖的商家分类信息 @@ -302,16 +322,16 @@ func newGetStoreSkus2(db *DaoDB, vendorID, storeID int, skuIDs []int, mustDirty SELECT t14.vendor_id, t14.vendor_org_code, t1.id bind_id, t1.sku_id, t1.price, t1.unit_price, t1.status store_sku_status, - %s vendor_sku_id, t1.%s_sync_status sku_sync_status, t1.%s_price vendor_price, + %s vendor_sku_id, t1.%s_sync_status sku_sync_status, t1.%s_price vendor_price, t1.%s_lock_time lock_time, t1.store_id, t1.deleted_at bind_deleted_at,t1.status_sale_begin,t1.status_sale_end, t2.*, - t3.id name_id, t3.prefix, t3.name, t3.unit, t3.upc, + t3.id name_id, t3.prefix, t3.name, t3.unit, t3.upc, t3.ex_prefix, t3.ex_prefix_begin, t3.ex_prefix_end, IF(t11.%s <> '', t11.%s, t3.img) img, IF(t12.%s <> '', t12.%s, t3.img2) img2, t13.%s desc_img, t4.%s_category_id vendor_vendor_cat_id` fmtParams := []interface{}{ - skuVendorIDField, fieldPrefix, fieldPrefix, + skuVendorIDField, fieldPrefix, fieldPrefix, fieldPrefix, GetDataResFieldName(vendorID), GetDataResFieldName(vendorID), GetDataResFieldName(vendorID), GetDataResFieldName(vendorID), GetDataResFieldName(vendorID), @@ -329,7 +349,7 @@ func newGetStoreSkus2(db *DaoDB, vendorID, storeID int, skuIDs []int, mustDirty } sql += ` FROM store_sku_bind t1 - LEFT JOIN store_map t14 ON t14.store_id = t1.store_id AND t14.vendor_id = ? AND t14.deleted_at = ? + JOIN store_map t14 ON t14.store_id = t1.store_id AND t14.vendor_id = ? AND t14.deleted_at = ? LEFT JOIN sku t2 ON t1.sku_id = t2.id AND t2.deleted_at = ? AND t2.status = ? LEFT JOIN sku_name t3 ON t2.name_id = t3.id AND t3.deleted_at = ? AND t3.status = ? LEFT JOIN sku_category t4 ON t3.category_id = t4.id AND t4.deleted_at = ? @@ -351,7 +371,7 @@ func newGetStoreSkus2(db *DaoDB, vendorID, storeID int, skuIDs []int, mustDirty } else { sql += ` LEFT JOIN sku_category t5sku ON t5sku.id = t2.category_id - LEFT JOIN thing_map t2m ON t2m.thing_id = t1.sku_id AND t2m.vendor_org_code = t14.vendor_org_code AND t2m.thing_type = ? AND t2m.vendor_id = ? AND t2m.deleted_at = ? + JOIN thing_map t2m ON t2m.thing_id = t1.sku_id AND t2m.vendor_org_code = t14.vendor_org_code AND t2m.thing_type = ? AND t2m.vendor_id = ? AND t2m.deleted_at = ? LEFT JOIN thing_map t4m ON t4m.thing_id = t3.category_id AND t4m.vendor_org_code = t14.vendor_org_code AND t4m.thing_type = ? AND t4m.vendor_id = ? AND t4m.deleted_at = ? LEFT JOIN thing_map t5skum ON t5skum.thing_id = t5sku.id AND t5skum.vendor_org_code = t14.vendor_org_code AND t5skum.thing_type = ? AND t5skum.vendor_id = ? AND t5skum.deleted_at = ? ` @@ -410,7 +430,7 @@ func oldGetStoreSkus2(db *DaoDB, vendorID, storeID int, skuIDs []int, mustDirty %s.%s_id vendor_sku_id, t1.%s_sync_status sku_sync_status, t1.%s_price vendor_price, t1.store_id, t1.deleted_at bind_deleted_at,t1.status_sale_begin,t1.status_sale_end, t2.*, - t3.id name_id, t3.prefix, t3.name, t3.unit, t3.upc, + t3.id name_id, t3.prefix, t3.name, t3.unit, t3.upc,t3.ex_prefix, t3.ex_prefix_begin, t3.ex_prefix_end, IF(t11.%s <> '', t11.%s, t3.img) img, IF(t12.%s <> '', t12.%s, t3.img2) img2, t13.%s desc_img, @@ -504,11 +524,15 @@ func GetFullStoreSkus(db *DaoDB, vendorID, storeID int) (skus []*StoreSkuSyncInf func newGetFullStoreSkus(db *DaoDB, vendorID, storeID int) (skus []*StoreSkuSyncInfo, err error) { globals.SugarLogger.Debugf("GetFullStoreSkus, storeID:%d, vendorID:%d", storeID, vendorID) + // 对于多门店平台,商品库删除后,不需要操作门店商品,所以sku_name用JOIN, sku与sku_name也可以直接排除下架的 sql := ` - SELECT t1.id bind_id, t1.price, t1.unit_price, t1.status store_sku_status, - t1.%s_sync_status sku_sync_status, t1.store_id, t1.deleted_at bind_deleted_at, + SELECT + sm.vendor_id, sm.vendor_org_code, + t1.id bind_id, t1.price, t1.unit_price, t1.status store_sku_status, + t1.%s_sync_status sku_sync_status, t1.%s_price vendor_price, t1.%s_lock_time lock_time, + t1.store_id, t1.deleted_at bind_deleted_at, t2.*, t2.id sku_id, t2m.vendor_thing_id vendor_sku_id, - t3.id name_id, t3.prefix, t3.name, t3.unit, t3.upc, + t3.id name_id, t3.prefix, t3.name, t3.unit, t3.upc, t3.ex_prefix, t3.ex_prefix_begin, t3.ex_prefix_end, IF(t11.%s <> '', t11.%s, t3.img) img, IF(t12.%s <> '', t12.%s, t3.img2) img2, t13.%s desc_img, @@ -516,12 +540,12 @@ func newGetFullStoreSkus(db *DaoDB, vendorID, storeID int) (skus []*StoreSkuSync t4m.sync_status cat_sync_status, t4m.vendor_thing_id vendor_cat_id, t5skum.sync_status sku_cat_sync_status, t5skum.vendor_thing_id sku_vendor_cat_id FROM sku t2 - LEFT JOIN store_sku_bind t1 ON t1.sku_id = t2.id AND t1.store_id = ? AND t1.deleted_at = ? - LEFT JOIN store_map sm ON sm.store_id = t1.store_id AND sm.vendor_id = ? AND sm.deleted_at = ? - LEFT JOIN thing_map t2m ON t2m.thing_id = t2.id AND t2m.vendor_org_code = sm.vendor_org_code AND t2m.thing_type = ? AND t2m.vendor_id = ? AND t2m.deleted_at = ? JOIN sku_name t3 ON t2.name_id = t3.id AND t3.deleted_at = ? AND t3.status = ? JOIN sku_category t4 ON t3.category_id = t4.id AND t4.deleted_at = ? - LEFT JOIN thing_map t4m ON t4m.thing_id = t3.category_id AND t4m.vendor_org_code = sm.vendor_org_code AND t4m.thing_type = ? AND t4m.vendor_id = ? AND t4m.deleted_at = ? + JOIN store_map sm ON sm.vendor_id = ? AND sm.store_id = ? AND sm.deleted_at = ? + JOIN thing_map t2m ON t2m.thing_id = t2.id AND t2m.vendor_org_code = sm.vendor_org_code AND t2m.thing_type = ? AND t2m.vendor_id = ? AND t2m.deleted_at = ? + JOIN thing_map t4m ON t4m.thing_id = t3.category_id AND t4m.vendor_org_code = sm.vendor_org_code AND t4m.thing_type = ? AND t4m.vendor_id = ? AND t4m.deleted_at = ? + LEFT JOIN store_sku_bind t1 ON sm.store_id = t1.store_id AND t1.sku_id = t2.id AND t1.deleted_at = ? LEFT JOIN sku_category t5sku ON t2.category_id = t5sku.id LEFT JOIN thing_map t5skum ON t5skum.thing_id = t2.category_id AND t5skum.vendor_org_code = sm.vendor_org_code AND t5skum.thing_type = ? AND t5skum.vendor_id = ? AND t5skum.deleted_at = ? LEFT JOIN data_resource t11 ON t11.main_url = t3.img @@ -530,21 +554,18 @@ func newGetFullStoreSkus(db *DaoDB, vendorID, storeID int) (skus []*StoreSkuSync WHERE t2.deleted_at = ? AND t2.status = ? AND t2m.vendor_thing_id <> '' ORDER BY t1.price DESC` sqlParams := []interface{}{ - storeID, + utils.DefaultTimeValue, model.SkuStatusNormal, utils.DefaultTimeValue, - vendorID, utils.DefaultTimeValue, + vendorID, storeID, utils.DefaultTimeValue, model.ThingTypeSku, vendorID, utils.DefaultTimeValue, - utils.DefaultTimeValue, - model.SkuStatusNormal, - utils.DefaultTimeValue, - model.ThingTypeCategory, vendorID, utils.DefaultTimeValue, model.ThingTypeCategory, vendorID, utils.DefaultTimeValue, utils.DefaultTimeValue, - model.SkuStatusNormal, + model.ThingTypeCategory, vendorID, utils.DefaultTimeValue, + utils.DefaultTimeValue, model.SkuStatusNormal, } fieldPrefix := ConvertDBFieldPrefix(model.VendorNames[vendorID]) sql = fmt.Sprintf(sql, - fieldPrefix, + fieldPrefix, fieldPrefix, fieldPrefix, GetDataResFieldName(vendorID), GetDataResFieldName(vendorID), GetDataResFieldName(vendorID), GetDataResFieldName(vendorID), GetDataResFieldName(vendorID), @@ -860,7 +881,7 @@ func GetStoresSkusInfoBySaleTime(db *DaoDB, storeID int) (storeSkuBindList []*mo return storeSkuBindList, err } -func UpdateStoreSkuBindSyncStatus(db *DaoDB, vendorIDs []int, storeID int) (num int64, err error) { +func UpdateStoreSkuBindSyncStatusForSaleStatus(db *DaoDB, vendorIDs []int, storeID int) (num int64, err error) { sql := ` UPDATE store_sku_bind SET @@ -892,6 +913,74 @@ func UpdateStoreSkuBindSyncStatus(db *DaoDB, vendorIDs []int, storeID int) (num return ExecuteSQL(db, sql, sqlParams...) } +func UpdateStoreSkuBindSyncStatusForExPrefix(db *DaoDB, vendorIDs []int) (num int64, err error) { + sql := ` + UPDATE store_sku_bind a + JOIN sku b ON a.sku_id = b.id AND b.deleted_at = ? + JOIN sku_name c ON c.id = b.name_id AND c.deleted_at = ? + SET + ` + fmtParams := []interface{}{} + sqlParams := []interface{}{ + utils.DefaultTimeValue, + utils.DefaultTimeValue, + } + if len(vendorIDs) > 0 { + for _, v := range vendorIDs { + fieldPrefix := ConvertDBFieldPrefix(model.VendorNames[v]) + sql += ` %s_sync_status = %s_sync_status | ?,` + fmtParams = append(fmtParams, fieldPrefix, fieldPrefix) + sqlParams = append(sqlParams, model.SyncFlagModifiedMask) + } + } else { + return 0, errors.New("取平台ID名有错误!partner.GetPurchasePlatformVendorIDs()") + } + sql = sql[0:strings.LastIndex(sql, ",")] + sql = fmt.Sprintf(sql, fmtParams...) + sql += ` WHERE a.deleted_at = ? + AND c.ex_prefix != "" + AND (c.ex_prefix_begin = DATE_FORMAT(DATE_ADD(NOW(),INTERVAL '6' HOUR),'%Y-%m-%d 00:00:00') + OR c.ex_prefix_end = DATE_FORMAT(NOW(),'%Y-%m-%d 00:00:00')) + ` + sqlParams = append(sqlParams, utils.DefaultTimeValue) + return ExecuteSQL(db, sql, sqlParams...) +} + +func UpdateSkuSyncStatusForExPrefix(db *DaoDB, vendorIDs []int) (num int64, err error) { + sql := ` + UPDATE thing_map t1 + JOIN sku t2 ON t2.id = t1.thing_id AND t2.deleted_at = ? + JOIN sku_name t3 ON t3.id = t2.name_id AND t3.deleted_at = ? + AND t3.ex_prefix <> '' AND (t3.ex_prefix_begin = DATE_FORMAT(DATE_ADD(NOW(),INTERVAL '6' HOUR),'%Y-%m-%d 00:00:00') + OR t3.ex_prefix_end = DATE_FORMAT(NOW(),'%Y-%m-%d 00:00:00')) + SET + t1.sync_status = t1.sync_status | ? + WHERE t1.deleted_at = ? AND t1.thing_type = ? AND t1.sync_status & ? <> 0 + ` + sqlParams := []interface{}{ + utils.DefaultTimeValue, + utils.DefaultTimeValue, + model.SyncFlagModifiedMask, + utils.DefaultTimeValue, model.ThingTypeSku, model.SyncFlagDeletedMask, + } + if len(vendorIDs) > 0 { + sql += " AND t1.vendor_id IN (" + GenQuestionMarks(len(vendorIDs)) + ")" + sqlParams = append(sqlParams, vendorIDs) + } + return ExecuteSQL(db, sql, sqlParams...) +} + +func DeleteSkuNameExPrefixOverdue(db *DaoDB) (num int64, err error) { + sql := ` + UPDATE sku_name + SET ex_prefix_begin = null,ex_prefix_end = null + WHERE deleted_at = ? + AND DATE_FORMAT(DATE_ADD(NOW(),INTERVAL '6' HOUR),'%Y-%m-%d 00:00:00') >= ex_prefix_end + ` + sqlParams := []interface{}{utils.DefaultTimeValue} + return ExecuteSQL(db, sql, sqlParams...) +} + func GetStoreSkusByNameIDs(db *DaoDB, storeIDs []int, nameID int) (skuList []*StoreSkuSyncInfo, err error) { sql := ` SELECT a.*,c.unit,c.name @@ -924,7 +1013,7 @@ func GetTopSkusByStoreIDs(db *DaoDB, storeIDs []int) (storeSkuNameExt []*StoreSk JOIN order_sku b ON a.vendor_order_id = b.vendor_order_id AND a.vendor_id = b.vendor_id JOIN sku c ON b.sku_id = c.id AND c.deleted_at = ? JOIN sku_name t1 ON t1.id = c.name_id AND t1.deleted_at = ? - STRAIGHT_JOIN store_sku_bind t4 ON t4.store_id = IF(a.store_id = 0,a.jx_store_id,a.store_id) AND t4.sku_id = b.sku_id AND t4.status = ? AND t4.deleted_at = ? + STRAIGHT_JOIN store_sku_bind t4 ON t4.store_id = IF(a.jx_store_id = 0,a.store_id,a.jx_store_id) AND t4.sku_id = b.sku_id AND t4.status = ? AND t4.deleted_at = ? JOIN store d ON d.id = a.store_id WHERE 1=1 AND a.order_created_at BETWEEN ? and NOW() @@ -948,7 +1037,7 @@ func GetTopSkusByStoreIDs(db *DaoDB, storeIDs []int) (storeSkuNameExt []*StoreSk ORDER BY t1.count DESC LIMIT ? ` - sqlParams = append(sqlParams, 100, 30) + sqlParams = append(sqlParams, salePriceLimit, 30) err = GetRows(db, &storeSkuNameExt, sql, sqlParams...) var skuNamesInfo = &StoreSkuNamesInfo{ SkuNames: storeSkuNameExt, @@ -984,7 +1073,33 @@ func GetTopSkusByStoreIDs(db *DaoDB, storeIDs []int) (storeSkuNameExt []*StoreSk return storeSkuNameExt, err } -func GetTopCategorysByStoreIDs(db *DaoDB, storeIDs []int) (skuCategory []*model.SkuCategory, err error) { +func GetTopSkusByCityCode(db *DaoDB, cityCode int, orderCreate time.Time) (skuNameAndPlace []*SkuNameAndPlace, err error) { + sql := ` + SELECT SUM(b.count) count, e.name city_name, d.city_code, f.* + FROM goods_order a + JOIN order_sku b ON a.vendor_order_id = b.vendor_order_id AND a.vendor_id = b.vendor_id + JOIN sku c ON b.sku_id = c.id AND c.deleted_at = ? + JOIN sku_name f ON f.id = c.name_id + JOIN store d ON d.id = IF(a.jx_store_id = 0,a.store_id,a.jx_store_id) AND d.deleted_at = ? AND d.city_code = ? + JOIN place e ON e.code = d.city_code + WHERE 1=1 + AND b.sale_price > ? + AND a.order_created_at BETWEEN ? and NOW() + GROUP BY 2,3,4 + ORDER BY count DESC + ` + sqlParams := []interface{}{ + utils.DefaultTimeValue, + utils.DefaultTimeValue, + cityCode, + salePriceLimit, + orderCreate, + } + err = GetRows(db, &skuNameAndPlace, sql, sqlParams...) + return skuNameAndPlace, err +} + +func GetTopCategoriesByStoreIDs(db *DaoDB, storeIDs []int, limit int) (skuCategory []*model.SkuCategory, err error) { sql := ` SELECT DISTINCT t5.* FROM( SELECT d.* @@ -993,10 +1108,10 @@ func GetTopCategorysByStoreIDs(db *DaoDB, storeIDs []int) (skuCategory []*model. FROM( SELECT SUM(b.count) count,d.category_id FROM goods_order a - JOIN order_sku b ON a.vendor_order_id = b.vendor_order_id + JOIN order_sku b ON a.vendor_order_id = b.vendor_order_id AND a.vendor_id = b.vendor_id JOIN sku c ON b.sku_id = c.id AND c.deleted_at = ? JOIN sku_name d ON d.id = c.name_id AND d.deleted_at = ? - JOIN store e ON e.id = a.store_id + JOIN store e ON e.id = IF(a.jx_store_id = 0,a.store_id,a.jx_store_id) AND e.status != -2 JOIN (SELECT city_code FROM store WHERE 1=1 ` sqlParams := []interface{}{ @@ -1023,11 +1138,51 @@ func GetTopCategorysByStoreIDs(db *DaoDB, storeIDs []int) (skuCategory []*model. Order by t4.count DESC)t5 LIMIT ? ` - sqlParams = append(sqlParams, time.Now().AddDate(0, -1, 0), 100, 2, utils.DefaultTimeValue, 1, 10) + sqlParams = append(sqlParams, time.Now().AddDate(0, -1, 0), salePriceLimit, 2, utils.DefaultTimeValue, 1, limit) err = GetRows(db, &skuCategory, sql, sqlParams...) return skuCategory, err } +func GetStoreSkuCategories(db *DaoDB, storeID, parentID int) (catList []*model.SkuCategory, err error) { + sql := ` + SELECT + t1.* + FROM sku_category t1 + JOIN + ( + SELECT DISTINCT t3.category_id + FROM store_sku_bind t1 + JOIN sku t2 ON t2.id = t1.sku_id AND t2.deleted_at = ? AND t2.status = ? + JOIN sku_name t3 ON t3.id = t2.name_id AND t3.deleted_at = ? AND t3.status = ? + WHERE t1.deleted_at = ? AND t1.status = ? AND t1.store_id = ? + ) t2 ON t2.category_id = t1.id + WHERE t1.deleted_at = ?` + sqlParams := []interface{}{ + utils.DefaultTimeValue, model.SkuStatusNormal, + utils.DefaultTimeValue, model.SkuStatusNormal, + utils.DefaultTimeValue, model.SkuStatusNormal, storeID, + utils.DefaultTimeValue, + } + if parentID >= 0 { + sql += " AND t1.parent_id = ?" + sqlParams = append(sqlParams, parentID) + } + sql += " ORDER BY t1.level, t1.seq" + if err = GetRows(db, &catList, sql, sqlParams...); err == nil && len(catList) > 0 { + parentIDMap := make(map[int]int) + for _, v := range catList { + parentIDMap[v.ParentID] = 1 + } + paretnCats, err2 := GetCategories(db, -1, 0, jxutils.IntMap2List(parentIDMap)) + if err = err2; err == nil { + catList = append(catList, paretnCats...) + } else { + catList = nil + } + } + return catList, err +} + func RefershStoreSkusMidPrice(db *DaoDB, storeIDs []int) (count int64, err error) { sql := ` UPDATE store_sku_bind a @@ -1068,16 +1223,21 @@ func GetStoreSkuNamePrice(db *DaoDB) (storeSkuNamePriceList []*model.StoreSkuNam return storeSkuNamePriceList, err } -func SetStoreSkuBindVendorPrice(storeSkuBind *model.StoreSkuBind, vendorID int, vendorPrice int) { +func SetStoreSkuBindVendorPrice(storeSkuBind *model.StoreSkuBind, vendorID int, vendorPrice int, lockTime time.Time) { + pLockTime := utils.Time2Pointer(lockTime) switch vendorID { case model.VendorIDJD: storeSkuBind.JdPrice = vendorPrice + storeSkuBind.JdLockTime = pLockTime case model.VendorIDMTWM: storeSkuBind.MtwmPrice = vendorPrice + storeSkuBind.MtwmLockTime = pLockTime case model.VendorIDEBAI: storeSkuBind.EbaiPrice = vendorPrice + storeSkuBind.EbaiLockTime = pLockTime case model.VendorIDJX: storeSkuBind.JxPrice = vendorPrice + storeSkuBind.JxLockTime = pLockTime } } @@ -1136,7 +1296,7 @@ func UpdateActPrice4StoreSkuNameNew(db *DaoDB, storeIDs, skuIDs []int, skuNamesI if actVendorID >= 0 { vendorIDs = []int{actVendorID} } - actStoreSkuList, err := GetEffectiveActStoreSkuInfo(db, 0, vendorIDs, storeIDs, skuIDs, time.Now(), time.Now()) + actStoreSkuList, err := GetEffectiveActStoreSkuInfo(db, 0, vendorIDs, model.ActTypeAll, storeIDs, skuIDs, time.Now(), time.Now()) if err != nil { globals.SugarLogger.Errorf("updateActPrice4StoreSkuNameNew can not get sku promotion info for error:%v", err) return err @@ -1151,15 +1311,16 @@ func UpdateActPrice4StoreSkuNameNew(db *DaoDB, storeIDs, skuIDs []int, skuNamesI v.ActPrice = int(actStoreSku.ActualActPrice) v.ActID = actStoreSku.ActID v.ActType = actStoreSku.Type + v.EarningPrice = int(jxutils.CaculateSkuEarningPrice(int64(v.ActPrice), int64(v.ActPrice), skuName.PayPercentage)) } if actStoreSku := actStoreSkuMap4EarningPrice.GetActStoreSku(skuName.StoreID, v.SkuID, -1); actStoreSku != nil { v.EarningPrice = int(actStoreSku.EarningPrice) v.EarningActID = actStoreSku.ActID - } - - v.RealEarningPrice = v.EarningPrice - if v.RealEarningPrice == 0 { - v.RealEarningPrice = int(jxutils.CaculateSkuEarningPrice(int64(v.BindPrice), int64(v.BindPrice), skuName.PayPercentage)) + } else { + earningPrice := int(jxutils.CaculateSkuEarningPrice(int64(v.BindPrice), int64(v.BindPrice), skuName.PayPercentage)) + if earningPrice < v.EarningPrice { + v.EarningPrice = earningPrice + } } } } else { @@ -1168,3 +1329,65 @@ func UpdateActPrice4StoreSkuNameNew(db *DaoDB, storeIDs, skuIDs []int, skuNamesI } return err } + +func GetDeletedStoreSkuBind(db *DaoDB, storeID, skuID int) (storeSkuBind *model.StoreSkuBind) { + sql := ` + SELECT a.* + FROM store_sku_bind a + WHERE a.store_id = ? AND a.sku_id = ? + ORDER BY a.deleted_at DESC` + sqlParams := []interface{}{ + storeID, skuID, + } + if err := GetRow(db, &storeSkuBind, sql, sqlParams...); err != nil { + storeSkuBind = nil + } + return storeSkuBind +} + +func GetMidPriceByNameID(db *DaoDB, cityCode, skuNameID int, snapDate time.Time) (midPrice int, err error) { + var ( + sku []*model.SkuAndName + skuMap = make(map[int]int) + ) + sql := ` + SELECT a.mid_price price, a.sku_id id, b.spec_quality, c.unit, b.spec_unit + FROM price_refer_snapshot a + JOIN sku b ON a.sku_id = b.id + JOIN sku_name c ON c.id = b.name_id + WHERE c.id = ? + AND a.snapshot_at = ? + AND a.city_code = ? + ` + sqlParams := []interface{}{ + skuNameID, + snapDate, + cityCode, + } + err = GetRows(db, &sku, sql, sqlParams...) + if err != nil { + return 0, err + } + if len(sku) > 0 { + for _, v := range sku { + var ( + price int + specQuality float64 + ) + if v.Unit == model.SpecialUnit { + if v.SpecUnit == model.SpecUnitNames[1] || v.SpecUnit == model.SpecUnitNames[2] { + specQuality = float64(v.SpecQuality) * 1000 + } else { + specQuality = float64(v.SpecQuality) + } + price = int(utils.Float64TwoInt64(utils.Int2Float64(model.SpecialSpecQuality) / specQuality * utils.Int2Float64(v.Price))) + } else { + price = v.Price + } + if skuMap[skuNameID] < price { + skuMap[skuNameID] = price + } + } + } + return skuMap[skuNameID], err +} diff --git a/business/model/dao/store_sku_test.go b/business/model/dao/store_sku_test.go new file mode 100644 index 000000000..9ef743329 --- /dev/null +++ b/business/model/dao/store_sku_test.go @@ -0,0 +1,30 @@ +package dao + +import ( + "testing" + + "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/model" + "git.rosy.net.cn/jx-callback/globals" +) + +func TestGetFullStoreSkus(t *testing.T) { + skuList, err := GetFullStoreSkus(GetDB(), model.VendorIDJD, 100118) + if err != nil { + t.Fatal(err) + } + globals.SugarLogger.Debug(utils.Format4Output(skuList, false)) +} + +func TestGetStoreSkus(t *testing.T) { + skuList, err := GetStoreSkus(GetDB(), model.VendorIDMTWM, 100134, nil) + if err != nil { + t.Fatal(err) + } + globals.SugarLogger.Debug(utils.Format4Output(skuList, false)) +} + +func TestGetDeletedStoreSkuBind(t *testing.T) { + storeSkuBind := GetDeletedStoreSkuBind(GetDB(), 100123, 30648) + globals.SugarLogger.Debug(utils.Format4Output(storeSkuBind, false)) +} diff --git a/business/model/order.go b/business/model/order.go index 96624d07f..375f91598 100644 --- a/business/model/order.go +++ b/business/model/order.go @@ -59,6 +59,7 @@ type GoodsOrder struct { TotalShopMoney int64 `json:"totalShopMoney"` // 应结金额-第三方平台结算给京西的金额(包括了所有的补贴,扣除) DiscountMoney int64 `json:"discountMoney"` // 订单总优惠金额 PmSubsidyMoney int64 `json:"pmSubsidyMoney"` // 平台活动补贴(订单主体活动补贴+订单单条sku补贴)1+ + BaseFreightMoney int64 `json:"baseFreightMoney"` // 商户承担的配送费(不包括DistanceFreightMoney) DistanceFreightMoney int64 `json:"distanceFreightMoney"` // 商户承担的远距离配送费(当前只有京东到家有值) WaybillTipMoney int64 `json:"waybillTipMoney"` // 京西加的平台配送小费 EarningPrice int64 `json:"earningPrice"` // 结算给门店老板的钱(未扣除可能的三方配送费) @@ -76,7 +77,7 @@ type GoodsOrder struct { GoodsCount int `json:"goodsCount"` // 商品个数 Status int `json:"status"` // 参见OrderStatus*相关的常量定义 VendorStatus string `orm:"size(255)" json:"vendorStatus"` - LockStatus int `json:"lockStatus"` + LockStatus int `json:"lockStatus"` // 当前只支持单一锁定 LockStatusTime time.Time `orm:"type(datetime);null" json:"lockStatusTime"` // last lock status time OrderSeq int `json:"orderSeq"` // 门店订单序号 BuyerComment string `orm:"size(255)" json:"buyerComment"` @@ -133,7 +134,7 @@ type OrderSku struct { ID int64 `orm:"column(id)" json:"-"` VendorOrderID string `orm:"column(vendor_order_id);size(48)" json:"vendorOrderID"` VendorID int `orm:"column(vendor_id)" json:"vendorID"` - StoreSubID int `orm:"column(store_sub_id)" json:"storeSubID"` // 当前这个字段被当成结算活动ID用 + StoreSubID int `orm:"column(store_sub_id)" json:"storeSubID"` // EarningActID,当前这个字段被当成结算活动ID用 StoreSubName string `orm:"size(64)" json:"storeSubName"` // 当前这个字段被用作vendorActType Count int `json:"count"` VendorSkuID string `orm:"column(vendor_sku_id);size(48)" json:"vendorSkuID"` @@ -172,6 +173,7 @@ type Waybill struct { VendorStatus string `orm:"size(255)" json:"-"` ActualFee int64 `json:"actualFee"` // 实际要支付给快递公司的费用 DesiredFee int64 `json:"desiredFee"` // 运单总费用 + TipFee int64 `json:"tipFee"` // 运单小费,不含在上两项中 DuplicatedCount int `json:"-"` // 重复新订单消息数,这个一般不是由于消息重发造成的(消息重发由OrderStatus过滤),一般是业务逻辑造成的 DeliveryFlag int8 `json:"deliveryFlag"` WaybillCreatedAt time.Time `orm:"type(datetime);index" json:"waybillCreatedAt"` @@ -196,6 +198,12 @@ func (w *Waybill) TableIndex() [][]string { } } +type WaybillExt struct { + Waybill + Lng float64 `json:"lng"` + Lat float64 `json:"lat"` +} + // 包含订单与运单的状态及事件vendor status type OrderStatus struct { ID int64 `orm:"column(id)" json:"id"` @@ -296,25 +304,26 @@ type OrderComment struct { type OrderPay struct { ModelIDCULD - VendorOrderID string `orm:"column(vendor_order_id);size(48)" json:"vendorOrderID"` - VendorID int `orm:"column(vendor_id)" json:"vendorID"` - PayType int `json:"payType"` + PayOrderID string `orm:"column(pay_order_id);size(48)" json:"payOrderID"` // 京西支付定单号 + PayType int `json:"payType"` + VendorPayType string `orm:"size(48)" json:"vendorPayType"` + VendorOrderID string `orm:"column(vendor_order_id);size(48);index" json:"vendorOrderID"` // 支付对应的购物订单号 + VendorID int `orm:"column(vendor_id)" json:"vendorID"` // 购物订单所属厂商代码(当前只有京西) Status int `json:"status"` PayCreatedAt time.Time `orm:"type(datetime);index" json:"payCreatedAt"` PayFinishedAt *time.Time `orm:"type(datetime);null" json:"payFinishedAt"` TotalFee int `json:"totalFee"` - TransactionID string `orm:"column(transaction_id);index;size(48)" json:"transactionID"` - PrepayID string `orm:"column(prepay_id);unique;size(48)" json:"prepayID"` + PrepayID string `orm:"column(prepay_id);index;size(48)" json:"prepayID"` // 下单后,支付前,支付方生成的事务ID + TransactionID string `orm:"column(transaction_id);index;size(48)" json:"transactionID"` // 支付成功后,支付方生成的事务ID CodeURL string `orm:"column(code_url);size(256)" json:"codeURL"` - PayOrderID string `orm:"column(pay_order_id);size(48)" json:"payOrderID"` OriginalData string `orm:"type(text)" json:"-"` } func (v *OrderPay) TableIndex() [][]string { return [][]string{ - []string{"VendorOrderID", "VendorID", "PayType", "DeletedAt"}, + []string{"PayOrderID", "PayType", "DeletedAt"}, } } @@ -322,12 +331,11 @@ type OrderPayRefund struct { ModelIDCULD RefundID string `orm:"column(refund_id);unique;size(48)" json:"refundID"` - VendorRefundID string `orm:"column(vendor_refund_id);unique;size(48)" json:"vendorRefundID"` + VendorRefundID string `orm:"column(vendor_refund_id);unique;size(48)" json:"vendorRefundID"` // 支付方退款成功后生成的退款单号 - AfsOrderID string `orm:"column(afs_order_id);index;size(48)" json:"afsOrderID"` // AfsOrderID与RefundID的区别? VendorOrderID string `orm:"column(vendor_order_id);index;size(48)" json:"vendorOrderID"` VendorID int `orm:"column(vendor_id)" json:"vendorID"` - TransactionID string `orm:"column(transaction_id);index;size(48)" json:"transactionID"` + TransactionID string `orm:"column(transaction_id);index;size(48)" json:"transactionID"` // 支付成功后,支付方生成的事务ID Status int `json:"status"` RefundCreatedAt time.Time `orm:"type(datetime);index" json:"payCreatedAt"` RefundFinishedAt *time.Time `orm:"type(datetime);null" json:"payFinishedAt"` @@ -336,6 +344,11 @@ type OrderPayRefund struct { OriginalData string `orm:"type(text)" json:"-"` } +type OrderSupplementFee struct { + ModelIDCULD + VendorOrderID string `orm:"column(vendor_order_id);index;size(48)" json:"vendorOrderID"` +} + // 判断是否是购买平台自有物流 // 对于京东,饿百来说,就是其自有的物流,对于微商城来说,是达达 func IsWaybillPlatformOwn(bill *Waybill) bool { diff --git a/business/model/sku.go b/business/model/sku.go index e2e51cf03..c248691ff 100644 --- a/business/model/sku.go +++ b/business/model/sku.go @@ -1,5 +1,7 @@ package model +import "time" + const ( SkuCategoryNormal = 0 SkuCategorySpecial = 1 @@ -166,8 +168,12 @@ func (*SkuCategory) TableIndex() [][]string { type SkuName struct { ModelIDCULD - Prefix string `orm:"size(255)" json:"prefix"` - Name string `orm:"size(255);index" json:"name"` + Prefix string `orm:"size(255)" json:"prefix"` + Name string `orm:"size(255)" json:"name"` + ExPrefix string `orm:"size(255)" json:"exPrefix"` + + ExPrefixBegin *time.Time `orm:"null" json:"exPrefixBegin"` + ExPrefixEnd *time.Time `orm:"null" json:"exPrefixEnd"` BrandID int `orm:"column(brand_id);default(0)" json:"brandID"` // todo,此属性暂时没有使用,且有问题,应该是不同平台都有一个brandid CategoryID int `orm:"column(category_id);index" json:"categoryID"` // 标准类别 @@ -187,9 +193,9 @@ type SkuName struct { DescImg string `orm:"size(255)" json:"descImg"` // 商品详情图片描述 // DescImgEbai string `orm:"size(255)" json:"descImgEbai"` // 饿百的商品详情图片描述RTF - Upc string `orm:"size(20);index"` - Status int `orm:"default(1)" json:"status"` // skuname状态,取值同sku.Status - IsSpu int8 `orm:"column(is_spu)" json:"isSpu"` // 用于指明是否SKUNAME当成SPU + Upc *string `orm:"size(20)"` + Status int `orm:"default(1)" json:"status"` // skuname状态,取值同sku.Status + IsSpu int8 `orm:"column(is_spu)" json:"isSpu"` // 用于指明是否SKUNAME当成SPU JdID int64 `orm:"column(jd_id);null;index" json:"jdID"` JdSyncStatus int8 `orm:"default(2)" json:"jdSyncStatus"` @@ -200,6 +206,13 @@ type SkuName struct { func (*SkuName) TableUnique() [][]string { return [][]string{ []string{"Name", "Prefix", "SpecQuality", "SpecUnit", "Unit", "IsSpu", "DeletedAt"}, + []string{"Upc", "DeletedAt"}, + } +} + +func (*SkuName) TableIndex() [][]string { + return [][]string{ + []string{"ExPrefix", "ExPrefixBegin", "ExPrefixEnd", "DeletedAt"}, } } @@ -223,10 +236,14 @@ type Sku struct { type SkuAndName struct { Sku - Name string - Unit string - Prefix string - IsSpu int + Name string + Unit string + Prefix string + IsSpu int + ExPrefix string + ExPrefixBegin *time.Time + ExPrefixEnd *time.Time + Price int } func (*Sku) TableUnique() [][]string { @@ -255,9 +272,9 @@ type SkuWithVendor struct { type SkuNameExt struct { SkuName - Skus []*SkuWithVendor `orm:"-" json:"skus"` - SkusStr string `json:"-"` - - Places []int `orm:"-" json:"places"` - PlacesStr string `json:"-"` + Skus []*SkuWithVendor `orm:"-" json:"skus"` + SkusStr string `json:"-"` + FullName string `json:"fullName"` + Places []int `orm:"-" json:"places"` + PlacesStr string `json:"-"` } diff --git a/business/model/store.go b/business/model/store.go index 80f5ff000..83467b027 100644 --- a/business/model/store.go +++ b/business/model/store.go @@ -49,6 +49,12 @@ const ( StoreChangePriceTypeManagedStore = 3 // 直营门店,禁止改价 ) +const ( + AutoReplyAll = 0 // 全部自动回复 + AutoReplyGoodComment = 1 // 禁止差评自动回复 + AutoReplyDisabled = 2 // 禁止自动回复 +) + var ( StoreStatusName = map[int]string{ StoreStatusDisabled: "禁用", @@ -240,6 +246,11 @@ var ( StoreChangePriceTypeBossDisabled: "普通门店禁止改价", StoreChangePriceTypeManagedStore: "直营门店禁止改价", } + AutoReplyTypeName = map[int]string{ + AutoReplyAll: "全部自动回复", + AutoReplyGoodComment: "禁止差评自动回复", + AutoReplyDisabled: "禁止自动回复", + } ) type Store struct { @@ -264,6 +275,7 @@ type Store struct { AutoEnableAt *time.Time `orm:"type(datetime);null" json:"autoEnableAt"` // 自动营业时间(临时休息用) ChangePriceType int8 `json:"changePriceType"` // 修改价格类型,即是否需要审核 SMSNotify int8 `orm:"column(sms_notify);" json:"smsNotify"` // 是否通过短信接收订单消息 + AutoReplyType int8 `json:"autoReplyType"` // 订单评价自动回复类型 PrinterDisabled int8 `orm:"default(0)" json:"printerDisabled"` // 是否禁用网络打印机 PrinterFontSize int8 `orm:"default(0)" json:"printerFontSize"` // 打印字体-1:小,0:正常,1:大 @@ -314,6 +326,7 @@ type Store struct { OperatorPhone2 string `orm:"size(16)" json:"operatorPhone2"` // 非京东运营人电话 OperatorRole2 string `orm:"size(32)" json:"operatorRole2"` // 非京东运营人组(角色) + PromoteInfo string `orm:"size(255)" json:"promoteInfo"` //门店公告(所有平台统一的公告) } func (*Store) TableUnique() [][]string { @@ -375,9 +388,10 @@ type StoreMap struct { VendorID int `orm:"column(vendor_id)" json:"vendorID"` VendorOrgCode string `orm:"size(32)" json:"vendorOrgCode"` // 同一平台下不同的商户代码,如果只有一个,可以为空 - VendorStoreID string `orm:"column(vendor_store_id);size(48)" json:"vendorStoreID"` - Status int `json:"status"` // 取值同Store.Status - StoreName string `orm:"size(255)" json:"storeName"` // 平台门店的名字 + VendorStoreID string `orm:"column(vendor_store_id);size(48)" json:"vendorStoreID"` + Status int `json:"status"` // 取值同Store.Status + StoreName string `orm:"size(255)" json:"storeName"` // 平台门店的名字,由平台到京西 + VendorStoreName string `orm:"size(255)" json:"vendorStoreName"` //平台门店名,由京西到平台 PricePercentage int16 `orm:"default(100)" json:"pricePercentage"` // todo 厂商价格相对于本地价格的百分比,这个字段的修改会比较特殊,因为可能需要刷新厂商价格 PricePercentagePack string `orm:"size(32)" json:"pricePercentagePack"` // @@ -389,10 +403,11 @@ type StoreMap struct { DeliveryFee int `json:"deliveryFee"` DeliveryCompetition int8 `orm:"default(1)" json:"deliveryCompetition"` // 是否支持配送竞争 - SyncStatus int8 `orm:"default(2)" json:"syncStatus"` - IsSync int8 `orm:"default(1)" json:"isSync"` // 是否同步 - FakeOpenStart int16 `orm:"default(0)" json:"fakeOpenStart"` // 假开店开始 - FakeOpenStop int16 `orm:"default(0)" json:"fakeOpenStop"` // 假开店结束 + SyncStatus int8 `orm:"default(2)" json:"syncStatus"` + IsSync int8 `orm:"default(1)" json:"isSync"` // 是否同步 + FakeOpenStart int16 `orm:"default(0)" json:"fakeOpenStart"` // 假开店开始 + FakeOpenStop int16 `orm:"default(0)" json:"fakeOpenStop"` // 假开店结束 + JdStoreLevel string `orm:"size(32)" json:"jdStoreLevel"` //京东门店等级 } func (*StoreMap) TableUnique() [][]string { @@ -522,6 +537,7 @@ type VendorStoreSnapshot struct { DeliveryType int8 `orm:"default(0)" json:"deliveryType"` // 配送类型 StoreName string `orm:"size(255)" json:"storeName"` // 平台门店的名字 IsAutoOrder int8 `json:"isAutoOrder"` // 平台是否自动接单,-1:否,0:未知,1:是 + JdStoreLevel string `orm:"size(32)" json:"jdStoreLevel"` //京东门店等级 } func (*VendorStoreSnapshot) TableUnique() [][]string { diff --git a/business/model/store_sku.go b/business/model/store_sku.go index 382a97b61..49aebbbc6 100644 --- a/business/model/store_sku.go +++ b/business/model/store_sku.go @@ -94,22 +94,26 @@ type StoreSkuBind struct { Status int // ElmID int64 `orm:"column(elm_id);index"` + MtwmID int64 `orm:"column(mtwm_id);index"` EbaiID int64 `orm:"column(ebai_id);index"` - MtwmID int64 `orm:"column(mtwm_id)"` // WscID int64 `orm:"column(wsc_id);index"` // 表示微盟skuId // WscID2 int64 `orm:"column(wsc_id2);index"` // 表示微盟goodsId // ElmSyncStatus int8 `orm:"default(2)"` JdSyncStatus int8 `orm:"default(2)"` - EbaiSyncStatus int8 `orm:"default(2)"` MtwmSyncStatus int8 `orm:"default(2)"` + EbaiSyncStatus int8 `orm:"default(2)"` // WscSyncStatus int8 `orm:"default(2)"` JdPrice int `json:"jdPrice"` - EbaiPrice int `json:"ebaiPrice"` MtwmPrice int `json:"mtwmPrice"` + EbaiPrice int `json:"ebaiPrice"` JxPrice int `json:"jxPrice"` - // WscPrice int `json:"wscPrice"` + + JdLockTime *time.Time `orm:"null" json:"jdLockTime"` + MtwmLockTime *time.Time `orm:"null" json:"mtwmLockTime"` + EbaiLockTime *time.Time `orm:"null" json:"ebaiLockTime"` + JxLockTime *time.Time `orm:"null" json:"jxLockTime"` AutoSaleAt time.Time `orm:"type(datetime);null" json:"autoSaleAt"` diff --git a/business/partner/delivery/dada/waybill.go b/business/partner/delivery/dada/waybill.go index 559300b3d..0b65f5f89 100644 --- a/business/partner/delivery/dada/waybill.go +++ b/business/partner/delivery/dada/waybill.go @@ -69,16 +69,12 @@ func (c *DeliveryHandler) onWaybillMsg(msg *dadaapi.CallbackMsg) (retVal *dadaap order := c.callbackMsg2Waybill(msg) switch msg.OrderStatus { case dadaapi.OrderStatusWaitingForAccept: - if result, err := api.DadaAPI.QueryOrderInfo(msg.OrderID); err == nil { - order.ActualFee = jxutils.StandardPrice2Int(utils.Interface2Float64WithDefault(result["actualFee"], 0.0)) - order.DesiredFee = jxutils.StandardPrice2Int(utils.Interface2Float64WithDefault(result["deliveryFee"], 0.0)) + if dadaOrder, err := api.DadaAPI.QueryOrderInfo2(msg.OrderID); err == nil { + order.ActualFee = jxutils.StandardPrice2Int(dadaOrder.ActualFee) + order.DesiredFee = jxutils.StandardPrice2Int(dadaOrder.DeliveryFee) } order.Status = model.WaybillStatusNew case dadaapi.OrderStatusAccepted: - // if result, err := api.DadaAPI.QueryOrderInfo(msg.OrderID); err == nil { - // order.ActualFee = jxutils.StandardPrice2Int(utils.Interface2Float64WithDefault(result["actualFee"], 0.0)) - // order.DesiredFee = jxutils.StandardPrice2Int(utils.Interface2Float64WithDefault(result["deliveryFee"], 0.0)) - // } order.Status = model.WaybillStatusAccepted case dadaapi.OrderStatusDelivering: order.Status = model.WaybillStatusDelivering @@ -204,10 +200,12 @@ func (c *DeliveryHandler) IsErrStoreExist(err error) bool { func (c *DeliveryHandler) GetWaybillFee(order *model.GoodsOrder) (deliveryFeeInfo *partner.WaybillFeeInfo, err error) { db := dao.GetDB() deliveryFeeInfo = &partner.WaybillFeeInfo{} - billParams, addParams, err := c.getBillParams(db, order) + // billParams, addParams, err := c.getBillParams(db, order) + billParams, err := c.getBillParams2(db, order) if err == nil { var result *dadaapi.CreateOrderResponse - if result, err = api.DadaAPI.QueryDeliverFee(billParams, addParams); err != nil { + // if result, err = api.DadaAPI.QueryDeliverFee(billParams, addParams); err != nil { + if result, err = api.DadaAPI.QueryDeliverFee2(billParams); err != nil { return nil, err } deliveryFeeInfo.DeliveryFee = jxutils.StandardPrice2Int(result.Fee) @@ -216,9 +214,34 @@ func (c *DeliveryHandler) GetWaybillFee(order *model.GoodsOrder) (deliveryFeeInf return deliveryFeeInfo, err } -func (c *DeliveryHandler) getBillParams(db *dao.DaoDB, order *model.GoodsOrder) (billParams *dadaapi.OperateOrderRequiredParams, addParams map[string]interface{}, err error) { - billParams = &dadaapi.OperateOrderRequiredParams{ - // ShopNo: utils.Int2Str(order.StoreID), // 当前达达的门店号与京西是一样的 +// func (c *DeliveryHandler) getBillParams(db *dao.DaoDB, order *model.GoodsOrder) (billParams *dadaapi.OperateOrderRequiredParams, addParams map[string]interface{}, err error) { +// billParams = &dadaapi.OperateOrderRequiredParams{ +// // ShopNo: utils.Int2Str(order.StoreID), // 当前达达的门店号与京西是一样的 +// OriginID: jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID), +// CargoPrice: jxutils.IntPrice2Standard(limitOrderPrice(order.ActualPayPrice)), +// IsPrepay: 0, +// ReceiverName: utils.FilterMb4(order.ConsigneeName), +// ReceiverAddress: utils.FilterMb4(order.ConsigneeAddress), +// ReceiverPhone: order.ConsigneeMobile, +// } +// if billParams.ShopNo, err = c.getDadaShopID(order, db); err == nil { +// if billParams.CityCode, err = c.getDataCityCodeFromOrder(order, db); err == nil { +// billParams.ReceiverLng, billParams.ReceiverLat, _ = jxutils.IntCoordinate2MarsStandard(order.ConsigneeLng, order.ConsigneeLat, order.CoordinateType) +// addParams = map[string]interface{}{ +// "info": fmt.Sprintf("%s第%d号订单, %s", model.VendorChineseNames[order.VendorID], order.OrderSeq, utils.FilterMb4(order.BuyerComment)), +// // "origin_mark": model.VendorNames[order.VendorID], // 订单来源标示(该字段可以显示在达达app订单详情页面,只支持字母,最大长度为10) +// // "origin_mark_no": fmt.Sprintf("%d", order.OrderSeq), // 订单来源编号(该字段可以显示在达达app订单详情页面,支持字母和数字,最大长度为30) +// "cargo_type": 13, +// "cargo_weight": jxutils.IntWeight2Float(limitOrderWeight(order.Weight)), +// "cargo_num": order.GoodsCount, +// } +// } +// } +// return billParams, addParams, err +// } + +func (c *DeliveryHandler) getBillParams2(db *dao.DaoDB, order *model.GoodsOrder) (billParams *dadaapi.OperateOrderParams, err error) { + billParams = &dadaapi.OperateOrderParams{ OriginID: jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID), CargoPrice: jxutils.IntPrice2Standard(limitOrderPrice(order.ActualPayPrice)), IsPrepay: 0, @@ -229,23 +252,20 @@ func (c *DeliveryHandler) getBillParams(db *dao.DaoDB, order *model.GoodsOrder) if billParams.ShopNo, err = c.getDadaShopID(order, db); err == nil { if billParams.CityCode, err = c.getDataCityCodeFromOrder(order, db); err == nil { billParams.ReceiverLng, billParams.ReceiverLat, _ = jxutils.IntCoordinate2MarsStandard(order.ConsigneeLng, order.ConsigneeLat, order.CoordinateType) - addParams = map[string]interface{}{ - "info": fmt.Sprintf("%s第%d号订单, %s", model.VendorChineseNames[order.VendorID], order.OrderSeq, utils.FilterMb4(order.BuyerComment)), - // "origin_mark": model.VendorNames[order.VendorID], // 订单来源标示(该字段可以显示在达达app订单详情页面,只支持字母,最大长度为10) - // "origin_mark_no": fmt.Sprintf("%d", order.OrderSeq), // 订单来源编号(该字段可以显示在达达app订单详情页面,支持字母和数字,最大长度为30) - "cargo_type": 13, - "cargo_weight": jxutils.IntWeight2Float(limitOrderWeight(order.Weight)), - "cargo_num": order.GoodsCount, - } + billParams.Info = fmt.Sprintf("%s第%d号订单, %s", model.VendorChineseNames[order.VendorID], order.OrderSeq, utils.FilterMb4(order.BuyerComment)) + billParams.CargoType = dadaapi.CargoTypeFresh + billParams.CargoWeight = float64(jxutils.IntWeight2Float(limitOrderWeight(order.Weight))) + billParams.CargoNum = order.GoodsCount } } - return billParams, addParams, err + return billParams, err } // IDeliveryPlatformHandler func (c *DeliveryHandler) CreateWaybill(order *model.GoodsOrder, maxDeliveryFee int64) (bill *model.Waybill, err error) { db := dao.GetDB() - billParams, addParams, err := c.getBillParams(db, order) + // billParams, addParams, err := c.getBillParams(db, order) + billParams, err := c.getBillParams2(db, order) if err == nil { if globals.EnableStoreWrite { // 达达要求第二次创建运单,调用函数不同。所以查找两天内有无相同订单号的运单 @@ -265,16 +285,19 @@ func (c *DeliveryHandler) CreateWaybill(order *model.GoodsOrder, maxDeliveryFee if err = delivery.CallCreateWaybillPolicy(waybillList[0].ActualFee, maxDeliveryFee, order, model.VendorIDDada); err != nil { return nil, err } - result, err = api.DadaAPI.ReaddOrder(billParams, addParams) + // result, err = api.DadaAPI.ReaddOrder(billParams, addParams) + result, err = api.DadaAPI.ReaddOrder2(billParams) } else { // 第一次创建 if err != nil { globals.SugarLogger.Warnf("CreateWaybill orderID:%s error:%v", order.VendorOrderID, err) } if false { - result, err = api.DadaAPI.AddOrder(billParams, addParams) + // result, err = api.DadaAPI.AddOrder(billParams, addParams) + result, err = api.DadaAPI.AddOrder2(billParams) } else { - if result, err = api.DadaAPI.QueryDeliverFee(billParams, addParams); err != nil { + // if result, err = api.DadaAPI.QueryDeliverFee(billParams, addParams); err != nil { + if result, err = api.DadaAPI.QueryDeliverFee2(billParams); err != nil { return nil, err } if err = delivery.CallCreateWaybillPolicy(jxutils.StandardPrice2Int(result.Fee), maxDeliveryFee, order, model.VendorIDDada); err != nil { @@ -363,3 +386,34 @@ func limitOrderWeight(weight int) int { } return weight } + +func (c *DeliveryHandler) ComplaintRider(bill *model.Waybill, resonID int, resonContent string) (err error) { + if globals.EnableStoreWrite { + err = api.DadaAPI.ComplaintRider(bill.VendorOrderID, resonID) + } + return err +} + +func (c *DeliveryHandler) GetWaybillTip(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID, vendorOrderID, vendorWaybillID, vendorWaybillID2 string) (tipFee int64, err error) { + order, err := api.DadaAPI.QueryOrderInfo2(vendorOrderID) + if err == nil { + tipFee = jxutils.StandardPrice2Int(order.Tips) + } + return tipFee, err +} + +func (c *DeliveryHandler) UpdateWaybillTip(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID, vendorOrderID, vendorWaybillID, vendorWaybillID2, cityCode string, tipFee int64) (err error) { + if globals.EnableStoreWrite { + err = api.DadaAPI.AddTip(vendorOrderID, jxutils.IntPrice2Standard(tipFee), cityCode, "") + } + return err +} + +func (c *DeliveryHandler) GetRidderPosition(ctx *jxcontext.Context, vendorOrgCode, vendorOrderID, vendorWaybillID, vendorWaybillID2 string) (lng, lat float64, err error) { + order, err := api.DadaAPI.QueryOrderInfo2(vendorOrderID) + if err == nil { + lng = utils.Str2Float64WithDefault(order.TransporterLng, 0) + lat = utils.Str2Float64WithDefault(order.TransporterLat, 0) + } + return lng, lat, err +} diff --git a/business/partner/delivery/dada/waybill_test.go b/business/partner/delivery/dada/waybill_test.go index d2b28e527..a7a680f69 100644 --- a/business/partner/delivery/dada/waybill_test.go +++ b/business/partner/delivery/dada/waybill_test.go @@ -5,6 +5,7 @@ import ( "time" _ "git.rosy.net.cn/jx-callback/business/jxcallback/orderman" + "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/testinit" @@ -18,15 +19,14 @@ func TestCreateWaybill(t *testing.T) { orderID := "817540316000041" if order, err := partner.CurOrderManager.LoadOrder(orderID, model.VendorIDJD); err == nil { // globals.SugarLogger.Debug(order) - c := new(DeliveryHandler) - _, err = c.CreateWaybill(order, nil) + _, err = CurDeliveryHandler.CreateWaybill(order, 0) if err == nil { time.Sleep(1 * time.Second) bill := &model.Waybill{ VendorOrderID: orderID, WaybillVendorID: model.VendorIDDada, } - err = c.CancelWaybill(bill, partner.CancelWaybillReasonOther, "") + err = CurDeliveryHandler.CancelWaybill(bill, partner.CancelWaybillReasonOther, "") if err != nil { t.Fatal(err.Error()) } @@ -37,3 +37,11 @@ func TestCreateWaybill(t *testing.T) { t.Fatal(err.Error()) } } + +func TestGetRidderPosition(t *testing.T) { + lng, lat, err := CurDeliveryHandler.GetRidderPosition(jxcontext.AdminCtx, "", "80704840263399812", "", "") + if err != nil { + t.Fatal(err) + } + t.Logf("lng:%f, lat:%f", lng, lat) +} diff --git a/business/partner/delivery/mtps/waybill.go b/business/partner/delivery/mtps/waybill.go index 25fca1ea7..20c18c817 100644 --- a/business/partner/delivery/mtps/waybill.go +++ b/business/partner/delivery/mtps/waybill.go @@ -8,6 +8,7 @@ import ( "git.rosy.net.cn/baseapi/platformapi/mtpsapi" "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" @@ -173,14 +174,18 @@ func (c *DeliveryHandler) CreateWaybill(order *model.GoodsOrder, maxDeliveryFee item.GoodCount += goodItem.GoodCount } } - addParams := map[string]interface{}{ - "note": utils.FilterMb4(order.BuyerComment), - "goods_detail": string(utils.MustMarshal(goods)), - "goods_pickup_info": fmt.Sprintf("%s第%d号单", model.VendorChineseNames[order.VendorID], order.OrderSeq), - "poi_seq": fmt.Sprintf("#%d", order.OrderSeq), - } + // addParams := map[string]interface{}{ + // "note": utils.FilterMb4(order.BuyerComment), + // "goods_detail": string(utils.MustMarshal(goods)), + // "goods_pickup_info": fmt.Sprintf("%s第%d号单", model.VendorChineseNames[order.VendorID], order.OrderSeq), + // "poi_seq": fmt.Sprintf("#%d", order.OrderSeq), + // } + billParams.Note = utils.FilterMb4(order.BuyerComment) + billParams.GoodsDetail = string(utils.MustMarshal(goods)) + billParams.GoodsPickupInfo = fmt.Sprintf("%s第%d号单", model.VendorChineseNames[order.VendorID], order.OrderSeq) + billParams.PoiSeq = fmt.Sprintf("#%d", order.OrderSeq) if globals.EnableStoreWrite { - result, err2 := api.MtpsAPI.CreateOrderByShop(billParams, addParams) + result, err2 := api.MtpsAPI.CreateOrderByShop2(billParams) if err = err2; err == nil { bill = &model.Waybill{ VendorOrderID: order.VendorOrderID, @@ -192,7 +197,7 @@ func (c *DeliveryHandler) CreateWaybill(order *model.GoodsOrder, maxDeliveryFee } delivery.OnWaybillCreated(bill) } else { - globals.SugarLogger.Debugf("CreateWaybill failed, orderID:%s, billParams:%v, addParams:%v, error:%v", order.VendorOrderID, billParams, addParams, err) + globals.SugarLogger.Debugf("CreateWaybill failed, orderID:%s, billParams:%v, error:%v", order.VendorOrderID, billParams, err) } } else { err = fmt.Errorf("测试环境不能真正创建运单") @@ -246,3 +251,19 @@ func limitOrderWeight(weight int) int { } return weight } + +func (c *DeliveryHandler) ComplaintRider(bill *model.Waybill, resonID int, resonContent string) (err error) { + if globals.EnableStoreWrite { + err = api.MtpsAPI.EvaluateRider(utils.Str2Int64(bill.VendorWaybillID2), bill.VendorWaybillID, 1, resonContent) + } + return err +} + +func (c *DeliveryHandler) GetRidderPosition(ctx *jxcontext.Context, vendorOrgCode, vendorOrderID, vendorWaybillID, vendorWaybillID2 string) (lng, lat float64, err error) { + intLng, intLat, err := api.MtpsAPI.RiderLocation(utils.Str2Int64(vendorWaybillID2), vendorWaybillID) + if err == nil { + lng = jxutils.IntCoordinate2Standard(intLng) + lat = jxutils.IntCoordinate2Standard(intLat) + } + return lng, lat, err +} diff --git a/business/partner/partner.go b/business/partner/partner.go index f9146c15d..990edfb9b 100644 --- a/business/partner/partner.go +++ b/business/partner/partner.go @@ -109,7 +109,7 @@ type IOrderManager interface { SaveOrderFinancialInfo(order *model.OrderFinancial, operation string) (err error) SaveAfsOrderFinancialInfo(afsOrder *model.AfsOrder) (err error) - GetOrderWaybillInfo(ctx *jxcontext.Context, vendorOrderID string, vendorID int, isNotEnded bool) (bills []*model.Waybill, err error) + GetOrderWaybillInfo(ctx *jxcontext.Context, vendorOrderID string, vendorID int, isNotEnded, isGetPos bool) (bills []*model.WaybillExt, err error) // afs order OnAfsOrderAdjust(afsOrder *model.AfsOrder, orderStatus *model.OrderStatus) (err error) @@ -156,10 +156,10 @@ type IMultipleStoresHandler interface { IPurchasePlatformHandler GetAllCategories(ctx *jxcontext.Context, vendorOrgCode string) (cats []*BareCategoryInfo, err error) - CreateCategory(db *dao.DaoDB, cat *model.SkuCategory, userName string) (err error) - UpdateCategory(db *dao.DaoDB, cat *model.SkuCategory, userName string) error - DeleteCategory(db *dao.DaoDB, cat *model.SkuCategory, userName string) error - ReorderCategories(db *dao.DaoDB, parentCatID int, userName string) (err error) + // CreateCategory(db *dao.DaoDB, cat *model.SkuCategory, userName string) (err error) + // UpdateCategory(db *dao.DaoDB, cat *model.SkuCategory, userName string) error + // DeleteCategory(db *dao.DaoDB, cat *model.SkuCategory, userName string) error + // ReorderCategories(db *dao.DaoDB, parentCatID int, userName string) (err error) CreateCategory2(ctx *jxcontext.Context, cat *dao.SkuStoreCatInfo) (err error) UpdateCategory2(ctx *jxcontext.Context, cat *dao.SkuStoreCatInfo) (err error) @@ -167,9 +167,9 @@ type IMultipleStoresHandler interface { ReorderCategories2(ctx *jxcontext.Context, vendorOrgCode, vendorParentCatID string, vendorCatIDList []string) (err error) // sku - CreateSku(db *dao.DaoDB, sku *model.Sku, userName string) (err error) - UpdateSku(db *dao.DaoDB, sku *model.Sku, userName string) (err error) - DeleteSku(db *dao.DaoDB, sku *model.Sku, userName string) (err error) + // CreateSku(db *dao.DaoDB, sku *model.Sku, userName string) (err error) + // UpdateSku(db *dao.DaoDB, sku *model.Sku, userName string) (err error) + // DeleteSku(db *dao.DaoDB, sku *model.Sku, userName string) (err error) // ReadSku(ctx *jxcontext.Context, vendorOrgCode, vendorSkuID string) (skuNameExt *model.SkuNameExt, err error) CreateSku2(ctx *jxcontext.Context, sku *dao.StoreSkuSyncInfo) (err error) @@ -277,3 +277,23 @@ func IsMultiStore(vendorID int) bool { } return false } + +func GetRidderPositionGetter(vendorID int) (handler IRidderPositionGetter) { + if handlerInfo := GetDeliveryPlatformFromVendorID(vendorID); handlerInfo != nil { + if handler, _ = handlerInfo.Handler.(IRidderPositionGetter); handler != nil { + return handler + } + } + handler, _ = GetPurchasePlatformFromVendorID(vendorID).(IRidderPositionGetter) + return handler +} + +func GetWaybillTipUpdater(vendorID int) (handler IAddWaybillTip) { + if handlerInfo := GetDeliveryPlatformFromVendorID(vendorID); handlerInfo != nil { + if handler, _ = handlerInfo.Handler.(IAddWaybillTip); handler != nil { + return handler + } + } + handler, _ = GetPurchasePlatformFromVendorID(vendorID).(IAddWaybillTip) + return handler +} diff --git a/business/partner/partner_delivery.go b/business/partner/partner_delivery.go index 3c3869413..36a45b563 100644 --- a/business/partner/partner_delivery.go +++ b/business/partner/partner_delivery.go @@ -38,6 +38,8 @@ type IDeliveryPlatformHandler interface { CreateWaybill(order *model.GoodsOrder, maxDeliveryFee int64) (bill *model.Waybill, err error) CancelWaybill(bill *model.Waybill, cancelReasonID int, cancelReason string) (err error) GetWaybillFee(order *model.GoodsOrder) (deliveryFeeInfo *WaybillFeeInfo, err error) + //投诉骑手 + ComplaintRider(bill *model.Waybill, resonID int, resonContent string) (err error) } type IDeliveryUpdateStoreHandler interface { diff --git a/business/partner/partner_order.go b/business/partner/partner_order.go index 42065ab7d..dace71dc7 100644 --- a/business/partner/partner_order.go +++ b/business/partner/partner_order.go @@ -13,6 +13,7 @@ type OrderPhoneNumberInfo struct { type IPurchasePlatformOrderHandler interface { Map2Order(orderData map[string]interface{}) (order *model.GoodsOrder) GetOrder(vendorOrgCode, vendorOrderID string) (order *model.GoodsOrder, err error) + GetOrderStatus(vendorOrgCode, vendorOrderID string) (status int, err error) GetStatusActionTimeout(order *model.GoodsOrder, statusType, status int) (params *StatusActionParams) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) @@ -57,6 +58,10 @@ type IPurchasePlatformOrderHandler interface { } type IAddWaybillTip interface { - GetWaybillTip(ctx *jxcontext.Context, order *model.GoodsOrder) (tipFee int64, err error) - AddWaybillTip(ctx *jxcontext.Context, order *model.GoodsOrder, tipFee2Add int64) (err error) + GetWaybillTip(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID, vendorOrderID, vendorWaybillID, vendorWaybillID2 string) (tipFee int64, err error) + UpdateWaybillTip(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID, vendorOrderID, vendorWaybillID, vendorWaybillID2, cityCode string, tipFee int64) (err error) +} + +type IRidderPositionGetter interface { + GetRidderPosition(ctx *jxcontext.Context, vendorOrgCode, vendorOrderID, vendorWaybillID, vendorWaybillID2 string) (lng, lat float64, err error) } diff --git a/business/partner/pay/pay.go b/business/partner/pay/pay.go new file mode 100644 index 000000000..246d86afa --- /dev/null +++ b/business/partner/pay/pay.go @@ -0,0 +1,51 @@ +package pay + +import ( + "time" + + "git.rosy.net.cn/jx-callback/business/jxutils/jxcontext" +) + +type PayOpStatus int + +const ( + OpStatusFailed PayOpStatus = 0 + OpStatusSuccessed PayOpStatus = 1 +) + +type CreatePayParam struct { + PayOrderID string + VendorPayType string + + VendorOrderID string + ProductDesc string + ProductDetail string + FeeType string + TotalFee int + TimeStart time.Time + TimeExpire time.Time + + UserData string +} + +type PayOpResult struct { + Status PayOpStatus + VendorStatus string + ErrMsg string + + ID string + VendorID string + + OriginalData string +} + +type ResponseHandler interface { + OnCreatePay(vendorID int, result *PayOpResult) (err error) + OnRefundPay(vendorID int, result *PayOpResult) (err error) +} + +type IPayPlatformHandler interface { + CreatePay(ctx *jxcontext.Context, param *CreatePayParam, isOffline bool) (prepayID, qrCodeURL string, err error) + ClosePay(ctx *jxcontext.Context, payOrderID, vendorPayOrderID string) (err error) + RefundPay(ctx *jxcontext.Context, payOrderID, vendorPayOrderID, refundID, reason string, totalFee, refundFee int) (vendorRefundID string, err error) +} diff --git a/business/partner/pay/wxpay/callback.go b/business/partner/pay/wxpay/callback.go new file mode 100644 index 000000000..e76447652 --- /dev/null +++ b/business/partner/pay/wxpay/callback.go @@ -0,0 +1,60 @@ +package wxpay + +import ( + "git.rosy.net.cn/baseapi/platformapi/wxpayapi" + "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/model" + "git.rosy.net.cn/jx-callback/business/partner/pay" + "git.rosy.net.cn/jx-callback/globals" +) + +func OnCallback(msg *wxpayapi.CallbackMsg) (err error) { + globals.SugarLogger.Debugf("wxpay OnCallback 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) { + opResult := &pay.PayOpResult{ + OriginalData: string(utils.MustMarshal(msg)), + } + if msg.ReturnCode == wxpayapi.ResponseCodeSuccess { + opResult.Status = pay.OpStatusSuccessed + opResult.ID = msg.OutTradeNo + if msg.ResultCode == wxpayapi.ResponseCodeSuccess { + opResult.VendorID = msg.TransactionID + } else { + opResult.VendorStatus = msg.ErrCode + opResult.ErrMsg = msg.ErrCodeDes + } + } else { + opResult.Status = pay.OpStatusFailed + } + err = payHandler.responseHandler.OnCreatePay(model.VendorIDWXPay, opResult) + return err +} + +func onWxpayRefund(msg *wxpayapi.RefundResultMsg) (err error) { + opResult := &pay.PayOpResult{ + OriginalData: string(utils.MustMarshal(msg)), + } + if msg.ReturnCode == wxpayapi.ResponseCodeSuccess { + opResult.Status = pay.OpStatusSuccessed + if msg.ResultCode == wxpayapi.ResponseCodeSuccess { + opResult.ID = msg.ReqInfoObj.OutRefundNo + opResult.VendorID = msg.ReqInfoObj.RefundID + } else { + opResult.VendorStatus = msg.ErrCode + opResult.ErrMsg = msg.ErrCodeDes + } + } else { + opResult.Status = pay.OpStatusFailed + } + err = payHandler.responseHandler.OnRefundPay(model.VendorIDWXPay, opResult) + return err +} diff --git a/business/partner/pay/wxpay/wxpay.go b/business/partner/pay/wxpay/wxpay.go new file mode 100644 index 000000000..ee161d7ed --- /dev/null +++ b/business/partner/pay/wxpay/wxpay.go @@ -0,0 +1,73 @@ +package wxpay + +import ( + "git.rosy.net.cn/baseapi/platformapi/wxpayapi" + "git.rosy.net.cn/jx-callback/business/auth2/authprovider/weixin" + "git.rosy.net.cn/jx-callback/business/jxutils/jxcontext" + "git.rosy.net.cn/jx-callback/business/partner/pay" + "git.rosy.net.cn/jx-callback/globals" + "git.rosy.net.cn/jx-callback/globals/api" +) + +type PayHandler struct { + responseHandler pay.ResponseHandler +} + +var ( + payHandler *PayHandler +) + +func New(responseHandler pay.ResponseHandler) (handler *PayHandler) { + return &PayHandler{ + responseHandler: responseHandler, + } +} + +func vendorPayType2WxpayType(vendorPayType string) string { + return vendorPayType +} + +func (p *PayHandler) CreatePay(ctx *jxcontext.Context, createParam *pay.CreatePayParam, isOffline bool) (prepayID, qrCodeURL string, err error) { + param := &wxpayapi.CreateOrderParam{ + OutTradeNo: createParam.PayOrderID, + Body: createParam.ProductDesc, + NotifyURL: globals.WxpayNotifyURL, + SpbillCreateIP: ctx.GetRealRemoteIP(), + TradeType: vendorPayType2WxpayType(createParam.VendorPayType), + TotalFee: createParam.TotalFee, + + TimeStart: wxpayapi.Time2PayTime(createParam.TimeStart), + TimeExpire: wxpayapi.Time2PayTime(createParam.TimeExpire), + } + if isOffline { + param.TradeType = wxpayapi.TradeTypeNative + } + if authInfo, err := ctx.GetV2AuthInfo(); err == nil && authInfo.GetAuthType() == weixin.AuthTypeMini { + param.OpenID = authInfo.GetAuthID() + } + if result, err := api.WxpayAPI.CreateUnifiedOrder(param); err == nil { + prepayID = result.PrepayID + qrCodeURL = result.CodeURL + } + return prepayID, qrCodeURL, err +} + +func (p *PayHandler) ClosePay(ctx *jxcontext.Context, payOrderID, vendorPayOrderID string) (err error) { + return api.WxpayAPI.CloseOrder(payOrderID) +} + +func (p *PayHandler) RefundPay(ctx *jxcontext.Context, payOrderID, vendorPayOrderID, refundID, reason string, totalFee, refundFee int) (vendorRefundID string, err error) { + param := &wxpayapi.PayRefundParam{ + OutTradeNo: payOrderID, + NotifyURL: globals.WxpayNotifyURL, + OutRefundNo: refundID, + TotalFee: totalFee, + RefundFee: refundFee, + RefundDesc: wxpayapi.CData(reason), + } + retVal, err := api.WxpayAPI.PayRefund(param) + if err == nil { + vendorRefundID = retVal.RefundID + } + return vendorRefundID, err +} diff --git a/business/partner/printer/feie/feie.go b/business/partner/printer/feie/feie.go index af0bc73b5..6333de9ad 100644 --- a/business/partner/printer/feie/feie.go +++ b/business/partner/printer/feie/feie.go @@ -57,11 +57,11 @@ func (c *PrinterHandler) getOrderContent(order *model.GoodsOrder, storeTel strin %s

-实际支付:%s

商品明细:
品名 数量 单价 小计
--------------------------------
` + // 实际支付:%s
orderParams := []interface{}{ globals.StoreName, utils.Time2Str(order.OrderCreatedAt), @@ -74,7 +74,7 @@ func (c *PrinterHandler) getOrderContent(order *model.GoodsOrder, storeTel strin order.ConsigneeMobile, order.ConsigneeAddress, order.BuyerComment, - jxutils.IntPrice2StandardCurrencyString(order.ActualPayPrice), + // jxutils.IntPrice2StandardCurrencyString(order.ActualPayPrice), } for _, sku := range order.Skus { @@ -131,11 +131,11 @@ func (c *PrinterHandler) getOrderContentBig(order *model.GoodsOrder, storeTel st %s

-实际支付:%s

商品明细:
品名数量单价小计
--------------------------------
` + // 实际支付:%s
orderParams := []interface{}{ globals.StoreName, utils.Time2Str(order.OrderCreatedAt), @@ -148,7 +148,7 @@ func (c *PrinterHandler) getOrderContentBig(order *model.GoodsOrder, storeTel st order.ConsigneeMobile, order.ConsigneeAddress, order.BuyerComment, - jxutils.IntPrice2StandardCurrencyString(order.ActualPayPrice), + // jxutils.IntPrice2StandardCurrencyString(order.ActualPayPrice), } for _, sku := range order.Skus { diff --git a/business/partner/printer/xiaowm/xiaowm.go b/business/partner/printer/xiaowm/xiaowm.go index 179c3828f..350ba923e 100644 --- a/business/partner/printer/xiaowm/xiaowm.go +++ b/business/partner/printer/xiaowm/xiaowm.go @@ -59,11 +59,11 @@ func (c *PrinterHandler) getOrderContent(order *model.GoodsOrder, storeTel strin * 客户备注: * %s* -实际支付: %s* 商品明细: * 品名 数量 单价 小计 --------------------------------* ` + // 实际支付: %s* orderParams := []interface{}{ globals.StoreName, utils.Time2Str(order.OrderCreatedAt), @@ -76,7 +76,7 @@ func (c *PrinterHandler) getOrderContent(order *model.GoodsOrder, storeTel strin order.ConsigneeMobile, order.ConsigneeAddress, buyerComment, - jxutils.IntPrice2StandardCurrencyString(order.ActualPayPrice), + // jxutils.IntPrice2StandardCurrencyString(order.ActualPayPrice), } for _, sku := range order.Skus { orderFmt += `%s*` @@ -128,17 +128,17 @@ func (c *PrinterHandler) getOrderContentBig(order *model.GoodsOrder, storeTel st %s\#%d* %s* ` + getCode + -`客户: %s* + `客户: %s* 电话: %s* 地址: %s* * 客户备注: * %s* -实际支付: %s* 商品明细: * 品名数量单价小计* --------------------------------* ` + // 实际支付: %s* orderParams := []interface{}{ globals.StoreName, utils.Time2Str(order.OrderCreatedAt), @@ -151,7 +151,7 @@ func (c *PrinterHandler) getOrderContentBig(order *model.GoodsOrder, storeTel st order.ConsigneeMobile, order.ConsigneeAddress, buyerComment, - jxutils.IntPrice2StandardCurrencyString(order.ActualPayPrice), + // jxutils.IntPrice2StandardCurrencyString(order.ActualPayPrice), } for _, sku := range order.Skus { orderFmt += `%s*` @@ -209,12 +209,12 @@ func (c *PrinterHandler) getOrderContent2(order *model.GoodsOrder, storeTel stri |5客户备注: |7%s |5 -|6实际支付: %s |5 |5商品明细: |5品名 数量 单价 小计 |5-------------------------------- ` + // |6实际支付: %s orderParams := []interface{}{ globals.StoreName, utils.Time2Str(order.OrderCreatedAt), @@ -227,7 +227,7 @@ func (c *PrinterHandler) getOrderContent2(order *model.GoodsOrder, storeTel stri order.ConsigneeMobile, order.ConsigneeAddress, buyerComment, - jxutils.IntPrice2StandardCurrencyString(order.ActualPayPrice), + // jxutils.IntPrice2StandardCurrencyString(order.ActualPayPrice), } for _, sku := range order.Skus { orderFmt += `|5%s` diff --git a/business/partner/printer/yilianyun/yilianyun.go b/business/partner/printer/yilianyun/yilianyun.go index 2f4009abd..1bb0a12f6 100644 --- a/business/partner/printer/yilianyun/yilianyun.go +++ b/business/partner/printer/yilianyun/yilianyun.go @@ -55,11 +55,11 @@ func (c *PrinterHandler) getOrderContent(order *model.GoodsOrder, storeTel strin 客户备注: \n %s\n \n -实际支付:%s\n \n 商品明细: \n 品名 数量 单价 小计\n --------------------------------\n` + // 实际支付:%s\n orderParams := []interface{}{ globals.StoreName, utils.Time2Str(order.OrderCreatedAt), @@ -72,7 +72,7 @@ func (c *PrinterHandler) getOrderContent(order *model.GoodsOrder, storeTel strin order.ConsigneeMobile, order.ConsigneeAddress, order.BuyerComment, - jxutils.IntPrice2StandardCurrencyString(order.ActualPayPrice), + // jxutils.IntPrice2StandardCurrencyString(order.ActualPayPrice), } for _, sku := range order.Skus { @@ -123,11 +123,11 @@ func (c *PrinterHandler) getOrderContentBig(order *model.GoodsOrder, storeTel st 客户备注: \n %s\n \n -实际支付:%s\n \n 商品明细: \n 品名数量单价小计\n --------------------------------\n` + // 实际支付:%s\n orderParams := []interface{}{ globals.StoreName, utils.Time2Str(order.OrderCreatedAt), @@ -140,7 +140,7 @@ func (c *PrinterHandler) getOrderContentBig(order *model.GoodsOrder, storeTel st order.ConsigneeMobile, order.ConsigneeAddress, order.BuyerComment, - jxutils.IntPrice2StandardCurrencyString(order.ActualPayPrice), + // jxutils.IntPrice2StandardCurrencyString(order.ActualPayPrice), } for _, sku := range order.Skus { diff --git a/business/partner/printer/zhongwu/zhongwu.go b/business/partner/printer/zhongwu/zhongwu.go index c434f0739..9db201d8e 100644 --- a/business/partner/printer/zhongwu/zhongwu.go +++ b/business/partner/printer/zhongwu/zhongwu.go @@ -56,11 +56,11 @@ func (c *PrinterHandler) getOrderContent(order *model.GoodsOrder, storeTel strin 客户备注: %s -实际支付:%s 商品明细: 品名 数量 单价 小计 ********************************` + // 实际支付:%s orderParams := []interface{}{ globals.StoreName, utils.Time2Str(order.OrderCreatedAt), @@ -73,7 +73,7 @@ func (c *PrinterHandler) getOrderContent(order *model.GoodsOrder, storeTel strin order.ConsigneeMobile, order.ConsigneeAddress, order.BuyerComment, - jxutils.IntPrice2StandardCurrencyString(order.ActualPayPrice), + // jxutils.IntPrice2StandardCurrencyString(order.ActualPayPrice), } for _, sku := range order.Skus { @@ -124,11 +124,11 @@ func (c *PrinterHandler) getOrderContentBig(order *model.GoodsOrder, storeTel st 客户备注: %s -实际支付:%s 商品明细: 品名数量单价小计 ********************************` + // 实际支付:%s orderParams := []interface{}{ globals.StoreName, utils.Time2Str(order.OrderCreatedAt), @@ -141,7 +141,7 @@ func (c *PrinterHandler) getOrderContentBig(order *model.GoodsOrder, storeTel st order.ConsigneeMobile, order.ConsigneeAddress, order.BuyerComment, - jxutils.IntPrice2StandardCurrencyString(order.ActualPayPrice), + // jxutils.IntPrice2StandardCurrencyString(order.ActualPayPrice), } for _, sku := range order.Skus { diff --git a/business/partner/purchase/ebai/callback.go b/business/partner/purchase/ebai/callback.go index b041d5165..fd7c41714 100644 --- a/business/partner/purchase/ebai/callback.go +++ b/business/partner/purchase/ebai/callback.go @@ -5,9 +5,11 @@ 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/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() { diff --git a/business/partner/purchase/ebai/order.go b/business/partner/purchase/ebai/order.go index 83f53d018..7f13d3ec8 100644 --- a/business/partner/purchase/ebai/order.go +++ b/business/partner/purchase/ebai/order.go @@ -28,8 +28,6 @@ const ( callDeliveryDelay = 10 * time.Minute callDeliveryDelayGap = 30 - fakeUserApplyCancel = "fake_user_apply_cancel" - fakeUserUndoApplyCancel = "fake_user_undo_apply_cancel" fakeAcceptOrder = "fake_accept_order" fakeOrderAdjustFinished = "fake_order_adjust_finished" fakeOrderCanceled = "fake_order_canceled" @@ -49,8 +47,6 @@ var ( ebaiapi.OrderStatusCanceled: model.OrderStatusCanceled, fakeOrderAdjustFinished: model.OrderStatusAdjust, - fakeUserApplyCancel: model.OrderStatusApplyCancel, - fakeUserUndoApplyCancel: model.OrderStatusUndoApplyCancel, fakeOrderCanceled: model.OrderStatusCanceled, } @@ -83,6 +79,14 @@ func (p *PurchaseHandler) GetOrder(vendorOrgCode, vendorOrderID string) (order * 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) { result, err := api.EbaiAPI.OrderGet(vendorOrderID) if err == nil { @@ -202,6 +206,7 @@ func (p *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *mo OrderCreatedAt: getTimeFromInterface(orderMap["create_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"]))), @@ -404,7 +409,7 @@ func (p *PurchaseHandler) SelfDeliverDelivered(order *model.GoodsOrder, userName // func (c *PurchaseHandler) onOrderMsg(msg *ebaiapi.CallbackMsg) (retVal *ebaiapi.CallbackResponse) { if c.isAfsMsg(msg) { - retVal = c.OnAfsOrderMsg(msg) + retVal = c.onAfsOrderMsg(msg) } else { status := c.callbackMsg2Status(msg) if partner.CurOrderManager.GetStatusDuplicatedCount(status) > 0 { @@ -424,7 +429,7 @@ func (c *PurchaseHandler) onOrderMsg(msg *ebaiapi.CallbackMsg) (retVal *ebaiapi. // 处理饿百降级订单的情况 // 是否降级;1:是,0:否;极少数订单因网络或信息交互异常,导致订单部分字段(如订单金额)生成延迟,此时订单会被标记为“已降级”状态,需开发者重新调用查看订单详情接口获取完整订单数据。 // toto sku是否也需要处理? - if status.Status == model.OrderStatusFinished { + 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 { @@ -478,11 +483,15 @@ func (c *PurchaseHandler) callbackMsg2Status(msg *ebaiapi.CallbackMsg) (orderSta if cancelType == ebaiapi.OrderUserCancelTypeBeforeSale { if msgType == ebaiapi.OrderUserCancelApply || msgType == ebaiapi.OrderUserCancelCSIntervene { - orderStatus.VendorStatus = fakeUserApplyCancel - } else if msgType == ebaiapi.OrderUserCancelInvalid || - msgType == ebaiapi.OrderUserCancelMerchantRefused || - msgType == ebaiapi.OrderUserCancelCSRefused { - orderStatus.VendorStatus = fakeUserUndoApplyCancel + 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 { @@ -500,7 +509,9 @@ func (c *PurchaseHandler) callbackMsg2Status(msg *ebaiapi.CallbackMsg) (orderSta } orderStatus.Remark = utils.Interface2String(msg.Body["reason"]) } - orderStatus.Status = c.getStatusFromVendorStatus(orderStatus.VendorStatus) + if orderStatus.Status == 0 { + orderStatus.Status = c.getStatusFromVendorStatus(orderStatus.VendorStatus) + } return orderStatus } @@ -649,3 +660,20 @@ func (c *PurchaseHandler) ListOrders(ctx *jxcontext.Context, vendorOrgCode strin } 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) + } + return err +} diff --git a/business/partner/purchase/ebai/order_afs.go b/business/partner/purchase/ebai/order_afs.go index fac74a1ea..d06c917a0 100644 --- a/business/partner/purchase/ebai/order_afs.go +++ b/business/partner/purchase/ebai/order_afs.go @@ -102,7 +102,7 @@ func (c *PurchaseHandler) onAfsOrderMsg(msg *ebaiapi.CallbackMsg) (retVal *ebaia afsOrder.Skus = append(afsOrder.Skus, orderSku) } } else if msg.Cmd == ebaiapi.CmdOrderUserCancel { - if afsOrder := c.createAfsOrder(msg); afsOrder != nil { + 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) diff --git a/business/partner/purchase/ebai/store.go b/business/partner/purchase/ebai/store.go index 31022b65e..3d36ed191 100644 --- a/business/partner/purchase/ebai/store.go +++ b/business/partner/purchase/ebai/store.go @@ -30,9 +30,10 @@ type tEbaiStoreInfo struct { EbaiStoreStatus int SyncStatus int - ProvinceID int `orm:"column(province_id)"` - CityID int `orm:"column(city_id)"` - DistrictID int `orm:"column(district_id)"` + 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) { @@ -156,7 +157,7 @@ func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName strin 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 + 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 = ? @@ -193,6 +194,9 @@ func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName strin } params := genStoreMapFromStore(store) if err = api.EbaiAPI.ShopUpdate(params); err == nil { + if store.PromoteInfo != "" { + err = api.EbaiAPI.ShopAnnouncementSet("", utils.Str2Int64(store.VendorStoreID), store.PromoteInfo) + } } } } @@ -389,8 +393,12 @@ func genStoreMapFromStore(store *tEbaiStoreInfo) map[string]interface{} { if store.VendorStoreID != "" { params["baidu_shop_id"] = store.VendorStoreID } - if store.SyncStatus&(model.SyncFlagNewMask /*|model.SyncFlagStoreName*/) != 0 { - params["name"] = jxutils.ComposeStoreName(store.Name, model.VendorIDEBAI) + if store.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagStoreName) != 0 { + if store.VendorStoreName != "" { + params["name"] = store.VendorStoreName + } else { + params["name"] = jxutils.ComposeStoreName(store.Name, model.VendorIDEBAI) + } } params["address"] = store.Address // todo 饿百 开店审核通过后不允许修改商户信息 diff --git a/business/partner/purchase/ebai/store_sku2.go b/business/partner/purchase/ebai/store_sku2.go index f11d4d038..1ce4b10c2 100644 --- a/business/partner/purchase/ebai/store_sku2.go +++ b/business/partner/purchase/ebai/store_sku2.go @@ -113,7 +113,7 @@ 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) (failedList []*partner.StoreSkuInfoWithErr, err error) { +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) params := genSkuParamsFromStoreSkuInfo2(storeSku, false) @@ -122,13 +122,19 @@ func (p *PurchaseHandler) UpdateStoreSkus(ctx *jxcontext.Context, storeID int, v if err != nil { failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorIDEBAI, "更新商品基础信息") } - utils.CallFuncAsync(func() { - api.EbaiAPI.SkuShopCategoryMap(strStoreID, utils.Str2Int64(storeSku.VendorSkuID), "", utils.Str2Int64(storeSku.VendorCatID), genSkuCatRank(storeSku)) - }) + if isNeedMapCat { + utils.CallFuncAsync(func() { + api.EbaiAPI.SkuShopCategoryMap(strStoreID, utils.Str2Int64(storeSku.VendorSkuID), "", utils.Str2Int64(storeSku.VendorCatID), genSkuCatRank(storeSku)) + }) + } } 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] @@ -139,6 +145,9 @@ func (p *PurchaseHandler) CreateStoreSkus(ctx *jxcontext.Context, storeID int, v if vendorSkuID, err = api.EbaiAPI.SkuCreate(ctx.GetTrackInfo(), strStoreID, storeSku.SkuID, params); err == nil { utils.AfterFuncWithRecover(5*time.Second, func() { api.EbaiAPI.SkuShopCategoryMap(strStoreID, vendorSkuID, "", utils.Str2Int64(storeSku.VendorCatID), genSkuCatRank(storeSku)) + // 饿百平台有BUG,会导致新建一个之前删除的商品时,信息不会及时更新,强制刷新一下 + // 比如门店:100887, skuID:33805,订单:1577176719141226065 + p.updateStoreSkus(ctx, storeID, vendorStoreID, storeSkuList, false) }) } else { failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorIDEBAI, "创建商品") @@ -321,7 +330,7 @@ func jxCatSeq2Ebai(seq int) int { } func formatCatName(name string) string { - return name + 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) { diff --git a/business/partner/purchase/elm/order.go b/business/partner/purchase/elm/order.go index 41f2130a5..4d94b4600 100644 --- a/business/partner/purchase/elm/order.go +++ b/business/partner/purchase/elm/order.go @@ -120,7 +120,7 @@ func (c *PurchaseHandler) onOrderCancelRefundMsg(msg *elmapi.CallbackOrderCancel default: status.Status = model.OrderStatusUnknown } - return elmapi.Err2CallbackResponse(partner.CurOrderManager.OnOrderStatusChanged(status), status.VendorStatus) + return elmapi.Err2CallbackResponse(partner.CurOrderManager.OnOrderStatusChanged("", status), status.VendorStatus) } func (c *PurchaseHandler) GetOrder(vendorOrgCode, orderID string) (order *model.GoodsOrder, err error) { @@ -223,7 +223,7 @@ func (c *PurchaseHandler) onOrderUserUrgeOrder(msg *elmapi.CallbackOrderUrgeMsg) StatusTime: utils.Timestamp2Time(msg.UpdateTime), } c.ClientUrgeOrder(msg.OrderID) - return elmapi.Err2CallbackResponse(partner.CurOrderManager.OnOrderStatusChanged(status), status.VendorStatus) + return elmapi.Err2CallbackResponse(partner.CurOrderManager.OnOrderStatusChanged("", status), status.VendorStatus) } func (c *PurchaseHandler) stateAndType2Str(state string, msgType int) string { diff --git a/business/partner/purchase/jd/act.go b/business/partner/purchase/jd/act.go index 613ce32d2..450f469e6 100644 --- a/business/partner/purchase/jd/act.go +++ b/business/partner/purchase/jd/act.go @@ -325,7 +325,7 @@ func (c *PurchaseHandler) onActMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.C 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) + act, actStoreSkuList, err := getActFromJD(AppKey2OrgCode(msg.AppKey), promotionID) if err == nil && len(actStoreSkuList) > 0 { _, err = partner.CurActManager.CreateActFromVendor(jxcontext.AdminCtx, act, actStoreSkuList) } diff --git a/business/partner/purchase/jd/callback.go b/business/partner/purchase/jd/callback.go index 9a4b0bf16..3e542426e 100644 --- a/business/partner/purchase/jd/callback.go +++ b/business/partner/purchase/jd/callback.go @@ -6,21 +6,21 @@ import ( func OnOrderMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) { if CurPurchaseHandler != nil { - retVal = CurPurchaseHandler.OnOrderMsg(appKey2OrgCode(msg.AppKey), msg) + 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) + 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) + retVal = CurPurchaseHandler.OnStoreMsg(AppKey2OrgCode(msg.AppKey), msg) } return retVal } diff --git a/business/partner/purchase/jd/financial.go b/business/partner/purchase/jd/financial.go index 45037f159..080ea5bd6 100644 --- a/business/partner/purchase/jd/financial.go +++ b/business/partner/purchase/jd/financial.go @@ -18,7 +18,7 @@ func (p *PurchaseHandler) OnFinancialMsg(msg *jdapi.CallbackOrderMsg) (retVal *j // 京东正向/退款订单类型处理--存储 func (p *PurchaseHandler) onFinancialMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) { var err error - a := GetAPIByAppKey(msg.AppKey) + 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) diff --git a/business/partner/purchase/jd/jd.go b/business/partner/purchase/jd/jd.go index 33f85cc61..c463e2f95 100644 --- a/business/partner/purchase/jd/jd.go +++ b/business/partner/purchase/jd/jd.go @@ -23,6 +23,9 @@ func init() { } 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) } @@ -30,7 +33,7 @@ func GetAPI(appOrgCode string) (apiObj *jdapi.API) { return getAPI(appOrgCode) } -func appKey2OrgCode(appKey string) (vendorOrgCode string) { +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) @@ -39,23 +42,10 @@ func appKey2OrgCode(appKey string) (vendorOrgCode string) { break } } - return vendorOrgCode -} - -func GetAPIByAppKey(appKey string) (apiObj *jdapi.API) { - if appKey == "" { - apiObj = getAPI("") - } else { - apiList := partner.CurAPIManager.GetAppOrgCodeList(model.VendorIDJD) - for _, v := range apiList { - jdAPI := partner.CurAPIManager.GetAPI(model.VendorIDJD, v).(*jdapi.API) - if jdAPI.GetAppKey() == appKey { - apiObj = jdAPI - break - } - } + if vendorOrgCode == "" { + globals.SugarLogger.Warnf("AppKey2OrgCode appKey:%s get empty vendorOrgCode", appKey) } - return apiObj + return vendorOrgCode } func (c *PurchaseHandler) GetVendorID() int { diff --git a/business/partner/purchase/jd/order.go b/business/partner/purchase/jd/order.go index dc658c7a9..2f307f2ba 100644 --- a/business/partner/purchase/jd/order.go +++ b/business/partner/purchase/jd/order.go @@ -27,13 +27,17 @@ var ( jdapi.OrderStatusFinishedPickup: model.OrderStatusFinishedPickup, jdapi.OrderStatusDelivering: model.OrderStatusDelivering, jdapi.OrderStatusDelivered: model.OrderStatusFinished, - // jdapi.OrderStatusFinished: model.OrderStatusFinished, // todo 这个状态不是真正都完成的意思 - jdapi.OrderStatusCanceled: model.OrderStatusCanceled, + 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, @@ -93,9 +97,6 @@ func (c *PurchaseHandler) onOrderMsg(vendorOrgCode string, msg *jdapi.CallbackOr }) } err := partner.CurOrderManager.OnOrderStatusChanged(vendorOrgCode, status) - // if globals.HandleLegacyJxOrder && err == nil { - // c.legacyJdOrderStatusChanged(status) - // } retVal = jdapi.Err2CallbackResponse(err, status.VendorStatus) } } @@ -147,6 +148,14 @@ func (c *PurchaseHandler) GetOrder(vendorOrgCode, orderID string) (order *model. return order, err } +func (p *PurchaseHandler) GetOrderStatus(vendorOrgCode, vendorOrderID string) (status int, err error) { + order, err := getAPI(vendorOrgCode).QuerySingleOrder2(vendorOrderID) + if err == nil { + status = p.getStatusFromVendorStatus(utils.Int2Str(order.OrderStatus)) + } + return status, err +} + func (c *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *model.GoodsOrder) { result := orderData orderID := utils.Int64ToStr(utils.MustInterface2Int64(result["orderId"])) @@ -177,6 +186,7 @@ func (c *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *mo OrderCreatedAt: utils.Str2Time(result[statusTimeField].(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"]), @@ -277,19 +287,24 @@ func (c *PurchaseHandler) callbackMsg2Status(msg *jdapi.CallbackOrderMsg) *model RefVendorOrderID: msg.BillID, RefVendorID: model.VendorIDJD, VendorStatus: msg.StatusID, - Status: c.getStatusFromVendorStatus(msg.StatusID), StatusTime: utils.Str2Time(msg.Timestamp), Remark: msg.Remark, } + if msg.MsgURL == jdapi.CallbackMsgOrderAddTips { + orderStatus.VendorStatus = jdapi.CallbackMsgOrderAddTips + } + orderStatus.Status = c.getStatusFromVendorStatus(orderStatus.VendorStatus) return orderStatus } -func (c *PurchaseHandler) postFakeMsg(vendorOrderID, vendorStatus string) { +func (c *PurchaseHandler) postFakeMsg(vendorOrgCode, vendorOrderID, vendorStatus string) { msg := &jdapi.CallbackOrderMsg{ - CallbackMsg: &jdapi.CallbackMsg{}, - BillID: vendorOrderID, - StatusID: vendorStatus, - Timestamp: utils.Time2Str(time.Now()), + CallbackMsg: &jdapi.CallbackMsg{ + AppKey: getAPI(vendorOrgCode).GetAppKey(), + }, + BillID: vendorOrderID, + StatusID: vendorStatus, + Timestamp: utils.Time2Str(time.Now()), } utils.CallFuncAsync(func() { OnOrderMsg(msg) @@ -309,14 +324,14 @@ func (c *PurchaseHandler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptI if globals.EnableJdStoreWrite { err = getAPI(order.VendorOrgCode).OrderAcceptOperate(order.VendorOrderID, isAcceptIt, userName) if isAcceptIt && err == nil { - c.postFakeMsg(order.VendorOrderID, jdapi.StatusIDWaitOutStore) + c.postFakeMsg(order.VendorOrgCode, order.VendorOrderID, jdapi.StatusIDWaitOutStore) } } else { if isAcceptIt { - c.postFakeMsg(order.VendorOrderID, jdapi.StatusIDWaitOutStore) + c.postFakeMsg(order.VendorOrgCode, order.VendorOrderID, jdapi.StatusIDWaitOutStore) } else { - c.postFakeMsg(order.VendorOrderID, jdapi.OrderStatusCanceled) + c.postFakeMsg(order.VendorOrgCode, order.VendorOrderID, jdapi.OrderStatusCanceled) } } return err @@ -327,7 +342,7 @@ func (c *PurchaseHandler) PickupGoods(order *model.GoodsOrder, isSelfDelivery bo if !isSelfDelivery && globals.EnableJdStoreWrite { _, err = getAPI(order.VendorOrgCode).OrderJDZBDelivery(order.VendorOrderID, userName) } else { - c.postFakeMsg(order.VendorOrderID, jdapi.OrderStatusFinishedPickup) + c.postFakeMsg(order.VendorOrgCode, order.VendorOrderID, jdapi.OrderStatusFinishedPickup) } return err } @@ -426,11 +441,18 @@ func (c *PurchaseHandler) CancelOrder(ctx *jxcontext.Context, order *model.Goods 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 { - oaosAdjustDTOList = append(oaosAdjustDTOList, &jdapi.OAOSAdjustDTO{ - OutSkuID: utils.Int2Str(jxutils.GetSkuIDFromOrderSku(sku)), - SkuCount: sku.Count, - }) + 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) @@ -462,31 +484,22 @@ func (c *PurchaseHandler) ListOrders(ctx *jxcontext.Context, vendorOrgCode strin return vendorOrderIDs, err } -func (c *PurchaseHandler) UpdateWaybillTip(ctx *jxcontext.Context, order *model.GoodsOrder, tipFee int64) (err error) { - a := getAPI(order.VendorOrgCode) - orderInfo, err := a.QuerySingleOrder2(order.VendorOrderID) - if err == nil { - tip2Add := int(tipFee) - orderInfo.Tips - if tip2Add != 0 { - if globals.EnableJdStoreWrite { - err = a.OrderAddTips(order.VendorOrderID, tip2Add, ctx.GetUserName()) - } - } - } - return err -} - -func (c *PurchaseHandler) GetWaybillTip(ctx *jxcontext.Context, order *model.GoodsOrder) (tipFee int64, err error) { - orderInfo, err := getAPI(order.VendorOrgCode).QuerySingleOrder2(order.VendorOrderID) +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) AddWaybillTip(ctx *jxcontext.Context, order *model.GoodsOrder, tipFee2Add int64) (err error) { - if globals.EnableJdStoreWrite { - err = getAPI(order.VendorOrgCode).OrderAddTips(order.VendorOrderID, int(tipFee2Add), ctx.GetUserName()) +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 } diff --git a/business/partner/purchase/jd/order_test.go b/business/partner/purchase/jd/order_test.go index 5703907bf..34aa07ea9 100644 --- a/business/partner/purchase/jd/order_test.go +++ b/business/partner/purchase/jd/order_test.go @@ -32,6 +32,14 @@ func TestGetOrder(t *testing.T) { } } +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 { diff --git a/business/partner/purchase/jd/sku.go b/business/partner/purchase/jd/sku.go index 214aea54b..5643a4c7b 100644 --- a/business/partner/purchase/jd/sku.go +++ b/business/partner/purchase/jd/sku.go @@ -2,491 +2,479 @@ package jd // 这里函数取得的信息,除了与自身实体相关的ID(比如PARENT ID),都已经转换成了本地ID了 -import ( - "fmt" - "unicode/utf8" +// 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"` +// } - "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/model/dao" - "git.rosy.net.cn/jx-callback/globals" -) +// var ( +// skuAddParamsKeyMap = map[string]int{ +// jdapi.KeyUpcCode: 1, +// } +// ) -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"` -} +// 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 +// } -var ( - skuAddParamsKeyMap = map[string]int{ - jdapi.KeyUpcCode: 1, - } -) +// 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) 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) DeleteCategory(db *dao.DaoDB, cat *model.SkuCategory, userName string) error { +// if globals.EnableJdStoreWrite { +// return getAPI("").DelShopCategory(cat.JdID) +// } +// return nil +// } -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) 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) 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(`一张图片`, 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, -// }) +// 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 { -// 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)) +// 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{}{} -// 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 +// 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(`一张图片`, 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 // } // } -// sellCities := sku.SellCities -// for _, v := range sellCities { -// if v == 0 { -// skuNameExt.IsGlobal = 1 +// } +// } +// 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 +// } // } -// } -// 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 +// 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 { -// err = partner.ErrCanNotFindItem +// } 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)) +// } // } // } -// 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" +// 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) // } -// 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) +// } 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 rootTask.ID, err +// return vendorSkuID, 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 -} +// 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 +// } diff --git a/business/partner/purchase/jd/sku2.go b/business/partner/purchase/jd/sku2.go index 5529bb772..147525810 100644 --- a/business/partner/purchase/jd/sku2.go +++ b/business/partner/purchase/jd/sku2.go @@ -12,6 +12,7 @@ import ( "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" ) @@ -113,7 +114,7 @@ func (p *PurchaseHandler) ReorderCategories2(ctx *jxcontext.Context, vendorOrgCo func (p *PurchaseHandler) getVendorCategories(level int, pid int64) (vendorCats []*model.SkuVendorCategory, err error) { // 得到平台的分类,不需要指定分账号 - cats, err := getAPI("").QueryChildCategoriesForOP(pid) + cats, err := api.Jd2API.QueryChildCategoriesForOP(pid) if err != nil { return nil, err } @@ -169,6 +170,10 @@ func skuInfo2Param(ctx *jxcontext.Context, sku *dao.StoreSkuSyncInfo) (param *jd 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) } @@ -200,6 +205,23 @@ func (p *PurchaseHandler) UpdateSku2(ctx *jxcontext.Context, sku *dao.StoreSkuSy 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), @@ -357,3 +379,101 @@ func jxStatus2jdStatus(jxStatus int) (jdStatus int) { } 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, + } +) diff --git a/business/partner/purchase/jd/sku_test.go b/business/partner/purchase/jd/sku_test.go index 26a23090e..d3ced1fdd 100644 --- a/business/partner/purchase/jd/sku_test.go +++ b/business/partner/purchase/jd/sku_test.go @@ -23,20 +23,6 @@ func TestCreateSku(t *testing.T) { // } } -func TestUpdateSku(t *testing.T) { - // t.Log(beego.BConfig.RunMode) - db := dao.GetDB() - skuID := 21741 - sku := &model.Sku{} - sku.ID = skuID - dao.GetEntity(db, sku) - - err := CurPurchaseHandler.UpdateSku(db, sku, "autotest") - if err != nil { - t.Fatal(err.Error()) - } -} - func TestGetAllCategories(t *testing.T) { result, err := CurPurchaseHandler.GetAllCategories(jxcontext.AdminCtx, "") if err != nil || len(result) == 0 { diff --git a/business/partner/purchase/jd/store.go b/business/partner/purchase/jd/store.go index fc88d91cd..40c97678b 100644 --- a/business/partner/purchase/jd/store.go +++ b/business/partner/purchase/jd/store.go @@ -36,6 +36,7 @@ type tJdStoreInfo struct { VendorStoreID string `orm:"column(vendor_store_id)"` RealLastOperator string SyncStatus int + VendorStoreName string } var ( @@ -123,7 +124,7 @@ func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName strin 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.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 @@ -146,7 +147,11 @@ func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName strin storeParams.OutSystemID = store.VendorStoreID } if store.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagStoreName) != 0 { - storeParams.StationName = jxutils.ComposeStoreName(store.Name, model.VendorIDJD) + if store.VendorStoreName != "" { + storeParams.StationName = store.VendorStoreName + } else { + storeParams.StationName = jxutils.ComposeStoreName(store.Name, model.VendorIDJD) + } } if store.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagStoreAddress) != 0 { storeParams.StationAddress = store.Address @@ -170,7 +175,7 @@ func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName strin 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 diff --git a/business/partner/purchase/jd/waybill.go b/business/partner/purchase/jd/waybill.go index 521c2a2c9..4b1068f0f 100644 --- a/business/partner/purchase/jd/waybill.go +++ b/business/partner/purchase/jd/waybill.go @@ -64,7 +64,7 @@ func (c *PurchaseHandler) callbackMsg2Waybill(msg *jdapi.CallbackDeliveryStatusM StatusTime: utils.Str2Time(msg.DeliveryStatusTime), Remark: msg.Remark, - VendorOrgCode: appKey2OrgCode(msg.AppKey), + VendorOrgCode: AppKey2OrgCode(msg.AppKey), } return retVal } diff --git a/business/partner/purchase/jx/localjx/order.go b/business/partner/purchase/jx/localjx/order.go index 640ec7d39..7d254f68d 100644 --- a/business/partner/purchase/jx/localjx/order.go +++ b/business/partner/purchase/jx/localjx/order.go @@ -152,13 +152,30 @@ func CreateOrder(ctx *jxcontext.Context, jxOrder *JxOrderInfo, addressID int64, outJxOrder.OrderID = GenOrderNo(ctx) order, err2 := jxOrder2GoodsOrder(ctx, outJxOrder, deliveryAddress) if err = err2; err == nil { - order.Status = model.OrderStatusCreated + order.Status = model.OrderStatusWait4Pay callNewOrder(order) } } return outJxOrder, err } +// 买家取消(或申请取消)订单 +func BuyerCancelOrder(ctx *jxcontext.Context, orderID int64) (canceled bool, err error) { + order, err := partner.CurOrderManager.LoadOrder(utils.Int64ToStr(orderID), model.VendorIDJX) + if err == nil { + if order.Status < model.OrderStatusNew { + order.Status = model.OrderStatusCanceled + order.VendorStatus = utils.Int2Str(model.OrderStatusCanceled) + if err = partner.CurOrderManager.UpdateOrderFields(order, []string{model.FieldStatus, "VendorStatus"}); err == nil { + canceled = true + } + } else { + err = changeOrderStatus(utils.Int64ToStr(orderID), model.OrderStatusApplyCancel, fmt.Sprintf("用户%s主动取消", ctx.GetUserName())) + } + } + return canceled, err +} + func Pay4Order(ctx *jxcontext.Context, orderID int64, payType int, vendorPayType string) (orderPay *model.OrderPay, err error) { order, err := partner.CurOrderManager.LoadOrder(utils.Int64ToStr(orderID), model.VendorIDJX) if err == nil { @@ -255,6 +272,10 @@ func GenOrderNo(ctx *jxcontext.Context) (orderNo int64) { return orderNo } +func GenPayOrderID(order *model.GoodsOrder) (payOrderID int64) { + return utils.Str2Int64(order.VendorOrderID) +} + func GenRefundID(order *model.GoodsOrder) (refundID int64) { const suffix = 100000 refundID = utils.Str2Int64(order.VendorOrderID) * suffix @@ -385,7 +406,7 @@ func generateOrder(ctx *jxcontext.Context, jxOrder *JxOrderInfo, addressID int64 Count: v.Count, SalePrice: int64(storeSkuBind.JxPrice), // todo 考虑活动价 Weight: sku.Weight, - Name: jxutils.ComposeSkuName(sku.Prefix, sku.Name, sku.Comment, sku.Unit, sku.SpecQuality, sku.SpecUnit, 0), + Name: jxutils.ComposeSkuName(sku.Prefix, sku.Name, sku.Comment, sku.Unit, sku.SpecQuality, sku.SpecUnit, 0, sku.ExPrefix, sku.ExPrefixBegin, sku.ExPrefixEnd), } if storeSkuBind.ActPrice != 0 && storeSkuBind.ActPrice < storeSkuBind.JxPrice { jxSku.SalePrice = int64(storeSkuBind.ActPrice) @@ -490,6 +511,10 @@ func AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName stri return changeOrderStatus(order.VendorOrderID, status, "") } +func AdjustOrder(ctx *jxcontext.Context, order *model.GoodsOrder, removedSkuList []*model.OrderSku, reason string) (err error) { + return err +} + func PickupGoods(order *model.GoodsOrder, isSelfDelivery bool, userName string) (err error) { return changeOrderStatus(order.VendorOrderID, model.OrderStatusFinishedPickup, "") } @@ -510,8 +535,9 @@ func CancelOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) errList := errlist.New() for _, orderPay := range payList { if orderPay.Status == model.PayStatusYes { - refundID := utils.Int64ToStr(GenRefundID(order)) - orderPayRefund, err2 := refundOrderByWX(ctx, orderPay, refundID) + // refundID := utils.Int64ToStr(GenRefundID(order)) + refundID := order.VendorOrderID + orderPayRefund, err2 := refundOrderByWX(ctx, orderPay, refundID, orderPay.TotalFee, reason) if err2 == nil { dao.WrapAddIDCULDEntity(orderPayRefund, ctx.GetUserName()) errList.AddErr(dao.CreateEntity(dao.GetDB(), orderPayRefund)) @@ -535,6 +561,15 @@ func CancelOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) return err } +func AgreeOrRefuseCancel(ctx *jxcontext.Context, order *model.GoodsOrder, isAgree bool, reason string) (err error) { + if isAgree { + err = CancelOrder(ctx, order, reason) + } else { + err = changeOrderStatus(order.VendorOrderID, model.OrderStatusVendorRejectCancel, reason) + } + return err +} + // todo 消息用异步可能导致丢失,单同步又有重入相关的问题 func callNewOrder(order *model.GoodsOrder) (err error) { jxutils.CallMsgHandlerAsync(func() { diff --git a/business/partner/purchase/jx/localjx/wxpay.go b/business/partner/purchase/jx/localjx/wxpay.go index 62d71fad7..453533def 100644 --- a/business/partner/purchase/jx/localjx/wxpay.go +++ b/business/partner/purchase/jx/localjx/wxpay.go @@ -4,7 +4,7 @@ import ( "fmt" "time" - "git.rosy.net.cn/baseapi/platformapi/wxpay" + "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" @@ -25,16 +25,16 @@ func getOrderBrief(order *model.GoodsOrder) string { func pay4OrderByWX(ctx *jxcontext.Context, order *model.GoodsOrder, vendorPayType string) (orderPay *model.OrderPay, err error) { payCreatedAt := time.Now() - param := &wxpay.CreateOrderParam{ + param := &wxpayapi.CreateOrderParam{ + OutTradeNo: utils.Int64ToStr(GenPayOrderID(order)), Body: getOrderBrief(order), NotifyURL: globals.WxpayNotifyURL, - OutTradeNo: order.VendorOrderID, SpbillCreateIP: ctx.GetRealRemoteIP(), TradeType: vendorPayType2WxpayType(vendorPayType), TotalFee: int(order.ActualPayPrice), - TimeStart: wxpay.Time2PayTime(payCreatedAt), - // TimeExpire: wxpay.Time2PayTime(payCreatedAt.Add(PayWaitingTime)), + TimeStart: wxpayapi.Time2PayTime(payCreatedAt), + // TimeExpire: wxpayapi.Time2PayTime(payCreatedAt.Add(PayWaitingTime)), } if authInfo, err := ctx.GetV2AuthInfo(); err == nil && authInfo.GetAuthType() == weixin.AuthTypeMini { param.OpenID = authInfo.GetAuthID() @@ -42,10 +42,12 @@ func pay4OrderByWX(ctx *jxcontext.Context, order *model.GoodsOrder, vendorPayTyp result, err := api.WxpayAPI.CreateUnifiedOrder(param) if err == nil { orderPay = &model.OrderPay{ - VendorOrderID: order.VendorOrderID, - VendorID: order.VendorID, + PayOrderID: param.OutTradeNo, PayType: model.PayTypeWX, VendorPayType: vendorPayType, + + VendorOrderID: order.VendorOrderID, + VendorID: order.VendorID, Status: 0, PayCreatedAt: payCreatedAt, PrepayID: result.PrepayID, @@ -56,37 +58,35 @@ func pay4OrderByWX(ctx *jxcontext.Context, order *model.GoodsOrder, vendorPayTyp return orderPay, err } -func OnWxPayCallback(msg *wxpay.CallbackMsg) (err error) { +func OnWxPayCallback(msg *wxpayapi.CallbackMsg) (err error) { globals.SugarLogger.Debugf("OnWxPayCallback msg:%s", utils.Format4Output(msg, true)) switch msg.MsgType { - case wxpay.MsgTypePay: - err = onWxpayFinished(msg.Data.(*wxpay.PayResultMsg)) - case wxpay.MsgTypeRefund: - err = onWxpayRefund(msg.Data.(*wxpay.RefundResultMsg)) + case wxpayapi.MsgTypePay: + err = onWxpayFinished(msg.Data.(*wxpayapi.PayResultMsg)) + case wxpayapi.MsgTypeRefund: + err = onWxpayRefund(msg.Data.(*wxpayapi.RefundResultMsg)) } return err } -func onWxpayFinished(msg *wxpay.PayResultMsg) (err error) { +func onWxpayFinished(msg *wxpayapi.PayResultMsg) (err error) { orderPay := &model.OrderPay{ - VendorOrderID: msg.OutTradeNo, - VendorID: jxutils.GetPossibleVendorIDFromVendorOrderID(msg.OutTradeNo), - PayType: model.PayTypeWX, + PayOrderID: msg.OutTradeNo, + PayType: model.PayTypeWX, } orderPay.DeletedAt = utils.DefaultTimeValue db := dao.GetDB() - if err = dao.GetEntity(db, orderPay, "VendorOrderID", "VendorID", "PayType", "DeletedAt"); err == nil { - orderPay.VendorPayType = msg.TradeType - orderPay.PayFinishedAt = utils.Time2Pointer(wxpay.PayTime2Time(msg.TimeEnd)) + 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 == wxpay.ResponseCodeSuccess { + if msg.ResultCode == wxpayapi.ResponseCodeSuccess { orderPay.Status = model.PayStatusYes } else { orderPay.Status = model.PayStatusFailed } dao.UpdateEntity(db, orderPay) - if msg.ResultCode == wxpay.ResponseCodeSuccess { + if msg.ResultCode == wxpayapi.ResponseCodeSuccess { err = OnPayFinished(orderPay) } } else { @@ -95,13 +95,13 @@ func onWxpayFinished(msg *wxpay.PayResultMsg) (err error) { return err } -func onWxpayRefund(msg *wxpay.RefundResultMsg) (err error) { +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 == wxpay.ResponseCodeSuccess { + if msg.ResultCode == wxpayapi.ResponseCodeSuccess { orderPayRefund.Status = model.RefundStatusYes } else { orderPayRefund.Status = model.RefundStatusFailed @@ -126,13 +126,14 @@ func onWxpayRefund(msg *wxpay.RefundResultMsg) (err error) { return err } -func refundOrderByWX(ctx *jxcontext.Context, orderPay *model.OrderPay, refundID string) (orderPayRefund *model.OrderPayRefund, err error) { - result, err := api.WxpayAPI.PayRefund(&wxpay.PayRefundParam{ +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: orderPay.TotalFee, + RefundFee: refundFee, + RefundDesc: wxpayapi.CData(refundDesc), }) if err == nil { orderPayRefund = &model.OrderPayRefund{ diff --git a/business/partner/purchase/jx/order.go b/business/partner/purchase/jx/order.go index 5bd3086bc..4c36f9c25 100644 --- a/business/partner/purchase/jx/order.go +++ b/business/partner/purchase/jx/order.go @@ -16,9 +16,18 @@ func (c *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *mo } 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 { @@ -86,6 +95,10 @@ func (c *PurchaseHandler) GetOrderRealMobile(ctx *jxcontext.Context, order *mode } 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 } @@ -99,6 +112,10 @@ func (c *PurchaseHandler) CancelOrder(ctx *jxcontext.Context, order *model.Goods } 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 } @@ -106,14 +123,6 @@ func (c *PurchaseHandler) ListOrders(ctx *jxcontext.Context, vendorOrgCode strin return vendorOrderIDs, err } -func (c *PurchaseHandler) GetWaybillTip(ctx *jxcontext.Context, order *model.GoodsOrder) (tipFee int64, err error) { - return tipFee, err -} - -func (c *PurchaseHandler) AddWaybillTip(ctx *jxcontext.Context, order *model.GoodsOrder, tipFee2Add int64) (err error) { - return err -} - func (c *PurchaseHandler) ConfirmSelfTake(ctx *jxcontext.Context, vendorOrderID, selfTakeCode string) (err error) { order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, model.VendorIDJX) if err == nil { diff --git a/business/partner/purchase/jx/sku.go b/business/partner/purchase/jx/sku.go index 7673a1423..32daa9b18 100644 --- a/business/partner/purchase/jx/sku.go +++ b/business/partner/purchase/jx/sku.go @@ -9,25 +9,25 @@ import ( "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) 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) 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) 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) 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 @@ -45,21 +45,21 @@ func (p *PurchaseHandler) ReorderCategories2(ctx *jxcontext.Context, vendorOrgCo return err } -func (p *PurchaseHandler) CreateSku(db *dao.DaoDB, sku *model.Sku, userName 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) 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) 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 diff --git a/business/partner/purchase/mtwm/act.go b/business/partner/purchase/mtwm/act.go index 91f244458..4571a5b4b 100644 --- a/business/partner/purchase/mtwm/act.go +++ b/business/partner/purchase/mtwm/act.go @@ -13,6 +13,17 @@ import ( "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{ @@ -73,7 +84,7 @@ func createOneShopAct(act *model.Act2, vendorStoreID string, actStoreSku []*mode actData := storeSku2ActData(act, actStoreSku, isCreateOrUpdate) if len(actData) > 0 { if globals.EnableMtwmStoreWrite { - actResult, err2 := api.MtwmAPI.RetailDiscountBatchSave(vendorStoreID, actData) + actResult, err2 := api.MtwmAPI.RetailDiscountBatchSave(vendorStoreID, jxActType2Mtwm(act.Type), actData) globals.SugarLogger.Debugf("mtwm createOneShopAct err2:%v", err2) if err = err2; err != nil { return err @@ -96,10 +107,10 @@ func createOneShopAct(act *model.Act2, vendorStoreID string, actStoreSku []*mode return err } -func cancelOneShopAct(ctx *jxcontext.Context, actStoreSku []*model.ActStoreSku2) (err error) { +func cancelOneShopAct(ctx *jxcontext.Context, act *model.Act2, actStoreSku []*model.ActStoreSku2) (err error) { if list := storeSku2ActData4Delete(actStoreSku, nil /*model.IsSyncStatusNeedDelete*/); len(list) > 0 { if globals.EnableMtwmStoreWrite { - err = api.MtwmAPI.RetailDiscountDelete(actStoreSku[0].VendorStoreID, list) + err = api.MtwmAPI.RetailDiscountDelete(actStoreSku[0].VendorStoreID, jxActType2Mtwm(act.Type), list) } } return err @@ -129,13 +140,13 @@ func createSkuAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.A return getActStoreSkuFromTaskResult(result), err } -func cancelSkuAct(ctx *jxcontext.Context, parentTask tasksch.ITask, actStoreSku []*model.ActStoreSku2) (canceledList []*model.ActStoreSku2, err error) { +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(ctx, actStoreSkuList); err == nil { + if err = cancelOneShopAct(ctx, act, actStoreSkuList); err == nil { retVal = []interface{}{actStoreSkuList} } return retVal, err @@ -162,7 +173,7 @@ func (c *PurchaseHandler) SyncAct(ctx *jxcontext.Context, parentTask tasksch.ITa } err = func() (err error) { if model.IsSyncStatusDelete(act.SyncStatus) { - canceledList, err2 := cancelSkuAct(ctx, nil, actStoreSkuList) + 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)) @@ -183,7 +194,7 @@ func (c *PurchaseHandler) SyncAct(ctx *jxcontext.Context, parentTask tasksch.ITa } } if len(actStoreSkuList4Delete) > 0 { - deletedList, err2 := cancelSkuAct(ctx, nil, actStoreSkuList4Delete) + deletedList, err2 := cancelSkuAct(ctx, nil, act, actStoreSkuList4Delete) updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, deletedList, model.SyncFlagDeletedMask)...) if err = err2; err != nil { return err diff --git a/business/partner/purchase/mtwm/order.go b/business/partner/purchase/mtwm/order.go index 9cc8fe70d..2be1bca8a 100644 --- a/business/partner/purchase/mtwm/order.go +++ b/business/partner/purchase/mtwm/order.go @@ -65,7 +65,7 @@ var ( fakeFinishedPickup: model.OrderStatusFinishedPickup, fakeOrderAdjustFinished: model.OrderStatusAdjust, - fakeRefuseUserApplyCancel: model.OrderStatusUnlocked, + fakeRefuseUserApplyCancel: model.OrderStatusVendorRejectCancel, fakeUserApplyCancel: model.OrderStatusApplyCancel, fakeUserUndoApplyCancel: model.OrderStatusUndoApplyCancel, fakeMerchantAgreeApplyCancel: model.OrderStatusCanceled, @@ -99,6 +99,14 @@ func (p *PurchaseHandler) GetOrder(vendorOrgCode, vendorOrderID string) (order * 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"])) @@ -127,6 +135,7 @@ func (p *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *mo OrderCreatedAt: getTimeFromTimestamp(utils.MustInterface2Int64(result["ctime"])), 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"]), @@ -746,3 +755,18 @@ func (p *PurchaseHandler) onNumberDowngrade(msg *mtwmapi.CallbackMsg) (response 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 +} diff --git a/business/partner/purchase/mtwm/order_test.go b/business/partner/purchase/mtwm/order_test.go index b5a3cac58..a7e62f6fe 100644 --- a/business/partner/purchase/mtwm/order_test.go +++ b/business/partner/purchase/mtwm/order_test.go @@ -18,6 +18,14 @@ func TestGetOrder(t *testing.T) { 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 { diff --git a/business/partner/purchase/mtwm/store.go b/business/partner/purchase/mtwm/store.go index 05de4e943..f0538aa3a 100644 --- a/business/partner/purchase/mtwm/store.go +++ b/business/partner/purchase/mtwm/store.go @@ -101,6 +101,7 @@ func (p *PurchaseHandler) CreateStore(db *dao.DaoDB, storeID int, userName strin } func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName string) (err error) { + var name string if db == nil { db = dao.GetDB() } @@ -115,10 +116,16 @@ func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName strin 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 + } + } // openLevel, isOnline := bizStatusJX2Mtwm(mergedStoreStatus) params := map[string]interface{}{ - "name": remoteStoreInfo.Name, //jxutils.ComposeStoreName(storeDetail.Store.Name, model.VendorIDMTWM), - "address": storeDetail.Address, // 美团好像地址也不能改的? + "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": storeDetail.Tel1, @@ -127,6 +134,7 @@ func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName strin "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 { diff --git a/business/partner/purchase/mtwm/store_sku2.go b/business/partner/purchase/mtwm/store_sku2.go index a1c8ee428..b9d35a1f6 100644 --- a/business/partner/purchase/mtwm/store_sku2.go +++ b/business/partner/purchase/mtwm/store_sku2.go @@ -44,7 +44,7 @@ func (p *PurchaseHandler) GetStoreSkusBatchSize(funcID int) (batchSize int) { case partner.FuncCreateStoreSkus: batchSize = 1 // 可考虑用批量操作 case partner.FuncUpdateStoreSkus: - batchSize = mtwmapi.MaxStoreSkuBatchSize + batchSize = 1 // mtwmapi.MaxStoreSkuBatchSize case partner.FuncGetStoreSkusFullInfo: batchSize = 1 } @@ -291,7 +291,9 @@ func (p *PurchaseHandler) createOrUpdateStoreSkus(ctx *jxcontext.Context, storeI skus[0]["price"] = foodData["price"] } skus[0]["stock"] = stockCount2Mtwm(model.MaxStoreSkuStockQty) - skus[0]["upc"] = storeSku.Upc + if storeSku.Upc != "" { + skus[0]["upc"] = storeSku.Upc + } if foodData["tag_id"] != nil { skus[0]["weight"] = storeSku.Weight // weight字段仅限服饰鞋帽、美妆、日用品、母婴、生鲜果蔬、生活超市下的便利店/超市门店品类的商家使用 } @@ -432,7 +434,9 @@ func (p *PurchaseHandler) GetStoreSkusFullInfo(ctx *jxcontext.Context, parentTas if err != nil { return nil, err } - skuNameList = append(skuNameList, vendorSku2Jx(skuInfo)) + if skuName := vendorSku2Jx(skuInfo); skuName != nil { + skuNameList = append(skuNameList, skuName) + } } else { var storeSkuMap map[string]*partner.StoreSkuInfo if storeSkuList != nil { @@ -449,7 +453,9 @@ func (p *PurchaseHandler) GetStoreSkusFullInfo(ctx *jxcontext.Context, parentTas } else { for _, v := range result { if storeSkuMap[v.AppFoodCode] != nil { - skuNameList = append(skuNameList, vendorSku2Jx(v)) + if skuName := vendorSku2Jx(v); skuName != nil { + skuNameList = append(skuNameList, skuName) + } } } } @@ -462,6 +468,10 @@ func (p *PurchaseHandler) GetStoreSkusFullInfo(ctx *jxcontext.Context, parentTas } 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)) @@ -507,7 +517,9 @@ func vendorSku2Jx(appFood *mtwmapi.AppFood) (skuName *partner.SkuNameInfo) { func vendorSkuList2Jx(appFoodList []*mtwmapi.AppFood) (skuNameList []*partner.SkuNameInfo) { for _, appFood := range appFoodList { - skuNameList = append(skuNameList, vendorSku2Jx(appFood)) + if skuName := vendorSku2Jx(appFood); skuName != nil { + skuNameList = append(skuNameList, skuName) + } } return skuNameList } diff --git a/business/partner/purchase/weimob/wsc/order.go b/business/partner/purchase/weimob/wsc/order.go index 0e5967048..7978f3b62 100644 --- a/business/partner/purchase/weimob/wsc/order.go +++ b/business/partner/purchase/weimob/wsc/order.go @@ -2,6 +2,7 @@ package wsc import ( "errors" + "fmt" "time" "git.rosy.net.cn/baseapi/platformapi/weimobapi" @@ -108,6 +109,10 @@ func (p *PurchaseHandler) GetOrder(vendorOrgCode, vendorOrderID string) (order * 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"])) diff --git a/business/userstore/food_recipe.go b/business/userstore/food_recipe.go index af0254ad8..e64ae900b 100644 --- a/business/userstore/food_recipe.go +++ b/business/userstore/food_recipe.go @@ -246,7 +246,7 @@ func GetRecipeDetail(ctx *jxcontext.Context, recipeID int) (recipeDetail *FoodRe } choiceMap := make(map[int8][]*dao.FoodRecipeItemChoiceExt) for _, v := range itemChoiceList { - v.SkuName = jxutils.ComposeSkuName(v.Prefix, v.SkuNameName, v.Comment, v.Unit, v.SpecQuality, v.SpecUnit, 0) + v.SkuName = jxutils.ComposeSkuNameOriginal(v.Prefix, v.SkuNameName, v.Comment, v.Unit, v.SpecQuality, v.SpecUnit, 0) choiceMap[v.Index] = append(choiceMap[v.Index], v) } diff --git a/conf/app.conf b/conf/app.conf index 166136d97..7f424bacf 100644 --- a/conf/app.conf +++ b/conf/app.conf @@ -15,6 +15,7 @@ dadaAppSecret = "2c717ad914767d6e2beb3f743db9e477" mtwmAppID = "589" mtwmSecret = "a81eb3df418d83d6a1a4b7c572156d2f" mtwmCallbackURL = "http://callback.jxc4.com" +mtwmCookieStr = "_lxsdk_cuid=16eb02a8a02c8-0a92cb9af9798c-3d375b01-15f900-16eb02a8a02c8; _lxsdk=16eb02a8a02c8-0a92cb9af9798c-3d375b01-15f900-16eb02a8a02c8; device_uuid=!aaa93749-2445-4e1e-b178-956ac0ea5e45; pushToken=0sMxJkF87HeJFNGInMgnpvQ3ohIqeo_UMZ8VDif29S6s*; _lx_utm=utm_source%3DBaidu%26utm_medium%3Dorganic; wpush_server_url=wss://wpush.meituan.com; acctId=26599188; token=0o7UnNs2yauqdj86R145ow78W9cT9krlWpKPmCan2z7Q*; brandId=-1; wmPoiId=-1; isOfflineSelfOpen=0; city_id=0; isChain=1; existBrandPoi=true; ignore_set_router_proxy=true; region_id=; region_version=0; newCategory=false; bsid=PgNahlgfXvqnBiqv9tIi9zg7LDWtV8n70tkl_GhfueXgrLxV9BEb1rP9emUMnUUKPI6rANs_Y-chSdYLZS3KCA; cityId=510100; provinceId=510000; city_location_id=0; location_id=0; JSESSIONID=uht6v2iau9s6fx86r1ue6vzd; set_info=%7B%22wmPoiId%22%3A-1%2C%22ignoreSetRouterProxy%22%3Atrue%7D; igateApp=shangouepc; LX_SC_CONSTANT=c_nehoktcu; shopCategory=food; _lxsdk_s=16f40af4486-049-a66-a48%7C26337904%7C37" autonaviKey = "ef64f638f31e05cb7bde28790f7309fe" @@ -58,8 +59,8 @@ wxpayNotifyURL = "http://callback.test.jxc4.com/wxpay/msg/" backstageHost = "http://www.jxc4.com" wxBackstageHost = "http://wx.jxc4.com" -jdStorePageCookie = "OPJQMA7B3FTKCAUGO7FHCH5NMBGAWGGXYRNLEHYYZNGNPNIBCAM4IOEPG3NT3RIA44G5C3535Q5LGG4F4SR4AZVLGYKYTKFJJKEAOXENVBL5VXNILRP3GLNVVWA26XZ3VGSYOHA72RICMVZS3G53DTEH3LYUCSS54VI6WPOAGGDK532VYPEWWVCXUFRWENWDI4PEKM7SXBZ5BJO6DBLLERUA74YR2CVCGP4WUROCAHAMXKJ2VBGHTZYRL2DHR3BMXAHCTBAHYQLL24K5YI2PULRJL2UGAVD7VFRMEYTOXYHWCYVDXJ6HYFIPWIN3ULLXDDLN2ICON4GRK" -jd2StorePageCookie = "CK5GE5MR2UIOBOZC7BBZLLSI7MVDWPEQ4BRJTJQ2OP3ZFKYDDYTHXLZR3RDCQD6WXIWTDOSXTP3AQEC2D3ZS24VYF7PTTKKUKN7G4XBQS3QOBGUDNLQNEY7CLSNLWZCC7LNI6GZOWOOEN72AWG53MMCURHIQRBG7CGEGVIZQNRKV2NAWXHUA2REY6NP2B3GHPO6S4H35ST5KQXRJWL5LJSIWZHXGPYA3OGPRNAHBLVVNTQE6OL2RPMHQYNXCFMU5QQERDWPFLIWKB7W4GI7GHKLYDY" +jdStorePageCookie = "YYJV3NHVBPHLD36FWP6F3EM5PTXJ2XZQS7U4HWRIDPP4IWGUKUIB4XG5N26CZRDLDF7PKOXBPD6BNTUAJLETLZOIWMCVFI3K6MYZIY4QBIXIMXYDJNUKFGJVQTN5356SAD6WPCIHWNQAG7DDMF7L7S3SHD6O37OTAHUCKU6ALXATYTGMHNFLM4XRLVSFUQAJR77M4URSZRKVO55243TDVXLO25PP4UYSPTTPMNRUFXDNP4WPE566Q6V4AH32F7HT" +jd2StorePageCookie = "CK5GE5MR2UIOBOZC7BBZLLSI7MVDWPEQ4BRJTJQ2OP3ZFKYDDYTFFV4XOXKLERC2UXFT44TMCUMRFP3C25HD6W3PYONTQCOML6YIZA5Z37P62UXFE655IRGYJ4ZLQIEBYQM32FABIN5RVJYZWPQWSRTZURNRLYV57XJEDWZT5UVZRYUBTN3AT6JJJJ22YHE6ZHCN6LCH27JHSRO55YA6TJH6G54IF72X3UAXCKW5P2G2MT3U6I3527NQFMAFLHXBZKQFFMYUKUHUU4GZWD4O7GO45Y" ebaiStorePageCookieWMUSS = "B0AAFQCAAAGbhkuMCsvcyYBDkkyAxBGIBlgXAQYVwc7VwYZFkx2HDoPSmo5eV1femopWgJRawhgAALG04cg1RUmhUakBbJRdgPS0tNEhnQhNRewwuWwYYBDEFPCQSDXV5YWA6PAVRHUJ9SnVGMThYAjNjLw9pRxIbS04-XFo05AQgBl%7ERLA33vWcR73gEAKZ" ebaiStorePageCookieWMSTOKEN = "gAALgNAAAGfBI5YEBHSQdZY1InIS8CVQU9aBU1f3VLWVQqKHAAAc5LnRLZ1QLLx0S5IuzCSX8ZQ7oUwAAUr-GEm9JpRc9AQAAsLkLHHXzuhh2lZkbyrcAAAWBESKg3ZA" @@ -198,7 +199,7 @@ jdOrgCode = "339032" jdToken = "84541069-fbe2-424b-b625-9b2ba1d4c9e6" jdAppKey = "5d5577a2506f41b8b4ec520ba83490f5" jdSecret = "0b01b9eeb15b41dab1c3d05d95c17a26" -jdStorePageCookie = "YDYCWYUGKSROMV3MKJQIFINJ5CLPYH6IRVFUMFJD3JI6VQKHX3YPHTWDIDBNMCBUKSY3P7SKAHHKR7PHQDSFRXZEWXA4XOUTALIQDGDYIEUCMDPWSYGDVT42DJ27CD27QKCR3UN7KF7EPIHGPR7GCRTBD5DAHYMIODMDYESTI4PQWPK4CSWXGB2U4Y7R57ZUWN2T5LH4LE5SSAFFJCY53F5ZPCFR2RAUWYMCKHC4Y4QRFKYYLPHHZ2B3SCDWNLTVJOU24WJL4PVF3PPYDNTOLLXDABUFAZSE6C6CNOMI6L2TAK43JJIJQRQAQUQSU537ZFLVPGBYFDJYY" +jdStorePageCookie = "YDYCWYUGKSROMV3MKJQIFINJ5CLPYH6IRVFUMFJD3JI6VQKHX3YPHTWDIDBNMCBUKSY3P7SKAHHKR7PHQDSFRXZEWXA4XOUTALIQDGDYIEUCMDPWSYGDVT42DJ27CD27QKCR3UN7KF7EPIHGPR7GCRTBD5YGNZW4AIACY4HXDMCETEWCPFKOTM4HRJBSMMQJ77SR62PYMP6RCG33IRQGP6PRCKAO4M7FUA7G2ZM2SFQ6F6WUNO5GXDJSVUELLBJT" ebaiSource = "35957" ebaiSecret = "10013fbb7c2ddad7" @@ -208,6 +209,7 @@ ebaiStorePageCookieWMSTOKEN = "gAAA4OkFSZBsOayRIAnRqd24YRRVvWgRFE2w2CGtjKlAIsYg1 mtwmAppID = "4123" mtwmSecret = "df2c88338b85f830cebce2a9eab56628" mtwmCallbackURL = "http://callback-jxgy.jxc4.com" +mtwmCookieStr = "_lxsdk_cuid=16f413bd94fc8-0daccb808f461b-1d336b5a-13c680-16f413bd94fc8; _lxsdk=16f413bd94fc8-0daccb808f461b-1d336b5a-13c680-16f413bd94fc8; uuid=d1e8adb3d2774b89fe6e.1577347439.1.0.0; uuid_update=true; wpush_server_url=wss://wpush.meituan.com; acctId=62884810; token=0LhaIAAgrL1Hy0DDATjZqt4lRHauN_bBL3q0AvxUFUWo*; brandId=-1; wmPoiId=-1; isOfflineSelfOpen=0; city_id=0; isChain=1; existBrandPoi=true; ignore_set_router_proxy=true; region_id=; region_version=0; newCategory=false; bsid=SUVq2IfzZ53EHaTVoCE3UsmKkH5ZevxTjkwpNcaLKkbUOBkEyuZp8mPFwhgqkxsCGNjZILNj5aV8uVSQc888bg; device_uuid=!625e0297-431a-49ad-8b18-a0562c38a8eb; cityId=510100; provinceId=510000; city_location_id=0; location_id=0; pushToken=0LhaIAAgrL1Hy0DDATjZqt4lRHauN_bBL3q0AvxUFUWo*; set_info=%7B%22wmPoiId%22%3A-1%2C%22ignoreSetRouterProxy%22%3Atrue%7D; igateApp=shangouepc; LX_SC_CONSTANT=c_nehoktcu; shopCategory=food; JSESSIONID=unlrbu07lvm2s734eyedxr0j; _lxsdk_s=16f413bd950-189-8bb-8df%7C%7C33" enableStoreWrite = true enableJdStoreWrite = true @@ -284,6 +286,10 @@ jdStorePageCookie = "5EOCZRXVCRXBTYD5EPV6FOXRCQWFFQO75FRMJ3BAKZ5JXY6XTJECMWXK5OZ ebaiSource = "62289" ebaiSecret = "d3ec2358d6a819ea" +ebaiStorePageCookieWMUSS = "AHYHAAApIX5oBXUFKFsXKEdObiclRUhTFRZ1MUh7KEMiClB7MnB5G3VvIB5KN0USAABjQ4KngBfQ4Wcj9ebWYiEHBxCyNiBT1Yc111PhQ7UBluCENnCUB0HjIzfCAaHjAKEDoscT8sDL8JDDuQD81NaQ1dW3kN1MS9DeFMPgwC2YYROVy7AV3cKhMPkQrBwA" +ebaiStorePageCookieWMSTOKEN = "UAABRL3ZhLykdGFQBBDxXVDBuYisaB3tQHjUmHlQ5cEAs5dxMdG0R-EwVILAy_CV1Vlw_nbQAA0ijuEe-F2xUzAQAAAdujHKzhohkrxY0c5LsAAH0CeSGnywAHBQAAMA" + +mtwmCookieStr = "_lxsdk_cuid=169b7bc1b9fc8-05092471a96611-12376d51-1fa400-169b7bc1b9fc8; _lxsdk=169b7bc1b9fc8-05092471a96611-12376d51-1fa400-169b7bc1b9fc8; uuid=7a6a1345b4a3f7aa5f81.1553565752.1.0.0; _ga=GA1.2.285163436.1559264188; uuid_update=true; pushToken=0sz3wYPQoNug6okzOjEacuvrEWGRhuv6gL5ZWX98prCw*; device_uuid=!88124822-2b68-4425-865d-a3ffffe355af; wpush_server_url=wss://wpush.meituan.com; acctId=26535718; token=0vt6ufSF1X8GXpVq3N5zhE5FhcgONSuNTg4LiqkqEyTM*; brandId=-1; wmPoiId=2523687; isOfflineSelfOpen=0; city_id=999999; isChain=0; existBrandPoi=false; ignore_set_router_proxy=false; region_id=2000000001; region_version=1522820107; newCategory=false; bsid=g54gdBCxg9fu4t99gGLf770bFzBT_eUQXA3_FWLgDeCWrEtsNdXkJtckKTvMEthURtXVg_j0mhDauKPgDUgZyQ; cityId=510100; provinceId=510000; city_location_id=10000004; location_id=10000005; set_info=%7B%22wmPoiId%22%3A2523687%2C%22region_id%22%3A%222000000001%22%2C%22region_version%22%3A1522820107%7D; igateApp=shangouepc; shopCategory=market; LX_SC_CONSTANT=c_nehoktcu; JSESSIONID=43y9tjdcnjh2kojf6qfehvdy; _lxsdk_s=16f4145a84c-d6a-c22-64c%7C%7C19" mtpsAppKey = "25e816550bc9484480642f19a95f13fd" mtpsSecret = "r4$HqrKx9~=7?2Jfo,$Z~a7%~k!Au&pEdI2)oPJvSbH2ao@2N0[8wSIvtuumh_J^" diff --git a/controllers/act.go b/controllers/act.go index d1f88fb30..8d05ff4de 100644 --- a/controllers/act.go +++ b/controllers/act.go @@ -287,6 +287,7 @@ func (c *ActController) RefreshPageActs() { // @Param token header string true "认证token" // @Param skuIDs query string true "skuID列表" // @Param vendorID query int true "厂商ID" +// @Param types query string false "活动类型列表" // @Param isAsync query bool false "是否异步" // @Param isContinueWhenError query bool false "单个同步失败是否继续,缺省false" // @Success 200 {object} controllers.CallResult @@ -294,9 +295,9 @@ func (c *ActController) RefreshPageActs() { // @router /DeleteSkusFromAct [delete] func (c *ActController) DeleteSkusFromAct() { c.callDeleteSkusFromAct(func(params *tActDeleteSkusFromActParams) (retVal interface{}, errCode string, err error) { - var skuIDs []int - if err = jxutils.Strings2Objs(params.SkuIDs, &skuIDs); err == nil { - retVal, err = act.DeleteSkusFromAct(params.Ctx, params.VendorID, skuIDs, params.IsAsync, params.IsContinueWhenError) + var skuIDs, types []int + if err = jxutils.Strings2Objs(params.SkuIDs, &skuIDs, params.Types, &types); err == nil { + retVal, err = act.DeleteSkusFromAct(params.Ctx, params.VendorID, types, skuIDs, params.IsAsync, params.IsContinueWhenError) } return retVal, "", err }) @@ -308,6 +309,7 @@ func (c *ActController) DeleteSkusFromAct() { // @Param type formData int true "活动类型,3:直降,4:秒杀(美团当前不支持秒杀)" // @Param vendorID formData int true "厂商ID,当前只支持,京东:0,京西(用于记录活动信息):9" // @Param actStoreSkuList formData string true "活动门店商品信息" +// @Param lockTime formData string false "平台价格锁定截止时间" // @Param isAsync formData bool false "是否异步,缺省否(暂时只支持同步)" // @Success 200 {object} controllers.CallResult // @Failure 200 {object} controllers.CallResult @@ -316,7 +318,10 @@ func (c *ActController) ForceUpdateVendorPrice() { c.callForceUpdateVendorPrice(func(params *tActForceUpdateVendorPriceParams) (retVal interface{}, errCode string, err error) { var actStoreSkuList []*act.ActStoreSkuParam if err = jxutils.Strings2Objs(params.ActStoreSkuList, &actStoreSkuList); err == nil { - retVal, err = act.ForceUpdateVendorPrice(params.Ctx, params.VendorID, params.Type, actStoreSkuList, params.IsAsync) + timeList, err2 := jxutils.BatchStr2Time(params.LockTime) + if err = err2; err == nil { + retVal, err = act.ForceUpdateVendorPrice(params.Ctx, params.VendorID, params.Type, actStoreSkuList, timeList[0], params.IsAsync) + } } return retVal, "", err }) diff --git a/controllers/cms_sku.go b/controllers/cms_sku.go index 5a501f55d..421308aa4 100644 --- a/controllers/cms_sku.go +++ b/controllers/cms_sku.go @@ -191,6 +191,9 @@ func (c *SkuController) UpdateSkuName() { // dummySkuName := &model.SkuName{} payload := make(map[string]interface{}) if err = utils.UnmarshalUseNumber([]byte(params.Payload), &payload); err == nil { + delete(payload, "exPrefix") + delete(payload, "exPrefixBegin") + delete(payload, "exPrefixEnd") retVal, err = cms.UpdateSkuName(params.Ctx, params.NameID, payload) } return retVal, "", err @@ -375,3 +378,40 @@ func (c *SkuController) GetStoreSkuSalesInfo() { return retVal, "", err }) } + +// @Title 根据名字查询京东商品UPC信息 +// @Description 根据名字查询京东商品UPC信息 +// @Param token header string true "认证token" +// @Param name query string false "商品名" +// @Param upcCode query string false "upcCode,不支持模糊" +// @Success 200 {object} controllers.CallResult +// @Failure 200 {object} controllers.CallResult +// @router /GetJdUpcCodeByName [get] +func (c *SkuController) GetJdUpcCodeByName() { + c.callGetJdUpcCodeByName(func(params *tSkuGetJdUpcCodeByNameParams) (retVal interface{}, errCode string, err error) { + retVal, err = cms.GetJdUpcCodeByName(params.Ctx, params.Name, params.UpcCode) + return retVal, "", err + }) +} + +// @Title 批量设置商品额外前缀 +// @Description 批量设置商品额外前缀 +// @Param token header string true "认证token" +// @Param nameIDs formData string true "商品nameIDs" +// @Param exPrefix formData string true "商品额外前缀" +// @Param fromDate formData string true "生效开始时间,格式 2006-01-01 " +// @Param toDate formData string true "生效结束时间,格式 2006-01-01 " +// @Param isAsync formData bool false "是否异步" +// @Param isContinueWhenError formData bool false "单个同步失败是否继续,缺省false" +// @Success 200 {object} controllers.CallResult +// @Failure 200 {object} controllers.CallResult +// @router /UpdateSkuNamesExPrefix [put] +func (c *SkuController) UpdateSkuNamesExPrefix() { + c.callUpdateSkuNamesExPrefix(func(params *tSkuUpdateSkuNamesExPrefixParams) (retVal interface{}, errCode string, err error) { + var skuIDList []int + if err = jxutils.Strings2Objs(params.NameIDs, &skuIDList); err == nil { + retVal, err = cms.UpdateSkuNamesExPrefix(params.Ctx, skuIDList, params.ExPrefix, params.FromDate, params.ToDate, params.IsAsync, params.IsContinueWhenError) + } + return retVal, "", err + }) +} diff --git a/controllers/cms_store.go b/controllers/cms_store.go index b9b340768..180344e6b 100644 --- a/controllers/cms_store.go +++ b/controllers/cms_store.go @@ -589,20 +589,21 @@ func (c *StoreController) GetVendorStoreInfo() { // @Description 查询门店价格评分 // @Param token header string true "认证token" // @Param storeIDs formData string false "门店列表" +// @Param vendorIDs formData string false "厂商列表" // @Param snapDate formData string true "时间,默认前一天(格式2006-01-02" // @Param fromScore formData int false "分数范围开始 默认0" // @Param toScore formData int false "分数范围结束 默认100" -// @Param sort formData int false "排序,默认降序,0为降序,1为升序" +// @Param sort formData int false "分数排序,-1降序,-升序 ,直降排序,-2降序,2升序,秒杀排序,-3降序,3升序" // @Param offset formData int false "门店列表起始序号(以0开始,缺省为0)" // @Param pageSize formData int false "门店列表页大小(缺省为50,-1表示全部)" // @Success 200 {object} controllers.CallResult // @Failure 200 {object} controllers.CallResult // @router /GetStorePriceScore [post] func (c *StoreController) GetStorePriceScore() { - var storeIDList []int + var storeIDList, vendorIDList []int c.callGetStorePriceScore(func(params *tStoreGetStorePriceScoreParams) (retVal interface{}, errCode string, err error) { - if jxutils.Strings2Objs(params.StoreIDs, &storeIDList); err == nil { - retVal, err = cms.GetStorePriceScore(params.Ctx, storeIDList, params.FromScore, params.ToScore, params.Sort, params.SnapDate, params.Offset, params.PageSize) + if jxutils.Strings2Objs(params.StoreIDs, &storeIDList, params.VendorIDs, &vendorIDList); err == nil { + retVal, err = cms.GetStorePriceScore(params.Ctx, storeIDList, vendorIDList, params.FromScore, params.ToScore, params.Sort, params.SnapDate, params.Offset, params.PageSize) } return retVal, "", err }) @@ -611,13 +612,25 @@ func (c *StoreController) GetStorePriceScore() { // @Title 生成门店价格分数表 // @Description 生成门店价格分数表 // @Param token header string true "认证token" -// @Param forRefresh formData bool true "是否是刷新中位价重新生成分数表" // @Success 200 {object} controllers.CallResult // @Failure 200 {object} controllers.CallResult // @router /CreateStorePriceScore [post] func (c *StoreController) CreateStorePriceScore() { c.callCreateStorePriceScore(func(params *tStoreCreateStorePriceScoreParams) (retVal interface{}, errCode string, err error) { - err = cms.CreateStorePriceScore(params.Ctx, params.ForRefresh) + err = cms.CreateStorePriceScore(params.Ctx) + return retVal, "", err + }) +} + +// @Title 刷新store_map的京东等级 +// @Description 刷新store_map的京东等级 +// @Param token header string true "认证token" +// @Success 200 {object} controllers.CallResult +// @Failure 200 {object} controllers.CallResult +// @router /RefreshJdLevel [post] +func (c *StoreController) RefreshJdLevel() { + c.callRefreshJdLevel(func(params *tStoreRefreshJdLevelParams) (retVal interface{}, errCode string, err error) { + err = cms.RefreshJdLevel(params.Ctx) return retVal, "", err }) } diff --git a/controllers/cms_store_sku.go b/controllers/cms_store_sku.go index 59fd3b635..0a56d880a 100644 --- a/controllers/cms_store_sku.go +++ b/controllers/cms_store_sku.go @@ -43,6 +43,7 @@ type StoreSkuController struct { // @Param jdSyncStatus query int false "京东同步标识" // @Param ebaiSyncStatus query int false "饿百同步标识" // @Param mtwmSyncStatus query int false "美团外卖同步标识" +// @Param lockTime query string false "价格锁定时间" // @Success 200 {object} controllers.CallResult // @Failure 200 {object} controllers.CallResult // @router /GetStoreSkus [get] @@ -83,6 +84,7 @@ func (c *StoreSkuController) GetStoreSkus() { // @Param jdSyncStatus query int false "京东同步标识" // @Param ebaiSyncStatus query int false "饿百同步标识" // @Param mtwmSyncStatus query int false "美团外卖同步标识" +// @Param lockTime query string false "价格锁定时间" // @Success 200 {object} controllers.CallResult // @Failure 200 {object} controllers.CallResult // @router /GetStoresSkus [get,post] @@ -448,7 +450,7 @@ func (c *StoreSkuController) GetMissingStoreSkuFromOrder() { // @Title 根据门店信息查找推荐商品(按销量) // @Description 根据门店信息查找推荐商品(按销量) -// @Param token header string false "认证token" +// @Param token header string true "认证token" // @Param storeIDs query string true "门店列表" // @Success 200 {object} controllers.CallResult // @Failure 200 {object} controllers.CallResult @@ -463,18 +465,33 @@ func (c *StoreSkuController) GetTopSkusByStoreIDs() { }) } +// @Title 根据城市信息查找推荐商品(按销量) +// @Description 根据城市信息查找推荐商品(按销量) +// @Param token header string true "认证token" +// @Param cityCode query int true "城市id" +// @Param storeID query int false "门店id" +// @Success 200 {object} controllers.CallResult +// @Failure 200 {object} controllers.CallResult +// @router /GetTopSkusByCityCode [get] +func (c *StoreSkuController) GetTopSkusByCityCode() { + c.callGetTopSkusByCityCode(func(params *tStoreSkuGetTopSkusByCityCodeParams) (retVal interface{}, errCode string, err error) { + retVal, err = cms.GetTopSkusByCityCode(params.Ctx, params.CityCode, params.StoreID) + return retVal, "", err + }) +} + // @Title 根据门店信息查找推荐分类(按商品销量) // @Description 根据门店信息查找推荐分类(按商品销量) -// @Param token header string false "认证token" +// @Param token header string true "认证token" // @Param storeIDs query string true "门店列表" // @Success 200 {object} controllers.CallResult // @Failure 200 {object} controllers.CallResult -// @router /GetTopCategorysByStoreIDs [get] -func (c *StoreSkuController) GetTopCategorysByStoreIDs() { +// @router /GetTopCategoriesByStoreIDs [get] +func (c *StoreSkuController) GetTopCategoriesByStoreIDs() { var storeIDList []int - c.callGetTopCategorysByStoreIDs(func(params *tStoreSkuGetTopCategorysByStoreIDsParams) (retVal interface{}, errCode string, err error) { + c.callGetTopCategoriesByStoreIDs(func(params *tStoreSkuGetTopCategoriesByStoreIDsParams) (retVal interface{}, errCode string, err error) { if jxutils.Strings2Objs(params.StoreIDs, &storeIDList); err == nil { - retVal, err = cms.GetTopCategorysByStoreIDs(params.Ctx, storeIDList) + retVal, err = cms.GetTopCategoriesByStoreIDs(params.Ctx, storeIDList) } return retVal, "", err }) @@ -517,3 +534,77 @@ func (c *StoreSkuController) RefreshJxPriceByExcel() { return retVal, "", err }) } + +// @Title 根据Excel中SkuID批量关注商品 +// @Description 根据Excel中SkuID批量关注商品 +// @Param token header string true "认证token" +// @Param isAsync formData bool true "是否异步,缺省是同步" +// @Param isContinueWhenError formData bool true "单个同步失败是否继续,缺省false" +// @Success 200 {object} controllers.CallResult +// @Failure 200 {object} controllers.CallResult +// @router /FocusStoreSkusByExcel [post] +func (c *StoreSkuController) FocusStoreSkusByExcel() { + c.callFocusStoreSkusByExcel(func(params *tStoreSkuFocusStoreSkusByExcelParams) (retVal interface{}, errCode string, err error) { + r := c.Ctx.Request + files := r.MultipartForm.File["userfiles"] + retVal, err = cms.FocusStoreSkusByExcel(params.Ctx, files, params.IsAsync, params.IsContinueWhenError) + return retVal, "", err + }) +} + +// @Title 得到门店的分类列表 +// @Description 得到门店的分类列表(按商品销量) +// @Param token header string true "认证token" +// @Param storeID query int true "门店ID" +// @Param parentID query int false "父分类id" +// @Success 200 {object} controllers.CallResult +// @Failure 200 {object} controllers.CallResult +// @router /GetStoreCategories [get] +func (c *StoreSkuController) GetStoreCategories() { + c.callGetStoreCategories(func(params *tStoreSkuGetStoreCategoriesParams) (retVal interface{}, errCode string, err error) { + if params.MapData["parentID"] == nil { + params.ParentID = -1 + } + retVal, err = cms.GetStoreCategories(params.Ctx, params.StoreID, params.ParentID) + return retVal, "", err + }) +} + +// @Title 获取各平台所有门店某商品的价格 +// @Description 获取各平台所有门店某商品的价格 +// @Param token header string true "认证token" +// @Param skuID formData int true "商品ID" +// @Param vendorIDs formData string true "厂商ID列表" +// @Param isAsync formData bool true "是否异步,缺省是同步" +// @Param isContinueWhenError formData bool true "单个同步失败是否继续,缺省false" +// @Success 200 {object} controllers.CallResult +// @Failure 200 {object} controllers.CallResult +// @router /GetVendorStoreSkuPrice [post] +func (c *StoreSkuController) GetVendorStoreSkuPrice() { + var vendorIDList []int + c.callGetVendorStoreSkuPrice(func(params *tStoreSkuGetVendorStoreSkuPriceParams) (retVal interface{}, errCode string, err error) { + if jxutils.Strings2Objs(params.VendorIDs, &vendorIDList); err == nil { + retVal, err = cms.GetVendorStoreSkuPrice(params.Ctx, vendorIDList, params.SkuID, params.IsAsync, params.IsContinueWhenError) + } + return retVal, "", err + }) +} + +// @Title 根据skuID关注商品,价格为中位价,部分可售 +// @Description 根据skuID关注商品,价格为中位价,部分可售 +// @Param token header string true "认证token" +// @Param skuIDs formData string true "商品ID列表" +// @Param isAsync formData bool true "是否异步,缺省是同步" +// @Param isContinueWhenError formData bool true "单个同步失败是否继续,缺省false" +// @Success 200 {object} controllers.CallResult +// @Failure 200 {object} controllers.CallResult +// @router /FocusStoreSkusBySku [post] +func (c *StoreSkuController) FocusStoreSkusBySku() { + var skuIDList []int + c.callFocusStoreSkusBySku(func(params *tStoreSkuFocusStoreSkusBySkuParams) (retVal interface{}, errCode string, err error) { + if jxutils.Strings2Objs(params.SkuIDs, &skuIDList); err == nil { + retVal, err = cms.FocusStoreSkusBySku(params.Ctx, skuIDList, params.IsAsync, params.IsContinueWhenError) + } + return retVal, "", err + }) +} diff --git a/controllers/cms_sync.go b/controllers/cms_sync.go index fd0dd2524..238f4e07a 100644 --- a/controllers/cms_sync.go +++ b/controllers/cms_sync.go @@ -205,7 +205,7 @@ func (c *SyncController) SyncSkuNames() { } // @Title 删除本地没有的平台门店商品信息 -// @Description 删除本地没有的平台门店商品信息 +// @Description 删除本地没有的平台门店商品信息(已废弃) // @Param token header string true "认证token" // @Param storeIDs query string true "门店ID列表" // @Param vendorIDs query string true "厂商ID列表" @@ -225,7 +225,7 @@ func (c *SyncController) PruneMissingStoreSkus() { } // @Title 把京西有,平台无且没有待创建标记的商品加上待创建标记 -// @Description 把京西有,平台无且没有待创建标记的商品加上待创建标记 +// @Description 把京西有,平台无且没有待创建标记的商品加上待创建标记(已废弃) // @Param token header string true "认证token" // @Param storeIDs formData string false "门店ID列表" // @Param vendorIDs formData string false "运营商ID列表(京东0 美团1 饿百3)" @@ -244,6 +244,28 @@ func (c *SyncController) AddCreateFlagForJxStoreSku() { }) } +// @Title 把京西有,平台无且没有待创建标记的商品加上待创建标记 +// @Description 把京西有,平台无且没有待创建标记的商品加上待创建标记 +// @Param token header string true "认证token" +// @Param storeIDs formData string false "门店ID列表" +// @Param vendorIDs formData string false "运营商ID列表(京东0 美团1 饿百3)" +// @Param optType formData int true "操作方式" +// @Param isForce formData bool false "是否强制刷新" +// @Param isAsync formData bool false "是否异步操作" +// @Param isContinueWhenError formData bool false "单个同步失败是否继续,缺省false" +// @Success 200 {object} controllers.CallResult +// @Failure 200 {object} controllers.CallResult +// @router /AmendAndPruneStoreStuff [post] +func (c *SyncController) AmendAndPruneStoreStuff() { + c.callAmendAndPruneStoreStuff(func(params *tSyncAmendAndPruneStoreStuffParams) (retVal interface{}, errCode string, err error) { + var storeIDs, vendorIDs []int + if err = jxutils.Strings2Objs(params.StoreIDs, &storeIDs, params.VendorIDs, &vendorIDs); err == nil { + retVal, err = cms.CurVendorSync.AmendAndPruneStoreStuff(params.Ctx, vendorIDs, storeIDs, params.IsAsync, params.IsContinueWhenError, params.OptType, params.IsForce) + } + return retVal, "", err + }) +} + // @Title 初始化多门店平台商品库(及商家分类) // @Description 初始化多门店平台商品库(及商家分类) // @Param token header string true "认证token" diff --git a/controllers/dada_order.go b/controllers/dada_order.go index bf9a258e6..290e91d62 100644 --- a/controllers/dada_order.go +++ b/controllers/dada_order.go @@ -3,8 +3,10 @@ package controllers import ( "net/http" + "git.rosy.net.cn/baseapi/platformapi/dadaapi" "git.rosy.net.cn/baseapi/utils" "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" "github.com/astaxie/beego" ) @@ -30,3 +32,21 @@ func (c *DadaDeliveryController) Msg() { c.Abort("404") } } + +func (c *DadaDeliveryController) Notify() { + if c.Ctx.Input.Method() == http.MethodPost { + obj, notifyResponse := api.DadaAPI.GetNotifyMsg(c.Ctx.Input.RequestBody) + if notifyResponse == nil { + err := api.DadaAPI.ConfirmRidderCancel(obj.MessageObj.OrderID, obj.MessageObj.DadaOrderID, true) + globals.SugarLogger.Debugf("dada notify, obj:%s, err:%v", utils.Format4Output(obj, false), err) + } + if notifyResponse == nil { + notifyResponse = dadaapi.SuccessNotifyResponse + } else { + c.Data["json"] = notifyResponse + c.ServeJSON() + } + } else { + c.Abort("404") + } +} diff --git a/controllers/jd_callback.go b/controllers/jd_callback.go index 73819c55f..476e2cdfe 100644 --- a/controllers/jd_callback.go +++ b/controllers/jd_callback.go @@ -19,12 +19,12 @@ type DjswController struct { beego.Controller } -func (c *DjswController) handleMsg(isNeedDecode bool, handler func(*jdapi.API, interface{}) *jdapi.CallbackResponse) (callbackResponse *jdapi.CallbackResponse) { - callbackMsg, mapData, callbackResponse := jdapi.GetCallbackMsg2(getUsefulRequest(c.Ctx)) +func (c *DjswController) handleMsg(handler func(*jdapi.API, interface{}) *jdapi.CallbackResponse) (callbackResponse *jdapi.CallbackResponse) { + callbackMsg, mapData, callbackResponse := jdapi.GetCallbackMsg(getUsefulRequest(c.Ctx)) globals.SugarLogger.Debug(utils.Format4Output(callbackMsg, true)) if callbackResponse == nil { - if jdAPI := jd.GetAPIByAppKey(callbackMsg.AppKey); jdAPI != nil { - if callbackResponse = jdAPI.CheckCallbackValidation2(mapData, callbackMsg.Sign); callbackResponse == nil { + if jdAPI := jd.GetAPI(jd.AppKey2OrgCode(callbackMsg.AppKey)); jdAPI != nil { + if callbackResponse = jdAPI.CheckCallbackValidation(mapData, callbackMsg.Sign); callbackResponse == nil { callbackResponse = handler(jdAPI, callbackMsg.Param) } } else { @@ -34,9 +34,9 @@ func (c *DjswController) handleMsg(isNeedDecode bool, handler func(*jdapi.API, i return callbackResponse } -func (c *DjswController) orderStatus(isCancelOrder bool) { +func (c *DjswController) orderStatus() { if c.Ctx.Input.Method() == http.MethodPost { - callbackResponse := c.handleMsg(isCancelOrder, func(a *jdapi.API, obj interface{}) (callbackResponse *jdapi.CallbackResponse) { + callbackResponse := c.handleMsg(func(a *jdapi.API, obj interface{}) (callbackResponse *jdapi.CallbackResponse) { callbackResponse = jd.OnOrderMsg(obj.(*jdapi.CallbackOrderMsg)) return callbackResponse }) @@ -48,48 +48,52 @@ func (c *DjswController) orderStatus(isCancelOrder bool) { } func (c *DjswController) NewOrder() { - c.orderStatus(false) + c.orderStatus() } func (c *DjswController) OrderAdjust() { - c.orderStatus(false) + c.orderStatus() } func (c *DjswController) OrderWaitOutStore() { - c.orderStatus(false) + c.orderStatus() } func (c *DjswController) PickFinishOrder() { - c.orderStatus(false) + c.orderStatus() } func (c *DjswController) DeliveryOrder() { - c.orderStatus(false) + c.orderStatus() } func (c *DjswController) FinishOrder() { - c.orderStatus(false) + c.orderStatus() } func (c *DjswController) LockOrder() { - c.orderStatus(false) + c.orderStatus() } func (c *DjswController) UnlockOrder() { - c.orderStatus(false) + c.orderStatus() } func (c *DjswController) UserCancelOrder() { - c.orderStatus(false) + c.orderStatus() } func (c *DjswController) ApplyCancelOrder() { - c.orderStatus(true) + c.orderStatus() +} + +func (c *DjswController) VenderAuditApplyCancelOrder() { + c.orderStatus() } func (c *DjswController) PushDeliveryStatus() { if c.Ctx.Input.Method() == http.MethodPost { - callbackResponse := c.handleMsg(true, func(a *jdapi.API, obj interface{}) (callbackResponse *jdapi.CallbackResponse) { + callbackResponse := c.handleMsg(func(a *jdapi.API, obj interface{}) (callbackResponse *jdapi.CallbackResponse) { callbackResponse = jd.OnWaybillMsg(obj.(*jdapi.CallbackDeliveryStatusMsg)) return callbackResponse }) @@ -101,7 +105,7 @@ func (c *DjswController) PushDeliveryStatus() { } func (c *DjswController) OrderCommentPush() { - c.orderStatus(false) + c.orderStatus() } func (c *DjswController) Token() { @@ -116,7 +120,7 @@ func (c *DjswController) Token() { func (c *DjswController) StockIsHave() { // globals.SugarLogger.Info(string(c.Ctx.Input.RequestBody)) if c.Ctx.Input.Method() == http.MethodPost { - callbackResponse := c.handleMsg(true, func(a *jdapi.API, obj interface{}) (callbackResponse *jdapi.CallbackResponse) { + callbackResponse := c.handleMsg(func(a *jdapi.API, obj interface{}) (callbackResponse *jdapi.CallbackResponse) { return callbackResponse }) c.Data["json"] = c.transferResponse("StockIsHave", callbackResponse) @@ -128,7 +132,7 @@ func (c *DjswController) StockIsHave() { func (c *DjswController) SinglePromoteCreate() { if c.Ctx.Input.Method() == http.MethodPost { - callbackResponse := c.handleMsg(false, func(a *jdapi.API, obj interface{}) (callbackResponse *jdapi.CallbackResponse) { + callbackResponse := c.handleMsg(func(a *jdapi.API, obj interface{}) (callbackResponse *jdapi.CallbackResponse) { callbackResponse = jd.OnActMsg(obj.(*jdapi.CallbackOrderMsg)) return callbackResponse }) @@ -141,7 +145,7 @@ func (c *DjswController) SinglePromoteCreate() { func (c *DjswController) StoreCrud() { if c.Ctx.Input.Method() == http.MethodPost { - callbackResponse := c.handleMsg(false, func(a *jdapi.API, obj interface{}) (callbackResponse *jdapi.CallbackResponse) { + callbackResponse := c.handleMsg(func(a *jdapi.API, obj interface{}) (callbackResponse *jdapi.CallbackResponse) { callbackResponse = jd.OnStoreMsg(obj.(*jdapi.CallbackOrderMsg)) return callbackResponse }) @@ -188,11 +192,11 @@ func (c *DjswController) NewAfterSaleBill() { } func (c *DjswController) AfterSaleBillStatus() { - c.orderStatus(false) + c.orderStatus() } func (c *DjswController) OrderAccounting() { - c.orderStatus(false) + c.orderStatus() } func getUsefulRequest(ctx *context.Context) *http.Request { @@ -208,3 +212,7 @@ func (c *DjswController) nullOperation() { func (c *DjswController) UpdateSku() { c.nullOperation() } + +func (c *DjswController) OrderAddTips() { + c.orderStatus() +} diff --git a/controllers/jx_order.go b/controllers/jx_order.go index 964fc08a4..7bbef01a4 100644 --- a/controllers/jx_order.go +++ b/controllers/jx_order.go @@ -220,12 +220,29 @@ func (c *OrderController) GetOrderInfo() { // @Param vendorOrderID query string true "订单ID" // @Param vendorID query int true "订单所属的厂商ID" // @Param isNotEnded query bool false "是否只是没有结束的运单" +// @Param isGetPos query bool false "是否得到骑手位置" // @Success 200 {object} controllers.CallResult // @Failure 200 {object} controllers.CallResult // @router /GetOrderWaybillInfo [get] func (c *OrderController) GetOrderWaybillInfo() { c.callGetOrderWaybillInfo(func(params *tOrderGetOrderWaybillInfoParams) (retVal interface{}, errCode string, err error) { - retVal, err = orderman.FixedOrderManager.GetOrderWaybillInfo(params.Ctx, params.VendorOrderID, params.VendorID, params.IsNotEnded) + retVal, err = orderman.FixedOrderManager.GetOrderWaybillInfo(params.Ctx, params.VendorOrderID, params.VendorID, params.IsNotEnded, params.IsGetPos) + return retVal, "", err + }) +} + +// @Title 补全遗漏的订单 +// @Description 补全遗漏的订单 +// @Param token header string true "认证token" +// @Param vendorOrderID formData string true "订单ID" +// @Param vendorID formData int true "订单所属的厂商ID" +// @Param tipFee formData int true "小费" +// @Success 200 {object} controllers.CallResult +// @Failure 200 {object} controllers.CallResult +// @router /UpdateOrderWaybillTip [post] +func (c *OrderController) UpdateOrderWaybillTip() { + c.callUpdateOrderWaybillTip(func(params *tOrderUpdateOrderWaybillTipParams) (retVal interface{}, errCode string, err error) { + err = defsch.FixedScheduler.SetOrderWaybillTip(params.Ctx, params.VendorOrderID, params.VendorID, int64(params.TipFee)) return retVal, "", err }) } @@ -514,7 +531,7 @@ func (c *OrderController) GetPrinterStatus() { }) } -func skuList2Map(skuList []*model.OrderSku) (skuCount int, skuMap map[int64]*model.OrderSku) { +func skuList2Map(skuList []*model.OrderSku) (skuCount int, skuMap map[int64]*model.OrderSku, outSkuList []*model.OrderSku) { skuMap = make(map[int64]*model.OrderSku) for _, sku := range skuList { skuCount += sku.Count @@ -524,12 +541,13 @@ func skuList2Map(skuList []*model.OrderSku) (skuCount int, skuMap map[int64]*mod if skuMap[index] == nil { tmpSku := *sku skuMap[index] = &tmpSku + outSkuList = append(outSkuList, skuMap[index]) } else { skuMap[index].Count += sku.Count } } } - return skuCount, skuMap + return skuCount, skuMap, outSkuList } func getSkuFromMap(skuMap map[int64]*model.OrderSku, skuID, actID int) (sku *model.OrderSku) { @@ -554,6 +572,7 @@ func (c *OrderController) AdjustOrder() { var skuList []*model.OrderSku err = jxutils.Strings2Objs(params.RemovedSkuInfo, &skuList) if err == nil { + _, _, skuList = skuList2Map(skuList) var order *model.GoodsOrder order, err = partner.CurOrderManager.LoadOrder(params.VendorOrderID, params.VendorID) if err == nil { @@ -780,6 +799,7 @@ func (c *OrderController) PartRefundOrder() { var skuList []*model.OrderSku err = jxutils.Strings2Objs(params.RefundSkuList, &skuList) if err == nil { + _, _, skuList = skuList2Map(skuList) var order *model.GoodsOrder order, err = partner.CurOrderManager.LoadOrder(params.VendorOrderID, params.VendorID) if err == nil { @@ -798,7 +818,7 @@ func (c *OrderController) PartRefundOrder() { } func fillSkuList(skuList, orderSkuList []*model.OrderSku) (isSame bool, err error) { - skuCount, orderSkuMap := skuList2Map(orderSkuList) + skuCount, orderSkuMap, _ := skuList2Map(orderSkuList) skuCount2 := 0 for _, sku := range skuList { skuCount2 += sku.Count @@ -875,3 +895,33 @@ func (c *OrderController) RefreshOrdersWithoutJxStoreID() { return retVal, "", err }) } + +// @Title 获取投诉原因 +// @Description 获取投诉原因 +// @Param token header string true "认证token" +// @Success 200 {object} controllers.CallResult +// @Failure 200 {object} controllers.CallResult +// @router /GetComplaintReasons [get] +func (c *OrderController) GetComplaintReasons() { + c.callGetComplaintReasons(func(params *tOrderGetComplaintReasonsParams) (retVal interface{}, errCode string, err error) { + retVal = orderman.GetComplaintReasons() + return retVal, "", err + }) +} + +// @Title 投诉骑手(三方运送) +// @Description 投诉骑手(三方运送) +// @Param token header string true "认证token" +// @Param vendorOrderID formData string true "订单ID" +// @Param vendorID formData int true "订单所属厂商ID" +// @Param waybillVendorID formData int true "运单所属厂商ID" +// @Param complaintID formData int true "投诉原因ID" +// @Success 200 {object} controllers.CallResult +// @Failure 200 {object} controllers.CallResult +// @router /ComplaintRider [post] +func (c *OrderController) ComplaintRider() { + c.callComplaintRider(func(params *tOrderComplaintRiderParams) (retVal interface{}, errCode string, err error) { + err = orderman.ComplaintRider(params.Ctx, params.VendorOrderID, params.VendorID, params.WaybillVendorID, params.ComplaintID) + return retVal, "", err + }) +} diff --git a/controllers/wxpay_callback.go b/controllers/wxpay_callback.go index 2d6d89e7d..4da448b20 100644 --- a/controllers/wxpay_callback.go +++ b/controllers/wxpay_callback.go @@ -4,7 +4,7 @@ import ( "fmt" "net/http" - "git.rosy.net.cn/baseapi/platformapi/wxpay" + "git.rosy.net.cn/baseapi/platformapi/wxpayapi" "git.rosy.net.cn/jx-callback/business/partner/purchase/jx/localjx" "git.rosy.net.cn/jx-callback/globals/api" "github.com/astaxie/beego" @@ -17,19 +17,19 @@ type WXPayController struct { func (c *WXPayController) Msg() { if c.Ctx.Input.Method() == http.MethodPost { msg, callbackResponse := api.WxpayAPI.GetCallbackMsg(c.Ctx.Request) - // globals.SugarLogger.Debugf("wxpay callback msg:%s, callbackResponse:%s, %t", utils.Format4Output(msg, true), utils.Format4Output(callbackResponse, true), callbackResponse == nil) + // globals.SugarLogger.Debugf("wxpayapi callback msg:%s, callbackResponse:%s, %t", utils.Format4Output(msg, true), utils.Format4Output(callbackResponse, true), callbackResponse == nil) var err error if callbackResponse == nil { - if msg.MsgType == wxpay.MsgTypeUnkown { + if msg.MsgType == wxpayapi.MsgTypeUnkown { err = fmt.Errorf("未知的微信支付回调类型:%d", msg.MsgType) } else { err = localjx.OnWxPayCallback(msg) } } if callbackResponse == nil { - callbackResponse = wxpay.SuccessResponse + callbackResponse = wxpayapi.SuccessResponse } else if err != nil { - callbackResponse = wxpay.Err2CallbackResponse(err, "") + callbackResponse = wxpayapi.Err2CallbackResponse(err, "") } c.Data["xml"] = callbackResponse c.ServeXML() diff --git a/deploy/ansible.yml b/deploy/ansible.yml index cc372ac79..f9b033a69 100644 --- a/deploy/ansible.yml +++ b/deploy/ansible.yml @@ -9,8 +9,8 @@ owner: ubuntu group: ubuntu mode: 0777 - - name: cleanup previous backup files - shell: cd {{ deploy_dir }} && ./cleanup.sh + # - name: cleanup previous backup files + # shell: cd {{ deploy_dir }} && ./cleanup.sh - name: copy execute file to dest copy: src: ../jx-callback @@ -18,7 +18,7 @@ owner: ubuntu group: ubuntu mode: 0755 - backup: yes + backup: no - name: copy conf file to dest copy: src: ../conf/ diff --git a/globals/api/api.go b/globals/api/api.go index 9ab7e5b4c..b22fbca19 100644 --- a/globals/api/api.go +++ b/globals/api/api.go @@ -19,7 +19,7 @@ import ( "git.rosy.net.cn/baseapi/platformapi/showapi" "git.rosy.net.cn/baseapi/platformapi/weimobapi" "git.rosy.net.cn/baseapi/platformapi/weixinapi" - "git.rosy.net.cn/baseapi/platformapi/wxpay" + "git.rosy.net.cn/baseapi/platformapi/wxpayapi" "git.rosy.net.cn/baseapi/platformapi/xiaowmapi" "git.rosy.net.cn/baseapi/platformapi/yilianyunapi" "git.rosy.net.cn/baseapi/platformapi/zhongwuapi" @@ -46,7 +46,7 @@ var ( WeixinMiniAPI *weixinapi.API // 小程序 WeixinMiniAPI2 *weixinapi.API // 小程序2 WeixinMiniAppID2 string - WxpayAPI *wxpay.API // 微信支付API + WxpayAPI *wxpayapi.API // 微信支付API WeixinPageAPI *weixinapi.API // 用户微信扫码登录 @@ -97,6 +97,9 @@ func Init() { } if !beego.AppConfig.DefaultBool("disableMtwm", false) { MtwmAPI = mtwmapi.New(beego.AppConfig.String("mtwmAppID"), beego.AppConfig.String("mtwmSecret"), beego.AppConfig.String("mtwmCallbackURL")) + if mtwmCookieStr := beego.AppConfig.DefaultString("mtwmCookieStr", ""); mtwmCookieStr != "" { + MtwmAPI.SetCookieWithStr(mtwmCookieStr) + } } else { MtwmAPI = nil } @@ -152,8 +155,8 @@ func Init() { } WeixinPageAPI = weixinapi.New(beego.AppConfig.String("weixinPageAppID"), beego.AppConfig.String("weixinPageSecret")) if globals.WxpayNotifyURL != "" { - // WxpayAPI = wxpay.New(beego.AppConfig.String("wxpayAppID"), beego.AppConfig.String("wxpayAppKey"), beego.AppConfig.String("wxpayAppMchID")) - WxpayAPI = wxpay.NewWithCertificate(beego.AppConfig.String("wxpayAppID"), beego.AppConfig.String("wxpayAppKey"), beego.AppConfig.String("wxpayAppMchID"), + // WxpayAPI = wxpayapi.New(beego.AppConfig.String("wxpayAppID"), beego.AppConfig.String("wxpayAppKey"), beego.AppConfig.String("wxpayAppMchID")) + WxpayAPI = wxpayapi.NewWithCertificate(beego.AppConfig.String("wxpayAppID"), beego.AppConfig.String("wxpayAppKey"), beego.AppConfig.String("wxpayAppMchID"), "conf/apiclient_cert.pem", "conf/apiclient_key.pem") } AutonaviAPI = autonavi.New(beego.AppConfig.String("autonaviKey")) diff --git a/globals/globals.go b/globals/globals.go index 17727ac4f..90fbc0fed 100644 --- a/globals/globals.go +++ b/globals/globals.go @@ -54,6 +54,8 @@ var ( Jd2OrgCode string IsUseThingMap bool + + OutputDebugMsgLevel int ) func init() { @@ -67,6 +69,10 @@ func init() { } func Init() { + if false { //IsProductEnv() { + OutputDebugMsgLevel = 1 + } + SugarLogger.Infof("globals RunMode=%s", beego.BConfig.RunMode) ReallyCallPlatformAPI = (beego.BConfig.RunMode != "dev" && beego.BConfig.RunMode != "test") ReallySendWeixinMsg = ReallyCallPlatformAPI && IsProductEnv() diff --git a/globals/refutil/refutil.go b/globals/refutil/refutil.go index 7cf3e21c6..412ca8b55 100644 --- a/globals/refutil/refutil.go +++ b/globals/refutil/refutil.go @@ -63,7 +63,7 @@ func FilterMapByStructObject(mapData map[string]interface{}, obj interface{}, ob valid = make(map[string]interface{}) invalid = make(map[string]interface{}) for k, v := range mapData { - if m[k] != nil && excludedMap[k] == 0 && v != nil && (!isCheckValue || !IsValueEqual(m[k], v)) { + if m[k] != nil && excludedMap[k] == 0 /*&& v != nil*/ && (!isCheckValue || !IsValueEqual(m[k], v)) { valid[k] = v m[k] = v } else { @@ -92,5 +92,17 @@ func FilterMapByFieldList(mapData map[string]interface{}, fields []string) (vali } func IsValueEqual(value1, value2 interface{}) bool { - return fmt.Sprint(value1) == fmt.Sprint(value2) + if value1 == nil || value2 == nil { + return value1 == value2 + } + return Interface2String(value1) == Interface2String(value2) +} + +func Interface2String(value interface{}) (str string) { + valueType := reflect.TypeOf(value) + if valueType.Kind() == reflect.Ptr { + value = reflect.ValueOf(value).Elem() + } + str = fmt.Sprint(value) + return str } diff --git a/globals/refutil/refutil_test.go b/globals/refutil/refutil_test.go new file mode 100644 index 000000000..e0596f4be --- /dev/null +++ b/globals/refutil/refutil_test.go @@ -0,0 +1,37 @@ +package refutil + +import ( + "testing" + + "git.rosy.net.cn/baseapi/utils" +) + +func TestIsValueEqual(t *testing.T) { + for _, v := range [][]interface{}{ + []interface{}{ + false, + 1, + "1.0", + }, + []interface{}{ + true, + "1", + utils.String2Pointer("1"), + }, + []interface{}{ + true, + "1", + 1, + }, + []interface{}{ + true, + int64(100), + int(100), + }, + } { + result := IsValueEqual(v[1], v[2]) + if result != v[0].(bool) { + t.Fatalf("%v,%v, desired:%v, get:%v", v[1], v[2], v[0], result) + } + } +} diff --git a/routers/commentsRouter_controllers.go b/routers/commentsRouter_controllers.go index 2f9319078..5035e0c11 100644 --- a/routers/commentsRouter_controllers.go +++ b/routers/commentsRouter_controllers.go @@ -783,6 +783,15 @@ func init() { Filters: nil, Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:OrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:OrderController"], + beego.ControllerComments{ + Method: "ComplaintRider", + Router: `/ComplaintRider`, + AllowHTTPMethods: []string{"post"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:OrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:OrderController"], beego.ControllerComments{ Method: "ConfirmReceiveGoods", @@ -864,6 +873,15 @@ func init() { Filters: nil, Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:OrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:OrderController"], + beego.ControllerComments{ + Method: "GetComplaintReasons", + Router: `/GetComplaintReasons`, + AllowHTTPMethods: []string{"get"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:OrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:OrderController"], beego.ControllerComments{ Method: "GetOrderInfo", @@ -1053,6 +1071,15 @@ func init() { Filters: nil, Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:OrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:OrderController"], + beego.ControllerComments{ + Method: "UpdateOrderWaybillTip", + Router: `/UpdateOrderWaybillTip`, + AllowHTTPMethods: []string{"post"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:ReportController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:ReportController"], beego.ControllerComments{ Method: "PriceRefer", @@ -1170,6 +1197,15 @@ func init() { Filters: nil, Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:SkuController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:SkuController"], + beego.ControllerComments{ + Method: "GetJdUpcCodeByName", + Router: `/GetJdUpcCodeByName`, + AllowHTTPMethods: []string{"get"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:SkuController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:SkuController"], beego.ControllerComments{ Method: "GetSensitiveWordList", @@ -1269,6 +1305,15 @@ func init() { Filters: nil, Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:SkuController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:SkuController"], + beego.ControllerComments{ + Method: "UpdateSkuNamesExPrefix", + Router: `/UpdateSkuNamesExPrefix`, + AllowHTTPMethods: []string{"put"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreController"], beego.ControllerComments{ Method: "AddStoreCourierMap", @@ -1467,6 +1512,15 @@ func init() { Filters: nil, Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreController"], + beego.ControllerComments{ + Method: "RefreshJdLevel", + Router: `/RefreshJdLevel`, + AllowHTTPMethods: []string{"post"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreController"], beego.ControllerComments{ Method: "ScoreStore", @@ -1566,6 +1620,24 @@ func init() { Filters: nil, Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreSkuController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreSkuController"], + beego.ControllerComments{ + Method: "FocusStoreSkusByExcel", + Router: `/FocusStoreSkusByExcel`, + AllowHTTPMethods: []string{"post"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreSkuController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreSkuController"], + beego.ControllerComments{ + Method: "FocusStoreSkusBySku", + Router: `/FocusStoreSkusBySku`, + AllowHTTPMethods: []string{"post"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreSkuController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreSkuController"], beego.ControllerComments{ Method: "GetMissingStoreSkuFromOrder", @@ -1584,6 +1656,15 @@ func init() { Filters: nil, Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreSkuController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreSkuController"], + beego.ControllerComments{ + Method: "GetStoreCategories", + Router: `/GetStoreCategories`, + AllowHTTPMethods: []string{"get"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreSkuController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreSkuController"], beego.ControllerComments{ Method: "GetStoreSkus", @@ -1613,8 +1694,17 @@ func init() { beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreSkuController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreSkuController"], beego.ControllerComments{ - Method: "GetTopCategorysByStoreIDs", - Router: `/GetTopCategorysByStoreIDs`, + Method: "GetTopCategoriesByStoreIDs", + Router: `/GetTopCategoriesByStoreIDs`, + AllowHTTPMethods: []string{"get"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreSkuController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreSkuController"], + beego.ControllerComments{ + Method: "GetTopSkusByCityCode", + Router: `/GetTopSkusByCityCode`, AllowHTTPMethods: []string{"get"}, MethodParams: param.Make(), Filters: nil, @@ -1629,6 +1719,15 @@ func init() { Filters: nil, Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreSkuController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreSkuController"], + beego.ControllerComments{ + Method: "GetVendorStoreSkuPrice", + Router: `/GetVendorStoreSkuPrice`, + AllowHTTPMethods: []string{"post"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreSkuController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreSkuController"], beego.ControllerComments{ Method: "GetVendorStoreSkusInfo", @@ -1737,6 +1836,15 @@ func init() { Filters: nil, Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:SyncController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:SyncController"], + beego.ControllerComments{ + Method: "AmendAndPruneStoreStuff", + Router: `/AmendAndPruneStoreStuff`, + AllowHTTPMethods: []string{"post"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:SyncController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:SyncController"], beego.ControllerComments{ Method: "DeleteRemoteStoreSkus",