enable bill storing

This commit is contained in:
Thomas Ruoff
2020-10-05 00:09:05 +02:00
committed by Thomas Ruoff
parent df6ec51af9
commit ec1b2e9629
7 changed files with 152 additions and 109 deletions

View File

@@ -1,6 +1,7 @@
import * as mongoose from 'mongoose' import * as mongoose from 'mongoose'
import Booker from './booker' import Booker from './booker'
import Booking from './booking' import Booking from './booking'
import Bill, { BillDocument } from './bill'
import { dateFormatFrontend } from '../helpers/date' import { dateFormatFrontend } from '../helpers/date'
import { BOOKING_STATUS } from './enums' import { BOOKING_STATUS } from './enums'
@@ -82,3 +83,15 @@ export async function createBooking({
await booking.populate('booker').execPopulate() await booking.populate('booker').execPopulate()
return booking.toJSON() return booking.toJSON()
} }
export async function createBill(bookingUUID: string, billData: BillDocument) {
await connect()
const bill = new Bill(billData)
const booking = await getBookingByUUID(bookingUUID)
bill.booking = booking._id
await bill.save()
await bill.populate('booking').execPopulate()
return bill.toJSON()
}

View File

@@ -0,0 +1,33 @@
import { NextApiRequest, NextApiResponse } from 'next'
import { BillDocument } from '../../../../db/bill'
import { createBill } from '../../../../db/index'
export default async function userHandler(
req: NextApiRequest,
res: NextApiResponse
) {
const {
method,
query: { uuid: uuids },
} = req
const bookingUUID = Array.isArray(uuids) ? uuids[0] : uuids
let bill: BillDocument
switch (method) {
case 'POST':
try {
bill = await createBill(bookingUUID, req.body)
res.status(200).json(bill)
} catch (e) {
console.error(e)
res.status(500).end(`Internal Server Error...Guru is meditating...`)
return
}
break
default:
res.setHeader('Allow', ['POST'])
res.status(405).end(`Method ${method} Not Allowed`)
}
}

View File

