chore(merge): integrate origin/staging into local staging
All checks were successful
Staging Build / build (push) Successful in 2m57s

Resolved conflict in customer-accordion-list.tsx by keeping
the per-device flattening (DeviceCard) implementation.
This commit is contained in:
DanielS
2026-07-23 09:47:37 +02:00
16 changed files with 255 additions and 50 deletions

View File

@@ -360,6 +360,8 @@ export function OrderWizard({
return { monthlyTotal: monthly, oneTimeTotal: oneTime }
}, [selections, products, categories, moduleQuantities])
// Ermittlung der Update-Faktoren basierend auf dem Lizenzdatum (nur für Kauf/einmalig relevant)
const updatePriceModifier = useMemo(() => {
if (selectedBillingInterval !== 'one_time' || !lastLicenseDate) return { factor: 1 }
@@ -413,6 +415,96 @@ export function OrderWizard({
})
}, [visibleCategories, selections, products, selectedBillingInterval])
const finalItemsToShow = basketItems.length > 0
? basketItems
: (allCategoriesFilled && productValidationErrors.length === 0
? [{ deviceName: deviceName || 'Kasse 1', selections, moduleQuantities, billingInterval: selectedBillingInterval }]
: [])
// Gesamtsummen für alle Items in der Bestellung (finalItemsToShow)
const { overallMonthlyTotal, overallOneTimeTotal, linkedFeeProducts } = useMemo(() => {
let monthly = 0
let oneTime = 0
const feeProductIds = new Set<string>()
finalItemsToShow.forEach(item => {
categories.forEach(cat => {
const sel = item.selections[cat.id]
if (!sel) return
const selectedProds: Product[] = []
if (cat.allow_multiselect && sel.productIds && sel.productIds.length > 0) {
sel.productIds.forEach((pId: string) => {
const p = products.find(prod => prod.id === pId)
if (p) selectedProds.push(p)
})
} else if (sel.productId) {
const p = products.find(prod => prod.id === sel.productId)
if (p) selectedProds.push(p)
}
const freeLimit = cat.allow_multiselect ? cat.free_items_limit : 0
const sortedProds = [...selectedProds].sort((a, b) => a.base_price - b.base_price)
sortedProds.forEach((prod, idx) => {
const isFree = idx < freeLimit
const basePrice = isFree ? 0 : prod.base_price
if (prod.billing_interval === 'monthly') {
monthly += basePrice
} else {
oneTime += basePrice
}
if (prod.linked_fee_product_id) {
feeProductIds.add(prod.linked_fee_product_id)
}
// Module
sel.moduleIds?.forEach((mId: string) => {
const mod = prod.modules?.find(m => m.id === mId)
if (mod) {
const qty = item.moduleQuantities?.[mId] || 1
if (prod.billing_interval === 'monthly') {
monthly += mod.price * qty
} else {
oneTime += mod.price * qty
}
}
})
})
})
})
const feeProducts: Product[] = []
feeProductIds.forEach(id => {
const p = products.find(prod => prod.id === id)
if (p) {
feeProducts.push(p)
if (p.billing_interval === 'monthly') {
monthly += p.base_price
} else {
oneTime += p.base_price
}
}
})
return {
overallMonthlyTotal: monthly,
overallOneTimeTotal: oneTime,
linkedFeeProducts: feeProducts
}
}, [finalItemsToShow, products, categories])
// Gesamte Endbeträge ermitteln
const overallOneTimeNet = overallOneTimeTotal * discountFactor
const overallOneTimeTax = overallOneTimeNet * 0.19
const overallOneTimeGross = overallOneTimeNet + overallOneTimeTax
const overallMonthlyNet = overallMonthlyTotal
const overallMonthlyTax = overallMonthlyNet * 0.19
const overallMonthlyGross = overallMonthlyNet + overallMonthlyTax
const isNextStepDisabled = !allCategoriesFilled || productValidationErrors.length > 0
// Helper: toggle module for a category's selected product
@@ -614,11 +706,7 @@ export function OrderWizard({
}
}
const finalItemsToShow = basketItems.length > 0
? basketItems
: (allCategoriesFilled && productValidationErrors.length === 0
? [{ deviceName: deviceName || 'Kasse 1', selections, moduleQuantities, billingInterval: selectedBillingInterval }]
: [])
function selectProduct(catId: string, productId: string) {
setSelections(prev => {
@@ -856,14 +944,14 @@ export function OrderWizard({
finalItemsToShow={finalItemsToShow}
visibleCategories={visibleCategories}
products={products}
oneTimeTotal={oneTimeTotal}
monthlyTotal={monthlyTotal}
oneTimeNet={oneTimeNet}
oneTimeTax={oneTimeTax}
oneTimeGross={oneTimeGross}
monthlyNet={monthlyNet}
monthlyTax={monthlyTax}
monthlyGross={monthlyGross}
oneTimeTotal={overallOneTimeTotal}
monthlyTotal={overallMonthlyTotal}
oneTimeNet={overallOneTimeNet}
oneTimeTax={overallOneTimeTax}
oneTimeGross={overallOneTimeGross}
monthlyNet={overallMonthlyNet}
monthlyTax={overallMonthlyTax}
monthlyGross={overallMonthlyGross}
updatePriceModifier={updatePriceModifier}
selectedEndCustomer={selectedEndCustomer}
customerData={customerData}
@@ -872,6 +960,7 @@ export function OrderWizard({
isSubmitting={isSubmitting}
initialOrder={initialOrder}
prevStep={prevStep}
linkedFeeProducts={linkedFeeProducts}
/>
</motion.div>
)}