StatisticService.java 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. package com.izouma.nineth.service;
  2. import cn.hutool.core.collection.CollUtil;
  3. import com.alibaba.fastjson.JSON;
  4. import com.alibaba.fastjson.JSONObject;
  5. import com.alipay.api.domain.PriceInfo;
  6. import com.github.kevinsawicki.http.HttpRequest;
  7. import com.izouma.nineth.domain.BalanceRecord;
  8. import com.izouma.nineth.domain.Order;
  9. import com.izouma.nineth.domain.RechargeOrder;
  10. import com.izouma.nineth.domain.User;
  11. import com.izouma.nineth.enums.BalanceType;
  12. import com.izouma.nineth.enums.CollectionSource;
  13. import com.izouma.nineth.enums.OrderStatus;
  14. import com.izouma.nineth.enums.OrderType;
  15. import com.izouma.nineth.exception.BusinessException;
  16. import com.izouma.nineth.repo.*;
  17. import com.izouma.nineth.utils.netease.CheckSumBuilder;
  18. import lombok.AllArgsConstructor;
  19. import org.apache.commons.lang.RandomStringUtils;
  20. import org.springframework.stereotype.Service;
  21. import javax.xml.stream.events.EndDocument;
  22. import java.math.BigDecimal;
  23. import java.math.RoundingMode;
  24. import java.sql.Timestamp;
  25. import java.time.*;
  26. import java.time.format.DateTimeFormatter;
  27. import java.util.*;
  28. import java.util.stream.Collectors;
  29. @Service
  30. @AllArgsConstructor
  31. public class StatisticService {
  32. private UserRepo userRepo;
  33. private OrderRepo orderRepo;
  34. private TokenHistoryRepo tokenHistoryRepo;
  35. private BalanceRecordRepo balanceRecordRepo;
  36. private PhotoAssetRepo photoAssetRepo;
  37. private DomainOrderRepo domainOrderRepo;
  38. public Map<String, Object> total(Long userId, Long companyId) {
  39. User user1 = userRepo.findByIdAndDelFalse(userId).orElseThrow(new BusinessException("无用户"));
  40. Map<String, Object> total = new HashMap<>();
  41. List<Order> orders;
  42. if (user1.isAdmin()) {
  43. long user = userRepo.countAllByDelFalse();
  44. total.put("userNum", user);
  45. Set<OrderType> orderTypes = new HashSet<>();
  46. orderTypes.add(OrderType.MIX);
  47. orders = orderRepo.findAllByStatusAndCompanyIdAndOrderTypeNotIn(OrderStatus.FINISH, companyId, orderTypes);
  48. BigDecimal allRecharged = balanceRecordRepo.sumRechargeAll();
  49. total.put("rechargePrice", allRecharged);
  50. } else {
  51. orders = orderRepo.findAllByStatusAndMinterId(OrderStatus.FINISH, userId);
  52. }
  53. Map<CollectionSource, List<Order>> orderMap = orders.stream().collect(Collectors.groupingBy(Order::getSource));
  54. List<Order> officialOrders = Optional.ofNullable(orderMap.get(CollectionSource.OFFICIAL))
  55. .orElse(Collections.emptyList());
  56. List<Order> transferOrders = Optional.ofNullable(orderMap.get(CollectionSource.TRANSFER))
  57. .orElse(Collections.emptyList());
  58. total.put("officialNum", officialOrders.size());
  59. total.put("transferNum", transferOrders.size());
  60. BigDecimal officialPrice = officialOrders.stream()
  61. .map(Order::getTotalPrice)
  62. .reduce(BigDecimal.ZERO, BigDecimal::add);
  63. BigDecimal transferPrice = transferOrders.stream()
  64. .map(Order::getTotalPrice)
  65. .reduce(BigDecimal.ZERO, BigDecimal::add);
  66. total.put("officialPrice", officialPrice);
  67. total.put("transferPrice", transferPrice);
  68. return total;
  69. }
  70. /*
  71. 按天
  72. */
  73. public Map<String, Long> userTrend(int day) {
  74. Map<String, Long> map = new HashMap<>();
  75. for (int i = 0; i < day; i++) {
  76. LocalDate date = LocalDate.now().minusDays(i);
  77. map.put(DateTimeFormatter.ofPattern("yyyy-MM-dd").format(date),
  78. userRepo.countByCreatedAtBetween(date.atStartOfDay(), date.atTime(LocalTime.MAX)));
  79. }
  80. return map;
  81. }
  82. /*
  83. 按月
  84. */
  85. public Map<String, Long> userTrendV2(String yearMonth) {
  86. Map<String, Long> map = new HashMap<>();
  87. YearMonth month = YearMonth.parse(yearMonth);
  88. LocalDateTime end = month.atEndOfMonth().atTime(LocalTime.MAX);
  89. LocalDateTime start = month.atDay(1).atStartOfDay();
  90. map.put(yearMonth, userRepo.countByCreatedAtBetween(start, end));
  91. return map;
  92. }
  93. public Map<String, Map<String, Long>> orderNumTrend(int day, Long userId, Long companyId) {
  94. LocalDateTime date = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
  95. LocalDateTime start = date.minusDays(day);
  96. User user = userRepo.findByIdAndDelFalse(userId).orElseThrow(new BusinessException("无用户"));
  97. List<Order> orders;
  98. if (user.isAdmin()) {
  99. orders = orderRepo.findAllByCreatedAtIsAfterAndStatusInAndCompanyIdAndOrderTypeNot(start,
  100. Arrays.asList(OrderStatus.PROCESSING, OrderStatus.FINISH), companyId, OrderType.MIX);
  101. } else {
  102. orders = orderRepo.findAllByCreatedAtIsAfterAndMinterIdAndStatusIn(start, userId,
  103. Arrays.asList(OrderStatus.PROCESSING, OrderStatus.FINISH));
  104. }
  105. Map<CollectionSource, List<Order>> orderMap = orders.stream().collect(Collectors.groupingBy(Order::getSource));
  106. Map<String, Long> official = null;
  107. if (CollUtil.isNotEmpty(orderMap.get(CollectionSource.OFFICIAL))) {
  108. official = orderMap.get(CollectionSource.OFFICIAL).stream().collect(Collectors.groupingBy(
  109. item -> DateTimeFormatter.ofPattern("yyyy-MM-dd")
  110. .format(item.getCreatedAt()), Collectors.counting()));
  111. }
  112. Map<String, Long> transfer = null;
  113. if (CollUtil.isNotEmpty(orderMap.get(CollectionSource.TRANSFER))) {
  114. transfer = orderMap.get(CollectionSource.TRANSFER).stream().collect(Collectors.groupingBy(
  115. item -> DateTimeFormatter.ofPattern("yyyy-MM-dd")
  116. .format(item.getCreatedAt()), Collectors.counting()));
  117. }
  118. Map<String, Map<String, Long>> trend = new HashMap<>();
  119. trend.put("official", official);
  120. trend.put("transfer", transfer);
  121. return trend;
  122. }
  123. public Map<String, Map<String, BigDecimal>> orderPriceTrend(int day, Long userId, Long companyId) {
  124. LocalDateTime date = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
  125. LocalDateTime start = date.minusDays(day);
  126. User user = userRepo.findByIdAndDelFalse(userId).orElseThrow(new BusinessException("无用户"));
  127. List<Order> orders;
  128. Map<String, Map<String, BigDecimal>> trend = new HashMap<>();
  129. if (user.isAdmin()) {
  130. orders = orderRepo.findAllByCreatedAtIsAfterAndStatusInAndCompanyIdAndOrderTypeNot(start,
  131. Arrays.asList(OrderStatus.PROCESSING, OrderStatus.FINISH), companyId, OrderType.MIX);
  132. List<BalanceRecord> balanceRecords = balanceRecordRepo
  133. .findByTypeAndCreatedAtBetween(BalanceType.RECHARGE, start, LocalDateTime.now());
  134. Map<String, BigDecimal> recharged = null;
  135. if (balanceRecords.size() > 0) {
  136. recharged = balanceRecords.stream()
  137. .collect(Collectors
  138. .groupingBy(item -> DateTimeFormatter.ofPattern("yyyy-MM-dd")
  139. .format(item
  140. .getCreatedAt()), Collectors
  141. .mapping(BalanceRecord::getAmount,
  142. Collectors
  143. .reducing(BigDecimal.ZERO, BigDecimal::add))));
  144. }
  145. trend.put("recharged", recharged);
  146. } else {
  147. orders = orderRepo.findAllByCreatedAtIsAfterAndMinterIdAndStatusIn(start, userId,
  148. Arrays.asList(OrderStatus.PROCESSING, OrderStatus.FINISH));
  149. }
  150. Map<CollectionSource, List<Order>> orderMap = orders.stream().collect(Collectors.groupingBy(Order::getSource));
  151. Map<String, BigDecimal> official = null;
  152. if (CollUtil.isNotEmpty(orderMap.get(CollectionSource.OFFICIAL))) {
  153. official = orderMap.get(CollectionSource.OFFICIAL)
  154. .stream()
  155. .collect(Collectors.groupingBy(
  156. item -> DateTimeFormatter.ofPattern("yyyy-MM-dd")
  157. .format(item.getCreatedAt()), Collectors
  158. .mapping(Order::getTotalPrice,
  159. Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
  160. }
  161. Map<String, BigDecimal> transfer = null;
  162. if (CollUtil.isNotEmpty(orderMap.get(CollectionSource.TRANSFER))) {
  163. transfer = orderMap.get(CollectionSource.TRANSFER)
  164. .stream()
  165. .collect(Collectors.groupingBy(
  166. item -> DateTimeFormatter.ofPattern("yyyy-MM-dd")
  167. .format(item.getCreatedAt()), Collectors
  168. .mapping(Order::getTotalPrice,
  169. Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
  170. }
  171. trend.put("official", official);
  172. trend.put("transfer", transfer);
  173. return trend;
  174. }
  175. public String top(LocalDateTime start, LocalDateTime end, int size) {
  176. List<Map<String, Object>> maps = tokenHistoryRepo.sumPrice(start, end, size);
  177. return JSONObject.toJSONString(maps);
  178. }
  179. public Map<String, BigDecimal> orderPriceTrendV2(String yearMonth, Long userId, Long companyId) {
  180. YearMonth month = YearMonth.parse(yearMonth);
  181. LocalDateTime end = month.atEndOfMonth().atTime(LocalTime.MAX);
  182. LocalDateTime start = month.atDay(1).atStartOfDay();
  183. User user = userRepo.findByIdAndDelFalse(userId).orElseThrow(new BusinessException("无用户"));
  184. List<Order> orders;
  185. Map<String, BigDecimal> map = new HashMap<>();
  186. if (user.isAdmin()) {
  187. orders = orderRepo.findAllByCreatedAtBetweenAndStatusInAndCompanyIdAndOrderTypeNot(start, end,
  188. Arrays.asList(OrderStatus.PROCESSING, OrderStatus.FINISH), companyId, OrderType.MIX);
  189. BigDecimal allRecharged = balanceRecordRepo.sumRechargeToday(start, end);
  190. map.put("recharged", allRecharged);
  191. } else {
  192. orders = orderRepo.findAllByCreatedAtBetweenAndMinterIdAndStatusIn(start, end, userId,
  193. Arrays.asList(OrderStatus.PROCESSING, OrderStatus.FINISH));
  194. }
  195. map.put("official", orders.stream().filter(order -> order.getSource().equals(CollectionSource.OFFICIAL))
  196. .map(Order::getPrice).reduce(BigDecimal::add).orElse(BigDecimal.ZERO));
  197. map.put("transfer", orders.stream().filter(order -> order.getSource().equals(CollectionSource.TRANSFER))
  198. .map(Order::getPrice).reduce(BigDecimal::add).orElse(BigDecimal.ZERO));
  199. return map;
  200. }
  201. //其他平台统计
  202. public Map<String, Object> otherStatistic() {
  203. Map<String, Object> resultMap = new HashMap<>();
  204. Map<String, Object> amountMap = new HashMap<>();
  205. Map<String, Object> transfer = new HashMap<>();
  206. Map<String, Object> official = new HashMap<>();
  207. Map<String, Object> transferNum = new HashMap<>();
  208. Map<String, Object> officialNum = new HashMap<>();
  209. Map<String, Object> userNum = new HashMap<>();
  210. Map<String, Object> numMap = new HashMap<>();
  211. //modern point
  212. try {
  213. String mpToken = getToken("admin", "pZ&VYa^Na&l6n^sMMdDtL", "https://modern.9space.vip/auth/login");
  214. Map<String, Object> mpParams = new HashMap<>();
  215. String mpResultString = httpPost(mpParams, "https://modern.9space.vip/statistic/total", mpToken);
  216. JSONObject mpResult = JSONObject.parseObject(mpResultString);
  217. transfer.put("MP", mpResult.getBigDecimal("transferPrice"));
  218. transferNum.put("MP", mpResult.getLong("transferNum"));
  219. official.put("MP", mpResult.getBigDecimal("officialPrice"));
  220. officialNum.put("MP", mpResult.getLong("officialNum"));
  221. userNum.put("MP", mpResult.getLong("userNum"));
  222. } catch (Exception ignored) {
  223. }
  224. //art
  225. try {
  226. String artToken = getToken("xingadmin", "eq6bVqLqkZpoqLpH", "https://art.hopesilence.com/auth/login");
  227. Map<String, Object> artParams = new HashMap<>();
  228. String artResultString = httpPost(artParams, "https://art.hopesilence.com/statistic/total", artToken);
  229. JSONObject artResult = JSONObject.parseObject(artResultString);
  230. transfer.put("ART", artResult.getBigDecimal("transferPrice"));
  231. transferNum.put("ART", artResult.getLong("transferNum"));
  232. official.put("ART", artResult.getBigDecimal("officialPrice"));
  233. officialNum.put("ART", artResult.getLong("officialNum"));
  234. userNum.put("ART", artResult.getLong("userNum"));
  235. } catch (Exception ignored) {
  236. }
  237. //cosmos
  238. try {
  239. String cosToken = getToken("xingadmin", "EnLs#(CkQdLS23BaY", "https://cos.9space.vip/auth/login");
  240. Map<String, Object> params = new HashMap<>();
  241. params.put("page", 0);
  242. params.put("search", "");
  243. params.put("size", 1);
  244. params.put("sort", "createdAt,desc");
  245. Map<String, Object> query = new HashMap<>();
  246. query.put("collectionId", "");
  247. query.put("createdAt", "");
  248. query.put("name", "");
  249. query.put("officialCollectionId", "");
  250. query.put("orderNo", "");
  251. query.put("transactionId", "");
  252. query.put("del", false);
  253. query.put("projectId", "1");
  254. query.put("source", "TRANSFER");
  255. query.put("status", "FINISH");
  256. params.put("query", query);
  257. String resultString = httpPost(params, "https://cos.9space.vip/order/all", cosToken);
  258. JSONObject result = JSONObject.parseObject(resultString);
  259. BigDecimal transferAmount = result.getBigDecimal("totalAmount");
  260. String transferElements = result.getString("totalElements");
  261. transfer.put("COS", transferAmount);
  262. transferNum.put("COS", transferElements);
  263. query.put("source", "OFFICIAL");
  264. params.put("query", query);
  265. resultString = httpPost(params, "https://cos.9space.vip/order/all", cosToken);
  266. result = JSONObject.parseObject(resultString);
  267. BigDecimal officialAmount = result.getBigDecimal("totalAmount");
  268. String officialElements = result.getString("totalElements");
  269. official.put("COS", officialAmount);
  270. officialNum.put("COS", officialElements);
  271. Map<String, Object> userQuery = new HashMap<>();
  272. userQuery.put("createdAt", "");
  273. userQuery.put("del", false);
  274. userQuery.put("phone", "");
  275. userQuery.put("invitor", "");
  276. userQuery.put("projectId", "1");
  277. params.put("query", userQuery);
  278. //用户
  279. resultString = httpPost(params, "https://cos.9space.vip/user/all", cosToken);
  280. result = JSONObject.parseObject(resultString);
  281. Long cosUserCount = result.getLong("totalElements");
  282. userNum.put("COS", cosUserCount);
  283. } catch (Exception ignored2) {
  284. }
  285. //第九空间
  286. try {
  287. String ninthToken = getToken("xingadmin", "123456", "https://nft.9space.vip/auth/login");
  288. Map<String, Object> params1 = new HashMap<>();
  289. params1.put("page", 0);
  290. params1.put("search", "");
  291. params1.put("size", 1);
  292. params1.put("sort", "createdAt,desc");
  293. Map<String, Object> query1 = new HashMap<>();
  294. query1.put("collectionId", "");
  295. query1.put("createdAt", "");
  296. query1.put("name", "");
  297. query1.put("officialCollectionId", "");
  298. query1.put("orderNo", "");
  299. query1.put("transactionId", "");
  300. query1.put("del", false);
  301. query1.put("projectId", "0");
  302. query1.put("source", "TRANSFER");
  303. query1.put("status", "FINISH");
  304. params1.put("query", query1);
  305. //二手市场
  306. String resultString1 = httpPost(params1, "https://nft.9space.vip/order/all", ninthToken);
  307. JSONObject result1 = JSONObject.parseObject(resultString1);
  308. BigDecimal transferAmount1 = result1.getBigDecimal("totalAmount");
  309. String transferElements1 = result1.getString("totalElements");
  310. transfer.put("NINTH", transferAmount1);
  311. transferNum.put("NINTH", transferElements1);
  312. query1.put("source", "OFFICIAL");
  313. params1.put("query", query1);
  314. //官方订单
  315. resultString1 = httpPost(params1, "https://nft.9space.vip/order/all", ninthToken);
  316. result1 = JSONObject.parseObject(resultString1);
  317. BigDecimal officialAmount1 = result1.getBigDecimal("totalAmount");
  318. String officialElements1 = result1.getString("totalElements");
  319. official.put("NINTH", officialAmount1);
  320. officialNum.put("NINTH", officialElements1);
  321. Map<String, Object> userQuery1 = new HashMap<>();
  322. userQuery1.put("createdAt", "");
  323. userQuery1.put("del", false);
  324. userQuery1.put("phone", "");
  325. userQuery1.put("invitor", "");
  326. userQuery1.put("projectId", "0");
  327. params1.put("query", userQuery1);
  328. //用户
  329. resultString1 = httpPost(params1, "https://nft.9space.vip/user/all", ninthToken);
  330. result1 = JSONObject.parseObject(resultString1);
  331. Long ninthUserCount = result1.getLong("totalElements");
  332. userNum.put("NINTH", ninthUserCount);
  333. } catch (Exception ignored) {
  334. }
  335. amountMap.put("transfer", transfer);
  336. amountMap.put("official", official);
  337. numMap.put("transfer", transferNum);
  338. numMap.put("official", officialNum);
  339. numMap.put("userCount", userNum);
  340. resultMap.put("priceInfo", amountMap);
  341. resultMap.put("numInfo", numMap);
  342. return resultMap;
  343. }
  344. public String httpPost(Map<String, Object> params, String url, String token) {
  345. Map<String, String> headers = new HashMap<>();
  346. headers.put("Authorization", "Bearer " + token);
  347. headers.put("Content-Type", "application/json; charset=UTF-8");
  348. headers.put("Accept", "application/json, text/plain, */*");
  349. return HttpRequest.post(url)
  350. .contentType(HttpRequest.CONTENT_TYPE_JSON)
  351. .headers(headers)
  352. .send(JSON.toJSONString(params))
  353. .body();
  354. }
  355. public String getToken(String username, String password, String url) {
  356. Map<String, Object> params = new HashMap<>();
  357. Map<String, String> headers = new HashMap<>();
  358. params.put("username", username);
  359. params.put("password", password);
  360. return HttpRequest.post(url)
  361. .contentType("application/x-www-form-urlencoded")
  362. .headers(headers)
  363. .form(params)
  364. .body();
  365. }
  366. public Map<String, Map<String, Object>> statisticDetail() {
  367. Map<String, Map<String, Object>> result = new HashMap<>();
  368. //今日
  369. LocalDateTime todayStart = LocalDate.now().atStartOfDay();
  370. LocalDateTime todayEnd = LocalDateTime.now();
  371. Map<String, Object> today = statisticDetail(todayStart, todayEnd);
  372. result.put("today", today);
  373. LocalDateTime lastStart = LocalDate.now().atStartOfDay().minusDays(1);
  374. LocalDateTime lastEnd = LocalDate.now().atTime(LocalTime.MAX).minusDays(1);
  375. Map<String, Object> last = statisticDetail(lastStart, lastEnd);
  376. result.put("yesterday", last);
  377. LocalDateTime yesterStart = LocalDate.now().atStartOfDay().minusDays(2);
  378. LocalDateTime yesterEnd = LocalDate.now().atTime(LocalTime.MAX).minusDays(2);
  379. Map<String, Object> yesterday = statisticDetail(yesterStart, yesterEnd);
  380. result.put("last", yesterday);
  381. return result;
  382. }
  383. public Map<String, Object> statisticDetail(LocalDateTime todayStart, LocalDateTime todayEnd) {
  384. Map<String, Object> today = new HashMap<>();
  385. //充值
  386. BigDecimal rcToday = Optional.ofNullable(balanceRecordRepo.sumRechargeToday(todayStart, todayEnd))
  387. .orElse(BigDecimal.ZERO);
  388. today.put("recharge", rcToday);
  389. //提现
  390. BigDecimal wdToday = Optional.ofNullable(balanceRecordRepo.sumWithdrawToday(todayStart, todayEnd))
  391. .orElse(BigDecimal.ZERO);
  392. today.put("withdraw", wdToday);
  393. //星图
  394. BigDecimal paToday = Optional.ofNullable(photoAssetRepo.sumPaid(todayStart, todayEnd)).orElse(BigDecimal.ZERO);
  395. today.put("photoAsset", paToday);
  396. List<Order> orders = orderRepo
  397. .findAllByCreatedAtBetweenAndStatusInAndCompanyIdAndOrderTypeNot(todayStart, todayEnd,
  398. Arrays.asList(OrderStatus.PROCESSING, OrderStatus.FINISH), 1L, OrderType.MIX);
  399. ///手续费
  400. List<BigDecimal> ros = new ArrayList<>();
  401. List<BigDecimal> scs = new ArrayList<>();
  402. for (Order order : orders) {
  403. BigDecimal amount = order.getTotalPrice();
  404. BigDecimal ro = BigDecimal.valueOf(order.getRoyalties());
  405. BigDecimal sc = BigDecimal.valueOf(order.getServiceCharge());
  406. BigDecimal orderRo = amount.multiply(ro).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_DOWN);
  407. ros.add(orderRo);
  408. BigDecimal orderSc = amount.multiply(sc).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_DOWN);
  409. scs.add(orderSc);
  410. }
  411. BigDecimal todayRo = Optional.of(ros.stream().reduce(BigDecimal::add).orElse(BigDecimal.ZERO))
  412. .orElse(BigDecimal.ZERO);
  413. today.put("royalties", todayRo);
  414. //版权费
  415. BigDecimal todaySc = scs.stream().reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
  416. today.put("serviceCharge", todaySc);
  417. //域名
  418. BigDecimal domainOrder = domainOrderRepo.sumToday(todayStart, todayEnd);
  419. today.put("domainOrder", Optional.ofNullable(domainOrder).orElse(BigDecimal.ZERO));
  420. //saas
  421. BigDecimal saas = orderRepo.sumSaas(todayStart, todayEnd);
  422. today.put("saas", Optional.ofNullable(saas).orElse(BigDecimal.ZERO));
  423. return today;
  424. }
  425. }