当前位置:网站首页>17 medical registration system_ [wechat Payment]
17 medical registration system_ [wechat Payment]
2022-07-06 09:56:00 【Learn from Tao Ge】
One 、 Introduction to wechat payment
1 Wechat code scanning payment application
Wechat code scanning payment refers to the payment QR code generated by the merchant system according to the wechat payment agreement , Wechat for users “ scan ” Mode of payment completion . This mode is applicable to PC Website Payment 、 Unit or order payment in physical stores 、 Media advertising payment and other scenarios .
Application steps :( understand )
First step : Official account number ( Type must be : Service number )
Please select the following subject registration according to the type of business license : Individual businesses | Enterprises / company | The government | The media | Other types .
The second step : Official account number
Only after the official account is certified can WeChat apply for payment , Certification fee :300 element / year .
The third step : Submit information and apply for wechat payment
Log on to the public platform , Click on the menu on the left 【 Wechat payment 】, Start filling in the information and wait for the review , The audit time is 1-5 Within 5 working days .
Step four : Account opened successfully , Log in to the merchant platform for verification
After the data is approved , Please login the contact email to check the merchant number and password , And log in to the merchant platform to fill in the amount of small amount of TenPay reserve , Complete account verification .
Step five : Sign the agreement online
This agreement is an online electronic agreement , The transaction and capital settlement can only be carried out after signing , It will take effect immediately after signing .
2 Developing documents
The overall idea of wechat payment interface call :
Press API Required assembly parameters , With XML Mode sending (POST) To wechat payment interface (URL), Wechat payment interface is also based on XML The way to respond . Based on the returned results ( Including payment URL) Generate QR code or judge order status .
Online wechat payment development document :
https://pay.weixin.qq.com/wiki/doc/api/index.html
- appid: Wechat public account or open platform APP Unique identification of
- mch_id: Merchant number ( In the configuration file partner)
- partnerkey: Merchant key
- sign: digital signature , An encrypted message generated according to the key officially provided by wechat and a set of algorithms , Just to ensure the security of the transaction
3 Wechat payment SDK
Add dependency
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
We mainly use wechat payment SDK The following functions of :
(1) Get random string
WXPayUtil.generateNonceStr()
(2) MAP Convert to XML character string ( Automatically add signatures )
WXPayUtil.generateSignedXml(param, partnerkey)
(3) XML String conversion to MAP
WXPayUtil.xmlToMap(result)
Wechat payment development
1、api Interface
scene : Users scan the QR code displayed by merchants in various scenarios for payment
Use cases :
Offline : Carrefour supermarket 、7-11 The convenience store 、 Top grade discount, offline stores, etc
on-line : Public comment website 、 CTRIP Website 、 Vipshop 、 Meilishuo website, etc
Development mode :
Model a : The merchant generates a QR code for you in the background , The user opens and scans
Model 2 : Merchant background system calls wechat payment 【 Unified order API】 Generate prepaid transaction , Generate the QR code from the link returned by the interface , After scanning the code, the user enters the password to complete the payment transaction . Be careful :** The validity period of prepayment order in this mode is 2 Hours ,** Cannot pay after expiration .
Wechat payment : Generate xml Send a request
Operation module :service-order
Introduce dependencies
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
1.2 Add the configuration
stay application.properties Add merchant information
spring.redis.host=192.168.44.165
spring.redis.port=6379
spring.redis.database= 0
spring.redis.timeout=1800000
spring.redis.lettuce.pool.max-active=20
spring.redis.lettuce.pool.max-wait=-1
# Maximum blocking waiting time ( A negative number means no limit )
spring.redis.lettuce.pool.max-idle=5
spring.redis.lettuce.pool.min-idle=0
# Associated official account appid
weixin.pay.appid=wx74862e0dfcf69954
# Merchant number
weixin.pay.partner=1558950191
# Merchant key
weixin.pay.partnerkey=T6m9iK73b0kn9g5v426MKfHQH7X8rKwb
1.3 Introduce tool classes
@Component
public class ConstantPropertiesUtils implements InitializingBean {
@Value("${weixin.appid}")
private String appid;
@Value("${weixin.partner}")
private String partner;
@Value("${weixin.partnerkey}")
private String partnerkey;
public static String APPID;
public static String PARTNER;
public static String PARTNERKEY;
@Override
public void afterPropertiesSet() throws Exception {
APPID = appid;
PARTNER = partner;
PARTNERKEY = partnerkey;
}
}
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.text.ParseException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/** * http Requesting client */
public class HttpClient {
private String url;
private Map<String, String> param;
private int statusCode;
private String content;
private String xmlParam;
private boolean isHttps;
private boolean isCert = false;
// Certificate password Wechat merchant No (mch_id)
private String certPassword;
public boolean isHttps() {
return isHttps;
}
public void setHttps(boolean isHttps) {
this.isHttps = isHttps;
}
public boolean isCert() {
return isCert;
}
public void setCert(boolean cert) {
isCert = cert;
}
public String getXmlParam() {
return xmlParam;
}
public void setXmlParam(String xmlParam) {
this.xmlParam = xmlParam;
}
public HttpClient(String url, Map<String, String> param) {
this.url = url;
this.param = param;
}
public HttpClient(String url) {
this.url = url;
}
public String getCertPassword() {
return certPassword;
}
public void setCertPassword(String certPassword) {
this.certPassword = certPassword;
}
public void setParameter(Map<String, String> map) {
param = map;
}
public void addParameter(String key, String value) {
if (param == null)
param = new HashMap<String, String>();
param.put(key, value);
}
public void post() throws ClientProtocolException, IOException {
HttpPost http = new HttpPost(url);
setEntity(http);
execute(http);
}
public void put() throws ClientProtocolException, IOException {
HttpPut http = new HttpPut(url);
setEntity(http);
execute(http);
}
public void get() throws ClientProtocolException, IOException {
if (param != null) {
StringBuilder url = new StringBuilder(this.url);
boolean isFirst = true;
for (String key : param.keySet()) {
if (isFirst)
url.append("?");
else
url.append("&");
url.append(key).append("=").append(param.get(key));
}
this.url = url.toString();
}
HttpGet http = new HttpGet(url);
execute(http);
}
/** * set http post,put param */
private void setEntity(HttpEntityEnclosingRequestBase http) {
if (param != null) {
List<NameValuePair> nvps = new LinkedList<NameValuePair>();
for (String key : param.keySet())
nvps.add(new BasicNameValuePair(key, param.get(key))); // Parameters
http.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); // Set parameters
}
if (xmlParam != null) {
http.setEntity(new StringEntity(xmlParam, Consts.UTF_8));
}
}
private void execute(HttpUriRequest http) throws ClientProtocolException,
IOException {
CloseableHttpClient httpClient = null;
try {
if (isHttps) {
if(isCert) {
FileInputStream inputStream = new FileInputStream(new File(ConstantPropertiesUtils.CERT));
KeyStore keystore = KeyStore.getInstance("PKCS12");
char[] partnerId2charArray = certPassword.toCharArray();
keystore.load(inputStream, partnerId2charArray);
SSLContext sslContext = SSLContexts.custom().loadKeyMaterial(keystore, partnerId2charArray).build();
SSLConnectionSocketFactory sslsf =
new SSLConnectionSocketFactory(sslContext,
new String[] {
"TLSv1" },
null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
} else {
SSLContext sslContext = new SSLContextBuilder()
.loadTrustMaterial(null, new TrustStrategy() {
// Trust all
public boolean isTrusted(X509Certificate[] chain,
String authType)
throws CertificateException {
return true;
}
}).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslContext);
httpClient = HttpClients.custom().setSSLSocketFactory(sslsf)
.build();
}
} else {
httpClient = HttpClients.createDefault();
}
CloseableHttpResponse response = httpClient.execute(http);
try {
if (response != null) {
if (response.getStatusLine() != null)
statusCode = response.getStatusLine().getStatusCode();
HttpEntity entity = response.getEntity();
// Response content
content = EntityUtils.toString(entity, Consts.UTF_8);
}
} finally {
response.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
httpClient.close();
}
}
public int getStatusCode() {
return statusCode;
}
public String getContent() throws ParseException, IOException {
return content;
}
}
1.4 Add transaction interface
1.4.1 add to Mapper
public interface PaymentInfoMapper extends BaseMapper<PaymentInfo> {
}
1.4.2 add to service Interface and implementation
1、 add to PaymentService class
public interface PaymentService extends IService<PaymentInfo> {
/** * Save transactions * @param order * @param paymentType Payment type (1: WeChat 2: Alipay ) */
void savePaymentInfo(OrderInfo order, Integer paymentType);
}
2、 add to PaymentServiceImpl Implementation class
@Service
public class PaymentServiceImpl extends
ServiceImpl<PaymentInfoMapper, PaymentInfo> implements PaymentService {
/** * Save transactions * @param orderInfo * @param paymentType Payment type (1: WeChat 2: Alipay ) */
@Override
public void savePaymentInfo(OrderInfo orderInfo, Integer paymentType) {
QueryWrapper<PaymentInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("order_id", orderInfo.getId());
queryWrapper.eq("payment_type", paymentType);
Integer count = baseMapper.selectCount(queryWrapper);
if(count >0) return;
// Save transactions
PaymentInfo paymentInfo = new PaymentInfo();
paymentInfo.setCreateTime(new Date());
paymentInfo.setOrderId(orderInfo.getId());
paymentInfo.setPaymentType(paymentType);
paymentInfo.setOutTradeNo(orderInfo.getOutTradeNo());
paymentInfo.setPaymentStatus(PaymentStatusEnum.UNPAID.getStatus());
String subject = new DateTime(orderInfo.getReserveDate()).toString("yyyy-MM-dd")+"|"+orderInfo.getHosname()+"|"+orderInfo.getDepname()+"|"+orderInfo.getTitle();
paymentInfo.setSubject(subject);
paymentInfo.setTotalAmount(orderInfo.getAmount());
baseMapper.insert(paymentInfo);
}
}
1.5 Add payment service Interface and implementation
1、 add to com.atguigu.yygh.order.service.WeixinService class
public interface WeixinService {
/** * Place an order according to the order number , Generate payment link */
Map createNative(Long orderId);
}
2、 add to com.atguigu.yygh.order.service.impl.WeixinServiceImpl class
@Service
public class WeixinServiceImpl implements WeixinService {
@Autowired
private OrderService orderService;
@Autowired
private PaymentService paymentService;
@Autowired
private RedisTemplate redisTemplate;
/** * Place an order according to the order number , Generate payment link */
@Override
public Map createNative(Long orderId) {
try {
Map payMap = (Map) redisTemplate.opsForValue().get(orderId.toString());
if(null != payMap) return payMap;
// according to id Get order information
OrderInfo order = orderService.getById(orderId);
// Save transactions
paymentService.savePaymentInfo(order, PaymentTypeEnum.WEIXIN.getStatus());
//1、 Set parameters
Map paramMap = new HashMap();
paramMap.put("appid", ConstantPropertiesUtils.APPID);
paramMap.put("mch_id", ConstantPropertiesUtils.PARTNER);
paramMap.put("nonce_str", WXPayUtil.generateNonceStr());
String body = order.getReserveDate() + " See a doctor "+ order.getDepname();
paramMap.put("body", body);
paramMap.put("out_trade_no", order.getOutTradeNo());
//paramMap.put("total_fee", order.getAmount().multiply(new BigDecimal("100")).longValue()+"");
paramMap.put("total_fee", "1");
paramMap.put("spbill_create_ip", "127.0.0.1");
paramMap.put("notify_url", "http://guli.shop/api/order/weixinPay/weixinNotify");
paramMap.put("trade_type", "NATIVE");
//2、HTTPClient According to URL Access third-party interfaces and pass parameters
HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
//client Set parameters
client.setXmlParam(WXPayUtil.generateSignedXml(paramMap, ConstantPropertiesUtils.PARTNERKEY));
client.setHttps(true);
client.post();
//3、 Return third-party data
String xml = client.getContent();
Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);
//4、 Encapsulate the return result set
Map map = new HashMap<>();
map.put("orderId", orderId);
map.put("totalFee", order.getAmount());
map.put("resultCode", resultMap.get("result_code"));
map.put("codeUrl", resultMap.get("code_url"));
if(null != resultMap.get("result_code")) {
// Wechat payment QR code 2 Hours expired , We can take 2 Hour unpaid cancellation order
redisTemplate.opsForValue().set(orderId.toString(), map, 1000, TimeUnit.MINUTES);
}
return map;
} catch (Exception e) {
e.printStackTrace();
return new HashMap<>();
}
}
}
1.6 add to controller Method
@RestController
@RequestMapping("/api/order/weixin")
public class WeixinController {
@Autowired
private WeixinService weixinPayService;
/** * Place an order Generate qr code */
@GetMapping("/createNative/{orderId}")
public Result createNative(
@ApiParam(name = "orderId", value = " Order id", required = true)
@PathVariable("orderId") Long orderId) {
return Result.ok(weixinPayService.createNative(orderId));
}
}
front end
2.1 encapsulation api request
add to /api/order/weixin.js file
createNative(orderId) {
return request({
url: `/api/order/weixin/createNative/${
orderId}`,
method: 'get'
})
},
2.2 introduce vue-qriously Generate qr code
1、 install vue-qriously
npm install vue-qriously
2、 introduce
stay /plugins/myPlugin.js File add import
import VueQriously from 'vue-qriously'
Vue.use(VueQriously)
2.3 The page display
modify /pages/order/show.vue Components
<template>
<!-- header -->
<div class="nav-container page-component">
<!-- The left navigation #start -->
<div class="nav left-nav">
<div class="nav-item ">
<span class="v-link clickable dark" οnclick="javascript:window.location='/user'"> Real name authentication </span>
</div>
<div class="nav-item selected">
<span class="v-link selected dark" οnclick="javascript:window.location='/order'"> Registered order </span>
</div>
<div class="nav-item ">
<span class="v-link clickable dark" οnclick="javascript:window.location='/patient'"> Patient management </span>
</div>
<div class="nav-item ">
<span class="v-link clickable dark"> Modify account information </span>
</div>
<div class="nav-item ">
<span class="v-link clickable dark"> Feedback </span>
</div>
</div>
<!-- The left navigation #end -->
<!-- Right side content #start -->
<div class="page-container">
<div class="order-detail">
<div class="title"> Registration details </div>
<div class="status-bar">
<div class="left-wrapper">
<div class="status-wrapper BOOKING_SUCCESS">
<span class="iconfont"></span> {
{ orderInfo.param.orderStatusString }}
</div>
</div>
<div class="right-wrapper">
<img src="//img.114yygh.com/static/web/code_order_detail.png" class="code-img">
<div class="content-wrapper">
<div> WeChat <span class="iconfont"></span> Focus on “ Make an appointment for registration ”</div>
<div class="watch-wrapper"> Fast registration , Easy medical treatment </div>
</div>
</div>
</div>
<div class="info-wrapper">
<div class="title-wrapper">
<div class="block"></div>
<div> Registration information </div>
</div>
<div class="info-form">
<el-form ref="form" :model="form">
<el-form-item label=" Patient information :">
<div class="content"><span>{
{ orderInfo.patientName }}</span></div>
</el-form-item>
<el-form-item label=" Date of visit :">
<div class="content"><span>{
{ orderInfo.reserveDate }} {
{ orderInfo.reserveTime == 0 ? ' In the morning ' : ' Afternoon ' }}</span></div>
</el-form-item>
<el-form-item label=" See a hospital :">
<div class="content"><span>{
{ orderInfo.hosname }} </span></div>
</el-form-item>
<el-form-item label=" Department of medical treatment :">
<div class="content"><span>{
{ orderInfo.depname }} </span></div>
</el-form-item>
<el-form-item label=" Doctor title :">
<div class="content"><span>{
{ orderInfo.title }} </span></div>
</el-form-item>
<el-form-item label=" Medical service fee :">
<div class="content">
<div class="fee">{
{ orderInfo.amount }} element
</div>
</div>
</el-form-item>
<el-form-item label=" Registration number :">
<div class="content"><span>{
{ orderInfo.outTradeNo }} </span></div>
</el-form-item>
<el-form-item label=" Registration time :">
<div class="content"><span>{
{ orderInfo.createTime }}</span></div>
</el-form-item>
</el-form>
</div>
</div>
<div class="rule-wrapper mt40">
<div class="rule-title"> matters needing attention </div>
<div>1、 Please confirm whether the information of the patient is accurate , If you fill in the wrong number, you will not be able to visit , Loss to be borne by myself ;<br>
<span style="color:red">2、【 Take the number 】 The day of treatment should be {
{ orderInfo.fetchTime }} Get a number in the hospital , Failure to take the number shall be deemed as breach of the agreement , This number is not refunded or changed ;</span><br>
3、【 Withdrawal number 】 stay {
{ orderInfo.quitTime }} You can return the number online before , If it is overdue, you can't refund the number or fee ;<br>
4、 Appointment registration supports self paying patients to make an appointment with their ID card , At the same time, support Beijing medical insurance patients to use Beijing social security card to make an appointment and register on the platform . Please visit on the same day , Take the valid ID card used for appointment registration to the hospital to get the number ;<br>
5、 Please note that medical insurance patients in Beijing cannot use social security cards to get numbers in outpatient clinics during hospitalization .
</div>
</div>
<div class="bottom-wrapper mt60" v-if="orderInfo.orderStatus == 0 || orderInfo.orderStatus == 1">
<div class="button-wrapper">
<div class="v-button white" @click="cancelOrder()"> cancel reservation </div>
</div>
<div class="button-wrapper ml20" v-if="orderInfo.orderStatus == 0">
<div class="v-button" @click="pay()"> payment </div>
</div>
</div>
</div>
</div><!-- Right side content #end -->
<!-- Wechat payment pop-up box -->
<el-dialog :visible.sync="dialogPayVisible" style="text-align: left" :append-to-body="true" width="500px" @close="closeDialog">
<div class="container">
<div class="operate-view" style="height: 350px;">
<div class="wrapper wechat">
<div>
<qriously :value="payObj.codeUrl" :size="220"/>
<div style="text-align: center;line-height: 25px;margin-bottom: 40px;">
Please use wechat to scan <br/>
Scanning QR code for payment
</div>
</div>
</div>
</div>
</div>
</el-dialog>
</div><!-- footer -->
</template>
<script>
import '~/assets/css/hospital_personal.css'
import '~/assets/css/hospital.css'
import orderInfoApi from '@/api/orderInfo'
import weixinApi from '@/api/weixin'
export default {
data() {
return {
orderId: null,
orderInfo: {
param: {}
},
dialogPayVisible: false,
payObj: {},
timer: null // Timer name
}
},
created() {
this.orderId = this.$route.query.orderId
this.init()
},
methods: {
init() {
orderInfoApi.getOrders(this.orderId).then(response => {
console.log(response.data);
this.orderInfo = response.data
})
},
pay() {
this.dialogPayVisible = true
weixinApi.createNative(this.orderId).then(response => {
this.payObj = response.data
if(this.payObj.codeUrl == '') {
this.dialogPayVisible = false
this.$message.error(" Payment error ")
} else {
this.timer = setInterval(() => {
this.queryPayStatus(this.orderId)
}, 3000);
}
})
},
queryPayStatus(orderId) {
weixinApi.queryPayStatus(orderId).then(response => {
if (response.message == ' In the payment ') {
return
}
clearInterval(this.timer);
window.location.reload()
})
},
closeDialog() {
if(this.timer) {
clearInterval(this.timer);
}
}
}
}
</script>
<style>
.info-wrapper {
padding-left: 0;
padding-top: 0;
}
.content-wrapper {
color: #333;
font-size: 14px;
padding-bottom: 0;
}
.bottom-wrapper {
width: 100%;
}
.button-wrapper {
margin: 0;
}
.el-form-item {
margin-bottom: 5px;
}
.bottom-wrapper .button-wrapper {
margin-top: 0;
}
</style>
explain : We can only poll to check the payment status , Next, we deal with the payment query interface
2.4 Add query api request
stay /api/weixin.js File adding method
queryPayStatus(orderId) {
return request({
url: `/api/order/weixin/queryPayStatus/${
orderId}`,
method: 'get'
})
},
Processing payment results
3.1 Payment inquiry
3.1.1 add to service Interface and implementation
1、 stay WeixinService Class add interface
/** * Go to the wechat third party to check the payment status according to the order number */
Map queryPayStatus(Long orderId, String paymentType);
2、 stay WeixinServiceImpl Class add implementation
@Override
public Map queryPayStatus(Long orderId, String paymentType) {
try {
OrderInfo orderInfo = orderService.getById(orderId);
//1、 Package parameters
Map paramMap = new HashMap<>();
paramMap.put("appid", ConstantPropertiesUtils.APPID);
paramMap.put("mch_id", ConstantPropertiesUtils.PARTNER);
paramMap.put("out_trade_no", orderInfo.getOutTradeNo());
paramMap.put("nonce_str", WXPayUtil.generateNonceStr());
//2、 Set the request
HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/orderquery");
client.setXmlParam(WXPayUtil.generateSignedXml(paramMap, ConstantPropertiesUtils.PARTNERKEY));
client.setHttps(true);
client.post();
//3、 Return third-party data , Turn into Map
String xml = client.getContent();
Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);
//4、 return
return resultMap;
} catch (Exception e) {
return null;
}
}
3.1.2 add to controller Method
stay WeixinController Class add method
@Autowired
private PaymentService paymentService;
@ApiOperation(value = " Query payment status ")
@GetMapping("/queryPayStatus/{orderId}")
public Result queryPayStatus(
@ApiParam(name = "orderId", value = " Order id", required = true)
@PathVariable("orderId") Long orderId) {
// Call query interface
Map<String, String> resultMap = weixinPayService.queryPayStatus(orderId, PaymentTypeEnum.WEIXIN.name());
if (resultMap == null) {
// error
return Result.fail().message(" Payment error ");
}
if ("SUCCESS".equals(resultMap.get("trade_state"))) {
// If it works
// Change order status , Processing payment results
String out_trade_no = resultMap.get("out_trade_no");
paymentService.paySuccess(out_trade_no, PaymentTypeEnum.WEIXIN.getStatus(), resultMap);
return Result.ok().message(" Successful payment ");
}
return Result.ok().message(" In the payment ");
}
explain : If the payment is successful , We need to update the payment status 、 Inform the hospital that the reservation has been paid successfully
3.2 Process payment success logic
3.2.1 add to service Interface and implementation
1、 stay PaymentService Class add interface
/** * Successful payment */
void paySuccess(String outTradeNo, Integer paymentType, Map<String, String> paramMap);
2、 stay PaymentServiceImpl Class add implementation
/** * Successful payment */
@Override
public void paySuccess(String outTradeNo,Integer paymentType, Map<String,String> paramMap) {
PaymentInfo paymentInfo = this.getPaymentInfo(outTradeNo, paymentType);
if (null == paymentInfo) {
throw new YyghException(ResultCodeEnum.PARAM_ERROR);
}
if (paymentInfo.getPaymentStatus() != PaymentStatusEnum.UNPAID.getStatus()) {
return;
}
// Modify payment status
PaymentInfo paymentInfoUpd = new PaymentInfo();
paymentInfoUpd.setPaymentStatus(PaymentStatusEnum.PAID.getStatus());
paymentInfoUpd.setTradeNo(paramMap.get("transaction_id"));
paymentInfoUpd.setCallbackTime(new Date());
paymentInfoUpd.setCallbackContent(paramMap.toString());
this.updatePaymentInfo(outTradeNo, paymentInfoUpd);
// Modify order status
OrderInfo orderInfo = orderService.getById(paymentInfo.getOrderId());
orderInfo.setOrderStatus(OrderStatusEnum.PAID.getStatus());
orderService.updateById(orderInfo);
// Call the hospital interface , Notify update payment status
}
/** * Get payment records */
private PaymentInfo getPaymentInfo(String outTradeNo, Integer paymentType) {
QueryWrapper<PaymentInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("out_trade_no", outTradeNo);
queryWrapper.eq("payment_type", paymentType);
return baseMapper.selectOne(queryWrapper);
}
/** * Change payment records */
private void updatePaymentInfo(String outTradeNo, PaymentInfo paymentInfoUpd) {
QueryWrapper<PaymentInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("out_trade_no", outTradeNo);
baseMapper.update(paymentInfoUpd, queryWrapper);
}
3.2.2 Update hospital payment status
Reference resources 《 Shang Yitong API Interface document .docx》 Business interface 5.2. Update payment status
/** * Successful payment */
@Override
public void paySuccess(String outTradeNo,Integer paymentType, Map<String,String> paramMap) {
PaymentInfo paymentInfo = this.getPaymentInfo(outTradeNo, paymentType);
if (null == paymentInfo) {
throw new YyghException(ResultCodeEnum.PARAM_ERROR);
}
if (paymentInfo.getPaymentStatus() != PaymentStatusEnum.UNPAID.getStatus()) {
return;
}
// Modify payment status
PaymentInfo paymentInfoUpd = new PaymentInfo();
paymentInfoUpd.setPaymentStatus(PaymentStatusEnum.PAID.getStatus());
paymentInfoUpd.setTradeNo(paramMap.get("transaction_id"));
paymentInfoUpd.setCallbackTime(new Date());
paymentInfoUpd.setCallbackContent(paramMap.toString());
this.updatePaymentInfo(outTradeNo, paymentInfoUpd);
// Modify order status
OrderInfo orderInfo = orderService.getById(paymentInfo.getOrderId());
orderInfo.setOrderStatus(OrderStatusEnum.PAID.getStatus());
orderService.updateById(orderInfo);
// Call the hospital interface , Notify update payment status
SignInfoVo signInfoVo
= hospitalFeignClient.getSignInfoVo(orderInfo.getHoscode());
if(null == signInfoVo) {
throw new YyghException(ResultCodeEnum.PARAM_ERROR);
}
Map<String, Object> reqMap = new HashMap<>();
reqMap.put("hoscode",orderInfo.getHoscode());
reqMap.put("hosRecordId",orderInfo.getHosRecordId());
reqMap.put("timestamp", HttpRequestHelper.getTimestamp());
String sign = HttpRequestHelper.getSign(reqMap, signInfoVo.getSignKey());
reqMap.put("sign", sign);
JSONObject result = HttpRequestHelper.sendRequest(reqMap, signInfoVo.getApiUrl()+"/order/updatePayStatus");
if(result.getInteger("code") != 200) {
throw new YyghException(result.getString("message"), ResultCodeEnum.FAIL.getCode());
}
}
cancel reservation
Requirements describe
There are two kinds of cancellation :
- Unpaid cancellation order , Directly notify the hospital to update the cancellation status
- Cancelled order paid , Refund to the user first , Then inform the hospital to update the cancellation status
Develop wechat refund interface
Reference documents :https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
This interface requires certificates , Refer to the documentation for details and download the certificate
2.1 Configure certificate
Please download the certificate on service-order modular /resources/cert Under the folder
stay application.properties File configuration certificate path
weixin.cert=
C:\\yygh_parent\\service\\service_order\\src\\main\\resources\\cert\\apiclient_cert.p12
2.2 Add an interface to get payment records
Refund we initiate the refund according to the payment record
1、 stay PaymentService Class add interface
/** * Get payment records * @param orderId * @param paymentType * @return */
PaymentInfo getPaymentInfo(Long orderId, Integer paymentType);
2、 stay PaymentServiceImpl Class add implementation
@Override
public PaymentInfo getPaymentInfo(Long orderId, Integer paymentType) {
QueryWrapper<PaymentInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("order_id", orderId);
queryWrapper.eq("payment_type", paymentType);
return baseMapper.selectOne(queryWrapper);
}
2.3 Add a refund record
2.3 .1 add to mapper
public interface RefundInfoMapper extends BaseMapper<RefundInfo> {
}
2.3 .2 add to service Interface and implementation
1、 add to service Interface
public interface RefundInfoService extends IService<RefundInfo> {
/** * Keep refund records * @param paymentInfo */
RefundInfo saveRefundInfo(PaymentInfo paymentInfo);
}
2、 add to service Interface implementation
@Service
public class RefundInfoServiceImpl extends ServiceImpl<RefundInfoMapper, RefundInfo> implements RefundInfoService {
@Autowired
private RefundInfoMapper refundInfoMapper;
@Override
public RefundInfo saveRefundInfo(PaymentInfo paymentInfo) {
QueryWrapper<RefundInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("order_id", paymentInfo.getOrderId());
queryWrapper.eq("payment_type", paymentInfo.getPaymentType());
RefundInfo refundInfo = refundInfoMapper.selectOne(queryWrapper);
if(null != refundInfo) return refundInfo;
// Save transactions
refundInfo = new RefundInfo();
refundInfo.setCreateTime(new Date());
refundInfo.setOrderId(paymentInfo.getOrderId());
refundInfo.setPaymentType(paymentInfo.getPaymentType());
refundInfo.setOutTradeNo(paymentInfo.getOutTradeNo());
refundInfo.setRefundStatus(RefundStatusEnum.UNREFUND.getStatus());
refundInfo.setSubject(paymentInfo.getSubject());
//paymentInfo.setSubject("test");
refundInfo.setTotalAmount(paymentInfo.getTotalAmount());
refundInfoMapper.insert(refundInfo);
return refundInfo;
}
}
2.4 Add wechat refund interface
1、 stay WeixinService Add interface
/*** * refund * @param orderId * @return */
Boolean refund(Long orderId);
2、 stay WeixinServiceImpl Add implementation
@Override
public Boolean refund(Long orderId) {
try {
PaymentInfo paymentInfoQuery = paymentService.getPaymentInfo(orderId, PaymentTypeEnum.WEIXIN.getStatus());
RefundInfo refundInfo = refundInfoService.saveRefundInfo(paymentInfoQuery);
if(refundInfo.getRefundStatus().intValue() == RefundStatusEnum.REFUND.getStatus().intValue()) {
return true;
}
Map<String,String> paramMap = new HashMap<>(8);
paramMap.put("appid",ConstantPropertiesUtils.APPID); // Public accounts ID
paramMap.put("mch_id",ConstantPropertiesUtils.PARTNER); // Merchant number
paramMap.put("nonce_str",WXPayUtil.generateNonceStr());
paramMap.put("transaction_id",paymentInfoQuery.getTradeNo()); // Wechat Order No
paramMap.put("out_trade_no",paymentInfoQuery.getOutTradeNo()); // Merchant order number
paramMap.put("out_refund_no","tk"+paymentInfoQuery.getOutTradeNo()); // Merchant refund No
// paramMap.put("total_fee",paymentInfoQuery.getTotalAmount().multiply(new BigDecimal("100")).longValue()+"");
// paramMap.put("refund_fee",paymentInfoQuery.getTotalAmount().multiply(new BigDecimal("100")).longValue()+"");
paramMap.put("total_fee","1");
paramMap.put("refund_fee","1");
String paramXml = WXPayUtil.generateSignedXml(paramMap,ConstantPropertiesUtils.PARTNERKEY);
HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/secapi/pay/refund");
client.setXmlParam(paramXml);
client.setHttps(true);
client.setCert(true);
client.setCertPassword(ConstantPropertiesUtils.PARTNER);
client.post();
//3、 Return third-party data
String xml = client.getContent();
Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);
if (null != resultMap && WXPayConstants.SUCCESS.equalsIgnoreCase(resultMap.get("result_code"))) {
refundInfo.setCallbackTime(new Date());
refundInfo.setTradeNo(resultMap.get("refund_id"));
refundInfo.setRefundStatus(RefundStatusEnum.REFUND.getStatus());
refundInfo.setCallbackContent(JSONObject.toJSONString(resultMap));
refundInfoService.updateById(refundInfo);
return true;
}
return false;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
2.5 Complete cancellation of appointment
Reference resources 《 Shang Yitong API Interface document .docx》 Business interface 5.3. cancel reservation
2.5.1 add to service Interface and implementation
1、 stay OrderService Add interface
/** * Cancellation of order * @param orderId */
Boolean cancelOrder(Long orderId);
2、 stay OrderServiceImpl Add implementation
@Override
public Boolean cancelOrder(Long orderId) {
OrderInfo orderInfo = this.getById(orderId);
// The current time is about the cancellation time , You can't cancel the appointment
DateTime quitTime = new DateTime(orderInfo.getQuitTime());
if(quitTime.isBeforeNow()) {
throw new YyghException(ResultCodeEnum.CANCEL_ORDER_NO);
}
SignInfoVo signInfoVo = hospitalFeignClient.getSignInfoVo(orderInfo.getHoscode());
if(null == signInfoVo) {
throw new YyghException(ResultCodeEnum.PARAM_ERROR);
}
Map<String, Object> reqMap = new HashMap<>();
reqMap.put("hoscode",orderInfo.getHoscode());
reqMap.put("hosRecordId",orderInfo.getHosRecordId());
reqMap.put("timestamp", HttpRequestHelper.getTimestamp());
String sign = HttpRequestHelper.getSign(reqMap, signInfoVo.getSignKey());
reqMap.put("sign", sign);
JSONObject result = HttpRequestHelper.sendRequest(reqMap, signInfoVo.getApiUrl()+"/order/updateCancelStatus");
if(result.getInteger("code") != 200) {
throw new YyghException(result.getString("message"), ResultCodeEnum.FAIL.getCode());
} else {
// Whether to pay refund
if(orderInfo.getOrderStatus().intValue() == OrderStatusEnum.PAID.getStatus().intValue()) {
// Paid refund
boolean isRefund = weixinService.refund(orderId);
if(!isRefund) {
throw new YyghException(ResultCodeEnum.CANCEL_ORDER_FAIL);
}
}
// Change order status
orderInfo.setOrderStatus(OrderStatusEnum.CANCLE.getStatus());
this.updateById(orderInfo);
// send out mq Number of information update appointments We use the same mq Information , Do not set the number of bookable and remaining bookings , The number of reservations available at the receiving end is reduced 1 that will do
OrderMqVo orderMqVo = new OrderMqVo();
orderMqVo.setScheduleId(orderInfo.getScheduleId());
// Text message prompt
MsmVo msmVo = new MsmVo();
msmVo.setPhone(orderInfo.getPatientPhone());
msmVo.setTemplateCode("SMS_194640722");
String reserveDate = new DateTime(orderInfo.getReserveDate()).toString("yyyy-MM-dd") + (orderInfo.getReserveTime()==0 ? " In the morning ": " Afternoon ");
Map<String,Object> param = new HashMap<String,Object>(){
{
put("title", orderInfo.getHosname()+"|"+orderInfo.getDepname()+"|"+orderInfo.getTitle());
put("reserveDate", reserveDate);
put("name", orderInfo.getPatientName());
}};
msmVo.setParam(param);
orderMqVo.setMsmVo(msmVo);
rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_ORDER, MqConst.ROUTING_ORDER, orderMqVo);
}
return true;
}
2.5.2 add to controller Method
stay OrderApiController Add method
@ApiOperation(value = " cancel reservation ")
@GetMapping("auth/cancelOrder/{orderId}")
public Result cancelOrder(
@ApiParam(name = "orderId", value = " Order id", required = true)
@PathVariable("orderId") Long orderId) {
return Result.ok(orderService.cancelOrder(orderId));
}
2.6 Modify monitor
operation :service-hosp modular
modify HospitalReceiver class
@RabbitListener(bindings = @QueueBinding(
value = @Queue(value = MqConst.QUEUE_ORDER, durable = "true"),
exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_ORDER),
key = {
MqConst.ROUTING_ORDER}
))
public void receiver(OrderMqVo orderMqVo, Message message, Channel channel) throws IOException {
if(null != orderMqVo.getAvailableNumber()) {
// The number of appointments updated successfully
Schedule schedule = scheduleService.getScheduleId(orderMqVo.getScheduleId());
schedule.setReservedNumber(orderMqVo.getReservedNumber());
schedule.setAvailableNumber(orderMqVo.getAvailableNumber());
scheduleService.update(schedule);
} else {
// Cancel the appointment and update the number of appointments
Schedule schedule = scheduleService.getScheduleId(orderMqVo.getScheduleId());
int availableNumber = schedule.getAvailableNumber().intValue() + 1;
schedule.setAvailableNumber(availableNumber);
scheduleService.update(schedule);
}
// Send a text message
MsmVo msmVo = orderMqVo.getMsmVo();
if(null != msmVo) {
rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_MSM, MqConst.ROUTING_MSM_ITEM, msmVo);
}
}
front end
3.1 encapsulation api request
add to /api/weixin.js file
cancelOrder(orderId) {
return request({
url: `/api/order/orderInfo/auth/cancelOrder/${
orderId}`,
method: 'get'
})
},
3.2 The page display
modify /pages/order/show.vue Components
cancelOrder() {
this.$confirm(' Are you sure to cancel the appointment ?', ' Tips ', {
confirmButtonText: ' determine ',
cancelButtonText: ' Cancel ',
type: 'warning'
}).then(() => { // promise
// Click ok , The remote invocation
return weixinApi.cancelOrder(this.orderId)
}).then((response) => {
this.$message.success(' Cancellation successful ')
this.init()
}).catch(() => {
this.$message.info(' The appointment has been canceled ')
})
}
边栏推荐
- 发生OOM了,你知道是什么原因吗,又该怎么解决呢?
- Take you back to spark ecosystem!
- 西南大学:胡航-关于学习行为和学习效果分析
- 单片机实现模块化编程:思维+实例+系统教程(实用程度令人发指)
- Solve the problem of too many small files
- 零基础学习单片机切记这四点要求,少走弯路
- Several silly built-in functions about relative path / absolute path operation in CAPL script
- Vs All comments and uncomments
- 嵌入式中的合作开发--函数指针
- Elk project monitoring platform deployment + deployment of detailed use (II)
猜你喜欢
[deep learning] semantic segmentation: paper reading: (2021-12) mask2former
MapReduce instance (x): chainmapreduce
一大波開源小抄來襲
大学C语言入门到底怎么学才可以走捷径
五月集训总结——来自阿光
Interview shock 62: what are the precautions for group by?
Une grande vague d'attaques à la source ouverte
CAPL脚本中关于相对路径/绝对路径操作的几个傻傻分不清的内置函数
[flask] crud addition and query operation of data
Contest3145 - the 37th game of 2021 freshman individual training match_ B: Password
随机推荐
Learning SCM is of great help to society
[flask] crud addition and query operation of data
[untitled]
[one click] it only takes 30s to build a blog with one click - QT graphical tool
Configure system environment variables through bat script
Tianmu MVC audit II
Why is 51+ assembly in college SCM class? Why not come directly to STM32
Single chip microcomputer realizes modular programming: Thinking + example + system tutorial (the degree of practicality is appalling)
How can I take a shortcut to learn C language in college
【深度学习】语义分割:论文阅读(NeurIPS 2021)MaskFormer: per-pixel classification is not all you need
MapReduce instance (VIII): Map end join
33岁可以学PLC吗
竞赛vscode配置指南
五月刷题01——数组
018. Valid palindromes
Basic concepts of libuv
Summary of May training - from a Guang
四川云教和双师模式
六月刷题02——字符串
Several ways of MySQL database optimization (pen interview must ask)