Passed
Push — master ( b3b246...bcec86 )
by Brian
05:30
created

GetPaid_Payment_Form_Submission::get_company()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
c 0
b 0
f 0
dl 0
loc 9
rs 10
cc 3
nc 3
nop 0
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 raw submission data.
50
	 *
51
	 * @var array
52
	 */
53
	protected $data = null;
54
55
	/**
56
	 * Whether this submission contains a recurring item.
57
	 *
58
	 * @var bool
59
	 */
60
	public $has_recurring = false;
61
62
	/**
63
	 * The sub total amount for the submission.
64
	 *
65
	 * @var float
66
	 */
67
	public $subtotal_amount = 0;
68
69
	/**
70
	 * The total discount amount for the submission.
71
	 *
72
	 * @var float
73
	 */
74
	protected $total_discount_amount = 0;
75
76
	/**
77
	 * The total recurring discount amount for the submission.
78
	 *
79
	 * @var float
80
	 */
81
	protected $total_recurring_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 recurring tax amount for the submission.
92
	 *
93
	 * @var float
94
	 */
95
	protected $total_recurring_tax_amount = 0;
96
97
	/**
98
	 * An array of fees for the submission.
99
	 *
100
	 * @var array
101
	 */
102
	protected $fees = array();
103
104
	/**
105
	 * The total fees amount for the submission.
106
	 *
107
	 * @var float
108
	 */
109
	protected $total_fees_amount = 0;
110
111
	/**
112
	 * The total fees amount for the submission.
113
	 *
114
	 * @var float
115
	 */
116
	protected $total_recurring_fees_amount = 0;
117
118
	/**
119
	 * An array of discounts for the submission.
120
	 *
121
	 * @var array
122
	 */
123
	protected $discounts = array();
124
125
	/**
126
	 * An array of taxes for the submission.
127
	 *
128
	 * @var array
129
	 */
130
	protected $taxes = array();
131
132
	/**
133
	 * An array of items for the submission.
134
	 *
135
	 * @var GetPaid_Form_Item[]
136
	 */
137
	protected $items = array();
138
139
	/**
140
	 * The last error.
141
	 *
142
	 * @var string
143
	 */
144
	public $last_error = null;
145
146
	/**
147
	 * Is the discount valid?
148
	 *
149
	 * @var bool
150
	 */
151
	public $is_discount_valid = true;
152
153
    /**
154
	 * Class constructor.
155
	 *
156
	 */
157
	public function __construct() {
158
159
		// Set the state and country to the default state and country.
160
		$this->country = wpinv_default_billing_country();
161
		$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...
162
163
		// Do we have an actual submission?
164
		if ( isset( $_POST['getpaid_payment_form_submission'] ) ) {
165
			$this->load_data( $_POST );
166
		}
167
168
	}
169
170
	/**
171
	 * Loads submission data.
172
	 *
173
	 * @param array $data
174
	 */
