ChargeOrderServiceImpl.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. package com.kym.service.miniapp.impl;
  2. import cn.dev33.satoken.stp.StpUtil;
  3. import cn.hutool.poi.excel.ExcelUtil;
  4. import cn.hutool.poi.excel.ExcelWriter;
  5. import com.github.pagehelper.PageHelper;
  6. import com.kym.common.exception.BusinessException;
  7. import com.kym.common.utils.CommUtil;
  8. import com.kym.common.utils.HttpUtil;
  9. import com.kym.entity.admin.Activity;
  10. import com.kym.entity.admin.queryParams.CustomChargeOrdersQueryParam;
  11. import com.kym.entity.admin.queryParams.StatQueryParam;
  12. import com.kym.entity.admin.vo.CustomOrderVo;
  13. import com.kym.entity.admin.vo.StationStatVo;
  14. import com.kym.entity.common.PageBean;
  15. import com.kym.entity.common.RedisKeys;
  16. import com.kym.entity.miniapp.queryParams.OrderQueryParams;
  17. import com.kym.entity.miniapp.vo.ChargeOrderVo;
  18. import com.kym.service.admin.ExportService;
  19. import com.kym.service.cache.KymCache;
  20. import com.kym.service.miniapp.UserCouponService;
  21. import com.kym.service.miniapp.UserRechargeRightsService;
  22. import com.kym.service.mybatisplus.MyBaseServiceImpl;
  23. import jakarta.servlet.http.HttpServletResponse;
  24. import lombok.SneakyThrows;
  25. import lombok.extern.slf4j.Slf4j;
  26. import okhttp3.Headers;
  27. import org.springframework.beans.BeanUtils;
  28. import org.springframework.beans.factory.annotation.Value;
  29. import org.springframework.context.annotation.Lazy;
  30. import org.springframework.data.redis.core.StringRedisTemplate;
  31. import org.springframework.stereotype.Service;
  32. import java.math.BigDecimal;
  33. import java.math.RoundingMode;
  34. import java.time.format.DateTimeFormatter;
  35. import java.util.Arrays;
  36. import java.util.HashMap;
  37. import java.util.List;
  38. import java.util.Map;
  39. import java.util.stream.Collectors;
  40. /**
  41. * <p>
  42. * 充电订单表 服务实现类
  43. * </p>
  44. *
  45. * @author skyline
  46. * @since 2023-08-08
  47. */
  48. @Service
  49. @Slf4j
  50. public class ChargeOrderServiceImpl extends MyBaseServiceImpl<ChargeOrderMapper, ChargeOrder> implements ChargeOrderService {
  51. private final ExportService exportService;
  52. private final UserCouponService userCouponService;
  53. private final UserRechargeRightsService userRechargeRightsService;
  54. private final StationStatDayService stationStatDayService;
  55. private final StationStatMonthService stationStatMonthService;
  56. private final StringRedisTemplate redisTemplate;
  57. @Value("${en-plus.sassClose}")
  58. public String saasClose;
  59. public ChargeOrderServiceImpl(ExportService exportService, @Lazy UserCouponService userCouponService, UserRechargeRightsService userRechargeRightsService,
  60. StationStatDayService stationStatDayService, StationStatMonthService stationStatMonthService, StringRedisTemplate redisTemplate) {
  61. this.exportService = exportService;
  62. this.userCouponService = userCouponService;
  63. this.userRechargeRightsService = userRechargeRightsService;
  64. this.stationStatDayService = stationStatDayService;
  65. this.stationStatMonthService = stationStatMonthService;
  66. this.redisTemplate = redisTemplate;
  67. }
  68. @Override
  69. public ChargeOrder getChargingOrderByUserId(Long userId) {
  70. return lambdaQuery()
  71. .eq(ChargeOrder::getUserId, userId)
  72. .eq(ChargeOrder::getOrderStatus, ChargeOrder.ORDER_STATUS_未知)
  73. .in(ChargeOrder::getChargeStatus, ChargeOrder.CHARGE_STATUS_预约中, ChargeOrder.CHARGE_STATUS_启动中, ChargeOrder.CHARGE_STATUS_充电中, ChargeOrder.CHARGE_STATUS_停止中)
  74. .one();
  75. }
  76. @Override
  77. public ChargeOrder getChargingOrderByStartChargeSeq(String startChargeSeq) {
  78. return lambdaQuery().eq(ChargeOrder::getStartChargeSeq, startChargeSeq).one();
  79. }
  80. @Override
  81. public PageBean<CustomOrderVo> customChargeOrders(CustomChargeOrdersQueryParam params) {
  82. if (params.getConnectorId() != null) {
  83. var connectorId = KymCache.INSTANCE.getConnectorId(params.getConnectorId());
  84. params.setConnectorId(connectorId);
  85. }
  86. // 判断数据权限
  87. if (params.getStationId() == null) {
  88. params.setStationId(CommUtil.isEmptyOrNull(KymCache.INSTANCE.getAdminUserStationIds(StpUtil.getLoginIdAsLong())) ? null : KymCache.INSTANCE.getAdminUserStationIds(StpUtil.getLoginIdAsLong()).get(0));
  89. }
  90. PageHelper.startPage(params.getPageNum(), params.getPageSize());
  91. // 查询订单列表(订单编号,手机号,充电站,充电桩SN/短码,订单状态,建单时间,结算时间,充电电量,实付金额,付款状态)
  92. var result = baseMapper.listChargeOrders(params);
  93. var page = new PageBean<>(result);
  94. page.setList(result.stream().map(item ->
  95. item.setShortId(KymCache.INSTANCE.getShortIdByEquipmentIdOrConnectorId(item.getConnectorId()))
  96. .setStationName(KymCache.INSTANCE.getStationNameById(item.getStationId()))).collect(Collectors.toList()));
  97. var map = baseMapper.statChargeOrders(params);
  98. return page.setExtraData(map);
  99. }
  100. @SneakyThrows
  101. @Override
  102. public void exportCustomChargeOrders(CustomChargeOrdersQueryParam params, HttpServletResponse response) {
  103. if (params.getConnectorId() != null) {
  104. var connectorId = KymCache.INSTANCE.getConnectorId(params.getConnectorId());
  105. params.setConnectorId(connectorId);
  106. }
  107. // 判断数据权限
  108. var adminStationIds = KymCache.INSTANCE.getAdminUserStationIds(StpUtil.getLoginIdAsLong());
  109. if (params.getStationId() != null && adminStationIds.contains(params.getStationId())) {
  110. params.setStationId(adminStationIds.get(0));
  111. }
  112. // 查询订单列表(订单编号,手机号,充电站,充电桩SN/短码,订单状态,建单时间,结算时间,充电电量,实付金额,付款状态)
  113. var result = baseMapper.listChargeOrders(params);
  114. result = result.stream().map(item ->
  115. item.setShortId(KymCache.INSTANCE.getShortIdByEquipmentIdOrConnectorId(item.getConnectorId()))
  116. .setStationName(KymCache.INSTANCE.getStationNameById(item.getStationId())))
  117. .toList();
  118. // stationId,startChargeSeq,connectorId,startTime,endTime,totalPower,totalMoney,elecMoney,serviceMoney,orderStatus,chargeStatus,stopReason,invoiceStatus
  119. var rows = result.stream().map(item -> {
  120. var map = new HashMap<String, Object>();
  121. map.put("stationId", item.getStationId());
  122. map.put("startChargeSeq", item.getStartChargeSeq());
  123. map.put("connectorId", item.getConnectorId());
  124. map.put("startTime", item.getStartTime() == null ? "-" : item.getStartTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
  125. map.put("endTime", item.getEndTime() == null ? "-" : item.getEndTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
  126. map.put("totalPower", item.getTotalPower());
  127. map.put("totalMoney", BigDecimal.valueOf(item.getTotalMoney()).divide(BigDecimal.valueOf(100)));
  128. map.put("elecMoney", BigDecimal.valueOf(item.getElecMoney()).divide(BigDecimal.valueOf(100)));
  129. map.put("serviceMoney", BigDecimal.valueOf(item.getServiceMoney()).divide(BigDecimal.valueOf(100)));
  130. map.put("orderStatus", item.getOrderStatus());
  131. map.put("chargeStatus", item.getChargeStatus());
  132. return map;
  133. }).toList();
  134. // 通过工具类创建writer,默认创建xls格式
  135. ExcelWriter writer = ExcelUtil.getWriter();
  136. //自定义标题别名
  137. writer.addHeaderAlias("stationId", "站点ID");
  138. writer.addHeaderAlias("startChargeSeq", "充电订单号");
  139. writer.addHeaderAlias("connectorId", "充电设备接口编号");
  140. writer.addHeaderAlias("startTime", "充电开始时间");
  141. writer.addHeaderAlias("endTime", "充电结束时间");
  142. writer.addHeaderAlias("totalPower", "充电量(度)");
  143. writer.addHeaderAlias("totalMoney", "累积总金额(元)");
  144. writer.addHeaderAlias("elecMoney", "累积电费(元)");
  145. writer.addHeaderAlias("serviceMoney", "累积服务费(元)");
  146. writer.addHeaderAlias("orderStatus", "订单状态");
  147. writer.addHeaderAlias("chargeStatus", "充电状态");
  148. exportService.exportExcel("订单列表", writer, rows, response);
  149. }
  150. @Override
  151. public PageBean<ChargeOrderVo> listUserChargeOrders(OrderQueryParams params) {
  152. PageHelper.startPage(params.getPageNum(), params.getPageSize());
  153. var list = lambdaQuery()
  154. .eq(!CommUtil.isEmptyOrNull(params.getInvoiceStatus()), ChargeOrder::getInvoiceStatus, params.getInvoiceStatus())
  155. .eq(ChargeOrder::getUserId, StpUtil.getLoginIdAsLong()).orderByDesc(ChargeOrder::getId).list();
  156. var res = new PageBean<>(list);
  157. var voList = list.stream().map(chargeOrder -> {
  158. var vo = new ChargeOrderVo();
  159. BeanUtils.copyProperties(chargeOrder, vo);
  160. vo.setPayServiceAmount(vo.getServiceMoney() - vo.getDiscountAmount());
  161. return vo;
  162. }).toList();
  163. return new PageBean<>(voList).setList(res);
  164. }
  165. @Override
  166. public ChargeOrderVo orderDetailForApp(String startChargeSeq) {
  167. var chargeOrder = lambdaQuery().eq(ChargeOrder::getStartChargeSeq, startChargeSeq).one();
  168. // 订单对应的优惠信息
  169. var orderVo = new ChargeOrderVo();
  170. BeanUtils.copyProperties(chargeOrder, orderVo);
  171. orderVo.setStationName(KymCache.INSTANCE.getStationNameById(chargeOrder.getStationId()));
  172. // todo 修改成只显示优惠金额,具体优惠信息点击详情查看具体权益卡/优惠券
  173. // if (chargeOrder.getDiscountAmount() > 0) {
  174. // // 充值权益
  175. // var orderRechargeRight = orderRechargeRightsService.lambdaQuery().eq(OrderRechargeRights::getStartChargeSeq, startChargeSeq).one();
  176. // DynamicDataSourceContextHolder.push("db-admin");
  177. // var rechargeRights = rechargeRightsService.lambdaQuery().eq(RechargeRights::getId, orderRechargeRight.getRightsId()).one();
  178. // DynamicDataSourceContextHolder.poll();
  179. // var desc = rechargeRights.getRightsDesc();
  180. // orderVo.setRightsDesc(desc);
  181. // }
  182. return orderVo;
  183. }
  184. @Override
  185. public Object orderDiscountDetail(String startChargeSeq, String discountType) {
  186. return switch (discountType) {
  187. case Activity.DISCOUNT_TYPE_服务费折扣权益 ->
  188. userRechargeRightsService.getUserOrderRechargeRights(startChargeSeq);
  189. case Activity.DISCOUNT_TYPE_优惠券 -> userCouponService.getUserOrderCoupon(startChargeSeq);
  190. default -> throw new BusinessException("未知的优惠类型");
  191. };
  192. }
  193. /**
  194. * 通过En+ sass关闭订单
  195. *
  196. * @param startChargeSeq
  197. */
  198. @Override
  199. public void closeChargeOrder(String startChargeSeq) {
  200. Headers headers = Headers.of("satoken", redisTemplate.opsForValue().get(RedisKeys.EN_PLUS_SASS_TOKEN));
  201. var res = HttpUtil.parseJson(HttpUtil.post(saasClose + startChargeSeq, headers));
  202. if (!(res.containsKey("success") && res.getBoolean("success"))) {
  203. log.error("关闭订单失败:{}", res);
  204. throw new BusinessException("关闭订单失败");
  205. }
  206. }
  207. /**
  208. * 站点统计
  209. *
  210. * @param params
  211. * @return
  212. */
  213. @Override
  214. public PageBean<StationStatVo> stationStat(StatQueryParam params) {
  215. // 判断数据权限
  216. var adminStationIds = KymCache.INSTANCE.getAdminUserStationIds(StpUtil.getLoginIdAsLong());
  217. if (params.getStationId() == null && !adminStationIds.isEmpty()) {
  218. params.setStationId(adminStationIds.get(0));
  219. }
  220. PageHelper.startPage(params.getPageNum(), params.getPageSize());
  221. var res = baseMapper.stationStat(params).stream().peek(item -> {
  222. item.setElecMoneyPercent((new BigDecimal(item.getElecMoney())).divide(new BigDecimal(Math.max(1, item.getTotalMoney())), 2, RoundingMode.HALF_UP));
  223. item.setServiceMoneyPercent(BigDecimal.ONE.subtract(item.getElecMoneyPercent()));
  224. }).collect(Collectors.toList());
  225. var map = Map.of(
  226. "totalPower", BigDecimal.valueOf(res.stream().mapToDouble(StationStatVo::getTotalPower).sum()).setScale(2, RoundingMode.HALF_UP).doubleValue(),
  227. "serviceMoney", res.stream().mapToInt(StationStatVo::getServiceMoney).sum(),
  228. "payServiceAmount", res.stream().mapToInt(StationStatVo::getPayServiceAmount).sum()
  229. );
  230. return new PageBean<>(res).setExtraData(map);
  231. }
  232. /**
  233. * 站点统计详情
  234. *
  235. * @param params
  236. * @return
  237. */
  238. @Override
  239. public Map<String, ?> stationStatDetail(StatQueryParam params) {
  240. CommUtil.asserts(CommUtil.isNotEmptyAndNull(params.getStationIds()), "站点不能为空");
  241. if (params.getType().equals(StatQueryParam.TYPE_DAY)) {
  242. return stationStatDayService.lambdaQuery()
  243. .in(StationStatDay::getStationId, params.getStationIds())
  244. .ge(StationStatDay::getStatDay, params.getStartTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))
  245. .le(StationStatDay::getStatDay, params.getEndTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))
  246. .orderByAsc(StationStatDay::getStatDay)
  247. .list().stream().collect(Collectors.groupingBy(StationStatDay::getStationId, Collectors.toList()));
  248. } else {
  249. return stationStatMonthService.lambdaQuery()
  250. .in(StationStatMonth::getStationId, params.getStationIds())
  251. .ge(StationStatMonth::getStatMonth, params.getStartTime().format(DateTimeFormatter.ofPattern("yyyy-MM")))
  252. .le(StationStatMonth::getStatMonth, params.getEndTime().format(DateTimeFormatter.ofPattern("yyyy-MM")))
  253. .orderByAsc(StationStatMonth::getStatMonth)
  254. .list().stream().collect(Collectors.groupingBy(StationStatMonth::getStationId, Collectors.toList()));
  255. }
  256. }
  257. /**
  258. * 充电站当日统计
  259. *
  260. * @return
  261. */
  262. @Override
  263. public Map<String, Object> stationTodayStat(String stationId) {
  264. if (CommUtil.null2Long(stationId) <= 0) {
  265. // 判断数据权限
  266. stationId = CommUtil.isEmptyOrNull(KymCache.INSTANCE.getAdminUserStationIds(StpUtil.getLoginIdAsLong())) ? null : KymCache.INSTANCE.getAdminUserStationIds(StpUtil.getLoginIdAsLong()).get(0);
  267. }
  268. return baseMapper.stationTodayStat(stationId);
  269. }
  270. /**
  271. * 订单号批量查询订单
  272. *
  273. * @param startChargeSeqs
  274. * @return
  275. */
  276. @Override
  277. public List<ChargeOrder> getChargeOrdersBySeqs(String[] startChargeSeqs) {
  278. return lambdaQuery().in(ChargeOrder::getStartChargeSeq, Arrays.stream(startChargeSeqs).toList()).list();
  279. }
  280. }