ChargeOrderServiceImpl.java 15 KB

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