diff --git a/apps/backoffice-v2/src/pages/Home/Home.page.tsx b/apps/backoffice-v2/src/pages/Home/Home.page.tsx
index c4b6160ad..3b11617b0 100644
--- a/apps/backoffice-v2/src/pages/Home/Home.page.tsx
+++ b/apps/backoffice-v2/src/pages/Home/Home.page.tsx
@@ -55,8 +55,9 @@ export const Home: FunctionComponent = () => {
{/* */}
{/* */}
{/**/}
- {(isDemo || isExample) && }
- {!isDemo && !isExample && }
+
+ {/* {(isDemo || isExample) && }
+ {!isDemo && !isExample && } */}
);
diff --git a/services/workflows-service/src/business-report/business-report.controller.external.ts b/services/workflows-service/src/business-report/business-report.controller.external.ts
index 1817d3d3b..6aab84877 100644
--- a/services/workflows-service/src/business-report/business-report.controller.external.ts
+++ b/services/workflows-service/src/business-report/business-report.controller.external.ts
@@ -44,7 +44,6 @@ import {
} from '@/business-report/dtos/business-report-metrics.dto';
import { BusinessReportMetricsDto } from './dtos/business-report-metrics-dto';
import { FEATURE_LIST, TCustomerWithFeatures } from '@/customer/types';
-import dayjs from 'dayjs';
@ApiBearerAuth()
@swagger.ApiTags('Business Reports')
@@ -167,19 +166,17 @@ export class BusinessReportControllerExternal {
@CurrentProject() currentProjectId: TProjectId,
@Query() { from, to }: BusinessReportMetricsRequestQueryDto,
) {
- const { id: customerId } = await this.customerService.getByProjectId(currentProjectId);
+ const { id: customerId, features } = await this.customerService.getByProjectId(
+ currentProjectId,
+ );
- const unmonitoredMerchants = await this.prismaService.business.count({
- where: {
- projectId: currentProjectId,
- metadata: {
- path: ['featureConfig', FEATURE_LIST.ONGOING_MERCHANT_REPORT, 'disabledAt'],
- not: 'null',
- ...(from && { gt: dayjs(from).toDate().getTime() }),
- ...(to && { lte: dayjs(to).toDate().getTime() }),
- },
- },
- });
+ const { totalActiveMerchants, addedMerchantsCount, unmonitoredMerchants } =
+ await this.businessService.getMerchantMonitoringMetrics({
+ projectIds: [currentProjectId],
+ features,
+ from,
+ to,
+ });
const merchantMonitoringMetrics = await this.merchantMonitoringClient.getMetrics({
customerId,
@@ -189,6 +186,8 @@ export class BusinessReportControllerExternal {
return {
...merchantMonitoringMetrics,
+ totalActiveMerchants,
+ addedMerchantsCount,
removedMerchantsCount: unmonitoredMerchants,
};
}
diff --git a/services/workflows-service/src/business/business.repository.ts b/services/workflows-service/src/business/business.repository.ts
index 1e0026371..4dc2c6555 100644
--- a/services/workflows-service/src/business/business.repository.ts
+++ b/services/workflows-service/src/business/business.repository.ts
@@ -106,4 +106,13 @@ export class BusinessRepository {
...args,
});
}
+
+ async count(
+ args: Prisma.SelectSubset,
+ projectIds: TProjectIds,
+ ) {
+ return await this.prismaService.business.count(
+ this.scopeService.scopeFindMany(args, projectIds),
+ );
+ }
}
diff --git a/services/workflows-service/src/business/business.service.ts b/services/workflows-service/src/business/business.service.ts
index 324a81d1d..376e907c1 100755
--- a/services/workflows-service/src/business/business.service.ts
+++ b/services/workflows-service/src/business/business.service.ts
@@ -4,17 +4,19 @@ import {
TCompanyInformation,
} from '@/business/types/business-information';
import { AppLoggerService } from '@/common/app-logger/app-logger.service';
+import { FEATURE_LIST, TCustomerFeaturesConfig, TCustomerWithFeatures } from '@/customer/types';
import { env } from '@/env';
import type { PrismaTransaction, TProjectIds } from '@/types';
import { HttpService } from '@nestjs/axios';
import * as common from '@nestjs/common';
import { Injectable } from '@nestjs/common';
-import { Business } from '@prisma/client';
+import { Business, Prisma } from '@prisma/client';
import { AxiosError } from 'axios';
import { plainToClass } from 'class-transformer';
+import dayjs from 'dayjs';
import { lastValueFrom } from 'rxjs';
+import { z } from 'zod';
import { BusinessRepository } from './business.repository';
-import { TCustomerWithFeatures } from '@/customer/types';
@Injectable()
export class BusinessService {
@@ -66,6 +68,105 @@ export class BusinessService {
return await this.repository.updateById(id, args, transaction);
}
+ async getMerchantMonitoringMetrics({
+ projectIds,
+ features,
+ from,
+ to,
+ }: {
+ projectIds: string[];
+ features: TCustomerWithFeatures['features'];
+ from: string | undefined;
+ to: string | undefined;
+ }): Promise<{
+ totalActiveMerchants: number;
+ addedMerchantsCount: number;
+ unmonitoredMerchants: number;
+ }> {
+ // Metrics are currently mostly requested by month
+ if (!from) {
+ from = dayjs().startOf('month').toISOString();
+ }
+
+ if (!to) {
+ to = dayjs(from).add(1, 'month').toISOString();
+ }
+
+ const allProjectMerchants = await this.repository.findMany({}, projectIds);
+
+ const totalActiveMerchants = allProjectMerchants.filter(b => {
+ const disabledAt = z
+ .number()
+ .nullable()
+ .catch(() => null)
+ .parse(
+ (
+ b.metadata as {
+ featureConfig: Record<
+ (typeof FEATURE_LIST)[keyof typeof FEATURE_LIST],
+ TCustomerFeaturesConfig & { disabledAt: number | null | undefined }
+ >;
+ }
+ )?.featureConfig?.[FEATURE_LIST.ONGOING_MERCHANT_REPORT]?.disabledAt,
+ );
+
+ return (
+ disabledAt === null ||
+ (b.metadata === null && features?.ONGOING_MERCHANT_REPORT?.options?.runByDefault)
+ );
+ }).length;
+
+ const addedMerchantsCount = await this.repository.count(
+ {
+ where: {
+ OR: [
+ {
+ metadata: {
+ path: ['featureConfig', FEATURE_LIST.ONGOING_MERCHANT_REPORT, 'disabledAt'],
+ equals: Prisma.AnyNull,
+ },
+ },
+ features?.ONGOING_MERCHANT_REPORT?.options?.runByDefault
+ ? { metadata: { equals: Prisma.AnyNull } }
+ : {},
+ ],
+ createdAt: {
+ gte: dayjs(from).toISOString(),
+ lt: dayjs(to).toISOString(),
+ },
+ },
+ },
+ projectIds,
+ );
+
+ const unmonitoredMerchants = await this.repository.count(
+ {
+ where: {
+ OR: [
+ {
+ metadata: {
+ path: ['featureConfig', FEATURE_LIST.ONGOING_MERCHANT_REPORT, 'disabledAt'],
+ not: 'null',
+ gte: dayjs(from).toDate().getTime(),
+ lt: dayjs(to).toDate().getTime(),
+ },
+ },
+ !features?.ONGOING_MERCHANT_REPORT?.options?.runByDefault
+ ? { metadata: { equals: Prisma.AnyNull } }
+ : {},
+ ],
+ },
+ },
+ projectIds,
+ );
+
+ return {
+ totalActiveMerchants,
+ addedMerchantsCount,
+ unmonitoredMerchants,
+ };
+ }
+
async fetchCompanyInformation({
registrationNumber,
jurisdictionCode,