175
	public function load_data( $data ) {
176
177
		// Prepare submitted data...
178
		$data = wp_unslash( $data );
179
180
		// Filter the data.
181
		$data = apply_filters( 'getpaid_submission_data', $data, $this );
182
183
		$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...
184
185
		$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

185
		$this->id = md5( /** @scrutinizer ignore-type */ wp_json_encode( $data ) );
Loading history...
186
187
		// Every submission needs an active payment form.
188
		if ( empty( $data['form_id'] ) ) {
189
			$this->last_error = __( 'Missing payment form', 'invoicing' );
190
            return;
191
		}
192
193
		// Fetch the payment form.
194
		$form = new GetPaid_Payment_Form( $data['form_id'] );
195
196
		if ( ! $form->is_active() ) {
197
			$this->last_error = __( 'Payment form not active', 'invoicing' );
198
			return;
199
		}
200
201
		// Fetch the payment form.
202
		$this->payment_form = $form;
203
204
		// For existing invoices, make sure that it is valid.
205
        if ( ! empty( $data['invoice_id'] ) ) {
206
            $invoice = wpinv_get_invoice( $data['invoice_id'] );
207
208
            if ( empty( $invoice ) ) {
209
				$this->last_error = __( 'Invalid invoice', 'invoicing' );
210
                return;
211
			}
212
213
			if ( $invoice->is_paid() ) {
214
				$this->last_error = __( 'This invoice is already paid for.', 'invoicing' );
215
                return;
216
			}
217
218
			$this->payment_form->set_items( $invoice->get_items() );
219
220
			$this->country = $invoice->get_country();
221
			$this->state   = $invoice->get_state();
222
			$this->invoice = $invoice;
223
224
		// Default forms do not have items.
225
        } else if ( $form->is_default() && isset( $data['getpaid-items'] ) ) {
226
			$this->payment_form->set_items( wpinv_clean( $data['getpaid-items'] ) );
0 ignored issues
show
Bug introduced by
It seems like wpinv_clean($data['getpaid-items']) can also be of type string; however, parameter $value of GetPaid_Payment_Form::set_items() does only seem to accept array, 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

226
			$this->payment_form->set_items( /** @scrutinizer ignore-type */ wpinv_clean( $data['getpaid-items'] ) );
Loading history...
227
		}
228
229
		// User's country.
230
		if ( ! empty( $data['wpinv_country'] ) ) {
231
			$this->country = $data['wpinv_country'];
232
		}
233
234
		// User's state.
235
		if ( ! empty( $data['wpinv_state'] ) ) {
236
			$this->country = $data['wpinv_state'];
237
		}
238
239
		// Handle items.
240
		$selected_items = array();
241
		if ( ! empty( $data['getpaid-items'] ) ) {
242
			$selected_items = wpinv_clean( $data['getpaid-items'] );
243
		}
244
245
		foreach ( $this->payment_form->get_items() as $item ) {
246
247
			// Continue if this is an optional item and it has not been selected.
248
			if ( ! $item->is_required() && ! isset( $selected_items[ $item->get_id() ] ) ) {
249
				continue;
250
			}
251
252
			// (maybe) let customers change the quantities and prices.
253
			if ( isset( $selected_items[ $item->get_id() ] ) ) {
254
255
				// Maybe change the quantities.
256
				if ( $item->allows_quantities() && is_numeric( $selected_items[ $item->get_id() ]['quantity'] ) ) {
257
					$item->set_quantity( (int) $selected_items[ $item->get_id() ]['quantity'] );
258
				}
259
260
				// Maybe change the price.
261
				if ( $item->user_can_set_their_price() ) {
262
					$price = (float) wpinv_sanitize_amount( $selected_items[ $item->get_id() ]['price'] );
263
264
					// But don't get lower than the minimum price.
265
					if ( $price < $item->get_minimum_price() ) {
266
						$price = $item->get_minimum_price();
267
					}
268
269
					$item->set_price( $price );
270
271
				}
272
273
			}
274
275
			// Add the item to the form.
276
			$this->add_item( $item );
277
278
		}
279
280
		// Fired when we are done processing a submission.
281
		do_action_ref_array( 'getpaid_process_submission', array( &$this ) );
282
283
		// Handle discounts.
284
		$this->process_discount();
285
286
	}
287
288
    /**
289
	 * Returns the payment form.
290
	 *
291
	 * @since 1.0.19
292
	 * @return GetPaid_Payment_Form
293
	 */
294
	public function get_payment_form() {
295
		return $this->payment_form;
296
	}
297
298
	/**
299
	 * Returns the associated invoice.
300
	 *
301
	 * @since 1.0.19
302
	 * @return WPInv_Invoice
303
	 */
304
	public function get_invoice() {
305
		return $this->invoice;
306
	}
307
308
	/**
309
	 * Checks whether there is an invoice associated with this submission.
310
	 *
311
	 * @since 1.0.19
312
	 * @return bool
313
	 */
314
	public function has_invoice() {
315
		return ! empty( $this->invoice );
316
	}
317
318
	/**
319
	 * Returns the appropriate currency for the submission.
320
	 *
321
	 * @since 1.0.19
322
	 * @return string
323
	 */
324
	public function get_currency() {
325
		if ( $this->has_invoice() ) {
326
			return $this->invoice->get_currency();
327
		}
328
		return wpinv_get_currency();
329
    }
