From 2cda8e26c67cf450f667bc15eef50548f7e00113 Mon Sep 17 00:00:00 2001
From: chen-xin-zhi <3588068430@qq.com>
Date: Mon, 9 Dec 2024 15:31:39 +0800
Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=BA=86=E5=95=86=E5=93=81?=
=?UTF-8?q?=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pom.xml | 6 +
.../cultural/heritage/config/WxPayConfig.java | 78 ++++++
.../book/BookingDateController.java | 161 +++++++----
.../good/AppointmentDateController.java | 210 ++++++++++++++
.../controller/good/GoodController.java | 90 +++++-
.../controller/wx/WeChatPayController.java | 120 ++++++++
.../heritage/mapper/TimeIntervalMapper.java | 7 +
.../AppointmentDateSingleAddRequest.java | 44 +++
.../model/dto/book/BookingDateAddRequest.java | 25 +-
.../dto/book/BookingDateUpdateRequest.java | 16 +-
.../service/ServiceGoodUpdateRequest.java | 4 +-
.../timeinterval/TimeIntervalAddRequest.java | 40 +++
.../timeperiod/TimePeriodUpdateRequest.java | 8 +
.../single/TimePeriodSingleAddRequest.java | 46 +++
.../single/TimePeriodSingleUpdateRequest.java | 36 +++
.../heritage/model/entity/BookingDate.java | 12 -
.../heritage/model/entity/TimeInterval.java | 67 +++++
.../heritage/model/vo/book/BookingDateVO.java | 19 +-
.../model/vo/timeinterval/TimeIntervalVO.java | 36 +++
.../service/book/BookingDateService.java | 4 +-
.../service/book/TimeIntervalService.java | 13 +
.../book/impl/BookingDateServiceImpl.java | 35 ++-
.../book/impl/TimeIntervalServiceImpl.java | 44 +++
.../heritage/service/wxpay/WeChatService.java | 53 ++++
.../service/wxpay/impl/WeChatServiceImpl.java | 265 ++++++++++++++++++
.../heritage/utils/AppointmentDateUtil.java | 23 --
src/main/resources/apiclient_key.pem | 28 ++
src/main/resources/application.yml | 19 +-
.../resources/mapper/TimeIntervalMapper.xml | 7 +
.../com/cultural/heritage/test/Animal.java | 39 +++
.../java/com/cultural/heritage/test/B.java | 8 +-
31 files changed, 1410 insertions(+), 153 deletions(-)
create mode 100644 src/main/java/com/cultural/heritage/config/WxPayConfig.java
create mode 100644 src/main/java/com/cultural/heritage/controller/good/AppointmentDateController.java
create mode 100644 src/main/java/com/cultural/heritage/controller/wx/WeChatPayController.java
create mode 100644 src/main/java/com/cultural/heritage/mapper/TimeIntervalMapper.java
create mode 100644 src/main/java/com/cultural/heritage/model/dto/appointment/single/AppointmentDateSingleAddRequest.java
create mode 100644 src/main/java/com/cultural/heritage/model/dto/timeinterval/TimeIntervalAddRequest.java
create mode 100644 src/main/java/com/cultural/heritage/model/dto/timeperiod/single/TimePeriodSingleAddRequest.java
create mode 100644 src/main/java/com/cultural/heritage/model/dto/timeperiod/single/TimePeriodSingleUpdateRequest.java
create mode 100644 src/main/java/com/cultural/heritage/model/entity/TimeInterval.java
create mode 100644 src/main/java/com/cultural/heritage/model/vo/timeinterval/TimeIntervalVO.java
create mode 100644 src/main/java/com/cultural/heritage/service/book/TimeIntervalService.java
create mode 100644 src/main/java/com/cultural/heritage/service/book/impl/TimeIntervalServiceImpl.java
create mode 100644 src/main/java/com/cultural/heritage/service/wxpay/WeChatService.java
create mode 100644 src/main/java/com/cultural/heritage/service/wxpay/impl/WeChatServiceImpl.java
delete mode 100644 src/main/java/com/cultural/heritage/utils/AppointmentDateUtil.java
create mode 100644 src/main/resources/apiclient_key.pem
create mode 100644 src/main/resources/mapper/TimeIntervalMapper.xml
create mode 100644 src/test/java/com/cultural/heritage/test/Animal.java
diff --git a/pom.xml b/pom.xml
index a5b8ea3..327420a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -177,6 +177,12 @@
5.2.0
+
+
+ com.github.wechatpay-apiv3
+ wechatpay-java
+ 0.2.10
+
diff --git a/src/main/java/com/cultural/heritage/config/WxPayConfig.java b/src/main/java/com/cultural/heritage/config/WxPayConfig.java
new file mode 100644
index 0000000..338b774
--- /dev/null
+++ b/src/main/java/com/cultural/heritage/config/WxPayConfig.java
@@ -0,0 +1,78 @@
+package com.cultural.heritage.config;
+
+import com.wechat.pay.java.core.RSAAutoCertificateConfig;
+import com.wechat.pay.java.core.util.IOUtil;
+import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
+import com.wechat.pay.java.service.refund.RefundService;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+
+@Data
+@Slf4j
+@Configuration
+@Component("WxPayConfig")
+@ConfigurationProperties(prefix = "wx.pay")
+public class WxPayConfig {
+
+ private String appId;
+
+ private String apiV3Key;
+
+ private String notifyUrl;
+
+ private String merchantId;
+
+ private String privateKeyPath;
+
+ private String merchantSerialNumber;
+
+ // RSA配置
+ private RSAAutoCertificateConfig RSAConfig;
+
+ // JSAPI支付
+ private JsapiServiceExtension jsapiServiceExtension;
+
+ // 退款
+ private RefundService refundService;
+
+ /**
+ * 初始化配置
+ */
+ @Bean
+ public boolean initWxPayConfig() throws IOException {
+ this.RSAConfig = buildRSAAutoCertificateConfig();
+ this.jsapiServiceExtension = buildJsapiServiceExtension(RSAConfig);
+ this.refundService = buildRefundService(RSAConfig);
+ return true;
+ }
+
+ // 构建并使用自动更新平台证书的RSA配置,一个商户号只能初始化一个配置,否则会因为重复的下载任务报错
+ private RSAAutoCertificateConfig buildRSAAutoCertificateConfig() throws IOException {
+ // 将 resource 目录下的文件转为 InputStream,然后利用 IOUtil.toString(inputStream) 转化为密钥
+ String privateKey = IOUtil.toString(new ClassPathResource(privateKeyPath).getInputStream());
+ return new RSAAutoCertificateConfig.Builder()
+ .merchantId(merchantId)
+ .privateKey(privateKey)
+ .merchantSerialNumber(merchantSerialNumber)
+ .apiV3Key(apiV3Key)
+ .build();
+ }
+
+ // 构建JSAPI支付
+ private JsapiServiceExtension buildJsapiServiceExtension(RSAAutoCertificateConfig config) {
+ return new JsapiServiceExtension.Builder().config(config).build();
+ }
+
+ // 构建退款
+ private RefundService buildRefundService(RSAAutoCertificateConfig config) {
+ return new RefundService.Builder().config(config).build();
+ }
+
+}
diff --git a/src/main/java/com/cultural/heritage/controller/book/BookingDateController.java b/src/main/java/com/cultural/heritage/controller/book/BookingDateController.java
index 31a7826..11988c9 100644
--- a/src/main/java/com/cultural/heritage/controller/book/BookingDateController.java
+++ b/src/main/java/com/cultural/heritage/controller/book/BookingDateController.java
@@ -1,6 +1,8 @@
package com.cultural.heritage.controller.book;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cultural.heritage.annotation.AuthCheck;
import com.cultural.heritage.common.BaseResponse;
@@ -11,27 +13,35 @@ import com.cultural.heritage.constant.UserConstant;
import com.cultural.heritage.exception.BusinessException;
import com.cultural.heritage.exception.ThrowUtils;
import com.cultural.heritage.model.dto.CommonStringRequest;
-import com.cultural.heritage.model.dto.book.BookingDateUpdateRequest;
+import com.cultural.heritage.model.dto.book.BookingDateAddRequest;
+import com.cultural.heritage.model.dto.timeinterval.TimeIntervalAddRequest;
import com.cultural.heritage.model.entity.BookingDate;
+import com.cultural.heritage.model.entity.TimeInterval;
import com.cultural.heritage.model.vo.book.BookingDateVO;
+import com.cultural.heritage.model.vo.timeinterval.TimeIntervalVO;
import com.cultural.heritage.service.book.BookingDateService;
+import com.cultural.heritage.service.book.TimeIntervalService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
-import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.bind.annotation.*;
+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 java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
@RestController
@RequestMapping("/book")
@Slf4j
-@Tag(name = "预约日期管理模块")
+@Tag(name = "写真预约日期管理模块")
public class BookingDateController {
@@ -39,75 +49,130 @@ public class BookingDateController {
private BookingDateService bookingDateService;
+ @Resource
+ private TimeIntervalService timeIntervalService;
+
+
+
/**
- * (写真预约)初始化未来一天的预约日期
+ * Web端管理员添加写真预约日期和时间段
+ * @param bookingDateAddRequestList 预约日期列表
+ * @return 是否添加成功
*/
-// @Scheduled(cron = "*/5 * * * * ?")
- // 每天00:00-00:00调用
- @Scheduled(cron = "0 0 0 * * ?")
+ @PostMapping("/add")
+ @Operation(summary = "Web端管理员添加写真预约日期和时间段", description = "参数:预约日期列表,权限:管理员(admin, boss),方法名:addBookingDate")
@Transactional(rollbackFor = Exception.class)
- @PostMapping("/init")
- @Operation(summary = "(自动调用)初始化未来一天的预约日期", description = "参数:无,权限:自动调用,方法名:initCurrentBookingDate")
- public void initCurrentBookingDate() {
- // 初始化预约日期
- List bookingDateList = new ArrayList<>();
- BookingDate bookingDateRent = bookingDateService.initBookingDate(BookConstant.RENT_CLOTHES, 3);
- BookingDate bookingDateOwn = bookingDateService.initBookingDate(BookConstant.OWN_CLOTHES, 3);
- bookingDateList.add(bookingDateRent);
- bookingDateList.add(bookingDateOwn);
+ @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
+ public BaseResponse addBookingDate(@RequestBody List bookingDateAddRequestList) {
+ if (bookingDateAddRequestList == null) {
+ throw new BusinessException(ErrorCode.PARAMS_ERROR);
+ }
+ // 添加写真预约日期
+ List bookingDateList = bookingDateAddRequestList.stream().map(bookingDateAddRequest -> {
+ BookingDate bookingDate = new BookingDate();
+ BeanUtils.copyProperties(bookingDateAddRequest, bookingDate);
+ bookingDateService.validBookingDate(bookingDate, false);
+ return bookingDate;
+ }).toList();
boolean result = bookingDateService.saveBatch(bookingDateList);
ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
+
+ // 添加写真预约时间段
+ List timeIntervals = new ArrayList<>();
+ for (int i = 0; i < bookingDateAddRequestList.size(); i++) {
+ BookingDate bookingDate = bookingDateList.get(i);
+ Long dateId = bookingDate.getId();
+ BookingDateAddRequest bookingDateAddRequest = bookingDateAddRequestList.get(i);
+ List timeIntervalAddRequestList = bookingDateAddRequest.getTimeIntervalAddRequestList();
+ List timeIntervalList = timeIntervalAddRequestList.stream().map(timeIntervalAddRequest -> {
+ TimeInterval timeInterval = new TimeInterval();
+ BeanUtils.copyProperties(timeIntervalAddRequest, timeInterval);
+ timeInterval.setBookingDateId(dateId);
+ timeIntervalService.validTimeInterval(timeInterval, false);
+ return timeInterval;
+ }).toList();
+ timeIntervals.addAll(timeIntervalList);
+ }
+ boolean success = timeIntervalService.saveBatch(timeIntervals);
+ ThrowUtils.throwIf(!success, ErrorCode.OPERATION_ERROR);
+ return ResultUtils.success(true);
}
-
-
/**
- * 根据预约类别查询未来四天(包括今天)的预约日期
+ * Web端管理员根据预约类型查询预约时间表
* @param commonStringRequest 预约类型
- * @return 当前预约类型未来四天的预约日期列表
+ * @return 预约时间表
*/
- @PostMapping("/list")
- @Operation(summary = "(小程序端)根据预约类别查询未来四天(包括今天)的预约日期", description = "参数:预约类型, 权限:所有人,方法名:listBookingDateByType")
+ @PostMapping("/list/type")
+ @Operation(summary = "Web端管理员根据预约类型查询预约时间表", description = "参数:预约类型,权限:管理员(admin, boss),方法名:listBookingDateByType")
+ @Transactional(rollbackFor = Exception.class)
+ @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
public BaseResponse> listBookingDateByType(@RequestBody CommonStringRequest commonStringRequest) {
if (commonStringRequest == null || StringUtils.isBlank(commonStringRequest.getType())) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
String type = commonStringRequest.getType();
+ if (!type.equals(BookConstant.RENT_CLOTHES) && !type.equals(BookConstant.OWN_CLOTHES)) {
+ throw new BusinessException(ErrorCode.PARAMS_ERROR, "类型参数错误");
+ }
QueryWrapper queryWrapper = new QueryWrapper<>();
queryWrapper.eq("type", type);
List bookingDateList = bookingDateService.list(queryWrapper);
- // 封装预约日期VO
- List bookingDateVOS = bookingDateList.stream().map(bookingDate -> {
+ List timeIntervalList = timeIntervalService.list();
+ // 存储写真预约时间段的map集合(键:预约日期id, 值:预约时间段列表)
+ Map> timeMap = new HashMap<>();
+ // 处理预约时间段,将预约时间段存入map集合
+ for (TimeInterval timeInterval : timeIntervalList) {
+ TimeIntervalVO timeIntervalVO = new TimeIntervalVO();
+ BeanUtils.copyProperties(timeInterval, timeIntervalVO);
+ Long bookingDateId = timeInterval.getBookingDateId();
+ List timeIntervalVOS = timeMap.get(bookingDateId);
+ if (timeIntervalVOS == null) {
+ timeIntervalVOS = new ArrayList<>();
+ }
+ timeIntervalVOS.add(timeIntervalVO);
+ timeMap.put(bookingDateId, timeIntervalVOS);
+ }
+ // 处理预约日期,填充当前预约日期对应的预约时间段
+ List bookingDateVOList = new ArrayList<>();
+ for (BookingDate bookingDate : bookingDateList) {
BookingDateVO bookingDateVO = new BookingDateVO();
BeanUtils.copyProperties(bookingDate, bookingDateVO);
- return bookingDateVO;
- }).toList();
- return ResultUtils.success(bookingDateVOS);
- }
-
-
-
- /**
- * 更新当天的预约情况
- * @param bookingDateUpdateRequest 预约日期更新请求体
- * @return 是否更新成功
- */
- @PostMapping("/update")
- @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
- @Operation(summary = "Web端管理员更新当天的预约情况", description = "参数:预约日期更新请求体, 权限:管理员(admin, boss),方法名:updateBookingDate")
- public BaseResponse updateBookingDate(@RequestBody BookingDateUpdateRequest bookingDateUpdateRequest) {
- if (bookingDateUpdateRequest == null || bookingDateUpdateRequest.getId() <= 0) {
- throw new BusinessException(ErrorCode.PARAMS_ERROR);
+ Long dateId = bookingDate.getId();
+ List timeIntervalVOS = timeMap.get(dateId);
+ bookingDateVO.setTimeIntervalVOList(timeIntervalVOS);
+ bookingDateVOList.add(bookingDateVO);
}
- BookingDate bookingDate = new BookingDate();
- BeanUtils.copyProperties(bookingDateUpdateRequest, bookingDate);
- boolean result = bookingDateService.updateById(bookingDate);
- ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
- return ResultUtils.success(true);
+
+ // 将预约日期从小到大排序
+ bookingDateVOList.sort((book1, book2) -> {
+ DateTime date1 = DateUtil.parse(book1.getSpecificDate(), "yyyy-MM-dd");
+ DateTime date2 = DateUtil.parse(book2.getSpecificDate(), "yyyy-MM-dd");
+ return date1.compareTo(date2);
+ });
+
+ return ResultUtils.success(bookingDateVOList);
}
+// @PostMapping("/update")
+// @Operation(summary = "Web端管理员根据预约类型更新预约时间表", description = "参数:预约类型,权限:管理员(admin, boss),方法名:updateBookingDate")
+// @Transactional(rollbackFor = Exception.class)
+// @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
+// public BaseResponse updateBookingDate(@RequestBody CommonStringRequest commonStringRequest) {
+// if (commonStringRequest == null || StringUtils.isBlank(commonStringRequest.getType())) {
+// throw new BusinessException(ErrorCode.PARAMS_ERROR);
+// }
+// String type = commonStringRequest.getType();
+// if (!type.equals(BookConstant.RENT_CLOTHES) && !type.equals(BookConstant.OWN_CLOTHES)) {
+// throw new BusinessException(ErrorCode.PARAMS_ERROR, "类型参数错误");
+// }
+// QueryWrapper queryWrapper = new QueryWrapper<>();
+// queryWrapper.eq("type", type);
+// return null;
+// }
+
}
diff --git a/src/main/java/com/cultural/heritage/controller/good/AppointmentDateController.java b/src/main/java/com/cultural/heritage/controller/good/AppointmentDateController.java
new file mode 100644
index 0000000..54eb20f
--- /dev/null
+++ b/src/main/java/com/cultural/heritage/controller/good/AppointmentDateController.java
@@ -0,0 +1,210 @@
+package com.cultural.heritage.controller.good;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.cultural.heritage.annotation.AuthCheck;
+import com.cultural.heritage.common.BaseResponse;
+import com.cultural.heritage.common.ErrorCode;
+import com.cultural.heritage.common.ResultUtils;
+import com.cultural.heritage.constant.UserConstant;
+import com.cultural.heritage.exception.BusinessException;
+import com.cultural.heritage.exception.ThrowUtils;
+import com.cultural.heritage.model.dto.CommonRequest;
+import com.cultural.heritage.model.dto.appointment.single.AppointmentDateSingleAddRequest;
+import com.cultural.heritage.model.dto.timeperiod.TimePeriodAddRequest;
+import com.cultural.heritage.model.dto.timeperiod.single.TimePeriodSingleAddRequest;
+import com.cultural.heritage.model.dto.timeperiod.single.TimePeriodSingleUpdateRequest;
+import com.cultural.heritage.model.entity.AppointmentDate;
+import com.cultural.heritage.model.entity.TimePeriod;
+import com.cultural.heritage.service.good.AppointmentDateService;
+import com.cultural.heritage.service.good.TimePeriodService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
+import org.springframework.transaction.annotation.Transactional;
+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 java.util.List;
+
+@RestController
+@RequestMapping("/appointmentDate")
+@Slf4j
+@Tag(name = "服务类商品预约日期模块")
+public class AppointmentDateController {
+
+
+ @Resource
+ private AppointmentDateService appointmentDateService;
+
+
+
+ @Resource
+ private TimePeriodService timePeriodService;
+
+
+ /**
+ * Web端管理员根据id删除预约日期
+ * @param commonRequest 预约日期id
+ * @return 是否删除成功
+ */
+ @PostMapping("/del/id")
+ @Operation(summary = "Web端管理员根据id删除预约日期", description = "参数:预约日期id,权限:管理员(admin, boss),方法名:delAppointmentDateById")
+ @Transactional(rollbackFor = Exception.class)
+ @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
+ public BaseResponse delAppointmentDateById(@RequestBody CommonRequest commonRequest) {
+ if (commonRequest == null || commonRequest.getId() <= 0) {
+ throw new BusinessException(ErrorCode.PARAMS_ERROR);
+ }
+ Long id = commonRequest.getId();
+ // 删除这个预约日期关联的所有时间段
+ QueryWrapper queryWrapper = new QueryWrapper<>();
+ queryWrapper.eq("appointmentDateId", id);
+ boolean remove = timePeriodService.remove(queryWrapper);
+ ThrowUtils.throwIf(!remove, ErrorCode.OPERATION_ERROR, "预约时间段删除失败");
+
+ // 删除这个预约日期
+ boolean success = appointmentDateService.removeById(id);
+ ThrowUtils.throwIf(!success, ErrorCode.OPERATION_ERROR, "预约日期删除失败");
+ return ResultUtils.success(true);
+ }
+
+
+
+
+ /**
+ * Web端管理员根据id删除预约时间段
+ * @param commonRequest 预约时间段id
+ * @return 是否删除成功
+ */
+ @PostMapping("/del/time/id")
+ @Operation(summary = "Web端管理员根据id删除预约时间段", description = "参数:预约日期段id,权限:管理员(admin, boss),方法名:delTimePeriodById")
+ @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
+ public BaseResponse delTimePeriodById(@RequestBody CommonRequest commonRequest) {
+ if (commonRequest == null || commonRequest.getId() <= 0) {
+ throw new BusinessException(ErrorCode.PARAMS_ERROR);
+ }
+ Long id = commonRequest.getId();
+ boolean remove = timePeriodService.removeById(id);
+ ThrowUtils.throwIf(!remove, ErrorCode.OPERATION_ERROR, "预约时间段删除失败");
+ return ResultUtils.success(true);
+ }
+
+
+
+ /**
+ * Web端管理员根据id修改预约日期的状态
+ * @param commonRequest 预约日期id
+ * @return 是否更新成功
+ */
+ @PostMapping("/update/status")
+ @Operation(summary = "Web端管理员根据id修改预约日期的状态", description = "参数:预约日期id,权限:管理员(admin, boss),方法名:updateTimePeriodStatusById")
+ @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
+ public BaseResponse updateTimePeriodStatusById(@RequestBody CommonRequest commonRequest) {
+ if (commonRequest == null || commonRequest.getId() <= 0) {
+ throw new BusinessException(ErrorCode.PARAMS_ERROR);
+ }
+ Long id = commonRequest.getId();
+ AppointmentDate appointmentDate = appointmentDateService.getById(id);
+ ThrowUtils.throwIf(appointmentDate == null, ErrorCode.OPERATION_ERROR, "预约日期不存在");
+ Integer status = appointmentDate.getIsAvailable() == 0 ? 1 : 0;
+ UpdateWrapper updateWrapper = new UpdateWrapper<>();
+ updateWrapper.eq("id", id);
+ updateWrapper.set("isAvailable", status);
+ boolean update = appointmentDateService.update(updateWrapper);
+ ThrowUtils.throwIf(!update, ErrorCode.OPERATION_ERROR, "预约日期状态修改失败");
+ return ResultUtils.success(true);
+ }
+
+
+
+
+ /**
+ * Web端管理员根据id修改预约时间段的人数
+ * @param timePeriodSingleUpdateRequest 预约日期id
+ * @return 是否更新成功
+ */
+ @PostMapping("/update/time")
+ @Operation(summary = "Web端管理员根据id修改预约时间段的人数", description = "参数:预约日期id,权限:管理员(admin, boss),方法名:updateTimePeriodPersonNumberById")
+ @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
+ public BaseResponse updateTimePeriodPersonNumberById(@RequestBody TimePeriodSingleUpdateRequest timePeriodSingleUpdateRequest) {
+ if (timePeriodSingleUpdateRequest == null || timePeriodSingleUpdateRequest.getId() <= 0) {
+ throw new BusinessException(ErrorCode.PARAMS_ERROR);
+ }
+ // 根据id获取当前的预约日期
+ Long id = timePeriodSingleUpdateRequest.getId();
+ TimePeriod time = timePeriodService.getById(id);
+ // 封装更新后的预约时间段
+ TimePeriod timePeriod = new TimePeriod();
+ BeanUtils.copyProperties(timePeriodSingleUpdateRequest, timePeriod);
+ timePeriod.setId(time.getId());
+ timePeriod.setTimeSlot(time.getTimeSlot());
+
+ boolean update = timePeriodService.updateById(timePeriod);
+ ThrowUtils.throwIf(!update, ErrorCode.OPERATION_ERROR, "预约时间段人数修改失败");
+ return ResultUtils.success(true);
+ }
+
+
+ /**
+ * Web端管理员添加预约时间段
+ * @param timePeriodSingleAddRequest 预约时间段添加请求体
+ * @return 是否添加成功
+ */
+ @PostMapping("/add/time")
+ @Operation(summary = "Web端管理员添加预约时间段", description = "参数:预约时间段添加请求体,权限:管理员(admin, boss),方法名:addAppointmentDate")
+ @Transactional(rollbackFor = Exception.class)
+ @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
+ public BaseResponse addTimePeriod(@RequestBody TimePeriodSingleAddRequest timePeriodSingleAddRequest) {
+ if (timePeriodSingleAddRequest == null) {
+ throw new BusinessException(ErrorCode.PARAMS_ERROR);
+ }
+ TimePeriod timePeriod = new TimePeriod();
+ BeanUtils.copyProperties(timePeriodSingleAddRequest, timePeriod);
+ boolean save = timePeriodService.save(timePeriod);
+ ThrowUtils.throwIf(!save, ErrorCode.OPERATION_ERROR, "预约时间段添加失败");
+ return ResultUtils.success(true);
+ }
+
+
+
+ /**
+ * Web端管理员添加预约日期
+ * @param appointmentDateSingleAddRequest 预约日期添加请求体
+ * @return 是否添加成功
+ */
+ @PostMapping("/add")
+ @Operation(summary = "Web端管理员添加预约日期", description = "参数:预约日期添加请求体,权限:管理员(admin, boss),方法名:addAppointmentDate")
+ @Transactional(rollbackFor = Exception.class)
+ @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
+ public BaseResponse addAppointmentDate(@RequestBody AppointmentDateSingleAddRequest appointmentDateSingleAddRequest) {
+ if (appointmentDateSingleAddRequest == null) {
+ throw new BusinessException(ErrorCode.PARAMS_ERROR);
+ }
+ // 添加当前商品的预约日期
+ AppointmentDate appointmentDate = new AppointmentDate();
+ BeanUtils.copyProperties(appointmentDateSingleAddRequest, appointmentDate);
+ boolean save = appointmentDateService.save(appointmentDate);
+ ThrowUtils.throwIf(!save, ErrorCode.OPERATION_ERROR, "预约日期添加失败");
+
+ // 添加当前预约日期的预约时间段
+ Long appointmentDateId = appointmentDate.getId();
+ List timePeriodAddRequestList = appointmentDateSingleAddRequest.getTimePeriodAddRequestList();
+ List timePeriodList = timePeriodAddRequestList.stream().map(timePeriodAddRequest -> {
+ TimePeriod timePeriod = new TimePeriod();
+ BeanUtils.copyProperties(timePeriodAddRequest, timePeriod);
+ timePeriod.setAppointmentDateId(appointmentDateId);
+ return timePeriod;
+ }).toList();
+ boolean result = timePeriodService.saveBatch(timePeriodList);
+ ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR, "批量添加预约时间段失败");
+
+ return ResultUtils.success(true);
+ }
+
+}
diff --git a/src/main/java/com/cultural/heritage/controller/good/GoodController.java b/src/main/java/com/cultural/heritage/controller/good/GoodController.java
index 1cbece6..a6aaaea 100644
--- a/src/main/java/com/cultural/heritage/controller/good/GoodController.java
+++ b/src/main/java/com/cultural/heritage/controller/good/GoodController.java
@@ -1,6 +1,8 @@
package com.cultural.heritage.controller.good;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -14,7 +16,6 @@ import com.cultural.heritage.exception.ThrowUtils;
import com.cultural.heritage.model.dto.CommonDelBatchRequest;
import com.cultural.heritage.model.dto.CommonRequest;
import com.cultural.heritage.model.dto.appointment.AppointmentDateAddRequest;
-import com.cultural.heritage.model.dto.appointment.AppointmentDateUpdateRequest;
import com.cultural.heritage.model.dto.good.GoodAddRequest;
import com.cultural.heritage.model.dto.good.GoodQueryRequest;
import com.cultural.heritage.model.dto.good.GoodUpdateRequest;
@@ -291,7 +292,7 @@ public class GoodController {
public BaseResponse> listGoodByPage(@RequestBody GoodQueryRequest goodQueryRequest) {
long current = goodQueryRequest.getCurrent();
long pageSize = goodQueryRequest.getPageSize();
- QueryWrapper goodQueryWrapper = goodService.getGoodQueryWrapper(goodQueryRequest, true);
+ QueryWrapper goodQueryWrapper = goodService.getGoodQueryWrapper(goodQueryRequest, false);
Page page = goodService.page(new Page<>(current, pageSize), goodQueryWrapper);
List records = page.getRecords();
List goodPageVOS = records.stream().map(good -> {
@@ -409,6 +410,13 @@ public class GoodController {
appointmentDateVOList.add(appointmentDateVO);
}
+ // 将预约日期从小到大排序
+ appointmentDateVOList.sort((app1, app2) -> {
+ DateTime date1 = DateUtil.parse(app1.getSpecificDate(), "yyyy-MM-dd");
+ DateTime date2 = DateUtil.parse(app2.getSpecificDate(), "yyyy-MM-dd");
+ return date1.compareTo(date2);
+ });
+
List serviceGoodVOList = new ArrayList<>();
for (Good good : records) {
ServiceGoodVO serviceGoodVO = new ServiceGoodVO();
@@ -481,6 +489,14 @@ public class GoodController {
appointmentDateVO.setTimePeriodVOList(timePeriodVOList);
appointmentDateVOList.add(appointmentDateVO);
}
+
+ // 将预约日期从小到大排序
+ appointmentDateVOList.sort((app1, app2) -> {
+ DateTime date1 = DateUtil.parse(app1.getSpecificDate(), "yyyy-MM-dd");
+ DateTime date2 = DateUtil.parse(app2.getSpecificDate(), "yyyy-MM-dd");
+ return date1.compareTo(date2);
+ });
+
serviceGoodVO.setAppointmentDateVOList(appointmentDateVOList);
return ResultUtils.success(serviceGoodVO);
}
@@ -517,6 +533,7 @@ public class GoodController {
*/
@PostMapping("/service/update")
@Operation(summary = "Web端管理员更新服务类商品", description = "参数:服务类商品更新请求体,权限:管理员(admin, boss),方法名:updateServiceGoodById")
+ @Transactional(rollbackFor = Exception.class)
@AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
public BaseResponse updateServiceGoodById(@RequestBody ServiceGoodUpdateRequest serviceGoodUpdateRequest) {
if (serviceGoodUpdateRequest == null || serviceGoodUpdateRequest.getId() <= 0) {
@@ -534,17 +551,74 @@ public class GoodController {
boolean result = goodService.updateById(good);
ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR, "商品不存在");
- List appointmentDateUpdateRequestList = serviceGoodUpdateRequest.getAppointmentDateUpdateRequestList();
- List appointmentDateList = appointmentDateUpdateRequestList.stream().map(appointmentDateUpdateRequest -> {
+ // 删除当前商品关联的所有日期和时间段
+ CommonRequest commonRequest = new CommonRequest();
+ commonRequest.setId(good.getId());
+ deleteServiceGoodAppointment(commonRequest);
+ // 为当前商品重新添加预约日期和时间段
+ ServiceGoodAddRequest serviceGoodAddRequest = new ServiceGoodAddRequest();
+ BeanUtils.copyProperties(serviceGoodUpdateRequest, serviceGoodAddRequest);
+ dealServiceGoodAppointmentDate(serviceGoodAddRequest, good);
+ return ResultUtils.success(true);
+ }
+
+
+
+ private void deleteServiceGoodAppointment(CommonRequest commonRequest) {
+ if (commonRequest == null || commonRequest.getId() <= 0) {
+ throw new BusinessException(ErrorCode.PARAMS_ERROR);
+ }
+ Long id = commonRequest.getId();
+
+ //删除预约时间段表中与该商品关联的记录
+ QueryWrapper dateQueryWrapper = new QueryWrapper<>();
+ dateQueryWrapper.eq("goodId", id);
+ List appointmentDateList = appointmentDateService.list(dateQueryWrapper);
+ List ids = appointmentDateList.stream().map(AppointmentDate::getId).toList();
+ QueryWrapper timePeriodQueryWrapper = new QueryWrapper<>();
+ timePeriodQueryWrapper.in("appointmentDateId", ids);
+ boolean remove = timePeriodService.remove(timePeriodQueryWrapper);
+ ThrowUtils.throwIf(!remove, ErrorCode.OPERATION_ERROR, "服务类商品预约时间段删除失败");
+
+ // 删除预约日期表中与该商品关联的记录
+ boolean isSuccess = appointmentDateService.remove(dateQueryWrapper);
+ ThrowUtils.throwIf(!isSuccess, ErrorCode.OPERATION_ERROR, "服务类商品预约日期删除失败");
+ }
+
+
+ private void dealServiceGoodAppointmentDate(ServiceGoodAddRequest serviceGoodAddRequest, Good good) {
+ // 添加当前商品的预约日期
+ List appointmentDateAddRequestList = serviceGoodAddRequest.getAppointmentDateAddRequestList();
+ List appointmentDateList = appointmentDateAddRequestList.stream().map(appointmentDateAddRequest -> {
AppointmentDate appointmentDate = new AppointmentDate();
- BeanUtils.copyProperties(appointmentDateUpdateRequest, appointmentDate);
+ BeanUtils.copyProperties(appointmentDateAddRequest, appointmentDate);
appointmentDate.setGoodId(good.getId());
+ // 校验
+ appointmentDateService.validAppointmentDate(appointmentDate, false);
return appointmentDate;
}).toList();
+ boolean isSaveBatch = appointmentDateService.saveBatch(appointmentDateList);
+ ThrowUtils.throwIf(!isSaveBatch, ErrorCode.OPERATION_ERROR);
-
-
- return ResultUtils.success(true);
+ // 添加当前商品的预约时间段
+ List timePeriods = new ArrayList<>();
+ for (int i = 0; i < appointmentDateAddRequestList.size(); i++) {
+ AppointmentDate appointmentDate = appointmentDateList.get(i);
+ AppointmentDateAddRequest appointmentDateAddRequest = appointmentDateAddRequestList.get(i);
+ Long appointmentDateId = appointmentDate.getId();
+ List timePeriodAddRequestList = appointmentDateAddRequest.getTimePeriodAddRequestList();
+ List timePeriodList = timePeriodAddRequestList.stream().map(timePeriodAddRequest -> {
+ TimePeriod timePeriod = new TimePeriod();
+ BeanUtils.copyProperties(timePeriodAddRequest, timePeriod);
+ timePeriod.setAppointmentDateId(appointmentDateId);
+ // 校验
+ timePeriodService.validTimePeriod(timePeriod, false);
+ return timePeriod;
+ }).toList();
+ timePeriods.addAll(timePeriodList);
+ }
+ boolean result = timePeriodService.saveBatch(timePeriods);
+ ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
}
diff --git a/src/main/java/com/cultural/heritage/controller/wx/WeChatPayController.java b/src/main/java/com/cultural/heritage/controller/wx/WeChatPayController.java
new file mode 100644
index 0000000..f80ff1d
--- /dev/null
+++ b/src/main/java/com/cultural/heritage/controller/wx/WeChatPayController.java
@@ -0,0 +1,120 @@
+package com.cultural.heritage.controller.wx;
+
+
+import com.cultural.heritage.annotation.AuthCheck;
+import com.cultural.heritage.common.BaseResponse;
+import com.cultural.heritage.common.ErrorCode;
+import com.cultural.heritage.common.ResultUtils;
+import com.cultural.heritage.constant.UserConstant;
+import com.cultural.heritage.exception.BusinessException;
+import com.cultural.heritage.exception.ThrowUtils;
+import com.cultural.heritage.model.dto.CommonRequest;
+import com.cultural.heritage.model.entity.Order;
+import com.cultural.heritage.model.entity.User;
+import com.cultural.heritage.service.order.OrderService;
+import com.cultural.heritage.service.user.UserService;
+import com.cultural.heritage.service.wxpay.WeChatService;
+import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
+import com.wechat.pay.java.service.payments.model.Transaction;
+import com.wechat.pay.java.service.refund.model.Refund;
+import com.wechat.pay.java.service.refund.model.RefundNotification;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.*;
+
+import java.io.IOException;
+
+/**
+ * 微信小程序相关接口
+ **/
+@Slf4j
+@RestController
+@Tag(name = "微信支付接口")
+@RequestMapping("/wechat")
+public class WeChatPayController {
+
+ @Resource
+ private UserService userService;
+
+ @Resource
+ private OrderService ordersService;
+
+ @Resource
+ private WeChatService weChatService;
+
+
+ /**
+ * JSAPI 下单
+ */
+ @PostMapping("/payment/create")
+ public BaseResponse createPayment(@RequestBody CommonRequest commonRequest, HttpServletRequest request) {
+ User loginUser = userService.getLoginUser(request);
+ String miniOpenId = loginUser.getMiniOpenId();
+ ThrowUtils.throwIf(miniOpenId == null, ErrorCode.NOT_FOUND_ERROR, "不是小程序用户");
+ Long orderId = commonRequest.getId();
+ Order order = ordersService.getById(orderId);
+ ThrowUtils.throwIf(order == null, ErrorCode.NOT_FOUND_ERROR, "订单不存在");
+// ThrowUtils.throwIf(order.getState() != 0, ErrorCode.OPERATION_ERROR, "订单状态错误");
+ if (!loginUser.getId().equals(order.getUserId())) {
+ throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "你不是该订单用户!");
+ }
+ PrepayWithRequestPaymentResponse response = weChatService.createPayment(String.valueOf(orderId), miniOpenId, order.getTotalAmount());
+ return ResultUtils.success(response);
+ }
+
+ /**
+ * JSAPI 下单回调
+ */
+ @PostMapping("/payment/callback")
+ @Transactional(rollbackFor = Exception.class)
+ public synchronized BaseResponse callbackPayment(HttpServletRequest request) throws IOException {
+ // 获取下单信息
+ Transaction transaction = weChatService.getTransactionInfo(request);
+ System.out.println("下单信息:" + transaction);
+ // 支付回调
+ boolean result = weChatService.paymentCallback(transaction);
+ ThrowUtils.throwIf(!result, ErrorCode.SYSTEM_ERROR, "微信支付回调失败");
+ return ResultUtils.success(true);
+ }
+
+ /**
+ * 退款(仅管理员和商家)
+ */
+ @PostMapping("/refund/create")
+ @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
+ public BaseResponse createRefund(@RequestBody CommonRequest commonRequest) {
+ Long orderId = commonRequest.getId();
+ Order order = ordersService.getById(orderId);
+ ThrowUtils.throwIf(order == null, ErrorCode.NOT_FOUND_ERROR, "订单不存在");
+ Refund refund = weChatService.refundPayment(String.valueOf(orderId), order.getTotalAmount());
+ return ResultUtils.success(refund);
+ }
+
+ /**
+ * 退款回调
+ */
+ @PostMapping("/refund/callback")
+ public BaseResponse callbackRefund(HttpServletRequest request) {
+ // 获取退款信息
+ RefundNotification refundNotification = weChatService.getRefundInfo(request);
+ // 退款回调
+ boolean result = weChatService.refundCallback(refundNotification);
+ ThrowUtils.throwIf(!result, ErrorCode.SYSTEM_ERROR, "退款回调失败");
+ return ResultUtils.success(true);
+ }
+
+ /**
+ * 发送订阅消息
+ */
+ @GetMapping("/refund/callback")
+ public BaseResponse testSendMessage() {
+ String miniOpenId = "o0o_B5CMLFiOs96dJZwtkyHcJzcM";
+ String templateId = "MK13FfX0XxsPV6m1vi6J8_8Bf7JT8rsayFs9q3f4FW4";
+ boolean subscribeMessage = weChatService.sendSubscribeMessage(miniOpenId, templateId);
+ return ResultUtils.success(subscribeMessage);
+ }
+
+}
diff --git a/src/main/java/com/cultural/heritage/mapper/TimeIntervalMapper.java b/src/main/java/com/cultural/heritage/mapper/TimeIntervalMapper.java
new file mode 100644
index 0000000..62d589e
--- /dev/null
+++ b/src/main/java/com/cultural/heritage/mapper/TimeIntervalMapper.java
@@ -0,0 +1,7 @@
+package com.cultural.heritage.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cultural.heritage.model.entity.TimeInterval;
+
+public interface TimeIntervalMapper extends BaseMapper {
+}
diff --git a/src/main/java/com/cultural/heritage/model/dto/appointment/single/AppointmentDateSingleAddRequest.java b/src/main/java/com/cultural/heritage/model/dto/appointment/single/AppointmentDateSingleAddRequest.java
new file mode 100644
index 0000000..df4b780
--- /dev/null
+++ b/src/main/java/com/cultural/heritage/model/dto/appointment/single/AppointmentDateSingleAddRequest.java
@@ -0,0 +1,44 @@
+package com.cultural.heritage.model.dto.appointment.single;
+
+import com.cultural.heritage.model.dto.timeperiod.TimePeriodAddRequest;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+
+
+@Data
+@Schema(description = "预约日期请求体", requiredProperties = {
+ "specificDate", "isAvailable", "timePeriodAddRequestList"
+})
+public class AppointmentDateSingleAddRequest implements Serializable {
+
+ /**
+ * 商品id
+ */
+ @Schema(description = "商品id", example = "2")
+ private Long goodId;
+
+ /**
+ * 具体预约时间
+ */
+ @Schema(description = "具体预约时间", example = "2024-12-04")
+ private String specificDate;
+
+ /**
+ * 是否可预约
+ */
+ @Schema(description = "是否可预约", example = "1")
+ private Integer isAvailable;
+
+ /**
+ * 预约时间段列表
+ */
+ private List timePeriodAddRequestList;
+
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+}
diff --git a/src/main/java/com/cultural/heritage/model/dto/book/BookingDateAddRequest.java b/src/main/java/com/cultural/heritage/model/dto/book/BookingDateAddRequest.java
index 495f8b8..9dc576e 100644
--- a/src/main/java/com/cultural/heritage/model/dto/book/BookingDateAddRequest.java
+++ b/src/main/java/com/cultural/heritage/model/dto/book/BookingDateAddRequest.java
@@ -1,13 +1,15 @@
package com.cultural.heritage.model.dto.book;
+import com.cultural.heritage.model.dto.timeinterval.TimeIntervalAddRequest;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
+import java.util.List;
@Data
-@Schema(description = "预约日期添加请求体", requiredProperties = {"specificDate", "timeSlot", "isAvailable", "maxNumber", "type"})
+@Schema(description = "预约日期添加请求体", requiredProperties = {"specificDate", "isAvailable", "type"})
public class BookingDateAddRequest implements Serializable {
/**
@@ -17,13 +19,6 @@ public class BookingDateAddRequest implements Serializable {
private String specificDate;
- /**
- * 时间段
- */
- @Schema(description = "时间段", example = "8:00-10:00;12:00-14:00")
- private String timeSlot;
-
-
/**
* 是否可预约
*/
@@ -31,13 +26,6 @@ public class BookingDateAddRequest implements Serializable {
private Integer isAvailable;
- /**
- * 各个时间段的最大预约人数(4,6..)
- */
- @Schema(description = "各个时间段的最大预约人数(4,6..)", example = "4,5,6")
- private String maxNumber;
-
-
/**
* 预约类别
*/
@@ -45,6 +33,13 @@ public class BookingDateAddRequest implements Serializable {
private String type;
+ /**
+ * 预约时间段列表
+ */
+ @Schema(description = "预约时间段列表")
+ private List timeIntervalAddRequestList;
+
+
@Serial
private static final long serialVersionUID = 1L;
}
diff --git a/src/main/java/com/cultural/heritage/model/dto/book/BookingDateUpdateRequest.java b/src/main/java/com/cultural/heritage/model/dto/book/BookingDateUpdateRequest.java
index c0c16a3..0e89bdd 100644
--- a/src/main/java/com/cultural/heritage/model/dto/book/BookingDateUpdateRequest.java
+++ b/src/main/java/com/cultural/heritage/model/dto/book/BookingDateUpdateRequest.java
@@ -7,7 +7,7 @@ import java.io.Serial;
import java.io.Serializable;
@Data
-@Schema(description = "预约日期更新请求体", requiredProperties = {"id", "specificDate", "timeSlot", "isAvailable", "maxNumber","type"})
+@Schema(description = "预约日期更新请求体", requiredProperties = {"id", "specificDate", "isAvailable","type"})
public class BookingDateUpdateRequest implements Serializable {
@@ -25,13 +25,6 @@ public class BookingDateUpdateRequest implements Serializable {
private String specificDate;
- /**
- * 时间段
- */
- @Schema(description = "时间段", example = "8:00-10:00;12:00-14:00")
- private String timeSlot;
-
-
/**
* 是否可预约
*/
@@ -39,13 +32,6 @@ public class BookingDateUpdateRequest implements Serializable {
private Integer isAvailable;
- /**
- * 各个时间段的最大预约人数(4,6..)
- */
- @Schema(description = "各个时间段的最大预约人数(4,6..)", example = "4,5,6")
- private String maxNumber;
-
-
/**
* 预约类别
*/
diff --git a/src/main/java/com/cultural/heritage/model/dto/good/service/ServiceGoodUpdateRequest.java b/src/main/java/com/cultural/heritage/model/dto/good/service/ServiceGoodUpdateRequest.java
index 5e8dbc3..5515712 100644
--- a/src/main/java/com/cultural/heritage/model/dto/good/service/ServiceGoodUpdateRequest.java
+++ b/src/main/java/com/cultural/heritage/model/dto/good/service/ServiceGoodUpdateRequest.java
@@ -1,6 +1,6 @@
package com.cultural.heritage.model.dto.good.service;
-import com.cultural.heritage.model.dto.appointment.AppointmentDateUpdateRequest;
+import com.cultural.heritage.model.dto.appointment.AppointmentDateAddRequest;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@@ -67,7 +67,7 @@ public class ServiceGoodUpdateRequest implements Serializable {
* 未来几天的预约时间表
*/
@Schema(description = "未来的预约时间表")
- private List appointmentDateUpdateRequestList;
+ private List appointmentDateAddRequestList;
@Serial
diff --git a/src/main/java/com/cultural/heritage/model/dto/timeinterval/TimeIntervalAddRequest.java b/src/main/java/com/cultural/heritage/model/dto/timeinterval/TimeIntervalAddRequest.java
new file mode 100644
index 0000000..5401322
--- /dev/null
+++ b/src/main/java/com/cultural/heritage/model/dto/timeinterval/TimeIntervalAddRequest.java
@@ -0,0 +1,40 @@
+package com.cultural.heritage.model.dto.timeinterval;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+@Data
+@Schema(description = "写真预约时间段添加请求体", requiredProperties = {
+ "timeSlot", "minNumber", "maxNumber"})
+public class TimeIntervalAddRequest implements Serializable {
+
+
+ /**
+ * 时间段
+ */
+ @Schema(description = "时间段", example = "08:00-10:00")
+ private String timeSlot;
+
+
+ /**
+ * 最小预约人数
+ */
+ @Schema(description = "最小预约人数", example = "3")
+ private Integer minNumber;
+
+
+ /**
+ * 最大预约人数
+ */
+ @Schema(description = "最大预约人数", example = "10")
+ private Integer maxNumber;
+
+
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+}
diff --git a/src/main/java/com/cultural/heritage/model/dto/timeperiod/TimePeriodUpdateRequest.java b/src/main/java/com/cultural/heritage/model/dto/timeperiod/TimePeriodUpdateRequest.java
index be9acad..45c04a6 100644
--- a/src/main/java/com/cultural/heritage/model/dto/timeperiod/TimePeriodUpdateRequest.java
+++ b/src/main/java/com/cultural/heritage/model/dto/timeperiod/TimePeriodUpdateRequest.java
@@ -17,6 +17,7 @@ public class TimePeriodUpdateRequest implements Serializable {
@Schema(description = "预约时间段id(id > 0)", example = "10")
private Long id;
+
/**
* 时间段
*/
@@ -39,6 +40,13 @@ public class TimePeriodUpdateRequest implements Serializable {
+ /**
+ * 预约日期id
+ */
+ @Schema(description = "预约日期id", example = "12")
+ private Long appointmentDateId;
+
+
@Serial
private static final long serialVersionUID = 1L;
}
diff --git a/src/main/java/com/cultural/heritage/model/dto/timeperiod/single/TimePeriodSingleAddRequest.java b/src/main/java/com/cultural/heritage/model/dto/timeperiod/single/TimePeriodSingleAddRequest.java
new file mode 100644
index 0000000..777b33d
--- /dev/null
+++ b/src/main/java/com/cultural/heritage/model/dto/timeperiod/single/TimePeriodSingleAddRequest.java
@@ -0,0 +1,46 @@
+package com.cultural.heritage.model.dto.timeperiod.single;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+@Data
+@Schema(description = "预约时间段添加请求体", requiredProperties = {
+ "timeSlot", "minNumber", "maxNumber"
+})
+public class TimePeriodSingleAddRequest implements Serializable {
+
+ /**
+ * 时间段
+ */
+ @Schema(description = "时间段", example = "08:00-10:00")
+ private String timeSlot;
+
+
+ /**
+ * 最小预约人数
+ */
+ @Schema(description = "最小预约人数", example = "3")
+ private Integer minNumber;
+
+
+ /**
+ * 最大预约人数
+ */
+ @Schema(description = "最大预约人数", example = "10")
+ private Integer maxNumber;
+
+
+ /**
+ * 预约日期id
+ */
+ @Schema(description = "预约日期id", example = "12")
+ private Long appointmentDateId;
+
+
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+}
diff --git a/src/main/java/com/cultural/heritage/model/dto/timeperiod/single/TimePeriodSingleUpdateRequest.java b/src/main/java/com/cultural/heritage/model/dto/timeperiod/single/TimePeriodSingleUpdateRequest.java
new file mode 100644
index 0000000..93b9165
--- /dev/null
+++ b/src/main/java/com/cultural/heritage/model/dto/timeperiod/single/TimePeriodSingleUpdateRequest.java
@@ -0,0 +1,36 @@
+package com.cultural.heritage.model.dto.timeperiod.single;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+@Data
+@Schema(description = "预约时间段更新请求体", requiredProperties = {"id", "minNumber", "maxNumber"})
+public class TimePeriodSingleUpdateRequest implements Serializable {
+
+
+ /**
+ * 预约时间段id
+ */
+ @Schema(description = "预约时间段id(id > 0)", example = "10")
+ private Long id;
+
+ /**
+ * 最小预约人数
+ */
+ @Schema(description = "最小预约人数", example = "3")
+ private Integer minNumber;
+
+
+ /**
+ * 最大预约人数
+ */
+ @Schema(description = "最大预约人数", example = "10")
+ private Integer maxNumber;
+
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+}
diff --git a/src/main/java/com/cultural/heritage/model/entity/BookingDate.java b/src/main/java/com/cultural/heritage/model/entity/BookingDate.java
index 65c9f08..fb338e8 100644
--- a/src/main/java/com/cultural/heritage/model/entity/BookingDate.java
+++ b/src/main/java/com/cultural/heritage/model/entity/BookingDate.java
@@ -31,24 +31,12 @@ public class BookingDate implements Serializable {
private String specificDate;
- /**
- * 时间段
- */
- private String timeSlot;
-
-
/**
* 是否可预约
*/
private Integer isAvailable;
- /**
- * 各个时间段的最大预约人数(4,6..)
- */
- private String maxNumber;
-
-
/**
* 预约类别
*/
diff --git a/src/main/java/com/cultural/heritage/model/entity/TimeInterval.java b/src/main/java/com/cultural/heritage/model/entity/TimeInterval.java
new file mode 100644
index 0000000..63d0868
--- /dev/null
+++ b/src/main/java/com/cultural/heritage/model/entity/TimeInterval.java
@@ -0,0 +1,67 @@
+package com.cultural.heritage.model.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+/**
+ * 写真预约时间段表
+ * @TableName time_interval
+ */
+@Data
+@TableName("time_interval")
+public class TimeInterval implements Serializable {
+
+ /**
+ * 预约时间段id
+ */
+ @TableId(type = IdType.AUTO)
+ private Long id;
+
+ /**
+ * 时间段
+ */
+ private String timeSlot;
+
+
+ /**
+ * 最小预约人数
+ */
+ private Integer minNumber;
+
+
+ /**
+ * 最大预约人数
+ */
+ private Integer maxNumber;
+
+
+ /**
+ * 预约日期id
+ */
+ private Long bookingDateId;
+
+ /**
+ * 创建时间
+ */
+ private Date createTime;
+
+ /**
+ * 更新时间
+ */
+ private Date updateTime;
+
+ /**
+ * 是否删除
+ */
+ private Integer isDelete;
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+}
diff --git a/src/main/java/com/cultural/heritage/model/vo/book/BookingDateVO.java b/src/main/java/com/cultural/heritage/model/vo/book/BookingDateVO.java
index 9be66ed..bb1594c 100644
--- a/src/main/java/com/cultural/heritage/model/vo/book/BookingDateVO.java
+++ b/src/main/java/com/cultural/heritage/model/vo/book/BookingDateVO.java
@@ -1,9 +1,11 @@
package com.cultural.heritage.model.vo.book;
+import com.cultural.heritage.model.vo.timeinterval.TimeIntervalVO;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
+import java.util.List;
@Data
public class BookingDateVO implements Serializable {
@@ -21,30 +23,23 @@ public class BookingDateVO implements Serializable {
private String specificDate;
- /**
- * 时间段
- */
- private String timeSlot;
-
-
/**
* 是否可预约
*/
private Integer isAvailable;
- /**
- * 各个时间段的最大预约人数(4,6..)
- */
- private String maxNumber;
-
-
/**
* 预约类别
*/
private String type;
+ /**
+ * 预约时间段
+ */
+ private List timeIntervalVOList;
+
@Serial
diff --git a/src/main/java/com/cultural/heritage/model/vo/timeinterval/TimeIntervalVO.java b/src/main/java/com/cultural/heritage/model/vo/timeinterval/TimeIntervalVO.java
new file mode 100644
index 0000000..8ea45f0
--- /dev/null
+++ b/src/main/java/com/cultural/heritage/model/vo/timeinterval/TimeIntervalVO.java
@@ -0,0 +1,36 @@
+package com.cultural.heritage.model.vo.timeinterval;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+@Data
+public class TimeIntervalVO implements Serializable {
+
+ /**
+ * 预约时间段id
+ */
+ private Long id;
+
+ /**
+ * 时间段
+ */
+ private String timeSlot;
+
+
+ /**
+ * 最小预约人数
+ */
+ private Integer minNumber;
+
+
+ /**
+ * 最大预约人数
+ */
+ private Integer maxNumber;
+
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+}
diff --git a/src/main/java/com/cultural/heritage/service/book/BookingDateService.java b/src/main/java/com/cultural/heritage/service/book/BookingDateService.java
index dc59c56..eaeb458 100644
--- a/src/main/java/com/cultural/heritage/service/book/BookingDateService.java
+++ b/src/main/java/com/cultural/heritage/service/book/BookingDateService.java
@@ -7,7 +7,7 @@ public interface BookingDateService extends IService {
/**
- * 初始化未来一天的预约日期
+ * 校验
*/
- BookingDate initBookingDate(String type, int offset);
+ void validBookingDate(BookingDate bookingDate, boolean update);
}
diff --git a/src/main/java/com/cultural/heritage/service/book/TimeIntervalService.java b/src/main/java/com/cultural/heritage/service/book/TimeIntervalService.java
new file mode 100644
index 0000000..3b41f12
--- /dev/null
+++ b/src/main/java/com/cultural/heritage/service/book/TimeIntervalService.java
@@ -0,0 +1,13 @@
+package com.cultural.heritage.service.book;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.cultural.heritage.model.entity.TimeInterval;
+
+public interface TimeIntervalService extends IService {
+
+
+ /**
+ * 校验
+ */
+ void validTimeInterval(TimeInterval timeInterval, boolean update);
+}
diff --git a/src/main/java/com/cultural/heritage/service/book/impl/BookingDateServiceImpl.java b/src/main/java/com/cultural/heritage/service/book/impl/BookingDateServiceImpl.java
index 541fa81..245b5ef 100644
--- a/src/main/java/com/cultural/heritage/service/book/impl/BookingDateServiceImpl.java
+++ b/src/main/java/com/cultural/heritage/service/book/impl/BookingDateServiceImpl.java
@@ -1,28 +1,37 @@
package com.cultural.heritage.service.book.impl;
-import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.cultural.heritage.common.ErrorCode;
+import com.cultural.heritage.exception.BusinessException;
import com.cultural.heritage.mapper.BookingDateMapper;
import com.cultural.heritage.model.entity.BookingDate;
import com.cultural.heritage.service.book.BookingDateService;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
@Service
public class BookingDateServiceImpl extends ServiceImpl implements BookingDateService {
- /**
- * 初始化未来一天的预约日期
- */
@Override
- public BookingDate initBookingDate(String type, int offset) {
- String currentDate = DateUtil.formatDate(DateUtil.offsetDay(DateUtil.date(), offset));
- BookingDate bookingDate = new BookingDate();
- bookingDate.setSpecificDate(currentDate);
- bookingDate.setTimeSlot("00:00-00:00");
- bookingDate.setIsAvailable(0);
- bookingDate.setMaxNumber("0");
- bookingDate.setType(type);
- return bookingDate;
+ public void validBookingDate(BookingDate bookingDate, boolean update) {
+ Long dateId = bookingDate.getId();
+ String specificDate = bookingDate.getSpecificDate();
+ Integer isAvailable = bookingDate.getIsAvailable();
+ String type = bookingDate.getType();
+
+ if (update) {
+ if (dateId == null) {
+ throw new BusinessException(ErrorCode.PARAMS_ERROR, "id参数错误");
+ }
+ }
+ if (ObjectUtils.isEmpty(isAvailable) || isAvailable != 1 && isAvailable != 0) {
+ throw new BusinessException(ErrorCode.PARAMS_ERROR, "是否可预约参数错误");
+ }
+ if (StringUtils.isAnyBlank(specificDate, type)) {
+ throw new BusinessException(ErrorCode.PARAMS_ERROR, "存在字符串类型参数为空");
+ }
+
}
}
diff --git a/src/main/java/com/cultural/heritage/service/book/impl/TimeIntervalServiceImpl.java b/src/main/java/com/cultural/heritage/service/book/impl/TimeIntervalServiceImpl.java
new file mode 100644
index 0000000..642bef6
--- /dev/null
+++ b/src/main/java/com/cultural/heritage/service/book/impl/TimeIntervalServiceImpl.java
@@ -0,0 +1,44 @@
+package com.cultural.heritage.service.book.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.cultural.heritage.common.ErrorCode;
+import com.cultural.heritage.exception.BusinessException;
+import com.cultural.heritage.mapper.TimeIntervalMapper;
+import com.cultural.heritage.model.entity.TimeInterval;
+import com.cultural.heritage.service.book.TimeIntervalService;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+@Service
+public class TimeIntervalServiceImpl extends ServiceImpl implements TimeIntervalService {
+
+ /**
+ * 校验
+ */
+ @Override
+ public void validTimeInterval(TimeInterval timeInterval, boolean update) {
+
+ Long id = timeInterval.getId();
+ Integer minNumber = timeInterval.getMinNumber();
+ Integer maxNumber = timeInterval.getMaxNumber();
+ String timeSlot = timeInterval.getTimeSlot();
+ Long bookingDateId = timeInterval.getBookingDateId();
+
+ if (update) {
+ if (id == null) {
+ throw new BusinessException(ErrorCode.PARAMS_ERROR, "预约日期id参数错误");
+ }
+ }
+ if (ObjectUtils.anyNull(minNumber, maxNumber, bookingDateId)) {
+ throw new BusinessException(ErrorCode.PARAMS_ERROR, "存在参数为空");
+ }
+ if (minNumber > maxNumber) {
+ throw new BusinessException(ErrorCode.PARAMS_ERROR, "最小预约人数不能超过最大预约人数");
+ }
+ if (StringUtils.isBlank(timeSlot)) {
+ throw new BusinessException(ErrorCode.PARAMS_ERROR, "时间段参数为空");
+ }
+
+ }
+}
diff --git a/src/main/java/com/cultural/heritage/service/wxpay/WeChatService.java b/src/main/java/com/cultural/heritage/service/wxpay/WeChatService.java
new file mode 100644
index 0000000..b163dad
--- /dev/null
+++ b/src/main/java/com/cultural/heritage/service/wxpay/WeChatService.java
@@ -0,0 +1,53 @@
+package com.cultural.heritage.service.wxpay;
+
+
+import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
+import com.wechat.pay.java.service.payments.model.Transaction;
+import com.wechat.pay.java.service.refund.model.Refund;
+import com.wechat.pay.java.service.refund.model.RefundNotification;
+import jakarta.servlet.http.HttpServletRequest;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+
+/**
+ * @author 玄德
+ */
+public interface WeChatService {
+
+ /**
+ * 微信支付
+ */
+ PrepayWithRequestPaymentResponse createPayment(String orderId, String miniOpenId, BigDecimal amount);
+
+ /**
+ * 获取支付回调信息
+ */
+ Transaction getTransactionInfo(HttpServletRequest request);
+
+ /**
+ * 支付回调
+ */
+ boolean paymentCallback(Transaction transaction) throws IOException;
+
+ /**
+ * 退款申请
+ */
+ Refund refundPayment(String orderId, BigDecimal amount);
+
+ /**
+ * 获取退款回调信息
+ */
+ RefundNotification getRefundInfo(HttpServletRequest request);
+
+ /**
+ * 退款回调
+ */
+ boolean refundCallback(RefundNotification refundNotification);
+
+ /**
+ * 发送订阅模板消息
+ */
+ boolean sendSubscribeMessage(String openid, String templateId);
+
+}
diff --git a/src/main/java/com/cultural/heritage/service/wxpay/impl/WeChatServiceImpl.java b/src/main/java/com/cultural/heritage/service/wxpay/impl/WeChatServiceImpl.java
new file mode 100644
index 0000000..fe1bcbb
--- /dev/null
+++ b/src/main/java/com/cultural/heritage/service/wxpay/impl/WeChatServiceImpl.java
@@ -0,0 +1,265 @@
+package com.cultural.heritage.service.wxpay.impl;
+
+
+import cn.binarywang.wx.miniapp.api.WxMaMsgService;
+import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage;
+import cn.hutool.core.util.RandomUtil;
+import com.cultural.heritage.common.ErrorCode;
+import com.cultural.heritage.config.WxOpenConfig;
+import com.cultural.heritage.config.WxPayConfig;
+import com.cultural.heritage.exception.BusinessException;
+import com.cultural.heritage.model.entity.Order;
+import com.cultural.heritage.service.order.OrderService;
+import com.cultural.heritage.service.wxpay.WeChatService;
+import com.wechat.pay.java.core.notification.NotificationParser;
+import com.wechat.pay.java.core.notification.RequestParam;
+import com.wechat.pay.java.service.payments.jsapi.model.Amount;
+import com.wechat.pay.java.service.payments.jsapi.model.Payer;
+import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
+import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
+import com.wechat.pay.java.service.payments.model.Transaction;
+import com.wechat.pay.java.service.refund.model.AmountReq;
+import com.wechat.pay.java.service.refund.model.CreateRequest;
+import com.wechat.pay.java.service.refund.model.Refund;
+import com.wechat.pay.java.service.refund.model.RefundNotification;
+import jakarta.annotation.Resource;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author 玄德
+ */
+@Slf4j
+@Service
+public class WeChatServiceImpl implements WeChatService {
+
+ @Resource
+ private WxPayConfig wxPayConfig;
+
+ @Resource
+ private WxOpenConfig wxOpenConfig;
+
+ @Resource
+ private OrderService ordersService;
+
+ /**
+ * 请求参数
+ */
+ public static RequestParam requestParam = null;
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public synchronized PrepayWithRequestPaymentResponse createPayment(String orderId, String miniOpenId, BigDecimal amount) {
+ // request.setXxx(val)设置所需参数,具体参数可见Request定义
+ PrepayRequest request = new PrepayRequest();
+ // 金额
+ Amount WxAmount = new Amount();
+ WxAmount.setTotal(amount.movePointRight(2).intValue());
+ WxAmount.setCurrency("CNY");
+ request.setAmount(WxAmount);
+ // 公众号id
+ request.setAppid(wxPayConfig.getAppId());
+ // 商户号
+ request.setMchid(wxPayConfig.getMerchantId());
+ // 支付者信息
+ Payer payer = new Payer();
+ payer.setOpenid(miniOpenId);
+ request.setPayer(payer);
+ // 描述
+ request.setDescription("订单号:" + orderId);
+ // 微信回调地址
+ request.setNotifyUrl(wxPayConfig.getNotifyUrl() + "/api/wechat/payment/callback");
+ // 商户订单号
+ request.setOutTradeNo(RandomUtil.randomNumbers(12));
+ //返回数据,前端调起支付
+ return wxPayConfig.getJsapiServiceExtension().prepayWithRequestPayment(request);
+ }
+
+ @Override
+ public Transaction getTransactionInfo(HttpServletRequest request) {
+ NotificationParser notificationParser = getNotificationParser(request);
+ return notificationParser.parse(requestParam, Transaction.class);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public synchronized boolean paymentCallback(Transaction transaction) throws IOException {
+ System.out.println("---------------------------微信支付回调(开始)-------------------------------");
+ // 获取订单信息
+ String orderIdByString = transaction.getOutTradeNo();
+ Order order = ordersService.getById(orderIdByString);
+ if (order == null) {
+ log.error("订单不存在");
+ throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "订单不存在,订单号:" + transaction.getOutTradeNo());
+ }
+ // 生成取餐码
+ // 获取当日的日期
+ LocalDate today = LocalDate.now();
+ // 获取当日的 00:00 时间
+ LocalDateTime startTime = today.atStartOfDay();
+ // 获取当日的 23:59 时间
+ LocalDateTime endTime = today.atTime(LocalTime.MAX);
+// // 生成取餐码
+// QueryWrapper queryWrapper = new QueryWrapper<>();
+// queryWrapper.eq("businessId", order.getBusinessId());
+// queryWrapper.between("createTime", startTime, endTime);
+// queryWrapper.in("state", 1, 2);
+// long count = ordersService.count(queryWrapper);
+// String pickupCode = String.format("%04d", count + 1);
+// // 修改订单信息
+// order.setState(1);
+// order.setPickupCode(pickupCode);
+// Date date = new Date();
+// order.setUpdateTime(date);
+// boolean update = ordersService.updateById(order);
+// ThrowUtils.throwIf(!update, ErrorCode.OPERATION_ERROR, "修改订单状态失败");
+// // 通知商家新订单
+// Business business = businessService.getById(order.getBusinessId());
+// Long userId = order.getUserId();
+// Long businessId = business.getUserId();
+// MessageVO messageVO = new MessageVO();
+// messageVO.setType(1);
+// messageVO.setUserId(userId);
+// messageVO.setToUserId(businessId);
+// messageVO.setContent(orderIdByString);
+// String message = JSONUtil.toJsonStr(messageVO);
+// // 通知商家新订单
+// webSocketServer.onMessage(message);
+ System.out.println("---------------------------微信支付回调(结束)-------------------------------");
+ return true;
+ }
+
+ @Override
+ public Refund refundPayment(String orderId, BigDecimal amount) {
+ // 退款请求
+ CreateRequest createRequest = new CreateRequest();
+ // 商户订单号
+ createRequest.setOutTradeNo(orderId);
+ // 商户退款单号
+ createRequest.setOutRefundNo(orderId);
+ // 退款结果回调
+ createRequest.setNotifyUrl(wxPayConfig.getNotifyUrl() + "/api/wechat/refund/callback");
+ // 退款金额
+ AmountReq amountReq = new AmountReq();
+ long refundAmount = amount.movePointRight(2).intValue();
+ amountReq.setRefund(refundAmount);
+ amountReq.setTotal(refundAmount);
+ amountReq.setCurrency("CNY");
+ createRequest.setAmount(amountReq);
+ // 申请退款
+ System.out.println("退款请求:" + createRequest);
+ Refund refund = wxPayConfig.getRefundService().create(createRequest);
+ System.out.println("退款申请结果:" + refund);
+ return refund;
+ }
+
+ @Override
+ public RefundNotification getRefundInfo(HttpServletRequest request) {
+ NotificationParser notificationParser = getNotificationParser(request);
+ return notificationParser.parse(requestParam, RefundNotification.class);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public synchronized boolean refundCallback(RefundNotification refundNotification) {
+ System.out.println("---------------------------微信退款回调(开始)-------------------------------");
+ // 获取订单信息
+ String orderIdByString = refundNotification.getOutTradeNo();
+ Order order = ordersService.getById(orderIdByString);
+ // 修改订单信息
+ order.setOrderStatus("已退款");
+ ordersService.updateById(order);
+ System.out.println("---------------------------微信退款回调(结束)-------------------------------");
+ return true;
+ }
+
+ @Override
+ public boolean sendSubscribeMessage(String openid, String templateId) {
+ try {
+ // 获取小程序对象
+ WxMaService wxMaService = wxOpenConfig.getWxMaService();
+ // 获取消息接口
+ WxMaMsgService msgService = wxMaService.getMsgService();
+ // 构建订阅消息体
+ WxMaSubscribeMessage wxMaSubscribeMessage = new WxMaSubscribeMessage();
+ wxMaSubscribeMessage.setToUser(openid);
+ wxMaSubscribeMessage.setTemplateId(templateId);
+ List msgDataList = getMsgData();
+ wxMaSubscribeMessage.setData(msgDataList);
+ // 发送消息
+ msgService.sendSubscribeMsg(wxMaSubscribeMessage);
+ return true;
+ } catch (Exception e) {
+ log.error("发送订阅消息失败:", e);
+ throw new BusinessException(ErrorCode.SYSTEM_ERROR, "发送订阅消息失败");
+ }
+ }
+
+ /**
+ * 提取消息数据
+ */
+ private static List getMsgData() {
+ List msgDataList = new ArrayList<>();
+ String[][] dataItems = {
+ {"thing1", "新订单"},
+ {"phrase2", "已支付"},
+ {"amount3", "666"},
+ {"thing10", "666666"},
+ {"time8", "2019-12-18 12:12:12"}
+ };
+ for (String[] item : dataItems) {
+ WxMaSubscribeMessage.MsgData msgData = new WxMaSubscribeMessage.MsgData();
+ msgData.setName(item[0]);
+ msgData.setValue(item[1]);
+ msgDataList.add(msgData);
+ }
+ return msgDataList;
+ }
+
+ /**
+ * 根据微信官方发送的请求获取信息
+ */
+ @SneakyThrows
+ public NotificationParser getNotificationParser(HttpServletRequest request) {
+ System.out.println("---------------------------获取信息-------------------------------");
+ // 获取RSA配置
+ NotificationParser notificationParser = new NotificationParser(wxPayConfig.getRSAConfig());
+ // 构建请求
+ StringBuilder bodyBuilder = new StringBuilder();
+ BufferedReader reader = request.getReader();
+ String line;
+ while ((line = reader.readLine()) != null) {
+ bodyBuilder.append(line);
+ }
+ String body = bodyBuilder.toString();
+ String timestamp = request.getHeader("Wechatpay-Timestamp");
+ String nonce = request.getHeader("Wechatpay-Nonce");
+ String signature = request.getHeader("Wechatpay-Signature");
+ String singType = request.getHeader("Wechatpay-Signature-Type");
+ String wechatPayCertificateSerialNumber = request.getHeader("Wechatpay-Serial");
+ requestParam = new RequestParam.Builder()
+ .serialNumber(wechatPayCertificateSerialNumber)
+ .nonce(nonce)
+ .signature(signature)
+ .timestamp(timestamp)
+ .signType(singType)
+ .body(body)
+ .build();
+ System.out.println(requestParam.toString());
+ System.out.println("---------------------------信息获取完毕-------------------------------");
+ return notificationParser;
+ }
+}
diff --git a/src/main/java/com/cultural/heritage/utils/AppointmentDateUtil.java b/src/main/java/com/cultural/heritage/utils/AppointmentDateUtil.java
deleted file mode 100644
index 3e2299b..0000000
--- a/src/main/java/com/cultural/heritage/utils/AppointmentDateUtil.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.cultural.heritage.utils;
-
-import cn.hutool.core.date.DateTime;
-import cn.hutool.core.date.DateUtil;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class AppointmentDateUtil {
-
- // 将当天及未来三天的日期加入到集合中
- public static List getDates() {
- List dates = new ArrayList<>();
- for (int i = 0; i < 4; i ++ ) {
- DateTime date = DateUtil.date();
- DateTime dateTime = DateUtil.offsetDay(date, i);
- String formatDate = DateUtil.formatDate(dateTime);
- dates.add(formatDate);
- }
- return dates;
- }
-
-}
diff --git a/src/main/resources/apiclient_key.pem b/src/main/resources/apiclient_key.pem
new file mode 100644
index 0000000..81400ad
--- /dev/null
+++ b/src/main/resources/apiclient_key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDQvDoLQ9+041aV
+lLvDgIdhenuq54wx+UeuIWd2Zc4E4Io+47PCr6kzpbkLhq47//dKAG1Fobb2vCRu
+HG+CUfhkOzYLxt9qC4k9TOAtQPWp3Hc3dTldw42C/pGzh8aro7rHtpRHDzQYdJgB
+w4dPQ0+RoZ2U9meiGWsy2DVOydPVxabxN9gFeeP5FRKjZP2JUAoKJRgWrBD9Fgyn
+mX/crOa8z5HTBK/LY+jBy57Bp9ZpUS9nDIpXSgdI7mZn3xvLmGfjki8WG9X8Ad99
+jvyTzD0HDcm7XoGo+Rp2Evh0pqQQf33R/OkH1WIFtcrqfwGUugTLDfIrFvDr3Qgc
+KE2Z2U7pAgMBAAECggEAXgIn8iLjgchRmpSd6/LbBh/vyoz2KxumGNqaikxXeQLX
+wHM05p3OiqA8suA5YHRrnzyJ+i5XBNC/Z4gPAJaCVEIGmU88F7qSWLVi0X7MJXBR
+kPyOlZgZB8I3RLAF3g+jc4bbSRWj1M/OFh1Ft4ENOP2cxxYinnLsQL33ZECp00Cc
+IXlX4lqjkoFbBaeCZLEV5tzZ3R/NsYZ5HTtvEh+vX7WdIqmgfL/cndfC+fIlWqbi
+kKITyfI//Ik02/07qbFaZOwCLAQccUBT/0K8v7b0rqr0XeiqN3a+lXkVY6DpFxXx
+aplsZ8rljBZ51AcAw8bS/JpwMkAQ5tYbgN2luEq3MQKBgQD/x2yk6YECbutRDsFA
+EOlZK1cwMbJSkCMgVxIrfzv0Ubj937CCzZ7StxiHCxAa3+Oj8uX3aL57ZEatudyU
+PsbZP6WWMqD3HiWUZoD1qcqRbp57FR9a3sFkgXoN9o93xdLiUS8LVAVLaqGSfO76
+o7euReXlK+hNAFmkAwFsPnVdawKBgQDQ6mWSaefUfDVddw8mPdgCtjCIKMBWTNs9
+U0ygVEsDs2FDxcC8175GQBbCNvtgh7DxWfOs847TVjH2CpZk74vSyt0Y59295Xx+
+t4Vn3CHCBxvYGIRCTOXjBRRUOxQLXjb+X6XN3y9pxhkhVdwr5m5q49JIWcNyNuAJ
+LTqq6CLl+wKBgAjaAeyDGC/ZXtNjS1TIQQsQ8Od+EMnCqzSHTt2qfYyq91fx0c31
+B7YLGBI0U85aSSp3UXYKbe0fP0Lr17JZqdAC39wezGtA49QK6BOYWKZHybxAsuEW
+LGMqB+tLyRNACVhDrvkZY0WE3yqOoEaUO9sQGDCiIFvp0zBV2krArpcZAoGAHiwM
+GVY0RireJi6AwJwj61hWsAN6q7wT2cqDAZDK+LDadkhEKsHZ2Bl/b/My4OEX+/Nq
+zuqqEPmc45Tp3Y//GKV1wxgRnVBcZ4yntrVDJtuR+Oapi03B0cS1B+k0XuPve1Nj
+BdWa6mLS1E6rKqfwAH4Aq7RTFta4Cns+wtod2CsCgYAu7gHrFJfB6C/Dl93ZXTiL
+HQdxpk0+L0hmXYaHFVK+0L2lswd7jlx6NLE3CNKEbUVr2fdhi8Qr2PLqiK/sAUCD
+yRN6z17oSZ6eUfax5wKO5yXkuKq9DAoWpLitLgQmrxV1xfBx/q8ojVnFAG17q3F+
+lN+FSz/IRCR9pAaVuVKw0w==
+-----END PRIVATE KEY-----
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index 11d3faf..a32ff44 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -61,11 +61,26 @@ hwyun:
wx:
mini:
- appId: wx3f968a09e31d6bed
- appSecret: 847bdda7c2b01e88d59948b9ba50ef8d
+ appId: wx61b63e27bddf4ea2
+ appSecret: 5ef9e1f17acd8180afe2d80199fd466e
official:
appId: wx5d04ca2de0e628a8
appSecret: 495af5bc4df1b86ffcfc21bb12daea76
+ pay:
+ #应用id(小程序id)
+ appId: wx61b63e27bddf4ea2
+ #商户号
+ merchantId: 1700326544
+ #商户API私钥
+ privateKeyPath: apiclient_key.pem
+ #商户证书序列号
+ merchantSerialNumber: 6DC8953AB741D309920DA650B92F837BE38A2757
+ #商户APIv3密钥
+ apiV3Key: fbemuj4Xql7CYlQJAoTEPYxvPSNgYT2t
+# 通知地址
+ notifyUrl: https://winning-mouse-internally.ngrok-free.app
+# notifyUrl: http://localhost:9092
+
knife4j:
diff --git a/src/main/resources/mapper/TimeIntervalMapper.xml b/src/main/resources/mapper/TimeIntervalMapper.xml
new file mode 100644
index 0000000..25ac858
--- /dev/null
+++ b/src/main/resources/mapper/TimeIntervalMapper.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/java/com/cultural/heritage/test/Animal.java b/src/test/java/com/cultural/heritage/test/Animal.java
new file mode 100644
index 0000000..61cabd4
--- /dev/null
+++ b/src/test/java/com/cultural/heritage/test/Animal.java
@@ -0,0 +1,39 @@
+package com.cultural.heritage.test;
+
+class Animal {
+ String name;
+ int age;
+
+ public Animal(String name, int age) {
+ this.name = name;
+ this.age = age;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
+
+class Bird extends Animal {
+ public Bird(String name, int age) {
+ super(name, age);
+ }
+
+ public void fly() {
+ System.out.println(name + " 能飞行");
+ }
+
+ public void showBirdInfo() {
+ System.out.println("鸟的名称: " + name);
+ }
+
+ public static void main(String[] args) {
+ Bird bird = new Bird("麻雀", 2);
+ bird.showBirdInfo();
+ bird.fly();
+ }
+}
diff --git a/src/test/java/com/cultural/heritage/test/B.java b/src/test/java/com/cultural/heritage/test/B.java
index 5907da3..4bf2a52 100644
--- a/src/test/java/com/cultural/heritage/test/B.java
+++ b/src/test/java/com/cultural/heritage/test/B.java
@@ -1,5 +1,11 @@
package com.cultural.heritage.test;
public class B {
- public Long num = 10L;
+ static {
+ System.out.println("静态块已执行");
+ }
+
+ public static void main(String[] args) {
+ new B(); // 创建对象,观察静态块是否执行
+ }
}