Completed
Branch BUG/3560-ticket-taxes (410ee3)
by
unknown
03:06 queued 32s
created
core/services/payment_methods/gateways/GatewayDataFormatterInterface.php 1 patch
Indentation   +45 added lines, -45 removed lines patch added patch discarded remove patch
@@ -16,64 +16,64 @@
 block discarded – undo
16 16
 interface GatewayDataFormatterInterface
17 17
 {
18 18
 
19
-    /**
20
-     * Gets the text to use for a gateway's line item name when this is a partial payment
21
-     *
22
-     * @param EEI_Payment $payment
23
-     * @return string
24
-     */
25
-    public function formatPartialPaymentLineItemName(EEI_Payment $payment): string;
19
+	/**
20
+	 * Gets the text to use for a gateway's line item name when this is a partial payment
21
+	 *
22
+	 * @param EEI_Payment $payment
23
+	 * @return string
24
+	 */
25
+	public function formatPartialPaymentLineItemName(EEI_Payment $payment): string;
26 26
 
27 27
 
28 28
 
29
-    /**
30
-     * Gets the text to use for a gateway's line item description when this is a partial payment
31
-     *
32
-     * @param EEI_Payment $payment
33
-     * @return string
34
-     */
35
-    public function formatPartialPaymentLineItemDesc(EEI_Payment $payment): string;
29
+	/**
30
+	 * Gets the text to use for a gateway's line item description when this is a partial payment
31
+	 *
32
+	 * @param EEI_Payment $payment
33
+	 * @return string
34
+	 */
35
+	public function formatPartialPaymentLineItemDesc(EEI_Payment $payment): string;
36 36
 
37 37
 
38 38
 
39
-    /**
40
-     * Gets the name to use for a line item when sending line items to the gateway
41
-     *
42
-     * @param EE_Line_Item $line_item
43
-     * @param EEI_Payment   $payment
44
-     * @return string
45
-     */
46
-    public function formatLineItemName(EE_Line_Item $line_item, EEI_Payment $payment): string;
39
+	/**
40
+	 * Gets the name to use for a line item when sending line items to the gateway
41
+	 *
42
+	 * @param EE_Line_Item $line_item
43
+	 * @param EEI_Payment   $payment
44
+	 * @return string
45
+	 */
46
+	public function formatLineItemName(EE_Line_Item $line_item, EEI_Payment $payment): string;
47 47
 
48 48
 
49 49
 
50
-    /**
51
-     * Gets the description to use for a line item when sending line items to the gateway
52
-     *
53
-     * @param EE_Line_Item $line_item
54
-     * @param EEI_Payment   $payment
55
-     * @return string
56
-     */
57
-    public function formatLineItemDesc(EE_Line_Item $line_item, EEI_Payment $payment): string;
50
+	/**
51
+	 * Gets the description to use for a line item when sending line items to the gateway
52
+	 *
53
+	 * @param EE_Line_Item $line_item
54
+	 * @param EEI_Payment   $payment
55
+	 * @return string
56
+	 */
57
+	public function formatLineItemDesc(EE_Line_Item $line_item, EEI_Payment $payment): string;
58 58
 
59 59
 
60 60
 
61
-    /**
62
-     * Gets the order description that should generally be sent to gateways
63
-     *
64
-     * @param EEI_Payment $payment
65
-     * @return string
66
-     */
67
-    public function formatOrderDescription(EEI_Payment $payment): string;
61
+	/**
62
+	 * Gets the order description that should generally be sent to gateways
63
+	 *
64
+	 * @param EEI_Payment $payment
65
+	 * @return string
66
+	 */
67
+	public function formatOrderDescription(EEI_Payment $payment): string;
68 68
 
69 69
 
70 70
 
71
-    /**
72
-     * Formats the amount so it can generally be sent to gateways
73
-     *
74
-     * @param float $amount
75
-     * @param int   $precision
76
-     * @return string
77
-     */
78
-    public function formatCurrency(float $amount, int $precision = 2): string;
71
+	/**
72
+	 * Formats the amount so it can generally be sent to gateways
73
+	 *
74
+	 * @param float $amount
75
+	 * @param int   $precision
76
+	 * @return string
77
+	 */
78
+	public function formatCurrency(float $amount, int $precision = 2): string;
79 79
 }
Please login to merge, or discard this patch.
core/services/payment_methods/gateways/GatewayDataFormatter.php 1 patch
Indentation   +107 added lines, -107 removed lines patch added patch discarded remove patch
@@ -19,121 +19,121 @@
 block discarded – undo
19 19
 class GatewayDataFormatter implements GatewayDataFormatterInterface
20 20
 {
21 21
 
22
-    /**
23
-     * Gets the text to use for a gateway's line item name when this is a partial payment
24
-     *
25
-     * @param EEI_Payment $payment
26
-     * @return string
27
-     */
28
-    public function formatPartialPaymentLineItemName(EEI_Payment $payment): string
29
-    {
30
-        return apply_filters(
31
-            'EEG_Paypal_Pro__do_direct_payment__partial_amount_line_item_name',
32
-            $payment->get_first_event_name(),
33
-            $this,
34
-            $payment
35
-        );
36
-    }
22
+	/**
23
+	 * Gets the text to use for a gateway's line item name when this is a partial payment
24
+	 *
25
+	 * @param EEI_Payment $payment
26
+	 * @return string
27
+	 */
28
+	public function formatPartialPaymentLineItemName(EEI_Payment $payment): string
29
+	{
30
+		return apply_filters(
31
+			'EEG_Paypal_Pro__do_direct_payment__partial_amount_line_item_name',
32
+			$payment->get_first_event_name(),
33
+			$this,
34
+			$payment
35
+		);
36
+	}
37 37
 
38 38
 
39
-    /**
40
-     * Gets the text to use for a gateway's line item description when this is a partial payment
41
-     *
42
-     * @param EEI_Payment $payment
43
-     * @return string
44
-     * @throws EE_Error
45
-     */
46
-    public function formatPartialPaymentLineItemDesc(EEI_Payment $payment): string
47
-    {
48
-        return apply_filters(
49
-            'FHEE__EE_Gateway___partial_payment_desc',
50
-            sprintf(
51
-                __('Payment of %1$s for %2$s', "event_espresso"),
52
-                $payment->get_pretty('PAY_amount', 'no_currency_code'),
53
-                $payment->get_first_event_name()
54
-            ),
55
-            $this,
56
-            $payment
57
-        );
58
-    }
39
+	/**
40
+	 * Gets the text to use for a gateway's line item description when this is a partial payment
41
+	 *
42
+	 * @param EEI_Payment $payment
43
+	 * @return string
44
+	 * @throws EE_Error
45
+	 */
46
+	public function formatPartialPaymentLineItemDesc(EEI_Payment $payment): string
47
+	{
48
+		return apply_filters(
49
+			'FHEE__EE_Gateway___partial_payment_desc',
50
+			sprintf(
51
+				__('Payment of %1$s for %2$s', "event_espresso"),
52
+				$payment->get_pretty('PAY_amount', 'no_currency_code'),
53
+				$payment->get_first_event_name()
54
+			),
55
+			$this,
56
+			$payment
57
+		);
58
+	}
59 59
 
60 60
 
61
-    /**
62
-     * Gets the name to use for a line item when sending line items to the gateway
63
-     *
64
-     * @param EE_Line_Item $line_item
65
-     * @param EEI_Payment  $payment
66
-     * @return string
67
-     * @throws EE_Error
68
-     * @throws ReflectionException
69
-     */
70
-    public function formatLineItemName(EE_Line_Item $line_item, EEI_Payment $payment): string
71
-    {
72
-        return apply_filters(
73
-            'FHEE__EE_gateway___line_item_name',
74
-            sprintf(
75
-                _x('%1$s for %2$s', 'Ticket for Event', 'event_espresso'),
76
-                $line_item->name(),
77
-                $line_item->ticket_event_name()
78
-            ),
79
-            $this,
80
-            $line_item,
81
-            $payment
82
-        );
83
-    }
61
+	/**
62
+	 * Gets the name to use for a line item when sending line items to the gateway
63
+	 *
64
+	 * @param EE_Line_Item $line_item
65
+	 * @param EEI_Payment  $payment
66
+	 * @return string
67
+	 * @throws EE_Error
68
+	 * @throws ReflectionException
69
+	 */
70
+	public function formatLineItemName(EE_Line_Item $line_item, EEI_Payment $payment): string
71
+	{
72
+		return apply_filters(
73
+			'FHEE__EE_gateway___line_item_name',
74
+			sprintf(
75
+				_x('%1$s for %2$s', 'Ticket for Event', 'event_espresso'),
76
+				$line_item->name(),
77
+				$line_item->ticket_event_name()
78
+			),
79
+			$this,
80
+			$line_item,
81
+			$payment
82
+		);
83
+	}
84 84
 
85 85
 
86
-    /**
87
-     * Gets the description to use for a line item when sending line items to the gateway
88
-     *
89
-     * @param EE_Line_Item $line_item
90
-     * @param EEI_Payment  $payment
91
-     * @return string
92
-     * @throws EE_Error
93
-     * @throws ReflectionException
94
-     */
95
-    public function formatLineItemDesc(EE_Line_Item $line_item, EEI_Payment $payment): string
96
-    {
97
-        return apply_filters(
98
-            'FHEE__EE_Gateway___line_item_desc',
99
-            $line_item->desc(),
100
-            $this,
101
-            $line_item,
102
-            $payment
103
-        );
104
-    }
86
+	/**
87
+	 * Gets the description to use for a line item when sending line items to the gateway
88
+	 *
89
+	 * @param EE_Line_Item $line_item
90
+	 * @param EEI_Payment  $payment
91
+	 * @return string
92
+	 * @throws EE_Error
93
+	 * @throws ReflectionException
94
+	 */
95
+	public function formatLineItemDesc(EE_Line_Item $line_item, EEI_Payment $payment): string
96
+	{
97
+		return apply_filters(
98
+			'FHEE__EE_Gateway___line_item_desc',
99
+			$line_item->desc(),
100
+			$this,
101
+			$line_item,
102
+			$payment
103
+		);
104
+	}
105 105
 
106 106
 
107
-    /**
108
-     * Gets the order description that should generally be sent to gateways
109
-     *
110
-     * @param EEI_Payment $payment
111
-     * @return string
112
-     */
113
-    public function formatOrderDescription(EEI_Payment $payment): string
114
-    {
115
-        return apply_filters(
116
-            'FHEE__EE_Gateway___order_description',
117
-            sprintf(
118
-                __('Event Registrations from %1$s for %2$s', "event_espresso"),
119
-                wp_specialchars_decode(get_bloginfo(), ENT_QUOTES),
120
-                $payment->get_first_event_name()
121
-            ),
122
-            $this,
123
-            $payment
124
-        );
125
-    }
107
+	/**
108
+	 * Gets the order description that should generally be sent to gateways
109
+	 *
110
+	 * @param EEI_Payment $payment
111
+	 * @return string
112
+	 */
113
+	public function formatOrderDescription(EEI_Payment $payment): string
114
+	{
115
+		return apply_filters(
116
+			'FHEE__EE_Gateway___order_description',
117
+			sprintf(
118
+				__('Event Registrations from %1$s for %2$s', "event_espresso"),
119
+				wp_specialchars_decode(get_bloginfo(), ENT_QUOTES),
120
+				$payment->get_first_event_name()
121
+			),
122
+			$this,
123
+			$payment
124
+		);
125
+	}
126 126
 
127 127
 
128
-    /**
129
-     * Formats the amount so it can generally be sent to gateways
130
-     *
131
-     * @param float $amount
132
-     * @param int $precision
133
-     * @return string
134
-     */
135
-    public function formatCurrency(float $amount, int $precision = 2): string
136
-    {
137
-        return number_format($amount, $precision, '.', '');
138
-    }
128
+	/**
129
+	 * Formats the amount so it can generally be sent to gateways
130
+	 *
131
+	 * @param float $amount
132
+	 * @param int $precision
133
+	 * @return string
134
+	 */
135
+	public function formatCurrency(float $amount, int $precision = 2): string
136
+	{
137
+		return number_format($amount, $precision, '.', '');
138
+	}
139 139
 }
Please login to merge, or discard this patch.
core/services/calculators/LineItemCalculator.php 2 patches
Indentation   +719 added lines, -719 removed lines patch added patch discarded remove patch
@@ -21,723 +21,723 @@
 block discarded – undo
21 21
 class LineItemCalculator
