From 96308ff6088112a6e5e96dd252231121425fed40 Mon Sep 17 00:00:00 2001 From: wucongxing <815046773@qq.com> Date: Thu, 3 Aug 2023 14:42:33 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=BE=AE=E4=BF=A1=E6=94=AF?= =?UTF-8?q?=E4=BB=98=E5=AF=B9=E6=8E=A5=EF=BC=8C=E5=90=8E=E5=8F=B0=E5=AE=A2?= =?UTF-8?q?=E6=9C=8D=E5=8F=96=E6=B6=88=E8=AE=A2=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/controller/base.go | 6 + api/controller/orderInquiry.go | 51 +++++ api/dao/orderInquiry.go | 73 +++++++ api/dao/orderInquiryRefund.go | 73 +++++++ api/model/orderInquiry.go | 62 ++++++ api/model/orderInquiryRefund.go | 39 ++++ api/router/router.go | 19 ++ api/service/OrderInquiry.go | 182 ++++++++++++++++++ config.yaml | 18 +- config/config.go | 1 + config/wechat.go | 17 ++ .../certs/1636644248/apiclient_cert.p12 | Bin 0 -> 2774 bytes .../certs/1636644248/apiclient_cert.pem | 25 +++ .../weChat/certs/1636644248/apiclient_key.pem | 28 +++ ...2FCCD1B9ECC8292703AB7363C73D74B6AFDC1A.pem | 24 +++ extend/weChat/weChatPay.go | 63 ++++++ go.mod | 1 + go.sum | 3 + 18 files changed, 684 insertions(+), 1 deletion(-) create mode 100644 api/controller/orderInquiry.go create mode 100644 api/dao/orderInquiry.go create mode 100644 api/dao/orderInquiryRefund.go create mode 100644 api/model/orderInquiry.go create mode 100644 api/model/orderInquiryRefund.go create mode 100644 api/service/OrderInquiry.go create mode 100644 config/wechat.go create mode 100644 extend/weChat/certs/1636644248/apiclient_cert.p12 create mode 100644 extend/weChat/certs/1636644248/apiclient_cert.pem create mode 100644 extend/weChat/certs/1636644248/apiclient_key.pem create mode 100644 extend/weChat/certs/1636644248/wechatpay_112FCCD1B9ECC8292703AB7363C73D74B6AFDC1A.pem create mode 100644 extend/weChat/weChatPay.go diff --git a/api/controller/base.go b/api/controller/base.go index b68855f..c1c5b9a 100644 --- a/api/controller/base.go +++ b/api/controller/base.go @@ -6,6 +6,7 @@ type Api struct { userDoctorManage // 医生管理 Admin // 公共方法 basic // 基础数据 + order // 订单管理 } // SysSetting 系统设置 @@ -31,3 +32,8 @@ type basic struct { Bank // 银行管理 Area // 省市区管理 } + +// 订单管理 +type order struct { + OrderInquiry // 问诊订单 +} diff --git a/api/controller/orderInquiry.go b/api/controller/orderInquiry.go new file mode 100644 index 0000000..f130683 --- /dev/null +++ b/api/controller/orderInquiry.go @@ -0,0 +1,51 @@ +package controller + +import ( + "github.com/gin-gonic/gin" + "hospital-admin-api/api/responses" + "hospital-admin-api/api/service" + "strconv" +) + +type OrderInquiry struct{} + +// GetOrderInquiryPage 获取问诊订单列表-分页 +func (r *OrderInquiry) GetOrderInquiryPage(c *gin.Context) { + responses.Ok(c) +} + +// GetOrderInquiry 问诊订单详情 +func (r *OrderInquiry) GetOrderInquiry(c *gin.Context) { + responses.Ok(c) +} + +// DeleteOrderInquiry 删除问诊订单 +func (r *OrderInquiry) DeleteOrderInquiry(c *gin.Context) { + responses.Ok(c) +} + +// CancelOrderInquiry 取消问诊订单 +func (r *OrderInquiry) CancelOrderInquiry(c *gin.Context) { + id := c.Param("order_inquiry_id") + if id == "" { + responses.FailWithMessage("缺少参数", c) + return + } + + // 将 id 转换为 int64 类型 + orderInquiryId, err := strconv.ParseInt(id, 10, 64) + if err != nil { + responses.Fail(c) + return + } + + // 业务处理 + orderInquiryService := service.OrderInquiryService{} + _, err = orderInquiryService.CancelOrderInquiry(orderInquiryId) + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + responses.Ok(c) +} diff --git a/api/dao/orderInquiry.go b/api/dao/orderInquiry.go new file mode 100644 index 0000000..04c3e3b --- /dev/null +++ b/api/dao/orderInquiry.go @@ -0,0 +1,73 @@ +package dao + +import ( + "gorm.io/gorm" + "gorm.io/gorm/clause" + "hospital-admin-api/api/model" + "hospital-admin-api/global" +) + +type OrderInquiryDao struct { +} + +// GetOrderInquiryById 获取问诊订单数据-问诊订单id +func (r *OrderInquiryDao) GetOrderInquiryById(doctorId int64) (m *model.OrderInquiry, err error) { + err = global.Db.First(&m, doctorId).Error + if err != nil { + return nil, err + } + return m, nil +} + +// GetOrderInquiryPreloadById 获取问诊订单数据-加载全部关联-问诊订单id +func (r *OrderInquiryDao) GetOrderInquiryPreloadById(orderInquiryId int64) (m *model.OrderInquiry, err error) { + err = global.Db.Preload(clause.Associations).First(&m, orderInquiryId).Error + if err != nil { + return nil, err + } + return m, nil +} + +// DeleteOrderInquiry 删除问诊订单 +func (r *OrderInquiryDao) DeleteOrderInquiry(tx *gorm.DB, maps interface{}) error { + err := tx.Where(maps).Delete(&model.OrderInquiry{}).Error + if err != nil { + return err + } + return nil +} + +// EditOrderInquiry 修改问诊订单 +func (r *OrderInquiryDao) EditOrderInquiry(tx *gorm.DB, maps interface{}, data interface{}) error { + err := tx.Model(&model.OrderInquiry{}).Where(maps).Updates(data).Error + if err != nil { + return err + } + return nil +} + +// EditOrderInquiryById 修改问诊订单-问诊订单id +func (r *OrderInquiryDao) EditOrderInquiryById(tx *gorm.DB, orderInquiryId int64, data interface{}) error { + err := tx.Model(&model.OrderInquiry{}).Where("order_inquiry_id = ?", orderInquiryId).Updates(data).Error + if err != nil { + return err + } + return nil +} + +// GetOrderInquiryList 获取问诊订单列表 +func (r *OrderInquiryDao) GetOrderInquiryList(maps interface{}) (m []*model.OrderInquiry, err error) { + err = global.Db.Where(maps).Find(&m).Error + if err != nil { + return nil, err + } + return m, nil +} + +// AddOrderInquiry 新增问诊订单 +func (r *OrderInquiryDao) AddOrderInquiry(tx *gorm.DB, model *model.OrderInquiry) (*model.OrderInquiry, error) { + if err := tx.Create(model).Error; err != nil { + return nil, err + } + return model, nil +} diff --git a/api/dao/orderInquiryRefund.go b/api/dao/orderInquiryRefund.go new file mode 100644 index 0000000..01c263f --- /dev/null +++ b/api/dao/orderInquiryRefund.go @@ -0,0 +1,73 @@ +package dao + +import ( + "gorm.io/gorm" + "gorm.io/gorm/clause" + "hospital-admin-api/api/model" + "hospital-admin-api/global" +) + +type OrderInquiryRefundDao struct { +} + +// GetOrderInquiryRefundById 获取问诊退款订单数据-问诊退款订单id +func (r *OrderInquiryRefundDao) GetOrderInquiryRefundById(doctorId int64) (m *model.OrderInquiryRefund, err error) { + err = global.Db.First(&m, doctorId).Error + if err != nil { + return nil, err + } + return m, nil +} + +// GetOrderInquiryRefundPreloadById 获取问诊退款订单数据-加载全部关联-问诊退款订单id +func (r *OrderInquiryRefundDao) GetOrderInquiryRefundPreloadById(inquiryRefundId int64) (m *model.OrderInquiryRefund, err error) { + err = global.Db.Preload(clause.Associations).First(&m, inquiryRefundId).Error + if err != nil { + return nil, err + } + return m, nil +} + +// DeleteOrderInquiryRefund 删除问诊退款订单 +func (r *OrderInquiryRefundDao) DeleteOrderInquiryRefund(tx *gorm.DB, maps interface{}) error { + err := tx.Where(maps).Delete(&model.OrderInquiryRefund{}).Error + if err != nil { + return err + } + return nil +} + +// EditOrderInquiryRefund 修改问诊退款订单 +func (r *OrderInquiryRefundDao) EditOrderInquiryRefund(tx *gorm.DB, maps interface{}, data interface{}) error { + err := tx.Model(&model.OrderInquiryRefund{}).Where(maps).Updates(data).Error + if err != nil { + return err + } + return nil +} + +// EditOrderInquiryRefundById 修改问诊退款订单-问诊退款订单id +func (r *OrderInquiryRefundDao) EditOrderInquiryRefundById(tx *gorm.DB, inquiryRefundId int64, data interface{}) error { + err := tx.Model(&model.OrderInquiryRefund{}).Where("inquiry_refund_id = ?", inquiryRefundId).Updates(data).Error + if err != nil { + return err + } + return nil +} + +// GetOrderInquiryRefundList 获取问诊退款订单列表 +func (r *OrderInquiryRefundDao) GetOrderInquiryRefundList(maps interface{}) (m []*model.OrderInquiryRefund, err error) { + err = global.Db.Where(maps).Find(&m).Error + if err != nil { + return nil, err + } + return m, nil +} + +// AddOrderInquiryRefund 新增问诊退款订单 +func (r *OrderInquiryRefundDao) AddOrderInquiryRefund(tx *gorm.DB, model *model.OrderInquiryRefund) (*model.OrderInquiryRefund, error) { + if err := tx.Create(model).Error; err != nil { + return nil, err + } + return model, nil +} diff --git a/api/model/orderInquiry.go b/api/model/orderInquiry.go new file mode 100644 index 0000000..a9bbdc4 --- /dev/null +++ b/api/model/orderInquiry.go @@ -0,0 +1,62 @@ +package model + +import ( + "gorm.io/gorm" + "hospital-admin-api/global" + "time" +) + +// OrderInquiry 订单-问诊表 +type OrderInquiry struct { + OrderInquiryId int64 `gorm:"column:order_inquiry_id;type:bigint(19);primary_key;comment:主键id" json:"order_inquiry_id"` + UserId int64 `gorm:"column:user_id;type:bigint(19);comment:用户id-患者;NOT NULL" json:"user_id"` + PatientId int64 `gorm:"column:patient_id;type:bigint(19);comment:患者id;NOT NULL" json:"patient_id"` + DoctorId int64 `gorm:"column:doctor_id;type:bigint(19);comment:医生id(未分配时为null)" json:"doctor_id"` + FamilyId int64 `gorm:"column:family_id;type:bigint(19);comment:家庭成员id(就诊用户);NOT NULL" json:"family_id"` + InquiryType int `gorm:"column:inquiry_type;type:tinyint(1);comment:订单类型(1:专家问诊 2:快速问诊 3:公益问诊 4:问诊购药 5:检测);NOT NULL" json:"inquiry_type"` + InquiryMode int `gorm:"column:inquiry_mode;type:tinyint(1);comment:订单问诊方式(1:图文 2:视频 3:语音 4:电话 5:会员);NOT NULL" json:"inquiry_mode"` + InquiryStatus int `gorm:"column:inquiry_status;type:tinyint(1);default:1;comment:问诊订单状态(1:待支付 2:待分配 3:待接诊 4:已接诊 5:已完成 6:已结束 7:已取消);NOT NULL" json:"inquiry_status"` + IsDelete int `gorm:"column:is_delete;type:tinyint(1);default:0;comment:删除状态(0:否 1:是)" json:"is_delete"` + InquiryRefundStatus int `gorm:"column:inquiry_refund_status;type:tinyint(1);default:0;comment:问诊订单退款状态(0:无退款 1:申请退款 2:退款中 3:退款成功 4:拒绝退款 5:退款关闭 6:退款异常)" json:"inquiry_refund_status"` + InquiryPayChannel int `gorm:"column:inquiry_pay_channel;type:tinyint(1);comment:支付渠道(1:小程序支付 2:微信扫码支付 3:模拟支付)" json:"inquiry_pay_channel"` + InquiryPayStatus int `gorm:"column:inquiry_pay_status;type:tinyint(1);default:1;comment:支付状态(1:未支付 2:已支付 3:支付中 4:支付失败 5:支付超时 6:支付关闭 7:已撤销 8:转入退款);NOT NULL" json:"inquiry_pay_status"` + InquiryNo string `gorm:"column:inquiry_no;type:varchar(30);comment:系统订单编号;NOT NULL" json:"inquiry_no"` + EscrowTradeNo string `gorm:"column:escrow_trade_no;type:varchar(100);comment:第三方支付流水号" json:"escrow_trade_no"` + AmountTotal float64 `gorm:"column:amount_total;type:decimal(10,2);default:0.00;comment:订单金额" json:"amount_total"` + CouponAmountTotal float64 `gorm:"column:coupon_amount_total;type:decimal(10,2);comment:优惠卷总金额" json:"coupon_amount_total"` + PaymentAmountTotal float64 `gorm:"column:payment_amount_total;type:decimal(10,2);default:0.00;comment:实际付款金额" json:"payment_amount_total"` + PayTime time.Time `gorm:"column:pay_time;type:datetime;comment:支付时间" json:"pay_time"` + ReceptionTime time.Time `gorm:"column:reception_time;type:datetime;comment:接诊时间(已接诊)" json:"reception_time"` + CompleteTime time.Time `gorm:"column:complete_time;type:datetime;comment:订单完成时间(问诊完成时间)" json:"complete_time"` + FinishTime time.Time `gorm:"column:finish_time;type:datetime;comment:订单结束时间" json:"finish_time"` + StatisticsStatus int `gorm:"column:statistics_status;type:tinyint(1);default:0;comment:订单统计状态(0:未统计 1:已统计 2:统计失败)" json:"statistics_status"` + StatisticsTime time.Time `gorm:"column:statistics_time;type:datetime;comment:订单统计时间" json:"statistics_time"` + IsWithdrawal int `gorm:"column:is_withdrawal;type:tinyint(1);default:0;comment:是否提现(0:否 1:是 2:提现中)" json:"is_withdrawal"` + WithdrawalTime time.Time `gorm:"column:withdrawal_time;type:datetime;comment:提现时间" json:"withdrawal_time"` + CancelTime time.Time `gorm:"column:cancel_time;type:datetime;comment:订单取消时间" json:"cancel_time"` + CancelReason int `gorm:"column:cancel_reason;type:tinyint(1);comment:取消订单原因(1:医生未接诊 2:主动取消 3:无可分配医生 4:客服取消 5:支付超时)" json:"cancel_reason"` + CancelRemarks string `gorm:"column:cancel_remarks;type:varchar(255);comment:取消订单备注(自动添加)" json:"cancel_remarks"` + PatientName string `gorm:"column:patient_name;type:varchar(255);comment:患者姓名-就诊人" json:"patient_name"` + PatientNameMask string `gorm:"column:patient_name_mask;type:varchar(255);comment:患者姓名-就诊人(掩码)" json:"patient_name_mask"` + PatientSex int `gorm:"column:patient_sex;type:tinyint(1);default:0;comment:患者性别-就诊人(0:未知 1:男 2:女)" json:"patient_sex"` + PatientAge int `gorm:"column:patient_age;type:int(1);comment:患者年龄-就诊人" json:"patient_age"` + Model +} + +func (m *OrderInquiry) TableName() string { + return "gdxz_order_inquiry" +} + +func (m *OrderInquiry) BeforeCreate(tx *gorm.DB) error { + if m.OrderInquiryId == 0 { + m.OrderInquiryId = global.Snowflake.Generate().Int64() + } + + m.CreatedAt = LocalTime(time.Now()) + tx.Statement.SetColumn("CreatedAt", m.CreatedAt) + + m.UpdatedAt = LocalTime(time.Now()) + tx.Statement.SetColumn("UpdatedAt", m.UpdatedAt) + + return nil +} diff --git a/api/model/orderInquiryRefund.go b/api/model/orderInquiryRefund.go new file mode 100644 index 0000000..5d2fada --- /dev/null +++ b/api/model/orderInquiryRefund.go @@ -0,0 +1,39 @@ +package model + +import ( + "gorm.io/gorm" + "hospital-admin-api/global" + "time" +) + +// OrderInquiryRefund 订单-问诊-退款表 +type OrderInquiryRefund struct { + InquiryRefundId int64 `gorm:"column:inquiry_refund_id;type:bigint(19);primary_key;comment:主键id" json:"inquiry_refund_id"` + PatientId int64 `gorm:"column:patient_id;type:bigint(19);comment:患者id" json:"patient_id"` + OrderInquiryId int64 `gorm:"column:order_inquiry_id;type:bigint(19);comment:订单-问诊id" json:"order_inquiry_id"` + InquiryNo string `gorm:"column:inquiry_no;type:varchar(40);comment:系统订单编号" json:"inquiry_no"` + InquiryRefundNo string `gorm:"column:inquiry_refund_no;type:varchar(50);comment:系统退款编号" json:"inquiry_refund_no"` + RefundId string `gorm:"column:refund_id;type:varchar(50);comment:第三方退款单号" json:"refund_id"` + InquiryRefundStatus int `gorm:"column:inquiry_refund_status;type:tinyint(4);comment:问诊订单退款状态(0:无退款 1:申请退款 2:退款中 3:退款成功 4:拒绝退款 5:退款关闭 6:退款异常)" json:"inquiry_refund_status"` + RefundTotal float64 `gorm:"column:refund_total;type:decimal(10,2);comment:退款金额" json:"refund_total"` + RefundReason string `gorm:"column:refund_reason;type:varchar(255);comment:退款原因" json:"refund_reason"` + SuccessTime time.Time `gorm:"column:success_time;type:datetime;comment:退款成功时间" json:"success_time"` + Model +} + +func (m *OrderInquiryRefund) TableName() string { + return "gdxz_order_inquiry_refund" +} +func (m *OrderInquiryRefund) BeforeCreate(tx *gorm.DB) error { + if m.InquiryRefundId == 0 { + m.InquiryRefundId = global.Snowflake.Generate().Int64() + } + + m.CreatedAt = LocalTime(time.Now()) + tx.Statement.SetColumn("CreatedAt", m.CreatedAt) + + m.UpdatedAt = LocalTime(time.Now()) + tx.Statement.SetColumn("UpdatedAt", m.UpdatedAt) + + return nil +} diff --git a/api/router/router.go b/api/router/router.go index 944161a..c441633 100644 --- a/api/router/router.go +++ b/api/router/router.go @@ -355,4 +355,23 @@ func privateRouter(r *gin.Engine, api controller.Api) { } } + // 订单管理 + orderGroup := adminGroup.Group("/order") + { + // 问诊订单 + inquiryGroup := orderGroup.Group("/inquiry") + { + // 获取问诊订单列表-分页 + inquiryGroup.GET("", api.OrderInquiry.GetOrderInquiryPage) + + // 问诊订单详情 + inquiryGroup.GET("/:order_inquiry_id", api.OrderInquiry.GetOrderInquiry) + + // 删除问诊订单 + inquiryGroup.DELETE("/:order_inquiry_id", api.OrderInquiry.DeleteOrderInquiry) + + // 取消问诊订单 + inquiryGroup.PUT("/:order_inquiry_id", api.OrderInquiry.CancelOrderInquiry) + } + } } diff --git a/api/service/OrderInquiry.go b/api/service/OrderInquiry.go new file mode 100644 index 0000000..fc98afd --- /dev/null +++ b/api/service/OrderInquiry.go @@ -0,0 +1,182 @@ +package service + +import ( + "errors" + "hospital-admin-api/api/dao" + "hospital-admin-api/api/model" + "hospital-admin-api/config" + "hospital-admin-api/extend/weChat" + "hospital-admin-api/global" + "strconv" + "time" +) + +type OrderInquiryService struct { +} + +// CancelOrderInquiry 取消问诊订单 +func (r *OrderInquiryService) CancelOrderInquiry(orderInquiryId int64) (bool, error) { + // 获取订单数据 + orderInquiryDao := dao.OrderInquiryDao{} + orderInquiry, err := orderInquiryDao.GetOrderInquiryById(orderInquiryId) + if err != nil || orderInquiry == nil { + return false, errors.New("订单数据错误") + } + + // 检测订单状态 问诊订单状态(1:待支付 2:待分配 3:待接诊 4:已接诊 5:已完成 6:已结束 7:已取消) + if orderInquiry.InquiryStatus == 6 { + return false, errors.New("订单已结束,无法取消") + } + + if orderInquiry.InquiryStatus == 7 { + return false, errors.New("订单已取消,无法再次取消") + } + + if orderInquiry.InquiryStatus == 1 { + return false, errors.New("订单处于待支付状态,无法取消") + } + + if orderInquiry.InquiryStatus == 2 { + return false, errors.New("订单处于分配状态,无法取消") + } + + if orderInquiry.InquiryStatus == 3 { + return false, errors.New("订单处于等待接诊状态,无法取消") + } + + // 检测订单退款状态 问诊订单退款状态(0:无退款 1:申请退款 2:退款中 3:退款成功 4:拒绝退款 5:退款关闭 6:退款异常) + if orderInquiry.InquiryRefundStatus == 1 { + return false, errors.New("订单申请退款中,无法取消") + } + + if orderInquiry.InquiryRefundStatus == 2 { + return false, errors.New("订单正在退款中,无法取消") + } + + if orderInquiry.InquiryRefundStatus == 3 { + return false, errors.New("订单已退款成功,无法取消") + } + + if orderInquiry.InquiryRefundStatus == 6 { + return false, errors.New("订单退款异常,请联系技术人员") + } + + // 检测支付状态 支付状态(1:未支付 2:已支付 3:支付中 4:支付失败 5:支付超时 6:支付关闭 7:已撤销 8:转入退款) + if orderInquiry.InquiryPayStatus != 2 { + return false, errors.New("订单未支付,无需取消") + } + + // 订单完成时间预留5分钟进行操作 + if !orderInquiry.CompleteTime.IsZero() { + // 计算三天后的时间 + threeDaysLater := orderInquiry.CompleteTime.Add(3 * 24 * time.Hour) + if time.Since(threeDaysLater) > 5*time.Minute { + return false, errors.New("距离订单完成时间不足5分钟,无法取消") + } + } + + // 开始事务 + tx := global.Db.Begin() + defer func() { + if r := recover(); r != nil { + tx.Rollback() + } + }() + + // 问诊订单修改数据 + orderInquiryData := make(map[string]interface{}) + + // 发起退款 + if orderInquiry.PaymentAmountTotal > 0 { + // 退款编号 + inquiryRefundNo := strconv.FormatInt(global.Snowflake.Generate().Int64(), 10) + + refundRequest := weChat.RefundRequest{ + TransactionId: orderInquiry.EscrowTradeNo, + OutTradeNo: orderInquiry.InquiryNo, + OutRefundNo: inquiryRefundNo, + Reason: "客服取消", + PaymentAmountTotal: int64(orderInquiry.PaymentAmountTotal * 100), + NotifyUrl: "https://dev.hospital.applets.igandanyiyuan.com/" + config.C.Wechat.PatientInquiryRefundNotifyUrl, + } + + refund, err := refundRequest.Refund() + if err != nil { + tx.Rollback() + return false, errors.New(err.Error()) + } + + if refund.Status == nil { + tx.Rollback() + return false, errors.New("退款状态错误") + } + + // 退款状态转换 + var inquiryRefundStatus int + var successTime time.Time + + if *refund.Status == "SUCCESS" { + // 退款成功 + inquiryRefundStatus = 3 + + if refund.SuccessTime != nil { + // 使用 time.Parse 解析时间字符串为 time.Time 类型 + successTime = *refund.SuccessTime + } + } else if *refund.Status == "CLOSED" { + // 退款关闭 + inquiryRefundStatus = 5 + } else if *refund.Status == "PROCESSING" { + // 退款处理中 + inquiryRefundStatus = 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("缺少退款订单编号") + } + + // 新增退款表 + orderInquiryRefundDao := dao.OrderInquiryRefundDao{} + + orderInquiryRefund := &model.OrderInquiryRefund{ + PatientId: orderInquiry.PatientId, + OrderInquiryId: orderInquiryId, + InquiryNo: orderInquiry.InquiryNo, + InquiryRefundNo: inquiryRefundNo, + RefundId: *refund.RefundId, + InquiryRefundStatus: inquiryRefundStatus, + RefundTotal: orderInquiry.PaymentAmountTotal, + RefundReason: "客服取消", + SuccessTime: successTime, + } + orderInquiryRefund, err = orderInquiryRefundDao.AddOrderInquiryRefund(tx, orderInquiryRefund) + if err != nil || orderInquiryRefund == nil { + tx.Rollback() + return false, errors.New(err.Error()) + } + } + + orderInquiryData["inquiry_status"] = 7 // 问诊订单状态(1:待支付 2:待分配 3:待接诊 4:已接诊 5:已完成 6:已结束 7:已取消) + orderInquiryData["cancel_time"] = time.Now().Format("2006-01-02 15:04:05") // 订单取消时间 + orderInquiryData["cancel_reason"] = 4 // 取消订单原因(1:医生未接诊 2:主动取消 3:无可分配医生 4:客服取消 5:支付超时) + orderInquiryData["cancel_remarks"] = "客服取消" // 取消订单备注(自动添加) + + // 修改问诊订单退款状态 + err = orderInquiryDao.EditOrderInquiryById(tx, orderInquiryId, orderInquiryData) + if err != nil { + tx.Rollback() + return false, errors.New("取消订单失败") + } + + tx.Commit() + + return true, nil +} diff --git a/config.yaml b/config.yaml index a0128ed..3593c94 100644 --- a/config.yaml +++ b/config.yaml @@ -55,4 +55,20 @@ im: # [阿里大鱼短信] dysms: dysms-access-key: LTAI4GGygjsKhyBwvvC3CghV - dysms-access-secret: rcx7lO9kQxG10m8NqNPEfEtT9IS8EI \ No newline at end of file + dysms-access-secret: rcx7lO9kQxG10m8NqNPEfEtT9IS8EI + +# [微信] +wechat: + patient-app-id: wx70a196902e0841b6 + patient-app-secret: 2671d2f4285180ddec5a5a2b16ed50f2 + patient-inquiry-pay-notify-url: callback/wxpay/inquiry/success + patient-inquiry-refund-notify-url: callback/wxpay/inquiry/refund + patient-product-pay-notify-url: callback/wxpay/product/success + 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 + doctor-app-id: wxc83296720404aa7b + doctor-app-secret: 817665d3763637fe66d56548f8484622 + mch-id: 1636644248 + v3-api-secret: gdxz292sjSOadN3m2pCda03NfCsmNadY + mch-certificate-serial-number: 7DEC0E6C57E0DC71F077F02F52406566AF39BEBB \ No newline at end of file diff --git a/config/config.go b/config/config.go index 4ed9b2e..23e0b19 100644 --- a/config/config.go +++ b/config/config.go @@ -14,4 +14,5 @@ type Config struct { CaOnline CaOnline `mapstructure:"ca-online" json:"ca-online" yaml:"ca-online"` Im Im `mapstructure:"im" json:"im" yaml:"im"` Dysms Dysms `mapstructure:"dysms" json:"dysms" yaml:"dysms"` + Wechat Wechat `mapstructure:"wechat" json:"wechat" yaml:"wechat"` } diff --git a/config/wechat.go b/config/wechat.go new file mode 100644 index 0000000..0c9d728 --- /dev/null +++ b/config/wechat.go @@ -0,0 +1,17 @@ +package config + +type Wechat struct { + PatientAppId string `mapstructure:"patient-app-id" json:"patient-app-id" yaml:"patient-app-id"` + PatientAppSecret string `mapstructure:"patient-app-secret" json:"patient-app-secret" yaml:"patient-app-secret"` + PatientInquiryPayNotifyUrl string `mapstructure:"patient-inquiry-pay-notify-url" json:"patient-inquiry-pay-notify-url" yaml:"patient-inquiry-pay-notify-url"` + PatientInquiryRefundNotifyUrl string `mapstructure:"patient-inquiry-refund-notify-url" json:"patient-inquiry-refund-notify-url" yaml:"patient-inquiry-refund-notify-url"` + PatientProductPayNotifyUrl string `mapstructure:"patient-product-pay-notify-url" json:"patient-product-pay-notify-url" yaml:"patient-product-pay-notify-url"` + 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"` + 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"` + MchId string `mapstructure:"mch-id" json:"mch-id" yaml:"mch-id"` // 商户号 + V3ApiSecret string `mapstructure:"v3-api-secret" json:"v3-api-secret" yaml:"v3-api-secret"` // 商户APIv3密钥 + MchCertificateSerialNumber string `mapstructure:"mch-certificate-serial-number" json:"mch-certificate-serial-number" yaml:"mch-certificate-serial-number"` // 商户证书序列号 +} diff --git a/extend/weChat/certs/1636644248/apiclient_cert.p12 b/extend/weChat/certs/1636644248/apiclient_cert.p12 new file mode 100644 index 0000000000000000000000000000000000000000..b5df8dd0b102f01e9cd6f8ad3eccced2874cdfb1 GIT binary patch literal 2774 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 P2WC~6nh_J`-!%Uh$j=r| literal 0 HcmV?d00001 diff --git a/extend/weChat/certs/1636644248/apiclient_cert.pem b/extend/weChat/certs/1636644248/apiclient_cert.pem new file mode 100644 index 0000000..101b476 --- /dev/null +++ b/extend/weChat/certs/1636644248/apiclient_cert.pem @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIELjCCAxagAwIBAgIUfewObFfg3HHwd/AvUkBlZq85vrswDQYJKoZIhvcNAQEL +BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT +FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg +Q0EwHhcNMjMwMzAxMDExNzE3WhcNMjgwMjI4MDExNzE3WjCBhzETMBEGA1UEAwwK +MTYzNjY0NDI0ODEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMTMwMQYDVQQL +DCrljJfkuqzmrKPmrKPnm7jnhaflgaXlurfnp5HmioDmnInpmZDlhazlj7gxCzAJ +BgNVBAYMAkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAK7x9ywApasrs+xIt0XxHhYOK4xZeuNEj5o7pzTcZMRkd6CB +1eX2ydlUfDe+FcNS03cwLNtUeAfrZXlhA807b4HuReaFqCrbt87hfIF/lOBpePdN +sSr8Wi6OKfPakuLNZ4RCOdlvgxPMhOf2b9VFQwns8h72H6JrFz7xR+Heundy3KGH +kEoG2qcl7nKyhkUVSRSH4/yzsxsDIwkpXjEiSL87E+A6GKik7jphYc+vfV9NURiA +JwbVWbQMhpj3YLRxgXadLS4xMryB59fYKm+VFMNg/jSZG55Jz2DW02aR2h3KjegY +SGA9qMKojkFVOrZvxKWOvtEWw2JQ/1dRvzYpgw0CAwEAAaOBuTCBtjAJBgNVHRME +AjAAMAsGA1UdDwQEAwID+DCBmwYDVR0fBIGTMIGQMIGNoIGKoIGHhoGEaHR0cDov +L2V2Y2EuaXRydXMuY29tLmNuL3B1YmxpYy9pdHJ1c2NybD9DQT0xQkQ0MjIwRTUw +REJDMDRCMDZBRDM5NzU0OTg0NkMwMUMzRThFQkQyJnNnPUhBQ0M0NzFCNjU0MjJF +MTJCMjdBOUQzM0E4N0FEMUNERjU5MjZFMTQwMzcxMA0GCSqGSIb3DQEBCwUAA4IB +AQCBjjBeJTRtnsIISCfoQ7pj70dil5LTBNjpzV9swGOG7sY9dTMbHV0K2BUyRvbD +eY2fuCcr3Qt3L1RykyomKbxD4O6b/ZPLTkiq2m+hq34g2Ig7zUx0a0sNKf/NPAq6 +6pVu5/XdIKYXz2OsByBI8aN2hkcUApmM1qlm+gb4FSmTzkdHaFRblhDlKfiRdAw8 +T4yliaOFovqhf/S8o5Xa76kQMOb3uJ/oE4KX02kp/ig5wZKj9nay46AyovBXOj+Z +0oaeIPFDXCPzZV7LA4E45zDl43fL8r+9OzaVprRZ9ASO0cgnPsHyS+o/mpMEBOR4 +NIwdIaqYRQ/Rh6eZQvrqDZ4r +-----END CERTIFICATE----- diff --git a/extend/weChat/certs/1636644248/apiclient_key.pem b/extend/weChat/certs/1636644248/apiclient_key.pem new file mode 100644 index 0000000..8e9da3d --- /dev/null +++ b/extend/weChat/certs/1636644248/apiclient_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCu8fcsAKWrK7Ps +SLdF8R4WDiuMWXrjRI+aO6c03GTEZHeggdXl9snZVHw3vhXDUtN3MCzbVHgH62V5 +YQPNO2+B7kXmhagq27fO4XyBf5TgaXj3TbEq/Foujinz2pLizWeEQjnZb4MTzITn +9m/VRUMJ7PIe9h+iaxc+8Ufh3rp3ctyhh5BKBtqnJe5ysoZFFUkUh+P8s7MbAyMJ +KV4xIki/OxPgOhiopO46YWHPr31fTVEYgCcG1Vm0DIaY92C0cYF2nS0uMTK8gefX +2CpvlRTDYP40mRueSc9g1tNmkdodyo3oGEhgPajCqI5BVTq2b8Sljr7RFsNiUP9X +Ub82KYMNAgMBAAECggEAT7uNyGs/FkVjykPV67WZ3bl1lZDOljgQLt4TNd9gubWE +ZA3om9efZULBHnKu3oeoQ0EcoJXd4tYhOHHD1szI5HHhP9AYtffPzSUtpqOsCZ9o +d2XcYlgDDgbTDgXHPkEZdcjtLrFJD0P+Ku5BR/U6OZLZQs0v28ltHc2/0iy91WQt +iB/NSf88dY1L5RVZc7dZfb8nFB2/BsITUXDFJpzdim3AXKvNYzDajs/yuoTp5r/b +2EOjUIGPP55W/8iPwbezgDToF79toum6V7yUpCq5P+QQvnnbJfoc1yXB48zHjmgP +I2P1cDVtFs+V9Edb6qsU3e4CMyBQg5Uykk3TUqZRIQKBgQDnXgGk8XnI1kG9jZMR +wMkra87Dx76vrBdM47n+c2I1xubM9WSeSUxtXGyryTwJ9i6/BUyc3Eyb2wi4Q8AK +1ZIEFhvIUkBJpUgevAksj4eX6z0qDwDc3ZhgAAWOplnOCCyJuOBKmZks4GaQb4Gv +/aSFVQ9jefOc5e9RIDNzkHFkaQKBgQDBkigvmusjad95Jt34TwyE4Dr9z2LzBker +6ebcyQmv4YdKvq0KaaVMrroH7pNu7CSFrj4CGqdS/Gg1BtK8Xaxn+gEWT6RPcsi1 +mPwy/7oiK0GodzNI6RW5HDZEHKG2icEb4ycDnHeLfThKmP/gckPifjcJHrP5OX1A +V6qrq4iFBQKBgGdgB1gNVJ65rJHnCckq3Dd8advsCXUwbRC7x0S7hSwF/OWi1xwq +H+3VF/EBbsP8rRJIadzESa5xhUnfa5Trq9wLjMpKhdLh+IFS/r5cOvdT8fYy0e3d +TNHH8LO1+/YkjNHUOtLaIih88xah284ohDPWt5N4z7JQwkb7HkIKTb/RAoGARt51 +7Afx8sM+WCLMva5jTPqzXl1hQsyXzO8T4N2RuFz/pXPt8pP/OvX1khXc0I2QSYkj +lq2feRiEJnXbDa/WATNc1ohOBfBmX2YlX56UzRG9Nip+EkGT/HPBwmohIq2Ij+c4 +T3AnrGAqDdW6SLhM9k1zZNli1uofW0E9cSCaGOkCgYAI29eelAwUxpbDXJB6vSyr +LBvDV+C+/3OW4AjlJ5lWSzY8oMn21Xzp03MwXOXOSFuR6vTMkJDKJ3zIDHBt9vJ2 +evNmfMKzqNdsvNjORb79GAZ0paBF1XGzXvPO9JSUi6oZxNg+pW8oxIzx0xFIgtZL +PxnzFj2IbraxYwuR1CI6rQ== +-----END PRIVATE KEY----- diff --git a/extend/weChat/certs/1636644248/wechatpay_112FCCD1B9ECC8292703AB7363C73D74B6AFDC1A.pem b/extend/weChat/certs/1636644248/wechatpay_112FCCD1B9ECC8292703AB7363C73D74B6AFDC1A.pem new file mode 100644 index 0000000..ab18f68 --- /dev/null +++ b/extend/weChat/certs/1636644248/wechatpay_112FCCD1B9ECC8292703AB7363C73D74B6AFDC1A.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEFDCCAvygAwIBAgIUES/M0bnsyCknA6tzY8c9dLav3BowDQYJKoZIhvcNAQEL +BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT +FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg +Q0EwHhcNMjMwMzAxMDExNzE2WhcNMjgwMjI4MDExNzE2WjBuMRgwFgYDVQQDDA9U +ZW5wYXkuY29tIHNpZ24xEzARBgNVBAoMClRlbnBheS5jb20xHTAbBgNVBAsMFFRl +bnBheS5jb20gQ0EgQ2VudGVyMQswCQYDVQQGDAJDTjERMA8GA1UEBwwIU2hlblpo +ZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvM2YfnzwBvd+B5Ro1 +z+LaCVYhxia9/hQwRhi5ag2HmeZZNgMNf4+bC75Nv+t3RW0lklbM9qJSBk03eEBG +75Q33VPGy//WCJZgXlHV+rZ7ejzWtwh9Muhd60HFXhIsM3pwlfWpPo6bkJie9Na0 +wMsgg/8UxsNydhEZF6HFLdqY+zqGOjRRCduIyJcFhtrkjNUMIFAOSkHBaGJjmGrm +OXigAnYAsaD1VWLOoblA0HlOs144KQ/5Shj74Ggk2pFo/YDN+i5hazHZo9hZnjmX +G5BV3KDJD0k3Gn/qymhiLlzGsYW79P+BbsmE/M6jKIP2jxcDDdpek0Z6Lk0Cz/au +02UPAgMBAAGjgbkwgbYwCQYDVR0TBAIwADALBgNVHQ8EBAMCA/gwgZsGA1UdHwSB +kzCBkDCBjaCBiqCBh4aBhGh0dHA6Ly9ldmNhLml0cnVzLmNvbS5jbi9wdWJsaWMv +aXRydXNjcmw/Q0E9MUJENDIyMEU1MERCQzA0QjA2QUQzOTc1NDk4NDZDMDFDM0U4 +RUJEMiZzZz1IQUNDNDcxQjY1NDIyRTEyQjI3QTlEMzNBODdBRDFDREY1OTI2RTE0 +MDM3MTANBgkqhkiG9w0BAQsFAAOCAQEAJX6C/QMYF0F3IiK9P8tW2DKN8y9vCU20 +6Ws8u4bcO3AaiSmsdAJ6I1MyZkUg3dKijtnDbieY2P364IEp48TmI4k6UJwP4+/f +i0NseOm3BmAJ3mBoNmuFul+61opKpeV67AYQuhbehVA4cDPqKb/hP0tEcb6nefIO +mnys5GReLWLFV2XFR1h9QtsohPOEYlpBl6lmKHNoQZdAPtSHq2iVFLbuD7GMKoj7 +Br2puJEQgxla1AsNxAYjGttEIO9I30+L5av7SKesSGXvL6G5eOvFrZl0S4EsNVz4 +QeL4qmtFEKDi2eaxeyLuWe9TMI/IiI3ngekoDyTwdnUzadumbio+dg== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/extend/weChat/weChatPay.go b/extend/weChat/weChatPay.go new file mode 100644 index 0000000..d3a4d8f --- /dev/null +++ b/extend/weChat/weChatPay.go @@ -0,0 +1,63 @@ +package weChat + +import ( + "context" + "errors" + "github.com/wechatpay-apiv3/wechatpay-go/core" + "github.com/wechatpay-apiv3/wechatpay-go/core/option" + "github.com/wechatpay-apiv3/wechatpay-go/services/refunddomestic" + "github.com/wechatpay-apiv3/wechatpay-go/utils" + "hospital-admin-api/config" + "path/filepath" +) + +type RefundRequest struct { + TransactionId string `json:"transaction_id" comment:"微信订单号"` + OutTradeNo string `json:"out_trade_no" comment:"商户订单号"` + OutRefundNo string `json:"out_refund_no" comment:"退款订单号"` + Reason string `json:"reason" comment:"退款原因"` + PaymentAmountTotal int64 `json:"payment_amount_total" comment:"退款金额"` + NotifyUrl string `json:"notify_url" comment:"回调地址"` +} + +// Refund 退款 +func (r RefundRequest) Refund() (*refunddomestic.Refund, error) { + // 使用 utils 提供的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名 + certsDir := filepath.Join("extend/weChat/certs", "/1636644248/apiclient_key.pem") + mchPrivateKey, err := utils.LoadPrivateKeyWithPath(certsDir) + if err != nil { + return nil, errors.New("微信签名生成失败") + } + + ctx := context.Background() + // 使用商户私钥等初始化 client,并使它具有自动定时获取微信支付平台证书的能力 + opts := []core.ClientOption{ + option.WithWechatPayAutoAuthCipher(config.C.Wechat.MchId, config.C.Wechat.MchCertificateSerialNumber, mchPrivateKey, config.C.Wechat.V3ApiSecret), + } + + client, err := core.NewClient(ctx, opts...) + if err != nil { + return nil, errors.New(err.Error()) + } + + refundRequest := refunddomestic.CreateRequest{ + TransactionId: core.String(r.TransactionId), + OutTradeNo: core.String(r.OutTradeNo), + OutRefundNo: core.String(r.OutRefundNo), + Reason: core.String(r.Reason), + NotifyUrl: core.String(r.NotifyUrl), + Amount: &refunddomestic.AmountReq{ + Currency: core.String("CNY"), + Refund: core.Int64(r.PaymentAmountTotal), + Total: core.Int64(r.PaymentAmountTotal), + }, + } + + svc := refunddomestic.RefundsApiService{Client: client} + resp, _, err := svc.Create(ctx, refundRequest) + if err != nil { + return nil, errors.New(err.Error()) + } + + return resp, nil +} diff --git a/go.mod b/go.mod index 952e7a9..a85baac 100644 --- a/go.mod +++ b/go.mod @@ -80,6 +80,7 @@ require ( github.com/tjfoc/gmsm v1.3.2 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect + github.com/wechatpay-apiv3/wechatpay-go v0.2.17 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/crypto v0.9.0 // indirect golang.org/x/image v0.7.0 // indirect diff --git a/go.sum b/go.sum index d90211a..d1baaa5 100644 --- a/go.sum +++ b/go.sum @@ -38,6 +38,7 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/agiledragon/gomonkey v2.0.2+incompatible/go.mod h1:2NGfXu1a80LLr2cmWXGBDaHEjb1idR6+FVlX5T3D9hw= github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 h1:iC9YFYKDGEy3n/FtqJnOkZsene9olVspKmkX5A2YBEo= github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc= github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.2/go.mod h1:5JHVmnHvGzR2wNdgaW1zDLQG8kOC4Uec8ubkMogW7OQ= @@ -333,6 +334,8 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/wechatpay-apiv3/wechatpay-go v0.2.17 h1:i4YJA/6BqAbi2YfyPZBjpeEeO/+oa4UbKP4gSTRhhQg= +github.com/wechatpay-apiv3/wechatpay-go v0.2.17/go.mod h1:A254AUBVB6R+EqQFo3yTgeh7HtyqRRtN2w9hQSOrd4Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=