From f514dd16c113768bc85deb5492aa4da1c9c97560 Mon Sep 17 00:00:00 2001 From: wucongxing8150 <815046773@qq.com> Date: Mon, 3 Jun 2024 13:26:00 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BA=86=E5=8F=96=E6=B6=88?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E5=8C=85=E8=AE=A2=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/controller/orderServicePackage.go | 47 ++++++ api/requests/OrderServicePackage.go | 7 + api/router/router.go | 4 +- api/service/OrderInquiry.go | 2 +- api/service/orderServicePackage.go | 226 ++++++++++++++++++++++++++ config.yaml | 2 + config/wechat.go | 2 + extend/weChat/weChatPay.go | 5 + 8 files changed, 292 insertions(+), 3 deletions(-) diff --git a/api/controller/orderServicePackage.go b/api/controller/orderServicePackage.go index 4affa0c..cecd7a7 100644 --- a/api/controller/orderServicePackage.go +++ b/api/controller/orderServicePackage.go @@ -110,3 +110,50 @@ func (r *OrderServicePackage) GetOrderServicePackageDetailInfo(c *gin.Context) { responses.OkWithData(getResponses, c) } + +// CancelOrderServicePackage 取消服务包订单 +func (r *OrderServicePackage) CancelOrderServicePackage(c *gin.Context) { + id := c.Param("order_service_id") + if id == "" { + responses.FailWithMessage("缺少参数", c) + return + } + + // 将 id 转换为 int64 类型 + orderServiceId, err := strconv.ParseInt(id, 10, 64) + if err != nil { + responses.Fail(c) + return + } + + orderServicePackageRequest := requests.OrderServicePackageRequest{} + req := orderServicePackageRequest.CancelOrderServicePackage + if err := c.ShouldBind(&req); err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 参数验证 + if err := global.Validate.Struct(req); err != nil { + responses.FailWithMessage(utils.Translate(err), c) + return + } + + if req.RefundAmount == nil { + responses.FailWithMessage("退款金额不可为空", c) + return + } + + // 后台用户id + adminUserId := c.GetInt64("UserId") + + // 业务处理 + orderServicePackageService := service.OrderServicePackageService{} + _, err = orderServicePackageService.CancelOrderServicePackage(req, orderServiceId, adminUserId) + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + responses.Ok(c) +} diff --git a/api/requests/OrderServicePackage.go b/api/requests/OrderServicePackage.go index b385014..220789c 100644 --- a/api/requests/OrderServicePackage.go +++ b/api/requests/OrderServicePackage.go @@ -2,6 +2,7 @@ package requests type OrderServicePackageRequest struct { GetOrderServicePackagePage // 获取药品订单列表-分页 + CancelOrderServicePackage // 取消服务包订单 } // GetOrderServicePackagePage 订单-服务包表 @@ -31,3 +32,9 @@ type GetOrderServicePackagePage struct { Mobile string `json:"mobile" form:"mobile" label:"手机号-医生/患者"` DoctorName string `json:"doctor_name" form:"doctor_name" label:"医生姓名"` } + +// CancelOrderServicePackage 取消服务包订单 +type CancelOrderServicePackage struct { + RefundAmount *float64 `json:"refund_amount" form:"refund_amount" label:"退款金额"` + CancelRemarks string `json:"cancel_remarks" form:"cancel_remarks" validate:"required" label:"取消订单备注"` +} diff --git a/api/router/router.go b/api/router/router.go index e677e7c..83f7661 100644 --- a/api/router/router.go +++ b/api/router/router.go @@ -456,8 +456,8 @@ func privateRouter(r *gin.Engine, api controller.Api) { // 获取服务包订单服务权益详情 serviceGroup.GET("/detail/:order_service_id", api.OrderServicePackage.GetOrderServicePackageDetailInfo) - // 取消问诊订单 - serviceGroup.PUT("/cancel/:order_inquiry_id", api.OrderServicePackage.GetOrderServicePackageDetailInfo) + // 取消服务包订单 + serviceGroup.PUT("/cancel/:order_service_id", api.OrderServicePackage.CancelOrderServicePackage) } } diff --git a/api/service/OrderInquiry.go b/api/service/OrderInquiry.go index b57d500..d3e1e0f 100644 --- a/api/service/OrderInquiry.go +++ b/api/service/OrderInquiry.go @@ -259,7 +259,7 @@ func (r *OrderInquiryService) CancelOrderInquiry(req requests.CancelOrderInquiry // 记录日志 orderOperationLog := &model.OrderOperationLog{ - OrderId: orderInquiry.OrderInquiryId, + OrderId: orderInquiry.OrderId, OrderNo: orderInquiry.InquiryNo, OrderType: 1, OperatorId: adminUserId, diff --git a/api/service/orderServicePackage.go b/api/service/orderServicePackage.go index 9ebff55..ea41f49 100644 --- a/api/service/orderServicePackage.go +++ b/api/service/orderServicePackage.go @@ -5,6 +5,10 @@ import ( "hospital-admin-api/api/dao" "hospital-admin-api/api/dto" "hospital-admin-api/api/model" + "hospital-admin-api/api/requests" + "hospital-admin-api/config" + "hospital-admin-api/extend/weChat" + "hospital-admin-api/global" "strconv" "time" ) @@ -149,6 +153,228 @@ func (r *OrderServicePackageService) GetOrderServicePackageDetailInfo(orderServi return g, nil } +// CancelOrderServicePackage 取消服务包订单 +func (r *OrderServicePackageService) CancelOrderServicePackage(req requests.CancelOrderServicePackage, orderServiceId, adminUserId int64) (bool, error) { + // 获取订单数据 + orderServicePackageDao := dao.OrderServicePackageDao{} + orderServicePackage, err := orderServicePackageDao.GetOrderServicePackagePreloadById(orderServiceId) + if err != nil || orderServicePackage == nil { + return false, errors.New("订单数据错误") + } + + // 订单状态(1:待支付 2:未开始 3:服务中 4:服务完成 5:服务取消) + if orderServicePackage.OrderServiceStatus == 5 { + return false, errors.New("订单已取消,无法再次取消") + } + + // 检测订单退款状态 问诊订单退款状态(0:无退款 1:申请退款 2:退款中 3:退款成功 4:拒绝退款 5:退款关闭 6:退款异常) + if orderServicePackage.RefundStatus == 1 { + return false, errors.New("订单申请退款中,无法取消") + } + + if orderServicePackage.RefundStatus == 2 { + return false, errors.New("订单正在退款中,无法取消") + } + + if orderServicePackage.RefundStatus == 3 { + return false, errors.New("订单已退款成功,无法取消") + } + + if orderServicePackage.RefundStatus == 6 { + return false, errors.New("订单退款异常,请联系技术人员") + } + + // 检测支付状态 支付状态(1:未支付 2:已支付 3:支付中 4:支付失败 5:支付超时 6:支付关闭 7:已撤销 8:转入退款) + if orderServicePackage.PayStatus != 2 { + return false, errors.New("订单未支付,无需取消") + } + + // 检测退款金额 + if *req.RefundAmount > orderServicePackage.PaymentAmountTotal { + return false, errors.New("退款金额不可超过实付金额") + } + + // 开始事务 + tx := global.Db.Begin() + defer func() { + if r := recover(); r != nil { + tx.Rollback() + } + }() + + // 退款编号 + refundNo := strconv.FormatInt(global.Snowflake.Generate().Int64(), 10) + + // 退款状态转换 + var refundStatus int + var successTime time.Time + var refundId string + + // 发起退款 + if orderServicePackage.PaymentAmountTotal > 0 { + refundRequest := weChat.RefundRequest{ + TransactionId: orderServicePackage.EscrowTradeNo, + OutTradeNo: orderServicePackage.OrderServiceNo, + OutRefundNo: refundNo, + Reason: "客服取消", + RefundAmount: int64(*req.RefundAmount * 100), + PaymentAmountTotal: int64(orderServicePackage.PaymentAmountTotal * 100), + NotifyUrl: config.C.Wechat.RefundNotifyDomain + config.C.Wechat.PatientServiceRefundNotifyUrl, + } + + refund, err := refundRequest.Refund(4) + if err != nil { + tx.Rollback() + return false, errors.New(err.Error()) + } + + if refund.Status == nil { + tx.Rollback() + return false, errors.New("退款状态错误") + } + + if *refund.Status == "SUCCESS" { + // 退款成功 + refundStatus = 3 + + if refund.SuccessTime != nil { + successTime = *refund.SuccessTime + } + } else if *refund.Status == "CLOSED" { + // 退款关闭 + refundStatus = 5 + + } else if *refund.Status == "PROCESSING" { + // 退款处理中 + refundStatus = 2 + + } else if *refund.Status == "ABNORMAL" { + // 退款异常 + tx.Rollback() + return false, errors.New("退款状态错误") + } else { + tx.Rollback() + return false, errors.New("退款状态错误") + } + + if refund.RefundId == nil { + tx.Rollback() + return false, errors.New("缺少退款订单编号") + } + + // 退款编号 + refundId = *refund.RefundId + } else { + // 支付金额为0,模拟退款 + refundId = "模拟退款:" + strconv.FormatInt(global.Snowflake.Generate().Int64(), 10) + refundStatus = 3 + successTime = time.Now() + + // 模拟退款时手动退还优惠卷 + if orderServicePackage.CouponAmountTotal > 0 { + orderService := OrderService{} + res, err := orderService.ReturnOrderCoupon(orderServicePackage.OrderServiceNo, tx) + if err != nil || !res { + // 退还优惠卷失败 + tx.Rollback() + return false, err + } + } + } + + // 修改订单为取消 + orderData := make(map[string]interface{}) + orderData["cancel_status"] = 1 + orderData["cancel_time"] = time.Now().Format("2006-01-02 15:04:05") + orderData["cancel_remarks"] = req.CancelRemarks + + orderDao := dao.OrderDao{} + err = orderDao.EditOrderById(tx, orderServicePackage.OrderId, orderData) + if err != nil { + tx.Rollback() + return false, errors.New("取消订单失败") + } + + // 修改服务包订单为取消 + orderServicePackageData := make(map[string]interface{}) + orderServicePackageData["order_service_status"] = 5 // 订单状态(1:待支付 2:未开始 3:服务中 4:服务完成 5:服务取消) + orderServicePackageData["cancel_time"] = time.Now().Format("2006-01-02 15:04:05") // 订单取消时间 + orderServicePackageData["cancel_reason"] = 4 // 取消订单原因(1:医生未接诊 2:主动取消 3:无可分配医生 4:客服取消 5:支付超时) + orderServicePackageData["cancel_remarks"] = req.CancelRemarks // 取消订单备注(自动添加) + err = orderServicePackageDao.EditOrderServicePackageById(tx, orderServiceId, orderServicePackageData) + if err != nil { + tx.Rollback() + return false, errors.New("取消订单失败") + } + + // 新增退款表 + orderRefund := &model.OrderRefund{ + OrderId: orderServicePackage.OrderId, + PatientId: orderServicePackage.PatientId, + OrderNo: orderServicePackage.OrderServiceNo, + RefundNo: refundNo, + RefundId: refundId, + RefundStatus: refundStatus, + RefundTotal: *req.RefundAmount, + RefundReason: req.CancelRemarks, + } + + if refundStatus == 3 && !successTime.IsZero() { + orderRefund.SuccessTime = model.LocalTime(successTime) + } + + orderRefundDao := dao.OrderRefundDao{} + orderRefund, err = orderRefundDao.AddOrderRefund(tx, orderRefund) + if err != nil || orderRefund == nil { + tx.Rollback() + return false, errors.New(err.Error()) + } + + // 新增服务包退款表 + orderServicePackageRefund := &model.OrderServicePackageRefund{ + PatientId: orderServicePackage.PatientId, + OrderServiceId: orderServicePackage.OrderServiceId, + OrderServiceNo: orderServicePackage.OrderServiceNo, + ServiceRefundNo: refundNo, + RefundId: refundId, + RefundStatus: refundStatus, + RefundTotal: *req.RefundAmount, + RefundReason: req.CancelRemarks, + SuccessTime: model.LocalTime(successTime), + } + + if refundStatus == 3 && !successTime.IsZero() { + orderRefund.SuccessTime = model.LocalTime(successTime) + } + + orderServicePackageRefundDao := dao.OrderServicePackageRefundDao{} + orderServicePackageRefund, err = orderServicePackageRefundDao.AddOrderServicePackageRefund(tx, orderServicePackageRefund) + if err != nil || orderServicePackageRefund == nil { + tx.Rollback() + return false, errors.New(err.Error()) + } + + // 记录日志 + orderOperationLog := &model.OrderOperationLog{ + OrderId: orderServicePackage.OrderId, + OrderNo: orderServicePackage.OrderServiceNo, + OrderType: 4, + OperatorId: adminUserId, + OperationContent: "取消订单并退款", + } + + orderOperationLogDao := dao.OrderOperationLogDao{} + orderOperationLog, err = orderOperationLogDao.AddOrderOperationLog(tx, orderOperationLog) + if err != nil || orderOperationLog == nil { + tx.Rollback() + return false, errors.New(err.Error()) + } + + tx.Commit() + + return true, nil +} + // 获取服务包当前月时间区间 func (r *OrderServicePackageService) getOrderServicePackageCurrentMonthDate(startTime model.LocalTime) (startDate, finishDate time.Time, err error) { if startTime.IsEmpty() { diff --git a/config.yaml b/config.yaml index fe07cbb..96ea071 100644 --- a/config.yaml +++ b/config.yaml @@ -72,6 +72,8 @@ wechat: patient-product-refund-notify-url: callback/wxpay/product/refund patient-detection-pay-notify-url: callback/wxpay/detection/success patient-detection-refund-notify-url: callback/wxpay/detection/refund + patient-service-pay-notify-url: callback/wxpay/service/success + patient-service-refund-notify-url: callback/wxpay/service/refund refund-notify-domain: https://dev.hospital.applets.igandanyiyuan.com/ doctor-app-id: wxc83296720404aa7b doctor-app-secret: 817665d3763637fe66d56548f8484622 diff --git a/config/wechat.go b/config/wechat.go index c13ba3d..ab46ef7 100644 --- a/config/wechat.go +++ b/config/wechat.go @@ -9,6 +9,8 @@ type Wechat struct { PatientProductRefundNotifyUrl string `mapstructure:"patient-product-refund-notify-url" json:"patient-product-refund-notify-url" yaml:"patient-product-refund-notify-url"` PatientDetectionPayNotifyUrl string `mapstructure:"patient-detection-pay-notify-url" json:"patient-detection-pay-notify-url" yaml:"patient-detection-pay-notify-url"` PatientDetectionRefundNotifyUrl string `mapstructure:"patient-detection-refund-notify-url" json:"patient-detection-refund-notify-url" yaml:"patient-detection-refund-notify-url"` + PatientServicePayNotifyUrl string `mapstructure:"patient-service-pay-notify-url" json:"patient-service-pay-notify-url" yaml:"patient-service-pay-notify-url"` + PatientServiceRefundNotifyUrl string `mapstructure:"patient-service-refund-notify-url" json:"patient-service-refund-notify-url" yaml:"patient-service-refund-notify-url"` RefundNotifyDomain string `mapstructure:"refund-notify-domain" json:"refund-notify-domain" yaml:"refund-notify-domain"` // 回调域名 DoctorAppId string `mapstructure:"doctor-app-id" json:"doctor-app-id" yaml:"doctor-app-id"` DoctorAppSecret string `mapstructure:"doctor-app-secret" json:"doctor-app-secret" yaml:"doctor-app-secret"` diff --git a/extend/weChat/weChatPay.go b/extend/weChat/weChatPay.go index 85aa982..0a3ea0b 100644 --- a/extend/weChat/weChatPay.go +++ b/extend/weChat/weChatPay.go @@ -38,6 +38,11 @@ func (r RefundRequest) Refund(orderType int) (*refunddomestic.Refund, error) { mchId = config.C.Wechat.Pay1636644248.MchId mchCertificateSerialNumber = config.C.Wechat.Pay1636644248.MchCertificateSerialNumber v3ApiSecret = config.C.Wechat.Pay1636644248.V3ApiSecret + } else if orderType == 4 { + // 服务包 + mchId = config.C.Wechat.Pay1659662936.MchId + mchCertificateSerialNumber = config.C.Wechat.Pay1659662936.MchCertificateSerialNumber + v3ApiSecret = config.C.Wechat.Pay1659662936.V3ApiSecret } if mchId == "" {