feat(orders): support active status and update RLS
Some checks failed
Staging Build / build (push) Has been cancelled

This commit is contained in:
DanielS
2026-07-20 23:00:02 +02:00
parent 13f647409f
commit 2b372be228
3 changed files with 87 additions and 9 deletions

View File

@@ -0,0 +1,7 @@
skill: lucide-icons-guide
description: Integration, Auswahl und Optimierung von Lucide React Icons (lucide.dev) für Next.js 15 (RSC/Server Actions) und Tailwind CSS.
rules:
- Importiere Icons direkt aus `lucide-react` (z. B. `import { Package, ShieldCheck, ShoppingCart } from 'lucide-react'`).
- Achte bei React Server Components (RSC) darauf, dass Icons performant gerendert und keine unnötigen Client-Side Bundles erzeugt werden.
- Verwende konsistente Größen (`size={18}` oder Tailwind `w-5 h-5`) und Stile (z. B. `strokeWidth={1.75}`) passend zum B2B-Design.
- Nutze dynamische Icon-Name-Renderings nur über eine typsichere Map/Registry, um Unused-Code-Elimination (Tree Shaking) zu gewährleisten.

View File

@@ -298,14 +298,15 @@ export async function submitOrder(params: {
export async function updateOrderStatus( export async function updateOrderStatus(
orderId: string, orderId: string,
newStatus: 'pending' | 'active' | 'completed' | 'cancelled' | 'rejected' newStatus: 'pending' | 'pending_approval' | 'in_review' | 'approved' | 'active' | 'completed' | 'cancelled' | 'rejected'
) { ) {
const admin = createAdminClient() const admin = createAdminClient()
const supabase = await createClient()
// 1. Fetch current order // 1. Fetch current order with full details (snapshots)
const { data: order, error: fetchError } = await admin const { data: order, error: fetchError } = await admin
.from('orders') .from('orders')
.select('id, user_id, order_number, status') .select('*')
.eq('id', orderId) .eq('id', orderId)
.single() .single()
@@ -316,7 +317,7 @@ export async function updateOrderStatus(
const oldStatus = order.status const oldStatus = order.status
if (oldStatus === newStatus) { if (oldStatus === newStatus) {
return order return order as Order
} }
// 2. Update order status // 2. Update order status
@@ -331,7 +332,41 @@ export async function updateOrderStatus(
throw new Error(`Fehler beim Aktualisieren des Status: ${updateError?.message || 'Unbekannt'}`) throw new Error(`Fehler beim Aktualisieren des Status: ${updateError?.message || 'Unbekannt'}`)
} }
// 3. Send email to the retailer (händler) // 3. Wenn Status auf 'active' wechselt, generiere PDF und lade es hoch (pdf-invoice-generator)
let attachmentBuffer: Buffer | null = null
if (newStatus === 'active') {
try {
const customerSnapshot = updatedOrder.customer_data
const orderSnapshot = updatedOrder.order_data
const buffer = await renderToBuffer(
React.createElement(InvoicePDF, {
order: updatedOrder,
customer: customerSnapshot,
orderSnapshot,
})
)
attachmentBuffer = buffer
// PDF in Supabase Storage hochladen
const fileName = `ab_${updatedOrder.id}.pdf`
const { error: uploadError } = await admin
.storage
.from('invoices')
.upload(fileName, buffer, { contentType: 'application/pdf', upsert: true })
if (uploadError) {
console.error('PDF Upload Error:', uploadError)
} else {
await admin.from('orders').update({ pdf_url: fileName }).eq('id', updatedOrder.id)
updatedOrder.pdf_url = fileName
}
} catch (pdfError) {
console.error('PDF Generation Error on active status transition:', pdfError)
}
}
// 4. E-Mail mit SMTP an den Besteller senden (b2b-mail-dispatcher)
if (order.user_id) { if (order.user_id) {
try { try {
const { data: { user }, error: userError } = await admin.auth.admin.getUserById(order.user_id) const { data: { user }, error: userError } = await admin.auth.admin.getUserById(order.user_id)
@@ -340,7 +375,10 @@ export async function updateOrderStatus(
const orderNumber = order.order_number || order.id.slice(0, 8) const orderNumber = order.order_number || order.id.slice(0, 8)
const statusLabelMap: Record<string, string> = { const statusLabelMap: Record<string, string> = {
pending: 'Eingegangen', pending: 'Eingegangen',
active: 'In Bearbeitung', pending_approval: 'Wartet auf Freigabe',
in_review: 'In Prüfung',
approved: 'Freigegeben',
active: 'Aktiviert',
completed: 'Abgeschlossen', completed: 'Abgeschlossen',
cancelled: 'Storniert', cancelled: 'Storniert',
rejected: 'Abgelehnt', rejected: 'Abgelehnt',
@@ -350,12 +388,25 @@ export async function updateOrderStatus(
const statusEmail = getStatusEmailTemplate(orderNumber, oldLabel, newLabel) const statusEmail = getStatusEmailTemplate(orderNumber, oldLabel, newLabel)
await sendMail({ const mailOptions: any = {
to: user.email, to: user.email,
subject: `Statusänderung Ihrer Anfrage ${orderNumber}`, subject: `Statusänderung Ihrer Anfrage ${orderNumber}`,
text: statusEmail.text, text: statusEmail.text,
html: statusEmail.html html: statusEmail.html,
}) }
// Bei Aktivierung hänge die PDF an
if (newStatus === 'active' && attachmentBuffer) {
mailOptions.attachments = [
{
filename: `Anfragebestaetigung_${orderNumber}.pdf`,
content: attachmentBuffer,
contentType: 'application/pdf',
}
]
}
await sendMail(mailOptions)
} }
} catch (mailError) { } catch (mailError) {
console.error('Failed to send status update email:', mailError) console.error('Failed to send status update email:', mailError)
@@ -367,6 +418,7 @@ export async function updateOrderStatus(
return updatedOrder as Order return updatedOrder as Order
} }
export async function updateOrder( export async function updateOrder(
orderId: string, orderId: string,
params: { params: {

View File

@@ -0,0 +1,19 @@
-- 1. Order Status Constraint anpassen
ALTER TABLE public.orders DROP CONSTRAINT IF EXISTS orders_status_check;
ALTER TABLE public.orders ADD CONSTRAINT orders_status_check
CHECK (status IN ('pending', 'pending_approval', 'in_review', 'approved', 'active', 'completed', 'cancelled', 'rejected'));
-- 2. Helper-Funktion für RLS anlegen
CREATE OR REPLACE FUNCTION public.get_auth_company_id()
RETURNS UUID AS $$
SELECT company_id FROM public.users WHERE id = auth.uid() LIMIT 1;
$$ LANGUAGE sql STABLE SECURITY DEFINER;
-- 3. RLS-Policies aktualisieren
DROP POLICY IF EXISTS "Partner sehen nur eigene Firmenbestellungen" ON public.orders;
CREATE POLICY "Partner sehen nur eigene Firmenbestellungen" ON public.orders
FOR SELECT USING (company_id = public.get_auth_company_id() OR public.is_admin(auth.uid()));
DROP POLICY IF EXISTS "Partner sehen nur eigene Endkunden" ON public.end_customers;
CREATE POLICY "Partner sehen nur eigene Endkunden" ON public.end_customers
FOR SELECT USING (partner_id = public.get_auth_company_id() OR public.is_admin(auth.uid()));