22 22
 {
23 23
 
24
-    /**
25
-     * @var DecimalValues
26
-     */
27
-    protected $decimal_values;
28
-
29
-    /**
30
-     * @var array
31
-     */
32
-    protected $default_query_params = [
33
-        ['LIN_type' => ['!=', EEM_Line_Item::type_cancellation]]
34
-    ];
35
-
36
-
37
-    /**
38
-     * @param DecimalValues $decimal_values
39
-     */
40
-    public function __construct(DecimalValues $decimal_values)
41
-    {
42
-        $this->decimal_values = $decimal_values;
43
-    }
44
-
45
-
46
-    /**
47
-     * Gets the final total on this item, taking taxes into account.
48
-     * Has the side-effect of setting the sub-total as it was just calculated.
49
-     * If this is used on a grand-total line item, also updates the transaction's
50
-     * TXN_total (provided this line item is allowed to persist, otherwise we don't
51
-     * want to change a persistable transaction with info from a non-persistent line item)
52
-     *
53
-     * @param EE_Line_Item $line_item
54
-     * @param bool         $update_txn_status
55
-     * @return float
56
-     * @throws EE_Error
57
-     * @throws ReflectionException
58
-     */
59
-    public function recalculateTotalIncludingTaxes(EE_Line_Item $line_item, bool $update_txn_status = false): float
60
-    {
61
-        $this->validateLineItemAndType($line_item, EEM_Line_Item::type_total);
62
-        $ticket_line_items = EEH_Line_Item::get_ticket_line_items($line_item);
63
-        if (empty($ticket_line_items)) {
64
-            return 0;
65
-        }
66
-        [, $pretax_total] = $this->recalculateLineItemTotals($line_item);
67
-        // EEH_Line_Item::visualize($line_item);
68
-        $total_tax = $this->recalculateTaxesAndTaxTotal($line_item);
69
-        // no negative totals plz
70
-        $grand_total  = max($pretax_total + $total_tax, 0);
71
-        $this->updatePreTaxTotal($line_item, $pretax_total, true);
72
-        $grand_total  = $this->updateTotal($line_item, $grand_total, true);
73
-        $this->updateTransaction($line_item, $grand_total, $update_txn_status);
74
-        return $grand_total;
75
-    }
76
-
77
-
78
-    /**
79
-     * Recursively goes through all the children and recalculates sub-totals EXCEPT for
80
-     * tax-sub-totals (they're a an odd beast). Updates the 'total' on each line item according to either its
81
-     * unit price * quantity or the total of all its children EXCEPT when we're only calculating the taxable total and
82
-     * when this is called on the grand total
83
-     *
84
-     * @param EE_Line_Item $line_item
85
-     * @param float        $total
86
-     * @param float        $pretax_total
87
-     * @return array
88
-     * @throws EE_Error
89
-     * @throws ReflectionException
90
-     */
91
-    public function recalculateLineItemTotals(
92
-        EE_Line_Item $line_item,
93
-        float $total = 0,
94
-        float $pretax_total = 0
95
-    ): array {
96
-        switch ($line_item->type()) {
97
-            case EEM_Line_Item::type_total:
98
-            case EEM_Line_Item::type_sub_total:
99
-                [$total, $pretax_total] = $this->recalculateSubTotal($line_item);
100
-                break;
101
-
102
-            case EEM_Line_Item::type_line_item:
103
-                [$total, $pretax_total] = $this->recalculateLineItem($line_item, $total, $pretax_total);
104
-                break;
105
-
106
-            case EEM_Line_Item::type_sub_line_item:
107
-                // sub line items operate on the total and update both the total AND the pre-tax total
108
-                [$total, $pretax_total] = $this->recalculateSubLineItem($line_item, $total, $pretax_total);
109
-                break;
110
-
111
-            case EEM_Line_Item::type_sub_tax:
112
-                // sub line item taxes ONLY operate on the pre-tax total and ONLY update the total
113
-                [$total, $pretax_total] = $this->recalculateSubTax($line_item, $pretax_total);
114
-                break;
115
-
116
-            case EEM_Line_Item::type_tax_sub_total:
117
-            case EEM_Line_Item::type_tax:
118
-            case EEM_Line_Item::type_cancellation:
119
-                // completely ignore tax totals, tax sub-totals, and cancelled line items
120
-                // when calculating the pre-tax-total
121
-                $total = $pretax_total = 0;
122
-                break;
123
-        }
124
-        return [$total, $pretax_total];
125
-    }
126
-
127
-
128
-    /**
129
-     * @param EE_Line_Item $line_item
130
-     * @return array
131
-     * @throws EE_Error
132
-     * @throws ReflectionException
133
-     */
134
-    private function recalculateSubTotal(EE_Line_Item $line_item): array
135
-    {
136
-        // reset the total and pretax total to zero since we are recalculating them
137
-        $total = $pretax_total = 0;
138
-        if ($line_item->is_total()) {
139
-            // if this is the grand total line item
140
-            // then first update ALL of the line item quantities (if need be)
141
-            $this->updateLineItemQuantities($line_item);
142
-        }
143
-        // recursively loop through children and recalculate their totals
144
-        $children = $line_item->children($this->default_query_params);
145
-        if (empty($children)) {
146
-            return [$total, $pretax_total];
147
-        }
148
-        foreach ($children as $child_line_item) {
149
-            [$child_total, $child_pretax_total] = $this->recalculateLineItemTotals(
150
-                $child_line_item,
151
-                $total,
152
-                $pretax_total
153
-            );
154
-            $total += $child_total;
155
-            $pretax_total += $child_pretax_total;
156
-        }
157
-        // update the unit price and pretax total
158
-        $this->updateUnitPrice($line_item, $pretax_total);
159
-        $pretax_total = $this->updatePreTaxTotal($line_item, $pretax_total, true);
160
-        // for the actual pre-tax sub total line item, we want to save the pretax value for everything
161
-        if ($line_item->is_sub_total() && $line_item->name() === esc_html__('Pre-Tax Subtotal', 'event_espresso')) {
162
-            $this->updateTotal($line_item, $pretax_total, true);
163
-        } elseif (! $line_item->is_total()) {
164
-            // we don't update the total for the total line item, because that will need to include taxes
165
-            $total = $this->updateTotal($line_item, $total, true);
166
-        }
167
-        return [$total, $pretax_total];
168
-    }
169
-
170
-
171
-    /**
172
-     * @param EE_Line_Item $line_item
173
-     * @param float        $total
174
-     * @param float        $pretax_total
175
-     * @return array
176
-     * @throws EE_Error
177
-     * @throws ReflectionException
178
-     */
179
-    private function recalculateLineItem(
180
-        EE_Line_Item $line_item,
181
-        float $total = 0,
182
-        float $pretax_total = 0
183
-    ): array {
184
-        if ($line_item->is_percent()) {
185
-            $total = $this->calculatePercentage($total, $line_item->percent());
186
-            $pretax_total = $this->calculatePercentage($pretax_total, $line_item->percent());
187
-        } else {
188
-            // recursively loop through children and recalculate their totals
189
-            $children = $line_item->children($this->default_query_params);
190
-            if (! empty($children)) {
191
-                // reset the total and pretax total to zero since we are recalculating them
192
-                $total = $pretax_total = 0;
193
-                foreach ($children as $child_line_item) {
194
-                    [$child_total, $child_pretax_total] = $this->recalculateLineItemTotals(
195
-                        $child_line_item,
196
-                        $total,
197
-                        $pretax_total
198
-                    );
199
-                    $total        += $child_total;
200
-                    $pretax_total += $child_pretax_total;
201
-                }
202
-            } else {
203
-                // no child line items, so recalculate the total from the unit price and quantity
204
-                // and set the pretax total to match since their are obviously no sub-taxes
205
-                $pretax_total = $total = $this->calculateTotalForQuantity($line_item);
206
-            }
207
-        }
208
-        $total  = $this->updateTotal($line_item, $total, true);
209
-        $pretax_total = $this->updatePreTaxTotal($line_item, $pretax_total, true);
210
-
211
-        // need to also adjust unit price too if the pretax total or quantity has been updated
212
-        $this->updateUnitPrice($line_item, $pretax_total);
213
-        return [$total, $pretax_total];
214
-    }
215
-
216
-
217
-    /**
218
-     * @param EE_Line_Item $sub_line_item
219
-     * @param float|int    $total
220
-     * @param float|int    $pretax_total
221
-     * @return float[]
222
-     * @throws EE_Error
223
-     * @throws ReflectionException
224
-     */
225
-    private function recalculateSubLineItem(EE_Line_Item $sub_line_item, float $total = 0, float $pretax_total = 0): array
226
-    {
227
-        if ($sub_line_item->is_percent()) {
228
-            $new_total = $this->calculatePercentage($total, $sub_line_item->percent());
229
-            $new_pretax_total = $this->calculatePercentage($pretax_total, $sub_line_item->percent());
230
-        } else {
231
-            $new_total = $new_pretax_total = $this->calculateTotalForQuantity($sub_line_item);
232
-        }
233
-        $total = $this->updateTotal($sub_line_item, $new_total);
234
-        $pretax_total = $this->updatePreTaxTotal($sub_line_item, $new_pretax_total);
235
-        // need to also adjust unit price too if the pretax total or quantity has been updated
236
-        $this->updateUnitPrice($sub_line_item, $pretax_total);
237
-        return [$total, $pretax_total];
238
-    }
239
-
240
-
241
-    /**
242
-     * @param EE_Line_Item $sub_line_item
243
-     * @param float|int    $pretax_total
244
-     * @return float[]
245
-     * @throws EE_Error
246
-     * @throws ReflectionException
247
-     */
248
-    private function recalculateSubTax(EE_Line_Item $sub_line_item, float $pretax_total = 0): array
249
-    {
250
-        $total_tax = $this->calculatePercentage($pretax_total, $sub_line_item->percent());
251
-        $total_tax = $this->updateTotal($sub_line_item, $total_tax);
252
-        return [$total_tax, 0];
253
-    }
254
-
255
-
256
-    /**
257
-     * recursively loops through the entire line item tree updating line item quantities accordingly.
258
-     * this needs to be done prior to running any other calculations for reasons that are hopefully obvious :p
259
-     *
260
-     * @param EE_Line_Item $line_item
261
-     * @param int          $quantity
262
-     * @return int
263
-     * @throws EE_Error
264
-     * @throws ReflectionException
265
-     */
266
-    private function updateLineItemQuantities(EE_Line_Item $line_item, int $quantity = 1): int
267
-    {
268
-        switch ($line_item->type()) {
269
-            case EEM_Line_Item::type_total:
270
-            case EEM_Line_Item::type_sub_total:
271
-            case EEM_Line_Item::type_tax_sub_total:
272
-                // first, loop through children and set their quantities
273
-                $count = 0;
274
-                $children = $line_item->children($this->default_query_params);
275
-                foreach ($children as $child_line_item) {
276
-                    $count += $this->updateLineItemQuantities($child_line_item);
277
-                }
278
-                // totals and subtotals should have a quantity of 1
279
-                // unless their children have all been removed, in which case we can set them to 0
280
-                $quantity = $count > 0 ? 1 : 0;
281
-                $this->updateQuantity($line_item, $quantity);
282
-                return $quantity;
283
-
284
-            case EEM_Line_Item::type_line_item:
285
-                // line items should ALREADY have accurate quantities set, if not, then somebody done goofed!
286
-                // but if this is a percentage based line item, then ensure its quantity is 1
287
-                if ($line_item->is_percent()) {
288
-                    $this->updateQuantity($line_item, 1);
289
-                }
290
-                // and we also need to loop through all of the sub items and ensure those quantities match this parent.
291
-                $children = $line_item->children($this->default_query_params);
292
-                $quantity = $line_item->quantity();
293
-                foreach ($children as $child_line_item) {
294
-                    $this->updateLineItemQuantities($child_line_item, $quantity);
295
-                }
296
-                // percentage line items should not increment their parent's count, so they return 0
297
-                return ! $line_item->is_percent() ? $quantity : 0;
298
-
299
-            case EEM_Line_Item::type_sub_line_item:
300
-                // percentage based items need their quantity set to 1,
301
-                // all others use the incoming value from the parent line item
302
-                $quantity = $line_item->is_percent() ? 1 : $quantity;
303
-                $this->updateQuantity($line_item, $quantity);
304
-                // percentage line items should not increment their parent's count, so they return 0
305
-                return ! $line_item->is_percent() ? $quantity : 0;
306
-
307
-            case EEM_Line_Item::type_tax:
308
-            case EEM_Line_Item::type_sub_tax:
309
-                // taxes should have a quantity of 1
310
-                $this->updateQuantity($line_item, 1);
311
-                return 1;
312
-
313
-            case EEM_Line_Item::type_cancellation:
314
-                // cancellations will be ignored for all calculations
315
-                // because their parent quantities should have already been adjusted when they were added
316
-                // so assume that things are already set correctly
317
-                return 0;
318
-        }
319
-        return 0;
320
-    }
321
-
322
-
323
-    /**
324
-     * @param float $total
325
-     * @param float $percent
326
-     * @param bool  $round
327
-     * @return float
328
-     */
329
-    private function calculatePercentage(float $total, float $percent, bool $round = false): float
330
-    {
331
-        $amount = $total * $percent / 100;
332
-        return $this->decimal_values->roundDecimalValue($amount, $round);
333
-    }
334
-
335
-
336
-    /**
337
-     * @param EE_Line_Item $line_item
338
-     * @return float
339
-     * @throws EE_Error
340
-     * @throws ReflectionException
341
-     */
342
-    private function calculateTotalForQuantity(EE_Line_Item $line_item): float
343
-    {
344
-        $total = $line_item->unit_price() * $line_item->quantity();
345
-        return $this->decimal_values->roundDecimalValue($total);
346
-    }
347
-
348
-
349
-    /**
350
-     * @param EE_Line_Item $line_item
351
-     * @param float        $percent
352
-     * @throws EE_Error
353
-     * @throws ReflectionException
354
-     */
355
-    private function updatePercent(EE_Line_Item $line_item, float $percent)
356
-    {
357
-        // update and save new percent only if incoming value does not match existing value
358
-        if ($line_item->percent() !== $percent) {
359
-            $line_item->set_percent($percent);
360
-            $line_item->maybe_save();
361
-        }
362
-    }
363
-
364
-
365
-    /**
366
-     * @param EE_Line_Item $line_item
367
-     * @param float        $pretax_total
368
-     * @param bool         $round
369
-     * @return float
370
-     * @throws EE_Error
371
-     * @throws ReflectionException
372
-     */
373
-    private function updatePreTaxTotal(EE_Line_Item $line_item, float $pretax_total, bool $round = false): float
374
-    {
375
-        $pretax_total = $this->decimal_values->roundDecimalValue($pretax_total, $round);
376
-        // update and save new total only if incoming value does not match existing value
377
-        if ($line_item->preTaxTotal() !== $pretax_total) {
378
-            $line_item->setPreTaxTotal($pretax_total);
379
-            $line_item->maybe_save();
380
-        }
381
-        return $pretax_total;
382
-    }
383
-
384
-
385
-    /**
386
-     * @param EE_Line_Item $line_item
387
-     * @param int          $quantity
388
-     * @throws EE_Error
389
-     * @throws ReflectionException
390
-     */
391
-    private function updateQuantity(EE_Line_Item $line_item, int $quantity)
392
-    {
393
-        // update and save new quantity only if incoming value does not match existing value
394
-        if ($line_item->quantity() !== $quantity) {
395
-            $line_item->set_quantity($quantity);
396
-            $line_item->maybe_save();
397
-        }
398
-    }
399
-
400
-
401
-    /**
402
-     * @param EE_Line_Item $line_item
403
-     * @param float        $total
404
-     * @param bool         $round
405
-     * @return float
406
-     * @throws EE_Error
407
-     * @throws ReflectionException
408
-     */
409
-    private function updateTotal(EE_Line_Item $line_item, float $total, bool $round = false): float
410
-    {
411
-        $total = $this->decimal_values->roundDecimalValue($total, $round);
412
-        // update and save new total only if incoming value does not match existing value
413
-        if ($line_item->total() !== $total) {
414
-            $line_item->set_total($total);
415
-            $line_item->maybe_save();
416
-        }
417
-        return $total;
418
-    }
419
-
420
-
421
-    /**
422
-     * @param EE_Line_Item $line_item
423
-     * @param float        $total
424
-     * @param bool         $update_status
425
-     * @return void
426
-     * @throws EE_Error
427
-     * @throws ReflectionException
428
-     */
429
-    private function updateTransaction(EE_Line_Item $line_item, float $total, bool $update_status)
430
-    {
431
-        // only update the related transaction's total
432
-        // if we intend to save this line item and its a grand total
433
-        if ($line_item->allow_persist()) {
434
-            $transaction = $line_item->transaction();
435
-            if ($transaction instanceof EE_Transaction) {
436
-                $transaction->set_total($total);
437
-                if ($update_status) {
438
-                    // don't save the TXN because that will be done below
439
-                    // and the following method only saves if the status changes
440
-                    $transaction->update_status_based_on_total_paid(false);
441
-                }
442
-                if ($transaction->ID()) {
443
-                    $transaction->save();
444
-                }
445
-            }
446
-        }
447
-    }
448
-
449
-
450
-    /**
451
-     * @param EE_Line_Item $line_item
452
-     * @param float        $pretax_total
453
-     * @return void
454
-     * @throws EE_Error
455
-     * @throws ReflectionException
456
-     */
457
-    private function updateUnitPrice(EE_Line_Item $line_item, float $pretax_total)
458
-    {
459
-        $quantity = $line_item->quantity();
460
-        // don't divide by zero else you'll create a singularity and implode the interweb
461
-        // we also don't set unit prices for percentage based line items
462
-        if ($quantity === 0 || $line_item->is_percent()) {
463
-            return;
464
-        }
465
-        $new_unit_price = $pretax_total / $quantity;
466
-        $new_unit_price = $this->decimal_values->roundDecimalValue($new_unit_price);
467
-        // update and save new total only if incoming value does not match existing value
468
-        if ($line_item->unit_price() !== $new_unit_price) {
469
-            $line_item->set_unit_price($new_unit_price);
470
-            $line_item->maybe_save();
471
-        }
472
-    }
473
-
474
-
475
-    /**
476
-     * Recalculates the total on each individual tax (based on a recalculation of the pre-tax total), sets
477
-     * the totals on each tax calculated, and returns the final tax total. Re-saves tax line items
478
-     * and tax sub-total if already in the DB
479
-     *
480
-     * @param EE_Line_Item $total_line_item
481
-     * @return float
482
-     * @throws EE_Error
483
-     * @throws ReflectionException
484
-     */
485
-    public function recalculateTaxesAndTaxTotal(EE_Line_Item $total_line_item): float
486
-    {
487
-        $this->validateLineItemAndType($total_line_item, EEM_Line_Item::type_total);
488
-        // calculate the total taxable amount for globally applied taxes
489
-        $taxable_total = $this->taxableAmountForGlobalTaxes($total_line_item);
490
-        $global_taxes     = $this->applyGlobalTaxes($total_line_item, $taxable_total);
491
-        $non_global_taxes = $this->calculateNonGlobalTaxes($total_line_item);
492
-        $all_tax_total        = $this->applyNonGlobalTaxes($total_line_item, $global_taxes, $non_global_taxes);
493
-        $this->recalculateTaxSubTotal($total_line_item);
494
-        return $all_tax_total;
495
-    }
496
-
497
-
498
-    /**
499
-     * @param EE_Line_Item $total_line_item
500
-     * @param float        $taxable_total
501
-     * @return float
502
-     * @throws EE_Error
503
-     * @throws ReflectionException
504
-     */
505
-    private function applyGlobalTaxes(EE_Line_Item $total_line_item, float $taxable_total): float
506
-    {
507
-        $this->validateLineItemAndType($total_line_item, EEM_Line_Item::type_total);
508
-        $total_tax = 0;
509
-        // loop through all global taxes all taxes
510
-        $global_taxes = $total_line_item->tax_descendants();
511
-        foreach ($global_taxes as $tax) {
512
-            $tax_total = $this->calculatePercentage($taxable_total, $tax->percent());
513
-            $tax_total = $this->updateTotal($tax, $tax_total, true);
514
-            $total_tax += $tax_total;
515
-        }
516
-        return $this->decimal_values->roundDecimalValue($total_tax, true);
517
-    }
518
-
519
-
520
-    /**
521
-     * Simply forces all the tax-sub-totals to recalculate. Assumes the taxes have been calculated
522
-     *
523
-     * @param EE_Line_Item $line_item
524
-     * @return void
525
-     * @throws EE_Error
526
-     * @throws ReflectionException
527
-     */
528
-    private function recalculateTaxSubTotal(EE_Line_Item $line_item)
529
-    {
530
-        $this->validateLineItemAndType($line_item, EEM_Line_Item::type_total);
531
-        foreach ($line_item->children() as $maybe_tax_subtotal) {
532
-            if (
533
-                $this->validateLineItemAndType($maybe_tax_subtotal)
534
-                && $maybe_tax_subtotal->is_tax_sub_total()
535
-            ) {
536
-                $total         = 0;
537
-                $total_percent = 0;
538
-                // simply loop through all its children (which should be taxes) and sum their total
539
-                foreach ($maybe_tax_subtotal->children() as $child_tax) {
540
-                    if ($this->validateLineItemAndType($child_tax) && $child_tax->isGlobalTax()) {
541
-                        $total         += $child_tax->total();
542
-                        $total_percent += $child_tax->percent();
543
-                    }
544
-                }
545
-                $this->updateTotal($maybe_tax_subtotal, $total, true);
546
-                $this->updatePercent($maybe_tax_subtotal, $total_percent);
547
-            }
548
-        }
549
-    }
550
-
551
-
552
-    /**
553
-     * returns an array of tax details like:
554
-     *  [
555
-     *      'GST_7' => [
556
-     *          'name'  => 'GST',
557
-     *          'rate'  => float(7),
558
-     *          'total' => float(4.9),
559
-     *      ]
560
-     *  ]
561
-     *
562
-     * @param EE_Line_Item $total_line_item
563
-     * @param array        $non_global_taxes
564
-     * @param float        $line_item_total
565
-     * @return array
566
-     * @throws EE_Error
567
-     * @throws ReflectionException
568
-     */
569
-    private function calculateNonGlobalTaxes(
570
-        EE_Line_Item $total_line_item,
571
-        array $non_global_taxes = [],
572
-        float $line_item_total = 0
573
-    ): array {
574
-        foreach ($total_line_item->children() as $line_item) {
575
-            if ($this->validateLineItemAndType($line_item)) {
576
-                if ($line_item->is_sub_total()) {
577
-                    $non_global_taxes = $this->calculateNonGlobalTaxes($line_item, $non_global_taxes);
578
-                } elseif ($line_item->is_line_item()) {
579
-                    $non_global_taxes = $this->calculateNonGlobalTaxes(
580
-                        $line_item,
581
-                        $non_global_taxes,
582
-                        $line_item->pretaxTotal()
583
-                    );
584
-                } elseif ($line_item->isSubTax()) {
585
-                    $tax_ID = $line_item->name() . '_' . $line_item->percent();
586
-                    if (! isset($non_global_taxes[ $tax_ID ])) {
587
-                        $non_global_taxes[ $tax_ID ] = [
588
-                            'name'  => $line_item->name(),
589
-                            'rate'  => $line_item->percent(),
590
-                            'total' => 0,
591
-                            'obj'   => $line_item->OBJ_type(),
592
-                            'objID' => $line_item->OBJ_ID(),
593
-                        ];
594
-                    }
595
-                    $tax = $this->calculatePercentage($line_item_total, $line_item->percent());
596
-                    $non_global_taxes[ $tax_ID ]['total'] += $tax;
597
-                }
598
-            }
599
-        }
600
-        return $non_global_taxes;
601
-    }
602
-
603
-
604
-    /**
605
-     * @param EE_Line_Item $total_line_item
606
-     * @param float        $tax_total
607
-     * @param array        $non_global_taxes array of tax details generated by calculateNonGlobalTaxes()
608
-     * @return float
609
-     * @throws EE_Error
610
-     * @throws ReflectionException
611
-     */
612
-    private function applyNonGlobalTaxes(
613
-        EE_Line_Item $total_line_item,
614
-        float $tax_total,
615
-        array $non_global_taxes
616
-    ): float {
617
-        $global_taxes   = $total_line_item->tax_descendants();
618
-        $taxes_subtotal = EEH_Line_Item::get_taxes_subtotal($total_line_item);
619
-        foreach ($non_global_taxes as $non_global_tax) {
620
-            $found = false;
621
-            foreach ($global_taxes as $global_tax) {
622
-                if (
623
-                    $this->validateLineItemAndType($global_tax)
624
-                    && $non_global_tax['obj'] === $global_tax->OBJ_type()
625
-                    && $non_global_tax['objID'] === $global_tax->OBJ_ID()
626
-                ) {
627
-                    $found = true;
628
-                    $new_total = $global_tax->total() + $non_global_tax['total'];
629
-                    // add non global tax to matching global tax AND the tax total
630
-                    $global_tax->set_total($new_total);
631
-                    $global_tax->maybe_save();
632
-                    $tax_total += $non_global_tax['total'];
633
-                }
634
-            }
635
-            if (! $found) {
636
-                // add a new line item for this non global tax
637
-                $taxes_subtotal->add_child_line_item(
638
-                    EE_Line_Item::new_instance(
639
-                        [
640
-                            'LIN_name'       => $non_global_tax['name'],
641
-                            'LIN_percent'    => $non_global_tax['rate'],
642
-                            'LIN_is_taxable' => false,
643
-                            'LIN_total'      => $non_global_tax['total'],
644
-                            'LIN_type'       => EEM_Line_Item::type_tax,
645
-                            'OBJ_type'       => $non_global_tax['obj'],
646
-                            'OBJ_ID'         => $non_global_tax['objID'],
647
-                        ]
648
-                    )
649
-                );
650
-                $tax_total += $non_global_tax['total'];
651
-            }
652
-        }
653
-        return $this->decimal_values->roundDecimalValue($tax_total, true);
654
-    }
655
-
656
-
657
-    /**
658
-     * Gets the total tax on this line item. Assumes taxes have already been calculated using
659
-     * recalculate_taxes_and_total
660
-     *
661
-     * @param EE_Line_Item $line_item
662
-     * @return float
663
-     * @throws EE_Error
664
-     * @throws ReflectionException
665
-     */
666
-    public function getTotalTax(EE_Line_Item $line_item): float
667
-    {
668
-        $this->validateLineItemAndType($line_item, EEM_Line_Item::type_total);
669
-        $this->recalculateTaxSubTotal($line_item);
670
-        $total = 0;
671
-        foreach ($line_item->tax_descendants() as $tax_line_item) {
672
-            if ($this->validateLineItemAndType($tax_line_item)) {
673
-                $total += $tax_line_item->total();
674
-            }
675
-        }
676
-        return $this->decimal_values->roundDecimalValue($total, true);
677
-    }
678
-
679
-
680
-    /**
681
-     * Returns the amount taxable among this line item's children (or if it has no children,
682
-     * how much of it is taxable). Does not recalculate totals or subtotals.
683
-     * If the taxable total is negative, (eg, if none of the tickets were taxable,
684
-     * but there is a "Taxable" discount), returns 0.
685
-     *
686
-     * @param EE_Line_Item|null $line_item
687
-     * @return float
688
-     * @throws EE_Error
689
-     * @throws ReflectionException
690
-     */
691
-    public function taxableAmountForGlobalTaxes(?EE_Line_Item $line_item): float
692
-    {
693
-        $total      = 0;
694
-        $child_line_items = $line_item->children($this->default_query_params);
695
-        foreach ($child_line_items as $child_line_item) {
696
-            $this->validateLineItemAndType($child_line_item);
697
-            if ($child_line_item->is_sub_total()) {
698
-                $total += $this->taxableAmountForGlobalTaxes($child_line_item);
699
-            } elseif ($child_line_item->is_line_item() && $child_line_item->is_taxable()) {
700
-                // if it's a percent item, only take into account
701
-                // the percentage that's taxable (the taxable total so far)
702
-                if ($child_line_item->is_percent()) {
703
-                    $total += $this->calculatePercentage($total, $child_line_item->percent(), true);
704
-                } else {
705
-                    // pretax total will be equal to the total for line items with globally applied taxes
706
-                    $pretax_total = $this->calculateTotalForQuantity($child_line_item);
707
-                    $total += $this->updatePreTaxTotal($child_line_item, $pretax_total);
708
-                }
709
-            }
710
-        }
711
-        return max($total, 0);
712
-    }
713
-
714
-
715
-    /**
716
-     * @param EE_Line_Item|null $line_item
717
-     * @param string|null       $type
718
-     * @return bool
719
-     * @throws EE_Error
720
-     * @throws ReflectionException
721
-     */
722
-    private function validateLineItemAndType(?EE_Line_Item $line_item, ?string $type = null): bool
723
-    {
724
-        if (! $line_item instanceof EE_Line_Item) {
725
-            throw new DomainException(
726
-                esc_html__('Invalid or missing Line Item supplied .', 'event_espresso')
727
-            );
728
-        }
729
-        if ($type && $line_item->type() !== $type) {
730
-            throw new DomainException(
731
-                sprintf(
732
-                    esc_html__(
733
-                        'Invalid Line Item type supplied. Received "%1$s" but expected "%2$s".',
734
-                        'event_espresso'
735
-                    ),
736
-                    $line_item->type(),
737
-                    $type
738
-                )
739
-            );
740
-        }
741
-        return true;
742
-    }
24
+	/**
25
+	 * @var DecimalValues
26
+	 */
27
+	protected $decimal_values;
28
+
29
+	/**
30
+	 * @var array
31
+	 */
32
+	protected $default_query_params = [
33
+		['LIN_type' => ['!=', EEM_Line_Item::type_cancellation]]
34
+	];
35
+
36
+
37
+	/**
38
+	 * @param DecimalValues $decimal_values
39
+	 */
40
+	public function __construct(DecimalValues $decimal_values)
41
+	{
42
+		$this->decimal_values = $decimal_values;
43
+	}
44
+
45
+
46
+	/**
47
+	 * Gets the final total on this item, taking taxes into account.
48
+	 * Has the side-effect of setting the sub-total as it was just calculated.
49
+	 * If this is used on a grand-total line item, also updates the transaction's
50
+	 * TXN_total (provided this line item is allowed to persist, otherwise we don't
51
+	 * want to change a persistable transaction with info from a non-persistent line item)
52
+	 *
53
+	 * @param EE_Line_Item $line_item
54
+	 * @param bool         $update_txn_status
55
+	 * @return float
56
+	 * @throws EE_Error
57
+	 * @throws ReflectionException
58
+	 */
59
+	public function recalculateTotalIncludingTaxes(EE_Line_Item $line_item, bool $update_txn_status = false): float
60
+	{
61
+		$this->validateLineItemAndType($line_item, EEM_Line_Item::type_total);
62
+		$ticket_line_items = EEH_Line_Item::get_ticket_line_items($line_item);
63
+		if (empty($ticket_line_items)) {
64
+			return 0;
65
+		}
66
+		[, $pretax_total] = $this->recalculateLineItemTotals($line_item);
67
+		// EEH_Line_Item::visualize($line_item);
68
+		$total_tax = $this->recalculateTaxesAndTaxTotal($line_item);
69
+		// no negative totals plz
70
+		$grand_total  = max($pretax_total + $total_tax, 0);
71
+		$this->updatePreTaxTotal($line_item, $pretax_total, true);
72
+		$grand_total  = $this->updateTotal($line_item, $grand_total, true);
73
+		$this->updateTransaction($line_item, $grand_total, $update_txn_status);
74
+		return $grand_total;
75
+	}
76
+
77
+
78
+	/**
79
+	 * Recursively goes through all the children and recalculates sub-totals EXCEPT for
80
+	 * tax-sub-totals (they're a an odd beast). Updates the 'total' on each line item according to either its
81
+	 * unit price * quantity or the total of all its children EXCEPT when we're only calculating the taxable total and
82
+	 * when this is called on the grand total
83
+	 *
84
+	 * @param EE_Line_Item $line_item
85
+	 * @param float        $total
86
+	 * @param float        $pretax_total
87
+	 * @return array
88
+	 * @throws EE_Error
89
+	 * @throws ReflectionException
90
+	 */
91
+	public function recalculateLineItemTotals(
92
+		EE_Line_Item $line_item,
93
+		float $total = 0,
94
+		float $pretax_total = 0
95
+	): array {
96
+		switch ($line_item->type()) {
97
+			case EEM_Line_Item::type_total:
98
+			case EEM_Line_Item::type_sub_total:
99
+				[$total, $pretax_total] = $this->recalculateSubTotal($line_item);
100
+				break;
101
+
102
+			case EEM_Line_Item::type_line_item:
103
+				[$total, $pretax_total] = $this->recalculateLineItem($line_item, $total, $pretax_total);
104
+				break;
105
+
106
+			case EEM_Line_Item::type_sub_line_item:
107
+				// sub line items operate on the total and update both the total AND the pre-tax total
108
+				[$total, $pretax_total] = $this->recalculateSubLineItem($line_item, $total, $pretax_total);
109
+				break;
110
+
111
+			case EEM_Line_Item::type_sub_tax:
112
+				// sub line item taxes ONLY operate on the pre-tax total and ONLY update the total
113
+				[$total, $pretax_total] = $this->recalculateSubTax($line_item, $pretax_total);
114
+				break;
115
+
116
+			case EEM_Line_Item::type_tax_sub_total:
117
+			case EEM_Line_Item::type_tax:
118
+			case EEM_Line_Item::type_cancellation:
119
+				// completely ignore tax totals, tax sub-totals, and cancelled line items
120
+				// when calculating the pre-tax-total
121
+				$total = $pretax_total = 0;
122
+				break;
123
+		}
124
+		return [$total, $pretax_total];
125
+	}
126
+
127
+
128
+	/**
129
+	 * @param EE_Line_Item $line_item
130
+	 * @return array
131
+	 * @throws EE_Error
132
+	 * @throws ReflectionException
133
+	 */
134
+	private function recalculateSubTotal(EE_Line_Item $line_item): array
135
+	{
136
+		// reset the total and pretax total to zero since we are recalculating them
137
+		$total = $pretax_total = 0;
138
+		if ($line_item->is_total()) {
139
+			// if this is the grand total line item
140
+			// then first update ALL of the line item quantities (if need be)
141
+			$this->updateLineItemQuantities($line_item);
142
+		}
143
+		// recursively loop through children and recalculate their totals
144
+		$children = $line_item->children($this->default_query_params);
145
+		if (empty($children)) {
146
+			return [$total, $pretax_total];
147
+		}
148
+		foreach ($children as $child_line_item) {
149
+			[$child_total, $child_pretax_total] = $this->recalculateLineItemTotals(
150
+				$child_line_item,
151
+				$total,
152
+				$pretax_total
153
+			);
154
+			$total += $child_total;
155
+			$pretax_total += $child_pretax_total;
156
+		}
157
+		// update the unit price and pretax total
158
+		$this->updateUnitPrice($line_item, $pretax_total);
159
+		$pretax_total = $this->updatePreTaxTotal($line_item, $pretax_total, true);
160
+		// for the actual pre-tax sub total line item, we want to save the pretax value for everything
161
+		if ($line_item->is_sub_total() && $line_item->name() === esc_html__('Pre-Tax Subtotal', 'event_espresso')) {
162
+			$this->updateTotal($line_item, $pretax_total, true);
163
+		} elseif (! $line_item->is_total()) {
164
+			// we don't update the total for the total line item, because that will need to include taxes
165
+			$total = $this->updateTotal($line_item, $total, true);
166
+		}
167
+		return [$total, $pretax_total];
168
+	}
169
+
170
+
171
+	/**
172
+	 * @param EE_Line_Item $line_item
173
+	 * @param float        $total
174
+	 * @param float        $pretax_total
175
+	 * @return array
176
+	 * @throws EE_Error
177
+	 * @throws ReflectionException
178
+	 */
179
+	private function recalculateLineItem(
180
+		EE_Line_Item $line_item,
181
+		float $total = 0,
182
+		float $pretax_total = 0
183
+	): array {
184
+		if ($line_item->is_percent()) {
185
+			$total = $this->calculatePercentage($total, $line_item->percent());
186
+			$pretax_total = $this->calculatePercentage($pretax_total, $line_item->percent());
187
+		} else {
188
+			// recursively loop through children and recalculate their totals
189
+			$children = $line_item->children($this->default_query_params);
190
+			if (! empty($children)) {
191
+				// reset the total and pretax total to zero since we are recalculating them
192
+				$total = $pretax_total = 0;
193
+				foreach ($children as $child_line_item) {
194
+					[$child_total, $child_pretax_total] = $this->recalculateLineItemTotals(
195
+						$child_line_item,
196
+						$total,
197
+						$pretax_total
198
+					);
199
+					$total        += $child_total;
200
+					$pretax_total += $child_pretax_total;
201
+				}
202
+			} else {
203
+				// no child line items, so recalculate the total from the unit price and quantity
204
+				// and set the pretax total to match since their are obviously no sub-taxes
205
+				$pretax_total = $total = $this->calculateTotalForQuantity($line_item);
206
+			}
207
+		}
208
+		$total  = $this->updateTotal($line_item, $total, true);
209
+		$pretax_total = $this->updatePreTaxTotal($line_item, $pretax_total, true);
210
+
211
+		// need to also adjust unit price too if the pretax total or quantity has been updated
212
+		$this->updateUnitPrice($line_item, $pretax_total);
213
+		return [$total, $pretax_total];
214
+	}
215
+
216
+
217
+	/**
218
+	 * @param EE_Line_Item $sub_line_item
219
+	 * @param float|int    $total
220
+	 * @param float|int    $pretax_total
221
+	 * @return float[]
222
+	 * @throws EE_Error
223
+	 * @throws ReflectionException
224
+	 */
225
+	private function recalculateSubLineItem(EE_Line_Item $sub_line_item, float $total = 0, float $pretax_total = 0): array
226
+	{
227
+		if ($sub_line_item->is_percent()) {
228
+			$new_total = $this->calculatePercentage($total, $sub_line_item->percent());
229
+			$new_pretax_total = $this->calculatePercentage($pretax_total, $sub_line_item->percent());
230
+		} else {
231
+			$new_total = $new_pretax_total = $this->calculateTotalForQuantity($sub_line_item);
232
+		}
233
+		$total = $this->updateTotal($sub_line_item, $new_total);
234
+		$pretax_total = $this->updatePreTaxTotal($sub_line_item, $new_pretax_total);
235
+		// need to also adjust unit price too if the pretax total or quantity has been updated
236
+		$this->updateUnitPrice($sub_line_item, $pretax_total);
237
+		return [$total, $pretax_total];
238
+	}
239
+
240
+
241
+	/**
242
+	 * @param EE_Line_Item $sub_line_item
243
+	 * @param float|int    $pretax_total
244
+	 * @return float[]
245
+	 * @throws EE_Error
246
+	 * @throws ReflectionException
247
+	 */
248
+	private function recalculateSubTax(EE_Line_Item $sub_line_item, float $pretax_total = 0): array
249
+	{
250
+		$total_tax = $this->calculatePercentage($pretax_total, $sub_line_item->percent());
251
+		$total_tax = $this->updateTotal($sub_line_item, $total_tax);
252
+		return [$total_tax, 0];
253
+	}
254
+
255
+
256
+	/**
257
+	 * recursively loops through the entire line item tree updating line item quantities accordingly.
258
+	 * this needs to be done prior to running any other calculations for reasons that are hopefully obvious :p
259
+	 *
260
+	 * @param EE_Line_Item $line_item
261
+	 * @param int          $quantity
262
+	 * @return int
263
+	 * @throws EE_Error
264
+	 * @throws ReflectionException
265
+	 */
266
+	private function updateLineItemQuantities(EE_Line_Item $line_item, int $quantity = 1): int
267
+	{
268
+		switch ($line_item->type()) {
269
+			case EEM_Line_Item::type_total:
270
+			case EEM_Line_Item::type_sub_total:
271
+			case EEM_Line_Item::type_tax_sub_total:
272
+				// first, loop through children and set their quantities
273
+				$count = 0;
274
+				$children = $line_item->children($this->default_query_params);
275
+				foreach ($children as $child_line_item) {
276
+					$count += $this->updateLineItemQuantities($child_line_item);
277
+				}
278
+				// totals and subtotals should have a quantity of 1
279
+				// unless their children have all been removed, in which case we can set them to 0
280
+				$quantity = $count > 0 ? 1 : 0;
281
+				$this->updateQuantity($line_item, $quantity);
282
+				return $quantity;
283
+
284
+			case EEM_Line_Item::type_line_item:
285
+				// line items should ALREADY have accurate quantities set, if not, then somebody done goofed!
286
+				// but if this is a percentage based line item, then ensure its quantity is 1
287
+				if ($line_item->is_percent()) {
288
+					$this->updateQuantity($line_item, 1);
289
+				}
290
+				// and we also need to loop through all of the sub items and ensure those quantities match this parent.
291
+				$children = $line_item->children($this->default_query_params);
292
+				$quantity = $line_item->quantity();
293
+				foreach ($children as $child_line_item) {
294
+					$this->updateLineItemQuantities($child_line_item, $quantity);
295
+				}
296
+				// percentage line items should not increment their parent's count, so they return 0
297
+				return ! $line_item->is_percent() ? $quantity : 0;
298
+
299
+			case EEM_Line_Item::type_sub_line_item:
300
+				// percentage based items need their quantity set to 1,
301
+				// all others use the incoming value from the parent line item
302
+				$quantity = $line_item->is_percent() ? 1 : $quantity;
303
+				$this->updateQuantity($line_item, $quantity);
304
+				// percentage line items should not increment their parent's count, so they return 0
305
+				return ! $line_item->is_percent() ? $quantity : 0;
306
+
307
+			case EEM_Line_Item::type_tax:
308
+			case EEM_Line_Item::type_sub_tax:
309
+				// taxes should have a quantity of 1
310
+				$this->updateQuantity($line_item, 1);
311
+				return 1;
312
+
313
+			case EEM_Line_Item::type_cancellation:
314
+				// cancellations will be ignored for all calculations
315
+				// because their parent quantities should have already been adjusted when they were added
316
+				// so assume that things are already set correctly
317
+				return 0;
318
+		}
319
+		return 0;
320
+	}
321
+
322
+
323
+	/**
324
+	 * @param float $total
325
+	 * @param float $percent
326
+	 * @param bool  $round
327
+	 * @return float
328
+	 */
329
+	private function calculatePercentage(float $total, float $percent, bool $round = false): float
330
+	{
331
+		$amount = $total * $percent / 100;
332
+		return $this->decimal_values->roundDecimalValue($amount, $round);
333
+	}
334
+
335
+
336
+	/**
337
+	 * @param EE_Line_Item $line_item
338
+	 * @return float
339
+	 * @throws EE_Error
340
+	 * @throws ReflectionException
341
+	 */
342
+	private function calculateTotalForQuantity(EE_Line_Item $line_item): float
343
+	{
344
+		$total = $line_item->unit_price() * $line_item->quantity();
345
+		return $this->decimal_values->roundDecimalValue($total);
346
+	}
347
+
348
+
349
+	/**
350
+	 * @param EE_Line_Item $line_item
351
+	 * @param float        $percent
352
+	 * @throws EE_Error
353
+	 * @throws ReflectionException
354
+	 */
355
+	private function updatePercent(EE_Line_Item $line_item, float $percent)
356
+	{
357
+		// update and save new percent only if incoming value does not match existing value
358
+		if ($line_item->percent() !== $percent) {
359
+			$line_item->set_percent($percent);
360
+			$line_item->maybe_save();
361
+		}
362
+	}
363
+
364
+
365
+	/**
366
+	 * @param EE_Line_Item $line_item
367
+	 * @param float        $pretax_total
368
+	 * @param bool         $round
369
+	 * @return float
370
+	 * @throws EE_Error
371
+	 * @throws ReflectionException
372
+	 */
373
+	private function updatePreTaxTotal(EE_Line_Item $line_item, float $pretax_total, bool $round = false): float
374
+	{
375
+		$pretax_total = $this->decimal_values->roundDecimalValue($pretax_total, $round);
376
+		// update and save new total only if incoming value does not match existing value
377
+		if ($line_item->preTaxTotal() !== $pretax_total) {
378
+			$line_item->setPreTaxTotal($pretax_total);
379
+			$line_item->maybe_save();
380
+		}
381
+		return $pretax_total;
382
+	}
383
+
384
+
385
+	/**
386
+	 * @param EE_Line_Item $line_item
387
+	 * @param int          $quantity
388
+	 * @throws EE_Error
389
+	 * @throws ReflectionException
390
+	 */
391
+	private function updateQuantity(EE_Line_Item $line_item, int $quantity)
392
+	{
393
+		// update and save new quantity only if incoming value does not match existing value
394
+		if ($line_item->quantity() !== $quantity) {
395
+			$line_item->set_quantity($quantity);
396
+			$line_item->maybe_save();
397
+		}
398
+	}
399
+
400
+
401
+	/**
402
+	 * @param EE_Line_Item $line_item
403
+	 * @param float        $total
404
+	 * @param bool         $round
405
+	 * @return float
406
+	 * @throws EE_Error
407
+	 * @throws ReflectionException
408
+	 */
409
+	private function updateTotal(EE_Line_Item $line_item, float $total, bool $round = false): float
410
+	{
411
+		$total = $this->decimal_values->roundDecimalValue($total, $round);
412
+		// update and save new total only if incoming value does not match existing value
413
+		if ($line_item->total() !== $total) {
414
+			$line_item->set_total($total);
415
+			$line_item->maybe_save();
416
+		}
417
+		return $total;
418
+	}
419
+
420
+
421
+	/**
422
+	 * @param EE_Line_Item $line_item
423
+	 * @param float        $total
424
+	 * @param bool         $update_status
425
+	 * @return void
426
+	 * @throws EE_Error
427
+	 * @throws ReflectionException
428
+	 */
429
+	private function updateTransaction(EE_Line_Item $line_item, float $total, bool $update_status)
430
+	{
431
+		// only update the related transaction's total
432
+		// if we intend to save this line item and its a grand total
433
+		if ($line_item->allow_persist()) {
434
+			$transaction = $line_item->transaction();
435
+			if ($transaction instanceof EE_Transaction) {
436
+				$transaction->set_total($total);
437
+				if ($update_status) {
438
+					// don't save the TXN because that will be done below
439
+					// and the following method only saves if the status changes
440
+					$transaction->update_status_based_on_total_paid(false);
441
+				}
442
+				if ($transaction->ID()) {
443
+					$transaction->save();
444
+				}
445
+			}
446
+		}
447
+	}
448
+
449
+
450
+	/**
451
+	 * @param EE_Line_Item $line_item
452
+	 * @param float        $pretax_total
453
+	 * @return void
454
+	 * @throws EE_Error
455
+	 * @throws ReflectionException
456
+	 */
457
+	private function updateUnitPrice(EE_Line_Item $line_item, float $pretax_total)
458
+	{
459
+		$quantity = $line_item->quantity();
460
+		// don't divide by zero else you'll create a singularity and implode the interweb
461
+		// we also don't set unit prices for percentage based line items
462
+		if ($quantity === 0 || $line_item->is_percent()) {
463
+			return;
464
+		}
465
+		$new_unit_price = $pretax_total / $quantity;
466
+		$new_unit_price = $this->decimal_values->roundDecimalValue($new_unit_price);
467
+		// update and save new total only if incoming value does not match existing value
468
+		if ($line_item->unit_price() !== $new_unit_price) {
469
+			$line_item->set_unit_price($new_unit_price);
470
+			$line_item->maybe_save();
471
+		}
472
+	}
473
+
474
+
475
+	/**
476
+	 * Recalculates the total on each individual tax (based on a recalculation of the pre-tax total), sets
477
+	 * the totals on each tax calculated, and returns the final tax total. Re-saves tax line items
478
+	 * and tax sub-total if already in the DB
479
+	 *
480
+	 * @param EE_Line_Item $total_line_item
481
+	 * @return float
482
+	 * @throws EE_Error
483
+	 * @throws ReflectionException
484
+	 */
485
+	public function recalculateTaxesAndTaxTotal(EE_Line_Item $total_line_item): float
486
+	{
487
+		$this->validateLineItemAndType($total_line_item, EEM_Line_Item::type_total);
488
+		// calculate the total taxable amount for globally applied taxes
489
+		$taxable_total = $this->taxableAmountForGlobalTaxes($total_line_item);
490
+		$global_taxes     = $this->applyGlobalTaxes($total_line_item, $taxable_total);
491
+		$non_global_taxes = $this->calculateNonGlobalTaxes($total_line_item);
492
+		$all_tax_total        = $this->applyNonGlobalTaxes($total_line_item, $global_taxes, $non_global_taxes);
493
+		$this->recalculateTaxSubTotal($total_line_item);
494
+		return $all_tax_total;
495
+	}
496
+
497
+
498
+	/**
499
+	 * @param EE_Line_Item $total_line_item
500
+	 * @param float        $taxable_total
501
+	 * @return float
502
+	 * @throws EE_Error
503
+	 * @throws ReflectionException
504
+	 */
505
+	private function applyGlobalTaxes(EE_Line_Item $total_line_item, float $taxable_total): float
506
+	{
507
+		$this->validateLineItemAndType($total_line_item, EEM_Line_Item::type_total);
508
+		$total_tax = 0;
509
+		// loop through all global taxes all taxes
510
+		$global_taxes = $total_line_item->tax_descendants();
511
+		foreach ($global_taxes as $tax) {
512
+			$tax_total = $this->calculatePercentage($taxable_total, $tax->percent());
513
+			$tax_total = $this->updateTotal($tax, $tax_total, true);
514
+			$total_tax += $tax_total;
515
+		}
516
+		return $this->decimal_values->roundDecimalValue($total_tax, true);
517
+	}
518
+
519
+
520
+	/**
521
+	 * Simply forces all the tax-sub-totals to recalculate. Assumes the taxes have been calculated
522
+	 *
523
+	 * @param EE_Line_Item $line_item
524
+	 * @return void
525
+	 * @throws EE_Error
526
+	 * @throws ReflectionException
527
+	 */
528
+	private function recalculateTaxSubTotal(EE_Line_Item $line_item)
529
+	{
530
+		$this->validateLineItemAndType($line_item, EEM_Line_Item::type_total);
531
+		foreach ($line_item->children() as $maybe_tax_subtotal) {
532
+			if (
533
+				$this->validateLineItemAndType($maybe_tax_subtotal)
534
+				&& $maybe_tax_subtotal->is_tax_sub_total()
535
+			) {
536
+				$total         = 0;
537
+				$total_percent = 0;
538
+				// simply loop through all its children (which should be taxes) and sum their total
539
+				foreach ($maybe_tax_subtotal->children() as $child_tax) {
540
+					if ($this->validateLineItemAndType($child_tax) && $child_tax->isGlobalTax()) {
541
+						$total         += $child_tax->total();
542
+						$total_percent += $child_tax->percent();
543
+					}
544
+				}
545
+				$this->updateTotal($maybe_tax_subtotal, $total, true);
546
+				$this->updatePercent($maybe_tax_subtotal, $total_percent);
547
+			}
548
+		}
549
+	}
550
+
551
+
552
+	/**
553
+	 * returns an array of tax details like:
554
+	 *  [
555
+	 *      'GST_7' => [
556
+	 *          'name'  => 'GST',
557
+	 *          'rate'  => float(7),
558
+	 *          'total' => float(4.9),
559
+	 *      ]
560
+	 *  ]
561
+	 *
562
+	 * @param EE_Line_Item $total_line_item
563
+	 * @param array        $non_global_taxes
564
+	 * @param float        $line_item_total
565
+	 * @return array
566
+	 * @throws EE_Error
567
+	 * @throws ReflectionException
568
+	 */
569
+	private function calculateNonGlobalTaxes(
570
+		EE_Line_Item $total_line_item,
571
+		array $non_global_taxes = [],
572
+		float $line_item_total = 0
573
+	): array {
574
+		foreach ($total_line_item->children() as $line_item) {
575
+			if ($this->validateLineItemAndType($line_item)) {
576
+				if ($line_item->is_sub_total()) {
577
+					$non_global_taxes = $this->calculateNonGlobalTaxes($line_item, $non_global_taxes);
578
+				} elseif ($line_item->is_line_item()) {
579
+					$non_global_taxes = $this->calculateNonGlobalTaxes(
580
+						$line_item,
581
+						$non_global_taxes,
582
+						$line_item->pretaxTotal()
583
+					);
584
+				} elseif ($line_item->isSubTax()) {
585
+					$tax_ID = $line_item->name() . '_' . $line_item->percent();
586
+					if (! isset($non_global_taxes[ $tax_ID ])) {
587
+						$non_global_taxes[ $tax_ID ] = [
588
+							'name'  => $line_item->name(),
589
+							'rate'  => $line_item->percent(),
590
+							'total' => 0,
591
+							'obj'   => $line_item->OBJ_type(),
592
+							'objID' => $line_item->OBJ_ID(),
593
+						];
594
+					}
595
+					$tax = $this->calculatePercentage($line_item_total, $line_item->percent());
596
+					$non_global_taxes[ $tax_ID ]['total'] += $tax;
597
+				}
598
+			}
599
+		}
600
+		return $non_global_taxes;
601
+	}
602
+
603
+
604
+	/**
605
+	 * @param EE_Line_Item $total_line_item
606
+	 * @param float        $tax_total
607
+	 * @param array        $non_global_taxes array of tax details generated by calculateNonGlobalTaxes()
608
+	 * @return float
609
+	 * @throws EE_Error
610
+	 * @throws ReflectionException
611
+	 */
612
+	private function applyNonGlobalTaxes(
613
+		EE_Line_Item $total_line_item,
614
+		float $tax_total,
615
+		array $non_global_taxes
616
+	): float {
617
+		$global_taxes   = $total_line_item->tax_descendants();
618
+		$taxes_subtotal = EEH_Line_Item::get_taxes_subtotal($total_line_item);
619
+		foreach ($non_global_taxes as $non_global_tax) {
620
+			$found = false;
621
+			foreach ($global_taxes as $global_tax) {
622
+				if (
623
+					$this->validateLineItemAndType($global_tax)
624
+					&& $non_global_tax['obj'] === $global_tax->OBJ_type()
625
+					&& $non_global_tax['objID'] === $global_tax->OBJ_ID()
626
+				) {
627
+					$found = true;
628
+					$new_total = $global_tax->total() + $non_global_tax['total'];
629
+					// add non global tax to matching global tax AND the tax total
630
+					$global_tax->set_total($new_total);
631
+					$global_tax->maybe_save();
632
+					$tax_total += $non_global_tax['total'];
633
+				}
634
+			}
635
+			if (! $found) {
636
+				// add a new line item for this non global tax
637
+				$taxes_subtotal->add_child_line_item(
638
+					EE_Line_Item::new_instance(
639
+						[
640
+							'LIN_name'       => $non_global_tax['name'],
641
+							'LIN_percent'    => $non_global_tax['rate'],
642
+							'LIN_is_taxable' => false,
643
+							'LIN_total'      => $non_global_tax['total'],
644
+							'LIN_type'       => EEM_Line_Item::type_tax,
645
+							'OBJ_type'       => $non_global_tax['obj'],
646
+							'OBJ_ID'         => $non_global_tax['objID'],
647
+						]
648
+					)
649
+				);
650
+				$tax_total += $non_global_tax['total'];
651
+			}
652
+		}
653
+		return $this->decimal_values->roundDecimalValue($tax_total, true);
654
+	}
655
+
656
+
657
+	/**
658
+	 * Gets the total tax on this line item. Assumes taxes have already been calculated using
659
+	 * recalculate_taxes_and_total
660
+	 *
661
+	 * @param EE_Line_Item $line_item
662
+	 * @return float
663
+	 * @throws EE_Error
664
+	 * @throws ReflectionException
665
+	 */
666
+	public function getTotalTax(EE_Line_Item $line_item): float
667
+	{
668
+		$this->validateLineItemAndType($line_item, EEM_Line_Item::type_total);
669
+		$this->recalculateTaxSubTotal($line_item);
670
+		$total = 0;
671
+		foreach ($line_item->tax_descendants() as $tax_line_item) {
672
+			if ($this->validateLineItemAndType($tax_line_item)) {
673
+				$total += $tax_line_item->total();
674
+			}
675
+		}
676
+		return $this->decimal_values->roundDecimalValue($total, true);
677
+	}
678
+
679
+
680
+	/**
681
+	 * Returns the amount taxable among this line item's children (or if it has no children,
682
+	 * how much of it is taxable). Does not recalculate totals or subtotals.
683
+	 * If the taxable total is negative, (eg, if none of the tickets were taxable,
684
+	 * but there is a "Taxable" discount), returns 0.
685
+	 *
686
+	 * @param EE_Line_Item|null $line_item
687
+	 * @return float
688
+	 * @throws EE_Error
689
+	 * @throws ReflectionException
690
+	 */
691
+	public function taxableAmountForGlobalTaxes(?EE_Line_Item $line_item): float
692
+	{
693
+		$total      = 0;
694
+		$child_line_items = $line_item->children($this->default_query_params);
695
+		foreach ($child_line_items as $child_line_item) {
696
+			$this->validateLineItemAndType($child_line_item);
697
+			if ($child_line_item->is_sub_total()) {
698
+				$total += $this->taxableAmountForGlobalTaxes($child_line_item);
699
+			} elseif ($child_line_item->is_line_item() && $child_line_item->is_taxable()) {
700
+				// if it's a percent item, only take into account
701
+				// the percentage that's taxable (the taxable total so far)
702
+				if ($child_line_item->is_percent()) {
703
+					$total += $this->calculatePercentage($total, $child_line_item->percent(), true);
704
+				} else {
705
+					// pretax total will be equal to the total for line items with globally applied taxes
706
+					$pretax_total = $this->calculateTotalForQuantity($child_line_item);
707
+					$total += $this->updatePreTaxTotal($child_line_item, $pretax_total);
708
+				}
709
+			}
710
+		}
711
+		return max($total, 0);
712
+	}
713
+
714
+
715
+	/**
716
+	 * @param EE_Line_Item|null $line_item
717
+	 * @param string|null       $type
718
+	 * @return bool
719
+	 * @throws EE_Error
720
+	 * @throws ReflectionException
721
+	 */
722
+	private function validateLineItemAndType(?EE_Line_Item $line_item, ?string $type = null): bool
723
+	{
724
+		if (! $line_item instanceof EE_Line_Item) {
725
+			throw new DomainException(
726
+				esc_html__('Invalid or missing Line Item supplied .', 'event_espresso')
727
+			);
728
+		}
729
+		if ($type && $line_item->type() !== $type) {
730
+			throw new DomainException(
731
+				sprintf(
732
+					esc_html__(
733
+						'Invalid Line Item type supplied. Received "%1$s" but expected "%2$s".',
734
+						'event_espresso'
735
+					),
736
+					$line_item->type(),
737
+					$type
738
+				)
739
+			);
740
+		}
741
+		return true;
742
+	}
743 743
 }
