package orderman import ( "crypto/md5" "errors" "fmt" "git.rosy.net.cn/jx-callback/business/authz/autils" "git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg" "git.rosy.net.cn/jx-callback/globals/api2" beego "github.com/astaxie/beego/server/web" "math" "strings" "time" "git.rosy.net.cn/baseapi/platformapi/dingdingapi" "git.rosy.net.cn/baseapi/platformapi/jdeclpapi" "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/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/client/orm" ) var ( orderNoBeginTimestamp int64 ) func init() { orderNoBeginTimestamp = utils.Str2Time("2010-01-01 00:00:00").Unix() } 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() txDB, _ := dao.Begin(db) defer func() { globals.SugarLogger.Debugf("OnOrderNew exit orderID:%s", order.VendorOrderID) if r := recover(); r != nil { dao.Rollback(db, txDB) 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, txDB) if !isDuplicated { err = scheduler.CurrentScheduler.OnOrderNew(order, false, false) } } else { dao.Rollback(db, txDB) } 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() txDB, _ := dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db, txDB) 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 //扣点的订单需要修改订单的totalshopmoney if err == nil && order.OrderPayPercentage < 50 && order.OrderPayPercentage > 0 { order2, _ := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).GetOrder(order.VendorOrgCode, order.VendorOrderID, order.VendorStoreID) order.TotalShopMoney = order2.TotalShopMoney } isDuplicated, err = c.SaveOrder(order, true, db) } if err == nil { dao.Commit(db, txDB) if !isDuplicated { // 因为订单调度器需要的是真实状态,所以用order的状态 _ = scheduler.CurrentScheduler.OnOrderNew(order, false, false) _ = scheduler.CurrentScheduler.OnOrderStatusChanged(order, orderStatus, false) } } else { dao.Rollback(db, txDB) } return err } func (c *OrderManager) OnOrderStatusChanged(vendorOrgCode string, orderStatus *model.OrderStatus) (err error) { // 有些平台(比如美团外卖),在新订单事件没有成功返回,但在重发订单消息前,订单状态转换,则不会再重发新订单事件,特殊处理一下 if orderStatus != nil { 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() txDB, _ := dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db, txDB) panic(r) } }() isDuplicated, order, err := c.addOrderStatus(orderStatus, db) if err == nil { dao.Commit(db, txDB) 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.NewEarningPrice == 0 || order.NewEarningPrice != order.TotalShopMoney*int64(100-order.OrderPayPercentage/2)/int64(100)) && order.OrderPayPercentage <= 50 { order.NewEarningPrice = order.TotalShopMoney * int64(100-order.OrderPayPercentage/2) / int64(100) } } else { if (order.NewEarningPrice == 0 || order.NewEarningPrice != (order.TotalShopMoney-waybill.DesiredFee)*int64(100-order.OrderPayPercentage/2)/int64(100)) && order.OrderPayPercentage <= 50 { order.NewEarningPrice = order.TotalShopMoney*int64(100-order.OrderPayPercentage/2)/int64(100) - waybill.DesiredFee } } 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) //门店发单的订单,取消后要退回配送费 resetCreateWaybillFee(db, order) } } if !isDuplicated { if order != nil { order.Skus = c.loadOrderSku(db, order.VendorOrderID, order.VendorID) _ = scheduler.CurrentScheduler.OnOrderStatusChanged(order, orderStatus, false) } } } else { dao.Rollback(db, txDB) } 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) // 忽略美团超市的订单 if order.VendorID == model.VendorIDMTWM { if order.VendorStoreID == "2391979" || order.VendorStoreID == "7379027" { return } } // 忽略查找JX信息错误 c.updateOrderOtherInfo(order, db) order.ID = 0 order.WaybillVendorID = model.VendorIDUnknown order.OrderFinishedAt = utils.DefaultTimeValue setFakeOrderFlag(db, order) // cms.HandleOrder4Consignee(order) txDB, _ := dao.Begin(db) defer func() { if r := recover(); r != nil || err != nil { dao.Rollback(db, txDB) 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) } } } else { //globals.SugarLogger.Warnf("saveOrder create order:%v, error:%v", order, err) } //修改商品库存 //if err == nil { // err = ModifyOrderSkusStock(db, order, false) //} if err == nil { dao.Commit(db, txDB) } 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 { // if !isAdd { // globals.SugarLogger.Warnf("此订单商品没得storsku,%v,%v", order.VendorOrderID, sku.SkuID) // } continue } storeSku, stock := storeSkus[0], 0 if storeSku.Stock == 0 { if !isAdd { // 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(storeSkus2) > 0 { storeSku3 := storeSkus2[0] storeSku3.Stock = storeSku3.Stock + sku.Count db.Db.Update(storeSku3, "Stock") } } realStock := checkPriceDefendOrderByStock(db, jxutils.GetSaleStoreIDFromOrder(order), sku.SkuID, stock, storeSku.JxPrice) if realStock != -1 { stock = realStock } } storeSku.Stock = stock db.Db.Update(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 resetCreateWaybillFee(db *dao.DaoDB, order *model.GoodsOrder) (err error) { store, _ := dao.GetStoreDetail(db, jxutils.GetSaleStoreIDFromOrder(order), order.VendorID, order.VendorOrgCode) if store != nil && store.CreateDeliveryType == model.YES { if expend, lastFee, err := partner.CurStoreAcctManager.GetStoreAcctExpendLastCreateWayBillFee(order.VendorOrderID); err == nil && expend != nil { partner.CurStoreAcctManager.InsertStoreAcctIncomeAndUpdateStoreAcctBalance(jxcontext.AdminCtx, jxutils.GetSaleStoreIDFromOrder(order), lastFee, partner.StoreAcctTypeIncomeCancelReal, order.VendorOrderID, expend.ID) } } return err } func checkPriceDefendOrderByStock(db *dao.DaoDB, storeID, skuID, stock, jxPrice int) (realStock int) { var ( sumStock = 0 ) priceDefends, _ := dao.GetPriceDefendOrder(db, "", []int{storeID}, []int{skuID}, []int{jxutils.GetDefendPriceIssue()}, 0, 1, 0, 1, "", utils.ZeroTimeValue, utils.ZeroTimeValue, false) if len(priceDefends) == 0 { return -1 } for _, v := range priceDefends { sumStock += v.Count } //如果现库存小于等于用户守价的库存,就要开始了 //如果小于,要按照守价时间的先后来决定 //如果等于,就刚好全部成功,然后库存清0 if stock < sumStock { tStock := stock for _, v := range priceDefends { if tStock <= v.Count { tStock -= v.Count v.IsSuccess = model.YES v.RealPrice = int64(jxPrice) dao.UpdateEntity(db, v, "IsSuccess", "RealPrice") } else { continue } } realStock = tStock } else if stock == sumStock { for _, v := range priceDefends { v.IsSuccess = model.YES v.RealPrice = int64(jxPrice) dao.UpdateEntity(db, v, "IsSuccess", "RealPrice") } realStock = 0 //库存清0 } else { realStock = -1 } return realStock } 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 && order.VendorOrgCode == "1" { 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 { if v.SkuID == 0 && v.JxSkuID != 0 { v.SkuID = v.JxSkuID } // 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 { // 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) // } // } // } // } } 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 var storeDetail *dao.StoreDetail if order.VendorID == model.VendorIDJDShop { storeDetail, err = dao.GetStoreDetailByVendorStoreID(db, order.VendorStoreID, order.VendorID, order.VendorOrgCode) } else { 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 changePriceType = int(storeDetail.ChangePriceType) //判断订单结算比例 if storeDetail.VendorPayPercentage != 0 { payPercentage = storeDetail.VendorPayPercentage } else { payPercentage = storeDetail.PayPercentage } if payPercentage < 50 { order.EarningType = model.EarningTypePoints } else { order.EarningType = model.EarningTypeQuote } order.OrderPayPercentage = payPercentage order.CreateDeliveryType = storeDetail.CreateDeliveryType } 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) txDB, _ := dao.Begin(db) defer func() { if r := recover(); r != nil || err != nil { dao.Rollback(db, txDB) 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, txDB) 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 txDB, _ := dao.Begin(db) defer func() { if r := recover(); r != nil || err != nil { dao.Rollback(db, txDB) 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, txDB) 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 { txDB, _ := dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db, txDB) panic(r) } }() if _, err = dao.UpdateEntity(db, newOrder); err != nil { dao.Rollback(db, txDB) return nil, err } for _, sku := range newOrder.Skus { if _, err = dao.UpdateEntity(db, sku); err != nil { dao.Rollback(db, txDB) return nil, err } } dao.Commit(db, txDB) } } 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 LIKE ? OR a.consignee_mobile LIKE ?) ORDER BY a.order_created_at DESC LIMIT 1 ` sqlParams := []interface{}{ "%" + vendorOrderID + "%", "%" + vendorOrderID + "%", } err = dao.GetRow(db, &getOrderSimpleInfoResult, sql, sqlParams) if getOrderSimpleInfoResult == nil { return getOrderSimpleInfoResult, fmt.Errorf("未查询到该订单的信息!") } return getOrderSimpleInfoResult, err } func setJdsOrderSeq(order *model.GoodsOrder) (err error) { type tCount struct { Count int `json:"count"` } var counts []*tCount sql := ` SELECT count(*) count FROM goods_order WHERE store_id = ? AND order_created_at >= ? AND order_created_at <= ? AND vendor_id = ? ` sqlParams := []interface{}{ order.StoreID, utils.Time2Date(time.Now()), utils.Time2Date(time.Now().AddDate(0, 0, 1)), order.VendorID, } err = dao.GetRows(dao.GetDB(), &counts, sql, sqlParams) order.OrderSeq = counts[0].Count + 1 return err } func MergeJdsOrders(ctx *jxcontext.Context, vendorOrderIDs []string) (vendorOrderIDJds string, err error) { globals.SugarLogger.Debugf("jds MergeJdsOrders vendorOrderIDs: %v", vendorOrderIDs) var ( db = dao.GetDB() orders []*model.GoodsOrder orderSkus []*model.OrderSku orderIDs []string storeDuplicate = make(map[int]int) storeID int ) for _, vendorOrderID := range vendorOrderIDs { order, _ := 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("暂不支持此状态的订单进行转移!订单号:[%v]", vendorOrderID) } if order.VendorID != model.VendorIDJDShop { return "", fmt.Errorf("暂不支持非京狗的订单进行转移!订单号:[%v]", vendorOrderID) } storeDuplicate[jxutils.GetSaleStoreIDFromOrder(order)] = jxutils.GetSaleStoreIDFromOrder(order) orders = append(orders, order) //订单商品 skus, _ := dao.GetSimpleOrderSkus(db, order.VendorOrderID, nil) orderSkus = append(orderSkus, skus...) orderIDs = append(orderIDs, vendorOrderID) } if len(storeDuplicate) > 1 { return "", fmt.Errorf("只能选择相同门店的订单进行合并!") } else { storeID = jxutils.GetSaleStoreIDFromOrder(orders[0]) } for _, order := range orders { var waybill *model.Waybill //将订单和运单取消 waybills, err := dao.GetWaybills(db, order.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 { if handler := partner.GetDeliveryPlatformFromVendorID(waybill.WaybillVendorID); handler != nil { err = handler.Handler.CancelWaybill(waybill, 0, "订单合并被取消") } } } } if err = jdshop.ChangeOrderStatus(order.VendorOrderID, model.OrderStatusCanceled, "订单合并被取消"); err != nil { return "", err } } //重新构建order的数据 storeMaps, err := dao.GetStoresMapList(db, []int{model.VendorIDJDShop}, []int{storeID}, nil, model.StoreStatusAll, model.StoreIsSyncAll, "", "", "") if err != nil || len(storeMaps) == 0 { return "", fmt.Errorf("该门店未绑定京狗平台,请先绑定后再转移!门店:[%v]", storeID) } stores, _ := dao.GetStoreList(db, []int{storeID}, nil, nil, nil, nil, "") var ( newEarningPrice int64 actualPrice int64 shopPrice int64 salePrice int64 totalShop int64 ) for _, v := range orders { newEarningPrice += v.NewEarningPrice actualPrice += v.ActualPayPrice shopPrice += v.ShopPrice salePrice += v.SalePrice totalShop += v.TotalShopMoney } store := stores[0] order := orders[0] order.ID = 0 order.NewEarningPrice = newEarningPrice order.ActualPayPrice = actualPrice order.SalePrice = salePrice order.ShopPrice = shopPrice order.TotalShopMoney = totalShop order.VendorOrderID = utils.Int64ToStr(utils.Str2Int64(orders[0].VendorOrderID2)*10000000) + utils.Int2Str(time.Now().Second()) if len(order.VendorOrderID) < 18 { order.VendorOrderID = order.VendorOrderID + "0" } order.VendorOrderID2 = strings.Join(orderIDs, ",") order.Status = model.OrderStatusNew setJdsOrderSeq(order) if order.BusinessType == model.BusinessTypeImmediate { var ( opentime1 = jxutils.JxOperationTime2TimeByDate(store.OpenTime1, order.CreatedAt) opentime2 = jxutils.JxOperationTime2TimeByDate(store.OpenTime2, order.CreatedAt) closetime1 = jxutils.JxOperationTime2TimeByDate(store.CloseTime1, order.CreatedAt) closetime2 = jxutils.JxOperationTime2TimeByDate(store.CloseTime2, order.CreatedAt) orderCreatedAt = order.CreatedAt ) 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 store.PayPercentage < 50 { order.EarningType = model.EarningTypePoints } else { order.EarningType = model.EarningTypeQuote } if storeID != model.JdShopMainStoreID { order.DeliveryFlag = model.NO } //skus for _, sku := range orderSkus { sku.VendorOrderID = order.VendorOrderID sku.ID = 0 } order.Skus = orderSkus err = partner.CurOrderManager.OnOrderNew(order, model.Order2Status(order)) vendorOrderIDJds = order.VendorOrderID return vendorOrderIDJds, 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 && order.VendorID != model.VendorIDJX { 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 handler := partner.GetDeliveryPlatformFromVendorID(waybill.WaybillVendorID); handler != nil { err = handler.Handler.CancelWaybill(waybill, 0, "订单转移被取消") } } } //重新构建order的数据 storeMaps, err := dao.GetStoresMapList(db, []int{order.VendorID}, []int{storeID}, nil, model.StoreStatusAll, model.StoreIsSyncAll, "", "", order.VendorOrgCode) if err != nil || len(storeMaps) == 0 { return "", fmt.Errorf("该门店未绑定平台,请先绑定后再转移!门店:[%v]", storeID) } stores, err := dao.GetStoreList(db, []int{storeID}, nil, 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 closetime1.Sub(opentime1) <= time.Hour { 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 order.VendorID == model.VendorIDJDShop { 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) for _, order := range goodsOrders { if order.Status != model.OrderStatusCanceled { err = jdshop.ChangeOrderStatus(order.VendorOrderID, model.OrderStatusCanceled, "订单转移被取消") } } // suffix := utils.Str2Int(goodsOrders[0].VendorOrderID[12:len(goodsOrders[0].VendorOrderID)]) // suffix++ if len(order.VendorOrderID2) > 18 { order.VendorOrderID2 = order.VendorOrderID2[0:12] } order.VendorOrderID = utils.Int64ToStr(utils.Str2Int64(order.VendorOrderID2)*10000000) + utils.Int2Str(time.Now().Second()) if len(order.VendorOrderID) < 18 { order.VendorOrderID = order.VendorOrderID + "0" } } if storeID != model.JdShopMainStoreID { order.DeliveryFlag = model.NO } err = jdshop.ChangeOrderStatus(vendorOrderID, model.OrderStatusCanceled, "订单转移被取消") if err != nil { return "", err } order.Status = model.OrderStatusNew if order.ActualPayPrice == 0 { msg, err := jdshop.GetJdsOrder(order.VendorOrderID2, order.VendorOrgCode) if err == nil { if jxutils.StandardPrice2Int(utils.Str2Float64(msg.OrderPayment)) == 0 { order.ActualPayPrice = jxutils.StandardPrice2Int(utils.Str2Float64(msg.OrderTotalPrice) + utils.Str2Float64(msg.FreightPrice) - utils.Str2Float64(msg.SellerDiscount)) } else { order.ActualPayPrice = jxutils.StandardPrice2Int(utils.Str2Float64(msg.OrderPayment)) } order.TotalShopMoney = utils.Float64TwoInt64(float64(order.ActualPayPrice) * jdshopapi.JdsPayPercentage) } } } else { order.VendorOrderID2 = order.VendorOrderID order.VendorOrderID = utils.Int64ToStr(jxutils.GenOrderNo()) order.DeliveryFlag = model.NO orderStatus := &model.OrderStatus{ VendorOrderID: vendorOrderID, VendorID: model.VendorIDJX, OrderType: model.OrderTypeOrder, RefVendorOrderID: vendorOrderID, RefVendorID: model.VendorIDJX, VendorStatus: utils.Int2Str(model.OrderStatusCanceled), Status: model.OrderStatusCanceled, StatusTime: time.Now(), Remark: "订单转移被取消", } jxutils.CallMsgHandlerAsync(func() { err = partner.CurOrderManager.OnOrderStatusChanged(order.VendorOrgCode, orderStatus) }, jxutils.ComposeUniversalOrderID(vendorOrderID, model.VendorIDJX)) if err != nil { return "", err } if order.VendorOrgCode == "1" { order.Status = model.OrderStatusAccepted } else { order.Status = model.OrderStatusNew } } for _, sku := range skus { sku.VendorOrderID = order.VendorOrderID sku.ID = 0 var storesSku *model.StoreSkuBind sql := ` SELECT * FROM store_sku_bind WHERE deleted_at = ? AND store_id = ? AND jds_id = ? ` sqlParams := []interface{}{utils.DefaultTimeValue, model.JdShopMainStoreID, sku.VendorSkuID} if err = dao.GetRow(db, &storesSku, sql, sqlParams); err == nil && storesSku != nil { if realStoresSkus, err := dao.GetStoresSkusInfo(db, []int{storeID}, []int{storesSku.SkuID}); err == nil && len(realStoresSkus) > 0 { sku.ShopPrice = int64(realStoresSkus[0].Price) } } order.Skus = append(order.Skus, sku) } 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 } } if handler := partner.GetDeliveryPlatformFromVendorID(model.VendorIDJDWL); handler != nil { 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, ShipperNo: jdeclpapi.ShipperNo, 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 { // if handler := partner.GetDeliveryPlatformFromVendorID(model.VendorIDJDWL); handler != nil { // 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) //如果不是商城模板店 if jxutils.GetSaleStoreIDFromOrder(order) != model.JdShopMainStoreID { return fmt.Errorf("目前只支持商城模板店的简单售前删除!") } 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) } order.AdjustCount++ order.ActualPayPrice = order.ActualPayPrice - orderSku.SalePrice order.TotalShopMoney = int64(float64(order.ActualPayPrice) * jdshopapi.JdsPayPercentage) dao.UpdateEntity(db, order, "AdjustCount", "TotalShopMoney") 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: utils.Int64ToStr(GenOrderNo(ctx)), 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 = waybill.VendorWaybillID dao.UpdateEntity(db, order, "VendorWaybillID") } else { bill.DesiredFee = int64(desiredFee) _, err = dao.UpdateEntity(db, bill, "DesiredFee") if order.EarningType == model.EarningTypePoints { order.NewEarningPrice = order.NewEarningPrice - int64(desiredFee) _, err = dao.UpdateEntity(db, order, "NewEarningPrice") } } return err } func AcceptOrRefuseOrder(ctx *jxcontext.Context, vendorOrderID string, vendorID int, isAccept bool) (err error) { order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID) handler := partner.GetPurchaseOrderHandlerFromVendorID(vendorID) err = handler.AcceptOrRefuseOrder(order, isAccept, ctx.GetUserName()) if err == nil && isAccept && vendorID == model.VendorIDEBAI { // netprinter.PrintOrderByOrder(jxcontext.AdminCtx, order) // smsmsg.NotifyNewOrder(order) // smsmsg.NotifyNewUserOrder(order) // weixinmsg.NotifyNewOrder(order) // msghub.OnNewOrder(order) } return err } func GenOrderNo(ctx *jxcontext.Context) (orderNo int64) { const prefix = 88 const randPartNum = 1000 orderNo = time.Now().Unix() - orderNoBeginTimestamp // fmt.Println(orderNo) orderNo = orderNo * randPartNum md5Bytes := md5.Sum([]byte(utils.GetUUID())) randPart := 0 for k, v := range md5Bytes { randPart += int(v) << ((k % 3) * 8) } orderNo += int64(randPart % randPartNum) orderNo += int64(math.Pow10(int(math.Log10(float64(orderNo)))+1)) * prefix return orderNo } func RefreshJdsOrderConsigneeInfo(ctx *jxcontext.Context, vendorOrderID string) (err error) { order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, model.VendorIDJDShop) if order == nil { return fmt.Errorf("未查询到此京东商城订单!") } waybill, err := partner.CurOrderManager.LoadWaybill(order.VendorWaybillID, order.WaybillVendorID) if waybill != nil { return fmt.Errorf("已经创建了三方运单不允许修改联系人信息!") } jdsOrder, err := jdshop.GetJdsOrder(order.VendorOrderID2, order.VendorOrgCode) if err != nil { return err } if jdsOrder == nil { return fmt.Errorf("未查询到对应的京东商城订单!") } order.ConsigneeAddress = jdshop.Decrypt(jdsOrder.ConsigneeInfo.FullAddress, order.VendorOrgCode) order.ConsigneeName = jdshop.Decrypt(jdsOrder.ConsigneeInfo.Fullname, order.VendorOrgCode) order.ConsigneeMobile = jdshop.Decrypt(jdsOrder.ConsigneeInfo.Mobile, order.VendorOrgCode) order.ConsigneeMobile2 = jdshop.Decrypt(jdsOrder.ConsigneeInfo.Telephone, order.VendorOrgCode) order.BuyerComment = jdsOrder.OrderRemark if order.ConsigneeAddress != "" { lng, lat, _ := api.AutonaviAPI.GetCoordinateFromAddress(order.ConsigneeAddress, "") order.ConsigneeLng = jxutils.StandardCoordinate2Int(lng) order.ConsigneeLat = jxutils.StandardCoordinate2Int(lat) } partner.CurOrderManager.UpdateOrderFields(order, []string{"ConsigneeAddress", "ConsigneeName", "ConsigneeMobile", "ConsigneeMobile2", "BuyerComment", "ConsigneeLng", "ConsigneeLat"}) return err } func UpdateOrderInfo(ctx *jxcontext.Context, vendorOrderID string, vendorID int, payload map[string]interface{}) (num int64, err error) { var ( db = dao.GetDB() jxSubsidyMoney int64 ) order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID) if payload["consigneeLng"] != nil || payload["consigneeLat"] != nil { payload["consigneeLng"] = jxutils.StandardCoordinate2Int(utils.Interface2Float64WithDefault(payload["consigneeLng"], 0.0)) payload["consigneeLat"] = jxutils.StandardCoordinate2Int(utils.Interface2Float64WithDefault(payload["consigneeLat"], 0.0)) } if payload["expectedDeliveredTime"] != nil { payload["expectedDeliveredTime"] = utils.Str2Time(payload["expectedDeliveredTime"].(string)) } if payload["jxSubsidyMoney"] != nil { jxSubsidyMoney = utils.Interface2Int64WithDefault(payload["jxSubsidyMoney"], 0) if order.EarningType == model.EarningTypeQuote { payload["earningPrice"] = order.EarningPrice - order.JxSubsidyMoney + jxSubsidyMoney } } valid := dao.StrictMakeMapByStructObject(payload, order, ctx.GetUserName()) if len(valid) > 0 { txDB, _ := dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db, txDB) panic(r) } }() if num, err = dao.UpdateEntityByKV(db, order, valid, nil); err != nil { dao.Rollback(db, txDB) return 0, err } dao.Commit(db, txDB) } if payload["jxSubsidyMoney"] != nil { var ( userIDs []string ) storeDetail, _ := dao.GetStoreDetail(db, jxutils.GetSaleStoreIDFromOrder(order), order.VendorID, order.VendorOrgCode) if storeDetail != nil && storeDetail.Tel1 != "" { user, _ := dao.GetUserByID(db, "mobile", storeDetail.Tel1) if user != nil { userIDs = append(userIDs, user.UserID) } if storeDetail.Tel2 != "" { user2, _ := dao.GetUserByID(db, "mobile", storeDetail.Tel2) if user2 != nil { userIDs = append(userIDs, user2.UserID) } } } weixinmsg.SendUserMessage(jxcontext.AdminCtx, "订单补偿", fmt.Sprintf("您收到了%v元的订单补偿,订单号:[%v]", jxSubsidyMoney, order.VendorOrderID), userIDs, true, true) } return num, err } func RefreshOrderSkuInfo(ctx *jxcontext.Context, vendorOrderID string, vendorID, skuID int) (num int64, err error) { var ( db = dao.GetDB() shopPrice, earningPrice int64 ) order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID) if order.EarningType != model.EarningTypeQuote { return 0, fmt.Errorf("目前只支持报价订单有此操作!") } updateOrderSku := func(v *model.OrderSku, skuID2 int) (err error) { storeSkus, _ := dao.GetStoresSkusInfo(db, []int{jxutils.GetSaleStoreIDFromOrder(order)}, []int{skuID2}) if len(storeSkus) == 0 { return fmt.Errorf("未找到此门店商品!") } storeSku := storeSkus[0] //if v.ShopPrice == v.EarningPrice { if beego.BConfig.RunMode == "jxgy" { if v.SalePrice > v.ShopPrice { v.EarningPrice = int64(math.Round(float64(storeSku.Price) * float64(order.OrderPayPercentage) / 100)) } else { v.EarningPrice = int64(math.Round(float64(v.SalePrice) * float64(order.OrderPayPercentage) / 100)) } } else { v.EarningPrice = int64(math.Round(float64(storeSku.Price) * float64(order.OrderPayPercentage) / 100)) } //} v.ShopPrice = int64(storeSku.Price) dao.UpdateEntity(db, v, "ShopPrice", "EarningPrice") return err } for _, v := range order.Skus { if v.SkuID == 0 { if v.JxSkuID == skuID { err = updateOrderSku(v, skuID) } } else { if v.SkuID == skuID { err = updateOrderSku(v, skuID) } } } if err != nil { return 0, err } for _, v := range order.Skus { shopPrice += v.ShopPrice * int64(v.Count) earningPrice += v.EarningPrice * int64(v.Count) } order.ShopPrice = shopPrice order.EarningPrice = earningPrice num, err = dao.UpdateEntity(db, order, "ShopPrice", "EarningPrice") return num, 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, "BF09DB25350611EB89AC525400E86DC0", "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 { 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) if order.OrderType == model.OrderTypeAddressErr { noticeMsg += " 此订单地址有问题,需要矫正坐标!" } var role = autils.NewRole("jdshop", 0) userIDList, _ := api2.RoleMan.GetRoleUserList(role) for _, v := range userIDList { ddmsg.SendUserMessage(dingdingapi.MsgTyeText, v, "京东商城来新订单了!", noticeMsg) } } return err } func result2Orders(ctx *jxcontext.Context, result *jdshopapi.AllOrdersResult) (orders []*model.GoodsOrder, err error) { var ( db = dao.GetDB() ) for _, jdsOrder := range result.OrderList { //等待付款的排除 if jdsOrder.OrderStatus != jdshopapi.JdsOrderStatusWaittingExport && jdsOrder.OrderStatus != jdshopapi.JdsOrderStatusPause && jdsOrder.OrderStatus != 51 { continue } //有可能是库里已经有这个订单了 orderE, err := partner.CurOrderManager.LoadOrder(utils.Int64ToStr(jdsOrder.OrderID)+"00000001", model.VendorIDJDShop) if orderE != nil { continue } orderDetail, err := jdshop.GetAPI("2").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) + "00000001", 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, VendorOrgCode: "2", } //获取真实手机号 fakeMobile, err := jdshop.GetAPI("2").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 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.JdsOrderStatusWaittingPayDel { order.ExpectedDeliveredTime = order.OrderCreatedAt.Add(time.Hour) order.BusinessType = model.BusinessTypeImmediate } 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) } var store *dao.StoreDetail if jdsOrder.MdbStoreID != 0 { if store, err = dao.GetStoreDetailByVendorStoreID(db, utils.Int64ToStr(jdsOrder.MdbStoreID), model.VendorIDJDShop, "2"); store != nil && err == nil { order.StoreID = store.ID order.JxStoreID = store.ID order.StoreName = store.Name globals.SugarLogger.Debugf("jds GetStoreListByLocation, orderID: %v storeID :%v", order.VendorOrderID, order.StoreID) //结算类型 if store.PayPercentage < 50 { order.EarningType = model.EarningTypePoints } else { order.EarningType = model.EarningTypeQuote } var ( shopPriceSum int ) for _, sku := range order.Skus { storeSkuList, _ := dao.GetStoresSkusInfo(db, []int{order.StoreID}, []int{sku.SkuID}) if len(storeSkuList) > 0 { shopPriceSum += storeSkuList[0].Price * sku.Count sku.ShopPrice = int64(storeSkuList[0].Price) } else { shopPriceSum += int(sku.SalePrice) * 70 / 100 } } if order.EarningType == model.EarningTypeQuote && shopPriceSum+700 > int(order.TotalShopMoney) { buildOrderTo102919(order) globals.SugarLogger.Debugf("resultjdsOrders return 2") } if order.ConsigneeAddress != "" { var ( cityCode = 0 lng, lat, lng2, lat2 float64 ) if shopDetail, _ := api.JdShopAPI.ShopDetail(int(jdsOrder.MdbStoreID)); shopDetail != nil { if shopDetail.AddCode2 != 0 { var place = &model.Place{} sql1 := "SELECT * FROM place WHERE jds_code = ?" sqlParams1 := []interface{}{shopDetail.AddCode2} if err2 := dao.GetRow(db, &place, sql1, sqlParams1); err2 == nil && place != nil { cityCode = place.JdsCode } else { sql2 := "SELECT * FROM place WHERE jd_code = ?" sqlParams2 := []interface{}{shopDetail.AddCode2} if err3 := dao.GetRow(db, &place, sql2, sqlParams2); err3 == nil && place != nil { cityCode = place.JdCode } } } } if cityCode != 0 { lng, lat, _ = api.AutonaviAPI.GetCoordinateFromAddressByPage(order.ConsigneeAddress, cityCode) } else { lng2, lat2, _ = api.AutonaviAPI.GetCoordinateFromAddress(order.ConsigneeAddress, "") order.ConsigneeLng = jxutils.StandardCoordinate2Int(lng2) order.ConsigneeLat = jxutils.StandardCoordinate2Int(lat2) } distance := jxutils.EarthDistance(lng, lat, lng2, lat2) if distance > 1 { order.OrderType = model.OrderTypeAddressErr } } } else { buildOrderTo102919(order) globals.SugarLogger.Debugf("resultjdsOrders return 5") } } else { buildOrderTo102919(order) globals.SugarLogger.Debugf("resultjdsOrders return 6") } if store != nil { distance := jxutils.EarthDistance(jxutils.IntCoordinate2Standard(order.ConsigneeLng), jxutils.IntCoordinate2Standard(order.ConsigneeLat), jxutils.IntCoordinate2Standard(store.Lng), jxutils.IntCoordinate2Standard(store.Lat)) if distance > 4 { buildOrderTo102919(order) globals.SugarLogger.Debugf("resultjdsOrders return 4") } } orders = append(orders, order) } return orders, err } func buildOrderTo102919(order *model.GoodsOrder) { // if order.VendorOrgCode == "1" { // order.StoreID = 102919 // order.JxStoreID = 102919 // order.StoreName = "商城模板(成都发货)" // order.VendorStoreID = model.JdShopMainVendorStoreID // } else { order.StoreID = model.JdShopMainStoreID order.JxStoreID = model.JdShopMainStoreID order.StoreName = "商城模板店2" order.VendorStoreID = model.JdShopMainVendorStoreID // } order.DeliveryFlag = model.OrderDeliveryFlagMaskScheduleDisabled }