Merge branch 'jihan_0920_护理服务、商城、积分兑换、在线问诊功能分支' into dev_gy_0920

# Conflicts:
#	xinelu-familydoctor/src/main/java/com/xinelu/familydoctor/applet/service/impl/ResidentPatientInfoServiceImpl.java
#	xinelu-nurse-manage/src/main/java/com/xinelu/manage/domain/orderevaluateinfo/OrderEvaluateInfo.java
#	xinelu-nurse-manage/src/main/resources/mapper/manage/orderevaluateinfo/OrderEvaluateInfoMapper.xml
This commit is contained in:
mengkuiliang 2023-10-17 16:33:42 +08:00
commit faf39a056b
104 changed files with 7832 additions and 978 deletions

View File

@ -36,6 +36,7 @@
<lombok.version>1.18.4</lombok.version>
<knife4j.version>3.0.3</knife4j.version>
<simple-xml.version>2.7.1</simple-xml.version>
<wechatpay-apiv3.version>0.4.4</wechatpay-apiv3.version>
</properties>
<!-- 依赖声明 -->
@ -235,6 +236,13 @@
<artifactId>simple-xml</artifactId>
<version>${simple-xml.version}</version>
</dependency>
<!-- 微信支付SDK -->
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-apache-httpclient</artifactId>
<version>${wechatpay-apiv3.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

View File

@ -243,7 +243,7 @@ xss:
# 过滤开关
enabled: true
# 排除链接(多个用逗号分隔)
excludes: /system/notice
excludes: /system/notice,/system/station/add,/system/station/edit,/system/stationItem/add,/system/stationItem/edit,/system/operateGoodInfo/add,/system/operateGoodInfo/edit,/system/goodsInfo/add,/system/goodsInfo/edit,/system/hospital/add,/system/hospital/edit,/system/informationInfo/add,/system/informationInfo/edit,/system/trainingItem/edit,/system/trainingItem/add
# 匹配链接
urlPatterns: /system/*,/monitor/*,/tool/*
@ -276,21 +276,6 @@ applet-chat-config:
# 微信小程序事件回调消息加密密钥
encoding-aes-key: 5rbyhMBpdnxTEVT54zeHMNcXi3ccilQZ209QqGi89EW
# 护理员微信小程序参数配置信息
nurse-applet-chat-config:
# 微信小程序idwxa4f2b43d2ccb9908
applet-id: wxa4f2b43d2ccb9908
# 微信小程序密钥,
secret: faeba9fc043cfdcb088f43be1747e054
# 微信小程序返回国家语言
lang: zh_CN
# 微信小程序授权类型
grant-type: authorization_code
# 微信小程序事件回调令牌
token: Yw3vfW1ILpc34qAVDtTpB2hesAMCpvW0
# 微信小程序事件回调消息加密密钥
encoding-aes-key: Lr2uq0F3ds36ZA4AUv1h3Pki0JO1Ql0QeG0z1r4A3at
# 小程序首页路径
applet-page-config:
# 首页跳转路径
@ -305,3 +290,37 @@ applet-page-config:
integral-page-url: pages/integral/integral
# 护理结构详情页面跳转路径
nursestation-details-page-url: pages/nursestation/nursestation
# 新医路微信商户号配置参数
xyl-we-chat-config:
xyl-mch-id: 1633348407
xyl-mch-serial-no: 7C6A18FC8E1F0445901B1BE1C4DD1ACE284C3D79
xyl-private-key-path: xinyilu_apiclient_key.pem
xyl-payment-key: Xyl699003981qazVFR4xsw23edcASDFG
xyl-wechat-notify-url: https://1608.xinelu.cn
# 医路优品微信商户号配置参数
ylyp-we-chat-config:
ylyp-mch-id: 1633506981
ylyp-mch-serial-no: 7840E8CE4B9B1F0F19D5DD2AB7BC159E007F9D90
ylyp-private-key-path: yiluyoupin_apiclient_key.pem
ylyp-payment-key: Xyk699003981qazxsw23edcvfr4bgt56
ylyp-we-chat-notify-url: https://1608.xinelu.cn
# 微信支付接口地址包含小程序和App支付接口地址
we-chat-payment-url-config:
jsapi-palce-order-url: https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi
query-order-no-url: https://api.mch.weixin.qq.com/v3/pay/transactions/id/%s
query-mch-id-url: https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/%s
close-order-url: https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/%s/close
refund-apply-url: https://api.mch.weixin.qq.com/v3/refund/domestic/refunds
refund-query-order-url: https://api.mch.weixin.qq.com/v3/refund/domestic/refunds/%s
trade-apply-bill-url: https://api.mch.weixin.qq.com/v3/bill/tradebill
capital-apply-bill-url: https://api.mch.weixin.qq.com/v3/bill/fundflowbill
app-place-order-url: https://api.mch.weixin.qq.com/v3/pay/transactions/app
# 快递鸟物流查询参数配置
logistics-config:
e-business-id: 1781371
api-key: 998b273d-c926-4659-a9d5-ae0613782d70
express-bird-url: https://api.kdniao.com/Ebusiness/EbusinessOrderHandle.aspx

View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDFgFmuT17PjBIN
B0wSGnchCCsB9ZRZZFpcpvBpO+VLspmTSM//zV621uTzZeWNONEBzwO4C7VCsbHW
gu7R5AQj9FYSzTKdycvs+097qQcQAvMr3VwrX0/dtH2U0iFX6zr3ztDKv2eQBegu
wEcZsoOEgEW1rsjs/t2MTJJLPYWfzDDUbDBJi2hKFzSGAPfpqeOz0+loKNUz/i7V
/dg5TXlbWfe0gdf4SI04sdrUkNsbQKabc7hWoPSVaRnX4ywfgzW8fHaIP+vuTzHr
p7h5dnFNUuA5CdobDnIl0sz+ekLfCFuX4pCYNE6uR/58uknmXW0jfrK/WPU5T+F7
sGDIsuJHAgMBAAECggEADIrkJx+/Q6r/kng+KoAnxJ9CK/OuoiavXmbzqZs2KqKD
AkmDfBlMxIvNKm/0Lg3HqDe/YrbLohqq0paqGAZFBQuFU9hYOJESNFCZcZ8AZdHq
I4UBT3fUGJ5Xw1W87Fpx+j7WH6ocJ5dYcW+glE8z7vw+cRVSiUp+Q2SxfbnAfK9c
anqJLWA8pxkGRcXzE/tcB4JAkPsluWslFPDeKVOZ5/NRs8oE5ppmQKxqx2KFK7rh
S0irhlJ/6t1jiI3t+syYXJILwbutJ9PUFaS1Uu3CErcvmBwWiLRZEkNa7xMlzEk+
R2dplVhT0W++Ku1cjtU4q7V+paea+/YZj3mtos45YQKBgQDsFc4KM8/Lm146dNJX
TOK1pDjZD5rfEpgtHCEm6dBRbueOYjb/D1Lo/JU4L6Yl2fGsJNtTX4a8i38nxTuI
6b+SEQoLinEyr8JQtBFMvU4vYOIiA5oCHaZIXn0WLLFbUBkOhq/dXC4xDT6MOyNd
2rDTSwvLqVE8K8sbupcvRP/RLwKBgQDWKVayVKGHz3cT+YyPhGTD19yBM0w6AGBR
MLNKdKek7/BnKXe009fxDg/gCtGUBmE+umFbEBLStg7zD31JXLm5/LyT2NBkJYRl
neO9UW8tWbnL6DOGgNvQTqDN650Od39R8rVoRSH4H4az6A/B1qrJReyrGw7xDXOz
0eAq9vnKaQKBgH1IDPDJEepAZr6qo7yEJoKxxSEa8NqT6YF2vfkCdvPf4K1kXT75
CMxuzVjloEvR3je1z1XtCXkgpbebKL69HFYNCMGbE/sL3hgplkyc4NKvnRDjzGR3
C3i3+7U6vltwo/tbahQUCMcq+hg8gcYaeV+HIZlQHrXJn5z1ZalF+mMtAoGAKVgZ
sJu+A2X96xFGHX7FpTlLDHZGxPvFnGb2de1HYAQiOQg8X+B108ePMQVlqFoC9AUv
PlFAEQWspSfcXAlWoZ01GqXEtVC42pU8nhPWjr6/q6nMKK8/wFstmBNgYqaXIc7l
TpfqEuijLKAkSpuSpQCmy/GRVN/v8ksWJ7U+S+ECgYB+e/GAdxHOdMGOFbrqZ3Dx
jmPshaFFj/3UEsBZ6lBBTbdlMI7wFrSsqxCe1KGh0yG2GnOXE2useggeJyDVuaEY
7/CNalD9w158WS9Zb7pPOm6QQpKUeIEXvpQbKi6FjKZKaFlUDk2auFT+d1lOga0T
QRowjmcym1p+moKlqdiXGw==
-----END PRIVATE KEY-----

View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC3rkr2Mp+Xb31y
xfTOJPSmjQkG5/Eko6cyJcb8e6fGrrtsPVM9kExpVIor61oWTS1gyKYLwCQ92xmh
qjKtazzd6KvqjKdxFknxxH9R1L+n7LnSEfK2KNaxIL17h2vdXOJatuinX0+7A9Ct
5ZnKb5O5HVctQH0xCca6C6yyuF0q11BFquKyGPVwhqVwQnt+qIeQ/VCKFD5AYf1r
ebkaHwKCg0rbzPFWeZfVI0z3j6M71DLxdIHV40xDn31ygQYlBeuTOUxFvKnri8m+
BalcSUhocS9VAIyuPyDXCAdujm3hKz/WgqVtvgB3OOiIeGVppbgDlW+JWgR7lizM
TzMYfhjPAgMBAAECggEBAJbB6SjVOAO1MEOpklo4Hs0saMJQUK3/3FTeiMnmPDho
ZdBbLR0UeILjLl0J2HEBe0M6rH5sf9J9KDZ2WQ3ZPKXuOFxUgYHiB2L2IoHpmjyb
oZB3xrwYHM5Yzuy6o5+Wgvptsdrd8bTPVtHD50wt9BM1r72mdppvKbq9pksx4tYr
apw4WXfjO2zbdOngY4T5pCk5NZgXrlBfY0/vXsP/3SR+52KXGre/lSt35A4SjNe6
voI1vZLDNlqzRaEZqBC0tLyvMH3NaYpRhwyEHtoABE9AQvVaQNt+fN1qhbhjtVdQ
lR64Dqdc6jjIhuUhs1umYswf2umA3duZox8RTLZo1UECgYEA4oM2gLsX7dVNiDI4
bZsMBdm8cb+N3/npiZBlDL9UL4tWCzLQP8sR/HJH3OZHQ1iLk+7QXi2g0YR5VtNx
tLvECK1+Cd3sGt2zyFcrSpeYAnvbsMqB9F/K3grCCnvzKKmHJS27c9EVGr+sRTbx
6hSqQyEAYTP1yRLnLVmWzkCBXh8CgYEAz5eqFmfou3U7B04tK739HTJGAaHTxVAR
C4u4x0HGUP+NhPKZzySc70vWHoNgyP/QBUgzf5gTEnGCJ7Rk6Y2YZxCLyPksEDFc
meW9ENSOQMwTWM1PAF+XLr4wXbyojMqlI7vWimTMOPK7WMVt4jYCoaN9lBS+McYj
e1ZpB5yEj1ECgYEAiSXLXVxq2604GYvW0L59JBm22OSTwZZuycUs+e/qyDLEcVld
8BJDnKeRTXX8lhFJydNiRHO6GMHuOh0ijrzVsC9jzhOZvpaYIWhuJObuuipGVZ/3
2YAatCCtZm2wR+GFm4Q6KKDi92QwqWPgS8whXy3fLfupCQsyACprfgxeiB8CgYBF
pfjm843d9wMK/GujVWbquMdMHONUO/y8BvDDyYmj+1mb1VlNaldM4gDA1AtQ5KMC
YqsEkB01/udQMvH4eg075w0/LHpgJG+RIsdAMlBX5SBIlvl+gpPSlvTbPkS+l+64
AnmEjTUHlkjNC9BGKSDQ4m1rlVoKkROuedtbNmQzQQKBgQCQdmmWy2Nr9NRmy5+r
3FKymUVGujww+R7IiFGnFiBBhec8hUPaBp1xG5d8XVIcLt6nleOX5ZunXBwTOmp6
XH6tQuup+hjFiNpRLmbVkTv8uQVy5sWEqiGp0i7Jhb+0QEOSEshOr8sQDDAFwWXl
FyCbC1amAeC1i1knzGrNOdppUw==
-----END PRIVATE KEY-----

View File

@ -0,0 +1,23 @@
package com.xinelu.common.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @Description 快递鸟物流接口配置参数类
* @Author 纪寒
* @Date 2022-11-01 13:30:47
* @Version 1.0
*/
@Data
@Component
@ConfigurationProperties(prefix = "logistics-config")
public class LogisticsConfig {
private String eBusinessId;
private String apiKey;
private String expressBirdUrl;
}

View File

@ -1,79 +0,0 @@
package com.xinelu.common.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 护理员小程序配置类
*
* @author ljh
* @version 1.0
* Create by 2023/3/29 15:40
*/
@Data
@Component
@ConfigurationProperties(prefix = "nurse-applet-chat-config")
public class NurseAppletChatConfig {
/**
* 小程序id
*/
private String appletId;
/**
* 小程序secret
*/
private String secret;
/**
* 返回国家地区语言版本zh_CN 简体zh_TW 繁体en 英语
*/
private String lang;
/**
* 授权类型
*/
private String grantType;
/**
* 微信小程序事件回调令牌
*/
private String token;
/**
* 微信小程序事件回调消息加密密钥
*/
private String encodingAesKey;
/**
* 护理站运营人员-服务派单通知-模板id
*/
private String serviceDispatchOperationsTemplateId;
/**
* 护理站运营人员-接单提醒-模板id
*/
private String receivingOrdersOperationsTemplateId;
/**
* 护理站运营人员-师傅拒绝接单通知-模板id
*/
private String refusalOrdersOperationsTemplateId;
/**
* 护理站运营人员和护理员-订单回池通知-模板id
*/
private String overtimeOrdersOperationsTemplateId;
/**
* 护理站运营人员-订单完成通知-模板id
*/
private String orderCompletionOperationsTemplateId;
/**
* 护理员-接单提醒-模板id
*/
private String receivingOrdersNurseTemplateId;
}

View File

@ -0,0 +1,35 @@
package com.xinelu.common.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @Description 微信支付接口地址
* @Author 纪寒
* @Date 2022-10-17 17:56:25
* @Version 1.0
*/
@Component
@Data
@ConfigurationProperties(prefix = "we-chat-payment-url-config")
public class WeChatPaymentUrlConfig {
private String jsapiPalceOrderUrl;
private String queryOrderNoUrl;
private String queryMchIdUrl;
private String closeOrderUrl;
private String refundApplyUrl;
private String refundQueryOrderUrl;
private String tradeApplyBillUrl;
private String capitalApplyBillUrl;
private String appPlaceOrderUrl;
}

View File

@ -0,0 +1,27 @@
package com.xinelu.common.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @Description 新医路商户号微信支付参数配置类
* @Author 纪寒
* @Date 2022-10-17 16:55:04
* @Version 1.0
*/
@Data
@Component
@ConfigurationProperties(prefix = "xyl-we-chat-config")
public class XylWeChatPaymentConfig {
private String xylMchId;
private String xylMchSerialNo;
private String xylPrivateKeyPath;
private String xylPaymentKey;
private String xylWeChatNotifyUrl;
}

View File

@ -0,0 +1,27 @@
package com.xinelu.common.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @Description 医路优品商户号微信支付参数配置类
* @Author 纪寒
* @Date 2022-10-17 16:55:04
* @Version 1.0
*/
@Data
@Component
@ConfigurationProperties(prefix = "ylyp-we-chat-config")
public class YlypWeChatPaymentConfig {
private String ylypMchId;
private String ylypMchSerialNo;
private String ylypPrivateKeyPath;
private String ylypPaymentKey;
private String ylypWeChatNotifyUrl;
}

View File

@ -0,0 +1,29 @@
package com.xinelu.common.enums;
import lombok.Getter;
/**
* @Description 订单来源枚举
* @Author 纪寒
* @Date 2023-10-16
*/
@Getter
public enum OrderSourceEnum {
/**
* 泉医模块
*/
SPRING_DOCTOR("SPRING_DOCTOR"),
/**
* 家医模块
*/
FAMILY_DOCTOR("FAMILY_DOCTOR"),
;
final private String info;
OrderSourceEnum(String info) {
this.info = info;
}
}

View File

@ -0,0 +1,30 @@
package com.xinelu.common.enums;
import lombok.Getter;
/**
* @Description 支付了类型枚举
* @Author 纪寒
* @Date 2022-10-18 15:16:02
* @Version 1.0
*/
@Getter
public enum PayTypeEnum {
/**
* 微信
*/
WECHAT_PAY("WECHAT_PAY"),
/**
* 支付宝
*/
ALI_PAY("ALI_PAY"),
;
final private String info;
PayTypeEnum(String info) {
this.info = info;
}
}

View File

@ -0,0 +1,30 @@
package com.xinelu.common.enums;
import lombok.Getter;
/**
* @Description 支付账户枚举
* @Author 纪寒
* @Date 2022-10-20 17:48:32
* @Version 1.0
*/
@Getter
public enum PaymentMerchantTypeEnum {
/**
* 新医路
*/
XINYILU("XINYILU"),
/**
* 医路优品
*/
YILUYOUPIN("YILUYOUPIN"),
;
final private String info;
PaymentMerchantTypeEnum(String info) {
this.info = info;
}
}

View File

@ -0,0 +1,41 @@
package com.xinelu.common.enums;
import lombok.Getter;
/**
* @Description 微信退款通知枚举
* @Author 纪寒
* @Date 2022-10-25 13:12:03
* @Version 1.0
*/
@Getter
public enum RefundStatusEnum {
/**
* 退款成功
*/
SUCCESS("SUCCESS"),
/**
* 退款关闭
*/
CLOSED("CLOSED"),
/**
* 退款处理中
*/
PROCESSING("PROCESSING"),
/**
* 退款异常退款到银行发现用户的卡作废或者冻结了
* 导致原路退款银行卡失败可前往商户平台>交易中心手动处理此笔退款
*/
ABNORMAL("ABNORMAL"),
;
final private String info;
RefundStatusEnum(String info) {
this.info = info;
}
}

View File

@ -0,0 +1,30 @@
package com.xinelu.common.enums;
import lombok.Getter;
/**
* @Description 退款类型枚举
* @Author 纪寒
* @Date 2022-10-18 15:16:02
* @Version 1.0
*/
@Getter
public enum RefundTypeEnum {
/**
* 微信
*/
WE_CHAT("WE_CHAT"),
/**
* 支付宝
*/
ALI_PAY("ALI_PAY"),
;
final private String info;
RefundTypeEnum(String info) {
this.info = info;
}
}

View File

@ -0,0 +1,52 @@
package com.xinelu.common.enums;
import lombok.Getter;
/**
* 微信支付回调通知状态
*/
@Getter
public enum WeChatTradeStateEnum {
/**
* 支付成功
*/
SUCCESS("SUCCESS"),
/**
* 未支付
*/
NOTPAY("NOTPAY"),
/**
* 已关闭
*/
CLOSED("CLOSED"),
/**
* 转入退款
*/
REFUND("REFUND"),
/**
* 已撤销付款码支付
*/
REVOKED("REVOKED"),
/**
* 用户支付中付款码支付
*/
USERPAYING("USERPAYING"),
/**
* 支付失败(其他原因如银行返回失败)
*/
PAYERROR("PAYERROR")
;
final private String info;
WeChatTradeStateEnum(String info) {
this.info = info;
}
}

View File

@ -16,6 +16,7 @@ import org.apache.http.HttpEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import javax.net.ssl.*;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
@ -253,4 +254,35 @@ public class HttpUtils {
}
return result;
}
/**
* 将通知参数转化为字符串
*
* @param request 请求信息
* @return 请求参数信息
*/
public static String readRequestData(HttpServletRequest request) {
BufferedReader br = null;
try {
StringBuilder result = new StringBuilder();
br = request.getReader();
for (String line; (line = br.readLine()) != null; ) {
if (result.length() > 0) {
result.append("\n");
}
result.append(line);
}
return result.toString();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}

View File

@ -95,5 +95,12 @@ public interface ResidentPatientInfoMapper {
**/
PatientInfo getByCardNo(String cardNo);
int selectPatientInfoByPhone(String phone);
List<PatientInfo> selectPatientInfoByPhone(String phone);
/**
*根据用户编号查询
*
*@param patientCode 用户编号
*@return PatientInfo
**/
PatientInfo getPatientInfoByPatientCode(String patientCode);
}

View File

@ -152,16 +152,18 @@ public class ResidentPatientInfoServiceImpl implements IResidentPatientInfoServi
if (ObjectUtils.isNotEmpty(body.getCardNo())) {
// 修改
if(!StringUtils.isBlank(body.getPatientCode())) {
PatientInfo patientInfo = residentPatientInfoMapper.getByCardNo(body.getCardNo());
BeanUtils.copyBeanProp(patientInfo, body);
if(body.getDiseaseList() != null) {
patientInfo.setDisease(body.getDiseaseList().stream().collect(Collectors.joining(",")));
} else {
patientInfo.setDisease("0");
PatientInfo patientInfo = residentPatientInfoMapper.getPatientInfoByPatientCode(body.getPatientCode());
if (ObjectUtils.isNotEmpty(patientInfo)) {
BeanUtils.copyBeanProp(patientInfo, body);
if (body.getDiseaseList() != null) {
patientInfo.setDisease(body.getDiseaseList().stream().collect(Collectors.joining(",")));
} else {
patientInfo.setDisease("0");
}
patientInfo.setLoginFlag(Long.valueOf(1));
updatePatientInfo(patientInfo);
// 注册
}
patientInfo.setLoginFlag(Long.valueOf(1));
updatePatientInfo(patientInfo);
// 注册
} else {
// 获取当前微信绑定的居民
List<PatientInfo> list = residentPatientInfoMapper.getList(body.getOpenid(), body.getCityCode());
@ -340,12 +342,22 @@ public class ResidentPatientInfoServiceImpl implements IResidentPatientInfoServi
} catch (Exception e) {
throw new ServiceException(e.getMessage());
}
//获取手机号
String code;
String cityCode = "";
AppletPhoneVO phone = getPhone(phoneCode);
String phoneNumber = phone.getPhoneInfo().getPhoneNumber();
HashMap.put("phone",phoneNumber);
code = residentPatientInfoMapper.selectPatientInfoByPhone(phoneNumber) == 0 ? "0" : "1";
List<PatientInfo> infoList = residentPatientInfoMapper.selectPatientInfoByPhone(phoneNumber);
code = infoList.size()== 0 ? "0" : "1";
//返回绑定城市
if ("1".equals(code)){
for (PatientInfo patientInfo : infoList) {
cityCode = patientInfo.getCityCode();
}
}
HashMap.put("code",code);
HashMap.put("cityCode",cityCode);
return HashMap;
}
}

View File

@ -1,7 +1,6 @@
package com.xinelu.familydoctor.applet.utils;
import com.xinelu.common.config.AppletChatConfig;
import com.xinelu.common.config.NurseAppletChatConfig;
import com.xinelu.common.constant.Constants;
import com.xinelu.common.entity.AppletAccessToken;
import com.xinelu.common.exception.ServiceException;
@ -27,8 +26,7 @@ public class AppletAccessTokenUtils {
private RedisTemplate<String, Object> redisTemplate;
@Resource
private AppletChatConfig appletChatConfig;
@Resource
private NurseAppletChatConfig nurseAppletChatConfig;
/**
* 返回成功状态码
*/
@ -65,34 +63,4 @@ public class AppletAccessTokenUtils {
return accessToken;
}
/**
* 护理员小程序获取小程序AccessToken方法
*
* @return 小程序的AccessToken
*/
public String getPersonAppletAccessToken() {
String accessToken;
String accessTokenKey = Constants.NURSE_STATION_PERSON_APPLET_ACCESS_TOKEN + "accessToken";
//从Redis中取出accessToken
Object object = redisTemplate.opsForValue().get(accessTokenKey);
if (Objects.isNull(object)) {
//没有获取accessToken
AppletAccessToken appletAccessToken = AppletChatUtil.getAppletAccessToken(nurseAppletChatConfig.getAppletId(), nurseAppletChatConfig.getSecret());
if (Objects.isNull(appletAccessToken)) {
throw new ServiceException("获取微信小程序accessToken信息失败");
}
if (Objects.nonNull(appletAccessToken.getErrcode()) && appletAccessToken.getErrcode() != SUCCESS_CODE) {
throw new ServiceException("获取微信小程序accessToken信息失败失败信息为" + appletAccessToken.getErrmsg(), 201);
}
if (StringUtils.isBlank(appletAccessToken.getAccessToken())) {
throw new ServiceException("accessToken信息为空");
}
//存入Redis中
redisTemplate.opsForValue().set(accessTokenKey, appletAccessToken.getAccessToken(), 3600, TimeUnit.SECONDS);
accessToken = appletAccessToken.getAccessToken();
} else {
accessToken = (String) object;
}
return accessToken;
}
}

View File

@ -479,10 +479,15 @@
<!-- 获取注册详细信息 -->
<select id="selectPatientInfoByPhone" parameterType="String" resultType="java.lang.Integer">
select count(1) from patient_info
<select id="selectPatientInfoByPhone" parameterType="String" resultMap="PatientInfoResult">
<include refid="selectPatientInfoVo"/>
where phone = #{pnone}
and login_flag = '1'
</select>
<select id="getPatientInfoByPatientCode" resultMap="PatientInfoResult">
<include refid="selectPatientInfoVo"/>
where patient_code = #{patientCode}
and del_flag = 0
</select>
</mapper>

View File

@ -78,6 +78,11 @@
<version>${knife4j.version}</version>
</dependency>
<!-- 微信支付SDK -->
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-apache-httpclient</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -26,7 +26,6 @@ public class AsyncExecutorConfig {
*/
@Bean
public Executor asyncThreadServiceExecutor() {
log.info("异步线程池配置执行");
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(20);

View File

@ -0,0 +1,97 @@
package com.xinelu.framework.config;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import com.xinelu.common.config.XylWeChatPaymentConfig;
import com.xinelu.common.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
/**
* @Description 新医路商户号微信支付核心配置类
* @Author 纪寒
* @Date 2022-10-17 18:56:22
* @Version 1.0
*/
@Configuration
@Slf4j
public class XylWeChatPaymentUtilConfig {
@Resource
private XylWeChatPaymentConfig xylWeChatPaymentConfig;
/**
* 获取新医路签名信息
*
* @return 签名信息
* @throws Exception 异常信息
*/
@Bean(name = "xylVerifier")
public Verifier getXylVerifier() throws Exception {
PrivateKey privateKey = getPrivateKey(xylWeChatPaymentConfig.getXylPrivateKeyPath());
PrivateKeySigner privateKeySigner = new PrivateKeySigner(xylWeChatPaymentConfig.getXylMchSerialNo(), privateKey);
WechatPay2Credentials wechatPay2Credentials = new WechatPay2Credentials(xylWeChatPaymentConfig.getXylMchId(), privateKeySigner);
CertificatesManager certificatesManager = CertificatesManager.getInstance();
certificatesManager.putMerchant(xylWeChatPaymentConfig.getXylMchId(), wechatPay2Credentials, xylWeChatPaymentConfig.getXylPaymentKey().getBytes(StandardCharsets.UTF_8));
return certificatesManager.getVerifier(xylWeChatPaymentConfig.getXylMchId());
}
/**
* 获取新医路商户号带有签名的http请求对象
*
* @return CloseableHttpClient对象
*/
@Bean(name = "xinYiLuWeChatPayClient")
public CloseableHttpClient getXinYiLuWeChatPayClient(Verifier xylVerifier) {
PrivateKey privateKey = getPrivateKey(xylWeChatPaymentConfig.getXylPrivateKeyPath());
CloseableHttpClient closeableHttpClient = null;
try {
closeableHttpClient = WechatPayHttpClientBuilder.create()
.withMerchant(xylWeChatPaymentConfig.getXylMchId(), xylWeChatPaymentConfig.getXylMchSerialNo(), privateKey)
.withValidator(new WechatPay2Validator(xylVerifier)).build();
} catch (Exception e) {
log.error("新医路验证签名信息失败,失败信息:{}", e.getMessage());
}
return closeableHttpClient;
}
/**
* 获取新医路商户号无签名的http请求对象
*
* @return CloseableHttpClient对象
*/
@Bean(name = "xinYiLuWeChatPayNoSignClient")
public CloseableHttpClient getXinYiLuWeChatPayNoSignClient() {
PrivateKey privateKey = getPrivateKey(xylWeChatPaymentConfig.getXylPrivateKeyPath());
return WechatPayHttpClientBuilder.create()
.withMerchant(xylWeChatPaymentConfig.getXylMchId(), xylWeChatPaymentConfig.getXylMchSerialNo(), privateKey)
.withValidator((response) -> true).build();
}
/**
* 获取商户的私钥文件
*
* @param filename 获取商户的私钥文件
* @return 商户私钥
*/
private PrivateKey getPrivateKey(String filename) {
try {
return PemUtil.loadPrivateKey(new ClassPathResource(filename).getInputStream());
} catch (Exception e) {
log.error("新医路商户私钥文件不存在,错误原因:{}", e.getMessage());
throw new ServiceException("新医路商户私钥文件不存在,请联系管理员!");
}
}
}

View File

@ -0,0 +1,97 @@
package com.xinelu.framework.config;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import com.xinelu.common.config.YlypWeChatPaymentConfig;
import com.xinelu.common.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
/**
* @Description 医路优品微信支付核心配置类
* @Author 纪寒
* @Date 2022-10-17 18:56:22
* @Version 1.0
*/
@Configuration
@Slf4j
public class YlypWeChatPaymentUtilConfig {
@Resource
private YlypWeChatPaymentConfig ylypWeChatPaymentConfig;
/**
* 获取新医路签名信息
*
* @return 签名信息
* @throws Exception 异常信息
*/
@Bean(name = "ylypVerifier")
public Verifier getYlypVerifier() throws Exception {
PrivateKey privateKey = getPrivateKey(ylypWeChatPaymentConfig.getYlypPrivateKeyPath());
PrivateKeySigner privateKeySigner = new PrivateKeySigner(ylypWeChatPaymentConfig.getYlypMchSerialNo(), privateKey);
WechatPay2Credentials wechatPay2Credentials = new WechatPay2Credentials(ylypWeChatPaymentConfig.getYlypMchId(), privateKeySigner);
CertificatesManager certificatesManager = CertificatesManager.getInstance();
certificatesManager.putMerchant(ylypWeChatPaymentConfig.getYlypMchId(), wechatPay2Credentials, ylypWeChatPaymentConfig.getYlypPaymentKey().getBytes(StandardCharsets.UTF_8));
return certificatesManager.getVerifier(ylypWeChatPaymentConfig.getYlypMchId());
}
/**
* 获取医路优品商户带有签名信息的http请求对象
*
* @return CloseableHttpClient对象
*/
@Bean(name = "yiLuYouPinWeChatPayClient")
public CloseableHttpClient getYiLuYouPinWeChatPayClient(Verifier ylypVerifier) {
PrivateKey privateKey = getPrivateKey(ylypWeChatPaymentConfig.getYlypPrivateKeyPath());
CloseableHttpClient closeableHttpClient = null;
try {
closeableHttpClient = WechatPayHttpClientBuilder.create()
.withMerchant(ylypWeChatPaymentConfig.getYlypMchId(), ylypWeChatPaymentConfig.getYlypMchSerialNo(), privateKey)
.withValidator(new WechatPay2Validator(ylypVerifier)).build();
} catch (Exception e) {
log.error("医路优品验证签名信息失败,失败信息:{}", e.getMessage());
}
return closeableHttpClient;
}
/**
* 获取HttpClient无需进行应答签名验证跳过验签的流程
*
* @return CloseableHttpClient对象
*/
@Bean(name = "yiLuYouPinWeChatPayNoSignClient")
public CloseableHttpClient getYiLuYouPinWeChatPayNoSignClient() {
PrivateKey privateKey = getPrivateKey(ylypWeChatPaymentConfig.getYlypPrivateKeyPath());
return WechatPayHttpClientBuilder.create()
.withMerchant(ylypWeChatPaymentConfig.getYlypMchId(), ylypWeChatPaymentConfig.getYlypMchSerialNo(), privateKey)
.withValidator((response) -> true).build();
}
/**
* 获取商户的私钥文件
*
* @param filename 获取商户的私钥文件
* @return 商户私钥
*/
private PrivateKey getPrivateKey(String filename) {
try {
return PemUtil.loadPrivateKey(new ClassPathResource(filename).getInputStream());
} catch (Exception e) {
log.error("医路优品商户私钥文件不存在,错误原因:{}", e.getMessage());
throw new ServiceException("医路优品商户私钥文件不存在,请联系管理员!");
}
}
}

View File

@ -46,5 +46,11 @@
<groupId>org.simpleframework</groupId>
<artifactId>simple-xml</artifactId>
</dependency>
<!-- 微信支付SDK -->
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-apache-httpclient</artifactId>
</dependency>
</dependencies>
</project>
</project>

View File

@ -0,0 +1,93 @@
package com.xinelu.applet.controller.healthconsultation;
import com.xinelu.applet.service.healthconsultation.HealthConsultationService;
import com.xinelu.applet.vo.healthconsultation.HealthConsultationOrderDTO;
import com.xinelu.common.annotation.MobileRequestAuthorization;
import com.xinelu.common.annotation.RepeatSubmit;
import com.xinelu.common.core.controller.BaseController;
import com.xinelu.common.core.domain.AjaxResult;
import com.xinelu.common.core.page.TableDataInfo;
import com.xinelu.common.custominterface.Insert;
import com.xinelu.common.exception.ServiceException;
import com.xinelu.manage.domain.hospitalpersoninfo.HospitalPersonInfo;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;
/**
* @Description APP及小程序健康咨询接口
* @Author zh
* @Date 2023-03-07
*/
@RestController
@RequestMapping("/nurseApp/healthConsultation")
public class HealthConsultationController extends BaseController {
@Resource
private HealthConsultationService healthConsultationService;
/**
* 健康咨询-预约医生
*/
@MobileRequestAuthorization
@GetMapping("/selectDepartment")
public TableDataInfo selectDepartment() {
return healthConsultationService.selectDepartment();
}
/**
* 健康咨询-预约医生(无分页)
*/
@MobileRequestAuthorization
@GetMapping("/selectDepartmentNoPage")
public AjaxResult selectDepartmentNoPage() {
return AjaxResult.success(healthConsultationService.selectDepartmentNoPage());
}
/**
* 健康咨询-预约医生-单查科室人员
*/
@MobileRequestAuthorization
@GetMapping("/selectHospitalPerson")
public TableDataInfo selectHospitalPerson(Long departmentId) {
startPage();
List<HospitalPersonInfo> list = healthConsultationService.selectHospitalPerson(departmentId);
return getDataTable(list);
}
/**
* 健康咨询-信息确认
*/
@MobileRequestAuthorization
@GetMapping("/informationConfirmation")
public AjaxResult informationConfirmation(Long patientId) {
if (Objects.isNull(patientId)) {
return AjaxResult.error("用户信息为空!");
}
return healthConsultationService.informationConfirmation(patientId);
}
/**
* 手机App和微信小程序健康咨询确认订单方法
*
* @param healthConsultationOrderDTO 健康咨询订单
* @return 结果
*/
@MobileRequestAuthorization
@RepeatSubmit
@PostMapping("/addHealthConsultationOrder")
public AjaxResult addHealthConsultationOrder(@Validated(Insert.class) @RequestBody HealthConsultationOrderDTO healthConsultationOrderDTO, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
throw new ServiceException(bindingResult.getAllErrors().get(0).getDefaultMessage());
}
if (Objects.nonNull(healthConsultationOrderDTO.getTotalPrice()) && healthConsultationOrderDTO.getTotalPrice().compareTo(BigDecimal.ZERO) <= 0) {
return AjaxResult.error("预约金额不正确,无法下单,请输入正确的预约金额!");
}
return healthConsultationService.insertHealthConsultationOrder(healthConsultationOrderDTO);
}
}

View File

@ -0,0 +1,46 @@
package com.xinelu.applet.controller.logistics;
import com.xinelu.applet.service.logistics.LogisticsService;
import com.xinelu.common.annotation.MobileRequestAuthorization;
import com.xinelu.common.core.controller.BaseController;
import com.xinelu.common.core.domain.AjaxResult;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @Description 快递鸟物流查询接口控制器
* @Author 纪寒
* @Date 2022-11-01 13:33:31
* @Version 1.0
*/
@RestController
@RequestMapping("/nurseApp/logistics")
public class LogisticsController extends BaseController {
@Resource
private LogisticsService logisticsService;
/**
* 根据快递单号查询物流信息
*
* @param orderNo 订单单号
* @param expressNo 快递单号
* @return 物流信息
* @throws Exception 异常信息
*/
@MobileRequestAuthorization
@GetMapping("/queryLogisticsInfo")
public AjaxResult queryLogisticsInfo(String orderNo, String expressNo) throws Exception {
if (StringUtils.isBlank(orderNo)) {
return AjaxResult.error("请选择要查询的订单信息!");
}
if (StringUtils.isBlank(expressNo)) {
return AjaxResult.error("请选择要查询的快递单号!");
}
return logisticsService.queryLogisticsInfo(orderNo, expressNo);
}
}

View File

@ -0,0 +1,96 @@
package com.xinelu.applet.controller.nursingorder;
import com.xinelu.applet.service.nursingorder.INursingOrderService;
import com.xinelu.applet.vo.nursingorder.AppletGoodsOrderVO;
import com.xinelu.applet.vo.nursingorder.NursingOrderInfoVO;
import com.xinelu.common.annotation.MobileRequestAuthorization;
import com.xinelu.common.core.controller.BaseController;
import com.xinelu.common.core.domain.AjaxResult;
import com.xinelu.common.core.domain.entity.SysDictData;
import com.xinelu.common.core.page.TableDataInfo;
import com.xinelu.common.enums.OrderTypeEnum;
import com.xinelu.manage.domain.goodsOrder.GoodsOrder;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
/**
* @Description 个人中心订单页面
* @Author zhangheng
* @Date 2022-09-06
* @Version 1.0
*/
@RestController
@RequestMapping("/nurseApplet/nursingOrder")
public class NursingOrderController extends BaseController {
@Resource
private INursingOrderService nursingOrderService;
/**
* 根据登录id查询订单列表
*/
@GetMapping("/userPage")
public TableDataInfo page(Long parentId) {
startPage();
List<NursingOrderInfoVO> nursingOrderByPatientId = nursingOrderService.getNursingOrderByPatientId(parentId);
return getDataTable(nursingOrderByPatientId);
}
/**
* 根据护理人id以及订单状态查询订单信息
*/
@MobileRequestAuthorization
@GetMapping("/goodsOrder")
public TableDataInfo goodsOrder(AppletGoodsOrderVO goodsOrderVO) {
startPage();
List<AppletGoodsOrderVO> goodsOrder = nursingOrderService.getGoodsOrder(goodsOrderVO);
return getDataTable(goodsOrder);
}
/**
* 查询退款原因
*/
@MobileRequestAuthorization
@GetMapping("/refundReason")
public TableDataInfo refundReason(SysDictData sysDictData) {
startPage();
List<SysDictData> refundReason = nursingOrderService.getRefundReason(sysDictData);
return getDataTable(refundReason);
}
/**
* 修改商品订单(退款售后记录信息)
*/
@MobileRequestAuthorization
@PostMapping("/edit")
public AjaxResult edit(@RequestBody GoodsOrder goodsOrder) {
if (Objects.isNull(goodsOrder.getId())) {
return AjaxResult.error("订单id不能为空");
}
if (StringUtils.isNotBlank(goodsOrder.getOrderType()) && !OrderTypeEnum.HEALTH_CONSULTATION.getInfo().equals(goodsOrder.getOrderType())) {
if (Objects.isNull(goodsOrder.getRefundReasonDictId())) {
return AjaxResult.error("请选择退款原因!");
}
}
return toAjax(nursingOrderService.updateGoodsOrder(goodsOrder));
}
/**
* 根据预约订单编号查询对应得订单详情信息
*
* @param orderNo 订单编号
* @return 详情信息
*/
@MobileRequestAuthorization
@GetMapping("/getAppointmentDetailsInfo")
public AjaxResult getAppointmentDetailsInfo(String orderNo) {
if (StringUtils.isBlank(orderNo)) {
return AjaxResult.error("请选择要查询的预约订单信息!");
}
return nursingOrderService.getAppointmentDetailsInfo(orderNo);
}
}

View File

@ -1,45 +0,0 @@
package com.xinelu.applet.controller.personappletlogin;
import com.xinelu.applet.service.personappletlogin.PersonAppletLoginService;
import com.xinelu.common.core.controller.BaseController;
import com.xinelu.common.core.domain.AjaxResult;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.annotations.Param;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @Description 护理员微信小程序登录注册控制器
* @Author zh
* @Date 2023-03-30
*/
@RestController
@RequestMapping("/nurseApplet/personLogin")
public class PersonAppletLoginController extends BaseController {
@Resource
private PersonAppletLoginService personAppletLoginService;
/**
* 护理员根据登录凭证获取用户的登录信息
*
* @param loginCode 登录凭证
* @param phoneCode 手机号凭证
* @return 微信用户登录信息
*/
@GetMapping("/getPersonWeChatUserInfo")
public AjaxResult appletLogin(@RequestParam("loginCode") String loginCode, @Param("phoneCode") String phoneCode) {
if (StringUtils.isBlank(loginCode)) {
return AjaxResult.error("登录凭证编码不能为空!");
}
if (StringUtils.isBlank(phoneCode)) {
return AjaxResult.error("获取手机号凭证不存在");
}
return personAppletLoginService.personAppletLogin(loginCode, phoneCode);
}
}

View File

@ -0,0 +1,159 @@
package com.xinelu.applet.controller.wechatpaymentinfo;
import com.xinelu.applet.service.wechatpaymentinfo.WeChatPayNotifyService;
import com.xinelu.applet.service.wechatpaymentinfo.WeChatPaymentService;
import com.xinelu.applet.service.wechatpaymentinfo.WeChatRefundService;
import com.xinelu.applet.vo.wechatpaymentinfo.dto.PaymentDTO;
import com.xinelu.applet.vo.wechatpaymentinfo.dto.RefundDTO;
import com.xinelu.common.annotation.MobileRequestAuthorization;
import com.xinelu.common.core.controller.BaseController;
import com.xinelu.common.core.domain.AjaxResult;
import com.xinelu.common.custominterface.Insert;
import com.xinelu.common.enums.BuySourceEnum;
import com.xinelu.common.exception.ServiceException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.Objects;
/**
* @Description 微信小程序和App支付控制器
* @Author 纪寒
* @Date 2022-10-18 14:47:11
* @Version 1.0
*/
@RestController
@RequestMapping("/nurseApp/weChatPayment")
public class WeChatPaymentController extends BaseController {
@Resource
private WeChatPaymentService weChatPaymentService;
@Resource
private WeChatPayNotifyService weChatPayNotifyService;
@Resource
private WeChatRefundService weChatRefundService;
/**
* 微信小程序购买商品和健康咨询支付接口
*
* @param paymentDTO 输入参数
* @return 支付返回结果
* @throws Exception 异常信息
*/
@MobileRequestAuthorization
@PostMapping("/appletGoodsOrderPay")
public AjaxResult appletGoodsOrderPay(@Validated(Insert.class) @RequestBody PaymentDTO paymentDTO, BindingResult bindingResult) throws Exception {
if (bindingResult.hasErrors()) {
throw new ServiceException(bindingResult.getAllErrors().get(0).getDefaultMessage());
}
if (StringUtils.isBlank(paymentDTO.getOpenid())) {
return AjaxResult.error("微信openid不能为空");
}
if (Objects.nonNull(paymentDTO.getPaymentPrice()) && paymentDTO.getPaymentPrice().compareTo(BigDecimal.ZERO) < 0) {
return AjaxResult.error("订单支付金额不能为负数,无法支付!");
}
if (Objects.nonNull(paymentDTO.getPaymentPrice()) && paymentDTO.getPaymentPrice().compareTo(BigDecimal.ZERO) == 0) {
return AjaxResult.error("订单支付金额不能为零,无法支付!");
}
return weChatPaymentService.appletGoodsOrderPay(paymentDTO);
}
/**
* 微信小程序预约服务订单支付接口
*
* @param paymentDTO 输入参数
* @return 支付返回结果信息
* @throws Exception 异常信息
*/
@MobileRequestAuthorization
@PostMapping("/appletAppointmentOrderPay")
public AjaxResult appletAppointmentOrderPay(@Validated(Insert.class) @RequestBody PaymentDTO paymentDTO, BindingResult bindingResult) throws Exception {
if (bindingResult.hasErrors()) {
throw new ServiceException(bindingResult.getAllErrors().get(0).getDefaultMessage());
}
if (StringUtils.isBlank(paymentDTO.getOpenid())) {
return AjaxResult.error("微信openid不能为空");
}
if (!BuySourceEnum.NURSE_STATION.getInfo().equals(paymentDTO.getBuySource())) {
return AjaxResult.error("当前订单非预约服务项,请重新预约!");
}
if (Objects.nonNull(paymentDTO.getPaymentPrice()) && paymentDTO.getPaymentPrice().compareTo(BigDecimal.ZERO) < 0) {
return AjaxResult.error("订单支付金额不能为负数,无法支付!");
}
return weChatPaymentService.appletAppointmentOrderPay(paymentDTO);
}
/**
* 新医路微信支付回调通知接口
*
* @param request 请求头信息
* @param response 响应信息
* @return 应答信息避免微信平台重复发送回调通知
* @throws Exception 异常信息
*/
@PostMapping("/xylWeChatPayNotify")
public String xylWeChatPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
return weChatPayNotifyService.xylWeChatPayNotify(request, response);
}
/**
* 医路优品微信支付回调通知接口
*
* @param request 请求头信息
* @param response 响应信息
* @return 应答信息避免微信平台重复发送回调通知
* @throws Exception 异常信息
*/
@PostMapping("/ylypWeChatPayNotify")
public String ylypWeChatPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
return weChatPayNotifyService.ylypWeChatPayNotify(request, response);
}
/**
* 微信确认退款接口
*
* @param refundDTO 退款参数
* @return 退款申请结果
* @throws Exception 异常信息
*/
@PostMapping("/weChatRefundOrderApply")
public AjaxResult weChatRefundOrderApply(@Validated(Insert.class) @RequestBody RefundDTO refundDTO) throws Exception {
return weChatRefundService.weChatRefundOrderApply(refundDTO);
}
/**
* 新医路微信退款回调通知接口
*
* @param request 请求头信息
* @param response 响应信息
* @return 应答信息避免微信平台重复发送回调通知
* @throws Exception 异常信息
*/
@PostMapping("/xylWeChatRefundNotify")
public String xylWeChatRefundNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
return weChatPayNotifyService.xylWeChatRefundNotify(request, response);
}
/**
* 医路优品微信退款回调通知接口
*
* @param request 请求头信息
* @param response 响应信息
* @return 应答信息避免微信平台重复发送回调通知
* @throws Exception 异常信息
*/
@PostMapping("/ylypWeChatRefundNotify")
public String ylypWeChatRefundNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
return weChatPayNotifyService.ylypWeChatRefundNotify(request, response);
}
}