Please login to merge, or discard this patch.
Spacing   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -160,7 +160,7 @@  discard block
 block discarded – undo
160 160
         // for the actual pre-tax sub total line item, we want to save the pretax value for everything
161 161
         if ($line_item->is_sub_total() && $line_item->name() === esc_html__('Pre-Tax Subtotal', 'event_espresso')) {
162 162
             $this->updateTotal($line_item, $pretax_total, true);
163
-        } elseif (! $line_item->is_total()) {
163
+        } elseif ( ! $line_item->is_total()) {
164 164
             // we don't update the total for the total line item, because that will need to include taxes
165 165
             $total = $this->updateTotal($line_item, $total, true);
166 166
         }
@@ -187,7 +187,7 @@  discard block
 block discarded – undo
187 187
         } else {
188 188
             // recursively loop through children and recalculate their totals
189 189
             $children = $line_item->children($this->default_query_params);
190
-            if (! empty($children)) {
190
+            if ( ! empty($children)) {
191 191
                 // reset the total and pretax total to zero since we are recalculating them
192 192
                 $total = $pretax_total = 0;
193 193
                 foreach ($children as $child_line_item) {
@@ -205,7 +205,7 @@  discard block
 block discarded – undo
205 205
                 $pretax_total = $total = $this->calculateTotalForQuantity($line_item);
206 206
             }
207 207
         }
208
-        $total  = $this->updateTotal($line_item, $total, true);
208
+        $total = $this->updateTotal($line_item, $total, true);
209 209
         $pretax_total = $this->updatePreTaxTotal($line_item, $pretax_total, true);
210 210
 
211 211
         // need to also adjust unit price too if the pretax total or quantity has been updated
@@ -489,7 +489,7 @@  discard block
 block discarded – undo
489 489
         $taxable_total = $this->taxableAmountForGlobalTaxes($total_line_item);
490 490
         $global_taxes     = $this->applyGlobalTaxes($total_line_item, $taxable_total);
491 491
         $non_global_taxes = $this->calculateNonGlobalTaxes($total_line_item);
492
-        $all_tax_total        = $this->applyNonGlobalTaxes($total_line_item, $global_taxes, $non_global_taxes);
492
+        $all_tax_total = $this->applyNonGlobalTaxes($total_line_item, $global_taxes, $non_global_taxes);
493 493
         $this->recalculateTaxSubTotal($total_line_item);
494 494
         return $all_tax_total;
495 495
     }
@@ -582,9 +582,9 @@  discard block
 block discarded – undo
582 582
                         $line_item->pretaxTotal()
583 583
                     );
584 584
                 } elseif ($line_item->isSubTax()) {
585
-                    $tax_ID = $line_item->name() . '_' . $line_item->percent();
586
-                    if (! isset($non_global_taxes[ $tax_ID ])) {
587
-                        $non_global_taxes[ $tax_ID ] = [
585
+                    $tax_ID = $line_item->name().'_'.$line_item->percent();
586
+                    if ( ! isset($non_global_taxes[$tax_ID])) {
587
+                        $non_global_taxes[$tax_ID] = [
588 588
                             'name'  => $line_item->name(),
589 589
                             'rate'  => $line_item->percent(),
590 590
                             'total' => 0,
@@ -593,7 +593,7 @@  discard block
 block discarded – undo
593 593
                         ];
594 594
                     }
595 595
                     $tax = $this->calculatePercentage($line_item_total, $line_item->percent());
596
-                    $non_global_taxes[ $tax_ID ]['total'] += $tax;
596
+                    $non_global_taxes[$tax_ID]['total'] += $tax;
597 597
                 }
598 598
             }
599 599
         }
@@ -632,7 +632,7 @@  discard block
 block discarded – undo
632 632
                     $tax_total += $non_global_tax['total'];
633 633
                 }
634 634
             }