330
331
    /**
332
	 * Returns the raw submission data.
333
	 *
334
	 * @since 1.0.19
335
	 * @return array
336
	 */
337
	public function get_data() {
338
		return $this->data;
339
	}
340
341
	/**
342
	 * Checks if a required field is set.
343
	 *
344
	 * @since 1.0.19
345
	 */
346
	public function is_required_field_set( $field ) {
347
		return empty( $field['required'] ) || ! empty( $this->data[ $field['id'] ] );
348
	}
349
350
	///////// Items //////////////
351
352
	/**
353
	 * Adds an item to the submission.
354
	 *
355
	 * @since 1.0.19
356
	 * @param GetPaid_Form_Item $item
357
	 */
358
	public function add_item( $item ) {
359
360
		// Make sure that it is available for purchase.
361
		if ( ! $item->can_purchase() ) {
362
			return;
363
		}
364
365
		// Do we have a recurring item?
366
		if ( $item->is_recurring() ) {
367
368
			if ( $this->has_recurring ) {
369
				$this->last_error = __( 'You can only buy one recurring item at a time.', 'invoicing' );
370
			}
371
372
			$this->has_recurring = true;
373
374
		}
375
376
		$this->items[ $item->get_id() ] = $item;
377
378
		$this->subtotal_amount += $item->get_sub_total();
379
380
	}
381
382
	/**
383
	 * Retrieves a specific item.
384
	 *
385
	 * @since 1.0.19
386
	 */
387
	public function get_item( $item_id ) {
388
		return isset( $this->items[ $item_id ] ) ? $this->items[ $item_id ] : null;
389
	}
390
391
	/**
392
	 * Returns all items.
393
	 *
394
	 * @since 1.0.19
395
	 * @return GetPaid_Form_Item[]
396
	 */
397
	public function get_items() {
398
		return $this->items;
399
	}
400
401
	/*
402
	|--------------------------------------------------------------------------
403
	| Taxes
404
	|--------------------------------------------------------------------------
405
	|
406
	| Functions for dealing with submission taxes. Taxes can be recurring
407
	| or only one-time.
408
    */
409
410
	/**
411
	 * Prepares the submission's taxes.
412
	 *
413
	 * @since 1.0.19
414
	 */
415
	public function process_taxes() {
416
417
		$tax_processor = new GetPaid_Payment_Form_Submission_Taxes( $this );
418
419
		if ( ! empty( $tax_processor->tax_error) ) {
420
			$this->last_error = $tax_processor->tax_error;
421
			return;
422
		}
423
424
		foreach ( $tax_processor->taxes as $tax ) {
425
			$this->add_tax( $tax );
426
		}
427
428
		do_action_ref_array( 'getpaid_submissions_process_taxes', array( &$this ) );
429
	}
430
431
	/**
432
	 * Adds a tax to the submission.
433
	 *
434
	 * @param array $tax An array of tax details. name, initial_tax, and recurring_tax are required.
435
	 * @since 1.0.19
436
	 */
437
	public function add_tax( $tax ) {
438
439
		$this->total_tax_amount           += wpinv_sanitize_amount( $tax['initial_tax'] );
440
		$this->total_recurring_tax_amount += wpinv_sanitize_amount( $tax['recurring_tax'] );
441
		$this->taxes[ $tax['name'] ]       = $tax;
442
443
	}
444
445
	/**
446
	 * Whether or not we'll use taxes for the submission.
447
	 *
448
	 * @since 1.0.19
449
	 */
450
	public function use_taxes() {
451
452
		$use_taxes = wpinv_use_taxes();
453
454
		if ( $this->has_invoice() && ! $this->invoice->is_taxable() ) {
455
			$use_taxes = false;
456
		}
457
458
		return apply_filters( 'getpaid_submission_use_taxes', $use_taxes, $this );
459
460
	}
461
462
	/**
463
	 * Returns the total tax amount.
464
	 *
465
	 * @since 1.0.19
466
	 */
467
	public function get_total_tax() {
468
		return $this->total_tax_amount;
469
	}
470
471
	/**
472
	 * Returns the total recurring tax amount.
473
	 *
474
	 * @since 1.0.19
475
	 */