View File

@ -0,0 +1,30 @@
package com.xinelu.applet.mapper.healthconsultation;
import com.xinelu.applet.vo.healthconsultation.HealthConsultationVO;
import com.xinelu.manage.domain.patientinfo.PatientInfo;
import java.util.List;
/**
* 健康咨询Mapper接口
*
* @author 张恒
* @date 2023-03-07
*/
public interface HealthConsultationMapper {
/**
* 健康咨询-信息确认
*
* @param patientId 用户信息
* @return PatientInfo
*/
PatientInfo selectPatientById(Long patientId);
/**
* 查询科室信息管理列表
*
* @return 科室信息管理集合
*/
List<HealthConsultationVO> selectHospitalDepartmentList();
}

View File

@ -0,0 +1,66 @@
package com.xinelu.applet.mapper.nursingorder;
import com.xinelu.applet.vo.nursingorder.AppletGoodsOrderVO;
import com.xinelu.applet.vo.nursingorder.NursingOrderInfoVO;
import com.xinelu.applet.vo.specialdisease.AppointmentOrderDetailsInfoVO;
import com.xinelu.common.core.domain.entity.SysDictData;
import com.xinelu.manage.domain.goodsOrder.GoodsOrder;
import java.util.List;
/**
* 功能描述: 护理站订单信息
*
* @author zhangheng
*/
public interface NursingOrderMapper {
/**
* 根据被护理人patientId查询订单信息
*
* @param patientId 会员id
* @return 订单列表
*/
List<NursingOrderInfoVO> getNursingOrderVOByPatientId(Long patientId);
/**
* 根据护理人id以及订单状态查询订单信息
*
* @param goodsOrderVO 订单信息
* @return AppletGoodsOrderVO
**/
List<AppletGoodsOrderVO> getGoodsOrder(AppletGoodsOrderVO goodsOrderVO);
/**
* 查询退款原因
*
* @param sysDictData 退款原因
* @return com.xinyilu.common.core.domain.entity.SysDictData
**/
List<SysDictData> getRefundReason(SysDictData sysDictData);
/**
* 修改商品订单(退款售后记录信息)
*
* @param goodsOrder 商品订单
* @return 结果
*/
int updateGoodsOrder(GoodsOrder goodsOrder);
/**
* 根据预约订单编号查询对应得详情信息
*
* @param orderNo 订单编号
* @return 详情信息
*/
AppointmentOrderDetailsInfoVO getAppointmentOrderDetailsInfo(String orderNo);
/**
* 查询护理站信息
*
* @param nurseStationItemId 护理站项目id
* @return 护理站信息
*/
AppointmentOrderDetailsInfoVO getNurseStationByItemId(Long nurseStationItemId);
}

View File

@ -0,0 +1,27 @@
package com.xinelu.applet.service.goodstock;
/**
* @Description 库存公共服务业务层
* @Author 纪寒
* @Date 2022-10-24 13:56:40
* @Version 1.0
*/
public interface GoodsStockService {
/**
* 新增库存数量服务
*
* @param orderNo 订单编号
* @param goodsAttributeDetailsId 商品属性明细id
* @param stockNum 商品数量
*/
void addGoodsStockInfo(String orderNo, Long goodsAttributeDetailsId, Integer stockNum);
/**
* 减少库存数量服务
*
* @param orderNo 订单编号
* @param goodsAttributeDetailsId 商品属性明细id
*/
void reduceGoodsStockInfo(String orderNo, Long goodsAttributeDetailsId);
}

View File

@ -0,0 +1,102 @@
package com.xinelu.applet.service.goodstock.impl;
import com.xinelu.applet.service.goodstock.GoodsStockService;
import com.xinelu.common.constant.Constants;
import com.xinelu.common.exception.ServiceException;
import com.xinelu.common.utils.RedisDistributedLockUtils;
import com.xinelu.manage.domain.goodsOrderDetails.GoodsOrderDetails;
import com.xinelu.manage.mapper.goodsAttributeDetails.GoodsAttributeDetailsMapper;
import com.xinelu.manage.mapper.goodsOrderDetails.GoodsOrderDetailsMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Objects;
/**
* @Description 商品库存公共服务业务层实现类
* @Author 纪寒
* @Date 2022-10-24 13:57:28
* @Version 1.0
*/
@Slf4j
@Service
public class GoodsStockServiceImpl implements GoodsStockService {
@Resource
private RedisDistributedLockUtils redisDistributedLockUtils;
@Resource
private GoodsOrderDetailsMapper goodsOrderDetailsMapper;
@Resource
private GoodsAttributeDetailsMapper goodsAttributeDetailsMapper;
/**
* 新增库存数量服务
*
* @param orderNo 订单编号
* @param goodsAttributeDetailsId 商品属性明细id
* @param stockNum 商品数量
*/
@Override
public void addGoodsStockInfo(String orderNo, Long goodsAttributeDetailsId, Integer stockNum) {
if (StringUtils.isBlank(orderNo)) {
throw new ServiceException("订单编号不能为空!");
}
if (Objects.isNull(goodsAttributeDetailsId)) {
throw new ServiceException("商品属性明细id不能为空");
}
String orderNoLockKey = Constants.ADD_GOODS_STOCK_KEY + orderNo + "_" + goodsAttributeDetailsId;
boolean tryLock = redisDistributedLockUtils.tryLock(orderNoLockKey, 5);
if (!tryLock) {
return;
}
try {
int updateCount = goodsAttributeDetailsMapper.addGoodsStockCount(goodsAttributeDetailsId, stockNum);
if (updateCount < 1) {
log.info("新增库存数量失败,订单编号:{}商品属性明细id{},数量数量:{}", orderNo, goodsAttributeDetailsId, stockNum);
}
} catch (Exception e) {
log.error("新增库存信息失败,失败原因为 ====> {}", e.getMessage());
throw new ServiceException(e.getMessage());
} finally {
redisDistributedLockUtils.unlock(orderNoLockKey);
}
}
/**
* 减少库存数量服务
*
* @param orderNo 订单编号
* @param goodsAttributeDetailsId 商品属性明细id
*/
@Override
public void reduceGoodsStockInfo(String orderNo, Long goodsAttributeDetailsId) {
if (StringUtils.isBlank(orderNo)) {
throw new ServiceException("订单编号不能为空!");
}
if (Objects.isNull(goodsAttributeDetailsId)) {
throw new ServiceException("商品属性明细id不能为空");
}
GoodsOrderDetails goodsOrderDetailInfo = goodsOrderDetailsMapper.getGoodsOrderDetailInfo(orderNo, goodsAttributeDetailsId);
if (Objects.isNull(goodsOrderDetailInfo)) {
return;
}
String orderNoLockKey = Constants.REDUCE_GOODS_STOCK_KEY + orderNo + "_" + goodsAttributeDetailsId;
boolean tryLock = redisDistributedLockUtils.tryLock(orderNoLockKey, 5);
if (!tryLock) {
return;
}
try {
int updateCount = goodsAttributeDetailsMapper.reduceGoodsStockCount(goodsAttributeDetailsId, goodsOrderDetailInfo.getGoodsCount());
if (updateCount < 1) {
log.info("减少库存数量失败,订单编号:{}商品属性明细id{},数量数量:{}", orderNo, goodsAttributeDetailsId, goodsOrderDetailInfo.getGoodsCount());
}
} catch (Exception e) {
log.error("减少库存信息失败,失败原因为 ====> {}", e.getMessage());
throw new ServiceException(e.getMessage());
} finally {
redisDistributedLockUtils.unlock(orderNoLockKey);
}
}
}

View File

@ -0,0 +1,58 @@
package com.xinelu.applet.service.healthconsultation;
import com.xinelu.applet.vo.healthconsultation.HealthConsultationOrderDTO;
import com.xinelu.applet.vo.healthconsultation.HealthConsultationVO;
import com.xinelu.common.core.domain.AjaxResult;
import com.xinelu.common.core.page.TableDataInfo;
import com.xinelu.manage.domain.hospitalpersoninfo.HospitalPersonInfo;
import java.util.List;
/**
* @Description 健康咨询接口业务层
* @Author zh
* @Date 2023-03-07
*/
public interface HealthConsultationService {
/**
* 健康咨询-预约医生
*
* @return AjaxResult
*/
TableDataInfo selectDepartment();
/**
* 健康咨询-预约医生(无分页)
*
* @return AjaxResult
*/
List<HealthConsultationVO> selectDepartmentNoPage();
/**
* 单查科室人员
*
* @param departmentId 科室id
* @return AjaxResult
*/
List<HospitalPersonInfo> selectHospitalPerson(Long departmentId);
/**
* 健康咨询-信息确认
*
* @param patientId 用户信息
* @return AjaxResult
*/
AjaxResult informationConfirmation(Long patientId);
/**
* 手机App和微信小程序健康咨询确认订单方法
*
* @param healthConsultationOrderDTO 健康咨询订单
* @return 结果
*/
AjaxResult insertHealthConsultationOrder(HealthConsultationOrderDTO healthConsultationOrderDTO);
}

View File

@ -0,0 +1,188 @@
package com.xinelu.applet.service.healthconsultation.impl;
import com.xinelu.applet.service.healthconsultation.HealthConsultationService;
import com.xinelu.applet.utils.AppointmentTimeUtil;
import com.xinelu.applet.vo.healthconsultation.HealthConsultationOrderDTO;
import com.xinelu.applet.vo.healthconsultation.HealthConsultationVO;
import com.xinelu.applet.vo.healthconsultation.PatientAndTimeVO;
import com.xinelu.applet.vo.specialdisease.WeekDaysVO;
import com.xinelu.common.core.domain.AjaxResult;
import com.xinelu.common.core.page.TableDataInfo;
import com.xinelu.common.enums.BuySourceEnum;
import com.xinelu.common.enums.GooodsOrderStatusEnum;
import com.xinelu.common.enums.OrderTypeEnum;
import com.xinelu.common.enums.PoserModuleTypeEnum;
import com.xinelu.common.exception.ServiceException;
import com.xinelu.common.utils.PageServiceUtil;
import com.xinelu.common.utils.StringUtils;
import com.xinelu.common.utils.bean.BeanUtils;
import com.xinelu.manage.domain.goodsOrder.GoodsOrder;
import com.xinelu.manage.domain.goodsOrderDetails.GoodsOrderDetails;
import com.xinelu.manage.domain.hospitalpersoninfo.HospitalPersonInfo;
import com.xinelu.manage.domain.patientinfo.PatientInfo;
import com.xinelu.manage.domain.poserInfo.PoserInfo;
import com.xinelu.manage.mapper.goodsOrder.GoodsOrderMapper;
import com.xinelu.manage.mapper.goodsOrderDetails.GoodsOrderDetailsMapper;
import com.xinelu.applet.mapper.healthconsultation.HealthConsultationMapper;
import com.xinelu.manage.mapper.hospitalpersoninfo.HospitalPersonInfoMapper;
import com.xinelu.manage.mapper.patientinfo.PatientInfoMapper;
import com.xinelu.manage.mapper.poserInfo.PoserInfoMapper;
import com.xinelu.manage.vo.patientinfo.PatientInfoVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* @Description 健康咨询接口业务层实现类
* @Author zh
* @Date 2023-03-07
*/
@Slf4j
@Service
public class HealthConsultationServiceImpl implements HealthConsultationService {
@Resource
private PatientInfoMapper patientInfoMapper;
@Resource
private GoodsOrderMapper goodsOrderMapper;
@Resource
private GoodsOrderDetailsMapper goodsOrderDetailsMapper;
@Resource
private HealthConsultationMapper healthConsultationMapper;
@Resource
private PoserInfoMapper poserInfoMapper;
@Resource
private HospitalPersonInfoMapper hospitalPersonInfoMapper;
@Resource
private AppointmentTimeUtil appointmentTimeUtil;
@Resource
private PageServiceUtil pageServiceUtil;
/**
* 健康咨询-预约医生
*
* @return AjaxResult
*/
@Override
public TableDataInfo selectDepartment() {
//查询海报及科室
List<PoserInfo> poserList = poserInfoMapper.selectPoserListByModuleTyp(PoserModuleTypeEnum.HEALTH_CONSUTION_MODULE.getInfo());
pageServiceUtil.startPage();
List<HealthConsultationVO> healthConsultation = healthConsultationMapper.selectHospitalDepartmentList();
if (CollectionUtils.isNotEmpty(healthConsultation)) {
healthConsultation.get(0).setPoserInfoList(poserList);
}
return pageServiceUtil.getDataTable(healthConsultation);
}
/**
* 健康咨询-预约医生(无分页)
*
* @return AjaxResult
*/
@Override
public List<HealthConsultationVO> selectDepartmentNoPage() {
//查询海报及科室
List<PoserInfo> poserList = poserInfoMapper.selectPoserListByModuleTyp(PoserModuleTypeEnum.HEALTH_CONSUTION_MODULE.getInfo());
List<HealthConsultationVO> healthConsultation = healthConsultationMapper.selectHospitalDepartmentList();
if (CollectionUtils.isNotEmpty(healthConsultation)) {
healthConsultation.get(0).setPoserInfoList(poserList);
}
return healthConsultation;
}
/**
* 单查科室人员
*
* @param departmentId 科室id
* @return AjaxResult
*/
@Override
public List<HospitalPersonInfo> selectHospitalPerson(Long departmentId) {
if (Objects.isNull(departmentId)) {
return new ArrayList<>();
}
return hospitalPersonInfoMapper.selectHospitalPerson(departmentId);
}
/**
* 健康咨询-信息确认
*
* @param patientId 用户信息
* @return AjaxResult
*/
@Override
public AjaxResult informationConfirmation(Long patientId) {
PatientAndTimeVO patientAndTime = new PatientAndTimeVO();
PatientInfo patientInfo = healthConsultationMapper.selectPatientById(patientId);
if (Objects.isNull(patientInfo)) {
return AjaxResult.error("用户信息不存在!");
}
LocalDate nowTime = LocalDate.now();
//近七天的预约时间点数据集合
List<WeekDaysVO> weekDaysList = Lists.newArrayList();
appointmentTimeUtil.setWeekDayAndWeekDate(nowTime, weekDaysList);
patientAndTime.setAppointmentTimeList(weekDaysList);
patientAndTime.setPatientName(patientInfo.getPatientName());
patientAndTime.setPhone(patientInfo.getPhone());
return AjaxResult.success(patientAndTime);
}
/**
* 手机App和微信小程序健康咨询确认订单方法
*
* @param healthConsultationOrderDTO 健康咨询订单
* @return 结果
*/
@Transactional(rollbackFor = Exception.class)
@Override
public AjaxResult insertHealthConsultationOrder(HealthConsultationOrderDTO healthConsultationOrderDTO) {
//判断当前会员信息是否存在
PatientInfoVO patientInfo = patientInfoMapper.getPatientInfoById(healthConsultationOrderDTO.getPatientId());
if (Objects.isNull(patientInfo)) {
return AjaxResult.error("用户信息不存在,无法预约专家!");
}
//根据id查询当前专家是否存在
HospitalPersonInfo hospitalPersonInfo = hospitalPersonInfoMapper.selectHospitalPersonInfoById(healthConsultationOrderDTO.getHospitalPersonId());
if (Objects.isNull(hospitalPersonInfo)) {
return AjaxResult.error("当前专家信息不存在,请重新预约!");
}
//生成订单信息
GoodsOrder goodsOrder = new GoodsOrder();
BeanUtils.copyProperties(healthConsultationOrderDTO, goodsOrder);
String goodOrderNo = StringUtils.fillZeroByPatientId(healthConsultationOrderDTO.getPatientId(), 5) + System.nanoTime();
goodsOrder.setOrderNo(goodOrderNo);
goodsOrder.setOrderStatus(GooodsOrderStatusEnum.WAIT_PAY.getInfo());
goodsOrder.setDelFlag(0);
goodsOrder.setOrderType(OrderTypeEnum.HEALTH_CONSULTATION.getInfo());
goodsOrder.setBuySource(BuySourceEnum.HEALTH_CONSULTATION.getInfo());
goodsOrder.setCreateTime(LocalDateTime.now());
goodsOrder.setOrderTime(LocalDateTime.now());
goodsOrder.setOriginalTotalPrice(healthConsultationOrderDTO.getTotalPrice());
int insertGoodsOrder = goodsOrderMapper.insertGoodsOrder(goodsOrder);
if (insertGoodsOrder <= 0) {
throw new ServiceException("预约订单新增信息失败,请联系管理员!");
}
GoodsOrderDetails goodsOrderDetails = new GoodsOrderDetails();
goodsOrderDetails.setGoodsOrderId(goodsOrder.getId());
goodsOrderDetails.setOrderNo(goodOrderNo);
goodsOrderDetails.setGoodsName("健康咨询");
goodsOrderDetails.setTotalPrice(healthConsultationOrderDTO.getTotalPrice());
goodsOrderDetails.setDelFlag(0);
goodsOrderDetails.setCreateTime(LocalDateTime.now());
int insertGoodsOrderDetails = goodsOrderDetailsMapper.insertGoodsOrderDetails(goodsOrderDetails);
if (insertGoodsOrderDetails <= 0) {
throw new ServiceException("预约订单明细新增信息失败,请联系管理员!");
}
return AjaxResult.success(goodsOrderMapper.getGoodsOrderByOrderNo(goodOrderNo));
}
}

View File

@ -0,0 +1,22 @@
package com.xinelu.applet.service.logistics;
import com.xinelu.common.core.domain.AjaxResult;
/**
* @Description 快递鸟物流查询接口业务层
* @Author 纪寒
* @Date 2022-11-01 13:35:04
* @Version 1.0
*/
public interface LogisticsService {
/**
* 根据快递快递单号查询物流信息
*
* @param orderNo 订单单号
* @param expressNo 快递单号
* @return 物流信息结果
* @throws Exception 异常信息
*/
AjaxResult queryLogisticsInfo(String orderNo, String expressNo) throws Exception;
}

View File

@ -0,0 +1,172 @@
package com.xinelu.applet.service.logistics.impl;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.xinelu.applet.service.logistics.LogisticsService;
import com.xinelu.applet.utils.LogisticsUtil;
import com.xinelu.applet.vo.logistics.DistinguishResultVO;
import com.xinelu.applet.vo.logistics.SearchMonitorResultVO;
import com.xinelu.common.config.LogisticsConfig;
import com.xinelu.common.core.domain.AjaxResult;
import com.xinelu.manage.domain.goodsOrder.GoodsOrder;
import com.xinelu.manage.mapper.goodsOrder.GoodsOrderMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
/**
* @Description 快递鸟物流查询接口业务层实现类
* @Author 纪寒
* @Date 2022-11-01 13:35:38
* @Version 1.0
*/
@Slf4j
@Service
public class LogisticsServiceImpl implements LogisticsService {
@Resource
private LogisticsConfig logisticsConfig;
@Resource
private GoodsOrderMapper goodsOrderMapper;
/**
* 编码格式
*/
private static final String CHARSET = "UTF-8";
/**
* 识别单号接口指令
*/
private static final String DISTINGUISH_REQUEST_TYPE = "2002";
/**
* DataType=2请求返回数据类型均为JSON格式
*/
private static final String DATA_TYPE = "2";
/**
* 即时查询接口指令
*/
private static final String SEARCH_MONITOR_REQUEST_TYPE = "8001";
/**
* 顺丰快递编码
*/
private static final String SF_SHIPPER_CODE_TYPE = "SF";
/**
* 根据快递快递单号查询物流信息
*
* @param orderNo 订单单号
* @param expressNo 快递单号
* @return 物流信息结果
* @throws Exception 异常信息
*/
@Override
public AjaxResult queryLogisticsInfo(String orderNo, String expressNo) throws Exception {
GoodsOrder goodsOrder = goodsOrderMapper.getGoodsOrderByOrderNo(orderNo);
if (Objects.isNull(goodsOrder) || StringUtils.isBlank(goodsOrder.getPhone())) {
return AjaxResult.error("当前订单信息不存在!");
}
if (StringUtils.isBlank(goodsOrder.getExpressNo())) {
return AjaxResult.error("当前订单未发货,暂无订物流信息!");
}
//用户idAPI KEY正式地址等参数信息
String eBusinessId = logisticsConfig.getEBusinessId();
String apiKey = logisticsConfig.getApiKey();
String expressBirdUrl = logisticsConfig.getExpressBirdUrl();
Map<String, String> distinguishParam = buildDistinguishParam(expressNo, eBusinessId, apiKey);
String distinguishResult = LogisticsUtil.sendPost(expressBirdUrl, distinguishParam);
if (StringUtils.isBlank(distinguishResult)) {
log.info("调用快递鸟识别单号返回结果为空,请求参数 ====> {}", distinguishParam.toString());
return AjaxResult.error("当前订单暂无物流信息!");
}
DistinguishResultVO vo = JSONObject.parseObject(distinguishResult, DistinguishResultVO.class);
if (Objects.isNull(vo) || BooleanUtils.isFalse(vo.getSuccess())) {
log.info("调用快递鸟识别单号返回结果为空,请求参数 ====> {}", distinguishParam.toString());
return AjaxResult.error("当前订单暂无物流信息!");
}
List<String> shipperCodeList = vo.getShippers().stream().filter(item -> StringUtils.isNotBlank(item.getShipperCode())).map(DistinguishResultVO.ShippersDTO::getShipperCode).distinct().collect(Collectors.toList());
//循环查询快递信息
SearchMonitorResultVO monitorResultVO = null;
for (String shipperCode : shipperCodeList) {
if (StringUtils.isBlank(shipperCode)) {
continue;
}
//构建在途查询中即时查询接口参数信息
Map<String, String> searchMonitorParam = buildSearchMonitorParam(expressNo, eBusinessId, apiKey, shipperCode, goodsOrder.getPhone());
String searchMonitorResult = LogisticsUtil.sendPost(expressBirdUrl, searchMonitorParam);
monitorResultVO = JSONObject.parseObject(searchMonitorResult, SearchMonitorResultVO.class);
if (Objects.nonNull(monitorResultVO) && BooleanUtils.isTrue(monitorResultVO.getSuccess())) {
List<SearchMonitorResultVO.TracesDTO> sortTraces = monitorResultVO.getTraces().stream()
.filter(item -> Objects.nonNull(item.getAcceptTime()))
.sorted(Comparator.comparing(SearchMonitorResultVO.TracesDTO::getAcceptTime).reversed()).collect(Collectors.toList());
monitorResultVO.setTraces(sortTraces);
monitorResultVO.setShipperName(vo.getShippers().stream().filter(item -> StringUtils.isNotBlank(item.getShipperName()))
.filter(item -> shipperCode.equals(item.getShipperCode())).map(DistinguishResultVO.ShippersDTO::getShipperName).findFirst().orElse(""));
break;
}
}
return AjaxResult.success(monitorResultVO);
}
/**
* 构建识别单号参数信息
*
* @param expressNo 快递单号
* @param eBusinessId 用户id
* @param apiKey API key
* @return 参数信息
* @throws Exception 异常信息
*/
private Map<String, String> buildDistinguishParam(String expressNo, String eBusinessId,
String apiKey) throws Exception {
String requestData = "{'LogisticCode': '" + expressNo + "'}";
Map<String, String> params = new LinkedHashMap<>();
params.put("RequestData", LogisticsUtil.urlEncoder(requestData, CHARSET));
params.put("EBusinessID", eBusinessId);
params.put("RequestType", DISTINGUISH_REQUEST_TYPE);
String dataSign = LogisticsUtil.encrypt(requestData, apiKey, CHARSET);
params.put("DataSign", LogisticsUtil.urlEncoder(dataSign, CHARSET));
params.put("DataType", DATA_TYPE);
return params;
}
/**
* 构建即时查询物流单号信息
*
* @param expressNo 快递单号
* @param eBusinessId 用户id
* @param apiKey API key
* @param shipperCode 快递公司编码
* @param phone 联系电话
* @return 参数信息
* @throws Exception 异常信息
*/
private Map<String, String> buildSearchMonitorParam(String expressNo, String eBusinessId, String apiKey,
String shipperCode, String phone) throws Exception {
Map<String, String> sysParamMap = new LinkedHashMap<>();
sysParamMap.put("OrderCode", "");
if (SF_SHIPPER_CODE_TYPE.equals(shipperCode)) {
sysParamMap.put("CustomerName", phone.substring(7, 11));
} else {
sysParamMap.put("CustomerName", "");
}
sysParamMap.put("ShipperCode", shipperCode);
sysParamMap.put("LogisticCode", expressNo);
String requestData = JSON.toJSONString(sysParamMap);
Map<String, String> params = new LinkedHashMap<>();
params.put("RequestData", LogisticsUtil.urlEncoder(requestData, CHARSET));
params.put("EBusinessID", eBusinessId);
params.put("RequestType", SEARCH_MONITOR_REQUEST_TYPE);
String dataSign = LogisticsUtil.encrypt(requestData, apiKey, CHARSET);
params.put("DataSign", LogisticsUtil.urlEncoder(dataSign, CHARSET));
params.put("DataType", DATA_TYPE);
return params;
}
}

View File

@ -8,7 +8,6 @@ import com.xinelu.common.enums.OrderStatusEnum;
import com.xinelu.common.exception.ServiceException;
import com.xinelu.manage.mapper.appointmentorder.AppointmentOrderMapper;
import com.xinelu.manage.mapper.appointmentorderdetails.AppointmentOrderDetailsMapper;
import com.xinelu.manage.service.stationmessagepush.StationMessagePushService;
import com.xinelu.manage.vo.appointmentorder.AppointmentReceivingOrderVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@ -29,8 +28,6 @@ public class NurseAppletPersonWorkOrderServiceImpl implements NurseAppletPersonW
@Resource
private AppointmentOrderMapper appointmentOrderMapper;
@Resource
private StationMessagePushService stationMessagePushService;
@Resource
private AppointmentOrderDetailsMapper appointmentOrderDetailsMapper;
/**
@ -50,8 +47,6 @@ public class NurseAppletPersonWorkOrderServiceImpl implements NurseAppletPersonW
if (update < 0) {
throw new ServiceException("接单失败,请联系管理员!");
}
//异步发送消息
stationMessagePushService.receivingOrdersOperationsPush(appointmentReceivingOrder);
return AjaxResult.success();
}
}

View File

@ -177,7 +177,9 @@ public class NurseAppLoginServiceImpl implements NurseAppLoginService {
patientDisease.setAge(AgeUtil.getAgeMonth(String.valueOf(patientDisease.getBirthDate())));
}
if (Objects.nonNull(patientDisease) && StringUtils.isNotBlank(patientDisease.getDisease())) {
patientDisease.setDiseaseList(patientDisease.getDisease().split(""));
patientDisease.setDiseaseList(Arrays.stream(patientDisease.getDisease().split(","))
.map(Integer::valueOf)
.toArray(Integer[]::new));
}
if (Objects.nonNull(patientDisease) && StringUtils.isNotBlank(patientDisease.getAreaCode())) {
SysAreaVO codeName = sysAreaMapper.getSubordinateRegionsFindSuperiorRegions(patientDisease.getAreaCode());

View File

@ -23,7 +23,6 @@ import com.xinelu.manage.mapper.nursestation.NurseStationMapper;
import com.xinelu.manage.mapper.nursestationperson.NurseStationPersonMapper;
import com.xinelu.manage.mapper.nursestationpersonrevenue.NurseStationPersonRevenueMapper;
import com.xinelu.manage.mapper.patientdiseaseinfo.PatientDiseaseInfoMapper;
import com.xinelu.manage.service.stationmessagepush.StationMessagePushService;
import com.xinelu.manage.vo.appointmentorder.AppointmentOrderRecordVO;
import com.xinelu.manage.vo.appointmentorder.AppointmentReceivingOrderVO;
import com.xinelu.manage.vo.nursestation.NurseStationSysUserVO;
@ -71,8 +70,6 @@ public class NursePersonAppLoginServiceImpl implements INursePersonAppLoginServi
private NurseStationPersonRevenueMapper nurseStationPersonRevenueMapper;
@Resource
private PatientDiseaseInfoMapper patientDiseaseInfoMapper;
@Resource
private StationMessagePushService stationMessagePushService;
/**
* 工单首页查询已完成以及未完成数量
@ -168,8 +165,6 @@ public class NursePersonAppLoginServiceImpl implements INursePersonAppLoginServi
if (update <= 0) {
throw new ServiceException("任务退回失败,请联系管理员!");
}
//异步发送信息
stationMessagePushService.refusalOrdersOperationsPush(appointmentReceivingOrder);
return AjaxResult.success();
}
@ -213,8 +208,6 @@ public class NursePersonAppLoginServiceImpl implements INursePersonAppLoginServi
Long nurseStationPersonId = Objects.isNull(orderDetails.getNurseStationPersonId()) ? 0 : orderDetails.getNurseStationPersonId();
BigDecimal orderCommissionAmount = Objects.isNull(orderDetails.getOrderCommissionAmount()) ? BigDecimal.ZERO : orderDetails.getOrderCommissionAmount();
nurseStationPersonMapper.updateTotalRevenueAmountById(nurseStationPersonId, orderCommissionAmount);
//异步发送信息
stationMessagePushService.orderCompletionOperationsPush(orderDetails);
return AjaxResult.success();
}

View File

@ -0,0 +1,58 @@
package com.xinelu.applet.service.nursingorder;
import com.xinelu.applet.vo.nursingorder.AppletGoodsOrderVO;
import com.xinelu.applet.vo.nursingorder.NursingOrderInfoVO;
import com.xinelu.common.core.domain.AjaxResult;
import com.xinelu.common.core.domain.entity.SysDictData;
import com.xinelu.manage.domain.goodsOrder.GoodsOrder;
import java.util.List;
/**
* 订单列表Service接口
*
* @author zhangheng
* @date 2022-09-06
*/
public interface INursingOrderService {
/**
* 根据被护理人patientId查询订单信息
*
* @param patientId 被护理人id
* @return 订单列表
*/
List<NursingOrderInfoVO> getNursingOrderByPatientId(Long patientId);
/**
* 根据护理人id以及订单状态查询订单信息
*
* @param goodsOrderVO 订单信息
* @return java.util.List<com.xinyilu.nurseapplet.domain.vo.nursingorder.AppletGoodsOrderVO>
**/
List<AppletGoodsOrderVO> getGoodsOrder(AppletGoodsOrderVO goodsOrderVO);
/**
* 查询退款原因
*
* @param sysDictData 退款原因
* @return com.xinyilu.common.core.domain.entity.SysDictData
**/
List<SysDictData> getRefundReason(SysDictData sysDictData);
/**
* 修改商品订单(退款售后记录信息)
*
* @param goodsOrder 商品订单
* @return 结果
*/
int updateGoodsOrder(GoodsOrder goodsOrder);
/**
* 根据预约订单编号查询对应得订单详情信息
*
* @param orderNo 订单编号
* @return 详情信息
*/
AjaxResult getAppointmentDetailsInfo(String orderNo);
}

View File

