Skip to content

Commit

Permalink
feat(api): verify and create period config base on transaction date (#…
Browse files Browse the repository at this point in the history
…246)

Resolves #236
  • Loading branch information
bkdev98 authored Sep 1, 2024
1 parent a0bad71 commit 31c0730
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 27 deletions.
4 changes: 3 additions & 1 deletion apps/api/v1/routes/transactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,9 @@ const router = new Hono()

logger.debug('Creating transaction %o', data)

const budget = budgetId ? await findBudget({ budgetId }) : null
const budget = budgetId
? await findBudget({ budgetId, anchorDate: data.date })
: null
if (budgetId && (!budget || !(await canUserReadBudget({ user, budget })))) {
logger.error(`Budget not found or user doesn't have read access %o`, {
budgetId,
Expand Down
55 changes: 39 additions & 16 deletions apps/api/v1/services/budget.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import {
calculateBudgetPeriodStartEndDates,
dayjsExtended,
} from '@6pm/utilities'
import { calculateBudgetPeriodStartEndDates } from '@6pm/utilities'
import type { CreateBudget, UpdateBudget } from '@6pm/validation'
import {
type Budget,
Expand Down Expand Up @@ -101,7 +98,10 @@ export async function isUserBudgetOwner({
return !!budgetUser
}

export async function findBudget({ budgetId }: { budgetId: string }) {
export async function findBudget({
budgetId,
anchorDate,
}: { budgetId: string; anchorDate?: Date }) {
const budget = await prisma.budget.findUnique({
where: { id: budgetId },
include: BUDGET_INCLUDE,
Expand All @@ -111,7 +111,7 @@ export async function findBudget({ budgetId }: { budgetId: string }) {
return null
}

return verifyBudgetPeriods({ budget })
return verifyBudgetPeriods({ budget, anchorDate })
}

export async function createBudget({
Expand Down Expand Up @@ -282,7 +282,27 @@ async function findBudgetLatestPeriodConfig({
})
}

async function verifyBudgetPeriods({ budget }: { budget: BudgetPopulated }) {
async function findPeriodConfigByDate({
budgetId,
date,
}: { budgetId: string; date: Date }) {
return prisma.budgetPeriodConfig.findFirst({
where: {
budgetId,
startDate: {
lte: date,
},
endDate: {
gte: date,
},
},
})
}

async function verifyBudgetPeriods({
budget,
anchorDate = new Date(),
}: { budget: BudgetPopulated; anchorDate?: Date }) {
const latestPeriodConfig = await findBudgetLatestPeriodConfig({
budgetId: budget.id,
})
Expand All @@ -291,18 +311,21 @@ async function verifyBudgetPeriods({ budget }: { budget: BudgetPopulated }) {
return budget
}

if (
latestPeriodConfig.type === 'MONTHLY' &&
latestPeriodConfig.endDate &&
latestPeriodConfig.endDate < new Date()
) {
const periodConfig = await findPeriodConfigByDate({
budgetId: budget.id,
date: anchorDate,
})

if (!periodConfig) {
await prisma.budgetPeriodConfig.create({
data: {
type: 'MONTHLY',
amount: 1,
startDate: latestPeriodConfig.endDate,
endDate: dayjsExtended().endOf('month').toDate(),
type: latestPeriodConfig.type,
amount: latestPeriodConfig.amount,
budgetId: budget.id,
...calculateBudgetPeriodStartEndDates({
anchorDate,
type: latestPeriodConfig.type,
}),
},
})
}
Expand Down
10 changes: 8 additions & 2 deletions apps/api/v1/services/transaction.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ export async function canUserReadTransaction({

// If user is the member of the budget of the transaction, they can read it
if (transaction.budgetId) {
const budget = await findBudget({ budgetId: transaction.budgetId })
const budget = await findBudget({
budgetId: transaction.budgetId,
anchorDate: transaction.date,
})
return budget && (await isUserBudgetMember({ user, budget }))
}

Expand Down Expand Up @@ -80,7 +83,10 @@ export async function canUserUpdateTransaction({

// If user owns the budget of the transaction, they can update it
if (transaction.budgetId) {
const budget = await findBudget({ budgetId: transaction.budgetId })
const budget = await findBudget({
budgetId: transaction.budgetId,
anchorDate: transaction.date,
})
return budget && (await isUserBudgetOwner({ user, budget }))
}

Expand Down
31 changes: 23 additions & 8 deletions packages/utilities/src/date/period.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,38 @@ export function calculateBudgetPeriodStartEndDates({
switch (type) {
case BudgetPeriodType.WEEKLY:
return {
startDate: dayjsExtended(anchorDate).startOf('week').toDate(),
endDate: dayjsExtended(anchorDate).endOf('week').toDate(),
startDate: dayjsExtended(anchorDate)
.startOf('day')
.startOf('week')
.toDate(),
endDate: dayjsExtended(anchorDate).endOf('day').endOf('week').toDate(),
}
case BudgetPeriodType.MONTHLY:
return {
startDate: dayjsExtended(anchorDate).startOf('month').toDate(),
endDate: dayjsExtended(anchorDate).endOf('month').toDate(),
startDate: dayjsExtended(anchorDate)
.startOf('day')
.startOf('month')
.toDate(),
endDate: dayjsExtended(anchorDate).endOf('day').endOf('month').toDate(),
}
case BudgetPeriodType.QUARTERLY:
return {
startDate: dayjsExtended(anchorDate).startOf('quarter').toDate(),
endDate: dayjsExtended(anchorDate).endOf('quarter').toDate(),
startDate: dayjsExtended(anchorDate)
.startOf('day')
.startOf('quarter')
.toDate(),
endDate: dayjsExtended(anchorDate)
.endOf('day')
.endOf('quarter')
.toDate(),
}
case BudgetPeriodType.YEARLY:
return {
startDate: dayjsExtended(anchorDate).startOf('year').toDate(),
endDate: dayjsExtended(anchorDate).endOf('year').toDate(),
startDate: dayjsExtended(anchorDate)
.startOf('day')
.startOf('year')
.toDate(),
endDate: dayjsExtended(anchorDate).endOf('day').endOf('year').toDate(),
}
default:
return {
Expand Down

0 comments on commit 31c0730

Please sign in to comment.