476
	public function get_total_recurring_tax() {
477
		return $this->total_recurring_tax_amount;
478
	}
479
480
	/**
481
	 * Returns all taxes.
482
	 *
483
	 * @since 1.0.19
484
	 */
485
	public function get_taxes() {
486
		return $this->taxes;
487
	}
488
489
	/*
490
	|--------------------------------------------------------------------------
491
	| Discounts
492
	|--------------------------------------------------------------------------
493
	|
494
	| Functions for dealing with submission discounts. Discounts can be recurring
495
	| or only one-time. They also do not have to come from a discount code.
496
    */
497
498
	/**
499
	 * Prepares the submission's discount.
500
	 *
501
	 * @since 1.0.19
502
	 */
503
	public function process_discount() {
504
505
		$total            = $this->subtotal_amount + $this->get_total_fees() + $this->get_total_tax();
506
		$discount_handler = new GetPaid_Payment_Form_Submission_Discount( $this, $total );
507
508
		if ( ! $discount_handler->is_discount_valid ) {
509
			$this->last_error = $discount_handler->discount_error;
510
			return;
511
		}
512
513
		// Process any existing invoice discounts.
514
		if ( $this->has_invoice() ) {
515
			$discounts = $this->get_invoice()->get_discounts();
516
517
			foreach ( $discounts as $discount ) {
518
				$this->add_discount( $discount );
519
			}
520
521
		}
522
523
		if ( $discount_handler->has_discount ) {
524
			$this->add_discount( $discount_handler->calculate_discount( $this ) );
525
		}
526
527
		do_action_ref_array( 'getpaid_submissions_process_discounts', array( &$this ) );
528
	}
529
530
	/**
531
	 * Adds a discount to the submission.
532
	 *
533
	 * @param array $discount An array of discount details. name, initial_discount, and recurring_discount are required. Include discount_code if the discount is from a discount code.
534
	 * @since 1.0.19
535
	 */
536
	public function add_discount( $discount ) {
537
538
		$this->total_discount_amount           += wpinv_sanitize_amount( $discount['initial_discount'] );
539
		$this->total_recurring_discount_amount += wpinv_sanitize_amount( $discount['recurring_discount'] );
540
		$this->discounts[ $discount['name'] ]   = $discount;
541
542
	}
543
544
	/**
545
	 * Removes a discount from the submission.
546
	 *
547
	 * @since 1.0.19
548
	 */
549
	public function remove_discount( $name ) {
550
551
		if ( isset( $this->discounts[ $name ] ) ) {
552
			$discount                               = $this->discounts[ $name ];
553
			$this->total_discount_amount           -= $discount['initial_discount'];
554
			$this->total_recurring_discount_amount -= $discount['recurring_discount'];
555
			unset( $this->discounts[ $name ] );
556
		}
557
558
	}
559
560
	/**
561
	 * Checks whether there is a discount code associated with this submission.
562
	 *
563
	 * @since 1.0.19
564
	 * @return bool
565
	 */
566
	public function has_discount_code() {
567
		return ! empty( $this->discounts['discount_code'] );
568
	}
569
570
	/**
571
	 * Returns the discount code.
572
	 *
573
	 * @since 1.0.19
574
	 * @return string
575
	 */
576
	public function get_discount_code() {
577
		return $this->has_discount_code() ? $this->discounts['discount_code']['discount_code'] : '';
578
	}
579
580
	/**
581
	 * Returns the total discount amount.
582
	 *
583
	 * @since 1.0.19
584
	 */
585
	public function get_total_discount() {
586
		return $this->total_discount_amount;
587
	}
588
589
	/**
590
	 * Returns the total recurring discount amount.
591
	 *
592
	 * @since 1.0.19
593
	 */
594
	public function get_total_recurring_discount() {
595
		return $this->total_recurring_discount_amount;
596
	}
597
598
	/**
599
	 * Returns all discounts.
600
	 *
601
	 * @since 1.0.19
602
	 */
603
	public function get_discounts() {
604
		return $this->discounts;
605
	}
606
607
	/*
608
	|--------------------------------------------------------------------------
609
	| Fees
610
	|--------------------------------------------------------------------------
611
	|
612
	| Functions for dealing with submission fees. Fees can be recurring
613
	| or only one-time. Price input and Price select elements are treated as 
614
	| fees.
615
    */
