Files
jx-callback/business/partner/delivery/fn/waybill.go
邹宗楠 bd810ac7ab 1
2022-11-09 15:53:27 +08:00

387 lines
14 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 fn
import (
"fmt"
"git.rosy.net.cn/baseapi/platformapi/mtpsapi"
"git.rosy.net.cn/baseapi/utils"
"strconv"
"strings"
"time"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/partner/delivery"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/baseapi/platformapi/fnpsapi"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals/api"
)
const (
ComplaintReasonsFn150 = 150 //:未保持餐品完整,
ComplaintReasonsFn220 = 220 //:少餐错餐,
ComplaintReasonsFn160 = 160 //:服务态度恶劣,
ComplaintReasonsFn190 = 190 //:额外索取费用,
ComplaintReasonsFn170 = 170 //:诱导收货人或商户退单,
ComplaintReasonsFn140 = 140 //:提前点击送达,
ComplaintReasonsFn210 = 210 //:虚假标记异常,
ComplaintReasonsFn200 = 200 //:虚假点击配送成功,
ComplaintReasonsFn130 = 130 //:未进行配送,导致订单失败或取消,
ComplaintReasonsFn120 = 120 //:配送超时
)
var (
curDeliveryHandler *DeliveryHandler
complaintReson2FnResonMap = map[int]int{
model.ComplaintReasons1: ComplaintReasonsFn160,
model.ComplaintReasons2: ComplaintReasonsFn130,
model.ComplaintReasons3: ComplaintReasonsFn130,
model.ComplaintReasons4: ComplaintReasonsFn120,
model.ComplaintReasons5: ComplaintReasonsFn130,
model.ComplaintReasons6: ComplaintReasonsFn150,
model.ComplaintReasons7: ComplaintReasonsFn190,
model.ComplaintReasons69: ComplaintReasonsFn170,
model.ComplaintReasons71: ComplaintReasonsFn140,
}
)
type DeliveryHandler struct {
}
func init() {
if api.FnAPI != nil {
curDeliveryHandler = new(DeliveryHandler)
partner.RegisterDeliveryPlatform(curDeliveryHandler, true)
}
}
func (c *DeliveryHandler) GetVendorID() int {
return model.VendorIDFengNiao
}
func (c *DeliveryHandler) CancelWaybill(bill *model.Waybill, cancelReasonID int, cancelReason string) (err error) {
parameter := &fnpsapi.CancelOrderReq{
OrderCancelCode: fnpsapi.OrderCancelReson9,
OrderCancelRole: 2,
}
parameter.PartnerOrderCode = bill.VendorOrderID
if err = api.FnAPI.CancelOrder(parameter); err != nil {
if strings.Contains(err.Error(), "运单暂未生成") {
err = nil
}
}
bill.Status = model.WaybillStatusCanceled
bill.Remark = cancelReason
partner.CurOrderManager.OnWaybillStatusChanged(bill)
return err
}
func (c *DeliveryHandler) ComplaintRider(bill *model.Waybill, resonID int, resonContent string) (err error) {
err = api.FnAPI.ComplaintRider(bill.VendorOrderID, complaintReson2FnResonMap[resonID])
return err
}
// 创建蜂鸟配送订单
func (c *DeliveryHandler) CreateWaybill(order *model.GoodsOrder, maxDeliveryFee int64) (bill *model.Waybill, err error) {
db := dao.GetDB()
// 检查配送平台是否被禁用
vendorOrgCode, err := dao.GetVendorOrgCode(db, model.VendorIDFengNiao, "", model.VendorOrgTypeDelivery)
if err != nil {
return nil, err
}
if len(vendorOrgCode) > 0 && vendorOrgCode[0].IsOpen == model.YES {
return nil, fmt.Errorf("此平台配送已被系统关闭,暂不发配送 [%v]", vendorOrgCode[0].Comment)
}
// 蜂鸟入参结构体
parameter := &fnpsapi.CreateOrderReqParam{
PartnerOrderCode: order.VendorOrderID,
OrderType: 1,
PositionSource: 3,
ReceiverAddress: order.ConsigneeAddress,
ReceiverLongitude: utils.Int2Float64(order.ConsigneeLng) / 1000000,
ReceiverLatitude: utils.Int2Float64(order.ConsigneeLat) / 1000000,
GoodsTotalAmountCent: order.SalePrice,
GoodsActualAmountCent: order.ActualPayPrice,
GoodsWeight: utils.Int2Float64(order.Weight) / 1000,
GoodsCount: order.GoodsCount,
GoodsItemList: nil,
ReceiverName: order.ConsigneeName,
ReceiverPrimaryPhone: order.ConsigneeMobile,
OutShopCode: utils.Int2Str(order.JxStoreID),
ChainStoreId: "",
}
// 重量超标减少配送费
weight := 4.9500
if utils.Int2Float64(order.Weight)/1000 >= weight {
parameter.GoodsWeight = weight
}
var goodsList []*fnpsapi.GoodsItemsList
for _, v := range order.Skus {
goodsList = append(goodsList, &fnpsapi.GoodsItemsList{
ItemName: v.SkuName,
ItemQuantity: v.Count,
ItemAmountCent: v.SalePrice,
ItemActualAmountCent: v.SalePrice,
ItemId: utils.Int2Str(v.SkuID),
})
}
parameter.GoodsItemList = goodsList
//要求饿百的订单要传来源
if order.VendorID == model.VendorIDEBAI {
parameter.OrderSource = "109"
}
// 创建蜂鸟订单,运单id
fnOrderId, err := api.FnAPI.CreateOrder(parameter)
if err != nil {
return nil, err
}
// 查询订单获取配送费
bill = &model.Waybill{
VendorOrderID: order.VendorOrderID,
OrderVendorID: order.VendorID,
VendorWaybillID: fnOrderId,
VendorWaybillID2: order.VendorOrderID,
WaybillVendorID: model.VendorIDFengNiao,
DesiredFee: GetDesiredFee(order.VendorOrderID),
}
delivery.OnWaybillCreated(bill)
return bill, err
}
// 预下单获取配送费
func (c *DeliveryHandler) GetWaybillFee(order *model.GoodsOrder) (deliveryFeeInfo *partner.WaybillFeeInfo, err error) {
preCreateOrder := &fnpsapi.PreCreateOrder{
PartnerOrderCode: order.VendorOrderID,
OrderType: 1,
PositionSource: 3,
ReceiverAddress: order.ConsigneeAddress,
ReceiverLongitude: utils.Int2Float64(order.ConsigneeLng) / 1000000,
ReceiverLatitude: utils.Int2Float64(order.ConsigneeLat) / 1000000,
GoodsTotalAmountCent: order.SalePrice,
GoodsActualAmountCent: order.ActualPayPrice,
GoodsWeight: utils.Int2Float64(order.Weight) / 1000,
GoodsCount: order.GoodsCount,
GoodsItemList: nil,
OutShopCode: utils.Int2Str(order.JxStoreID),
}
// 重量超标减少配送费
weight := 4.9500
if utils.Int2Float64(order.Weight)/1000 >= weight {
preCreateOrder.GoodsWeight = weight
}
var goodsList []*fnpsapi.GoodsItemsList
for _, v := range order.Skus {
goodsList = append(goodsList, &fnpsapi.GoodsItemsList{
ItemName: v.SkuName,
ItemQuantity: v.Count,
ItemAmountCent: v.SalePrice,
ItemActualAmountCent: v.SalePrice,
ItemId: utils.Int2Str(v.SkuID),
})
}
preCreateOrder.GoodsItemList = goodsList
deliveryFeeInfo = &partner.WaybillFeeInfo{}
deliveryFeeInfo.RefDeliveryFee, deliveryFeeInfo.RefAddFee, err = api.FnAPI.PreCreateByShopFn(preCreateOrder)
deliveryFeeInfo.DeliveryFee = deliveryFeeInfo.RefDeliveryFee
return deliveryFeeInfo, err
}
// 订单状态
func OnWaybillMsg(msg *fnpsapi.OrderStatusNottify) (resp *fnpsapi.CallbackResponse) {
cc := &fnpsapi.OrderCallbackParam{}
if err := utils.Map2StructByJson(msg.Param, cc, true); err != nil {
return fnpsapi.Err2CallbackResponse(err, "")
}
order := &model.Waybill{
VendorWaybillID: utils.Int64ToStr(cc.OrderId),
VendorWaybillID2: cc.PartnerOrderCode,
WaybillVendorID: model.VendorIDFengNiao,
CourierName: cc.CarrierDriverName,
CourierMobile: cc.CarrierDriverPhone,
VendorStatus: utils.Int2Str(cc.OrderStatus),
StatusTime: utils.Timestamp2Time(cc.PushTime),
Remark: cc.Description,
}
if cc.PushTime == 0 {
order.StatusTime = time.Now()
}
order.VendorOrderID, order.OrderVendorID = jxutils.SplitUniversalOrderID(cc.PartnerOrderCode)
var good *model.GoodsOrder
sql := `SELECT * FROM goods_order WHERE vendor_order_id = ? ORDER BY order_created_at DESC LIMIT 1 OFFSET 0`
sqlParams := []interface{}{cc.PartnerOrderCode}
dao.GetRow(dao.GetDB(), &good, sql, sqlParams)
order.OrderVendorID = good.VendorID
orderStatus, err := strconv.Atoi(order.VendorStatus)
if err != nil {
return fnpsapi.Err2CallbackResponse(err, "")
}
switch orderStatus {
case fnpsapi.OrderStatusAcceptCreate, fnpsapi.OrderStatusAccept: // 0 创建订单
order.DesiredFee = GetDesiredFee(order.VendorOrderID)
order.Status = model.WaybillStatusNew //5 带调度
case fnpsapi.OrderStatusAssigned: //20分配骑手
order.DesiredFee = GetDesiredFee(order.VendorOrderID)
order.Status = model.WaybillStatusCourierAssigned //12
order.Remark = order.CourierName + "" + order.CourierMobile
case fnpsapi.OrderStatusArrived: // 80 到店
order.DesiredFee = GetDesiredFee(order.VendorOrderID)
order.Status = model.WaybillStatusCourierArrived
case fnpsapi.OrderStatusDelivering: // 2 配送中
order.Status = model.WaybillStatusDelivering
case fnpsapi.OrderStatusDelivered: // 3 已经送达
order.Status = model.WaybillStatusDelivered
case fnpsapi.OrderStatusAcceptCacle: // 4取消订单
order.Status = model.WaybillStatusCanceled
case fnpsapi.OrderStatusException: // 5 异常
order.Status = model.WaybillStatusDeliverFailed // 22
default:
globals.SugarLogger.Warnf("onWaybillMsg unknown msg:%v", msg)
}
if err := partner.CurOrderManager.OnWaybillStatusChanged(order); err != nil {
return fnpsapi.Err2CallbackResponse(err, "")
}
if order.OrderVendorID == model.VendorIDDD {
result := &mtpsapi.RiderInfo{
OrderId: order.VendorOrderID,
ThirdCarrierOrderId: order.VendorOrderID,
CourierName: order.CourierName,
CourierPhone: order.CourierMobile,
LogisticsProviderCode: "10002",
LogisticsStatus: order.Status,
OpCode: "",
}
switch orderStatus {
case fnpsapi.OrderStatusAcceptCreate, fnpsapi.OrderStatusAccept: // 待接单,召唤骑手
result.LogisticsStatus = model.WaybillStatusNew
result.LogisticsContext = model.RiderWaitRider
case fnpsapi.OrderStatusAssigned: //20分配骑手 待取货
result.LogisticsStatus = model.WaybillStatusCourierAssigned // 分配骑手
result.LogisticsContext = model.RiderWaitGetGoods
case fnpsapi.OrderStatusDelivering: // 2 配送中 // 配送中
result.LogisticsStatus = model.WaybillStatusDelivering
result.LogisticsContext = model.RiderGetOrderDelivering
case fnpsapi.OrderStatusDelivered: // 3 已经送达 // 完成
result.LogisticsStatus = model.WaybillStatusDelivered
result.LogisticsContext = model.RiderGetOrderDelivered
case fnpsapi.OrderStatusAcceptCacle: // 取消
result.LogisticsStatus = model.WaybillStatusCanceled
result.LogisticsContext = model.RiderGetOrderCanceled
case fnpsapi.OrderStatusException: // 5 异常: // 配送异常返回值
result.LogisticsStatus = model.WaybillStatusDeliverFailed
result.LogisticsContext = model.RiderGetOrderDeliverFailed
case fnpsapi.OrderStatusArrived: // 80 到店 // 骑手到店
result.LogisticsStatus = model.WaybillStatusCourierArrived
result.LogisticsContext = model.RiderToStore
default:
result.LogisticsStatus = 0
result.LogisticsContext = model.RiderGetOrderDeliverOther
}
delivery.PullTiktokRiderInfo(result)
}
defer delivery.GetOrderRiderInfoToPlatform(order.VendorOrderID, order.Status) // 骑手位置更新
return fnpsapi.Err2CallbackResponse(nil, "")
}
// 异常报备
func OnWaybillExceptFn(msg *fnpsapi.AbnormalReportNotify) (retVal *fnpsapi.CallbackResponse) {
return curDeliveryHandler.OnWaybillExcept(msg)
}
func (c *DeliveryHandler) OnWaybillExcept(msg *fnpsapi.AbnormalReportNotify) (retVal *fnpsapi.CallbackResponse) {
jxutils.CallMsgHandler(func() {
order := &model.Waybill{
VendorWaybillID: msg.PartnerOrderCode,
VendorWaybillID2: utils.Int64ToStr(msg.OrderId),
WaybillVendorID: model.VendorIDFengNiao,
CourierName: string(msg.CarrierDriverId),
CourierMobile: "",
Status: model.WaybillStatusUnknown, // todo 这里要再确定一下是否只要收到订单异常消息就只简单当成一个消息
VendorStatus: msg.AbnormalCode,
StatusTime: utils.Timestamp2Time(msg.AbnormalReportTime),
}
order.VendorOrderID, order.OrderVendorID = jxutils.SplitUniversalOrderID(msg.PartnerOrderCode)
retVal = fnpsapi.Err2CallbackResponse(partner.CurOrderManager.OnWaybillStatusChanged(order), "fn OnWaybillExcept")
}, jxutils.ComposeUniversalOrderID(msg.PartnerOrderCode, model.VendorIDFengNiao))
return retVal
}
// 查询订单配送费
func GetDesiredFee(vendorOrderID string) (desiredFee int64) {
if result, err := api.FnAPI.QueryOrder(vendorOrderID); err == nil {
return result.OrderActualAmountCent
}
return desiredFee
}
// 获取骑手信息
func (c *DeliveryHandler) GetRiderInfo(orderId string, deliveryId int64, mtPeisongId string) (rider *mtpsapi.RiderInfo, err error) {
// 获取订单状态
order, err := api.FnAPI.QueryOrder(orderId)
if err != nil {
return nil, err
}
// 获取骑手坐标
knightInfo, err := api.FnAPI.GetKnightInfo(&fnpsapi.GetOrderDetailReq{PartnerOrderCode: orderId})
if err != nil {
return nil, err
}
result := &mtpsapi.RiderInfo{
OrderId: orderId,
ThirdCarrierOrderId: utils.Int64ToStr(order.TrackingId),
CourierName: knightInfo.CarrierDriverName,
CourierPhone: knightInfo.CarrierDriverPhone,
LogisticsProviderCode: mtpsapi.FnPsCode,
LogisticsStatus: order.OrderStatus, // 默认正在配送中
Latitude: knightInfo.CarrierDriverLatitude,
Longitude: knightInfo.CarrierDriverLongitude,
}
switch order.OrderStatus {
case 0: // 新订单
result.LogisticsStatus = model.WaybillStatusNew
result.LogisticsContext = model.RiderWaitRider
case 20: // 骑手接单
result.LogisticsStatus = model.WaybillStatusCourierAssigned
result.LogisticsContext = model.RiderGetOrder
case 80: // 骑手到店
result.LogisticsStatus = model.WaybillStatusCourierArrived
result.LogisticsContext = model.RiderToStore
case 2: // 配送中
result.LogisticsStatus = model.WaybillStatusDelivering
result.LogisticsContext = model.RiderGetOrderDelivering
case 3: // 完成
result.LogisticsStatus = model.WaybillStatusDelivered
result.LogisticsContext = model.RiderGetOrderDelivered
case 4: // 取消
result.LogisticsStatus = model.WaybillStatusCanceled
result.LogisticsContext = model.RiderGetOrderCanceled
case 5: // 配送异常
result.LogisticsStatus = model.WaybillStatusDeliverFailed
result.LogisticsContext = model.RiderGetOrderDeliverFailed
default:
result.LogisticsStatus = 0
result.LogisticsContext = model.RiderGetOrderDeliverOther
}
return result, nil
}