|
|
@@ -1,7 +1,11 @@
|
|
|
package com.dtm.order.service;
|
|
|
|
|
|
+import com.dtm.order.domain.OrderAnalyticsRecord;
|
|
|
+import com.dtm.order.domain.OrderFunnelSummary;
|
|
|
+import com.dtm.order.domain.OrderLeakageSummary;
|
|
|
import com.dtm.order.dto.CoPurchaseDTO;
|
|
|
import com.dtm.order.dto.ProductDTO;
|
|
|
+import com.dtm.order.mapper.OrderAnalyticsMapper;
|
|
|
import org.apache.poi.ss.usermodel.Row;
|
|
|
import org.apache.poi.ss.usermodel.Sheet;
|
|
|
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
|
|
@@ -27,32 +31,45 @@ public class AnalysisService {
|
|
|
|
|
|
|
|
|
private final OrderDataStore orderDataStore;
|
|
|
+ private final OrderAnalyticsMapper orderAnalyticsMapper;
|
|
|
|
|
|
@Autowired
|
|
|
- public AnalysisService(OrderDataStore orderDataStore) {
|
|
|
+ public AnalysisService(OrderDataStore orderDataStore, OrderAnalyticsMapper orderAnalyticsMapper) {
|
|
|
this.orderDataStore = orderDataStore;
|
|
|
+ this.orderAnalyticsMapper = orderAnalyticsMapper;
|
|
|
}
|
|
|
|
|
|
public Double calculateTotalGMV(String startDate, String endDate) {
|
|
|
- LocalDateRange range = parseRange(startDate, endDate);
|
|
|
- double sum = 0.0;
|
|
|
- for (OrderRecord order : orderDataStore.getOrders()) {
|
|
|
- if (range.contains(order.getCreatedDate())) {
|
|
|
- sum += order.getOrderActualPayment();
|
|
|
+ if (hasDatabaseOrders()) {
|
|
|
+ try {
|
|
|
+ Double total = orderAnalyticsMapper.selectTotalGmv(startDate, endDate);
|
|
|
+ return total == null ? 0.0 : total;
|
|
|
+ } catch (Exception ignored) {
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ double sum = 0.0;
|
|
|
+ for (OrderAnalyticsRecord order : getAnalyticsOrders(startDate, endDate)) {
|
|
|
+ sum += order.getOrderActualPayment();
|
|
|
+ }
|
|
|
return sum;
|
|
|
}
|
|
|
|
|
|
public List<ProductDTO> getTop5Products(String startDate, String endDate) {
|
|
|
- LocalDateRange range = parseRange(startDate, endDate);
|
|
|
+ if (hasDatabaseOrders()) {
|
|
|
+ try {
|
|
|
+ List<ProductDTO> products = orderAnalyticsMapper.selectTop5Products(startDate, endDate);
|
|
|
+ if (products != null) {
|
|
|
+ return products;
|
|
|
+ }
|
|
|
+ } catch (Exception ignored) {
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
Map<String, Double> salesBySku = new HashMap<>();
|
|
|
Map<String, String> nameBySku = new HashMap<>();
|
|
|
|
|
|
- for (OrderRecord order : orderDataStore.getOrders()) {
|
|
|
- if (!range.contains(order.getCreatedDate())) {
|
|
|
- continue;
|
|
|
- }
|
|
|
+ for (OrderAnalyticsRecord order : getAnalyticsOrders(startDate, endDate)) {
|
|
|
String sku = order.getProductMerchantCode();
|
|
|
if (sku == null || sku.isEmpty()) {
|
|
|
sku = order.getProductId();
|
|
|
@@ -79,19 +96,23 @@ public class AnalysisService {
|
|
|
}
|
|
|
|
|
|
public Map<String, Double> calculateP80AndRBig(String startDate, String endDate) {
|
|
|
- LocalDateRange range = parseRange(startDate, endDate);
|
|
|
- List<Double> payments = new ArrayList<>();
|
|
|
-
|
|
|
- for (OrderRecord order : orderDataStore.getOrders()) {
|
|
|
- if (!range.contains(order.getCreatedDate())) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- double payment = order.getOrderActualPayment();
|
|
|
- if (payment <= 0 && order.getOrderPayable() > 0) {
|
|
|
- payment = order.getOrderPayable();
|
|
|
+ List<Double> payments = null;
|
|
|
+ if (hasDatabaseOrders()) {
|
|
|
+ try {
|
|
|
+ payments = orderAnalyticsMapper.selectPaymentAmounts(startDate, endDate);
|
|
|
+ } catch (Exception ignored) {
|
|
|
}
|
|
|
- if (payment > 0) {
|
|
|
- payments.add(payment);
|
|
|
+ }
|
|
|
+ if (payments == null) {
|
|
|
+ payments = new ArrayList<>();
|
|
|
+ for (OrderAnalyticsRecord order : getAnalyticsOrders(startDate, endDate)) {
|
|
|
+ double payment = order.getOrderActualPayment();
|
|
|
+ if (payment <= 0 && order.getOrderPayable() > 0) {
|
|
|
+ payment = order.getOrderPayable();
|
|
|
+ }
|
|
|
+ if (payment > 0) {
|
|
|
+ payments.add(payment);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -124,14 +145,27 @@ public class AnalysisService {
|
|
|
}
|
|
|
|
|
|
public Map<String, Double> calculateLeakageRate(String startDate, String endDate) {
|
|
|
- LocalDateRange range = parseRange(startDate, endDate);
|
|
|
+ if (hasDatabaseOrders()) {
|
|
|
+ try {
|
|
|
+ OrderLeakageSummary summary = orderAnalyticsMapper.selectLeakageSummary(startDate, endDate);
|
|
|
+ if (summary != null) {
|
|
|
+ double totalRefundAmount = valueOrZero(summary.getTotalRefundAmount());
|
|
|
+ double totalSuccessAmount = valueOrZero(summary.getTotalSuccessAmount());
|
|
|
+ double leakageRate = (totalSuccessAmount > 0) ? (totalRefundAmount / totalSuccessAmount) * 100 : 0.0;
|
|
|
+ Map<String, Double> result = new HashMap<>();
|
|
|
+ result.put("totalRefundAmount", totalRefundAmount);
|
|
|
+ result.put("totalSuccessAmount", totalSuccessAmount);
|
|
|
+ result.put("leakageRatePercent", leakageRate);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ } catch (Exception ignored) {
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
double totalRefundAmount = 0.0;
|
|
|
double totalSuccessAmount = 0.0;
|
|
|
|
|
|
- for (OrderRecord order : orderDataStore.getOrders()) {
|
|
|
- if (!range.contains(order.getCreatedDate())) {
|
|
|
- continue;
|
|
|
- }
|
|
|
+ for (OrderAnalyticsRecord order : getAnalyticsOrders(startDate, endDate)) {
|
|
|
double payment = order.getOrderActualPayment();
|
|
|
if (payment <= 0 && order.getOrderPayable() > 0) {
|
|
|
payment = order.getOrderPayable();
|
|
|
@@ -162,7 +196,8 @@ public class AnalysisService {
|
|
|
long refundAmountCount = 0;
|
|
|
long refundStatusCount = 0;
|
|
|
|
|
|
- for (OrderRecord order : orderDataStore.getOrders()) {
|
|
|
+ List<OrderAnalyticsRecord> orders = getAnalyticsOrders(null, null);
|
|
|
+ for (OrderAnalyticsRecord order : orders) {
|
|
|
String refundStatus = normalize(order.getOrderRefundStatus());
|
|
|
if (!refundStatus.isEmpty()) {
|
|
|
statusCounts.merge(refundStatus, 1L, Long::sum);
|
|
|
@@ -185,7 +220,7 @@ public class AnalysisService {
|
|
|
}
|
|
|
|
|
|
Map<String, Object> result = new HashMap<>();
|
|
|
- result.put("orders", orderDataStore.getOrders().size());
|
|
|
+ result.put("orders", orders.size());
|
|
|
result.put("refundAmountSum", refundAmountSum);
|
|
|
result.put("refundAmountCount", refundAmountCount);
|
|
|
result.put("refundStatusCount", refundStatusCount);
|
|
|
@@ -198,11 +233,21 @@ public class AnalysisService {
|
|
|
}
|
|
|
|
|
|
public List<CoPurchaseDTO> findCoPurchaseRules(String skuKeyword) {
|
|
|
+ if (hasDatabaseOrders()) {
|
|
|
+ try {
|
|
|
+ List<CoPurchaseDTO> rules = orderAnalyticsMapper.selectCoPurchaseRules(normalize(skuKeyword));
|
|
|
+ if (rules != null) {
|
|
|
+ return rules;
|
|
|
+ }
|
|
|
+ } catch (Exception ignored) {
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
String normalizedKeyword = normalize(skuKeyword).toLowerCase();
|
|
|
Map<String, Set<String>> purchaseProducts = new HashMap<>();
|
|
|
Map<String, String> productTitle = new HashMap<>();
|
|
|
|
|
|
- for (OrderRecord order : orderDataStore.getOrders()) {
|
|
|
+ for (OrderAnalyticsRecord order : getAnalyticsOrders(null, null)) {
|
|
|
String purchaseKey = order.getPurchaseId();
|
|
|
if (purchaseKey == null || purchaseKey.isEmpty()) {
|
|
|
purchaseKey = order.getPurchasePaymentId();
|
|
|
@@ -273,13 +318,17 @@ public class AnalysisService {
|
|
|
}
|
|
|
|
|
|
public Double calculateAveragePaymentTime(String startDate, String endDate) {
|
|
|
- LocalDateRange range = parseRange(startDate, endDate);
|
|
|
+ if (hasDatabaseOrders()) {
|
|
|
+ try {
|
|
|
+ Double average = orderAnalyticsMapper.selectAveragePaymentSeconds(startDate, endDate);
|
|
|
+ return average == null ? 0.0 : average;
|
|
|
+ } catch (Exception ignored) {
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
double totalSeconds = 0.0;
|
|
|
long count = 0;
|
|
|
- for (OrderRecord order : orderDataStore.getOrders()) {
|
|
|
- if (!range.contains(order.getCreatedDate())) {
|
|
|
- continue;
|
|
|
- }
|
|
|
+ for (OrderAnalyticsRecord order : getAnalyticsOrders(startDate, endDate)) {
|
|
|
if (order.getCreatedTime() == null || order.getPaidTime() == null) {
|
|
|
continue;
|
|
|
}
|
|
|
@@ -293,16 +342,27 @@ public class AnalysisService {
|
|
|
}
|
|
|
|
|
|
public Map<String, Long> analyzePaymentDecisionFunnel(String startDate, String endDate) {
|
|
|
- LocalDateRange range = parseRange(startDate, endDate);
|
|
|
+ if (hasDatabaseOrders()) {
|
|
|
+ try {
|
|
|
+ OrderFunnelSummary summary = orderAnalyticsMapper.selectPaymentFunnel(startDate, endDate);
|
|
|
+ if (summary != null) {
|
|
|
+ Map<String, Long> funnelData = new HashMap<>();
|
|
|
+ funnelData.put("paidWithin5Mins", valueOrZero(summary.getPaidWithin5Mins()));
|
|
|
+ funnelData.put("paidBetween5And30Mins", valueOrZero(summary.getPaidBetween5And30Mins()));
|
|
|
+ funnelData.put("paidAfter30Mins", valueOrZero(summary.getPaidAfter30Mins()));
|
|
|
+ funnelData.put("unpaidOrders", valueOrZero(summary.getUnpaidOrders()));
|
|
|
+ return funnelData;
|
|
|
+ }
|
|
|
+ } catch (Exception ignored) {
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
long paidWithin5Mins = 0;
|
|
|
long paidBetween5And30Mins = 0;
|
|
|
long paidAfter30Mins = 0;
|
|
|
long unpaidOrders = 0;
|
|
|
|
|
|
- for (OrderRecord order : orderDataStore.getOrders()) {
|
|
|
- if (!range.contains(order.getCreatedDate())) {
|
|
|
- continue;
|
|
|
- }
|
|
|
+ for (OrderAnalyticsRecord order : getAnalyticsOrders(startDate, endDate)) {
|
|
|
if (order.getCreatedTime() == null) {
|
|
|
continue;
|
|
|
}
|
|
|
@@ -346,6 +406,18 @@ public class AnalysisService {
|
|
|
}
|
|
|
|
|
|
public Double calculateTop5Percentage(String startDate, String endDate) {
|
|
|
+ if (hasDatabaseOrders()) {
|
|
|
+ try {
|
|
|
+ Double top5Sum = orderAnalyticsMapper.selectTop5SalesTotal(startDate, endDate);
|
|
|
+ Double totalGmv = orderAnalyticsMapper.selectTotalGmv(startDate, endDate);
|
|
|
+ if (totalGmv == null || totalGmv <= 0) {
|
|
|
+ return 0.0;
|
|
|
+ }
|
|
|
+ return (valueOrZero(top5Sum) / totalGmv) * 100;
|
|
|
+ } catch (Exception ignored) {
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
List<ProductDTO> top5List = getTop5Products(startDate, endDate);
|
|
|
if (top5List == null || top5List.isEmpty()) {
|
|
|
return 0.0;
|
|
|
@@ -361,13 +433,72 @@ public class AnalysisService {
|
|
|
}
|
|
|
|
|
|
public String getMaxOrderDate() {
|
|
|
- LocalDate maxDate = orderDataStore.getMaxOrderDate();
|
|
|
- if (maxDate != null) {
|
|
|
- return maxDate.toString();
|
|
|
+ String maxDate = getDatabaseMaxOrderDate();
|
|
|
+ if (maxDate != null && !maxDate.isEmpty()) {
|
|
|
+ return maxDate;
|
|
|
+ }
|
|
|
+ LocalDate localMaxDate = orderDataStore.getMaxOrderDate();
|
|
|
+ if (localMaxDate != null) {
|
|
|
+ return localMaxDate.toString();
|
|
|
}
|
|
|
return LocalDate.now().toString();
|
|
|
}
|
|
|
|
|
|
+ private List<OrderAnalyticsRecord> getAnalyticsOrders(String startDate, String endDate) {
|
|
|
+ if (hasDatabaseOrders()) {
|
|
|
+ List<OrderAnalyticsRecord> databaseOrders = orderAnalyticsMapper.selectOrders(startDate, endDate);
|
|
|
+ if (databaseOrders != null) {
|
|
|
+ return databaseOrders;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return convertOrders(orderDataStore.getOrders(), startDate, endDate);
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getDatabaseMaxOrderDate() {
|
|
|
+ if (!hasDatabaseOrders()) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return orderAnalyticsMapper.selectMaxOrderDate();
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean hasDatabaseOrders() {
|
|
|
+ try {
|
|
|
+ Long count = orderAnalyticsMapper.countOrders();
|
|
|
+ return count != null && count > 0;
|
|
|
+ } catch (Exception ignored) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<OrderAnalyticsRecord> convertOrders(List<OrderRecord> orders, String startDate, String endDate) {
|
|
|
+ LocalDateRange range = parseRange(startDate, endDate);
|
|
|
+ List<OrderAnalyticsRecord> result = new ArrayList<>();
|
|
|
+ for (OrderRecord order : orders) {
|
|
|
+ if (!range.contains(order.getCreatedDate())) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ OrderAnalyticsRecord item = new OrderAnalyticsRecord();
|
|
|
+ item.setPurchaseId(order.getPurchaseId());
|
|
|
+ item.setOrderId(order.getOrderId());
|
|
|
+ item.setProductId(order.getProductId());
|
|
|
+ item.setProductTitle(order.getProductTitle());
|
|
|
+ item.setProductProperties(order.getProductProperties());
|
|
|
+ item.setProductMerchantCode(order.getProductMerchantCode());
|
|
|
+ item.setOrderPrice(order.getOrderPrice());
|
|
|
+ item.setOrderQuantity(order.getOrderQuantity());
|
|
|
+ item.setOrderStatus(order.getOrderStatus());
|
|
|
+ item.setOrderPayable(order.getOrderPayable());
|
|
|
+ item.setOrderActualPayment(order.getOrderActualPayment());
|
|
|
+ item.setOrderRefundStatus(order.getOrderRefundStatus());
|
|
|
+ item.setOrderRefundAmount(order.getOrderRefundAmount());
|
|
|
+ item.setCreatedTime(order.getCreatedTime());
|
|
|
+ item.setPaidTime(order.getPaidTime());
|
|
|
+ item.setPurchasePaymentId(order.getPurchasePaymentId());
|
|
|
+ result.add(item);
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
private LocalDateRange parseRange(String startDate, String endDate) {
|
|
|
LocalDate start = parseDate(startDate);
|
|
|
LocalDate end = parseDate(endDate);
|
|
|
@@ -406,6 +537,14 @@ public class AnalysisService {
|
|
|
return value == null ? "" : value.trim();
|
|
|
}
|
|
|
|
|
|
+ private double valueOrZero(Double value) {
|
|
|
+ return value == null ? 0.0 : value;
|
|
|
+ }
|
|
|
+
|
|
|
+ private long valueOrZero(Long value) {
|
|
|
+ return value == null ? 0L : value;
|
|
|
+ }
|
|
|
+
|
|
|
private static class LocalDateRange {
|
|
|
private final LocalDate start;
|
|
|
private final LocalDate end;
|