Files
jx-callback/business/partner/purchase/mtwm/order.go
邹宗楠 14b6c34652 1
2025-08-12 17:52:30 +08:00

1070 lines
46 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 mtwm
import (
"encoding/json"
"errors"
"fmt"
push "git.rosy.net.cn/jx-callback/business/jxutils/unipush"
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
"net/url"
"regexp"
"strconv"
"strings"
"time"
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
"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"
)
const (
FakeMsgType = "fakeMsgType"
fakeFinishedPickup = "fake_finished_pickup"
fakeUserApplyCancel = "fake_user_apply_cancel"
fakeMerchantAgreeApplyCancel = "fake_merchant_agree_apply_cancel"
fakeRefuseUserApplyCancel = "fake_refuse_user_apply_cancel"
fakeUserUndoApplyCancel = "fake_user_undo_apply_cancel"
fakeOrderAdjustFinished = "fake_order_adjust_finished"
keyVendorOrgCode = "vendorOrgCode"
)
const (
SelfDeliveryCarrierNo = 1 // 美团配送方式0-美团专送1-商家自送
)
const (
// pickupOrderDelay = 260 * time.Second
// pickupOrderDelay = 1 * time.Second
// callDeliveryDelay = 10 * time.Minute
// callDeliveryDelayGap = 30
)
var (
specPat = regexp.MustCompile(`(\d+)(.+)`)
)
var (
VendorStatus2StatusMap = map[string]int{
mtwmapi.OrderStatusUserCommitted: model.OrderStatusUnknown,
mtwmapi.OrderStatusNew: model.OrderStatusNew,
// mtwmapi.OrderStatusReceived: model.OrderStatusAccepted,
// mtwmapi.OrderStatusAccepted: model.OrderStatusFinishedPickup,
mtwmapi.OrderStatusAccepted: model.OrderStatusAccepted,
mtwmapi.OrderStatusDelivering: model.OrderStatusDelivering,
mtwmapi.OrderStatusDelivered: model.OrderStatusUnknown, // 以mtwmapi.OrderStatusFinished为结束状态这个当成一个中间状态且很少看到这个状态
mtwmapi.OrderStatusFinished: model.OrderStatusFinished,
mtwmapi.OrderStatusCanceled: model.OrderStatusCanceled,
mtwmapi.MsgTypeOrderModified: model.OrderStatusAdjust, // 用户调整订单
mtwmapi.MsgTypeOrderFinancial: model.OrderStatusUnknown, // 订单结算
fakeFinishedPickup: model.OrderStatusFinishedPickup,
fakeOrderAdjustFinished: model.OrderStatusAdjust,
fakeRefuseUserApplyCancel: model.OrderStatusVendorRejectCancel,
fakeUserApplyCancel: model.OrderStatusApplyCancel,
fakeUserUndoApplyCancel: model.OrderStatusUndoApplyCancel,
fakeMerchantAgreeApplyCancel: model.OrderStatusCanceled,
}
skuActTypeMap = map[int]int{
mtwmapi.ExtrasPromotionTypeTeJiaCai: 1,
mtwmapi.ExtrasPromotionTypeZheKouCai: 1,
mtwmapi.ExtrasPromotionTypeSecondHalfPrice: 1,
}
)
func (p *PurchaseHandler) getStatusFromVendorStatus(vendorStatus string) int {
if status, ok := VendorStatus2StatusMap[vendorStatus]; ok {
return status
}
return model.OrderStatusUnknown
}
func (p *PurchaseHandler) getOrder(vendorOrgCode, vendorOrderID, vendorStoreID string) (order *model.GoodsOrder, orderMap map[string]interface{}, err error) {
result, err := getAPI(vendorOrgCode, 0, vendorStoreID).OrderGetOrderDetail(utils.Str2Int64(vendorOrderID), true)
if err == nil {
result[keyVendorOrgCode] = vendorOrgCode
order = p.Map2Order(result)
}
return order, result, err
}
func (p *PurchaseHandler) GetOrderRider(vendorOrgCode, vendorStoreID string, param map[string]interface{}) (err error) {
return getAPI(vendorOrgCode, 0, vendorStoreID).OrderStatusAndPsInfo(param)
}
func (p *PurchaseHandler) GetOrder(vendorOrgCode, vendorOrderID, vendorStoreID string) (order *model.GoodsOrder, err error) {
order, _, err = p.getOrder(vendorOrgCode, vendorOrderID, vendorStoreID)
return order, err
}
func (p *PurchaseHandler) GetOrderStatus(vendorOrgCode, vendorOrderID string) (status int, err error) {
if order, _ := partner.CurOrderManager.LoadOrder(vendorOrderID, model.VendorIDMTWM); order != nil {
status, err = getAPI(vendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), "").OrderViewStatus(utils.Str2Int64(vendorOrderID))
}
if err == nil {
status = p.getStatusFromVendorStatus(utils.Int2Str(status))
}
return status, err
}
func (p *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *model.GoodsOrder) {
result := orderData
vendorOrderID := utils.Int64ToStr(utils.MustInterface2Int64(result["order_id"]))
// 因为美团外卖不能自动设置商家门店号,且只能通过商家门店号来访问门店,
// 为了在后台设置简单一致把app_poi_code直接当成平台门店号使用(即在后台设置时,平台门店号与商家门店号一样)
// 订单中wm_poi_id实际来平台门店号app_poi_code为商家门店号这样一来这两个就相同了
//_修改为,
caution := strings.ReplaceAll(utils.Interface2String(result["caution"]), "_", ",")
order = &model.GoodsOrder{
VendorOrderID: vendorOrderID,
// VendorOrderID2: utils.Int64ToStr(utils.MustInterface2Int64(result["wm_order_id_view"])),
VendorID: model.VendorIDMTWM,
VendorStoreID: result["app_poi_code"].(string),
StoreID: 0,
// VendorStoreID: utils.Int64ToStr(utils.MustInterface2Int64(result["wm_poi_id"])),
// StoreID: int(utils.Str2Int64WithDefault(utils.Interface2String(result["app_poi_code"]), 0)),
StoreName: result["wm_poi_name"].(string),
ConsigneeName: result["recipient_name"].(string),
ConsigneeMobile: jxutils.FormalizeMobile(result["recipient_phone"].(string)),
ConsigneeAddress: result["recipient_address"].(string),
CoordinateType: model.CoordinateTypeMars,
//BuyerComment: utils.TrimBlankChar(utils.Interface2String(result["caution"])),
BuyerComment: utils.TrimBlankChar(caution),
ExpectedDeliveredTime: getTimeFromTimestamp(utils.Interface2Int64WithDefault(result["delivery_time"], 0)),
PickDeadline: utils.DefaultTimeValue,
VendorStatus: utils.Int64ToStr(utils.MustInterface2Int64(result["status"])),
OrderSeq: int(utils.MustInterface2Int64(result["day_seq"])),
StatusTime: getTimeFromTimestamp(utils.MustInterface2Int64(result["ctime"])),
OrderCreatedAt: getTimeFromTimestamp(utils.MustInterface2Int64(result["ctime"])),
// OrderFinishedAt: getTimeFromTimestamp(utils.MustInterface2Int64(result["order_completed_time"])),
OriginalData: string(utils.MustMarshal(result)),
ActualPayPrice: jxutils.StandardPrice2Int(utils.MustInterface2Float64(result["total"])),
BaseFreightMoney: jxutils.StandardPrice2Int(utils.Interface2Float64WithDefault(result["shipping_fee"], 0)),
InvoiceTitle: utils.Interface2String(result["invoice_title"]),
InvoiceTaxerID: utils.Interface2String(result["taxpayer_id"]),
InvoiceEmail: jxutils.GetOneEmailFromStr(utils.Interface2String(result["caution"])),
VendorOrgCode: utils.Interface2String(result[keyVendorOrgCode]),
}
if result["order_completed_time"] != nil {
order.OrderFinishedAt = getTimeFromTimestamp(utils.MustInterface2Int64(result["order_completed_time"]))
} else {
order.OrderFinishedAt = utils.DefaultTimeValue
}
if result["backup_recipient_phone"] != nil {
backupRecipientPhone := result["backup_recipient_phone"].(string)
phones := make([]string, 0, 0)
json.Unmarshal([]byte(backupRecipientPhone), &phones)
if len(phones) > model.NO {
order.ConsigneeMobile2 = jxutils.FormalizeMobile(phones[0])
}
}
pickType := int(utils.Interface2Int64WithDefault(result["pick_type"], 0))
if pickType == mtwmapi.OrderPickTypeSelf {
order.DeliveryType = model.OrderDeliveryTypeSelfTake
} else {
logisticsCode := utils.Interface2String(result["logistics_code"])
if logisticsCode == mtwmapi.PeiSongTypeSelf || logisticsCode == mtwmapi.PeiSongTypeMTZSPT {
order.DeliveryType = model.OrderDeliveryTypeStoreSelf
} else {
order.DeliveryType = model.OrderDeliveryTypePlatform
}
}
openUID := utils.Interface2Int64WithDefault(result["openUid"], 0)
if openUID > 0 {
order.VendorUserID = utils.Int64ToStr(openUID)
}
// 不设置最晚拣货时间,以缺省值为准
// if utils.IsTimeZero(order.PickDeadline) && !utils.IsTimeZero(order.StatusTime) {
// order.PickDeadline = order.StatusTime.Add(pickupOrderDelay) // 美团外卖要求在5分钟内拣货不然订单会被取消
// }
order.Status = p.getStatusFromVendorStatus(order.VendorStatus)
if utils.IsTimeZero(order.ExpectedDeliveredTime) {
order.BusinessType = model.BusinessTypeImmediate
} else {
order.BusinessType = model.BusinessTypeDingshida
}
if utils.Interface2Int64WithDefault(result["delivery_time"], 0) == 0 {
order.ExpectedDeliveredTime = getTimeFromTimestamp(utils.Interface2Int64WithDefault(result["estimate_arrival_time"], 0))
}
originalLng := utils.MustInterface2Float64(result["longitude"])
originalLat := utils.MustInterface2Float64(result["latitude"])
order.ConsigneeLng = jxutils.StandardCoordinate2Int(originalLng)
order.ConsigneeLat = jxutils.StandardCoordinate2Int(originalLat)
var detail []map[string]interface{}
if err := utils.UnmarshalUseNumber([]byte(result["detail"].(string)), &detail); err != nil {
panic(fmt.Sprintf("mtwm Map2Order vendorID:%s failed with error:%v", vendorOrderID, err))
}
// 添加需要赠送的东西
if result["extras"] != nil {
var extraList []*mtwmapi.OrderExtraInfo
if err := utils.UnmarshalUseNumber([]byte(result["extras"].(string)), &extraList); err != nil {
panic(fmt.Sprintf("mtwm Map2Order vendorID:%s failed with error:%v", vendorOrderID, err))
}
for _, extra := range extraList {
order.DiscountMoney += jxutils.StandardPrice2Int(extra.ReduceFee)
if extra.Type == mtwmapi.ExtrasPromotionTypeTaoCanZeng || extra.Type == mtwmapi.ExtrasPromotionTypeManZeng {
sku := &model.OrderSku{
VendorOrderID: order.VendorOrderID,
VendorID: model.VendorIDMTWM,
Count: 1,
SkuID: 0,
VendorSkuID: "",
SkuName: extra.Remark,
Weight: 0,
SalePrice: 0,
StoreSubName: utils.Int2Str(extra.Type),
LocationCode: "活动商品,暂无货架码",
}
order.Skus = append(order.Skus, sku)
}
}
}
if poiReceiveDetailStr := utils.Interface2String(result["poi_receive_detail"]); poiReceiveDetailStr != "" {
var poiReceiveDetail *mtwmapi.PoiReceiveDetailInfo
utils.UnmarshalUseNumber([]byte(poiReceiveDetailStr), &poiReceiveDetail)
if poiReceiveDetail != nil {
order.TotalShopMoney = poiReceiveDetail.WmPoiReceiveCent
for _, v := range poiReceiveDetail.ActOrderChargeByMt {
order.PmSubsidyMoney += v.MoneyCent
}
}
}
var skuBenefitDetailMap map[string]*mtwmapi.SkuBenefitDetailInfo
if skuBenefitDetai := utils.Interface2String(result["sku_benefit_detail"]); skuBenefitDetai != "" {
skuBenefitDetailMap = make(map[string]*mtwmapi.SkuBenefitDetailInfo)
var skuBenefitDetailList []*mtwmapi.SkuBenefitDetailInfo
utils.UnmarshalUseNumber([]byte(skuBenefitDetai), &skuBenefitDetailList)
for _, v := range skuBenefitDetailList {
skuBenefitDetailMap[v.SkuID] = v
}
}
ignoreSkuMap := make(map[int]int)
multiSkuMap := make(map[int]int)
for _, product := range detail {
skuName := product["food_name"].(string)
skuID := utils.Interface2String(product["sku_id"])
sku := &model.OrderSku{
VendorOrderID: order.VendorOrderID,
VendorID: model.VendorIDMTWM,
Count: int(utils.MustInterface2Float64(product["quantity"])),
SkuID: int(utils.Str2Int64WithDefault(skuID, 0)),
VendorSkuID: skuID,
SkuName: skuName,
Weight: getSkuWeight(product),
VendorPrice: jxutils.StandardPrice2Int(utils.MustInterface2Float64(product["price"])),
SalePrice: jxutils.StandardPrice2Int(utils.MustInterface2Float64(product["price"])),
LocationCode: utils.Interface2String(product["location_code"]),
}
if product["upc"] != nil && product["upc"].(string) != "" {
sku.Upc = product["upc"].(string)
}
_, _, _, specUnit, _, specQuality := jxutils.SplitSkuName(sku.SkuName)
nameWeight := jxutils.FormatSkuWeight(specQuality, specUnit)
if nameWeight == 0 {
skuName += " " + product["spec"].(string)
}
if sku.VendorSkuID == "" {
if !strings.Contains(product["app_food_code"].(string), "mtcode") {
sku.VendorSkuID = product["app_food_code"].(string)
} else {
sku.VendorSkuID = utils.Int64ToStr(utils.Interface2Int64WithDefault(product["mt_sku_id"], 0))
}
}
if sku.Weight == 0 {
sku.Weight = 222 // 如果名字里找不到缺省给半斤左右的一个特别值
}
if skuBenefitDetailMap != nil && skuBenefitDetailMap[sku.VendorSkuID] != nil && ignoreSkuMap[sku.SkuID] == 0 /* && sku.Count == 1 */ {
for _, v := range skuBenefitDetailMap[sku.VendorSkuID].WmAppOrderActDetails {
if /*skuActTypeMap[v.Type] == 1 && */ strings.Index(v.Remark, skuName) >= 0 && sku.Count == v.Count {
if sku.SalePrice-jxutils.StandardPrice2Int(v.MtCharge+v.PoiCharge) < 0 {
continue
} else {
ignoreSkuMap[sku.SkuID] = 1
sku.SalePrice -= jxutils.StandardPrice2Int(v.MtCharge + v.PoiCharge)
}
sku.StoreSubName = utils.Int2Str(v.Type)
}
}
}
if sku.SalePrice < 0 {
sku.SalePrice = jxutils.StandardPrice2Int(utils.MustInterface2Float64(product["price"]))
}
order.Skus = append(order.Skus, sku)
multiSkuMap[sku.SkuID]++
}
for _, v := range order.Skus {
if multiSkuMap[v.SkuID] > 1 && v.SalePrice == v.VendorPrice {
v.IsVendorAct = model.YES
}
}
// 包装袋金额
store, _ := dao.GetStoreDetailByVendorStoreID(dao.GetDB(), order.VendorStoreID, model.VendorIDMTWM, order.VendorOrgCode)
if store != nil {
order.StoreName = store.Name // 真实门店名称
order.PackagePrice = store.PackageSetting
}
jxutils.RefreshOrderSkuRelated(order)
return order
}
func getRefundSkuDetailList(msg *mtwmapi.CallbackMsg, order *model.GoodsOrder) (skuList []*mtwmapi.RefundSkuDetail, err error) {
if false {
skuList = getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), "").GetRefundSkuDetailFromMsg(msg)
} else {
refundOrderDetailList, err2 := getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), "").GetOrderRefundDetail(utils.Str2Int64(GetOrderIDFromMsg(msg)), mtwmapi.RefundTypePart)
if err = err2; err == nil {
for _, v := range refundOrderDetailList {
skuList = append(skuList, v.WmAppRetailForOrderPartRefundList...)
}
}
}
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(msg *mtwmapi.CallbackMsg) (response *mtwmapi.CallbackResponse) {
var err error
if c.isAfsMsg(msg) {
response = c.OnAfsOrderMsg(msg)
return response
} else {
status := c.callbackMsg2Status(msg)
if partner.CurOrderManager.GetStatusDuplicatedCount(status) > 1 { // 重复消息推送校验,允许推送两次
return nil
}
if msg.Cmd == mtwmapi.MsgTypeNewOrder {
order, orderMap, err2 := c.getOrder(msg.AppID, GetOrderIDFromMsg(msg), GetVendorStoreIDFromMsg(msg))
if err = err2; err == nil {
// 存在新订单用户未支付推送,导致订单取消,但是订单又会被送出
if order.OrderSeq == 0 {
return mtwmapi.Err2CallbackResponse(fmt.Errorf("day_seq暂未获取到"), "")
}
err = partner.CurOrderManager.OnOrderNew(order, c.callbackMsg2Status(msg))
if err == nil {
utils.CallFuncAsync(func() {
if msg.Cmd == mtwmapi.MsgTypeNewOrder {
c.OnOrderDetail(orderMap, partner.CreatedPeration)
} else {
c.OnOrderDetail(orderMap, partner.UpdatedPeration)
}
})
}
}
} else if msg.Cmd == mtwmapi.MsgTypeOrderModified || msg.Cmd == mtwmapi.MsgTypeOrderDeliveryFeeChange {
order, orderObj, err2 := c.getOrder(msg.AppID, GetOrderIDFromMsg(msg), GetVendorStoreIDFromMsg(msg))
localOrder, _ := partner.CurOrderManager.LoadOrder(GetOrderIDFromMsg(msg), model.VendorIDMTWM)
if localOrder == nil {
return mtwmapi.Err2CallbackResponse(err, "")
// 会存在用户没支付订单,但是订单已经创建了,这个时候有可能会取消订单,所以这个地方直接退出不管了
// 等到美团推送新订单的时候再创建订单
/* localOrder = order
partner.CurOrderManager.OnOrderNew(order, status)
partner.CurOrderManager.SaveOrder(order, false, dao.GetDB())
partner.CurOrderManager.OnOrderMsg(localOrder, fmt.Sprintf("订单重新创建,加入监视器,检查是否会自动拣货[%s]", order.VendorOrderID), "")*/
}
if err2 == nil {
switch msg.Cmd {
case mtwmapi.MsgTypeOrderModified:
// 推送订单信息变更(可能包含地址变更)
localOrder.ConsigneeName = order.ConsigneeName
localOrder.ConsigneeMobile = order.ConsigneeMobile
localOrder.BuyerComment = order.BuyerComment
localOrder.ExpectedDeliveredTime = order.ExpectedDeliveredTime
localOrder.ConsigneeAddress = order.ConsigneeAddress
localOrder.ConsigneeLat = order.ConsigneeLat
localOrder.ConsigneeLng = order.ConsigneeLng
var changeFee int64 = 0
if addressChangeFee, ok := orderObj["address_change_fee"]; ok {
changeFee = utils.Float64TwoInt64(utils.Str2Float64(utils.Interface2String(addressChangeFee)) * 100)
localOrder.TotalShopMoney += changeFee
}
dao.UpdateEntity(dao.GetDB(), localOrder, "TotalShopMoney", "ConsigneeName", "ConsigneeMobile", "BuyerComment", "ExpectedDeliveredTime", "ConsigneeAddress", "ConsigneeLat", "ConsigneeLng")
weixinmsg.NotifyAdjustOrder(order)
push.NotifyAdjustOrder(order)
partner.CurOrderManager.OnOrderMsg(localOrder, fmt.Sprintf("订单[%s],被用户发起修改,补充运费差价[%d]", order.VendorOrderID, changeFee), "")
case mtwmapi.MsgTypeOrderDeliveryFeeChange:
// 推送自配订单地址变更费退款详情,当订单为自配订单且用户修改地址时支付了地址变更费,如果订单最终流转到了取消状态,当地址变更费退款成功时平台会通过此接口推送退款详情
var changeFee int64 = 0
if addressChangeFee, ok := orderObj["address_change_fee"]; ok {
changeFee = utils.Float64TwoInt64(utils.Str2Float64(utils.Interface2String(addressChangeFee)) * 100)
localOrder.TotalShopMoney -= changeFee
}
dao.UpdateEntity(dao.GetDB(), localOrder, "TotalShopMoney")
partner.CurOrderManager.OnOrderMsg(localOrder, fmt.Sprintf("订单[%s],地址发送改变且订单被取消,返回推送配送差价[%s]元,{接口[%.2f]元}", order.VendorOrderID, msg.FormData.Get("money"), float64(changeFee)/float64(100)), "")
}
}
} else {
if status != nil {
var order *model.GoodsOrder
if order, err = partner.CurOrderManager.LoadOrder(GetOrderIDFromMsg(msg), model.VendorIDMTWM); err == nil {
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 status.Status == model.OrderStatusUnknown && status.VendorStatus == mtwmapi.MsgTypeOrderFinancial && order.Status == model.OrderStatusCanceled {
return nil
} else {
if status.Status == model.OrderStatusDelivering {
// 美团订单即使时在配送状态时,如果之前没有调用过拣货完成,也会对门店指标生成影响,这里强制再调用拣货完成,且忽略错误
utils.CallFuncAsync(func() {
if globals.EnableMtwmStoreWrite {
err = getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), "").PreparationMealComplete(utils.Str2Int64(status.VendorOrderID))
}
})
}
err = partner.CurOrderManager.OnOrderStatusChanged(msg.AppID, status)
if err == nil && msg.Cmd == mtwmapi.MsgTypeOrderFinished {
utils.CallFuncAsync(func() {
orderMap, err := getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), "").OrderGetOrderDetail(utils.Str2Int64(GetOrderIDFromMsg(msg)), true)
if err == nil && utils.MustInterface2Int64(orderMap["is_third_shipping"]) == SelfDeliveryCarrierNo {
c.OnOrderDetail(orderMap, partner.UpdatedPeration)
}
})
// 美团订单完成时,获取跑腿费用
//if fee, feeErr := partner.GetPurchasePlatformFromVendorID(order.VendorID).GetPlatformLogisticsFee(order); feeErr != nil {
// bill, err := partner.CurOrderManager.LoadWaybill(order.VendorOrderID, model.VendorIDMTWM)
// if bill == nil && err == nil {
// bill.ActualFee = fee
// bill.DesiredFee = fee
// dao.UpdateEntity(dao.GetDB(), bill, "ActualFee", "DesiredFee")
// }
//}
}
}
}
}
}
}
return mtwmapi.Err2CallbackResponse(err, "")
}
func (c *PurchaseHandler) callbackMsg2Status(msg *mtwmapi.CallbackMsg) (orderStatus *model.OrderStatus) {
orderID := GetOrderIDFromMsg(msg)
vendorStatus := msg.Cmd
remark := ""
statusTime := utils.Str2Int64(msg.FormData.Get("timestamp"))
switch msg.Cmd {
case mtwmapi.MsgTypeUserUrgeOrder, mtwmapi.MsgTypeOrderModified, mtwmapi.MsgTypeOrderFinancial:
vendorStatus = msg.Cmd
case mtwmapi.MsgTypeOrderCanceled:
vendorStatus = mtwmapi.OrderStatusCanceled
remark = msg.FormData.Get("reason")
case FakeMsgType, mtwmapi.MsgTypeNewOrder, mtwmapi.MsgTypeOrderAccepted, mtwmapi.MsgTypeOrderFinished:
vendorStatus = msg.FormData.Get("status")
statusTime = utils.Str2Int64(msg.FormData.Get("utime"))
case mtwmapi.MsgTypeOrderRefund, mtwmapi.MsgTypeOrderPartialRefund: // 订单退款,部分退款
notifyType := msg.FormData.Get("notify_type")
vendorStatus = msg.Cmd + "-" + notifyType
if true { // 已经提前判断了,到这里的都是售中
remark = msg.FormData.Get("reason")
if msg.Cmd == mtwmapi.MsgTypeOrderPartialRefund { // 部分退款
if notifyType == mtwmapi.NotifyTypePartyApply {
if globals.EnableMtwmStoreWrite {
//if order, _ := partner.CurOrderManager.LoadOrder(orderID, model.VendorIDMTWM); order != nil {
// getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), "").OrderRefundAgree(utils.Str2Int64(orderID), "自动确认退款")
//}
// goods, err := dao.GetSimpleOrder(dao.GetDB(), orderID)
// if err == nil {
// if goods.Status < model.OrderStatusDelivering {
// } else {
// api.MtwmAPI.OrderRefundReject(utils.Str2Int64(orderID), "商品配送中,请联系门店。") // todo 京东与饿百都没有售前用户提出订单调整的,自动拒绝调整单
// }
// }
}
} else if notifyType == mtwmapi.NotifyTypeSuccess {
vendorStatus = fakeOrderAdjustFinished
}
} else if msg.Cmd == mtwmapi.MsgTypeOrderRefund {
if notifyType == mtwmapi.NotifyTypeApply {
vendorStatus = fakeUserApplyCancel
} else if notifyType == mtwmapi.NotifyTypeCancelRefund || notifyType == mtwmapi.NotifyTypeCancelRefundComplaint {
vendorStatus = fakeUserUndoApplyCancel
} else if notifyType == mtwmapi.NotifyTypeReject {
vendorStatus = fakeRefuseUserApplyCancel
} else if notifyType == mtwmapi.NotifyTypeSuccess {
vendorStatus = fakeMerchantAgreeApplyCancel // todo 可能导致订单取消消息重复
}
}
}
default:
globals.SugarLogger.Errorf("mtwm unkonw msg:%s", utils.Format4Output(msg, false))
}
if vendorStatus != "" {
orderStatus = &model.OrderStatus{
VendorOrderID: orderID,
VendorID: model.VendorIDMTWM,
OrderType: model.OrderTypeOrder,
RefVendorOrderID: orderID,
RefVendorID: model.VendorIDMTWM,
VendorStatus: vendorStatus,
Status: c.getStatusFromVendorStatus(vendorStatus),
StatusTime: getTimeFromTimestamp(statusTime),
Remark: remark,
}
}
return orderStatus
}
func (c *PurchaseHandler) postFakeMsg(vendorOrderID, cmd, vendorStatus string) {
msg := &mtwmapi.CallbackMsg{
Cmd: cmd,
FormData: make(url.Values),
}
timeStr := utils.Int64ToStr(time.Now().Unix())
msg.FormData.Set(mtwmapi.KeyOrderID, vendorOrderID)
msg.FormData.Set("status", vendorStatus)
msg.FormData.Set("timestamp", timeStr)
msg.FormData.Set("utime", timeStr)
utils.CallFuncAsync(func() {
response := c.onOrderMsg(msg)
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, model.VendorIDMTWM)
if err == nil {
partner.CurOrderManager.OnOrderMsg(order, "美团订单假拣货", utils.Format4Output(response, false))
}
})
}
func (c *PurchaseHandler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) {
if isAcceptIt {
if globals.EnableMtwmStoreWrite {
err = getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), "").OrderConfirm(utils.Str2Int64(order.VendorOrderID))
if err != nil {
if utils.IsErrMatch(err, utils.Int2Str(mtwmapi.ErrCodeOpFailed), []string{
"订单已经确认过了",
}) {
err = nil
goodsOrder, _ := partner.CurOrderManager.LoadOrder(order.VendorOrderID, order.VendorID)
if goodsOrder.Status < model.OrderStatusAccepted {
order.Status = model.OrderStatusAccepted
dao.UpdateEntity(dao.GetDB(), order, "Status")
}
partner.CurOrderManager.OnOrderMsg(order, "订单确认接单成功", utils.Time2TimeStr(time.Now()))
} else {
globals.SugarLogger.Warnf("mtwm AcceptOrRefuseOrder orderID:%s failed with err:%v", order.VendorOrderID, err)
}
}
}
} else {
if globals.EnableMtwmStoreWrite {
err = c.CancelOrder(jxcontext.AdminCtx, order, "bu")
}
}
return err
}
// 美团配送门店配送方式
func (c *PurchaseHandler) PickupGoods(order *model.GoodsOrder, isSelfDelivery bool, userName string) (err error) {
orderDetail, err := getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), "").OrderGetOrderDetail(utils.Str2Int64(order.VendorOrderID), false)
if err != nil {
return err
}
// 美团专送、快送、混合送、美团企客
logisticsCode := utils.Interface2String(orderDetail["logistics_code"])
isSelfDelivery = logisticsCode == mtwmapi.PeiSongTypeMTZSJM || logisticsCode == mtwmapi.PeiSongTypeMTZSPT ||
logisticsCode == mtwmapi.PeiSongTypeMTZSZJ || logisticsCode == mtwmapi.PeiSongTypeKuaiDi || logisticsCode == mtwmapi.PeiSongTypeMTZSDL ||
logisticsCode == mtwmapi.PeiSongTypeMixed || logisticsCode == mtwmapi.PeiSongTypeQiKe ||
logisticsCode == mtwmapi.PeiSongTypeMixedExpressQiKe || logisticsCode == mtwmapi.PeiSongTypeFranchise ||
logisticsCode == mtwmapi.PeiSongTypeSelf || logisticsCode == mtwmapi.PeiSongTypeWholeCity ||
logisticsCode == mtwmapi.PeiSongTypeMixedSelf || logisticsCode == mtwmapi.PeiSongTypeNewQuik
//1001-专送加盟1002-专送(自建)
//2002-快送3001-混合送(专送+快送)
//4015-企客远距离配送
//此接口适用于美团专送、快送、混合送、美团企客的订单确认备货完成
//PeiSongTypeSelf = "0000" // 商家自配
//PeiSongTypeQuHuo = "0002" // 趣活
//PeiSongTypeDada = "0016" // 达达
//PeiSongTypeE = "0033" // E代送
//PeiSongTypeMTZSJM = "1001" // 美团专送-加盟
//PeiSongTypeMTZSZJ = "1002" // 美团专送-自建
//PeiSongTypeMTZSPT = "1003" // 美团跑腿(原众包)
//PeiSongTypeMTZSDL = "1004" // 美团专送-城市代理
//PeiSongTypeJiaoMa = "2001" // 角马
//PeiSongTypeKuaiDi = "2002" // 快送
//PeiSongTypeWholeCity = "2010" // 全城送
//PeiSongTypeMixed = "3001" // 混合送(即美团专送+快送)
//PeiSongTypeMixedExpressQiKe // 混合快送
// 30011002
if isSelfDelivery {
err = getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), "").PreparationMealComplete(utils.Str2Int64(order.VendorOrderID))
}
if err != nil && strings.Contains(err.Error(), "商家接单后1分钟内不能确认已完成备货") {
partner.CurOrderManager.OnOrderMsg(order, "订单自动拣货失败", err.Error())
return err
}
if err == nil || strings.Contains(err.Error(), "808") {
// 配送类型只能为美团配送或美团企客配送 level:0, code:808
c.postFakeMsg(order.VendorOrderID, FakeMsgType, fakeFinishedPickup)
return nil
}
return nil
}
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
}
// 美团预定单不能转商家自送
func (c *PurchaseHandler) CanSwitch2SelfDeliver(order *model.GoodsOrder) (isCan bool, err error) {
return order.BusinessType != model.BusinessTypeDingshida, nil
}
func (c *PurchaseHandler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) {
if globals.EnableMtwmStoreWrite {
err = getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), "").OrderLogisticsChange2Self(utils.Str2Int64(order.VendorOrderID))
}
return err
}
func (c *PurchaseHandler) Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) {
if globals.EnableMtwmStoreWrite {
// 您好,之前的答复已经更正为,调用变更配送状态的接口,会校验门店的配送类型。美团配送的门店即便转自配后因门店配送类型是美团配送所以无法调用接口变更配送状态。可提醒顾客点击确认收货。谢谢
// 非自配送门店订单调用OrderArrived好像会报错{"data":"ng","error":{"code":1038,"msg":"只允许商家配送调用该接口"}}
// err = api.MtwmAPI.OrderArrived(utils.Str2Int64(order.VendorOrderID))
}
return err
}
func (c *PurchaseHandler) SelfDeliverDelivering(order *model.GoodsOrder, userName string) (err error) {
if globals.EnableMtwmStoreWrite {
err = getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), "").OrderDelivering(utils.Str2Int64(order.VendorOrderID))
}
return err
}
// SelfDeliverDelivered 自配送订单送达
func (c *PurchaseHandler) SelfDeliverDelivered(order *model.GoodsOrder, userName string) (err error) {
if globals.EnableMtwmStoreWrite {
api := getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), "")
db := dao.GetDB()
err = api.OrderArrived(utils.Str2Int64(order.VendorOrderID))
if err == nil {
riderInfo := &utils.RiderInfo{
OrderId: order.VendorOrderID,
ThirdCarrierOrderId: order.VendorWaybillID,
CourierName: "",
CourierPhone: "",
LogisticsProviderCode: "10015", // 商家自建配送
LogisticsStatus: utils.Str2Int(mtwmapi.WaybillStatusDelivered),
Latitude: utils.Float64ToStr(jxutils.IntCoordinate2Standard(order.ConsigneeLat)), // 送达即为客户坐标
Longitude: utils.Float64ToStr(jxutils.IntCoordinate2Standard(order.ConsigneeLng)),
}
waybills, _ := dao.GetWaybills(db, order.VendorOrderID, nil)
if len(waybills) == model.NO {
store, _ := dao.GetStoreDetail(db, jxutils.GetSaleStoreIDFromOrder(order), order.VendorID, order.VendorOrgCode)
riderInfo.CourierName = "老板1"
riderInfo.CourierPhone = store.Tel1
riderInfo.ThirdCarrierOrderId = order.VendorOrderID
} else {
for _, v := range waybills {
if v.Status != model.OrderStatusCanceled && v.Status != model.OrderStatusFinished && v.Status != model.OrderStatusEndEnd {
riderInfo.CourierName = v.CourierName
riderInfo.CourierPhone = v.CourierMobile
riderInfo.ThirdCarrierOrderId = v.VendorWaybillID
continue
}
}
}
if riderInfo.CourierName == "" || riderInfo.CourierPhone == "" {
riderInfo.CourierName = "老板2"
riderInfo.CourierPhone = "18048531223"
}
if riderInfo.ThirdCarrierOrderId == "" {
riderInfo.ThirdCarrierOrderId = order.VendorOrderID
}
err = c.GetOrderRider(order.VendorOrgCode, order.VendorStoreID, utils.Struct2Map(riderInfo, "", true))
}
}
return err
}
func getTimeFromTimestamp(timeStamp int64) time.Time {
if timeStamp < 1538103149 { // 立即达订单给的是1而不是空01538103149不是特殊值只是一个任意之前的时间这样写可以处理
return utils.DefaultTimeValue
}
return utils.Timestamp2Time(timeStamp)
}
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) {
if globals.EnableMtwmStoreWrite {
if isAgree {
err = getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), "").OrderRefundAgree(utils.Str2Int64(order.VendorOrderID), reason)
} else {
err = getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), "").OrderRefundReject(utils.Str2Int64(order.VendorOrderID), reason)
}
}
return err
}
func (c *PurchaseHandler) CancelOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
if globals.EnableMtwmStoreWrite {
if err = getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), "").OrderCancel(utils.Str2Int64(order.VendorOrderID), reason, mtwmapi.CancelReasonOther); err == nil {
// 调用开放平台接口取消订单,不推送取消订单消息和退款消息。
c.postFakeMsg(order.VendorOrderID, mtwmapi.MsgTypeOrderCanceled, mtwmapi.OrderStatusCanceled)
}
}
return err
}
func (c *PurchaseHandler) AdjustOrder(ctx *jxcontext.Context, order *model.GoodsOrder, removedSkuList []*model.OrderSku, reason string) (err error) {
// 美团外卖必须要确认订单后才能调整单
if order.Status < model.OrderStatusFinishedPickup {
err = c.PickupGoods(order, false, ctx.GetUserName())
}
if err == nil {
var skuList []*mtwmapi.RefundSku
for _, sku := range removedSkuList {
skuID := utils.Int2Str(jxutils.GetSkuIDFromOrderSku(sku))
skuList = append(skuList, &mtwmapi.RefundSku{
AppFoodCode: skuID,
SkuID: skuID,
Count: sku.Count,
})
}
if globals.EnableMtwmStoreWrite {
err = getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), "").OrderApplyPartRefund(utils.Str2Int64(order.VendorOrderID), reason, skuList)
}
}
return err
}
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)
endData := queryDate.AddDate(0, 0, -6)
if time.Now().Day()-queryDate.Day() > 90 {
return nil, fmt.Errorf("只能查询九十天的数据")
}
if time.Now().Day()-queryDate.Day() >= 3 {
endData = queryDate.AddDate(0, 0, 3)
} else {
endData = time.Now()
}
var vendorStoreIDs []string
if vendorStoreID == "" {
vendorStoreIDs, err = c.GetAllStoresVendorID(ctx, vendorOrgCode)
if err != nil {
return nil, err
}
} else {
vendorStoreIDs = []string{vendorStoreID}
}
task := tasksch.NewParallelTask("mtwm ListOrders", nil, ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
vendorStoreID := batchItemList[0].(string)
var orderIDs []string
tmpOrderIDs, _ := getAPI(vendorOrgCode, 0, vendorStoreID).EcommerceGetOrderIdByPage(vendorStoreID, queryDate, endData)
if len(tmpOrderIDs) > 0 {
for _, v := range tmpOrderIDs {
orderIDs = append(orderIDs, utils.Int64ToStr(v))
}
}
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
}
// func (c *PurchaseHandler) UpdateWaybillTip(ctx *jxcontext.Context, order *model.GoodsOrder, tipFee int64) (err error) {
// if globals.EnableMtwmStoreWrite {
// err = api.MtwmAPI.OrderUpdateTip(utils.Str2Int64(order.VendorOrderID), jxutils.IntPrice2Standard(tipFee))
// }
// return err
// }
func (p *PurchaseHandler) GetOrderConsigneeNumber(ctx *jxcontext.Context, storeID int, vendorStoreID string) (numberList []*partner.OrderPhoneNumberInfo, err error) {
offset := 0
for {
store, _ := dao.GetStoreDetail(dao.GetDB(), storeID, model.VendorIDMTWM, "")
result, err2 := getAPI(store.VendorOrgCode, storeID, "").OrderBatchPullPhoneNumber(vendorStoreID, offset, mtwmapi.MaxBatchPullPhoneNumberLimit)
if err = err2; err == nil {
for _, v := range result {
v2 := &partner.OrderPhoneNumberInfo{
VendorOrderID: utils.Int64ToStr(v.OrderID),
PhoneNumber: v.RealPhoneNumber,
}
if v2.PhoneNumber == "" {
v2.PhoneNumber = v.RealOrderPhoneNumber
}
numberList = append(numberList, v2)
}
if len(result) <= mtwmapi.MaxBatchPullPhoneNumberLimit {
break
}
offset += mtwmapi.MaxBatchPullPhoneNumberLimit
} else {
break
}
}
return numberList, err
}
func (p *PurchaseHandler) GetOrderCourierNumber(ctx *jxcontext.Context, storeID int, vendorStoreID string) (numberList []*partner.OrderPhoneNumberInfo, err error) {
offset := 0
for {
store, _ := dao.GetStoreDetail(dao.GetDB(), storeID, model.VendorIDMTWM, "")
result, err2 := getAPI(store.VendorOrgCode, 0, "").OrderGetRiderInfoPhoneNumber(vendorStoreID, offset, mtwmapi.MaxBatchPullPhoneNumberLimit)
if err = err2; err == nil {
for _, v := range result {
numberList = append(numberList, &partner.OrderPhoneNumberInfo{
VendorOrderID: utils.Int64ToStr(v.OrderID),
PhoneNumber: v.RiderRealPhoneNumber,
})
}
if len(result) <= mtwmapi.MaxBatchPullPhoneNumberLimit {
break
}
offset += mtwmapi.MaxBatchPullPhoneNumberLimit
} else {
break
}
}
return numberList, err
}
func (p *PurchaseHandler) onNumberDowngrade(msg *mtwmapi.CallbackMsg) (response *mtwmapi.CallbackResponse) {
userNumberMap := make(map[string]*partner.OrderPhoneNumberInfo)
courierNumberMap := make(map[string]*partner.OrderPhoneNumberInfo)
orderMap := make(map[string]int)
ctx := jxcontext.AdminCtx
task := tasksch.NewParallelTask("美团外卖平台处理隐私号降级通知", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(true), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
step := batchItemList[0].(int)
switch step {
case 0:
userNumberList, err2 := p.GetOrderConsigneeNumber(ctx, 0, "")
if err = err2; err == nil {
for _, v := range userNumberList {
userNumberMap[v.VendorOrderID] = v
orderMap[v.VendorOrderID] = 1
}
}
case 1:
courierNumberList, err2 := p.GetOrderCourierNumber(ctx, 0, "")
if err = err2; err == nil {
for _, v := range courierNumberList {
courierNumberMap[v.VendorOrderID] = v
orderMap[v.VendorOrderID] = 1
}
}
case 2:
orderList := jxutils.StringMap2List(orderMap)
if len(orderList) > 0 {
updateTask := tasksch.NewParallelTask("美团外卖平台处理隐私号降级通知/处理订单", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(true), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
vendorOrderID := batchItemList[0].(string)
db := dao.GetDB()
if userNumberMap[vendorOrderID] != nil {
_, err = dao.UpdateEntityByKV(db, &model.GoodsOrder{}, map[string]interface{}{
"ConsigneeMobile": userNumberMap[vendorOrderID].PhoneNumber,
"ConsigneeMobile2": userNumberMap[vendorOrderID].PhoneNumber,
}, map[string]interface{}{
model.FieldVendorOrderID: vendorOrderID,
model.FieldVendorID: model.VendorIDMTWM,
})
}
if courierNumberMap[vendorOrderID] != nil {
_, err = dao.UpdateEntityByKV(db, &model.Waybill{}, map[string]interface{}{
"CourierMobile": courierNumberMap[vendorOrderID].PhoneNumber,
}, map[string]interface{}{
"VendorWaybillID": vendorOrderID,
"WaybillVendorID": model.VendorIDMTWM,
})
}
return retVal, err
}, orderList)
tasksch.HandleTask(updateTask, task, true).Run()
_, err = updateTask.GetResult(0)
}
}
return retVal, err
}, []int{0, 1, 2})
tasksch.HandleTask(task, nil, true).Run()
return response
}
func (c *PurchaseHandler) GetWaybillTip(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID, vendorOrderID, vendorWaybillID, vendorWaybillID2 string) (tipFee int64, err error) {
orderInfo, err := getAPI(vendorOrgCode, 0, vendorStoreID).GetDistributeOrderDetail(vendorOrderID, vendorStoreID)
if err == nil {
tipFee = jxutils.StandardPrice2Int(orderInfo.TipAmount)
}
return tipFee, err
}
func (c *PurchaseHandler) UpdateWaybillTip(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID, vendorOrderID, vendorWaybillID, vendorWaybillID2, cityCode string, tipFee int64) (err error) {
if globals.EnableMtwmStoreWrite {
err = getAPI(vendorOrgCode, 0, vendorStoreID).OrderModityTips(vendorOrderID, vendorStoreID, jxutils.IntPrice2Standard(tipFee))
}
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("如果想投诉美团外卖骑手,请拨打美团客服热线:10107888")
}
// GetCancelDeliveryReason 转自配送时取消非专送混合送门店取消理由
func (c *PurchaseHandler) GetCancelDeliveryReason(order *model.GoodsOrder) (string, error) {
reason, err := getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), "").GetCancelDeliveryReason(utils.Str2Int64(order.VendorOrderID), order.VendorStoreID)
if err != nil {
return "", err
}
return reason, nil
}
// 取消美团外卖理由转使用三方配送
func (c *PurchaseHandler) CancelLogisticsByWmOrderId(order *model.GoodsOrder, reasonCode, detailContent, appPoiCode, orderId string) error {
return getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), "").CancelLogisticsByWmOrderId(reasonCode, detailContent, appPoiCode, orderId)
}
// 获取订单配送状态
func (c *PurchaseHandler) OrderLogisticsStatus(orderId string) (*utils.RiderInfo, error) {
orderInfo, err := dao.GetSimpleOrder(dao.GetDB(), orderId)
if err != nil {
return nil, errors.New("获取本地门店账号信息失败,请重试")
}
api := getAPI(orderInfo.VendorOrgCode, orderInfo.JxStoreID, orderInfo.VendorOrderID)
// 获取骑手信息
status, err := api.OrderLogisticsStatus(utils.Str2Int64(orderId))
if err != nil {
return nil, err
}
// 获取骑手坐标最后一个
lng, lat, _ := api.GetDeliveryPath(utils.Str2Int64(orderId), orderInfo.VendorStoreID)
status.Longitude = utils.Float64ToStr(jxutils.IntCoordinate2Standard(int(lng)))
status.Latitude = utils.Float64ToStr(jxutils.IntCoordinate2Standard(int(lat)))
return status, nil
}
// GetOrderSettleAccounts 获取订单结算信息
func (c *PurchaseHandler) GetOrderSettleAccounts(order *model.GoodsOrder) (int64, error) {
oderDetail, err := getAPI(order.VendorOrgCode, 0, order.VendorStoreID).OrderGetOrderDetail(utils.Str2Int64(order.VendorOrderID), true)
if err != nil {
return 0, err
}
if poiReceiveDetailStr := utils.Interface2String(oderDetail["poi_receive_detail"]); poiReceiveDetailStr != "" {
var poiReceiveDetail *mtwmapi.PoiReceiveDetailInfo
utils.UnmarshalUseNumber([]byte(poiReceiveDetailStr), &poiReceiveDetail)
if poiReceiveDetail != nil {
return poiReceiveDetail.WmPoiReceiveCent, nil
}
}
return 0, nil
}
// GetPlatformLogisticsFee 获取美团自配送订单的配送费
func (c *PurchaseHandler) GetPlatformLogisticsFee(order *model.GoodsOrder) (int64, error) {
fee, err := getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), order.VendorStoreID).OrderLogisticsFee(utils.Str2Int64(order.VendorOrderID))
if err != nil {
return 0, err
}
return utils.Float64TwoInt64(fee * 100), nil
}
// ApplyCompensationOrder 订单索赔
func (c *PurchaseHandler) ApplyCompensationOrder(order *model.GoodsOrder) (string, error) {
num, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", utils.Int64ToFloat64(order.TotalShopMoney)/float64(100)), 64)
return "", getAPI(order.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(order), "").ApplyCompensation(&mtwmapi.ApplyCompensationRes{
OrderId: utils.Str2Int64(order.VendorOrderID),
Reason: "商户申请",
ApplyStatus: mtwmapi.ApplyCompensationStatusOne,
Amount: num,
})
}
func UploadInvoice(param *model.InvoiceMsg) error {
goodsOrder, err := partner.CurOrderManager.LoadOrder(param.OrderId, param.VendorID)
if err != nil {
return err
}
return getAPI(goodsOrder.VendorOrgCode, jxutils.GetSaleStoreIDFromOrder(goodsOrder), goodsOrder.VendorStoreID).UploadInvoice(param.OrderId, param.InvoiceUrl, param.InvoiceId, param.InvoiceTaskId)
}