@ -0,0 +1,110 @@
package com.xinelu.applet.service.nursingorder.impl;
import com.xinelu.applet.mapper.nursingorder.NursingOrderMapper;
import com.xinelu.applet.service.nursingorder.INursingOrderService;
import com.xinelu.applet.vo.nursingorder.AppletGoodsOrderVO;
import com.xinelu.applet.vo.nursingorder.NursingOrderInfoVO;
import com.xinelu.applet.vo.specialdisease.AppointmentOrderDetailsInfoVO;
import com.xinelu.common.core.domain.AjaxResult;
import com.xinelu.common.core.domain.entity.SysDictData;
import com.xinelu.common.enums.ConfirmRefundStatusEnum;
import com.xinelu.common.enums.GooodsOrderStatusEnum;
import com.xinelu.manage.domain.goodsOrder.GoodsOrder;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
/**
* @Description 订单分页
* @Author ZhangHeng
* @Date 2022-09-06
* @Version
*/
@Service
public class NursingOrderServiceImpl implements INursingOrderService {
@Resource
private NursingOrderMapper nursingOrderMapper;
/**
* 查询个人订单列表并分页
*
* @param patientId 被护理人id
* @return 结果
*/
@Override
public List<NursingOrderInfoVO> getNursingOrderByPatientId(Long patientId) {
return nursingOrderMapper.getNursingOrderVOByPatientId(patientId);
}
/**
* 根据护理人id以及订单状态查询订单信息
*
* @param goodsOrderVO 订单信息
* @return java.util.List<com.xinyilu.nurseapplet.domain.vo.nursingorder.GoodsOrderVO>
**/
@Override
public List<AppletGoodsOrderVO> getGoodsOrder(AppletGoodsOrderVO goodsOrderVO) {
return nursingOrderMapper.getGoodsOrder(goodsOrderVO);
}
/**
* 查询退款原因
*
* @param sysDictData 退款原因
* @return com.xinyilu.common.core.domain.entity.SysDictData
**/
@Override
public List<SysDictData> getRefundReason(SysDictData sysDictData) {
//dict_type 字典类型refund_reason
sysDictData.setDictType("refund_reason");
return nursingOrderMapper.getRefundReason(sysDictData);
}
/**
* 修改商品订单(退款售后记录信息)
*
* @param goodsOrder 商品订单
* @return 结果
*/
@Override
public int updateGoodsOrder(GoodsOrder goodsOrder) {
//设置修改人以及修改时间
goodsOrder.setUpdateTime(LocalDateTime.now());
//订单状态 退款中 WAIT_REFUND
goodsOrder.setOrderStatus(GooodsOrderStatusEnum.WAIT_REFUND.getInfo());
//确认退款状态 未确认 NOT_CONFIRM
goodsOrder.setConfirmRefundStatus(ConfirmRefundStatusEnum.NOT_CONFIRM.getInfo());
return nursingOrderMapper.updateGoodsOrder(goodsOrder);
}
/**
* 根据预约订单编号查询对应得订单详情信息
*
* @param orderNo 订单编号
* @return 详情信息
*/
@Override
public AjaxResult getAppointmentDetailsInfo(String orderNo) {
//查询预约服务订单信息
AppointmentOrderDetailsInfoVO detailsInfoVO = nursingOrderMapper.getAppointmentOrderDetailsInfo(orderNo);
if (Objects.isNull(detailsInfoVO)) {
return AjaxResult.success();
}
//查询护理站相关信息
AppointmentOrderDetailsInfoVO nurseStationInfo = nursingOrderMapper.getNurseStationByItemId(Objects.isNull(detailsInfoVO.getNurseStationItemId()) ? 0L : detailsInfoVO.getNurseStationItemId());
if (Objects.nonNull(nurseStationInfo)) {
detailsInfoVO.setNurseStationName(StringUtils.isBlank(nurseStationInfo.getNurseStationName()) ? "" : nurseStationInfo.getNurseStationName());
detailsInfoVO.setStationPhone(StringUtils.isBlank(nurseStationInfo.getStationPhone()) ? "" : nurseStationInfo.getStationPhone());
detailsInfoVO.setAddress(StringUtils.isBlank(nurseStationInfo.getAddress()) ? "" : nurseStationInfo.getAddress());
detailsInfoVO.setStationPictureUrl(StringUtils.isBlank(nurseStationInfo.getStationPictureUrl()) ? "" : nurseStationInfo.getStationPictureUrl());
detailsInfoVO.setItemPictureUrl(StringUtils.isBlank(nurseStationInfo.getItemPictureUrl()) ? "" : nurseStationInfo.getItemPictureUrl());
}
return AjaxResult.success(detailsInfoVO);
}
}

View File

@ -1,231 +0,0 @@
package com.xinelu.applet.service.personappletlogin.Impl;
import com.xinelu.applet.mapper.nursemanagepersonwechatinfo.NurseManagePersonWechatInfoMapper;
import com.xinelu.applet.mapper.personappletlogin.PersonAppletLoginMapper;
import com.xinelu.applet.service.personappletlogin.PersonAppletLoginService;
import com.xinelu.applet.utils.AppletAccessTokenUtil;
import com.xinelu.applet.vo.personappletlogin.PersonAppletVO;
import com.xinelu.applet.vo.personappletlogin.UserAndRole;
import com.xinelu.common.config.NurseAppletChatConfig;
import com.xinelu.common.constant.Constants;
import com.xinelu.common.core.domain.AjaxResult;
import com.xinelu.common.entity.AppletLoginVO;
import com.xinelu.common.entity.AppletPhoneVO;
import com.xinelu.common.exception.ServiceException;
import com.xinelu.common.utils.AppletChatUtil;
import com.xinelu.manage.domain.nursemanagepersonwechatinfo.NurseManagePersonWechatInfo;
import com.xinelu.manage.mapper.nursestationperson.NurseStationPersonMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* @Description 护理员微信小程序登录注册业务层实现类
* @Author zh
* @Date 2023-03-30
* @Version 1.0
*/
@Slf4j
@Service
public class PersonAppletLoginServiceImpl implements PersonAppletLoginService {
@Resource
private RedisTemplate<String, Object> redisTemplate;
@Resource
private NurseAppletChatConfig nurseAppletChatConfig;
@Resource
private AppletAccessTokenUtil appletAccessTokenUtil;
@Resource
private NurseStationPersonMapper nurseStationPersonMapper;
@Resource
private PersonAppletLoginMapper personAppletLoginMapper;
@Resource
private NurseManagePersonWechatInfoMapper nurseManagePersonWechatInfoMapper;
/**
* 返回成功状态码
*/
private static final int SUCCESS_CODE = 0;
/**
* 获取微信小程序access_token错误码
*/
private static final int ERROR_ACCESS_CODE = 40001;
/**
* 返回成功状态码
*/
private static final String OK = "ok";
/**
* 根据登录凭证获取用户的登录信息
*
* @param loginCode 登录凭证
* @return 微信用户登录信息
*/
@Transactional(rollbackFor = Exception.class)
@Override
public AjaxResult personAppletLogin(String loginCode, String phoneCode) {
//根据code获取用户的微信unionId以及openId等信息
AppletLoginVO appletLoginInfo = AppletChatUtil.getAppletLoginInfo(nurseAppletChatConfig.getAppletId(), nurseAppletChatConfig.getSecret(), loginCode, nurseAppletChatConfig.getGrantType());
if (Objects.isNull(appletLoginInfo)) {
return AjaxResult.error("获取微信小程序用户信息失败");
}
if (Objects.nonNull(appletLoginInfo.getErrcode()) && appletLoginInfo.getErrcode() != SUCCESS_CODE) {
return AjaxResult.error("获取微信小程序用户信息失败,失败信息为:" + appletLoginInfo.getErrmsg());
}
//获取微信accessToken,从Redis中取出accessToken
String accessToken;
String accessTokenKey = Constants.NURSE_STATION_PERSON_APPLET_ACCESS_TOKEN + "accessToken";
Object object = redisTemplate.opsForValue().get(accessTokenKey);
if (Objects.isNull(object)) {
accessToken = appletAccessTokenUtil.getPersonAppletAccessToken();
} else {
accessToken = (String) object;
}
//获取用户手机号
AppletPhoneVO appletPhoneInfo = AppletChatUtil.getAppletPhoneInfo(phoneCode, accessToken);
if (Objects.isNull(appletPhoneInfo)) {
return AjaxResult.error("获取用户手机号失败");
}
if (Objects.nonNull(appletPhoneInfo.getErrcode()) && appletPhoneInfo.getErrcode() == ERROR_ACCESS_CODE) {
//当前Redis缓存中的access_token无效直接删除
if (Objects.nonNull(object)) {
redisTemplate.delete(accessTokenKey);
accessToken = appletAccessTokenUtil.getPersonAppletAccessToken();
appletPhoneInfo = AppletChatUtil.getAppletPhoneInfo(phoneCode, accessToken);
if (Objects.isNull(appletPhoneInfo)) {
return AjaxResult.error("获取用户手机号失败");
}
if (Objects.nonNull(appletPhoneInfo.getErrcode()) && appletPhoneInfo.getErrcode() == ERROR_ACCESS_CODE) {
return AjaxResult.error("登录失败!");
}
}
}
if (StringUtils.isNotBlank(appletPhoneInfo.getErrmsg()) && !OK.equals(appletPhoneInfo.getErrmsg())) {
return AjaxResult.error("获取用户手机号失败,失败信息为:" + appletPhoneInfo.getErrmsg());
}
PersonAppletVO personAppletVO = getPersonApplet(appletPhoneInfo, appletLoginInfo);
return AjaxResult.success(personAppletVO);
}
/**
* 护理站管理人员微信个人信息对象
*
* @param phone 护理员手机号
* @param openid 用户的信息
* @param sysUser 管理员信息
*/
private void getNurseManagePersonWechat(String phone, String openid, List<UserAndRole> sysUser) {
//护理站管理人员微信个人信息对象
NurseManagePersonWechatInfo nurseManagePersonWechat = nurseManagePersonWechatInfoMapper.selectNurseManagePersonWechatInfoByPhone(phone);
NurseManagePersonWechatInfo nurseManagePersonWechatInfo = new NurseManagePersonWechatInfo();
if (Objects.isNull(nurseManagePersonWechat)) {
nurseManagePersonWechatInfo.setOpenid(openid);
nurseManagePersonWechatInfo.setPhone(phone);
nurseManagePersonWechatInfo.setNurseStationId(StringUtils.isBlank(sysUser.get(0).getNurseStationIds()) ? "" : sysUser.get(0).getNurseStationIds());
nurseManagePersonWechatInfo.setUserId(Objects.isNull(sysUser.get(0).getUserId()) ? null : sysUser.get(0).getUserId());
nurseManagePersonWechatInfo.setCreateTime(LocalDateTime.now());
int count = nurseManagePersonWechatInfoMapper.insertNurseManagePersonWechatInfo(nurseManagePersonWechatInfo);
if (count <= 0) {
throw new ServiceException("新增护理站管理人员微信个人信息失败,请联系管理员!");
}
}
if (Objects.nonNull(nurseManagePersonWechat)) {
nurseManagePersonWechatInfo.setId(Objects.isNull(nurseManagePersonWechat.getId()) ? null : nurseManagePersonWechat.getId());
nurseManagePersonWechatInfo.setOpenid(openid);
nurseManagePersonWechatInfo.setPhone(phone);
nurseManagePersonWechatInfo.setNurseStationId(StringUtils.isBlank(sysUser.get(0).getNurseStationIds()) ? "" : sysUser.get(0).getNurseStationIds());
nurseManagePersonWechatInfo.setUserId(Objects.isNull(sysUser.get(0).getUserId()) ? null : sysUser.get(0).getUserId());
int update = nurseManagePersonWechatInfoMapper.updateNurseManagePersonWechatInfo(nurseManagePersonWechatInfo);
if (update <= 0) {
throw new ServiceException("新增护理站管理人员微信个人信息失败,请联系管理员!");
}
}
}
/**
* 护理员登录接口方法抽取
*
* @param appletPhoneInfo 微信用户信息
* @param appletLoginInfo 手机号信息
* @return 登录标识
*/
private PersonAppletVO getPersonApplet(AppletPhoneVO appletPhoneInfo, AppletLoginVO appletLoginInfo) {
PersonAppletVO appletParent = new PersonAppletVO();
String phone = StringUtils.isBlank(appletPhoneInfo.getPhoneInfo().getPhoneNumber()) ? "" : appletPhoneInfo.getPhoneInfo().getPhoneNumber();
String openid = StringUtils.isBlank(appletLoginInfo.getOpenid()) ? "" : appletLoginInfo.getOpenid();
PersonAppletVO nurseStationPerson = personAppletLoginMapper.getNurseStationPersonByPhone(phone);
List<UserAndRole> sysUser = personAppletLoginMapper.selectSysUser(phone);
//说明当前用户角色即是护理员又是护理站运营人员
if (Objects.nonNull(nurseStationPerson) && CollectionUtils.isNotEmpty(sysUser)) {
//更新用户的openid等微信标识信息
this.updateNurseStationPerson(appletParent, nurseStationPerson, openid);
appletParent.setPersonRoleLoginFlag(Constants.PERSON_ROLE_NAME);
//护理站管理人员微信个人信息对象
List<String> roleKeyList = sysUser.stream().filter(Objects::nonNull).map(UserAndRole::getRoleKey).collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(roleKeyList) && (String.join((","), roleKeyList).contains(Constants.STATION_ROLE_NAME))) {
this.getNurseManagePersonWechat(phone, openid, sysUser);
appletParent.setPersonRoleLoginFlag(Constants.STATION_AND_PERSON_ROLE_NAME);
}
}
//说明当前用户角色即是护理员
if (Objects.nonNull(nurseStationPerson) && Objects.isNull(sysUser)) {
//更新用户的openid等微信标识信息
this.updateNurseStationPerson(appletParent, nurseStationPerson, openid);
appletParent.setPersonRoleLoginFlag(Constants.PERSON_ROLE_NAME);
}
//说明当前用户角色即是护理站运营人员
if (Objects.isNull(nurseStationPerson) && Objects.nonNull(sysUser)) {
List<String> roleKeyList = sysUser.stream().filter(Objects::nonNull).map(UserAndRole::getRoleKey).collect(Collectors.toList());
appletParent.setPersonRoleLoginFlag(Constants.NOT_ROLE_NAME);
if (CollectionUtils.isNotEmpty(roleKeyList) && (String.join((","), roleKeyList).contains(Constants.STATION_ROLE_NAME))) {
this.getNurseManagePersonWechat(phone, openid, sysUser);
appletParent.setPersonRoleLoginFlag(Constants.STATION_ROLE_NAME);
}
appletParent.setPhone(phone);
}
//说明当前用户角色即是即不是护理员又是不是护理站运营人员
if (Objects.isNull(nurseStationPerson) && Objects.isNull(sysUser)) {
appletParent.setPhone(phone);
appletParent.setPersonRoleLoginFlag(Constants.NOT_ROLE_NAME);
}
//当前用户角色只要包含护理员那么将护理员的信息返回给前端
if (Objects.nonNull(nurseStationPerson)) {
appletParent.setNurseStationId(Objects.isNull(nurseStationPerson.getNurseStationId()) ? null : nurseStationPerson.getNurseStationId());
appletParent.setNurseStationPersonId(Objects.isNull(nurseStationPerson.getNurseStationPersonId()) ? null : nurseStationPerson.getNurseStationPersonId());
appletParent.setNursePersonName(StringUtils.isBlank(nurseStationPerson.getNursePersonName()) ? "" : nurseStationPerson.getNursePersonName());
}
return appletParent;
}
/**
* 修改护理人员信息
*
* @param appletParent 护理员信息
* @param nurseStationPerson 护理员信息
* @param openid 护理员信息
*/
private void updateNurseStationPerson(PersonAppletVO appletParent, PersonAppletVO nurseStationPerson, String openid) {
appletParent.setId(nurseStationPerson.getNurseStationPersonId());
appletParent.setNurseStationPersonId(nurseStationPerson.getNurseStationPersonId());
appletParent.setOpenid(openid);
appletParent.setPhone(StringUtils.isBlank(nurseStationPerson.getPhone()) ? "" : nurseStationPerson.getPhone());
appletParent.setUpdateTime(LocalDateTime.now());
int updateCount = nurseStationPersonMapper.updateNurseStationPerson(appletParent);
if (updateCount <= 0) {
throw new ServiceException("修改护理人员信息失败,请联系管理员!");
}
}
}

View File

@ -1,21 +0,0 @@
package com.xinelu.applet.service.personappletlogin;
import com.xinelu.common.core.domain.AjaxResult;
import org.springframework.web.bind.annotation.RequestParam;
/**
* @Description 护理员微信小程序登录注册业务层
* @Author zh
* @Date 2023-03-30
*/
public interface PersonAppletLoginService {
/**
* 护理员根据登录凭证获取用户的登录信息
*
* @param loginCode 登录凭证
* @param phoneCode 手机号凭证
* @return 微信用户登录信息
*/
AjaxResult personAppletLogin(@RequestParam("loginCode") String loginCode, String phoneCode);
}

View File

@ -0,0 +1,53 @@
package com.xinelu.applet.service.wechatpaymentinfo;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @Description 微信支付回调业务层
* @Author 纪寒
* @Date 2022-10-20 14:00:21
* @Version 1.0
*/
public interface WeChatPayNotifyService {
/**
* 新医路支付回调接口
*
* @param request 请求信息
* @param response 响应信息
* @return 应答信息避免微信平台重复发送回调通知
* @throws Exception 异常信息
*/
String xylWeChatPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception;
/**
* 医路优品支付回调接口
*
* @param request 请求信息
* @param response 响应信息
* @return 应答信息避免微信平台重复发送回调通知
* @throws Exception 异常信息
*/
String ylypWeChatPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception;
/**
* 新医路退款回调接口
*
* @param request 请求信息
* @param response 响应信息
* @return 应答信息避免微信平台重复发送回调通知
* @throws Exception 异常信息
*/
String xylWeChatRefundNotify(HttpServletRequest request, HttpServletResponse response) throws Exception;
/**
* 医路优品退款回调接口
*
* @param request 请求信息
* @param response 响应信息
* @return 应答信息避免微信平台重复发送回调通知
* @throws Exception 异常信息
*/
String ylypWeChatRefundNotify(HttpServletRequest request, HttpServletResponse response) throws Exception;
}

View File

@ -0,0 +1,82 @@
package com.xinelu.applet.service.wechatpaymentinfo;
import com.xinelu.applet.vo.wechatpaymentinfo.dto.PaymentDTO;
import com.xinelu.applet.vo.wechatpaymentinfo.vo.OrderStatusInfoVO;
import com.xinelu.common.core.domain.AjaxResult;
/**
* @Description 微信小程序和App支付业务层
* @Author 纪寒
* @Date 2022-10-18 15:02:27
* @Version 1.0
*/
public interface WeChatPaymentService {
/**
* 微信小程序购买商品和健康咨询支付接口
*
* @param paymentDTO 输入参数
* @return 支付结果
* @throws Exception 异常信息
*/
AjaxResult appletGoodsOrderPay(PaymentDTO paymentDTO) throws Exception;
/**
* 微信小程序预约服务订单支付接口
*
* @param paymentDTO 输入参数
* @return 支付结果
* @throws Exception 异常信息
*/
AjaxResult appletAppointmentOrderPay(PaymentDTO paymentDTO) throws Exception;
/**
* 取消订单接口
*
* @param orderNo 点单编号
* @param buySource 购买来源
* @return 取消结果信息
* @throws Exception 异常信息
*/
AjaxResult cancelOrderInfo(String orderNo, String buySource) throws Exception;
/**
* 查询订单状态信息
*
* @param orderNo 点单编号
* @param buySource 购买来源
* @return 结果信息
* @throws Exception 异常信息
*/
AjaxResult getOrderStatusInfo(String orderNo, String buySource) throws Exception;
/**
* 微信关闭订单方法
*
* @param orderNo 订单编号
* @param buySource 购买来源
* @return 状态码
* @throws Exception 异常信息
*/
int closeWeChatOrderInfo(String orderNo, String buySource) throws Exception;
/**
* 查询预约服务订单信息
*
* @param orderNo 订单编号
* @param vo 返回值信息
* @return 订单状态标识
*/
OrderStatusInfoVO queryAppointmentOrderStatus(String orderNo, OrderStatusInfoVO vo);
/**
* 查询上商品订单信息
*
* @param orderNo 订单编号
* @param buySource 购买来源
* @param vo 返回值信息
* @return 订单状态标识
* @throws Exception 异常信息
*/
OrderStatusInfoVO queryGoodsOrderStatus(String orderNo, OrderStatusInfoVO vo, String buySource) throws Exception;
}

View File

@ -0,0 +1,41 @@
package com.xinelu.applet.service.wechatpaymentinfo;
import com.xinelu.applet.vo.wechatpaymentinfo.dto.RefundDTO;
import com.xinelu.applet.vo.wechatpaymentinfo.vo.WeChatRefundInfoVO;
import com.xinelu.common.core.domain.AjaxResult;
/**
* @Description 微信退款业务层
* @Author 纪寒
* @Date 2022-10-24 15:22:49
* @Version 1.0
*/
public interface WeChatRefundService {
/**
* 微信确认退款接口
*
* @param refundDTO 退款参数
* @return 返回信息
* @throws Exception 异常信息
*/
AjaxResult weChatRefundOrderApply(RefundDTO refundDTO) throws Exception;
/**
* 调用微信查询单笔退款接口查询预约订单状态信息
*
* @param refundNo 退款单号
* @return 退款信息
*/
WeChatRefundInfoVO queryAppointmentOrderRefundStatus(String refundNo);
/**
* 调用微信查询单笔退款接口查询商品订单状态信息
*
* @param refundNo 退单编号
* @param buySource 购买来源
* @return 退款信息
* @throws Exception 异常信息
*/
WeChatRefundInfoVO queryGoodsOrderRefundStatus(String refundNo, String buySource) throws Exception;
}

View File

@ -0,0 +1,486 @@
package com.xinelu.applet.service.wechatpaymentinfo.impl;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import com.wechat.pay.contrib.apache.httpclient.notification.Notification;
import com.wechat.pay.contrib.apache.httpclient.notification.NotificationHandler;
import com.wechat.pay.contrib.apache.httpclient.notification.NotificationRequest;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import com.xinelu.applet.service.wechatpaymentinfo.WeChatPayNotifyService;
import com.xinelu.applet.vo.wechatpaymentinfo.vo.WeChatPayNotifyPlaintextVO;
import com.xinelu.applet.vo.wechatpaymentinfo.vo.WeChatRefundNotifyVO;
import com.xinelu.common.config.XylWeChatPaymentConfig;
import com.xinelu.common.config.YlypWeChatPaymentConfig;
import com.xinelu.common.constant.Constants;
import com.xinelu.common.enums.*;
import com.xinelu.common.exception.ServiceException;
import com.xinelu.common.utils.RedisDistributedLockUtils;
import com.xinelu.common.utils.http.HttpUtils;
import com.xinelu.manage.domain.appointmentorder.AppointmentOrder;
import com.xinelu.manage.domain.goodsOrder.GoodsOrder;
import com.xinelu.manage.domain.paymentinfo.PaymentInfo;
import com.xinelu.manage.domain.refundinfo.RefundInfo;
import com.xinelu.manage.mapper.appointmentorder.AppointmentOrderMapper;
import com.xinelu.manage.mapper.goodsAttributeDetails.GoodsAttributeDetailsMapper;
import com.xinelu.manage.mapper.goodsOrder.GoodsOrderMapper;
import com.xinelu.manage.mapper.patientcouponreceive.PatientCouponReceiveMapper;
import com.xinelu.manage.mapper.paymentinfo.PaymentInfoMapper;
import com.xinelu.manage.mapper.refundinfo.RefundInfoMapper;
import com.xinelu.manage.vo.AppointOrderAndDetailsInfo;
import com.xinelu.manage.vo.appointmentorder.AppointmentOrderInfoVO;
import com.xinelu.manage.vo.goods.GoodsOrderAndDetailsInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* @Description 微信支付回调业务层实现类
* @Author 纪寒
* @Date 2022-10-20 14:00:52
* @Version 1.0
*/
@Slf4j
@Service
public class WeChatPayNotifyServiceImpl implements WeChatPayNotifyService {
@Resource
private XylWeChatPaymentConfig xylWeChatPaymentConfig;
@Resource
private GoodsOrderMapper goodsOrderMapper;
@Resource
private AppointmentOrderMapper appointmentOrderMapper;
@Resource
private YlypWeChatPaymentConfig ylypWeChatPaymentConfig;
@Resource
private PaymentInfoMapper paymentInfoMapper;
@Resource
private RedisDistributedLockUtils redisDistributedLockUtils;
@Resource(name = "transactionManager")
private DataSourceTransactionManager transactionManager;
@Resource
private GoodsAttributeDetailsMapper goodsAttributeDetailsMapper;
@Resource
private RefundInfoMapper refundInfoMapper;
@Resource(name = "xylVerifier")
private Verifier xylVerifier;
@Resource(name = "ylypVerifier")
private Verifier ylypVerifier;
@Resource
private RedisTemplate<String, Object> redisTemplate;
@Resource
private PatientCouponReceiveMapper patientCouponReceiveMapper;
/**
* 新医路账户标识
*/
private static final String XINYILU_ACCOUNT = "XINYILU";
/**
* 新医路账户标识
*/
private static final String YILUYOUPIN_ACCOUNT = "YILUYOUPIN";
/**
* 支付回调标识
*/
private static final String PAY = "PAY";
/**
* 退款回调标识
*/
private static final String REFUND = "REFUND";
/**
* 新医路支付回调接口
*
* @param request 请求信息
* @param response 响应信息
* @return 应答信息避免微信平台重复发送回调通知
*/
@Override
public String xylWeChatPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
log.info("新医路微信支付回调开始执行");
return weChatPayNotifyInfo(request, response, PaymentMerchantTypeEnum.XINYILU.getInfo(), PAY);
}
/**
* 医路优品支付回调接口
*
* @param request 请求信息
* @param response 响应信息
* @return 应答信息避免微信平台重复发送回调通知
* @throws Exception 异常信息
*/
@Override
public String ylypWeChatPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
log.info("医路优品微信支付回调开始执行");
return weChatPayNotifyInfo(request, response, PaymentMerchantTypeEnum.YILUYOUPIN.getInfo(), PAY);
}
/**
* 新医路退款回调接口
*
* @param request 请求信息
* @param response 响应信息
* @return 应答信息避免微信平台重复发送回调通知
* @throws Exception 异常信息
*/
@Override
public String xylWeChatRefundNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
log.info("新医路微信退款回调开始执行");
return weChatPayNotifyInfo(request, response, PaymentMerchantTypeEnum.XINYILU.getInfo(), REFUND);
}
/**
* 医路优品退款回调接口
*
* @param request 请求信息
* @param response 响应信息
* @return 应答信息避免微信平台重复发送回调通知
* @throws Exception 异常信息
*/
@Override
public String ylypWeChatRefundNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
log.info("医路优品微信退款回调开始执行");
return weChatPayNotifyInfo(request, response, PaymentMerchantTypeEnum.YILUYOUPIN.getInfo(), REFUND);
}
/**
* 微信支付回调通知公共方法
*
* @param request 请求信息
* @param response 响应信息
* @param accountFlag 账户标识用于区分是新医路还是医路优品
* @param refundAndPaymentFlag 支付和回调标识
* @return 返回信息
* @throws Exception 异常信息
*/
private String weChatPayNotifyInfo(HttpServletRequest request, HttpServletResponse response,
String accountFlag, String refundAndPaymentFlag) throws Exception {
Map<String, Object> resultMap = new HashMap<>();
String body = HttpUtils.readRequestData(request);
if (StringUtils.isBlank(body)) {
log.error(accountFlag + "微信回调通知失败,请求体 ====> {}", body);
response.setStatus(500);
resultMap.put("code", "ERROR");
resultMap.put("message", "通知验签失败");
return JSON.toJSONString(resultMap);
}
String nonce = request.getHeader("Wechatpay-Nonce");
String timestamp = request.getHeader("Wechatpay-Timestamp");
String signature = request.getHeader("Wechatpay-Signature");
String serialNo = request.getHeader("Wechatpay-Serial");
Notification notification = null;
if (XINYILU_ACCOUNT.equals(accountFlag)) {
NotificationRequest notificationRequest = new NotificationRequest.Builder().withSerialNumber(serialNo)
.withNonce(nonce).withTimestamp(timestamp).withSignature(signature).withBody(body).build();
NotificationHandler handler = new NotificationHandler(xylVerifier, xylWeChatPaymentConfig.getXylPaymentKey().getBytes(StandardCharsets.UTF_8));
notification = handler.parse(notificationRequest);
}
if (YILUYOUPIN_ACCOUNT.equals(accountFlag)) {
NotificationRequest notificationRequest = new NotificationRequest.Builder().withSerialNumber(serialNo)
.withNonce(nonce).withTimestamp(timestamp).withSignature(signature).withBody(body).build();
NotificationHandler handler = new NotificationHandler(ylypVerifier, ylypWeChatPaymentConfig.getYlypPaymentKey().getBytes(StandardCharsets.UTF_8));
notification = handler.parse(notificationRequest);
}
if (Objects.isNull(notification)) {
log.error(accountFlag + "微信通知验签失败,请求体 ====> {}", body);
response.setStatus(500);
resultMap.put("code", "ERROR");
resultMap.put("message", "通知验签失败");
return JSON.toJSONString(resultMap);
}
String ciphertext = StringUtils.isBlank(notification.getResource().getCiphertext()) ? "" : notification.getResource().getCiphertext();
String nonceTwo = StringUtils.isBlank(notification.getResource().getNonce()) ? "" : notification.getResource().getNonce();
String associatedData = StringUtils.isBlank(notification.getResource().getAssociatedData()) ? "" : notification.getResource().getAssociatedData();
String plainText = "";
if (XINYILU_ACCOUNT.equals(accountFlag)) {
AesUtil aesUtil = new AesUtil(xylWeChatPaymentConfig.getXylPaymentKey().getBytes(StandardCharsets.UTF_8));
plainText = aesUtil.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8), nonceTwo.getBytes(StandardCharsets.UTF_8), ciphertext);
}
if (YILUYOUPIN_ACCOUNT.equals(accountFlag)) {
AesUtil aesUtil = new AesUtil(ylypWeChatPaymentConfig.getYlypPaymentKey().getBytes(StandardCharsets.UTF_8));
plainText = aesUtil.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8), nonceTwo.getBytes(StandardCharsets.UTF_8), ciphertext);
}
if (StringUtils.isBlank(plainText)) {
response.setStatus(500);
resultMap.put("code", "ERROR");
resultMap.put("message", "解密失败!");
return JSON.toJSONString(resultMap);
}
//记录支付日志和修改订单状态
if (Constants.PAY_NOTIFY.equals(refundAndPaymentFlag)) {
this.processPaymentInfo(plainText);
}
//修改订单状态以及增加库存以及退还用户所使用的优惠券信息
if (Constants.REFUND_NOTIFY.equals(refundAndPaymentFlag)) {
this.processRefundInfo(plainText);
}
response.setStatus(200);
resultMap.put("code", "SUCCESS");
resultMap.put("message", "成功");
log.info("微信回调方法执行完成!");
return JSON.toJSONString(resultMap);
}
/**
* 记录支付信息和修改订单状态
*
* @param plainText 支付验签以后的通知内容
*/
private void processPaymentInfo(String plainText) {
WeChatPayNotifyPlaintextVO notifyPlaintext = JSONObject.parseObject(plainText, WeChatPayNotifyPlaintextVO.class);
if (StringUtils.isBlank(notifyPlaintext.getOutTradeNo())) {
return;
}
String orderNoLockKey = Constants.WE_CHAT_NOTIFY_KEY + notifyPlaintext.getOutTradeNo();
boolean tryLock = redisDistributedLockUtils.tryLock(orderNoLockKey, 5);
if (!tryLock) {
return;
}
TransactionStatus transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition());
try {
//商品订单信息
GoodsOrder goodsOrderInfo = goodsOrderMapper.getGoodsOrderByOrderNo(notifyPlaintext.getOutTradeNo());
if (Objects.nonNull(goodsOrderInfo)) {
insertPaymentInfo(notifyPlaintext, goodsOrderInfo, null, plainText);
if (WeChatTradeStateEnum.SUCCESS.getInfo().equals(notifyPlaintext.getTradeState())) {
goodsOrderMapper.updateGoodsOrderStatus(GooodsOrderStatusEnum.WAIT_RECEIVED_GOODS.getInfo(), goodsOrderInfo.getOrderNo());
} else {
log.info("商品订单微信订单状态异常,订单状态为 ====> {}", notifyPlaintext.getTradeState());
}
transactionManager.commit(transactionStatus);
return;
}
AppointmentOrderInfoVO appointmentOrderInfo = appointmentOrderMapper.getAppointmentOrderInfoByOrderNo(notifyPlaintext.getOutTradeNo());
if (Objects.isNull(appointmentOrderInfo)) {
return;
}
//预约服务订单信息
insertPaymentInfo(notifyPlaintext, null, appointmentOrderInfo, plainText);
if (WeChatTradeStateEnum.SUCCESS.getInfo().equals(notifyPlaintext.getTradeState())) {
appointmentOrderMapper.updateAppointmentOrderStatus(OrderStatusEnum.WAIT_DISPATCH.getInfo(), appointmentOrderInfo.getOrderNo());
} else {
log.info("预约服务微信订单状态异常,订单状态为 ====> {}", notifyPlaintext.getTradeState());
}
transactionManager.commit(transactionStatus);
} catch (Exception e) {
transactionManager.rollback(transactionStatus);
log.error("微信支付回调失败,失败原因:{}", e.getMessage());
throw e;
} finally {
redisDistributedLockUtils.unlock(orderNoLockKey);
log.info("支付回调释放锁完成...........");
}
}
/**
* 记录支付日志信息
*
* @param notifyPlaintext 回调信息
* @param goodsOrderInfo 商品订单信息
* @param appointmentOrder 预约订单信息
* @param plainText 回调明文
*/
private void insertPaymentInfo(WeChatPayNotifyPlaintextVO notifyPlaintext, GoodsOrder goodsOrderInfo,
AppointmentOrder appointmentOrder, String plainText) {
int paymentInfoCount = paymentInfoMapper.getPaymentInfoByOrderNo(notifyPlaintext.getOutTradeNo());
if (paymentInfoCount <= 0) {
PaymentInfo paymentInfo = buildPaymentInfo(notifyPlaintext, goodsOrderInfo, appointmentOrder, plainText);
int insertCount = paymentInfoMapper.insertPaymentInfo(paymentInfo);
if (insertCount <= 0) {
log.error("记录支付日志出错,参数为 ====> [{}]", paymentInfo);
throw new ServiceException("记录支付日志出错,请联系管理员!");
}
}
}
/**
* 构建支付信息参数
*
* @param notifyPlaintext 通知明文信息
* @param goodsOrderInfo 商品订单信息
* @param appointmentOrderInfo 预约订单信息
*/
private PaymentInfo buildPaymentInfo(WeChatPayNotifyPlaintextVO notifyPlaintext, GoodsOrder goodsOrderInfo,
AppointmentOrder appointmentOrderInfo, String plainText) {
PaymentInfo paymentInfo = new PaymentInfo();
if (Objects.nonNull(goodsOrderInfo)) {
paymentInfo.setPatientId(Objects.isNull(goodsOrderInfo.getPatientId()) ? null : goodsOrderInfo.getPatientId());
paymentInfo.setOrderNo(StringUtils.isBlank(goodsOrderInfo.getOrderNo()) ? "" : goodsOrderInfo.getOrderNo());
paymentInfo.setPayChannel(StringUtils.isBlank(goodsOrderInfo.getOrderChannel()) ? "" : goodsOrderInfo.getOrderChannel());
} else if (Objects.nonNull(appointmentOrderInfo)) {
paymentInfo.setPatientId(Objects.isNull(appointmentOrderInfo.getPatientId()) ? null : appointmentOrderInfo.getPatientId());
paymentInfo.setOrderNo(StringUtils.isBlank(appointmentOrderInfo.getOrderNo()) ? "" : appointmentOrderInfo.getOrderNo());
paymentInfo.setPayChannel(StringUtils.isBlank(appointmentOrderInfo.getOrderChannel()) ? "" : appointmentOrderInfo.getOrderChannel());
}
paymentInfo.setTransactionNo(StringUtils.isBlank(notifyPlaintext.getTransactionId()) ? "" : notifyPlaintext.getTransactionId());
paymentInfo.setPayPrice(BigDecimal.valueOf(Objects.isNull(notifyPlaintext.getAmount().getPayerTotal()) ? 0 : notifyPlaintext.getAmount().getPayerTotal()).divide(BigDecimal.valueOf(100), 2, BigDecimal.ROUND_DOWN));
paymentInfo.setPayType(PayTypeEnum.WECHAT_PAY.getInfo());
paymentInfo.setWechatTradeState(StringUtils.isBlank(notifyPlaintext.getTradeState()) ? "" : notifyPlaintext.getTradeState());
paymentInfo.setPayNotifyContent(plainText);
paymentInfo.setPayTime(LocalDateTime.parse(StringUtils.isBlank(notifyPlaintext.getSuccessTime()) ? "" : notifyPlaintext.getSuccessTime(), DateTimeFormatter.ISO_DATE_TIME));
if (notifyPlaintext.getMchid().equals(xylWeChatPaymentConfig.getXylMchId())) {
paymentInfo.setPaymentMerchantType(PaymentMerchantTypeEnum.XINYILU.getInfo());
}
if (notifyPlaintext.getMchid().equals(ylypWeChatPaymentConfig.getYlypMchId())) {
paymentInfo.setPaymentMerchantType(PaymentMerchantTypeEnum.YILUYOUPIN.getInfo());
}
paymentInfo.setDelFlag(0);
paymentInfo.setCreateTime(LocalDateTime.now());
return paymentInfo;
}
/**
* 修改订单状态以及减少库存信息
*
* @param plainText 支付验签以后的通知内容
*/
private void processRefundInfo(String plainText) {
WeChatRefundNotifyVO refundNotifyVO = JSONObject.parseObject(plainText, WeChatRefundNotifyVO.class);
if (StringUtils.isBlank(refundNotifyVO.getOutTradeNo())) {
return;
}
String orderNoLockKey = Constants.WE_CHAT_REFUND_KEY + refundNotifyVO.getOutTradeNo();
boolean tryLock = redisDistributedLockUtils.tryLock(orderNoLockKey, 5);
if (!tryLock) {
return;
}
TransactionStatus transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition());
RedisAtomicLong redisAtomicLong = null;
try {
GoodsOrderAndDetailsInfo detailsOrderInfo = goodsOrderMapper.getGoodsAndDetailsOrderInfo(refundNotifyVO.getOutTradeNo());
AppointOrderAndDetailsInfo appointmentOrderInfo = appointmentOrderMapper.getAppointOrderAndDetailsInfo(refundNotifyVO.getOutTradeNo());
if (Objects.isNull(detailsOrderInfo) && Objects.isNull(appointmentOrderInfo)) {
return;
}
if (Objects.nonNull(appointmentOrderInfo)) {
updateAppointmentInfo(appointmentOrderInfo, plainText, refundNotifyVO);
if (Objects.nonNull(appointmentOrderInfo.getAppointmentLimitCount()) && StringUtils.equals(AppointmentOrderTypeEnum.OTHER.getInfo(), appointmentOrderInfo.getOrderType())) {
String appointLimitCountKey = Constants.PRE_APPOINTMENT_LIMIT_COUNT_KEY + appointmentOrderInfo.getNurseStationItemId() + "_" + appointmentOrderInfo.getServiceDate() + "_" + appointmentOrderInfo.getServiceStartTime();
redisAtomicLong = new RedisAtomicLong(appointLimitCountKey, Objects.requireNonNull(redisTemplate.getConnectionFactory()));
if (redisAtomicLong.get() >= 0 && redisAtomicLong.get() < appointmentOrderInfo.getAppointmentLimitCount()) {
redisAtomicLong.incrementAndGet();
}
}
}
if (Objects.nonNull(detailsOrderInfo)) {
updateGoodsInfo(detailsOrderInfo, plainText, refundNotifyVO);
}
transactionManager.commit(transactionStatus);
} catch (Exception e) {
transactionManager.rollback(transactionStatus);
log.error("微信退款回调通知失败,失败信息为:{}", e.getMessage());
if (Objects.nonNull(redisAtomicLong) && redisAtomicLong.get() > 0) {
redisAtomicLong.decrementAndGet();
}
throw e;
} finally {
redisDistributedLockUtils.unlock(orderNoLockKey);
log.info("退款回调释放锁完成.............");
}
}
/**
* 处理预约服务订单信息
*
* @param appointmentOrderInfo 预约订单信息
* @param plainText 明文
* @param refundNotifyVO 退款回调信息
*/
private void updateAppointmentInfo(AppointmentOrder appointmentOrderInfo, String plainText, WeChatRefundNotifyVO refundNotifyVO) {
if (RefundStatusEnum.SUCCESS.getInfo().equals(refundNotifyVO.getRefundStatus())
&& StringUtils.isNotBlank(appointmentOrderInfo.getOrderStatus())
&& !(OrderStatusEnum.REFUNDED.getInfo().equals(appointmentOrderInfo.getOrderStatus()))) {
int updateCount = appointmentOrderMapper.updateAppointmentOrderStatus(OrderStatusEnum.REFUNDED.getInfo(), appointmentOrderInfo.getOrderNo());
if (updateCount < 1) {
log.info("微信退款通知,修改预约订单状态失败,订单编号 =====> {}", refundNotifyVO.getOutTradeNo());
}
RefundInfo refundInfo = buildRefundInfo(plainText, refundNotifyVO);
int refundCount = refundInfoMapper.updateRefundInfoByNo(refundInfo);
if (refundCount < 1) {
log.info("微信退款通知,记录预约订单微信退款单信息失败,订单编号 =====> {}", refundNotifyVO.getOutTradeNo());
}
}
if (RefundStatusEnum.CLOSED.getInfo().equals(refundNotifyVO.getRefundStatus())) {
log.info("当前预约退款单已经关闭,订单号 ====> {}, 退款单号 =====> {}", refundNotifyVO.getOutTradeNo(), refundNotifyVO.getOutRefundNo());
}
if (RefundStatusEnum.ABNORMAL.getInfo().equals(refundNotifyVO.getRefundStatus())) {
log.info("预约订单退款异常,退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往【商户平台—>交易中心】,手动处理此笔退款,订单号 ====> {}, 退款单号 =====> {}", refundNotifyVO.getOutTradeNo(), refundNotifyVO.getOutRefundNo());
}
}
/**
* 处理商品订单信息
*
* @param detailsOrderInfo 商品订单信息
* @param plainText 明文
* @param refundNotifyVO 退款回调信息
*/
private void updateGoodsInfo(GoodsOrderAndDetailsInfo detailsOrderInfo, String plainText, WeChatRefundNotifyVO refundNotifyVO) {
if (RefundStatusEnum.SUCCESS.getInfo().equals(refundNotifyVO.getRefundStatus())
&& StringUtils.isNotBlank(detailsOrderInfo.getOrderStatus())
&& !(GooodsOrderStatusEnum.REFUNDED.getInfo().equals(detailsOrderInfo.getOrderStatus()))) {
int updateGoodsOrderCount = goodsOrderMapper.updateGoodsOrderStatus(OrderStatusEnum.REFUNDED.getInfo(), detailsOrderInfo.getOrderNo());
if (updateGoodsOrderCount < 1) {
log.info("微信退款通知,修改商品单状态失败,订单编号 =====> {}", refundNotifyVO.getOutTradeNo());
}
if (StringUtils.isNotBlank(detailsOrderInfo.getOrderType()) && !OrderTypeEnum.HEALTH_CONSULTATION.getInfo().equals(detailsOrderInfo.getOrderType())) {
if (!GooodsOrderStatusEnum.REFUNDED.getInfo().equals(detailsOrderInfo.getOrderStatus())) {
int updateStockCount = goodsAttributeDetailsMapper.addGoodsStockCount(detailsOrderInfo.getGoodsAttributeDetailsId(), detailsOrderInfo.getGoodsCount());
if (updateStockCount < 1) {
log.info("新增库存数量失败,订单编号:{}商品属性明细id{},数量数量:{}", detailsOrderInfo.getOrderNo(), detailsOrderInfo.getGoodsAttributeDetailsId(), detailsOrderInfo.getGoodsCount());
}
}
if (Objects.nonNull(detailsOrderInfo.getCouponId()) && Objects.nonNull(detailsOrderInfo.getPatientId())) {
patientCouponReceiveMapper.updatePatientCouponUseStatus(detailsOrderInfo.getPatientId(), detailsOrderInfo.getCouponId(), CouponUseStatusEnum.NOT_USED.getInfo());
}
}
RefundInfo refundInfo = buildRefundInfo(plainText, refundNotifyVO);
int refundCount = refundInfoMapper.updateRefundInfoByNo(refundInfo);
if (refundCount < 1) {
log.info("微信退款通知,记录商品订单微信退款单信息失败,订单编号 =====> {}", refundNotifyVO.getOutTradeNo());
}
}
if (RefundStatusEnum.CLOSED.getInfo().equals(refundNotifyVO.getRefundStatus())) {
log.info("当前商品退款单已经关闭,订单号 ====> {}, 退款单号 =====> {}", refundNotifyVO.getOutTradeNo(), refundNotifyVO.getOutRefundNo());
}
if (RefundStatusEnum.ABNORMAL.getInfo().equals(refundNotifyVO.getRefundStatus())) {
log.info("商品订单退款异常,退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往【商户平台—>交易中心】,手动处理此笔退款,订单号 ====> {}, 退款单号 =====> {}", refundNotifyVO.getOutTradeNo(), refundNotifyVO.getOutRefundNo());
}
}
/**
* 构建退款单信息
*
* @param plainText 退款通知解密的明文信息
* @param refundNotifyVO 通知参数
* @return 结果
*/
private RefundInfo buildRefundInfo(String plainText, WeChatRefundNotifyVO refundNotifyVO) {
RefundInfo refundInfo = new RefundInfo();
refundInfo.setWechatRefundStatus(StringUtils.isBlank(refundNotifyVO.getRefundStatus()) ? "" : refundNotifyVO.getRefundStatus());
refundInfo.setSuccessTime(LocalDateTime.parse(StringUtils.isBlank(refundNotifyVO.getSuccessTime()) ? "" : refundNotifyVO.getSuccessTime(), DateTimeFormatter.ISO_DATE_TIME));
refundInfo.setRefundNotifyContent(plainText);
refundInfo.setOrderNo(StringUtils.isBlank(refundNotifyVO.getOutTradeNo()) ? "" : refundNotifyVO.getOutTradeNo());
refundInfo.setOutRefundNo(StringUtils.isBlank(refundNotifyVO.getOutRefundNo()) ? "" : refundNotifyVO.getOutRefundNo());
return refundInfo;
}
}

