package q_bida import ( "errors" "fmt" bida "git.rosy.net.cn/baseapi/platformapi/q_bida" "git.rosy.net.cn/baseapi/platformapi/tonglianpayapi" "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/model" "git.rosy.net.cn/jx-callback/business/model/dao" "git.rosy.net.cn/jx-callback/globals" "git.rosy.net.cn/jx-callback/globals/api" "time" ) // ExpressCompany 快递公司 var ExpressCompany = []int{ bida.JDExpressInt, bida.DBExpressInt, bida.STExpressInt, bida.YTExpressInt, bida.DBAirCraftExpressInt, bida.SFExpressInt, bida.JDDWExpressInt, bida.JDStoreExpressInt, bida.ZTExpressInt, bida.JSTExpressInt, bida.YDExpressInt, } // LogisticsCompany 物流 var LogisticsCompany = []int{ bida.SXJDExpressInt, bida.SFKYExpressInt, bida.ZTKYExpressInt, bida.KYExpressInt, bida.JDLogisticsExpressInt, bida.DBLogisticsExpressInt, } const MarkupAmount = 50 // 每公斤加价五毛 // QueryExpressPrice 查询配送价格,获取所有快递价格 func QueryExpressPrice(param *bida.GetExpressPriceReq) (map[string]*bida.GetExpressPriceRes, error) { if param.Weight <= 0 { return nil, errors.New("物品重量必须大于0") } // 给快递默认值 result := make(map[string]*bida.GetExpressPriceRes, 0) if param.Type == 0 { // 渠道费每公斤加价五毛 switch param.ChannelType { case 1: // 快递 for i := 0; i < len(ExpressCompany); i++ { param.Type = ExpressCompany[i] fee, err := api.QBiDaAPI.GetExpressPrice(param) if err != nil { continue } if fee.Code != 0 { result[fmt.Sprintf("%d", ExpressCompany[i])] = fee continue } if fee.Data.ChannelFee != 0 { addFee := int(fee.Data.ChannelFee*100) + param.Weight*MarkupAmount fee.Data.ChannelFee = utils.Int2Float64(addFee) / float64(100) result[fmt.Sprintf("%d", ExpressCompany[i])] = fee } } case 2: // 物流 for i := 0; i < len(LogisticsCompany); i++ { param.Type = LogisticsCompany[i] fee, err := api.QBiDaAPI.GetExpressPrice(param) if err != nil { continue } if fee.Code != 0 { result[fmt.Sprintf("%d", LogisticsCompany[i])] = fee continue } if fee.Data.ChannelFee != 0 { addFee := int(fee.Data.ChannelFee*100) + param.Weight*MarkupAmount fee.Data.ChannelFee = utils.Int2Float64(addFee) / float64(100) result[fmt.Sprintf("%d", LogisticsCompany[i])] = fee } } } } else { fee, err := api.QBiDaAPI.GetExpressPrice(param) if err != nil { return nil, err } if fee.Code != 0 { return nil, errors.New(fee.Msg) } if fee.Data.ChannelFee != 0 { addFee := int(fee.Data.ChannelFee*100) + param.Weight*MarkupAmount fee.Data.ChannelFee = utils.Int2Float64(addFee) / float64(100) result[fmt.Sprintf("%d", param.Type)] = fee } } return result, nil } // CreateWayOrder 创建快递订单 func CreateWayOrder(ctx *jxcontext.Context, param *model.MakeOrderParamReq, userId string) (*model.UserVendorOrder, error) { // 检查价格 reallyCannelleFee := param.ChannelFee if err := checkWayFeeIsTrue(param); err != nil { return nil, err } // 第三方数据创建成功,则创建本地数据 random := RandomString(5) vendorOrder := &model.UserVendorOrder{ UserId: userId, LocalWayBill: utils.Int64ToStr(time.Now().Unix()) + userId[:4] + random, // 当前时间秒数加用户ID前四位 OtherWayBill: utils.Int64ToStr(time.Now().Unix()) + userId[:4] + random, PromiseTimeType: param.PromiseTimeType, DeliveryType: param.DeliveryType, Goods: param.Goods, GuaranteeValueAmount: param.GuaranteeValueAmount, Weight: param.Weight, Length: param.Length, Height: param.Height, Width: param.Width, OrderSendTime: param.OrderSendTime, PackageNum: param.PackageNum, ReceiveAddressID: param.ReceiveAddressId, Remark: param.Remark, SenderAddressID: param.SenderAddressId, ThirdPlatform: param.ThirdPlatform, Type: param.Type, ReallyChannelFee: reallyCannelleFee, ChannelFee: param.ChannelFee, ServiceCharge: param.ServiceCharge, GuarantFee: param.GuarantFee, OriginalFee: param.OriginalFee, Bulk: param.Bulk, Increment: param.Increment, ChannelType: param.ChannelType, OrderStatus: model.OrderStatusWaitPay, // 创建待支付 Img: param.Images, IsForward: model.YES, // } // 事务创建待支付运单,和待支付order db := dao.GetDB() tdb, _ := dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db, tdb) panic(r) } }() // 添加运单表 dao.WrapAddIDCULDEntity(vendorOrder, ctx.GetUserName()) if err := dao.CreateEntityTx(tdb, vendorOrder); err != nil { dao.Rollback(db, tdb) return nil, err } // 添加待支付订单表 orderPayStatus := &model.Order{ OrderID: vendorOrder.LocalWayBill, UserID: vendorOrder.UserId, Type: model.OrderTypePay, OrderType: model.PayType4Express, Way: "", Status: model.OrderStatusWaitPay, // 待支付状态 PayPrice: int(vendorOrder.ChannelFee * 100), TransactionID: "", PayFinishedAt: time.Time{}, PrepayID: "", OriginalData: "", Comment: "", Lng: 0, Lat: 0, CityCode: 0, DistrictCode: 0, Address: "", PayMethod: 0, } if err := dao.CreateEntityTx(tdb, orderPayStatus); err != nil { dao.Rollback(db, tdb) return nil, err } dao.Commit(db, tdb) return vendorOrder, nil } // CancelWayOrder 取消运单 todo func CancelWayOrder(ctx *jxcontext.Context, userId string, param *bida.CancelOrderReq) error { // 查询订单 globals.SugarLogger.Debug("userid==================", userId) globals.SugarLogger.Debug("param.order_no==================", param.OrderNo) order := &model.UserVendorOrder{UserId: userId, LocalWayBill: param.OrderNo} if err := dao.GetEntity(dao.GetDB(), order, "UserId", "LocalWayBill"); err != nil { return err } globals.SugarLogger.Debugf("sdhgeagqweg344w33qgweag== %s ", order.OtherWayBill) globals.SugarLogger.Debugf("jbhbhjdsgbgjhghiwsg== %s ", order.LastOperator) if time.Now().Unix()-order.CreatedAt.Unix() <= 30 { return errors.New("支付成功后,超过30s才能取消") } // 待支付或者支付失败 switch order.OrderStatus { case model.OrderStatusFailPay, model.OrderStatusWaitPay: // 待支付订单,或者支付失败订单,不需要退款,取消本地订单以及order记录表 db := dao.GetDB() tx, _ := dao.Begin(db) defer func() { if r := recover(); r != nil { panic(r) } }() order.OrderStatus = model.OrderStatusCancel if _, err := dao.UpdateEntityTx(tx, order, "OrderStatus"); err != nil { tx.Rollback() return err } if _, err := dao.UpdateEntityTx(tx, &model.Order{OrderID: param.OrderNo, UserID: userId, Status: model.OrderStatusCancel}, "Status"); err != nil { tx.Rollback() return err } tx.Commit() case model.OrderStatusSuccessPay, model.OrderStatusWaitPickup: // 支付成功,取消三方订单,本地转取消状态,,原路退款 // 发起QBiDa取消,过去取消通过,则取消本地!不通过,则不予取消! cancelParma := &bida.CancelOrderReq{ Genre: param.Genre, OrderNo: order.OtherWayBill, Type: param.Type, } if err := api.QBiDaAPI.CancelOrder(cancelParma); err != nil { globals.SugarLogger.Debug("err==========================", err) } // 暂时考虑余额支付渠道,加载order表判断支付渠道方式 orderWay := &model.Order{OrderID: param.OrderNo, UserID: userId} if err := dao.GetEntity(dao.GetDB(), orderWay, "OrderID", "UserID"); err != nil { return err } globals.SugarLogger.Debug("============", orderWay.PayPrice) globals.SugarLogger.Debug("========= dfedfwfwdsw", orderWay.PayMethod) if orderWay.PayMethod == 1 { // 余额支付 // 支付方式为余额支付,则需要修改order/userVendorOrder,修改订单状态,给用户账户价钱,生成一个价钱数据 } else if orderWay.PayMethod == 2 { // 微信支付 // 微信支付原路退款,发起退款申请 _, err := RefundOrderByTL(ctx, orderWay, order, order.OtherWayBill, int(order.ChannelFee*100), "申请退款") return err } } return nil } // QueryOrderDetail 获取订单详细信息 func QueryOrderDetail(typeCode int, orderNo string) (*bida.OrderDetail, error) { detail, err := api.QBiDaAPI.GetOrderDetail(&bida.GetOrderDetailReq{ Type: typeCode, OrderNo: orderNo, }) if err != nil { return nil, err } // 本地查询获取真是支付快递费用 sql := `SELECT * FROM user_vendor_order a WHERE a.other_way_bill = ? and a.type = ? ` data := &model.UserVendorOrder{} param := []interface{}{orderNo, typeCode} if err := dao.GetRow(dao.GetDB(), data, sql, param); err != nil { return nil, err } addFee := int(detail.PayFee*100) + detail.Weight*MarkupAmount detail.PayFee = utils.Int2Float64(addFee) / float64(100) detail.Images = data.Img return detail, nil } // QueryUserOrderList 查询用户订单列表 func QueryUserOrderList(userId string, expressType, orderStatus int, pageNum, pageSize int, orderNo string) ([]*model.UserOrderList, int, error) { sql := ` SELECT SQL_CALC_FOUND_ROWS a.type,a.other_way_bill,a.local_way_bill,a.user_id,a.receive_address_id,a.sender_address_id, a.created_at,a.order_status,a.channel_fee,add1.consignee_name send_user_name,add2.consignee_name receive_user_name, district.name sender_address,city.name receive_address FROM user_vendor_order a LEFT JOIN user_delivery_address add1 ON a.sender_address_id = add1.id LEFT JOIN user_delivery_address add2 ON a.receive_address_id = add2.id LEFT JOIN place district ON district.code = add1.city_code LEFT JOIN place city ON city.code = add2.city_code WHERE a.deleted_at = ? AND a.user_id = ? ` param := make([]interface{}, 0, 0) param = append(param, utils.DefaultTimeValue) param = append(param, userId) if orderNo != "" { sql = sql + `AND a.other_way_bill = ? OR a.local_way_bill = ? ` param = append(param, orderNo, orderNo) } if expressType != 0 { sql = sql + ` AND a.type = ? ` param = append(param, expressType) } if orderStatus != 0 { sql = sql + ` AND a.order_status = ? ` param = append(param, orderStatus) } // 获取数据条数 sql = sql + ` ORDER BY a.created_at DESC LIMIT ? OFFSET ? ` pageSize = jxutils.FormalizePageSize(pageSize) param = append(param, pageSize, (pageNum-1)*pageSize) // 获取数据 var result []*model.UserOrderList db := dao.GetDB() tx, _ := dao.Begin(db) defer func() { if r := recover(); r != nil { panic(r) } }() if err := dao.GetRowsTx(tx, &result, sql, param...); err != nil { dao.Rollback(db, tx) return nil, 0, err } count := dao.GetLastTotalRowCountTx(tx) dao.Commit(db, tx) return result, count, nil } // CreateOrder2QBiDa 订单回调成功,且为运费支付时使用该接口 func CreateOrder2QBiDa(order *model.UserVendorOrder, orderId string) error { //// 加载订单 //order := &model.UserVendorOrder{} //sql := `SELECT * FROM user_vendor_order WHERE local_way_bill = ? ` //if err := dao.GetRow(dao.GetDB(), order, sql, []interface{}{orderId}...); err != nil { // return err //} // //if order.OrderStatus != model.OrderStatusSuccessPay { // globals.SugarLogger.Debug("Callback Success But Order Status Update Fail ....") // return errors.New("Callback Success But Order Status Update Fail ") //} globals.SugarLogger.Debug("order==================", order) globals.SugarLogger.Debug("order==================", order.LocalWayBill) // 创建QBIDA订单 makeOrder := &bida.MakeOrderReq{ PromiseTimeType: order.PromiseTimeType, DeliveryType: order.DeliveryType, Goods: order.Goods, GuaranteeValueAmount: order.GuaranteeValueAmount, Weight: order.Weight, Length: order.Length, Height: order.Height, Width: order.Width, OrderSendTime: order.OrderSendTime, PackageNum: order.PackageNum, Remark: order.Remark, ThirdPlatform: order.ThirdPlatform, Type: order.Type, Img: order.Img, } // 获取发货地址以及送货地址 // GetAddressDetail 获取配送地址详情 sendAddress, err := dao.GetAddressDetail(int(order.SenderAddressID)) if err != nil { return err } makeOrder.SenderAddress = sendAddress.AutoAddress makeOrder.SenderName = sendAddress.ConsigneeName makeOrder.SenderPhone = sendAddress.ConsigneeMobile receiveAddress, err := dao.GetAddressDetail(int(order.ReceiveAddressID)) if err != nil { return err } makeOrder.ReceiveAddress = receiveAddress.AutoAddress makeOrder.ReceiveName = receiveAddress.ConsigneeName makeOrder.ReceivePhone = receiveAddress.ConsigneeMobile otherId, err := createOtherOrder(makeOrder) if err != nil { order.ErrorMsg = err.Error() globals.SugarLogger.Debug("err==========", err) } globals.SugarLogger.Debug("otherId==========", otherId) order.OtherWayBill = otherId order.OrderStatus = model.OrderStatusWaitPickup order.UpdatedAt = time.Now() if _, err = dao.UpdateEntity(dao.GetDB(), order, "OtherWayBill", "OrderStatus", "UpdatedAt", "ErrorMsg"); err != nil { return err } return nil } // RefundOrderByTL 发起取消订单 func RefundOrderByTL(ctx *jxcontext.Context, orderPay *model.Order, order *model.UserVendorOrder, refundID string, refundFee int, refundDesc string) (orderPayRefund *model.OrderPayRefund, err error) { result, err := api.TLpayAPI.PayRefund(&tonglianpayapi.PayRefundParam{ Trxamt: refundFee, Reqsn: utils.GetUUID(), Remark: refundDesc, OldTrxID: orderPay.TransactionID, }) if err == nil { orderPayRefund = &model.OrderPayRefund{ RefundID: refundID, VendorRefundID: result.TrxID, VendorOrderID: orderPay.OrderID, //本地生成Id Status: model.RefundStatusNo, TransactionID: orderPay.TransactionID, // 支付事务id RefundFee: refundFee, RefundCreatedAt: time.Now(), } dao.WrapAddIDCULDEntity(orderPayRefund, ctx.GetUserName()) db := dao.GetDB() if result.TrxStatus == tonglianpayapi.TrxStatusSuccess { orderPayRefund.Status = model.RefundStatusYes } else { orderPayRefund.Status = model.RefundStatusFailed } orderPayRefund.OriginalData = utils.Format4Output(result, true) tx, _ := dao.Begin(db) defer func() { if r := recover(); r != nil { panic(r) } }() if err := dao.CreateEntityTx(tx, orderPayRefund); err != nil { dao.Rollback(db, tx) return nil, err } order.OrderStatus = model.OrderStatusCancel if _, err := dao.UpdateEntityTx(tx, order); err != nil { dao.Rollback(db, tx) return nil, err } dao.Commit(db, tx) } return orderPayRefund, err } // ManagerGetOrderList 管理系统查询订单列表 func ManagerGetOrderList(param *model.OrderListReq) ([]*model.UserVendorOrder, int, error) { sql := `SELECT SQL_CALC_FOUND_ROWS * FROM user_vendor_order uo WHERE uo.deleted_at = ? ` paramSql := make([]interface{}, 0, 0) paramSql = append(paramSql, utils.DefaultTimeValue) result := make([]*model.UserVendorOrder, 0, 0) if param.OrderNo != "" { sql += ` AND (uo.local_way_bill = ? OR uo.other_way_bill = ? )` paramSql = append(paramSql, param.OrderNo, param.OrderNo) if err := dao.GetRows(dao.GetDB(), &result, sql, paramSql...); err != nil { return nil, 0, err } return result, 0, nil } if param.StartTime.IsZero() && param.EndTime.IsZero() { sql += ` AND uo.created_at >= ? AND ou.created_at <= ? ` paramSql = append(paramSql, param.StartTime, param.EndTime) } if param.ExpressType != 0 { sql += ` AND uo.type = ? ` paramSql = append(paramSql, param.ExpressType) } if param.OrderStatus != 0 { sql += ` AND uo.order_status = ? ` paramSql = append(paramSql, param.OrderStatus) } if param.PageNum == 0 { param.PageNum = 1 } if param.PageSize == 0 { param.PageSize = 10 } sql += ` ORDER BY uo.created_at DESC LIMIT ? OFFSET ? ` paramSql = append(paramSql, param.PageSize, (param.PageNum-1)*param.PageSize) db := dao.GetDB() txdb, _ := dao.Begin(db) defer func() { if r := recover(); r != nil { panic(r) } }() if err := dao.GetRowsTx(txdb, &result, sql, paramSql...); err != nil { dao.Rollback(db, txdb) return nil, 0, err } count := dao.GetLastTotalRowCountTx(txdb) dao.Commit(db, txdb) return result, count, nil } // DeleteOrderByLocalId 删除订单 func DeleteOrderByLocalId(userId, localId string) (int64, error) { sql := `SELECT * FROM user_vendor_order a WHERE 1=1 AND a.user_id = ? AND a.local_way_bill = ? ` paramSql := make([]interface{}, 0, 0) paramSql = append(paramSql, userId, localId) data := model.UserVendorOrder{} if err := dao.GetRow(dao.GetDB(), &data, sql, paramSql...); err != nil { return 0, err } if data.ID <= 0 { return 0, errors.New("用户数据不存在") } // 待支付,支付失败,取消,可以删除 data.DeletedAt = time.Now() if data.OrderStatus == 2 || data.OrderStatus == 3 || data.OrderStatus == 150 { return dao.UpdateEntity(dao.GetDB(), &data, "DeletedAt") } // 支付成功保留15天,可以删除 if !data.CreatedAt.IsZero() && data.CreatedAt.AddDate(0, 0, 15).Unix() > time.Now().Unix() { return dao.UpdateEntity(dao.GetDB(), &data, "DeletedAt") } return 0, errors.New("订单完成后保存15天,才可以删除") } // UpdateOrderStatus 查询所有支付成功的订单 func UpdateOrderStatus() { globals.SugarLogger.Debug("每十分钟更新一下订单,定时任务") // 查询状态值为【4-支付成功,10预下单11待取件12运输中17终止揽收】//2,3 15已签收16取消订单 完成订单 db := dao.GetDB() sql := `SELECT * FROM user_vendor_order WHERE order_status IN (4,10,11,12,17) AND deleted_at = ?` param := []interface{}{utils.DefaultTimeValue} var data []*model.UserVendorOrder if err := dao.GetRows(db, &data, sql, param...); err != nil { globals.SugarLogger.Debug("Scheduled task Err = ", err) return } for _, v := range data { if v.LocalWayBill == v.OtherWayBill && v.OrderStatus == model.OrderStatusSuccessPay { globals.SugarLogger.Debug("ERROR ", "第三方订单Id写入错误,") continue } if v.OrderStatus == 2 || v.OrderStatus == 3 || v.OrderStatus == 15 || v.OrderStatus == 16 || v.OrderStatus == 115 { continue } otherOrder, err := QueryOrderDetail(v.Type, v.OtherWayBill) if err != nil { globals.SugarLogger.Debug("Get Order Fail To QBiDa:", err) continue } param := model.UserVendorOrder{ModelIDCULD: model.ModelIDCULD{ID: v.ModelIDCULD.ID}} param.OrderStatus = otherOrder.Status + 10 if _, err := dao.UpdateEntity(db, ¶m, "OrderStatus"); err != nil { globals.SugarLogger.Debug("Update Order Status Fail ", err) continue } } } // TryAgainOrder 再来一单 func TryAgainOrder(ctx *jxcontext.Context, oldNo string) (*model.UserVendorOrder, error) { sql := `SELECT * FROM user_vendor_order WHERE local_way_bill = ?` var oldOrder *model.UserVendorOrder if err := dao.GetRow(dao.GetDB(), &oldOrder, sql, []interface{}{oldNo}...); err != nil { return nil, err } // 获取用户发货地址信息 sendAddress, countSend, err := dao.QueryUserDeliveryAddress(dao.GetDB(), oldOrder.SenderAddressID, nil, 0, 0, 10) if err != nil || countSend != model.YES { return nil, errors.New("查询错误/送货地址信息不正确") } // 获取用户收货 receiveAddress, receiveSend, err := dao.QueryUserDeliveryAddress(dao.GetDB(), oldOrder.ReceiveAddressID, nil, 0, 0, 10) if err != nil || receiveSend != model.YES { return nil, errors.New("查询错误/收货地址信息不正确") } // 查询配送费选择最低的 fee, err := QueryExpressPrice(&bida.GetExpressPriceReq{ Type: oldOrder.Type, PromiseTimeType: oldOrder.PromiseTimeType, DeliveryType: oldOrder.DeliveryType, GoodsValue: oldOrder.GuarantFee, ReceiveAddress: receiveAddress[0].AutoAddress, SendAddress: sendAddress[0].AutoAddress, Weight: oldOrder.Weight, Length: oldOrder.Length, Height: oldOrder.Height, Width: oldOrder.Width, SendPhone: sendAddress[0].ConsigneeMobile, ChannelType: oldOrder.ChannelType, }) if err != nil { return nil, err } param := &model.MakeOrderParamReq{ PromiseTimeType: oldOrder.PromiseTimeType, DeliveryType: oldOrder.DeliveryType, Goods: oldOrder.Goods, GuaranteeValueAmount: oldOrder.GuaranteeValueAmount, Weight: oldOrder.Weight, Length: oldOrder.Length, Height: oldOrder.Height, Width: oldOrder.Width, OrderSendTime: oldOrder.OrderSendTime, PackageNum: oldOrder.PackageNum, ReceiveAddressId: oldOrder.ReceiveAddressID, ReceiveAddress: receiveAddress[0].AutoAddress, ReceiveName: receiveAddress[0].ConsigneeName, ReceivePhone: receiveAddress[0].ConsigneeMobile, Remark: oldOrder.Remark, SenderAddressId: oldOrder.SenderAddressID, SenderAddress: sendAddress[0].AutoAddress, SenderName: sendAddress[0].ConsigneeName, SenderPhone: sendAddress[0].ConsigneeMobile, ThirdPlatform: oldOrder.ThirdPlatform, Type: oldOrder.Type, ChannelType: oldOrder.ChannelType, Images: oldOrder.Img, ChannelFee: fee[fmt.Sprintf("%d", oldOrder.Type)].Data.ChannelFee, Bulk: utils.Int2Float64(fee[fmt.Sprintf("%d", oldOrder.Type)].Data.Bulk), ServiceCharge: fee[fmt.Sprintf("%d", oldOrder.Type)].Data.ServiceCharge, GuarantFee: fee[fmt.Sprintf("%d", oldOrder.Type)].Data.GuarantFee, OriginalFee: utils.Int2Float64(fee[fmt.Sprintf("%d", oldOrder.Type)].Data.OriginalFee), Increment: fee[fmt.Sprintf("%d", oldOrder.Type)].Data.IncrementFee, } return CreateWayOrder(ctx, param, oldOrder.UserId) }