switch to prisma

This commit is contained in:
Thomas Ruoff
2022-10-11 11:43:32 +02:00
parent 41342475ba
commit 1ef9b14e95
28 changed files with 764 additions and 780 deletions

View File

@@ -17,6 +17,6 @@ export function getNextBigger<T>(array: T[], pivot: T): T {
return array.sort().find((day) => day > pivot)
}
export function uniqueFilter(value, index, self) {
export function uniqueFilter<T>(value: T, index: number, self: T[]) {
return self.indexOf(value) === index
}

View File

@@ -1,79 +1,27 @@
import { MILAGE_TARIFS } from '../db/enums'
import { AdditionalCost, Bill } from '../db/bill'
import { Bill, Prisma } from '@prisma/client'
import fetch from './fetch'
function roundToCent(amount: number): number {
return Math.round(amount * 100) / 100
}
export function getMilageCosts({
tarif,
km,
}: {
tarif: MILAGE_TARIFS
km: number
}): number {
if (tarif === MILAGE_TARIFS.NOCHARGE) {
return 0
}
if (km <= 0) {
return 0
}
let rate: number
if (tarif === MILAGE_TARIFS.EXTERN) {
if (km <= 200) {
rate = 0.42
} else if (km <= 1000) {
rate = 0.25
} else if (km <= 2000) {
rate = 0.2
} else {
rate = 0.18
}
}
if (tarif === MILAGE_TARIFS.INTERN) {
if (km <= 200) {
rate = 0.37
} else if (km <= 1000) {
rate = 0.22
} else if (km <= 2000) {
rate = 0.15
} else {
rate = 0.13
}
}
if (rate === undefined) {
throw Error('Unable to determine rate')
}
return roundToCent(km * rate)
}
export function getBillTotal({
tarif,
milage,
additionalCosts,
}: {
tarif: MILAGE_TARIFS
tarif: Prisma.Decimal
milage?: number
additionalCosts: AdditionalCost[]
}): number {
const milageCosts = getMilageCosts({ tarif, km: milage })
additionalCosts: Prisma.AdditionalCostsCreateInput[]
}): Prisma.Decimal {
const milageCosts = tarif.mul(milage)
const additionalCostsSum = additionalCosts
.map(({ value }) => value)
.reduce((acc: number, value: number) => acc + value, 0)
.reduce((acc, {value} ) => (value as Prisma.Decimal).plus(acc), new Prisma.Decimal(0))
return roundToCent(milageCosts + additionalCostsSum)
return additionalCostsSum.add(milageCosts).toDecimalPlaces(2);
}
export async function createBill(
bookingUuid: string,
bill: Bill
bill: Prisma.BillCreateInput
): Promise<Bill> {
return fetch(`/api/bookings/${bookingUuid}/bill`, {
method: 'POST',
@@ -83,7 +31,7 @@ export async function createBill(
export async function patchBill(
bookingUuid: string,
bill: Bill
bill: Prisma.BillUpdateInput
): Promise<Bill> {
return fetch(`/api/bookings/${bookingUuid}/bill`, {
method: 'POST',

View File

@@ -1,23 +1,22 @@
import { BookFormData } from '../context/book'
import { BOOKING_STATUS } from '../db/enums'
import { Prisma, BookingStatus } from '@prisma/client'
import fetch from './fetch'
export function getBookingStatus(status: BOOKING_STATUS) {
export function getBookingStatus(status: BookingStatus) {
switch (status) {
case BOOKING_STATUS.REQUESTED:
case BookingStatus.REQUESTED:
return 'Angefragt'
case BOOKING_STATUS.CONFIRMED:
case BookingStatus.CONFIRMED:
return 'Bestätigt'
case BOOKING_STATUS.REJECTED:
case BookingStatus.REJECTED:
return 'Abgewiesen'
case BOOKING_STATUS.CANCELED:
case BookingStatus.CANCELED:
return 'Storniert'
default:
return 'Unbekannt - bitte kontaktieren Sie uns!'
}
}
export async function createBooking(formData: BookFormData) {
export async function createBooking(formData: Prisma.BookingCreateInput) {
return fetch('/api/bookings', {
method: 'POST',
body: formData,
@@ -27,13 +26,13 @@ export async function createBooking(formData: BookFormData) {
export async function cancelBooking(uuid: string) {
return fetch(`/api/bookings/${uuid}`, {
method: 'PATCH',
body: { status: BOOKING_STATUS.CANCELED },
body: { status: BookingStatus.CANCELED },
})
}
export async function patchBooking(
uuid: string,
bookingData: Partial<BookFormData>
bookingData: Prisma.BookingUpdateInput
) {
return fetch(`/api/bookings/${uuid}`, {
method: 'PATCH',

View File

@@ -1,4 +1,4 @@
import { parse, format, addDays, subDays } from 'date-fns'
import { parse, format, addDays, subDays, differenceInDays } from 'date-fns'
import { utcToZonedTime } from 'date-fns-tz'
const FRONTEND_FORMAT = 'dd.MM.yyyy'
@@ -23,18 +23,18 @@ export function getDays({
endDate,
endDateExclusive = false,
}: {
startDate: Date
endDate: Date
startDate: string,
endDate: string,
endDateExclusive?: boolean
}): string[] {
let currentDay = new Date(startDate.getTime())
let currentDay = new Date(startDate);
const days = [dateFormatBackend(currentDay)]
if (!endDate) {
return days
}
const inclusiveEndDate = endDateExclusive ? subDays(endDate, 1) : endDate
const inclusiveEndDate = endDateExclusive ? subDays(new Date(endDate), 1) : new Date(endDate)
while (currentDay < inclusiveEndDate) {
currentDay = addDays(currentDay, 1)
@@ -84,3 +84,8 @@ export function nowInTz(timezone = 'Europe/Berlin'): Date {
export function getNextDay(date: Date) {
return addDays(date, 1)
}
export function getDayCount({ startDate, endDate }: { startDate: string, endDate: string }) {
// TODO: check if this actually works as expected
return differenceInDays(new Date(startDate), new Date(endDate)) + 1 // add one as it only counts full days;
}

View File

@@ -1,8 +1,7 @@
import { createEvents, createEvent, EventStatus } from 'ics'
import { Booking } from '../db/booking'
import { BOOKING_STATUS } from '../db/enums'
import { Booking, BookingStatus} from '@prisma/client';
import { getBaseURL } from './url'
import { daysFormatFrontend } from './date'
import { dateFormatFrontend, getDayCount } from './date'
function convertDay(value: string): [number, number, number] {
const parts = value.split('-')
@@ -16,9 +15,9 @@ export function generateCalendarEntry(booking: Booking): string {
const { error, value } = createEvent({
productId: 'app.vercel.pfadi-bussle/ics',
title: `Pfadi-Bussle Buchung`,
start: convertDay(booking.days[0]),
start: convertDay(booking.startDate),
startOutputType: 'local',
duration: { days: booking.days.length },
duration: { days: getDayCount(booking) },
location: 'Mömpelgardgasse 25, 72348 Rosenfeld, Deutschland',
geo: { lat: 48.287044, lon: 8.726361 },
description: `Gebucht auf ${booking.name}
@@ -26,7 +25,7 @@ export function generateCalendarEntry(booking: Booking): string {
Buchungs-Link: ${getBaseURL()}/bookings/${booking.uuid}
`,
status:
booking.status === BOOKING_STATUS.CONFIRMED
booking.status === BookingStatus.CONFIRMED
? ('CONFIRMED' as EventStatus)
: ('TENTATIVE' as EventStatus),
})
@@ -54,12 +53,12 @@ export function generateBookedCalendar(bookings: Booking[]): string {
} => ({
productId: 'app.vercel.pfadi-bussle/ics',
calName: 'Pfadi-Bussle Buchungen',
start: convertDay(booking.days[0]),
start: convertDay(booking.startDate),
startOutputType: 'local',
duration: { days: booking.days.length },
duration: { days: getDayCount(booking) },
title: `Buchung ${booking.name}`,
description: `Name: ${booking.name}
Zeitraum: ${daysFormatFrontend(booking.days)}
Zeitraum: ${dateFormatFrontend(new Date(booking.startDate))}-${dateFormatFrontend(new Date(booking.endDate))}
Email: ${booking.email}
Telefon: ${booking.phone}
@@ -67,7 +66,7 @@ Telefon: ${booking.phone}
Link: ${getBaseURL()}/admin/bookings/${booking.uuid}
`,
status:
booking.status === BOOKING_STATUS.CONFIRMED
booking.status === BookingStatus.CONFIRMED
? ('CONFIRMED' as EventStatus)
: ('TENTATIVE' as EventStatus),
})

View File

@@ -1,7 +1,7 @@
import { Booking } from '../db/booking'
import { Booking, Prisma } from '@prisma/client';
import { getBaseURL } from '../helpers/url'
import { log } from '../helpers/log'
import { daysFormatFrontend } from './date'
import { dateFormatFrontend } from './date'
import { generateCalendarEntry } from './ical'
import sgMail from '@sendgrid/mail'
@@ -34,10 +34,11 @@ Tel. 0151/212 253 62
${getBaseURL()}
`
function getReceivedBookingBookerText(booking: Booking): string {
function getReceivedBookingBookerText(booking: Prisma.BookingCreateInput): string {
return `Hallo liebe/r ${booking.name},
Vielen Dank für Deine Buchungsanfrage zum ${daysFormatFrontend(booking.days)}!
Vielen Dank für Deine Buchungsanfrage vom
${dateFormatFrontend(new Date(booking.startDate))} bis ${dateFormatFrontend(new Date(booking.endDate))}
Nach Prüfung bestätigen wir die Buchung bald per E-Mail!
@@ -54,9 +55,9 @@ ${footer}
function getBookingConfirmedText(booking: Booking): string {
return `Hallo liebe/r ${booking.name},
deine Buchunganfrage zum ${daysFormatFrontend(
booking.days
)} bestätigen wir gerne!
deine Buchunganfrage vom
${dateFormatFrontend(new Date(booking.startDate))} bis ${dateFormatFrontend(new Date(booking.endDate))}
bestätigen wir gerne!
Bitte melde dich spätestens 7 Tage vor dem Buchungstermin per E-Mail oder Telefon
um eine Schlüsselübergabe zu vereinbaren.
@@ -71,9 +72,9 @@ ${footer}
function getBookingRejectedText(booking: Booking): string {
return `Hallo liebe/r ${booking.name},
es tut uns leid, aber deine Buchungsanfrage zum ${daysFormatFrontend(
booking.days
)} konnten wir leider nicht bestätigen.
es tut uns leid, aber deine Buchungsanfrage vom
${dateFormatFrontend(new Date(booking.startDate))} bis ${dateFormatFrontend(new Date(booking.endDate))}
konnten wir leider nicht bestätigen.
Willst du das Bussle an einem anderen Termin buchen? Dann stelle bitte nochmal
eine Buchungsanfrage auf ${getBaseURL()}.
@@ -85,7 +86,9 @@ ${footer}
function getBookingCanceledText(booking: Booking): string {
return `Hallo liebe/r ${booking.name},
deine Buchungsanfrage zum ${daysFormatFrontend(booking.days)} wurde storniert.
deine Buchungsanfrage vom
${dateFormatFrontend(new Date(booking.startDate))} bis ${dateFormatFrontend(new Date(booking.endDate))}
wurde storniert.
Willst du das Bussle an einem anderen Termin buchen? Dann stelle bitte nochmal
eine Buchungsanfrage auf ${getBaseURL()}.
@@ -109,7 +112,7 @@ export async function sendReceivedBookingAdminMail(
await sendMail({
to: [{ email: ADMIN_EMAIL }],
from: { email: FROM_EMAIL, name: 'Pfadi-Bussle Wart' },
subject: `Buchung für ${booking.days} eingegangen!`,
subject: `Buchung für ${booking.startDate}-${booking.endDate} eingegangen!`,
textPlainContent: getReceivedBookingAdminText(booking),
})
} catch (error) {
@@ -118,7 +121,7 @@ export async function sendReceivedBookingAdminMail(
}
export async function sendReceivedBookingBookerMail(
booking: Booking
booking: Prisma.BookingCreateInput
): Promise<void> {
try {
await sendMail({

View File

@@ -1,4 +1,4 @@
import { Booking } from '../db/booking'
import { Booking } from '@prisma/client'
import { log } from '../helpers/log'
const BOOKING_DATA_KEY = 'pfadiBussleBookingData'