View File

@ -0,0 +1,565 @@
package com.xinelu.applet.service.wechatpaymentinfo.impl;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.xinelu.applet.service.wechatpaymentinfo.WeChatPaymentService;
import com.xinelu.applet.utils.WeChatUtil;
import com.xinelu.applet.vo.wechatpaymentinfo.dto.PaymentDTO;
import com.xinelu.applet.vo.wechatpaymentinfo.vo.OrderStatusInfoVO;
import com.xinelu.applet.vo.wechatpaymentinfo.vo.WeChatAppletSignVO;
import com.xinelu.applet.vo.wechatpaymentinfo.vo.WeChatQueryOrderVO;
import com.xinelu.common.config.AppletChatConfig;
import com.xinelu.common.config.WeChatPaymentUrlConfig;
import com.xinelu.common.config.XylWeChatPaymentConfig;
import com.xinelu.common.config.YlypWeChatPaymentConfig;
import com.xinelu.common.constant.Constants;
import com.xinelu.common.core.domain.AjaxResult;
import com.xinelu.common.enums.BuySourceEnum;
import com.xinelu.common.enums.GooodsOrderStatusEnum;
import com.xinelu.common.enums.OrderStatusEnum;
import com.xinelu.common.enums.WeChatTradeStateEnum;
import com.xinelu.common.exception.ServiceException;
import com.xinelu.manage.domain.appointmentorder.AppointmentOrder;
import com.xinelu.manage.domain.goodsOrder.GoodsOrder;
import com.xinelu.manage.mapper.appointmentorder.AppointmentOrderMapper;
import com.xinelu.manage.mapper.goodsOrder.GoodsOrderMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Base64Utils;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.Signature;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @Description 微信小程序和App支付业务层实现类
* @Author 纪寒
* @Date 2022-10-18 15:02:40
* @Version 1.0
*/
@Service
@Slf4j
public class WeChatPaymentServiceImpl implements WeChatPaymentService {
@Resource
private GoodsOrderMapper goodsOrderMapper;
@Resource
private AppointmentOrderMapper appointmentOrderMapper;
@Resource
private AppletChatConfig appletChatConfig;
@Resource
private XylWeChatPaymentConfig xylWeChatPaymentConfig;
@Resource
private YlypWeChatPaymentConfig ylypWeChatPaymentConfig;
@Resource(name = "xinYiLuWeChatPayClient")
private CloseableHttpClient xinYiLuWeChatPayClient;
@Resource(name = "yiLuYouPinWeChatPayClient")
private CloseableHttpClient yiLuYouPinWeChatPayClient;
@Resource
private WeChatPaymentUrlConfig weChatPaymentUrlConfig;
@Resource
private RedisTemplate<String, String> redisTemplate;
@Resource
private WeChatUtil weChatUtil;
/**
* 新医路支付商品描述
*/
private static final String XIN_YI_LU_DESCRIPTION = "山东新医路信息科技有限公司";
/**
* 医路优品支付商品描述
*/
private static final String YI_LU_YOU_PIN_DESCRIPTION = "医路优品信息科技有限公司";
/**
* JsApi下单成功状态码
*/
private static final int HAVE_BODY_SUCCESS_CODE = 200;
/**
* JsApi下单成功状态码
*/
private static final int NO_HAVE_BODY_SUCCESS_CODE = 204;
/**
* 签名算法
*/
private static final String SIGNATURE_ALGORITHM = "SHA256withRSA";
/**
* 签名方式
*/
private static final String SIGN_TYPE = "RSA";
/**
* 新医路支付回调接口地址
*/
private static final String XINYILU_WE_CHAT_NOTIFY_URL = "/nurseApp/weChatPayment/xylWeChatPayNotify";
/**
* 医路优品支付回调接口地址
*/
private static final String YINLUYOUPIN_WE_CHAT_NOTIFY_URL = "/nurseApp/weChatPayment/ylypWeChatPayNotify";
/**
* 微信小程序购买商品和健康咨询支付接口
*
* @param paymentDTO 输入参数
* @return 支付结果
* @throws Exception 常信息
*/
@Override
public AjaxResult appletGoodsOrderPay(PaymentDTO paymentDTO) throws Exception {
String prepayId = redisTemplate.opsForValue().get(Constants.PREPAY_ID_KEY + paymentDTO.getOrderNo());
if (StringUtils.isBlank(prepayId)) {
GoodsOrder goodsOrderInfo = goodsOrderMapper.getGoodsOrderByOrderNo(paymentDTO.getOrderNo());
if (Objects.isNull(goodsOrderInfo) || StringUtils.isBlank(goodsOrderInfo.getOrderStatus())) {
return AjaxResult.error("未查询到当前订单信息,请选择正确的订单信息!");
}
if (!goodsOrderInfo.getOrderStatus().equals(GooodsOrderStatusEnum.WAIT_PAY.getInfo())) {
return AjaxResult.error("订单状态异常,无法支付,请联系管理员!");
}
if (StringUtils.isBlank(goodsOrderInfo.getBuySource())
|| !paymentDTO.getBuySource().equals(goodsOrderInfo.getBuySource())) {
log.info("购买来源不一致,请进行确认!");
return AjaxResult.error("订单状态异常,无法支付,请联系管理员!");
}
String jsApiParams = this.buildGoodsOrderJsApiParams(paymentDTO, goodsOrderInfo);
prepayId = this.requestJsApiInterface(jsApiParams, paymentDTO, prepayId);
} else {
prepayId = redisTemplate.opsForValue().get(Constants.PREPAY_ID_KEY + paymentDTO.getOrderNo());
}
return AjaxResult.success(getSignInfo(prepayId, paymentDTO.getBuySource()));
}
/**
* 微信小程序预约服务订单支付接口
*
* @param paymentDTO 输入参数
* @return 支付结果
* @throws Exception 异常信息
*/
@Override
public AjaxResult appletAppointmentOrderPay(PaymentDTO paymentDTO) throws Exception {
String prepayId = redisTemplate.opsForValue().get(Constants.PREPAY_ID_KEY + paymentDTO.getOrderNo());
if (StringUtils.isBlank(prepayId)) {
AppointmentOrder appointmentOrderInfo = appointmentOrderMapper.getAppointmentOrderByOrderNo(paymentDTO.getOrderNo());
if (Objects.isNull(appointmentOrderInfo) || StringUtils.isBlank(appointmentOrderInfo.getOrderStatus())) {
return AjaxResult.error("未查询到当前预约订单信息,请选择重新预约!");
}
if (!appointmentOrderInfo.getOrderStatus().equals(OrderStatusEnum.WAIT_PAY.getInfo())) {
return AjaxResult.error("订单状态异常,无法支付,请联系管理员!");
}
String jsApiParams = this.buildAppointmentOrderJsApiParams(paymentDTO, appointmentOrderInfo);
prepayId = this.requestJsApiInterface(jsApiParams, paymentDTO, prepayId);
} else {
prepayId = redisTemplate.opsForValue().get(Constants.PREPAY_ID_KEY + paymentDTO.getOrderNo());
}
return AjaxResult.success(getSignInfo(prepayId, paymentDTO.getBuySource()));
}
/**
* 取消订单接口
*
* @param orderNo 点单编号
* @param buySource 购买来源
* @return 取消结果信息
*/
@Transactional(rollbackFor = Exception.class)
@Override
public AjaxResult cancelOrderInfo(String orderNo, String buySource) throws Exception {
GoodsOrder goodsOrderInfo = goodsOrderMapper.getGoodsOrderByOrderNo(orderNo);
AppointmentOrder appointmentOrderInfo = appointmentOrderMapper.getAppointmentOrderByOrderNo(orderNo);
if (Objects.isNull(goodsOrderInfo) && Objects.isNull(appointmentOrderInfo)) {
return AjaxResult.error("当前订单信息不存在,请重新选择!");
}
//商品订单
if (Objects.nonNull(goodsOrderInfo)) {
if (StringUtils.isBlank(goodsOrderInfo.getOrderStatus())
|| !GooodsOrderStatusEnum.WAIT_PAY.getInfo().equals(goodsOrderInfo.getOrderStatus())) {
log.info("订单状态为:====> {}", StringUtils.isBlank(goodsOrderInfo.getOrderStatus()) ? "不存在" : goodsOrderInfo.getOrderStatus());
return AjaxResult.error("当前订单状态异常,请联系管理员!");
}
LocalDateTime tenAfterTime = goodsOrderInfo.getOrderTime().plusMinutes(10);
if (LocalDateTime.now().isBefore(tenAfterTime)) {
return AjaxResult.error("10分钟以后才能取消当前订单请耐心等待");
}
OrderStatusInfoVO orderStatusInfoVO = new OrderStatusInfoVO();
OrderStatusInfoVO vo = this.queryGoodsOrderStatus(goodsOrderInfo.getOrderNo(), orderStatusInfoVO, buySource);
if (BooleanUtils.isTrue(vo.getPayFlag())) {
int statusCode = this.closeWeChatOrderInfo(goodsOrderInfo.getOrderNo(), goodsOrderInfo.getBuySource());
if (!(statusCode == HAVE_BODY_SUCCESS_CODE || statusCode == NO_HAVE_BODY_SUCCESS_CODE)) {
return AjaxResult.error("取消订单失败,请联系管理员!");
}
goodsOrderMapper.updateGoodsOrderStatus(GooodsOrderStatusEnum.CANCEL.getInfo(), orderNo);
}
}
//预约服务订单信息
if (Objects.nonNull(appointmentOrderInfo)) {
if (StringUtils.isBlank(appointmentOrderInfo.getOrderStatus())
|| !OrderStatusEnum.WAIT_PAY.getInfo().equals(appointmentOrderInfo.getOrderStatus())) {
log.info("订单状态为:====> {}", StringUtils.isBlank(appointmentOrderInfo.getOrderStatus()) ? "不存在" : appointmentOrderInfo.getOrderStatus());
return AjaxResult.error("当前订单状态异常,请联系管理员!");
}
LocalDateTime tenAfterTime = appointmentOrderInfo.getCreateTime().plusMinutes(10);
if (LocalDateTime.now().isBefore(tenAfterTime)) {
return AjaxResult.error("10分钟以后才能取消当前订单请耐心等待");
}
OrderStatusInfoVO orderStatusInfoVO = new OrderStatusInfoVO();
OrderStatusInfoVO vo = this.queryAppointmentOrderStatus(appointmentOrderInfo.getOrderNo(), orderStatusInfoVO);
if (BooleanUtils.isTrue(vo.getPayFlag())) {
int statusCode = this.closeWeChatOrderInfo(appointmentOrderInfo.getOrderNo(), BuySourceEnum.NURSE_STATION.getInfo());
if (!(statusCode == HAVE_BODY_SUCCESS_CODE || statusCode == NO_HAVE_BODY_SUCCESS_CODE)) {
return AjaxResult.error("取消订单失败,请联系管理员!");
}
appointmentOrderMapper.updateAppointmentOrderStatus(OrderStatusEnum.CANCEL.getInfo(), orderNo);
}
}
return AjaxResult.success("取消订单成功!");
}
/**
* 查询订单状态信息
*
* @param orderNo 点单编号
* @param buySource 购买来源
* @return 结果信息
* @throws Exception 异常信息
*/
@Override
public AjaxResult getOrderStatusInfo(String orderNo, String buySource) throws Exception {
OrderStatusInfoVO vo = new OrderStatusInfoVO();
GoodsOrder goodsOrder = goodsOrderMapper.getGoodsOrderByOrderNo(orderNo);
AppointmentOrder appointmentOrder = appointmentOrderMapper.getAppointmentOrderByOrderNo(orderNo);
if (Objects.isNull(goodsOrder) && Objects.isNull(appointmentOrder)) {
vo.setPayFlag(true);
return AjaxResult.success(vo);
}
//预约服务订单不为空调用微信查单接口确认订单状态
if (Objects.nonNull(appointmentOrder)) {
OrderStatusInfoVO order = new OrderStatusInfoVO();
vo = this.queryAppointmentOrderStatus(appointmentOrder.getOrderNo(), order);
}
//商品订单不为空调用微信查单接口确认订单状态
if (Objects.nonNull(goodsOrder)) {
OrderStatusInfoVO order = new OrderStatusInfoVO();
vo = this.queryGoodsOrderStatus(goodsOrder.getOrderNo(), order, buySource);
}
return AjaxResult.success(vo);
}
/**
* 微信关闭订单方法
*
* @param orderNo 订单编号
* @param buySource 购买来源
* @return 状态码
* @throws Exception 异常信息
*/
@Override
public int closeWeChatOrderInfo(String orderNo, String buySource) throws Exception {
String closeUrl = String.format(weChatPaymentUrlConfig.getCloseOrderUrl(), orderNo);
HttpPost httpPost = new HttpPost(closeUrl);
Map<String, Object> paramMap = new HashMap<>();
String jsonParams;
CloseableHttpResponse response = null;
if (BuySourceEnum.NURSE_STATION.getInfo().equals(buySource)) {
paramMap.put("mchid", xylWeChatPaymentConfig.getXylMchId());
jsonParams = JSON.toJSONString(paramMap);
StringEntity entity = new StringEntity(jsonParams, "utf-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
httpPost.setHeader("Accept", "application/json");
response = xinYiLuWeChatPayClient.execute(httpPost);
}
if (BuySourceEnum.SHOPPING_MALL.getInfo().equals(buySource)
|| BuySourceEnum.HEALTH_CONSULTATION.getInfo().equals(buySource) || BuySourceEnum.TRAINING.getInfo().equals(buySource)) {
paramMap.put("mchid", ylypWeChatPaymentConfig.getYlypMchId());
jsonParams = JSON.toJSONString(paramMap);
StringEntity entity = new StringEntity(jsonParams, "utf-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
httpPost.setHeader("Accept", "application/json");
response = yiLuYouPinWeChatPayClient.execute(httpPost);
}
try {
if (response == null) {
throw new ServiceException("获取微信HttpClient对象失败请联系管理员");
}
int statusCode = response.getStatusLine().getStatusCode();
switch (statusCode) {
case HAVE_BODY_SUCCESS_CODE:
log.info("微信关闭订单成功!");
break;
case NO_HAVE_BODY_SUCCESS_CODE:
log.info("微信关闭订单成功,无返回体!");
break;
default:
throw new ServiceException("微信关闭订单失败!");
}
return statusCode;
} finally {
if (response != null) {
response.close();
}
}
}
/**
* 查询预约服务订单状态
*
* @param orderNo 订单编号
* @param vo 返回值信息
*/
@Override
public OrderStatusInfoVO queryAppointmentOrderStatus(String orderNo, OrderStatusInfoVO vo) {
String requestUrl = String.format(weChatPaymentUrlConfig.getQueryMchIdUrl(), orderNo);
requestUrl = requestUrl.concat("?mchid=").concat(xylWeChatPaymentConfig.getXylMchId());
HttpGet httpGet = new HttpGet(requestUrl);
httpGet.setHeader("Accept", "application/json");
try (CloseableHttpResponse response = xinYiLuWeChatPayClient.execute(httpGet)) {
String responseBody = EntityUtils.toString(response.getEntity());
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HAVE_BODY_SUCCESS_CODE) {
WeChatQueryOrderVO weChatQueryOrderVO = JSONObject.parseObject(responseBody, WeChatQueryOrderVO.class);
vo.setPayFlag(StringUtils.isNotBlank(weChatQueryOrderVO.getTradeState())
&& WeChatTradeStateEnum.NOTPAY.getInfo().equals(weChatQueryOrderVO.getTradeState()));
vo.setTradeStatus(weChatQueryOrderVO.getTradeState());
vo.setWeChatQueryOrderVO(weChatQueryOrderVO);
} else if (statusCode == NO_HAVE_BODY_SUCCESS_CODE) {
log.warn("请求微信查单接口成功,无返回信息!");
} else {
throw new ServiceException("调用微信查询订单接口异常,响应码为:" + statusCode + ", 查询订单返回结果 = " + responseBody);
}
return vo;
} catch (Exception e) {
log.error("请求微信查单接口异常,异常信息为 ====> {}", e.getMessage());
throw new ServiceException("查询预约订单状态失败,请联系管理员!");
}
}
/**
* 查询上商品订单状态
*
* @param orderNo 订单编号
* @param vo 返回值信息
*/
@Override
public OrderStatusInfoVO queryGoodsOrderStatus(String orderNo, OrderStatusInfoVO vo,
String buySource) throws Exception {
String requestUrl = "";
if (BuySourceEnum.NURSE_STATION.getInfo().equals(buySource)) {
requestUrl = String.format(weChatPaymentUrlConfig.getQueryMchIdUrl(), orderNo).concat("?mchid=").concat(xylWeChatPaymentConfig.getXylMchId());
}
if (BuySourceEnum.SHOPPING_MALL.getInfo().equals(buySource)
|| BuySourceEnum.HEALTH_CONSULTATION.getInfo().equals(buySource) || BuySourceEnum.TRAINING.getInfo().equals(buySource)) {
requestUrl = String.format(weChatPaymentUrlConfig.getQueryMchIdUrl(), orderNo).concat("?mchid=").concat(ylypWeChatPaymentConfig.getYlypMchId());
}
HttpGet httpGet = new HttpGet(requestUrl);
httpGet.setHeader("Accept", "application/json");
CloseableHttpResponse response = null;
try {
if (BuySourceEnum.NURSE_STATION.getInfo().equals(buySource)) {
response = xinYiLuWeChatPayClient.execute(httpGet);
}
if (BuySourceEnum.SHOPPING_MALL.getInfo().equals(buySource)
|| BuySourceEnum.HEALTH_CONSULTATION.getInfo().equals(buySource) || BuySourceEnum.TRAINING.getInfo().equals(buySource)) {
response = yiLuYouPinWeChatPayClient.execute(httpGet);
}
if (response == null) {
throw new ServiceException("获取微信HttpClient对象失败请联系管理员");
}
String responseBody = EntityUtils.toString(response.getEntity());
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HAVE_BODY_SUCCESS_CODE) {
WeChatQueryOrderVO weChatQueryOrderVO = JSONObject.parseObject(responseBody, WeChatQueryOrderVO.class);
vo.setPayFlag(StringUtils.isNotBlank(weChatQueryOrderVO.getTradeState())
&& WeChatTradeStateEnum.NOTPAY.getInfo().equals(weChatQueryOrderVO.getTradeState()));
vo.setTradeStatus(weChatQueryOrderVO.getTradeState());
vo.setWeChatQueryOrderVO(weChatQueryOrderVO);
}
if (statusCode == NO_HAVE_BODY_SUCCESS_CODE) {
log.warn("请求微信查单接口成功,无返回信息!");
}
return vo;
} catch (Exception e) {
log.error("请求微信查单接口异常,异常信息为 ====> {}", e.getMessage());
throw new ServiceException("查询商品订单状态失败,请联系管理员!");
} finally {
if (response != null) {
response.close();
}
}
}
/**
* 构建商品订单JsApi微信下单参数
*
* @param paymentDTO 前端传值
* @param goodsOrderInfo 订单信息
* @return 下单参数json串
*/
private String buildGoodsOrderJsApiParams(PaymentDTO paymentDTO, GoodsOrder goodsOrderInfo) {
Map<String, Object> paramMap = new LinkedHashMap<>();
if (BuySourceEnum.NURSE_STATION.getInfo().equals(paymentDTO.getBuySource())) {
paramMap.put("mchid", xylWeChatPaymentConfig.getXylMchId());
paramMap.put("out_trade_no", goodsOrderInfo.getOrderNo());
paramMap.put("appid", appletChatConfig.getAppletId());
paramMap.put("description", XIN_YI_LU_DESCRIPTION);
paramMap.put("notify_url", xylWeChatPaymentConfig.getXylWeChatNotifyUrl() + XINYILU_WE_CHAT_NOTIFY_URL);
}
if (BuySourceEnum.SHOPPING_MALL.getInfo().equals(paymentDTO.getBuySource()) || BuySourceEnum.HEALTH_CONSULTATION.getInfo().equals(paymentDTO.getBuySource())) {
paramMap.put("mchid", ylypWeChatPaymentConfig.getYlypMchId());
paramMap.put("out_trade_no", goodsOrderInfo.getOrderNo());
paramMap.put("appid", appletChatConfig.getAppletId());
paramMap.put("description", YI_LU_YOU_PIN_DESCRIPTION);
paramMap.put("notify_url", ylypWeChatPaymentConfig.getYlypWeChatNotifyUrl() + YINLUYOUPIN_WE_CHAT_NOTIFY_URL);
}
Map<String, Object> amountParamMap = new LinkedHashMap<>();
int totalPrice = paymentDTO.getPaymentPrice().multiply(BigDecimal.valueOf(100)).intValue();
amountParamMap.put("total", totalPrice);
amountParamMap.put("currency", "CNY");
paramMap.put("amount", amountParamMap);
Map<String, Object> payerParamMap = new LinkedHashMap<>();
payerParamMap.put("openid", paymentDTO.getOpenid());
paramMap.put("payer", payerParamMap);
return JSON.toJSONString(paramMap);
}
/**
* 请求JsApi下单接口方法
*
* @param jsApiParams 下单参数
* @param paymentDTO 输入参数
* @param prepayId JsAp下单接口返回值
* @return 结果
* @throws Exception 异常信息
*/
private String requestJsApiInterface(String jsApiParams, PaymentDTO paymentDTO, String prepayId) throws Exception {
StringEntity stringEntity = new StringEntity(jsApiParams, StandardCharsets.UTF_8);
stringEntity.setContentType("application/json");
HttpPost httpPost = new HttpPost(weChatPaymentUrlConfig.getJsapiPalceOrderUrl());
httpPost.setEntity(stringEntity);
httpPost.setHeader("Accept", "application/json");
CloseableHttpResponse response = null;
String payAccount = "";
try {
if (BuySourceEnum.NURSE_STATION.getInfo().equals(paymentDTO.getBuySource())) {
response = xinYiLuWeChatPayClient.execute(httpPost);
payAccount = "山东新医路信息科技有限公司";
}
//泉医会员小程序中的商城订单健康咨询订单泉医助手学习培训订单都使用医路优品账户进行支付
if (BuySourceEnum.SHOPPING_MALL.getInfo().equals(paymentDTO.getBuySource())
|| BuySourceEnum.HEALTH_CONSULTATION.getInfo().equals(paymentDTO.getBuySource())
|| BuySourceEnum.TRAINING.getInfo().equals(paymentDTO.getBuySource())) {
response = yiLuYouPinWeChatPayClient.execute(httpPost);
payAccount = "医路优品信息科技有限公司";
}
if (Objects.isNull(response)) {
log.error("JsApi下单接口执行错误 执行账户为 ====> {}", payAccount);
throw new ServiceException("JsApi下单接口执行异常请联系管理员");
}
int statusCode = response.getStatusLine().getStatusCode();
String result = EntityUtils.toString(response.getEntity());
if (statusCode == HAVE_BODY_SUCCESS_CODE) {
Map<String, Object> resultMap = JSONObject.parseObject(result);
prepayId = resultMap.getOrDefault("prepay_id", "").toString();
redisTemplate.opsForValue().set(Constants.PREPAY_ID_KEY + paymentDTO.getOrderNo(), prepayId, 5400, TimeUnit.SECONDS);
} else if (statusCode == NO_HAVE_BODY_SUCCESS_CODE) {
log.info("JsApi下单成功无返回值信息");
} else {
log.error("JsApi下单失败失败原因为 ====> {}", result);
throw new ServiceException("JsApi下单失败失败原因为" + result);
}
} catch (Exception e) {
log.error("JsApi下单失败失败原因 =====> {}", e.getMessage());
throw new ServiceException("JsApi下单失败请联系管理员");
} finally {
if (response != null) {
response.close();
}
}
return prepayId;
}
/**
* 构建微信小程序调起支付参数设置
*
* @param prepayId jsapi下单返回参数信息
* @param buySource 购买来源
* @return 参数信息
* @throws Exception 异常信息
*/
private WeChatAppletSignVO getSignInfo(String prepayId, String buySource) throws Exception {
String appId = appletChatConfig.getAppletId();
String nonceStr = UUID.randomUUID().toString().replace("-", "");
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
PrivateKey privateKey = null;
//泉医到家小程序中的护理站模块的支付账户均使用新医路账户进行支付
if (BuySourceEnum.NURSE_STATION.getInfo().equals(buySource)) {
privateKey = weChatUtil.getPrivateKey(xylWeChatPaymentConfig.getXylPrivateKeyPath());
}
//泉医到家小程序中的商城模块和健康咨询模块以及泉医助手中的学习培训模块使用医路优品账户进行支付
if (BuySourceEnum.SHOPPING_MALL.getInfo().equals(buySource)
|| BuySourceEnum.HEALTH_CONSULTATION.getInfo().equals(buySource)
|| BuySourceEnum.TRAINING.getInfo().equals(buySource)) {
privateKey = weChatUtil.getPrivateKey(ylypWeChatPaymentConfig.getYlypPrivateKeyPath());
}
if (privateKey == null) {
throw new ServiceException("获取商户私钥失败,请联系管理员!");
}
prepayId = "prepay_id=" + prepayId;
String signatureStr = Stream.of(appId, timestamp, nonceStr, prepayId)
.collect(Collectors.joining("\n", "", "\n"));
log.info("计算签名认证信息 =====> {}", signatureStr);
Signature sign = Signature.getInstance(SIGNATURE_ALGORITHM);
sign.initSign(privateKey);
sign.update(signatureStr.getBytes(StandardCharsets.UTF_8));
String paySign = Base64Utils.encodeToString(sign.sign());
return WeChatAppletSignVO.builder().appId(appId).timeStamp(timestamp).nonceStr(nonceStr).prepayId(prepayId)
.signType(SIGN_TYPE).paySign(paySign).build();
}
/**
* 构建预约订单JsApi微信下单参数
*
* @param paymentDTO 前端传值
* @param appointmentOrder 预约订单信息
* @return 下单参数json串
*/
private String buildAppointmentOrderJsApiParams(PaymentDTO paymentDTO, AppointmentOrder appointmentOrder) {
Map<String, Object> paramMap = new LinkedHashMap<>();
paramMap.put("mchid", xylWeChatPaymentConfig.getXylMchId());
paramMap.put("out_trade_no", appointmentOrder.getOrderNo());
paramMap.put("appid", appletChatConfig.getAppletId());
paramMap.put("description", XIN_YI_LU_DESCRIPTION);
paramMap.put("notify_url", xylWeChatPaymentConfig.getXylWeChatNotifyUrl() + XINYILU_WE_CHAT_NOTIFY_URL);
Map<String, Object> amountParamMap = new LinkedHashMap<>();
int totalPrice = appointmentOrder.getTotalPrice().multiply(BigDecimal.valueOf(100)).intValue();
amountParamMap.put("total", totalPrice);
amountParamMap.put("currency", "CNY");
paramMap.put("amount", amountParamMap);
Map<String, Object> payerParamMap = new LinkedHashMap<>();
payerParamMap.put("openid", paymentDTO.getOpenid());
paramMap.put("payer", payerParamMap);
return JSON.toJSONString(paramMap);
}
}

View File

