140 lines
5.1 KiB
TypeScript
140 lines
5.1 KiB
TypeScript
import { NextResponse } from 'next/server';
|
|
import { prisma } from '../../../lib/prisma';
|
|
import { requireAuth } from '../../../lib/jwt';
|
|
import { UserStatus } from '@prisma/client';
|
|
|
|
const selectListingLabel = (translations: { title: string; locale: string; slug: string }[]) => {
|
|
if (!translations || translations.length === 0) return 'Listing';
|
|
const sorted = [...translations].sort((a, b) => a.locale.localeCompare(b.locale));
|
|
return sorted[0].title || sorted[0].slug || 'Listing';
|
|
};
|
|
|
|
export async function GET(req: Request) {
|
|
try {
|
|
const session = await requireAuth(req);
|
|
const user = await prisma.user.findUnique({
|
|
where: { id: session.userId },
|
|
select: {
|
|
status: true,
|
|
agentBillingEnabled: true,
|
|
agentBankAccount: true,
|
|
agentVatBreakdownRequired: true,
|
|
agentUseListingOverrides: true,
|
|
},
|
|
});
|
|
|
|
if (!user || user.status !== UserStatus.ACTIVE) {
|
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
}
|
|
|
|
const listings = await prisma.listing.findMany({
|
|
where: { ownerId: session.userId },
|
|
select: {
|
|
id: true,
|
|
translations: { select: { title: true, slug: true, locale: true } },
|
|
billingSettings: { select: { bankAccount: true, vatBreakdownRequired: true } },
|
|
},
|
|
orderBy: { createdAt: 'desc' },
|
|
});
|
|
|
|
const listingOverrides = listings.map((listing) => ({
|
|
id: listing.id,
|
|
label: selectListingLabel(listing.translations),
|
|
bankAccount: listing.billingSettings?.bankAccount ?? '',
|
|
vatBreakdownRequired: listing.billingSettings?.vatBreakdownRequired ?? false,
|
|
}));
|
|
|
|
return NextResponse.json({
|
|
settings: {
|
|
agentBillingEnabled: user.agentBillingEnabled,
|
|
agentBankAccount: user.agentBankAccount ?? '',
|
|
agentVatBreakdownRequired: user.agentVatBreakdownRequired,
|
|
agentUseListingOverrides: user.agentUseListingOverrides,
|
|
},
|
|
listingOverrides,
|
|
});
|
|
} catch (error) {
|
|
console.error('Billing settings fetch error', error);
|
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
}
|
|
}
|
|
|
|
export async function PATCH(req: Request) {
|
|
try {
|
|
const session = await requireAuth(req);
|
|
const body = await req.json();
|
|
|
|
const user = await prisma.user.findUnique({ where: { id: session.userId }, select: { status: true } });
|
|
if (!user || user.status !== UserStatus.ACTIVE) {
|
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
}
|
|
|
|
const agentBillingEnabled = Boolean(body.agentBillingEnabled);
|
|
const agentVatBreakdownRequired = Boolean(body.agentVatBreakdownRequired);
|
|
const agentUseListingOverrides = Boolean(body.agentUseListingOverrides);
|
|
const agentBankAccountRaw = typeof body.agentBankAccount === 'string' ? body.agentBankAccount.trim() : '';
|
|
const agentBankAccount = agentBankAccountRaw.length ? agentBankAccountRaw : null;
|
|
|
|
const updates = await prisma.$transaction(async (tx) => {
|
|
const updatedUser = await tx.user.update({
|
|
where: { id: session.userId },
|
|
data: {
|
|
agentBillingEnabled,
|
|
agentVatBreakdownRequired,
|
|
agentUseListingOverrides,
|
|
agentBankAccount,
|
|
},
|
|
select: {
|
|
agentBillingEnabled: true,
|
|
agentBankAccount: true,
|
|
agentVatBreakdownRequired: true,
|
|
agentUseListingOverrides: true,
|
|
},
|
|
});
|
|
|
|
const listingOverrides: any[] = Array.isArray(body.listingOverrides) ? body.listingOverrides : [];
|
|
const sanitizedOverrides = listingOverrides
|
|
.map((o) => ({
|
|
listingId: typeof o.listingId === 'string' ? o.listingId : '',
|
|
bankAccount: typeof o.bankAccount === 'string' ? o.bankAccount.trim() : '',
|
|
vatBreakdownRequired: Boolean(o.vatBreakdownRequired),
|
|
}))
|
|
.filter((o) => o.listingId);
|
|
|
|
for (const override of sanitizedOverrides) {
|
|
const listing = await tx.listing.findFirst({ where: { id: override.listingId, ownerId: session.userId }, select: { id: true } });
|
|
if (!listing) continue;
|
|
|
|
await tx.listingBillingSettings.upsert({
|
|
where: { listingId: override.listingId },
|
|
update: {
|
|
bankAccount: override.bankAccount || null,
|
|
vatBreakdownRequired: override.vatBreakdownRequired,
|
|
},
|
|
create: {
|
|
listingId: override.listingId,
|
|
bankAccount: override.bankAccount || null,
|
|
vatBreakdownRequired: override.vatBreakdownRequired,
|
|
},
|
|
});
|
|
}
|
|
|
|
return updatedUser;
|
|
});
|
|
|
|
return NextResponse.json({
|
|
ok: true,
|
|
settings: {
|
|
agentBillingEnabled: updates.agentBillingEnabled,
|
|
agentBankAccount: updates.agentBankAccount ?? '',
|
|
agentVatBreakdownRequired: updates.agentVatBreakdownRequired,
|
|
agentUseListingOverrides: updates.agentUseListingOverrides,
|
|
},
|
|
});
|
|
} catch (error) {
|
|
console.error('Billing settings update error', error);
|
|
return NextResponse.json({ error: 'Failed to update billing settings' }, { status: 500 });
|
|
}
|
|
}
|
|
|
|
export const dynamic = 'force-dynamic';
|