616
617
	/**
618
	 * Prepares the submission's fees.
619
	 *
620
	 * @since 1.0.19
621
	 */
622
	public function process_fees() {
623
624
		$fees_processor = new GetPaid_Payment_Form_Submission_Fees( $this );
625
626
		if ( ! empty( $fees_processor->fee_error) ) {
627
			$this->last_error = $fees_processor->fee_error;
628
			return;
629
		}
630
631
		foreach ( $fees_processor->fees as $fee ) {
632
			$this->add_fee( $fee );
633
		}
634
635
		do_action_ref_array( 'getpaid_submissions_process_fees', array( &$this ) );
636
	}
637
638
	/**
639
	 * Adds a fee to the submission.
640
	 *
641
	 * @param array $fee An array of fee details. name, initial_fee, and recurring_fee are required.
642
	 * @since 1.0.19
643
	 */
644
	public function add_fee( $fee ) {
645
646
		$this->total_fees_amount           += wpinv_sanitize_amount( $fee['initial_fee'] );
647
		$this->total_recurring_fees_amount += wpinv_sanitize_amount( $fee['recurring_fee'] );
648
		$this->fees[ $fee['name'] ]         = $fee;
649
650
	}
651
652
	/**
653
	 * Removes a fee from the submission.
654
	 *
655
	 * @since 1.0.19
656
	 */
657
	public function remove_fee( $name ) {
658
659
		if ( isset( $this->fees[ $name ] ) ) {
660
			$fee                                = $this->fees[ $name ];
661
			$this->total_fees_amount           -= $fee['initial_fee'];
662
			$this->total_recurring_fees_amount -= $fee['recurring_fee'];
663
			unset( $this->fees[ $name ] );
664
		}
665
666
	}
667
668
	/**
669
	 * Returns the total fees amount.
670
	 *
671
	 * @since 1.0.19
672
	 */
673
	public function get_total_fees() {
674
		return $this->total_fees_amount;
675
	}
676
677
	/**
678
	 * Returns the total recurring fees amount.
679
	 *
680
	 * @since 1.0.19
681
	 */
682
	public function get_total_recurring_fees() {
683
		return $this->total_recurring_fees_amount;
684
	}
685
686
	/**
687
	 * Returns all fees.
688
	 *
689
	 * @since 1.0.19
690
	 */
691
	public function get_fees() {
692
		return $this->fees;
693
	}
694
695
	// MISC //
696
697
	/**
698
	 * Returns the total amount to collect for this submission.
699
	 *
700
	 * @since 1.0.19
701
	 */
702
	public function get_total() {
703
		$total = $this->subtotal_amount + $this->get_total_fees() - $this->get_total_discount() + $this->get_total_tax();
704
		$total = apply_filters( 'getpaid_get_submission_total_amount', $total, $this  );
705
		return wpinv_sanitize_amount( $total );
706
	}
707
708
	/**
709
	 * Whether payment details should be collected for this submission.
710
	 *
711
	 * @since 1.0.19
712
	 */
713
	public function get_payment_details() {
714
		$collect = $this->subtotal_amount + $this->get_total_fees() - $this->get_total_discount() + $this->get_total_tax();
715
716
		if ( $this->has_recurring ) {
717
			$collect = true;
718
		}
719
720
		$collect = apply_filters( 'getpaid_submission_collect_payment_details', $collect, $this  );
721
		return $collect;
722
	}
723
724
	/**
725
	 * Returns the billing email of the user.
726
	 *
727
	 * @since 1.0.19
728
	 */
729
	public function get_billing_email() {
730
		$billing_email = empty( $this->data['billing_email'] ) ? '' : $this->data['billing_email'];
731
		return apply_filters( 'getpaid_get_submission_billing_email', $billing_email, $this  );
732
	}
733
734
	/**
735
	 * Checks if the submitter has a billing email.
736
	 *
737
	 * @since 1.0.19
738
	 */
739
	public function has_billing_email() {
740
		$billing_email = $this->get_billing_email();
741
		return ! empty( $billing_email );
742
	}
743
744
}
745