@ -0,0 +1,451 @@
package com.xinelu.applet.service.wechatpaymentinfo.impl;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.xinelu.applet.service.goodstock.GoodsStockService;
import com.xinelu.applet.service.wechatpaymentinfo.WeChatRefundService;
import com.xinelu.applet.vo.wechatpaymentinfo.dto.RefundDTO;
import com.xinelu.applet.vo.wechatpaymentinfo.vo.WeChatRefundInfoVO;
import com.xinelu.common.config.WeChatPaymentUrlConfig;
import com.xinelu.common.config.XylWeChatPaymentConfig;
import com.xinelu.common.config.YlypWeChatPaymentConfig;
import com.xinelu.common.core.domain.AjaxResult;
import com.xinelu.common.enums.*;
import com.xinelu.common.exception.ServiceException;
import com.xinelu.manage.domain.appointmentorder.AppointmentOrder;
import com.xinelu.manage.domain.goodsOrder.GoodsOrder;
import com.xinelu.manage.domain.patientintegralchange.PatientIntegralChange;
import com.xinelu.manage.domain.refundinfo.RefundInfo;
import com.xinelu.manage.mapper.appointmentorder.AppointmentOrderMapper;
import com.xinelu.manage.mapper.goodsOrder.GoodsOrderMapper;
import com.xinelu.manage.mapper.patientinfo.PatientInfoMapper;
import com.xinelu.manage.mapper.patientintegralchange.PatientIntegralChangeMapper;
import com.xinelu.manage.mapper.refundinfo.RefundInfoMapper;
import com.xinelu.manage.vo.goodsorder.GoodsInfoRedemptionVO;
import com.xinelu.manage.vo.patientinfo.PatientInfoVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
/**
* @Description 微信退款业务层实现类
* @Author 纪寒
* @Date 2022-10-24 15:23:16
* @Version 1.0
*/
@Slf4j
@Service
public class WeChatRefundServiceImpl implements WeChatRefundService {
@Resource
private GoodsOrderMapper goodsOrderMapper;
@Resource
private AppointmentOrderMapper appointmentOrderMapper;
@Resource
private XylWeChatPaymentConfig xylWeChatPaymentConfig;
@Resource
private YlypWeChatPaymentConfig ylypWeChatPaymentConfig;
@Resource(name = "xinYiLuWeChatPayClient")
private CloseableHttpClient xinYiLuWeChatPayClient;
@Resource(name = "yiLuYouPinWeChatPayClient")
private CloseableHttpClient yiLuYouPinWeChatPayClient;
@Resource
private WeChatPaymentUrlConfig weChatPaymentUrlConfig;
@Resource
private RefundInfoMapper refundInfoMapper;
@Resource
private GoodsStockService goodsStockService;
@Resource
private PatientIntegralChangeMapper patientIntegralChangeMapper;
@Resource
private PatientInfoMapper patientInfoMapper;
/**
* 成功状态码
*/
private static final int HAVE_BODY_SUCCESS_CODE = 200;
/**
* 成功状态码
*/
private static final int NO_HAVE_BODY_SUCCESS_CODE = 204;
/**
* 新医路退款回调接口地址
*/
private static final String XINYILU_WE_CHAT_REFUND_URL = "/nurseApp/weChatPayment/xylWeChatRefundNotify";
/**
* 医路优品退款回调接口地址
*/
private static final String YINLUYOUPIN_WE_CHAT_REFUND_URL = "/nurseApp/weChatPayment/ylypWeChatRefundNotify";
/**
* 微信确认退款接口
*
* @param refundDTO 退款参数
* @return 退款申请结果
* @throws Exception 异常信息
*/
@Transactional(rollbackFor = Exception.class)
@Override
public AjaxResult weChatRefundOrderApply(RefundDTO refundDTO) throws Exception {
if (StringUtils.isNotBlank(refundDTO.getOrderType()) && StringUtils.equals(OrderTypeEnum.INTEGRAL_EXCHANGE.getInfo(), refundDTO.getOrderType())) {
return refundPointsRedemption(refundDTO);
}
AppointmentOrder appointmentOrderInfo = appointmentOrderMapper.getAppointmentOrderByOrderNo(refundDTO.getOrderNo());
if (Objects.nonNull(appointmentOrderInfo)) {
AjaxResult ajaxResult = judgeRefundInfo(appointmentOrderInfo.getCreateTime(), refundDTO.getRefundPrice(), appointmentOrderInfo.getTotalPrice());
if (Objects.nonNull(ajaxResult)) {
return ajaxResult;
}
if (StringUtils.isBlank(appointmentOrderInfo.getConfirmRefundStatus())
|| !(ConfirmRefundStatusEnum.NOT_CONFIRM.getInfo().equals(appointmentOrderInfo.getConfirmRefundStatus()))) {
return AjaxResult.error("当前预约订单未进行退款确认,请先进行确认!");
}
if (StringUtils.isBlank(appointmentOrderInfo.getOrderStatus())
|| !OrderStatusEnum.WAIT_REFUND.getInfo().equals(appointmentOrderInfo.getOrderStatus())
|| OrderStatusEnum.REFUNDED.getInfo().equals(appointmentOrderInfo.getOrderStatus())) {
return AjaxResult.error("当前预约订单正在退款中或者已退款,无法进行退款处理!");
}
Long patientId = Objects.isNull(appointmentOrderInfo.getPatientId()) ? 0 : appointmentOrderInfo.getPatientId();
String outRefundNo = com.xinelu.common.utils.StringUtils.fillZeroByPatientId(patientId, 5) + System.nanoTime();
String refundParam = buildRefundParam(null, appointmentOrderInfo, refundDTO, outRefundNo);
this.applyWeRefund(refundParam, appointmentOrderInfo, null, patientId, refundDTO);
return AjaxResult.success();
}
GoodsOrder goodsOrderInfo = goodsOrderMapper.getGoodsOrderByOrderNo(refundDTO.getOrderNo());
if (Objects.nonNull(goodsOrderInfo)) {
AjaxResult ajaxResult = judgeRefundInfo(goodsOrderInfo.getOrderTime(), refundDTO.getRefundPrice(), goodsOrderInfo.getTotalPrice());
if (Objects.nonNull(ajaxResult)) {
return ajaxResult;
}
if (StringUtils.isBlank(goodsOrderInfo.getConfirmRefundStatus())
|| !(ConfirmRefundStatusEnum.NOT_CONFIRM.getInfo().equals(goodsOrderInfo.getConfirmRefundStatus()))) {
return AjaxResult.error("当前商品订单未进行退款确认,请先进行确认!");
}
if (StringUtils.isBlank(goodsOrderInfo.getOrderStatus())
|| !GooodsOrderStatusEnum.WAIT_REFUND.getInfo().equals(goodsOrderInfo.getOrderStatus())
|| GooodsOrderStatusEnum.REFUNDED.getInfo().equals(goodsOrderInfo.getOrderStatus())) {
return AjaxResult.error("当前商品订单非退款中或者已退款,无法进行退款处理!");
}
Long patientId = Objects.isNull(goodsOrderInfo.getPatientId()) ? 0 : goodsOrderInfo.getPatientId();
String outRefundNo = com.xinelu.common.utils.StringUtils.fillZeroByPatientId(patientId, 5) + System.nanoTime();
String refundParam = buildRefundParam(goodsOrderInfo, null, refundDTO, outRefundNo);
this.applyWeRefund(refundParam, null, goodsOrderInfo, patientId, refundDTO);
return AjaxResult.success();
}
return AjaxResult.success();
}
/**
* 调用微信查询单笔退款接口查询预约订单状态信息
*
* @param refundNo 退款单号
* @return 退款信息
*/
@Override
public WeChatRefundInfoVO queryAppointmentOrderRefundStatus(String refundNo) {
WeChatRefundInfoVO weChatRefundInfoVO = new WeChatRefundInfoVO();
String requestUrl = String.format(weChatPaymentUrlConfig.getRefundQueryOrderUrl(), refundNo);
HttpGet httpGet = new HttpGet(requestUrl);
httpGet.setHeader("Accept", "application/json");
try (CloseableHttpResponse response = xinYiLuWeChatPayClient.execute(httpGet)) {
String body = EntityUtils.toString(response.getEntity());
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HAVE_BODY_SUCCESS_CODE) {
weChatRefundInfoVO = JSONObject.parseObject(body, WeChatRefundInfoVO.class);
} else if (statusCode == NO_HAVE_BODY_SUCCESS_CODE) {
log.warn("请求微信查询单笔退款接口成功,无返回信息!");
} else {
throw new ServiceException("调用微信查询单笔退款接口异常,响应码为:" + statusCode + ", 查询退款返回结果 = " + body);
}
return weChatRefundInfoVO;
} catch (Exception e) {
log.error("请求微信查询单笔退款接口异常,异常信息为 ====> {}", e.getMessage());
throw new ServiceException("查询预约订单状态失败,请联系管理员!");
}
}
/**
* 调用微信查询单笔退款接口查询商品订单状态信息
*
* @param refundNo 退单编号
* @param buySource 购买来源
* @return 退款信息
* @throws Exception 异常信息
*/
@Override
public WeChatRefundInfoVO queryGoodsOrderRefundStatus(String refundNo, String buySource) throws Exception {
WeChatRefundInfoVO weChatRefundInfoVO = new WeChatRefundInfoVO();
String requestUrl = String.format(weChatPaymentUrlConfig.getRefundQueryOrderUrl(), refundNo);
HttpGet httpGet = new HttpGet(requestUrl);
httpGet.setHeader("Accept", "application/json");
CloseableHttpResponse response = null;
try {
if (BuySourceEnum.NURSE_STATION.getInfo().equals(buySource)) {
response = xinYiLuWeChatPayClient.execute(httpGet);
}
if (BuySourceEnum.SHOPPING_MALL.getInfo().equals(buySource)
|| BuySourceEnum.HEALTH_CONSULTATION.getInfo().equals(buySource) || BuySourceEnum.TRAINING.getInfo().equals(buySource)) {
response = yiLuYouPinWeChatPayClient.execute(httpGet);
}
if (response == null) {
throw new ServiceException("获取微信HttpClient对象失败请联系管理员");
}
String body = EntityUtils.toString(response.getEntity());
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HAVE_BODY_SUCCESS_CODE) {
weChatRefundInfoVO = JSONObject.parseObject(body, WeChatRefundInfoVO.class);
} else if (statusCode == NO_HAVE_BODY_SUCCESS_CODE) {
log.warn("请求微信查询单笔退款接口成功,无返回信息!");
} else {
throw new ServiceException("调用微信查询单笔退款接口异常,响应码为:" + statusCode + ", 查询退款返回结果 = " + body);
}
return weChatRefundInfoVO;
} catch (Exception e) {
log.error("请求微信查询单笔退款接口,异常信息为 ====> {}", e.getMessage());
throw new ServiceException("查询商品订单状态失败,请联系管理员!");
} finally {
if (response != null) {
response.close();
}
}
}
/**
* 退款参数检验
*
* @param orderTime 下单时间
* @param refundPrice 退款金额
* @param totalPrice 支付总金额
* @return 返回结果信息
*/
private AjaxResult judgeRefundInfo(LocalDateTime orderTime, BigDecimal refundPrice, BigDecimal totalPrice) {
LocalDateTime localDateTime = orderTime.plusYears(1);
if (LocalDateTime.now().isAfter(localDateTime)) {
return AjaxResult.error("当前订单超过一年,无法进行退款处理!");
}
if (refundPrice.compareTo(totalPrice) > 0) {
return AjaxResult.error("当前退款金额大于订单支付金额,无法进行退款处理!");
}
return null;
}
/**
* 构建微信退款参数信息
*
* @param goodsOrderInfo 商品订单信息
* @param appointmentOrderInfo 预约服务订单信息
* @param refundDTO 退款参数信息
* @return 退款申请Json串
*/
private String buildRefundParam(GoodsOrder goodsOrderInfo, AppointmentOrder appointmentOrderInfo,
RefundDTO refundDTO, String outRefundNo) {
Map<String, Object> paramMap = new LinkedHashMap<>();
paramMap.put("out_trade_no", refundDTO.getOrderNo());
paramMap.put("out_refund_no", outRefundNo);
Map<String, Object> amountMap = new LinkedHashMap<>();
//回调通知地址和退款金额预约订单使用新医路账户
if (Objects.nonNull(appointmentOrderInfo) && Objects.isNull(goodsOrderInfo)) {
paramMap.put("notify_url", xylWeChatPaymentConfig.getXylWeChatNotifyUrl() + XINYILU_WE_CHAT_REFUND_URL);
amountMap.put("refund", refundDTO.getRefundPrice().multiply(BigDecimal.valueOf(100)).intValue());
amountMap.put("total", appointmentOrderInfo.getTotalPrice().multiply(BigDecimal.valueOf(100)).intValue());
}
//护理站商品购买订单使用新医路账户商城商品订单和健康咨询订单使用医路优品账户
if (Objects.nonNull(goodsOrderInfo) && Objects.isNull(appointmentOrderInfo)) {
if (BuySourceEnum.NURSE_STATION.getInfo().equals(goodsOrderInfo.getBuySource())) {
paramMap.put("notify_url", xylWeChatPaymentConfig.getXylWeChatNotifyUrl() + XINYILU_WE_CHAT_REFUND_URL);
}
if (BuySourceEnum.SHOPPING_MALL.getInfo().equals(goodsOrderInfo.getBuySource()) || BuySourceEnum.HEALTH_CONSULTATION.getInfo().equals(goodsOrderInfo.getBuySource())) {
paramMap.put("notify_url", ylypWeChatPaymentConfig.getYlypWeChatNotifyUrl() + YINLUYOUPIN_WE_CHAT_REFUND_URL);
}
amountMap.put("refund", refundDTO.getRefundPrice().multiply(BigDecimal.valueOf(100)).intValue());
amountMap.put("total", goodsOrderInfo.getTotalPrice().multiply(BigDecimal.valueOf(100)).intValue());
}
amountMap.put("currency", "CNY");
paramMap.put("amount", amountMap);
return JSON.toJSONString(paramMap);
}
/**
* 发起退款申请
*
* @param refundParam 请求参数
* @param appointmentOrderInfo 预约服务订单信息
* @param goodsOrderInfo 商品订单信息
* @param patientId 会员id
* @param refundDTO 申请信息
* @throws Exception 异常信息
*/
public void applyWeRefund(String refundParam, AppointmentOrder appointmentOrderInfo, GoodsOrder goodsOrderInfo,
Long patientId, RefundDTO refundDTO) throws Exception {
String requestUrl = weChatPaymentUrlConfig.getRefundApplyUrl();
HttpPost httpPost = new HttpPost(requestUrl);
StringEntity entity = new StringEntity(refundParam, "utf-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
httpPost.setHeader("Accept", "application/json");
CloseableHttpResponse response = null;
String refundMerchantType = "";
try {
//预约订单使用新医路账户
if (Objects.nonNull(appointmentOrderInfo) && Objects.isNull(goodsOrderInfo)) {
response = xinYiLuWeChatPayClient.execute(httpPost);
refundMerchantType = PaymentMerchantTypeEnum.XINYILU.getInfo();
}
//护理站商品购买订单使用新医路账户商城商品订单和健康咨询订单使用医路优品账户
if (Objects.nonNull(goodsOrderInfo) && Objects.isNull(appointmentOrderInfo)) {
if (BuySourceEnum.NURSE_STATION.getInfo().equals(goodsOrderInfo.getBuySource())) {
response = xinYiLuWeChatPayClient.execute(httpPost);
refundMerchantType = PaymentMerchantTypeEnum.XINYILU.getInfo();
}
if (BuySourceEnum.SHOPPING_MALL.getInfo().equals(goodsOrderInfo.getBuySource()) || BuySourceEnum.HEALTH_CONSULTATION.getInfo().equals(goodsOrderInfo.getBuySource())) {
response = yiLuYouPinWeChatPayClient.execute(httpPost);
refundMerchantType = PaymentMerchantTypeEnum.YILUYOUPIN.getInfo();
}
}
if (Objects.isNull(response)) {
throw new ServiceException("获取httpclient对象失败");
}
int statusCode = response.getStatusLine().getStatusCode();
String body = EntityUtils.toString(response.getEntity());
if (statusCode != HAVE_BODY_SUCCESS_CODE && statusCode != NO_HAVE_BODY_SUCCESS_CODE) {
throw new ServiceException("微信申请退款异常, 响应码:" + statusCode + ", 退款返回结果:" + body);
}
if (Objects.nonNull(appointmentOrderInfo)) {
appointmentOrderMapper.updateAppointConfirmRefundStatus(appointmentOrderInfo.getOrderNo(), ConfirmRefundStatusEnum.CONFIRMED.getInfo());
}
if (Objects.nonNull(goodsOrderInfo)) {
goodsOrderMapper.updateGoodsConfirmRefundStatus(goodsOrderInfo.getOrderNo(), ConfirmRefundStatusEnum.CONFIRMED.getInfo());
}
WeChatRefundInfoVO weChatRefundInfoVO = JSONObject.parseObject(body, WeChatRefundInfoVO.class);
int refundInfoCount = refundInfoMapper.getRefundInfoByOrderNo(weChatRefundInfoVO.getOutTradeNo());
if (refundInfoCount <= 0) {
RefundInfo refundInfo = buildRefundInfo(patientId, weChatRefundInfoVO, refundDTO, body, refundMerchantType);
int insertCunt = refundInfoMapper.insertRefundInfo(refundInfo);
if (insertCunt <= 0) {
throw new ServiceException("记录退款信息失败,请联系管理员!");
}
}
} catch (Exception e) {
log.error("微信申请退款接口出错,原因:{}", e.getMessage());
} finally {
if (response != null) {
response.close();
}
}
}
/**
* 构建微信退款信息
*
* @param patientId 会员id
* @param refundInfoVO 退款信息参数
* @param refundDTO 退款申请参数
* @param refundBody 返回体
* @param refundMerchantType 退款账户类型新医路或者医路优品
*/
private RefundInfo buildRefundInfo(Long patientId, WeChatRefundInfoVO refundInfoVO,
RefundDTO refundDTO, String refundBody, String refundMerchantType) {
RefundInfo refundInfo = new RefundInfo();
refundInfo.setPatientId(patientId);
refundInfo.setOrderNo(refundInfoVO.getOutTradeNo());
refundInfo.setRefundNo(refundInfoVO.getRefundId());
refundInfo.setOutRefundNo(refundInfoVO.getOutRefundNo());
refundInfo.setTransactionNo(StringUtils.isBlank(refundInfoVO.getTransactionId()) ? "" : refundInfoVO.getTransactionId());
refundInfo.setRefundReason(StringUtils.isBlank(refundDTO.getRefundReason()) ? "" : refundDTO.getRefundReason());
refundInfo.setRefundType(RefundTypeEnum.WE_CHAT.getInfo());
refundInfo.setWechatRefundStatus(RefundStatusEnum.PROCESSING.getInfo());
refundInfo.setOrderTotalPrice(BigDecimal.valueOf(refundInfoVO.getAmount().getTotal()).divide(BigDecimal.valueOf(100), 2, BigDecimal.ROUND_DOWN));
refundInfo.setRefundPrice(BigDecimal.valueOf(refundInfoVO.getAmount().getRefund()).divide(BigDecimal.valueOf(100), 2, BigDecimal.ROUND_DOWN));
refundInfo.setCurrency(refundInfoVO.getAmount().getCurrency());
refundInfo.setChannel(refundInfoVO.getChannel());
refundInfo.setUserreceivedaccount(refundInfoVO.getUserReceivedAccount());
refundInfo.setSuccessTime(StringUtils.isBlank(refundInfoVO.getSuccessTime()) ? null : LocalDateTime.parse(refundInfoVO.getSuccessTime(), DateTimeFormatter.ISO_DATE_TIME));
refundInfo.setApplyRefundReturnContent(refundBody);
refundInfo.setRefundMerchantType(refundMerchantType);
refundInfo.setDelFlag(0);
refundInfo.setCreateTime(LocalDateTime.parse(refundInfoVO.getCreateTime(), DateTimeFormatter.ISO_DATE_TIME));
return refundInfo;
}
/**
* 会员积分兑换商品确认退款接口
*
* @param refundDTO 退款参数
* @return com.xinyilu.common.core.domain.AjaxResult
**/
public AjaxResult refundPointsRedemption(RefundDTO refundDTO) {
GoodsInfoRedemptionVO goodsOrderInfo = goodsOrderMapper.getGoodOrder(refundDTO.getOrderNo());
if (Objects.isNull(goodsOrderInfo)) {
return AjaxResult.error("当前订单信息不存在,请重新选择!");
}
PatientInfoVO patientInfo = patientInfoMapper.getPatientInfoById(goodsOrderInfo.getPatientId());
if (Objects.isNull(patientInfo)) {
return AjaxResult.error("当前用户信息不存在,无法退款!");
}
AjaxResult ajaxResult = goodIntegralVerification(goodsOrderInfo);
if (Objects.nonNull(ajaxResult)) {
return ajaxResult;
}
goodsOrderMapper.updateConfirmRefundStatusAndOrderStatus(refundDTO.getOrderNo(), ConfirmRefundStatusEnum.CONFIRMED.getInfo(), OrderStatusEnum.REFUNDED.getInfo());
Integer stockNum = Objects.isNull(goodsOrderInfo.getIntegralExchangeCount()) ? 0 : goodsOrderInfo.getIntegralExchangeCount();
goodsStockService.addGoodsStockInfo(goodsOrderInfo.getOrderNo(), goodsOrderInfo.getGoodsAttributeDetailsId(), stockNum);
int stockIntegralNum = Objects.isNull(goodsOrderInfo.getIntegralExchangeSill()) ? 0 : goodsOrderInfo.getIntegralExchangeSill();
patientInfoMapper.addPatientIntegralCount(goodsOrderInfo.getPatientId(), stockIntegralNum);
PatientIntegralChange patientIntegralChange = new PatientIntegralChange();
patientIntegralChange.setPatientId(goodsOrderInfo.getPatientId());
patientIntegralChange.setOriginalIntegral(Objects.isNull(patientInfo.getIntegral()) ? 0 : patientInfo.getIntegral());
patientIntegralChange.setChangeIntegral(stockIntegralNum);
patientIntegralChange.setChangeTime(LocalDateTime.now());
patientIntegralChange.setChangeType(IntegralChangeType.COMMODITY_EXCHANGE.getInfo());
patientIntegralChange.setChangeRemark("积分兑换商品订单新增积分变更");
patientIntegralChange.setChangeIntegralChannel(StringUtils.isBlank(goodsOrderInfo.getOrderChannel()) ? "" : goodsOrderInfo.getOrderChannel());
patientIntegralChange.setCreateTime(LocalDateTime.now());
int integralChange = patientIntegralChangeMapper.insertPatientIntegralChange(patientIntegralChange);
if (integralChange <= 0) {
log.error("积分兑换商品-生成积分变更记录表信息失败,积分变更信息:{}", integralChange);
throw new ServiceException("确认退款失败,请联系管理员!");
}
return AjaxResult.success();
}
/**
* 校验积分兑换商品订单状态以及订单时间等下信息
*
* @return 返回结果信息
*/
private AjaxResult goodIntegralVerification(GoodsInfoRedemptionVO goodsOrderInfo) {
LocalDateTime localDateTime = goodsOrderInfo.getOrderTime().plusYears(1);
if (LocalDateTime.now().isAfter(localDateTime)) {
return AjaxResult.error("当前订单超过一年,无法进行退款处理!");
}
if (StringUtils.isBlank(goodsOrderInfo.getConfirmRefundStatus())
|| !ConfirmRefundStatusEnum.NOT_CONFIRM.getInfo().equals(goodsOrderInfo.getConfirmRefundStatus())) {
return AjaxResult.error("当前商品订单未进行退款确认,请先进行确认!");
}
if (StringUtils.isBlank(goodsOrderInfo.getOrderStatus())
|| !GooodsOrderStatusEnum.WAIT_REFUND.getInfo().equals(goodsOrderInfo.getOrderStatus())
|| GooodsOrderStatusEnum.REFUNDED.getInfo().equals(goodsOrderInfo.getOrderStatus())) {
return AjaxResult.error("当前商品订单非退款中或者已退款,无法进行退款处理!");
}
return null;
}
}

View File

@ -1,7 +1,6 @@
package com.xinelu.applet.utils;
import com.xinelu.common.config.AppletChatConfig;
import com.xinelu.common.config.NurseAppletChatConfig;
import com.xinelu.common.constant.Constants;
import com.xinelu.common.entity.AppletAccessToken;
import com.xinelu.common.exception.ServiceException;
@ -27,8 +26,7 @@ public class AppletAccessTokenUtil {
private RedisTemplate<String, Object> redisTemplate;
@Resource
private AppletChatConfig appletChatConfig;
@Resource
private NurseAppletChatConfig nurseAppletChatConfig;
/**
* 返回成功状态码
*/
@ -65,34 +63,4 @@ public class AppletAccessTokenUtil {
return accessToken;
}
/**
* 护理员小程序获取小程序AccessToken方法
*
* @return 小程序的AccessToken
*/
public String getPersonAppletAccessToken() {
String accessToken;
String accessTokenKey = Constants.NURSE_STATION_PERSON_APPLET_ACCESS_TOKEN + "accessToken";
//从Redis中取出accessToken
Object object = redisTemplate.opsForValue().get(accessTokenKey);
if (Objects.isNull(object)) {
//没有获取accessToken
AppletAccessToken appletAccessToken = AppletChatUtil.getAppletAccessToken(nurseAppletChatConfig.getAppletId(), nurseAppletChatConfig.getSecret());
if (Objects.isNull(appletAccessToken)) {
throw new ServiceException("获取微信小程序accessToken信息失败");
}
if (Objects.nonNull(appletAccessToken.getErrcode()) && appletAccessToken.getErrcode() != SUCCESS_CODE) {
throw new ServiceException("获取微信小程序accessToken信息失败失败信息为" + appletAccessToken.getErrmsg(), 201);
}
if (StringUtils.isBlank(appletAccessToken.getAccessToken())) {
throw new ServiceException("accessToken信息为空");
}
//存入Redis中
redisTemplate.opsForValue().set(accessTokenKey, appletAccessToken.getAccessToken(), 3600, TimeUnit.SECONDS);
accessToken = appletAccessToken.getAccessToken();
} else {
accessToken = (String) object;
}
return accessToken;
}
}

View File

@ -0,0 +1,145 @@
package com.xinelu.applet.utils;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import com.xinelu.common.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Map;
/**
* @Description 快递鸟物流查询工具类
* @Author 纪寒
* @Date 2022-11-01 13:43:03
* @Version 1.0
*/
@Slf4j
public class LogisticsUtil {
/**
* 发送POST请求
*
* @param url 请求地址
* @param params 请求参数
* @return 返回结果信息
* @throws Exception 异常信息
*/
public static String sendPost(String url, Map<String, String> params) throws Exception {
OutputStreamWriter out = null;
BufferedReader in = null;
StringBuilder result = new StringBuilder();
try {
URL realUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
//发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setRequestMethod("POST");
//设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.connect();
//获取URLConnection对象对应的输出流
out = new OutputStreamWriter(conn.getOutputStream(), StandardCharsets.UTF_8);
StringBuilder param = new StringBuilder();
for (Map.Entry<String, String> entry : params.entrySet()) {
if (param.length() > 0) {
param.append("&");
}
param.append(entry.getKey());
param.append("=");
param.append(entry.getValue());
}
out.write(param.toString());
out.flush();
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
String line;
while ((line = in.readLine()) != null) {
result.append(line);
}
} catch (Exception e) {
log.error("调用快递鸟识别单号异常,异常信息:{}", e.getMessage());
throw new ServiceException("查询物流信息出错,请联系管理员!");
} finally {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
}
return result.toString();
}
/**
* sign签名生成
*
* @param content 内容
* @param keyValue ApiKey
* @param charset 编码方式
* @return 签名信息
* @throws Exception 异常信息
*/
public static String encrypt(String content, String keyValue, String charset) throws Exception {
if (keyValue != null) {
return base64(logisticsMd5(content + keyValue, charset), charset);
}
return base64(logisticsMd5(content, charset), charset);
}
/**
* 编码格式信息
*
* @param content 内容
* @param charset 字符集
* @return 编码结果信息
* @throws Exception 异常信息
*/
public static String urlEncoder(String content, String charset) throws Exception {
return URLEncoder.encode(content, charset);
}
/**
* base64编码
*
* @param content 内容
* @param charset 编码方式
* @return 编码结果信息
* @throws Exception 异常信息
*/
public static String base64(String content, String charset) throws Exception {
return Base64.encode(content.getBytes(charset));
}
/**
* MD5加密
*
* @param content 内容
* @param charset 编码方式
* @return 结果
* @throws Exception 异常信息
*/
public static String logisticsMd5(String content, String charset) throws Exception {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(content.getBytes(charset));
byte[] result = md.digest();
StringBuilder sb = new StringBuilder(32);
for (byte b : result) {
int val = b & 0xff;
if (val <= 0xf) {
sb.append("0");
}
sb.append(Integer.toHexString(val));
}
return sb.toString().toLowerCase();
}
}

View File

@ -0,0 +1,35 @@
package com.xinelu.applet.utils;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import com.xinelu.common.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import java.security.PrivateKey;
/**
* @Description 微信工具类
* @Author 纪寒
* @Date 2022-10-20 10:11:38
* @Version 1.0
*/
@Component
@Slf4j
public class WeChatUtil {
/**
* 获取商户的私钥文件
*
* @param filename 获取商户的私钥文件
* @return 商户私钥
*/
public PrivateKey getPrivateKey(String filename) {
try {
return PemUtil.loadPrivateKey(new ClassPathResource(filename).getInputStream());
} catch (Exception e) {
log.error("商户私钥文件不存在,错误原因:{}", e.getMessage());
throw new ServiceException("商户私钥文件不存在,请联系管理员!");
}
}
}

View File

@ -0,0 +1,131 @@
package com.xinelu.applet.vo.healthconsultation;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.xinelu.common.custominterface.Insert;
import com.xinelu.common.custominterface.Update;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Date;
/**
* @author ljh
* @version 1.0
* Create by 2023/3/8 13:59
*/
@Data
public class HealthConsultationOrderDTO implements Serializable {
private static final long serialVersionUID = 8664995394794180987L;
/**
* 主键id
*/
private Long id;
/**
* 商品订单表id
*/
private Long goodsOrderId;
/**
* 订单编号
*/
private String orderNo;
/**
* 01
*/
private Integer delFlag;
/**
* 会员id
*/
@NotNull(message = "咨询人员信息不能为空!", groups = {Insert.class, Update.class})
private Long patientId;
/**
* 订单状态待付款WAIT_PAY已付款PAY已取消CANCEL待收货WAIT_RECEIVED已收货RECEIVED待退款WAIT_REFUND已退款REFUNDED待退货WAIT_RETURNED已退货RETURNED
*/
private String orderStatus;
/**
* 订单总金额
*/
@NotNull(message = "金额不能为空", groups = {Insert.class, Update.class})
private BigDecimal totalPrice;
/**
* 收货人
*/
@NotBlank(message = "姓名不能为空", groups = {Insert.class, Update.class})
@Length(max = 20, message = "姓名不能超过20位", groups = {Insert.class, Update.class})
private String receiver;
/**
* 联系电话
*/
@NotBlank(message = "联系电话不能为空", groups = {Insert.class, Update.class})
@Length(max = 11, message = "联系电话不能超过11位", groups = {Insert.class, Update.class})
private String phone;
/**
* 下单时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime orderTime;
/**
* 下单方式手机AppMOBILE_APP微信小程序WECHAT_APPLET支付宝小程序ALI_PAY_APPLET
*/
@NotNull(message = "下单方式不能为空", groups = {Insert.class, Update.class})
private String orderChannel;
/**
* 护理站NURSE_STATION商城SHOPPING_MALL健康咨询HEALTH_CONSULTATION
*/
private String buySource;
/**
* 订单类型积分兑换INTEGRAL_EXCHANGE直接购买DIRECT_BUY健康咨询HEALTH_CONSULTATION
*/
private String orderType;
/**
* 健康咨询人员表id记录咨询订单中选择的医生健康咨询订单使用
*/
@NotNull(message = "请选择咨询的专家!", groups = {Insert.class, Update.class})
private Long hospitalPersonId;
/**
* 商品原始金额商品数量 * 商品单价
*/
private BigDecimal originalTotalPrice;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
/**
* 健康咨询预约时间健康咨询订单使用
**/
@JsonFormat(pattern = "yyyy-MM-dd")
@NotNull(message = "服务日期不能为空", groups = {Insert.class, Update.class})
private Date healthAppointDate;
/**
* 健康咨询内容健康咨询类型的订单使用
*/
private String healthConsultationContent;
/**
* 健康咨询专家记录咨询订单中选择的医生姓名健康咨询订单使用
*/
@NotBlank(message = "请选择咨询的专家!", groups = {Insert.class, Update.class})
private String hospitalPersonName;
}

View File

@ -0,0 +1,30 @@
package com.xinelu.applet.vo.healthconsultation;
import com.xinelu.manage.domain.poserInfo.PoserInfo;
import lombok.Data;
import java.util.List;
/**
* @Description 健康咨询返回值实体类
* @Author zh
* @Date 2023-03-07
*/
@Data
public class HealthConsultationVO {
/**
* 科室id
*/
private Long departmentId;
/**
* 科室名称
*/
private String departmentName;
/**
* 海报集合
*/
List<PoserInfo> poserInfoList;
}

View File

@ -0,0 +1,30 @@
package com.xinelu.applet.vo.healthconsultation;
import com.xinelu.applet.vo.specialdisease.WeekDaysVO;
import lombok.Data;
import java.util.List;
/**
* @Description 信息确认返回值实体类
* @Author zh
* @Date 2023-03-07
*/
@Data
public class PatientAndTimeVO {
/**
* 用户姓名
*/
private String patientName;
/**
* 手机号码
*/
private String phone;
/**
* 近七天的预约时间点集合
*/
List<WeekDaysVO> appointmentTimeList;
}

View File

@ -0,0 +1,44 @@
package com.xinelu.applet.vo.logistics;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.List;
/**
* @Description 快递鸟单号识别接口返回值实体类
* @Author 纪寒
* @Date 2022-11-01 14:44:06
* @Version 1.0
*/
@NoArgsConstructor
@Data
public class DistinguishResultVO implements Serializable {
private static final long serialVersionUID = 5858502009039750987L;
@JsonProperty("EBusinessID")
private String eBusinessID;
@JsonProperty("Success")
private Boolean success;
@JsonProperty("LogisticCode")
private String logisticCode;
@JsonProperty("Shippers")
private List<ShippersDTO> shippers;
@NoArgsConstructor
@Data
public static class ShippersDTO {
@JsonProperty("ShipperCode")
private String shipperCode;
@JsonProperty("ShipperName")
private String shipperName;
}
}

View File

@ -0,0 +1,66 @@
package com.xinelu.applet.vo.logistics;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
/**
* @Description 快递鸟即时查询接口返回值实体类
* @Author 纪寒
* @Date 2022-11-01 15:21:32
* @Version 1.0
*/
@NoArgsConstructor
@Data
public class SearchMonitorResultVO implements Serializable {
private static final long serialVersionUID = -3109050110048632561L;
@JsonProperty("EBusinessID")
private String eBusinessID;
@JsonProperty("ShipperCode")
private String shipperCode;
private String shipperName;
@JsonProperty("Success")
private Boolean success;
@JsonProperty("LogisticCode")
private String logisticCode;
@JsonProperty("State")
private String state;
@JsonProperty("StateEx")
private String stateEx;
@JsonProperty("Location")
private String location;
@JsonProperty("Traces")
private List<TracesDTO> traces;
@NoArgsConstructor
@Data
public static class TracesDTO {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonProperty("AcceptTime")
private LocalDateTime acceptTime;
@JsonProperty("AcceptStation")
private String acceptStation;
@JsonProperty("Location")
private String location;
@JsonProperty("Action")
private String action;
}
}

View File

@ -163,5 +163,5 @@ public class PatientAndDiseaseVO implements Serializable {
/**
* 基础疾病信息
*/
private String[] diseaseList;
private Integer[] diseaseList;
}

View File

@ -0,0 +1,249 @@
package com.xinelu.applet.vo.nursingorder;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Date;
/**
* @author ljh
* @version 1.0
* Create by 2022/10/25 15:49
*/
@Data
public class AppletGoodsOrderVO implements Serializable {
private static final long serialVersionUID = -1046127024688630443L;
/**
* 商品订单表id
*/
private Long goodsOrderId;
/**
* 护理站id
*/
private Long nurseStationId;
/**
* 会员id
*/
private Long patientId;
/**
* 订单编号
*/
private String goOrderNo;
/**
* 订单编号
*/
private String godOrderNo;
/**
* 订单状态待付款WAIT_PAY已付款PAY已取消CANCEL待收货WAIT_RECEIVED已收货RECEIVED待退款WAIT_REFUND已退款REFUNDED待退货WAIT_RETURNED已退货RETURNED
*/
private String orderStatus;
/**
* 订单总金额
*/
private BigDecimal totalPrice;
/**
* 收货人
*/
private String receiver;
/**
* 收货地址
*/
private String receiveAddress;
/**
* 联系电话
*/
private String phone;
/**
* 订单总金额
*/
private BigDecimal godTotalPrice;
/**
* 下单时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime orderTime;
/**
* 主键id
*/
private Long goodsOrderDetailsId;
/**
* 商品名称
*/
private String goodsName;
/**
* 商品数量
*/
private Integer goodsCount;
/**
* 商品属性名称
*/
private String goodsAttributeName;
/**
* 商品属性内容
*/
private String goodsAttributeContent;
/**
* 商品单价
*/
private BigDecimal goodsPrice;
/**
* 优惠金额
*/
private BigDecimal discountPrice;
/**
* 运费金额
*/
private BigDecimal transportPrice;
/**
* 赠送积分
*/
private Integer giveIntegral;
/**
* 退款退货类型REFUND_MONEY_GOODS仅退款ONLY_REFUND_MONEY
*/
private String refundType;
/**
* 退款原因类型字典表id
*/
private Long refundReasonDictId;
/**
* 退货原因具体描述
*/
private String refundReasonRemark;
/**
* 确认退款状态未确认NOT_CONFIRM已确认CONFIRMED
*/
private String confirmRefundStatus;
/**
* 商品属性图片地址
*/
private String attributePitureUrl;
/**
* 退款时间时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
/**
* 字典标签
*/
private String dictLabel;
/**
* 快递单号
*/
private String expressNo;
/**
* 购买来源
*/
private String buySource;
/**
* 订单类型积分兑换INTEGRAL_EXCHANGE直接购买DIRECT_BUY健康咨询HEALTH_CONSULTATION
*/
private String orderType;
/**
* 积分抵扣数量
*/
private Integer integralDeductionCount;
/**
* 退款详情-申请时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime appleTime;
/**
* 积分兑换标识01
*/
private Integer integralExchangeFlag;
/**
* 积分兑换门槛值
*/
private Integer integralExchangeSill;
/**
* 积分兑换商品数量
*/
private Integer integralExchangeCount;
/**
* 订单原始总金额优惠券之前的价格商品数量*商品单价
*/
private BigDecimal originalTotalPrice;
/**
* 优惠券名称
*/
private String couponTitle;
/**
* 优惠券id
*/
private Long couponId;
/**
* 健康咨询人员表id记录咨询订单中选择的医生
*/
private Long hospitalPersonId;
/**
* 下单方式手机AppMOBILE_APP微信小程序WECHAT_APPLET支付宝小程序ALI_PAY_APPLET
*/
private String orderChannel;
/**
* 健康咨询内容健康咨询类型的订单使用
*/
private String healthConsultationContent;
/**
* 健康咨询预约时间健康咨询订单使用
**/
@JsonFormat(pattern = "yyyy-MM-dd")
private Date healthAppointDate;
/**
* 健康咨询专家名称健康咨询类型的订单使用
*/
private String hospitalPersonName;
/**
* 科室人员头像地址
*/
private String personPictureUrl;
}

View File

@ -0,0 +1,103 @@
package com.xinelu.applet.vo.nursingorder;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.xinelu.common.core.domain.BaseDomain;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalTime;
/**
* 个人中心订单Controller
*
* @author zhangheng
* @date 2022-09-06
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class NursingOrderInfoVO extends BaseDomain implements Serializable {
private static final long serialVersionUID = -2337545308977415936L;
/**
* 预约订单编号
*/
private String orderNo;
/**
* 订单数量
*/
private Long orderCount;
/**
* 服务日期格式yyyy-MM-dd
*/
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate serviceDate;
/**
* 服务开始时间格式HH:mm
*/
@JsonFormat(pattern = "HH:mm:ss")
private LocalTime serviceStartTime;
/**
* 服务结束时间格式HH:mm
*/
@JsonFormat(pattern = "HH:mm:ss")
private LocalTime serviceEndTime;
/**
* 预约订单状态代付款WAIT_PAY待派单WAIT_DISPATCH未完成NOT_FINISH服务完成COMPLETE
*/
private String orderStatus;
/**
* 预约状态0可以预约1不可以预约
*/
private Integer appointmentStatus;
/**
* 预约总价格单位
*/
private BigDecimal totalPrice;
/**
* 护理项目名称
*/
private String nurseItemName;
/**
* 护理项目价格
*/
private BigDecimal nurseItemPrice;
/**
* 是否删除标识01
*/
private Integer delFlag;
/**
* 提前预约时长单位小时
*/
private Integer advanceAppointDuration;
/**
* 护理站图片路径
*/
private String itemPictureUrl;
/**
* 护理站图片路径
*/
private String nurseStationName;
/**
* 服务时长和单位
*/
private String itemServeDurationUnit;
}

View File

@ -0,0 +1,208 @@
package com.xinelu.applet.vo.specialdisease;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.xinelu.manage.domain.appointmentorderconsumable.AppointmentOrderConsumable;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
/**
* @Description 预约服务订单详情返回值实体类
* @Author 纪寒
* @Date 2022-11-11 14:48:01
* @Version 1.0
*/
@Data
public class AppointmentOrderDetailsInfoVO implements Serializable {
private static final long serialVersionUID = 7042842920314984169L;
/**
* 订单主表id
*/
private Long appointmentOrderId;
/**
* 会员id
*/
private Long patientId;
/**
* 护理项目id
*/
private Long nurseStationItemId;
/**
* 护理站名称
*/
private String nurseStationName;
/**
* 护理站头像
*/
private String stationPictureUrl;
/**
* 护理站地址
*/
private String address;
/**
* 护理站联系电话
*/
private String stationPhone;
/**
* 护理人联系电话
*/
private String patientPhone;
/**
* 服务项目名称
*/
private String nurseItemName;
/**
* 服务时长
*/
private String itemServeDurationUnit;
/**
* 护理人名称即会员名称
*/
private String patientName;
/**
* 服务地址
*/
private String serviceAddress;
/**
* 服务时间
*/
private LocalDate serviceDate;
/**
* 服务开始时间
*/
private LocalTime serviceStartTime;
/**
* 服务结束时间
*/
private LocalTime serviceEndTime;
/**
* 订单编号
*/
private String orderNo;
/**
* 备注信息
*/
private String remark;
/**
* 服务项目价格
*/
private BigDecimal nurseItemPrice;
/**
* 耗材总价格
*/
private BigDecimal consumableTotalPrice;
/**
* 订单总价格
*/
private String totalPrice;
/**
* 订单状态
*/
private String orderStatus;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
/**
* 服务项目图片
*/
private String itemPictureUrl;
/**
* 预约订单耗材信息
*/
private List<AppointmentOrderConsumable> itemConsumableList;
/**
* 失能情况NOT_DISABLED未失能DISABLED已失能
*/
private String disablingCondition;
/**
* 失能原因
*/
private String disablingReason;
/**
* 订单类型院内陪护COMPANION_IN_HOSPITAL其它OTHER
*/
private String orderType;
/**
* 陪护开始时间院内陪护订单使用格式yyyy-MM-dd
*/
@JsonFormat(pattern = "yyyy-MM-dd")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate companionStartDate;
/**
* 陪护结束时间院内陪护订单使用格式yyyy-MM-dd
*/
@JsonFormat(pattern = "yyyy-MM-dd")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate companionEndDate;
/**
* 陪护天数院内陪护订单使用
*/
private Integer companionDays;
/**
* 订单填写人姓名院内陪护订单使用
*/
private String orderWriteName;
/**
* 护理人姓名院内陪护订单使用
*/
private String caregiverName;
/**
* 护理人电话院内陪护订单使用
*/
private String caregiverPhone;
/**
* 医院名称院内陪护订单使用
*/
private String hospitalName;
/**
* 科室名称院内陪护订单使用
*/
private String departmentName;
/**
* 病床号院内陪护订单使用
*/
private String hospitalBedNumber;
}

