From f5f577ea730fd849df92f576479f6defb51f3e3f Mon Sep 17 00:00:00 2001 From: DanielS Date: Fri, 3 Jul 2026 09:46:47 +0200 Subject: [PATCH] feat(customer): add bank account details support --- shop/app/my-customers/[id]/page.tsx | 9 +++++++++ shop/app/my-customers/new/page.tsx | 5 +++++ shop/app/order/success/page.tsx | 8 ++++++++ shop/components/invoice-pdf.tsx | 5 +++++ shop/components/order-wizard.tsx | 10 +++++++++- shop/lib/actions/companies.ts | 16 ++++++++++++++++ shop/lib/actions/end-customers.ts | 16 ++++++++++++++++ shop/lib/license-transform.ts | 4 ++++ shop/lib/types.ts | 8 ++++++++ ...3094300_add_bank_details_to_end_customers.sql | 6 ++++++ 10 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 shop/supabase/migrations/20260703094300_add_bank_details_to_end_customers.sql diff --git a/shop/app/my-customers/[id]/page.tsx b/shop/app/my-customers/[id]/page.tsx index 7bab62a..a6702d0 100644 --- a/shop/app/my-customers/[id]/page.tsx +++ b/shop/app/my-customers/[id]/page.tsx @@ -22,6 +22,7 @@ export default function CustomerDetailPage({ params }: { params: Promise<{ id: s const [showGdprConfirm, setShowGdprConfirm] = useState(false) const [form, setForm] = useState({ company_name: '', vat_id: '', first_name: '', last_name: '', street: '', zip: '', city: '', email: '', + bank_iban: '', bank_bic: '', bank_name: '', bank_owner: '', }) useEffect(() => { @@ -38,6 +39,10 @@ export default function CustomerDetailPage({ params }: { params: Promise<{ id: s zip: c.zip ?? '', city: c.city ?? '', email: c.email ?? '', + bank_iban: c.bank_iban ?? '', + bank_bic: c.bank_bic ?? '', + bank_name: c.bank_name ?? '', + bank_owner: c.bank_owner ?? '', }) setLoading(false) }) @@ -126,6 +131,10 @@ export default function CustomerDetailPage({ params }: { params: Promise<{ id: s { label: 'Straße & Hausnummer', key: 'street', span: true }, { label: 'PLZ', key: 'zip', span: false }, { label: 'Ort', key: 'city', span: false }, + { label: 'Kontoinhaber', key: 'bank_owner', span: false }, + { label: 'IBAN', key: 'bank_iban', span: false }, + { label: 'BIC', key: 'bank_bic', span: false }, + { label: 'Bankname', key: 'bank_name', span: false }, ] as const).map(({ label, key, span }) => (
diff --git a/shop/app/my-customers/new/page.tsx b/shop/app/my-customers/new/page.tsx index c8ad134..75e14aa 100644 --- a/shop/app/my-customers/new/page.tsx +++ b/shop/app/my-customers/new/page.tsx @@ -15,6 +15,7 @@ export default function NewCustomerPage() { const [saving, setSaving] = useState(false) const [form, setForm] = useState({ company_name: '', vat_id: '', first_name: '', last_name: '', street: '', zip: '', city: '', email: '', + bank_iban: '', bank_bic: '', bank_name: '', bank_owner: '', }) const handleSave = async () => { @@ -62,6 +63,10 @@ export default function NewCustomerPage() { { label: 'Straße & Hausnummer', key: 'street', span: true, placeholder: 'Musterstraße 1' }, { label: 'PLZ', key: 'zip', span: false, placeholder: '12345' }, { label: 'Ort', key: 'city', span: false, placeholder: 'Musterstadt' }, + { label: 'Kontoinhaber', key: 'bank_owner', span: false, placeholder: 'Max Mustermann' }, + { label: 'IBAN', key: 'bank_iban', span: false, placeholder: 'DE89370400440532013000' }, + { label: 'BIC', key: 'bank_bic', span: false, placeholder: 'SOLADE21XXX' }, + { label: 'Bankname', key: 'bank_name', span: false, placeholder: 'Musterbank' }, ] as const).map(({ label, key, span, placeholder }) => (
diff --git a/shop/app/order/success/page.tsx b/shop/app/order/success/page.tsx index 7f8b52e..44f3bc3 100644 --- a/shop/app/order/success/page.tsx +++ b/shop/app/order/success/page.tsx @@ -194,6 +194,14 @@ export default async function OrderSuccessPage({

{o.customer_data?.company_name}

{o.customer_data?.first_name} {o.customer_data?.last_name}

{o.customer_data?.address}, {o.customer_data?.zip_code} {o.customer_data?.city}

+ {o.customer_data?.bank_iban && ( +
+

Kontoinhaber: {o.customer_data.bank_owner}

+

IBAN: {o.customer_data.bank_iban}

+ {o.customer_data.bank_bic &&

BIC: {o.customer_data.bank_bic}

} + {o.customer_data.bank_name &&

Bank: {o.customer_data.bank_name}

} +
+ )}
{/* PDF-Download */} diff --git a/shop/components/invoice-pdf.tsx b/shop/components/invoice-pdf.tsx index deac4e1..d7778ec 100644 --- a/shop/components/invoice-pdf.tsx +++ b/shop/components/invoice-pdf.tsx @@ -134,6 +134,11 @@ export const InvoicePDF = ({ order, orderSnapshot, customer }: any) => { {customer.address} {customer.zip_code} {customer.city} USt-IdNr: {customer.vat_id} + {customer.bank_iban && ( + + Bank: {customer.bank_name || '-'} · IBAN: {customer.bank_iban} · BIC: {customer.bank_bic || '-'} · Inhaber: {customer.bank_owner || '-'} + + )} diff --git a/shop/components/order-wizard.tsx b/shop/components/order-wizard.tsx index f562e34..1f5eb9c 100644 --- a/shop/components/order-wizard.tsx +++ b/shop/components/order-wizard.tsx @@ -135,6 +135,7 @@ export function OrderWizard({ const [isCreatingCustomer, setIsCreatingCustomer] = useState(false) const [newCustomerForm, setNewCustomerForm] = useState({ company_name: '', vat_id: '', first_name: '', last_name: '', street: '', zip: '', city: '', + bank_iban: '', bank_bic: '', bank_name: '', bank_owner: '', }) // Abrechnungsmodell-Auswahl ('one_time' = Kauf, 'monthly' = Abo) @@ -388,7 +389,10 @@ export function OrderWizard({ setEndCustomers(prev => [...prev, created]) setSelectedEndCustomerId(created.id) setCustomerMode('select') - setNewCustomerForm({ company_name: '', vat_id: '', first_name: '', last_name: '', street: '', zip: '', city: '' }) + setNewCustomerForm({ + company_name: '', vat_id: '', first_name: '', last_name: '', street: '', zip: '', city: '', + bank_iban: '', bank_bic: '', bank_name: '', bank_owner: '', + }) } catch (e) { alert('Fehler beim Anlegen des Kunden.') } finally { @@ -573,6 +577,10 @@ export function OrderWizard({ { label: 'Straße & Hausnummer', key: 'street', span: true, placeholder: '' }, { label: 'PLZ', key: 'zip', span: false, placeholder: '' }, { label: 'Ort', key: 'city', span: false, placeholder: '' }, + { label: 'Kontoinhaber', key: 'bank_owner', span: false, placeholder: 'Max Mustermann' }, + { label: 'IBAN', key: 'bank_iban', span: false, placeholder: 'DE89370400440532013000' }, + { label: 'BIC', key: 'bank_bic', span: false, placeholder: 'SOLADE21XXX' }, + { label: 'Bankname', key: 'bank_name', span: false, placeholder: 'Musterbank' }, ] as const).map(({ label, key, span, placeholder }) => (
diff --git a/shop/lib/actions/companies.ts b/shop/lib/actions/companies.ts index adc8881..527d1f2 100644 --- a/shop/lib/actions/companies.ts +++ b/shop/lib/actions/companies.ts @@ -174,6 +174,10 @@ export async function adminCreateEndCustomer(data: { zip?: string city?: string email?: string + bank_iban?: string + bank_bic?: string + bank_name?: string + bank_owner?: string }) { const admin = createAdminClient() const { data: dbData, error } = await admin @@ -188,6 +192,10 @@ export async function adminCreateEndCustomer(data: { zip: data.zip || null, city: data.city || null, email: data.email || null, + bank_iban: data.bank_iban || null, + bank_bic: data.bank_bic || null, + bank_name: data.bank_name || null, + bank_owner: data.bank_owner || null, }]) .select() .single() @@ -205,6 +213,10 @@ export async function adminUpdateEndCustomer(id: string, data: { zip?: string city?: string email?: string + bank_iban?: string + bank_bic?: string + bank_name?: string + bank_owner?: string }) { const admin = createAdminClient() const { data: dbData, error } = await admin @@ -219,6 +231,10 @@ export async function adminUpdateEndCustomer(id: string, data: { zip: data.zip || null, city: data.city || null, email: data.email || null, + bank_iban: data.bank_iban || null, + bank_bic: data.bank_bic || null, + bank_name: data.bank_name || null, + bank_owner: data.bank_owner || null, }) .eq('id', id) .select() diff --git a/shop/lib/actions/end-customers.ts b/shop/lib/actions/end-customers.ts index 30a65c1..a88eac3 100644 --- a/shop/lib/actions/end-customers.ts +++ b/shop/lib/actions/end-customers.ts @@ -16,6 +16,10 @@ export type EndCustomerFormData = { zip?: string city?: string email?: string + bank_iban?: string + bank_bic?: string + bank_name?: string + bank_owner?: string } // ─── Lesen ─────────────────────────────────────────────────────────────────── @@ -74,6 +78,10 @@ export async function createEndCustomer(formData: EndCustomerFormData): Promise< zip: formData.zip || null, city: formData.city || null, email: formData.email || null, + bank_iban: formData.bank_iban || null, + bank_bic: formData.bank_bic || null, + bank_name: formData.bank_name || null, + bank_owner: formData.bank_owner || null, }]) .select() .single() @@ -104,6 +112,10 @@ export async function updateEndCustomer(id: string, formData: EndCustomerFormDat zip: formData.zip || null, city: formData.city || null, email: formData.email || null, + bank_iban: formData.bank_iban || null, + bank_bic: formData.bank_bic || null, + bank_name: formData.bank_name || null, + bank_owner: formData.bank_owner || null, }) .eq('id', id) @@ -138,6 +150,10 @@ export async function anonymizeEndCustomer(id: string): Promise { zip: null, city: null, email: null, + bank_iban: null, + bank_bic: null, + bank_name: null, + bank_owner: null, is_anonymized: true, }) .eq('id', id) diff --git a/shop/lib/license-transform.ts b/shop/lib/license-transform.ts index 06f74c4..d39a229 100644 --- a/shop/lib/license-transform.ts +++ b/shop/lib/license-transform.ts @@ -58,6 +58,10 @@ export function buildCustomerSnapshot( address: endCustomer.street ?? '', zip_code: endCustomer.zip ?? '', city: endCustomer.city ?? '', + bank_iban: endCustomer.bank_iban ?? undefined, + bank_bic: endCustomer.bank_bic ?? undefined, + bank_name: endCustomer.bank_name ?? undefined, + bank_owner: endCustomer.bank_owner ?? undefined, } } return { diff --git a/shop/lib/types.ts b/shop/lib/types.ts index c31527e..def5159 100644 --- a/shop/lib/types.ts +++ b/shop/lib/types.ts @@ -68,6 +68,10 @@ export type EndCustomer = { zip: string | null city: string | null email?: string | null + bank_iban: string | null + bank_bic: string | null + bank_name: string | null + bank_owner: string | null is_anonymized: boolean created_at: string } @@ -100,6 +104,10 @@ export type CustomerSnapshot = { zip_code: string city: string email?: string + bank_iban?: string + bank_bic?: string + bank_name?: string + bank_owner?: string } export type OrderModuleSnapshot = { diff --git a/shop/supabase/migrations/20260703094300_add_bank_details_to_end_customers.sql b/shop/supabase/migrations/20260703094300_add_bank_details_to_end_customers.sql new file mode 100644 index 0000000..d0054a6 --- /dev/null +++ b/shop/supabase/migrations/20260703094300_add_bank_details_to_end_customers.sql @@ -0,0 +1,6 @@ +-- Migration: Add bank details to end_customers table +ALTER TABLE end_customers + ADD COLUMN IF NOT EXISTS bank_iban TEXT, + ADD COLUMN IF NOT EXISTS bank_bic TEXT, + ADD COLUMN IF NOT EXISTS bank_name TEXT, + ADD COLUMN IF NOT EXISTS bank_owner TEXT;