PluginProbe
Easy Invoice – Invoice Generator, PDF Quotes & Payments / 2.3.2
Easy Invoice – Invoice Generator, PDF Quotes & Payments v2.3.2
2.4.0 2.4.1 2.3.8 2.3.7 2.3.6 2.3.5 2.3.4 2.3.3 2.3.2 2.3.1 2.2.0 2.1.21 2.1.20 2.1.19 2.1.18 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.16 2.1.2 All 57 releases
easy-invoice / includes / Repositories / InvoiceRepository.php

InvoiceRepository.php in Easy Invoice – Invoice Generator, PDF Quotes & Payments 2.3.2, at includes/Repositories/InvoiceRepository.php

592 lines 18.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Invoice Repository Class
4 *
5 * @package Easy_Invoice
6 * @subpackage Repositories
7 */
8
9 namespace EasyInvoice\Repositories;
10
11 use EasyInvoice\Interfaces\InvoiceRepositoryInterface;
12 use EasyInvoice\Models\Invoice;
13 use WP_Post;
14 use WP_Query;
15
16 /**
17 * InvoiceRepository Class
18 *
19 * Handles data access for invoice objects with extensible architecture for pro features.
20 */
21 class InvoiceRepository implements InvoiceRepositoryInterface {
22
23 /**
24 * The post type name
25 *
26 * @var string
27 */
28 protected $post_type = \EasyInvoice\Constants\PostTypes::EASY_INVOICE_POST_TYPE;
29
30 /**
31 * Find an invoice by ID
32 *
33 * @param int $id The invoice ID
34 * @return Invoice|null The invoice model or null if not found
35 */
36 public function find($id) {
37 $post = get_post($id);
38
39 if (!$post || $post->post_type !== $this->post_type) {
40 return null;
41 }
42
43 $invoice = new Invoice($post);
44
45 // Ensure invoice has proper slug for pretty URLs
46 $invoice->ensureProperSlug();
47
48 // Allow plugins to modify the found invoice
49 return apply_filters('easy_invoice_invoice_found', $invoice, $id);
50 }
51
52 /**
53 * Get all invoices
54 *
55 * @param array $args Optional arguments to filter the results
56 * @return array Array of Invoice models
57 */
58 public function all($args = []) {
59 $default_args = [
60 'post_type' => $this->post_type,
61 'posts_per_page' => -1,
62 'post_status' => 'publish',
63 'orderby' => 'date',
64 'order' => 'DESC',
65 ];
66
67 $query_args = wp_parse_args($args, $default_args);
68
69 // Allow plugins to modify query arguments
70 $query_args = apply_filters('easy_invoice_invoice_query_args', $query_args);
71
72 $query = new WP_Query($query_args);
73 $invoices = [];
74
75 if ($query->have_posts()) {
76 foreach ($query->posts as $post) {
77 $invoice = new Invoice($post);
78
79 // Ensure invoice has proper slug for pretty URLs
80 $invoice->ensureProperSlug();
81
82 $invoices[] = $invoice;
83 }
84 }
85
86 // Allow plugins to modify the results
87 return apply_filters('easy_invoice_invoices_found', $invoices, $query_args);
88 }
89
90 /**
91 * Create a new invoice
92 *
93 * @param array $data Invoice data
94 * @return Invoice|false The created invoice or false on failure
95 */
96 public function create($data) {
97 // Allow plugins to modify the data before creation
98 $data = apply_filters('easy_invoice_invoice_create_data', $data);
99
100 // Create a new invoice object
101 $invoice = new Invoice();
102
103 // Set basic data
104 $invoice->setTitle($data['title'] ?? 'New Invoice');
105
106 // Auto-generate invoice number if not provided
107 if ((!isset($data['number']) || empty($data['number'])) &&
108 (!isset($data['invoice_number']) || empty($data['invoice_number']))) {
109 $invoice_number_service = easy_invoice_get_invoice_number_service();
110 $data['number'] = $invoice_number_service->generateUniqueNumber();
111 }
112
113 // Set invoice data
114 $this->setInvoiceData($invoice, $data, false);
115
116 // Allow plugins to modify the invoice before saving
117 do_action('easy_invoice_invoice_before_create', $invoice, $data);
118
119 // Save the invoice (this will create the post and ensure proper permalinks)
120 if ($invoice->save()) {
121 // Allow plugins to perform actions after creation
122 do_action('easy_invoice_invoice_created', $invoice, $data);
123 return $invoice;
124 }
125
126 return false;
127 }
128
129 /**
130 * Update an existing invoice
131 *
132 * @param int $id The invoice ID
133 * @param array $data The invoice data
134 * @return Invoice|null The updated invoice model or null if not found
135 */
136 public function update($id, $data) {
137 try {
138 $invoice = $this->find($id);
139
140 if (!$invoice) {
141 return null;
142 }
143
144 // Set invoice data
145 $this->setInvoiceData($invoice, $data);
146
147 // Save the invoice
148 $result = $invoice->save();
149
150 return $result ? $invoice : null;
151 } catch (\Exception $e) {
152 return null;
153 }
154 }
155
156 /**
157 * Delete an invoice
158 *
159 * @param int $id The invoice ID
160 * @return bool True if successful, false otherwise
161 */
162 public function delete($id) {
163 $invoice = $this->find($id);
164
165 if (!$invoice) {
166 return false;
167 }
168
169 // Allow plugins to perform actions before deletion
170 do_action('easy_invoice_invoice_before_delete', $invoice);
171
172 $result = wp_delete_post($id, true);
173
174 if ($result) {
175 // Allow plugins to perform actions after deletion
176 do_action('easy_invoice_invoice_deleted', $id);
177 }
178
179 return $result instanceof WP_Post;
180 }
181
182 /**
183 * Find invoices by customer ID
184 *
185 * @param int $customer_id The customer ID
186 * @return array Array of Invoice models
187 */
188 public function findByCustomer($customer_id) {
189 $args = [
190 'meta_query' => [
191 [
192 'key' => '_easy_invoice_customer_id',
193 'value' => $customer_id,
194 'compare' => '=',
195 ],
196 ],
197 ];
198
199 $invoices = $this->all($args);
200
201 // Allow plugins to modify the filtered results
202 return apply_filters('easy_invoice_invoices_by_customer', $invoices, $customer_id);
203 }
204
205 /**
206 * Find invoices by status
207 *
208 * @param string $status The invoice status
209 * @return array Array of Invoice models
210 */
211 public function findByStatus($status) {
212 $args = [
213 'meta_query' => [
214 [
215 'key' => '_easy_invoice_status',
216 'value' => $status,
217 'compare' => '=',
218 ],
219 ],
220 ];
221
222 $invoices = $this->all($args);
223
224 // Allow plugins to modify the filtered results
225 return apply_filters('easy_invoice_invoices_by_status', $invoices, $status);
226 }
227
228 /**
229 * Find invoices due within a date range
230 *
231 * @param string $start_date The start date in 'Y-m-d' format
232 * @param string $end_date The end date in 'Y-m-d' format
233 * @return array Array of Invoice models
234 */
235 public function findByDueDate($start_date, $end_date = null) {
236 $meta_query = [
237 [
238 'key' => '_easy_invoice_due_date',
239 'value' => $start_date,
240 'compare' => '>=',
241 'type' => 'DATE',
242 ],
243 ];
244
245 if ($end_date) {
246 $meta_query[] = [
247 'key' => '_easy_invoice_due_date',
248 'value' => $end_date,
249 'compare' => '<=',
250 'type' => 'DATE',
251 ];
252 }
253
254 $args = [
255 'meta_query' => $meta_query,
256 ];
257
258 $invoices = $this->all($args);
259
260 // Allow plugins to modify the filtered results
261 return apply_filters('easy_invoice_invoices_by_due_date', $invoices, $start_date, $end_date);
262 }
263
264 /**
265 * Count invoices
266 *
267 * @param array $args Optional arguments to filter the results
268 * @return int Number of invoices
269 */
270 public function count($args = []) {
271 $default_args = [
272 'post_type' => $this->post_type,
273 'post_status' => 'publish',
274 ];
275
276 $query_args = wp_parse_args($args, $default_args);
277
278 // Allow plugins to modify query arguments
279 $query_args = apply_filters('easy_invoice_invoice_count_query_args', $query_args);
280
281 $query = new WP_Query($query_args);
282
283 $count = $query->found_posts;
284
285 // Allow plugins to modify the count
286 return apply_filters('easy_invoice_invoice_count', $count, $query_args);
287 }
288
289 /**
290 * Find an invoice by its invoice number (stored in post meta)
291 *
292 * @param string $number Invoice number (exact match)
293 * @return Invoice|null
294 */
295 public function findByNumber(string $number) {
296 $args = [
297 'post_type' => $this->post_type,
298 'post_status' => ['publish', 'draft', 'private', 'pending'],
299 'posts_per_page' => 1,
300 'meta_query' => [
301 [
302 'key' => \EasyInvoice\Constants\InvoiceMetaKeys::NUMBER,
303 'value' => $number,
304 'compare' => '=',
305 ],
306 ],
307 'orderby' => 'date',
308 'order' => 'DESC',
309 ];
310
311 $query = new WP_Query($args);
312 if (!empty($query->posts)) {
313 $post = $query->posts[0];
314 if ($post && $post->post_type === $this->post_type) {
315 $invoice = new Invoice($post);
316 $invoice->ensureProperSlug();
317 return apply_filters('easy_invoice_invoice_found_by_number', $invoice, $number);
318 }
319 }
320 return null;
321 }
322
323 /**
324 * Find published invoice by ID
325 *
326 * @param int $id The invoice ID
327 * @return Invoice|null The invoice model or null if not found
328 */
329 public function findPublished(int $id) {
330 $post = get_post($id);
331
332 if (!$post || $post->post_type !== $this->post_type || $post->post_status !== 'publish') {
333 return null;
334 }
335
336 $invoice = new Invoice($post);
337
338 // Ensure invoice has proper slug for pretty URLs
339 $invoice->ensureProperSlug();
340
341 return $invoice;
342 }
343
344 /**
345 * Update all existing draft invoices to published status for proper permalinks
346 *
347 * @return int Number of invoices updated
348 */
349 public function updateAllExistingInvoices(): int {
350 global $wpdb;
351
352 // Find all draft invoices
353 $draft_invoices = $wpdb->get_col($wpdb->prepare(
354 "SELECT ID FROM {$wpdb->posts}
355 WHERE post_type = %s
356 AND post_status = 'draft'",
357 $this->post_type
358 ));
359
360 $updated_count = 0;
361
362 foreach ($draft_invoices as $invoice_id) {
363 $invoice = $this->find($invoice_id);
364 if ($invoice) {
365 // Save the invoice (this will publish it and ensure proper permalinks)
366 if ($invoice->save()) {
367 $updated_count++;
368 }
369 }
370 }
371
372 // Allow plugins to perform actions after bulk update
373 do_action('easy_invoice_invoices_bulk_updated', $updated_count);
374
375 return $updated_count;
376 }
377
378 /**
379 * Set invoice data from array
380 *
381 * @param Invoice $invoice
382 * @param array $data
383 * @param bool $preserve_number
384 * @return void
385 */
386 protected function setInvoiceData(Invoice $invoice, array $data, $preserve_number = false) {
387 // Allow plugins to modify the data setting process
388 do_action('easy_invoice_invoice_set_data_before', $invoice, $data);
389
390 // Set basic invoice fields (core fields that have dedicated methods)
391 if (isset($data['title'])) {
392 $invoice->setTitle($data['title']);
393 }
394
395 if (isset($data['invoice_title'])) {
396 $invoice->setTitle($data['invoice_title']);
397 }
398
399 // Always update description if it exists in data (even if empty, to allow clearing)
400 if (array_key_exists('description', $data)) {
401 $invoice->setDescription($data['description'] ?? '');
402 }
403
404 if (array_key_exists('invoice_description', $data)) {
405 $invoice->setDescription($data['invoice_description'] ?? '');
406 }
407
408 // Set invoice number (only if not preserving existing)
409 if (isset($data['invoice_number']) && !empty($data['invoice_number'])) {
410 $invoice->setNumber($data['invoice_number']);
411 } elseif (isset($data['number']) && !empty($data['number'])) {
412 $invoice->setNumber($data['number']);
413 }
414
415 // Set dates
416 if (isset($data['issue_date'])) {
417 $invoice->setIssueDate($data['issue_date']);
418 }
419
420 if (isset($data['invoice_date'])) {
421 $invoice->setIssueDate($data['invoice_date']);
422 }
423
424 if (isset($data['issue-date'])) {
425 $invoice->setIssueDate($data['issue-date']);
426 }
427
428 if (isset($data['due_date'])) {
429 $invoice->setDueDate($data['due_date']);
430 }
431
432 if (isset($data['due-date'])) {
433 $invoice->setDueDate($data['due-date']);
434 }
435
436 // Set status
437 if (isset($data['status'])) {
438 $invoice->setStatus($data['status']);
439 }
440
441 if (isset($data['invoice_status'])) {
442 $invoice->setStatus($data['invoice_status']);
443 }
444
445 if (isset($data['payment_status'])) {
446 $invoice->setStatus($data['payment_status']);
447 }
448
449 // Set notes and terms
450 if (isset($data['notes'])) {
451 $invoice->setNotes($data['notes']);
452 }
453
454 if (isset($data['terms_and_conditions'])) {
455 $invoice->setTerms($data['terms_and_conditions']);
456 }
457
458 if (isset($data['internal_notes'])) {
459 $invoice->setInternalNotes($data['internal_notes']);
460 }
461
462 if (isset($data['payment_instructions'])) {
463 $invoice->setPaymentInstructions($data['payment_instructions']);
464 }
465
466 // Set payment gateways
467 if (isset($data['payment_gateways']) && is_array($data['payment_gateways'])) {
468 $invoice->setPaymentGateways($data['payment_gateways']);
469 } elseif (isset($data['payment_gateways']) && is_string($data['payment_gateways'])) {
470 $gateways = array_filter(explode(',', $data['payment_gateways']));
471 $invoice->setPaymentGateways($gateways);
472 } else {
473 $invoice->setPaymentGateways([]);
474 }
475
476 // Set payment gateways toggle state
477 if (isset($data['payment_gateways_toggle_state'])) {
478 $invoice->setPaymentGatewaysToggleState((string)$data['payment_gateways_toggle_state']);
479 }
480
481 // Set template
482 if (isset($data['invoice_template'])) {
483 $invoice->setTemplate($data['invoice_template']);
484 }
485
486 // Set client information
487 if (isset($data['customer_name'])) {
488 $invoice->setCustomerName($data['customer_name']);
489 }
490
491 if (isset($data['customer_address'])) {
492 $invoice->setCustomerAddress($data['customer_address']);
493 }
494
495 if (isset($data['customer_email'])) {
496 $invoice->setCustomerEmail($data['customer_email']);
497 }
498
499 // Set discount and tax settings
500 if (isset($data['discount_type'])) {
501 $invoice->setDiscountType($data['discount_type']);
502 }
503
504 if (isset($data['discount_value'])) {
505 $invoice->setDiscountValue($data['discount_value']);
506 }
507
508 if (isset($data['discount'])) {
509 $invoice->setDiscountValue($data['discount']);
510 }
511
512 if (isset($data['tax_rate'])) {
513 $invoice->setTaxRate($data['tax_rate']);
514 }
515
516 if (isset($data['discount_calculation_method'])) {
517 $invoice->setDiscountCalculationMethod($data['discount_calculation_method']);
518 } elseif (isset($data['calculation_method'])) {
519 $invoice->setDiscountCalculationMethod($data['calculation_method']);
520 }
521
522 if (isset($data['prices_include_tax'])) {
523 $invoice->setPricesIncludeTax($data['prices_include_tax']);
524 }
525
526 // Set currency settings
527 if (isset($data['currency_code'])) {
528 $invoice->setCurrencyCode($data['currency_code']);
529 }
530
531 if (isset($data['currency_position'])) {
532 $invoice->setCurrencyPosition($data['currency_position']);
533 }
534
535 // Set footer text
536 if (isset($data['footer_text'])) {
537 $invoice->setFooterText($data['footer_text']);
538 }
539
540 // Set client ID
541 if (isset($data['client_id']) && !empty($data['client_id'])) {
542 $invoice->setClientId((int) $data['client_id']);
543 }
544
545 // Set items
546 if (isset($data['items']) && is_array($data['items'])) {
547 $invoice->setItems($data['items']);
548 }
549
550 // Set custom fields
551 if (isset($data['custom_fields']) && is_array($data['custom_fields'])) {
552 $invoice->setCustomFields($data['custom_fields']);
553 }
554
555 // Set recurring fields
556 if (isset($data['recurring_enabled'])) {
557 $invoice->setRecurringEnabled((bool) $data['recurring_enabled']);
558 }
559
560 if (isset($data['recurring_frequency'])) {
561 $invoice->setRecurringFrequency($data['recurring_frequency']);
562 }
563
564 if (isset($data['recurring_interval'])) {
565 $invoice->setRecurringInterval((int) $data['recurring_interval']);
566 }
567
568 if (isset($data['recurring_start_date'])) {
569 $invoice->setRecurringStartDate($data['recurring_start_date']);
570 }
571
572 // Use configuration-driven approach for all other fields
573 $form_processor = new \EasyInvoice\Forms\FormProcessor();
574 $field_registration = new \EasyInvoice\Forms\Invoice\InvoiceFieldRegistration();
575
576 // Get all field definitions from all tabs
577 $field_definitions = [];
578 $tabs = $field_registration->getTabs();
579 foreach ($tabs as $tab_id => $tab) {
580 $tab_fields = $field_registration->getFields($tab_id);
581 foreach ($tab_fields as $field) {
582 $field_definitions[] = $field;
583 }
584 }
585
586 // Save form data using field configuration
587 $form_processor->saveFormDataToDatabase($data, $field_definitions, $invoice);
588
589 // Allow plugins to modify the data setting process
590 do_action('easy_invoice_invoice_set_data_after', $invoice, $data);
591 }
592 }