View File

@ -0,0 +1,67 @@
package com.xinelu.applet.vo.wechatpaymentinfo.dto;
import com.xinelu.common.custominterface.Insert;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* @Description 微信支付参数接受实体类
* @Author 纪寒
* @Date 2022-10-18 15:12:51
* @Version 1.0
*/
@Data
public class PaymentDTO implements Serializable {
private static final long serialVersionUID = 4090244715734558969L;
/**
* 会员id
*/
@NotNull(message = "会员id不能为空", groups = {Insert.class})
private Long patientId;
/**
* 微信用户openid
*/
private String openid;
/**
* 订单编号
*/
@NotBlank(message = "订单编号不能为空!", groups = {Insert.class})
private String orderNo;
/**
* 支付类型微信支付WECHAT_PAY支付宝支付ALI_PAY
*/
@NotBlank(message = "支付类型不能为空!", groups = {Insert.class})
private String payType;
/**
* 支付渠道手机AppMOBILE_APP微信小程序WECHAT_APPLET支付宝小程序ALI_PAY_APPLE
*/
@NotBlank(message = "支付渠道不能为空!", groups = {Insert.class})
private String orderChannel;
/**
* 购买来源用于判断使用那个商户进行支付
* 护理站NURSE_STATION商城SHOPPING_MAL, 健康咨询HEALTH_CONSULTATION学习培训TRAINING
*/
@NotBlank(message = "购买来源不能为空!", groups = {Insert.class})
private String buySource;
/**
* 支付金额
*/
@NotNull(message = "支付金额不能为空!", groups = {Insert.class})
private BigDecimal paymentPrice;
/**
* 护理员id
*/
private Long nurseStationPersonId;
}

View File

@ -0,0 +1,57 @@
package com.xinelu.applet.vo.wechatpaymentinfo.dto;
import com.xinelu.common.custominterface.Insert;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* @Description
* @Author 纪寒
* @Date 2022-10-24 16:15:44
* @Version 1.0
*/
@Data
public class RefundDTO implements Serializable {
private static final long serialVersionUID = -1990509784850994288L;
/**
* 订单编号必传字段
*/
@NotBlank(message = "订单编号不能为空!", groups = {Insert.class})
private String orderNo;
/**
* 退款原因
*/
private String refundReason;
/**
* 退款金额必传字段
*/
@NotNull(message = "退款金额不能为空!", groups = {Insert.class})
private BigDecimal refundPrice;
/**
* 补充描述和凭证
*/
private String remark;
/**
* 货物到货状态目前用不到
*/
private String goodsStatus;
/**
* 订单类型健康咨询订单退款使用积分兑换INTEGRAL_EXCHANGE直接购买DIRECT_BUY健康咨询HEALTH_CONSULTATION
*/
private String orderType;
/**
* 学习培训订单标识学习培训订单退款使用
*/
private String trainingOrderFlag;
}

View File

@ -0,0 +1,22 @@
package com.xinelu.applet.vo.wechatpaymentinfo.vo;
import lombok.Data;
import java.io.Serializable;
/**
* @Description 订单状态返回值实体类
* @Author 纪寒
* @Date 2022-10-21 10:47:20
* @Version 1.0
*/
@Data
public class OrderStatusInfoVO implements Serializable {
private static final long serialVersionUID = -8522003863208703215L;
private Boolean payFlag;
private String tradeStatus;
WeChatQueryOrderVO weChatQueryOrderVO;
}

View File

@ -0,0 +1,34 @@
package com.xinelu.applet.vo.wechatpaymentinfo.vo;
import lombok.Builder;
import lombok.Data;
import java.io.Serializable;
/**
* @Description 微信App调起支付参数信息
* @Author 纪寒
* @Date 2022-10-31 09:59:19
* @Version 1.0
*/
@Builder
@Data
public class WeChatAppSignVO implements Serializable {
private static final long serialVersionUID = 6921828781484230912L;
private String appId;
private String partnerId;
private String prepayId;
private String packageValue;
private String nonceStr;
private String timeStamp;
private String sign;
}

View File

@ -0,0 +1,30 @@
package com.xinelu.applet.vo.wechatpaymentinfo.vo;
import lombok.Builder;
import lombok.Data;
import java.io.Serializable;
/**
* @Description 微信小程序调起支付参数信息
* @Author 纪寒
* @Date 2022-10-20 09:59:19
* @Version 1.0
*/
@Builder
@Data
public class WeChatAppletSignVO implements Serializable {
private static final long serialVersionUID = -2527792374746553807L;
private String appId;
private String timeStamp;
private String nonceStr;
private String prepayId;
private String signType;
private String paySign;
}

View File

@ -0,0 +1,57 @@
package com.xinelu.applet.vo.wechatpaymentinfo.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @Description 微信只顾回调密文参数实体类
* @Author 纪寒
* @Date 2022-10-20 14:10:15
* @Version 1.0
*/
@NoArgsConstructor
@Data
public class WeChatPayNotifyCiphertextVO implements Serializable {
private static final long serialVersionUID = -3000851624508762861L;
@JsonProperty("id")
private String id;
@JsonProperty("create_time")
private String createTime;
@JsonProperty("resource_type")
private String resourceType;
@JsonProperty("event_type")
private String eventType;
@JsonProperty("summary")
private String summary;
@JsonProperty("resource")
private ResourceDTO resource;
@NoArgsConstructor
@Data
public static class ResourceDTO {
@JsonProperty("original_type")
private String originalType;
@JsonProperty("algorithm")
private String algorithm;
@JsonProperty("ciphertext")
private String ciphertext;
@JsonProperty("associated_data")
private String associatedData;
@JsonProperty("nonce")
private String nonce;
}
}

View File

@ -0,0 +1,146 @@
package com.xinelu.applet.vo.wechatpaymentinfo.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.List;
/**
* @Description 微信支付回调通知明文参数实体类
* @Author 纪寒
* @Date 2022-10-20 14:08:07
* @Version 1.0
*/
@NoArgsConstructor
@Data
public class WeChatPayNotifyPlaintextVO implements Serializable {
private static final long serialVersionUID = -3950813376227389879L;
@JsonProperty("transaction_id")
private String transactionId;
@JsonProperty("amount")
private AmountDTO amount;
@JsonProperty("mchid")
private String mchid;
@JsonProperty("trade_state")
private String tradeState;
@JsonProperty("bank_type")
private String bankType;
@JsonProperty("promotion_detail")
private List<PromotionDetailDTO> promotionDetail;
@JsonProperty("success_time")
private String successTime;
@JsonProperty("payer")
private PayerDTO payer;
@JsonProperty("out_trade_no")
private String outTradeNo;
@JsonProperty("appid")
private String appid;
@JsonProperty("trade_state_desc")
private String tradeStateDesc;
@JsonProperty("trade_type")
private String tradeType;
@JsonProperty("attach")
private String attach;
@JsonProperty("scene_info")
private SceneInfoDTO sceneInfo;
@NoArgsConstructor
@Data
public static class AmountDTO {
@JsonProperty("payer_total")
private Integer payerTotal;
@JsonProperty("total")
private Integer total;
@JsonProperty("currency")
private String currency;
@JsonProperty("payer_currency")
private String payerCurrency;
}
@NoArgsConstructor
@Data
public static class PayerDTO {
@JsonProperty("openid")
private String openid;
}
@NoArgsConstructor
@Data
public static class SceneInfoDTO {
@JsonProperty("device_id")
private String deviceId;
}
@NoArgsConstructor
@Data
public static class PromotionDetailDTO {
@JsonProperty("amount")
private Integer amount;
@JsonProperty("wechatpay_contribute")
private Integer wechatpayContribute;
@JsonProperty("coupon_id")
private String couponId;
@JsonProperty("scope")
private String scope;
@JsonProperty("merchant_contribute")
private Integer merchantContribute;
@JsonProperty("name")
private String name;
@JsonProperty("other_contribute")
private Integer otherContribute;
@JsonProperty("currency")
private String currency;
@JsonProperty("stock_id")
private String stockId;
@JsonProperty("goods_detail")
private List<GoodsDetailDTO> goodsDetail;
@NoArgsConstructor
@Data
public static class GoodsDetailDTO {
@JsonProperty("goods_remark")
private String goodsRemark;
@JsonProperty("quantity")
private Integer quantity;
@JsonProperty("discount_amount")
private Integer discountAmount;
@JsonProperty("goods_id")
private String goodsId;
@JsonProperty("unit_price")
private Integer unitPrice;
}
}
}

View File

@ -0,0 +1,82 @@
package com.xinelu.applet.vo.wechatpaymentinfo.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.List;
/**
* @Description 微信查单接口返回值实体类
* @Author 纪寒
* @Date 2022-10-21 11:26:12
* @Version 1.0
*/
@NoArgsConstructor
@Data
public class WeChatQueryOrderVO implements Serializable {
private static final long serialVersionUID = 8467953500266751257L;
@JsonProperty("amount")
private AmountDTO amount;
@JsonProperty("appid")
private String appid;
@JsonProperty("attach")
private String attach;
@JsonProperty("bank_type")
private String bankType;
@JsonProperty("mchid")
private String mchid;
@JsonProperty("out_trade_no")
private String outTradeNo;
@JsonProperty("payer")
private PayerDTO payer;
@JsonProperty("promotion_detail")
private List<?> promotionDetail;
@JsonProperty("success_time")
private String successTime;
@JsonProperty("trade_state")
private String tradeState;
@JsonProperty("trade_state_desc")
private String tradeStateDesc;
@JsonProperty("trade_type")
private String tradeType;
@JsonProperty("transaction_id")
private String transactionId;
@NoArgsConstructor
@Data
public static class AmountDTO {
@JsonProperty("currency")
private String currency;
@JsonProperty("payer_currency")
private String payerCurrency;
@JsonProperty("payer_total")
private Integer payerTotal;
@JsonProperty("total")
private Integer total;
}
@NoArgsConstructor
@Data
public static class PayerDTO {
@JsonProperty("openid")
private String openid;
}
}

View File

@ -0,0 +1,140 @@
package com.xinelu.applet.vo.wechatpaymentinfo.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.List;
/**
* @Description 微信申请退款返回值实体类
* @Author 纪寒
* @Date 2022-10-24 17:50:40
* @Version 1.0
*/
@NoArgsConstructor
@Data
public class WeChatRefundInfoVO implements Serializable {
private static final long serialVersionUID = -7834783600438774698L;
@JsonProperty("refund_id")
private String refundId;
@JsonProperty("out_refund_no")
private String outRefundNo;
@JsonProperty("transaction_id")
private String transactionId;
@JsonProperty("out_trade_no")
private String outTradeNo;
@JsonProperty("channel")
private String channel;
@JsonProperty("user_received_account")
private String userReceivedAccount;
@JsonProperty("success_time")
private String successTime;
@JsonProperty("create_time")
private String createTime;
@JsonProperty("status")
private String status;
@JsonProperty("funds_account")
private String fundsAccount;
@JsonProperty("amount")
private AmountDTO amount;
@JsonProperty("promotion_detail")
private List<PromotionDetailDTO> promotionDetail;
@NoArgsConstructor
@Data
public static class AmountDTO {
@JsonProperty("total")
private Integer total;
@JsonProperty("refund")
private Integer refund;
@JsonProperty("from")
private List<FromDTO> from;
@JsonProperty("payer_total")
private Integer payerTotal;
@JsonProperty("payer_refund")
private Integer payerRefund;
@JsonProperty("settlement_refund")
private Integer settlementRefund;
@JsonProperty("settlement_total")
private Integer settlementTotal;
@JsonProperty("discount_refund")
private Integer discountRefund;
@JsonProperty("currency")
private String currency;
@NoArgsConstructor
@Data
public static class FromDTO {
@JsonProperty("account")
private String account;
@JsonProperty("amount")
private Integer amount;
}
}
@NoArgsConstructor
@Data
public static class PromotionDetailDTO {
@JsonProperty("promotion_id")
private String promotionId;
@JsonProperty("scope")
private String scope;
@JsonProperty("type")
private String type;
@JsonProperty("amount")
private Integer amount;
@JsonProperty("refund_amount")
private Integer refundAmount;
@JsonProperty("goods_detail")
private List<GoodsDetailDTO> goodsDetail;
@NoArgsConstructor
@Data
public static class GoodsDetailDTO {
@JsonProperty("merchant_goods_id")
private String merchantGoodsId;
@JsonProperty("wechatpay_goods_id")
private String wechatpayGoodsId;
@JsonProperty("goods_name")
private String goodsName;
@JsonProperty("unit_price")
private Integer unitPrice;
@JsonProperty("refund_amount")
private Integer refundAmount;
@JsonProperty("refund_quantity")
private Integer refundQuantity;
}
}
}

View File

@ -0,0 +1,61 @@
package com.xinelu.applet.vo.wechatpaymentinfo.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @Description 微信退款回调通知参数实体类
* @Author 纪寒
* @Date 2022-10-25 11:38:39
* @Version 1.0
*/
@NoArgsConstructor
@Data
public class WeChatRefundNotifyVO implements Serializable {
private static final long serialVersionUID = -2553550636560311860L;
@JsonProperty("mchid")
private String mchid;
@JsonProperty("transaction_id")
private String transactionId;
@JsonProperty("out_trade_no")
private String outTradeNo;
@JsonProperty("refund_id")
private String refundId;
@JsonProperty("out_refund_no")
private String outRefundNo;
@JsonProperty("refund_status")
private String refundStatus;
@JsonProperty("success_time")
private String successTime;
@JsonProperty("user_received_account")
private String userReceivedAccount;
@JsonProperty("amount")
private AmountDTO amount;
@NoArgsConstructor
@Data
public static class AmountDTO {
@JsonProperty("total")
private Integer total;
@JsonProperty("refund")
private Integer refund;
@JsonProperty("payer_total")
private Integer payerTotal;
@JsonProperty("payer_refund")
private Integer payerRefund;
}
}

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xinelu.applet.mapper.healthconsultation.HealthConsultationMapper">
<select id="selectPatientById" resultType="com.xinelu.manage.domain.patientinfo.PatientInfo">
SELECT patient_name,
phone
FROM patient_info
WHERE id = #{patientId}
</select>
<select id="selectHospitalDepartmentList"
resultType="com.xinelu.applet.vo.healthconsultation.HealthConsultationVO">
select id departmentId,
department_name
from hospital_department_info
order by department_sort asc
</select>
</mapper>

View File

@ -0,0 +1,334 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xinelu.applet.mapper.nursingorder.NursingOrderMapper">
<!-- 预约服务订单详情映射关系 -->
<resultMap id="getAppointmentDetailsResultMap"
type="com.xinelu.applet.vo.specialdisease.AppointmentOrderDetailsInfoVO">
<result property="patientId" column="patient_id"/>
<result property="appointmentOrderId" column="appointmentOrderId"/>
<result property="patientName" column="patient_name"/>
<result property="patientPhone" column="patientPhone"/>
<result property="orderNo" column="order_no"/>
<result property="totalPrice" column="total_price"/>
<result property="orderStatus" column="order_status"/>
<result property="remark" column="remark"/>
<result property="createTime" column="create_time"/>
<result property="nurseStationItemId" column="nurse_station_item_id"/>
<result property="serviceAddress" column="service_address"/>
<result property="serviceDate" column="service_date"/>
<result property="serviceStartTime" column="service_start_time"/>
<result property="serviceEndTime" column="service_end_time"/>
<result property="nurseItemName" column="nurse_item_name"/>
<result property="nurseItemPrice" column="nurse_item_price"/>
<result property="itemServeDurationUnit" column="item_serve_duration_unit"/>
<result property="consumableTotalPrice" column="consumable_total_price"/>
<result property="disablingCondition" column="disabling_condition"/>
<result property="disablingReason" column="disabling_reason"/>
<result property="orderType" column="order_type"/>
<result property="companionStartDate" column="companion_start_date"/>
<result property="companionEndDate" column="companion_end_date"/>
<result property="companionDays" column="companion_days"/>
<result property="orderWriteName" column="order_write_name"/>
<result property="caregiverName" column="caregiver_name"/>
<result property="caregiverPhone" column="caregiver_phone"/>
<result property="hospitalName" column="hospital_name"/>
<result property="departmentName" column="department_name"/>
<result property="hospitalBedNumber" column="hospital_bed_number"/>
<collection property="itemConsumableList" javaType="java.util.List"
resultMap="getAppointmentOrderConsumableResult"/>
</resultMap>
<!-- 预约服务耗材映射关系 -->
<resultMap type="com.xinelu.manage.domain.appointmentorderconsumable.AppointmentOrderConsumable"
id="getAppointmentOrderConsumableResult">
<result property="id" column="id"/>
<result property="appointOrderDetailsId" column="appoint_order_details_id"/>
<result property="orderConsumableName" column="order_consumable_name"/>
<result property="orderConsumablePrice" column="order_consumable_price"/>
<result property="orderConsumableCount" column="order_consumable_count"/>
<result property="consumableUnit" column="consumable_unit"/>
</resultMap>
<select id="getNursingOrderVOByPatientId" parameterType="long"
resultType="com.xinelu.applet.vo.nursingorder.NursingOrderInfoVO">
SELECT
aod.order_no,
aod.service_date,
aod.service_start_time,
aod.service_end_time,
aod.appointment_status,
aod.total_price,
aod.item_serve_duration_unit,
aod.nurse_item_name,
aod.order_status,
nsi.advance_appoint_duration,
nsi.item_picture_url,
ns.nurse_station_name
FROM
appointment_order_details aod
LEFT JOIN nurse_station_item nsi ON nsi.id = aod.nurse_station_item_id
LEFT JOIN nurse_station ns ON ns.id = nsi.nurse_station_id
LEFT JOIN appointment_order ao ON ao.order_no = aod.order_no
WHERE
aod.del_flag = 0 and ao.del_flag = 0
<if test="patientId != null">
AND ao.patient_id = #{patientId}
</if>
ORDER BY
aod.service_date DESC,
aod.service_start_time DESC
</select>
<select id="getGoodsOrder" parameterType="com.xinelu.applet.vo.nursingorder.AppletGoodsOrderVO"
resultType="com.xinelu.applet.vo.nursingorder.AppletGoodsOrderVO">
SELECT
gr.id goodsOrderId,
gr.nurse_station_id,
gr.patient_id,
gr.order_no goOrderNo,
gr.order_status,
gr.total_price,
gr.receiver,
gr.receive_address,
gr.phone,
gr.order_time,
gr.refund_type,
gr.refund_reason_dict_id,
gr.refund_reason_remark,
gr.confirm_refund_status,
gr.express_no,
gr.buy_source,
gr.order_type,
gr.original_total_price,
gr.order_channel,
gr.hospital_person_id,
gr.health_consultation_content,
gr.health_appoint_date,
god.integral_deduction_count,
god.id goodsOrderDetailsId,
god.order_no godOrderNo,
god.goods_name,
god.goods_count,
god.goods_attribute_name,
god.goods_attribute_content,
god.goods_price,
god.total_price godTotalPrice,
god.discount_price,
god.transport_price,
god.give_integral,
gad.attribute_piture_url,
gad.integral_exchange_flag,
god.integral_exchange_sill,
god.integral_exchange_count,
god.coupon_id,
god.coupon_title,
sdd.dict_label,
gr.update_time appleTime,
(select rf.success_time from refund_info rf where rf.order_no = gr.order_no) update_time,
IF( gr.order_type = 'HEALTH_CONSULTATION', ( SELECT person_picture_url FROM hospital_person_info WHERE id =
gr.hospital_person_id ), NULL ) person_picture_url,
gr.hospital_person_name
FROM
goods_order gr
LEFT JOIN goods_order_details god ON gr.id = god.goods_order_id
LEFT JOIN goods_attribute_details gad ON god.goods_attribute_details_id = gad.id
LEFT JOIN sys_dict_data sdd ON sdd.dict_code = gr.refund_reason_dict_id
<where>
<if test="patientId != null ">
and gr.patient_id = #{patientId}
</if>
<if test="orderStatus != null and orderStatus != ''">
and gr.order_status = #{orderStatus}
</if>
<if test="goodsName != null and goodsName != ''">
and god.goods_name like concat('%', #{goodsName}, '%')
</if>
<if test="goodsOrderId != null ">
and gr.id = #{goodsOrderId}
</if>
<if test="goOrderNo != null ">
and gr.order_no = #{goOrderNo}
</if>
<if test="orderType != null and orderType != ''">
and gr.order_type = #{orderType}
</if>
and gr.del_flag = 0
and god.del_flag = 0
</where>
ORDER BY gr.order_time DESC
</select>
<select id="getRefundReason" parameterType="com.xinelu.common.core.domain.entity.SysDictData"
resultType="com.xinelu.common.core.domain.entity.SysDictData">
SELECT
dict_code,
dict_sort,
dict_label,
dict_value,
dict_type
FROM
sys_dict_data
<where>
<if test="dictType != null and dictType != ''">
AND dict_type = #{dictType}
</if>
</where>
</select>
<update id="updateGoodsOrder" parameterType="com.xinelu.manage.domain.goodsOrder.GoodsOrder">
update goods_order
<trim prefix="SET" suffixOverrides=",">
<if test="nurseStationId != null">
nurse_station_id =
#{nurseStationId},
</if>
<if test="patientId != null">
patient_id =
#{patientId},
</if>
<if test="orderNo != null">
order_no =
#{orderNo},
</if>
<if test="orderStatus != null">
order_status =
#{orderStatus},
</if>
<if test="totalPrice != null">
total_price =
#{totalPrice},
</if>
<if test="receiver != null">
receiver =
#{receiver},
</if>
<if test="receiveAddress != null">
receive_address =
#{receiveAddress},
</if>
<if test="phone != null">
phone =
#{phone},
</if>
<if test="orderTime != null">
order_time =
#{orderTime},
</if>
<if test="orderChannel != null">
order_channel =
#{orderChannel},
</if>
<if test="buySource != null">
buy_source =
#{buySource},
</if>
<if test="remark != null">
remark =
#{remark},
</if>
<if test="delFlag != null">
del_flag =
#{delFlag},
</if>
<if test="createBy != null">
create_by =
#{createBy},
</if>
<if test="createTime != null">
create_time =
#{createTime},
</if>
<if test="updateBy != null">
update_by =
#{updateBy},
</if>
<if test="updateTime != null">
update_time =
#{updateTime},
</if>
<if test="refundType != null">
refund_type =
#{refundType},
</if>
<if test="refundReasonDictId != null">
refund_reason_dict_id =
#{refundReasonDictId},
</if>
<if test="refundReasonRemark != null">
refund_reason_remark =
#{refundReasonRemark},
</if>
<if test="confirmRefundStatus != null">
confirm_refund_status =
#{confirmRefundStatus},
</if>
</trim>
where id = #{id}
</update>
<select id="getAppointmentOrderDetailsInfo" resultMap="getAppointmentDetailsResultMap">
SELECT pi.patient_name,
pi.phone patientPhone,
aor.id appointmentOrderId,
aor.patient_id,
aor.order_no,
aor.total_price,
aor.order_status,
aor.remark,
aor.create_time,
aor.order_type,
aor.companion_start_date,
aor.companion_end_date,
aor.companion_days,
aor.order_write_name,
aod.nurse_station_item_id,
aod.service_address,
aod.service_date,
aod.service_start_time,
aod.service_end_time,
aod.nurse_item_name,
aod.nurse_item_price,
aod.item_serve_duration_unit,
aod.consumable_total_price,
aoc.id,
aoc.appoint_order_details_id,
aoc.order_consumable_name,
aoc.order_consumable_price,
aoc.order_consumable_count,
aoc.consumable_unit,
aod.disabling_condition,
aod.disabling_reason,
aod.caregiver_name,
aod.caregiver_phone,
aod.hospital_name,
aod.department_name,
aod.hospital_bed_number
FROM appointment_order aor
LEFT JOIN appointment_order_details aod ON aor.order_no = aod.order_no
LEFT JOIN appointment_order_consumable aoc ON aod.id = aoc.appoint_order_details_id
LEFT JOIN patient_info pi ON pi.id = aor.patient_id
where aor.order_no = #{ordeNo}
AND aor.del_flag = 0
and aod.del_flag = 0
</select>
<select id="getNurseStationByItemId"
resultType="com.xinelu.applet.vo.specialdisease.AppointmentOrderDetailsInfoVO">
SELECT ns.nurse_station_name nurseStationName,
ns.phone stationPhone,
ns.address,
ns.station_picture_url,
nsi.item_picture_url
FROM nurse_station_item nsi
LEFT JOIN nurse_station ns ON nsi.nurse_station_id = ns.id
WHERE nsi.id = #{nurseStationItemId}
</select>
</mapper>

View File

@ -179,6 +179,11 @@ public class GoodsOrder extends BaseDomain implements Serializable {
*/
private String hospitalPersonName;
/**
* 专家咨询信息表id
*/
private Long consultationInfoId;
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)

View File

@ -19,6 +19,7 @@ import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
* 被护理人基本信息对象 patient_info
@ -247,6 +248,23 @@ public class PatientInfo extends BaseDomain implements Serializable {
*/
private String disease;
/**
* 绑定城市(1德州 2东营)
*/
private String cityCode;
/**
* 小程序绑定时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime bindingTime;
/**
* 当前是否选中(0 1)
*/
private String isChecked;
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
@ -275,6 +293,9 @@ public class PatientInfo extends BaseDomain implements Serializable {
.append("loginFlag", getLoginFlag())
.append("primaryAccountFlag", getPrimaryAccountFlag())
.append("delFlag", getDelFlag())
.append("cityCode", getCityCode())
.append("bindingTime", getBindingTime())
.append("isChecked", getIsChecked())
.toString();
}
}

View File

@ -0,0 +1,156 @@
package com.xinelu.manage.domain.paymentinfo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.xinelu.common.annotation.Excel;
import com.xinelu.common.core.domain.BaseDomain;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 支付记录信息对象 payment_info
*
* @author xinyilu
* @date 2022-10-18
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "支付记录信息对象", description = "payment_info")
public class PaymentInfo extends BaseDomain implements Serializable {
private static final long serialVersionUID = 3272597744303067026L;
/**
* 主键id
*/
private Long id;
/**
* 会员id
*/
@ApiModelProperty(value = "会员id")
@Excel(name = "会员id")
private Long patientId;
/**
* 护理员表id
*/
private Long nurseStationPersonId;
/**
* 商品订单编号系统自动生成
*/
@ApiModelProperty(value = "商品订单编号,系统自动生成")
@Excel(name = "商品订单编号,系统自动生成")
private String orderNo;
/**
* 支付标题
*/
@ApiModelProperty(value = "支付标题")
@Excel(name = "支付标题")
private String paymentTitle;
/**
* 交易流水号
*/
@ApiModelProperty(value = "交易流水号")
@Excel(name = "交易流水号")
private String transactionNo;
/**
* 支付金额
*/
@ApiModelProperty(value = "支付金额")
@Excel(name = "支付金额", readConverterExp = "分=")
private BigDecimal payPrice;
/**
* 支付类型微信支付WECHAT_PAY支付宝支付ALI_PAY
*/
@ApiModelProperty(value = "支付类型微信支付WECHAT_PAY支付宝支付ALI_PAY")
@Excel(name = "支付类型微信支付WECHAT_PAY支付宝支付ALI_PAY")
private String payType;
/**
* 支付渠道手机AppMOBILE_APP微信小程序WECHAT_APPLET支付宝小程序ALI_PAY_APPLET
*/
@ApiModelProperty(value = "支付渠道手机AppMOBILE_APP微信小程序WECHAT_APPLET支付宝小程序ALI_PAY_APPLET")
@Excel(name = "支付渠道手机AppMOBILE_APP微信小程序WECHAT_APPLET支付宝小程序ALI_PAY_APPLET")
private String payChannel;
/**
* 微信支付交易状态支付成功SUCCESS转入退款REFUND未支付NOTPAY已关闭CLOSED已撤销付款码支付REVOKED用户支付中付款码支付USERPAYING支付失败(其他原因如银行返回失败)PAYERROR
*/
@ApiModelProperty(value = "微信支付交易状态支付成功SUCCESS转入退款REFUND未支付NOTPAY已关闭CLOSED已撤销")
@Excel(name = "微信支付交易状态支付成功SUCCESS转入退款REFUND未支付NOTPAY已关闭CLOSED已撤销", readConverterExp = "付=款码支付")
private String wechatTradeState;
/**
* 支付宝交易状态支付成功SUCCESS转入退款REFUND未支付NOTPAY已关闭CLOSED已撤销付款码支付REVOKED用户支付中付款码支付USERPAYING支付失败(其他原因如银行返回失败)PAYERROR
*/
@ApiModelProperty(value = "支付宝交易状态支付成功SUCCESS转入退款REFUND未支付NOTPAY已关闭CLOSED已撤销")
@Excel(name = "支付宝交易状态支付成功SUCCESS转入退款REFUND未支付NOTPAY已关闭CLOSED已撤销", readConverterExp = "付=款码支付")
private String alipayTradeState;
/**
* 支付通知参数内容微信或者支付宝支付回调通知信息
*/
@ApiModelProperty(value = "支付通知参数内容,微信或者支付宝支付回调通知信息")
@Excel(name = "支付通知参数内容,微信或者支付宝支付回调通知信息")
private String payNotifyContent;
/**
* 支付时间
*/
@ApiModelProperty(value = "支付时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "支付时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime payTime;
/**
* 支付账户类型新医路账户XINYILU医路优品YILUYOUPIN
*/
@ApiModelProperty(value = "支付账户类型新医路账户XINYILU医路优品YILUYOUPIN")
@Excel(name = "支付账户类型新医路账户XINYILU医路优品YILUYOUPIN")
private String paymentMerchantType;
/**
* 是否删除01
*/
private Integer delFlag;
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("patientId", getPatientId())
.append("orderNo", getOrderNo())
.append("paymentTitle", getPaymentTitle())
.append("transactionNo", getTransactionNo())
.append("payPrice", getPayPrice())
.append("payType", getPayType())
.append("payChannel", getPayChannel())
.append("wechatTradeState", getWechatTradeState())
.append("alipayTradeState", getAlipayTradeState())
.append("payNotifyContent", getPayNotifyContent())
.append("payTime", getPayTime())
.append("paymentMerchantType", getPaymentMerchantType())
.append("delFlag", getDelFlag())
.append("createBy", getCreateBy())
.append("createTime", getCreateTime())
.append("updateBy", getUpdateBy())
.append("updateTime", getUpdateTime())
.toString();
}
}

View File

@ -0,0 +1,205 @@
package com.xinelu.manage.domain.refundinfo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.xinelu.common.annotation.Excel;
import com.xinelu.common.core.domain.BaseDomain;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 退款记录信息对象 refund_info
*
* @author xinyilu
* @date 2022-10-18
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "退款记录信息对象", description = "refund_info")
public class RefundInfo extends BaseDomain implements Serializable {
private static final long serialVersionUID = -3202049270867033957L;
/**
* 主键id
*/
private Long id;
/**
* 会员id
*/
@ApiModelProperty(value = "会员id")
@Excel(name = "会员id")
private Long patientId;
/**
* 护理员表id
*/
private Long nurseStationPersonId;
/**
* 商品订单号
*/
@ApiModelProperty(value = "商品订单号")
@Excel(name = "商品订单号")
private String orderNo;
/**
* 支付退款单号多种支付方式共用
*/
@ApiModelProperty(value = "支付退款单号,多种支付方式共用")
@Excel(name = "支付退款单号,多种支付方式共用")
private String refundNo;
/**
* 商户退款单号系统自动生成
*/
@ApiModelProperty(value = "商户退款单号,系统自动生成")
@Excel(name = "商户退款单号,系统自动生成")
private String outRefundNo;
/**
* 支付交易订单号多种支付方式共用
*/
@ApiModelProperty(value = "支付交易订单号,多种支付方式共用")
@Excel(name = "支付交易订单号,多种支付方式共用")
private String transactionNo;
/**
* 退款原因
*/
@ApiModelProperty(value = "退款原因")
@Excel(name = "退款原因")
private String refundReason;
/**
* 退款方式微信WE_CHAT支付宝ALI_PAY
*/
@ApiModelProperty(value = "退款方式微信WE_CHAT支付宝ALI_PAY")
@Excel(name = "退款方式微信WE_CHAT支付宝ALI_PAY")
private String refundType;
/**
* 微信退款状态退款成功SUCCESS退款关闭CLOSED退款处理中PROCESSING退款异常ABNORMAL
*/
@ApiModelProperty(value = "微信退款状态退款成功SUCCESS退款关闭CLOSED退款处理中PROCESSING退款异常ABNORMAL")
@Excel(name = "微信退款状态退款成功SUCCESS退款关闭CLOSED退款处理中PROCESSING退款异常ABNORMAL")
private String wechatRefundStatus;
/**
* 支付宝退款状态退款成功SUCCESS退款关闭CLOSED退款处理中PROCESSING退款异常ABNORMAL
*/
@ApiModelProperty(value = "支付宝退款状态退款成功SUCCESS退款关闭CLOSED退款处理中PROCESSING退款异常ABNORMAL")
@Excel(name = "支付宝退款状态退款成功SUCCESS退款关闭CLOSED退款处理中PROCESSING退款异常ABNORMAL")
private String alipayRefundStatus;
/**
* 订单金额
*/
@ApiModelProperty(value = "订单金额")
@Excel(name = "订单金额", readConverterExp = "分=")
private BigDecimal orderTotalPrice;
/**
* 退款金额
*/
@ApiModelProperty(value = "退款金额")
@Excel(name = "退款金额", readConverterExp = "分=")
private BigDecimal refundPrice;
/**
* 退款币种人民币CNY
*/
@ApiModelProperty(value = "退款币种人民币CNY")
@Excel(name = "退款币种人民币CNY")
private String currency;
/**
* ORIGINAL原路退款BALANCE退回到余额OTHER_BALANCE原账户异常退到其他余额账户OTHER_BANKCARD原银行卡异常退到其他银行卡
*/
@ApiModelProperty(value = "ORIGINAL原路退款BALANCE退回到余额OTHER_BALANCE原账户异常退到其他余额账户OTHER_BANKCARD原银行卡异常退到其他银行卡")
@Excel(name = "ORIGINAL原路退款BALANCE退回到余额OTHER_BALANCE原账户异常退到其他余额账户OTHER_BANKCARD原银行卡异常退到其他银行卡")
private String channel;
/**
* 退款入账账户
*/
@ApiModelProperty(value = "退款入账账户")
@Excel(name = "退款入账账户")
private String userreceivedaccount;
/**
* 退款成功时间
*/
@ApiModelProperty(value = "退款成功时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "退款成功时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime successTime;
/**
* 退款回调通知内容微信或者支付款退款通知内容
*/
@ApiModelProperty(value = "退款回调通知内容,微信或者支付款退款通知内容")
@Excel(name = "退款回调通知内容,微信或者支付款退款通知内容")
private String refundNotifyContent;
/**
* 申请退款返回参数内容
*/
@ApiModelProperty(value = "申请退款返回参数内容")
@Excel(name = "申请退款返回参数内容")
private String applyRefundReturnContent;
/**
* 退款账户类型新医路账户XINYILU医路优品YILUYOUPIN
*/
@ApiModelProperty(value = "退款账户类型新医路账户XINYILU医路优品YILUYOUPIN")
@Excel(name = "退款账户类型新医路账户XINYILU医路优品YILUYOUPIN")
private String refundMerchantType;
/**
* 是否删除01
*/
private Integer delFlag;
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("patientId", getPatientId())
.append("orderNo", getOrderNo())
.append("refundNo", getRefundNo())
.append("outRefundNo", getOutRefundNo())
.append("transactionNo", getTransactionNo())
.append("refundReason", getRefundReason())
.append("refundType", getRefundType())
.append("wechatRefundStatus", getWechatRefundStatus())
.append("alipayRefundStatus", getAlipayRefundStatus())
.append("orderTotalPrice", getOrderTotalPrice())
.append("refundPrice", getRefundPrice())
.append("currency", getCurrency())
.append("channel", getChannel())
.append("userreceivedaccount", getUserreceivedaccount())
.append("successTime", getSuccessTime())
.append("refundNotifyContent", getRefundNotifyContent())
.append("applyRefundReturnContent", getApplyRefundReturnContent())
.append("refundMerchantType", getRefundMerchantType())
.append("delFlag", getDelFlag())
.append("createBy", getCreateBy())
.append("createTime", getCreateTime())
.append("updateBy", getUpdateBy())
.append("updateTime", getUpdateTime())
.toString();
}
}

View File

@ -0,0 +1,70 @@
package com.xinelu.manage.mapper.paymentinfo;
import com.xinelu.manage.domain.paymentinfo.PaymentInfo;
import java.util.List;
/**
* 支付记录信息Mapper接口
*
* @author xinyilu
* @date 2022-10-18
*/
public interface PaymentInfoMapper {
/**
* 查询支付记录信息
*
* @param id 支付记录信息主键
* @return 支付记录信息
*/
PaymentInfo selectPaymentInfoById(Long id);
/**
* 查询支付记录信息列表
*
* @param paymentInfo 支付记录信息
* @return 支付记录信息集合
*/
List<PaymentInfo> selectPaymentInfoList(PaymentInfo paymentInfo);
/**
* 新增支付记录信息
*
* @param paymentInfo 支付记录信息
* @return 结果
*/
int insertPaymentInfo(PaymentInfo paymentInfo);
/**
* 修改支付记录信息
*
* @param paymentInfo 支付记录信息
* @return 结果
*/
int updatePaymentInfo(PaymentInfo paymentInfo);
/**
* 删除支付记录信息
*
* @param id 支付记录信息主键
* @return 结果
*/
int deletePaymentInfoById(Long id);
/**
* 批量删除支付记录信息
*
* @param ids 需要删除的数据主键集合
* @return 结果
*/
int deletePaymentInfoByIds(Long[] ids);
/**
* 根据订单查询支付记录表信息
*
* @param orderNo 订单编号
* @return 数量
*/
int getPaymentInfoByOrderNo(String orderNo);
}

View File

