1. 完善首页接口,增加订单环比、同比数据

2. 公众号模板消息结构调整,增加订单待支付消息
3. 微信支付附加信息添加描述
4. 交易信息中添加微信支付API类型字段
5. 微信支付 添加native支付功能
6. 云平台对于公司订单,添加多条扫码支付功能
7. 优化代码结构
This commit is contained in:
Administrator 2025-02-14 17:01:39 +08:00
parent 4cb6391f42
commit 151220705c
67 changed files with 1609 additions and 223 deletions

View File

@ -0,0 +1,17 @@
package com.evotech.hd.common.core.dao.cloud;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.evotech.hd.common.core.entity.cloud.BatteryStationCdStrategy;
/**
* @author zrb
* @since 2025-02-10
*/
public interface BatteryStationCdStrategyDao extends BaseMapper<BatteryStationCdStrategy> {
List<BatteryStationCdStrategy> listCdStrategy(@Param("stationCode") String stationCode, @Param("status") Integer status);
}

View File

@ -0,0 +1,15 @@
package com.evotech.hd.common.core.dao.cloud;
import java.util.List;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.evotech.hd.common.core.entity.cloud.BatteryStationCdStrategyDetail;
/**
* @author zrb
* @since 2025-02-10
*/
public interface BatteryStationCdStrategyDetailDao extends BaseMapper<BatteryStationCdStrategyDetail> {
List<BatteryStationCdStrategyDetail> getDetailById(Integer id);
}

View File

@ -1,4 +1,4 @@
package com.evotech.hd.cloud.dao;
package com.evotech.hd.common.core.dao.cloud;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.evotech.hd.common.core.entity.cloud.OrderSwapBattery;

View File

@ -23,7 +23,7 @@ import lombok.Data;
* @since 2024-10-15
*/
@Data
@TableName("yt_t_battery_station")
@TableName("hd_cloud_manage.yt_t_battery_station")
@Schema(name = "BatteryStation", description = "换电站")
public class BatteryStation implements Serializable {

View File

@ -0,0 +1,74 @@
package com.evotech.hd.common.core.entity.cloud;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import org.springframework.format.annotation.DateTimeFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
/**
* @author zrb
* @since 2025-02-10
*/
@Data
@TableName("hd_cloud_manage.yt_t_battery_station_cd_strategy")
@Schema(name = "电站-充电策略")
public class BatteryStationCdStrategy implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "pk_id", type = IdType.AUTO)
@Schema(hidden = true)
private Integer pkId;
@Schema(description = "策略名称", requiredMode = RequiredMode.REQUIRED)
@NotBlank
private String name;
@Schema(description = "换电站编码", requiredMode = RequiredMode.REQUIRED)
@NotBlank
private String stationCode;
@Schema(description = "换电站名称", requiredMode = RequiredMode.REQUIRED)
@NotBlank
private String stationName;
@Schema(description = "最低数量", requiredMode = RequiredMode.REQUIRED)
@NotNull
@Min(1)
private Integer miniLimit;
@Schema(description = "状态0-未启用1-启用")
private Integer status;
@Schema(description = "创建人")
private String creater;
@Schema(description = "创建时间", hidden = true)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date ctime;
@Schema(description = "更新人", hidden = true)
private String updater;
@Schema(description = "更新时间", hidden = true)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date uptime;
@Schema(description = "详情", hidden = true)
private List<BatteryStationCdStrategyDetail> detailList;
}

View File

@ -0,0 +1,72 @@
package com.evotech.hd.common.core.entity.cloud;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serializable;
import java.util.Date;
import org.springframework.format.annotation.DateTimeFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
/**
* @author zrb
* @since 2025-02-10
*/
@Data
@TableName("hd_cloud_manage.yt_t_battery_station_cd_strategy_detail")
@Schema(name = "电站-充电策略详情")
public class BatteryStationCdStrategyDetail implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "pk_id", type = IdType.AUTO)
@Schema(hidden = true)
private Integer pkId;
@Schema(description = "换电站编码", requiredMode = RequiredMode.REQUIRED)
@NotBlank
private String stationCode;
@Schema(description = "换电站名称", requiredMode = RequiredMode.REQUIRED)
@NotBlank
private String stationName;
@Schema(description = "策略ID", requiredMode = RequiredMode.REQUIRED)
@NotNull
private Integer strategyId;
@Schema(description = "开始时间", requiredMode = RequiredMode.REQUIRED, example = "20:01:32")
@NotBlank
private String beginTime;
@Schema(description = "结束时间", requiredMode = RequiredMode.REQUIRED, example = "23:05:41")
@NotBlank
private String endTime;
@Schema(description = "充电功率")
private Double chargingPower;
@Schema(description = "创建人")
private String creater;
@Schema(description = "创建时间", hidden = true)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date ctime;
@Schema(description = "更新人", hidden = true)
private String updater;
@Schema(description = "更新时间", hidden = true)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date uptime;
}

View File

