Compare commits

...

3 Commits

Author SHA1 Message Date
DanielS
a93fb975c0 docs: finalize request terminology updates and clean up license transforms
All checks were successful
Staging Build / build (push) Successful in 2m48s
2026-07-09 22:58:35 +02:00
DanielS
21c4aa859e fix: rename invoice terminology to request and quotation confirmation across pdf and mail services 2026-07-09 22:58:29 +02:00
DanielS
20f7d5a05a fix: resolve syntax error in invoice-pdf.tsx 2026-07-09 22:57:31 +02:00
5 changed files with 14 additions and 17 deletions

View File

@@ -62,15 +62,13 @@ graph TD
- **Snapshot-Exklusivität**: Die Rechnungsgenerierung erfolgt ausschließlich auf Basis der in `orders.order_data` und `orders.customer_data` eingefrorenen Snapshots. - **Snapshot-Exklusivität**: Die Rechnungsgenerierung erfolgt ausschließlich auf Basis der in `orders.order_data` und `orders.customer_data` eingefrorenen Snapshots.
- **Layout-Unterscheidung**: - **Layout-Unterscheidung**:
- **Typ `purchase` (Kauf)**: - **Typ `purchase` (Kauf)**:
- Generiert eine klassische **B2B-Rechnung**. - Generiert eine klassische **B2B-Angebot**.
- Weist die einmalige Gesamtsumme aus. - Weist die einmalige Gesamtsumme aus.
- Beinhaltet ein explizites Zahlungsziel ("Zahlbar innerhalb von 14 Tagen ohne Abzug").
- **Typ `subscription` (Abonnement)**: - **Typ `subscription` (Abonnement)**:
- Generiert eine **Vertragsbestätigung (Abonnement)**. - Generiert eine **Angebotsbestätigung Abonnement**.
- Weist monatlich wiederkehrende Kosten aus. - Weist monatlich wiederkehrende Kosten aus.
- Beinhaltet das SEPA-Lastschriftmandat inklusive Kontoinhaber und IBAN.
- **Archivierung & Benachrichtigung**: - **Archivierung & Benachrichtigung**:
- Hochladen des PDFs in den Supabase Storage (`invoices` Bucket). - Hochladen des PDFs in den Supabase Storage (`invoices` Bucket).
- E-Mail-Versand mit PDF-Anhang an den Besteller. - E-Mail-Versand mit PDF-Anhang an den Partner.

View File