@ -0,0 +1,90 @@
package com.xinelu.manage.mapper.refundinfo;
import com.xinelu.manage.domain.refundinfo.RefundInfo;
import org.apache.ibatis.annotations.Param;
import java.time.LocalDateTime;
import java.util.List;
/**
* 退款记录信息Mapper接口
*
* @author xinyilu
* @date 2022-10-18
*/
public interface RefundInfoMapper {
/**
* 查询退款记录信息
*
* @param id 退款记录信息主键
* @return 退款记录信息
*/
RefundInfo selectRefundInfoById(Long id);
/**
* 查询退款记录信息列表
*
* @param refundInfo 退款记录信息
* @return 退款记录信息集合
*/
List<RefundInfo> selectRefundInfoList(RefundInfo refundInfo);
/**
* 新增退款记录信息
*
* @param refundInfo 退款记录信息
* @return 结果
*/
int insertRefundInfo(RefundInfo refundInfo);
/**
* 修改退款记录信息
*
* @param refundInfo 退款记录信息
* @return 结果
*/
int updateRefundInfo(RefundInfo refundInfo);
/**
* 删除退款记录信息
*
* @param id 退款记录信息主键
* @return 结果
*/
int deleteRefundInfoById(Long id);
/**
* 批量删除退款记录信息
*
* @param ids 需要删除的数据主键集合
* @return 结果
*/
int deleteRefundInfoByIds(Long[] ids);
/**
* 修改退款单信息
*
* @param refundInfo 退款单信息
* @return 更新数量
*/
int updateRefundInfoByNo(RefundInfo refundInfo);
/**
* 批量更新支付订单状态
*
* @param orderNo 订单编号
* @param successTime 退款成功时间
* @param weChatRefundStatus 订单状态
* @return 更新数量
*/
int updateBatchRefundStatus(@Param("orderNo") String orderNo, @Param("successTime") LocalDateTime successTime,
@Param("weChatRefundStatus") String weChatRefundStatus);
/**
* 根据订单编号查询支付退款表信息
*
* @param orderNo 订单编号
* @return 数量
*/
int getRefundInfoByOrderNo(String orderNo);
}

View File

@ -13,7 +13,6 @@ import com.xinelu.manage.mapper.appointmentorder.AppointmentOrderMapper;
import com.xinelu.manage.mapper.appointmentorderconsumable.AppointmentOrderConsumableMapper;
import com.xinelu.manage.mapper.appointmentorderdetails.AppointmentOrderDetailsMapper;
import com.xinelu.manage.service.appointmentorder.IAppointmentOrderService;
import com.xinelu.manage.service.stationmessagepush.StationMessagePushService;
import com.xinelu.manage.vo.appointmentorder.AppointmentOrderVO;
import com.xinelu.manage.vo.appointmentorder.PersonAndDepartmentVO;
import lombok.extern.slf4j.Slf4j;
@ -42,8 +41,6 @@ public class AppointmentOrderServiceImpl implements IAppointmentOrderService {
private AppointmentOrderDetailsMapper appointmentOrderDetailsMapper;
@Resource
private AppointmentOrderConsumableMapper appointmentOrderConsumableMapper;
@Resource
private StationMessagePushService stationMessagePushService;
/**
* 查询预约订单信息
@ -178,7 +175,6 @@ public class AppointmentOrderServiceImpl implements IAppointmentOrderService {
if (updateAppointmentOrderStatus <= 0) {
throw new ServiceException("派单失败,请联系管理员!");
}
stationMessagePushService.waitReceiveMessagePush(appointmentOrder);
return AjaxResult.success();
}

View File

@ -61,4 +61,4 @@ public interface IInformationService {
* @return 结果
*/
int deleteInformationById(Long id);
}
}

View File

@ -1,408 +0,0 @@
package com.xinelu.manage.service.stationmessagepush.Impl;
import com.alibaba.fastjson2.JSON;
import com.xinelu.common.config.NurseAppletChatConfig;
import com.xinelu.common.config.NurseAppletPageConfig;
import com.xinelu.common.constant.Constants;
import com.xinelu.common.entity.AppletAccessToken;
import com.xinelu.common.entity.MessageValueEntity;
import com.xinelu.common.enums.AppletSubscriptionMessageEnum;
import com.xinelu.common.enums.SubscribeStatusEnum;
import com.xinelu.common.utils.AppletChatUtil;
import com.xinelu.common.utils.http.HttpUtils;
import com.xinelu.manage.domain.appointmentorder.AppointmentOrder;
import com.xinelu.manage.domain.personsubscribemessage.PersonSubscribeMessage;
import com.xinelu.manage.mapper.appointmentorder.AppointmentOrderMapper;
import com.xinelu.manage.mapper.personsubscribemessage.PersonSubscribeMessageMapper;
import com.xinelu.manage.service.stationmessagepush.StationMessagePushService;
import com.xinelu.manage.vo.appointmentorder.AppointmentOrderInfoVO;
import com.xinelu.manage.vo.appointmentorder.AppointmentOrderRecordVO;
import com.xinelu.manage.vo.appointmentorder.AppointmentReceivingOrderVO;
import com.xinelu.manage.vo.personsubscribemessage.PersonSubscribeMessageVO;
import com.xinelu.manage.vo.stationmessagepush.WaitReceiveMessagePushVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
/**
* 派单消息推送业务层
*
* @author zh
*/
@Slf4j
@Service
public class StationMessagePushServiceImpl implements StationMessagePushService {
@Resource
private NurseAppletChatConfig nurseAppletChatConfig;
@Resource
private PersonSubscribeMessageMapper personSubscribeMessageMapper;
@Resource
private AppointmentOrderMapper appointmentOrderMapper;
@Resource
private NurseAppletPageConfig nurseAppletPageConfig;
/**
* 微信消息推送url
*/
private static final String MESSAGE_PUSH_URL = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=";
/**
* 派单后提醒护理员接单消息推送
*
* @param appointmentOrder 订单信息
*/
@Override
@Async("asyncThreadServiceExecutor")
public void waitReceiveMessagePush(AppointmentOrder appointmentOrder) {
log.info("待接单消息提醒,订单参数:{}", appointmentOrder);
//获取AppletAccessToken的值
AppletAccessToken appletAccessToken = AppletChatUtil.getAppletAccessToken(nurseAppletChatConfig.getAppletId(), nurseAppletChatConfig.getSecret());
if (Objects.isNull(appletAccessToken)) {
log.error("获取微信小程序accessToken信息失败");
return;
}
if (Objects.nonNull(appletAccessToken.getErrcode()) && appletAccessToken.getErrcode() != AppletSubscriptionMessageEnum.SUCCESS_ERRCODE.getValue()) {
log.error("获取微信小程序accessToken信息失败失败信息为" + appletAccessToken.getErrmsg(), 201);
return;
}
if (StringUtils.isBlank(appletAccessToken.getAccessToken())) {
log.error("accessToken信息为空");
return;
}
//获取用户信息订阅消息记录规则信息
PersonSubscribeMessage personSubscribeMessage = personSubscribeMessageMapper
.selectPersonSubscribeMessageByPatientId(appointmentOrder.getNurseStationPersonId(), null, nurseAppletChatConfig.getReceivingOrdersNurseTemplateId());
if (Objects.isNull(personSubscribeMessage) || StringUtils.isBlank(personSubscribeMessage.getOpenid()) || StringUtils.isBlank(personSubscribeMessage.getSubscribeStatus()) || !SubscribeStatusEnum.ACCEPT.getInfo().equals(personSubscribeMessage.getSubscribeStatus())) {
return;
}
WaitReceiveMessagePushVO waitReceiveOrderDetails = appointmentOrderMapper.selectOrderDetailsAndPatientBy(appointmentOrder.getOrderNo());
if (Objects.isNull(waitReceiveOrderDetails)) {
return;
}
this.waitReceiveMessage(waitReceiveOrderDetails, personSubscribeMessage, appletAccessToken);
}
/**
* 待接单消息推送
*
* @param appletAccessToken 令牌
* @param dispatchOrderDetails 订单信息
* @param personSubscribeMessage 订阅消息记录
*/
@Override
public void waitReceiveMessage(WaitReceiveMessagePushVO dispatchOrderDetails, PersonSubscribeMessage personSubscribeMessage, AppletAccessToken appletAccessToken) {
//模板参数用户openid推送消息模板id
Map<String, Object> paramsMap = new LinkedHashMap<>();
paramsMap.put("touser", personSubscribeMessage.getOpenid());
paramsMap.put("template_id", nurseAppletChatConfig.getReceivingOrdersNurseTemplateId());
paramsMap.put("page", nurseAppletPageConfig.getWorkPageUrl());
String serviceDate = DateTimeFormatter.ofPattern("yyyy-MM-dd").format(Objects.isNull(dispatchOrderDetails.getServiceDate()) ? LocalDate.now() : dispatchOrderDetails.getServiceDate());
LocalTime serviceStartTime = Objects.isNull(dispatchOrderDetails.getServiceStartTime()) ? LocalTime.now() : dispatchOrderDetails.getServiceStartTime();
//模板内容
Map<String, MessageValueEntity> messageValueEntityMap = new LinkedHashMap<>();
messageValueEntityMap.put("thing2", new MessageValueEntity(StringUtils.isBlank(dispatchOrderDetails.getNurseItemName()) ? "" : dispatchOrderDetails.getNurseItemName()));
String serviceAddress = StringUtils.isBlank(dispatchOrderDetails.getServiceAddress()) ? "" : dispatchOrderDetails.getServiceAddress();
if (StringUtils.isNotBlank(serviceAddress) && dispatchOrderDetails.getServiceAddress().length() > 20) {
serviceAddress = dispatchOrderDetails.getServiceAddress().substring(0, 19);
}
messageValueEntityMap.put("thing6", new MessageValueEntity(serviceAddress));
messageValueEntityMap.put("time16", new MessageValueEntity(serviceDate + " " + serviceStartTime));
messageValueEntityMap.put("thing7", new MessageValueEntity(StringUtils.isBlank(dispatchOrderDetails.getPatientName()) ? "" : dispatchOrderDetails.getPatientName()));
messageValueEntityMap.put("phone_number8", new MessageValueEntity(StringUtils.isBlank(dispatchOrderDetails.getPhone()) ? "" : dispatchOrderDetails.getPhone()));
paramsMap.put("data", messageValueEntityMap);
this.sendPosts(appletAccessToken, paramsMap);
}
/**
* 服务派单通知运营人员
*
* @param appointmentOrderInfo 订单信息表
**/
@Override
@Async("asyncThreadServiceExecutor")
public void serviceDispatchOperationsPush(AppointmentOrderInfoVO appointmentOrderInfo) {
log.info("预定订单下单派单消息提醒,订单参数:{}", appointmentOrderInfo);
//根据护理人员id去查询护理人员角色是否是护理站管理人员
List<PersonSubscribeMessageVO> personSubscribe = personSubscribeMessageMapper.selectPersonSubscribeMessageByPersonWechatId(appointmentOrderInfo.getNurseStationId(), null, null, nurseAppletChatConfig.getServiceDispatchOperationsTemplateId());
if (CollectionUtils.isEmpty(personSubscribe)) {
return;
}
//循环发送
AppletAccessToken appletAccessToken = getAppletAccessToken();
for (PersonSubscribeMessageVO personSubscribeMessage : personSubscribe) {
boolean subscribeMessage = Objects.nonNull(personSubscribeMessage)
&& StringUtils.isNotBlank(personSubscribeMessage.getSubscribeStatus())
&& SubscribeStatusEnum.ACCEPT.getInfo().equals(personSubscribeMessage.getSubscribeStatus());
if (BooleanUtils.isTrue(subscribeMessage)) {
//构建微信小程序消息推送参数
Map<String, Object> paramsMap = new LinkedHashMap<>();
paramsMap.put("template_id", StringUtils.isBlank(personSubscribeMessage.getTemplateId()) ? "" : personSubscribeMessage.getTemplateId());
paramsMap.put("page", nurseAppletPageConfig.getNursePageUrl());
paramsMap.put("touser", StringUtils.isBlank(personSubscribeMessage.getOpenid()) ? "" : personSubscribeMessage.getOpenid());
paramsMap.put("lang", "zh_CN");
//构建微信小程序消息推送内容参数
Map<String, MessageValueEntity> amountParamMap = new HashMap<>();
//服务项目
amountParamMap.put("thing2", new MessageValueEntity(StringUtils.isBlank(appointmentOrderInfo.getNurseItemName()) ? "" : appointmentOrderInfo.getNurseItemName()));
//服务信息
amountParamMap.put("thing3", new MessageValueEntity(StringUtils.isBlank(appointmentOrderInfo.getItemServeDurationUnit()) ? "" : appointmentOrderInfo.getItemServeDurationUnit()));
//订单编号
amountParamMap.put("character_string13", new MessageValueEntity(StringUtils.isBlank(appointmentOrderInfo.getOrderNo()) ? "" : appointmentOrderInfo.getOrderNo()));
//上门时间
String serviceDate = DateTimeFormatter.ofPattern("yyyy-MM-dd").format(Objects.isNull(appointmentOrderInfo.getServiceDate()) ? LocalDate.now() : appointmentOrderInfo.getServiceDate());
LocalTime serviceStartTime = Objects.isNull(appointmentOrderInfo.getServiceStartTime()) ? LocalTime.now() : appointmentOrderInfo.getServiceStartTime();
amountParamMap.put("time24", new MessageValueEntity(serviceDate + " " + serviceStartTime));
//上门地址
String serviceAddress = StringUtils.isBlank(appointmentOrderInfo.getServiceAddress()) ? "" : appointmentOrderInfo.getServiceAddress();
if (StringUtils.isNotBlank(serviceAddress) && appointmentOrderInfo.getServiceAddress().length() > 20) {
serviceAddress = appointmentOrderInfo.getServiceAddress().substring(0, 19);
}
amountParamMap.put("thing25", new MessageValueEntity(serviceAddress));
paramsMap.put("data", amountParamMap);
//发送
this.sendPosts(appletAccessToken, paramsMap);
}
}
}
/**
* 接单提醒通知运营人员
*
* @param appointmentReceivingOrder 订单信息表
**/
@Override
@Async("asyncThreadServiceExecutor")
public void receivingOrdersOperationsPush(AppointmentReceivingOrderVO appointmentReceivingOrder) {
//根据护理人员id去查询护理人员角色是否是护理站管理人员
log.info("预约订单接单消息提醒,订单参数:{}", appointmentReceivingOrder);
List<PersonSubscribeMessageVO> personSubscribe = personSubscribeMessageMapper.selectPersonSubscribeMessageByPersonWechatId(appointmentReceivingOrder.getNurseStationId(), null, null, nurseAppletChatConfig.getReceivingOrdersOperationsTemplateId());
if (CollectionUtils.isEmpty(personSubscribe)) {
return;
}
//循环发送
AppletAccessToken appletAccessToken = getAppletAccessToken();
for (PersonSubscribeMessageVO personSubscribeMessage : personSubscribe) {
boolean subscribeMessage = Objects.nonNull(personSubscribeMessage)
&& StringUtils.isNotBlank(personSubscribeMessage.getSubscribeStatus())
&& SubscribeStatusEnum.ACCEPT.getInfo().equals(personSubscribeMessage.getSubscribeStatus());
if (BooleanUtils.isTrue(subscribeMessage)) {
//构建微信小程序消息推送参数
Map<String, Object> paramsMap = new LinkedHashMap<>();
paramsMap.put("template_id", StringUtils.isBlank(personSubscribeMessage.getTemplateId()) ? "" : personSubscribeMessage.getTemplateId());
paramsMap.put("page", nurseAppletPageConfig.getNursePageUrl());
paramsMap.put("touser", StringUtils.isBlank(personSubscribeMessage.getOpenid()) ? "" : personSubscribeMessage.getOpenid());
paramsMap.put("lang", "zh_CN");
//构建微信小程序消息推送内容参数
Map<String, MessageValueEntity> amountParamMap = new HashMap<>();
//服务师傅
amountParamMap.put("thing15", new MessageValueEntity(StringUtils.isBlank(appointmentReceivingOrder.getNursePersonName()) ? "" : appointmentReceivingOrder.getNursePersonName()));
//预约时间
String serviceDate = DateTimeFormatter.ofPattern("yyyy-MM-dd").format(Objects.isNull(appointmentReceivingOrder.getServiceDate()) ? LocalDate.now() : appointmentReceivingOrder.getServiceDate());
LocalTime serviceStartTime = Objects.isNull(appointmentReceivingOrder.getServiceStartTime()) ? LocalTime.now() : appointmentReceivingOrder.getServiceStartTime();
amountParamMap.put("time11", new MessageValueEntity(serviceDate + " " + serviceStartTime));
//地点
String serviceAddress = StringUtils.isBlank(appointmentReceivingOrder.getServiceAddress()) ? "" : appointmentReceivingOrder.getServiceAddress();
if (StringUtils.isNotBlank(serviceAddress) && appointmentReceivingOrder.getServiceAddress().length() > 20) {
serviceAddress = appointmentReceivingOrder.getServiceAddress().substring(0, 19);
}
amountParamMap.put("thing9", new MessageValueEntity(serviceAddress));
//电话
amountParamMap.put("phone_number8", new MessageValueEntity(StringUtils.isBlank(appointmentReceivingOrder.getPhone()) ? "" : appointmentReceivingOrder.getPhone()));
//业主
amountParamMap.put("thing7", new MessageValueEntity(StringUtils.isBlank(appointmentReceivingOrder.getPatientName()) ? "" : appointmentReceivingOrder.getPatientName()));
paramsMap.put("data", amountParamMap);
//发送
this.sendPosts(appletAccessToken, paramsMap);
}
}
}
/**
* 拒单通知运营人员
*
* @param appointmentReceivingOrder 订单信息表
**/
@Override
@Async("asyncThreadServiceExecutor")
public void refusalOrdersOperationsPush(AppointmentReceivingOrderVO appointmentReceivingOrder) {
//根据护理人员id去查询护理人员角色是否是护理站管理人员
log.info("预约订单拒单消息提醒,订单参数:{}", appointmentReceivingOrder);
List<PersonSubscribeMessageVO> personSubscribe = personSubscribeMessageMapper.selectPersonSubscribeMessageByPersonWechatId(appointmentReceivingOrder.getNurseStationId(), null, null, nurseAppletChatConfig.getRefusalOrdersOperationsTemplateId());
if (CollectionUtils.isEmpty(personSubscribe)) {
return;
}
//循环发送
AppletAccessToken appletAccessToken = getAppletAccessToken();
for (PersonSubscribeMessageVO personSubscribeMessage : personSubscribe) {
boolean subscribeMessage = Objects.nonNull(personSubscribeMessage)
&& StringUtils.isNotBlank(personSubscribeMessage.getSubscribeStatus())
&& SubscribeStatusEnum.ACCEPT.getInfo().equals(personSubscribeMessage.getSubscribeStatus());
if (BooleanUtils.isTrue(subscribeMessage)) {
//构建微信小程序消息推送参数
Map<String, Object> paramsMap = new LinkedHashMap<>();
paramsMap.put("template_id", StringUtils.isBlank(personSubscribeMessage.getTemplateId()) ? "" : personSubscribeMessage.getTemplateId());
paramsMap.put("page", nurseAppletPageConfig.getNursePageUrl());
paramsMap.put("touser", StringUtils.isBlank(personSubscribeMessage.getOpenid()) ? "" : personSubscribeMessage.getOpenid());
paramsMap.put("lang", "zh_CN");
//构建微信小程序消息推送内容参数
Map<String, MessageValueEntity> amountParamMap = new HashMap<>();
//订单编号
amountParamMap.put("character_string3", new MessageValueEntity(StringUtils.isBlank(appointmentReceivingOrder.getOrderNo()) ? "" : appointmentReceivingOrder.getOrderNo()));
//服务内容
amountParamMap.put("thing1", new MessageValueEntity(StringUtils.isBlank(appointmentReceivingOrder.getNurseItemName()) ? "" : appointmentReceivingOrder.getNurseItemName()));
//服务时间
String serviceDate = DateTimeFormatter.ofPattern("yyyy-MM-dd").format(Objects.isNull(appointmentReceivingOrder.getServiceDate()) ? LocalDate.now() : appointmentReceivingOrder.getServiceDate());
LocalTime serviceStartTime = Objects.isNull(appointmentReceivingOrder.getServiceStartTime()) ? LocalTime.now() : appointmentReceivingOrder.getServiceStartTime();
amountParamMap.put("time4", new MessageValueEntity(serviceDate + " " + serviceStartTime));
//服务地点
String serviceAddress = StringUtils.isBlank(appointmentReceivingOrder.getServiceAddress()) ? "" : appointmentReceivingOrder.getServiceAddress();
if (StringUtils.isNotBlank(serviceAddress) && appointmentReceivingOrder.getServiceAddress().length() > 20) {
serviceAddress = appointmentReceivingOrder.getServiceAddress().substring(0, 19);
}
amountParamMap.put("thing5", new MessageValueEntity(serviceAddress));
//拒单理由
String taskReturnReason = StringUtils.isBlank(appointmentReceivingOrder.getTaskReturnReason()) ? "" : appointmentReceivingOrder.getTaskReturnReason();
String[] split = StringUtils.split(taskReturnReason, ";");
if (split.length > 0) {
taskReturnReason = split[0];
if (StringUtils.isNotBlank(taskReturnReason) && taskReturnReason.length() > 20) {
taskReturnReason = taskReturnReason.substring(0, 19);
}
}
amountParamMap.put("thing6", new MessageValueEntity(taskReturnReason));
paramsMap.put("data", amountParamMap);
//发送
this.sendPosts(appletAccessToken, paramsMap);
}
}
}
/**
* 订单完成通知运营人员
*
* @param appointmentOrderRecordVO 订单信息表
**/
@Override
@Async("asyncThreadServiceExecutor")
public void orderCompletionOperationsPush(AppointmentOrderRecordVO appointmentOrderRecordVO) {
//根据护理人员id去查询护理人员角色是否是护理站管理人员
log.info("预约订单完成消息提醒,订单参数:{}", appointmentOrderRecordVO);
List<PersonSubscribeMessageVO> personSubscribe = personSubscribeMessageMapper.selectPersonSubscribeMessageByPersonWechatId(appointmentOrderRecordVO.getNurseStationId(), null, null, nurseAppletChatConfig.getOrderCompletionOperationsTemplateId());
if (CollectionUtils.isEmpty(personSubscribe)) {
return;
}
//循环发送
AppletAccessToken appletAccessToken = getAppletAccessToken();
for (PersonSubscribeMessageVO personSubscribeMessage : personSubscribe) {
boolean subscribeMessage = Objects.nonNull(personSubscribeMessage)
&& StringUtils.isNotBlank(personSubscribeMessage.getSubscribeStatus())
&& SubscribeStatusEnum.ACCEPT.getInfo().equals(personSubscribeMessage.getSubscribeStatus());
if (BooleanUtils.isTrue(subscribeMessage)) {
//构建微信小程序消息推送参数
Map<String, Object> paramsMap = new LinkedHashMap<>();
paramsMap.put("template_id", StringUtils.isBlank(personSubscribeMessage.getTemplateId()) ? "" : personSubscribeMessage.getTemplateId());
paramsMap.put("page", nurseAppletPageConfig.getNursePageUrl());
paramsMap.put("touser", StringUtils.isBlank(personSubscribeMessage.getOpenid()) ? "" : personSubscribeMessage.getOpenid());
paramsMap.put("lang", "zh_CN");
//构建微信小程序消息推送内容参数
Map<String, MessageValueEntity> amountParamMap = new HashMap<>();
//订单编号
amountParamMap.put("character_string5", new MessageValueEntity(StringUtils.isBlank(appointmentOrderRecordVO.getOrderNo()) ? "" : appointmentOrderRecordVO.getOrderNo()));
//服务内容
amountParamMap.put("thing6", new MessageValueEntity(StringUtils.isBlank(appointmentOrderRecordVO.getNurseItemName()) ? "" : appointmentOrderRecordVO.getNurseItemName()));
//服务金额
BigDecimal totalPrice = Objects.isNull(appointmentOrderRecordVO.getTotalPrice()) ? BigDecimal.ZERO : appointmentOrderRecordVO.getTotalPrice();
amountParamMap.put("amount8", new MessageValueEntity(totalPrice + ""));
//骑手和电话
amountParamMap.put("thing21", new MessageValueEntity((StringUtils.isBlank(appointmentOrderRecordVO.getNursePersonName()) ? "" : appointmentOrderRecordVO.getNursePersonName()) + " " + (StringUtils.isBlank(appointmentOrderRecordVO.getPhone()) ? "" : appointmentOrderRecordVO.getPhone())));
//订单地址
String serviceAddress = StringUtils.isBlank(appointmentOrderRecordVO.getServiceAddress()) ? "" : appointmentOrderRecordVO.getServiceAddress();
if (StringUtils.isNotBlank(serviceAddress) && appointmentOrderRecordVO.getServiceAddress().length() > 20) {
serviceAddress = appointmentOrderRecordVO.getServiceAddress().substring(0, 19);
}
amountParamMap.put("thing1", new MessageValueEntity(serviceAddress));
paramsMap.put("data", amountParamMap);
//发送
this.sendPosts(appletAccessToken, paramsMap);
}
}
}
/**
* 获取appletAccessToken
*
* @return com.xinyilu.common.entity.AppletAccessToken
**/
private AppletAccessToken getAppletAccessToken() {
//获取AppletAccessToken的值
AppletAccessToken appletAccessToken = AppletChatUtil.getAppletAccessToken(nurseAppletChatConfig.getAppletId(), nurseAppletChatConfig.getSecret());
if (Objects.isNull(appletAccessToken)) {
log.error("获取微信小程序accessToken信息失败");
}
if (Objects.nonNull(appletAccessToken.getErrcode()) && appletAccessToken.getErrcode() != AppletSubscriptionMessageEnum.SUCCESS_ERRCODE.getValue()) {
log.error("获取微信小程序accessToken信息失败失败信息为" + appletAccessToken.getErrmsg(), 201);
}
if (StringUtils.isBlank(appletAccessToken.getAccessToken())) {
log.error("accessToken信息为空");
}
return appletAccessToken;
}
/**
* 发送
*
* @param appletAccessToken 令牌
* @param paramsMap 模板
**/
@Override
public void sendPosts(AppletAccessToken appletAccessToken, Map<String, Object> paramsMap) {
//拼接请求地址并发送
String messageUrl = MESSAGE_PUSH_URL + appletAccessToken.getAccessToken();
String param = JSON.toJSONString(paramsMap);
String result = HttpUtils.sendPostJson(messageUrl, param);
//返回参数映射
AppletAccessToken errCode = JSON.parseObject(result, AppletAccessToken.class);
if (Objects.nonNull(errCode) && Objects.nonNull(errCode.getErrcode())) {
switch (errCode.getErrcode()) {
case Constants.SUCCESS_ERRCODE:
log.info("发送消息成功!");
break;
case Constants.INVALID_CREDENTIAL_ACCESS_TOKEN_ISINVALID_OR_NOT_LATEST:
log.error("取 access_token 时 AppSecret 错误,或者 access_token 无效!");
break;
case Constants.INVALID_OPENID:
log.error("不合法的 OpenId");
break;
case Constants.INVALID_ACCESS_TOKEN:
log.error("合法的 access_token");
break;
case Constants.INVALID_TEMPLATE_ID:
log.error("不合法的 template_id");
break;
case Constants.ARGUMENT_INVALID:
log.error("参数无效!");
break;
case Constants.DENY_SUBSCRIPTION:
log.error("用户拒接订阅!");
break;
default:
break;
}
}
}
}

View File

@ -1,73 +0,0 @@
package com.xinelu.manage.service.stationmessagepush;
import com.xinelu.common.entity.AppletAccessToken;
import com.xinelu.manage.domain.appointmentorder.AppointmentOrder;
import com.xinelu.manage.domain.personsubscribemessage.PersonSubscribeMessage;
import com.xinelu.manage.vo.appointmentorder.AppointmentOrderInfoVO;
import com.xinelu.manage.vo.appointmentorder.AppointmentOrderRecordVO;
import com.xinelu.manage.vo.appointmentorder.AppointmentReceivingOrderVO;
import com.xinelu.manage.vo.stationmessagepush.WaitReceiveMessagePushVO;
import java.util.Map;
/**
* 派单消息推送Service接口
*
* @author zh
* @date 2023-04-03
*/
public interface StationMessagePushService {
/**
* 派单后提醒护理员接单提醒
*
* @param appointmentOrder 订单信息
*/
void waitReceiveMessagePush(AppointmentOrder appointmentOrder);
/**
* 服务代派单通知运营人员
*
* @param appointmentOrderInfo 订单信息表
**/
void serviceDispatchOperationsPush(AppointmentOrderInfoVO appointmentOrderInfo);
/**
* 接单提醒通知运营人员
*
* @param appointmentReceivingOrder 订单信息表
**/
void receivingOrdersOperationsPush(AppointmentReceivingOrderVO appointmentReceivingOrder);
/**
* 拒单通知运营人员
*
* @param appointmentReceivingOrder 订单信息表
**/
void refusalOrdersOperationsPush(AppointmentReceivingOrderVO appointmentReceivingOrder);
/**
* 订单完成通知运营人员
*
* @param appointmentOrderRecordVO 订单信息表
**/
void orderCompletionOperationsPush(AppointmentOrderRecordVO appointmentOrderRecordVO);
/**
* 发送
*
* @param appletAccessToken 令牌
* @param paramsMap 模板
**/
void sendPosts(AppletAccessToken appletAccessToken, Map<String, Object> paramsMap);
/**
* 待接单消息推送
*
* @param appletAccessToken 令牌
* @param dispatchOrderDetails 订单信息
* @param personSubscribeMessage 订阅消息记录
*/
void waitReceiveMessage(WaitReceiveMessagePushVO dispatchOrderDetails, PersonSubscribeMessage personSubscribeMessage, AppletAccessToken appletAccessToken);
}

View File

@ -34,6 +34,7 @@
<result property="healthConsultationContent" column="health_consultation_content"/>
<result property="healthAppointDate" column="health_appoint_date"/>
<result property="hospitalPersonName" column="hospital_person_name"/>
<result property="consultationInfoId" column="consultation_info_id"/>
</resultMap>
<!--商品订单信息及评价-->
@ -117,7 +118,8 @@
original_total_price,
health_consultation_content,
health_appoint_date,
hospital_person_name
hospital_person_name,
consultation_info_id
from goods_order
</sql>
@ -273,6 +275,8 @@
</if>
<if test="hospitalPersonName != null">hospital_person_name,
</if>
<if test="consultationInfoId != null">consultation_info_id,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="nurseStationId != null">#{nurseStationId},
@ -331,6 +335,8 @@
</if>
<if test="hospitalPersonName != null">#{hospitalPersonName},
</if>
<if test="consultationInfoId != null">#{consultationInfoId},
</if>
</trim>
</insert>
@ -421,6 +427,9 @@
<if test="hospitalPersonName != null">hospital_person_name =
#{hospitalPersonName},
</if>
<if test="consultationInfoId != null">consultation_info_id =
#{consultationInfoId},
</if>
</trim>
where id = #{id}
</update>

View File

@ -22,6 +22,8 @@
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
<result property="updateTime" column="update_time"/>
<result property="personAccount" column="person_account"/>
<result property="personPassword" column="person_password"/>
</resultMap>
<resultMap type="com.xinelu.manage.vo.hospitalpersoninfo.HospitalPersonInfoVO" id="HospitalPersonByIdVO">
@ -71,6 +73,8 @@
person_introduce,
person_sort,
person_picture_url,
person_account,
person_password,
create_by,
create_time,
update_by,
@ -238,6 +242,10 @@
</if>
<if test="personPictureUrl != null">person_picture_url,
</if>
<if test="personAccount != null">person_account,
</if>
<if test="personPassword != null">person_password,
</if>
<if test="createBy != null">create_by,
</if>
<if test="createTime != null">create_time,
@ -270,6 +278,10 @@
</if>
<if test="personPictureUrl != null">#{personPictureUrl},
</if>
<if test="personAccount != null">#{personAccount},
</if>
<if test="personPassword != null">#{personPassword},
</if>
<if test="createBy != null">#{createBy},
</if>
<if test="createTime != null">#{createTime},
@ -316,6 +328,12 @@
<if test="personPictureUrl != null">person_picture_url =
#{personPictureUrl},
</if>
<if test="personAccount != null">person_account =
#{personAccount},
</if>
<if test="personPassword != null">person_password =
#{personPassword},
</if>
<if test="createBy != null">create_by =
#{createBy},
</if>
@ -367,6 +385,12 @@
<if test="personPictureUrl != null">person_picture_url =
#{personPictureUrl},
</if>
<if test="personAccount != null">person_account =
#{personAccount},
</if>
<if test="personPassword != null">person_password =
#{personPassword},
</if>
<if test="createBy != null">create_by =
#{createBy},
</if>

View File

@ -194,8 +194,8 @@
<if test="compositeScore != null">composite_score =
#{compositeScore},
</if>
<if test="orderSource != null">
order_source = #{orderSource},
<if test="orderSource != null">order_source =
#{orderSource},
</if>
<if test="createBy != null">create_by =
#{createBy},

View File

@ -42,6 +42,10 @@
<result property="personalWechatCodeUrl" column="personal_wechat_code_url"/>
<result property="disablingCondition" column="disabling_condition"/>
<result property="disablingReason" column="disabling_reason"/>
<result property="disease" column="disease"/>
<result property="cityCode" column="city_code"/>
<result property="bindingTime" column="binding_time"/>
<result property="isChecked" column="is_checked"/>
</resultMap>
<sql id="selectPatientInfoVo">
@ -77,7 +81,11 @@
del_flag,
personal_wechat_code_url,
disabling_condition,
disabling_reason
disabling_reason,
disease,
city_code,
binding_time,
is_checked
from patient_info
</sql>
@ -289,6 +297,14 @@
</if>
<if test="disablingReason != null">disabling_reason,
</if>
<if test="disease != null">disease,
</if>
<if test="cityCode != null">city_code,
</if>
<if test="bindingTime != null">binding_time,
</if>
<if test="isChecked != null">is_checked,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="communityCode != null and communityCode != ''">#{communityCode},
@ -361,6 +377,14 @@
</if>
<if test="disablingReason != null">#{disablingReason},
</if>
<if test="disease != null">#{disease},
</if>
<if test="cityCode != null">#{cityCode},
</if>
<if test="bindingTime != null">#{bindingTime},
</if>
<if test="isChecked != null">#{isChecked},
</if>
</trim>
</insert>
@ -472,6 +496,18 @@
<if test="disablingReason != null">disabling_reason =
#{disablingReason},
</if>
<if test="disease != null">disease =
#{disease},
</if>
<if test="cityCode != null">city_code =
#{cityCode},
</if>
<if test="bindingTime != null">binding_time =
#{bindingTime},
</if>
<if test="isChecked != null">is_checked =
#{isChecked},
</if>
</trim>
where id = #{id}
</update>

View File

@ -0,0 +1,263 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xinelu.manage.mapper.paymentinfo.PaymentInfoMapper">
<resultMap type="PaymentInfo" id="PaymentInfoResult">
<result property="id" column="id"/>
<result property="patientId" column="patient_id"/>
<result property="nurseStationPersonId" column="nurse_station_person_id"/>
<result property="orderNo" column="order_no"/>
<result property="paymentTitle" column="payment_title"/>
<result property="transactionNo" column="transaction_no"/>
<result property="payPrice" column="pay_price"/>
<result property="payType" column="pay_type"/>
<result property="payChannel" column="pay_channel"/>
<result property="wechatTradeState" column="wechat_trade_state"/>
<result property="alipayTradeState" column="alipay_trade_state"/>
<result property="payNotifyContent" column="pay_notify_content"/>
<result property="payTime" column="pay_time"/>
<result property="paymentMerchantType" column="payment_merchant_type"/>
<result property="delFlag" column="del_flag"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
<result property="updateTime" column="update_time"/>
</resultMap>
<sql id="selectPaymentInfoVo">
select id,
patient_id,
nurse_station_person_id,
order_no,
payment_title,
transaction_no,
pay_price,
pay_type,
pay_channel,
wechat_trade_state,
alipay_trade_state,
pay_notify_content,
pay_time,
payment_merchant_type,
del_flag,
create_by,
create_time,
update_by,
update_time
from payment_info
</sql>
<select id="selectPaymentInfoList" parameterType="PaymentInfo" resultMap="PaymentInfoResult">
<include refid="selectPaymentInfoVo"/>
<where>
<if test="patientId != null ">
and patient_id = #{patientId}
</if>
<if test="nurseStationPersonId != null ">
and nurse_station_person_id = #{nurseStationPersonId}
</if>
<if test="orderNo != null and orderNo != ''">
and order_no = #{orderNo}
</if>
<if test="paymentTitle != null and paymentTitle != ''">
and payment_title = #{paymentTitle}
</if>
<if test="transactionNo != null and transactionNo != ''">
and transaction_no = #{transactionNo}
</if>
<if test="payPrice != null ">
and pay_price = #{payPrice}
</if>
<if test="payType != null and payType != ''">
and pay_type = #{payType}
</if>
<if test="payChannel != null and payChannel != ''">
and pay_channel = #{payChannel}
</if>
<if test="wechatTradeState != null and wechatTradeState != ''">
and wechat_trade_state = #{wechatTradeState}
</if>
<if test="alipayTradeState != null and alipayTradeState != ''">
and alipay_trade_state = #{alipayTradeState}
</if>
<if test="payNotifyContent != null and payNotifyContent != ''">
and pay_notify_content = #{payNotifyContent}
</if>
<if test="payTime != null ">
and pay_time = #{payTime}
</if>
<if test="paymentMerchantType != null and paymentMerchantType != ''">
and payment_merchant_type = #{paymentMerchantType}
</if>
</where>
</select>
<select id="selectPaymentInfoById" parameterType="Long"
resultMap="PaymentInfoResult">
<include refid="selectPaymentInfoVo"/>
where id = #{id}
</select>
<insert id="insertPaymentInfo" parameterType="PaymentInfo" useGeneratedKeys="true"
keyProperty="id">
insert into payment_info
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="patientId != null">patient_id,
</if>
<if test="nurseStationPersonId != null">nurse_station_person_id,
</if>
<if test="orderNo != null">order_no,
</if>
<if test="paymentTitle != null">payment_title,
</if>
<if test="transactionNo != null">transaction_no,
</if>
<if test="payPrice != null">pay_price,
</if>
<if test="payType != null">pay_type,
</if>
<if test="payChannel != null">pay_channel,
</if>
<if test="wechatTradeState != null">wechat_trade_state,
</if>
<if test="alipayTradeState != null">alipay_trade_state,
</if>
<if test="payNotifyContent != null">pay_notify_content,
</if>
<if test="payTime != null">pay_time,
</if>
<if test="paymentMerchantType != null">payment_merchant_type,
</if>
<if test="delFlag != null">del_flag,
</if>
<if test="createBy != null">create_by,
</if>
<if test="createTime != null">create_time,
</if>
<if test="updateBy != null">update_by,
</if>
<if test="updateTime != null">update_time,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="patientId != null">#{patientId},
</if>
<if test="nurseStationPersonId != null">#{nurseStationPersonId},
</if>
<if test="orderNo != null">#{orderNo},
</if>
<if test="paymentTitle != null">#{paymentTitle},
</if>
<if test="transactionNo != null">#{transactionNo},
</if>
<if test="payPrice != null">#{payPrice},
</if>
<if test="payType != null">#{payType},
</if>
<if test="payChannel != null">#{payChannel},
</if>
<if test="wechatTradeState != null">#{wechatTradeState},
</if>
<if test="alipayTradeState != null">#{alipayTradeState},
</if>
<if test="payNotifyContent != null">#{payNotifyContent},
</if>
<if test="payTime != null">#{payTime},
</if>
<if test="paymentMerchantType != null">#{paymentMerchantType},
</if>
<if test="delFlag != null">#{delFlag},
</if>
<if test="createBy != null">#{createBy},
</if>
<if test="createTime != null">#{createTime},
</if>
<if test="updateBy != null">#{updateBy},
</if>
<if test="updateTime != null">#{updateTime},
</if>
</trim>
</insert>
<update id="updatePaymentInfo" parameterType="PaymentInfo">
update payment_info
<trim prefix="SET" suffixOverrides=",">
<if test="patientId != null">patient_id =
#{patientId},
</if>
<if test="nurseStationPersonId != null">nurse_station_person_id =
#{nurseStationPersonId},
</if>
<if test="orderNo != null">order_no =
#{orderNo},
</if>
<if test="paymentTitle != null">payment_title =
#{paymentTitle},
</if>
<if test="transactionNo != null">transaction_no =
#{transactionNo},
</if>
<if test="payPrice != null">pay_price =
#{payPrice},
</if>
<if test="payType != null">pay_type =
#{payType},
</if>
<if test="payChannel != null">pay_channel =
#{payChannel},
</if>
<if test="wechatTradeState != null">wechat_trade_state =
#{wechatTradeState},
</if>
<if test="alipayTradeState != null">alipay_trade_state =
#{alipayTradeState},
</if>
<if test="payNotifyContent != null">pay_notify_content =
#{payNotifyContent},
</if>
<if test="payTime != null">pay_time =
#{payTime},
</if>
<if test="paymentMerchantType != null">payment_merchant_type =
#{paymentMerchantType},
</if>
<if test="delFlag != null">del_flag =
#{delFlag},
</if>
<if test="createBy != null">create_by =
#{createBy},
</if>
<if test="createTime != null">create_time =
#{createTime},
</if>
<if test="updateBy != null">update_by =
#{updateBy},
</if>
<if test="updateTime != null">update_time =
#{updateTime},
</if>
</trim>
where id = #{id}
</update>
<delete id="deletePaymentInfoById" parameterType="Long">
delete
from payment_info
where id = #{id}
</delete>
<delete id="deletePaymentInfoByIds" parameterType="String">
delete from payment_info where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
<select id="getPaymentInfoByOrderNo" parameterType="string" resultType="int">
select count(1) paymentCount
from payment_info
where order_no = #{orderNo}
</select>
</mapper>