@ -23,7 +23,7 @@ import lombok.Setter;
*/
@Getter
@Setter
@TableName("yt_t_battery_station_dc")
@TableName("hd_cloud_manage.yt_t_battery_station_dc")
@Schema(name = "电站-电池")
public class BatteryStationDc implements Serializable {

View File

@ -23,7 +23,7 @@ import lombok.Setter;
*/
@Getter
@Setter
@TableName("yt_t_battery_station_dcc")
@TableName("hd_cloud_manage.yt_t_battery_station_dcc")
@Schema(name = "电站-电池仓")
public class BatteryStationDcc implements Serializable {

View File

@ -23,7 +23,7 @@ import lombok.Setter;
*/
@Getter
@Setter
@TableName("yt_t_battery_station_dj")
@TableName("hd_cloud_manage.yt_t_battery_station_dj")
@Schema(name = "电站-电机")
public class BatteryStationDj implements Serializable {

View File

@ -27,7 +27,7 @@ import lombok.Setter;
*/
@Getter
@Setter
@TableName("yt_t_battery_station_hd_fee_standard")
@TableName("hd_cloud_manage.yt_t_battery_station_hd_fee_standard")
@Schema(name = "电站-换电费用标准")
public class BatteryStationHdFeeStandard implements Serializable {

View File

@ -27,7 +27,7 @@ import lombok.Setter;
*/
@Getter
@Setter
@TableName("yt_t_battery_station_hd_fee_standard_detail")
@TableName("hd_cloud_manage.yt_t_battery_station_hd_fee_standard_detail")
@Schema(name = "电站-换电费用标准细节")
public class BatteryStationHdFeeStandardDetail implements Serializable {

View File

@ -23,7 +23,7 @@ import lombok.Setter;
*/
@Getter
@Setter
@TableName("yt_t_battery_station_robot")
@TableName("hd_cloud_manage.yt_t_battery_station_robot")
@Schema(name = "电站-机器人")
public class BatteryStationRobot implements Serializable {

View File

@ -21,7 +21,7 @@ import lombok.Data;
* @since 2024-12-06
*/
@Data
@TableName("yt_t_battery_trace")
@TableName("hd_cloud_manage.yt_t_battery_trace")
@Schema(name = "电池追溯表")
public class BatteryTrace implements Serializable {

View File

@ -23,7 +23,7 @@ import lombok.Setter;
*/
@Getter
@Setter
@TableName("yt_t_company")
@TableName("hd_cloud_manage.yt_t_company")
@Schema(name = "公司客户信息表")
public class Company implements Serializable {

View File

@ -20,7 +20,7 @@ import lombok.Setter;
*/
@Getter
@Setter
@TableName("yt_t_order_recharge")
@TableName("hd_cloud_manage.yt_t_order_recharge")
@Schema(name = "充值订单")
public class OrderRecharge implements Serializable {

View File

@ -22,7 +22,7 @@ import lombok.Data;
* @since 2024-11-22
*/
@Data
@TableName("yt_t_order_swap_battery")
@TableName("hd_cloud_manage.yt_t_order_swap_battery")
@Schema(name = "换电订单信息表")
public class OrderSwapBattery implements Serializable {

View File

@ -21,7 +21,7 @@ import lombok.Data;
* @since 2024-12-04
*/
@Data
@TableName("yt_t_order_swap_battery_pre")
@TableName("hd_cloud_manage.yt_t_order_swap_battery_pre")
@Schema(name = "换电预约订单")
public class OrderSwapBatteryPre implements Serializable {

View File

@ -18,7 +18,7 @@ import lombok.Data;
* @since 2024-12-11
*/
@Data
@TableName("yt_t_order_swap_battery_step")
@TableName("hd_cloud_manage.yt_t_order_swap_battery_step")
@Schema(name = "换电步骤记录")
public class OrderSwapBatteryStep implements Serializable {

View File

@ -18,7 +18,7 @@ import lombok.Data;
* @since 2024-11-22
*/
@Data
@TableName("yt_t_trade_detail")
@TableName("hd_cloud_manage.yt_t_trade_detail")
@Schema(name = "交易信息表")
public class TradeDetail implements Serializable {
@ -51,6 +51,12 @@ public class TradeDetail implements Serializable {
@Schema(description = "收款商户号")
private String mchid;
@Schema(description = "微信支付API类型")
private String wechatPayApiType;
@Schema(description = "订单总描述")
private String description;
@Schema(description = "交易编码")
private String outTradeNo;

View File

@ -22,7 +22,7 @@ import lombok.Data;
* @since 2024-11-22
*/
@Data
@TableName("yt_t_vehicle_info")
@TableName("hd_cloud_manage.yt_t_vehicle_info")
@Schema(name = "车辆信息表")
public class VehicleInfo implements Serializable {

View File

@ -21,7 +21,7 @@ import lombok.Data;
* @since 2024-11-22
*/
@Data
@TableName("yt_t_vehicle_wechat_user_relation")
@TableName("hd_cloud_manage.yt_t_vehicle_wechat_user_relation")
@Schema(name = "车辆和用户关系")
public class VehicleWechatUserRelation implements Serializable {

View File

@ -21,7 +21,7 @@ import lombok.Data;
* @since 2024-11-22
*/
@Data
@TableName("yt_t_wallet_account")
@TableName("hd_cloud_manage.yt_t_wallet_account")
@Schema(name = "资金钱包账户表")
public class WalletAccount implements Serializable {

View File

@ -21,7 +21,7 @@ import lombok.Data;
* @since 2024-11-22
*/
@Data
@TableName("yt_t_wallet_account_detail")
@TableName("hd_cloud_manage.yt_t_wallet_account_detail")
@Schema(name = "资金账户明细")
public class WalletAccountDetail implements Serializable {

View File

@ -26,4 +26,7 @@ public class WechatPayAttach {
@Schema(description = "钱包编码")
private String walletCode;
@Schema(description = "订单总描述")
private String description;
}

View File

@ -40,6 +40,9 @@ public class WechatPayPreOrder implements Serializable {
@Schema(description = "商户号")
private String mchid;
@Schema(description = "类型")
private String type;
@Schema(description = "商户订单号")
private String outTradeNo;

View File

@ -4,7 +4,7 @@ public enum OrderStatusEnums {
CREATE(1, "已创建"),
SWAP(2, "换电"),
SWAP(2, "换电开始"),
SWAPOVER(3, "换电完成"),

View File

@ -6,7 +6,7 @@ public enum TradeTypeEnums {
PAYORDER(2, "支付订单"),
CASHOUT(9, "提现");
REFUND(9, "提现");
Integer code;

View File

@ -0,0 +1,36 @@
package com.evotech.hd.common.core.enums;
public enum WechatPayApiTypeEnums {
JSAPI("JSAPI", "微信支付"),
NATIVE("NATIVE", "微信扫码支付"),
APP("APP", "微信APP支付"),
MICROPAY("MICROPAY", "小程序内嵌H5支付"),
MWEB("MWEB", "微信H5支付"),
FACEPAY("FACEPAY", "刷脸支付");
String code;
String name;
public String getCode() {
return code;
}
public String getName() {
return name;
}
WechatPayApiTypeEnums(String code, String name) {
this.code = code;
this.name = name;
}
}

View File

@ -7,12 +7,14 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableDiscoveryClient
@ComponentScan("com.evotech.hd.**")
@MapperScan({"com.evotech.hd.cloud.dao.**", "com.evotech.hd.common.core.dao.**"})
@EnableFeignClients
@EnableScheduling
public class CloudManageServerApplication {
public static void main(String[] args) {

View File

@ -0,0 +1,90 @@
package com.evotech.hd.cloud.controller;
import java.util.List;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.evotech.hd.cloud.service.BatteryStationCdStrategyService;
import com.evotech.hd.common.core.entity.Result;
import com.evotech.hd.common.core.entity.cloud.BatteryStationCdStrategy;
import com.evotech.hd.common.core.entity.cloud.BatteryStationCdStrategyDetail;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
@Tag(name = "充电策略")
@ApiSupport(order = 48)
@RestController
@RequestMapping("/batterystation/cd/strategy")
public class BatteryStationCdStrategyController {
@Resource
private BatteryStationCdStrategyService strategyService;
@Operation(summary = "增加")
@PostMapping("/add")
@ApiOperationSupport(order = 1)
public Result<Integer> add(@Valid @ParameterObject BatteryStationCdStrategy bscs) {
return strategyService.add(bscs);
}
@Operation(summary = "删除")
@PostMapping("/del")
@ApiOperationSupport(order = 2)
public Result<Integer> delete(Integer id) {
return strategyService.delete(id);
}
@Operation(summary = "修改")
@PostMapping({"/update"})
@ApiOperationSupport(order = 3)
public Result<Integer> update(@ParameterObject BatteryStationCdStrategy bscs) {
return strategyService.update(bscs);
}
@Operation(summary = "查询")
@GetMapping("/list")
@ApiOperationSupport(order = 4)
public Result<List<BatteryStationCdStrategy>> list(String stationCode, Integer status) {
return strategyService.list(stationCode, status);
}
@Operation(summary = "详情增加")
@PostMapping("/detail/add")
@ApiOperationSupport(order = 5)
public Result<Integer> addDetail(@Valid @ParameterObject BatteryStationCdStrategyDetail bscsd) {
return strategyService.addDetail(bscsd);
}
@Operation(summary = "详情删除")
@PostMapping("/detail/del")
@ApiOperationSupport(order = 6)
public Result<Integer> deleteDetail(Integer id) {
return strategyService.deleteDetail(id);
}
@Operation(summary = "详情修改")
@PostMapping({"/detail/update"})
@ApiOperationSupport(order = 7)
public Result<Integer> updateDetail(@ParameterObject BatteryStationCdStrategyDetail bscsd) {
return strategyService.updateDetail(bscsd);
}
@Operation(summary = "详情查询")
@GetMapping("/detail/list")
@ApiOperationSupport(order = 8)
public Result<List<BatteryStationCdStrategyDetail>> listDetail(Integer strategyId) {
return strategyService.listDetail(strategyId);
}
}

View File

@ -13,6 +13,8 @@ import com.evotech.hd.cloud.entity.vo.HomeData2;
import com.evotech.hd.cloud.entity.vo.HomeData3;
import com.evotech.hd.cloud.entity.vo.HomeData4;
import com.evotech.hd.cloud.entity.vo.HomeData5;
import com.evotech.hd.cloud.entity.vo.HomeData6;
import com.evotech.hd.cloud.entity.vo.HomeData7;
import com.evotech.hd.cloud.service.HomeService;
import com.evotech.hd.common.core.entity.Result;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
@ -66,5 +68,20 @@ public class HomeController {
public Result<List<HomeData5>> homeData5(@ParameterObject HomeDataRequest hd) {
return homeService.homeData5(hd);
}
@Operation(summary = "数据6-近6个月交易统计")
@GetMapping("/data6")
@ApiOperationSupport(order = 6)
public Result<List<HomeData6>> homeData6(@ParameterObject HomeDataRequest hd) {
return homeService.homeData6(hd);
}
@Operation(summary = "数据7-同比、环比")
@GetMapping("/data7")
@ApiOperationSupport(order = 7)
public Result<HomeData7> homeData7(Integer type) {
return homeService.homeData7(type);
}
}

View File

@ -9,7 +9,7 @@ import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(name = "首页请求参数")
@Schema(name = "首页请求参数")
@Data
public class HomeDataRequest {

View File

@ -0,0 +1,26 @@
package com.evotech.hd.cloud.entity.vo;
import lombok.Data;
/**
* copy微信的这没有引那个包
*/
@Data
public class GoodsDetail {
/** 商户侧商品编码 说明:由半角的大小写字母、数字、中划线、下划线中的一种或几种组成。 */
private String merchantGoodsId;
/** 微信侧商品编码 说明:微信支付定义的统一商品编号(没有可不传)。 */
private String wechatpayGoodsId;
/** 商品名称 说明:商品的实际名称。 */
private String goodsName;
/** 商品数量 说明:用户购买的数量。 */
private Integer quantity;
/** 商品单价 说明:商品单价,单位为分。 */
private Integer unitPrice;
}

View File

@ -0,0 +1,30 @@
package com.evotech.hd.cloud.entity.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
@Schema(name = "同比、环比")
public class HomeData7 {
@Schema(description = "年月")
private String month;
@Schema(description = "订单数量")
private Integer totalOrder;
@Schema(description = "同比订单数量")
private Integer lastMonthTotalOrder;
@Schema(description = "环比订单数量")
private Integer lastYearTotalOrder;
@Schema(description = "交易数量")
private Integer totalTrade;
@Schema(description = "同比交易数量")
private Integer lastMonthTotalTrade;
@Schema(description = "环比交易数量")
private Integer lastYearTotalTrade;
}

View File

@ -0,0 +1,61 @@
package com.evotech.hd.cloud.entity.vo;
import java.util.Date;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Data
@Schema(name = "Native下单参数")
public class NativePayVO {
@Schema(description = "用户编码", requiredMode = RequiredMode.REQUIRED)
@NotBlank
private String wuid;
@Schema(description = "订单总描述", requiredMode = RequiredMode.REQUIRED)
@NotBlank
private String description;
@Schema(description = "支付金额,单位:分", requiredMode = RequiredMode.REQUIRED)
@NotNull
@Min(1)
@Max(100000000)
private Integer total;
@Schema(description = "支付结束时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date timeExp;
@Schema(description = "换电站编码", requiredMode = RequiredMode.REQUIRED)
private String StationCode;
@Schema(description = "订单附加信息")
private String attach;
@Schema(description = "使用的优惠活动编码", hidden = true)
private String goodsTag;
@Schema(description = "商家小票ID", hidden = true)
private String invoiceId;
@Schema(description = "商家小票金额", hidden = true)
private Integer costPrice;
@Schema(description = "商品详情")
private List<GoodsDetail> goodsDetail;
@Schema(description = "用户IP", requiredMode = RequiredMode.REQUIRED)
private String payerClientIp;
@Schema(description = "用户设备型号")
private String deviceId;
}

View File

@ -20,17 +20,19 @@ public class EventMessageService {
*/
public void event(MessageTopic topic, MqttMessageHeader header, JSONObject dataBody) {
switch (EventFunctionTypesEnum.getFunctionType(header.getFunction())) {
case FUN_CHARGE_RECORD:
// TODO 写充电记录表
// TODO 回复 confirm 消息
// TODO 订单结算
break;
case FUN_SWAP_RECORD:
// TODO 写换电记录表
// TODO 回复 confirm 消息
// TODO 更新订单
break;
// // 这个事件不用了
// case FUN_CHARGE_RECORD:
// // TODO 写充电记录表
// // TODO 回复 confirm 消息
// // TODO 订单结算
//
// break;
// // 这个事件不用了
// case FUN_SWAP_RECORD:
// // TODO 写换电记录表
// // TODO 回复 confirm 消息
// // TODO 更新订单
// break;
case FUN_WARN_RECORD:
// TODO 写预警记录表
// TODO 回复 confirm 消息

View File

@ -12,7 +12,6 @@ import org.springframework.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.evotech.hd.cloud.dao.BatteryStationDcDao;
import com.evotech.hd.cloud.dao.OrderSwapBatteryDao;
import com.evotech.hd.cloud.dao.OrderSwapBatteryPreDao;
import com.evotech.hd.cloud.dao.VehicleWechatUserRelationDao;
import com.evotech.hd.cloud.mqtt.enums.MqttMessageTypeEnum;
@ -29,6 +28,7 @@ import com.evotech.hd.cloud.mqtt.message.dto.newer.req.order.OrderData;
import com.evotech.hd.cloud.service.OrderSwapBatteryService;
import com.evotech.hd.cloud.utils.CommonUtil;
import com.evotech.hd.cloud.utils.components.SwapOrderBasicFeeComponent;
import com.evotech.hd.common.core.dao.cloud.OrderSwapBatteryDao;
import com.evotech.hd.common.core.entity.cloud.BatteryStationDc;
import com.evotech.hd.common.core.entity.cloud.OrderSwapBattery;
import com.evotech.hd.common.core.entity.cloud.OrderSwapBatteryPre;

View File

@ -7,7 +7,6 @@ import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.evotech.hd.cloud.dao.OrderSwapBatteryDao;
import com.evotech.hd.cloud.dao.OrderSwapBatteryPreDao;
import com.evotech.hd.cloud.dao.OrderSwapBatteryStepDao;
import com.evotech.hd.cloud.mqtt.enums.StateFunctionTypesEnum;
@ -18,11 +17,11 @@ import com.evotech.hd.cloud.mqtt.message.dto.newer.state.OrderStatusData;
import com.evotech.hd.cloud.mqtt.message.dto.newer.state.SwapStep;
import com.evotech.hd.cloud.service.BatteryStationDcService;
import com.evotech.hd.cloud.utils.components.HDStepDictComponent;
import com.evotech.hd.common.core.dao.cloud.OrderSwapBatteryDao;
import com.evotech.hd.common.core.entity.cloud.BatteryTrace;
import com.evotech.hd.common.core.entity.cloud.OrderSwapBattery;
import com.evotech.hd.common.core.entity.cloud.OrderSwapBatteryPre;
import com.evotech.hd.common.core.entity.cloud.OrderSwapBatteryStep;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import jakarta.annotation.Resource;

View File

@ -0,0 +1,27 @@
package com.evotech.hd.cloud.service;
import java.util.List;
import com.evotech.hd.common.core.entity.Result;
import com.evotech.hd.common.core.entity.cloud.BatteryStationCdStrategy;
import com.evotech.hd.common.core.entity.cloud.BatteryStationCdStrategyDetail;
public interface BatteryStationCdStrategyService {
public Result<Integer> add(BatteryStationCdStrategy bscs);
public Result<Integer> delete(Integer id);
public Result<Integer> update(BatteryStationCdStrategy bscs);
public Result<List<BatteryStationCdStrategy>> list(String stationCode, Integer status);
public Result<Integer> addDetail(BatteryStationCdStrategyDetail bscsd);
public Result<Integer> deleteDetail(Integer id);
public Result<Integer> updateDetail(BatteryStationCdStrategyDetail bscsd);
public Result<List<BatteryStationCdStrategyDetail>> listDetail(Integer strategyId);
}

View File

@ -8,6 +8,8 @@ import com.evotech.hd.cloud.entity.vo.HomeData2;
import com.evotech.hd.cloud.entity.vo.HomeData3;
import com.evotech.hd.cloud.entity.vo.HomeData4;
import com.evotech.hd.cloud.entity.vo.HomeData5;
import com.evotech.hd.cloud.entity.vo.HomeData6;
import com.evotech.hd.cloud.entity.vo.HomeData7;
import com.evotech.hd.common.core.entity.Result;
public interface HomeService {
@ -21,5 +23,9 @@ public interface HomeService {
public Result<HomeData4> homeData4(HomeDataRequest hd);
public Result<List<HomeData5>> homeData5(HomeDataRequest hd);
public Result<List<HomeData6>> homeData6(HomeDataRequest hd);
public Result<HomeData7> homeData7(Integer type);
}

View File

@ -28,6 +28,8 @@ public interface OrderSwapBatteryService {
public Result<String> calculateCost(String orderNo);
public Result<String> calculateCost(OrderSwapBattery osb);
public Result<String> walletPay(String orderNo, String wuid, String uname);
}

View File

@ -0,0 +1,109 @@
package com.evotech.hd.cloud.service.impl;
import java.util.Date;
import java.util.List;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.evotech.hd.cloud.service.BatteryStationCdStrategyService;
import com.evotech.hd.common.core.dao.cloud.BatteryStationCdStrategyDao;
import com.evotech.hd.common.core.dao.cloud.BatteryStationCdStrategyDetailDao;
import com.evotech.hd.common.core.entity.Result;
import com.evotech.hd.common.core.entity.cloud.BatteryStationCdStrategy;
import com.evotech.hd.common.core.entity.cloud.BatteryStationCdStrategyDetail;
import com.evotech.hd.common.core.enums.CodeMsg;
import jakarta.annotation.Resource;
@Service
public class BatteryStationCdStrategyServiceImpl implements BatteryStationCdStrategyService {
@Resource
private BatteryStationCdStrategyDao strategyDao;
@Resource
private BatteryStationCdStrategyDetailDao strategyDetailDao;
@Override
public Result<Integer> add(BatteryStationCdStrategy bscs) {
bscs.setCtime(new Date());
int n = strategyDao.insert(bscs);
if (n == 1) {
return new Result<Integer>().success(n);
}
return new Result<Integer>().error("添加充电策略出错!");
}
@Override
@Transactional
public Result<Integer> delete(Integer id) {
int n = strategyDao.deleteById(id);
if (n == 1) {
strategyDetailDao.delete(new QueryWrapper<BatteryStationCdStrategyDetail>().eq("strategy_id", id));
return new Result<Integer>().success(n);
}
return new Result<Integer>().error("删除充电策略出错!");
}
@Override
public Result<Integer> update(BatteryStationCdStrategy bscs) {
int n = strategyDao.updateById(bscs);
if (n == 1) {
return new Result<Integer>().success(n);
}
return new Result<Integer>().error("更新充电策略失败!");
}
@Override
public Result<List<BatteryStationCdStrategy>> list(String stationCode, Integer status) {
List<BatteryStationCdStrategy> list = strategyDao.listCdStrategy(stationCode, status);
if (list.isEmpty()) {
return new Result<List<BatteryStationCdStrategy>>().error(CodeMsg.DATABASE_RESULT_NULL);
}
return new Result<List<BatteryStationCdStrategy>>().success(list);
}
@Override
public Result<Integer> addDetail(BatteryStationCdStrategyDetail bscsd) {
bscsd.setCtime(new Date());
int n = strategyDetailDao.insert(bscsd);
if (n == 1) {
return new Result<Integer>().success(n);
}
return new Result<Integer>().error("添加充电策略详情出错!");
}
@Override
public Result<Integer> deleteDetail(Integer id) {
int n = strategyDetailDao.deleteById(id);
if (n == 1) {
return new Result<Integer>().success(n);
}
return new Result<Integer>().error("删除充电策略详情出错!");
}
@Override
public Result<Integer> updateDetail(BatteryStationCdStrategyDetail bscsd) {
int n = strategyDetailDao.updateById(bscsd);
if (n == 1) {
return new Result<Integer>().success(n);
}
return new Result<Integer>().error("更新充电策略详情失败!");
}
@Override
public Result<List<BatteryStationCdStrategyDetail>> listDetail(Integer strategyId) {
List<BatteryStationCdStrategyDetail> list = strategyDetailDao.selectList(new QueryWrapper<BatteryStationCdStrategyDetail>()
.eq(strategyId != null, "strategy_id", strategyId));
if (list.isEmpty()) {
return new Result<List<BatteryStationCdStrategyDetail>>().error(CodeMsg.DATABASE_RESULT_NULL);
}
return new Result<List<BatteryStationCdStrategyDetail>>().success(list);
}
}

View File

@ -14,7 +14,6 @@ import com.evotech.hd.cloud.dao.BatteryStationDao;
import com.evotech.hd.cloud.dao.BatteryStationDcDao;
import com.evotech.hd.cloud.dao.BatteryStationRobotDao;
import com.evotech.hd.cloud.dao.CompanyDao;
import com.evotech.hd.cloud.dao.OrderSwapBatteryDao;
import com.evotech.hd.cloud.dao.TradeDetailDao;
import com.evotech.hd.cloud.dao.VehicleInfoDao;
import com.evotech.hd.cloud.entity.request.HomeDataRequest;
@ -23,7 +22,10 @@ import com.evotech.hd.cloud.entity.vo.HomeData2;
import com.evotech.hd.cloud.entity.vo.HomeData3;
import com.evotech.hd.cloud.entity.vo.HomeData4;
import com.evotech.hd.cloud.entity.vo.HomeData5;
import com.evotech.hd.cloud.entity.vo.HomeData6;
import com.evotech.hd.cloud.entity.vo.HomeData7;
import com.evotech.hd.cloud.service.HomeService;
import com.evotech.hd.common.core.dao.cloud.OrderSwapBatteryDao;
import com.evotech.hd.common.core.dao.resource.ProxyOperaterDao;
import com.evotech.hd.common.core.dao.wechat.WechatUserDao;
import com.evotech.hd.common.core.entity.Result;
@ -36,7 +38,10 @@ import com.evotech.hd.common.core.entity.cloud.TradeDetail;
import com.evotech.hd.common.core.entity.cloud.VehicleInfo;
import com.evotech.hd.common.core.entity.resource.ProxyOperater;
import com.evotech.hd.common.core.entity.wechat.WechatUser;
import com.evotech.hd.common.core.enums.OrderStatusEnums;
import com.evotech.hd.common.core.enums.PayTypeEnums;
import com.evotech.hd.common.core.enums.TradeResultEnums;
import com.evotech.hd.common.core.enums.TradeTypeEnums;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
@ -205,4 +210,90 @@ public class HomeServiceImpl implements HomeService {
return new Result<List<HomeData5>>().success(list);
}
@Override
public Result<List<HomeData6>> homeData6(HomeDataRequest hd) {
List<HomeData6> list = new ArrayList<HomeData6>();
// 1. 找出6个月
String[] monthArr = new String[7];
Date d = new Date();
monthArr[0] = DateUtil.format(d, DatePattern.SIMPLE_MONTH_FORMATTER);
for (int i = 1; i < monthArr.length; i++) {
monthArr[i] = DateUtil.format(DateUtil.offsetMonth(d, -i), DatePattern.SIMPLE_MONTH_FORMATTER);
}
Date beginTime = DateUtil.beginOfMonth(DateUtil.offsetMonth(d, -6));
List<TradeDetail> tradeList = tradeDetailDao.selectList(new QueryWrapper<TradeDetail>()
.eq("del_flag", 0)
.ge("pay_time", beginTime));
// 成功交易
List<TradeDetail> successList = tradeList.stream().filter(i -> TradeResultEnums.SUCCESS.getName().equals(i.getPayResult())).toList();
// 收入
Map<Object, Integer> map1 = successList.parallelStream().filter(i -> i.getTradeType() == TradeTypeEnums.RECHARGE.getCode()
||
(i.getTradeType() == TradeTypeEnums.PAYORDER.getCode() && i.getPayType() != PayTypeEnums.WALLET.getCode())
)
.collect(Collectors.groupingBy(i -> DateUtil.format(i.getPayTime(), DatePattern.SIMPLE_MONTH_FORMATTER),
Collectors.reducing(0, TradeDetail::getTradeAmount, Integer::sum)));
// 退款
Map<Object, Integer> map2 = successList.parallelStream().filter(i -> i.getTradeType() == TradeTypeEnums.REFUND.getCode())
.collect(Collectors.groupingBy(i -> DateUtil.format(i.getPayTime(), DatePattern.SIMPLE_MONTH_FORMATTER),
Collectors.reducing(0, TradeDetail::getTradeAmount, Integer::sum)));
for (int i = 0; i < monthArr.length; i++) {
HomeData6 data = new HomeData6();
data.setMonth(monthArr[i]);
data.setTotalMoney(map1.get(monthArr[i]) == null ? 0 : map1.get(monthArr[i]));
data.setTotalRefund(map2.get(monthArr[i]) == null ? 0 : map2.get(monthArr[i]));
list.add(data);
}
return new Result<List<HomeData6>>().success(list);
}
@Override
public Result<HomeData7> homeData7(Integer type) {
HomeData7 data = new HomeData7();
Date d = new Date();
// 按月
if (type == 1) {
Date beginOfMonth = DateUtil.beginOfMonth(d);
Date lastBeginOfMonth = DateUtil.offsetMonth(beginOfMonth, -1);
data.setMonth(DateUtil.format(lastBeginOfMonth, DatePattern.SIMPLE_MONTH_FORMATTER));
Date last2BeginOfMonth = DateUtil.offsetMonth(lastBeginOfMonth, -1);
// 订单
Long monthCount = orderSwapBatteryDao.selectCount(new QueryWrapper<OrderSwapBattery>()
.ne("status", OrderStatusEnums.CANCLE.getCode())
.ge("order_time", lastBeginOfMonth)
.lt("order_time", beginOfMonth));
Long lastMonthCount = orderSwapBatteryDao.selectCount(new QueryWrapper<OrderSwapBattery>()
.ne("status", OrderStatusEnums.CANCLE.getCode())
.ge("order_time", last2BeginOfMonth)
.lt("order_time", lastBeginOfMonth));
Long lastYearCount = orderSwapBatteryDao.selectCount(new QueryWrapper<OrderSwapBattery>()
.ne("status", OrderStatusEnums.CANCLE.getCode())
.ge("order_time", DateUtil.offsetYear(lastBeginOfMonth, -1))
.lt("order_time", DateUtil.offsetYear(beginOfMonth, -1)));
data.setTotalOrder(monthCount.intValue());
data.setLastMonthTotalOrder(lastMonthCount.intValue());
data.setLastYearTotalOrder(lastYearCount.intValue());
return new Result<HomeData7>().success(data);
}
// 按年
Date beginOfYear = DateUtil.beginOfYear(d);
Date lastBeginOfYear = DateUtil.offsetYear(beginOfYear, -1);
data.setMonth(DateUtil.year(lastBeginOfYear) + "");
Date last2BeginOfYear = DateUtil.offsetYear(lastBeginOfYear, -1);
Long yearCount = orderSwapBatteryDao.selectCount(new QueryWrapper<OrderSwapBattery>()
.ne("status", OrderStatusEnums.CANCLE.getCode())
.ge("order_time", lastBeginOfYear)
.lt("order_time", beginOfYear));
Long lastYearCount = orderSwapBatteryDao.selectCount(new QueryWrapper<OrderSwapBattery>()
.ne("status", OrderStatusEnums.CANCLE.getCode())
.ge("order_time", last2BeginOfYear)
.lt("order_time", lastBeginOfYear));
data.setTotalOrder(yearCount.intValue());
data.setLastYearTotalOrder(lastYearCount.intValue());
return new Result<HomeData7>().success(data);
}
}

View File

@ -13,7 +13,6 @@ import org.springframework.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.evotech.hd.cloud.dao.OrderSwapBatteryDao;
import com.evotech.hd.cloud.dao.OrderSwapBatteryPreDao;
import com.evotech.hd.cloud.dao.OrderSwapBatteryStepDao;
import com.evotech.hd.cloud.dao.VehicleInfoDao;
@ -23,6 +22,7 @@ import com.evotech.hd.cloud.service.TradeService;
import com.evotech.hd.cloud.service.WalletAccountService;
import com.evotech.hd.cloud.service.newthread.GZHTemplateMessageService;
import com.evotech.hd.cloud.utils.components.SwapOrderBasicFeeComponent;
import com.evotech.hd.common.core.dao.cloud.OrderSwapBatteryDao;
import com.evotech.hd.common.core.dao.wechat.WechatUserDao;
import com.evotech.hd.common.core.entity.Result;
import com.evotech.hd.common.core.entity.cloud.OrderSwapBattery;
@ -108,6 +108,7 @@ public class OrderSwapBatteryServiceImpl implements OrderSwapBatteryService {
OrderSwapBatteryPre osbp = new OrderSwapBatteryPre();
osbp.setPkId(id);
osbp.setStatus(status != null? status : 3);
osbp.setUptime(null);
int n = orderSwapBatteryPreDao.updateById(osbp);
if (n == 1) {
return new Result<Integer>().success(n);
@ -153,6 +154,7 @@ public class OrderSwapBatteryServiceImpl implements OrderSwapBatteryService {
@Override
public Result<Integer> update(OrderSwapBattery osb) {
osb.setUptime(null);
int n = orderSwapBatteryDao.updateById(osb);
if (n == 1) {
return new Result<Integer>().success(n);
@ -212,6 +214,30 @@ public class OrderSwapBatteryServiceImpl implements OrderSwapBatteryService {
if (order.getStatus() != 5) {
return new Result<String>().error("订单状态异常!");
}
return calculateCost(order);
// // 2. 检查数据
// if (order.getBasicFee() == null || order.getServiceFee() == null) {
// order = orderBasicFeeComponent.orderBasicFee(order);
// if (order.getBasicFee() == null || order.getServiceFee() == null) {
// return new Result<String>().error("订单费用标准异常!");
// }
// }
// // 3. 选择费用计算方式 计算费用
// // 先按电量计算
// if (order.getElectAmount() == null) {
// return new Result<String>().error("充电订单 充电量 异常!");
// }
// BigDecimal fee = order.getServiceFee().add(order.getBasicFee().multiply(order.getElectAmount())).setScale(0, RoundingMode.HALF_UP);
// // 4. 修改订单
// order.setAmount(fee.intValue());
// order.setStatus(6);
// orderSwapBatteryDao.updateById(order);
// return new Result<String>().success(fee);
}
@Override
public Result<String> calculateCost(OrderSwapBattery order) {
// 2. 检查数据
if (order.getBasicFee() == null || order.getServiceFee() == null) {
order = orderBasicFeeComponent.orderBasicFee(order);
@ -228,10 +254,12 @@ public class OrderSwapBatteryServiceImpl implements OrderSwapBatteryService {
// 4. 修改订单
order.setAmount(fee.intValue());
order.setStatus(6);
order.setUptime(null);
orderSwapBatteryDao.updateById(order);
return new Result<String>().success(fee);
}
@Override
@Transactional
public Result<String> walletPay(String orderNo, String wuid, String uname) {
@ -292,11 +320,13 @@ public class OrderSwapBatteryServiceImpl implements OrderSwapBatteryService {
// 改余额
wallet.setTotalAmount(wad.getAfterTotalAmount());
wallet.setRechargeAmount(wad.getAfterRechargeAmount());
wallet.setUptime(null);
walletAccountDao.updateById(wallet);
// 修改订单状态
order.setStatus(OrderStatusEnums.FINISH.getCode());
order.setTradeNo(trade.getOutTradeNo());
order.setUptime(null);
orderSwapBatteryDao.updateById(order);
return new Result<String>().success("OK");
}

View File

@ -9,21 +9,13 @@ import org.springframework.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.evotech.hd.cloud.dao.OrderSwapBatteryDao;
import com.evotech.hd.cloud.dao.TradeDetailDao;
import com.evotech.hd.cloud.dao.WalletAccountDao;
import com.evotech.hd.cloud.dao.WalletAccountDetailDao;
import com.evotech.hd.cloud.entity.request.PageListTradeRequest;
import com.evotech.hd.cloud.service.TradeService;
import com.evotech.hd.cloud.service.newthread.GZHTemplateMessageService;
import com.evotech.hd.cloud.service.newthread.WechatPayNotifyHandleService;
import com.evotech.hd.common.core.entity.Result;
import com.evotech.hd.common.core.entity.cloud.OrderSwapBattery;
import com.evotech.hd.common.core.entity.cloud.TradeDetail;
import com.evotech.hd.common.core.entity.cloud.WalletAccount;
import com.evotech.hd.common.core.entity.cloud.WalletAccountDetail;
import com.evotech.hd.common.core.enums.CodeMsg;
import com.evotech.hd.common.core.enums.OrderStatusEnums;
import com.evotech.hd.common.core.enums.TradeResultEnums;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
@ -34,13 +26,8 @@ public class TradeServiceImpl implements TradeService {
@Resource
private TradeDetailDao tradeDetailDao;
@Resource
private OrderSwapBatteryDao orderSwapBatteryDao;
@Resource
private GZHTemplateMessageService templateMessageService;
@Resource
private WalletAccountDao walletAccountDao;
@Resource
private WalletAccountDetailDao walletAccountDetailDao;
private WechatPayNotifyHandleService payNotifyHandleService;
@Override
public Result<Integer> add(TradeDetail td) {
@ -105,65 +92,13 @@ public class TradeServiceImpl implements TradeService {
}
// 添加交易
add(tradeDetail);
// 2. 业务类型
if (tradeDetail.getTradeType() == 1) {
// 充值
WalletAccount wallet = walletAccountDao.selectOne(new QueryWrapper<WalletAccount>().eq("code", tradeDetail.getWallet()));
if (wallet == null) {
return null;
}
// 添加明细
WalletAccountDetail wad = new WalletAccountDetail();
// TODO 写一个算法计算充值的减多少赠送的减多少总金额减多少
wad.setTradeRechargeAmount(tradeDetail.getTradeAmount());
wad.setTradeGiftAmount(0);
wad.setTradeTotalAmount(wad.getTradeRechargeAmount() + wad.getTradeGiftAmount());
wad.setPreTotalAmount(wallet.getTotalAmount());
wad.setPreRechargeAmount(wallet.getRechargeAmount());
wad.setPreGiftAmount(wallet.getGiftAmount());
wad.setAfterRechargeAmount(wad.getPreRechargeAmount() + Math.abs(wad.getTradeRechargeAmount()));
wad.setAfterTotalAmount(wad.getPreTotalAmount() + Math.abs(wad.getTradeTotalAmount()));
wad.setAfterGiftAmount(wad.getPreGiftAmount() + Math.abs(wad.getTradeGiftAmount()));
wad.setTradeGiftAmount(0);
wad.setCode(tradeDetail.getWallet());
wad.setTradeType(tradeDetail.getTradeType());
wad.setTradeNo(tradeDetail.getOutTradeNo());
walletAccountDetailDao.insert(wad);
// 改余额
wallet.setTotalAmount(wad.getAfterTotalAmount());
wallet.setRechargeAmount(wad.getAfterRechargeAmount());
wallet.setGiftAmount(wad.getAfterGiftAmount());
walletAccountDao.updateById(wallet);
// 发送公众号消息
templateMessageService.rechargeMessageSend(tradeDetail, wallet.getTotalAmount());
} else if (tradeDetail.getTradeType() == 2) {
// 支付订单
OrderSwapBattery one = orderSwapBatteryDao.selectOne(new QueryWrapper<OrderSwapBattery>().eq("order_no", tradeDetail.getOrderNo()));
if (one.getStatus() == 6) {
if (TradeResultEnums.SUCCESS.getName().equals(tradeDetail.getPayResult())) {
// 支付成功修改订单
OrderSwapBattery osb = new OrderSwapBattery();
osb.setStatus(OrderStatusEnums.FINISH.getCode());
osb.setTradeNo(tradeDetail.getOutTradeNo());
orderSwapBatteryDao.update(osb, new QueryWrapper<OrderSwapBattery>().eq("order_no", tradeDetail.getOrderNo()));
// 发送公众号消息
templateMessageService.orderMessageSend(one, 3);
}
} else {
log.info("\r\n===>>>支付订单存在问题:" + tradeDetail);
}
} else {
}
// 2. 业务类型处理
payNotifyHandleService.payNotifyBussinessHandle(tradeDetail);
return new Result<String>().success("OK");
}
}

View File

@ -27,6 +27,11 @@ public class GZHTemplateMessageService {
wechatService.orderMessage(osb, type);
}
@Async("taskExecutor")
public void orderMessageSend2(Integer id, Integer type) {
wechatService.orderMessage2(id, type);
}
@Async("taskExecutor")
public void rechargeMessageSend(TradeDetail trade, Integer money) {
wechatService.rechargeMessage(trade, money);

View File

@ -0,0 +1,147 @@
package com.evotech.hd.cloud.service.newthread;
import java.util.Arrays;
import java.util.List;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.evotech.hd.cloud.dao.WalletAccountDao;
import com.evotech.hd.cloud.dao.WalletAccountDetailDao;
import com.evotech.hd.common.core.dao.cloud.OrderSwapBatteryDao;
import com.evotech.hd.common.core.entity.cloud.OrderSwapBattery;
import com.evotech.hd.common.core.entity.cloud.TradeDetail;
import com.evotech.hd.common.core.entity.cloud.WalletAccount;
import com.evotech.hd.common.core.entity.cloud.WalletAccountDetail;
import com.evotech.hd.common.core.enums.OrderStatusEnums;
import com.evotech.hd.common.core.enums.TradeResultEnums;
import com.evotech.hd.common.core.enums.WechatPayApiTypeEnums;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
@Service
@Slf4j
public class WechatPayNotifyHandleService {
@Resource
private WalletAccountDao walletAccountDao;
@Resource
private WalletAccountDetailDao walletAccountDetailDao;
@Resource
private GZHTemplateMessageService templateMessageService;
@Resource
private OrderSwapBatteryDao orderSwapBatteryDao;
// @Async("taskExecutor")
public void payNotifyBussinessHandle(TradeDetail tradeDetail) {
if (tradeDetail.getTradeType() == 1) {
// 充值
WalletAccount wallet = walletAccountDao.selectOne(new QueryWrapper<WalletAccount>().eq("code", tradeDetail.getWallet()));
if (wallet == null) {
return;
}
// 添加明细
WalletAccountDetail wad = new WalletAccountDetail();
// TODO 写一个算法计算充值的减多少赠送的减多少总金额减多少
wad.setTradeRechargeAmount(tradeDetail.getTradeAmount());
wad.setTradeGiftAmount(0);
wad.setTradeTotalAmount(wad.getTradeRechargeAmount() + wad.getTradeGiftAmount());
wad.setPreTotalAmount(wallet.getTotalAmount());
wad.setPreRechargeAmount(wallet.getRechargeAmount());
wad.setPreGiftAmount(wallet.getGiftAmount());
wad.setAfterRechargeAmount(wad.getPreRechargeAmount() + Math.abs(wad.getTradeRechargeAmount()));
wad.setAfterTotalAmount(wad.getPreTotalAmount() + Math.abs(wad.getTradeTotalAmount()));
wad.setAfterGiftAmount(wad.getPreGiftAmount() + Math.abs(wad.getTradeGiftAmount()));
wad.setTradeGiftAmount(0);
wad.setCode(tradeDetail.getWallet());
wad.setTradeType(tradeDetail.getTradeType());
wad.setTradeNo(tradeDetail.getOutTradeNo());
walletAccountDetailDao.insert(wad);
// 改余额
wallet.setTotalAmount(wad.getAfterTotalAmount());
wallet.setRechargeAmount(wad.getAfterRechargeAmount());
wallet.setGiftAmount(wad.getAfterGiftAmount());
walletAccountDao.updateById(wallet);
// 发送公众号消息
templateMessageService.rechargeMessageSend(tradeDetail, wallet.getTotalAmount());
} else if (tradeDetail.getTradeType() == 2) {
// 支付订单
if (WechatPayApiTypeEnums.JSAPI.getCode().equals(tradeDetail.getWechatPayApiType())) {
// jsapi支付
jsapiPayHandle(tradeDetail);
}
if (WechatPayApiTypeEnums.NATIVE.getCode().equals(tradeDetail.getWechatPayApiType())) {
// native支付企业
nativePayHandle(tradeDetail);
}
} else {
}
}
/**
* 一般个人单条付款
* @param tradeDetail
*/
private void jsapiPayHandle(TradeDetail tradeDetail) {
OrderSwapBattery one = orderSwapBatteryDao.selectOne(new QueryWrapper<OrderSwapBattery>().eq("order_no", tradeDetail.getOrderNo()));
if (one.getStatus() == 6) {
if (TradeResultEnums.SUCCESS.getName().equals(tradeDetail.getPayResult())) {
// 支付成功修改订单
afterPayAlterOrder(tradeDetail, one);
// 发送公众号消息
templateMessageService.orderMessageSend(one, 3);
}
} else {
log.info("\r\n===>>>支付订单存在问题:" + tradeDetail);
}
}
/**
* 一般企业多条付款
* @param tradeDetail
*/
private void nativePayHandle(TradeDetail tradeDetail) {
List<String> orderNoList = Arrays.asList(tradeDetail.getOrderNo().split(","));
List<OrderSwapBattery> orderList = orderSwapBatteryDao.selectList(new QueryWrapper<OrderSwapBattery>()
.eq("status", 6).in("order_no", orderNoList));
if (orderList.size() != orderNoList.size()) {
log.info("\r\n **********");
log.error("\r\n===>>>交易订单存在问题:" + tradeDetail);
log.info("\r\n **********");
}
List<Integer> idList = orderList.stream().map(i -> i.getPkId()).toList();
orderSwapBatteryDao.update(new UpdateWrapper<OrderSwapBattery>().in("pk_id", idList)
.set("status", OrderStatusEnums.FINISH.getCode())
.set("trade_no", tradeDetail.getOutTradeNo()));
// 发送公众号消息发给企业绑定的微信号
// templateMessageService.orderMessageSend(one, 3);
}
/**
* 支付成功后修改订单状态
* @param tradeDetail
* @param one
*/
private void afterPayAlterOrder(TradeDetail tradeDetail, OrderSwapBattery one) {
OrderSwapBattery osb = new OrderSwapBattery();
osb.setPkId(one.getPkId());
osb.setStatus(OrderStatusEnums.FINISH.getCode());
osb.setTradeNo(tradeDetail.getOutTradeNo());
orderSwapBatteryDao.updateById(osb);
}
}

View File

@ -32,6 +32,10 @@ public interface WechatService {
consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
public Result<String> orderMessage(@ParameterObject OrderSwapBattery osb, @RequestParam Integer templateType);
@PostMapping(value = "/wechat/gzh/msg/send/order2",
consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
public Result<String> orderMessage2(@RequestParam Integer id, @RequestParam Integer templateType);
@PostMapping(value = "/wechat/gzh/msg/send/recharge",
consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
public Result<String> rechargeMessage(@ParameterObject TradeDetail trade, @RequestParam Integer money);

View File

@ -0,0 +1,66 @@
package com.evotech.hd.cloud.task;
import java.util.List;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.evotech.hd.cloud.service.OrderSwapBatteryService;
import com.evotech.hd.cloud.service.newthread.GZHTemplateMessageService;
import com.evotech.hd.common.core.dao.cloud.OrderSwapBatteryDao;
import com.evotech.hd.common.core.entity.Result;
import com.evotech.hd.common.core.entity.cloud.OrderSwapBattery;
import com.evotech.hd.common.core.enums.CodeMsg;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
@Component
@Slf4j
public class OrderCostCalculateTask {
@Resource
private OrderSwapBatteryDao orderSwapBatteryDao;
@Resource
private OrderSwapBatteryService orderSwapBatteryService;
@Resource
private GZHTemplateMessageService gzhTemplateMessageService;
@Scheduled(cron ="0 0 11,14,16,18,20 * * ?")
public void calculateOrder() {
log.info("\r\n===>>>开始查找订单计算费用");
// 查询状态为5的订单
Boolean flag = true;
int n = 0;
while (flag) {
List<OrderSwapBattery> list = orderSwapBatteryDao.selectList(new QueryWrapper<OrderSwapBattery>()
.eq("status", 5).ne("del_flag", 1).last("limit 20"));
if (!list.isEmpty()) {
n = orderCalculate(n, list);
} else {
flag = false;
}
}
log.info("\r\n===>>>订单计算费用完成:{} 条数据", n);
}
private int orderCalculate(int n, List<OrderSwapBattery> list) {
for (int i = 0; i < list.size(); i++) {
Result<String> res = orderSwapBatteryService.calculateCost(list.get(i));
if ( CodeMsg.SUCCESS.getCode().equals(res.getCode())) {
n += 1;
// 发送微信消息
gzhTemplateMessageService.orderMessageSend2(list.get(i).getPkId(), 2);
}
}
return n;
}
}

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.evotech.hd.common.core.dao.cloud.BatteryStationCdStrategyDetailDao">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.evotech.hd.common.core.entity.cloud.BatteryStationCdStrategyDetail">
<id column="pk_id" property="pkId" />
<result column="station_code" property="stationCode" />
<result column="station_name" property="stationName" />
<result column="strategy_id" property="strategyId" />
<result column="begin_time" property="beginTime" />
<result column="end_time" property="endTime" />
<result column="charging_power" property="chargingPower" />
<result column="ctime" property="ctime" />
<result column="creater" property="creater" />
<result column="uptime" property="uptime" />
<result column="updater" property="updater" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
pk_id, station_code, station_name, strategy_id, begin_time, end_time, charging_power, ctime, creater, uptime, updater
</sql>
<select id="getDetailById" resultMap="BaseResultMap">
SELECT
*
FROM
yt_t_battery_station_cd_strategy_detail
WHERE
strategy_id = #{id}
</select>
</mapper>

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.evotech.hd.common.core.dao.cloud.BatteryStationCdStrategyDao">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.evotech.hd.common.core.entity.cloud.BatteryStationCdStrategy">
<id column="pk_id" property="pkId" />
<result column="station_code" property="stationCode" />
<result column="station_name" property="stationName" />
<result column="mini_limit" property="miniLimit" />
<result column="status" property="status" />
<result column="ctime" property="ctime" />
<result column="creater" property="creater" />
<result column="uptime" property="uptime" />
<result column="updater" property="updater" />
<collection property="detailList"
select="com.evotech.hd.common.core.dao.cloud.BatteryStationCdStrategyDetailDao.getDetailById"
column="pk_id">
</collection>
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
pk_id, station_code, station_name, mini_limit, status, ctime, creater, uptime, updater
</sql>
<select id="listCdStrategy" resultMap="BaseResultMap">
select
a.*
From
yt_t_battery_station_cd_strategy a
where
1 = 1
<if test="stationCode != null and stationCode != '' ">
and a.station_code = #{stationCode}
</if>
<if test="status != null and status != '' ">
and a.status = #{status}
</if>
order by a.pk_id desc
</select>
</mapper>

View File

@ -55,13 +55,13 @@ public class AuthorizationManager implements ReactiveAuthorizationManager<Author
return Mono.just(new AuthorizationDecision(true));
}
ServerHttpRequest request = authorizationContext.getExchange().getRequest();
String uri = request.getURI().toString();
System.out.println("&&&&&&>" + uri);
// 1. 对应跨域的预检请求直接放行
if (request.getMethod() == HttpMethod.OPTIONS) {
return Mono.just(new AuthorizationDecision(true));
}
String uri = request.getURI().toString();
System.out.println("===>>>" + uri);
// 2. 微信服务token验证
if (uri.contains("/gateway/wechat/")) {
// 提到另一个类了应该走不到这了
@ -146,7 +146,6 @@ public class AuthorizationManager implements ReactiveAuthorizationManager<Author
*/
private boolean checkAuthorities(String token, ServerHttpRequest request, Authentication auth) {
String uri = request.getURI().toString();
// 0. Redis中含有JTI才可用
String jti = TokenUtil.getJti(token);
if (!redisUtil.hasKey(HDConstant.LOGIN_CACHE_KEY_PREFIX + jti + ":token") ) {

View File

@ -26,6 +26,8 @@ public class XcxProperties {
private String notifyUrl;
private String nativeNotifyUrl;
private String refundNotifyUrl;
private String publicKeyId;

View File

@ -0,0 +1,92 @@
package com.evotech.hd.wechat.controller;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.evotech.hd.common.core.entity.Result;
import com.evotech.hd.wechat.entity.NativePayVO;
import com.evotech.hd.wechat.service.WechatNativePayService;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
@Tag(name = "微信Native支付")
@RestController
@RequestMapping("/wechatpay/native")
@ApiSupport(order = 18)
public class WechatNativePayController {
@Resource
private WechatNativePayService nativePayService;
@Operation(summary = "Native预支付订单")
@PostMapping("/prepay")
@ApiOperationSupport(order = 1)
public Result<String> nativePrepay(@RequestBody NativePayVO prePay) {
return nativePayService.nativePrepay(prePay);
}
@Operation(summary = "支付回调地址")
@PostMapping("/nativeback/msg")
@ApiOperationSupport(order = 2)
@Hidden
public ResponseEntity<String> nativeBack(HttpServletRequest request) {
return nativePayService.nativeBack(request);
}
@Operation(summary = "支付订单查询状态")
@GetMapping("/order/query")
@ApiOperationSupport(order = 3)
public Result<String> orderQuery(Integer type, @RequestParam(required = false)String transactionId, @RequestParam(required = false)String outTradeNo) {
return nativePayService.orderQuery(type, transactionId, outTradeNo);
}
// @Operation(summary = "退款")
// @PostMapping("/refunds")
// @ApiOperationSupport(order = 4)
// public Result<String> refunds(String outTradeNo, String transactionId, String reason, Integer money, Integer total) {
// return wechatPayService.refunds(outTradeNo, transactionId, reason, money, total);
// }
//
//
// @Operation(summary = "退款回调地址")
// @PostMapping("/refundsback/msg")
// @ApiOperationSupport(order = 5)
// @Hidden
// public ResponseEntity<String> refundsBack(HttpServletRequest request) {
// return wechatPayService.refundsBack(request);
//
// }
//
//
// @Operation(summary = "单笔退款查询")
// @GetMapping("/refunds/query")
// @ApiOperationSupport(order = 6)
// public Result<String> refundsQuery(String outRefundNo) {
// return wechatPayService.refundsQuery(outRefundNo);
// }
//
//
// @Operation(summary = "单日交易账单进3月内")
// @PostMapping("/daytradebill")
// @ApiOperationSupport(order = 7)
// public Result<String> dayTradebill(@RequestParam @NotBlank String day) {
// return wechatPayService.dayTradebill(day);
// }
}

View File

@ -51,7 +51,7 @@ public class WechatPayController {
@Operation(summary = "支付订单查询状态")
@GetMapping("/order/query")
@ApiOperationSupport(order = 3)
public Result<String> orderQuery(Integer type, String transactionId, String outTradeNo) {
public Result<String> orderQuery(Integer type, @RequestParam(required = false) String transactionId, @RequestParam(required = false)String outTradeNo) {
return wechatPayService.orderQuery(type, transactionId, outTradeNo);
}

View File

@ -45,6 +45,13 @@ public class GZHMessageSendController {
return gzhMessageTemplateService.sendTemplateMessageOrder(osb, templateType);
}
@Operation(summary = "推送公众号订单消息2")
@PostMapping("/order2")
@Hidden
public Result<String> orderMessage2(@RequestParam Integer id, @RequestParam Integer templateType) {
return gzhMessageTemplateService.sendTemplateMessageOrder2(id, templateType);
}
@Operation(summary = "预约发送公众号消息2")
@PostMapping("/preorder2")

View File

@ -0,0 +1,63 @@
package com.evotech.hd.wechat.entity;
import java.util.Date;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.wechat.pay.java.service.payments.nativepay.model.GoodsDetail;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Data
@Schema(name = "Native下单参数")
public class NativePayVO {
@Schema(description = "用户编码", requiredMode = RequiredMode.REQUIRED)
@NotBlank
private String wuid;
@Schema(description = "订单总描述", requiredMode = RequiredMode.REQUIRED)
@NotBlank
private String description;
@Schema(description = "支付金额,单位:分", requiredMode = RequiredMode.REQUIRED)
@NotNull
@Min(1)
@Max(100000000)
private Integer total;
@Schema(description = "支付结束时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date timeExp;
@Schema(description = "换电站编码", requiredMode = RequiredMode.REQUIRED)
private String StationCode;
@Schema(description = "订单附加信息")
private String attach;
@Schema(description = "使用的优惠活动编码", hidden = true)
private String goodsTag;
@Schema(description = "商家小票ID", hidden = true)
private String invoiceId;
@Schema(description = "商家小票金额", hidden = true)
private Integer costPrice;
@Schema(description = "商品详情")
private List<GoodsDetail> goodsDetail;
@Schema(description = "用户IP", requiredMode = RequiredMode.REQUIRED)
private String payerClientIp;
@Schema(description = "用户设备型号")
private String deviceId;
}

View File

@ -0,0 +1,18 @@
package com.evotech.hd.wechat.service;
import org.springframework.http.ResponseEntity;
import com.evotech.hd.common.core.entity.Result;
import com.evotech.hd.wechat.entity.NativePayVO;
import jakarta.servlet.http.HttpServletRequest;
public interface WechatNativePayService {
public Result<String> nativePrepay(NativePayVO prePay);
public ResponseEntity<String> nativeBack(HttpServletRequest request);
public Result<String> orderQuery(Integer type, String transactionId, String outTradeNo);
}

View File

@ -40,7 +40,6 @@ public class GZHMessageReceiveService {
return "";
}
try {
System.out.println("++++++++");
String res = HttpUtil.getString(request.getInputStream(), Charset.defaultCharset(), false);
Map<String, Object> map = XmlUtil.xmlToMap(res);
if ("event".equals(map.get("MsgType").toString())) {

View File

@ -4,6 +4,7 @@ import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.evotech.hd.common.core.dao.cloud.OrderSwapBatteryDao;
import com.evotech.hd.common.core.dao.wechat.WechatUserDao;
import com.evotech.hd.common.core.entity.Result;
import com.evotech.hd.common.core.entity.cloud.OrderSwapBattery;
@ -47,6 +48,8 @@ public class GZHMessageTemplateService {
private XcxProperties xcxProperties;
@Resource
private WechatUserDao wechatUserDao;
@Resource
private OrderSwapBatteryDao orderSwapBatteryDao;
@ -106,7 +109,6 @@ public class GZHMessageTemplateService {
if (!StringUtils.hasText(wuser.getGzhOpenid())) {
return new Result<String>().error("未关注公众号!");
}
MessageTemplateSendData sendData = new MessageTemplateSendData();
sendData.setTouser(wuser.getGzhOpenid());
String templateId = "";
@ -126,7 +128,7 @@ public class GZHMessageTemplateService {
break;
// 充电完成待结算
case 2:
templateId = gzhProperties.getOrderEndTemplateId();
templateId = gzhProperties.getOrderToPayTemplateId();
miniprogram.setPath(orderPage);
ChargeTemplateData chargeData = new ChargeTemplateData();
chargeData.setCharacter_string14(osb.getOrderNo());
@ -164,6 +166,11 @@ public class GZHMessageTemplateService {
}
public Result<String> sendTemplateMessageOrder2(Integer id, Integer templateType) {
OrderSwapBattery order = orderSwapBatteryDao.selectById(id);
return sendTemplateMessageOrder(order, templateType);
}
/**
* 充值成功推送公众号消息
* @param osb

View File

@ -0,0 +1,154 @@
package com.evotech.hd.wechat.service.impl;
import java.util.Date;
import java.util.List;
import org.springframework.beans.BeanUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.evotech.hd.common.core.dao.wechat.WechatUserDao;
import com.evotech.hd.common.core.entity.Result;
import com.evotech.hd.common.core.entity.wechat.WechatPayPreOrder;
import com.evotech.hd.common.core.entity.wechat.WechatUser;
import com.evotech.hd.common.core.utils.XCXUtil;
import com.evotech.hd.wechat.config.XcxProperties;
import com.evotech.hd.wechat.entity.NativePayVO;
import com.evotech.hd.wechat.service.WechatNativePayService;
import com.evotech.hd.wechat.utils.wechatpay.WechatPayComponent;
import com.evotech.hd.wechat.utils.wechatpay.NativePayUtil;
import com.evotech.hd.wechat.utils.wechatpay.WechatPayUtil;
import com.wechat.pay.java.core.RSAPublicKeyConfig;
import com.wechat.pay.java.core.notification.RSAPublicKeyNotificationConfig;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.payments.nativepay.model.Amount;
import com.wechat.pay.java.service.payments.nativepay.model.Detail;
import com.wechat.pay.java.service.payments.nativepay.model.GoodsDetail;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse;
import com.wechat.pay.java.service.payments.nativepay.model.QueryOrderByIdRequest;
import com.wechat.pay.java.service.payments.nativepay.model.QueryOrderByOutTradeNoRequest;
import com.wechat.pay.java.service.payments.nativepay.model.SceneInfo;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
@Service
public class WechatNativePayServiceImpl implements WechatNativePayService {
@Resource
private RSAPublicKeyConfig config;
@Resource
private RSAPublicKeyNotificationConfig notificationConfig;
@Resource
private XcxProperties xcxProperties;
@Resource
private WechatUserDao wechatUserDao;
@Resource
private WechatPayComponent wechatPayComponent;
@Override
public Result<String> nativePrepay(NativePayVO prePay) {
// 校验用户
WechatUser wuser = wechatUserDao.selectOne(new QueryWrapper<WechatUser>().eq("wuid", prePay.getWuid()));
if (wuser == null || !StringUtils.hasText(wuser.getOpenid())) {
return new Result<String>().error("用户信息错误");
}
WechatPayPreOrder preOrder = new WechatPayPreOrder();
// 组装数据
PrepayRequest request = new PrepayRequest();
// 基础信息
request.setTimeExpire(prePay.getTimeExp() == null
? DateUtil.format(DateUtil.offsetMinute(new Date(), 30), DatePattern.UTC_PATTERN)
: DateUtil.format(prePay.getTimeExp(), DatePattern.UTC_PATTERN));
request.setAttach(prePay.getAttach());
request.setAppid(xcxProperties.getAppid());
request.setMchid(xcxProperties.getMchid());
request.setDescription(prePay.getDescription());
request.setNotifyUrl(xcxProperties.getNativeNotifyUrl());
request.setOutTradeNo(XCXUtil.payOutTradeNo(prePay.getStationCode()));
// 金额
Amount amount = new Amount();
// amount.setTotal(prePay.getMoney());
amount.setTotal(1);
request.setAmount(amount);
preOrder.setTotal(amount.getTotal());
// 付款人 不需要
// 商品信息
Detail detail = new Detail();
detail.setCostPrice(prePay.getCostPrice());
detail.setInvoiceId(prePay.getInvoiceId());
List<GoodsDetail> goodsDetail = prePay.getGoodsDetail();
if (goodsDetail != null && !goodsDetail.isEmpty()) {
detail.setGoodsDetail(goodsDetail);
preOrder.setGoodsDetail(JSONUtil.toJsonStr(goodsDetail));
request.setDetail(detail);
}
// 场景信息
if (StringUtils.hasText(prePay.getPayerClientIp())) {
SceneInfo si = new SceneInfo();
si.setPayerClientIp(prePay.getPayerClientIp());
si.setDeviceId(prePay.getDeviceId());
request.setSceneInfo(si);
preOrder.setPayerClientIp(prePay.getPayerClientIp());
preOrder.setDeviceId(prePay.getDeviceId());
}
PrepayResponse response = NativePayUtil.nativePrepay(config, request);
// System.out.println("\r\n=====response>>>>>" + response);
// 写表
BeanUtils.copyProperties(request, preOrder);
wechatPayComponent.wechatPrePayLog(prePay.getWuid(), prePay.getCostPrice(), preOrder, JSONUtil.toJsonStr(response));
return new Result<String>().success(response);
}
@Override
public ResponseEntity<String> nativeBack(HttpServletRequest request) {
// 1. 验签解密
Transaction transaction;
try {
transaction = WechatPayUtil.decryptWechatPayNotify(request, notificationConfig);
} catch (Exception e) {
JSONObject jo = new JSONObject();
jo.set("code", "FAIL");
jo.set("message", "解析body异常");
return new ResponseEntity<String>(jo.toJSONString(0), HttpStatus.FAILED_DEPENDENCY);
}
// 2. 业务处理逻辑
wechatPayComponent.wechatPayBussinessHandle(transaction);
// 3. 回复微信
return new ResponseEntity<String>("", HttpStatus.OK);
}
@Override
public Result<String> orderQuery(Integer type, String transactionId, String outTradeNo) {
NativePayService nativeService = new NativePayService.Builder().config(config).build();
Transaction transaction;
if (type == 1) {
QueryOrderByIdRequest request = new QueryOrderByIdRequest();
request.setTransactionId(transactionId);
request.setMchid(xcxProperties.getMchid());
transaction = nativeService.queryOrderById(request);
} else {
QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
request.setMchid(xcxProperties.getMchid());
request.setOutTradeNo(outTradeNo);
transaction = nativeService.queryOrderByOutTradeNo(request);
}
return new Result<String>().success(transaction);
}
}

View File

@ -14,15 +14,13 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.evotech.hd.common.core.dao.wechat.WechatPayPreOrderDao;
import com.evotech.hd.common.core.dao.wechat.WechatUserDao;
import com.evotech.hd.common.core.entity.Result;
import com.evotech.hd.common.core.entity.cloud.TradeDetail;
import com.evotech.hd.common.core.entity.wechat.WechatPayAttach;
import com.evotech.hd.common.core.entity.wechat.WechatPayPreOrder;
import com.evotech.hd.common.core.entity.wechat.WechatUser;
import com.evotech.hd.common.core.utils.XCXUtil;
import com.evotech.hd.wechat.config.XcxProperties;
import com.evotech.hd.wechat.entity.PrePayVO;
import com.evotech.hd.wechat.service.WechatPayService;
import com.evotech.hd.wechat.service.rpc.CloudService;
import com.evotech.hd.wechat.utils.wechatpay.WechatPayComponent;
import com.evotech.hd.wechat.utils.wechatpay.WechatPayUtil;
import com.wechat.pay.java.core.RSAPublicKeyConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
@ -43,7 +41,6 @@ import com.wechat.pay.java.service.payments.jsapi.model.QueryOrderByIdRequest;
import com.wechat.pay.java.service.payments.jsapi.model.QueryOrderByOutTradeNoRequest;
import com.wechat.pay.java.service.payments.jsapi.model.SceneInfo;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.payments.model.Transaction.TradeTypeEnum;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
@ -75,7 +72,7 @@ public class WechatPayServiceImpl implements WechatPayService {
@Resource
private WechatPayPreOrderDao preOrderDao;
@Resource
private CloudService cloudService;
private WechatPayComponent wechatPayComponent;
@Override
@ -101,6 +98,7 @@ public class WechatPayServiceImpl implements WechatPayService {
// amount.setTotal(prePay.getMoney());
amount.setTotal(1);
request.setAmount(amount);
preOrder.setTotal(amount.getTotal());
// 付款人
Payer payer = new Payer();
payer.setOpenid(wuser.getOpenid());
@ -128,14 +126,8 @@ public class WechatPayServiceImpl implements WechatPayService {
PrepayWithRequestPaymentResponse response = WechatPayUtil.jsapiPrepay(config, request);
// System.out.println("\r\n=====response>>>>>" + response);
// 写表
BeanUtils.copyProperties(request, preOrder);
preOrder.setPrePayResponse(JSONUtil.toJsonStr(response));
preOrder.setWuid(prePay.getWuid());
preOrder.setTotal(amount.getTotal());
preOrder.setOpenid(payer.getOpenid());
preOrder.setCostPrice(prePay.getCostPrice());
preOrder.setCtime(new Date());
preOrderDao.insert(preOrder);
BeanUtils.copyProperties(request, preOrder);
wechatPayComponent.wechatPrePayLog(prePay.getWuid(), prePay.getCostPrice(), preOrder, JSONUtil.toJsonStr(response));
return new Result<String>().success(response);
}
@ -148,7 +140,7 @@ public class WechatPayServiceImpl implements WechatPayService {
// 1. 验签解密
Transaction transaction;
try {
transaction = decryptWechatPayNotify(request);
transaction = WechatPayUtil.decryptWechatPayNotify(request, notificationConfig);
} catch (Exception e) {
JSONObject jo = new JSONObject();
jo.set("code", "FAIL");
@ -156,98 +148,14 @@ public class WechatPayServiceImpl implements WechatPayService {
return new ResponseEntity<String>(jo.toJSONString(0), HttpStatus.FAILED_DEPENDENCY);
}
// 2. 业务处理逻辑
wechatPayBussinessHandle(transaction);
wechatPayComponent.wechatPayBussinessHandle(transaction);
// 3. 回复微信
return new ResponseEntity<String>("", HttpStatus.OK);
}
/**
* 微信支付回调 解密
* @param request
* @return
* @throws IOException
*/
private Transaction decryptWechatPayNotify(HttpServletRequest request) throws IOException {
String body = "";
try {
ServletInputStream inputStream = request.getInputStream();
body = IOUtil.toString(inputStream);
} catch (IOException e) {
e.printStackTrace();
throw e;
}
// 1. 初始化解析器
NotificationParser parser = new NotificationParser(notificationConfig);
// 2. 构造解析器所需参数
RequestParam param = new RequestParam.Builder()
// 序列号
.serialNumber(request.getHeader("Wechatpay-Serial"))
// 随机数
.nonce(request.getHeader("Wechatpay-Nonce"))
// 签名
.signature(request.getHeader("Wechatpay-Signature"))
// 时间戳
.timestamp(request.getHeader("Wechatpay-Timestamp"))
// 默认值为 WECHATPAY2-SHA256-RSA2048
.signType(request.getHeader("Wechatpay-Signature-Type"))
.body(body)
.build();
// 3. 验签解密parse方法中包含2个方法一个验签一个解密
Transaction transaction;
try {
transaction = parser.parse(param, Transaction.class);
log.info("\r\n===>>>支付回调信息:" + JSONUtil.toJsonStr(transaction));
} catch (Exception e) {
e.printStackTrace();
throw e;
}
return transaction;
}
/**
* 微信支付回调业务处理
* @param transaction
*/
private void wechatPayBussinessHandle(Transaction transaction) {
// 1. 生成交易信息
TradeDetail tradeDetail = new TradeDetail();
BeanUtils.copyProperties(transaction, tradeDetail);
WechatUser wuser = wechatUserDao.selectOne(new QueryWrapper<WechatUser>().eq("openid", transaction.getPayer().getOpenid()));
if (wuser != null) {
tradeDetail.setPayer(wuser.getWuid());
} else {
tradeDetail.setPayer(transaction.getPayer().getOpenid());
}
// 附加信息处理
WechatPayAttach payAttach = JSONUtil.toBean(transaction.getAttach(), WechatPayAttach.class);
tradeDetail.setTradeType(payAttach.getType());
tradeDetail.setTrader(payAttach.getTrader());
tradeDetail.setTraderCode(payAttach.getTraderCode());
tradeDetail.setWallet(payAttach.getWalletCode());
if (payAttach.getType() == 2) {
tradeDetail.setOrderNo(payAttach.getOrderNo());
tradeDetail.setOrderCount(payAttach.getOrderNo().split(",").length);
}
tradeDetail.setTradeAmount(transaction.getAmount().getPayerTotal());
TradeTypeEnum tradePayType = transaction.getTradeType();
if (tradePayType.equals(Transaction.TradeTypeEnum.JSAPI)) {
tradeDetail.setPayType(21);
}
if (tradePayType.equals(Transaction.TradeTypeEnum.NATIVE)) {
tradeDetail.setPayType(22);
}
tradeDetail.setPayResult(transaction.getTradeState().name());
tradeDetail.setPayMsg(transaction.getTradeStateDesc());
tradeDetail.setPayTime(DateUtil.parseUTC(transaction.getSuccessTime()));
// 2. 处理订单看要不要异步
cloudService.wechatPayNotifyHandle(tradeDetail);
}
@Override
public Result<String> orderQuery(Integer type, String transactionId, String outTradeNo) {

View File

@ -84,7 +84,7 @@ public class WechatUserServiceImpl implements WechatUserService {
@Override
public Result<List<WalletAccount>> listWallet(String wuid, HttpServletRequest request) {
if (!wuid.equals(request.getHeader(HDConstant.WECHAT_SERVER_AUTHORIZATION_KEY))) {
if (wuid == null || !wuid.equals(request.getHeader(HDConstant.WECHAT_SERVER_AUTHORIZATION_KEY))) {
return new Result<List<WalletAccount>>().error("账号错误");
}

View File

@ -0,0 +1,30 @@
package com.evotech.hd.wechat.utils.wechatpay;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse;
/**
* 微信支付工具类2
*/
public class NativePayUtil {
/**
* Native下单
* @param config
* @param request
* @return
*/
public static PrepayResponse nativePrepay(Config config, PrepayRequest request) {
NativePayService nativeService = new NativePayService.Builder().config(config).build();
PrepayResponse response = nativeService.prepay(request);
return response;
}
}

View File

@ -0,0 +1,100 @@
package com.evotech.hd.wechat.utils.wechatpay;
import java.util.Date;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.evotech.hd.common.core.dao.wechat.WechatPayPreOrderDao;
import com.evotech.hd.common.core.dao.wechat.WechatUserDao;
import com.evotech.hd.common.core.entity.cloud.TradeDetail;
import com.evotech.hd.common.core.entity.wechat.WechatPayAttach;
import com.evotech.hd.common.core.entity.wechat.WechatPayPreOrder;
import com.evotech.hd.common.core.entity.wechat.WechatUser;
import com.evotech.hd.common.core.enums.PayTypeEnums;
import com.evotech.hd.common.core.enums.TradeTypeEnums;
import com.evotech.hd.common.core.enums.WechatPayApiTypeEnums;
import com.evotech.hd.wechat.service.rpc.CloudService;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.payments.model.Transaction.TradeTypeEnum;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import jakarta.annotation.Resource;
@Component
public class WechatPayComponent {
@Resource
private WechatPayPreOrderDao preOrderDao;
@Resource
private WechatUserDao wechatUserDao;
@Resource
private CloudService cloudService;
/**
* 记录预支付订单信息
* @param wuid
* @param costPrice
* @param preOrder
* @param jsonStrResponse
*/
public void wechatPrePayLog(String wuid, Integer costPrice, WechatPayPreOrder preOrder,
String jsonStrResponse) {
preOrder.setPrePayResponse(jsonStrResponse);
preOrder.setType(Transaction.TradeTypeEnum.NATIVE.name());
preOrder.setWuid(wuid);
preOrder.setCostPrice(costPrice);
preOrder.setCtime(new Date());
preOrderDao.insert(preOrder);
}
/**
* 微信支付回调业务处理
* @param transaction
*/
public void wechatPayBussinessHandle(Transaction transaction) {
// 1. 生成交易信息
TradeDetail tradeDetail = new TradeDetail();
BeanUtils.copyProperties(transaction, tradeDetail);
WechatUser wuser = wechatUserDao.selectOne(new QueryWrapper<WechatUser>().eq("openid", transaction.getPayer().getOpenid()));
if (wuser != null) {
tradeDetail.setPayer(wuser.getWuid());
} else {
tradeDetail.setPayer(transaction.getPayer().getOpenid());
}
// 附加信息处理
WechatPayAttach payAttach = JSONUtil.toBean(transaction.getAttach(), WechatPayAttach.class);
tradeDetail.setTradeType(payAttach.getType());
tradeDetail.setTrader(payAttach.getTrader());
tradeDetail.setTraderCode(payAttach.getTraderCode());
tradeDetail.setWallet(payAttach.getWalletCode());
tradeDetail.setDescription(payAttach.getDescription());
if (payAttach.getType() == TradeTypeEnums.PAYORDER.getCode()) {
tradeDetail.setOrderNo(payAttach.getOrderNo());
tradeDetail.setOrderCount(payAttach.getOrderNo().split(",").length);
}
tradeDetail.setTradeAmount(transaction.getAmount().getPayerTotal());
tradeDetail.setPayType(PayTypeEnums.WECHAT.getCode());
TradeTypeEnum tradePayType = transaction.getTradeType();
if (tradePayType.equals(Transaction.TradeTypeEnum.JSAPI)) {
tradeDetail.setWechatPayApiType(WechatPayApiTypeEnums.JSAPI.getCode());
}
if (tradePayType.equals(Transaction.TradeTypeEnum.NATIVE)) {
tradeDetail.setWechatPayApiType(WechatPayApiTypeEnums.NATIVE.getCode());
}
tradeDetail.setPayResult(transaction.getTradeState().name());
tradeDetail.setPayMsg(transaction.getTradeStateDesc());
tradeDetail.setPayTime(DateUtil.parseUTC(transaction.getSuccessTime()));
// 2. 处理订单看要不要异步
cloudService.wechatPayNotifyHandle(tradeDetail);
}
}

View File

@ -1,13 +1,27 @@
package com.evotech.hd.wechat.utils.wechatpay;
import java.io.IOException;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RSAPublicKeyNotificationConfig;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.core.util.IOUtil;
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 cn.hutool.json.JSONUtil;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
/**
* 微信支付工具类
*/
@Slf4j
public class WechatPayUtil {
/**
@ -21,8 +35,47 @@ public class WechatPayUtil {
}
/**
* 微信支付回调 解密
* @param request
* @return
* @throws IOException
*/
public static Transaction decryptWechatPayNotify(HttpServletRequest request, RSAPublicKeyNotificationConfig notificationConfig) throws IOException {
String body = "";
try {
ServletInputStream inputStream = request.getInputStream();
body = IOUtil.toString(inputStream);
} catch (IOException e) {
e.printStackTrace();
throw e;
}
// 1. 初始化解析器
NotificationParser parser = new NotificationParser(notificationConfig);
// 2. 构造解析器所需参数
RequestParam param = new RequestParam.Builder()
// 序列号
.serialNumber(request.getHeader("Wechatpay-Serial"))
// 随机数
.nonce(request.getHeader("Wechatpay-Nonce"))
// 签名
.signature(request.getHeader("Wechatpay-Signature"))
// 时间戳
.timestamp(request.getHeader("Wechatpay-Timestamp"))
// 默认值为 WECHATPAY2-SHA256-RSA2048
.signType(request.getHeader("Wechatpay-Signature-Type"))
.body(body)
.build();
// 3. 验签解密parse方法中包含2个方法一个验签一个解密
Transaction transaction;
try {
transaction = parser.parse(param, Transaction.class);
log.info("\r\n===>>>支付回调信息:" + JSONUtil.toJsonStr(transaction));
} catch (Exception e) {
e.printStackTrace();
throw e;
}
return transaction;
}
}

View File

@ -60,6 +60,8 @@ hbyt:
public_key_path: src/main/resources/static/key/pub_key.pem
# 支付回调地址
notify_url: https://api.evo-techina.com/wechat/wechatpay/prepayback/msg
# Native支付回调地址
native_notify_url: https://api.evo-techina.com/wechat/wechatpay/native/nativeback/msg
# 退款回调地址
refund_notify_url: https://api.evo-techina.com/wechat/wechatpay/refundsback/msg
# token缓存时效小时