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

GetPaid_Payment_Form_Submission_Discount   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 193
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 26
eloc 49
c 1
b 0
f 0
dl 0
loc 193
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 2
A is_discount_active() 0 2 4
A validate_single_use_discount() 0 16 4
A set_error() 0 4 2
A get_user_id_or_email() 0 7 3
A calculate_discount() 0 27 5
A validate_discount_amount() 0 12 3
A pre_process_discount() 0 20 3
1
<?php
2
/**
3
 * Processes discounts for a payment form submission.
4
 *
5
 */
6
7
defined( 'ABSPATH' ) || exit;
8
9
/**
10
 * Payment form submission discount class
11
 *
12
 */
13
class GetPaid_Payment_Form_Submission_Discount {
14
15
	/**
16
	 * Whether or not the submission has a discount.
17
	 * @var bool.
0 ignored issues
show
Documentation Bug introduced by
The doc comment bool. at position 0 could not be parsed: Unknown type name 'bool.' at position 0 in bool..
Loading history...
18
	 */
19
	public $has_discount = false;
20
21
	/**
22
	 * Whether or not the discount is valid.
23
	 * @var bool
24
	 */
25
	public $is_discount_valid = true;
26
27
	/**
28
	 * The discount validation error.
29
	 * @var string
30
	 */
31
	public $discount_error;
32
33
	/**
34
	 * The discount.
35
	 * @var WPInv_Discount
36
	 */
37
	public $discount;
38
39
    /**
40
	 * Class constructor
41
	 *
42
	 * @param GetPaid_Payment_Form_Submission $submission
43
	 * @param float                           $amount
44
	 */
45
	public function __construct( $submission, $amount ) {
46
47
		// Do we have a discount?
48
		$submission_data = $submission->get_data();
49
		if ( ! empty( $submission_data['discount'] ) ) {
50
			$this->has_discount = true;
51
			$this->pre_process_discount( $submission, $submission_data['discount'], $amount );
52
		}
53
54
	}
55
56
	/**
57
	 * Preprocesses a submission discount.
58
	 *
59
	 * @param GetPaid_Payment_Form_Submission $submission
60
	 * @param string                          $discount
61
	 * @param float                           $amount
62
	 */
63
	public function pre_process_discount( $submission, $discount, $amount ) {
64
65
		// Fetch the discount.
66
		$this->discount = new WPInv_Discount( $discount );
67
68
		// Ensure it is active.
69
        if ( ! $this->is_discount_active( $this->discount ) ) {
70
			return $this->set_error( __( 'Invalid or expired discount code', 'invoicing' ) );
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->set_error(__('Inv...nt code', 'invoicing')) targeting GetPaid_Payment_Form_Sub...n_Discount::set_error() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
71
		}
72
73
		// Exceeded limit.
74
		if ( $this->discount->has_exceeded_limit() ) {
75
			return $this->set_error( __( 'This discount code has been used up', 'invoicing' ) );
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->set_error(__('Thi...used up', 'invoicing')) targeting GetPaid_Payment_Form_Sub...n_Discount::set_error() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
76
		}
77
78
		// Validate usages.
79
		$this->validate_single_use_discount( $submission, $this->discount );
80
81
		// Validate amount.
82
		$this->validate_discount_amount( $submission, $this->discount, $amount );
83
	}
84
85
	/**
86
	 * Validates a single use discount.
87
	 *
88
	 * @param WPInv_Discount                  $discount
89
	 * @return bool
90
	 */
91
	public function is_discount_active(  $discount ) {
92
		return $discount->exists() && $discount->is_active() && $discount->has_started() && ! $discount->is_expired();
93
	}
94
95
	/**
96
	 * Sets an error without overwriting the previous error.
97
	 *
98
	 * @param string $error
99
	 */
100
	public function set_error( $error ) {
101
		if ( $this->is_discount_valid ) {
102
			$this->is_discount_valid = false;
103
			$this->discount_error    = $error;
104
		}
105
	}
106
107
	/**
108
	 * Returns a user's id or email.
109
	 *
110
	 * @param string $email
111
	 * @return int|string|false
112
	 */
113
	public function get_user_id_or_email( $email ) {
114
115
		if ( is_user_logged_in() ) {
116
			return get_current_user_id();
117
		}
118
119
		return empty( $email ) ? false : sanitize_email( $email );
120
	}
121
122
	/**
123
	 * Validates a single use discount.
124
	 *
125
	 * @param GetPaid_Payment_Form_Submission $submission
126
	 * @param WPInv_Discount                  $discount
127
	 */
128
	public function validate_single_use_discount( $submission, $discount ) {
129
130
		// Abort if it is not a single use discount.
131
		if ( ! $discount->is_single_use() ) {
132
			return;
133
		}
134
135
		// Ensure there is a valid billing email.
136
		$user = $this->get_user_id_or_email( $submission->get_billing_email() );
137
		if ( ! empty( $user ) ) {
138
			$this->set_error( __( 'You need to either log in or enter your billing email before applying this discount', 'invoicing' ) );
139
		}
140
141
		// Has the user used this discount code before?
142
		if ( ! $discount->is_valid_for_user( $user ) ) {
0 ignored issues
show
Bug introduced by
It seems like $user can also be of type false; however, parameter $user of WPInv_Discount::is_valid_for_user() does only seem to accept integer|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

142
		if ( ! $discount->is_valid_for_user( /** @scrutinizer ignore-type */ $user ) ) {
Loading history...
143
			return $this->set_error( __( 'You have already used this discount', 'invoicing' ) );
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->set_error(__('You...iscount', 'invoicing')) targeting GetPaid_Payment_Form_Sub...n_Discount::set_error() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
144
		}
145
146
	}
147
148
	/**
149
	 * Validates the discount's amount.
150
	 *
151
	 * @param GetPaid_Payment_Form_Submission $submission
152
	 * @param WPInv_Discount         $discount
153
	 * @param float                  $amount
154
	 */
155
	public function validate_discount_amount( $submission, $discount, $amount ) {
156
157
		// Validate minimum amount.
158
		if ( ! $discount->is_minimum_amount_met( $amount ) ) {
159
            $min = wpinv_price( $discount->get_minimum_total(), $submission->get_currency() );
160
			return $this->set_error( sprintf( __( 'The minimum total for using this discount is %s', 'invoicing' ), $min ) );
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->set_error(sprintf...', 'invoicing'), $min)) targeting GetPaid_Payment_Form_Sub...n_Discount::set_error() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
161
		}
162
163
		// Validate the maximum amount.
164
		if ( ! $discount->is_maximum_amount_met( $amount ) ) {
165
			$max = wpinv_price( $discount->get_maximum_total(), $submission->get_currency() );
166
			return $this->set_error( sprintf( __( 'The maximum total for using this discount is %s', 'invoicing' ), $max ) );
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->set_error(sprintf...', 'invoicing'), $max)) targeting GetPaid_Payment_Form_Sub...n_Discount::set_error() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
167
		}
168
169
	}
170
171
	/**
172
	 * Calculates the discount code's amount.
173
	 *
174
	 * Ensure that the discount exists and has been validated before calling this method.
175
	 *
176
	 * @param GetPaid_Payment_Form_Submission $submission
177
	 * @return array
178
	 */
179
	public function calculate_discount( $submission ) {
180
181
		$initial_discount   = 0;
182
		$recurring_discount = 0;
183
184
		foreach ( $submission->get_items() as $item ) {
185
186
			// Abort if it is not valid for this item.
187
			if ( ! $this->discount->is_valid_for_items( array( $item->get_id() ) ) ) {
188
				continue;
189
			}
190
191
			// Calculate the initial amount...
192
			$initial_discount += $this->discount->get_discounted_amount( $item->get_initial_price() * $item->get_quantity() );
193
194
			// ... and maybe the recurring amount.
195
			if ( $item->is_recurring() && $this->discount->is_recurring() ) {
196
				$recurring_discount += $this->discount->get_discounted_amount( $item->get_recurring_price() * $item->get_quantity() );
197
			}
198
199
		}
200
201
		return array(
202
			'name'               => 'discount_code',
203
			'discount_code'      => $this->discount->get_code(),
204
			'initial_discount'   => $initial_discount,
205
			'recurring_discount' => $recurring_discount,
206
		);
207
208
	}
209
210
}
211