package orderman import ( "errors" "fmt" "math" "strings" "time" "git.rosy.net.cn/baseapi/platformapi/jdeclpapi" "git.rosy.net.cn/jx-callback/business/jxstore/common" "git.rosy.net.cn/jx-callback/business/jxutils/ddmsg" "git.rosy.net.cn/jx-callback/business/jxutils/tasksch" "git.rosy.net.cn/jx-callback/business/partner/purchase/jdshop" "git.rosy.net.cn/jx-callback/globals/api" "git.rosy.net.cn/baseapi" "git.rosy.net.cn/baseapi/platformapi/dingdingapi" "git.rosy.net.cn/baseapi/platformapi/jdshopapi" "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/business/jxcallback/scheduler" "git.rosy.net.cn/jx-callback/business/jxutils" "git.rosy.net.cn/jx-callback/business/jxutils/jxcontext" "git.rosy.net.cn/jx-callback/business/model" "git.rosy.net.cn/jx-callback/business/model/dao" "git.rosy.net.cn/jx-callback/business/partner" "git.rosy.net.cn/jx-callback/globals" "github.com/astaxie/beego/orm" ) func init() { } type tSkuCountPrice struct { Count int `json:"count"` SalePrice int64 `json:"salePrice"` } // msgVendorStatus的意思是事件本身的类型,类似有时收到NewOrder事件去取,订单状态不一定就是New的 // OnOrderAdjust也类似,而OrderStatus要记录的是消息,所以添加这个 func (c *OrderManager) OnOrderNew(order *model.GoodsOrder, orderStatus *model.OrderStatus) (err error) { globals.SugarLogger.Debugf("OnOrderNew orderID:%s", order.VendorOrderID) if order.ConsigneeMobile2 == "" && jxutils.IsStringLikeMobile(order.ConsigneeMobile) { order.ConsigneeMobile2 = order.ConsigneeMobile } db := dao.GetDB() dao.Begin(db) defer func() { globals.SugarLogger.Debugf("OnOrderNew exit orderID:%s", order.VendorOrderID) if r := recover(); r != nil { dao.Rollback(db) panic(r) } }() if order.Status == model.OrderStatusUnknown { order.Status = model.OrderStatusNew } var isDuplicated bool if order.Status == model.OrderStatusNew && order.VendorID == model.VendorIDJX && !model.IsOrderJXTemp(order) { isDuplicated, _, err = c.addOrderStatus(orderStatus, db) } else { isDuplicated, err = addOrderOrWaybillStatus(orderStatus, db) if err == nil && !isDuplicated { isDuplicated, err = c.SaveOrder(order, false, db) } } if err == nil { dao.Commit(db) if !isDuplicated { err = scheduler.CurrentScheduler.OnOrderNew(order, false) } } else { dao.Rollback(db) } return err } // 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 } db := dao.GetDB() dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db) panic(r) } }() // 出现过调整单后,状态回到新订单状态,比如:911350836000622 // 不完全确定,加一个处理 if order.Status < model.OrderStatusAccepted { order.Status = model.OrderStatusAccepted } isDuplicated, err := addOrderOrWaybillStatus(orderStatus, db) if err == nil && !isDuplicated { err = utils.CallFuncLogError(func() error { _, err = db.Db.Raw("DELETE FROM order_sku WHERE vendor_order_id = ? AND vendor_id = ?", order.VendorOrderID, order.VendorID).Exec() return err }, "OnAdjustOrder delete order, orderID:%s", order.VendorOrderID) if err != nil { return err } adjustCount := int8(0) previousOrder := &model.GoodsOrder{ VendorOrderID: order.VendorOrderID, VendorID: order.VendorID, } if err = dao.GetEntity(db, previousOrder, model.FieldVendorOrderID, model.FieldVendorID); err != nil && !dao.IsNoRowsError(err) { globals.SugarLogger.Warnf("OnOrderAdjust, order:%s GetEntity failed with error:%v", order.VendorOrderID, err) return err } if err == nil { adjustCount = previousOrder.AdjustCount if _, err = dao.DeleteEntity(db, previousOrder); err != nil { return err } order.VendorWaybillID = previousOrder.VendorWaybillID order.WaybillVendorID = previousOrder.WaybillVendorID } else { globals.SugarLogger.Warnf("OnOrderAdjust, but previous order:%s doesn't exist", order.VendorOrderID) } // err = utils.CallFuncLogError(func() error { // _, err = db.Db.Raw("DELETE FROM goods_order WHERE vendor_order_id = ? AND vendor_id = ?", order.VendorOrderID, order.VendorID).Exec() // return err // }, "OnAdjustOrder delete order_sku, orderID:%s", order.VendorOrderID) order.AdjustCount = adjustCount + 1 isDuplicated, err = c.SaveOrder(order, true, db) } if err == nil { dao.Commit(db) if !isDuplicated { // 因为订单调度器需要的是真实状态,所以用order的状态 _ = scheduler.CurrentScheduler.OnOrderNew(order, false) _ = scheduler.CurrentScheduler.OnOrderStatusChanged(order, orderStatus, false) } } else { dao.Rollback(db) } return err } func (c *OrderManager) OnOrderStatusChanged(vendorOrgCode string, orderStatus *model.OrderStatus) (err error) { // 有些平台(比如美团外卖),在新订单事件没有成功返回,但在重发订单消息前,订单状态转换,则不会再重发新订单事件,特殊处理一下 if orderStatus.Status == model.OrderStatusAccepted { if _, err2 := c.LoadOrder(orderStatus.VendorOrderID, orderStatus.VendorID); err2 == ErrCanNotFindOrder { if handler := partner.GetPurchaseOrderHandlerFromVendorID(orderStatus.VendorID); handler != nil { if order, err2 := handler.GetOrder(vendorOrgCode, orderStatus.VendorOrderID); err2 == nil { c.OnOrderNew(order, orderStatus) } } } } db := dao.GetDB() dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db) panic(r) } }() 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") } } } } //更新订单new_earning_price if order.EarningType == model.EarningTypePoints { waybill, _ := c.LoadWaybill(order.VendorWaybillID, order.WaybillVendorID) store, _ := c.LoadStoreDetail(jxutils.GetSaleStoreIDFromOrder(order), order.VendorID) if waybill == nil { // if order.VendorID == model.VendorIDJDShop || order.VendorID == model.VendorIDJX { // if order.NewEarningPrice == 0 || order.NewEarningPrice != order.TotalShopMoney*int64(100-store.PayPercentage)/int64(100) { // order.NewEarningPrice = order.TotalShopMoney * int64(100-store.PayPercentage) / int64(100) // } // } else { if order.NewEarningPrice == 0 || order.NewEarningPrice != order.TotalShopMoney*int64(100-store.PayPercentage/2)/int64(100) { order.NewEarningPrice = order.TotalShopMoney * int64(100-store.PayPercentage/2) / int64(100) } // } } else { // if order.VendorID == model.VendorIDJDShop || order.VendorID == model.VendorIDJX { // if order.NewEarningPrice == 0 || order.NewEarningPrice != (order.TotalShopMoney-waybill.DesiredFee)*int64(100-store.PayPercentage)/int64(100) { // order.NewEarningPrice = (order.TotalShopMoney - waybill.DesiredFee) * int64(100-store.PayPercentage) / int64(100) // } // } else { if order.NewEarningPrice == 0 || order.NewEarningPrice != (order.TotalShopMoney-waybill.DesiredFee)*int64(100-store.PayPercentage/2)/int64(100) { order.NewEarningPrice = (order.TotalShopMoney - waybill.DesiredFee) * int64(100-store.PayPercentage/2) / int64(100) } // } } dao.UpdateEntity(db, order, "NewEarningPrice") } } } else if orderStatus.Status == model.OrderStatusCanceled { //如果取消订单则要把库存加回去 if order, err2 := c.LoadOrder(orderStatus.VendorOrderID, orderStatus.VendorID); err2 == nil { ModifyOrderSkusStock(db, order, true) } } if !isDuplicated { if order != nil { order.Skus = c.loadOrderSku(db, order.VendorOrderID, order.VendorID) _ = scheduler.CurrentScheduler.OnOrderStatusChanged(order, orderStatus, false) } } } else { dao.Rollback(db) } return err } func (c *OrderManager) ChangeOrderInfo(order *model.GoodsOrder) (err error) { db := dao.GetDB() _, err = dao.UpdateEntity(db, order, "ConsigneeAddress", "ConsigneeName", "ConsigneeMobile", "ConsigneeLat", "ConsigneeLng", "BuyerComment") return err } func (c *OrderManager) OnOrderMsg(order *model.GoodsOrder, vendorStatus, remark string) (err error) { _, _, err = c.addOrderStatus(&model.OrderStatus{ VendorOrderID: order.VendorOrderID, VendorID: order.VendorID, OrderType: model.OrderTypeOrder, RefVendorOrderID: order.VendorOrderID, RefVendorID: order.VendorID, VendorStatus: vendorStatus, Status: model.OrderStatusMsg, StatusTime: time.Now(), Remark: utils.LimitUTF8StringLen(remark, 255), }, nil) return err } func setFakeOrderFlag(db *dao.DaoDB, order *model.GoodsOrder) { if order.DeliveryType == model.OrderDeliveryTypeSelfTake { if realMobile := jxutils.GetRealMobile4Order(order); realMobile != "" { if configList, err := dao.QueryConfigs(db, model.ConfigSysFakeOrderMobiles, model.ConfigTypeSys, ""); err == nil && len(configList) > 0 { isMatch := false mobileList := strings.Split(configList[0].Value, ",") for _, v := range mobileList { if jxutils.TrimDecorationChar(v) == realMobile { isMatch = true break } } if isMatch { order.Flag |= model.OrderFlagMaskFake } } } } } func (c *OrderManager) SaveOrder(order *model.GoodsOrder, isAdjust bool, db *dao.DaoDB) (isDuplicated bool, err error) { globals.SugarLogger.Debugf("SaveOrder orderID:%s, VendorStoreID:%s, status:%d", order.VendorOrderID, order.VendorStoreID, order.Status) // 忽略查找JX信息错误 c.updateOrderOtherInfo(order, db) order.ID = 0 order.WaybillVendorID = model.VendorIDUnknown order.OrderFinishedAt = utils.DefaultTimeValue setFakeOrderFlag(db, order) // cms.HandleOrder4Consignee(order) dao.Begin(db) defer func() { if r := recover(); r != nil || err != nil { dao.Rollback(db) if r != nil { panic(r) } } }() // todo hardcode 兼容京东消息错序问题 if true { //order.VendorID == model.VendorIDJD { orderStatus := &model.OrderStatus{} if dao.GetRow(db, orderStatus, ` SELECT * FROM order_status 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 { if orderStatus.Status > order.Status { order.Status = orderStatus.Status order.VendorStatus = orderStatus.VendorStatus order.StatusTime = orderStatus.StatusTime // jxutils.RefreshOrderSkuRelated(order) } } } filterOrderInfo(order) created, _, err2 := db.Db.ReadOrCreate(order, "VendorOrderID", "VendorID") if err = err2; err == nil { originalOrder := &model.GoodsOrderOriginal{ VendorOrderID: order.VendorOrderID, VendorID: order.VendorID, OrderCreatedAt: order.OrderCreatedAt, OriginalData: order.OriginalData, } if _, _, err = db.Db.ReadOrCreate(originalOrder, "VendorOrderID", "VendorID"); err == nil { if created { if err = dao.CreateMultiEntities(db, order.Skus); err != nil { baseapi.SugarLogger.Warnf("saveOrder orderID:%s, save order_sku failed with error:%v", order.VendorOrderID, err) } } else { isDuplicated = true order.DuplicatedCount++ db.Db.Update(order, "DuplicatedCount") baseapi.SugarLogger.Infof("saveOrder duplicated orderid:%s msg received", order.VendorOrderID) } } //修改商品库存 if err == nil { err = ModifyOrderSkusStock(db, order, false) } } else { globals.SugarLogger.Warnf("saveOrder create order:%v, error:%v", order, err) } if err == nil { dao.Commit(db) } return isDuplicated, err } func ModifyOrderSkusStock(db *dao.DaoDB, order *model.GoodsOrder, isAdd bool) (err error) { skus := order.Skus for _, sku := range skus { storeSkus, _ := dao.GetStoresSkusInfo(db, []int{jxutils.GetSaleStoreIDFromOrder(order)}, []int{sku.SkuID}) if len(storeSkus) == 0 { globals.SugarLogger.Warnf("此订单商品没得storsku,%v,%v", order.VendorOrderID, sku.SkuID) continue } storeSku, stock := storeSkus[0], 0 if storeSku.Stock == 0 { globals.SugarLogger.Warnf("此订单商品库存为0,%v,%v", order.VendorOrderID, sku.SkuID) continue } if isAdd { stock = storeSku.Stock + sku.Count } else { stock = storeSku.Stock - sku.Count //如果是进货的订单,进货方门店对应商品要加上这么多库存 if order.OrderType == model.OrderTypeSupplyGoods { storeSkus2, _ := dao.GetStoresSkusInfo(db, []int{order.FromStoreID}, []int{sku.SkuID}) if len(storeSkus) > 0 { storeSku2 := storeSkus2[0] storeSku2.Stock = storeSku2.Stock + sku.Count dao.UpdateEntity(db, storeSku2, "Stock") dao.SetStoreSkuSyncStatus(db, order.VendorID, []int{order.FromStoreID}, []int{sku.SkuID}, model.SyncFlagStockMask) } } } storeSku.Stock = stock dao.UpdateEntity(db, storeSku, "Stock") if order.VendorID != model.VendorIDJX { dao.SetStoreSkuSyncStatus(db, order.VendorID, []int{jxutils.GetSaleStoreIDFromOrder(order)}, []int{sku.SkuID}, model.SyncFlagStockMask) } } return err } func filterOrderInfo(order *model.GoodsOrder) { order.ConsigneeName = utils.LimitUTF8StringLen2(order.ConsigneeName, 32) order.ConsigneeAddress = utils.LimitUTF8StringLen2(order.ConsigneeAddress, 255) order.ConsigneeAddress = strings.ReplaceAll(order.ConsigneeAddress, "·", "") } func (c *OrderManager) updateOrderSkuOtherInfo(order *model.GoodsOrder, db *dao.DaoDB, storePayPercentage, changePriceType int) (err error) { globals.SugarLogger.Debugf("updateOrderSkuOtherInfo orderID:%s, VendorStoreID:%s", order.VendorOrderID, order.VendorStoreID) jxStoreID := jxutils.GetShowStoreIDFromOrder(order) var opNumStr string if time.Now().Sub(order.OrderCreatedAt) < 1*time.Hour && order.VendorID != model.VendorIDJD { opNumStr = "2" } else { opNumStr = "2" } if jxStoreID == 0 { return nil } orderSkus := order.Skus var vendorSkuIDs []string for _, v := range orderSkus { if v.VendorSkuID != "" { vendorSkuIDs = append(vendorSkuIDs, v.VendorSkuID) } } if len(vendorSkuIDs) > 0 { var vendorStoreID string if order.VendorID == model.VendorIDJDShop { vendorStoreID = model.JdShopMainVendorStoreID } else { vendorStoreID = order.VendorStoreID } l, err := dao.GetStoreSkuPriceAndWeight(db, vendorStoreID, order.VendorID, vendorSkuIDs) if err != nil { globals.SugarLogger.Warnf("updateOrderSkuOtherInfo orderID:%s failed with err:%v", order.VendorOrderID, err) return err } skumapper := storeSkuPriceAndWeight2Map(l) for _, v := range orderSkus { v.VendorOrderID = order.VendorOrderID v.VendorID = order.VendorID intVendorSkuID := utils.Str2Int64WithDefault(v.VendorSkuID, 0) if intVendorSkuID != 0 && v.VendorSkuID != "-70000" { // todo hard code skuBindInfo := skumapper[v.VendorSkuID] if skuBindInfo == nil { if v.ShopPrice == 0 { v.ShopPrice = v.SalePrice * 70 / 100 } globals.SugarLogger.Infof("updateOrderSkuOtherInfo [运营%s]%s订单sku找不到门店价格(或商品映射),orderID:%s, StoreID:%d, VendorSkuID:%s, sku:%v", opNumStr, model.VendorChineseNames[order.VendorID], order.VendorOrderID, jxStoreID, v.VendorSkuID, v) } else { // TODO 客户端当前逻辑认为SkuID为0为赠品 if v.SkuID == 0 { v.SkuID = v.JxSkuID } v.JxSkuID = skuBindInfo.SkuID //京东商城的话,门店里可能取不到对应商品 if order.VendorID == model.VendorIDJDShop { v.JxSkuID = v.SkuID storeSkus, _ := dao.GetStoresSkusInfo(db, []int{order.StoreID}, []int{v.SkuID}) if len(storeSkus) > 0 { v.ShopPrice = int64(storeSkus[0].Price) } else { v.ShopPrice = v.SalePrice * 70 / 100 } } else { v.ShopPrice = int64(skuBindInfo.Price) if v.ShopPrice == 0 { v.ShopPrice = v.SalePrice * 70 / 100 } } v.SkuName = jxutils.ComposeSkuNameOriginal(skuBindInfo.Prefix, skuBindInfo.Name, skuBindInfo.Comment, skuBindInfo.Unit, skuBindInfo.SpecQuality, skuBindInfo.SpecUnit, 0) v.Weight = skuBindInfo.Weight // 以本地信息中的WEIGHT为准 //饿鲜达的订单做一下处理 if strings.Contains(order.StoreName, model.ExdStoreName) { if v.SkuID == 0 && !strings.Contains(v.SkuName, "免费") { v.SkuID = v.JxSkuID } } if skuBindInfo.Price == 0 { globals.SugarLogger.Infof("updateOrderSkuOtherInfo [运营%s]%s订单sku门店价格为零(一般原因为没有门店价格信息),orderID:%s, StoreID:%d, SkuID:%d, sku:%v", opNumStr, model.VendorChineseNames[order.VendorID], order.VendorOrderID, jxStoreID, v.JxSkuID, v) } } } // 直营店始终按比例结算,不考虑活动与结算表 salePrice := v.SalePrice if changePriceType == model.StoreChangePriceTypeManagedStore && v.ShopPrice != 0 { salePrice = 0 } v.EarningPrice = jxutils.CaculateSkuEarningPrice(v.ShopPrice, salePrice, storePayPercentage) } // 直营店始终按比例结算,不考虑活动与结算表 if changePriceType != model.StoreChangePriceTypeManagedStore { updateSingleOrderEarningPrice(order, db) } //TODO 重复购买有活动且结算价大于0的商品需要拆分,第一个商品按结算价,后面的商品按shopprice 或者 saleprice, 2020-05-06 //TODO 京东美团的订单,做活动的商品之前就会拆分出来,所以只做更新,饿百暂时不管, 2020-05-07 //TODO 不根据商品是否拆分,直接根据该商品做了活动,并且他的vendorPrice 和 salePrice 相等,就按新规则结算, 2020-05-11 //TODO 现在不判断商品做没做活动,只要vendorPrice和salePrice不等,就默认为做了活动,不做活动的商品就按新规则结算,2020-05-18 if order.VendorID == model.VendorIDJD || order.VendorID == model.VendorIDMTWM { for _, v := range orderSkus { if v.EarningPrice > 0 { // var storeID int // if order.StoreID == 0 { // storeID = order.JxStoreID // } else { // storeID = order.StoreID // } // result, err := dao.GetEffectiveActStoreSkuInfo2(db, 0, []int{order.VendorID}, []int{model.ActSkuSecKill, model.ActSkuDirectDown}, []int{storeID}, []int{v.SkuID}, order.OrderCreatedAt, order.OrderCreatedAt) // if (len(result) > 0 && err == nil) || v.IsVendorAct == model.YES { if v.VendorPrice == v.SalePrice { var earningPrice = 0 if v.ShopPrice < v.SalePrice { if v.ShopPrice == 0 { earningPrice = int(utils.Float64TwoInt64(math.Round(utils.Int2Float64(int(v.SalePrice)) * utils.Int2Float64(storePayPercentage) / 100))) } else { earningPrice = int(utils.Float64TwoInt64(math.Round(utils.Int2Float64(int(v.ShopPrice)) * utils.Int2Float64(storePayPercentage) / 100))) } } else { earningPrice = int(utils.Float64TwoInt64(math.Round(utils.Int2Float64(int(v.SalePrice)) * utils.Int2Float64(storePayPercentage) / 100))) } v.EarningPrice = int64(earningPrice) // v.StoreSubID = 0 } // } } } } } return nil } func storeSkuPriceAndWeight2Map(l []*dao.StoreSkuPriceAndWeight) (skuMapper map[string]*dao.StoreSkuPriceAndWeight) { skuMapper = make(map[string]*dao.StoreSkuPriceAndWeight) for _, v := range l { skuMapper[v.VendorSkuID] = v } return skuMapper } func updateSingleOrderEarningPrice(order *model.GoodsOrder, db *dao.DaoDB) { jxStoreID := jxutils.GetShowStoreIDFromOrder(order) skuIDMap := make(map[int]int) for _, v := range order.Skus { if skuID := jxutils.GetSkuIDFromOrderSku(v); skuID > 0 { skuIDMap[skuID] = 1 } } if len(skuIDMap) > 0 { 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) } if actStoreSkuMap := jxutils.NewActStoreSkuMap(actStoreSkuList, false); actStoreSkuMap != nil { for _, v := range order.Skus { if skuID := jxutils.GetSkuIDFromOrderSku(v); skuID > 0 { if actStoreSku := actStoreSkuMap.GetActStoreSku(jxStoreID, skuID, order.VendorID); actStoreSku != nil { v.EarningPrice = actStoreSku.EarningPrice if true { //v.StoreSubName != "" { // 之前这里为什么要加判断? v.StoreSubID = actStoreSku.ActID } } } } } } } func (c *OrderManager) updateOrderOtherInfo(order *model.GoodsOrder, db *dao.DaoDB) (err error) { globals.SugarLogger.Debugf("updateOrderOtherInfo orderID:%s, VendorStoreID:%s", order.VendorOrderID, order.VendorStoreID) payPercentage := 0 changePriceType := model.StoreChangePriceTypeDirect storeDetail, err := dao.GetStoreDetailByVendorStoreID(db, order.VendorStoreID, order.VendorID) if err != nil { if !dao.IsNoRowsError(err) { globals.SugarLogger.Warnf("updateOrderOtherInfo GetStoreDetailByVendorStoreID orderID:%s, VendorStoreID:%s, error:%v", order.VendorOrderID, order.VendorStoreID, err) return err } if time.Now().Sub(order.OrderCreatedAt) < 1*time.Hour { globals.SugarLogger.Infof("updateOrderOtherInfo [运营]订单在京西与平台都找不到京西门店信息,订单:%s,平台门店ID:%s,平台:%s", order.VendorOrderID, order.VendorStoreID, model.VendorChineseNames[order.VendorID]) } err = nil } else { order.JxStoreID = storeDetail.Store.ID payPercentage = storeDetail.PayPercentage changePriceType = int(storeDetail.ChangePriceType) if payPercentage < 50 { order.EarningType = model.EarningTypePoints } else { order.EarningType = model.EarningTypeQuote } } if err = c.updateOrderSkuOtherInfo(order, db, payPercentage, changePriceType); err == nil { jxutils.RefreshOrderSkuRelated(order) //EarningPrice2, 新规则,门店结算比例在50以下的做新规则计算 jxutils.RefreshOrderEarningPrice2(order, payPercentage) // caculateOrderEarningPrice(order, payPercentage) } return err } // 计算结算给门店的金额 // func caculateOrderEarningPrice(order *model.GoodsOrder, storePayPercentage int) { // order.EarningPrice = 0 // for _, v := range order.Skus { // skuEarningPrice := v.EarningPrice // if skuEarningPrice == 0 { // skuEarningPrice = jxutils.CaculateSkuEarningPrice(v.ShopPrice, v.SalePrice, storePayPercentage) // } // order.EarningPrice += skuEarningPrice * int64(v.Count) // } // } func (c *OrderManager) addOrderStatus(orderStatus *model.OrderStatus, db *dao.DaoDB) (isDuplicated bool, order *model.GoodsOrder, err error) { globals.SugarLogger.Debugf("addOrderStatus refOrderID:%s, orderID:%s", orderStatus.RefVendorOrderID, orderStatus.VendorOrderID) if db == nil { db = dao.GetDB() } isDuplicated, err = addOrderOrWaybillStatus(orderStatus, db) if err == nil && !isDuplicated && (orderStatus.Status != model.OrderStatusUnknown && orderStatus.Status != model.OrderStatusMsg) { order = &model.GoodsOrder{ VendorOrderID: orderStatus.VendorOrderID, VendorID: orderStatus.VendorID, } if err = db.Db.ReadForUpdate(order, "VendorOrderID", "VendorID"); err == nil { // todo 美团在订单完成后,还可能收到订单取消(应该当成售后单处理才合适),强制忽略这种情况,比如订单:80662201436073600 // 后来又发现有订单(81710104014426376)在完成后,直接再被取消的情况,不能生成售后单,还是再允许完成后取消。。。 // if orderStatus.VendorID == model.VendorIDMTWM && model.IsOrderFinalStatus(order.Status) { // return false, order, nil // } if (model.IsOrderLockStatus(orderStatus.Status) || model.IsOrderUnlockStatus(orderStatus.Status)) || (model.IsOrderMainStatus(orderStatus.Status) && orderStatus.Status >= order.Status) { // todo 要求status不能回绕 order.VendorStatus = orderStatus.VendorStatus updateFields := []string{ "VendorStatus", "UpdatedAt", } if model.IsOrderMainStatus(orderStatus.Status) { order.Status = orderStatus.Status order.StatusTime = orderStatus.StatusTime updateFields = append(updateFields, "Status", "StatusTime") if model.IsOrderFinalStatus(orderStatus.Status) { order.OrderFinishedAt = orderStatus.StatusTime updateFields = append(updateFields, "OrderFinishedAt") if order.LockStatus != model.OrderStatusUnknown { order.LockStatus = model.OrderStatusUnknown updateFields = append(updateFields, "LockStatus") } } } else { if model.IsOrderUnlockStatus(orderStatus.Status) { order.LockStatus = model.OrderStatusUnknown updateFields = append(updateFields, "LockStatus") } else if model.IsOrderLockStatus(orderStatus.Status) { if order.LockStatus != model.OrderStatusUnknown { globals.SugarLogger.Warnf("addOrderStatus refOrderID:%s, orderID:%s, order.LockStatus:%d, status.LockStatus:%d", orderStatus.RefVendorOrderID, orderStatus.VendorOrderID, order.LockStatus, orderStatus.Status) } order.Flag &= ^model.OrderFlagMaskUserApplyCancel order.LockStatus = orderStatus.Status order.LockStatusTime = orderStatus.StatusTime updateFields = append(updateFields, "LockStatus", "LockStatusTime", "Flag") } } utils.CallFuncLogError(func() error { _, err = db.Db.Update(order, updateFields...) return err }, "addOrderStatus update orderID:%s, status:%v", order.VendorOrderID, orderStatus) } else { isDuplicated = true } } else { order = nil if dao.IsNoRowsError(err) { // todo 消息错序 err = nil } else { globals.SugarLogger.Warnf("addOrderStatus orderID:%s read failed with error:%v", order.VendorOrderID, err) } } } return isDuplicated, order, err } func (c *OrderManager) loadOrderSku(db *dao.DaoDB, vendorOrderID string, vendorID int) (orderSkus []*model.OrderSku) { utils.CallFuncLogError(func() (err error) { _, err = db.Db.QueryTable("order_sku").Filter("vendor_order_id", vendorOrderID).Filter("vendor_id", vendorID).All(&orderSkus) return err }, "loadOrderSku orderID:%s", vendorOrderID) return orderSkus } func (c *OrderManager) LoadStoreDetail(storeID, vendorID int) (storeDetail *dao.StoreDetail, err error) { var ( db = dao.GetDB() ) storeDetail, err = dao.GetStoreDetail(db, storeID, vendorID) return storeDetail, err } func (c *OrderManager) loadOrder(vendorOrderID, vendorOrderID2 string, vendorID int) (order *model.GoodsOrder, err error) { db1 := dao.GetDB() db := db1.Db order = &model.GoodsOrder{ VendorOrderID: vendorOrderID, VendorOrderID2: vendorOrderID2, VendorID: vendorID, } keyFields := []string{ model.FieldVendorID, } if vendorOrderID != "" { keyFields = append(keyFields, model.FieldVendorOrderID) } if vendorOrderID2 != "" { keyFields = append(keyFields, model.FieldVendorOrderID2) } if err = db.Read(order, keyFields...); err == nil { vendorOrderID = order.VendorOrderID order.Skus = c.loadOrderSku(db1, vendorOrderID, vendorID) } if err != nil { order = nil if err == orm.ErrNoRows { err = ErrCanNotFindOrder } globals.SugarLogger.Infof("LoadOrder orderID:%s failed with error:%v", vendorOrderID, err) } return order, err } func (c *OrderManager) LoadOrder(vendorOrderID string, vendorID int) (order *model.GoodsOrder, err error) { return c.loadOrder(vendorOrderID, "", vendorID) } func (c *OrderManager) LoadOrder2(vendorOrderID2 string, vendorID int) (order *model.GoodsOrder, err error) { return c.loadOrder("", vendorOrderID2, vendorID) } func (c *OrderManager) LoadOrderFinancial(vendorOrderID string, vendorID int) (order *model.OrderFinancial, err error) { return c.loadOrderFinancial(vendorOrderID, "", vendorID) } func (c *OrderManager) LoadOrderFinancial2(vendorOrderID2 string, vendorID int) (order *model.OrderFinancial, err error) { return c.loadOrderFinancial("", vendorOrderID2, vendorID) } func (c *OrderManager) loadOrderFinancial(vendorOrderID, vendorOrderID2 string, vendorID int) (order *model.OrderFinancial, err error) { db := orm.NewOrm() order = &model.OrderFinancial{ VendorOrderID: vendorOrderID, VendorOrderID2: vendorOrderID2, VendorID: vendorID, } keyFields := []string{ model.FieldVendorID, } if vendorOrderID != "" { keyFields = append(keyFields, model.FieldVendorOrderID) } if vendorOrderID2 != "" { keyFields = append(keyFields, model.FieldVendorOrderID2) } // 这块不知道怎么写了、、、标注一下 if err = db.Read(order, keyFields...); err == nil { vendorOrderID = order.VendorOrderID err = utils.CallFuncLogError(func() error { _, err = db.QueryTable("order_sku_financial").Filter("vendor_order_id", vendorOrderID).Filter("vendor_id", vendorID).Filter("is_afs_order", 0).All(&order.Skus) return err }, "LoadOrder orderID:%s", vendorOrderID) } if err != nil { order = nil if err == orm.ErrNoRows { err = ErrCanNotFindOrder } globals.SugarLogger.Infof("LoadOrderFinancial orderID:%s failed with error:%v", vendorOrderID, err) } return order, err } func (c *OrderManager) UpdateOrderStatusAndDeliveryFlag(order *model.GoodsOrder) (err error) { return c.UpdateOrderFields(order, []string{"Status", "DeliveryFlag"}) } func (c *OrderManager) UpdateOrderFields(order *model.GoodsOrder, fieldList []string) (err error) { db := dao.GetDB() utils.CallFuncLogError(func() error { if order.ID == 0 { order2 := *order if err = dao.GetEntity(db, &order2, model.FieldVendorOrderID, model.FieldVendorID); err == nil { order.ID = order2.ID } else if dao.IsNoRowsError(err) { err = nil // 强制忽略订单不存在错误 } } if err == nil && order.ID != 0 { _, err = db.Db.Update(order, fieldList...) } return err }, "UpdateOrderFields orderID:%s failed with error:%v", order.VendorOrderID, err) return err } func (c *OrderManager) RefreshHistoryOrdersEarningPrice(ctx *jxcontext.Context, vendorOrderID string, actID int, vendorIDs []int, storeID int, fromDate, toDate string, isAsync, isContinueWhenError bool) (hint string, errCode string, err error) { var ( orderList []*model.GoodsOrder fromDateParam time.Time toDateParam time.Time beginAt time.Time endAt time.Time ) db := dao.GetDB() if actID > 0 { if fromDate != "" && toDate != "" { fromDateParam = utils.Str2Time(fromDate) toDateParam = utils.Str2Time(toDate) actList, _ := dao.QueryActs(db, actID, 0, math.MaxInt32, 0, "", -1, nil, nil, nil, 0, nil, 0, utils.DefaultTimeValue, utils.DefaultTimeValue, utils.DefaultTimeValue, utils.DefaultTimeValue) if len(actList.Data) > 0 { actBeginAt := actList.Data[0].BeginAt actEndAt := actList.Data[0].EndAt if fromDateParam.Sub(actBeginAt) > 0 && fromDateParam.Sub(actEndAt) > 0 { return "", model.ErrCodeGeneralFailed, errors.New(fmt.Sprintf("结算活动有效时间范围与订单创建时间范围不一致!,活动时间范围:[%v] 至 [%v] ,订单创建时间范围 :[%v] 至 [%v]", actBeginAt, actEndAt, fromDateParam, toDateParam)) } if actBeginAt.Sub(toDateParam) > 0 && actEndAt.Sub(toDateParam) > 0 { return "", model.ErrCodeGeneralFailed, errors.New(fmt.Sprintf("结算活动有效时间范围与订单创建时间范围不一致!,活动时间范围:[%v] 至 [%v] ,订单创建时间范围 :[%v] 至 [%v]", actBeginAt, actEndAt, fromDateParam, toDateParam)) } if fromDateParam.Sub(actBeginAt) > 0 { beginAt = fromDateParam if toDateParam.Sub(actEndAt) > 0 { endAt = actEndAt } else { endAt = toDateParam } } else { beginAt = actBeginAt if toDateParam.Sub(actEndAt) > 0 { endAt = actEndAt } else { endAt = toDateParam } } orderList, _ = dao.QueryOrders(db, vendorOrderID, actID, vendorIDs, storeID, beginAt, endAt) } else { return "", model.ErrCodeGeneralFailed, errors.New(fmt.Sprintf("未查询到相关结算活动,活动ID:[%d]", actID)) } } else if fromDate == "" && toDate == "" { actList, _ := dao.QueryActs(db, actID, 0, math.MaxInt32, 0, "", -1, nil, nil, nil, 0, nil, 0, utils.DefaultTimeValue, utils.DefaultTimeValue, utils.DefaultTimeValue, utils.DefaultTimeValue) if len(actList.Data) > 0 { orderList, _ = dao.QueryOrders(db, vendorOrderID, actID, vendorIDs, storeID, actList.Data[0].BeginAt, actList.Data[0].EndAt) if len(orderList) == 0 { return "", model.ErrCodeGeneralFailed, errors.New(fmt.Sprintf("未查询到相关订单!开始时间:[%v],结束时间:[%v]", actList.Data[0].BeginAt, actList.Data[0].EndAt)) } } else { return "", model.ErrCodeGeneralFailed, errors.New(fmt.Sprintf("未查询到相关结算活动,活动ID:[%d]", actID)) } } else { return "", model.ErrCodeGeneralFailed, errors.New(fmt.Sprintf("间隔时间必须完整!时间范围:[%v] 至 [%v]", fromDate, toDate)) } } else { if fromDate != "" && toDate != "" { fromDateParam = utils.Str2Time(fromDate) toDateParam = utils.Str2Time(toDate) //若未传入活动ID,且时间间隔大于10天则不允许查询 if math.Ceil(toDateParam.Sub(fromDateParam).Hours()/24) > 10 { return "", model.ErrCodeGeneralFailed, errors.New(fmt.Sprintf("查询间隔时间不允许大于10天!时间范围:[%v] 至 [%v]", fromDate, toDate)) } orderList, _ = dao.QueryOrders(db, vendorOrderID, actID, vendorIDs, storeID, fromDateParam, toDateParam) } else { return "", model.ErrCodeGeneralFailed, errors.New(fmt.Sprintf("若不按活动查询则间隔时间必须完整!时间范围:[%v] 至 [%v]", fromDate, toDate)) } } if len(orderList) <= 0 { return "", model.ErrCodePoint, errors.New(fmt.Sprintf("所选活动没有要更新结算价的订单!,vendorOrderID : %s, actID : %d, 时间范围:[%v] 至 [%v]", vendorOrderID, actID, fromDate, toDate)) } task := tasksch.NewParallelTask("刷新历史订单结算价", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { order := batchItemList[0].(*model.GoodsOrder) db := dao.GetDB() updateSingleOrderEarningPrice(order, db) dao.Begin(db) defer func() { if r := recover(); r != nil || err != nil { dao.Rollback(db) if r != nil { panic(r) } } }() for _, value := range order.Skus { // storeID := 0 // if order.StoreID == 0 { // storeID = order.JxStoreID // } else { // storeID = order.StoreID // } // result, _ := dao.GetEffectiveActStoreSkuInfo(db, 0, nil, 0, []int{storeID}, []int{value.SkuID}, order.OrderCreatedAt, order.OrderCreatedAt) // if len(result) > 0 { // if result[0].EarningPrice != 0 { // var ( // storePayPercentage int // ) // stores, _ := dao.GetStoreList(db, []int{order.StoreID}, nil, nil, nil, "") // if len(stores) > 0 { // storePayPercentage = stores[0].PayPercentage // } else { // storePayPercentage = 70 // } // sku := value // sku.Count = value.Count - 1 // value.Count = 1 // if value.ShopPrice < value.SalePrice { // sku.EarningPrice = value.ShopPrice * int64(storePayPercentage) // } else { // sku.EarningPrice = value.SalePrice * int64(storePayPercentage) // } // order.Skus = append(order.Skus, sku) // } // } if _, err = dao.UpdateEntity(db, value, "EarningPrice", "StoreSubID"); err != nil { return nil, err } } jxutils.RefreshOrderSkuRelated(order) storeID := 0 if order.StoreID == 0 { storeID = order.JxStoreID } else { storeID = order.StoreID } store, _ := dao.GetStoreDetail(db, storeID, order.VendorID) payPercentage := store.PayPercentage if payPercentage <= 50 { order.NewEarningPrice = order.TotalShopMoney * int64((100 - payPercentage/2)) / 100 } else { order.NewEarningPrice = order.EarningPrice } num, err := dao.UpdateEntity(db, order, "EarningPrice", "NewEarningPrice") if err != nil { return nil, err } dao.Commit(db) retVal = []string{utils.Int64ToStr(num)} return retVal, err }, orderList) tasksch.HandleTask(task, nil, true).Run() if !isAsync { resultNum, err2 := task.GetResult(0) if err = err2; err == nil { hint = resultNum[0].(string) } } else { hint = task.GetID() } return hint, model.ErrCodeSuccess, err } func RefreshOrdersWithoutJxStoreID(ctx *jxcontext.Context, fromDate, toDate string, isAsync, isContinueWhenError bool) (hint string, err error) { var ( fromDateParam time.Time toDateParam time.Time ) if fromDate != "" { fromDateParam = utils.Str2Time(fromDate) } if toDate != "" { toDateParam = utils.Str2Time(toDate) } db := dao.GetDB() task := tasksch.NewParallelTask("订单门店归属补漏", tasksch.NewParallelConfig().SetParallelCount(1), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { _, err = dao.UpdateOrdersWithoutJxStoreID(db, fromDateParam, toDateParam) return retVal, err }, []int{0}) tasksch.HandleTask(task, nil, true).Run() if !isAsync { _, err = task.GetResult(0) hint = "1" } else { hint = task.GetID() } return hint, err } func GetOrdersSupplement(ctx *jxcontext.Context, storIDs, vendorIDs, statuss []int, vendorOrderID, fromTime, toTime string, stype, IsReverse, offset, pageSize int) (pageInfo *model.PagedInfo, err error) { var ( db = dao.GetDB() fromTimeP time.Time toTimeP time.Time ) if fromTime != "" { fromTimeP = utils.Str2Time(fromTime) } if toTime != "" { toTimeP = utils.Str2Time(toTime) } if fromTimeP.After(toTimeP) { return nil, fmt.Errorf("时间范围不合法!开始时间:[%v],结束时间:[%v]", fromTimeP, toTimeP) } result, totalCount, err := dao.GetOrdersSupplement(db, storIDs, vendorIDs, statuss, vendorOrderID, fromTimeP, toTimeP, stype, IsReverse, offset, pageSize) pageInfo = &model.PagedInfo{ Data: result, TotalCount: totalCount, } return pageInfo, err } func AddUpdateOrdersSupplement(ctx *jxcontext.Context, ordersSupplement *model.OrderSupplementFee) (num int64, err error) { var ( db = dao.GetDB() id = ordersSupplement.ID ) now := time.Now() ordersSupplement.SupplementTime = &now defer func() { if r := recover(); r != nil || err != nil { dao.Rollback(db) if r != nil { panic(r) } } }() if id > 0 { orderSupplementFee, _ := dao.GetOrdersSupplementNoPage(db, id, nil, nil, nil, "", utils.ZeroTimeValue, utils.ZeroTimeValue, 0, 0) if len(orderSupplementFee) > 2 || len(orderSupplementFee) == 0 { return 0, fmt.Errorf("查询扣款记录有误,请联系技术部!") } if orderSupplementFee[0].Status == 1 { return 0, fmt.Errorf("已结账的扣款信息不允许修改!门店ID:[%v],订单号:[%v]", ordersSupplement.StoreID, ordersSupplement.VendorOrderID) } ordersSupplement.UpdatedAt = time.Now() ordersSupplement.LastOperator = ctx.GetUserName() ordersSupplement.CreatedAt = orderSupplementFee[0].CreatedAt if ordersSupplement.Status == -1 { ordersSupplement.DeletedAt = time.Now() } else { ordersSupplement.DeletedAt = utils.DefaultTimeValue } num, err = dao.UpdateEntity(db, ordersSupplement) } else { dao.WrapAddIDCULDEntity(ordersSupplement, ctx.GetUserName()) err = dao.CreateEntity(db, ordersSupplement) } dao.Commit(db) return num, err } func RefreshOrdersPriceInfo(ctx *jxcontext.Context, fromTime, toTime time.Time, isAsync, isContinueWhenError bool) (hint string, err error) { if utils.IsTimeZero(fromTime) { return "", fmt.Errorf("必须指定起始时间") } if utils.IsTimeZero(toTime) { toTime = fromTime } db := dao.GetDB() orderList, err := dao.QueryOrders(db, "", 0, nil, 0, fromTime, toTime) if err == nil && len(orderList) > 0 { task := tasksch.NewParallelTask("RefreshOrdersPriceInfo", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(isContinueWhenError), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { curOrder := batchItemList[0].(*model.GoodsOrder) newOrder, err := FixedOrderManager.LoadOrder(curOrder.VendorOrderID, curOrder.VendorID) if err == nil { db := dao.GetDB() if err = FixedOrderManager.updateOrderOtherInfo(newOrder, db); err == nil { dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db) panic(r) } }() if _, err = dao.UpdateEntity(db, newOrder); err != nil { dao.Rollback(db) return nil, err } for _, sku := range newOrder.Skus { if _, err = dao.UpdateEntity(db, sku); err != nil { dao.Rollback(db) return nil, err } } dao.Commit(db) } } return retVal, err }, orderList) tasksch.HandleTask(task, nil, true).Run() if isAsync { hint = task.GetID() } else { _, err = task.GetResult(0) hint = "1" } } return hint, err } type GetOrderSimpleInfoResult struct { VendorOrderID string `orm:"column(vendor_order_id)" json:"vendorOrderID"` Status int `json:"status"` WaybillVendorID int `orm:"column(waybill_vendor_id)" json:"waybillVendorID"` CourierName string `json:"courierName"` CourierMobile string `json:"courierMobile"` Tel1 string `json:"tel1"` MarketManPhone string `json:"marketManPhone"` } func GetOrderSimpleInfo(ctx *jxcontext.Context, vendorOrderID string) (getOrderSimpleInfoResult *GetOrderSimpleInfoResult, err error) { db := dao.GetDB() sql := ` SELECT a.vendor_order_id, a.status, a.waybill_vendor_id, c.courier_name, c.courier_mobile, b.tel1, b.market_man_phone FROM goods_order a JOIN store b ON IF(a.store_id <> '', a.store_id, a.jx_store_id) = b.id LEFT JOIN waybill c ON c.vendor_order_id = a.vendor_order_id WHERE a.vendor_order_id = ? ` sqlParams := []interface{}{vendorOrderID} err = dao.GetRow(db, &getOrderSimpleInfoResult, sql, sqlParams) if getOrderSimpleInfoResult == nil { return getOrderSimpleInfoResult, fmt.Errorf("未查询到该订单的信息!") } return getOrderSimpleInfoResult, err } func SaveJdsOrders(ctx *jxcontext.Context, orderCreatedStart, orderCreatedEnd time.Time) (err error) { var ( pageSize = 20 ) orderResult, err := jdshop.CurPurchaseHandler.GetJdsOrders(ctx, utils.Time2Str(orderCreatedStart), utils.Time2Str(orderCreatedEnd), 1, pageSize) if err != nil { noticeMsg := fmt.Sprintf("京东商城保存订单出错!(多半是cookie过期了),err :[%v]", err) ddmsg.SendUserMessage(dingdingapi.MsgTyeText, "DDC5657B43EE11E9A9FF525400E86DC0", "cookie", noticeMsg) ddmsg.SendUserMessage(dingdingapi.MsgTyeText, "1439B3E07D3911EA881A525400E86DC0", "cookie", noticeMsg) return err } orders, err := result2Orders(ctx, orderResult) if orderResult.TotalCount > pageSize { for pageNO := 2; pageNO < orderResult.TotalCount/pageSize+1; pageNO++ { orderResult, _ := jdshop.CurPurchaseHandler.GetJdsOrders(ctx, utils.Time2Str(orderCreatedStart), utils.Time2Str(orderCreatedEnd), pageNO, pageSize) orders2, _ := result2Orders(ctx, orderResult) orders = append(orders, orders2...) } } for _, order := range orders { order.StoreID = 102919 order.JxStoreID = 102919 order.StoreName = "商城模板(成都发货)" order.VendorStoreID = model.JdShopMainVendorStoreID partner.CurOrderManager.OnOrderNew(order, model.Order2Status(order)) globals.SugarLogger.Debugf("SaveJdsOrders, order: [%v]", utils.Format4Output(order, false)) noticeMsg := fmt.Sprintf("京东商城新订单,订单号:[%v] ,将要发到的门店id:[%v] , 门店名:[%v]", order.VendorOrderID, order.StoreID, order.StoreName) ddmsg.SendUserMessage(dingdingapi.MsgTyeText, "DDC5657B43EE11E9A9FF525400E86DC0", "京东商城来新订单了!", noticeMsg) ddmsg.SendUserMessage(dingdingapi.MsgTyeText, "1439B3E07D3911EA881A525400E86DC0", "京东商城来新订单了!", noticeMsg) } return err } func result2Orders(ctx *jxcontext.Context, result *jdshopapi.AllOrdersResult) (orders []*model.GoodsOrder, err error) { for _, jdsOrder := range result.OrderList { //等待付款的排除 if jdsOrder.OrderStatus != jdshopapi.JdsOrderStatusWaittingExport && jdsOrder.OrderStatus != jdshopapi.JdsOrderStatusPause { continue } //有可能是库里已经有这个订单了 orderE, err := partner.CurOrderManager.LoadOrder(utils.Int64ToStr(jdsOrder.OrderID)+"01", model.VendorIDJDShop) if orderE != nil { continue } orderDetail, err := api.JdShopAPI.OrderDetail(utils.Int64ToStr(jdsOrder.OrderID)) if err != nil { globals.SugarLogger.Debugf("jds OrderDetail error: %v", err.Error()) continue } order := &model.GoodsOrder{ VendorOrderID2: utils.Int64ToStr(jdsOrder.OrderID), VendorOrderID: utils.Int64ToStr(jdsOrder.OrderID) + "000001", VendorID: model.VendorIDJDShop, BaseFreightMoney: jxutils.StandardPrice2Int(jdsOrder.Freight), VendorStatus: utils.Int2Str(jdsOrder.OrderStatus), VendorUserID: jdsOrder.UserPin, BuyerComment: jdsOrder.UserRemark, PickDeadline: utils.DefaultTimeValue, OriginalData: string(utils.MustMarshal(jdsOrder)), StoreName: jdsOrder.StoreName, OrderCreatedAt: utils.Str2Time(jdsOrder.OrderCreateTime + ":00"), ConsigneeAddress: orderDetail.ConsigneeAddress, ConsigneeName: orderDetail.ConsigneeName, ActualPayPrice: orderDetail.ActualPayPrice, Status: model.OrderStatusNew, TotalShopMoney: utils.Float64TwoInt64(math.Round(utils.Int64ToFloat64(orderDetail.ActualPayPrice) * jdshopapi.JdsPayPercentage)), DeliveryFlag: model.OrderDeliveryFlagMaskScheduleDisabled, DeliveryType: model.OrderDeliveryTypeStoreSelf, StatusTime: utils.Str2Time(jdsOrder.OrderCreateTime + ":00"), OrderSeq: 0, } //获取真实手机号 fakeMobile, err := api.JdShopAPI.PhoneSensltiveInfo(order.VendorOrderID2, orderDetail.MobileKey) if err != nil { globals.SugarLogger.Debugf("jds PhoneSensltiveInfo error: %v", err.Error()) continue } else { order.ConsigneeMobile = jxutils.DecryptDESECB([]byte(fakeMobile), []byte(jdshopapi.JdsMobileKey)) } if order.TotalShopMoney < 100 { order.TotalShopMoney = 100 } if order.ConsigneeAddress != "" { lng, lat, _ := api.AutonaviAPI.GetCoordinateFromAddress(order.ConsigneeAddress, "") order.ConsigneeLng = jxutils.StandardCoordinate2Int(lng) order.ConsigneeLat = jxutils.StandardCoordinate2Int(lat) } storeList, err := common.GetStoreListByLocation(ctx, jxutils.IntCoordinate2Standard(order.ConsigneeLng), jxutils.IntCoordinate2Standard(order.ConsigneeLat), 5000, false, true) if err != nil { globals.SugarLogger.Debugf("jds GetStoreListByLocation error: %v", err.Error()) continue } order.StoreID = storeList[0].ID order.StoreName = storeList[0].Name storeMaps, _ := dao.GetStoresMapList(dao.GetDB(), []int{model.VendorIDJDShop}, []int{order.StoreID}, nil, model.StoreStatusAll, model.StoreIsSyncAll, "", "") if len(storeMaps) > 0 { order.VendorStoreID = storeMaps[0].VendorStoreID } //如果是暂停,表示是预订单 if jdsOrder.OrderStatus == jdshopapi.JdsOrderStatusPause { order.BusinessType = model.BusinessTypeDingshida order.ExpectedDeliveredTime = utils.Str2Time(orderDetail.ExpectedDeliveredTime) order.PickDeadline = order.ExpectedDeliveredTime.Add(-time.Hour) } else if jdsOrder.OrderStatus == jdshopapi.JdsOrderStatusWaittingExport { order.ExpectedDeliveredTime = order.OrderCreatedAt.Add(time.Hour) order.BusinessType = model.BusinessTypeImmediate } else { globals.SugarLogger.Errorf("未知的京东商城订单状态!status : %v", jdsOrder.OrderStatus) } //结算类型 storeDetail, _ := dao.GetStoreDetail(dao.GetDB(), order.StoreID, model.VendorIDJDShop) if storeDetail != nil { if storeDetail.PayPercentage < 50 { order.EarningType = model.EarningTypePoints } else { order.EarningType = model.EarningTypeQuote } } setJdsOrderSeq(order) for _, v := range jdsOrder.OrderItems { sku := &model.OrderSku{ VendorID: model.VendorIDJDShop, VendorOrderID: order.VendorOrderID, Count: v.SkuNum, VendorSkuID: utils.Int64ToStr(v.SkuID), SkuName: v.SkuName, VendorPrice: jxutils.StandardPrice2Int(v.JdPrice), SalePrice: jxutils.StandardPrice2Int(v.JdPrice), } var storeSku *model.StoreSkuBind sql := ` SELECT * FROM store_sku_bind WHERE store_id = ? AND jds_id = ? AND deleted_at = ? ` sqlParams := []interface{}{model.JdShopMainStoreID, v.SkuID, utils.DefaultTimeValue} err = dao.GetRow(dao.GetDB(), &storeSku, sql, sqlParams) if storeSku != nil { sku.SkuID = storeSku.SkuID } _, _, _, specUnit, _, specQuality := jxutils.SplitSkuName(v.SkuName) sku.Weight = jxutils.FormatSkuWeight(specQuality, specUnit) order.Skus = append(order.Skus, sku) } orders = append(orders, order) } return orders, err } func setJdsOrderSeq(order *model.GoodsOrder) (err error) { type tCount struct { Count int `json:"count"` } var count = &tCount{} sql := ` SELECT count(*) count FROM goods_order WHERE store_id = ? AND order_create_at >= ? AND order_create_at <= ? AND vendor_id = ? ` sqlParams := []interface{}{ order.StoreID, utils.Time2Date(time.Now()), utils.Time2Date(time.Now().AddDate(0, 0, 1)), order.VendorID, } err = dao.GetRow(dao.GetDB(), &count, sql, sqlParams) order.OrderSeq = count.Count + 1 return err } func TransferJdsOrder(ctx *jxcontext.Context, vendorOrderID string, storeID int) (vendorOrderIDJds string, err error) { globals.SugarLogger.Debugf("jds TransferJdsOrder vendorOrderID: %v, storeID : %v", vendorOrderID, storeID) var ( db = dao.GetDB() waybill *model.Waybill ) order, err := dao.GetSimpleOrder(db, vendorOrderID) if err != nil || order == nil { return "", fmt.Errorf("未查询到该订单!订单号:[%v]", vendorOrderID) } if order.Status >= model.OrderStatusDelivering && order.Status != model.OrderStatusCanceled { return "", fmt.Errorf("暂不支持此状态的订单进行转移!") } if order.VendorID != model.VendorIDJDShop { return "", fmt.Errorf("暂不支持非京狗的订单进行转移!") } skus, err := dao.GetSimpleOrderSkus(db, vendorOrderID, nil) if err != nil || order == nil { return "", fmt.Errorf("未查询到该订单商品!订单号:[%v]", vendorOrderID) } //将订单和运单取消 waybills, err := dao.GetWaybills(db, vendorOrderID) if err != nil { return "", err } if len(waybills) > 0 { for _, v := range waybills { if v.Status != model.WaybillStatusCanceled { waybill = v } } if waybill != nil { if waybill.WaybillVendorID != model.VendorIDJDWL { handler := partner.DeliveryPlatformHandlers[waybill.WaybillVendorID] err = handler.Handler.CancelWaybill(waybill, 0, "订单转移被取消") if err != nil { return "", err } } } } err = jdshop.ChangeOrderStatus(vendorOrderID, model.OrderStatusCanceled, "订单转移被取消") if err != nil { return "", err } //重新构建order的数据 storeMaps, err := dao.GetStoresMapList(db, []int{order.VendorID}, []int{storeID}, nil, model.StoreStatusAll, model.StoreIsSyncAll, "", "") if err != nil || len(storeMaps) == 0 { return "", fmt.Errorf("该门店未绑定京狗平台,请先绑定后再转移!门店:[%v]", storeID) } stores, err := dao.GetStoreList(db, []int{storeID}, nil, nil, nil, "") if len(storeMaps) > 0 && len(stores) > 0 { if storeMaps[0].VendorStoreID == "" { return "", fmt.Errorf("该门店未绑定京狗平台,或绑定有误,请联系技术部!门店:[%v]", storeID) } order.StoreID = storeID order.StoreName = stores[0].Name order.VendorStoreID = storeMaps[0].VendorStoreID //如果是立即达的订单,要判断一下下单时间是否在门店营业时间范围内 //若没有,则要把这个订单变成定时达,预计送达时间改为门店的营业时间 //如果门店没有营业时间,则直接报错 if order.BusinessType == model.BusinessTypeImmediate { store := stores[0] var ( opentime1 = jxutils.JxOperationTime2TimeByDate(store.OpenTime1, order.OrderCreatedAt) opentime2 = jxutils.JxOperationTime2TimeByDate(store.OpenTime2, order.OrderCreatedAt) closetime1 = jxutils.JxOperationTime2TimeByDate(store.CloseTime1, order.OrderCreatedAt) closetime2 = jxutils.JxOperationTime2TimeByDate(store.CloseTime2, order.OrderCreatedAt) orderCreatedAt = order.OrderCreatedAt ) if store.OpenTime1 == 0 || store.CloseTime1 == 0 { return "", fmt.Errorf("该门店没有营业时间,不能接单!门店:[%v]", storeID) } if !(orderCreatedAt.Sub(opentime1) >= 0 && orderCreatedAt.Sub(closetime1) <= 0) { if store.OpenTime2 != 0 && store.CloseTime2 != 0 { if !(orderCreatedAt.Sub(opentime2) >= 0 && orderCreatedAt.Sub(closetime2) <= 0) { if orderCreatedAt.Sub(opentime1) < 0 { order.ExpectedDeliveredTime = opentime1 order.BusinessType = model.BusinessTypeDingshida } else { if orderCreatedAt.Sub(opentime2) < 0 { order.ExpectedDeliveredTime = opentime2 } else { order.ExpectedDeliveredTime = opentime1.AddDate(0, 0, 1) } order.BusinessType = model.BusinessTypeDingshida } } } else { if orderCreatedAt.Sub(opentime1) < 0 { order.ExpectedDeliveredTime = opentime1 } else { order.ExpectedDeliveredTime = opentime1.AddDate(0, 0, 1) } order.BusinessType = model.BusinessTypeDingshida } } } //结算类型 if stores[0].PayPercentage < 50 { order.EarningType = model.EarningTypePoints } else { order.EarningType = model.EarningTypeQuote } } else { return "", fmt.Errorf("未查询到该门店对应的平台信息!门店:[%v]", order.StoreID) } if len(order.VendorOrderID) > 12 { var goodsOrders []*model.GoodsOrder sql := ` SELECT * FROM goods_order WHERE vendor_order_id2 = ? ORDER BY vendor_order_id DESC ` sqlParams := []interface{}{order.VendorOrderID2} err = dao.GetRows(db, &goodsOrders, sql, sqlParams) if goodsOrders[0].Status != model.OrderStatusCanceled { err = jdshop.ChangeOrderStatus(goodsOrders[0].VendorOrderID, model.OrderStatusCanceled, "订单转移被取消") } suffix := utils.Str2Int(goodsOrders[0].VendorOrderID[12:len(goodsOrders[0].VendorOrderID)]) suffix++ order.VendorOrderID = utils.Int64ToStr(utils.Str2Int64(order.VendorOrderID2)*100000) + utils.Int2Str(suffix) } for _, sku := range skus { sku.VendorOrderID = order.VendorOrderID sku.ID = 0 order.Skus = append(order.Skus, sku) } if storeID != model.JdShopMainStoreID { order.DeliveryFlag = model.NO } order.Status = model.OrderStatusNew setJdsOrderSeq(order) err = partner.CurOrderManager.OnOrderNew(order, model.Order2Status(order)) vendorOrderIDJds = order.VendorOrderID return vendorOrderIDJds, err } func SendJdwlForJdsOrder(ctx *jxcontext.Context, vendorOrderID string) (err error) { db := dao.GetDB() order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, model.VendorIDJDShop) if order == nil || err != nil { return fmt.Errorf("目前只支持京狗订单创建!") } if order.Status >= model.OrderStatusDelivering { return fmt.Errorf("订单当前状态不支持创建!") } waybill := &model.Waybill{} waybills, err := dao.GetWaybills(db, vendorOrderID) if err != nil { return err } if len(waybills) > 0 { for _, v := range waybills { if v.Status != model.WaybillStatusCanceled { waybill = v } } handler := partner.DeliveryPlatformHandlers[waybill.WaybillVendorID] err = handler.Handler.CancelWaybill(waybill, 0, "订单已发送其他物流") if err != nil { return err } } var vendorWaybillID string if order.StoreID == model.JdShopMainStoreID { var ( goodsNos []string prices []string quantities []string ) for _, v := range order.Skus { skus, err := dao.GetSkus(db, []int{v.SkuID}, nil, nil, nil, nil) if err != nil || len(skus) == 0 { continue } goodsNos = append(goodsNos, skus[0].EclpID) prices = append(prices, "0") quantities = append(quantities, utils.Int2Str(v.Count)) } eclpSoNo, err := api.JdEclpAPI.AddOrder(&jdeclpapi.AddOrderParam{ IsvUUID: order.VendorOrderID, IsvSource: jdeclpapi.IsvSource, ShopNo: jdeclpapi.ShopNo, DepartmentNo: jdeclpapi.DepartmentNo, WarehouseNo: jdeclpapi.WarehouseNo, SalesPlatformOrderNo: order.VendorOrderID, SalePlatformSource: jdeclpapi.SalePlatformSource, ConsigneeName: order.ConsigneeName, ConsigneeMobile: order.ConsigneeMobile, ConsigneeAddress: order.ConsigneeAddress, OrderMark: jdeclpapi.OrderMark, GoodsNo: strings.Join(goodsNos, ","), Price: strings.Join(prices, ","), Quantity: strings.Join(quantities, ","), }) waybill := &model.Waybill{ VendorOrderID: order.VendorOrderID, OrderVendorID: model.VendorIDJX, VendorWaybillID: eclpSoNo, WaybillVendorID: model.VendorIDJDWL, Status: model.WaybillStatusDelivering, WaybillCreatedAt: time.Now(), StatusTime: time.Now(), WaybillFinishedAt: utils.DefaultTimeValue, DeliveryFlag: model.OrderDeliveryFlagMaskScheduleDisabled, } dao.CreateEntity(db, waybill) if err != nil { return err } order.EclpOutID = eclpSoNo dao.UpdateEntity(db, order, "EclpOutID") vendorWaybillID = eclpSoNo } else { handler := partner.DeliveryPlatformHandlers[model.VendorIDJDWL] waybill2, err := handler.Handler.CreateWaybill(order, 0) if err != nil { return err } vendorWaybillID = waybill2.VendorWaybillID } jdshop.CurPurchaseHandler.OrderExport(ctx, vendorOrderID, vendorWaybillID, false) return err } func AdjustJdsOrderSimple(ctx *jxcontext.Context, vendorOrderID string, skuID int) (err error) { var ( db = dao.GetDB() ) orderSkus, err := dao.GetSimpleOrderSkus(db, vendorOrderID, []int{skuID}) order, err := dao.GetSimpleOrder(db, vendorOrderID) orderSkus2, err := dao.GetSimpleOrderSkus(db, vendorOrderID, nil) if len(orderSkus2) == 1 { return fmt.Errorf("这一单只剩这最后一个商品了,不允许删除!") } if len(orderSkus) == 0 { return fmt.Errorf("未查询到该订单商品!") } if order.Status > model.OrderStatusAccepted { return fmt.Errorf("目前只支持待拣货状态前的订单售前调整!") } orderSku := orderSkus[0] if orderSku.Count > 1 { orderSku.Count-- _, err = dao.UpdateEntity(db, orderSku, "Count") } else { _, err = dao.DeleteEntity(db, orderSku) } return err } func UpdateWaybillDesiredFee(ctx *jxcontext.Context, vendorOrderID string, desiredFee int) (err error) { var ( db = dao.GetDB() ) order, _ := dao.GetSimpleOrder(db, vendorOrderID) if order == nil { return fmt.Errorf("未找到该订单!orderID: %v", vendorOrderID) } bill, _ := partner.CurOrderManager.LoadWaybill(order.VendorWaybillID, order.WaybillVendorID) if bill == nil { waybill := &model.Waybill{ VendorOrderID: order.VendorOrderID, OrderVendorID: order.VendorID, VendorWaybillID: "-1", WaybillVendorID: -1, Status: model.WaybillStatusDelivered, WaybillCreatedAt: time.Now(), StatusTime: time.Now(), WaybillFinishedAt: utils.DefaultTimeValue, DeliveryFlag: model.OrderDeliveryFlagMaskScheduleDisabled, DesiredFee: int64(desiredFee), } dao.CreateEntity(db, waybill) order.VendorWaybillID = "-1" dao.UpdateEntity(db, order, "VendorWaybillID") } else { bill.DesiredFee = int64(desiredFee) _, err = dao.UpdateEntity(db, bill, "DesiredFee") } return err }