Passed
Pull Request — master (#375)
by Brian
104:55
created

GetPaid_Payment_Form_Submission::load_data()   F

Complexity

Conditions 18
Paths 219

Size

Total Lines 107
Code Lines 44

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 44
c 1
b 0
f 1
dl 0
loc 107
rs 3.7958
cc 18
nc 219
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
if ( ! defined( 'ABSPATH' ) ) {
3
	exit;
4
}
5
6
/**
7
 * Payment form submission class
8
 *
9
 */
10
class GetPaid_Payment_Form_Submission {
11
12
    /**
13
	 * Submission ID
14
	 *
15
	 * @var string
16
	 */
17
	public $id = null;
18
19
	/**
20
	 * Sets the associated payment form.
21
	 *
22
	 * @var GetPaid_Payment_Form
23
	 */
24
    protected $payment_form = null;
25
26
    /**
27
	 * The country for the submission.
28
	 *
29
	 * @var string
30
	 */
31
	public $country = null;
32
33
    /**
34
	 * The state for the submission.
35
	 *
36
	 * @since 1.0.19
37
	 * @var string
38
	 */
39
	public $state = null;
40
41
	/**
42
	 * The invoice associated with the submission.
43
	 *
44
	 * @var WPInv_Invoice
45
	 */
46
	protected $invoice = null;
47
48
	/**
49
	 * The discount associated with the submission.
50
	 *
51
	 * @var WPInv_Discount
52
	 */
53
	protected $discount = null;
54
55
	/**
56
	 * The raw submission data.
57
	 *
58
	 * @var array
59
	 */
60
	protected $data = null;
61
62
	/**
63
	 * Whether this submission contains a recurring item.
64
	 *
65
	 * @var bool
66
	 */
67
	public $has_recurring = false;
68
69
	/**
70
	 * The sub total amount for the submission.
71
	 *
72
	 * @var float
73
	 */
74
	public $subtotal_amount = 0;
75
76
	/**
77
	 * The total discount amount for the submission.
78
	 *
79
	 * @var float
80
	 */
81
	protected $total_discount_amount = 0;
82
83
	/**
84
	 * The total tax amount for the submission.
85
	 *
86
	 * @var float
87
	 */
88
	protected $total_tax_amount = 0;
89
90
	/**
91
	 * The total fees amount for the submission.
92
	 *
93
	 * @var float
94
	 */
95
	protected $total_fees_amount = 0;
96
97
	/**
98
	 * An array of fees for the submission.
99
	 *
100
	 * @var array
101
	 */
102
	protected $fees = array();
103
104
	/**
105
	 * An array of discounts for the submission.
106
	 *
107
	 * @var array
108
	 */
109
	protected $discounts = array();
110
111
	/**
112
	 * An array of taxes for the submission.
113
	 *
114
	 * @var array
115
	 */
116
	protected $taxes = array();
117
118
	/**
119
	 * An array of items for the submission.
120
	 *
121
	 * @var GetPaid_Form_Item[]
122
	 */
123
	protected $items = array();
124
125
	/**
126
	 * The last error.
127
	 *
128
	 * @var string
129
	 */
130
	public $last_error = null;
131
132
	/**
133
	 * Is the discount valid?
134
	 *
135
	 * @var string
136
	 */
137
    public $is_discount_valid = true;
138
139
    /**
140
	 * Class constructor.
141
	 *
142
	 */
143
	public function __construct() {
144
145
		// Set the state and country to the default state and country.
146
		$this->country = wpinv_default_billing_country();
147
		$this->state = wpinv_get_default_state();
0 ignored issues
show
Documentation Bug introduced by
It seems like wpinv_get_default_state() can also be of type false. However, the property $state is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
148
149
		// Do we have an actual submission?
150
		if ( isset( $_POST['getpaid_payment_form_submission'] ) ) {
151
			$this->load_data( $_POST );
152
		}
153
	}
154
155
	/**
156
	 * Loads submission data.
157
	 *
158
	 * @param array $data
159
	 */
160
	public function load_data( $data ) {
161
162
		// Prepare submitted data...
163
		$data = wp_unslash( $data );
164
165
		// Fitter the data.
166
		$data = apply_filters( 'getpaid_submission_data', $data, $this );
167
168
		$this->data = $data;
0 ignored issues
show
Documentation Bug introduced by
It seems like $data can also be of type string. However, the property $data is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
169
170
		$this->id = md5( wp_json_encode( $data ) );
0 ignored issues
show
Bug introduced by
It seems like wp_json_encode($data) can also be of type false; however, parameter $str of md5() does only seem to accept 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

170
		$this->id = md5( /** @scrutinizer ignore-type */ wp_json_encode( $data ) );
Loading history...
171
172
		// Every submission needs an active payment form.
173
		if ( empty( $data['form_id'] ) ) {
174
			$this->last_error = __( 'Missing payment form', 'invoicing' );
175
            return;
176
		}
177
178
		// Fetch the payment form.
179
		$form = new GetPaid_Payment_Form( $data['form_id'] );
180
181
		if ( ! $form->is_active() ) {
182
			$this->last_error = __( 'Payment form not active', 'invoicing' );
183
			return;
184
		}
185
186
		// Fetch the payment form.
187
		$this->payment_form = $form;
188
189
		// For existing invoices, make sure that it is valid.
190
        if ( ! empty( $data['invoice_id'] ) ) {
191
            $invoice = wpinv_get_invoice( $data['invoice_id'] );
192
193
            if ( empty( $invoice ) ) {
194
				$this->last_error = __( 'Invalid invoice', 'invoicing' );
195
                return;
196
            }
197
198
			$this->payment_form->set_items( $invoice->cart_details );
199
200
			$this->country = $invoice->country;
201
			$this->state = $invoice->state;
202
203
		// Default forms do not have items.
204
        } else if ( $form->is_default() && isset( $data['form_items'] ) ) {
205
			$this->payment_form->set_items( $data['form_items'] );
206
		}
207
208
		// User's country.
209
		if ( ! empty( $data['wpinv_country'] ) ) {
210
			$this->country = $data['wpinv_country'];
211
		}
212
213
		// User's state.
214
		if ( ! empty( $data['wpinv_state'] ) ) {
215
			$this->country = $data['wpinv_state'];
216
		}
217
218
		// Handle discounts.
219
		$this->maybe_prepare_discount();
220
221
		// Handle items.
222
		$selected_items = array();
223
		if ( ! empty( $data['getpaid-items'] ) ) {
224
			$selected_items = wpinv_clean( $data['getpaid-items'] );
225
		}
226
227
		foreach ( $this->payment_form->get_items() as $item ) {
228
229
			// Continue if this is an optional item and it has not been selected.
230
			if ( ! $item->is_required() && ! isset( $selected_items[ $item->get_id() ] ) ) {
231
				continue;
232
			}
233
234
			// (maybe) let customers change the quantities and prices.
235
			if ( isset( $selected_items[ $item->get_id() ] ) ) {
236
237
				// Maybe change the quantities.
238
				if ( $item->allows_quantities() && is_numeric( $selected_items[ $item->get_id() ]['quantity'] ) ) {
239
					$item->set_quantity( (int) $selected_items[ $item->get_id() ]['quantity'] );
240
				}
241
242
				// Maybe change the price.
243
				if ( $item->user_can_set_their_price() ) {
244
					$price = (float) wpinv_sanitize_amount( $selected_items[ $item->get_id() ]['price'] );
245
246
					// But don't get lower than the minimum price.
247
					if ( $price < $item->get_minimum_price() ) {
248
						$price = $item->get_minimum_price();
249
					}
250
251
					$item->set_price( $price );
252
253
				}
254
255
			}
256
257
			// Add the item to the form.
258
			$this->add_item( $item );
259
260
		}
261
262
		// Fired when we are done processing a submission.
263
		do_action( 'getpaid_process_submission', $this );
264
265
		// Remove invalid discount.
266
		$this->maybe_remove_discount();
267
268
	}
269
270
    /**
271
	 * Returns the payment form.
272
	 *
273
	 * @since 1.0.19
274
	 * @return GetPaid_Payment_Form
275
	 */
276
	public function get_payment_form() {
277
		return $this->payment_form;
278
	}
279
280
	/**
281
	 * Returns the associated invoice.
282
	 *
283
	 * @since 1.0.19
284
	 * @return WPInv_Invoice
285
	 */
286
	public function get_invoice() {
287
		return $this->invoice;
288
	}
289
290
	/**
291
	 * Checks whether there is an invoice associated with this submission.
292
	 *
293
	 * @since 1.0.19
294
	 * @return bool
295
	 */
296
	public function has_invoice() {
297
		return ! empty( $this->invoice );
298
	}
299
	
300
	/**
301
	 * Returns the appropriate currency for the submission.
302
	 *
303
	 * @since 1.0.19
304
	 * @return string
305
	 */
306
	public function get_currency() {
307
		if ( $this->has_invoice() ) {
308
			return $this->invoice->get_currency();
309
		}
310
		return wpinv_get_currency();
311
    }
312
313
    /**
314
	 * Returns the raw submission data.
315
	 *
316
	 * @since 1.0.19
317
	 * @return array
318
	 */
319
	public function get_data() {
320
		return $this->data;
321
	}
322
323
	/**
324
	 * Checks if a required field is set.
325
	 *
326
	 * @since 1.0.19
327
	 */
328
	public function is_required_field_set( $field ) {
329
		return empty( $field['required'] ) || ! empty( $this->data[ $field['id'] ] );
330
	}
331
332
	///////// Items //////////////
333
334
	/**
335
	 * Adds an item to the submission.
336
	 *
337
	 * @since 1.0.19
338
	 * @param GetPaid_Form_Item $item
339
	 */
340
	public function add_item( $item ) {
341
342
		// Make sure that it is available for purchase.
343
		if ( ! $item->can_purchase() ) {
344
			return;
345
		}
346
347
		// Do we have a recurring item?
348
		if ( $item->is_recurring() ) {
349
			$this->has_recurring = true;
350
		}
351
352
		$this->items[ $item->get_id() ] = $item;
353
354
		$this->subtotal_amount += $item->get_price() * $item->get_qantity();
0 ignored issues
show
Deprecated Code introduced by
The function GetPaid_Form_Item::get_qantity() has been deprecated. ( Ignorable by Annotation )

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

354
		$this->subtotal_amount += $item->get_price() * /** @scrutinizer ignore-deprecated */ $item->get_qantity();
Loading history...
355
356
		$this->process_item_discount( $item );
357
358
		$this->process_item_tax( $item );
359
	}
360
361
	/**
362
	 * Retrieves a specific item.
363
	 *
364
	 * @since 1.0.19
365
	 */
366
	public function get_item( $item_id ) {
367
		return isset( $this->items[ $item_id ] ) ? $this->items[ $item_id ] : null;
368
	}
369
370
	/**
371
	 * Returns all items.
372
	 *
373
	 * @since 1.0.19
374
	 * @return GetPaid_Form_Item[]
375
	 */
376
	public function get_items() {
377
		return $this->items;
378
	}
379
380
	///////// TAXES //////////////
381
382
	/**
383
	 * Adds a tax to the submission.
384
	 *
385
	 * @since 1.0.19
386
	 */
387
	public function add_tax( $name, $amount ) {
388
		$amount = (float) wpinv_sanitize_amount( $amount );
389
390
		$this->total_tax_amount += $amount;
391
392
		if ( isset( $this->taxes[ $name ] ) ) {
393
			$this->taxes[ $name ] += $amount;
394
		} else {
395
			$this->taxes[ $name ] = $amount;
396
		}
397
398
	}
399
400
	/**
401
	 * Whether or not we'll use taxes for the submission.
402
	 *
403
	 * @since 1.0.19
404
	 */
405
	public function use_taxes() {
406
407
		$use_taxes = wpinv_use_taxes();
408
409
		if ( $this->has_invoice() && $this->invoice->disable_taxes ) {
410
			$use_taxes = false;
411
		}
412
413
		return apply_filters( 'getpaid_submission_use_taxes', $use_taxes, $this );
414
415
	}
416
417
	/**
418
	 * Maybe process tax.
419
	 *
420
	 * @since 1.0.19 
421
	 * @param GetPaid_Form_Item $item
422
	 */
423
	public function process_item_tax( $item ) {
424
425
		// Abort early if we're not using taxes.
426
		if ( ! $this->use_taxes() ) {
427
			return;
428
		}
429
430
		$rate  = wpinv_get_tax_rate( $this->country, $this->state, $item->get_id() );
431
		$price = $item->get_sub_total();
432
433
		if ( wpinv_prices_include_tax() ) {
434
			$item_tax = $price - ( $price - $price * $rate * 0.01 );
435
		} else {
436
			$item_tax = $price * $rate * 0.01;
437
		}
438
439
		$this->add_tax( 'Tax', $item_tax );
440
441
	}
442
443
	/**
444
	 * Returns the total tax amount.
445
	 *
446
	 * @since 1.0.19
447
	 */
448
	public function get_total_tax() {
449
		return $this->total_tax_amount;
450
	}
451
452
	/**
453
	 * Retrieves a specific tax.
454
	 *
455
	 * @since 1.0.19
456
	 */
457
	public function get_tax( $name ) {
458
		return isset( $this->taxes[ $name ] ) ? $this->taxes[ $name ] : 0;
459
	}
460
461
	/**
462
	 * Returns all taxes.
463
	 *
464
	 * @since 1.0.19
465
	 */
466
	public function get_taxes() {
467
		return $this->taxes;
468
	}
469
470
	///////// DISCOUNTS //////////////
471
472
	/**
473
	 * Adds a discount to the submission.
474
	 *
475
	 * @since 1.0.19
476
	 */
477
	public function add_discount( $name, $amount ) {
478
		$amount = wpinv_sanitize_amount( $amount );
479
480
		$this->total_discount_amount += $amount;
481
482
		if ( isset( $this->discounts[ $name ] ) ) {
483
			$this->discounts[ $name ] += $amount;
484
		} else {
485
			$this->discounts[ $name ] = $amount;
486
		}
487
488
	}
489
490
	/**
491
	 * Removes a discount from the submission.
492
	 *
493
	 * @since 1.0.19
494
	 */
495
	public function remove_discount( $name ) {
496
497
		if ( isset( $this->discounts[ $name ] ) ) {
498
			$this->total_discount_amount -= $this->discounts[ $name ];
499
			unset( $this->discounts[ $name ] );
500
		}
501
502
	}
503
504
	/**
505
	 * Checks whether there is a discount code associated with this submission.
506
	 *
507
	 * @since 1.0.19
508
	 * @return bool
509
	 */
510
	public function has_discount_code() {
511
		return ! empty( $this->discount );
512
	}
513
514
	/**
515
	 * Returns the discount code.
516
	 *
517
	 * @since 1.0.19
518
	 * @return bool
519
	 */
520
	public function get_discount_code() {
521
		return $this->has_discount_code() ? $this->discount->code : '';
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->has_discou...is->discount->code : '' returns the type string which is incompatible with the documented return type boolean.
Loading history...
522
	}
523
524
	/**
525
	 * Prepares an item discount.
526
	 *
527
	 * @since 1.0.19
528
	 */
529
	public function maybe_prepare_discount() {
530
531
		// Do we have a discount?
532
		if ( empty( $this->data['discount'] ) ) {
533
			return;
534
		}
535
536
		// Fetch the discount.
537
		$discount = wpinv_get_discount_obj( $this->data['discount'] );
538
539
		// Ensure it is active.
540
        if ( ! $discount->exists() || ! $discount->is_active() || ! $discount->has_started() || $discount->is_expired() ) {
541
			$this->is_discount_valid = false;
0 ignored issues
show
Documentation Bug introduced by
The property $is_discount_valid was declared of type string, but false is of type false. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
542
			$this->last_error = __( 'Invalid or expired discount code', 'invoicing' );
543
			return;
544
		}
545
546
		// For single use discounts...
547
		if ( $discount->is_single_use ) {
548
549
			if ( ! $this->has_billing_email() ) {
550
				$this->is_discount_valid = false;
551
				$this->last_error = __( 'You need to enter your billing email before applying this discount', 'invoicing' );
552
				return;
553
			}
554
555
			if ( ! $discount->is_valid_for_user( $this->get_billing_email() ) ) {
556
				$this->is_discount_valid = false;
557
				$this->last_error = __( 'You have already used this discount', 'invoicing' );
558
				return;
559
			}
560
		}
561
562
		// Set the discount.
563
		$this->discount = $discount;
564
565
	}
566
567
	/**
568
	 * Removes an invalid discount code.
569
	 *
570
	 * @since 1.0.19
571
	 */
572
	public function maybe_remove_discount() {
573
574
		// Do we have a discount?
575
		if ( empty( $this->has_discount_code() ) ) {
576
			return;
577
		}
578
579
		// Fetch the discount amount.
580
		$amount = $this->get_discount( 'Discount' );
581
582
		// Abort early if this is a "zero" discount.
583
		if ( empty( $amount ) ) {
584
			return;
585
		}
586
587
		$total = $this->subtotal_amount + $this->get_total_fees() + $this->get_total_tax();
588
589
		if ( ! $this->discount->is_minimum_amount_met( $total ) ) {
590
			$this->is_discount_valid = false;
0 ignored issues
show
Documentation Bug introduced by
The property $is_discount_valid was declared of type string, but false is of type false. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
591
            $min = wpinv_price( wpinv_format_amount( $$this->discount->min_total ) );
592
			$this->last_error = sprintf( __( 'The minimum total for using this discount is %s', 'invoicing' ), $min );
593
        }
594
595
        if ( ! $$this->discount->is_maximum_amount_met( $total ) ) {
596
			$this->is_discount_valid = false;
597
            $max = wpinv_price( wpinv_format_amount( $$this->discount->max_total ) );
598
			$this->last_error = sprintf( __( 'The maximum total for using this discount is %s', 'invoicing' ), $max );
599
		}
600
601
		if ( ! $this->is_discount_valid ) {
602
			$this->discount = null;
603
			$this->remove_discount( 'Discount' );
604
		}
605
606
    }
607
608
	/**
609
	 * Maybe process discount.
610
	 *
611
	 * @since 1.0.19
612
	 * @param GetPaid_Form_Item $item
613
	 */
614
	public function process_item_discount( $item ) {
615
616
		// Abort early if there is no discount.
617
		if ( ! $this->has_discount_code() ) {
618
			return;
619
		}
620
621
		// Ensure that it is valid for this item.
622
		if ( ! $this->discount->is_valid_for_items( array( $item->get_id() ) ) ) {
623
			return;
624
		}
625
626
		// Fetch the discounted amount.
627
		$discount = $this->discount->get_discounted_amount( $item->get_price() * $item->get_qantity() );
0 ignored issues
show
Deprecated Code introduced by
The function GetPaid_Form_Item::get_qantity() has been deprecated. ( Ignorable by Annotation )

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

627
		$discount = $this->discount->get_discounted_amount( $item->get_price() * /** @scrutinizer ignore-deprecated */ $item->get_qantity() );
Loading history...
628
629
		$this->add_discount( 'Discount', $discount );
630
631
	}
632
633
	/**
634
	 * Returns the total discount amount.
635
	 *
636
	 * @since 1.0.19
637
	 */
638
	public function get_total_discount() {
639
		return $this->total_discount_amount;
640
	}
641
642
	/**
643
	 * Gets a specific discount.
644
	 *
645
	 * @since 1.0.19
646
	 */
647
	public function get_discount( $name ) {
648
		return isset( $this->discounts[ $name ] ) ? $this->discounts[ $name ] : 0;
649
	}
650
651
	/**
652
	 * Returns all discounts.
653
	 *
654
	 * @since 1.0.19
655
	 */
656
	public function get_discounts() {
657
		return $this->discounts;
658
	}
659
660
	///////// FEES //////////////
661
662
	/**
663
	 * Adds a fee to the submission.
664
	 *
665
	 * @since 1.0.19
666
	 */
667
	public function add_fee( $name, $amount ) {
668
		$amount = wpinv_sanitize_amount( $amount );
669
670
		$this->total_fees_amount += $amount;
671
672
		if ( isset( $this->fees[ $name ] ) ) {
673
			$this->fees[ $name ] += $amount;
674
		} else {
675
			$this->fees[ $name ] = $amount;
676
		}
677
678
	}
679
680
	/**
681
	 * Returns the total fees amount.
682
	 *
683
	 * @since 1.0.19
684
	 */
685
	public function get_total_fees() {
686
		return $this->total_fees_amount;
687
	}
688
689
	/**
690
	 * Retrieves a specific fee.
691
	 *
692
	 * @since 1.0.19
693
	 */
694
	public function get_fee( $name ) {
695
		return isset( $this->fees[ $name ] ) ? $this->fees[ $name ] : 0;
696
	}
697
698
	/**
699
	 * Returns all fees.
700
	 *
701
	 * @since 1.0.19
702
	 */
703
	public function get_fees() {
704
		return $this->fees;
705
	}
706
707
	// MISC //
708
709
	/**
710
	 * Returns the total amount to collect for this submission.
711
	 *
712
	 * @since 1.0.19
713
	 */
714
	public function get_total() {
715
		$total = $this->subtotal_amount + $this->get_total_fees() - $this->get_total_discount() + $this->get_total_tax();
716
		$total = apply_filters( 'getpaid_get_submission_total_amount', $total, $this  );
717
		return wpinv_sanitize_amount( $total );
718
	}
719
720
	/**
721
	 * Whether payment details should be collected for this submission.
722
	 *
723
	 * @since 1.0.19
724
	 */
725
	public function get_payment_details() {
726
		$collect = $this->subtotal_amount + $this->get_total_fees() - $this->get_total_discount() + $this->get_total_tax();
727
728
		if ( $this->has_recurring ) {
729
			$collect = true;
730
		}
731
732
		$collect = apply_filters( 'getpaid_submission_collect_payment_details', $collect, $this  );
733
		return $collect;
734
	}
735
736
	/**
737
	 * Returns the billing email of the user.
738
	 *
739
	 * @since 1.0.19
740
	 */
741
	public function get_billing_email() {
742
		$billing_email = empty( $this->data['billing_email'] ) ? '' : $this->data['billing_email'];
743
		return apply_filters( 'getpaid_get_submission_billing_email', $billing_email, $this  );
744
	}
745
746
	/**
747
	 * Checks if the submitter has a billing email.
748
	 *
749
	 * @since 1.0.19
750
	 */
751
	public function has_billing_email() {
752
		$billing_email = $this->get_billing_email();
753
		return ! empty( $billing_email );
754
	}
755
756
}
757