Files
jx-callback/business/partner/purchase/tao_vegetable/order.go
2023-10-30 09:09:14 +08:00

968 lines
40 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)
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
//var salePrice int64 = 0
//var weight int = 0
order.PmSubsidyMoney = *orderDetail.SkuDiscountPlatformFee // 平台承担优惠
// 添加需要赠送的东西(暂时没有赠品套餐直接商品)
multiSkuMap := make(map[int]int)
if len(*orderDetail.SubOrderResponseList) > 0 {
for _, extra := range *orderDetail.SubOrderResponseList {
// 这个是包装袋的价格,用户退款是包装袋未推送退款,导致本地订单退款状态无法更新,取消包装袋的记录
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)
// 用户信息
order.ConsigneeName = *orderDetail.ReceiveInfo.ReceiverName
order.ConsigneeMobile = *orderDetail.ReceiveInfo.ReceiverPhone
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 = "未获取到" // 真实门店名称
}
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
}
api := getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), "")
for i := 0; i < 3; i++ {
err2 := api.DeliveryFinish(param)
if err2 != nil {
time.Sleep(200 * time.Millisecond)
err = err2
continue
}
if err2 == nil {
c.postFakeMsg(order.VendorOrderID, tao_vegetable.OrderStatusPickedUp, tao_vegetable.OrderStatusPickedUp)
return nil
}
}
}
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 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 err
}
// 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
}