ChargeOrderInfoServiceImpl.java 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. package com.zsElectric.boot.business.service.impl;
  2. import cn.hutool.core.util.ObjectUtil;
  3. import cn.hutool.core.util.StrUtil;
  4. import com.baomidou.mybatisplus.core.metadata.IPage;
  5. import com.baomidou.mybatisplus.core.toolkit.Assert;
  6. import com.baomidou.mybatisplus.core.toolkit.Wrappers;
  7. import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  8. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  9. import com.fasterxml.jackson.core.JsonProcessingException;
  10. import com.zsElectric.boot.business.converter.ChargeOrderInfoConverter;
  11. import com.zsElectric.boot.business.mapper.*;
  12. import com.zsElectric.boot.business.model.dto.ChargeOrderInfoExportDTO;
  13. import com.zsElectric.boot.business.model.entity.*;
  14. import com.zsElectric.boot.business.model.form.ChargeOrderInfoForm;
  15. import com.zsElectric.boot.business.model.form.applet.AppInvokeChargeForm;
  16. import com.zsElectric.boot.business.model.form.applet.AppStopChargeForm;
  17. import com.zsElectric.boot.business.model.query.ChargeOrderInfoQuery;
  18. import com.zsElectric.boot.business.model.query.applet.AppChargeOrderInfoQuery;
  19. import com.zsElectric.boot.business.model.vo.ChargeOrderInfoVO;
  20. import com.zsElectric.boot.business.model.vo.applet.AppChargeVO;
  21. import com.zsElectric.boot.business.model.vo.applet.AppUserInfoVO;
  22. import com.zsElectric.boot.business.service.AppletHomeService;
  23. import com.zsElectric.boot.business.service.ChargeOrderInfoService;
  24. import com.zsElectric.boot.business.service.UserAccountService;
  25. import com.zsElectric.boot.charging.dto.StartChargingRequestDTO;
  26. import com.zsElectric.boot.charging.dto.StartChargingResponseVO;
  27. import com.zsElectric.boot.charging.service.ChargingBusinessService;
  28. import com.zsElectric.boot.charging.vo.EquipmentAuthResponseVO;
  29. import com.zsElectric.boot.charging.vo.StopChargingOperationResponseVO;
  30. import com.zsElectric.boot.common.constant.ConnectivityConstants;
  31. import com.zsElectric.boot.common.constant.SystemConstants;
  32. import com.zsElectric.boot.core.exception.BusinessException;
  33. import com.zsElectric.boot.security.util.SecurityUtils;
  34. import lombok.RequiredArgsConstructor;
  35. import lombok.extern.slf4j.Slf4j;
  36. import org.springframework.stereotype.Service;
  37. import java.math.BigDecimal;
  38. import java.text.SimpleDateFormat;
  39. import java.util.Arrays;
  40. import java.util.Date;
  41. import java.util.List;
  42. import java.util.Objects;
  43. /**
  44. * 充电订单信息服务实现类
  45. *
  46. * @author zsElectric
  47. * @since 2025-12-17 19:13
  48. */
  49. @Slf4j
  50. @Service
  51. @RequiredArgsConstructor
  52. public class ChargeOrderInfoServiceImpl extends ServiceImpl<ChargeOrderInfoMapper, ChargeOrderInfo> implements ChargeOrderInfoService {
  53. private final ChargeOrderInfoConverter chargeOrderInfoConverter;
  54. private final ChargingBusinessService chargingBusinessService;
  55. private final UserInfoMapper userInfoMapper;
  56. private final FirmInfoMapper firmInfoMapper;
  57. private final CouponMapper couponMapper;
  58. private final CouponTemplateMapper couponTemplateMapper;
  59. private final UserAccountService userAccountService;
  60. private final AppletHomeService appletHomeService;
  61. private final UserFirmMapper userFirmMapper;
  62. //充电订单号前缀
  63. private final String ORDER_NO_PREFIX = "CD";
  64. //设备流水号前缀
  65. private final String EQUIPMENT_NO_PREFIX = "SB";
  66. /**
  67. * 获取充电订单信息分页列表
  68. *
  69. * @param queryParams 查询参数
  70. * @return {@link IPage <ChargeOrderInfoVO>} 充电订单信息分页列表
  71. */
  72. @Override
  73. public IPage<ChargeOrderInfoVO> getChargeOrderInfoPage(ChargeOrderInfoQuery queryParams) {
  74. Page<ChargeOrderInfoVO> pageVO = this.baseMapper.getChargeOrderInfoPage(
  75. new Page<>(queryParams.getPageNum(), queryParams.getPageSize()),
  76. queryParams
  77. );
  78. return pageVO;
  79. }
  80. /**
  81. * 获取充电订单信息表单数据
  82. *
  83. * @param id 充电订单信息ID
  84. * @return 充电订单信息表单数据
  85. */
  86. @Override
  87. public ChargeOrderInfoForm getChargeOrderInfoFormData(Long id) {
  88. ChargeOrderInfo entity = this.getById(id);
  89. return chargeOrderInfoConverter.toForm(entity);
  90. }
  91. /**
  92. * 新增充电订单信息
  93. *
  94. * @param formData 充电订单信息表单对象
  95. * @return 是否新增成功
  96. */
  97. @Override
  98. public boolean saveChargeOrderInfo(ChargeOrderInfoForm formData) {
  99. ChargeOrderInfo entity = chargeOrderInfoConverter.toEntity(formData);
  100. return this.save(entity);
  101. }
  102. /**
  103. * 更新充电订单信息
  104. *
  105. * @param id 充电订单信息ID
  106. * @param formData 充电订单信息表单对象
  107. * @return 是否修改成功
  108. */
  109. @Override
  110. public boolean updateChargeOrderInfo(Long id,ChargeOrderInfoForm formData) {
  111. ChargeOrderInfo entity = chargeOrderInfoConverter.toEntity(formData);
  112. return this.updateById(entity);
  113. }
  114. /**
  115. * 删除充电订单信息
  116. *
  117. * @param ids 充电订单信息ID,多个以英文逗号(,)分割
  118. * @return 是否删除成功
  119. */
  120. @Override
  121. public boolean deleteChargeOrderInfos(String ids) {
  122. Assert.isTrue(StrUtil.isNotBlank(ids), "删除的充电订单信息数据为空");
  123. // 逻辑删除
  124. List<Long> idList = Arrays.stream(ids.split(","))
  125. .map(Long::parseLong)
  126. .toList();
  127. return this.removeByIds(idList);
  128. }
  129. @Override
  130. public IPage<ChargeOrderInfoVO> getPage(AppChargeOrderInfoQuery queryParams) {
  131. queryParams.setUserId(SecurityUtils.getUserId());
  132. Page<ChargeOrderInfoVO> pageVO = this.baseMapper.getPage(
  133. new Page<>(queryParams.getPageNum(), queryParams.getPageSize()),
  134. queryParams
  135. );
  136. return pageVO;
  137. }
  138. @Override
  139. public AppChargeVO invokeCharge(AppInvokeChargeForm formData) {
  140. log.info("启动充电开始,用户ID:{},设备认证流水号:{},充电桩编号:{}", SecurityUtils.getUserId(), formData.getEquipAuthSeq(), formData.getEquipmentId());
  141. try {
  142. AppChargeVO appInvokeChargeVO = new AppChargeVO();
  143. //渠道方启动充电
  144. if (Objects.equals(formData.getOrderType(), SystemConstants.CHARGE_ORDER_TYPE_CHANNEL)) {
  145. String orderNo = channelInvokeCharge(formData);
  146. appInvokeChargeVO.setChargeOrderNo(orderNo);
  147. return appInvokeChargeVO;
  148. }
  149. //必要校验
  150. Long userId = SecurityUtils.getUserId();
  151. Assert.isTrue(userId != null, "用户ID不能为空");
  152. AppUserInfoVO userInfo = userInfoMapper.getAppletUserInfo(userId);
  153. Assert.isTrue(userInfo != null, "用户信息不存在");
  154. //判断有没有正在进行中的订单
  155. Long count = this.baseMapper.selectCount(Wrappers.lambdaQuery(ChargeOrderInfo.class).eq(ChargeOrderInfo::getUserId, userId).in(ChargeOrderInfo::getStatus, SystemConstants.STATUS_ZERO, SystemConstants.STATUS_ONE, SystemConstants.STATUS_TWO));
  156. if (count > 0){
  157. throw new BusinessException("您有正在进行中的订单,请先停止充电");
  158. }
  159. //生成系统充电订单号及互联互通充电订单号 startChargeSeq equipAuthSeq (格式"运营商ID+唯一编号")
  160. assert userId != null;
  161. String chargeOrderNo = generateNo(ORDER_NO_PREFIX, userId);
  162. String seq = ConnectivityConstants.OPERATOR_ID + chargeOrderNo;
  163. //请求设备认证
  164. EquipmentAuthResponseVO equipmentAuthResponseVO = chargingBusinessService.queryEquipAuth(seq,
  165. formData.getConnectorId());
  166. if (Objects.equals(equipmentAuthResponseVO.getSuccStat(), SystemConstants.STATUS_ONE)) {
  167. throw new BusinessException("设备认证失败,请检查枪是否正确接入充电槽!");
  168. }else {
  169. log.info("设备认证成功,设备认证流水号:{}", equipmentAuthResponseVO.getEquipAuthSeq());
  170. }
  171. //创建订单
  172. ChargeOrderInfo chargeOrderInfo = new ChargeOrderInfo();
  173. chargeOrderInfo.setUserId(userId);
  174. chargeOrderInfo.setConnectorId(formData.getConnectorId());
  175. chargeOrderInfo.setEquipmentId(formData.getEquipmentId());
  176. chargeOrderInfo.setEquipAuthSeq(seq);
  177. chargeOrderInfo.setChargeOrderNo(chargeOrderNo);
  178. chargeOrderInfo.setStartChargeSeq(seq);
  179. chargeOrderInfo.setPhoneNum(userInfo.getPhone());
  180. chargeOrderInfo.setThirdPartyStationId(formData.getStationId());
  181. chargeOrderInfo.setOrderType(formData.getOrderType());
  182. //预支付金额
  183. BigDecimal preAmt = appletHomeService.calculateAvailableChargingAmount(formData.getConnectorId());
  184. chargeOrderInfo.setPreAmt(preAmt);
  185. //判断用户是否绑定企业
  186. if (ObjectUtil.isNotEmpty(userInfo.getFirmId())) {
  187. FirmInfo firmInfo = firmInfoMapper.selectById(userInfo.getFirmId());
  188. if(firmInfo != null && Objects.equals(firmInfo.getStatus(), SystemConstants.STATUS_ONE)) {
  189. chargeOrderInfo.setFirmId(firmInfo.getId());
  190. chargeOrderInfo.setOrderType(SystemConstants.STATUS_ONE);
  191. }
  192. }
  193. //优惠券
  194. if(ObjectUtil.isNotEmpty(formData.getCouponId())) {
  195. Coupon coupon = couponMapper.selectById(formData.getCouponId());
  196. if(coupon != null && Objects.equals(coupon.getStatus(), SystemConstants.STATUS_ONE)) {
  197. CouponTemplate couponTemplate = couponTemplateMapper.selectById(coupon.getTemplateId());
  198. chargeOrderInfo.setCouponId(coupon.getId());
  199. chargeOrderInfo.setCouponPrice(couponTemplate.getDiscountPrice());
  200. }
  201. }
  202. //启动充电
  203. StartChargingRequestDTO requestDTO = new StartChargingRequestDTO();
  204. requestDTO
  205. .setStartChargeSeq(seq)
  206. .setConnectorID(formData.getConnectorId())
  207. .setPhoneNum(userInfo.getPhone())
  208. //预支付金额
  209. .setChargingAmt(preAmt.toString())
  210. ;
  211. StartChargingResponseVO startChargingResponseVO = chargingBusinessService.startCharging(requestDTO);
  212. if (!Objects.equals(startChargingResponseVO.getSuccStat(), SystemConstants.STATUS_ZERO)) {
  213. throw new BusinessException(startChargingResponseVO.getFailReasonMsg());
  214. }
  215. //保存订单
  216. this.save(chargeOrderInfo);
  217. appInvokeChargeVO.setChargeOrderNo(chargeOrderNo);
  218. appInvokeChargeVO.setChargeOrderId(chargeOrderInfo.getId());
  219. return appInvokeChargeVO;
  220. } catch (Exception e) {
  221. log.error("启动充电失败,系统错误", e);
  222. throw new BusinessException("启动充电失败 !" + e.getMessage());
  223. }
  224. }
  225. /**
  226. * 渠道方启动充电
  227. *
  228. * @param formData
  229. * @return
  230. */
  231. public String channelInvokeCharge(AppInvokeChargeForm formData) throws JsonProcessingException {
  232. String seq = ConnectivityConstants.OPERATOR_ID + formData.getChannelOrderNo();
  233. //请求设备认证
  234. EquipmentAuthResponseVO equipmentAuthResponseVO = chargingBusinessService.queryEquipAuth(seq,
  235. formData.getConnectorId());
  236. if (Objects.equals(equipmentAuthResponseVO.getSuccStat(), SystemConstants.STATUS_ONE)) {
  237. throw new BusinessException("设备认证失败,请检查枪是否正确接入充电槽!");
  238. } else {
  239. log.info("设备认证成功,设备认证流水号:{}", equipmentAuthResponseVO.getEquipAuthSeq());
  240. }
  241. Long userId = SecurityUtils.getUserId();
  242. UserFirm userFirm = userFirmMapper.selectOne(Wrappers.lambdaQuery(UserFirm.class).eq(UserFirm::getUserId, userId).last("limit 1"));
  243. //创建订单
  244. ChargeOrderInfo chargeOrderInfo = new ChargeOrderInfo();
  245. chargeOrderInfo.setUserId(userId);
  246. chargeOrderInfo.setFirmId(userFirm.getFirmId());
  247. chargeOrderInfo.setOrderType(SystemConstants.CHARGE_ORDER_TYPE_CHANNEL);
  248. chargeOrderInfo.setConnectorId(formData.getConnectorId());
  249. chargeOrderInfo.setEquipmentId(formData.getEquipmentId());
  250. chargeOrderInfo.setEquipAuthSeq(seq);
  251. chargeOrderInfo.setChargeOrderNo(formData.getChannelOrderNo());
  252. chargeOrderInfo.setStartChargeSeq(seq);
  253. chargeOrderInfo.setPhoneNum(formData.getChannelUserPhone());
  254. chargeOrderInfo.setThirdPartyStationId(formData.getStationId());
  255. //预支付金额
  256. chargeOrderInfo.setPreAmt(formData.getChannelPreAmt());
  257. //启动充电
  258. StartChargingRequestDTO requestDTO = new StartChargingRequestDTO();
  259. requestDTO
  260. .setStartChargeSeq(seq)
  261. .setConnectorID(formData.getConnectorId())
  262. .setPhoneNum(formData.getChannelUserPhone())
  263. //预支付金额
  264. .setChargingAmt(formData.getChannelPreAmt().toString())
  265. ;
  266. StartChargingResponseVO startChargingResponseVO = chargingBusinessService.startCharging(requestDTO);
  267. if (!Objects.equals(startChargingResponseVO.getSuccStat(), SystemConstants.STATUS_ZERO)) {
  268. throw new BusinessException(startChargingResponseVO.getFailReasonMsg());
  269. }
  270. //保存订单
  271. this.save(chargeOrderInfo);
  272. return chargeOrderInfo.getChargeOrderNo();
  273. }
  274. @Override
  275. public AppChargeVO stopCharge(AppStopChargeForm formData) {
  276. try {
  277. AppChargeVO appInvokeChargeVO = new AppChargeVO();
  278. //订单
  279. ChargeOrderInfo chargeOrderInfo = this.getOne(Wrappers.lambdaQuery(ChargeOrderInfo.class).eq(ChargeOrderInfo::getChargeOrderNo,
  280. formData.getChargeOrderNo()).last("limit 1"));
  281. if(ObjectUtil.isEmpty(chargeOrderInfo)){
  282. throw new BusinessException("订单不存在");
  283. }
  284. StopChargingOperationResponseVO stopChargingOperationResponseVO = chargingBusinessService.stopCharging(chargeOrderInfo.getStartChargeSeq(), chargeOrderInfo.getConnectorId());
  285. if (!Objects.equals(stopChargingOperationResponseVO.getSuccStat(), SystemConstants.STATUS_ZERO)) {
  286. throw new BusinessException("停止充电失败,请切换设备或稍后再重试!");
  287. }
  288. // 更新订单状态为停止中(状态3)
  289. chargeOrderInfo.setStatus(SystemConstants.STATUS_THREE);
  290. chargeOrderInfo.setStopType(1); // 1-主动停止
  291. this.updateById(chargeOrderInfo);
  292. appInvokeChargeVO.setChargeOrderId(chargeOrderInfo.getId());
  293. appInvokeChargeVO.setChargeOrderNo(chargeOrderInfo.getChargeOrderNo());
  294. return appInvokeChargeVO;
  295. } catch (Exception e) {
  296. log.error("停止充电失败,系统错误", e);
  297. throw new BusinessException("停止充电失败,请切换设备或稍后再重试!");
  298. }
  299. }
  300. @Override
  301. public void orderSettlement(Long chargeOrderId) {
  302. ChargeOrderInfo chargeOrderInfo = this.getById(chargeOrderId);
  303. Long userId = chargeOrderInfo.getUserId();
  304. //平台收费总金额
  305. BigDecimal totalCharge = chargeOrderInfo.getRealCost();
  306. //加积分
  307. userAccountService.update(Wrappers.lambdaUpdate(UserAccount.class)
  308. .eq(UserAccount::getUserId, userId)
  309. .setSql("`integral` = `integral` +" + totalCharge)
  310. );
  311. //账户变动及日志记录
  312. userAccountService.updateAccountBalanceAndLog(
  313. userId,
  314. totalCharge,
  315. SystemConstants.CHANGE_TYPE_REDUCE,
  316. SystemConstants.CHARGE_DEDUCT_NOTE,
  317. chargeOrderInfo.getId()
  318. );
  319. }
  320. @Override
  321. public ChargeOrderInfoVO queryOrder(String chargeOrderNo) {
  322. return baseMapper.queryOrder(chargeOrderNo);
  323. }
  324. /**
  325. * 获取充电订单信息导出列表
  326. *
  327. * @param queryParams 查询参数
  328. * @return 充电订单信息导出列表
  329. */
  330. @Override
  331. public List<ChargeOrderInfoExportDTO> listExportChargeOrderInfo(ChargeOrderInfoQuery queryParams) {
  332. return baseMapper.listExportChargeOrderInfo(queryParams);
  333. }
  334. /**
  335. * 创建商户订单号
  336. * 要求 32个字符内,只能是数字、大小写字母_-|*且在同一个商户号下唯一
  337. * 组成 两位前缀 + 17位时间戳 + 9位id补零 + 4位随机数 合计32位
  338. *
  339. * @param head 例如 商品-SP 退款-TK 等等
  340. * @param id 用户id
  341. * @return
  342. */
  343. public String generateNo(String head, Long id) {
  344. StringBuilder uid = new StringBuilder(id.toString());
  345. Date date = new Date();
  346. SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
  347. int length = uid.length();
  348. for (int i = 0; i < 9 - length; i++) {
  349. uid.insert(0, "0");
  350. }
  351. return head + sdf.format(date) + uid + (int) ((Math.random() * 9 + 1) * 1000);
  352. }
  353. }