source: src/app/api/invoices/route.ts@ 87c9f1e

main
Last change on this file since 87c9f1e was 87c9f1e, checked in by Naum Shapkarovski <naumshapkarovski@…>, 5 weeks ago

update the seed script. update the prisma schema, use mapping

  • Property mode set to 100644
File size: 4.4 KB
Line 
1import { NextRequest, NextResponse } from 'next/server';
2import { createInvoiceSchema, invoiceSchema, invoiceTableFiltersSchema } from 'src/schemas';
3import prisma from 'src/lib/prisma';
4import { auth } from 'src/lib/firebase-admin';
5import { InvoiceStatus } from '@prisma/client';
6
7// Helper function to get userId from Authorization header
8async function getUserId(request: NextRequest) {
9 const authHeader = request.headers.get('Authorization');
10 if (!authHeader?.startsWith('Bearer ')) {
11 return null;
12 }
13
14 try {
15 const token = authHeader.split('Bearer ')[1];
16 const decodedToken = await auth.verifyIdToken(token);
17 return decodedToken.uid;
18 } catch (error) {
19 return null;
20 }
21}
22
23export async function GET(request: NextRequest) {
24 try {
25 const userId = await getUserId(request);
26 // if (!userId) {
27 // return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
28 // }
29
30 const searchParams = request.nextUrl.searchParams;
31 const filters = {
32 name: searchParams.get('name') || '',
33 service: searchParams.getAll('service'),
34 status: searchParams.get('status') || '',
35 startDate: searchParams.get('startDate') ? new Date(searchParams.get('startDate')!) : null,
36 endDate: searchParams.get('endDate') ? new Date(searchParams.get('endDate')!) : null,
37 };
38
39 // Validate filters
40 const validatedFilters = invoiceTableFiltersSchema.parse(filters);
41
42 const invoices = await prisma.invoice.findMany({
43 where: {
44 status: validatedFilters.status
45 ? { equals: validatedFilters.status as InvoiceStatus }
46 : undefined,
47 issueDate: {
48 ...(validatedFilters.startDate && { gte: validatedFilters.startDate }),
49 ...(validatedFilters.endDate && { lte: validatedFilters.endDate }),
50 },
51 items:
52 validatedFilters.service.length > 0
53 ? { some: { service: { id: { in: validatedFilters.service } } } }
54 : undefined,
55 },
56 include: {
57 items: {
58 include: {
59 service: true,
60 },
61 },
62 invoiceFrom: true,
63 invoiceTo: true,
64 },
65 });
66
67 return NextResponse.json(invoices);
68 } catch (error) {
69 return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });
70 }
71}
72
73export async function POST(request: NextRequest) {
74 try {
75 const userId = await getUserId(request);
76 // if (!userId) {
77 // return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
78 // }
79
80 const body = await request.json();
81 const validatedData = createInvoiceSchema.parse(body);
82
83 const tenant = await prisma.tenant.findUnique({
84 where: { id: validatedData.invoiceFrom.id },
85 });
86
87 const toCustomer = await prisma.client.findUnique({
88 where: { id: validatedData.invoiceTo.id },
89 });
90
91 if (!tenant || !toCustomer) {
92 return NextResponse.json({ error: 'Invoice sender or recipient not found' }, { status: 404 });
93 }
94
95 // Update lastInvoiceNumber in tenant
96 const updatedTenant = await prisma.tenant.update({
97 where: { id: tenant.id },
98 data: {
99 lastInvoiceNumber: validatedData.invoiceNumber,
100 },
101 });
102
103 const invoice = await prisma.invoice.create({
104 data: {
105 dueDate: validatedData.dueDate,
106 status: validatedData.status,
107 currency: validatedData.currency,
108 quantityType: validatedData.quantityType,
109 subTotal: validatedData.subTotal,
110 issueDate: validatedData.issueDate,
111 month: validatedData.month,
112 discount: validatedData.discount,
113 taxes: validatedData.taxes,
114 totalAmount: validatedData.totalAmount,
115 invoiceNumber: validatedData.invoiceNumber,
116 invoiceFromId: tenant.id,
117 invoiceToId: toCustomer.id,
118 items: {
119 create: validatedData.items.map((item) => ({
120 title: item.title,
121 price: item.price,
122 total: item.total,
123 quantity: item.quantity,
124 description: item.description,
125 service: {
126 connect: { id: item.service.id },
127 },
128 })),
129 },
130 },
131 include: {
132 items: {
133 include: {
134 service: true,
135 },
136 },
137 invoiceFrom: true,
138 invoiceTo: true,
139 },
140 });
141
142 return NextResponse.json(invoice, { status: 201 });
143 } catch (error) {
144 console.error(error);
145 return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });
146 }
147}
Note: See TracBrowser for help on using the repository browser.