@@ -142,9 +142,9 @@ export async function POST(request: Request) {
try { try {
await sendMail({ await sendMail({
to: user.email, to: user.email,
subject: `Bestellbestätigung ${order.order_number}`, subject: `Bestätigung Ihrer CASPOS-Anfrage ${order.order_number}`,
text: `Vielen Dank für Ihre Bestellung ${order.order_number}. Typ: ${type}.`, text: `Vielen Dank für Ihre Anfrage ${order.order_number}.`,
html: `<p>Vielen Dank für Ihre Bestellung <strong>${order.order_number}</strong>.</p><p>Typ: ${type}</p>` html: `<p>Vielen Dank für Ihre Anfrage <strong>${order.order_number}</strong>.</p>`
}); });
} catch (mailErr) { } catch (mailErr) {
console.error('Mail error for order ' + order.id, mailErr); console.error('Mail error for order ' + order.id, mailErr);

View File

@@ -103,7 +103,7 @@ export const InvoicePDF = ({ order, orderSnapshot, customer }: any) => {
const totalTax = Math.round(totalNet * (taxRate / 100) * 100) / 100; const totalTax = Math.round(totalNet * (taxRate / 100) * 100) / 100;
const totalGross = Math.round((totalNet + totalTax) * 100) / 100; const totalGross = Math.round((totalNet + totalTax) * 100) / 100;
const formattedPrice = (val: number) => const formattedPrice = (val: number) =>
new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(val); new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(val);
return ( return (
@@ -123,7 +123,7 @@ export const InvoicePDF = ({ order, orderSnapshot, customer }: any) => {
</View> </View>
<Text style={styles.title}> <Text style={styles.title}>
{isSubscription ? 'Vertragsbestätigung (Abonnement)' : 'B2B-Rechnung'} {isSubscription ? 'Anfragebestätigung: Software-Abonnement' : 'Anfragebestätigung: Einmalige Lizenzen'}
</Text> </Text>
<View style={styles.section}> <View style={styles.section}>
@@ -207,7 +207,7 @@ export const InvoicePDF = ({ order, orderSnapshot, customer }: any) => {
<View style={styles.sepaBox}> <View style={styles.sepaBox}>
<Text style={{ fontWeight: 'bold', marginBottom: 4 }}>SEPA-Lastschriftmandat</Text> <Text style={{ fontWeight: 'bold', marginBottom: 4 }}>SEPA-Lastschriftmandat</Text>
<Text style={{ fontSize: 8, color: '#555' }}> <Text style={{ fontSize: 8, color: '#555' }}>
Ich ermächtige die CASPOS GmbH, Zahlungen von meinem Konto mittels Lastschrift einzuziehen. Zugleich weise ich mein Kreditinstitut an, die von der CASPOS GmbH auf mein Konto gezogenen Lastschriften einzulösen. Ich ermächtige die CASPOS GmbH, Zahlungen von meinem Konto mittels Lastschrift einzuziehen. Zugleich weise ich mein Kreditinstitut an, die von der CASPOS GmbH auf mein Konto gezogenen Lastschriften einzulösen. Das Mandat wird erst mit der finalen Aktivierung der Lizenzen durch den CASPOS-Support wirksam.
</Text> </Text>
{customer.bank_iban && ( {customer.bank_iban && (
<Text style={{ marginTop: 4, fontSize: 8, fontWeight: 'bold' }}> <Text style={{ marginTop: 4, fontSize: 8, fontWeight: 'bold' }}>
@@ -217,9 +217,8 @@ export const InvoicePDF = ({ order, orderSnapshot, customer }: any) => {
</View> </View>
) : ( ) : (
<View style={{ marginTop: 20 }}> <View style={{ marginTop: 20 }}>
<Text style={{ fontWeight: 'bold' }}>Zahlungsziel</Text> <Text style={{ fontSize: 9, color: '#555', fontStyle: 'italic' }}>
<Text style={{ color: '#555' }}> Dies ist eine unverbindliche Bestätigung Ihrer Anfrage. Ein verbindliches Angebot wird Ihnen in Kürze von unserem Vertriebsteam zugesendet.
Zahlbar innerhalb von 14 Tagen nach Erhalt dieser Rechnung ohne Abzug.
</Text> </Text>
</View> </View>
)} )}

View File

@@ -346,7 +346,7 @@ export async function updateOrderStatus(
await sendMail({ await sendMail({
to: user.email, to: user.email,
subject: `Statusänderung Ihrer Bestellung ${orderNumber}`, subject: `Statusänderung Ihrer Anfrage ${orderNumber}`,
text: statusEmail.text, text: statusEmail.text,
html: statusEmail.html html: statusEmail.html
}) })

View File

@@ -136,7 +136,7 @@ export function buildOrderSnapshot(
}) })
const moduleTotal = selectedModules.reduce((acc, m) => acc + (m.total_price || m.price), 0) const moduleTotal = selectedModules.reduce((acc, m) => acc + (m.total_price || m.price), 0)
// If this product falls under the free limit, set its base price to 0 // If this product falls under the free limit, set its base price to 0
const actualBasePrice = (sortedIndex < freeLimit) ? 0 : prod.base_price const actualBasePrice = (sortedIndex < freeLimit) ? 0 : prod.base_price
const itemTotal = actualBasePrice + moduleTotal const itemTotal = actualBasePrice + moduleTotal
@@ -146,7 +146,7 @@ export function buildOrderSnapshot(
category_id: cat.id, category_id: cat.id,
category_name: cat.name, category_name: cat.name,
product_id: prod.id, product_id: prod.id,
product_name: prod.name + (actualBasePrice === 0 ? " (Inklusive/Frei)" : ""), product_name: prod.name + (actualBasePrice === 0 ? "" : ""),
base_price: actualBasePrice, base_price: actualBasePrice,
billing_interval: prod.billing_interval, billing_interval: prod.billing_interval,
selected_modules: selectedModules, selected_modules: selectedModules,