*/ public static function validMonths(string $billingCycle): array { $cycleMonths = OrderHelper::cycleToMonths($billingCycle); if ($cycleMonths > 24) { return [$cycleMonths]; } $maxMultiple = intdiv(24, $cycleMonths); return array_map(static fn (int $n): int => $n * $cycleMonths, range(1, $maxMultiple)); } public static function addonTotal(Service $service, int $cycles): int { return (int) array_sum(array_column(self::addonInvoiceItems($service, $cycles, 0), 'total_price')); } /** @return list> */ public static function addonInvoiceItems(Service $service, int $cycles, int $months): array { $meta = array_filter( (array) ($service->orderItem?->addons_meta ?? []), static fn ($entry): bool => is_array($entry) && (int) ($entry['qty'] ?? 0) > 0, ); if ($meta === []) { return []; } $currentPrices = Addon::whereIn('id', array_column($meta, 'addon_id'))->pluck('price', 'id'); $items = []; foreach ($meta as $entry) { $qty = (int) $entry['qty']; $unitPrice = (int) ($currentPrices[$entry['addon_id'] ?? null] ?? $entry['price'] ?? 0); $totalPrice = $unitPrice * $qty * $cycles; if ($totalPrice <= 0) { continue; } $items[] = [ 'product_id' => $service->product_id, 'type' => 'addon', 'description' => 'Addon: ' . ($entry['name'] ?? strtoupper((string) ($entry['code'] ?? ''))) . ' x' . $qty, 'months' => $months, 'quantity' => $qty, 'unit_price' => $unitPrice * $cycles, 'total_price' => $totalPrice, ]; } return $items; } }