diff --git a/model/gmodel/fs_refund_reason_logic.go b/model/gmodel/fs_refund_reason_logic.go index 76d6810b..48e67d51 100644 --- a/model/gmodel/fs_refund_reason_logic.go +++ b/model/gmodel/fs_refund_reason_logic.go @@ -2,6 +2,7 @@ package gmodel import ( "context" + "fusenapi/utils/handler" "gorm.io/gorm" ) @@ -35,6 +36,32 @@ func (m *FsRefundReasonModel) CreateOrUpdate(ctx context.Context, req *FsRefundR return req, err } +func (m *FsRefundReasonModel) FindOneByQuery(ctx context.Context, rowBuilder *gorm.DB, filterMap map[string]string) (*FsRefundReason, error) { + var resp FsRefundReason + + if filterMap != nil { + rowBuilder = rowBuilder.Scopes(handler.FilterData(filterMap)) + } + + result := rowBuilder.WithContext(ctx).Limit(1).Find(&resp) + if result.Error != nil { + return nil, result.Error + } else { + return &resp, nil + } +} + +func (m *FsRefundReasonModel) RowSelectBuilder(selectData []string) *gorm.DB { + var rowBuilder = m.db.Table(m.name) + + if selectData != nil { + rowBuilder = rowBuilder.Select(selectData) + } else { + rowBuilder = rowBuilder.Select("*") + } + return rowBuilder +} + func (m *FsRefundReasonModel) TableName() string { return m.name } diff --git a/server/home-user-auth/internal/logic/userordercancellogic.go b/server/home-user-auth/internal/logic/userordercancellogic.go index 0f23aa41..ce64a5b2 100644 --- a/server/home-user-auth/internal/logic/userordercancellogic.go +++ b/server/home-user-auth/internal/logic/userordercancellogic.go @@ -52,18 +52,18 @@ func (l *UserOrderCancelLogic) UserOrderCancel(req *types.UserOrderCancelReq, us } // 判断订单状态 - var notCancelStatusMap = make(map[constants.Order]struct{}, 3) - notCancelStatusMap[constants.STATUS_NEW_NOT_PAY] = struct{}{} - notCancelStatusMap[constants.STATUS_NEW_PART_PAY] = struct{}{} - notCancelStatusMap[constants.STATUS_NEW_PAY_COMPLETED] = struct{}{} - _, ok := notCancelStatusMap[constants.Order(*orderInfo.Status)] + var notCancelStatusMap = make(map[int64]struct{}, 3) + notCancelStatusMap[int64(constants.STATUS_NEW_NOT_PAY)] = struct{}{} + notCancelStatusMap[int64(constants.STATUS_NEW_PART_PAY)] = struct{}{} + notCancelStatusMap[int64(constants.STATUS_NEW_PAY_COMPLETED)] = struct{}{} + _, ok := notCancelStatusMap[int64(*orderInfo.Status)] if !ok { return resp.SetStatusWithMessage(basic.CodeOrderNotCancelledErr, "the order status not cancle") } var cancelTime int64 = time.Now().Unix() - (*orderInfo.Ctime + int64(constants.CANCLE_ORDER_EXPIRE)) // 第一次支付成功后48小时后不能进行取消操作 - if orderInfo.IsPayCompleted != nil && cancelTime > 0 { + if *orderInfo.IsPayCompleted == 1 && cancelTime > 0 { return resp.SetStatusWithMessage(basic.CodeOrderNotCancelledErr, "The current order cannot be cancelled") } diff --git a/server/pay/internal/logic/stripewebhooklogic.go b/server/pay/internal/logic/stripewebhooklogic.go index 8deaf2a6..038c2bce 100644 --- a/server/pay/internal/logic/stripewebhooklogic.go +++ b/server/pay/internal/logic/stripewebhooklogic.go @@ -106,12 +106,13 @@ func (l *StripeWebhookLogic) StripeWebhook(req *types.StripeWebhookReq, userinfo var paymentIntent stripe.PaymentIntent err := json.Unmarshal(event.Data.Raw, &paymentIntent) if err != nil { - logx.Error(err) + logx.Errorf("err:%+v,desc:%s", err, "pay notify Unmarshal fail event.Type payment_intent.succeeded") return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type payment_intent.succeeded") } err = l.HandlePaymentIntentSucceeded(&paymentIntent) if err != nil { - return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type Unhandled") + logx.Errorf("err:%+v,desc:%s", err, "pay notify handle payment_intent.succeeded") + return resp.SetStatusWithMessage(basic.CodePaybackNotOk, "pay notify handle payment_intent.succeeded") } case "payment_method.attached": var paymentMethod stripe.PaymentMethod @@ -120,6 +121,19 @@ func (l *StripeWebhookLogic) StripeWebhook(req *types.StripeWebhookReq, userinfo logx.Error(err) return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type payment_method.attached") } + case "charge.refunded": + var chargeRefunded stripe.Charge + err := json.Unmarshal(event.Data.Raw, &chargeRefunded) + if err != nil { + logx.Errorf("err:%+v,desc:%s", err, "pay notify Unmarshal fail event.Type charge.refunded") + return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type charge.refunded") + } + err = l.HandleChargeRefunded(&chargeRefunded) + if err != nil { + logx.Errorf("err:%+v,desc:%s", err, "pay notify handle charge.refunded") + return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify handle charge.refunded") + } + // ... handle other event types default: logx.Error("Unhandled event") @@ -135,6 +149,66 @@ func (l *StripeWebhookLogic) HandlePayEventCreate(fsPayEvent *gmodel.FsPayEvent) return err } +// 退款成功 +func (l *StripeWebhookLogic) HandleChargeRefunded(chargeRefunded *stripe.Charge) (err error) { + // 退款成功 + if chargeRefunded.Status == "succeeded" { + orderModel := gmodel.NewFsOrderModel(l.svcCtx.MysqlConn) + err = orderModel.Trans(l.ctx, func(ctx context.Context, connGorm *gorm.DB) (err error) { + // 查询支付记录 + payModelT := gmodel.NewFsPayModel(connGorm) + payModelTRSB := payModelT.RowSelectBuilder(nil) + payModelTRSB1 := payModelTRSB.Where("trade_no = ?", chargeRefunded.PaymentIntent.ID).Where("pay_status = ?", constants.PAYSTATUS_SUCCESS).Where("is_refund = ?", 0) + payInfo, err := payModelT.FindOneByQuery(l.ctx, payModelTRSB1, nil) + if err != nil { + return err + } + // 更新支付记录 + *payInfo.IsRefund = 1 + _, err = payModelT.CreateOrUpdate(ctx, payInfo) + if err != nil { + return err + } + // 获取是否还有未退款的数据 + payModelTRSB2 := payModelTRSB.Where("order_number = ?", payInfo.OrderNumber).Where("pay_status = ?", constants.PAYSTATUS_SUCCESS).Where("is_refund = ?", 0) + count, err := payModelT.FindCount(l.ctx, payModelTRSB2, nil) + if count == 0 { + // 退款完成更新订单状态 + orderModelT := gmodel.NewFsOrderModel(connGorm) + orderModelTRSB := orderModelT.RowSelectBuilder(nil).Where("sn =?", payInfo.OrderNumber) + orderInfoRel, err := orderModelT.FindOneByQuery(ctx, orderModelTRSB, nil) + if err != nil { + return err + } + var isRefunded int64 = 1 + var isRefunding int64 = 1 + var orderStatus int64 = int64(constants.STATUS_NEW_REFUNDED) + var orderInfo = &gmodel.FsOrder{} + orderInfo.Id = orderInfoRel.Id + orderInfo.IsRefunded = &isRefunded + orderInfo.IsRefunding = &isRefunding + orderInfo.Status = &orderStatus + orderModelT.Update(ctx, orderInfo) + + // 记录退款原因 + refundReasonModelT := gmodel.NewFsRefundReasonModel(connGorm) + refundReasonModelTRSB := refundReasonModelT.RowSelectBuilder(nil).Where("order_id =?", orderInfoRel.Id) + refundReasonInfo, err := refundReasonModelT.FindOneByQuery(ctx, refundReasonModelTRSB, nil) + if err != nil { + return err + } + *refundReasonInfo.IsRefund = 1 + _, err = refundReasonModelT.CreateOrUpdate(ctx, refundReasonInfo) + if err != nil { + return err + } + } + return err + }) + } + return err +} + // session完成 // func (l *StripeWebhookLogic) handlePaymentSessionCompleted(sessionId string, tradeNo string) (err error) { // // 查询支付记录 @@ -157,7 +231,7 @@ func (l *StripeWebhookLogic) HandlePayEventCreate(fsPayEvent *gmodel.FsPayEvent) // return err // } -// 成功的付款 +// 付款成功 func (l *StripeWebhookLogic) HandlePaymentIntentSucceeded(paymentIntent *stripe.PaymentIntent) error { orderSn, ok := paymentIntent.Metadata["order_sn"] if !ok || orderSn == "" { diff --git a/utils/basic/basic.go b/utils/basic/basic.go index 66aaffc0..c8a5f370 100644 --- a/utils/basic/basic.go +++ b/utils/basic/basic.go @@ -62,6 +62,8 @@ var ( CodePayCancelOk = &StatusResponse{5021, "cancellation successful"} // 支付取消成功 CodePayCancelNotOk = &StatusResponse{5022, "cancellation failed"} // 支付取消失败 + CodePaybackNotOk = &StatusResponse{5023, "pay back failed"} // 支付回调处理失败 + CodeGuestDupErr = &StatusResponse{5010, "user is already guest and does not need to reapply"} // 用户已经是访客用户,无需重复申请 CodeGuestGenErr = &StatusResponse{5011, "serialization failed for guest ID"} // 访客ID序列化失败