|
|
@@ -0,0 +1,369 @@
|
|
|
+package com.chuanghai.smartschool.tuitionpayment.service.impl;
|
|
|
+
|
|
|
+import com.alibaba.excel.EasyExcel;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
|
+import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
|
|
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
+import com.chuanghai.smartschool.tuitionpayment.common.exception.BizCodeEnume;
|
|
|
+import com.chuanghai.smartschool.tuitionpayment.common.exception.RRException;
|
|
|
+import com.chuanghai.smartschool.tuitionpayment.common.utils.MyQuery;
|
|
|
+import com.chuanghai.smartschool.tuitionpayment.common.utils.PageParam;
|
|
|
+import com.chuanghai.smartschool.tuitionpayment.common.utils.PageUtils;
|
|
|
+import com.chuanghai.smartschool.tuitionpayment.dao.PayOrderDao;
|
|
|
+import com.chuanghai.smartschool.tuitionpayment.entity.PayOrderEntity;
|
|
|
+import com.chuanghai.smartschool.tuitionpayment.entity.PayableInfoEntity;
|
|
|
+import com.chuanghai.smartschool.tuitionpayment.enume.PayMethod;
|
|
|
+import com.chuanghai.smartschool.tuitionpayment.enume.PayStatus;
|
|
|
+import com.chuanghai.smartschool.tuitionpayment.service.EnablePayLimitByGradeService;
|
|
|
+import com.chuanghai.smartschool.tuitionpayment.service.PayMethodSettingService;
|
|
|
+import com.chuanghai.smartschool.tuitionpayment.service.PayOrderService;
|
|
|
+import com.chuanghai.smartschool.tuitionpayment.service.PayService;
|
|
|
+import com.chuanghai.smartschool.tuitionpayment.service.PayableInfoService;
|
|
|
+import com.chuanghai.smartschool.tuitionpayment.to.PayOrderQueryTO;
|
|
|
+import com.chuanghai.smartschool.tuitionpayment.utils.MyUtil;
|
|
|
+import com.chuanghai.smartschool.tuitionpayment.vo.CreateOrderResultVO;
|
|
|
+import com.chuanghai.smartschool.tuitionpayment.vo.OrderStatusVO;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.util.StringUtils;
|
|
|
+
|
|
|
+import javax.servlet.http.HttpServletResponse;
|
|
|
+import java.io.IOException;
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.net.URLEncoder;
|
|
|
+import java.time.LocalDate;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.time.temporal.ChronoUnit;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+@Slf4j
|
|
|
+@Service("payOrderService")
|
|
|
+public class PayOrderServiceImpl extends ServiceImpl<PayOrderDao, PayOrderEntity> implements PayOrderService {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private PayableInfoService payableInfoService;
|
|
|
+ @Autowired
|
|
|
+ private PayMethodSettingService payMethodSettingService;
|
|
|
+ @Autowired
|
|
|
+ private EnablePayLimitByGradeService enablePayLimitByGradeService;
|
|
|
+ @Autowired
|
|
|
+ private PayService payService;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public PageUtils queryPage(PayOrderQueryTO queryTO, PageParam pageParam) {
|
|
|
+ QueryWrapper<PayOrderEntity> wrapper = new QueryWrapper<>();
|
|
|
+
|
|
|
+ commonWrapper(wrapper, queryTO);
|
|
|
+
|
|
|
+ wrapper.orderByDesc("finish_time").orderByDesc("create_time").orderByAsc("pay_for_identify");
|
|
|
+
|
|
|
+ IPage<PayOrderEntity> page = this.page(
|
|
|
+ new MyQuery<PayOrderEntity>().getPage(pageParam),
|
|
|
+ wrapper
|
|
|
+ );
|
|
|
+
|
|
|
+ return new PageUtils(page);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public PageUtils queryPage(PageParam pageParam, String cardNumber) {
|
|
|
+ QueryWrapper<PayOrderEntity> wrapper = new QueryWrapper<>();
|
|
|
+ wrapper.eq("payer_identify", cardNumber);
|
|
|
+ IPage<PayOrderEntity> page = this.page(
|
|
|
+ new MyQuery<PayOrderEntity>().getPage(pageParam),
|
|
|
+ wrapper
|
|
|
+ );
|
|
|
+
|
|
|
+ return new PageUtils(page);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取用户是否缴费
|
|
|
+ * @param studentNo 学号
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public boolean isAlreadyPay(String studentNo) {
|
|
|
+ QueryWrapper<PayOrderEntity> wrapper = new QueryWrapper<>();
|
|
|
+ wrapper.eq("pay_for_identify", studentNo);
|
|
|
+ wrapper.eq("status", PayStatus.ALREADY_PAY.getCode());
|
|
|
+
|
|
|
+ List<PayOrderEntity> payList = this.list(wrapper);
|
|
|
+ if (payList != null && payList.size() > 0) {
|
|
|
+ return true;
|
|
|
+ } else {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建缴费订单
|
|
|
+ * @param cardNumber 当前用户
|
|
|
+ * @param studentNo 需要缴费的用户
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public CreateOrderResultVO createOrder(String cardNumber, String studentNo) {
|
|
|
+ // 查询用户是否已经缴费
|
|
|
+ boolean alreadyPay = isAlreadyPay(studentNo);
|
|
|
+ if (alreadyPay) {
|
|
|
+ throw new RRException(BizCodeEnume.DATA_IS_EXIST, "学号【" + studentNo + "】已缴费,请勿重复缴费");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查询支付金额、被支付用户信息
|
|
|
+ PayableInfoEntity payableInfo = payableInfoService.getByStudentNo(studentNo);
|
|
|
+
|
|
|
+ // 获取学生入学年份
|
|
|
+ String grade = payableInfo.getGrade();
|
|
|
+ Integer currentGrade = MyUtil.calcStudentGrade(Integer.valueOf(grade.trim()));
|
|
|
+
|
|
|
+ // 判断当前年级是否可线上缴费
|
|
|
+ boolean enablePay = enablePayLimitByGradeService.getCurrentGradeEnablePay(currentGrade);
|
|
|
+ if (!enablePay) {
|
|
|
+ throw new RRException(BizCodeEnume.PAYABLE_INFO_IS_NOT_EXIT, "当前学生所在年级不允许线上缴费");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取当前支付方式
|
|
|
+ String currentPayMethod = payMethodSettingService.getCurrentPayMethod();
|
|
|
+
|
|
|
+ QueryWrapper<PayOrderEntity> wrapper = new QueryWrapper<>();
|
|
|
+ wrapper.eq("payer_identify", cardNumber);
|
|
|
+ wrapper.eq("pay_for_identify", studentNo);
|
|
|
+ wrapper.orderByDesc("create_time");
|
|
|
+ wrapper.last("limit 1");
|
|
|
+ PayOrderEntity payOrderEntity = this.getOne(wrapper);
|
|
|
+
|
|
|
+
|
|
|
+ // 订单已经存在超过30分钟没有支付,直接删除该订单
|
|
|
+ if (payOrderEntity != null && PayStatus.NON_PAY.getCode().equals(payOrderEntity.getStatus())) {
|
|
|
+ if (Math.abs(ChronoUnit.MINUTES.between(LocalDateTime.now(), payOrderEntity.getCreateTime())) > 30) {
|
|
|
+ // 再次查询订单状态
|
|
|
+ OrderStatusVO orderStatusVO = queryOrderStatus(payOrderEntity);
|
|
|
+ if (PayStatus.NON_PAY.getCode().equals(orderStatusVO.getStatus())) {
|
|
|
+ this.removeById(payOrderEntity.getId());
|
|
|
+ payOrderEntity = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ CreateOrderResultVO createOrderResultVO = new CreateOrderResultVO();
|
|
|
+ if (payOrderEntity == null) {
|
|
|
+ createOrderResultVO.setMsg("新创建订单");
|
|
|
+
|
|
|
+ payOrderEntity = new PayOrderEntity();
|
|
|
+ payOrderEntity.setOrderNo(generateOrderNo());
|
|
|
+ payOrderEntity.setPayerIdentify(cardNumber);
|
|
|
+ payOrderEntity.setPayForIdentify(studentNo);
|
|
|
+ payOrderEntity.setStatus(PayStatus.NON_PAY.getCode());
|
|
|
+ payOrderEntity.setPayMethod(currentPayMethod);
|
|
|
+ payOrderEntity.setCreateTime(LocalDateTime.now());
|
|
|
+
|
|
|
+ // 支付金额、被支付用户信息
|
|
|
+ payOrderEntity.setOrderAmount(payableInfo.getRealPayAmount());
|
|
|
+ payOrderEntity.setStudentName(payableInfo.getStudentName());
|
|
|
+ payOrderEntity.setClassName(payableInfo.getClassName());
|
|
|
+
|
|
|
+ this.save(payOrderEntity);
|
|
|
+ } else {
|
|
|
+ if (!payOrderEntity.getPayMethod().equals(currentPayMethod)) {
|
|
|
+ payOrderEntity.setPayMethod(currentPayMethod);
|
|
|
+ this.updateById(payOrderEntity);
|
|
|
+ }
|
|
|
+ createOrderResultVO.setMsg("订单早已创建");
|
|
|
+ }
|
|
|
+
|
|
|
+ createOrderResultVO.setAmount(payOrderEntity.getOrderAmount());
|
|
|
+ createOrderResultVO.setOrderNo(payOrderEntity.getOrderNo());
|
|
|
+ createOrderResultVO.setPayMethod(payOrderEntity.getPayMethod());
|
|
|
+ return createOrderResultVO;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据订单号查询订单
|
|
|
+ * @param orderNo
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public PayOrderEntity getByOrderNo(String orderNo) {
|
|
|
+ QueryWrapper<PayOrderEntity> wrapper = new QueryWrapper<>();
|
|
|
+ wrapper.eq("order_no", orderNo);
|
|
|
+ PayOrderEntity payOrderEntity = this.getOne(wrapper);
|
|
|
+ if (payOrderEntity == null) {
|
|
|
+ throw new RRException(BizCodeEnume.ORDER_IS_NOT_EXIT);
|
|
|
+ }
|
|
|
+
|
|
|
+ return payOrderEntity;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询订单状态
|
|
|
+ * @param cardNumber 支付者标识
|
|
|
+ * @param orderNo 订单号
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public OrderStatusVO queryOrderStatus(String cardNumber, String orderNo) {
|
|
|
+ OrderStatusVO orderStatusVO = queryOrderStatus(orderNo);
|
|
|
+
|
|
|
+ if (!orderStatusVO.getPayerId().equals(cardNumber)) {
|
|
|
+ throw new RRException(BizCodeEnume.NO_PERMISSION);
|
|
|
+ }
|
|
|
+
|
|
|
+ return orderStatusVO;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public OrderStatusVO queryOrderStatus(PayOrderEntity payOrder) {
|
|
|
+ String orderNo = payOrder.getOrderNo();
|
|
|
+ // 订单未支付状态,先查询一下银行订单状态
|
|
|
+ if (PayStatus.NON_PAY.getCode().equalsIgnoreCase(payOrder.getStatus())) {
|
|
|
+ try {
|
|
|
+ if (PayMethod.CCB_PAY.getCode().equals(payOrder.getPayMethod())) {
|
|
|
+ Map<String, String> map = payService.queryCCBOrderStatus(orderNo);
|
|
|
+ String orderId = map.get("ORDERID");
|
|
|
+ String statusCode = map.get("STATUSCODE");
|
|
|
+ String amount = map.get("AMOUNT");
|
|
|
+ if (orderNo.equals(orderId)
|
|
|
+ && payOrder.getOrderAmount().setScale(2, BigDecimal.ROUND_UP).toString().equals(amount)
|
|
|
+ && "1".equals(statusCode)) {
|
|
|
+ // TODO 完成时间应该改成实际完成支付时间
|
|
|
+ payOrder.setFinishTime(LocalDateTime.now());
|
|
|
+ payOrder.setStatus(PayStatus.ALREADY_PAY.getCode());
|
|
|
+ this.updateById(payOrder);
|
|
|
+ }
|
|
|
+ } else if (PayMethod.JXNXS_PAY.getCode().equals(payOrder.getPayMethod())) {
|
|
|
+ Map<String, String> map = payService.queryJXNXSOrderStatus(orderNo);
|
|
|
+ String orderId = map.get("out_no");
|
|
|
+ String statusCode = map.get("status");
|
|
|
+ String amount = map.get("trade_amount");
|
|
|
+ BigDecimal realPayAmount = new BigDecimal(amount).divide(new BigDecimal("100")).setScale(2, BigDecimal.ROUND_UP); // 分转成元
|
|
|
+
|
|
|
+ if (orderNo.equals(orderId) && "1".equals(statusCode)) {
|
|
|
+ if (Math.abs(payOrder.getOrderAmount().setScale(2, BigDecimal.ROUND_UP).subtract(realPayAmount).doubleValue()) < 0.01) {
|
|
|
+ payOrder.setStatus(PayStatus.ALREADY_PAY.getCode());
|
|
|
+ // TODO 完成时间应该改成实际完成支付时间
|
|
|
+ payOrder.setFinishTime(LocalDateTime.now());
|
|
|
+ this.updateById(payOrder);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (RRException e) {
|
|
|
+ log.error("订单状态查询失败【{}】", e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ OrderStatusVO orderStatusVO = new OrderStatusVO();
|
|
|
+ orderStatusVO.setOrderNo(orderNo);
|
|
|
+ orderStatusVO.setStatus(payOrder.getStatus());
|
|
|
+ orderStatusVO.setPayerId(payOrder.getPayerIdentify());
|
|
|
+ return orderStatusVO;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询订单状态
|
|
|
+ * @param orderNo 订单号
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public OrderStatusVO queryOrderStatus(String orderNo) {
|
|
|
+ PayOrderEntity payOrder = getByOrderNo(orderNo);
|
|
|
+ return queryOrderStatus(payOrder);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询当前已完成支付金额
|
|
|
+ * @return
|
|
|
+ * @param queryTO
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public BigDecimal queryCurrentPayedAmount(PayOrderQueryTO queryTO) {
|
|
|
+ QueryWrapper<PayOrderEntity> wrapper = new QueryWrapper<>();
|
|
|
+ queryTO.setPayStatus(PayStatus.ALREADY_PAY.getCode());
|
|
|
+
|
|
|
+ commonWrapper(wrapper, queryTO);
|
|
|
+
|
|
|
+ wrapper.select("ifnull(sum(order_amount), 0) as total");
|
|
|
+ Map<String, Object> resultMap = this.getMap(wrapper);
|
|
|
+
|
|
|
+ return new BigDecimal(String.valueOf(resultMap.get("total"))).setScale(2, BigDecimal.ROUND_HALF_UP);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 下载完成缴费的名单
|
|
|
+ * @param response
|
|
|
+ * @param flag
|
|
|
+ * @param dateStr
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public void downloadResult(HttpServletResponse response, String flag, String dateStr, String payMethod) throws IOException {
|
|
|
+
|
|
|
+ QueryWrapper<PayOrderEntity> wrapper = new QueryWrapper<>();
|
|
|
+ wrapper.eq("status", PayStatus.ALREADY_PAY.getCode());
|
|
|
+ wrapper.eq(StringUtils.hasText(payMethod), "pay_method", payMethod);
|
|
|
+ wrapper.apply("2".equals(flag) ,"date_format(finish_time, '%Y-%m') = {0}", dateStr);
|
|
|
+ wrapper.apply("3".equals(flag), "date_format(finish_time, '%Y-%m-%d') = {0}", dateStr);
|
|
|
+ wrapper.orderByDesc("finish_time").orderByAsc("pay_for_identify");
|
|
|
+
|
|
|
+ List<PayOrderEntity> parOrder = this.list(wrapper);
|
|
|
+ String fileName = URLEncoder.encode("已完成缴费学生名单" + new Date().getTime(), "UTF-8");
|
|
|
+ response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
|
|
+ response.setCharacterEncoding("utf-8");
|
|
|
+ response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
|
|
|
+
|
|
|
+ EasyExcel.write(response.getOutputStream(), PayOrderEntity.class).sheet("已完成缴费学生名单").doWrite(parOrder);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Integer queryCurrentPayedRecordNum(PayOrderQueryTO queryTO) {
|
|
|
+ QueryWrapper<PayOrderEntity> wrapper = new QueryWrapper<>();
|
|
|
+ queryTO.setPayStatus(PayStatus.ALREADY_PAY.getCode());
|
|
|
+
|
|
|
+ commonWrapper(wrapper, queryTO);
|
|
|
+
|
|
|
+ return this.count(wrapper);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成订单号
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private String generateOrderNo() {
|
|
|
+ String idStr = IdWorker.getIdStr();
|
|
|
+ QueryWrapper<PayOrderEntity> wrapper = new QueryWrapper<>();
|
|
|
+ wrapper.eq("order_no", idStr);
|
|
|
+ PayOrderEntity one = this.getOne(wrapper);
|
|
|
+ if (one == null) {
|
|
|
+ return idStr;
|
|
|
+ } else {
|
|
|
+ return generateOrderNo();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建公共的查询wrapper
|
|
|
+ * @param wrapper
|
|
|
+ * @param queryTO
|
|
|
+ */
|
|
|
+ private void commonWrapper(QueryWrapper<PayOrderEntity> wrapper, PayOrderQueryTO queryTO) {
|
|
|
+ wrapper.eq(StringUtils.hasText(queryTO.getPayStatus()), "status", queryTO.getPayStatus());
|
|
|
+ wrapper.eq(StringUtils.hasText(queryTO.getPayMethod()), "pay_method", queryTO.getPayMethod());
|
|
|
+ String keyword = queryTO.getKeyword();
|
|
|
+ if (StringUtils.hasText(keyword)) {
|
|
|
+ wrapper.and(w -> w.like("student_name", keyword)
|
|
|
+ .or()
|
|
|
+ .like("class_name", keyword)
|
|
|
+ .or()
|
|
|
+ .eq("order_no", keyword));
|
|
|
+ }
|
|
|
+
|
|
|
+ String flag = queryTO.getFlag();
|
|
|
+ String dateStr = queryTO.getDateStr();
|
|
|
+ wrapper.apply("2".equals(flag) ,"date_format(finish_time, '%Y-%m') = {0}", dateStr);
|
|
|
+ wrapper.apply("3".equals(flag), "date_format(finish_time, '%Y-%m-%d') = {0}", dateStr);
|
|
|
+ }
|
|
|
+}
|