update code ngu
This commit is contained in:
13
src/Analytic/analytic.module.ts
Normal file
13
src/Analytic/analytic.module.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { Module } from '@nestjs/common'
|
||||||
|
import { AnalyticSchema } from './analytic.schema'
|
||||||
|
import { ServiceSchema } from 'src/Service/service.schema'
|
||||||
|
import { CenterSchema } from 'src/Center/center.schema'
|
||||||
|
import { OrderSchema } from 'src/Order/order.schema'
|
||||||
|
import { PayosModule } from 'src/Payos/payos.module'
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [PayosModule],
|
||||||
|
providers: [AnalyticSchema, ServiceSchema, CenterSchema, OrderSchema],
|
||||||
|
exports: [AnalyticSchema, ServiceSchema, CenterSchema, OrderSchema],
|
||||||
|
})
|
||||||
|
export class AnalyticModule {}
|
||||||
458
src/Analytic/analytic.schema.ts
Normal file
458
src/Analytic/analytic.schema.ts
Normal file
@@ -0,0 +1,458 @@
|
|||||||
|
import { Inject, Injectable } from '@nestjs/common'
|
||||||
|
import { OrderStatus, Prisma, Role, ServiceStatus } from '@prisma/client'
|
||||||
|
import {
|
||||||
|
Pothos,
|
||||||
|
PothosRef,
|
||||||
|
PothosSchema,
|
||||||
|
SchemaBuilderToken,
|
||||||
|
} from '@smatch-corp/nestjs-pothos'
|
||||||
|
import { DateTimeUtils } from 'src/common/utils/datetime.utils'
|
||||||
|
import { Builder } from 'src/Graphql/graphql.builder'
|
||||||
|
import { PrismaService } from 'src/Prisma/prisma.service'
|
||||||
|
import { ServiceSchema } from 'src/Service/service.schema'
|
||||||
|
import { CenterSchema } from 'src/Center/center.schema'
|
||||||
|
import { OrderSchema } from 'src/Order/order.schema'
|
||||||
|
@Injectable()
|
||||||
|
export class AnalyticSchema extends PothosSchema {
|
||||||
|
constructor(
|
||||||
|
@Inject(SchemaBuilderToken) private readonly builder: Builder,
|
||||||
|
private readonly prisma: PrismaService,
|
||||||
|
private readonly serviceSchema: ServiceSchema,
|
||||||
|
private readonly centerSchema: CenterSchema,
|
||||||
|
private readonly orderSchema: OrderSchema,
|
||||||
|
) {
|
||||||
|
super()
|
||||||
|
}
|
||||||
|
|
||||||
|
@PothosRef()
|
||||||
|
customerAnalytic() {
|
||||||
|
return this.builder.simpleObject('CustomerAnalytic', {
|
||||||
|
description: 'A customer analytic in the system.',
|
||||||
|
fields: (t) => ({
|
||||||
|
userId: t.string({
|
||||||
|
description: 'The ID of the user.',
|
||||||
|
}),
|
||||||
|
activeServiceCount: t.int({
|
||||||
|
description: 'The number of active services.',
|
||||||
|
}),
|
||||||
|
totalServiceCount: t.int({
|
||||||
|
description: 'The total number of services.',
|
||||||
|
}),
|
||||||
|
totalSpent: t.float({
|
||||||
|
description: 'The total amount spent.',
|
||||||
|
}),
|
||||||
|
updatedAt: t.field({
|
||||||
|
type: 'DateTime',
|
||||||
|
description: 'The date the analytic was last updated.',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
@PothosRef()
|
||||||
|
mentorAnalytic() {
|
||||||
|
return this.builder.simpleObject('MentorAnalytic', {
|
||||||
|
description: 'A mentor analytic in the system.',
|
||||||
|
fields: (t) => ({
|
||||||
|
userId: t.string({
|
||||||
|
description: 'The ID of the mentor.',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
@PothosRef()
|
||||||
|
centerAnalytic() {
|
||||||
|
return this.builder.simpleObject('CenterAnalytic', {
|
||||||
|
description: 'A center analytic in the system.',
|
||||||
|
fields: (t) => ({
|
||||||
|
centerId: t.string({
|
||||||
|
description: 'The ID of the center.',
|
||||||
|
}),
|
||||||
|
activeMentorCount: t.int({
|
||||||
|
description: 'The number of active mentors.',
|
||||||
|
}),
|
||||||
|
activeServiceCount: t.int({
|
||||||
|
description: 'The number of active services.',
|
||||||
|
}),
|
||||||
|
totalServiceCount: t.int({
|
||||||
|
description: 'The total number of services.',
|
||||||
|
}),
|
||||||
|
revenue: t.int({
|
||||||
|
description: 'The total revenue.',
|
||||||
|
}),
|
||||||
|
rating: t.float({
|
||||||
|
description: 'The average rating.',
|
||||||
|
nullable: true,
|
||||||
|
}),
|
||||||
|
updatedAt: t.field({
|
||||||
|
type: 'DateTime',
|
||||||
|
description: 'The date the analytic was last updated.',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
@PothosRef()
|
||||||
|
platformAnalytic() {
|
||||||
|
return this.builder.simpleObject('PlatformAnalytic', {
|
||||||
|
description: 'A platform analytic in the system.',
|
||||||
|
fields: (t) => ({
|
||||||
|
topServices: t.field({
|
||||||
|
type: [this.serviceSchema.service()],
|
||||||
|
description: 'The top services by revenue.',
|
||||||
|
}),
|
||||||
|
topCenters: t.field({
|
||||||
|
type: [this.centerSchema.center()],
|
||||||
|
description: 'The top centers by revenue.',
|
||||||
|
}),
|
||||||
|
pendingRefunds: t.field({
|
||||||
|
type: [this.orderSchema.order()],
|
||||||
|
description: 'The pending refunds.',
|
||||||
|
}),
|
||||||
|
activeCenterCount: t.int({
|
||||||
|
description: 'The number of active centers.',
|
||||||
|
}),
|
||||||
|
totalCenterCount: t.int({
|
||||||
|
description: 'The total number of centers.',
|
||||||
|
}),
|
||||||
|
totalUserCount: t.int({
|
||||||
|
description: 'The total number of users.',
|
||||||
|
}),
|
||||||
|
activeMentorCount: t.int({
|
||||||
|
description: 'The number of active mentors.',
|
||||||
|
}),
|
||||||
|
totalMentorCount: t.int({
|
||||||
|
description: 'The total number of mentors.',
|
||||||
|
}),
|
||||||
|
revenue: t.int({
|
||||||
|
description: 'The total revenue.',
|
||||||
|
}),
|
||||||
|
approvedServiceCount: t.int({
|
||||||
|
description: 'The number of approved services.',
|
||||||
|
}),
|
||||||
|
rejectedServiceCount: t.int({
|
||||||
|
description: 'The number of rejected services.',
|
||||||
|
}),
|
||||||
|
updatedAt: t.field({
|
||||||
|
type: 'DateTime',
|
||||||
|
description: 'The date the analytic was last updated.',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
@PothosRef()
|
||||||
|
timeframes() {
|
||||||
|
return this.builder.enumType('Timeframe', {
|
||||||
|
values: ['day', 'week', 'month', 'year'],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
@PothosRef()
|
||||||
|
serviceSortBy() {
|
||||||
|
return this.builder.enumType('ServiceSortBy', {
|
||||||
|
values: ['order', 'rating'],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
@PothosRef()
|
||||||
|
centerSortBy() {
|
||||||
|
return this.builder.enumType('CenterSortBy', {
|
||||||
|
values: ['revenue', 'rating', 'services'],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
@Pothos()
|
||||||
|
init(): void {
|
||||||
|
this.builder.queryFields((t) => ({
|
||||||
|
customerAnalytic: t.field({
|
||||||
|
type: this.customerAnalytic(),
|
||||||
|
description: 'Retrieve a single customer analytic.',
|
||||||
|
resolve: async (_parent, _args, ctx, _info) => {
|
||||||
|
if (ctx.isSubscription) throw new Error('Not allowed')
|
||||||
|
if (!ctx.http.me) throw new Error('Unauthorized')
|
||||||
|
if (ctx.http.me.role !== Role.CUSTOMER)
|
||||||
|
throw new Error('Only customers can access this data')
|
||||||
|
// calculate analytic
|
||||||
|
const activeServiceCount = await this.prisma.order.count({
|
||||||
|
where: {
|
||||||
|
userId: ctx.http.me.id,
|
||||||
|
status: OrderStatus.PAID,
|
||||||
|
schedule: {
|
||||||
|
dates: {
|
||||||
|
some: {
|
||||||
|
end: {
|
||||||
|
gte: DateTimeUtils.now().toJSDate(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const totalServiceCount = await this.prisma.order.count({
|
||||||
|
where: {
|
||||||
|
userId: ctx.http.me.id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const totalSpent = await this.prisma.order.aggregate({
|
||||||
|
where: {
|
||||||
|
userId: ctx.http.me.id,
|
||||||
|
status: OrderStatus.PAID,
|
||||||
|
},
|
||||||
|
_sum: {
|
||||||
|
total: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
userId: ctx.http.me.id,
|
||||||
|
activeServiceCount: activeServiceCount,
|
||||||
|
totalServiceCount: totalServiceCount,
|
||||||
|
totalSpent: totalSpent._sum.total,
|
||||||
|
updatedAt: DateTimeUtils.now(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
mentorAnalytic: t.field({
|
||||||
|
type: this.mentorAnalytic(),
|
||||||
|
description: 'Retrieve a single mentor analytic.',
|
||||||
|
resolve: async (_parent, _args, ctx, _info) => {
|
||||||
|
if (ctx.isSubscription) throw new Error('Not allowed')
|
||||||
|
if (!ctx.http.me) throw new Error('Unauthorized')
|
||||||
|
if (ctx.http.me.role !== Role.CENTER_MENTOR)
|
||||||
|
throw new Error('Only center mentors can access this data')
|
||||||
|
// calculate analytic
|
||||||
|
return {
|
||||||
|
userId: ctx.http.me.id,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
centerAnalytic: t.field({
|
||||||
|
type: this.centerAnalytic(),
|
||||||
|
description: 'Retrieve a single center analytic.',
|
||||||
|
resolve: async (_parent, _args, ctx, _info) => {
|
||||||
|
if (ctx.isSubscription) throw new Error('Not allowed')
|
||||||
|
if (!ctx.http.me) throw new Error('Unauthorized')
|
||||||
|
if (ctx.http.me.role !== Role.CENTER_OWNER)
|
||||||
|
throw new Error('Only center owners can access this data')
|
||||||
|
// get center by owner id
|
||||||
|
const center = await this.prisma.center.findUnique({
|
||||||
|
where: {
|
||||||
|
centerOwnerId: ctx.http.me.id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if (!center) throw new Error('Center not found')
|
||||||
|
// calculate analytic
|
||||||
|
|
||||||
|
// active mentor include center owner
|
||||||
|
const activeMentorCount = await this.prisma.user.count({
|
||||||
|
where: {
|
||||||
|
center: {
|
||||||
|
centerOwnerId: ctx.http.me.id,
|
||||||
|
},
|
||||||
|
banned: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const activeServiceCount = await this.prisma.service.count({
|
||||||
|
where: {
|
||||||
|
centerId: center.id,
|
||||||
|
status: ServiceStatus.APPROVED,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const totalServiceCount = await this.prisma.service.count({
|
||||||
|
where: {
|
||||||
|
centerId: center.id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
// calculate revenue from orders of services in the center and factor in commission percentage
|
||||||
|
// query all orders of services in the center and calculate actual revenue of each order
|
||||||
|
// then sum up the revenue
|
||||||
|
let revenue = 0
|
||||||
|
const orders = await this.prisma.order.findMany({
|
||||||
|
where: {
|
||||||
|
service: { centerId: center.id },
|
||||||
|
status: OrderStatus.PAID,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
for (const order of orders) {
|
||||||
|
const service = await this.prisma.service.findUnique({
|
||||||
|
where: { id: order.serviceId },
|
||||||
|
})
|
||||||
|
if (!service) continue
|
||||||
|
const commission = service.commission
|
||||||
|
const actualRevenue =
|
||||||
|
(order.total || 0) - (order.total || 0) * commission
|
||||||
|
revenue += actualRevenue
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
centerId: center.id,
|
||||||
|
activeMentorCount: activeMentorCount,
|
||||||
|
activeServiceCount: activeServiceCount,
|
||||||
|
totalServiceCount: totalServiceCount,
|
||||||
|
revenue: revenue,
|
||||||
|
updatedAt: DateTimeUtils.now(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
platformAnalytic: t.field({
|
||||||
|
type: this.platformAnalytic(),
|
||||||
|
args: {
|
||||||
|
take: t.arg({
|
||||||
|
type: 'Int',
|
||||||
|
description: 'The number of services to take.',
|
||||||
|
required: true,
|
||||||
|
}),
|
||||||
|
serviceSortBy: t.arg({
|
||||||
|
type: this.serviceSortBy(),
|
||||||
|
description: 'The field to sort by.',
|
||||||
|
required: true,
|
||||||
|
}),
|
||||||
|
centerSortBy: t.arg({
|
||||||
|
type: this.centerSortBy(),
|
||||||
|
description: 'The field to sort by.',
|
||||||
|
required: true,
|
||||||
|
}),
|
||||||
|
timeframes: t.arg({
|
||||||
|
type: this.timeframes(),
|
||||||
|
description: 'The frame of time Eg day, week, month, year.',
|
||||||
|
required: true,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
description: 'Retrieve a single platform analytic.',
|
||||||
|
resolve: async (_parent, args, ctx, _info) => {
|
||||||
|
if (ctx.isSubscription) throw new Error('Not allowed')
|
||||||
|
if (!ctx.http.me) throw new Error('Unauthorized')
|
||||||
|
if (
|
||||||
|
ctx.http.me.role !== Role.ADMIN &&
|
||||||
|
ctx.http.me.role !== Role.MODERATOR
|
||||||
|
)
|
||||||
|
throw new Error('Only admins and moderators can access this data')
|
||||||
|
// calculate analytic for services sorted by args.serviceSortBy and args.timeframes
|
||||||
|
const topServices = await this.prisma.service.findMany({
|
||||||
|
where: {
|
||||||
|
status: ServiceStatus.APPROVED,
|
||||||
|
},
|
||||||
|
orderBy: {
|
||||||
|
[args.serviceSortBy]: {
|
||||||
|
_count: Prisma.SortOrder.desc,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
take: args.take,
|
||||||
|
})
|
||||||
|
// get top centers by args.centerSortBy
|
||||||
|
const topCenters = await this.prisma.center.findMany({
|
||||||
|
orderBy: {
|
||||||
|
[args.centerSortBy]: {
|
||||||
|
_count: Prisma.SortOrder.desc,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
take: args.take,
|
||||||
|
})
|
||||||
|
// get pending refunds
|
||||||
|
const pendingRefunds = await this.prisma.order.findMany({
|
||||||
|
where: {
|
||||||
|
status: OrderStatus.PENDING_REFUND,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
// get active center count by center owner not banned and have schedule with dates in the future
|
||||||
|
const activeCenterCount = await this.prisma.center.count({
|
||||||
|
where: {
|
||||||
|
centerOwner: {
|
||||||
|
banned: false,
|
||||||
|
},
|
||||||
|
centerMentors: {
|
||||||
|
some: {
|
||||||
|
managedService: {
|
||||||
|
some: {
|
||||||
|
schedule: {
|
||||||
|
some: {
|
||||||
|
dates: {
|
||||||
|
some: {
|
||||||
|
end: {
|
||||||
|
gte: DateTimeUtils.now().toJSDate(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
// get total center count
|
||||||
|
const totalCenterCount = await this.prisma.center.count()
|
||||||
|
// get total user count
|
||||||
|
const totalUserCount = await this.prisma.user.count()
|
||||||
|
// get active mentor count
|
||||||
|
const activeMentorCount = await this.prisma.user.count({
|
||||||
|
where: {
|
||||||
|
role: Role.CENTER_MENTOR,
|
||||||
|
banned: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
// get total mentor count
|
||||||
|
const totalMentorCount = await this.prisma.user.count({
|
||||||
|
where: {
|
||||||
|
role: Role.CENTER_MENTOR,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
// get approved service count
|
||||||
|
const approvedServiceCount = await this.prisma.service.count({
|
||||||
|
where: {
|
||||||
|
status: ServiceStatus.APPROVED,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
// get rejected service count
|
||||||
|
const rejectedServiceCount = await this.prisma.service.count({
|
||||||
|
where: {
|
||||||
|
status: ServiceStatus.REJECTED,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
// get revenue
|
||||||
|
let revenue = 0
|
||||||
|
// query all orders of services in all centers in the past args.timeframes and calculate actual revenue of each order by convert commission percentage to float
|
||||||
|
// convert args.timeframes to number of days
|
||||||
|
const timeframes = DateTimeUtils.subtractDaysFromTimeframe(
|
||||||
|
args.timeframes,
|
||||||
|
)
|
||||||
|
const orders = await this.prisma.order.findMany({
|
||||||
|
where: {
|
||||||
|
status: OrderStatus.PAID,
|
||||||
|
createdAt: {
|
||||||
|
gte: timeframes.toJSDate(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
for (const order of orders) {
|
||||||
|
const service = await this.prisma.service.findUnique({
|
||||||
|
where: { id: order.serviceId },
|
||||||
|
})
|
||||||
|
if (!service) continue
|
||||||
|
const commission = service.commission
|
||||||
|
const actualRevenue =
|
||||||
|
(order.total || 0) - (order.total || 0) * commission
|
||||||
|
revenue += actualRevenue
|
||||||
|
}
|
||||||
|
// return analytic
|
||||||
|
return {
|
||||||
|
topServices: topServices,
|
||||||
|
topCenters: topCenters,
|
||||||
|
pendingRefunds: pendingRefunds,
|
||||||
|
activeCenterCount: activeCenterCount,
|
||||||
|
totalCenterCount: totalCenterCount,
|
||||||
|
totalUserCount: totalUserCount,
|
||||||
|
activeMentorCount: activeMentorCount,
|
||||||
|
totalMentorCount: totalMentorCount,
|
||||||
|
revenue: revenue,
|
||||||
|
approvedServiceCount: approvedServiceCount,
|
||||||
|
rejectedServiceCount: rejectedServiceCount,
|
||||||
|
updatedAt: DateTimeUtils.now(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -80,7 +80,7 @@ export class CronService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// cron every 1 minute to check payment status where created_at is more than 15 minutes
|
// cron every 1 minute to check payment status where created_at is more than 15 minutes
|
||||||
@Cron(CronExpression.EVERY_MINUTE)
|
@Cron(CronExpression.EVERY_10_MINUTES)
|
||||||
async checkPaymentStatus() {
|
async checkPaymentStatus() {
|
||||||
Logger.log('Checking payment status', 'checkPaymentStatus')
|
Logger.log('Checking payment status', 'checkPaymentStatus')
|
||||||
const payments = await this.prisma.payment.findMany({
|
const payments = await this.prisma.payment.findMany({
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
import { Module } from '@nestjs/common'
|
|
||||||
import { FinanceSchema } from './finance.schema'
|
|
||||||
|
|
||||||
@Module({
|
|
||||||
providers: [FinanceSchema],
|
|
||||||
exports: [FinanceSchema],
|
|
||||||
})
|
|
||||||
export class FinanceModule {}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
import { Inject, Injectable } from '@nestjs/common'
|
|
||||||
import { Pothos, PothosRef, PothosSchema, SchemaBuilderToken } from '@smatch-corp/nestjs-pothos'
|
|
||||||
import { Builder } from 'src/Graphql/graphql.builder'
|
|
||||||
import { PrismaService } from 'src/Prisma/prisma.service'
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class FinanceSchema extends PothosSchema {
|
|
||||||
constructor(
|
|
||||||
@Inject(SchemaBuilderToken) private readonly builder: Builder,
|
|
||||||
private readonly prisma: PrismaService,
|
|
||||||
) {
|
|
||||||
super()
|
|
||||||
}
|
|
||||||
|
|
||||||
@PothosRef()
|
|
||||||
finance() {
|
|
||||||
return this.builder.simpleObject('Finance', {
|
|
||||||
description: 'A finance in the system.',
|
|
||||||
fields: (t) => ({
|
|
||||||
id: t.string({
|
|
||||||
description: 'The ID of the finance.',
|
|
||||||
}),
|
|
||||||
amount: t.string({
|
|
||||||
description: 'The amount of the finance.',
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
@PothosRef()
|
|
||||||
init(): void {
|
|
||||||
this.builder.queryFields((t) => ({
|
|
||||||
finance: t.field({
|
|
||||||
type: this.finance(),
|
|
||||||
description: 'Retrieve a single finance by its unique identifier.',
|
|
||||||
resolve: async () => {
|
|
||||||
return {
|
|
||||||
id: '1',
|
|
||||||
amount: '100',
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -42,7 +42,7 @@ import { initContextCache } from '@pothos/core'
|
|||||||
import { RedisPubSub } from 'graphql-redis-subscriptions'
|
import { RedisPubSub } from 'graphql-redis-subscriptions'
|
||||||
import { DocumentModule } from 'src/Document/document.module'
|
import { DocumentModule } from 'src/Document/document.module'
|
||||||
import { Context } from 'graphql-ws'
|
import { Context } from 'graphql-ws'
|
||||||
import { FinanceModule } from 'src/Finance/finance.module'
|
import { AnalyticModule } from 'src/Analytic/analytic.module'
|
||||||
import { MeetingRoomModule } from 'src/MeetingRoom/meetingroom.module'
|
import { MeetingRoomModule } from 'src/MeetingRoom/meetingroom.module'
|
||||||
|
|
||||||
@Global()
|
@Global()
|
||||||
@@ -79,7 +79,7 @@ import { MeetingRoomModule } from 'src/MeetingRoom/meetingroom.module'
|
|||||||
WorkshopMeetingRoomModule,
|
WorkshopMeetingRoomModule,
|
||||||
AdminNoteModule,
|
AdminNoteModule,
|
||||||
DocumentModule,
|
DocumentModule,
|
||||||
FinanceModule,
|
AnalyticModule,
|
||||||
MeetingRoomModule,
|
MeetingRoomModule,
|
||||||
PothosModule.forRoot({
|
PothosModule.forRoot({
|
||||||
builder: {
|
builder: {
|
||||||
|
|||||||
@@ -142,4 +142,19 @@ export class DateTimeUtils {
|
|||||||
static getTimeFromDateTime(dateTime: DateTime): TimeType {
|
static getTimeFromDateTime(dateTime: DateTime): TimeType {
|
||||||
return this.toTime(`${dateTime.hour}:${dateTime.minute}:${dateTime.second}`)
|
return this.toTime(`${dateTime.hour}:${dateTime.minute}:${dateTime.second}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static subtractDaysFromTimeframe(timeframe: string): DateTime {
|
||||||
|
// convert timeframe to number of days: 'day' -> 1, 'week' -> 7, 'month' -> 30, 'year' -> 365
|
||||||
|
const daysMap: Record<string, number> = {
|
||||||
|
day: 1,
|
||||||
|
week: 7,
|
||||||
|
month: 30,
|
||||||
|
year: 365,
|
||||||
|
}
|
||||||
|
const days = daysMap[timeframe.toLowerCase()]
|
||||||
|
if (days === undefined) {
|
||||||
|
throw new Error(`Invalid timeframe: ${timeframe}`)
|
||||||
|
}
|
||||||
|
return DateTime.now().minus({ days })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user