View File

@ -0,0 +1,356 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xinelu.manage.mapper.refundinfo.RefundInfoMapper">
<resultMap type="RefundInfo" id="RefundInfoResult">
<result property="id" column="id"/>
<result property="patientId" column="patient_id"/>
<result property="nurseStationPersonId" column="nurse_station_person_id"/>
<result property="orderNo" column="order_no"/>
<result property="refundNo" column="refund_no"/>
<result property="outRefundNo" column="out_refund_no"/>
<result property="transactionNo" column="transaction_no"/>
<result property="refundReason" column="refund_reason"/>
<result property="refundType" column="refund_type"/>
<result property="wechatRefundStatus" column="wechat_refund_status"/>
<result property="alipayRefundStatus" column="alipay_refund_status"/>
<result property="orderTotalPrice" column="order_total_price"/>
<result property="refundPrice" column="refund_price"/>
<result property="currency" column="currency"/>
<result property="channel" column="channel"/>
<result property="userreceivedaccount" column="userReceivedAccount"/>
<result property="successTime" column="success_time"/>
<result property="refundNotifyContent" column="refund_notify_content"/>
<result property="applyRefundReturnContent" column="apply_refund_return_content"/>
<result property="refundMerchantType" column="refund_merchant_type"/>
<result property="delFlag" column="del_flag"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
<result property="updateTime" column="update_time"/>
</resultMap>
<sql id="selectRefundInfoVo">
select id,
patient_id,
nurse_station_person_id,
order_no,
refund_no,
out_refund_no,
transaction_no,
refund_reason,
refund_type,
wechat_refund_status,
alipay_refund_status,
order_total_price,
refund_price,
currency,
channel,
userReceivedAccount,
success_time,
refund_notify_content,
apply_refund_return_content,
refund_merchant_type,
del_flag,
create_by,
create_time,
update_by,
update_time
from refund_info
</sql>
<select id="selectRefundInfoList" parameterType="RefundInfo" resultMap="RefundInfoResult">
<include refid="selectRefundInfoVo"/>
<where>
<if test="patientId != null ">
and patient_id = #{patientId}
</if>
<if test="nurseStationPersonId != null ">
and nurse_station_person_id = #{nurseStationPersonId}
</if>
<if test="orderNo != null and orderNo != ''">
and order_no = #{orderNo}
</if>
<if test="refundNo != null and refundNo != ''">
and refund_no = #{refundNo}
</if>
<if test="outRefundNo != null and outRefundNo != ''">
and out_refund_no = #{outRefundNo}
</if>
<if test="transactionNo != null and transactionNo != ''">
and transaction_no = #{transactionNo}
</if>
<if test="refundReason != null and refundReason != ''">
and refund_reason = #{refundReason}
</if>
<if test="refundType != null and refundType != ''">
and refund_type = #{refundType}
</if>
<if test="wechatRefundStatus != null and wechatRefundStatus != ''">
and wechat_refund_status = #{wechatRefundStatus}
</if>
<if test="alipayRefundStatus != null and alipayRefundStatus != ''">
and alipay_refund_status = #{alipayRefundStatus}
</if>
<if test="orderTotalPrice != null ">
and order_total_price = #{orderTotalPrice}
</if>
<if test="refundPrice != null ">
and refund_price = #{refundPrice}
</if>
<if test="currency != null and currency != ''">
and currency = #{currency}
</if>
<if test="channel != null and channel != ''">
and channel = #{channel}
</if>
<if test="userreceivedaccount != null and userreceivedaccount != ''">
and userReceivedAccount = #{userreceivedaccount}
</if>
<if test="successTime != null ">
and success_time = #{successTime}
</if>
<if test="refundNotifyContent != null and refundNotifyContent != ''">
and refund_notify_content = #{refundNotifyContent}
</if>
<if test="applyRefundReturnContent != null and applyRefundReturnContent != ''">
and apply_refund_return_content = #{applyRefundReturnContent}
</if>
<if test="refundMerchantType != null and refundMerchantType != ''">
and refund_merchant_type = #{refundMerchantType}
</if>
</where>
</select>
<select id="selectRefundInfoById" parameterType="Long"
resultMap="RefundInfoResult">
<include refid="selectRefundInfoVo"/>
where id = #{id}
</select>
<insert id="insertRefundInfo" parameterType="RefundInfo" useGeneratedKeys="true"
keyProperty="id">
insert into refund_info
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="patientId != null">patient_id,
</if>
<if test="nurseStationPersonId != null">nurse_station_person_id,
</if>
<if test="orderNo != null">order_no,
</if>
<if test="refundNo != null">refund_no,
</if>
<if test="outRefundNo != null">out_refund_no,
</if>
<if test="transactionNo != null">transaction_no,
</if>
<if test="refundReason != null">refund_reason,
</if>
<if test="refundType != null">refund_type,
</if>
<if test="wechatRefundStatus != null">wechat_refund_status,
</if>
<if test="alipayRefundStatus != null">alipay_refund_status,
</if>
<if test="orderTotalPrice != null">order_total_price,
</if>
<if test="refundPrice != null">refund_price,
</if>
<if test="currency != null">currency,
</if>
<if test="channel != null">channel,
</if>
<if test="userreceivedaccount != null">userReceivedAccount,
</if>
<if test="successTime != null">success_time,
</if>
<if test="refundNotifyContent != null">refund_notify_content,
</if>
<if test="applyRefundReturnContent != null">apply_refund_return_content,
</if>
<if test="refundMerchantType != null">refund_merchant_type,
</if>
<if test="delFlag != null">del_flag,
</if>
<if test="createBy != null">create_by,
</if>
<if test="createTime != null">create_time,
</if>
<if test="updateBy != null">update_by,
</if>
<if test="updateTime != null">update_time,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="patientId != null">#{patientId},
</if>
<if test="nurseStationPersonId != null">#{nurseStationPersonId},
</if>
<if test="orderNo != null">#{orderNo},
</if>
<if test="refundNo != null">#{refundNo},
</if>
<if test="outRefundNo != null">#{outRefundNo},
</if>
<if test="transactionNo != null">#{transactionNo},
</if>
<if test="refundReason != null">#{refundReason},
</if>
<if test="refundType != null">#{refundType},
</if>
<if test="wechatRefundStatus != null">#{wechatRefundStatus},
</if>
<if test="alipayRefundStatus != null">#{alipayRefundStatus},
</if>
<if test="orderTotalPrice != null">#{orderTotalPrice},
</if>
<if test="refundPrice != null">#{refundPrice},
</if>
<if test="currency != null">#{currency},
</if>
<if test="channel != null">#{channel},
</if>
<if test="userreceivedaccount != null">#{userreceivedaccount},
</if>
<if test="successTime != null">#{successTime},
</if>
<if test="refundNotifyContent != null">#{refundNotifyContent},
</if>
<if test="applyRefundReturnContent != null">#{applyRefundReturnContent},
</if>
<if test="refundMerchantType != null">#{refundMerchantType},
</if>
<if test="delFlag != null">#{delFlag},
</if>
<if test="createBy != null">#{createBy},
</if>
<if test="createTime != null">#{createTime},
</if>
<if test="updateBy != null">#{updateBy},
</if>
<if test="updateTime != null">#{updateTime},
</if>
</trim>
</insert>
<update id="updateRefundInfo" parameterType="RefundInfo">
update refund_info
<trim prefix="SET" suffixOverrides=",">
<if test="patientId != null">patient_id =
#{patientId},
</if>
<if test="nurseStationPersonId != null">nurse_station_person_id =
#{nurseStationPersonId},
</if>
<if test="orderNo != null">order_no =
#{orderNo},
</if>
<if test="refundNo != null">refund_no =
#{refundNo},
</if>
<if test="outRefundNo != null">out_refund_no =
#{outRefundNo},
</if>
<if test="transactionNo != null">transaction_no =
#{transactionNo},
</if>
<if test="refundReason != null">refund_reason =
#{refundReason},
</if>
<if test="refundType != null">refund_type =
#{refundType},
</if>
<if test="wechatRefundStatus != null">wechat_refund_status =
#{wechatRefundStatus},
</if>
<if test="alipayRefundStatus != null">alipay_refund_status =
#{alipayRefundStatus},
</if>
<if test="orderTotalPrice != null">order_total_price =
#{orderTotalPrice},
</if>
<if test="refundPrice != null">refund_price =
#{refundPrice},
</if>
<if test="currency != null">currency =
#{currency},
</if>
<if test="channel != null">channel =
#{channel},
</if>
<if test="userreceivedaccount != null">userReceivedAccount =
#{userreceivedaccount},
</if>
<if test="successTime != null">success_time =
#{successTime},
</if>
<if test="refundNotifyContent != null">refund_notify_content =
#{refundNotifyContent},
</if>
<if test="applyRefundReturnContent != null">apply_refund_return_content =
#{applyRefundReturnContent},
</if>
<if test="refundMerchantType != null">refund_merchant_type =
#{refundMerchantType},
</if>
<if test="delFlag != null">del_flag =
#{delFlag},
</if>
<if test="createBy != null">create_by =
#{createBy},
</if>
<if test="createTime != null">create_time =
#{createTime},
</if>
<if test="updateBy != null">update_by =
#{updateBy},
</if>
<if test="updateTime != null">update_time =
#{updateTime},
</if>
</trim>
where id = #{id}
</update>
<delete id="deleteRefundInfoById" parameterType="Long">
delete
from refund_info
where id = #{id}
</delete>
<delete id="deleteRefundInfoByIds" parameterType="String">
delete from refund_info where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
<update id="updateRefundInfoByNo" parameterType="refundInfo">
update refund_info
set wechat_refund_status = #{wechatRefundStatus},
success_time = #{successTime},
refund_notify_content = #{refundNotifyContent},
update_time = now()
where order_no = #{orderNo}
and out_refund_no = #{outRefundNo}
and wechat_refund_status &lt;&gt; #{wechatRefundStatus}
</update>
<update id="updateBatchRefundStatus">
UPDATE refund_info
SET wechat_refund_status = #{weChatRefundStatus},
success_time = #{successTime},
update_time = now()
WHERE del_flag = 0
and order_no = #{orderNo}
and wechat_refund_status &lt;&gt; #{weChatRefundStatus}
</update>
<select id="getRefundInfoByOrderNo" parameterType="string" resultType="int">
select count(1) refundCount
from refund_info
where order_no = #{orderNo}
</select>
</mapper>

View File

@ -35,6 +35,15 @@
<artifactId>xinelu-common</artifactId>
</dependency>
<dependency>
<groupId>com.xinelu</groupId>
<artifactId>xinelu-nurse-manage</artifactId>
</dependency>
<dependency>
<groupId>com.xinelu</groupId>
<artifactId>xinelu-nurse-applet</artifactId>
</dependency>
</dependencies>
</project>
</project>

View File

@ -0,0 +1,30 @@
package com.xinelu.quartz.controller;
import com.xinelu.quartz.task.CouponTask;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @Description 优惠券定时任务控制器
* @Author 纪寒
* @Date 2023-02-28 15:04:38
* @Version 1.0
*/
@RestController
@RequestMapping("/monitor/couponTask")
public class CouponTaskController {
@Resource
private CouponTask couponTask;
/**
* 手动执行更新会员领取已过期的优惠券状态定时任务
*/
@GetMapping("/patientCouponStatus")
public void patientCouponStatus() {
couponTask.patientCouponReceiveStatusTask();
}
}

View File

@ -0,0 +1,42 @@
package com.xinelu.quartz.controller;
import com.xinelu.quartz.task.PaymentInfoTask;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @Description 手动处理支付定时任务控制器
* @Author 纪寒
* @Date 2022-10-21 15:11:38
* @Version 1.0
*/
@RestController
@RequestMapping("/monitor/payTask")
public class PaymentInfoTaskController {
@Resource
private PaymentInfoTask paymentInfoTask;
/**
* 手动执行关闭订单定时任务
*
* @throws Exception 异常信息
*/
@GetMapping("/handCloseOrder")
public void handCloseOrder() throws Exception {
paymentInfoTask.automaticOrderTask();
}
/**
* 手动执行更新订单状态定时任务
*
* @throws Exception 异常信息
*/
@GetMapping("/handOrderStatus")
public void handOrderStatus() throws Exception {
paymentInfoTask.automaticUpdateOrderStatusTask();
}
}

View File

@ -0,0 +1,32 @@
package com.xinelu.quartz.controller;
import com.xinelu.quartz.task.RefundInfoTask;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @Description 手动处理退款定时任务控制器
* @Author 纪寒
* @Date 2022-10-25 14:39:10
* @Version 1.0
*/
@RestController
@RequestMapping("/monitor/refundTask")
public class RefundInfoTaskController {
@Resource
private RefundInfoTask refundInfoTask;
/**
* 手动执行修改退款单状态定时任务
*
* @throws Exception 异常信息
*/
@GetMapping("/handleRefundStatus")
public void handleRefundStatus() throws Exception {
refundInfoTask.automaticProcessRefundInfo();
}
}

View File

@ -0,0 +1,15 @@
package com.xinelu.quartz.service;
/**
* @Description 优惠券定时任务业务层
* @Author 纪寒
* @Date 2023-02-28 14:58:30
* @Version 1.0
*/
public interface CouponTaskService {
/**
* 自动修改会员领取已过期的优惠券状态第二天凌晨12点半执行一次
*/
void patientCouponReceiveStatusTask();
}

View File

@ -0,0 +1,24 @@
package com.xinelu.quartz.service;
/**
* @Description 支付定时任务业务层
* @Author 纪寒
* @Date 2022-10-21 15:03:05
* @Version 1.0
*/
public interface PaymentInfoTaskService {
/**
* 自动关闭商品订单24小时与预约订单2小时未支付的订单信息每10分钟执行一次
*
* @throws Exception 异常信息
*/
void automaticOrderTask() throws Exception;
/**
* 自动修改未支付的订单状态每10分钟执行一次
*
* @throws Exception 异常信息
*/
void automaticUpdateOrderStatusTask() throws Exception;
}

View File

@ -0,0 +1,18 @@
package com.xinelu.quartz.service;
/**
* @Description 微信退款定时任务业务层
* @Author 纪寒
* @Date 2022-10-25 14:32:12
* @Version 1.0
*/
public interface RefundInfoTaskService {
/**
* 自动处理退款状态定时任务
* 防止由于网络等其它原因未接受到退款回调通知进而导致的退款单状态修改不及时
*
* @throws Exception 异常信息
*/
void automaticProcessRefundInfo() throws Exception;
}

View File

@ -0,0 +1,64 @@
package com.xinelu.quartz.service.impl;
import com.xinelu.common.enums.CouponUseStatusEnum;
import com.xinelu.common.exception.ServiceException;
import com.xinelu.manage.domain.patientcouponreceive.PatientCouponReceive;
import com.xinelu.manage.mapper.patientcouponreceive.PatientCouponReceiveMapper;
import com.xinelu.quartz.service.CouponTaskService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* @Description
* @Author 纪寒
* @Date 2023-02-28 14:59:01
* @Version 1.0
*/
@Service
@Slf4j
public class CouponTaskServiceImpl implements CouponTaskService {
@Resource(name = "transactionManager")
private DataSourceTransactionManager transactionManager;
@Resource
private PatientCouponReceiveMapper patientCouponReceiveMapper;
/**
* 自动修改会员领取已过期的优惠券状态第二天凌晨12点半执行一次
*/
@Override
public void patientCouponReceiveStatusTask() {
log.info("开始执行修改会员领取已过期的优惠券状态定时任务......");
LocalDateTime timePrevious = LocalDateTime.now();
List<PatientCouponReceive> patientCouponReceiveList = patientCouponReceiveMapper.getPatientCouponExpirationEndTime(timePrevious, CouponUseStatusEnum.EXPIRED.getInfo());
if (CollectionUtils.isEmpty(patientCouponReceiveList)) {
return;
}
TransactionStatus transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition());
try {
List<Long> idList = patientCouponReceiveList.stream().filter(item -> Objects.nonNull(item.getId())).map(PatientCouponReceive::getId).collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(idList)) {
int insertCount = patientCouponReceiveMapper.updateCouponReceiveStatus(CouponUseStatusEnum.EXPIRED.getInfo(), idList);
if (insertCount <= 0) {
throw new ServiceException("更新修改券状态失败!");
}
}
transactionManager.commit(transactionStatus);
log.info("完成修改会员领取已过期的优惠券状态定时任务......");
} catch (Exception e) {
log.error("修改会员领取已过期的优惠券状态定时任务失败,失败原因为 =====> {}", e.getMessage());
transactionManager.rollback(transactionStatus);
throw e;
}
}
}

View File

@ -0,0 +1,386 @@
package com.xinelu.quartz.service.impl;
import com.alibaba.fastjson2.JSON;
import com.xinelu.applet.service.goodstock.GoodsStockService;
import com.xinelu.applet.service.wechatpaymentinfo.WeChatPaymentService;
import com.xinelu.applet.vo.wechatpaymentinfo.vo.OrderStatusInfoVO;
import com.xinelu.applet.vo.wechatpaymentinfo.vo.WeChatQueryOrderVO;
import com.xinelu.common.config.XylWeChatPaymentConfig;
import com.xinelu.common.config.YlypWeChatPaymentConfig;
import com.xinelu.common.constant.Constants;
import com.xinelu.common.enums.*;
import com.xinelu.manage.domain.appointmentorder.AppointmentOrder;
import com.xinelu.manage.domain.goodsOrder.GoodsOrder;
import com.xinelu.manage.domain.paymentinfo.PaymentInfo;
import com.xinelu.manage.mapper.appointmentorder.AppointmentOrderMapper;
import com.xinelu.manage.mapper.goodsOrder.GoodsOrderMapper;
import com.xinelu.manage.mapper.patientcouponreceive.PatientCouponReceiveMapper;
import com.xinelu.manage.mapper.paymentinfo.PaymentInfoMapper;
import com.xinelu.manage.vo.AppointOrderAndDetailsInfo;
import com.xinelu.manage.vo.goods.GoodsOrderAndDetailsInfo;
import com.xinelu.quartz.service.PaymentInfoTaskService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import javax.annotation.Resource;
import javax.sql.rowset.serial.SerialException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* @Description 支付定时任务实现类
* @Author 纪寒
* @Date 2022-10-21 15:03:41
* @Version 1.0
*/
@Slf4j
@Service
public class PaymentInfoTaskServiceImpl implements PaymentInfoTaskService {
@Resource
private AppointmentOrderMapper appointmentOrderMapper;
@Resource
private GoodsOrderMapper goodsOrderMapper;
@Resource
private WeChatPaymentService weChatPaymentService;
@Resource
private PaymentInfoMapper paymentInfoMapper;
@Resource
private XylWeChatPaymentConfig xylWeChatPaymentConfig;
@Resource
private YlypWeChatPaymentConfig ylypWeChatPaymentConfig;
@Resource(name = "transactionManager")
private DataSourceTransactionManager transactionManager;
@Resource
private GoodsStockService goodsStockService;
@Resource
private RedisTemplate<String, Objects> redisTemplate;
@Resource
private PatientCouponReceiveMapper patientCouponReceiveMapper;
/**
* 成功状态码
*/
private static final int SUCCESS_CODE = 200;
/**
* 成功状态码
*/
private static final int SUCCESS_CODE_TWO = 204;
/**
* 自动关闭商品订单2小时与预约订单2小时未支付的订单信息每10分钟执行一次
*
* @throws Exception 异常信息
*/
@Override
public void automaticOrderTask() throws Exception {
LocalDateTime localDateTime = LocalDateTime.now().minusHours(2);
List<AppointOrderAndDetailsInfo> appointmentOrderList = appointmentOrderMapper.getWaitPayAppointmentOrderList(localDateTime);
List<GoodsOrderAndDetailsInfo> goodsOrderList = goodsOrderMapper.getWaitPayGoodsOrderList(localDateTime);
if (CollectionUtils.isEmpty(appointmentOrderList) && CollectionUtils.isEmpty(goodsOrderList)) {
return;
}
TransactionStatus transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition());
List<AppointOrderAndDetailsInfo> successAppointOrderList = Lists.newArrayList();
try {
if (CollectionUtils.isNotEmpty(appointmentOrderList)) {
successAppointOrderList = processAppointmentOrderInfo(appointmentOrderList);
}
if (CollectionUtils.isNotEmpty(goodsOrderList)) {
processGoodsOrderInfo(goodsOrderList);
}
transactionManager.commit(transactionStatus);
} catch (Exception e) {
transactionManager.rollback(transactionStatus);
log.error("自动关闭订单失败,失败原因为 =====> {}", e.getMessage());
if (CollectionUtils.isNotEmpty(successAppointOrderList)) {
for (AppointOrderAndDetailsInfo orderAndDetailsInfo : successAppointOrderList) {
String appointLimitCountKey = Constants.PRE_APPOINTMENT_LIMIT_COUNT_KEY + orderAndDetailsInfo.getNurseStationItemId() + "_" + orderAndDetailsInfo.getServiceDate() + "_" + orderAndDetailsInfo.getServiceStartTime();
RedisAtomicLong redisAtomicLong = new RedisAtomicLong(appointLimitCountKey, Objects.requireNonNull(redisTemplate.getConnectionFactory()));
if (redisAtomicLong.get() > 0) {
redisAtomicLong.decrementAndGet();
}
}
}
throw e;
}
}
/**
* 自动修改未支付的订单状态每15分钟执行一次
*
* @throws Exception 异常信息
*/
@Override
public void automaticUpdateOrderStatusTask() throws Exception {
List<AppointmentOrder> appointmentOrderList = appointmentOrderMapper.getWaitPayStatusAppointmentOrderList(OrderStatusEnum.WAIT_PAY.getInfo());
List<GoodsOrder> goodsOrderList = goodsOrderMapper.getWaitPayStatusGoodsOrderList(GooodsOrderStatusEnum.WAIT_PAY.getInfo());
if (CollectionUtils.isEmpty(appointmentOrderList) && CollectionUtils.isEmpty(goodsOrderList)) {
return;
}
TransactionStatus transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition());
try {
if (CollectionUtils.isNotEmpty(appointmentOrderList)) {
updateAppointmentPaymentInfo(appointmentOrderList);
}
if (CollectionUtils.isNotEmpty(goodsOrderList)) {
updateGoodsPaymentInfo(goodsOrderList);
}
transactionManager.commit(transactionStatus);
} catch (Exception e) {
log.error("修改订单状态定时任务失败,失败原因为 =====> {}", e.getMessage());
transactionManager.rollback(transactionStatus);
throw e;
}
}
/**
* 处理预约订单状态
*
* @param appointmentOrderList 预约订单列表
* @return List<AppointOrderAndDetailsInfo> 处理成功的预约订单信息
* @throws Exception 异常信息
*/
private List<AppointOrderAndDetailsInfo> processAppointmentOrderInfo(List<AppointOrderAndDetailsInfo> appointmentOrderList) throws Exception {
List<AppointOrderAndDetailsInfo> successList = Lists.newArrayList();
List<String> closedOrderList = Lists.newArrayList();
for (AppointOrderAndDetailsInfo orderAndDetailsInfo : appointmentOrderList) {
if (StringUtils.isBlank(orderAndDetailsInfo.getOrderNo())) {
continue;
}
OrderStatusInfoVO vo = new OrderStatusInfoVO();
OrderStatusInfoVO statusInfoVO = weChatPaymentService.queryAppointmentOrderStatus(orderAndDetailsInfo.getOrderNo(), vo);
if (BooleanUtils.isFalse(statusInfoVO.getPayFlag())) {
closedOrderList.add(orderAndDetailsInfo.getOrderNo());
continue;
}
int statusCode = weChatPaymentService.closeWeChatOrderInfo(orderAndDetailsInfo.getOrderNo(), BuySourceEnum.NURSE_STATION.getInfo());
if (statusCode == SUCCESS_CODE || statusCode == SUCCESS_CODE_TWO) {
updateAppointmentOrderStatus(orderAndDetailsInfo, successList);
}
}
if (CollectionUtils.isNotEmpty(closedOrderList)) {
List<AppointOrderAndDetailsInfo> waitPayAppointList = appointmentOrderMapper.getWaitPayAppointList(closedOrderList);
if (CollectionUtils.isNotEmpty(waitPayAppointList)) {
for (AppointOrderAndDetailsInfo orderAndDetailsInfo : waitPayAppointList) {
updateAppointmentOrderStatus(orderAndDetailsInfo, successList);
}
}
}
return successList;
}
/**
* 处理商品订单信息
*
* @param goodsOrderList 商品订单列表
* @throws Exception 异常信息
*/
private void processGoodsOrderInfo(List<GoodsOrderAndDetailsInfo> goodsOrderList) throws Exception {
List<String> orderList = Lists.newArrayList();
List<String> closedOrderList = Lists.newArrayList();
for (GoodsOrderAndDetailsInfo goodOrder : goodsOrderList) {
if (StringUtils.isBlank(goodOrder.getOrderNo())) {
continue;
}
OrderStatusInfoVO vo = new OrderStatusInfoVO();
OrderStatusInfoVO statusInfoVO = weChatPaymentService.queryGoodsOrderStatus(goodOrder.getOrderNo(), vo, goodOrder.getBuySource());
if (BooleanUtils.isFalse(statusInfoVO.getPayFlag())) {
closedOrderList.add(goodOrder.getOrderNo());
continue;
}
int statusCode = weChatPaymentService.closeWeChatOrderInfo(goodOrder.getOrderNo(), goodOrder.getBuySource());
if (statusCode == SUCCESS_CODE || statusCode == SUCCESS_CODE_TWO) {
orderList.add(goodOrder.getOrderNo());
}
if (StringUtils.isNotBlank(goodOrder.getOrderType()) && !OrderTypeEnum.HEALTH_CONSULTATION.getInfo().equals(goodOrder.getOrderType())) {
goodsStockService.addGoodsStockInfo(goodOrder.getOrderNo(), goodOrder.getGoodsAttributeDetailsId(), Objects.isNull(goodOrder.getGoodsCount()) ? 0 : goodOrder.getGoodsCount());
if (Objects.nonNull(goodOrder.getCouponId()) && Objects.nonNull(goodOrder.getPatientId())) {
patientCouponReceiveMapper.updatePatientCouponUseStatus(goodOrder.getPatientId(), goodOrder.getCouponId(), CouponUseStatusEnum.NOT_USED.getInfo());
}
}
}
if (CollectionUtils.isNotEmpty(orderList)) {
log.info("自动修改商品订单信息状态 ======> [{}]", orderList);
goodsOrderMapper.updateBatchGoodsOrderStatus(orderList, GooodsOrderStatusEnum.CANCEL.getInfo());
}
if (CollectionUtils.isNotEmpty(closedOrderList)) {
//说明当前订单在微信系统中已经关闭需要重新确认本地订单状态是否同步更新未更新则需要同步更新并且新增库存数量
List<GoodsOrderAndDetailsInfo> goodsOrderInfoList = goodsOrderMapper.getWaitPayGoodsOrderCountList(closedOrderList);
if (CollectionUtils.isNotEmpty(goodsOrderInfoList)) {
//新增库存数量和修改优惠券状态健康咨询类型的订单无需新增库存数量和退还优惠券
for (GoodsOrderAndDetailsInfo detailsInfo : goodsOrderInfoList) {
if (StringUtils.isNotBlank(detailsInfo.getOrderType()) && OrderTypeEnum.HEALTH_CONSULTATION.getInfo().equals(detailsInfo.getOrderType())) {
continue;
}
goodsStockService.addGoodsStockInfo(detailsInfo.getOrderNo(), detailsInfo.getGoodsAttributeDetailsId(), Objects.isNull(detailsInfo.getGoodsCount()) ? 0 : detailsInfo.getGoodsCount());
if (Objects.nonNull(detailsInfo.getCouponId()) && Objects.nonNull(detailsInfo.getPatientId())) {
patientCouponReceiveMapper.updatePatientCouponUseStatus(detailsInfo.getPatientId(), detailsInfo.getCouponId(), CouponUseStatusEnum.NOT_USED.getInfo());
}
}
//批量更新本地订单状态将订单状态修改为已取消
List<String> orderNos = goodsOrderInfoList.stream().filter(item -> StringUtils.isNotBlank(item.getOrderNo())).map(GoodsOrderAndDetailsInfo::getOrderNo).distinct().collect(Collectors.toList());
goodsOrderMapper.updateBatchGoodsOrderStatus(orderNos, GooodsOrderStatusEnum.CANCEL.getInfo());
}
}
}
/**
* 新增预约订单支付信息
*
* @param appointmentOrderList 预约订单列表
* @throws Exception 异常信息
*/
private void updateAppointmentPaymentInfo(List<AppointmentOrder> appointmentOrderList) throws Exception {
for (AppointmentOrder appointmentOrder : appointmentOrderList) {
if (StringUtils.isBlank(appointmentOrder.getOrderNo())) {
continue;
}
OrderStatusInfoVO vo = new OrderStatusInfoVO();
OrderStatusInfoVO statusInfoVO = weChatPaymentService.queryAppointmentOrderStatus(appointmentOrder.getOrderNo(), vo);
if (StringUtils.isNotBlank(statusInfoVO.getTradeStatus())
&& WeChatTradeStateEnum.SUCCESS.getInfo().equals(statusInfoVO.getTradeStatus())) {
insertAppointmentOrderPaymentInfo(appointmentOrder, statusInfoVO);
}
}
}
/**
* 新增商品订单支付信息
*
* @param goodsOrderList 商品订单列表
* @throws Exception 异常信息
*/
private void updateGoodsPaymentInfo(List<GoodsOrder> goodsOrderList) throws Exception {
for (GoodsOrder goodsOrder : goodsOrderList) {
if (Objects.isNull(goodsOrder) || StringUtils.isBlank(goodsOrder.getOrderNo())) {
continue;
}
OrderStatusInfoVO vo = new OrderStatusInfoVO();
OrderStatusInfoVO statusInfoVO = weChatPaymentService.queryGoodsOrderStatus(goodsOrder.getOrderNo(), vo, goodsOrder.getBuySource());
if (StringUtils.isNotBlank(statusInfoVO.getTradeStatus())
&& WeChatTradeStateEnum.SUCCESS.getInfo().equals(statusInfoVO.getTradeStatus())) {
insertGoodsOrderPaymentInfo(goodsOrder, statusInfoVO);
}
}
}
/**
* 修改预约订单状态和记录预约订单信息
*
* @param appointmentOrder 预约订单信息
* @param vo 微信查单信息
* @throws Exception 异常信息
*/
private void insertAppointmentOrderPaymentInfo(AppointmentOrder appointmentOrder, OrderStatusInfoVO vo) throws Exception {
appointmentOrderMapper.updateAppointmentOrderStatus(OrderStatusEnum.WAIT_DISPATCH.getInfo(), appointmentOrder.getOrderNo());
int paymentInfoCount = paymentInfoMapper.getPaymentInfoByOrderNo(appointmentOrder.getOrderNo());
if (paymentInfoCount <= 0) {
WeChatQueryOrderVO weChatQueryOrderVO = vo.getWeChatQueryOrderVO();
PaymentInfo paymentInfo = buildPaymentInfo(weChatQueryOrderVO, null, appointmentOrder);
int insertCount = paymentInfoMapper.insertPaymentInfo(paymentInfo);
if (insertCount <= 0) {
log.error("记录预约订单支付日志出错,参数为 ====> [{}]", paymentInfo);
throw new SerialException("记录预约订单支付日志出错,请联系管理员!");
}
}
}
/**
* 修改商品订单状态和记录商品订单支付日志信息
*
* @param goodsOrder 商品订单信息
* @param vo 微信查单信息
* @throws Exception 异常信息
*/
private void insertGoodsOrderPaymentInfo(GoodsOrder goodsOrder, OrderStatusInfoVO vo) throws Exception {
int paymentInfoCount = 0;
if (Objects.nonNull(goodsOrder)) {
goodsOrderMapper.updateGoodsOrderStatus(GooodsOrderStatusEnum.WAIT_RECEIVED_GOODS.getInfo(), goodsOrder.getOrderNo());
paymentInfoCount = paymentInfoMapper.getPaymentInfoByOrderNo(goodsOrder.getOrderNo());
}
if (paymentInfoCount <= 0) {
WeChatQueryOrderVO weChatQueryOrderVO = vo.getWeChatQueryOrderVO();
PaymentInfo paymentInfo = buildPaymentInfo(weChatQueryOrderVO, goodsOrder, null);
int insertCount = paymentInfoMapper.insertPaymentInfo(paymentInfo);
if (insertCount <= 0) {
log.error("记录商品或者学习培训支付订单支付日志出错,参数为 ====> [{}]", paymentInfo);
throw new SerialException("记录商品或者学习培训支付订单支付日志出错,请联系管理员!");
}
}
}
/**
* 构建支付信息参数
*
* @param weChatQueryOrderVO 微信查单返回结果信息
* @param goodsOrderInfo 商品订单信息
* @param appointmentOrderInfo 预约订单信息
*/
public PaymentInfo buildPaymentInfo(WeChatQueryOrderVO weChatQueryOrderVO, GoodsOrder goodsOrderInfo,
AppointmentOrder appointmentOrderInfo) {
PaymentInfo paymentInfo = new PaymentInfo();
if (Objects.nonNull(goodsOrderInfo)) {
paymentInfo.setPatientId(Objects.isNull(goodsOrderInfo.getPatientId()) ? null : goodsOrderInfo.getPatientId());
paymentInfo.setOrderNo(StringUtils.isBlank(goodsOrderInfo.getOrderNo()) ? "" : goodsOrderInfo.getOrderNo());
paymentInfo.setPayChannel(StringUtils.isBlank(goodsOrderInfo.getOrderChannel()) ? "" : goodsOrderInfo.getOrderChannel());
} else if (Objects.nonNull(appointmentOrderInfo)) {
paymentInfo.setPatientId(Objects.isNull(appointmentOrderInfo.getPatientId()) ? null : appointmentOrderInfo.getPatientId());
paymentInfo.setOrderNo(StringUtils.isBlank(appointmentOrderInfo.getOrderNo()) ? "" : appointmentOrderInfo.getOrderNo());
paymentInfo.setPayChannel(StringUtils.isBlank(appointmentOrderInfo.getOrderChannel()) ? "" : appointmentOrderInfo.getOrderChannel());
}
paymentInfo.setTransactionNo(StringUtils.isBlank(weChatQueryOrderVO.getTransactionId()) ? "" : weChatQueryOrderVO.getTransactionId());
paymentInfo.setPayPrice(BigDecimal.valueOf(Objects.isNull(weChatQueryOrderVO.getAmount().getPayerTotal()) ? 0 : weChatQueryOrderVO.getAmount().getPayerTotal()).divide(BigDecimal.valueOf(100), 2, BigDecimal.ROUND_DOWN));
paymentInfo.setPayType(PayTypeEnum.WECHAT_PAY.getInfo());
paymentInfo.setWechatTradeState(StringUtils.isBlank(weChatQueryOrderVO.getTradeState()) ? "" : weChatQueryOrderVO.getTradeState());
paymentInfo.setPayNotifyContent(JSON.toJSON(weChatQueryOrderVO).toString());
paymentInfo.setPayTime(LocalDateTime.parse(StringUtils.isBlank(weChatQueryOrderVO.getSuccessTime()) ? "" : weChatQueryOrderVO.getSuccessTime(), DateTimeFormatter.ISO_DATE_TIME));
if (weChatQueryOrderVO.getMchid().equals(xylWeChatPaymentConfig.getXylMchId())) {
paymentInfo.setPaymentMerchantType(PaymentMerchantTypeEnum.XINYILU.getInfo());
}
if (weChatQueryOrderVO.getMchid().equals(ylypWeChatPaymentConfig.getYlypMchId())) {
paymentInfo.setPaymentMerchantType(PaymentMerchantTypeEnum.YILUYOUPIN.getInfo());
}
paymentInfo.setDelFlag(0);
paymentInfo.setCreateTime(LocalDateTime.now());
return paymentInfo;
}
/**
* 修改预约订单状态和修改预约次数上限
*
* @param orderAndDetailsInfo 输入参数
* @param successList 处理成功的订单集合
*/
private void updateAppointmentOrderStatus(AppointOrderAndDetailsInfo orderAndDetailsInfo, List<AppointOrderAndDetailsInfo> successList) {
//关闭系统内部预约订单
List<String> orderList = Collections.singletonList(orderAndDetailsInfo.getOrderNo());
appointmentOrderMapper.updateBatchAppointmentOrderStatus(orderList, OrderStatusEnum.CANCEL.getInfo());
//新增Redis中的预约次数
if (Objects.nonNull(orderAndDetailsInfo.getAppointmentLimitCount()) && StringUtils.equals(AppointmentOrderTypeEnum.OTHER.getInfo(), orderAndDetailsInfo.getOrderType())) {
String appointLimitCountKey = Constants.PRE_APPOINTMENT_LIMIT_COUNT_KEY + orderAndDetailsInfo.getNurseStationItemId() + "_" + orderAndDetailsInfo.getServiceDate() + "_" + orderAndDetailsInfo.getServiceStartTime();
RedisAtomicLong redisAtomicLong = new RedisAtomicLong(appointLimitCountKey, Objects.requireNonNull(redisTemplate.getConnectionFactory()));
if (redisAtomicLong.get() >= 0 && redisAtomicLong.get() < orderAndDetailsInfo.getAppointmentLimitCount()) {
//预约次数加一
redisAtomicLong.incrementAndGet();
successList.add(orderAndDetailsInfo);
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More