Passed
Push — master ( 968588...618fc1 )
by Brian
11:17
created

GetPaid_Invoice_Notification_Emails::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 19
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 14
nc 1
nop 0
dl 0
loc 19
rs 9.7998
c 0
b 0
f 0
1
<?php
2
/**
3
 * Contains the invoice notification emails management class.
4
 *
5
 */
6
7
defined( 'ABSPATH' ) || exit;
8
9
/**
10
 * This class handles invoice notificaiton emails.
11
 *
12
 */
13
class GetPaid_Invoice_Notification_Emails {
14
15
	/**
16
	 * The array of invoice email actions.
17
	 *
18
	 * @param array
19
	 */
20
	public $invoice_actions;
21
22
	/**
23
	 * Class constructor
24
	 *
25
	 */
26
	public function __construct() {
27
28
		$this->invoice_actions = apply_filters(
29
			'getpaid_notification_email_invoice_triggers',
30
			array(
31
				'getpaid_new_invoice'                   => array( 'new_invoice', 'user_invoice' ),
32
				'getpaid_invoice_status_wpi-cancelled'  => 'cancelled_invoice',
33
				'getpaid_invoice_status_wpi-failed'     => 'failed_invoice',
34
				'getpaid_invoice_status_wpi-onhold'     => 'onhold_invoice',
35
				'getpaid_invoice_status_wpi-processing' => 'processing_invoice',
36
				'getpaid_invoice_status_publish'        => 'completed_invoice',
37
				'getpaid_invoice_status_wpi-renewal'    => 'completed_invoice',
38
				'getpaid_invoice_status_wpi-refunded'   => 'refunded_invoice',
39
				'getpaid_new_customer_note'             => 'user_note',
40
				'getpaid_daily_maintenance'             => 'overdue',
41
			)
42
		);
43
44
		$this->init_hooks();
45
46
	}
47
48
	/**
49
	 * Registers email hooks.
50
	 */
51
	public function init_hooks() {
52
53
		add_filter( 'getpaid_get_email_merge_tags', array( $this, 'invoice_merge_tags' ), 10, 2 );
54
		add_filter( 'getpaid_invoice_email_recipients', array( $this, 'filter_email_recipients' ), 10, 2 );
55
56
		foreach ( $this->invoice_actions as $hook => $email_type ) {
57
			$this->init_email_type_hook( $hook, $email_type );
58
		}
59
	}
60
61
	/**
62
	 * Registers an email hook for an invoice action.
63
	 * 
64
	 * @param string $hook
65
	 * @param string|array $email_type
66
	 */
67
	public function init_email_type_hook( $hook, $email_type ) {
68
69
		$email_type = wpinv_parse_list( $email_type );
70
71
		foreach ( $email_type as $type ) {
72
73
			$email = new GetPaid_Notification_Email( $type );
74
75
			// Abort if it is not active.
76
			if ( ! $email->is_active() ) {
77
				continue;
78
			}
79
80
			if ( method_exists( $this, $type ) ) {
81
				add_action( $hook, array( $this, $type ), 100, 2 );
82
				continue;
83
			}
84
85
			do_action( 'getpaid_invoice_init_email_type_hook', $type, $hook );
86
		}
87
88
	}
89
90
	/**
91
	 * Filters invoice merge tags.
92
	 *
93
	 * @param array $merge_tags
94
	 * @param mixed|WPInv_Invoice|WPInv_Subscription $object
95
	 */
96
	public function invoice_merge_tags( $merge_tags, $object ) {
97
98
		if ( is_a( $object, 'WPInv_Invoice' ) ) {
99
			return array_merge(
100
				$merge_tags,
101
				$this->get_invoice_merge_tags( $object )
102
			);
103
		}
104
105
		if ( is_a( $object, 'WPInv_Subscription' ) ) {
106
			return array_merge(
107
				$merge_tags,
108
				$this->get_invoice_merge_tags( $object->get_parent_payment() )
109
			);
110
		}
111
112
		return $merge_tags;
113
114
	}
115
116
	/**
117
	 * Generates invoice merge tags.
118
	 *
119
	 * @param WPInv_Invoice $invoice
120
	 * @return array
121
	 */
122
	public function get_invoice_merge_tags( $invoice ) {
123
124
		// Abort if it does not exist.
125
		if ( ! $invoice->get_id() ) {
126
			return array();
127
		}
128
129
		$merge_tags = array(
130
			'{name}'                => sanitize_text_field( $invoice->get_user_full_name() ),
131
			'{full_name}'           => sanitize_text_field( $invoice->get_user_full_name() ),
132
			'{first_name}'          => sanitize_text_field( $invoice->get_first_name() ),
133
			'{last_name}'           => sanitize_text_field( $invoice->get_last_name() ),
134
			'{email}'               => sanitize_email( $invoice->get_email() ),
135
			'{invoice_number}'      => sanitize_text_field( $invoice->get_number() ),
136
			'{invoice_currency}'    => sanitize_text_field( $invoice->get_currency() ),
137
			'{invoice_total}'       => sanitize_text_field( wpinv_price( $invoice->get_total(), $invoice->get_currency() ) ),
138
			'{invoice_link}'        => esc_url( $invoice->get_view_url() ),
139
			'{invoice_pay_link}'    => esc_url( $invoice->get_checkout_payment_url() ),
140
			'{invoice_receipt_link}'=> esc_url( $invoice->get_receipt_url() ),
141
			'{invoice_date}'        => getpaid_format_date_value( $invoice->get_date_created() ),
142
			'{invoice_due_date}'    => getpaid_format_date_value( $invoice->get_due_date(), __( 'on receipt', 'invoicing' ) ),
143
			'{invoice_quote}'       => sanitize_text_field( strtolower( $invoice->get_label() ) ),
144
			'{invoice_label}'       => sanitize_text_field( ucfirst( $invoice->get_label() ) ),
145
			'{invoice_description}' => wp_kses_post( $invoice->get_description() ),
146
			'{subscription_name}'   => wp_kses_post( $invoice->get_subscription_name() ),
147
			'{is_was}'              => strtotime( $invoice->get_due_date() ) < current_time( 'timestamp' ) ? __( 'was', 'invoicing' ) : __( 'is', 'invoicing' ),
148
		);
149
150
		$payment_form_data = $invoice->get_meta( 'payment_form_data', true );
151
152
		if ( is_array( $payment_form_data ) ) {
153
154
			foreach ( $payment_form_data as $label => $value ) {
155
156
				$label = preg_replace( '/[^a-z0-9]+/', '_', strtolower( $label ) );
157
				$value = is_array( $value ) ? implode( ', ', $value ) : $value;
158
159
				if ( is_scalar ( $value ) ) {
160
					$merge_tags[ "{{$label}}" ] = wp_kses_post( $value );
161
				}
162
163
			}
164
165
		}
166
167
		return apply_filters( 'getpaid_invoice_email_merge_tags', $merge_tags, $invoice );
168
	}
169
170
	/**
171
	 * Helper function to send an email.
172
	 *
173
	 * @param WPInv_Invoice $invoice
174
	 * @param GetPaid_Notification_Email $email
175
	 * @param string $type
176
	 * @param string|array $recipients
177
	 * @param array $extra_args Extra template args.
178
	 */
179
	public function send_email( $invoice, $email, $type, $recipients, $extra_args = array() ) {
180
181
		do_action( 'getpaid_before_send_invoice_notification', $type, $invoice, $email );
182
183
		$skip = $invoice->is_free() && wpinv_get_option( 'skip_email_free_invoice' );
184
		if ( apply_filters( 'getpaid_skip_invoice_email', $skip, $type, $invoice ) ) {
185
			return;
186
		}
187
188
		$mailer     = new GetPaid_Notification_Email_Sender();
189
		$merge_tags = $email->get_merge_tags();
190
191
		$result = $mailer->send(
192
			apply_filters( 'getpaid_invoice_email_recipients', wpinv_parse_list( $recipients ), $email ),
193
			$email->add_merge_tags( $email->get_subject(), $merge_tags ),
194
			$email->get_content( $merge_tags, $extra_args ),
195
			$email->get_attachments()
196
		);
197
198
		// Maybe send a copy to the admin.
199
		if ( $email->include_admin_bcc() ) {
200
			$mailer->send(
201
				wpinv_get_admin_email(),
0 ignored issues
show
Bug introduced by
It seems like wpinv_get_admin_email() can also be of type false; however, parameter $to of GetPaid_Notification_Email_Sender::send() does only seem to accept array|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

201
				/** @scrutinizer ignore-type */ wpinv_get_admin_email(),
Loading history...
202
				$email->add_merge_tags( $email->get_subject() . __( ' - ADMIN BCC COPY', 'invoicing' ), $merge_tags ),
203
				$email->get_content( $merge_tags ),
204
				$email->get_attachments()
205
			);
206
		}
207
208
		if ( $result ) {
209
			$invoice->add_system_note(
210
				sprintf(
211
					__( 'Successfully sent %s notification email to %s.', 'invoicing' ),
212
					sanitize_key( $type ),
213
					$email->is_admin_email() ? __( 'admin' ) : __( 'the customer' )
214
				)
215
			);
216
		} else {
217
			$invoice->add_system_note(
218
				sprintf(
219
					__( 'Failed sending %s notification email to %s.', 'invoicing' ),
220
					sanitize_key( $type ),
221
					$email->is_admin_email() ? __( 'admin' ) : __( 'the customer' )
222
				)
223
			);	
224
		}
225
226
		do_action( 'getpaid_after_send_invoice_notification', $type, $invoice, $email );
227
228
		return $result;
229
	}
230
231
	/**
232
	 * Also send emails to any cc users.
233
	 *
234
	 * @param array $recipients
235
	 * @param GetPaid_Notification_Email $email
236
	 */
237
	public function filter_email_recipients( $recipients, $email ) {
238
239
		if ( ! $email->is_admin_email() ) {
240
			$cc   = $email->object->get_email_cc();
0 ignored issues
show
Bug introduced by
The method get_email_cc() does not exist on WPInv_Subscription. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

240
			/** @scrutinizer ignore-call */ 
241
   $cc   = $email->object->get_email_cc();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Bug introduced by
The method get_email_cc() does not exist on WPInv_Item. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

240
			/** @scrutinizer ignore-call */ 
241
   $cc   = $email->object->get_email_cc();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
241
			$cc_2 = get_user_meta( $email->object->get_user_id(), '_wpinv_email_cc', true );
0 ignored issues
show
Bug introduced by
The method get_user_id() does not exist on WPInv_Subscription. Did you maybe mean get_customer_id()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

241
			$cc_2 = get_user_meta( $email->object->/** @scrutinizer ignore-call */ get_user_id(), '_wpinv_email_cc', true );

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Bug introduced by
The method get_user_id() does not exist on WPInv_Item. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

241
			$cc_2 = get_user_meta( $email->object->/** @scrutinizer ignore-call */ get_user_id(), '_wpinv_email_cc', true );

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
242
243
			if ( ! empty( $cc ) ) {
244
				$cc = array_map( 'sanitize_email', wpinv_parse_list( $cc ) );
245
				$recipients = array_filter( array_unique( array_merge( $recipients, $cc ) ) );
246
			}
247
248
			if ( ! empty( $cc_2 ) ) {
249
				$cc_2 = array_map( 'sanitize_email', wpinv_parse_list( $cc_2 ) );
250
				$recipients = array_filter( array_unique( array_merge( $recipients, $cc_2 ) ) );
251
			}
252
253
		}
254
255
		return $recipients;
256
257
	}
258
259
	/**
260
	 * Sends a new invoice notification.
261
	 *
262
	 * @param WPInv_Invoice $invoice
263
	 */
264
	public function new_invoice( $invoice ) {
265
266
		// Only send this email for invoices created via the admin page.
267
		if ( ! $invoice->is_type( 'invoice' ) || $invoice->is_paid() || $this->is_payment_form_invoice( $invoice->get_id() ) ) {
268
			return;
269
		}
270
271
		$email     = new GetPaid_Notification_Email( __FUNCTION__, $invoice );
272
		$recipient = wpinv_get_admin_email();
273
274
		return $this->send_email( $invoice, $email, __FUNCTION__, $recipient );
0 ignored issues
show
Bug introduced by
It seems like $recipient can also be of type false; however, parameter $recipients of GetPaid_Invoice_Notification_Emails::send_email() does only seem to accept array|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

274
		return $this->send_email( $invoice, $email, __FUNCTION__, /** @scrutinizer ignore-type */ $recipient );
Loading history...
275
276
	}
277
278
	/**
279
	 * Sends a cancelled invoice notification.
280
	 *
281
	 * @param WPInv_Invoice $invoice
282
	 */
283
	public function cancelled_invoice( $invoice ) {
284
285
		$email     = new GetPaid_Notification_Email( __FUNCTION__, $invoice );
286
		$recipient = wpinv_get_admin_email();
287
288
		return $this->send_email( $invoice, $email, __FUNCTION__, $recipient );
0 ignored issues
show
Bug introduced by
It seems like $recipient can also be of type false; however, parameter $recipients of GetPaid_Invoice_Notification_Emails::send_email() does only seem to accept array|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

288
		return $this->send_email( $invoice, $email, __FUNCTION__, /** @scrutinizer ignore-type */ $recipient );
Loading history...
289
290
	}
291
292
	/**
293
	 * Sends a failed invoice notification.
294
	 *
295
	 * @param WPInv_Invoice $invoice
296
	 */
297
	public function failed_invoice( $invoice ) {
298
299
		$email     = new GetPaid_Notification_Email( __FUNCTION__, $invoice );
300
		$recipient = wpinv_get_admin_email();
301
302
		return $this->send_email( $invoice, $email, __FUNCTION__, $recipient );
0 ignored issues
show
Bug introduced by
It seems like $recipient can also be of type false; however, parameter $recipients of GetPaid_Invoice_Notification_Emails::send_email() does only seem to accept array|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

302
		return $this->send_email( $invoice, $email, __FUNCTION__, /** @scrutinizer ignore-type */ $recipient );
Loading history...
303
304
	}
305
306
	/**
307
	 * Sends a notification whenever an invoice is put on hold.
308
	 *
309
	 * @param WPInv_Invoice $invoice
310
	 */
311
	public function onhold_invoice( $invoice ) {
312
313
		$email     = new GetPaid_Notification_Email( __FUNCTION__, $invoice );
314
		$recipient = $invoice->get_email();
315
316
		return $this->send_email( $invoice, $email, __FUNCTION__, $recipient );
317
318
	}
319
320
	/**
321
	 * Sends a notification whenever an invoice is marked as processing payment.
322
	 *
323
	 * @param WPInv_Invoice $invoice
324
	 */
325
	public function processing_invoice( $invoice ) {
326
327
		$email     = new GetPaid_Notification_Email( __FUNCTION__, $invoice );
328
		$recipient = $invoice->get_email();
329
330
		return $this->send_email( $invoice, $email, __FUNCTION__, $recipient );
331
332
	}
333
334
	/**
335
	 * Sends a notification whenever an invoice is paid.
336
	 *
337
	 * @param WPInv_Invoice $invoice
338
	 */
339
	public function completed_invoice( $invoice ) {
340
341
		// (Maybe) abort if it is a renewal invoice.
342
		if ( $invoice->is_renewal() && ! wpinv_get_option( 'email_completed_invoice_renewal_active', false ) ) {
343
			return;
344
		}
345
346
		$email     = new GetPaid_Notification_Email( __FUNCTION__, $invoice );
347
		$recipient = $invoice->get_email();
348
349
		return $this->send_email( $invoice, $email, __FUNCTION__, $recipient );
350
351
	}
352
353
	/**
354
	 * Sends a notification whenever an invoice is refunded.
355
	 *
356
	 * @param WPInv_Invoice $invoice
357
	 */
358
	public function refunded_invoice( $invoice ) {
359
360
		$email     = new GetPaid_Notification_Email( __FUNCTION__, $invoice );
361
		$recipient = $invoice->get_email();
362
363
		return $this->send_email( $invoice, $email, __FUNCTION__, $recipient );
364
365
	}
366
367
	/**
368
	 * Notifies a user about new invoices
369
	 *
370
	 * @param WPInv_Invoice $invoice
371
	 * @param bool $force
372
	 */
373
	public function user_invoice( $invoice, $force = false ) {
374
375
		if ( ! $force && ! empty( $GLOBALS['wpinv_skip_invoice_notification'] ) ) {
376
			return;
377
		}
378
379
		// Only send this email for invoices created via the admin page.
380
		if ( ! $invoice->is_type( 'invoice' ) || ( empty( $force ) && $invoice->is_paid() ) || ( empty( $force ) && $this->is_payment_form_invoice( $invoice->get_id() ) ) ) {
381
			return;
382
		}
383
384
		$email     = new GetPaid_Notification_Email( __FUNCTION__, $invoice );
385
		$recipient = $invoice->get_email();
386
387
		return $this->send_email( $invoice, $email, __FUNCTION__, $recipient );
388
389
	}
390
391
	/**
392
	 * Checks if an invoice is a payment form invoice.
393
	 *
394
	 * @param int $invoice
395
	 * @return bool
396
	 */
397
	public function is_payment_form_invoice( $invoice ) {
398
		$is_payment_form_invoice = empty( $_GET['getpaid-admin-action'] ) && ( 'payment_form' == get_post_meta( $invoice, 'wpinv_created_via', true ) || 'geodirectory' == get_post_meta( $invoice, 'wpinv_created_via', true ) );
399
		return apply_filters( 'getpaid_invoice_notifications_is_payment_form_invoice', $is_payment_form_invoice, $invoice );
400
	}
401
402
	/**
403
	 * Notifies admin about new invoice notes
404
	 *
405
	 * @param WPInv_Invoice $invoice
406
	 * @param string $note
407
	 */
408
	public function user_note( $invoice, $note ) {
409
410
		$email     = new GetPaid_Notification_Email( __FUNCTION__, $invoice );
411
		$recipient = $invoice->get_email();
412
413
		return $this->send_email( $invoice, $email, __FUNCTION__, $recipient, array( 'customer_note' => $note ) );
414
415
	}
416
417
	/**
418
	 * (Force) Sends overdue notices.
419
	 *
420
	 * @param WPInv_Invoice $invoice
421
	 */
422
	public function force_send_overdue_notice( $invoice ) {
423
		$email = new GetPaid_Notification_Email( 'overdue', $invoice );
424
		return $this->send_email( $invoice, $email, 'overdue', $invoice->get_email() );
425
	}
426
427
	/**
428
	 * Sends overdue notices.
429
	 *
430
	 * @TODO: Create an invoices query class.
431
	 */
432
	public function overdue() {
433
		global $wpdb;
434
435
		$email = new GetPaid_Notification_Email( __FUNCTION__ );
436
437
		// Fetch reminder days.
438
		$reminder_days = array_unique( wp_parse_id_list( $email->get_option( 'days' ) ) );
439
440
		// Abort if non is set.
441
		if ( empty( $reminder_days ) ) {
442
			return;
443
		}
444
445
		// Retrieve date query.
446
		$date_query = $this->get_date_query( $reminder_days );
447
448
		// Invoices table.
449
		$table = $wpdb->prefix . 'getpaid_invoices';
450
451
		// Fetch invoices.
452
		$invoices  = $wpdb->get_col(
453
			"SELECT posts.ID FROM $wpdb->posts as posts
454
			LEFT JOIN $table as invoices ON invoices.post_id = posts.ID
455
			WHERE posts.post_type = 'wpi_invoice' AND posts.post_status = 'wpi-pending' $date_query");
456
457
		foreach ( $invoices as $invoice ) {
458
459
			// Only send this email for invoices created via the admin page.
460
			if ( ! $this->is_payment_form_invoice( $invoice ) ) {
461
				$invoice       = new WPInv_Invoice( $invoice );
462
				$email->object = $invoice;
463
464
				if ( $invoice->needs_payment() ) {
465
					$this->send_email( $invoice, $email, __FUNCTION__, $invoice->get_email() );
466
				}
467
468
			}
469
470
		}
471
472
	}
473
474
	/**
475
	 * Calculates the date query for an invoices query
476
	 *
477
	 * @param array $reminder_days
478
	 * @return string
479
	 */
480
	public function get_date_query( $reminder_days ) {
481
482
		$date_query = array(
483
			'relation'  => 'OR'
484
		);
485
486
		foreach ( $reminder_days as $days ) {
487
			$date = date_parse( date( 'Y-m-d', strtotime( "-$days days", current_time( 'timestamp' ) ) ) );
488
489
			$date_query[] = array(
490
				'year'  => $date['year'],
491
				'month' => $date['month'],
492
				'day'   => $date['day'],
493
			);
494
495
		}
496
497
		$date_query = new WP_Date_Query( $date_query, 'invoices.due_date' );
498
499
		return $date_query->get_sql();
500
501
	}
502
503
}
504