findNextUniqueNumber($next_number, $prefix); // Update the counter to the number we actually used + 1 for next time update_option('easy_invoice_next_quote_number', $unique_number + 1); return $prefix . str_pad($unique_number, 6, '0', STR_PAD_LEFT); } /** * Get the next quote number without incrementing * * @return string The next quote number */ public function getNextNumber(): string { $prefix = get_option('easy_invoice_quote_prefix', 'QT-'); $next_number = get_option('easy_invoice_next_quote_number', 1); // Find what the next unique number would be $unique_number = $this->findNextUniqueNumber($next_number, $prefix); return $prefix . str_pad($unique_number, 6, '0', STR_PAD_LEFT); } /** * Find the next unique number starting from the given number * * @param int $start_number The number to start checking from * @param string $prefix The prefix to use for checking * @return int The next unique number */ private function findNextUniqueNumber(int $start_number, string $prefix): int { $current_number = $start_number; $max_attempts = 1000; // Prevent infinite loops $attempts = 0; while ($attempts < $max_attempts) { $quote_number = $prefix . str_pad($current_number, 6, '0', STR_PAD_LEFT); if (!$this->numberExists($quote_number)) { return $current_number; } $current_number++; $attempts++; } // If we can't find a unique number, add timestamp to ensure uniqueness return $current_number + time(); } /** * Reset the quote number counter * * @param int $new_starting_number The new starting number * @return void */ public function resetCounter(int $new_starting_number = 1): void { update_option('easy_invoice_next_quote_number', $new_starting_number); } /** * Check if a quote number already exists * * @param string $quote_number The quote number to check * @return bool True if the number exists, false otherwise */ public function numberExists(string $quote_number): bool { global $wpdb; $result = $wpdb->get_var($wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->postmeta} WHERE meta_key = '_easy_invoice_quote_number' AND meta_value = %s", $quote_number )); return intval($result) > 0; } /** * Generate a unique quote number (handles duplicates) * * @return string A unique quote number */ public function generateUniqueNumber(): string { // Get settings $prefix = get_option('easy_invoice_quote_prefix', 'QT-'); // Get the next number to use from the current settings $next_number = get_option('easy_invoice_next_quote_number', 1); // Find the next unique number $unique_number = $this->findNextUniqueNumber($next_number, $prefix); // Update the counter to the number we actually used + 1 for next time update_option('easy_invoice_next_quote_number', $unique_number + 1); return $prefix . str_pad($unique_number, 6, '0', STR_PAD_LEFT); } /** * Get the highest quote number from existing quotes * * @return int The highest quote number found */ public function getHighestQuoteNumber(): int { global $wpdb; $prefix = get_option('easy_invoice_quote_prefix', 'QT-'); // Get all quote numbers from the database $results = $wpdb->get_results($wpdb->prepare( "SELECT meta_value FROM {$wpdb->postmeta} WHERE meta_key = '_easy_invoice_quote_number' AND meta_value LIKE %s ORDER BY meta_value DESC LIMIT 1", $prefix . '%' )); if (empty($results)) { return 0; } $highest_number = $results[0]->meta_value; // Extract the number part (remove prefix and padding) $number_part = str_replace($prefix, '', $highest_number); $number_part = ltrim($number_part, '0'); return intval($number_part); } /** * Format a quote number with custom formatting * * @param int $number The number to format * @param string $prefix The prefix to use * @param int $padding The number of digits to pad to * @return string The formatted quote number */ public function formatNumber(int $number, string $prefix = 'QT-', int $padding = 6): string { return $prefix . str_pad($number, $padding, '0', STR_PAD_LEFT); } }