package tao_vegetable import ( "errors" "fmt" "git.rosy.net.cn/baseapi/platformapi/dingdingapi" "git.rosy.net.cn/jx-callback/business/jxutils/ddmsg" "regexp" "strings" "time" "git.rosy.net.cn/baseapi/platformapi/tao_vegetable" domain3156 "git.rosy.net.cn/baseapi/platformapi/tao_vegetable/sdk/ability3156/domain" request3156 "git.rosy.net.cn/baseapi/platformapi/tao_vegetable/sdk/ability3156/request" domain591 "git.rosy.net.cn/baseapi/platformapi/tao_vegetable/sdk/ability591/domain" request591 "git.rosy.net.cn/baseapi/platformapi/tao_vegetable/sdk/ability591/request" "git.rosy.net.cn/baseapi/platformapi/tao_vegetable/sdk/util" "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/business/jxutils" "git.rosy.net.cn/jx-callback/business/jxutils/jxcontext" "git.rosy.net.cn/jx-callback/business/jxutils/tasksch" "git.rosy.net.cn/jx-callback/business/model" "git.rosy.net.cn/jx-callback/business/model/dao" "git.rosy.net.cn/jx-callback/business/partner" "git.rosy.net.cn/jx-callback/globals" ) var ( specPat = regexp.MustCompile(`(\d+)(.+)`) ) var ( VendorStatus2StatusMap = map[string]int{ tao_vegetable.OrderStatusPayFinsh: model.OrderStatusNew, // 商户接单 tao_vegetable.OrderStatusNew: model.OrderStatusAccepted, // 商户接单 tao_vegetable.OrderStatusPickedUp: model.OrderStatusFinishedPickup, // 拣货完成 tao_vegetable.OrderStatusCallRider: model.OrderStatusFinishedPickup, // 打包出库(呼叫骑手,骑手到店,骑手取货) tao_vegetable.OrderStatusDelivery: model.OrderStatusDelivering, // 配送中 tao_vegetable.OrderStatusDeliveryOver: model.OrderStatusFinished, // 配送结束 tao_vegetable.OrderStatusUserRejection: model.OrderStatusDeliverFailed, // 用户拒收 tao_vegetable.OrderStatusMerchantCancel: model.OrderStatusCanceled, // 商户取消订单 tao_vegetable.OrderStatusSuccess: model.OrderStatusFinished, // 订单完成 } ) func (p *PurchaseHandler) getStatusFromVendorStatus(vendorStatus string) int { if status, ok := VendorStatus2StatusMap[vendorStatus]; ok { return status } return model.OrderStatusUnknown } // getOrder 获取订单详情 func (p *PurchaseHandler) getOrder(vendorOrgCode string, vendorOrderID int64, vendorStoreID string) (order *model.GoodsOrder, orderMap *domain591.AlibabaAelophyOrderGetOrderResponse, err error) { requestParam := &request591.AlibabaAelophyOrderGetRequest{OrderGetRequest: &domain591.AlibabaAelophyOrderGetOrderGetRequest{ StoreId: utils.String2Pointer(vendorStoreID), BizOrderId: utils.Int64ToPointer(vendorOrderID), }} api := getAPI(vendorOrgCode, 0, vendorStoreID) orderDetail, err := api.QueryOrderDetail(requestParam) if err != nil { return nil, nil, err } orderMap = orderDetail order = &model.GoodsOrder{ VendorOrderID: utils.Int64ToStr(vendorOrderID), VendorID: model.VendorIDTaoVegetable, VendorStoreID: vendorStoreID, VendorOrderID2: *orderDetail.OutOrderId, StoreID: utils.Str2Int(*orderDetail.StoreId), JxStoreID: utils.Str2Int(*orderDetail.StoreId), CoordinateType: model.CoordinateTypeMars, BuyerComment: *orderDetail.ReceiveInfo.ReceiverMemo, PickDeadline: utils.DefaultTimeValue, VendorStatus: *orderDetail.OrderStatus, // PAID = 订单支付完成 PACKAGED = 订单打包出库 SHIPPING = 订单配送揽收 SUCCESS = 交易完成 CLOSE = 订单取消 StatusTime: time.Now(), OrderCreatedAt: utils.Str2TimeWithDefault(orderDetail.PayTime.String(), time.Now()), OriginalData: string(utils.MustMarshal(orderDetail)), ActualPayPrice: *orderDetail.PayFee, BaseFreightMoney: *orderDetail.PostFee, InvoiceTitle: "", InvoiceTaxerID: "", InvoiceEmail: "", VendorOrgCode: api.GetVendorOrgCode(), UserID: *orderDetail.OpenUid, } if *orderDetail.OrderStatus == tao_vegetable.OrderStatusDeliveryOver { order.OrderFinishedAt = time.Now() } else { order.OrderFinishedAt = utils.DefaultTimeValue } order.Status = p.getStatusFromVendorStatus(*orderDetail.OrderStatus) if orderDetail.ReceiveInfo.ReceiverPoi != nil { originalList := strings.Split(*orderDetail.ReceiveInfo.ReceiverPoi, ",") order.ConsigneeLng = jxutils.StandardCoordinate2Int(utils.Str2Float64(originalList[0])) order.ConsigneeLat = jxutils.StandardCoordinate2Int(utils.Str2Float64(originalList[1])) } order.DiscountMoney = *orderDetail.DiscountFee order.PmSubsidyMoney = *orderDetail.SkuDiscountPlatformFee // 平台承担优惠 // 添加需要赠送的东西(暂时没有赠品套餐直接商品) multiSkuMap := make(map[int]int) var ( skuSalePrice int64 = 0 // 商品售卖价 merchantDiscountsPrice int64 = 0 // 商户优惠价 // 平台优惠价 platformDiscountsPrice int64 = *orderDetail.PlatformDeduction.BaseLogisticsFee + *orderDetail.PlatformDeduction.TechnicalServiceFee + *orderDetail.PlatformDeduction.PayServiceFee + *orderDetail.PlatformDeduction.ThirdpartnarFee ) if len(*orderDetail.SubOrderResponseList) > 0 { for _, extra := range *orderDetail.SubOrderResponseList { skuSalePrice += *extra.OriginalFee merchantDiscountsPrice += *extra.DiscountMerchantFee // 这个是包装袋的价格,用户退款是包装袋未推送退款,导致本地订单退款状态无法更新,取消包装袋的记录(但是结算的时候需要加上去) if *extra.SkuCode == "6108080" { continue } sku := &model.OrderSku{ VendorOrderID: order.VendorOrderID, VendorSubOrderID: *extra.OutSubOrderId, VendorID: model.VendorIDTaoVegetable, StoreSubID: 0, StoreSubName: "", Count: utils.Float64TwoInt(*extra.BuySaleQuantity), VendorSkuID: *extra.SkuCode, SkuID: 0, JxSkuID: 0, SkuName: *extra.SkuName, ShopPrice: *extra.Price, VendorPrice: *extra.OriginalFee / utils.Float64TwoInt64(*extra.BuySaleQuantity), SalePrice: *extra.OriginalFee / utils.Float64TwoInt64(*extra.BuySaleQuantity), EarningPrice: 0, Weight: int(*extra.Weight / utils.Float64TwoInt64(*extra.BuySaleQuantity)), SkuType: 0, PromotionType: 0, OrderCreatedAt: order.OrderCreatedAt, IsVendorAct: 0, Upc: *extra.Barcode, } // extra.SkuCode 为int类型会超出长度,有时商品为平台创建 if len(*extra.SkuCode) < 10 { sku.SkuID = utils.Str2Int(*extra.SkuCode) sku.JxSkuID = utils.Str2Int(*extra.SkuCode) } activityId := make([]int64, 0) activityName := make([]string, 0) if extra.Activitys != nil { for _, v := range *extra.Activitys { // 渠道活动 if v.ChannelActivityId != nil { activityId = append(activityId, utils.Str2Int64WithDefault(*v.ChannelActivityId, 999)) //activityName = append(activityName, *v.ChannelActivityId+":"+*v.ActivityName) activityName = append(activityName, *v.ChannelActivityId) } // 业务活动 if v.BizActivityId != nil { activityId = append(activityId, utils.Str2Int64WithDefault(*v.BizActivityId, 999)) //activityName = append(activityName, *v.BizActivityId+":"+*v.ActivityName) activityName = append(activityName, *v.BizActivityId) } // 商家erp活动 if v.MerchantActivityId != nil { activityId = append(activityId, utils.Str2Int64WithDefault(*v.MerchantActivityId, 999)) //activityName = append(activityName, *v.MerchantActivityId+":"+*v.ActivityName) activityName = append(activityName, *v.MerchantActivityId) } } } if len(activityId) > 0 { //sku.StoreSubName = strings.Join(activityName, ",") } if sku.Weight == 0 { sku.Weight = 222 // 如果名字里找不到缺省给半斤左右的一个特别值 } multiSkuMap[sku.SkuID]++ order.Skus = append(order.Skus, sku) } } // 淘宝默认自配送 if *orderDetail.DeliveryType == tao_vegetable.OrderDeliveryTypeTime { order.DeliveryType = model.OrderDeliveryTypePlatform } else if *orderDetail.DeliveryType == tao_vegetable.OrderDeliveryTypeSelf { order.DeliveryType = model.OrderDeliveryTypeSelfTake } else if *orderDetail.DeliveryType == tao_vegetable.OrderDeliveryTypeStore { order.DeliveryType = model.OrderDeliveryTypeStoreSelf } // 期望送达时间两小时内为立即达 earliestTime := utils.Str2Time(strings.Split(*orderDetail.ReceiveInfo.ExpectArriveTime, "~")[0]).Unix() if earliestTime-time.Now().Unix() > 2*60*60 { order.BusinessType = model.BusinessTypeDingshida order.ExpectedDeliveredTime = getTimeFromTimestamp(earliestTime + 30*60) // 预计最晚送达时间 } else { // 定时达 order.BusinessType = model.BusinessTypeImmediate order.ExpectedDeliveredTime = getTimeFromTimestamp(earliestTime + 30*60) // 预计最晚送达时间 } order.PickDeadline = order.ExpectedDeliveredTime.Add(-1 * time.Hour) // 用户信息 if orderDetail.ReceiveInfo.ReceiverName != nil { order.ConsigneeName = *orderDetail.ReceiveInfo.ReceiverName } if orderDetail.ReceiveInfo.ReceiverPhone != nil { order.ConsigneeMobile = *orderDetail.ReceiveInfo.ReceiverPhone } if orderDetail.ReceiveInfo.ReceiverAddress != nil { order.ConsigneeAddress = *orderDetail.ReceiveInfo.ReceiverAddress } for _, v := range order.Skus { if multiSkuMap[v.SkuID] > 1 && v.SalePrice == v.VendorPrice { v.IsVendorAct = model.YES } } //订单手机号和收货地址是否同城(虚拟号,无法获取到正确地址) order.PhoneAscription = model.PhoneAscriptionAddressNo + "-" + "归属信息不匹配:" + "虚拟电话号码" // 本地获取订单记录 orderSeq, _ := dao.GetVendorOrderNumber(dao.GetDB(), model.VendorIDTaoVegetable, order.VendorStoreID) order.OrderSeq = orderSeq + 1 // 包装袋金额 store, _ := dao.GetStoreDetailByVendorStoreID(dao.GetDB(), order.VendorStoreID, model.VendorIDTaoVegetable, order.VendorOrgCode) if store != nil { order.StoreName = store.Name // 真实门店名称 order.PackagePrice = int(*orderDetail.PackageFee) + store.PackageSetting } else { order.PackagePrice = int(*orderDetail.PackageFee) order.StoreName = "未获取到" // 真实门店名称 } //结算类型 if store.PayPercentage < 50 { order.EarningType = model.EarningTypePoints } else { order.EarningType = model.EarningTypeQuote } // 平台结算金额 order.TotalShopMoney = skuSalePrice + *orderDetail.PostFee - merchantDiscountsPrice - platformDiscountsPrice if order.EarningType == model.EarningTypePoints { waybill, _ := partner.CurOrderManager.LoadWaybill(order.VendorWaybillID, order.WaybillVendorID) 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 } } } return order, orderMap, err } type RiderInfo struct { OrderId string `json:"order_id"` // 发单平台订单id(美团,京西,京,京东) ThirdCarrierOrderId string `json:"third_carrier_order_id"` // 京西平台id(运单id) CourierName string `json:"courier_name"` // 骑手名称 CourierPhone string `json:"courier_phone"` // 骑手电话 LogisticsProviderCode string `json:"logistics_provider_code"` // 配送平台code 10001-顺丰, 10002-达达, 10003-闪送, 10004-蜂鸟, 10005 UU跑腿,10006 快跑者, 10007 极客快送,10008-点我达,10009 同达, 10010-生活半径,10011 邻趣,10012 趣送, 10013 快服务 10014 菜鸟新配盟 10015 商家自建配送 10016 风先生,10017-其他,10018-抖音配送(小时达),10032-美团跑腿 LogisticsStatus int `json:"logistics_status"` // 配送状态(美团用) LogisticsContext string `json:"logistics_context"` // 配送状态描述 Latitude string `json:"latitude"` // 骑手当前的纬度,美团使用的是高德坐标系。 Longitude string `json:"longitude"` // 骑手当前的经度,美团使用的是高德坐标系。 OpCode string `json:"opcode"` // 抖音状态(抖音才需要) } // GetOrderRider 自配送商家同步发货状态和配送信息(推荐) func (p *PurchaseHandler) GetOrderRider(vendorOrgCode, vendorStoreID string, param map[string]interface{}) (err error) { req := &request591.AlibabaAelophyOrderLogisticsTraceCallbackRequest{ LogisticsTraceCallbackRequest: &domain591.AlibabaAelophyOrderLogisticsTraceCallbackLogisticsTraceCallbackRequest{ StoreId: utils.String2Pointer(vendorStoreID), BizOrderId: utils.Int64ToPointer(utils.Str2Int64(param["order_id"].(string))), Longitude: utils.String2Pointer(param["longitude"].(string)), Latitude: utils.String2Pointer(param["latitude"].(string)), UpdateTime: (*util.LocalTime)(utils.Time2Pointer(time.Now())), }, } return getAPI(vendorOrgCode, 0, vendorStoreID).DeliveryTrajectory(req) } func PushDelivererChangeInfo(order *model.GoodsOrder, bill *model.Waybill, deliveryType string) error { param := &request591.AlibabaAelophyOrderDelivererChangeRequest{ DelivererChangeRequest: &domain591.AlibabaAelophyOrderDelivererChangeDelivererChangeRequest{ StoreId: utils.String2Pointer(order.VendorStoreID), BizOrderId: utils.Int64ToPointer(utils.Str2Int64(order.VendorOrderID)), DelivererName: utils.String2Pointer(bill.CourierName), DelivererPhone: utils.String2Pointer(bill.CourierMobile), DelivererCompany: nil, LogisticsNo: utils.String2Pointer(bill.VendorWaybillID), }, } return getAPI(order.VendorOrgCode, order.JxStoreID, order.VendorStoreID).DelivererChange(param) } func (p *PurchaseHandler) GetOrder(vendorOrgCode, vendorOrderID, vendorStoreID string) (order *model.GoodsOrder, err error) { order, _, err = p.getOrder(vendorOrgCode, utils.Str2Int64(vendorOrderID), vendorStoreID) return order, err } func (p *PurchaseHandler) GetOrderStatus(vendorOrgCode, vendorOrderID string) (status int, err error) { order, _ := partner.CurOrderManager.LoadOrder(vendorOrderID, model.VendorIDTaoVegetable) if order == nil { return 0, err } requestParam := &request591.AlibabaAelophyOrderGetRequest{OrderGetRequest: &domain591.AlibabaAelophyOrderGetOrderGetRequest{ StoreId: utils.String2Pointer(order.VendorStoreID), BizOrderId: utils.Int64ToPointer(utils.Str2Int64(vendorOrderID)), }} orderDetail, err := getAPI(vendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), "").QueryOrderDetail(requestParam) if err != nil { return 0, err } status = p.getStatusFromVendorStatus(*orderDetail.OrderStatus) return status, err } func (c *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *model.GoodsOrder) { order, _, _ = c.getOrder(orderData["VendorOrgCode"].(string), utils.Str2Int64(orderData["vendorOrderID"].(string)), "") return order } // getRefundSkuDetailList 获取商家部分退款的订单列表 func getRefundSkuDetailList(order *model.GoodsOrder) (skuList []*domain591.AlibabaAelophyOrderGetSubOrderResponse, err error) { requestParam := &request591.AlibabaAelophyOrderGetRequest{OrderGetRequest: &domain591.AlibabaAelophyOrderGetOrderGetRequest{ StoreId: utils.String2Pointer(order.VendorStoreID), BizOrderId: utils.Int64ToPointer(utils.Str2Int64(order.VendorOrderID)), }} orderDetail, err := getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), "").QueryOrderDetail(requestParam) if err != nil { return nil, err } for _, v := range *orderDetail.SubOrderResponseList { if *v.OrderStatus == tao_vegetable.OrderStatusRefundClose { skuList = append(skuList, &v) } } return skuList, err } func getSkuWeight(product map[string]interface{}) (weight int) { if weight = int(utils.Interface2Int64WithDefault(product["weight"], 0)); weight == 0 { searchResult := specPat.FindStringSubmatch(product["spec"].(string)) if len(searchResult) == 3 { weight = jxutils.FormatSkuWeight(float32(utils.Str2Float64WithDefault(searchResult[1], 0)), utils.TrimBlankChar(searchResult[2])) } if weight == 0 { _, _, _, specUnit, _, specQuality := jxutils.SplitSkuName(product["food_name"].(string)) weight = jxutils.FormatSkuWeight(specQuality, specUnit) } } return weight } func (c *PurchaseHandler) onOrderMsg(orderStatus, orderId string, orderCallback interface{}) (response *tao_vegetable.CallBackResult) { var err error // 售后单 if c.isAfsMsg(orderStatus, orderId, orderCallback) { response = c.OnAfsOrderMsg(orderId, orderStatus, orderCallback) return response } // 正常订单 msg := orderCallback.(*tao_vegetable.CallbackOrder) if orderStatus == tao_vegetable.OrderStatusOnSaleCancel { onSale := orderCallback.(*tao_vegetable.OnSaleCancel) //msg.PublicModel = onSale.PublicModel msg.MerchantCode = onSale.PartCancelRequest.MerchantCode msg.StoreId = onSale.PartCancelRequest.StoreId msg.BizOrderId = onSale.PartCancelRequest.BizOrderId msg.OrderStatus = tao_vegetable.OrderStatusOnSaleCancel } status := c.callbackOrderMsg2Status(msg) // 校验重复消息 if partner.CurOrderManager.GetStatusDuplicatedCount(status) > 0 { return tao_vegetable.CallBackResultInfo(nil) } // 商户接单/支付完成代表新订单 if msg.OrderStatus == tao_vegetable.OrderStatusPayFinsh { order, orderMap, err2 := c.getOrder("", msg.BizOrderId, msg.StoreId) if err = err2; err == nil { err = partner.CurOrderManager.OnOrderNew(order, status) if err == nil { utils.CallFuncAsync(func() { if msg.OrderStatus == tao_vegetable.OrderStatusPayFinsh { c.OnOrderDetail(orderMap, partner.CreatedPeration) if handler := partner.GetPurchaseOrderHandlerFromVendorID(model.VendorIDTaoVegetable); handler != nil { handler.AcceptOrRefuseOrder(order, true, "jxAdmin") } } else { c.OnOrderDetail(orderMap, partner.UpdatedPeration) } }) } } } else { order, err := partner.CurOrderManager.LoadOrder(utils.Int64ToStr(msg.BizOrderId), model.VendorIDTaoVegetable) if err != nil { return tao_vegetable.CallBackResultInfo(err) } if status.Status == model.OrderStatusAdjust { //skuList, err2 := getRefundSkuDetailList(msg, order) //if err = err2; err == nil { // var removedSkuList []*model.OrderSku // for _, mtwmSku := range skuList { // order.ActualPayPrice -= jxutils.StandardPrice2Int(mtwmSku.RefundPrice) * int64(mtwmSku.Count) // removedSkuList = append(removedSkuList, &model.OrderSku{ // SkuID: int(utils.Str2Int64WithDefault(mtwmSku.SkuID, 0)), // Count: mtwmSku.Count, // }) // } // order = jxutils.RemoveSkuFromOrder(order, removedSkuList) // jxutils.RefreshOrderSkuRelated(order) // err = partner.CurOrderManager.OnOrderAdjust(order, status) //} } else { // 发货完成 if msg.OrderStatus == tao_vegetable.OrderStatusCallRider { // || msgId == tiktokShop.CallbackPartGoodsMsgTagId 部分发货 utils.CallFuncAsync(func() { orderMap, _ := getAPI("", jxutils.GetSaleStoreIDFromOrder(order), order.VendorStoreID).QueryOrderDetail(&request591.AlibabaAelophyOrderGetRequest{ OrderGetRequest: &domain591.AlibabaAelophyOrderGetOrderGetRequest{ StoreId: utils.String2Pointer(msg.StoreId), BizOrderId: utils.Int64ToPointer(msg.BizOrderId), }, }) c.OnOrderDetail(orderMap, partner.UpdatedPeration) }) } if err := partner.CurOrderManager.OnOrderStatusChanged(order.VendorOrgCode, status); err != nil { return tao_vegetable.CallBackResultInfo(err) } } } return tao_vegetable.CallBackResultInfo(err) } func (c *PurchaseHandler) callbackOrderMsg2Status(msg *tao_vegetable.CallbackOrder) (orderStatus *model.OrderStatus) { orderId := utils.Int64ToStr(msg.BizOrderId) orderStatus = &model.OrderStatus{ VendorOrderID: orderId, VendorID: model.VendorIDTaoVegetable, OrderType: model.OrderTypeOrder, RefVendorOrderID: orderId, RefVendorID: model.VendorIDTaoVegetable, VendorStatus: msg.OrderStatus, //StatusTime: utils.Str2TimeWithDefault(msg.Timestamp, time.Now()), StatusTime: time.Now(), } switch msg.OrderStatus { case tao_vegetable.OrderStatusPayFinsh: // 新订单 orderStatus.Status = model.OrderStatusNew orderStatus.Remark = "新订单" case tao_vegetable.OrderStatusNew: // 商户接单 orderStatus.Status = model.OrderStatusAccepted orderStatus.Remark = "商户接单" case tao_vegetable.OrderStatusPickedUp: // 拣货完成 orderStatus.Status = model.OrderStatusFinishedPickup orderStatus.Remark = "拣货完成" case tao_vegetable.OrderStatusCallRider: // 打包出库(呼叫骑手,骑手到店,骑手取货) orderStatus.Status = model.OrderStatusFinishedPickup orderStatus.Remark = "打包出库(呼叫骑手,骑手到店,骑手取货)" case tao_vegetable.OrderStatusDelivery: // 配送中 orderStatus.Status = model.OrderStatusDelivering orderStatus.Remark = "配送中" case tao_vegetable.OrderStatusDeliveryOver: // 配送结束 orderStatus.Status = model.OrderStatusFinished orderStatus.Remark = "送达" case tao_vegetable.OrderStatusUserRejection: // 用户拒收 orderStatus.Status = model.OrderStatusDeliverFailed orderStatus.Remark = "用户拒收" case tao_vegetable.OrderStatusMerchantCancel: // 商户取消订单 orderStatus.Status = model.OrderStatusCanceled orderStatus.Remark = "商户取消" case tao_vegetable.OrderStatusOnSaleCancel: orderStatus.Status = model.OrderStatusCanceled orderStatus.Remark = "用户售中取消" case tao_vegetable.OrderStatusSuccess: // 送达 orderStatus.Status = model.OrderStatusFinished orderStatus.Remark = "订单送达" case tao_vegetable.OrderStatusRefundClose: // 订单取消 orderStatus.Status = model.OrderStatusCanceled orderStatus.Remark = "订单取消" } return orderStatus } func (c *PurchaseHandler) postFakeMsg(vendorOrderID, cmd, vendorStatus string) { msg := &tao_vegetable.CallbackOrder{ //PublicModel: tao_vegetable.PublicModel{ // Method: "", // AppKey: "", // Session: "", // Timestamp: utils.Time2Str(time.Now()), // V: "", // SignMethod: "", // Sign: "", // Format: "", // Simplify: false, // CustomerId: false, //}, MerchantCode: "", StoreId: "", BizOrderId: utils.Str2Int64(vendorOrderID), OrderStatus: vendorStatus, } utils.CallFuncAsync(func() { c.onOrderMsg(vendorStatus, vendorOrderID, msg) }) } // AcceptOrRefuseOrder 自动接单 func (c *PurchaseHandler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) { if isAcceptIt { param := &request591.AlibabaAelophyOrderWorkCallbackRequest{} param.WorkCallbackRequest = &domain591.AlibabaAelophyOrderWorkCallbackWorkCallbackRequest{ StoreId: utils.String2Pointer(order.VendorStoreID), BizOrderId: utils.Int64ToPointer(utils.Str2Int64(order.VendorOrderID)), Status: utils.String2Pointer(tao_vegetable.OrderStatusNew), StatusRemark: nil, DelivererName: nil, DelivererPhone: nil, WorkCallbackSubOrderInfoList: nil, DelivererCompany: nil, LogisticsNo: nil, } for i := 0; i < 3; i++ { err = getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), order.VendorStoreID).DeliveryFinish(param) if err != nil { continue } } } else { err = c.CancelOrder(jxcontext.AdminCtx, order, "bu") } return err } // PickupGoods 拣货 func (c *PurchaseHandler) PickupGoods(order *model.GoodsOrder, isSelfDelivery bool, userName string) (err error) { //if isSelfDelivery { // 淘宝订货单不关系自提还是平台配送都需要拣货 param, err := orderStatusChangeNotice(order, tao_vegetable.OrderStatusPickedUp) if err != nil { return err } err = getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), "").DeliveryFinish(param) if err != nil { return err } c.postFakeMsg(order.VendorOrderID, tao_vegetable.OrderStatusPickedUp, tao_vegetable.OrderStatusPickedUp) //} return err } func (p *PurchaseHandler) AcceptOrRefuseFailedGetOrder(ctx *jxcontext.Context, order *model.GoodsOrder, isAcceptIt bool) (err error) { return err } func (p *PurchaseHandler) CallCourier(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 拣货失败后再次招唤平台配送 return err } func (p *PurchaseHandler) ConfirmReceiveGoods(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 投递失败后确认收到退货 return err } // CanSwitch2SelfDeliver 判断订单能不能转自送,淘宝为纯自送门店 func (c *PurchaseHandler) CanSwitch2SelfDeliver(order *model.GoodsOrder) (isCan bool, err error) { return true, nil } // Swtich2SelfDeliver 转自送接口通知淘鲜达发货 func (c *PurchaseHandler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) { param, err := orderStatusChangeNotice(order, tao_vegetable.OrderStatusCallRider) if err != nil { return nil } if err = getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), "").DeliveryFinish(param); err != nil && !strings.Contains(err.Error(), "当前状态不允许更新") { globals.SugarLogger.Debugf("Swtich2SelfDeliver 出库失败可能是BizSubOrderId 没填写 : %s", err.Error()) } return nil } // Swtich2SelfDelivered 订单送达 func (c *PurchaseHandler) Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) { param := OrderStatusChangeDelivery(order, tao_vegetable.OrderStatusDeliveryOver) return getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), "").DeliveryFinish(param) } // SelfDeliverDelivering 自配送订单配送中 func (c *PurchaseHandler) SelfDeliverDelivering(order *model.GoodsOrder, userName string) (err error) { api := getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), "") // 出库 param, err := orderStatusChangeNotice(order, tao_vegetable.OrderStatusCallRider) if err != nil { return err } err = api.DeliveryFinish(param) if err == nil { paramDelivery := OrderStatusChangeDelivery(order, tao_vegetable.OrderStatusDelivery) // 开始配送 return api.DeliveryFinish(paramDelivery) } else if strings.Contains(err.Error(), "当前状态不允许更新, 请求更新状态") { // "当前状态不允许更新, 请求更新状态: PACKAGED, 当前状态:SHIPPING" 这个时候代表上一次状态以及更新成了,返回错误消息不在处理 return nil } return err } // SelfDeliverDelivered 自配送订单送达 func (c *PurchaseHandler) SelfDeliverDelivered(order *model.GoodsOrder, userName string) (err error) { param := OrderStatusChangeDelivery(order, tao_vegetable.OrderStatusDeliveryOver) api := getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), "") err = api.DeliveryFinish(param) // 这个是因为自动拣货失败出现订单状态为更新,无法设置送达 if err != nil && strings.Contains(err.Error(), "当前状态不允许更新") { errMap := make(map[string]interface{}, 0) pickupErr := c.PickupGoods(order, true, userName) // 自动拣货 time.Sleep(200 * time.Millisecond) deliverErr := c.Swtich2SelfDeliver(order, userName) // 出库 time.Sleep(200 * time.Millisecond) deliveringErr := c.SelfDeliverDelivering(order, userName) // 配送中 time.Sleep(200 * time.Millisecond) deliveredErr := c.Swtich2SelfDelivered(order, userName) // 送达 if pickupErr != nil { errMap["pickupErr"] = pickupErr } if deliverErr != nil { errMap["deliverErr"] = deliverErr } if deliveringErr != nil { errMap["deliveringErr"] = deliveringErr } if deliveredErr != nil { errMap["deliveredErr"] = deliveredErr } if len(errMap) > 0 { ddmsg.SendUserMessage(dingdingapi.MsgTyeText, "2452A93EEB9111EC9B06525400E86DC0", "淘宝订单拣货异常,导致设置送达错误:", utils.Format4Output(errMap, false)) } } return err } func (c *PurchaseHandler) GetOrderRealMobile(ctx *jxcontext.Context, order *model.GoodsOrder) (mobile string, err error) { err = errors.New("淘菜菜外卖还未实现GetOrderRealMobile") return mobile, err } func (c *PurchaseHandler) AgreeOrRefuseCancel(ctx *jxcontext.Context, order *model.GoodsOrder, isAgree bool, reason string) (err error) { db := dao.GetDB() afsOrder, err := partner.CurOrderManager.LoadAfsOrder(order.VendorOrderID, order.VendorID) if err != nil { return err } if isAgree { // 加载子订单号 orderDetail, _ := partner.CurOrderManager.LoadOrder(order.VendorOrderID, model.VendorIDTaoVegetable) // 加载退款商品 afsSkuOrder, _ := dao.GetOrderRefundSkuList(db, []string{order.VendorOrderID}) param := &request3156.AlibabaTclsAelophyRefundAgreeRequest{ StoreId: utils.String2Pointer(order.VendorStoreID), OutOrderId: utils.String2Pointer(orderDetail.VendorOrderID2), RefundId: utils.String2Pointer(afsOrder.AfsOrderID), OrderFrom: utils.Int64ToPointer(utils.Str2Int64(tao_vegetable.TaoVegetableChannelCode)), } // 加载购买商品 sku, _ := dao.GetSimpleOrderSkus(db, order.VendorOrderID, nil) skuCount := 0 for _, v := range sku { skuCount += v.Count } refundSkuCount := 0 subRefundList := make([]domain3156.AlibabaTclsAelophyRefundAgreeSubrefundlist, 0, len(afsSkuOrder)) for _, v := range afsSkuOrder { subRefundList = append(subRefundList, domain3156.AlibabaTclsAelophyRefundAgreeSubrefundlist{ OutSubOrderId: utils.String2Pointer(v.VendorSubOrderID), RefundFee: utils.Int64ToPointer(v.UserMoney), }) refundSkuCount += v.Count } // 全退退运费 if skuCount == refundSkuCount { } param.SubRefundList = &subRefundList param.AuditMemo = utils.String2Pointer(fmt.Sprintf("商户同意退款")) if reason != "" { param.AuditMemo = utils.String2Pointer(*param.AuditMemo + fmt.Sprintf(",%s", reason)) } err = getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromAfsOrder(afsOrder), order.VendorStoreID).AgreeUserCancel(param) } else { param := &request3156.AlibabaTclsAelophyRefundDisagreeRequest{ RefundId: utils.String2Pointer(afsOrder.AfsOrderID), RejectReason: utils.String2Pointer(reason), OrderFrom: utils.Int64ToPointer(utils.Str2Int64(tao_vegetable.TaoVegetableChannelCode)), } err = getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromAfsOrder(afsOrder), order.VendorStoreID).DisAgreeUserCancel(param) if err != nil { afsOrder.Status = model.AfsOrderStatusFailed afsOrder.VendorStatus = "老板拒绝" afsOrder.ReasonDesc += "," + reason dao.UpdateEntity(dao.GetDB(), afsOrder, "Status", "ReasonDesc", "VendorStatus") } } return err } // CancelOrder 商户取消订单(取消订单全部商品) func (c *PurchaseHandler) CancelOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) { api := getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), "") if order.Status < model.OrderStatusEndBegin { // 发送取消状态,商户取消 err = api.DeliveryFinish(&request591.AlibabaAelophyOrderWorkCallbackRequest{ WorkCallbackRequest: &domain591.AlibabaAelophyOrderWorkCallbackWorkCallbackRequest{ StoreId: utils.String2Pointer(order.VendorStoreID), BizOrderId: utils.Int64ToPointer(utils.Str2Int64(order.VendorOrderID)), Status: utils.String2Pointer(tao_vegetable.OrderStatusMerchantCancel), }, }) } else { localSkuList, _ := dao.GetSimpleOrderSkus(dao.GetDB(), order.VendorOrderID, nil) skuMap := make(map[string]*model.OrderSku, 0) for _, v := range localSkuList { skuMap[v.VendorSubOrderID] = v } orderSkuList, err := getOrderCancelList(api, order) if err != nil { return err } outSubOrderIds := make([]domain3156.AlibabaTclsAelophyRefundCsapplyNewCsApplySubOrderDTO, 0, len(*orderSkuList.OutSubOrders)) for _, v := range *orderSkuList.OutSubOrders { if *v.CanReverse { subOrder := domain3156.AlibabaTclsAelophyRefundCsapplyNewCsApplySubOrderDTO{ RefundFee: utils.String2Pointer(utils.Int64ToStr(*v.MaxRefundFee)), RefundAmount: nil, OutSubOrderId: v.OutSubOrderId, } if skuMap[*v.OutSubOrderId] != nil { subOrder.RefundAmount = utils.String2Pointer(utils.Int2Str(skuMap[*v.OutSubOrderId].Count)) } else { continue } outSubOrderIds = append(outSubOrderIds, subOrder) } } reasonId := *orderSkuList.ReasonList param := &request3156.AlibabaTclsAelophyRefundCsapplyNewRequest{ RefundCsApplyDTO: &domain3156.AlibabaTclsAelophyRefundCsapplyNewRefundCsApplyNewDTO{ ReasonId: reasonId[0].ReasonId, OutOrderId: utils.String2Pointer(order.VendorOrderID2), StoreId: utils.String2Pointer(order.VendorStoreID), RequestId: utils.String2Pointer(fmt.Sprintf("%s%d", order.VendorStoreID, time.Now().UnixNano())), Memo: utils.String2Pointer(reason), SubRefundOrders: &outSubOrderIds, RefundReason: utils.String2Pointer(reason), OrderFrom: utils.Int64ToPointer(tao_vegetable.ChannelCome), }, } if err = api.PartialRefund(param); err == nil { c.postFakeMsg(order.VendorOrderID, tao_vegetable.OrderStatusMerchantCancel, tao_vegetable.OrderStatusMerchantCancel) } } return err } // AdjustOrder 商户发起部分退款(取消订单部分商品),淘宝没有部分退款,所以调整订单的时候就是在拣货,把缺货的部分排除 // 1、子单部分缺货,骑手妥投的时候退款给用户 // 2、子单整单缺货,商家打包完成退款给用户 // 3、整单缺货,拣货完成退款给用户 func (c *PurchaseHandler) AdjustOrder(ctx *jxcontext.Context, order *model.GoodsOrder, removedSkuList []*model.OrderSku, reason string) (err error) { api := getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), "") // 获取需要退货商品的子订单id refundSkuOrderID := make(map[int]*model.OrderSku, 0) for _, v := range removedSkuList { refundSkuOrderID[v.SkuID] = v } param := &request591.AlibabaAelophyOrderWorkCallbackRequest{} param.WorkCallbackRequest = &domain591.AlibabaAelophyOrderWorkCallbackWorkCallbackRequest{ StoreId: utils.String2Pointer(order.VendorStoreID), BizOrderId: utils.Int64ToPointer(utils.Str2Int64(order.VendorOrderID)), Status: utils.String2Pointer(tao_vegetable.OrderStatusPickedUp), } workCallbackSubOrderInfoList := make([]domain591.AlibabaAelophyOrderWorkCallbackWorkCallbackSubOrderInfo, 0, 0) orderDetail, err := getAPI(order.VendorOrgCode, order.JxStoreID, order.VendorStoreID).QueryOrderDetail(&request591.AlibabaAelophyOrderGetRequest{OrderGetRequest: &domain591.AlibabaAelophyOrderGetOrderGetRequest{ StoreId: utils.String2Pointer(order.VendorStoreID), BizOrderId: utils.Int64ToPointer(utils.Str2Int64(order.VendorOrderID)), }}) if err != nil { return err } for _, v := range *orderDetail.SubOrderResponseList { // 缺货 if refundSkuOrderID[utils.Str2Int(*v.SkuCode)] != nil { if refundSkuOrderID[utils.Str2Int(*v.SkuCode)].Count > utils.Float64TwoInt(*v.BuyStockQuantity) { return fmt.Errorf("商品[%s],缺货数量[%d],大于订单数量[%d],请重新调整", refundSkuOrderID[utils.Str2Int(*v.SkuCode)].SkuName, refundSkuOrderID[utils.Str2Int(*v.SkuCode)].Count, utils.Float64TwoInt(*v.BuyStockQuantity)) } workCallbackSubOrderInfo := domain591.AlibabaAelophyOrderWorkCallbackWorkCallbackSubOrderInfo{ BizSubOrderId: v.BizSubOrderId, SkuCode: v.SkuCode, PickSaleQuantity: utils.String2Pointer(utils.Int2Str(utils.Float64TwoInt(*v.BuySaleQuantity) - refundSkuOrderID[utils.Str2Int(*v.SkuCode)].Count)), PickStockQuantity: utils.String2Pointer(utils.Int2Str(utils.Float64TwoInt(*v.BuyStockQuantity) - refundSkuOrderID[utils.Str2Int(*v.SkuCode)].Count)), } workCallbackSubOrderInfoList = append(workCallbackSubOrderInfoList, workCallbackSubOrderInfo) } else { workCallbackSubOrderInfo := domain591.AlibabaAelophyOrderWorkCallbackWorkCallbackSubOrderInfo{ BizSubOrderId: v.BizSubOrderId, SkuCode: v.SkuCode, PickSaleQuantity: utils.String2Pointer(utils.Float64ToStr(*v.BuySaleQuantity)), PickStockQuantity: utils.String2Pointer(utils.Float64ToStr(*v.BuyStockQuantity)), } workCallbackSubOrderInfoList = append(workCallbackSubOrderInfoList, workCallbackSubOrderInfo) } } // 出库 param.WorkCallbackRequest.WorkCallbackSubOrderInfoList = &workCallbackSubOrderInfoList if err = api.DeliveryFinish(param); err != nil { globals.SugarLogger.Debugf("PickupGoods 拣货失败可能是BizSubOrderId 没填写 : %s", err.Error()) return fmt.Errorf("订单缺货失败,请拣货完成前取货.或者联系客户发起部分退款:%v", err) } c.postFakeMsg(order.VendorOrderID, tao_vegetable.OrderStatusPickedUp, tao_vegetable.OrderStatusPickedUp) return nil } // ListOrders 获取门店订单列表(补全遗漏订单) func (c *PurchaseHandler) ListOrders(ctx *jxcontext.Context, vendorOrgCode string, parentTask tasksch.ITask, queryDate time.Time, vendorStoreID string) (vendorOrderIDs []string, err error) { if utils.IsTimeZero(queryDate) { return nil, fmt.Errorf("queryDate必须指定") } queryDate = utils.Time2Date(queryDate) var vendorStoreIDs []string var api = getAPI(vendorOrgCode, 0, vendorStoreID) if vendorStoreID == "" { vendorStoreIDs, err = c.GetAllStoresVendorID(ctx, vendorOrgCode) if err != nil { return nil, err } } else { vendorStoreIDs = []string{vendorStoreID} } task := tasksch.NewParallelTask("tao ListOrders", nil, ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { vendorStoreID := batchItemList[0].(string) var orderIDs []string // 获取当前门店当天的订单 if vendorOderID, err2 := api.GetTransactionOrderListByTime(vendorStoreID, queryDate); err2 == nil { orderIDs = vendorOderID } retVal = orderIDs return retVal, nil }, vendorStoreIDs) tasksch.HandleTask(task, parentTask, true).Run() orderList, err := task.GetResult(0) if err == nil && len(orderList) > 0 { vendorOrderIDs = make([]string, len(orderList)) for k, v := range orderList { vendorOrderIDs[k] = v.(string) } } return vendorOrderIDs, err } // GetWaybillTip 自配送暂无小费 func (c *PurchaseHandler) GetWaybillTip(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID, vendorOrderID, vendorWaybillID, vendorWaybillID2 string) (tipFee int64, err error) { return tipFee, err } // UpdateWaybillTip 暂无小费 func (c *PurchaseHandler) UpdateWaybillTip(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID, vendorOrderID, vendorWaybillID, vendorWaybillID2, cityCode string, tipFee int64) (err error) { return err } func (c *PurchaseHandler) GetSelfTakeCode(ctx *jxcontext.Context, order *model.GoodsOrder) (selfTakeCode string, err error) { return selfTakeCode, err } func (c *PurchaseHandler) ConfirmSelfTake(ctx *jxcontext.Context, order *model.GoodsOrder, selfTakeCode string) (err error) { return err } func (c *PurchaseHandler) ComplaintRider(vendorOrderId string, resonID int, resonContent string) (err error) { return fmt.Errorf("淘宝暂未对接配送API") } // GetCancelDeliveryReason 转自配送时取消非专送混合送门店取消理由 func (c *PurchaseHandler) GetCancelDeliveryReason(order *model.GoodsOrder) (string, error) { return "", nil } // 取消美团外卖理由转使用三方配送 func (c *PurchaseHandler) CancelLogisticsByWmOrderId(order *model.GoodsOrder, reasonCode, detailContent, appPoiCode, orderId string) error { return nil } // 获取订单配送状态 func (c *PurchaseHandler) OrderLogisticsStatus(orderId string) (*utils.RiderInfo, error) { return nil, nil } // GetOrderSettleAccounts 获取订单结算信息(t+1)当前订单获取不到结算 func (c *PurchaseHandler) GetOrderSettleAccounts(order *model.GoodsOrder) (int64, error) { return 0, nil } // GetOrderTotalShopMoney 获取门店结算信息 func GetOrderTotalShopMoney(appOrgCode string, vendorStoreID string, start, end time.Time) (map[string]string, error) { if appOrgCode == "" || vendorStoreID == "" { return nil, errors.New("appKey 不能为空且平台门店ID不能为空") } if start.IsZero() || end.IsZero() { return nil, errors.New("开始时间和结束时间不能为空") } settlement := make(map[string]string, 0) api := getAPI(appOrgCode, 0, vendorStoreID) startBillDate := util.LocalTime(start) endBillDate := util.LocalTime(end) pageSize := 200 pageIndex := 1 param := &request591.AlibabaWdkBillListRequest{ TxdBillListGetRequest: &domain591.AlibabaWdkBillListTxdBillListGetRequest{ EndBillDate: &endBillDate, StartBillDate: &startBillDate, ShopCode: utils.String2Pointer(vendorStoreID), PageSize: utils.Int64ToPointer(int64(pageSize)), PageIndex: utils.Int64ToPointer(int64(pageIndex)), }, } var totalIndex int64 = 0 result, err := api.QueryBillList(param) if err != nil { return settlement, nil } for _, v := range *result.TxdBillDetailBOS { if *v.OrderType == "positive" { settlement[*v.BizOrderId] = *v.ReceivableAmount } } if *result.Total > int64(pageSize) { totalIndex = *result.Total / int64(pageSize) if *result.Total%int64(pageSize) != model.NO { totalIndex += 1 } for i := 2; i <= int(totalIndex); i++ { param.TxdBillListGetRequest.PageIndex = utils.Int64ToPointer(int64(i)) result2, err := api.QueryBillList(param) if err != nil { return settlement, nil } for _, v := range *result2.TxdBillDetailBOS { if *v.OrderType == "positive" { settlement[*v.BizOrderId] = *v.ReceivableAmount } } } } return settlement, nil } // GetPlatformLogisticsFee 获取自配送订单的配送费 func (c *PurchaseHandler) GetPlatformLogisticsFee(order *model.GoodsOrder) (int64, error) { return 0, nil } // ApplyCompensationOrder 订单索赔 func (c *PurchaseHandler) ApplyCompensationOrder(order *model.GoodsOrder) (string, error) { return "", nil }