Browse Source

feat:customer order timeout 30s

master
黄梓健 5 years ago
parent
commit
5f944aab0e
  1. 5
      controllers/client/good.go
  2. 1
      controllers/client/order_entry.go
  3. 17
      models/customer_order.go
  4. 10
      models/customer_order_sub.go
  5. 119
      services/pay/handle.go
  6. 94
      services/pay/loop.go
  7. 6
      services/pay/order.go
  8. 8
      test/order_test.go

5
controllers/client/good.go

@ -200,8 +200,9 @@ func (t *GoodCtl) Order() {
}
}
var expireAt = time.Now().Add(30 * time.Second).Unix()
res, err := pay_service.UnifiedOrder("欧轩互动-直播商品", user.Openid, int64(price+int(option.PostFee*100)),
4, userId, activity.Id, time.Now().Add(30*time.Second).Unix())
4, userId, activity.Id, expireAt)
if err != nil {
session.Rollback()
t.CheckErr(err)
@ -224,10 +225,12 @@ func (t *GoodCtl) Order() {
TotalAmount: float64(price)/100 + option.PostFee,
PayAmount: float64(price)/100 + option.PostFee,
Status: 0,
Type: 1, // 直播订单
Receiver: param.Name,
Address: param.Address,
Phone: param.Phone,
IsDrawCash: 0,
ExpireTime: expireAt,
Postage: option.PostFee,
}
_, err = session.InsertOne(&order)

1
controllers/client/order_entry.go

@ -120,6 +120,7 @@ func (t *OrderEntryCtl) Order() {
order.AreaName = area.Name
order.BuyerId = userId
order.GoodsId = goodId
order.Type = 0
order.ActivityId = activityId
order.RehearsalId = activity.RehearsalId
order.OrderEntryPersonId = entryPerson.Id

17
models/customer_order.go

@ -26,10 +26,12 @@ type CustomerOrder struct {
GoodsId int64 `json:"goods_id,omitempty" xorm:"not null default 0 comment('customer_goods表id') BIGINT(20)"`
GoodsName string `json:"goods_name,omitempty" xorm:"not null default '' comment('商品名字') VARCHAR(255)"`
GoodsNum int `json:"goods_num,omitempty" xorm:"not null default 0 comment('商品数量') INT(11)"`
TotalAmount float64 `json:"total_amount" xorm:"not null default 0.00 comment('订单总额') DECIMAL(18)"`
PayAmount float64 `json:"pay_amount" xorm:"not null default 0.00 comment('支付金额') DECIMAL(18)"`
Postage float64 `json:"postage" xorm:"not null default 0.00 comment('邮费[0免邮]') DECIMAL(18)"`
TotalAmount float64 `json:"total_amount" xorm:"not null default 0.00 comment('订单总额')"`
PayAmount float64 `json:"pay_amount" xorm:"not null default 0.00 comment('支付金额')"`
Postage float64 `json:"postage" xorm:"not null default 0.00 comment('邮费[0免邮]')"`
Status int `json:"status" xorm:"not null default 0 comment('订单状态[0未支付1已支付即待发货3已发货4确认收货5申请退款6已退款7申请退货8已退货9已取消]')"`
ExpireTime int64 `json:"expire_time" xorm:"not null default 0 comment('订单过时') INT(11)"`
Type int `json:"type" xorm:"not null default 0 comment('订单类型、0录入订单1直播订单')"`
// 快递信息
Receiver string `json:"receiver" xorm:"not null default '' comment('收件人') VARCHAR(128)"`
@ -84,3 +86,12 @@ func (t *CustomerOrder) UpdateStatusBy(outTradeNo string, originStatus, status i
return core.GetXormAuto().Where("is_delete=0 and status=? and out_trade_no=?",
originStatus, outTradeNo).Cols("status, cancel_time").Update(t)
}
func GetExpiredAtLiveCustomerOrder() ([]*CustomerOrder, error) {
orders := make([]*CustomerOrder, 0)
err := core.GetXormAuto().Where("type=1 and is_delete=0 and status=0 and expire_time <= ?", time.Now()).Find(&orders)
if err != nil {
return nil, err
}
return orders, nil
}

10
models/customer_order_sub.go

@ -40,3 +40,13 @@ func GetCustomerOrderSubsByOrderNos(orderNos ...string) (subs []map[string]strin
Desc("s.created_at").Find(&subs)
return
}
func GetSubOrdersByOrderNo(orderNo string) ([]*CustomerOrderSub, error) {
subs := make([]*CustomerOrderSub, 0)
err := core.GetXormAuto().Where("is_delete=0 and order_no=?", orderNo).Find(&subs)
return subs, err
}
func (t *CustomerOrderSub) IncrStock() {
}

119
services/pay/handle.go

@ -6,90 +6,15 @@ import (
"github.com/xormplus/xorm"
"hudongzhuanjia/logger"
"hudongzhuanjia/models"
im_service "hudongzhuanjia/services/im"
"hudongzhuanjia/services/im"
"hudongzhuanjia/utils"
"hudongzhuanjia/utils/define"
"math"
"time"
)
func init() {
//go loopOrder()
go utils.HandleTicker(30*time.Minute, HandleReward) // 打赏24小时退款
}
var orderDelayQueue = make(chan *models.UserOrder, math.MaxInt8)
func PutOrderDelayQueue(order *models.UserOrder) {
orderDelayQueue <- order
}
func loopOrder() {
orders, err := models.GetUserOrdersByStatus(0, 3)
if err != nil {
panic(err)
}
for _, order := range orders {
PutOrderDelayQueue(order)
}
defer func() {
if err := recover(); err != nil {
logger.Error("订单轮询查询: panic 恢复错误", err)
}
// 重启
time.Sleep(5 * time.Second)
loopOrder()
}()
for {
select {
case order, ok := <-orderDelayQueue:
if !ok {
panic("通道异常关闭")
}
if order.ExpireAt <= time.Now().Unix() { // 订单超时
if order.Status == 0 {
go HandleTimeout(order)
}
continue
}
if order.Status == 0 {
res, err := OrderQuery(order.OutTradeNo)
if err != nil {
logger.Error("查询订单出现错误: 错误原因-->", err.Error(), "交易订单号-->", order.OutTradeNo)
orderDelayQueue <- order // 重新进入队列
continue
}
if res["trade_state"] == define.CODE_TRADE_SUCCESS {
go HandleSuccess(order)
} else if res["trade_state"] == define.CODE_TRADE_REFUND {
order.Status = 3
orderDelayQueue <- order
continue
} else {
orderDelayQueue <- order
continue
}
} else if order.Status == 3 {
res, err := QueryRefund(order.OutTradeNo)
if err != nil {
logger.Error("退款订单查询错误: 错误原因-->", err.Error(), "交易订单号-->", order.OutTradeNo)
continue
}
order.RefundAccount = res.RefundList[0].RefundAccount
order.RefundRecvAccount = res.RefundList[0].RefundRecvAccout
order.Status = 4
_, err = models.Update(order.Id, order, "refund_account", "refund_recv_account", "status")
if err != nil {
logger.Error("退款状态改变错误: 错误原因-->", err, "交易订单号-->", order.OutTradeNo)
continue
}
}
}
}
go utils.HandleTicker(30*time.Minute, HandleReward) // 打赏24小时退款
go utils.HandleTicker(30*time.Second, HandleGoodOrder) // 订单关闭信息
}
//处理支付成功之后的回调问题
@ -232,12 +157,40 @@ func HandleSuccess(order *models.UserOrder) error {
return nil
}
func HandleTimeout(order *models.UserOrder) error {
// 退还库存
if order.GoodType == 4 {
err := HandleCancelOrder(order.OutTradeNo)
// 处理商品订单超时的状态
func HandleGoodOrder() error {
orders, err := models.GetExpiredAtLiveCustomerOrder()
if err != nil {
err = fmt.Errorf("获取过期订单信息错误原因: %v", err)
}
for _, v := range orders {
if v.Type != 1 || v.Status != 0 {
continue
}
_, err := OrderQuery(v.OutTradeNo)
if err == nil {
continue
}
err = Close(v.OutTradeNo)
if err != nil {
return err
}
v.Status = 9
v.CancelTime = time.Now()
_, err = models.Update(v.Id, v, "status", "cancel_time")
if err != nil {
return err
}
subs, err := models.GetSubOrdersByOrderNo(v.OrderNo)
if err != nil {
logger.Error(err)
return err
}
for _, sub := range subs {
_, err = new(models.CustomerGoods).IncrStockById(sub.GoodsId, sub.GoodsNum)
if err != nil {
return err
}
}
}
return nil

94
services/pay/loop.go

@ -0,0 +1,94 @@
package pay_service
import (
"hudongzhuanjia/logger"
"hudongzhuanjia/models"
"hudongzhuanjia/utils/define"
"math"
"time"
)
var orderDelayQueue = make(chan *models.UserOrder, math.MaxInt8)
func PutOrderDelayQueue(order *models.UserOrder) {
orderDelayQueue <- order
}
func loopOrder() {
orders, err := models.GetUserOrdersByStatus(0, 3)
if err != nil {
panic(err)
}
for _, order := range orders {
PutOrderDelayQueue(order)
}
defer func() {
if err := recover(); err != nil {
logger.Error("订单轮询查询: panic 恢复错误", err)
}
// 重启
time.Sleep(5 * time.Second)
loopOrder()
}()
for {
select {
case order, ok := <-orderDelayQueue:
if !ok {
panic("通道异常关闭")
}
if order.ExpireAt <= time.Now().Unix() { // 订单超时
if order.Status == 0 {
go HandleTimeout(order)
}
continue
}
if order.Status == 0 {
res, err := OrderQuery(order.OutTradeNo)
if err != nil {
logger.Error("查询订单出现错误: 错误原因-->", err.Error(), "交易订单号-->", order.OutTradeNo)
orderDelayQueue <- order // 重新进入队列
continue
}
if res["trade_state"] == define.CODE_TRADE_SUCCESS {
go HandleSuccess(order)
} else if res["trade_state"] == define.CODE_TRADE_REFUND {
order.Status = 3
orderDelayQueue <- order
continue
} else {
orderDelayQueue <- order
continue
}
} else if order.Status == 3 {
res, err := QueryRefund(order.OutTradeNo)
if err != nil {
logger.Error("退款订单查询错误: 错误原因-->", err.Error(), "交易订单号-->", order.OutTradeNo)
continue
}
order.RefundAccount = res.RefundList[0].RefundAccount
order.RefundRecvAccount = res.RefundList[0].RefundRecvAccout
order.Status = 4
_, err = models.Update(order.Id, order, "refund_account", "refund_recv_account", "status")
if err != nil {
logger.Error("退款状态改变错误: 错误原因-->", err, "交易订单号-->", order.OutTradeNo)
continue
}
}
}
}
}
func HandleTimeout(order *models.UserOrder) error {
// 退还库存
if order.GoodType == 4 {
err := HandleCancelOrder(order.OutTradeNo)
if err != nil {
logger.Error(err)
}
}
return nil
}

6
services/pay/order.go

@ -62,7 +62,7 @@ func UnifiedOrder(content, openId string, fee, goodType, userId, activityId, exp
pac := "prepay_id=" + resp["prepay_id"]
paySign := pay_core.JsapiSign(client.AppId(), timestamp, nonceStr, pac, pay_core.SignType_MD5, define.ApiKey)
go PutOrderDelayQueue(userOrder)
//go PutOrderDelayQueue(userOrder)
return map[string]interface{}{
"appid": client.AppId(),
"timestamp": timestamp,
@ -90,7 +90,7 @@ func ReOrder(outTradeNo string) (map[string]interface{}, error) {
//获取H5支付需要的paySign
pac := "prepay_id=" + userOrder.PrepayId
paySign := pay_core.JsapiSign(define.AppId, timestamp, nonceStr, pac, pay_core.SignType_MD5, define.ApiKey)
go PutOrderDelayQueue(userOrder)
//go PutOrderDelayQueue(userOrder)
return map[string]interface{}{
"appid": define.AppId,
"timestamp": timestamp,
@ -249,7 +249,7 @@ func Refund(reason, outTradeNo string) (map[string]string, error) {
return nil, err
}
go PutOrderDelayQueue(userOrder) // 退款查询
//go PutOrderDelayQueue(userOrder) // 退款查询
return res, nil
}

8
test/order_test.go

@ -39,3 +39,11 @@ func TestHandleReward(t *testing.T) {
func TestLoggerLine(t *testing.T) {
logger.Error("test")
}
func TestOrderQuery(t *testing.T) {
fmt.Println(pay_service.OrderQuery("xxxxxx"))
}
func TestCloseOrder(t *testing.T) {
fmt.Println(pay_service.Close("xxxxxxx"))
}
Loading…
Cancel
Save