diff --git a/api/controller/base.go b/api/controller/base.go index 7c9e501..5eb14b5 100644 --- a/api/controller/base.go +++ b/api/controller/base.go @@ -35,6 +35,7 @@ type basic struct { // 订单管理 type order struct { + Order // 订单 OrderInquiry // 问诊订单 OrderProduct // 药品订单 } diff --git a/api/controller/order.go b/api/controller/order.go new file mode 100644 index 0000000..63ae910 --- /dev/null +++ b/api/controller/order.go @@ -0,0 +1,18 @@ +package controller + +import ( + "fmt" + "github.com/gin-gonic/gin" + "hospital-admin-api/api/responses" + "hospital-admin-api/extend/prescription" +) + +type Order struct{} + +func (r *Order) ReportPreOrder(c *gin.Context) { + token, err := prescription.NoticePreOrderCancel("124") + if err != nil { + responses.OkWithData(err.Error(), c) + } + fmt.Println(token) +} diff --git a/api/middlewares/jwt.go b/api/middlewares/jwt.go index 288e479..1e6d38d 100644 --- a/api/middlewares/jwt.go +++ b/api/middlewares/jwt.go @@ -1,7 +1,6 @@ package middlewares import ( - "fmt" "github.com/gin-gonic/gin" "hospital-admin-api/consts" "hospital-admin-api/global" @@ -30,8 +29,6 @@ func Jwt() gin.HandlerFunc { // 检测是否存在黑名单 res, _ := global.Redis.Get(c, "jwt_black_"+authorization).Result() - - fmt.Println(res) if res != "" { c.JSON(http.StatusOK, gin.H{ "message": "token错误/过期", diff --git a/api/router/router.go b/api/router/router.go index da3e062..bda8039 100644 --- a/api/router/router.go +++ b/api/router/router.go @@ -386,5 +386,14 @@ func privateRouter(r *gin.Engine, api controller.Api) { // 取消药品订单 productGroup.PUT("/cancel/:order_product_id", api.OrderProduct.CancelOrderProduct) } + + // 上报数据 + reportGroup := orderGroup.Group("/report") + { + // 上报处方平台 + reportGroup.POST("/pre/:order_product_id", api.Order.ReportPreOrder) + + // 上报监管平台 + } } } diff --git a/api/service/order.go b/api/service/order.go new file mode 100644 index 0000000..9dfc2c6 --- /dev/null +++ b/api/service/order.go @@ -0,0 +1,6 @@ +package service + +// ReportPreProduct 商品订单上报处方平台 +func ReportPreProduct() { + +} diff --git a/api/service/orderProduct.go b/api/service/orderProduct.go index 0502c79..ccfe730 100644 --- a/api/service/orderProduct.go +++ b/api/service/orderProduct.go @@ -8,6 +8,7 @@ import ( "hospital-admin-api/api/requests" "hospital-admin-api/api/responses/orderProductResponse" "hospital-admin-api/config" + "hospital-admin-api/extend/prescription" "hospital-admin-api/extend/weChat" "hospital-admin-api/global" "strconv" @@ -142,11 +143,6 @@ func (r *OrderProductService) CancelOrderProduct(req requests.CancelOrderProduct return false, errors.New("订单已取消,无法取消") } - // 已上报暂不允许取消订单 - if orderProduct.ReportPreStatus == 1 { - return false, errors.New("订单已上报,暂不允许取消") - } - // 检测订单退款状态 if orderProduct.RefundStatus == 1 { return false, errors.New("订单申请退款中,无法取消") @@ -188,6 +184,14 @@ func (r *OrderProductService) CancelOrderProduct(req requests.CancelOrderProduct var successTime time.Time var refundId string + // 通知处方平台订单取消 + _, err = prescription.NoticePreOrderCancel(orderProduct.OrderProductNo) + if err != nil { + tx.Rollback() + return false, errors.New("取消订单失败") + } + + // 微信退款 refundRequest := weChat.RefundRequest{ TransactionId: orderProduct.EscrowTradeNo, OutTradeNo: orderProduct.OrderProductNo, @@ -240,13 +244,12 @@ func (r *OrderProductService) CancelOrderProduct(req requests.CancelOrderProduct // 退款编号 refundId = *refund.RefundId + // 修改问诊订单退款状态 orderProductData["refund_status"] = refundStatus orderProductData["order_product_status"] = 5 // 订单状态(1:待支付 2:待发货 3:已发货 4:已签收 5:已取消) orderProductData["cancel_time"] = time.Now().Format("2006-01-02 15:04:05") // 订单取消时间 orderProductData["cancel_reason"] = 4 // 订单取消原因(1:主动取消 2:复核失败/库存不足 3:支付超时 4:客服取消) orderProductData["cancel_remarks"] = req.CancelRemarks // 取消订单备注(自动添加) - - // 修改问诊订单退款状态 err = orderProductDao.EditOrderProductById(tx, orderProductId, orderProductData) if err != nil { tx.Rollback() diff --git a/config.yaml b/config.yaml index 601a5a0..a85ae80 100644 --- a/config.yaml +++ b/config.yaml @@ -72,4 +72,11 @@ wechat: doctor-app-secret: 817665d3763637fe66d56548f8484622 mch-id: 1636644248 v3-api-secret: gdxz292sjSOadN3m2pCda03NfCsmNadY - mch-certificate-serial-number: 7DEC0E6C57E0DC71F077F02F52406566AF39BEBB \ No newline at end of file + mch-certificate-serial-number: 7DEC0E6C57E0DC71F077F02F52406566AF39BEBB + +# [处方平台] +pre: + pre-plat-client-id: ZD-004 + pre-plat-client-secret: 0baa5927164710b9f800bf33546b6da3 + pre-plat-app-url: http://49.233.3.200:6304/api/thridapi/ + pre-plat-pharmacy-code: ZD-10003 \ No newline at end of file diff --git a/config/config.go b/config/config.go index 23e0b19..1d6ead0 100644 --- a/config/config.go +++ b/config/config.go @@ -15,4 +15,5 @@ type Config struct { Im Im `mapstructure:"im" json:"im" yaml:"im"` Dysms Dysms `mapstructure:"dysms" json:"dysms" yaml:"dysms"` Wechat Wechat `mapstructure:"wechat" json:"wechat" yaml:"wechat"` + Pre Pre `mapstructure:"pre" json:"pre" yaml:"pre"` // 处方平台 } diff --git a/config/pre.go b/config/pre.go new file mode 100644 index 0000000..9a048e0 --- /dev/null +++ b/config/pre.go @@ -0,0 +1,8 @@ +package config + +type Pre struct { + PrePlatClientId string `mapstructure:"pre-plat-client-id" json:"pre-plat-client-id" yaml:"pre-plat-client-id"` + PrePlatClientSecret string `mapstructure:"pre-plat-client-secret" json:"pre-plat-client-secret" yaml:"pre-plat-client-secret"` + PrePlatAppUrl string `mapstructure:"pre-plat-app-url" json:"pre-plat-app-url" yaml:"pre-plat-app-url"` + PrePlatPharmacyCode string `mapstructure:"pre-plat-pharmacy-code" json:"pre-plat-pharmacy-code" yaml:"pre-plat-pharmacy-code"` +} diff --git a/extend/ca/ca.go b/extend/ca/ca.go index 3c0d919..e9845a3 100644 --- a/extend/ca/ca.go +++ b/extend/ca/ca.go @@ -6,7 +6,6 @@ import ( "encoding/hex" "encoding/json" "errors" - "fmt" "hospital-admin-api/config" "io" "net/http" @@ -79,6 +78,7 @@ func postRequest(requestUrl string, formData url.Values, signature string) (map[ if resp.StatusCode != 200 { return nil, errors.New("请求失败") } + // 读取响应内容 respBody, err := io.ReadAll(resp.Body) if err != nil { @@ -108,7 +108,6 @@ func postRequest(requestUrl string, formData url.Values, signature string) (map[ } } - fmt.Println(body) if len(body) == 0 { return nil, nil } diff --git a/extend/prescription/prescription.go b/extend/prescription/prescription.go new file mode 100644 index 0000000..06d33c9 --- /dev/null +++ b/extend/prescription/prescription.go @@ -0,0 +1,329 @@ +// Package prescription 处方平台 +package prescription + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "hospital-admin-api/config" + "hospital-admin-api/global" + "io" + "net/http" + "time" +) + +// 获取token请求值 +type getTokeRequest struct { + ClientId string `json:"clientId"` + ClientSecret string `json:"clientSecret"` +} + +// 通知处方平台订单取消 +type noticePreOrderCancelRequest struct { + OrgCode string `json:"orgCode"` // 机构编码 + OrderNo string `json:"orderNo"` // 院内订单编号 + OptCode string `json:"optCode"` // 操作状态 +} + +// 通知处方平台订单取消返回数据 +type noticePreOrderCancelResponse struct { + ResultCode string `json:"resultCode"` // 操作编码 + ResultDesc string `json:"resultDesc"` // 描述 +} + +// ReportPreRequest 上报处方请求值 +type ReportPreRequest struct { + TerminalCode string `json:"terminalCode"` // 终端代码 + OrderNo string `json:"orderNo"` // 订单编号 + TransactNo string `json:"transactNo"` // 流水单号 + PayDate string `json:"payDate"` // 支付时间 + Money float64 `json:"money"` // 订单金额 + Freight float64 `json:"freight"` // 运费(单位:元) + TakeTypeCode int `json:"takeTypeCode"` // 取货方式 1 自提 2 快递,目前只支持快递,传固定值 2 + BuyerName string `json:"buyerName"` // 收货人姓名 + BuyerPhone string `json:"buyerPhone"` // 收货人联系方式 + BuyerAddress string `json:"buyerAddress"` // 收货人地址 + ProvinceCode string `json:"provinceCode"` // 收货地址(省) 编码 + ProvinceName string `json:"provinceName"` // 收货地址(省) 名称 + CityCode string `json:"cityCode"` // 收货地址(市) 编码 + CityName string `json:"cityName"` // 收货地址(市) 名称 + DistrictCode string `json:"districtCode"` // 收货地址(区 县)编码 + DistrictName string `json:"districtName"` // 收货地址(区 县)名称 + PresList []Pres `json:"presList"` // 处方列表 +} + +// Pres 上报处方请求值 +type Pres struct { + PrescriptionNo string `json:"prescriptionNo"` // 处方编号 + PrescriptionSubType int `json:"prescriptionSubType"` // 处方类型 0:无类型 1:普通处方 2:儿科处方 + PatientName string `json:"patientName"` // 就诊人姓名 + PatientPhone string `json:"patientPhone"` // 就诊人联系方式 + IdCard string `json:"idCard"` // 身份证号 + Advice string `json:"advice"` // 医嘱 + DiagnosisName string `json:"diagnosisName"` // 诊断 + ThirdDoctorName string `json:"thirdDoctorName"` // 开方医生姓名 + ThirdDeptName string `json:"thirdDeptName"` // 开方科室名称 + ThirdDoctorNameImg string `json:"thirdDoctorNameImg"` // 开方医生签名链接 + PrescriptionTime string `json:"prescriptionTime"` // 开方时间 + ThirdFirstPharmacist string `json:"thirdFirstPharmacist"` // 初审药师姓名 + ThirdFirstPharmacistImg string `json:"thirdFirstPharmacistImg"` // 初审药师签名链接 + ThirdFirstTime string `json:"thirdFirstTime"` // 初审时间 + ThirdLastPharmacist string `json:"thirdLastPharmacist"` // 终审药师姓名 + ThirdLastPharmacistImg string `json:"thirdLastPharmacistImg"` // 终审药师签名链接 + ThirdLastTime string `json:"ThirdLastTime"` // 终审时间 + ThirdSignImg string `json:"thirdSignImg"` // 处方签章链接 + ReferenceCharge float64 `json:"referenceCharge"` // 处方费用(不包含运费) + ChiefComplaint string `json:"chiefComplaint"` // 主诉 + HistoryPresent string `json:"historyPresent"` // 现病史 + PastHistory string `json:"pastHistory"` // 既往史 + PhysicalExamination string `json:"physicalExamination"` // 体格检查 + SupplementaryExamination string `json:"supplementaryExamination"` // 辅助检查 + AllergicHistory string `json:"allergicHistory"` // 过敏史 + DrugList []Drug `json:"drugList"` // 药品列表 + OrderDrugList []OrderDrug `json:"orderDrugList"` // 订单药品列表 +} + +// Drug 上报处方请求值 +type Drug struct { + DrugCode string `json:"drugCode"` // 药品编码 + ApprovalNumber string `json:"approvalNumber"` // 批准文号 + DrugName string `json:"drugName"` // 药品名称 + Specifications string `json:"specifications"` // 药品规格 + Price float64 `json:"price"` // 药品单价 + PackingCount int `json:"packingCount"` // 药品数量 + SurplusPackingCount int `json:"surplusPackingCount"` // 处方药品剩余使用数量 + PackingUnit string `json:"packingUnit"` // 药品单位 + SingleDosage int `json:"singleDosage"` // 单次用量 + SingleDosageUnit string `json:"singleDosageUnit"` // 单次用量单位 + UseName string `json:"useName"` // 用法名称 + FrequencyName string `json:"frequencyName"` // 频次名称 + UseDays int `json:"useDays"` // 使用天数 +} + +// OrderDrug 上报处方请求值 +type OrderDrug struct { + DrugCode string `json:"drugCode"` // 药品编码 + ApprovalNumber string `json:"approvalNumber"` // 批准文号 + DrugName string `json:"drugName"` // 药品名称 + Specifications string `json:"specifications"` // 药品规格 + Price float64 `json:"price"` // 药品单价 + DrugCount int `json:"drugCount"` // 药品数量 + PackingUnit string `json:"packingUnit"` // 药品单位 +} + +// 上报处方返回数据 +type reportPreResponse struct { + ResultCode string `json:"resultCode"` // 操作编码 + ResultDesc string `json:"resultDesc"` // 描述 +} + +// GetToken 获取token +func GetToken() (string, error) { + // 准备要发送的 JSON 数据 + requestData := getTokeRequest{ + ClientId: config.C.Pre.PrePlatClientId, + ClientSecret: config.C.Pre.PrePlatClientSecret, + } + + // 将 JSON 数据编码为字节数组 + jsonData, err := json.Marshal(requestData) + if err != nil { + return "", err + } + + // 准备请求体 + requestBody := bytes.NewBuffer(jsonData) + + // 设置请求 URL + url := config.C.Pre.PrePlatAppUrl + "v1/user_thrid/token" + + // 创建 POST 请求 + req, err := http.NewRequest("POST", url, requestBody) + if err != nil { + return "", err + } + + // 设置请求头 + req.Header.Set("Content-Type", "application/json") + + // 发送请求 + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return "", err + } + + defer func(Body io.ReadCloser) { + _ = Body.Close() + }(resp.Body) + + // 检查响应状态码 + if resp.StatusCode != 200 { + return "", errors.New("返回数据错误") + } + + // 读取响应体 + var response map[string]interface{} + err = json.NewDecoder(resp.Body).Decode(&response) + if err != nil { + return "", errors.New("返回数据错误") + } + + // 获取 result 字段 + result, ok := response["data"].(map[string]interface{})["result"].(map[string]interface{}) + if !ok { + return "", errors.New("返回数据错误2") + } + + // 获取 token 值 + token, ok := result["token"].(string) + if !ok { + return "", errors.New("返回数据错误3") + } + + // 添加缓存 + _, err = global.Redis.Set(context.Background(), "prescription_token", token, (60*60*1.5)*time.Second).Result() + if err != nil { + return "", errors.New("添加缓存失败") + } + + return token, nil +} + +// NoticePreOrderCancel 通知处方平台订单取消 +func NoticePreOrderCancel(orderNo string) (bool, error) { + // 准备要发送的 JSON 数据 + data := noticePreOrderCancelRequest{ + OrgCode: config.C.Pre.PrePlatPharmacyCode, + OrderNo: orderNo, + OptCode: "EVTDOD-04", + } + + // 将 JSON 数据编码为字节数组 + jsonData, err := json.Marshal(data) + if err != nil { + return false, err + } + + // 准备请求体 + requestBody := bytes.NewBuffer(jsonData) + + // 设置请求 URL + url := config.C.Pre.PrePlatAppUrl + "v1/preOrder/changeOrderByOrg" + + // 创建 POST 请求 + req, err := http.NewRequest("POST", url, requestBody) + if err != nil { + return false, err + } + + // 设置请求头,指定 Content-Type 为 application/json + req.Header.Set("Content-Type", "application/json") + + token, _ := global.Redis.Get(context.Background(), "prescription_token").Result() + if token == "" { + token, err = GetToken() + if err != nil { + return false, err + } + } + + req.Header.Set("Authorization", "Bearer "+token) + + // 发送请求 + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return false, err + } + + defer func(Body io.ReadCloser) { + _ = Body.Close() + }(resp.Body) + + // 检查响应状态码 + if resp.StatusCode != 200 { + return false, errors.New("返回数据错误") + } + + var response noticePreOrderCancelResponse + err = json.NewDecoder(resp.Body).Decode(&response) + if err != nil { + return false, err + } + + if response.ResultCode != "1000" { + if response.ResultDesc != "" { + return false, errors.New(response.ResultDesc) + } + return false, errors.New("取消处方平台订单失败") + } + + return true, nil +} + +// ReportPre 上报处方 +func (r ReportPreRequest) ReportPre() (bool, error) { + // 将 JSON 数据编码为字节数组 + jsonData, err := json.Marshal(r) + if err != nil { + return false, err + } + + // 准备请求体 + requestBody := bytes.NewBuffer(jsonData) + + // 设置请求 URL + url := config.C.Pre.PrePlatAppUrl + "v1/preOrder/receivePreOrder" + + // 创建 POST 请求 + req, err := http.NewRequest("POST", url, requestBody) + if err != nil { + return false, err + } + + // 设置请求头,指定 Content-Type 为 application/json + req.Header.Set("Content-Type", "application/json") + + token, _ := global.Redis.Get(context.Background(), "prescription_token").Result() + if token == "" { + token, err = GetToken() + if err != nil { + return false, err + } + } + + req.Header.Set("Authorization", "Bearer "+token) + + // 发送请求 + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return false, err + } + + defer func(Body io.ReadCloser) { + _ = Body.Close() + }(resp.Body) + + // 检查响应状态码 + if resp.StatusCode != 200 { + return false, errors.New("返回数据错误") + } + + var response reportPreResponse + err = json.NewDecoder(resp.Body).Decode(&response) + if err != nil { + return false, err + } + + if response.ResultCode != "1000" { + if response.ResultDesc != "" { + return false, errors.New(response.ResultDesc) + } + return false, errors.New("上报处方平台失败") + } + + return true, nil +}