package jdshop import ( "bytes" "encoding/base64" "encoding/hex" "fmt" "math" "strings" "time" "git.rosy.net.cn/jx-callback/business/authz/autils" "git.rosy.net.cn/jx-callback/business/partner/delivery/dada" "git.rosy.net.cn/jx-callback/business/jxutils/jxcontext" beego "github.com/astaxie/beego/adapter" "git.rosy.net.cn/baseapi/platformapi/dadaapi" "git.rosy.net.cn/baseapi/platformapi/dingdingapi" "git.rosy.net.cn/baseapi/platformapi/jcqapi" "git.rosy.net.cn/baseapi/platformapi/jdshopapi" "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/business/jxstore/common" "git.rosy.net.cn/jx-callback/business/jxutils" "git.rosy.net.cn/jx-callback/business/jxutils/ddmsg" "git.rosy.net.cn/jx-callback/business/model" "git.rosy.net.cn/jx-callback/business/model/dao" "git.rosy.net.cn/jx-callback/business/partner" "git.rosy.net.cn/jx-callback/globals" "git.rosy.net.cn/jx-callback/globals/api" "git.rosy.net.cn/jx-callback/globals/api2" ) func OnCallbackMsg(msg *jdshopapi.CallBackResult) (err error) { msgType := msg.MsgType switch msgType { case jcqapi.TopicOrderPay: utils.CallFuncAsync(func() { SaveJdsOrders(msg) }) case jcqapi.TopicOrderCancel: utils.CallFuncAsync(func() { order := getRealOrderID(msg.OrderID) if order != nil { if order.Status != model.OrderStatusCanceled { CurPurchaseHandler.CancelOrder(jxcontext.AdminCtx, order, "系统取消") } } }) case jcqapi.TopicOrderOut: utils.CallFuncAsync(func() { globals.SugarLogger.Debugf("jdsOrderOut", utils.Format4Output(msg, false)) orders := getAllRealOrderID(msg.OrderID) if len(orders) > 0 { for _, order := range orders { if order.ActualPayPrice == 0 { if jxutils.StandardPrice2Int(utils.Str2Float64(msg.OrderPayment)) == 0 { order.ActualPayPrice = jxutils.StandardPrice2Int(utils.Str2Float64(msg.OrderTotalPrice) + utils.Str2Float64(msg.FreightPrice) - utils.Str2Float64(msg.SellerDiscount)) } else { order.ActualPayPrice = jxutils.StandardPrice2Int(utils.Str2Float64(msg.OrderPayment)) } order.TotalShopMoney = utils.Float64TwoInt64(float64(order.ActualPayPrice) * jdshopapi.JdsPayPercentage) partner.CurOrderManager.UpdateOrderFields(order, []string{"ActualPayPrice", "TotalShopMoney"}) } } } }) default: return fmt.Errorf("暂不支持的topic类型!topic: %v", msgType) } return err } func SaveJdsOrders(msg *jdshopapi.CallBackResult) (err error) { order, err := result2Orders(msg) if err != nil || order == nil { return err } globals.SugarLogger.Debugf("SaveJdsOrders : %v", utils.Format4Output(order, false)) partner.CurOrderManager.OnOrderNew(order, model.Order2Status(order)) noticeMsg := fmt.Sprintf("京东商城新订单,订单号:[%v] ,将要发到的门店id:[%v] , 门店名:[%v]", order.VendorOrderID, order.StoreID, order.StoreName) if order.OrderType == model.OrderTypeAddressErr { noticeMsg += " 此订单地址有问题,需要矫正坐标!" } var role = autils.NewRole("jdshop", 0) userIDList, err := api2.RoleMan.GetRoleUserList(role) for _, v := range userIDList { ddmsg.SendUserMessage(dingdingapi.MsgTyeText, v, "京东商城来新订单了!", noticeMsg) } // ddmsg.SendUserMessage(dingdingapi.MsgTyeText, "1439B3E07D3911EA881A525400E86DC0", "京东商城来新订单了!", noticeMsg) return err } func result2Orders(msg *jdshopapi.CallBackResult) (order *model.GoodsOrder, err error) { var ( db = dao.GetDB() ) //有可能是库里已经有这个订单了 orderE, err := partner.CurOrderManager.LoadOrder(msg.OrderID+"000001", model.VendorIDJDShop) if orderE != nil { return order, fmt.Errorf("已经存在此订单!") } order = &model.GoodsOrder{ VendorOrderID2: msg.OrderID, VendorOrderID: msg.OrderID + "000001", VendorID: model.VendorIDJDShop, BaseFreightMoney: jxutils.StandardPrice2Int(utils.Str2Float64(msg.FreightPrice)), VendorStatus: msg.OrderState, VendorUserID: msg.Pin, BuyerComment: msg.OrderRemark, PickDeadline: utils.DefaultTimeValue, OriginalData: string(utils.MustMarshal(msg)), OrderCreatedAt: utils.Str2Time(msg.OrderStartTime), ConsigneeAddress: Decrypt(msg.ConsigneeInfo.FullAddress, msg.VendorOrgCode), ConsigneeName: Decrypt(msg.ConsigneeInfo.Fullname, msg.VendorOrgCode), // ConsigneeMobile: Decrypt(msg.ConsigneeInfo.Mobile), // ConsigneeMobile2: Decrypt(msg.ConsigneeInfo.Telephone), ActualPayPrice: jxutils.StandardPrice2Int(utils.Str2Float64(msg.OrderPayment)), Status: model.OrderStatusNew, TotalShopMoney: utils.Float64TwoInt64(math.Round(float64(jxutils.StandardPrice2Int(utils.Str2Float64(msg.OrderPayment))) * jdshopapi.JdsPayPercentage)), DeliveryType: model.OrderDeliveryTypeStoreSelf, StatusTime: utils.Str2Time(msg.OrderStartTime), OrderSeq: 0, VendorOrgCode: msg.VendorOrgCode, } if utils.Str2Float64(msg.BalanceUsed) != 0 { order.ActualPayPrice += jxutils.StandardPrice2Int(utils.Str2Float64(msg.BalanceUsed)) } if len(msg.ConsigneeInfo.Mobile) != 11 { order.ConsigneeMobile = Decrypt(msg.ConsigneeInfo.Mobile, msg.VendorOrgCode) } else { order.ConsigneeMobile = msg.ConsigneeInfo.Mobile } if len(msg.ConsigneeInfo.Telephone) != 11 { order.ConsigneeMobile2 = Decrypt(msg.ConsigneeInfo.Telephone, msg.VendorOrgCode) } else { order.ConsigneeMobile2 = msg.ConsigneeInfo.Telephone } if order.TotalShopMoney < 100 { order.TotalShopMoney = 100 } if order.ConsigneeAddress != "" { var cityCode int place, err := dao.GetPlaceByJdsCode(db, utils.Str2Int(msg.ConsigneeInfo.CityID)) if place == nil { cityCode = 510100 } else { if place.Level == 3 { cityCode = place.ParentCode } else if place.Level == 2 { cityCode = place.Code } } lng, lat, err2 := api.AutonaviAPI.GetCoordinateFromAddressByPage(order.ConsigneeAddress, cityCode) if err = err2; err != nil { globals.SugarLogger.Infof("高德page err: %v", err) } lng2, lat2, _ := api.AutonaviAPI.GetCoordinateFromAddress(order.ConsigneeAddress, "") distance := jxutils.EarthDistance(lng, lat, lng2, lat2) if distance > 1 { order.OrderType = model.OrderTypeAddressErr } if err == nil && lng != 0 && lat != 0 { order.ConsigneeLng = jxutils.StandardCoordinate2Int(lng) order.ConsigneeLat = jxutils.StandardCoordinate2Int(lat) } else { order.ConsigneeLng = jxutils.StandardCoordinate2Int(lng2) order.ConsigneeLat = jxutils.StandardCoordinate2Int(lat2) } order.CoordinateType = model.CoordinateTypeMars } for _, v := range msg.ItemInfoList { sku := &model.OrderSku{ VendorID: model.VendorIDJDShop, VendorOrderID: order.VendorOrderID, Count: utils.Str2Int(v.ItemTotal), VendorSkuID: v.SkuID, SkuName: v.SkuName, VendorPrice: jxutils.StandardPrice2Int(utils.Str2Float64(v.JdPrice)), SalePrice: jxutils.StandardPrice2Int(utils.Str2Float64(v.JdPrice)), // SkuID: utils.Str2Int(v.OuterSkuID), } if v.OuterSkuID != "" { sku.SkuID = utils.Str2Int(v.OuterSkuID) } _, _, _, specUnit, _, specQuality := jxutils.SplitSkuName(v.SkuName) sku.Weight = jxutils.FormatSkuWeight(specQuality, specUnit) order.Skus = append(order.Skus, sku) } storeList, err := common.GetStoreListByLocation(jxcontext.AdminCtx, jxutils.IntCoordinate2Standard(order.ConsigneeLng), jxutils.IntCoordinate2Standard(order.ConsigneeLat), 3000, false, true, 0) if err != nil { globals.SugarLogger.Debugf("jds GetStoreListByLocation error: %v", err.Error()) return order, err } if len(storeList) > 0 { for _, store := range storeList { order.StoreID = store.ID order.JxStoreID = store.ID order.StoreName = store.Name globals.SugarLogger.Debugf("jds GetStoreListByLocation, orderID: %v storeID :%v", order.VendorOrderID, order.StoreID) //结算类型 storeDetail, _ := dao.GetStoreDetail(db, order.StoreID, model.VendorIDJDShop, "") if storeDetail != nil { if storeDetail.PayPercentage < 50 { order.EarningType = model.EarningTypePoints } else { order.EarningType = model.EarningTypeQuote } } var ( shopPriceSum int saleNormalSum int ) for _, sku := range order.Skus { storeSkuList, _ := dao.GetStoresSkusInfo(db, []int{order.StoreID}, []int{sku.SkuID}) if len(storeSkuList) > 0 { if storeSkuList[0].Status == model.StoreSkuBindStatusNormal { saleNormalSum += 1 } shopPriceSum += storeSkuList[0].Price * sku.Count } else { shopPriceSum += int(sku.SalePrice) * 70 / 100 } } //可售数小于一半就不行 if math.Mod(float64(len(order.Skus)), float64(2)) == 0 { if saleNormalSum < len(order.Skus)/2 { buildOrderTo102919(order) continue } else { if order.EarningType == model.EarningTypeQuote && shopPriceSum+700 > int(order.TotalShopMoney) { buildOrderTo102919(order) continue } } } else { if saleNormalSum <= len(order.Skus)/2 { buildOrderTo102919(order) continue } else { if order.EarningType == model.EarningTypeQuote && shopPriceSum+700 > int(order.TotalShopMoney) { buildOrderTo102919(order) continue } } } break } } else { buildOrderTo102919(order) } storeMaps, _ := dao.GetStoresMapList(db, []int{model.VendorIDJDShop}, []int{order.StoreID}, nil, model.StoreStatusAll, model.StoreIsSyncAll, "", "", msg.VendorOrgCode) if len(storeMaps) > 0 { order.VendorStoreID = storeMaps[0].VendorStoreID } // 如果是暂停,表示是预订单g if msg.OrderState == jdshopapi.OrderStatusPause || msg.OrderState == jdshopapi.OrderStatusPopPause { order.BusinessType = model.BusinessTypeDingshida if time2, err := getAPI(msg.VendorOrgCode).GetOrderExtInfoByOrderId(order.VendorOrderID2); err == nil { if time2 == "" { order.ExpectedDeliveredTime = order.OrderCreatedAt.Add(time.Hour) } else { order.ExpectedDeliveredTime = utils.Str2Time(time2) } } else { order.ExpectedDeliveredTime = order.OrderCreatedAt.Add(time.Hour) err = nil } order.PickDeadline = order.ExpectedDeliveredTime.Add(-time.Hour) } else if msg.OrderState == jdshopapi.OrderStatusWait || msg.OrderState == "WAIT_GOODS_RECEIVE_CONFIRM" || msg.OrderState == "FINISHED_L" { order.ExpectedDeliveredTime = order.OrderCreatedAt.Add(time.Hour) order.BusinessType = model.BusinessTypeImmediate } else if msg.OrderState == "UN_KNOWN" { order.ExpectedDeliveredTime = order.OrderCreatedAt.Add(time.Hour) order.BusinessType = model.BusinessTypeImmediate } else { globals.SugarLogger.Debugf("暂不支持的京东商城订单类型!type: %v", msg.OrderState) return nil, err } if msg.IDSopShipmenttype == jdshopapi.IdSopShipmenttypeTC { if msg.VendorOrgCode == "1" { if time2, err := getAPI(msg.VendorOrgCode).GetOrderExtInfoByOrderId(order.VendorOrderID2); err == nil { order.BusinessType = model.BusinessTypeDingshida if time2 == "" { order.ExpectedDeliveredTime = order.OrderCreatedAt.Add(time.Hour) } else { order.ExpectedDeliveredTime = utils.Str2Time(time2) } } } else { order.BusinessType = model.BusinessTypeImmediate if time2, err := getAPI(msg.VendorOrgCode).GetOrderExtInfoByOrderId(order.VendorOrderID2); err == nil { if time2 == "" { order.ExpectedDeliveredTime = order.OrderCreatedAt.Add(time.Hour) } else { order.ExpectedDeliveredTime = utils.Str2Time(time2) } } else { order.ExpectedDeliveredTime = order.OrderCreatedAt.Add(time.Hour) } } } setJdsOrderSeq(order) if order.OrderType == model.OrderTypeAddressErr { buildOrderTo102919(order) } billParams, _ := GetDaDaBillParams(db, order) if result, err := api.DadaAPI.QueryDeliverFee(billParams); err == nil { if result.Fee > 10 { buildOrderTo102919(order) } } if order.ExpectedDeliveredTime.Sub(order.OrderCreatedAt) <= time.Hour+time.Minute { order.BusinessType = model.BusinessTypeImmediate } buildOrderTo102919(order) return order, 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.JdShopMainStoreID2 order.JxStoreID = model.JdShopMainStoreID2 order.StoreName = "商城模板店2" order.VendorStoreID = model.JdShopMainVendorStoreID2 } order.DeliveryFlag = model.OrderDeliveryFlagMaskScheduleDisabled } func setJdsOrderSeq(order *model.GoodsOrder) (err error) { type tCount struct { Count int `json:"count"` } var count = &tCount{} sql := ` SELECT count(*) count FROM goods_order WHERE store_id = ? AND order_create_at >= ? AND order_create_at <= ? AND vendor_id = ? ` sqlParams := []interface{}{ order.StoreID, utils.Time2Date(time.Now()), utils.Time2Date(time.Now().AddDate(0, 0, 1)), order.VendorID, } err = dao.GetRow(dao.GetDB(), &count, sql, sqlParams) order.OrderSeq = count.Count + 1 return err } func Decrypt(p, vendorOrgCode string) (result string) { if p == "" { return "" } data, _ := base64.StdEncoding.DecodeString(strings.ReplaceAll(p, " ", "+")) key := GetKey(hex.EncodeToString(data)[4:36], vendorOrgCode) globals.SugarLogger.Debugf("Decrypt keys : %v", key) data2, _ := base64.StdEncoding.DecodeString(key) b := bytes.NewBuffer(data) b.Next(18) iv := make([]byte, 16) b.Read(iv) main := make([]byte, len(data)-18-16) b.Read(main) decryptedData, _ := utils.AESCBCDecpryt(main, data2[:16], iv) return string(decryptedData) } func getRealOrderID(orderID string) (order *model.GoodsOrder) { var ( db = dao.GetDB() ) sql := ` SELECT * FROM goods_order WHERE vendor_order_id2 = ? ORDER BY vendor_order_id DESC LIMIT 1 ` sqlParams := []interface{}{ orderID, } dao.GetRow(db, &order, sql, sqlParams) return order } func getAllRealOrderID(orderID string) (orders []*model.GoodsOrder) { var ( db = dao.GetDB() ) sql := ` SELECT * FROM goods_order WHERE vendor_order_id2 = ? ` sqlParams := []interface{}{ orderID, } dao.GetRows(db, &orders, sql, sqlParams) return orders } func GetDaDaBillParams(db *dao.DaoDB, order *model.GoodsOrder) (billParams *dadaapi.OperateOrderParams, err error) { billParams = &dadaapi.OperateOrderParams{ OriginID: jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID), CargoPrice: jxutils.IntPrice2Standard(limitOrderPrice(order.ActualPayPrice)), IsPrepay: 0, ReceiverName: utils.FilterMb4(order.ConsigneeName), ReceiverAddress: utils.FilterMb4(order.ConsigneeAddress), ReceiverPhone: order.ConsigneeMobile, } if billParams.ShopNo, err = getDadaShopID(order, db); err == nil { if billParams.CityCode, err = getDataCityCodeFromOrder(order, db); err == nil { // storeTel := "" // storeID := jxutils.GetSaleStoreIDFromOrder(order) // storeDeatail, _ := dao.GetStoreDetail(db, storeID, order.VendorID) // if storeDeatail.Tel2 != "" { // storeTel = ",门店电话:" + storeDeatail.Tel2 // } billParams.ReceiverLng, billParams.ReceiverLat, _ = jxutils.IntCoordinate2MarsStandard(order.ConsigneeLng, order.ConsigneeLat, order.CoordinateType) billParams.Info = fmt.Sprintf("%s第%d号订单, %s", model.VendorChineseNames[order.VendorID], order.OrderSeq, utils.FilterMb4("客户电话:"+order.ConsigneeMobile+","+order.BuyerComment+"取货失败或配送遇到问题请联系18048531223,禁止未配送直接完成定单!")) billParams.CargoType = dadaapi.CargoTypeFresh billParams.CargoWeight = float64(jxutils.IntWeight2Float(limitOrderWeight(order.Weight))) billParams.CargoNum = order.GoodsCount } } return billParams, err } func limitOrderPrice(price int64) int64 { var maxOrderPrice int64 = 6399 if price > maxOrderPrice { return maxOrderPrice } return price } func limitOrderWeight(weight int) int { maxOrderWeight := 5000 // 5公斤 if weight > maxOrderWeight { return maxOrderWeight } return weight } func getDadaShopID(order *model.GoodsOrder, db *dao.DaoDB) (retVal string, err error) { saleStoreID := jxutils.GetSaleStoreIDFromOrder(order) storeCourierList, err2 := dao.GetOpenedStoreCouriersByStoreID(db, saleStoreID, model.VendorIDDada) if err = err2; err != nil && !dao.IsNoRowsError(err) { return "", err } if len(storeCourierList) == 0 { return "", partner.ErrStoreHaveNoCourier } retVal = storeCourierList[0].VendorStoreID if beego.BConfig.RunMode == "dev" { retVal = "test_0001" } return retVal, nil } func getDataCityCodeFromOrder(order *model.GoodsOrder, db *dao.DaoDB) (retVal string, err error) { jxStoreID := jxutils.GetSaleStoreIDFromOrder(order) sql := ` SELECT t2.tel_code FROM store t1 JOIN place t2 on t1.city_code = t2.code WHERE t1.id = ? ` codeInfo := &struct { TelCode string }{} if err = dao.GetRow(db, codeInfo, sql, jxStoreID); err != nil { globals.SugarLogger.Errorf("GetDataCityCodeFromOrder can not find store info for vendorID:%d, store:%s, error:%v", order.VendorID, order.VendorStoreID, err) if err == nil { err = dada.ErrCanNotFindDadaCityCode } return "", err } return codeInfo.TelCode, nil }