Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: first versions for a framework to get metrics from the backend #113

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.metric;

public enum MetricEnum {

BALANCE_SHEET,
INCOME_STATEMENT;

public enum SubMetric {
ASSET_CATEGORIES,
BALANCE_SHEET_OVERVIEW,
TOTAL_EXPENSES,
INCOME_STREAMS
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.cardanofoundation.lob.app.accounting_reporting_core.exception;

public class MetricNotFoundException extends RuntimeException {
public MetricNotFoundException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.Set;

Expand All @@ -20,7 +23,6 @@ public interface ReportRepository extends JpaRepository<ReportEntity, String> {
Set<ReportEntity> findDispatchableTransactions(@Param("organisationId") String organisationId,
Limit limit);


@Query("""
SELECT r FROM accounting_reporting_core.report.ReportEntity r
WHERE r.organisation.id = :organisationId
Expand All @@ -40,4 +42,13 @@ Set<ReportEntity> findDispatchableTransactions(@Param("organisationId") String o
ORDER BY r.ver DESC, r.ledgerDispatchApproved ASC
LIMIT 1""")
Optional<ReportEntity> findLatestByIdControl(@Param("organisationId") String organisationId, @Param("idControl") String idControl);

@Query("""
SELECT r FROM accounting_reporting_core.report.ReportEntity r
WHERE r.organisation.id = :organisationId
AND r.date >= :startDate AND r.date <= :endDate
""")
List<ReportEntity> getReportEntitiesByDateBetween(@Param("organisationId") String organisationId,
@Param("startDate") LocalDate startDate,
@Param("endDate") LocalDate endDate);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package org.cardanofoundation.lob.app.accounting_reporting_core.resource;

import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.GetMetricDataRequest;
import org.cardanofoundation.lob.app.accounting_reporting_core.resource.views.MetricDataResponse;
import org.cardanofoundation.lob.app.accounting_reporting_core.resource.views.MetricView;
import org.cardanofoundation.lob.app.accounting_reporting_core.service.internal.metrics.MetricService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Optional;

@RestController
@RequestMapping("/api/metrics")
@CrossOrigin(origins = "http://localhost:3000")
@RequiredArgsConstructor
@Slf4j
public class MetricController {

private final MetricService metricService;

@Tag(name = "Metrics", description = "Available Metrics")
@GetMapping(value = "/availableMetrics", produces = "application/json")
public ResponseEntity<MetricView> availableDashboards() {
return ResponseEntity.ok(new MetricView(metricService.getAvailableMetrics()));
}

@Tag(name = "Metrics", description = "Get Data from Metrics")
@PostMapping(value = "/data", produces = "application/json")
public ResponseEntity<MetricDataResponse> getDashboardData(@RequestBody GetMetricDataRequest getMetricDataRequest) {
return ResponseEntity.ok(new MetricDataResponse(metricService.getData(
getMetricDataRequest.getMetricView().getMetrics(),
getMetricDataRequest.getOrganisationID(),
Optional.ofNullable(getMetricDataRequest.getStartDate()),
Optional.ofNullable(getMetricDataRequest.getEndDate()))));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.cardanofoundation.lob.app.accounting_reporting_core.resource.views.MetricView;

import java.time.LocalDate;

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class GetMetricDataRequest {

String organisationID;
MetricView metricView;
LocalDate startDate;
LocalDate endDate;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.cardanofoundation.lob.app.accounting_reporting_core.resource.views;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.metric.MetricEnum;

import java.util.List;
import java.util.Map;

@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class MetricDataResponse {

Map<MetricEnum, List<Object>> data;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.cardanofoundation.lob.app.accounting_reporting_core.resource.views;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.metric.MetricEnum;

import java.util.Date;
import java.util.List;
import java.util.Map;

@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class MetricView {

Map<MetricEnum, List<MetricEnum.SubMetric>> metrics;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.cardanofoundation.lob.app.accounting_reporting_core.service.internal.metrics;

import lombok.Getter;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.metric.MetricEnum;
import org.cardanofoundation.lob.app.accounting_reporting_core.exception.MetricNotFoundException;

import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public abstract class MetricExecutor {

protected Map<MetricEnum.SubMetric, MetricFunction> metrics;

@Getter
protected MetricEnum name;

public List<MetricEnum.SubMetric> getAvailableMetrics() {
return Optional.ofNullable(metrics)
.orElseThrow(() -> new MetricNotFoundException(String.format("Metrics %s not initialized", name)))
.keySet().stream().toList();
}

public Object getData(MetricEnum.SubMetric id, String organisationID, Optional<LocalDate> startDate, Optional<LocalDate> endDate) {
Map<MetricEnum.SubMetric, MetricFunction> metricsNotInitialized = Optional.ofNullable(metrics).orElseThrow(() -> new MetricNotFoundException("Metrics not initialized"));
MetricFunction metricFunction = metricsNotInitialized.getOrDefault(id, (String orgId, Optional<LocalDate> start, Optional<LocalDate> end) -> {
throw new MetricNotFoundException(String.format("Metric Function %s not found in %s", id.toString(), name));
});
return metricFunction.getData(organisationID, startDate, endDate);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.cardanofoundation.lob.app.accounting_reporting_core.service.internal.metrics;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Optional;

@FunctionalInterface
public interface MetricFunction {

Object getData(String organisationID, Optional<LocalDate> startDate, Optional<LocalDate> endDate);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.cardanofoundation.lob.app.accounting_reporting_core.service.internal.metrics;

import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.metric.MetricEnum;

import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public interface MetricService {

Map<MetricEnum, List<MetricEnum.SubMetric>> getAvailableMetrics();
Map<MetricEnum, List<Object>> getData(Map<MetricEnum, List<MetricEnum.SubMetric>> metrics, String organisationID, Optional<LocalDate> startDate, Optional<LocalDate> endDate);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.cardanofoundation.lob.app.accounting_reporting_core.service.internal.metrics;

import lombok.RequiredArgsConstructor;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.metric.MetricEnum;
import org.cardanofoundation.lob.app.accounting_reporting_core.exception.MetricNotFoundException;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class MetricServiceImpl implements MetricService{

private final List<MetricExecutor> metricExecutors;

@Override
public Map<MetricEnum, List<MetricEnum.SubMetric>> getAvailableMetrics() {
return metricExecutors.stream()
.map(metricExecutorInterface -> Map.entry(metricExecutorInterface.getName(),
metricExecutorInterface.getAvailableMetrics()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}

@Override
public Map<MetricEnum, List<Object>> getData(Map<MetricEnum, List<MetricEnum.SubMetric>> metrics, String organisationID, Optional<LocalDate> startDate, Optional<LocalDate> endDate) {
return metrics.entrySet().stream()
.map(metric -> {
MetricExecutor metricExecutor = getMetricExecutor(metric.getKey());
List<Object> metricData = metric.getValue().stream().map(s -> metricExecutor.getData(s,organisationID, startDate, endDate)).toList();

return Map.entry(metric.getKey(), metricData);
}).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}

private MetricExecutor getMetricExecutor(MetricEnum metricName) {
return metricExecutors.stream()
.filter(metricExecutorInterface -> metricExecutorInterface.getName().equals(metricName))
.findFirst()
.orElseThrow(() -> new MetricNotFoundException(String.format("Metric %s not found", metricName)));
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.cardanofoundation.lob.app.accounting_reporting_core.service.internal.metrics.executors;

import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.metric.MetricEnum;
import org.cardanofoundation.lob.app.accounting_reporting_core.service.internal.metrics.MetricExecutor;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.util.Map;
import java.util.Optional;

import static org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.metric.MetricEnum.BALANCE_SHEET;

@Component
@RequiredArgsConstructor
public class BalanceSheetMetricService extends MetricExecutor {

@PostConstruct
public void init() {
name = BALANCE_SHEET;
metrics = Map.of(
MetricEnum.SubMetric.ASSET_CATEGORIES, this::getAssetCategories,
MetricEnum.SubMetric.BALANCE_SHEET_OVERVIEW, this::getBalanceSheetOverview
);
}

private Object getBalanceSheetOverview(String organisationID, Optional<LocalDate> startDate, Optional<LocalDate> endDate) {
return Map.of(
"BalanceOverview", 1000
);
}

private Map<String, Integer> getAssetCategories(String organisationID, Optional<LocalDate> startDate, Optional<LocalDate> endDate) {
return Map.of(
"totalAssets", 1000
);
}
}
Loading
Loading