mirror of
https://github.com/tomru/pfadi-bussle.git
synced 2026-03-04 15:07:13 +01:00
further work on billing
This commit is contained in:
committed by
Thomas Ruoff
parent
f8434233d9
commit
c396cdcbf9
@@ -1,6 +1,5 @@
|
||||
import * as mongoose from 'mongoose'
|
||||
import { BILL_STATUS, MILAGE_RATES, getMilageRateValue } from './enums'
|
||||
import { BookingDocument } from './booking'
|
||||
|
||||
export interface AdditionalCosts {
|
||||
name: string
|
||||
@@ -10,7 +9,6 @@ export interface AdditionalCosts {
|
||||
export interface BillDocument
|
||||
extends mongoose.SchemaTimestampsConfig,
|
||||
mongoose.Document {
|
||||
booking: BookingDocument
|
||||
milageStart: number
|
||||
milageEnd: number
|
||||
milage?: number
|
||||
@@ -23,12 +21,6 @@ export interface BillModel extends mongoose.Model<BillDocument> {}
|
||||
|
||||
const BillSchema = new mongoose.Schema<BillDocument>(
|
||||
{
|
||||
booking: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: 'Booking',
|
||||
unique: true,
|
||||
required: true,
|
||||
},
|
||||
milageStart: {
|
||||
type: Number,
|
||||
required: true,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as mongoose from 'mongoose'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { dateFormatBackend, getDays } from '../helpers/date'
|
||||
import { BillDocument } from './bill'
|
||||
import { BookerDocument } from './booker'
|
||||
import { BOOKING_STATUS } from './enums'
|
||||
|
||||
@@ -9,6 +10,7 @@ export interface BookingDocument
|
||||
mongoose.SchemaTimestampsConfig {
|
||||
uuid: string
|
||||
booker: BookerDocument
|
||||
bill: BillDocument
|
||||
startDate: Date
|
||||
endDate: Date
|
||||
status: BOOKING_STATUS
|
||||
@@ -35,6 +37,11 @@ const BookingSchema = new mongoose.Schema<BookingDocument>(
|
||||
ref: 'Booker',
|
||||
required: true,
|
||||
},
|
||||
bill: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: 'Bill',
|
||||
required: false,
|
||||
},
|
||||
startDate: {
|
||||
type: Date,
|
||||
required: true,
|
||||
@@ -56,11 +63,6 @@ const BookingSchema = new mongoose.Schema<BookingDocument>(
|
||||
purpose: { type: String, required: false },
|
||||
org: { type: String, required: false },
|
||||
destination: { type: String, required: false },
|
||||
bill: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: 'bill',
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
|
||||
30
db/index.ts
30
db/index.ts
@@ -27,8 +27,8 @@ export async function getBookedDays() {
|
||||
|
||||
export async function getBookingByUUID(uuid: string) {
|
||||
await connect()
|
||||
const booking = await Booking.findOne({ uuid })
|
||||
return booking?.populate('booker').execPopulate()
|
||||
return Booking.findOne({ uuid })
|
||||
//return booking.populate('bill').populate('booker').execPopulate()
|
||||
}
|
||||
|
||||
export async function getBookings() {
|
||||
@@ -87,14 +87,32 @@ export async function createBooking({
|
||||
export async function createBill(bookingUUID: string, billData: BillDocument) {
|
||||
await connect()
|
||||
const booking = await getBookingByUUID(bookingUUID)
|
||||
const bill =
|
||||
(await Bill.findOne({ booking: booking._id })) ||
|
||||
new Bill({ booking: booking._id })
|
||||
|
||||
const bill = new Bill()
|
||||
bill.set(billData)
|
||||
|
||||
await bill.save()
|
||||
await bill.populate('booking').execPopulate()
|
||||
|
||||
booking.bill = bill._id
|
||||
await booking.save()
|
||||
|
||||
return bill.toJSON()
|
||||
}
|
||||
|
||||
export async function patchBill(bookingUUID: string, billData: BillDocument) {
|
||||
await connect()
|
||||
const booking = await getBookingByUUID(bookingUUID)
|
||||
const bill =
|
||||
(booking.bill && (await Bill.findById(booking.bill))) ||
|
||||
(await Bill.create())
|
||||
|
||||
bill.set(billData)
|
||||
await bill.save()
|
||||
|
||||
if (booking.bill !== bill._id) {
|
||||
booking.bill = bill._id
|
||||
await booking.save()
|
||||
}
|
||||
|
||||
return bill.toJSON()
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
import { BillDocument } from '../../../../db/bill'
|
||||
import { createBill } from '../../../../db/index'
|
||||
import { createBill, patchBill } from '../../../../db/index'
|
||||
|
||||
export default async function userHandler(
|
||||
req: NextApiRequest,
|
||||
@@ -26,6 +26,16 @@ export default async function userHandler(
|
||||
return
|
||||
}
|
||||
break
|
||||
case 'PATCH':
|
||||
try {
|
||||
bill = await patchBill(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`)
|
||||
|
||||
@@ -3,7 +3,7 @@ import React, { useEffect, useState } from 'react'
|
||||
import Footer from '../../../components/footer'
|
||||
import Header from '../../../components/header'
|
||||
import Input from '../../../components/wizard/input'
|
||||
import Bill, { AdditionalCosts, BillDocument } from '../../../db/bill'
|
||||
import { AdditionalCosts, BillDocument } from '../../../db/bill'
|
||||
import { BookingDocument } from '../../../db/booking'
|
||||
import {
|
||||
BILL_STATUS,
|
||||
@@ -20,21 +20,17 @@ export const getServerSideProps: GetServerSideProps = async (context) => {
|
||||
} = context
|
||||
const uuid = Array.isArray(uuids) ? uuids[0] : uuids
|
||||
const booking = await getBookingByUUID(uuid)
|
||||
await booking.populate('booker').populate('bill').execPopulate()
|
||||
|
||||
if (!booking) {
|
||||
res.statusCode = 404
|
||||
res.end()
|
||||
return { props: {} }
|
||||
}
|
||||
const bill =
|
||||
(await Bill.findOne({ booking: booking._id })) ||
|
||||
new Bill({ booking: booking._id })
|
||||
|
||||
// TODO: hack, not sure why _id is not serilizable
|
||||
const bookingJSON = JSON.parse(JSON.stringify(booking.toJSON()))
|
||||
const billJSON = JSON.parse(JSON.stringify(bill?.toJSON()))
|
||||
return {
|
||||
props: { booking: bookingJSON, bill: billJSON },
|
||||
props: { booking: bookingJSON },
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,10 +78,11 @@ async function saveBill(
|
||||
milage?: number
|
||||
rate: MILAGE_RATES
|
||||
additionalCosts?: AdditionalCosts[]
|
||||
status: BILL_STATUS
|
||||
}
|
||||
) {
|
||||
): Promise<BillDocument> {
|
||||
const response = await fetch(`/api/booking/${booking.uuid}/bill/`, {
|
||||
method: 'POST',
|
||||
method: booking.bill?._id ? 'PATCH' : 'POST',
|
||||
mode: 'cors',
|
||||
cache: 'no-cache',
|
||||
credentials: 'same-origin',
|
||||
@@ -100,17 +97,16 @@ async function saveBill(
|
||||
|
||||
export default function BillPage({
|
||||
booking: bookingProp,
|
||||
bill: billProp,
|
||||
}: {
|
||||
booking: BookingDocument
|
||||
bill: BillDocument
|
||||
}) {
|
||||
const [booking, setBooking] = useState(bookingProp)
|
||||
const [bill, setBill] = useState(billProp)
|
||||
const [milageStart, setMilageStart] = useState(bill.milageStart)
|
||||
const [milageEnd, setMilageEnd] = useState(bill.milageEnd)
|
||||
const [rate, setRate] = useState(bill.rate)
|
||||
const [status, setStatus] = useState(bill.status)
|
||||
const [milageStart, setMilageStart] = useState(booking.bill?.milageStart)
|
||||
const [milageEnd, setMilageEnd] = useState(booking.bill?.milageEnd)
|
||||
const [rate, setRate] = useState(
|
||||
booking.bill?.rate || MILAGE_RATES.EXTERN_LTE_200
|
||||
)
|
||||
const [status, setStatus] = useState(booking.bill?.status)
|
||||
const milage =
|
||||
(0 < milageStart && milageStart < milageEnd && milageEnd - milageStart) || 0
|
||||
const total =
|
||||
@@ -119,25 +115,27 @@ export default function BillPage({
|
||||
|
||||
// in case the props change, update the internal state
|
||||
useEffect(() => setBooking(bookingProp), [bookingProp])
|
||||
useEffect(() => setBill(billProp), [billProp])
|
||||
|
||||
const onSubmit = async (event) => {
|
||||
event.preventDefault()
|
||||
const bill = await saveBill(booking, {
|
||||
milageStart,
|
||||
milageEnd,
|
||||
milage,
|
||||
rate,
|
||||
status,
|
||||
})
|
||||
|
||||
booking.bill = bill
|
||||
setBooking(booking)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mx-3 flex flex-col min-h-screen">
|
||||
<Header />
|
||||
<main className="flex-grow">
|
||||
<h2 className="text-3xl">Pfadi Bussle Buchung</h2>
|
||||
<form
|
||||
className="form"
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault()
|
||||
saveBill(booking, {
|
||||
milageStart,
|
||||
milageEnd,
|
||||
milage,
|
||||
rate: MILAGE_RATES[rate],
|
||||
})
|
||||
}}
|
||||
>
|
||||
<form className="form" onSubmit={onSubmit}>
|
||||
<div>
|
||||
<strong>Buchungszeitraum:</strong>{' '}
|
||||
{dateFormatFrontend(new Date(booking.startDate))} -{' '}
|
||||
@@ -178,7 +176,9 @@ export default function BillPage({
|
||||
value={rate}
|
||||
onChange={(
|
||||
e: React.ChangeEvent<React.ElementRef<'select'>>
|
||||
) => setRate(MILAGE_RATES[e.target.value])}
|
||||
) => {
|
||||
setRate(e.target.value as MILAGE_RATES)
|
||||
}}
|
||||
>
|
||||
{Object.values(MILAGE_RATES).map((rate) => {
|
||||
return (
|
||||
@@ -210,7 +210,7 @@ export default function BillPage({
|
||||
value={status}
|
||||
onChange={(
|
||||
e: React.ChangeEvent<React.ElementRef<'select'>>
|
||||
) => setStatus(BILL_STATUS[e.target.value])}
|
||||
) => setStatus(e.target.value as BILL_STATUS)}
|
||||
>
|
||||
{Object.values(BILL_STATUS).map((status) => {
|
||||
return (
|
||||
@@ -236,7 +236,7 @@ export default function BillPage({
|
||||
<Input label="Summe" name="milage" readOnly value={total} />
|
||||
</div>
|
||||
<button type="submit" className="btn btn-blue">
|
||||
Rechnung Erstellen
|
||||
Rechnung {booking.bill?._id ? 'Updaten' : 'Erstellen'}
|
||||
</button>
|
||||
</form>
|
||||
</main>
|
||||
|
||||
@@ -14,6 +14,7 @@ export const getServerSideProps: GetServerSideProps = async (context) => {
|
||||
} = context
|
||||
const uuid = Array.isArray(uuids) ? uuids[0] : uuids
|
||||
const booking = await getBookingByUUID(uuid)
|
||||
await booking.populate('booker').execPopulate()
|
||||
|
||||
if (!booking) {
|
||||
res.statusCode = 404
|
||||
|
||||
Reference in New Issue
Block a user