@@ -1,7 +1,7 @@
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { BookingDocument } from '../../../db/booking' import { BookingDocument } from '../../../../db/booking'
import { BOOKING_STATUS } from '../../../db/enums' import { BOOKING_STATUS } from '../../../../db/enums'
import { getBookingByUUID } from '../../../db/index' import { getBookingByUUID } from '../../../../db/index'
export default async function userHandler( export default async function userHandler(
req: NextApiRequest, req: NextApiRequest,

View File

@@ -3,6 +3,7 @@ import React, { useEffect, useState } from 'react'
import Footer from '../../../components/footer' import Footer from '../../../components/footer'
import Header from '../../../components/header' import Header from '../../../components/header'
import Input from '../../../components/wizard/input' import Input from '../../../components/wizard/input'
import { BillDocument } from '../../../db/bill'
import { BookingDocument } from '../../../db/booking' import { BookingDocument } from '../../../db/booking'
import { BOOKING_STATUS, MILAGE_RATES } from '../../../db/enums' import { BOOKING_STATUS, MILAGE_RATES } from '../../../db/enums'
import { getBookingByUUID } from '../../../db/index' import { getBookingByUUID } from '../../../db/index'
@@ -44,9 +45,9 @@ function getBookingStatus(booking: BookingDocument) {
} }
} }
async function cancelBooking(booking: BookingDocument) { async function saveBill(booking: BookingDocument, bill: BillDocument) {
const response = await fetch(`/api/booking/${booking.uuid}`, { const response = await fetch(`/api/booking/${booking.uuid}/bill/`, {
method: 'PATCH', method: 'POST',
mode: 'cors', mode: 'cors',
cache: 'no-cache', cache: 'no-cache',
credentials: 'same-origin', credentials: 'same-origin',
@@ -54,7 +55,7 @@ async function cancelBooking(booking: BookingDocument) {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
referrerPolicy: 'no-referrer', referrerPolicy: 'no-referrer',
body: JSON.stringify({ status: BOOKING_STATUS.CANCELED }), body: JSON.stringify(bill),
}) })
return response.json() return response.json()
} }
@@ -69,122 +70,118 @@ export default function Bill({
const [milageEnd, setMilageEnd] = useState(0) const [milageEnd, setMilageEnd] = useState(0)
const [rate, setRate] = useState(MILAGE_RATES.EXTERN_UP_TO_200) const [rate, setRate] = useState(MILAGE_RATES.EXTERN_UP_TO_200)
const milage = const milage =
(0 < milageEnd && (0 < milageStart && milageStart < milageEnd && milageEnd - milageStart) || 0
0 < milageStart && const total = (milage && rate && milage * rate) || 0
milageStart < milageEnd &&
milageEnd - milageStart) ||
0
const total = milage && rate && milage * rate
// in case the props change, update the internal state // in case the props change, update the internal state
useEffect(() => setBooking(bookingProp), [bookingProp]) useEffect(() => setBooking(bookingProp), [bookingProp])
const onCancelBooking = async () => {
if (!confirm('Soll die Buchung wirklich storniert werden?')) {
return
}
try {
const updatedBooking = await cancelBooking(booking)
setBooking(updatedBooking)
} catch (e) {
alert(
'Die Buchung konnte nicht storniert werden. Kontaktieren Sie uns bitt per E-Mail!'
)
}
}
return ( return (
<div className="mx-3 flex flex-col min-h-screen"> <div className="mx-3 flex flex-col min-h-screen">
<Header /> <Header />
<main className="flex-grow"> <main className="flex-grow">
<h2 className="text-3xl">Pfadi Bussle Buchung</h2> <h2 className="text-3xl">Pfadi Bussle Buchung</h2>
<div> <form
<strong>Buchungsstatus:</strong> {getBookingStatus(booking)} className="form"
</div> onSubmit={(event) => {
<div> event.preventDefault()
<strong>Buchungszeitraum:</strong>{' '} saveBill(booking, {
{dateFormatFrontend(new Date(booking.startDate))} -{' '} milageStart,
{dateFormatFrontend(new Date(booking.endDate))} milageEnd,
</div> milage,
<div> total,
<strong>Bucher:</strong> {booking.booker.name} rate: MILAGE_RATES[rate],
</div> })
<div> }}
<Input >
label="Anfangskilometer" <div>
name="milageStart" <strong>Buchungsstatus:</strong> {getBookingStatus(booking)}
required </div>
value={milageStart} <div>
type="number" <strong>Buchungszeitraum:</strong>{' '}
onChange={(e: React.ChangeEvent<React.ElementRef<'input'>>) => {dateFormatFrontend(new Date(booking.startDate))} -{' '}
setMilageStart(Number(e.target.value)) {dateFormatFrontend(new Date(booking.endDate))}
} </div>
/> <div>
<Input <strong>Bucher:</strong> {booking.booker.name}
label="Endkilometer" </div>
name="milageEnd" <div>
required <Input
value={milageEnd} label="Anfangskilometer"
type="number" name="milageStart"
onChange={(e: React.ChangeEvent<React.ElementRef<'input'>>) => required
setMilageEnd(Number(e.target.value)) value={milageStart}
} type="number"
/> onChange={(e: React.ChangeEvent<React.ElementRef<'input'>>) =>
<Input label="Gefahren" name="milage" readOnly value={milage} /> setMilageStart(Number(e.target.value))
<div className="fsw"> }
<div className="fs"> />
<label className="flabel">Rate</label> <Input
<div className="relative"> label="Endkilometer"
<select name="milageEnd"
className="block appearance-none w-full bg-gray-200 border border-gray-200 text-gray-700 py-3 px-4 pr-8 rounded leading-tight focus:outline-none focus:bg-white focus:border-gray-500" required
id="rate" value={milageEnd}
onChange={( type="number"
e: React.ChangeEvent<React.ElementRef<'select'>> onChange={(e: React.ChangeEvent<React.ElementRef<'input'>>) =>
) => setRate(Number(e.target.value))} setMilageEnd(Number(e.target.value))
> }
<option value={MILAGE_RATES.INTERN_UP_TO_200}> />
Intern bis 200 ({MILAGE_RATES.INTERN_UP_TO_200}) <Input label="Gefahren" name="milage" readOnly value={milage} />
</option> <div className="fsw">
<option value={MILAGE_RATES.INTERN_200_1000}> <div className="fs">
Intern 200-1000 ({MILAGE_RATES.INTERN_200_1000}) <label className="flabel">Rate</label>
</option> <div className="relative">
<option value={MILAGE_RATES.INTERN_1001_2000}> <select
Intern 1001-2000 ({MILAGE_RATES.INTERN_1001_2000}) className="block appearance-none w-full bg-gray-200 border border-gray-200 text-gray-700 py-3 px-4 pr-8 rounded leading-tight focus:outline-none focus:bg-white focus:border-gray-500"
</option> id="rate"
<option value={MILAGE_RATES.INTERN_OVER_2000}> onChange={(
Intern ab 2001 ({MILAGE_RATES.INTERN_OVER_2000}) e: React.ChangeEvent<React.ElementRef<'select'>>
</option> ) => setRate(Number(e.target.value))}
<option value={MILAGE_RATES.EXTERN_UP_TO_200}>
Extern bis 200 ({MILAGE_RATES.EXTERN_UP_TO_200})
</option>
<option value={MILAGE_RATES.EXTERN_200_1000}>
Extern 200-1000 ({MILAGE_RATES.EXTERN_200_1000})
</option>
<option value={MILAGE_RATES.EXTERN_1001_2000}>
Extern 1001-2000 ({MILAGE_RATES.EXTERN_1001_2000})
</option>
<option value={MILAGE_RATES.EXTERN_OVER_2000}>
Extern ab 2001 ({MILAGE_RATES.EXTERN_OVER_2000})
</option>
</select>
<div className="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700">
<svg
className="fill-current h-4 w-4"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
> >
<path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z" /> <option value={MILAGE_RATES.INTERN_UP_TO_200}>
</svg> Intern bis 200 ({MILAGE_RATES.INTERN_UP_TO_200})
</option>
<option value={MILAGE_RATES.INTERN_200_1000}>
Intern 200-1000 ({MILAGE_RATES.INTERN_200_1000})
</option>
<option value={MILAGE_RATES.INTERN_1001_2000}>
Intern 1001-2000 ({MILAGE_RATES.INTERN_1001_2000})
</option>
<option value={MILAGE_RATES.INTERN_OVER_2000}>
Intern ab 2001 ({MILAGE_RATES.INTERN_OVER_2000})
</option>
<option value={MILAGE_RATES.EXTERN_UP_TO_200}>
Extern bis 200 ({MILAGE_RATES.EXTERN_UP_TO_200})
</option>
<option value={MILAGE_RATES.EXTERN_200_1000}>
Extern 200-1000 ({MILAGE_RATES.EXTERN_200_1000})
</option>
<option value={MILAGE_RATES.EXTERN_1001_2000}>
Extern 1001-2000 ({MILAGE_RATES.EXTERN_1001_2000})
</option>
<option value={MILAGE_RATES.EXTERN_OVER_2000}>
Extern ab 2001 ({MILAGE_RATES.EXTERN_OVER_2000})
</option>
</select>
<div className="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700">
<svg
className="fill-current h-4 w-4"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
>
<path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z" />
</svg>
</div>
</div> </div>
</div> </div>
</div> </div>
</div>
<Input label="Summe" name="milage" readOnly value={total} /> <Input label="Summe" name="milage" readOnly value={total} />
</div> </div>
<button onClick={onCancelBooking} className="btn btn-blue"> <button type="submit" className="btn btn-blue">
Rechnung Erstellen Rechnung Erstellen
</button> </button>
</form>
</main> </main>
<Footer /> <Footer />