findByInvoice($invoice_id); if ($item_index === null) { return $items; } return isset($items[$item_index]) ? $items[$item_index] : null; } /** * Get all items (this method doesn't make sense for meta-based items, but kept for interface compatibility) * * @param array $args Optional arguments (ignored for meta-based items) * @return array Array of invoice item data */ public function all($args = []) { // This method doesn't make sense for meta-based items // Return empty array as items are tied to specific invoices return []; } /** * Add a new item to an invoice * * @param int $invoice_id The invoice ID * @param array $data The item data * @return bool True if successful, false otherwise */ public function create($invoice_id, $data) { $items = $this->findByInvoice($invoice_id); $items[] = $data; $result = update_post_meta($invoice_id, self::ITEMS_META_KEY, $items); return $result !== false; } /** * Update an existing item * * @param int $invoice_id The invoice ID * @param int $item_index The item index (0-based) * @param array $data The item data * @return bool True if successful, false otherwise */ public function update($invoice_id, $item_index, $data) { $items = $this->findByInvoice($invoice_id); if (!isset($items[$item_index])) { return false; } $items[$item_index] = $data; $result = update_post_meta($invoice_id, self::ITEMS_META_KEY, $items); return $result !== false; } /** * Delete an item * * @param int $invoice_id The invoice ID * @param int $item_index The item index (0-based) * @return bool True if successful, false otherwise */ public function delete($invoice_id, $item_index) { $items = $this->findByInvoice($invoice_id); if (!isset($items[$item_index])) { return false; } // Remove the item unset($items[$item_index]); // Re-index the array $items = array_values($items); // Update the meta $result = update_post_meta($invoice_id, self::ITEMS_META_KEY, $items); return $result !== false; } /** * Delete all items for an invoice * * @param int $invoice_id The invoice ID * @return bool True if successful, false otherwise */ public function deleteAll($invoice_id) { $result = delete_post_meta($invoice_id, self::ITEMS_META_KEY); return $result !== false; } /** * Count items for an invoice * * @param int $invoice_id The invoice ID * @return int The count of items */ public function count($invoice_id) { $items = $this->findByInvoice($invoice_id); return count($items); } /** * Get total amount for all items in an invoice * * @param int $invoice_id The invoice ID * @return float The total amount */ public function getTotalAmount($invoice_id) { $items = $this->findByInvoice($invoice_id); $total = 0; foreach ($items as $item) { $quantity = isset($item['quantity']) ? floatval($item['quantity']) : 0; $price = isset($item['price']) ? floatval($item['price']) : 0; $total += $quantity * $price; } return $total; } /** * Replace all items for an invoice * * @param int $invoice_id The invoice ID * @param array $items Array of item data * @return bool True if successful, false otherwise */ public function replaceAll($invoice_id, $items) { $result = update_post_meta($invoice_id, self::ITEMS_META_KEY, $items); return $result !== false; } /** * Sanitize item data * * @param array $data The raw item data * @return array The sanitized item data */ protected function sanitizeItemData($data) { return [ 'name' => isset($data['name']) ? sanitize_text_field($data['name']) : '', 'description' => isset($data['description']) ? sanitize_textarea_field($data['description']) : '', 'quantity' => isset($data['quantity']) ? floatval($data['quantity']) : 0, 'price' => isset($data['price']) ? floatval($data['price']) : 0, 'tax_rate' => isset($data['tax_rate']) ? floatval($data['tax_rate']) : 0, 'taxable' => isset($data['taxable']) ? (string) $data['taxable'] : '0', 'discount' => isset($data['discount']) ? floatval($data['discount']) : 0, 'discount_type' => isset($data['discount_type']) ? sanitize_text_field($data['discount_type']) : 'percentage', ]; } }