Skip to content
New issue

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

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

Already on GitHub? # to your account

feat(api): add verify budget period config #152

Merged
merged 1 commit into from
Jul 20, 2024
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
8 changes: 4 additions & 4 deletions apps/api/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ model Budget {
preferredCurrency String
type BudgetType @default(SPENDING)

periodConfig BudgetPeriodConfig?
budgetUsers BudgetUser[]
transactions Transaction[]
invitations BudgetUserInvitation[]
periodConfigs BudgetPeriodConfig[]
budgetUsers BudgetUser[]
transactions Transaction[]
invitations BudgetUserInvitation[]
}

enum BudgetType {
Expand Down
111 changes: 93 additions & 18 deletions apps/api/v1/services/budget.service.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
import { calculateBudgetPeriodStartEndDates } from '@6pm/utilities'
import {
calculateBudgetPeriodStartEndDates,
dayjsExtended,
} from '@6pm/utilities'
import type { CreateBudget, UpdateBudget } from '@6pm/validation'
import { type Budget, BudgetUserPermission, type User } from '@prisma/client'
import {
type Budget,
BudgetUserPermission,
type Prisma,
type User,
} from '@prisma/client'
import prisma from '../../lib/prisma'
import { inviteUserToBudget } from './budget-invitation.service'

const BUDGET_INCLUDE: Prisma.BudgetInclude = {
periodConfigs: true,
}

export async function canUserCreateBudget({
// biome-ignore lint/correctness/noUnusedVariables: <explanation>
user,
Expand Down Expand Up @@ -85,12 +97,16 @@ export async function isUserBudgetOwner({
}

export async function findBudget({ budgetId }: { budgetId: string }) {
return prisma.budget.findUnique({
const budget = await prisma.budget.findUnique({
where: { id: budgetId },
include: {
periodConfig: true,
},
include: BUDGET_INCLUDE,
})

if (!budget) {
return null
}

return verifyBudgetPeriods({ budget })
}

export async function createBudget({
Expand Down Expand Up @@ -122,7 +138,7 @@ export async function createBudget({
type,
description,
preferredCurrency,
periodConfig: {
periodConfigs: {
create: {
type: period.type,
amount: period.amount,
Expand All @@ -137,6 +153,7 @@ export async function createBudget({
},
},
},
include: BUDGET_INCLUDE,
})

// Invite users as members
Expand All @@ -156,7 +173,7 @@ export async function createBudget({
throw error
}

return budget
return verifyBudgetPeriods({ budget })
}

export async function updateBudget({
Expand All @@ -168,25 +185,37 @@ export async function updateBudget({
}) {
const { name, description, type, preferredCurrency, period } = data

const latestPeriodConfig = await findBudgetLatestPeriodConfig({ budgetId })

const budget = await prisma.budget.update({
where: { id: budgetId },
data: {
name,
description,
type,
preferredCurrency,
periodConfig: {
periodConfigs: {
update: {
type: period?.type,
amount: period?.amount,
startDate: period?.startDate,
endDate: period?.endDate,
where: {
id: latestPeriodConfig?.id,
},
data: {
type: period?.type,
amount: period?.amount,
startDate: period?.startDate,
endDate: period?.endDate,
},
},
},
},
include: BUDGET_INCLUDE,
})

return budget
if (!budget) {
return null
}

return verifyBudgetPeriods({ budget })
}

export async function deleteBudget({ budgetId }: { budgetId: string }) {
Expand All @@ -199,7 +228,7 @@ export async function findBudgetsOfUser({
user,
permission,
}: { user: User; permission?: BudgetUserPermission }) {
return prisma.budget.findMany({
const budgets = await prisma.budget.findMany({
where: {
budgetUsers: {
some: {
Expand All @@ -208,10 +237,10 @@ export async function findBudgetsOfUser({
},
},
},
include: {
periodConfig: true,
},
include: BUDGET_INCLUDE,
})

return Promise.all(budgets.map((budget) => verifyBudgetPeriods({ budget })))
}

export async function createBudgetUser({
Expand All @@ -231,3 +260,49 @@ export async function createBudgetUser({
},
})
}

async function findBudgetLatestPeriodConfig({
budgetId,
}: {
budgetId: string
}) {
return prisma.budgetPeriodConfig.findFirst({
where: {
budgetId,
},
orderBy: {
startDate: 'desc',
},
})
}

async function verifyBudgetPeriods({ budget }: { budget: Budget }) {
const latestPeriodConfig = await findBudgetLatestPeriodConfig({
budgetId: budget.id,
})

if (!latestPeriodConfig) {
return budget
}

if (
latestPeriodConfig.type === 'MONTHLY' &&
latestPeriodConfig.endDate &&
latestPeriodConfig.endDate < new Date()
) {
await prisma.budgetPeriodConfig.create({
data: {
type: 'MONTHLY',
amount: 1,
startDate: latestPeriodConfig.endDate,
endDate: dayjsExtended().endOf('month').toDate(),
budgetId: budget.id,
},
})
}

return prisma.budget.findUnique({
where: { id: budget.id },
include: BUDGET_INCLUDE,
})
}
Loading