635
-            if (! $found) {
635
+            if ( ! $found) {
636 636
                 // add a new line item for this non global tax
637 637
                 $taxes_subtotal->add_child_line_item(
638 638
                     EE_Line_Item::new_instance(
@@ -690,7 +690,7 @@  discard block
 block discarded – undo
690 690
      */
691 691
     public function taxableAmountForGlobalTaxes(?EE_Line_Item $line_item): float
692 692
     {
693
-        $total      = 0;
693
+        $total = 0;
694 694
         $child_line_items = $line_item->children($this->default_query_params);
695 695
         foreach ($child_line_items as $child_line_item) {
696 696
             $this->validateLineItemAndType($child_line_item);
@@ -721,7 +721,7 @@  discard block
 block discarded – undo
721 721
      */
722 722
     private function validateLineItemAndType(?EE_Line_Item $line_item, ?string $type = null): bool
723 723
     {
724
-        if (! $line_item instanceof EE_Line_Item) {
724
+        if ( ! $line_item instanceof EE_Line_Item) {
725 725
             throw new DomainException(
726 726
                 esc_html__('Invalid or missing Line Item supplied .', 'event_espresso')
727 727
             );
Please login to merge, or discard this patch.
core/libraries/payment_methods/EE_Gateway.lib.php 1 patch
Indentation   +500 added lines, -500 removed lines patch added patch discarded remove patch
@@ -23,504 +23,504 @@
 block discarded – undo
23 23
  */
24 24
 abstract class EE_Gateway
25 25
 {
26
-    /**
27
-     * a constant used as a possible value for $_currencies_supported to indicate
28
-     * that ALL currencies are supported by this gateway
29
-     */
30
-    const all_currencies_supported = 'all_currencies_supported';
31
-    /**
32
-     * Where values are 3-letter currency codes
33
-     *
34
-     * @var array
35
-     */
36
-    protected $_currencies_supported = array();
37
-    /**
38
-     * Whether or not this gateway can support SENDING a refund request (ie, initiated by
39
-     * admin in EE's wp-admin page)
40
-     *
41
-     * @var boolean
42
-     */
43
-    protected $_supports_sending_refunds = false;
44
-
45
-    /**
46
-     * Whether or not this gateway can support RECEIVING a refund request from the payment
47
-     * provider (ie, initiated by admin on the payment prover's website who sends an IPN to EE)
48
-     *
49
-     * @var boolean
50
-     */
51
-    protected $_supports_receiving_refunds = false;
52
-    /**
53
-     * Model for querying for existing payments
54
-     *
55
-     * @var EEMI_Payment
56
-     */
57
-    protected $_pay_model;
58
-
59
-    /**
60
-     * Model used for adding to the payments log
61
-     *
62
-     * @var EEMI_Payment_Log
63
-     */
64
-    protected $_pay_log;
65
-
66
-    /**
67
-     * Used for formatting some input to gateways
68
-     *
69
-     * @var EEHI_Template
70
-     */
71
-    protected $_template;
72
-
73
-    /**
74
-     * Concrete class that implements EEHI_Money, used by most gateways
75
-     *
76
-     * @var EEHI_Money
77
-     */
78
-    protected $_money;
79
-
80
-    /**
81
-     * Concrete class that implements EEHI_Line_Item, used for manipulating the line item tree
82
-     *
83
-     * @var EEHI_Line_Item
84
-     */
85
-    protected $_line_item;
86
-
87
-    /**
88
-     * @var GatewayDataFormatterInterface
89
-     */
90
-    protected $_gateway_data_formatter;
91
-
92
-    /**
93
-     * @var FormatterInterface
94
-     */
95
-    protected $_unsupported_character_remover;
96
-
97
-    /**
98
-     * The ID of the payment method using this gateway
99
-     *
100
-     * @var int
101
-     */
102
-    protected $_ID;
103
-
104
-    /**
105
-     * @var $_debug_mode boolean whether to send requests to teh sandbox site or not
106
-     */
107
-    protected $_debug_mode;
108
-    /**
109
-     *
110
-     * @var string $_name name to show for this payment method
111
-     */
112
-    protected $_name;
113
-    /**
114
-     *
115
-     * @var string name to show fir this payment method to admin-type users
116
-     */
117
-    protected $_admin_name;
118
-
119
-    /**
120
-     * EE_Gateway constructor
121
-     */
122
-    public function __construct()
123
-    {
124
-    }
125
-
126
-    /**
127
-     * We don't want to serialize models as they often have circular structures
128
-     * (eg a payment model has a reference to each payment model object; and most
129
-     * payments have a transaction, most transactions have a payment method;
130
-     * most payment methods have a payment method type; most payment method types
131
-     * have a gateway. And if a gateway serializes its models, we start at the
132
-     * beginning again)
133
-     *
134
-     * @return array
135
-     */
136
-    public function __sleep()
137
-    {
138
-        $properties = get_object_vars($this);
139
-        unset($properties['_pay_model'], $properties['_pay_log']);
140
-        return array_keys($properties);
141
-    }
142
-
143
-    /**
144
-     * Returns whether or not this gateway should support SENDING refunds
145
-     * see $_supports_sending_refunds
146
-     *
147
-     * @return boolean
148
-     */
149
-    public function supports_sending_refunds()
150
-    {
151
-        return $this->_supports_sending_refunds;
152
-    }
153
-
154
-    /**
155
-     * Returns whether or not this gateway should support RECEIVING refunds
156
-     * see $_supports_receiving_refunds
157
-     *
158
-     * @return boolean
159
-     */
160
-    public function supports_receiving_refunds()
161
-    {
162
-        return $this->_supports_receiving_refunds;
163
-    }
164
-
165
-
166
-    /**
167
-     * Tries to refund the payment specified, taking into account the extra
168
-     * refund info. Note that if the gateway's _supports_sending_refunds is false,
169
-     * this should just throw an exception.
170
-     *
171
-     * @param EE_Payment $payment
172
-     * @param array      $refund_info
173
-     * @return EE_Payment for the refund
174
-     * @throws EE_Error
175
-     */
176
-    public function do_direct_refund(EE_Payment $payment, $refund_info = null)
177
-    {
178
-        return null;
179
-    }
180
-
181
-
182
-    /**
183
-     * Sets the payment method's settings so the gateway knows where to send the request
184
-     * etc
185
-     *
186
-     * @param array $settings_array
187
-     */
188
-    public function set_settings($settings_array)
189
-    {
190
-        foreach ($settings_array as $name => $value) {
191
-            $property_name = "_" . $name;
192
-            $this->{$property_name} = $value;
193
-        }
194
-    }
195
-
196
-    /**
197
-     * See this class description
198
-     *
199
-     * @param EEMI_Payment $payment_model
200
-     */
201
-    public function set_payment_model($payment_model)
202
-    {
203
-        $this->_pay_model = $payment_model;
204
-    }
205
-
206
-    /**
207
-     * See this class description
208
-     *
209
-     * @param EEMI_Payment_Log $payment_log_model
210
-     */
211
-    public function set_payment_log($payment_log_model)
212
-    {
213
-        $this->_pay_log = $payment_log_model;
214
-    }
215
-
216
-    /**
217
-     * See this class description
218
-     *
219
-     * @param EEHI_Template $template_helper
220
-     */
221
-    public function set_template_helper($template_helper)
222
-    {
223
-        $this->_template = $template_helper;
224
-    }
225
-
226
-    /**
227
-     * See this class description
228
-     *
229
-     * @param EEHI_Line_Item $line_item_helper
230
-     */
231
-    public function set_line_item_helper($line_item_helper)
232
-    {
233
-        $this->_line_item = $line_item_helper;
234
-    }
235
-
236
-    /**
237
-     * See this class description
238
-     *
239
-     * @param EEHI_Money $money_helper
240
-     */
241
-    public function set_money_helper($money_helper)
242
-    {
243
-        $this->_money = $money_helper;
244
-    }
245
-
246
-
247
-    /**
248
-     * Sets the gateway data formatter helper
249
-     *
250
-     * @param GatewayDataFormatterInterface $gateway_data_formatter
251
-     * @throws InvalidEntityException if it's not set properly
252
-     */
253
-    public function set_gateway_data_formatter(GatewayDataFormatterInterface $gateway_data_formatter)
254
-    {
255
-        if (! $gateway_data_formatter instanceof GatewayDataFormatterInterface) {
256
-            throw new InvalidEntityException(
257
-                is_object($gateway_data_formatter)
258
-                    ? get_class($gateway_data_formatter)
259
-                    : esc_html__('Not an object', 'event_espresso'),
260
-                '\\EventEspresso\\core\\services\\payment_methods\\gateways\\GatewayDataFormatterInterface'
261
-            );
262
-        }
263
-        $this->_gateway_data_formatter = $gateway_data_formatter;
264
-    }
265
-
266
-    /**
267
-     * Gets the gateway data formatter
268
-     *
269
-     * @return GatewayDataFormatterInterface
270
-     * @throws InvalidEntityException if it's not set properly
271
-     */
272
-    protected function _get_gateway_formatter()
273
-    {
274
-        if (! $this->_gateway_data_formatter instanceof GatewayDataFormatterInterface) {
275
-            throw new InvalidEntityException(
276
-                is_object($this->_gateway_data_formatter)
277
-                    ? get_class($this->_gateway_data_formatter)
278
-                    : esc_html__('Not an object', 'event_espresso'),
279
-                '\\EventEspresso\\core\\services\\payment_methods\\gateways\\GatewayDataFormatterInterface'
280
-            );
281
-        }
282
-        return $this->_gateway_data_formatter;
283
-    }
284
-
285
-
286
-    /**
287
-     * Sets the helper which will remove unsupported characters for most gateways
288
-     *
289
-     * @param FormatterInterface $formatter
290
-     * @return FormatterInterface
291
-     * @throws InvalidEntityException
292
-     */
293
-    public function set_unsupported_character_remover(FormatterInterface $formatter)
294
-    {
295
-        if (! $formatter instanceof FormatterInterface) {
296
-            throw new InvalidEntityException(
297
-                is_object($formatter)
298
-                    ? get_class($formatter)
299
-                    : esc_html__('Not an object', 'event_espresso'),
300
-                '\\EventEspresso\\core\\services\\formatters\\FormatterInterface'
301
-            );
302
-        }
303
-        $this->_unsupported_character_remover = $formatter;
304
-    }
305
-
306
-    /**
307
-     * Gets the helper which removes characters which gateways might not support, like emojis etc.
308
-     *
309
-     * @return FormatterInterface
310
-     * @throws InvalidEntityException
311
-     */
312
-    protected function _get_unsupported_character_remover()
313
-    {
314
-        if (! $this->_unsupported_character_remover instanceof FormatterInterface) {
315
-            throw new InvalidEntityException(
316
-                is_object($this->_unsupported_character_remover)
317
-                    ? get_class($this->_unsupported_character_remover)
318
-                    : esc_html__('Not an object', 'event_espresso'),
319
-                '\\EventEspresso\\core\\services\\formatters\\FormatterInterface'
320
-            );
321
-        }
322
-        return $this->_unsupported_character_remover;
323
-    }
324
-
325
-
326
-    /**
327
-     * @param $message
328
-     * @param $payment
329
-     */
330
-    public function log($message, $object_logged)
331
-    {
332
-        if ($object_logged instanceof EEI_Payment) {
333
-            $type = 'Payment';
334
-            $id = $object_logged->ID();
335
-        } elseif ($object_logged instanceof EEI_Transaction) {
336
-            $type = 'Transaction';
337
-            $id = $object_logged->ID();
338
-        } else {
339
-            $type = 'Payment_Method';
340
-            $id = $this->_ID;
341
-        }
342
-        // only log if we're going to store it for longer than the minimum time
343
-        $reg_config = LoaderFactory::getLoader()->load('EE_Registration_Config');
344
-        if ($reg_config->gateway_log_lifespan !== '1 second') {
345
-            $this->_pay_log->gateway_log($message, $id, $type);
346
-        }
347
-    }
348
-
349
-    /**
350
-     * Formats the amount so it can generally be sent to gateways
351
-     *
352
-     * @param float $amount
353
-     * @return string
354
-     * @deprecated since 4.9.31 insetad use
355
-     *             EventEspresso\core\services\payment_methods\gateways\GatewayDataFormatter::format_currency()
356
-     */
357
-    public function format_currency($amount)
358
-    {
359
-        return $this->_get_gateway_formatter()->formatCurrency($amount);
360
-    }
361
-
362
-    /**
363
-     * Returns either an array of all the currency codes supported,
364
-     * or a string indicating they're all supported (EE_gateway::all_currencies_supported)
365
-     *
366
-     * @return mixed array or string
367
-     */
368
-    public function currencies_supported()
369
-    {
370
-        return $this->_currencies_supported;
371
-    }
372
-
373
-    /**
374
-     * Returns what a simple summing of items and taxes for this transaction. This
375
-     * can be used to determine if some more complex line items, like promotions,
376
-     * surcharges, or cancellations occurred (in which case we might want to forget
377
-     * about creating an itemized list of purchases and instead only send the total due)
378
-     *
379
-     * @param EE_Transaction $transaction
380
-     * @return float
381
-     */
382
-    protected function _sum_items_and_taxes(EE_Transaction $transaction)
383
-    {
384
-        $total_line_item = $transaction->total_line_item();
385
-        $total = 0;
386
-        foreach ($total_line_item->get_items() as $item_line_item) {
387
-            $total += max($item_line_item->total(), 0);
388
-        }
389
-        foreach ($total_line_item->tax_descendants() as $tax_line_item) {
390
-            $total += max($tax_line_item->total(), 0);
391
-        }
392
-        return $total;
393
-    }
394
-
395
-    /**
396
-     * Determines whether or not we can easily itemize the transaction using only
397
-     * items and taxes (ie, no promotions or surcharges or cancellations needed)
398
-     *
399
-     * @param EEI_Payment $payment
400
-     * @return boolean
401
-     */
402
-    protected function _can_easily_itemize_transaction_for(EEI_Payment $payment)
403
-    {
404
-        return $this->_money->compare_floats(
405
-            $this->_sum_items_and_taxes($payment->transaction()),
406
-            $payment->transaction()->total()
407
-        )
408
-               && $this->_money->compare_floats(
409
-                   $payment->amount(),
410
-                   $payment->transaction()->total()
411
-               );
412
-    }
413
-
414
-    /**
415
-     * Handles updating the transaction and any other related data based on the payment.
416
-     * You may be tempted to do this as part of do_direct_payment or handle_payment_update,
417
-     * but doing so on those functions might be too early. It's possible that the changes
418
-     * you make to teh transaction or registration or line items may just get overwritten
419
-     * at that point. Instead, you should store any info you need on the payment during those
420
-     * functions, and use that information at this step, which client code will decide
421
-     * for you when it should be called.
422
-     *
423
-     * @param EE_Payment $payment
424
-     * @return void
425
-     */
426
-    public function update_txn_based_on_payment($payment)
427
-    {
428
-        // maybe update the transaction or line items or registrations
429
-        // but most gateways don't need to do this, because they only update the payment
430
-    }
431
-
432
-    /**
433
-     * Gets the first event for this payment (it's possible that it could be for multiple)
434
-     *
435
-     * @param EEI_Payment $payment
436
-     * @return EEI_Event|null
437
-     * @deprecated since 4.9.31 instead use EEI_Payment::get_first_event()
438
-     */
439
-    protected function _get_first_event_for_payment(EEI_Payment $payment)
440
-    {
441
-        return $payment->get_first_event();
442
-    }
443
-
444
-    /**
445
-     * Gets the name of the first event for which is being paid
446
-     *
447
-     * @param EEI_Payment $payment
448
-     * @return string
449
-     * @deprecated since 4.9.31 instead use EEI_Payment::get_first_event_name()
450
-     */
451
-    protected function _get_first_event_name_for_payment(EEI_Payment $payment)
452
-    {
453
-        return $payment->get_first_event_name();
454
-    }
455
-
456
-    /**
457
-     * Gets the text to use for a gateway's line item name when this is a partial payment
458
-     *
459
-     * @deprecated since 4.9.31 instead use $this->_get_gateway_formatter()->formatPartialPaymentLineItemName($payment)
460
-     * @param EE_Payment $payment
461
-     * @return string
462
-     */
463
-    protected function _format_partial_payment_line_item_name(EEI_Payment $payment)
464
-    {
465
-        return $this->_get_gateway_formatter()->formatPartialPaymentLineItemName($payment);
466
-    }
467
-
468
-    /**
469
-     * Gets the text to use for a gateway's line item description when this is a partial payment
470
-     *
471
-     * @deprecated since 4.9.31 instead use $this->_get_gateway_formatter()->formatPartialPaymentLineItemDesc()
472
-     * @param EEI_Payment $payment
473
-     * @return string
474
-     */
475
-    protected function _format_partial_payment_line_item_desc(EEI_Payment $payment)
476
-    {
477
-        return $this->_get_gateway_formatter()->formatPartialPaymentLineItemDesc($payment);
478
-    }
479
-
480
-    /**
481
-     * Gets the name to use for a line item when sending line items to the gateway
482
-     *
483
-     * @deprecated since 4.9.31 instead use $this->_get_gateway_formatter()->formatLineItemName($line_item,$payment)
484
-     * @param EE_Line_Item $line_item
485
-     * @param EEI_Payment   $payment
486
-     * @return string
487
-     */
488
-    protected function _format_line_item_name(EE_Line_Item $line_item, EEI_Payment $payment)
489
-    {
490
-        return $this->_get_gateway_formatter()->formatLineItemName($line_item, $payment);
491
-    }
492
-
493
-    /**
494
-     * Gets the description to use for a line item when sending line items to the gateway
495
-     *
496
-     * @deprecated since 4.9.31 instead use $this->_get_gateway_formatter()->formatLineItemDesc($line_item, $payment))
497
-     * @param EE_Line_Item $line_item
498
-     * @param EEI_Payment   $payment
499
-     * @return string
500
-     */
501
-    protected function _format_line_item_desc(EE_Line_Item $line_item, EEI_Payment $payment)
502
-    {
503
-        return $this->_get_gateway_formatter()->formatLineItemDesc($line_item, $payment);
504
-    }
505
-
506
-    /**
507
-     * Gets the order description that should generlly be sent to gateways
508
-     *
509
-     * @deprecated since 4.9.31 instead use $this->_get_gateway_formatter()->formatOrderDescription($payment)
510
-     * @param EEI_Payment $payment
511
-     * @return type
512
-     */
513
-    protected function _format_order_description(EEI_Payment $payment)
514
-    {
515
-        return $this->_get_gateway_formatter()->formatOrderDescription($payment);
516
-    }
517
-
518
-
519
-    /**
520
-     * @return bool
521
-     */
522
-    public function isInSandboxMode(): bool
523
-    {
524
-        return $this->_debug_mode;
525
-    }
26
+	/**
27
+	 * a constant used as a possible value for $_currencies_supported to indicate
28
+	 * that ALL currencies are supported by this gateway
29
+	 */
30
+	const all_currencies_supported = 'all_currencies_supported';
31
+	/**
32
+	 * Where values are 3-letter currency codes
33
+	 *
34
+	 * @var array
35
+	 */
36
+	protected $_currencies_supported = array();
37
+	/**
38
+	 * Whether or not this gateway can support SENDING a refund request (ie, initiated by
39
+	 * admin in EE's wp-admin page)
40
+	 *
41
+	 * @var boolean
42
+	 */
43
+	protected $_supports_sending_refunds = false;
44
+
45
+	/**
46
+	 * Whether or not this gateway can support RECEIVING a refund request from the payment
47
+	 * provider (ie, initiated by admin on the payment prover's website who sends an IPN to EE)
48
+	 *
49
+	 * @var boolean
50
+	 */
51
+	protected $_supports_receiving_refunds = false;
52
+	/**
53
+	 * Model for querying for existing payments
54
+	 *
55
+	 * @var EEMI_Payment
56
+	 */
57
+	protected $_pay_model;
58
+
59
+	/**
60
+	 * Model used for adding to the payments log
61
+	 *
62
+	 * @var EEMI_Payment_Log
63
+	 */
64
+	protected $_pay_log;
65
+
66
+	/**
67
+	 * Used for formatting some input to gateways
68
+	 *
69
+	 * @var EEHI_Template
70
+	 */
71
+	protected $_template;
72
+
73
+	/**
74
+	 * Concrete class that implements EEHI_Money, used by most gateways
75
+	 *
76
+	 * @var EEHI_Money
77
+	 */
78
+	protected $_money;
79
+
80
+	/**
81
+	 * Concrete class that implements EEHI_Line_Item, used for manipulating the line item tree
82
+	 *
83
+	 * @var EEHI_Line_Item
84
+	 */
85
+	protected $_line_item;
86
+
87
+	/**
88
+	 * @var GatewayDataFormatterInterface
89
+	 */
90
+	protected $_gateway_data_formatter;
91
+
92
+	/**
93
+	 * @var FormatterInterface
94
+	 */
95
+	protected $_unsupported_character_remover;
96
+
97
+	/**
98
+	 * The ID of the payment method using this gateway
99
+	 *
100
+	 * @var int
101
+	 */
102
+	protected $_ID;
103
+
104
+	/**
105
+	 * @var $_debug_mode boolean whether to send requests to teh sandbox site or not
106
+	 */
107
+	protected $_debug_mode;
108
+	/**
109
+	 *
110
+	 * @var string $_name name to show for this payment method
111
+	 */
112
+	protected $_name;
113
+	/**
114
+	 *
115
+	 * @var string name to show fir this payment method to admin-type users
116
+	 */
117
+	protected $_admin_name;
118
+
119
+	/**
120
+	 * EE_Gateway constructor
121
+	 */
122
+	public function __construct()
123
+	{
124
+	}
125
+
126
+	/**
127
+	 * We don't want to serialize models as they often have circular structures
128
+	 * (eg a payment model has a reference to each payment model object; and most
129
+	 * payments have a transaction, most transactions have a payment method;
130
+	 * most payment methods have a payment method type; most payment method types
131
+	 * have a gateway. And if a gateway serializes its models, we start at the
132
+	 * beginning again)
133
+	 *
134
+	 * @return array
135
+	 */
136
+	public function __sleep()
137
+	{
138
+		$properties = get_object_vars($this);
139
+		unset($properties['_pay_model'], $properties['_pay_log']);
140
+		return array_keys($properties);
141
+	}
142
+
143
+	/**
144
+	 * Returns whether or not this gateway should support SENDING refunds
145
+	 * see $_supports_sending_refunds
146
+	 *
147
+	 * @return boolean
148
+	 */
149
+	public function supports_sending_refunds()
150
+	{
151
+		return $this->_supports_sending_refunds;
152
+	}
153
+
154
+	/**
155
+	 * Returns whether or not this gateway should support RECEIVING refunds
156
+	 * see $_supports_receiving_refunds
157
+	 *
158
+	 * @return boolean
159
+	 */
160
+	public function supports_receiving_refunds()
161
+	{
162
+		return $this->_supports_receiving_refunds;
163
+	}
164
+
165
+
166
+	/**
167
+	 * Tries to refund the payment specified, taking into account the extra
168
+	 * refund info. Note that if the gateway's _supports_sending_refunds is false,
169
+	 * this should just throw an exception.
170
+	 *
171
+	 * @param EE_Payment $payment
172
+	 * @param array      $refund_info
173
+	 * @return EE_Payment for the refund
174
+	 * @throws EE_Error
175
+	 */
176
+	public function do_direct_refund(EE_Payment $payment, $refund_info = null)
177
+	{
178
+		return null;
179
+	}
180
+
181
+
182
+	/**
183
+	 * Sets the payment method's settings so the gateway knows where to send the request
184
+	 * etc
185
+	 *
186
+	 * @param array $settings_array
187
+	 */
188
+	public function set_settings($settings_array)
189
+	{
190
+		foreach ($settings_array as $name => $value) {
191
+			$property_name = "_" . $name;
192
+			$this->{$property_name} = $value;
193
+		}
194
+	}
195
+
196
+	/**
197
+	 * See this class description
198
+	 *
199
+	 * @param EEMI_Payment $payment_model
200
+	 */
201
+	public function set_payment_model($payment_model)
202
+	{
203
+		$this->_pay_model = $payment_model;
204
+	}
205
+
206
+	/**
207
+	 * See this class description
208
+	 *
209
+	 * @param EEMI_Payment_Log $payment_log_model
210
+	 */
211
+	public function set_payment_log($payment_log_model)
212
+	{
213
+		$this->_pay_log = $payment_log_model;
214
+	}
215
+
216
+	/**
217
+	 * See this class description
218
+	 *
219
+	 * @param EEHI_Template $template_helper
220
+	 */
221
+	public function set_template_helper($template_helper)
222
+	{
223
+		$this->_template = $template_helper;
224
+	}
225
+
226
+	/**
227
+	 * See this class description
228
+	 *
229
+	 * @param EEHI_Line_Item $line_item_helper
230
+	 */
231
+	public function set_line_item_helper($line_item_helper)
232
+	{
233
+		$this->_line_item = $line_item_helper;
234
+	}
235
+
236
+	/**
237
+	 * See this class description
238
+	 *
239
+	 * @param EEHI_Money $money_helper
240
+	 */
241
+	public function set_money_helper($money_helper)
242
+	{
243
+		$this->_money = $money_helper;
244
+	}
245
+
246
+
247
+	/**
248
+	 * Sets the gateway data formatter helper
249
+	 *
250
+	 * @param GatewayDataFormatterInterface $gateway_data_formatter
251
+	 * @throws InvalidEntityException if it's not set properly
252
+	 */
253
+	public function set_gateway_data_formatter(GatewayDataFormatterInterface $gateway_data_formatter)
254
+	{
255
+		if (! $gateway_data_formatter instanceof GatewayDataFormatterInterface) {
256
+			throw new InvalidEntityException(
257
+				is_object($gateway_data_formatter)
258
+					? get_class($gateway_data_formatter)
259
+					: esc_html__('Not an object', 'event_espresso'),
260
+				'\\EventEspresso\\core\\services\\payment_methods\\gateways\\GatewayDataFormatterInterface'
261
+			);
262
+		}
263
+		$this->_gateway_data_formatter = $gateway_data_formatter;
264
+	}
265
+
266
+	/**
267
+	 * Gets the gateway data formatter
268
+	 *
269
+	 * @return GatewayDataFormatterInterface
270
+	 * @throws InvalidEntityException if it's not set properly
271
+	 */
272
+	protected function _get_gateway_formatter()
273
+	{
274
+		if (! $this->_gateway_data_formatter instanceof GatewayDataFormatterInterface) {
275
+			throw new InvalidEntityException(
276
+				is_object($this->_gateway_data_formatter)
277
+					? get_class($this->_gateway_data_formatter)
278
+					: esc_html__('Not an object', 'event_espresso'),
279
+				'\\EventEspresso\\core\\services\\payment_methods\\gateways\\GatewayDataFormatterInterface'
280
+			);
281
+		}
282
+		return $this->_gateway_data_formatter;
283
+	}
284
+
285
+
286
+	/**
287
+	 * Sets the helper which will remove unsupported characters for most gateways
288
+	 *
289
+	 * @param FormatterInterface $formatter
290
+	 * @return FormatterInterface
291
+	 * @throws InvalidEntityException
292
+	 */
293
+	public function set_unsupported_character_remover(FormatterInterface $formatter)
294
+	{
295
+		if (! $formatter instanceof FormatterInterface) {
296
+			throw new InvalidEntityException(
297
+				is_object($formatter)
298
+					? get_class($formatter)
299
+					: esc_html__('Not an object', 'event_espresso'),
300
+				'\\EventEspresso\\core\\services\\formatters\\FormatterInterface'
301
+			);
302
+		}
303
+		$this->_unsupported_character_remover = $formatter;
304
+	}
305
+
306
+	/**
307
+	 * Gets the helper which removes characters which gateways might not support, like emojis etc.
308
+	 *
309
+	 * @return FormatterInterface
310
+	 * @throws InvalidEntityException
311
+	 */
312
+	protected function _get_unsupported_character_remover()
313
+	{
314
+		if (! $this->_unsupported_character_remover instanceof FormatterInterface) {
315
+			throw new InvalidEntityException(
316
+				is_object($this->_unsupported_character_remover)
317
+					? get_class($this->_unsupported_character_remover)
318
+					: esc_html__('Not an object', 'event_espresso'),
319
+				'\\EventEspresso\\core\\services\\formatters\\FormatterInterface'
320
+			);
321
+		}
322
+		return $this->_unsupported_character_remover;
323
+	}
324
+
325
+
326
+	/**
327
+	 * @param $message
328
+	 * @param $payment
329
+	 */
330
+	public function log($message, $object_logged)
331
+	{
332
+		if ($object_logged instanceof EEI_Payment) {
333
+			$type = 'Payment';
334
+			$id = $object_logged->ID();
335
+		} elseif ($object_logged instanceof EEI_Transaction) {
336
+			$type = 'Transaction';
337
+			$id = $object_logged->ID();
338
+		} else {
339
+			$type = 'Payment_Method';
340
+			$id = $this->_ID;
341
+		}
342
+		// only log if we're going to store it for longer than the minimum time
343
+		$reg_config = LoaderFactory::getLoader()->load('EE_Registration_Config');
344
+		if ($reg_config->gateway_log_lifespan !== '1 second') {
345
+			$this->_pay_log->gateway_log($message, $id, $type);
346
+		}
347
+	}
348
+
349
+	/**
350
+	 * Formats the amount so it can generally be sent to gateways
351
+	 *
352
+	 * @param float $amount
353
+	 * @return string
354
+	 * @deprecated since 4.9.31 insetad use
355
+	 *             EventEspresso\core\services\payment_methods\gateways\GatewayDataFormatter::format_currency()
356
+	 */
357
+	public function format_currency($amount)
358
+	{
359
+		return $this->_get_gateway_formatter()->formatCurrency($amount);
360
+	}
361
+
362
+	/**
363
+	 * Returns either an array of all the currency codes supported,
364
+	 * or a string indicating they're all supported (EE_gateway::all_currencies_supported)
365
+	 *
366
+	 * @return mixed array or string
367
+	 */
368
+	public function currencies_supported()
369
+	{
370
+		return $this->_currencies_supported;
371
+	}
372
+
373
+	/**
374
+	 * Returns what a simple summing of items and taxes for this transaction. This
375
+	 * can be used to determine if some more complex line items, like promotions,
376
+	 * surcharges, or cancellations occurred (in which case we might want to forget
377
+	 * about creating an itemized list of purchases and instead only send the total due)
378
+	 *
379
+	 * @param EE_Transaction $transaction
380
+	 * @return float
381
+	 */
382
+	protected function _sum_items_and_taxes(EE_Transaction $transaction)
383
+	{
384
+		$total_line_item = $transaction->total_line_item();
385
+		$total = 0;
386
+		foreach ($total_line_item->get_items() as $item_line_item) {
387
+			$total += max($item_line_item->total(), 0);
388
+		}
389
+		foreach ($total_line_item->tax_descendants() as $tax_line_item) {
390
+			$total += max($tax_line_item->total(), 0);
391
+		}
392
+		return $total;
393
+	}
394
+
395
+	/**
396
+	 * Determines whether or not we can easily itemize the transaction using only
397
+	 * items and taxes (ie, no promotions or surcharges or cancellations needed)
398
+	 *
399
+	 * @param EEI_Payment $payment
400
+	 * @return boolean
401
+	 */
402
+	protected function _can_easily_itemize_transaction_for(EEI_Payment $payment)
403
+	{
404
+		return $this->_money->compare_floats(
405
+			$this->_sum_items_and_taxes($payment->transaction()),
406
+			$payment->transaction()->total()
407
+		)
408
+			   && $this->_money->compare_floats(
409
+				   $payment->amount(),
410
+				   $payment->transaction()->total()
411
+			   );
412
+	}
413
+
414
+	/**
415
+	 * Handles updating the transaction and any other related data based on the payment.
416
+	 * You may be tempted to do this as part of do_direct_payment or handle_payment_update,
417
+	 * but doing so on those functions might be too early. It's possible that the changes
418
+	 * you make to teh transaction or registration or line items may just get overwritten
419
+	 * at that point. Instead, you should store any info you need on the payment during those
420
+	 * functions, and use that information at this step, which client code will decide
421
+	 * for you when it should be called.
422
+	 *
423
+	 * @param EE_Payment $payment
424
+	 * @return void
425
+	 */
426
+	public function update_txn_based_on_payment($payment)
427
+	{
428
+		// maybe update the transaction or line items or registrations
429
+		// but most gateways don't need to do this, because they only update the payment
430
+	}
431
+
432
+	/**
433
+	 * Gets the first event for this payment (it's possible that it could be for multiple)
434
+	 *
435
+	 * @param EEI_Payment $payment
436
+	 * @return EEI_Event|null
437
+	 * @deprecated since 4.9.31 instead use EEI_Payment::get_first_event()
438
+	 */
439
+	protected function _get_first_event_for_payment(EEI_Payment $payment)
440
+	{
441
+		return $payment->get_first_event();
442
+	}
443
+
444
+	/**
445
+	 * Gets the name of the first event for which is being paid
446
+	 *
447
+	 * @param EEI_Payment $payment
448
+	 * @return string
449
+	 * @deprecated since 4.9.31 instead use EEI_Payment::get_first_event_name()
450
+	 */
451
+	protected function _get_first_event_name_for_payment(EEI_Payment $payment)
452
+	{
453
+		return $payment->get_first_event_name();
454
+	}
455
+
456
+	/**
457
+	 * Gets the text to use for a gateway's line item name when this is a partial payment
458
+	 *
459
+	 * @deprecated since 4.9.31 instead use $this->_get_gateway_formatter()->formatPartialPaymentLineItemName($payment)
460
+	 * @param EE_Payment $payment
461
+	 * @return string
462
+	 */
463
+	protected function _format_partial_payment_line_item_name(EEI_Payment $payment)
464
+	{
465
+		return $this->_get_gateway_formatter()->formatPartialPaymentLineItemName($payment);
466
+	}
467
+
468
+	/**
469
+	 * Gets the text to use for a gateway's line item description when this is a partial payment
470
+	 *
471
+	 * @deprecated since 4.9.31 instead use $this->_get_gateway_formatter()->formatPartialPaymentLineItemDesc()
472
+	 * @param EEI_Payment $payment
473
+	 * @return string
474
+	 */
475
+	protected function _format_partial_payment_line_item_desc(EEI_Payment $payment)
476
+	{
477
+		return $this->_get_gateway_formatter()->formatPartialPaymentLineItemDesc($payment);
478
+	}
479
+
480
+	/**
481
+	 * Gets the name to use for a line item when sending line items to the gateway
482
+	 *
483
+	 * @deprecated since 4.9.31 instead use $this->_get_gateway_formatter()->formatLineItemName($line_item,$payment)
484
+	 * @param EE_Line_Item $line_item
485
+	 * @param EEI_Payment   $payment
486
+	 * @return string
487
+	 */
488
+	protected function _format_line_item_name(EE_Line_Item $line_item, EEI_Payment $payment)
489
+	{
490
+		return $this->_get_gateway_formatter()->formatLineItemName($line_item, $payment);
491
+	}
492
+
493
+	/**
494
+	 * Gets the description to use for a line item when sending line items to the gateway
495
+	 *
496
+	 * @deprecated since 4.9.31 instead use $this->_get_gateway_formatter()->formatLineItemDesc($line_item, $payment))
497
+	 * @param EE_Line_Item $line_item
498
+	 * @param EEI_Payment   $payment
499
+	 * @return string
500
+	 */
501
+	protected function _format_line_item_desc(EE_Line_Item $line_item, EEI_Payment $payment)
502
+	{
503
+		return $this->_get_gateway_formatter()->formatLineItemDesc($line_item, $payment);
504
+	}
505
+
506
+	/**
507
+	 * Gets the order description that should generlly be sent to gateways
508
+	 *
509
+	 * @deprecated since 4.9.31 instead use $this->_get_gateway_formatter()->formatOrderDescription($payment)
510
+	 * @param EEI_Payment $payment
511
+	 * @return type
512
+	 */
513
+	protected function _format_order_description(EEI_Payment $payment)
514
+	{
515
+		return $this->_get_gateway_formatter()->formatOrderDescription($payment);
516
+	}
517
+
518
+
519
+	/**
520
+	 * @return bool
521
+	 */
522
+	public function isInSandboxMode(): bool
523
+	{
524
+		return $this->_debug_mode;
525
+	}
526 526
 }
Please login to merge, or discard this patch.
core/libraries/payment_methods/EE_Offsite_Gateway.lib.php 1 patch
Indentation   +102 added lines, -102 removed lines patch added patch discarded remove patch
@@ -15,117 +15,117 @@
 block discarded – undo
15 15
 abstract class EE_Offsite_Gateway extends EE_Gateway
16 16
 {
17 17
 
18
-    /**
19
-     * whether or not the gateway uses an IPN
20
-     * that is sent in a separate request than the returning registrant.
21
-     * if false, then we need to process the payment results manually
22
-     * as soon as the registrant returns from the off-site gateway
23
-     *
24
-     * @type bool
25
-     */
26
-    protected $_uses_separate_IPN_request = false;
18
+	/**
19
+	 * whether or not the gateway uses an IPN
20
+	 * that is sent in a separate request than the returning registrant.
21
+	 * if false, then we need to process the payment results manually
22
+	 * as soon as the registrant returns from the off-site gateway
23
+	 *
24
+	 * @type bool
25
+	 */
26
+	protected $_uses_separate_IPN_request = false;
27 27
 
28 28
 
29
-    /**
30
-     * EE_Offsite_Gateway constructor
31
-     */
32
-    public function __construct()
33
-    {
34
-        $this->_supports_receiving_refunds = true;
35
-        parent::__construct();
36
-    }
29
+	/**
30
+	 * EE_Offsite_Gateway constructor
31
+	 */
32
+	public function __construct()
33
+	{
34
+		$this->_supports_receiving_refunds = true;
35
+		parent::__construct();
36
+	}
37 37
 
38 38
 
39
-    /**
40
-     * Adds information into the payment object's redirect_url and redirect_args so
41
-     * client code can use that payment to know where (and with what information)
42
-     * to redirect the user to in order to make the payment on the offsite gateway's website.
43
-     * Saving the payment from within this method is unnecessary,
44
-     * as it is the responsibility of client code to save it.
45
-     *
46
-     * @param EE_Payment $payment    to process
47
-     * @param array      $billing_info
48
-     * @param string     $return_url URL to send the user to after a successful payment on the payment provider's
49
-     *                               website
50
-     * @param string     $notify_url URL to send the instant payment notification
51
-     * @param string     $cancel_url URL to send the user to after a cancelled payment attempt on teh payment
52
-     *                               provider's website
53
-     * @return EE_Payment
54
-     */
55
-    abstract public function set_redirection_info(
56
-        $payment,
57
-        $billing_info = array(),
58
-        $return_url = null,
59
-        $notify_url = null,
60
-        $cancel_url = null
61
-    );
39
+	/**
40
+	 * Adds information into the payment object's redirect_url and redirect_args so
41
+	 * client code can use that payment to know where (and with what information)
42
+	 * to redirect the user to in order to make the payment on the offsite gateway's website.
43
+	 * Saving the payment from within this method is unnecessary,
44
+	 * as it is the responsibility of client code to save it.
45
+	 *
46
+	 * @param EE_Payment $payment    to process
47
+	 * @param array      $billing_info
48
+	 * @param string     $return_url URL to send the user to after a successful payment on the payment provider's
49
+	 *                               website
50
+	 * @param string     $notify_url URL to send the instant payment notification
51
+	 * @param string     $cancel_url URL to send the user to after a cancelled payment attempt on teh payment
52
+	 *                               provider's website
53
+	 * @return EE_Payment
54
+	 */
55
+	abstract public function set_redirection_info(
56
+		$payment,
57
+		$billing_info = array(),
58
+		$return_url = null,
59
+		$notify_url = null,
60
+		$cancel_url = null
61
+	);
62 62
 
63 63
 
64
-    /**
65
-     * Often used for IPNs. But applies the info in $update_info to the payment.
66
-     * What is $update_info? Often the contents of $_REQUEST, but not necessarily. Whatever
67
-     * the payment method passes in. Saving the payment from within this method is unnecessary,
68
-     * as it is the responsibility of client code to save it.
69
-     *
70
-     * @param array           $update_info of whatever
71
-     * @param EEI_Transaction $transaction
72
-     * @return EEI_Payment updated
73
-     */
74
-    abstract public function handle_payment_update($update_info, $transaction);
64
+	/**
65
+	 * Often used for IPNs. But applies the info in $update_info to the payment.
66
+	 * What is $update_info? Often the contents of $_REQUEST, but not necessarily. Whatever
67
+	 * the payment method passes in. Saving the payment from within this method is unnecessary,
68
+	 * as it is the responsibility of client code to save it.
69
+	 *
70
+	 * @param array           $update_info of whatever
71
+	 * @param EEI_Transaction $transaction
72
+	 * @return EEI_Payment updated
73
+	 */
74
+	abstract public function handle_payment_update($update_info, $transaction);
75 75
 
76 76
 
77
-    /**
78
-     * uses_separate_IPN_request
79
-     *
80
-     * return true or false for whether or not the gateway uses an IPN
81
-     * that is sent in a separate request than the returning registrant.
82
-     * if false, then we need to process the payment results manually
83
-     * as soon as the registrant returns from the off-site gateway
84
-     *
85
-     * @deprecated since version 4.8.39.rc.001 please use handle_IPN_in_this_request() instead
86
-     *
87
-     * @return bool
88
-     */
89
-    public function uses_separate_IPN_request()
90
-    {
91
-        return $this->_uses_separate_IPN_request;
92
-    }
77
+	/**
78
+	 * uses_separate_IPN_request
79
+	 *
80
+	 * return true or false for whether or not the gateway uses an IPN
81
+	 * that is sent in a separate request than the returning registrant.
82
+	 * if false, then we need to process the payment results manually
83
+	 * as soon as the registrant returns from the off-site gateway
84
+	 *
85
+	 * @deprecated since version 4.8.39.rc.001 please use handle_IPN_in_this_request() instead
86
+	 *
87
+	 * @return bool
88
+	 */
89
+	public function uses_separate_IPN_request()
90
+	{
91
+		return $this->_uses_separate_IPN_request;
92
+	}
93 93
 
94 94
 
95
-    /**
96
-     * set_uses_separate_IPN_request
97
-     *
98
-     * @access protected
99
-     * @param boolean $uses_separate_IPN_request
100
-     */
101
-    protected function set_uses_separate_IPN_request($uses_separate_IPN_request)
102
-    {
103
-        $this->_uses_separate_IPN_request = filter_var($uses_separate_IPN_request, FILTER_VALIDATE_BOOLEAN);
104
-    }
95
+	/**
96
+	 * set_uses_separate_IPN_request
97
+	 *
98
+	 * @access protected
99
+	 * @param boolean $uses_separate_IPN_request
100
+	 */
101
+	protected function set_uses_separate_IPN_request($uses_separate_IPN_request)
102
+	{
103
+		$this->_uses_separate_IPN_request = filter_var($uses_separate_IPN_request, FILTER_VALIDATE_BOOLEAN);
104
+	}
105 105
 
106
-    /**
107
-     * Allows gateway to dynamically decide whether or not to handle a payment update
108
-     * by overriding this method. By default, if this is a "true" IPN (meaning
109
-     * it's a separate request from when the user returns from the offsite gateway)
110
-     * and this gateway class is setup to handle IPNs in separate "true" IPNs, then
111
-     * this will return true, otherwise it will return false.
112
-     * If however, this is a request when the user is returning
113
-     * from an offsite gateway, and this gateway class is setup to process the payment
114
-     * data when the user returns, then this will return true.
115
-     *
116
-     * @param array   $request_data
117
-     * @param boolean $separate_IPN_request
118
-     * @return boolean
119
-     */
120
-    public function handle_IPN_in_this_request($request_data, $separate_IPN_request)
121
-    {
122
-        if ($separate_IPN_request) {
123
-            // payment data being sent in a request separate from the user
124
-            // it is this other request that will update the TXN and payment info
125
-            return $this->_uses_separate_IPN_request;
126
-        } else {
127
-            // it's a request where the user returned from an offsite gateway WITH the payment data
128
-            return ! $this->_uses_separate_IPN_request;
129
-        }
130
-    }
106
+	/**
107
+	 * Allows gateway to dynamically decide whether or not to handle a payment update
108
+	 * by overriding this method. By default, if this is a "true" IPN (meaning
109
+	 * it's a separate request from when the user returns from the offsite gateway)
110
+	 * and this gateway class is setup to handle IPNs in separate "true" IPNs, then
111
+	 * this will return true, otherwise it will return false.
112
+	 * If however, this is a request when the user is returning
113
+	 * from an offsite gateway, and this gateway class is setup to process the payment
114
+	 * data when the user returns, then this will return true.
115
+	 *
116
+	 * @param array   $request_data
117
+	 * @param boolean $separate_IPN_request
118
+	 * @return boolean
119
+	 */
120
+	public function handle_IPN_in_this_request($request_data, $separate_IPN_request)
121
+	{
122
+		if ($separate_IPN_request) {
123
+			// payment data being sent in a request separate from the user
124
+			// it is this other request that will update the TXN and payment info
125
+			return $this->_uses_separate_IPN_request;
126
+		} else {
127
+			// it's a request where the user returned from an offsite gateway WITH the payment data
128
+			return ! $this->_uses_separate_IPN_request;
129
+		}
130
+	}
131 131
 }
Please login to merge, or discard this patch.
payment_methods/Paypal_Express/EEG_Paypal_Express.gateway.php 2 patches
Indentation   +544 added lines, -544 removed lines patch added patch discarded remove patch
@@ -13,548 +13,548 @@
 block discarded – undo
13 13
 class EEG_Paypal_Express extends EE_Offsite_Gateway
14 14
 {
15 15
 
16
-    /**
17
-     * Merchant API Username.
18
-     *
19
-     * @var string
20
-     */
21
-    protected $_api_username;
22
-
23
-    /**
24
-     * Merchant API Password.
25
-     *
26
-     * @var string
27
-     */
28
-    protected $_api_password;
29
-
30
-    /**
31
-     * API Signature.
32
-     *
33
-     * @var string
34
-     */
35
-    protected $_api_signature;
36
-
37
-    /**
38
-     * Request Shipping address on PP checkout page.
39
-     *
40
-     * @var string
41
-     */
42
-    protected $_request_shipping_addr;
43
-
44
-    /**
45
-     * Business/personal logo.
46
-     *
47
-     * @var string
48
-     */
49
-    protected $_image_url = '';
50
-
51
-    /**
52
-     * gateway URL variable
53
-     *
54
-     * @var string
55
-     */
56
-    protected $_base_gateway_url = '';
57
-
58
-
59
-    /**
60
-     * number of decimal places to round numbers to when performing calculations
61
-     *
62
-     * @var integer
63
-     */
64
-    protected $decimal_precision = 6;
65
-
66
-    /**
67
-     * @var ItemizedOrder
68
-     * @since $VID:$
69
-     */
70
-    protected $itemized_order;
71
-
72
-    /**
73
-     * @var TokenRequest
74
-     * @since $VID:$
75
-     */
76
-    protected $token_request;
77
-
78
-
79
-    /**
80
-     * EEG_Paypal_Express constructor.
81
-     */
82
-    public function __construct()
83
-    {
84
-        require_once 'polyfills.php';
85
-        $this->_currencies_supported = [
86
-            'USD',
87
-            'AUD',
88
-            'BRL',
89
-            'CAD',
90
-            'CZK',
91
-            'DKK',
92
-            'EUR',
93
-            'HKD',
94
-            'HUF',
95
-            'ILS',
96
-            'JPY',
97
-            'MYR',
98
-            'MXN',
99
-            'NOK',
100
-            'NZD',
101
-            'PHP',
102
-            'PLN',
103
-            'GBP',
104
-            'RUB',
105
-            'SGD',
106
-            'SEK',
107
-            'CHF',
108
-            'TWD',
109
-            'THB',
110
-            'TRY',
111
-            'INR',
112
-        ];
113
-        parent::__construct();
114
-        $this->decimal_precision = EE_Registry::instance()->CFG->currency->dec_plc;
115
-    }
116
-
117
-
118
-    /**
119
-     * Sets the gateway URL variable based on whether debug mode is enabled or not.
120
-     *
121
-     * @param array $settings_array
122
-     */
123
-    public function set_settings($settings_array)
124
-    {
125
-        parent::set_settings($settings_array);
126
-        // Redirect URL.
127
-        $this->_base_gateway_url = $this->_debug_mode
128
-            ? 'https://api-3t.sandbox.paypal.com/nvp'
129
-            : 'https://api-3t.paypal.com/nvp';
130
-    }
131
-
132
-
133
-    /**
134
-     * @param EEI_Payment $payment
135
-     * @param array       $billing_info
136
-     * @param string      $return_url
137
-     * @param string      $notify_url
138
-     * @param string      $cancel_url
139
-     * @return EE_Payment|EEI_Payment
140
-     * @throws EE_Error
141
-     * @throws ReflectionException
142
-     * @throws Exception
143
-     */
144
-    public function set_redirection_info(
145
-        $payment,
146
-        $billing_info = [],
147
-        $return_url = null,
148
-        $notify_url = null,
149
-        $cancel_url = null
150
-    ) {
151
-        if (! $this->validatePayment($payment)) {
152
-            return $payment;
153
-        }
154
-        if (! $this->validateTransaction($payment)) {
155
-            return $payment;
156
-        }
157
-        $this->token_request = new TokenRequest($this->_get_gateway_formatter());
158
-        $token_request_details = apply_filters(
159
-            'FHEE__EEG_Paypal_Express__set_redirection_info__arguments',
160
-            $this->token_request->generateDetails(
161
-                $payment,
162
-                $this->getOrderItems($payment),
163
-                $return_url ?? '',
164
-                $cancel_url ?? '',
165
-                $this->_image_url ?? '',
166
-                $this->_request_shipping_addr ?? ''
167
-            ),
168
-            $this
169
-        );
170
-        // Request PayPal token.
171
-        $token_request_response = $this->_ppExpress_request($token_request_details, 'Payment Token', $payment);
172
-        $token_request_status   = $this->_ppExpress_check_response($token_request_response);
173
-        $this->token_request->processResponse($payment, $token_request_status, $this->isInSandboxMode());
174
-
175
-        return $payment;
176
-    }
177
-
178
-
179
-    /**
180
-     * @param array           $update_info {
181
-     * @type string           $gateway_txn_id
182
-     * @type string           $status      an EEMI_Payment status
183
-     *                                     }
184
-     * @param EEI_Transaction $transaction
185
-     * @return EEI_Payment
186
-     * @throws Exception
187
-     */
188
-    public function handle_payment_update($update_info, $transaction): EEI_Payment
189
-    {
190
-        // if the supplied transaction is valid, we'll retrieve the actual payment object from it
191
-        // but we'll use a temporary payment for now that we can return with errors if things go wrong
192
-        $payment = EE_Payment::new_instance();
193
-        if (! $this->validateTransaction($payment, $transaction)) {
194
-            return $payment;
195
-        }
196
-        $payment = $transaction->last_payment();
197
-        if (! $this->validatePayment($payment)) {
198
-            return $payment;
199
-        }
200
-        // payment appears to be good... so far
201
-        $this->log(['Return from Authorization' => $update_info], $payment);
202
-        $payment_token = $this->getPaymentToken($payment);
203
-        $customer_details = $this->requestCustomerDetails($payment, $payment_token);
204
-        // We got the PayerID so now we can Complete the transaction.
205
-        $this->processPayment($payment, $payment_token, $customer_details);
206
-
207
-        return $payment;
208
-    }
209
-
210
-
211
-    /**
212
-     * @throws Exception
213
-     */
214
-    private function getOrderItems(EE_Payment $payment, array $request_response_args = []): array
215
-    {
216
-        $this->itemized_order = new ItemizedOrder($this->_get_gateway_formatter());
217
-        try {
218
-            $itemized_order = $this->itemized_order->getExistingItemizedOrder($request_response_args);
219
-        } catch (Exception $exception) {
220
-            if (WP_DEBUG) {
221
-                throw $exception;
222
-            }
223
-            // Reset the list and log an error, maybe allow to try and generate a new list (below).
224
-            $itemized_order = [];
225
-            $this->log(
226
-                [
227
-                    esc_html__(
228
-                        'Could not generate a proper item list with:',
229
-                        'event_espresso'
230
-                    ) => $request_response_args,
231
-                ],
232
-                $payment
233
-            );
234
-        }
235
-        if (empty($itemized_order)) {
236
-            $itemized_order = $this->itemized_order->generateItemizedOrder($payment);
237
-        }
238
-        return $itemized_order;
239
-    }
240
-
241
-
242
-    /**
243
-     *  Make the Express checkout request.
244
-     *
245
-     * @param array       $request_params
246
-     * @param string      $request_text
247
-     * @param EEI_Payment $payment
248
-     * @return array|WP_Error
249
-     */
250
-    public function _ppExpress_request(array $request_params, string $request_text, EEI_Payment $payment)
251
-    {
252
-        $request_dtls = [
253
-            'VERSION'      => '204.0',
254
-            'USER'         => $this->_api_username,
255
-            'PWD'          => $this->_api_password,
256
-            'SIGNATURE'    => $this->_api_signature,
257
-            // EE will blow up if you change this
258
-            'BUTTONSOURCE' => 'EventEspresso_SP',
259
-        ];
260
-        $dtls         = array_merge($request_dtls, $request_params);
261
-        $this->_log_clean_request($dtls, $payment, $request_text . ' Request');
262
-        // Request Customer Details.
263
-        $request_response = wp_remote_post(
264
-            $this->_base_gateway_url,
265
-            [
266
-                'method'      => 'POST',
267
-                'timeout'     => 45,
268
-                'httpversion' => '1.1',
269
-                'cookies'     => [],
270
-                'headers'     => [],
271
-                'body'        => http_build_query($dtls),
272
-            ]
273
-        );
274
-        // Log the response.
275
-        $this->log([$request_text . ' Response' => $request_response], $payment);
276
-        return $request_response;
277
-    }
278
-
279
-
280
-    /**
281
-     *  Check the response status.
282
-     *
283
-     * @param mixed $request_response
284
-     * @return array
285
-     */
286
-    public function _ppExpress_check_response($request_response): array
287
-    {
288
-        if (is_wp_error($request_response) || empty($request_response['body'])) {
289
-            // If we got here then there was an error in this request.
290
-            return ['status' => false, 'args' => $request_response];
291
-        }
292
-        $response_args = [];
293
-        parse_str(urldecode($request_response['body']), $response_args);
294
-        if (! isset($response_args['ACK'])) {
295
-            return ['status' => false, 'args' => $request_response];
296
-        }
297
-        if (
298
-            (
299
-                isset($response_args['PAYERID'])
300
-                || isset($response_args['TOKEN'])
301
-                || isset($response_args['PAYMENTINFO_0_TRANSACTIONID'])
302
-                || (isset($response_args['PAYMENTSTATUS']) && $response_args['PAYMENTSTATUS'] === 'Completed')
303
-            )
304
-            && in_array($response_args['ACK'], ['Success', 'SuccessWithWarning'], true)
305
-        ) {
306
-            // Response status OK, return response parameters for further processing.
307
-            return ['status' => true, 'args' => $response_args];
308
-        }
309
-        $errors = $this->_get_errors($response_args);
310
-        return ['status' => false, 'args' => $errors];
311
-    }
312
-
313
-
314
-    /**
315
-     *  Log a "Cleared" request.
316
-     *
317
-     * @param array       $request
318
-     * @param EEI_Payment $payment
319
-     * @param string      $info
320
-     * @return void
321
-     */
322
-    private function _log_clean_request(array $request, EEI_Payment $payment, string $info)
323
-    {
324
-        $cleaned_request_data = $request;
325
-        unset($cleaned_request_data['PWD'], $cleaned_request_data['USER'], $cleaned_request_data['SIGNATURE']);
326
-        $this->log([$info => $cleaned_request_data], $payment);
327
-    }
328
-
329
-
330
-    /**
331
-     *  Get error from the response data.
332
-     *
333
-     * @param array $data_array
334
-     * @return array
335
-     */
336
-    private function _get_errors(array $data_array): array
337
-    {
338
-        $errors = [];
339
-        $n      = 0;
340
-        while (isset($data_array[ "L_ERRORCODE{$n}" ])) {
341
-            $l_error_code    = $data_array[ "L_ERRORCODE{$n}" ] ?? '';
342
-            $l_severity_code = $data_array[ "L_SEVERITYCODE{$n}" ] ?? '';
343
-            $l_short_message = $data_array[ "L_SHORTMESSAGE{$n}" ] ?? '';
344
-            $l_long_message  = $data_array[ "L_LONGMESSAGE{$n}" ] ?? '';
345
-            if ($n === 0) {
346
-                $errors = [
347
-                    'L_ERRORCODE'    => $l_error_code,
348
-                    'L_SHORTMESSAGE' => $l_short_message,
349
-                    'L_LONGMESSAGE'  => $l_long_message,
350
-                    'L_SEVERITYCODE' => $l_severity_code,
351
-                ];
352
-            } else {
353
-                $errors['L_ERRORCODE']    .= ', ' . $l_error_code;
354
-                $errors['L_SHORTMESSAGE'] .= ', ' . $l_short_message;
355
-                $errors['L_LONGMESSAGE']  .= ', ' . $l_long_message;
356
-                $errors['L_SEVERITYCODE'] .= ', ' . $l_severity_code;
357
-            }
358
-            $n++;
359
-        }
360
-        return $errors;
361
-    }
362
-
363
-
364
-    /**
365
-     * @param EE_Payment $payment
366
-     * @return mixed|null
367
-     * @throws EE_Error
368
-     * @since   $VID:$
369
-     */
370
-    private function getPaymentToken(EE_Payment $payment)
371
-    {
372
-        $payment_details = $payment->details();
373
-        // Check if we still have the token.
374
-        if (! isset($payment_details['TOKEN']) || empty($payment_details['TOKEN'])) {
375
-            $payment->set_status($this->_pay_model->failed_status());
376
-            return null;
377
-        }
378
-        return $payment_details['TOKEN'];
379
-    }
380
-
381
-    /**
382
-     * @param EE_Payment $payment
383
-     * @param array      $checkout_response
384
-     * @param array      $customer_data
385
-     * @throws EE_Error
386
-     * @throws ReflectionException
387
-     * @since   $VID:$
388
-     */
389
-    private function paymentApproved(EE_Payment $payment, array $checkout_response, array $customer_data)
390
-    {
391
-        $primary_registrant = $payment->transaction()->primary_registration();
392
-        $primary_registration_code = $primary_registrant instanceof EE_Registration ?
393
-            $primary_registrant->reg_code()
394
-            : '';
395
-        $payment->set_extra_accntng($primary_registration_code);
396
-        $payment_amount = $checkout_response['PAYMENTINFO_0_AMT'] ?? 0;
397
-        $payment->set_amount((float) $payment_amount);
398
-        $payment->set_txn_id_chq_nmbr($checkout_response['PAYMENTINFO_0_TRANSACTIONID'] ?? null);
399
-        $payment->set_details($customer_data);
400
-        $payment->set_gateway_response($checkout_response['PAYMENTINFO_0_ACK'] ?? '');
401
-        $payment->set_status($this->_pay_model->approved_status());
402
-    }
403
-
404
-
405
-    /**
406
-     * @param EE_Payment $payment
407
-     * @param array      $checkout_response
408
-     * @throws EE_Error
409
-     * @since   $VID:$
410
-     */
411
-    private function paymentDeclined(EE_Payment $payment, array $checkout_response)
412
-    {
413
-        $gateway_response = isset($checkout_response['L_ERRORCODE'])
414
-            ? $checkout_response['L_ERRORCODE'] . '; ' . $checkout_response['L_SHORTMESSAGE']
415
-            : esc_html__('Error occurred while trying to Capture the funds.', 'event_espresso');
416
-
417
-        $payment->set_gateway_response($gateway_response);
418
-        $payment->set_details($checkout_response);
419
-        $payment->set_status($this->_pay_model->declined_status());
420
-    }
421
-
422
-
423
-    /**
424
-     * @param EE_Payment $payment
425
-     * @param array $customer_data
426
-     * @throws EE_Error
427
-     * @since   $VID:$
428
-     */
429
-    private function paymentFailed(EE_Payment $payment, array $customer_data)
430
-    {
431
-        $gateway_response = isset($customer_data['L_ERRORCODE'])
432
-            ? $customer_data['L_ERRORCODE'] . '; ' . $customer_data['L_SHORTMESSAGE']
433
-            : esc_html__('Error occurred while trying to get payment Details from PayPal.', 'event_espresso');
434
-
435
-        $payment->set_gateway_response($gateway_response);
436
-        $payment->set_details($customer_data);
437
-        $payment->set_status($this->_pay_model->failed_status());
438
-    }
439
-
440
-
441
-    /**
442
-     * @param EE_Payment $payment
443
-     * @param string     $payment_token
444
-     * @param array      $customer_details
445
-     * @return void
446
-     * @throws EE_Error
447
-     * @throws ReflectionException
448
-     * @throws Exception
449
-     * @since   $VID:$
450
-     */
451
-    private function processPayment(EE_Payment $payment, string $payment_token, array $customer_details)
452
-    {
453
-        $checkout_request_dtls = [
454
-            'METHOD'                         => 'DoExpressCheckoutPayment',
455
-            'PAYERID'                        => $customer_details['PAYERID'],
456
-            'TOKEN'                          => $payment_token,
457
-            'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale',
458
-            'PAYMENTREQUEST_0_AMT'           => $payment->amount(),
459
-            'PAYMENTREQUEST_0_CURRENCYCODE'  => $payment->currency_code(),
460
-        ];
461
-        // Include itemized list.
462
-        $itemized_list         = $this->getOrderItems($payment, $customer_details);
463
-        $checkout_request_dtls = array_merge($checkout_request_dtls, $itemized_list);
464
-        // Payment Checkout/Capture.
465
-        $checkout_request_response = $this->_ppExpress_request(
466
-            $checkout_request_dtls,
467
-            'Do Payment',
468
-            $payment
469
-        );
470
-        $checkout_request_status   = $this->_ppExpress_check_response($checkout_request_response);
471
-        $checkout_response         =
472
-            isset($checkout_request_status['args']) && is_array($checkout_request_status['args'])
473
-                ? $checkout_request_status['args']
474
-                : [];
475
-        if ($checkout_request_status['status']) {
476
-            // All is well, payment approved.
477
-            $this->paymentApproved($payment, $checkout_response, $customer_details);
478
-        } else {
479
-            $this->paymentDeclined($payment, $checkout_response);
480
-        }
481
-    }
482
-
483
-
484
-    /**
485
-     * @param EE_Payment $payment
486
-     * @param string $payment_token
487
-     * @return array
488
-     * @throws EE_Error
489
-     * @since   $VID:$
490
-     */
491
-    private function requestCustomerDetails(EE_Payment $payment, string $payment_token): array
492
-    {
493
-        $customer_details_request_dtls = [
494
-            'METHOD' => 'GetExpressCheckoutDetails',
495
-            'TOKEN'  => $payment_token,
496
-        ];
497
-        // Request Customer Details.
498
-        $customer_details_request_response = $this->_ppExpress_request(
499
-            $customer_details_request_dtls,
500
-            'Customer Details',
501
-            $payment
502
-        );
503
-        $customer_details_rstatus          = $this->_ppExpress_check_response($customer_details_request_response);
504
-        $customer_details = isset($customer_details_rstatus['args']) && is_array($customer_details_rstatus['args'])
505
-            ? $customer_details_rstatus['args']
506
-            : [];
507
-        if (! $customer_details_rstatus['status']) {
508
-            $this->paymentFailed($payment, $customer_details);
509
-        }
510
-        return $customer_details;
511
-    }
512
-
513
-
514
-
515
-    /**
516
-     * @param EE_Payment|null $payment
517
-     * @return bool
518
-     * @throws EE_Error
519
-     * @since   $VID:$
520
-     */
521
-    private function validatePayment(?EE_Payment $payment): bool
522
-    {
523
-        if (! $payment instanceof EE_Payment) {
524
-            $payment = EE_Payment::new_instance();
525
-            $payment->set_gateway_response(
526
-                esc_html__(
527
-                    'An error occurred while trying to process the payment.',
528
-                    'event_espresso'
529
-                )
530
-            );
531
-            $payment->set_status($this->_pay_model->failed_status());
532
-            return false;
533
-        }
534
-        return true;
535
-    }
536
-
537
-
538
-    /**
539
-     * @param EE_Payment          $payment
540
-     * @param EE_Transaction|null $transaction
541
-     * @return bool
542
-     * @throws EE_Error
543
-     * @since   $VID:$
544
-     */
545
-    private function validateTransaction(EE_Payment $payment, ?EE_Transaction $transaction = null): bool
546
-    {
547
-        $transaction = $transaction ?? $payment->transaction();
548
-        if (! $transaction instanceof EE_Transaction) {
549
-            $payment->set_gateway_response(
550
-                esc_html__(
551
-                    'Could not process this payment because it has no associated transaction.',
552
-                    'event_espresso'
553
-                )
554
-            );
555
-            $payment->set_status($this->_pay_model->failed_status());
556
-            return false;
557
-        }
558
-        return true;
559
-    }
16
+	/**
17
+	 * Merchant API Username.
18
+	 *
19
+	 * @var string
20
+	 */
21
+	protected $_api_username;
22
+
23
+	/**
24
+	 * Merchant API Password.
25
+	 *
26
+	 * @var string
27
+	 */
28
+	protected $_api_password;
29
+
30
+	/**
31
+	 * API Signature.
32
+	 *
33
+	 * @var string
34
+	 */
35
+	protected $_api_signature;
36
+
37
+	/**
38
+	 * Request Shipping address on PP checkout page.
39
+	 *
40
+	 * @var string
41
+	 */
42
+	protected $_request_shipping_addr;
43
+
44
+	/**
45
+	 * Business/personal logo.
46
+	 *
47
+	 * @var string
48
+	 */
49
+	protected $_image_url = '';
50
+
51
+	/**
52
+	 * gateway URL variable
53
+	 *
54
+	 * @var string
55
+	 */
56
+	protected $_base_gateway_url = '';
57
+
58
+
59
+	/**
60
+	 * number of decimal places to round numbers to when performing calculations
61
+	 *
62
+	 * @var integer
63
+	 */
64
+	protected $decimal_precision = 6;
65
+
66
+	/**
67
+	 * @var ItemizedOrder
68
+	 * @since $VID:$
69
+	 */
70
+	protected $itemized_order;
71
+
72
+	/**
73
+	 * @var TokenRequest
74
+	 * @since $VID:$
75
+	 */
76
+	protected $token_request;
77
+
78
+
79
+	/**
80
+	 * EEG_Paypal_Express constructor.
81
+	 */
82
+	public function __construct()
83
+	{
84
+		require_once 'polyfills.php';
85
+		$this->_currencies_supported = [
86
+			'USD',
87
+			'AUD',
88
+			'BRL',
89
+			'CAD',
90
+			'CZK',
91
+			'DKK',
92
+			'EUR',
93
+			'HKD',
94
+			'HUF',
95
+			'ILS',
96
+			'JPY',
97
+			'MYR',
98
+			'MXN',
99
+			'NOK',
100
+			'NZD',
101
+			'PHP',
102
+			'PLN',
103
+			'GBP',
104
+			'RUB',
105
+			'SGD',
106
+			'SEK',
107
+			'CHF',
108
+			'TWD',
109
+			'THB',
110
+			'TRY',
111
+			'INR',
112
+		];
113
+		parent::__construct();
114
+		$this->decimal_precision = EE_Registry::instance()->CFG->currency->dec_plc;
115
+	}
116
+
117
+
118
+	/**
119
+	 * Sets the gateway URL variable based on whether debug mode is enabled or not.
120
+	 *
121
+	 * @param array $settings_array
122
+	 */
123
+	public function set_settings($settings_array)
124
+	{
125
+		parent::set_settings($settings_array);
126
+		// Redirect URL.
127
+		$this->_base_gateway_url = $this->_debug_mode
128
+			? 'https://api-3t.sandbox.paypal.com/nvp'
129
+			: 'https://api-3t.paypal.com/nvp';
130
+	}
131
+
132
+
133
+	/**
134
+	 * @param EEI_Payment $payment
135
+	 * @param array       $billing_info
136
+	 * @param string      $return_url
137
+	 * @param string      $notify_url
138
+	 * @param string      $cancel_url
139
+	 * @return EE_Payment|EEI_Payment
140
+	 * @throws EE_Error
141
+	 * @throws ReflectionException
142
+	 * @throws Exception
143
+	 */
144
+	public function set_redirection_info(
145
+		$payment,
146
+		$billing_info = [],
147
+		$return_url = null,
148
+		$notify_url = null,
149
+		$cancel_url = null
150
+	) {
151
+		if (! $this->validatePayment($payment)) {
152
+			return $payment;
153
+		}
154
+		if (! $this->validateTransaction($payment)) {
155
+			return $payment;
156
+		}
157
+		$this->token_request = new TokenRequest($this->_get_gateway_formatter());
158
+		$token_request_details = apply_filters(
159
+			'FHEE__EEG_Paypal_Express__set_redirection_info__arguments',
160
+			$this->token_request->generateDetails(
161
+				$payment,
162
+				$this->getOrderItems($payment),
163
+				$return_url ?? '',
164
+				$cancel_url ?? '',
165
+				$this->_image_url ?? '',
166
+				$this->_request_shipping_addr ?? ''
167
+			),
168
+			$this
169
+		);
170
+		// Request PayPal token.
171
+		$token_request_response = $this->_ppExpress_request($token_request_details, 'Payment Token', $payment);
172
+		$token_request_status   = $this->_ppExpress_check_response($token_request_response);
173
+		$this->token_request->processResponse($payment, $token_request_status, $this->isInSandboxMode());
174
+
175
+		return $payment;
176
+	}
177
+
178
+
179
+	/**
180
+	 * @param array           $update_info {
181
+	 * @type string           $gateway_txn_id
182
+	 * @type string           $status      an EEMI_Payment status
183
+	 *                                     }
184
+	 * @param EEI_Transaction $transaction
185
+	 * @return EEI_Payment
186
+	 * @throws Exception
187
+	 */
188
+	public function handle_payment_update($update_info, $transaction): EEI_Payment
189
+	{
190
+		// if the supplied transaction is valid, we'll retrieve the actual payment object from it
191
+		// but we'll use a temporary payment for now that we can return with errors if things go wrong
192
+		$payment = EE_Payment::new_instance();
193
+		if (! $this->validateTransaction($payment, $transaction)) {
194
+			return $payment;
195
+		}
196
+		$payment = $transaction->last_payment();
197
+		if (! $this->validatePayment($payment)) {
198
+			return $payment;
199
+		}
200
+		// payment appears to be good... so far
201
+		$this->log(['Return from Authorization' => $update_info], $payment);
202
+		$payment_token = $this->getPaymentToken($payment);
203
+		$customer_details = $this->requestCustomerDetails($payment, $payment_token);
204
+		// We got the PayerID so now we can Complete the transaction.
205
+		$this->processPayment($payment, $payment_token, $customer_details);
206
+
207
+		return $payment;
208
+	}
209
+
210
+
211
+	/**
212
+	 * @throws Exception
213
+	 */
214
+	private function getOrderItems(EE_Payment $payment, array $request_response_args = []): array
215
+	{
216
+		$this->itemized_order = new ItemizedOrder($this->_get_gateway_formatter());
217
+		try {
218
+			$itemized_order = $this->itemized_order->getExistingItemizedOrder($request_response_args);
219
+		} catch (Exception $exception) {
220
+			if (WP_DEBUG) {
221
+				throw $exception;
222
+			}
223
+			// Reset the list and log an error, maybe allow to try and generate a new list (below).
224
+			$itemized_order = [];
225
+			$this->log(
226
+				[
227
+					esc_html__(
228
+						'Could not generate a proper item list with:',
229
+						'event_espresso'
230
+					) => $request_response_args,
231
+				],
232
+				$payment
233
+			);
234
+		}
235
+		if (empty($itemized_order)) {
236
+			$itemized_order = $this->itemized_order->generateItemizedOrder($payment);
237
+		}
238
+		return $itemized_order;
239
+	}
240
+
241
+
242
+	/**
243
+	 *  Make the Express checkout request.
244
+	 *
245
+	 * @param array       $request_params
246
+	 * @param string      $request_text
247
+	 * @param EEI_Payment $payment
248
+	 * @return array|WP_Error
249
+	 */
250
+	public function _ppExpress_request(array $request_params, string $request_text, EEI_Payment $payment)
251
+	{
252
+		$request_dtls = [
253
+			'VERSION'      => '204.0',
254
+			'USER'         => $this->_api_username,
255
+			'PWD'          => $this->_api_password,
256
+			'SIGNATURE'    => $this->_api_signature,
257
+			// EE will blow up if you change this
258
+			'BUTTONSOURCE' => 'EventEspresso_SP',
259
+		];
260
+		$dtls         = array_merge($request_dtls, $request_params);
261
+		$this->_log_clean_request($dtls, $payment, $request_text . ' Request');
262
+		// Request Customer Details.
263
+		$request_response = wp_remote_post(
264
+			$this->_base_gateway_url,
265
+			[
266
+				'method'      => 'POST',
267
+				'timeout'     => 45,
268
+				'httpversion' => '1.1',
269
+				'cookies'     => [],
270
+				'headers'     => [],
271
+				'body'        => http_build_query($dtls),
272
+			]
273
+		);
274
+		// Log the response.
275
+		$this->log([$request_text . ' Response' => $request_response], $payment);
276
+		return $request_response;
277
+	}
278
+
279
+
280
+	/**
281
+	 *  Check the response status.
282
+	 *
283
+	 * @param mixed $request_response
284
+	 * @return array
285
+	 */
286
+	public function _ppExpress_check_response($request_response): array
287
+	{
288
+		if (is_wp_error($request_response) || empty($request_response['body'])) {
289
+			// If we got here then there was an error in this request.
290
+			return ['status' => false, 'args' => $request_response];
291
+		}
292
+		$response_args = [];
293
+		parse_str(urldecode($request_response['body']), $response_args);
294
+		if (! isset($response_args['ACK'])) {
295
+			return ['status' => false, 'args' => $request_response];
296
+		}
297
+		if (
298
+			(
299
+				isset($response_args['PAYERID'])
300
+				|| isset($response_args['TOKEN'])
301
+				|| isset($response_args['PAYMENTINFO_0_TRANSACTIONID'])
302
+				|| (isset($response_args['PAYMENTSTATUS']) && $response_args['PAYMENTSTATUS'] === 'Completed')
303
+			)
304
+			&& in_array($response_args['ACK'], ['Success', 'SuccessWithWarning'], true)
305
+		) {
306
+			// Response status OK, return response parameters for further processing.
307
+			return ['status' => true, 'args' => $response_args];
308
+		}
309
+		$errors = $this->_get_errors($response_args);
310
+		return ['status' => false, 'args' => $errors];
311
+	}
312
+
313
+
314
+	/**
315
+	 *  Log a "Cleared" request.
316
+	 *
317
+	 * @param array       $request
318
+	 * @param EEI_Payment $payment
319
+	 * @param string      $info
320
+	 * @return void
321
+	 */
322
+	private function _log_clean_request(array $request, EEI_Payment $payment, string $info)
323
+	{
324
+		$cleaned_request_data = $request;
325
+		unset($cleaned_request_data['PWD'], $cleaned_request_data['USER'], $cleaned_request_data['SIGNATURE']);
326
+		$this->log([$info => $cleaned_request_data], $payment);
327
+	}
328
+
329
+
330
+	/**
331
+	 *  Get error from the response data.
332
+	 *
333
+	 * @param array $data_array
334
+	 * @return array
335
+	 */
336
+	private function _get_errors(array $data_array): array
337
+	{
338
+		$errors = [];
339
+		$n      = 0;
340
+		while (isset($data_array[ "L_ERRORCODE{$n}" ])) {
341
+			$l_error_code    = $data_array[ "L_ERRORCODE{$n}" ] ?? '';
342
+			$l_severity_code = $data_array[ "L_SEVERITYCODE{$n}" ] ?? '';
343
+			$l_short_message = $data_array[ "L_SHORTMESSAGE{$n}" ] ?? '';
344
+			$l_long_message  = $data_array[ "L_LONGMESSAGE{$n}" ] ?? '';
345
+			if ($n === 0) {
346
+				$errors = [
347
+					'L_ERRORCODE'    => $l_error_code,
348
+					'L_SHORTMESSAGE' => $l_short_message,
349
+					'L_LONGMESSAGE'  => $l_long_message,
350
+					'L_SEVERITYCODE' => $l_severity_code,
351
+				];
352
+			} else {
353
+				$errors['L_ERRORCODE']    .= ', ' . $l_error_code;
354
+				$errors['L_SHORTMESSAGE'] .= ', ' . $l_short_message;
355
+				$errors['L_LONGMESSAGE']  .= ', ' . $l_long_message;
356
+				$errors['L_SEVERITYCODE'] .= ', ' . $l_severity_code;
357
+			}
358
+			$n++;
359
+		}
360
+		return $errors;
361
+	}
362
+
363
+
364
+	/**
365
+	 * @param EE_Payment $payment
366
+	 * @return mixed|null
367
+	 * @throws EE_Error
368
+	 * @since   $VID:$
369
+	 */
370
+	private function getPaymentToken(EE_Payment $payment)
371
+	{
372
+		$payment_details = $payment->details();
373
+		// Check if we still have the token.
374
+		if (! isset($payment_details['TOKEN']) || empty($payment_details['TOKEN'])) {
375
+			$payment->set_status($this->_pay_model->failed_status());
376
+			return null;
377
+		}
378
+		return $payment_details['TOKEN'];
379
+	}
380
+
381
+	/**
382
+	 * @param EE_Payment $payment
383
+	 * @param array      $checkout_response
384
+	 * @param array      $customer_data
385
+	 * @throws EE_Error
386
+	 * @throws ReflectionException
387
+	 * @since   $VID:$
388
+	 */
389
+	private function paymentApproved(EE_Payment $payment, array $checkout_response, array $customer_data)
390
+	{
391
+		$primary_registrant = $payment->transaction()->primary_registration();
392
+		$primary_registration_code = $primary_registrant instanceof EE_Registration ?
393
+			$primary_registrant->reg_code()
394
+			: '';
395
+		$payment->set_extra_accntng($primary_registration_code);
396
+		$payment_amount = $checkout_response['PAYMENTINFO_0_AMT'] ?? 0;
397
+		$payment->set_amount((float) $payment_amount);
398
+		$payment->set_txn_id_chq_nmbr($checkout_response['PAYMENTINFO_0_TRANSACTIONID'] ?? null);
399
+		$payment->set_details($customer_data);
400
+		$payment->set_gateway_response($checkout_response['PAYMENTINFO_0_ACK'] ?? '');
401
+		$payment->set_status($this->_pay_model->approved_status());
402
+	}
403
+
404
+
405
+	/**
406
+	 * @param EE_Payment $payment
407
+	 * @param array      $checkout_response
408
+	 * @throws EE_Error
409
+	 * @since   $VID:$
410
+	 */
411
+	private function paymentDeclined(EE_Payment $payment, array $checkout_response)
412
+	{
413
+		$gateway_response = isset($checkout_response['L_ERRORCODE'])
414
+			? $checkout_response['L_ERRORCODE'] . '; ' . $checkout_response['L_SHORTMESSAGE']
415
+			: esc_html__('Error occurred while trying to Capture the funds.', 'event_espresso');
416
+
417
+		$payment->set_gateway_response($gateway_response);
418
+		$payment->set_details($checkout_response);
419
+		$payment->set_status($this->_pay_model->declined_status());
420
+	}
421
+
422
+
423
+	/**
424
+	 * @param EE_Payment $payment
425
+	 * @param array $customer_data
426
+	 * @throws EE_Error
427
+	 * @since   $VID:$
428
+	 */
429
+	private function paymentFailed(EE_Payment $payment, array $customer_data)
430
+	{
431
+		$gateway_response = isset($customer_data['L_ERRORCODE'])
432
+			? $customer_data['L_ERRORCODE'] . '; ' . $customer_data['L_SHORTMESSAGE']
433
+			: esc_html__('Error occurred while trying to get payment Details from PayPal.', 'event_espresso');
434
+
435
+		$payment->set_gateway_response($gateway_response);
436
+		$payment->set_details($customer_data);
437
+		$payment->set_status($this->_pay_model->failed_status());
438
+	}
439
+
440
+
441
+	/**
442
+	 * @param EE_Payment $payment
443
+	 * @param string     $payment_token
444
+	 * @param array      $customer_details
445
+	 * @return void
446
+	 * @throws EE_Error
447
+	 * @throws ReflectionException
448
+	 * @throws Exception
449
+	 * @since   $VID:$
450
+	 */
451
+	private function processPayment(EE_Payment $payment, string $payment_token, array $customer_details)
452
+	{
453
+		$checkout_request_dtls = [
454
+			'METHOD'                         => 'DoExpressCheckoutPayment',
455
+			'PAYERID'                        => $customer_details['PAYERID'],
456
+			'TOKEN'                          => $payment_token,
457
+			'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale',
458
+			'PAYMENTREQUEST_0_AMT'           => $payment->amount(),
459
+			'PAYMENTREQUEST_0_CURRENCYCODE'  => $payment->currency_code(),
460
+		];
461
+		// Include itemized list.
462
+		$itemized_list         = $this->getOrderItems($payment, $customer_details);
463
+		$checkout_request_dtls = array_merge($checkout_request_dtls, $itemized_list);
464
+		// Payment Checkout/Capture.
465
+		$checkout_request_response = $this->_ppExpress_request(
466
+			$checkout_request_dtls,
467
+			'Do Payment',
468
+			$payment
469
+		);
470
+		$checkout_request_status   = $this->_ppExpress_check_response($checkout_request_response);
471
+		$checkout_response         =
472
+			isset($checkout_request_status['args']) && is_array($checkout_request_status['args'])
473
+				? $checkout_request_status['args']
474
+				: [];
475
+		if ($checkout_request_status['status']) {
476
+			// All is well, payment approved.
477
+			$this->paymentApproved($payment, $checkout_response, $customer_details);
478
+		} else {
479
+			$this->paymentDeclined($payment, $checkout_response);
480
+		}
481
+	}
482
+
483
+
484
+	/**
485
+	 * @param EE_Payment $payment
486
+	 * @param string $payment_token
487
+	 * @return array
488
+	 * @throws EE_Error
489
+	 * @since   $VID:$
490
+	 */
491
+	private function requestCustomerDetails(EE_Payment $payment, string $payment_token): array
492
+	{
493
+		$customer_details_request_dtls = [
494
+			'METHOD' => 'GetExpressCheckoutDetails',
495
+			'TOKEN'  => $payment_token,
496
+		];
497
+		// Request Customer Details.
498
+		$customer_details_request_response = $this->_ppExpress_request(
499
+			$customer_details_request_dtls,
500
+			'Customer Details',
501
+			$payment
502
+		);
503
+		$customer_details_rstatus          = $this->_ppExpress_check_response($customer_details_request_response);
504
+		$customer_details = isset($customer_details_rstatus['args']) && is_array($customer_details_rstatus['args'])
505
+			? $customer_details_rstatus['args']
506
+			: [];
507
+		if (! $customer_details_rstatus['status']) {
508
+			$this->paymentFailed($payment, $customer_details);
509
+		}
510
+		return $customer_details;
511
+	}
512
+
513
+
514
+
515
+	/**
516
+	 * @param EE_Payment|null $payment
517
+	 * @return bool
518
+	 * @throws EE_Error
519
+	 * @since   $VID:$
520
+	 */
521
+	private function validatePayment(?EE_Payment $payment): bool
522
+	{
523
+		if (! $payment instanceof EE_Payment) {
524
+			$payment = EE_Payment::new_instance();
525
+			$payment->set_gateway_response(
526
+				esc_html__(
527
+					'An error occurred while trying to process the payment.',
528
+					'event_espresso'
529
+				)
530
+			);
531
+			$payment->set_status($this->_pay_model->failed_status());
532
+			return false;
533
+		}
534
+		return true;
535
+	}
536
+
537
+
538
+	/**
539
+	 * @param EE_Payment          $payment
540
+	 * @param EE_Transaction|null $transaction
541
+	 * @return bool
542
+	 * @throws EE_Error
543
+	 * @since   $VID:$
544
+	 */
545
+	private function validateTransaction(EE_Payment $payment, ?EE_Transaction $transaction = null): bool
546
+	{
547
+		$transaction = $transaction ?? $payment->transaction();
548
+		if (! $transaction instanceof EE_Transaction) {
549
+			$payment->set_gateway_response(
550
+				esc_html__(
551
+					'Could not process this payment because it has no associated transaction.',
552
+					'event_espresso'
553
+				)
554
+			);
555
+			$payment->set_status($this->_pay_model->failed_status());
556
+			return false;
557
+		}
558
+		return true;
559
+	}
560 560
 }
Please login to merge, or discard this patch.
Spacing   +24 added lines, -24 removed lines patch added patch discarded remove patch
@@ -148,10 +148,10 @@  discard block
 block discarded – undo
148 148
         $notify_url = null,
149 149
         $cancel_url = null
150 150
     ) {
151
-        if (! $this->validatePayment($payment)) {
151
+        if ( ! $this->validatePayment($payment)) {
152 152
             return $payment;
153 153
         }
154
-        if (! $this->validateTransaction($payment)) {
154
+        if ( ! $this->validateTransaction($payment)) {
155 155
             return $payment;
156 156
         }
157 157
         $this->token_request = new TokenRequest($this->_get_gateway_formatter());
@@ -190,11 +190,11 @@  discard block
 block discarded – undo
190 190
         // if the supplied transaction is valid, we'll retrieve the actual payment object from it
191 191
         // but we'll use a temporary payment for now that we can return with errors if things go wrong
192 192
         $payment = EE_Payment::new_instance();
193
-        if (! $this->validateTransaction($payment, $transaction)) {
193
+        if ( ! $this->validateTransaction($payment, $transaction)) {
194 194
             return $payment;
195 195
         }
196 196
         $payment = $transaction->last_payment();
197
-        if (! $this->validatePayment($payment)) {
197
+        if ( ! $this->validatePayment($payment)) {
198 198
             return $payment;
199 199
         }
200 200
         // payment appears to be good... so far
@@ -257,8 +257,8 @@  discard block
 block discarded – undo
257 257
             // EE will blow up if you change this
258 258
             'BUTTONSOURCE' => 'EventEspresso_SP',
259 259
         ];
260
-        $dtls         = array_merge($request_dtls, $request_params);
261
-        $this->_log_clean_request($dtls, $payment, $request_text . ' Request');
260
+        $dtls = array_merge($request_dtls, $request_params);
261
+        $this->_log_clean_request($dtls, $payment, $request_text.' Request');
262 262
         // Request Customer Details.
263 263
         $request_response = wp_remote_post(
264 264
             $this->_base_gateway_url,
@@ -272,7 +272,7 @@  discard block
 block discarded – undo
272 272
             ]
273 273
         );
274 274
         // Log the response.
275
-        $this->log([$request_text . ' Response' => $request_response], $payment);
275
+        $this->log([$request_text.' Response' => $request_response], $payment);
276 276
         return $request_response;
277 277
     }
278 278
 
@@ -291,7 +291,7 @@  discard block
 block discarded – undo
291 291
         }
292 292
         $response_args = [];
293 293
         parse_str(urldecode($request_response['body']), $response_args);
294
-        if (! isset($response_args['ACK'])) {
294
+        if ( ! isset($response_args['ACK'])) {
295 295
             return ['status' => false, 'args' => $request_response];
296 296
         }
297 297
         if (
@@ -337,11 +337,11 @@  discard block
 block discarded – undo
337 337
     {
338 338
         $errors = [];
339 339
         $n      = 0;
340
-        while (isset($data_array[ "L_ERRORCODE{$n}" ])) {
341
-            $l_error_code    = $data_array[ "L_ERRORCODE{$n}" ] ?? '';
342
-            $l_severity_code = $data_array[ "L_SEVERITYCODE{$n}" ] ?? '';
343
-            $l_short_message = $data_array[ "L_SHORTMESSAGE{$n}" ] ?? '';
344
-            $l_long_message  = $data_array[ "L_LONGMESSAGE{$n}" ] ?? '';
340
+        while (isset($data_array["L_ERRORCODE{$n}"])) {
341
+            $l_error_code    = $data_array["L_ERRORCODE{$n}"] ?? '';
342
+            $l_severity_code = $data_array["L_SEVERITYCODE{$n}"] ?? '';
343
+            $l_short_message = $data_array["L_SHORTMESSAGE{$n}"] ?? '';
344
+            $l_long_message  = $data_array["L_LONGMESSAGE{$n}"] ?? '';
345 345
             if ($n === 0) {
346 346
                 $errors = [
347 347
                     'L_ERRORCODE'    => $l_error_code,
@@ -350,10 +350,10 @@  discard block
 block discarded – undo
350 350
                     'L_SEVERITYCODE' => $l_severity_code,
351 351
                 ];
352 352
             } else {
353
-                $errors['L_ERRORCODE']    .= ', ' . $l_error_code;
354
-                $errors['L_SHORTMESSAGE'] .= ', ' . $l_short_message;
355
-                $errors['L_LONGMESSAGE']  .= ', ' . $l_long_message;
356
-                $errors['L_SEVERITYCODE'] .= ', ' . $l_severity_code;
353
+                $errors['L_ERRORCODE']    .= ', '.$l_error_code;
354
+                $errors['L_SHORTMESSAGE'] .= ', '.$l_short_message;
355
+                $errors['L_LONGMESSAGE']  .= ', '.$l_long_message;
356
+                $errors['L_SEVERITYCODE'] .= ', '.$l_severity_code;
357 357
             }
358 358
             $n++;
359 359
         }
@@ -371,7 +371,7 @@  discard block
 block discarded – undo
371 371
     {
372 372
         $payment_details = $payment->details();
373 373
         // Check if we still have the token.
374
-        if (! isset($payment_details['TOKEN']) || empty($payment_details['TOKEN'])) {
374
+        if ( ! isset($payment_details['TOKEN']) || empty($payment_details['TOKEN'])) {
375 375
             $payment->set_status($this->_pay_model->failed_status());
376 376
             return null;
377 377
         }
@@ -411,7 +411,7 @@  discard block
 block discarded – undo
411 411
     private function paymentDeclined(EE_Payment $payment, array $checkout_response)
412 412
     {
413 413
         $gateway_response = isset($checkout_response['L_ERRORCODE'])
414
-            ? $checkout_response['L_ERRORCODE'] . '; ' . $checkout_response['L_SHORTMESSAGE']
414
+            ? $checkout_response['L_ERRORCODE'].'; '.$checkout_response['L_SHORTMESSAGE']
415 415
             : esc_html__('Error occurred while trying to Capture the funds.', 'event_espresso');
416 416
 
417 417
         $payment->set_gateway_response($gateway_response);
@@ -429,7 +429,7 @@  discard block
 block discarded – undo
429 429
     private function paymentFailed(EE_Payment $payment, array $customer_data)
430 430
     {
431 431
         $gateway_response = isset($customer_data['L_ERRORCODE'])
432
-            ? $customer_data['L_ERRORCODE'] . '; ' . $customer_data['L_SHORTMESSAGE']
432
+            ? $customer_data['L_ERRORCODE'].'; '.$customer_data['L_SHORTMESSAGE']
433 433
             : esc_html__('Error occurred while trying to get payment Details from PayPal.', 'event_espresso');
434 434
 
435 435
         $payment->set_gateway_response($gateway_response);
@@ -500,11 +500,11 @@  discard block
 block discarded – undo
500 500
             'Customer Details',
501 501
             $payment
502 502
         );
503
-        $customer_details_rstatus          = $this->_ppExpress_check_response($customer_details_request_response);
503
+        $customer_details_rstatus = $this->_ppExpress_check_response($customer_details_request_response);
504 504
         $customer_details = isset($customer_details_rstatus['args']) && is_array($customer_details_rstatus['args'])
505 505
             ? $customer_details_rstatus['args']
506 506
             : [];
507
-        if (! $customer_details_rstatus['status']) {
507
+        if ( ! $customer_details_rstatus['status']) {
508 508
             $this->paymentFailed($payment, $customer_details);
509 509
         }
510 510
         return $customer_details;
@@ -520,7 +520,7 @@  discard block
 block discarded – undo
520 520
      */
521 521
     private function validatePayment(?EE_Payment $payment): bool
522 522
     {
523
-        if (! $payment instanceof EE_Payment) {
523
+        if ( ! $payment instanceof EE_Payment) {
524 524
             $payment = EE_Payment::new_instance();
525 525
             $payment->set_gateway_response(
526 526
                 esc_html__(
@@ -545,7 +545,7 @@  discard block
 block discarded – undo
545 545
     private function validateTransaction(EE_Payment $payment, ?EE_Transaction $transaction = null): bool
546 546
     {
547 547
         $transaction = $transaction ?? $payment->transaction();
548
-        if (! $transaction instanceof EE_Transaction) {
548
+        if ( ! $transaction instanceof EE_Transaction) {
549 549
             $payment->set_gateway_response(
550 550
                 esc_html__(
551 551
                     'Could not process this payment because it has no associated transaction.',
Please login to merge, or discard this patch.
payment_methods/Paypal_Express/ItemizedOrder.php 2 patches
Indentation   +265 added lines, -265 removed lines patch added patch discarded remove patch
@@ -16,292 +16,292 @@
 block discarded – undo
16 16
 {
17 17
 
18 18
 
19
-    /**
20
-     * number of decimal places to round numbers to when performing calculations
21
-     *
22
-     * @var integer
23
-     */
24
-    protected $decimal_precision = 6;
19
+	/**
20
+	 * number of decimal places to round numbers to when performing calculations
21
+	 *
22
+	 * @var integer
23
+	 */
24
+	protected $decimal_precision = 6;
25 25
 
26
-    /**
27
-     * @var GatewayDataFormatterInterface
28
-     */
29
-    protected $gateway_data_formatter;
26
+	/**
27
+	 * @var GatewayDataFormatterInterface
28
+	 */
29
+	protected $gateway_data_formatter;
30 30
 
31
-    /**
32
-     * keeps track of exactly how much the itemized order amount equals
33
-     *
34
-     * @var float
35
-     */
36
-    private $itemized_order_sum = 0.00;
31
+	/**
32
+	 * keeps track of exactly how much the itemized order amount equals
33
+	 *
34
+	 * @var float
35
+	 */
36
+	private $itemized_order_sum = 0.00;
37 37
 
38
-    /**
39
-     * @var array
40
-     */
41
-    private $order_items;
38
+	/**
39
+	 * @var array
40
+	 */
41
+	private $order_items;
42 42
 
43
-    /**
44
-     * the payment being processed
45
-     *
46
-     * @var EE_Payment
47
-     */
48
-    protected $payment;
43
+	/**
44
+	 * the payment being processed
45
+	 *
46
+	 * @var EE_Payment
47
+	 */
48
+	protected $payment;
49 49
 
50
-    /**
51
-     * @var EE_Transaction
52
-     */
53
-    private $transaction;
50
+	/**
51
+	 * @var EE_Transaction
52
+	 */
53
+	private $transaction;
54 54
 
55 55
 
56
-    /**
57
-     * @param GatewayDataFormatterInterface $gateway_data_formatter
58
-     */
59
-    public function __construct(GatewayDataFormatterInterface $gateway_data_formatter)
60
-    {
61
-        $this->decimal_precision      = EE_Registry::instance()->CFG->currency->dec_plc;
62
-        $this->gateway_data_formatter = $gateway_data_formatter;
63
-        $this->order_items            = [];
64
-    }
56
+	/**
57
+	 * @param GatewayDataFormatterInterface $gateway_data_formatter
58
+	 */
59
+	public function __construct(GatewayDataFormatterInterface $gateway_data_formatter)
60
+	{
61
+		$this->decimal_precision      = EE_Registry::instance()->CFG->currency->dec_plc;
62
+		$this->gateway_data_formatter = $gateway_data_formatter;
63
+		$this->order_items            = [];
64
+	}
65 65
 
66 66
 
67
-    /**
68
-     * @param array $request_response_args
69
-     * @return array
70
-     */
71
-    public function getExistingItemizedOrder(array $request_response_args): array
72
-    {
73
-        // If we have data from a previous communication with PP (on this transaction) we may use that for our list...
74
-        if (
75
-            ! empty($request_response_args)
76
-            && array_key_exists('L_PAYMENTREQUEST_0_AMT0', $request_response_args)
77
-            && array_key_exists('PAYMENTREQUEST_0_ITEMAMT', $request_response_args)
78
-        ) {
79
-            foreach ($request_response_args as $arg_key => $arg_val) {
80
-                if (
81
-                    strpos($arg_key, 'PAYMENTREQUEST_') !== false
82
-                    && strpos($arg_key, 'NOTIFYURL') === false
83
-                ) {
84
-                    $this->order_items[ $arg_key ] = $arg_val;
85
-                }
86
-            }
87
-            // If we only get a few Items then something is not right.
88
-            if (count($this->order_items) < 3) {
89
-                throw new RuntimeException(
90
-                    sprintf(
91
-                        esc_html__(
92
-                            'Unable to continue with the checkout because a proper purchase list could not be generated. The purchased list we could have sent was %1$s',
93
-                            'event_espresso'
94
-                        ),
95
-                        wp_json_encode($this->order_items)
96
-                    )
97
-                );
98
-            }
99
-        }
100
-        return $this->order_items;
101
-    }
67
+	/**
68
+	 * @param array $request_response_args
69
+	 * @return array
70
+	 */
71
+	public function getExistingItemizedOrder(array $request_response_args): array
72
+	{
73
+		// If we have data from a previous communication with PP (on this transaction) we may use that for our list...
74
+		if (
75
+			! empty($request_response_args)
76
+			&& array_key_exists('L_PAYMENTREQUEST_0_AMT0', $request_response_args)
77
+			&& array_key_exists('PAYMENTREQUEST_0_ITEMAMT', $request_response_args)
78
+		) {
79
+			foreach ($request_response_args as $arg_key => $arg_val) {
80
+				if (
81
+					strpos($arg_key, 'PAYMENTREQUEST_') !== false
82
+					&& strpos($arg_key, 'NOTIFYURL') === false
83
+				) {
84
+					$this->order_items[ $arg_key ] = $arg_val;
85
+				}
86
+			}
87
+			// If we only get a few Items then something is not right.
88
+			if (count($this->order_items) < 3) {
89
+				throw new RuntimeException(
90
+					sprintf(
91
+						esc_html__(
92
+							'Unable to continue with the checkout because a proper purchase list could not be generated. The purchased list we could have sent was %1$s',
93
+							'event_espresso'
94
+						),
95
+						wp_json_encode($this->order_items)
96
+					)
97
+				);
98
+			}
99
+		}
100
+		return $this->order_items;
101
+	}
102 102
 
103 103
 
104
-    /**
105
-     *  Make a list of items that are in the giver transaction.
106
-     *
107
-     * @param EE_Payment $payment
108
-     * @return array
109
-     * @throws EE_Error
110
-     * @throws ReflectionException
111
-     */
112
-    public function generateItemizedOrder(EE_Payment $payment): array
113
-    {
114
-        $this->payment     = $payment;
115
-        $this->transaction = $this->payment->transaction();
116
-        // reset order items
117
-        $this->order_items = [];
118
-        if ($this->paymentIsForTransactionTotal()) {
119
-            $this->itemizeOrderForFullPayment();
120
-        } else {
121
-            $this->handlePartialPayment();
122
-        }
123
-        return $this->order_items;
124
-    }
104
+	/**
105
+	 *  Make a list of items that are in the giver transaction.
106
+	 *
107
+	 * @param EE_Payment $payment
108
+	 * @return array
109
+	 * @throws EE_Error
110
+	 * @throws ReflectionException
111
+	 */
112
+	public function generateItemizedOrder(EE_Payment $payment): array
113
+	{
114
+		$this->payment     = $payment;
115
+		$this->transaction = $this->payment->transaction();
116
+		// reset order items
117
+		$this->order_items = [];
118
+		if ($this->paymentIsForTransactionTotal()) {
119
+			$this->itemizeOrderForFullPayment();
120
+		} else {
121
+			$this->handlePartialPayment();
122
+		}
123
+		return $this->order_items;
124
+	}
125 125
 
126 126
 
127
-    /**
128
-     * @return bool
129
-     * @throws ReflectionException
130
-     * @throws EE_Error
131
-     */
132
-    private function paymentIsForTransactionTotal(): bool
133
-    {
134
-        return EEH_Money::compare_floats($this->payment->amount(), $this->transaction->total(), '==');
135
-    }
127
+	/**
128
+	 * @return bool
129
+	 * @throws ReflectionException
130
+	 * @throws EE_Error
131
+	 */
132
+	private function paymentIsForTransactionTotal(): bool
133
+	{
134
+		return EEH_Money::compare_floats($this->payment->amount(), $this->transaction->total(), '==');
135
+	}
136 136
 
137 137
 
138
-    /**
139
-     * @return void
140
-     * @throws EE_Error
141
-     * @throws ReflectionException
142
-     */
143
-    private function itemizeOrderForFullPayment()
144
-    {
145
-        $item_num        = 0;
146
-        $total_line_item = $this->transaction->total_line_item();
147
-        $item_num        = $this->addOrderItemsForLineItems($total_line_item, $item_num);
148
-        $this->addOrderItemsForAdditionalCharges($total_line_item);
149
-        $this->handleItemizedOrderSumDifference($total_line_item, $item_num);
150
-    }
138
+	/**
139
+	 * @return void
140
+	 * @throws EE_Error
141
+	 * @throws ReflectionException
142
+	 */
143
+	private function itemizeOrderForFullPayment()
144
+	{
145
+		$item_num        = 0;
146
+		$total_line_item = $this->transaction->total_line_item();
147
+		$item_num        = $this->addOrderItemsForLineItems($total_line_item, $item_num);
148
+		$this->addOrderItemsForAdditionalCharges($total_line_item);
149
+		$this->handleItemizedOrderSumDifference($total_line_item, $item_num);
150
+	}
151 151
 
152 152
 
153
-    /**
154
-     * @return void
155
-     * @throws EE_Error
156
-     */
157
-    private function handlePartialPayment()
158
-    {
159
-        // Item Name.
160
-        $this->order_items['L_PAYMENTREQUEST_0_NAME0'] = mb_strcut(
161
-            $this->gateway_data_formatter->formatPartialPaymentLineItemName($this->payment),
162
-            0,
163
-            127
164
-        );
165
-        // Item description.
166
-        $this->order_items['L_PAYMENTREQUEST_0_DESC0'] = mb_strcut(
167
-            $this->gateway_data_formatter->formatPartialPaymentLineItemDesc($this->payment),
168
-            0,
169
-            127
170
-        );
171
-        // Cost of individual item.
172
-        $this->order_items['L_PAYMENTREQUEST_0_AMT0'] = $this->gateway_data_formatter->formatCurrency(
173
-            $this->payment->amount(),
174
-            $this->decimal_precision
175
-        );
176
-        // Item Number.
177
-        $this->order_items['L_PAYMENTREQUEST_0_NUMBER0'] = 1;
178
-        // Item quantity.
179
-        $this->order_items['L_PAYMENTREQUEST_0_QTY0'] = 1;
180
-        // Digital item is sold.
181
-        $this->order_items['L_PAYMENTREQUEST_0_ITEMCATEGORY0'] = 'Physical';
182
-        // Item's sales S/H and tax amount.
183
-        $this->order_items['PAYMENTREQUEST_0_ITEMAMT']     = $this->gateway_data_formatter->formatCurrency(
184
-            $this->payment->amount(),
185
-            $this->decimal_precision
186
-        );
187
-        $this->order_items['PAYMENTREQUEST_0_TAXAMT']      = '0';
188
-        $this->order_items['PAYMENTREQUEST_0_SHIPPINGAMT'] = '0';
189
-        $this->order_items['PAYMENTREQUEST_0_HANDLINGAMT'] = '0';
190
-    }
153
+	/**
154
+	 * @return void
155
+	 * @throws EE_Error
156
+	 */
157
+	private function handlePartialPayment()
158
+	{
159
+		// Item Name.
160
+		$this->order_items['L_PAYMENTREQUEST_0_NAME0'] = mb_strcut(
161
+			$this->gateway_data_formatter->formatPartialPaymentLineItemName($this->payment),
162
+			0,
163
+			127
164
+		);
165
+		// Item description.
166
+		$this->order_items['L_PAYMENTREQUEST_0_DESC0'] = mb_strcut(
167
+			$this->gateway_data_formatter->formatPartialPaymentLineItemDesc($this->payment),
168
+			0,
169
+			127
170
+		);
171
+		// Cost of individual item.
172
+		$this->order_items['L_PAYMENTREQUEST_0_AMT0'] = $this->gateway_data_formatter->formatCurrency(
173
+			$this->payment->amount(),
174
+			$this->decimal_precision
175
+		);
176
+		// Item Number.
177
+		$this->order_items['L_PAYMENTREQUEST_0_NUMBER0'] = 1;
178
+		// Item quantity.
179
+		$this->order_items['L_PAYMENTREQUEST_0_QTY0'] = 1;
180
+		// Digital item is sold.
181
+		$this->order_items['L_PAYMENTREQUEST_0_ITEMCATEGORY0'] = 'Physical';
182
+		// Item's sales S/H and tax amount.
183
+		$this->order_items['PAYMENTREQUEST_0_ITEMAMT']     = $this->gateway_data_formatter->formatCurrency(
184
+			$this->payment->amount(),
185
+			$this->decimal_precision
186
+		);
187
+		$this->order_items['PAYMENTREQUEST_0_TAXAMT']      = '0';
188
+		$this->order_items['PAYMENTREQUEST_0_SHIPPINGAMT'] = '0';
189
+		$this->order_items['PAYMENTREQUEST_0_HANDLINGAMT'] = '0';
190
+	}
191 191
 
192 192
 
193
-    /**
194
-     * @param EE_Line_Item $total_line_item
195
-     * @param int          $item_num
196
-     * @return int
197
-     * @throws EE_Error
198
-     * @throws ReflectionException
199
-     */
200
-    private function addOrderItemsForLineItems(EE_Line_Item $total_line_item, int $item_num): int
201
-    {
202
-        // Go through each item in the list.
203
-        foreach ($total_line_item->get_items() as $line_item) {
204
-            if ($line_item instanceof EE_Line_Item) {
205
-                // PayPal doesn't like line items with 0.00 amount, so we may skip those.
206
-                if (EEH_Money::compare_floats($line_item->pretaxTotal(), '0.00', '==')) {
207
-                    continue;
208
-                }
209
-                $unit_price         = $this->gateway_data_formatter->formatCurrency(
210
-                    $line_item->unit_price(),
211
-                    $this->decimal_precision
212
-                );
213
-                $line_item_quantity = $line_item->quantity();
214
-                // This is a discount.
215
-                if ($line_item->is_percent()) {
216
-                    $unit_price         = $line_item->pretaxTotal();
217
-                    $line_item_quantity = 1;
218
-                }
219
-                // Item Name.
220
-                $this->order_items[ "L_PAYMENTREQUEST_0_NAME{$item_num}" ] = mb_strcut(
221
-                    $this->gateway_data_formatter->formatLineItemName($line_item, $this->payment),
222
-                    0,
223
-                    127
224
-                );
225
-                // Item description.
226
-                $this->order_items[ "L_PAYMENTREQUEST_0_DESC{$item_num}" ] = mb_strcut(
227
-                    $this->gateway_data_formatter->formatLineItemDesc($line_item, $this->payment),
228
-                    0,
229
-                    127
230
-                );
231
-                // Cost of individual item.
232
-                $this->order_items[ "L_PAYMENTREQUEST_0_AMT{$item_num}" ] = $unit_price;
233
-                // Item Number.
234
-                $this->order_items[ "L_PAYMENTREQUEST_0_NUMBER{$item_num}" ] = $item_num + 1;
235
-                // Item quantity.
236
-                $this->order_items[ "L_PAYMENTREQUEST_0_QTY{$item_num}" ] = $line_item_quantity;
237
-                // Digital item is sold.
238
-                $this->order_items[ "L_PAYMENTREQUEST_0_ITEMCATEGORY{$item_num}" ] = 'Physical';
239
-                // add item total to order sum
240
-                $this->itemized_order_sum += $unit_price * $line_item_quantity;
241
-                ++$item_num;
242
-            }
243
-        }
244
-        return $item_num;
245
-    }
193
+	/**
194
+	 * @param EE_Line_Item $total_line_item
195
+	 * @param int          $item_num
196
+	 * @return int
197
+	 * @throws EE_Error
198
+	 * @throws ReflectionException
199
+	 */
200
+	private function addOrderItemsForLineItems(EE_Line_Item $total_line_item, int $item_num): int
201
+	{
202
+		// Go through each item in the list.
203
+		foreach ($total_line_item->get_items() as $line_item) {
204
+			if ($line_item instanceof EE_Line_Item) {
205
+				// PayPal doesn't like line items with 0.00 amount, so we may skip those.
206
+				if (EEH_Money::compare_floats($line_item->pretaxTotal(), '0.00', '==')) {
207
+					continue;
208
+				}
209
+				$unit_price         = $this->gateway_data_formatter->formatCurrency(
210
+					$line_item->unit_price(),
211
+					$this->decimal_precision
212
+				);
213
+				$line_item_quantity = $line_item->quantity();
214
+				// This is a discount.
215
+				if ($line_item->is_percent()) {
216
+					$unit_price         = $line_item->pretaxTotal();
217
+					$line_item_quantity = 1;
218
+				}
219
+				// Item Name.
220
+				$this->order_items[ "L_PAYMENTREQUEST_0_NAME{$item_num}" ] = mb_strcut(
221
+					$this->gateway_data_formatter->formatLineItemName($line_item, $this->payment),
222
+					0,
223
+					127
224
+				);
225
+				// Item description.
226
+				$this->order_items[ "L_PAYMENTREQUEST_0_DESC{$item_num}" ] = mb_strcut(
227
+					$this->gateway_data_formatter->formatLineItemDesc($line_item, $this->payment),
228
+					0,
229
+					127
230
+				);
231
+				// Cost of individual item.
232
+				$this->order_items[ "L_PAYMENTREQUEST_0_AMT{$item_num}" ] = $unit_price;
233
+				// Item Number.
234
+				$this->order_items[ "L_PAYMENTREQUEST_0_NUMBER{$item_num}" ] = $item_num + 1;
235
+				// Item quantity.
236
+				$this->order_items[ "L_PAYMENTREQUEST_0_QTY{$item_num}" ] = $line_item_quantity;
237
+				// Digital item is sold.
238
+				$this->order_items[ "L_PAYMENTREQUEST_0_ITEMCATEGORY{$item_num}" ] = 'Physical';
239
+				// add item total to order sum
240
+				$this->itemized_order_sum += $unit_price * $line_item_quantity;
241
+				++$item_num;
242
+			}
243
+		}
244
+		return $item_num;
245
+	}
246 246
 
247 247
 
248
-    /**
249
-     * @param EE_Line_Item $total_line_item
250
-     * @return void
251
-     * @throws EE_Error
252
-     * @throws ReflectionException
253
-     */
254
-    private function addOrderItemsForAdditionalCharges(EE_Line_Item $total_line_item)
255
-    {
256
-        // Item's sales S/H and tax amount.
257
-        $this->order_items['PAYMENTREQUEST_0_ITEMAMT']     = $total_line_item->get_items_total();
258
-        $this->order_items['PAYMENTREQUEST_0_TAXAMT']      = $total_line_item->get_total_tax();
259
-        $this->order_items['PAYMENTREQUEST_0_SHIPPINGAMT'] = '0';
260
-        $this->order_items['PAYMENTREQUEST_0_HANDLINGAMT'] = '0';
261
-    }
248
+	/**
249
+	 * @param EE_Line_Item $total_line_item
250
+	 * @return void
251
+	 * @throws EE_Error
252
+	 * @throws ReflectionException
253
+	 */
254
+	private function addOrderItemsForAdditionalCharges(EE_Line_Item $total_line_item)
255
+	{
256
+		// Item's sales S/H and tax amount.
257
+		$this->order_items['PAYMENTREQUEST_0_ITEMAMT']     = $total_line_item->get_items_total();
258
+		$this->order_items['PAYMENTREQUEST_0_TAXAMT']      = $total_line_item->get_total_tax();
259
+		$this->order_items['PAYMENTREQUEST_0_SHIPPINGAMT'] = '0';
260
+		$this->order_items['PAYMENTREQUEST_0_HANDLINGAMT'] = '0';
261
+	}
262 262
 
263 263
 
264
-    /**
265
-     * @param EE_Line_Item $total_line_item
266
-     * @param int          $item_num
267
-     * @return void
268
-     * @throws EE_Error
269
-     * @throws ReflectionException
270
-     */
271
-    private function handleItemizedOrderSumDifference(EE_Line_Item $total_line_item, int $item_num)
272
-    {
273
-        // calculate the difference between the TXN total and the itemized order sum
274
-        $itemized_order_sum_difference = round(
275
-            $this->transaction->total()
276
-            - $this->itemized_order_sum
277
-            - $total_line_item->get_total_tax(),
278
-            $this->decimal_precision
279
-        );
280
-        // If we were not able to recognize some item like promotion, surcharge or cancellation,
281
-        // add the difference as an extra line item.
282
-        if (EEH_Money::compare_floats($itemized_order_sum_difference, 0, '!=')) {
283
-            // Item Name.
284
-            $this->order_items[ "L_PAYMENTREQUEST_0_NAME{$item_num}" ] = mb_strcut(
285
-                esc_html__(
286
-                    'Other (promotion/surcharge/cancellation)',
287
-                    'event_espresso'
288
-                ),
289
-                0,
290
-                127
291
-            );
292
-            // Item description.
293
-            $this->order_items[ "L_PAYMENTREQUEST_0_DESC{$item_num}" ] = '';
294
-            // Cost of individual item.
295
-            $this->order_items[ "L_PAYMENTREQUEST_0_AMT{$item_num}" ] = $this->gateway_data_formatter->formatCurrency(
296
-                $itemized_order_sum_difference,
297
-                $this->decimal_precision
298
-            );
299
-            // Item Number.
300
-            $this->order_items[ "L_PAYMENTREQUEST_0_NUMBER{$item_num}" ] = $item_num + 1;
301
-            // Item quantity.
302
-            $this->order_items[ "L_PAYMENTREQUEST_0_QTY{$item_num}" ] = 1;
303
-            // Digital item is sold.
304
-            $this->order_items[ "L_PAYMENTREQUEST_0_ITEMCATEGORY{$item_num}" ] = 'Physical';
305
-        }
306
-    }
264
+	/**
265
+	 * @param EE_Line_Item $total_line_item
266
+	 * @param int          $item_num
267
+	 * @return void
268
+	 * @throws EE_Error
269
+	 * @throws ReflectionException
270
+	 */
271
+	private function handleItemizedOrderSumDifference(EE_Line_Item $total_line_item, int $item_num)
272
+	{
273
+		// calculate the difference between the TXN total and the itemized order sum
274
+		$itemized_order_sum_difference = round(
275
+			$this->transaction->total()
276
+			- $this->itemized_order_sum
277
+			- $total_line_item->get_total_tax(),
278
+			$this->decimal_precision
279
+		);
280
+		// If we were not able to recognize some item like promotion, surcharge or cancellation,
281
+		// add the difference as an extra line item.
282
+		if (EEH_Money::compare_floats($itemized_order_sum_difference, 0, '!=')) {
283
+			// Item Name.
284
+			$this->order_items[ "L_PAYMENTREQUEST_0_NAME{$item_num}" ] = mb_strcut(
285
+				esc_html__(
286
+					'Other (promotion/surcharge/cancellation)',
287
+					'event_espresso'
288
+				),
289
+				0,
290
+				127
291
+			);
292
+			// Item description.
293
+			$this->order_items[ "L_PAYMENTREQUEST_0_DESC{$item_num}" ] = '';
294
+			// Cost of individual item.
295
+			$this->order_items[ "L_PAYMENTREQUEST_0_AMT{$item_num}" ] = $this->gateway_data_formatter->formatCurrency(
296
+				$itemized_order_sum_difference,
297
+				$this->decimal_precision
298
+			);
299
+			// Item Number.
300
+			$this->order_items[ "L_PAYMENTREQUEST_0_NUMBER{$item_num}" ] = $item_num + 1;
301
+			// Item quantity.
302
+			$this->order_items[ "L_PAYMENTREQUEST_0_QTY{$item_num}" ] = 1;
303
+			// Digital item is sold.
304
+			$this->order_items[ "L_PAYMENTREQUEST_0_ITEMCATEGORY{$item_num}" ] = 'Physical';
305
+		}
306
+	}
307 307
 }
Please login to merge, or discard this patch.
Spacing   +15 added lines, -15 removed lines patch added patch discarded remove patch
@@ -81,7 +81,7 @@  discard block
 block discarded – undo
81 81
                     strpos($arg_key, 'PAYMENTREQUEST_') !== false
82 82
                     && strpos($arg_key, 'NOTIFYURL') === false
83 83
                 ) {
84
-                    $this->order_items[ $arg_key ] = $arg_val;
84
+                    $this->order_items[$arg_key] = $arg_val;
85 85
                 }
86 86
             }
87 87
             // If we only get a few Items then something is not right.
@@ -180,7 +180,7 @@  discard block
 block discarded – undo
180 180
         // Digital item is sold.
181 181
         $this->order_items['L_PAYMENTREQUEST_0_ITEMCATEGORY0'] = 'Physical';
182 182
         // Item's sales S/H and tax amount.
183
-        $this->order_items['PAYMENTREQUEST_0_ITEMAMT']     = $this->gateway_data_formatter->formatCurrency(
183
+        $this->order_items['PAYMENTREQUEST_0_ITEMAMT'] = $this->gateway_data_formatter->formatCurrency(
184 184
             $this->payment->amount(),
185 185
             $this->decimal_precision
186 186
         );
@@ -206,7 +206,7 @@  discard block
 block discarded – undo
206 206
                 if (EEH_Money::compare_floats($line_item->pretaxTotal(), '0.00', '==')) {
207 207
                     continue;
208 208
                 }
209
-                $unit_price         = $this->gateway_data_formatter->formatCurrency(
209
+                $unit_price = $this->gateway_data_formatter->formatCurrency(
210 210
                     $line_item->unit_price(),
211 211
                     $this->decimal_precision
212 212
                 );
@@ -217,25 +217,25 @@  discard block
 block discarded – undo
217 217
                     $line_item_quantity = 1;
218 218
                 }
219 219
                 // Item Name.
220
-                $this->order_items[ "L_PAYMENTREQUEST_0_NAME{$item_num}" ] = mb_strcut(
220
+                $this->order_items["L_PAYMENTREQUEST_0_NAME{$item_num}"] = mb_strcut(
221 221
                     $this->gateway_data_formatter->formatLineItemName($line_item, $this->payment),
222 222
                     0,
223 223
                     127
224 224
                 );
225 225
                 // Item description.
226
-                $this->order_items[ "L_PAYMENTREQUEST_0_DESC{$item_num}" ] = mb_strcut(
226
+                $this->order_items["L_PAYMENTREQUEST_0_DESC{$item_num}"] = mb_strcut(
227 227
                     $this->gateway_data_formatter->formatLineItemDesc($line_item, $this->payment),
228 228
                     0,
229 229
                     127
230 230
                 );
231 231
                 // Cost of individual item.
232
-                $this->order_items[ "L_PAYMENTREQUEST_0_AMT{$item_num}" ] = $unit_price;
232
+                $this->order_items["L_PAYMENTREQUEST_0_AMT{$item_num}"] = $unit_price;
233 233
                 // Item Number.
234
-                $this->order_items[ "L_PAYMENTREQUEST_0_NUMBER{$item_num}" ] = $item_num + 1;
234
+                $this->order_items["L_PAYMENTREQUEST_0_NUMBER{$item_num}"] = $item_num + 1;
235 235
                 // Item quantity.
236
-                $this->order_items[ "L_PAYMENTREQUEST_0_QTY{$item_num}" ] = $line_item_quantity;
236
+                $this->order_items["L_PAYMENTREQUEST_0_QTY{$item_num}"] = $line_item_quantity;
237 237
                 // Digital item is sold.
238
-                $this->order_items[ "L_PAYMENTREQUEST_0_ITEMCATEGORY{$item_num}" ] = 'Physical';
238
+                $this->order_items["L_PAYMENTREQUEST_0_ITEMCATEGORY{$item_num}"] = 'Physical';
239 239
                 // add item total to order sum
240 240
                 $this->itemized_order_sum += $unit_price * $line_item_quantity;
241 241
                 ++$item_num;
@@ -281,7 +281,7 @@  discard block
 block discarded – undo
281 281
         // add the difference as an extra line item.
282 282
         if (EEH_Money::compare_floats($itemized_order_sum_difference, 0, '!=')) {
283 283
             // Item Name.
284
-            $this->order_items[ "L_PAYMENTREQUEST_0_NAME{$item_num}" ] = mb_strcut(
284
+            $this->order_items["L_PAYMENTREQUEST_0_NAME{$item_num}"] = mb_strcut(
285 285
                 esc_html__(
286 286
                     'Other (promotion/surcharge/cancellation)',
287 287
                     'event_espresso'
@@ -290,18 +290,18 @@  discard block
 block discarded – undo
290 290
                 127
291 291
             );
292 292
             // Item description.
293
-            $this->order_items[ "L_PAYMENTREQUEST_0_DESC{$item_num}" ] = '';
293
+            $this->order_items["L_PAYMENTREQUEST_0_DESC{$item_num}"] = '';
294 294
             // Cost of individual item.
295
-            $this->order_items[ "L_PAYMENTREQUEST_0_AMT{$item_num}" ] = $this->gateway_data_formatter->formatCurrency(
295
+            $this->order_items["L_PAYMENTREQUEST_0_AMT{$item_num}"] = $this->gateway_data_formatter->formatCurrency(
296 296
                 $itemized_order_sum_difference,
297 297
                 $this->decimal_precision
298 298
             );
299 299
             // Item Number.
300
-            $this->order_items[ "L_PAYMENTREQUEST_0_NUMBER{$item_num}" ] = $item_num + 1;
300
+            $this->order_items["L_PAYMENTREQUEST_0_NUMBER{$item_num}"] = $item_num + 1;
301 301
             // Item quantity.
302
-            $this->order_items[ "L_PAYMENTREQUEST_0_QTY{$item_num}" ] = 1;
302
+            $this->order_items["L_PAYMENTREQUEST_0_QTY{$item_num}"] = 1;
303 303
             // Digital item is sold.
304
-            $this->order_items[ "L_PAYMENTREQUEST_0_ITEMCATEGORY{$item_num}" ] = 'Physical';
304
+            $this->order_items["L_PAYMENTREQUEST_0_ITEMCATEGORY{$item_num}"] = 'Physical';
305 305
         }
306 306
     }
307 307
 }
Please login to merge, or discard this patch.
payment_methods/Paypal_Express/TokenRequest.php 2 patches
Indentation   +113 added lines, -113 removed lines patch added patch discarded remove patch
@@ -13,124 +13,124 @@
 block discarded – undo
13 13
 class TokenRequest
14 14
 {
15 15
 
16
-    /**
17
-     * @var GatewayDataFormatterInterface
18
-     */
19
-    protected $gateway_data_formatter;
16
+	/**
17
+	 * @var GatewayDataFormatterInterface
18
+	 */
19
+	protected $gateway_data_formatter;
20 20
 
21 21
 
22
-    /**
23
-     * @param GatewayDataFormatterInterface $gateway_data_formatter
24
-     */
25
-    public function __construct(GatewayDataFormatterInterface $gateway_data_formatter)
26
-    {
27
-        $this->gateway_data_formatter = $gateway_data_formatter;
28
-    }
22
+	/**
23
+	 * @param GatewayDataFormatterInterface $gateway_data_formatter
24
+	 */
25
+	public function __construct(GatewayDataFormatterInterface $gateway_data_formatter)
26
+	{
27
+		$this->gateway_data_formatter = $gateway_data_formatter;
28
+	}
29 29
 
30 30
 
31
-    /**
32
-     * @param EE_Payment $payment
33
-     * @param array      $itemized_order
34
-     * @param string     $return_url
35
-     * @param string     $cancel_url
36
-     * @param string     $logo_image_url
37
-     * @param bool       $request_shipping_address
38
-     * @return array
39
-     * @throws EE_Error
40
-     * @throws ReflectionException
41
-     */
42
-    public function generateDetails(
43
-        EE_Payment $payment,
44
-        array $itemized_order = [],
45
-        string $return_url = '',
46
-        string $cancel_url = '',
47
-        string $logo_image_url = '',
48
-        bool $request_shipping_address = false
49
-    ): array {
50
-        $locale = explode('-', get_bloginfo('language'));
51
-        // Gather request parameters.
52
-        $token_request_details = [
53
-            'METHOD'                         => 'SetExpressCheckout',
54
-            'PAYMENTREQUEST_0_AMT'           => $payment->amount(),
55
-            'PAYMENTREQUEST_0_CURRENCYCODE'  => $payment->currency_code(),
56
-            'PAYMENTREQUEST_0_DESC'          => mb_strcut(
57
-                $this->gateway_data_formatter->formatOrderDescription($payment),
58
-                0,
59
-                127
60
-            ),
61
-            'RETURNURL'                      => $return_url,
62
-            'CANCELURL'                      => $cancel_url,
63
-            'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale',
64
-            // Buyer does not need to create a PayPal account to check out.
65
-            // This is referred to as PayPal Account Optional.
66
-            'SOLUTIONTYPE'                   => 'Sole',
67
-            // Locale of the pages displayed by PayPal during Express Checkout.
68
-            'LOCALECODE'                     => $locale[1],
69
-        ];
70
-        $token_request_details = array_merge($token_request_details, $itemized_order);
71
-        if (! $request_shipping_address) {
72
-            // Do not request shipping details on the PP Checkout page.
73
-            $token_request_details['NOSHIPPING']         = '1';
74
-            $token_request_details['REQCONFIRMSHIPPING'] = '0';
75
-        } else {
76
-            // Automatically filling out shipping and contact information.
77
-            $transaction          = $payment->transaction();
78
-            $primary_registration = $transaction->primary_registration();
79
-            $primary_attendee     = $primary_registration instanceof EE_Registration
80
-                ? $primary_registration->attendee()
81
-                : false;
82
-            if ($primary_attendee instanceof EE_Attendee) {
83
-                // If you do not pass the shipping address, PayPal obtains it from the buyer's account profile.
84
-                $token_request_details['NOSHIPPING']                         = '2';
85
-                $token_request_details['PAYMENTREQUEST_0_SHIPTOSTREET']      = $primary_attendee->address();
86
-                $token_request_details['PAYMENTREQUEST_0_SHIPTOSTREET2']     = $primary_attendee->address2();
87
-                $token_request_details['PAYMENTREQUEST_0_SHIPTOCITY']        = $primary_attendee->city();
88
-                $token_request_details['PAYMENTREQUEST_0_SHIPTOSTATE']       = $primary_attendee->state_abbrev();
89
-                $token_request_details['PAYMENTREQUEST_0_SHIPTOCOUNTRYCODE'] = $primary_attendee->country_ID();
90
-                $token_request_details['PAYMENTREQUEST_0_SHIPTOZIP']         = $primary_attendee->zip();
91
-                $token_request_details['PAYMENTREQUEST_0_EMAIL']             = $primary_attendee->email();
92
-                $token_request_details['PAYMENTREQUEST_0_SHIPTOPHONENUM']    = $primary_attendee->phone();
93
-            }
94
-        }
95
-        // Used a business/personal logo on the PayPal page.
96
-        if (! empty($logo_image_url)) {
97
-            $token_request_details['LOGOIMG'] = $logo_image_url;
98
-        }
99
-        return $token_request_details;
100
-    }
31
+	/**
32
+	 * @param EE_Payment $payment
33
+	 * @param array      $itemized_order
34
+	 * @param string     $return_url
35
+	 * @param string     $cancel_url
36
+	 * @param string     $logo_image_url
37
+	 * @param bool       $request_shipping_address
38
+	 * @return array
39
+	 * @throws EE_Error
40
+	 * @throws ReflectionException
41
+	 */
42
+	public function generateDetails(
43
+		EE_Payment $payment,
44
+		array $itemized_order = [],
45
+		string $return_url = '',
46
+		string $cancel_url = '',
47
+		string $logo_image_url = '',
48
+		bool $request_shipping_address = false
49
+	): array {
50
+		$locale = explode('-', get_bloginfo('language'));
51
+		// Gather request parameters.
52
+		$token_request_details = [
53
+			'METHOD'                         => 'SetExpressCheckout',
54
+			'PAYMENTREQUEST_0_AMT'           => $payment->amount(),
55
+			'PAYMENTREQUEST_0_CURRENCYCODE'  => $payment->currency_code(),
56
+			'PAYMENTREQUEST_0_DESC'          => mb_strcut(
57
+				$this->gateway_data_formatter->formatOrderDescription($payment),
58
+				0,
59
+				127
60
+			),
61
+			'RETURNURL'                      => $return_url,
62
+			'CANCELURL'                      => $cancel_url,
63
+			'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale',
64
+			// Buyer does not need to create a PayPal account to check out.
65
+			// This is referred to as PayPal Account Optional.
66
+			'SOLUTIONTYPE'                   => 'Sole',
67
+			// Locale of the pages displayed by PayPal during Express Checkout.
68
+			'LOCALECODE'                     => $locale[1],
69
+		];
70
+		$token_request_details = array_merge($token_request_details, $itemized_order);
71
+		if (! $request_shipping_address) {
72
+			// Do not request shipping details on the PP Checkout page.
73
+			$token_request_details['NOSHIPPING']         = '1';
74
+			$token_request_details['REQCONFIRMSHIPPING'] = '0';
75
+		} else {
76
+			// Automatically filling out shipping and contact information.
77
+			$transaction          = $payment->transaction();
78
+			$primary_registration = $transaction->primary_registration();
79
+			$primary_attendee     = $primary_registration instanceof EE_Registration
80
+				? $primary_registration->attendee()
81
+				: false;
82
+			if ($primary_attendee instanceof EE_Attendee) {
83
+				// If you do not pass the shipping address, PayPal obtains it from the buyer's account profile.
84
+				$token_request_details['NOSHIPPING']                         = '2';
85
+				$token_request_details['PAYMENTREQUEST_0_SHIPTOSTREET']      = $primary_attendee->address();
86
+				$token_request_details['PAYMENTREQUEST_0_SHIPTOSTREET2']     = $primary_attendee->address2();
87
+				$token_request_details['PAYMENTREQUEST_0_SHIPTOCITY']        = $primary_attendee->city();
88
+				$token_request_details['PAYMENTREQUEST_0_SHIPTOSTATE']       = $primary_attendee->state_abbrev();
89
+				$token_request_details['PAYMENTREQUEST_0_SHIPTOCOUNTRYCODE'] = $primary_attendee->country_ID();
90
+				$token_request_details['PAYMENTREQUEST_0_SHIPTOZIP']         = $primary_attendee->zip();
91
+				$token_request_details['PAYMENTREQUEST_0_EMAIL']             = $primary_attendee->email();
92
+				$token_request_details['PAYMENTREQUEST_0_SHIPTOPHONENUM']    = $primary_attendee->phone();
93
+			}
94
+		}
95
+		// Used a business/personal logo on the PayPal page.
96
+		if (! empty($logo_image_url)) {
97
+			$token_request_details['LOGOIMG'] = $logo_image_url;
98
+		}
99
+		return $token_request_details;
100
+	}
101 101
 
102 102
 
103
-    /**
104
-     * @param EE_Payment $payment
105
-     * @param array      $token_request_status
106
-     * @param bool       $is_in_sandbox_mode
107
-     * @throws EE_Error
108
-     * @throws ReflectionException
109
-     */
110
-    public function processResponse(EE_Payment $payment, array $token_request_status, bool $is_in_sandbox_mode)
111
-    {
112
-        $response_args = (isset($token_request_status['args']) && is_array($token_request_status['args']))
113
-            ? $token_request_status['args']
114
-            : [];
115
-        if ($token_request_status['status']) {
116
-            // We got the Token so we may continue with the payment and redirect the client.
117
-            $payment->set_details($response_args);
118
-            $gateway_url = $is_in_sandbox_mode ? 'https://www.sandbox.paypal.com' : 'https://www.paypal.com';
119
-            $token       = $response_args['TOKEN'];
120
-            $payment->set_redirect_url(
121
-                "{$gateway_url}/checkoutnow?useraction=commit&cmd=_express-checkout&token={$token}"
122
-            );
123
-            return;
124
-        }
125
-        $gateway_response = isset($response_args['L_ERRORCODE'])
126
-            ? $response_args['L_ERRORCODE'] . '; ' . $response_args['L_SHORTMESSAGE']
127
-            : esc_html__(
128
-                'Error occurred while trying to setup the Express Checkout.',
129
-                'event_espresso'
130
-            );
103
+	/**
104
+	 * @param EE_Payment $payment
105
+	 * @param array      $token_request_status
106
+	 * @param bool       $is_in_sandbox_mode
107
+	 * @throws EE_Error
108
+	 * @throws ReflectionException
109
+	 */
110
+	public function processResponse(EE_Payment $payment, array $token_request_status, bool $is_in_sandbox_mode)
111
+	{
112
+		$response_args = (isset($token_request_status['args']) && is_array($token_request_status['args']))
113
+			? $token_request_status['args']
114
+			: [];
115
+		if ($token_request_status['status']) {
116
+			// We got the Token so we may continue with the payment and redirect the client.
117
+			$payment->set_details($response_args);
118
+			$gateway_url = $is_in_sandbox_mode ? 'https://www.sandbox.paypal.com' : 'https://www.paypal.com';
119
+			$token       = $response_args['TOKEN'];
120
+			$payment->set_redirect_url(
121
+				"{$gateway_url}/checkoutnow?useraction=commit&cmd=_express-checkout&token={$token}"
122
+			);
123
+			return;
124
+		}
125
+		$gateway_response = isset($response_args['L_ERRORCODE'])
126
+			? $response_args['L_ERRORCODE'] . '; ' . $response_args['L_SHORTMESSAGE']
127
+			: esc_html__(
128
+				'Error occurred while trying to setup the Express Checkout.',
129
+				'event_espresso'
130
+			);
131 131
 
132
-        $payment->set_gateway_response($gateway_response);
133
-        $payment->set_details($response_args);
134
-        $payment->set_status(EEM_Payment::instance()->failed_status());
135
-    }
132
+		$payment->set_gateway_response($gateway_response);
133
+		$payment->set_details($response_args);
134
+		$payment->set_status(EEM_Payment::instance()->failed_status());
135
+	}
136 136
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -68,7 +68,7 @@  discard block
 block discarded – undo
68 68
             'LOCALECODE'                     => $locale[1],
69 69
         ];
70 70
         $token_request_details = array_merge($token_request_details, $itemized_order);
71
-        if (! $request_shipping_address) {
71
+        if ( ! $request_shipping_address) {
72 72
             // Do not request shipping details on the PP Checkout page.
73 73
             $token_request_details['NOSHIPPING']         = '1';
74 74
             $token_request_details['REQCONFIRMSHIPPING'] = '0';
@@ -93,7 +93,7 @@  discard block
 block discarded – undo
93 93
             }
94 94
         }
95 95
         // Used a business/personal logo on the PayPal page.
96
-        if (! empty($logo_image_url)) {
96
+        if ( ! empty($logo_image_url)) {
97 97
             $token_request_details['LOGOIMG'] = $logo_image_url;
98 98
         }
99 99
         return $token_request_details;
@@ -123,7 +123,7 @@  discard block
 block discarded – undo
123 123
             return;
124 124
         }
125 125
         $gateway_response = isset($response_args['L_ERRORCODE'])
126
-            ? $response_args['L_ERRORCODE'] . '; ' . $response_args['L_SHORTMESSAGE']
126
+            ? $response_args['L_ERRORCODE'].'; '.$response_args['L_SHORTMESSAGE']
127 127
             : esc_html__(
128 128
                 'Error occurred while trying to setup the Express Checkout.',
129 129
                 'event_espresso'
Please login to merge, or discard this patch.
payment_methods/Paypal_Express/polyfills.php 2 patches
Indentation   +14 added lines, -14 removed lines patch added patch discarded remove patch
@@ -1,18 +1,18 @@
 block discarded – undo
1 1
 <?php
2 2
 
3 3
 if (! function_exists('mb_strcut')) {
4
-    /**
5
-     * Quickfix to address https://events.codebasehq.com/projects/event-espresso/tickets/11089 ASAP
6
-     * Very simple mimic of mb_substr (which WP ensures exists in wp-includes/compat.php). Still has all the problems of mb_substr
7
-     * (namely, that we might send too many characters to PayPal; however in this case they just issue a warning but nothing breaks)
8
-     *
9
-     * @param $string
10
-     * @param $start
11
-     * @param $length
12
-     * @return string
13
-     */
14
-    function mb_strcut($string, $start, $length = null): string
15
-    {
16
-        return mb_substr($string, $start, $length);
17
-    }
4
+	/**
5
+	 * Quickfix to address https://events.codebasehq.com/projects/event-espresso/tickets/11089 ASAP
6
+	 * Very simple mimic of mb_substr (which WP ensures exists in wp-includes/compat.php). Still has all the problems of mb_substr
7
+	 * (namely, that we might send too many characters to PayPal; however in this case they just issue a warning but nothing breaks)
8
+	 *
9
+	 * @param $string
10
+	 * @param $start
11
+	 * @param $length
12
+	 * @return string
13
+	 */
14
+	function mb_strcut($string, $start, $length = null): string
15
+	{
16
+		return mb_substr($string, $start, $length);
17
+	}
18 18
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -1,6 +1,6 @@
 block discarded – undo
1 1
 <?php
2 2
 
3
-if (! function_exists('mb_strcut')) {
3
+if ( ! function_exists('mb_strcut')) {
4 4
     /**
5 5
      * Quickfix to address https://events.codebasehq.com/projects/event-espresso/tickets/11089 ASAP
6 6
      * Very simple mimic of mb_substr (which WP ensures exists in wp-includes/compat.php). Still has all the problems of mb_substr
Please login to merge, or discard this patch.