Passed
Push — master ( ece56d...190d73 )
by Brian
09:21 queued 04:12
created

GetPaid_Checkout::process_checkout()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 21
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 10
c 0
b 0
f 0
dl 0
loc 21
rs 9.9332
cc 1
nc 1
nop 0
1
<?php
2
/**
3
 * Contains the Main Checkout Class.
4
 *
5
 */
6
7
defined( 'ABSPATH' ) || exit;
8
9
/**
10
 * Main Checkout Class.
11
 *
12
 */
13
class GetPaid_Checkout {
14
15
	/**
16
	 * @var GetPaid_Payment_Form_Submission
17
	 */
18
	protected $payment_form_submission;
19
20
	/**
21
	 * Class constructor.
22
	 * 
23
	 * @param GetPaid_Payment_Form_Submission $submission
24
	 */
25
	public function __construct( $submission ) {
26
		$this->payment_form_submission = $submission;
27
	}
28
29
	/**
30
	 * Processes the checkout.
31
	 *
32
	 */
33
	public function process_checkout() {
34
35
		// Validate the submission.
36
		$this->validate_submission();
37
38
		// Prepare the invoice.
39
		$items      = $this->get_submission_items();
40
		$invoice    = $this->get_submission_invoice();
41
		$invoice    = $this->process_submission_invoice( $invoice, $items );
42
		$prepared   = $this->prepare_submission_data_for_saving();
43
44
		$this->prepare_billing_info( $invoice );
45
46
		$shipping   = $this->prepare_shipping_info( $invoice );
47
48
		// Save the invoice.
49
		$invoice->recalculate_total();
50
        $invoice->save();
51
52
		// Send to the gateway.
53
		$this->post_process_submission( $invoice, $prepared, $shipping );
54
	}
55
56
	/**
57
	 * Validates the submission.
58
	 *
59
	 */
60
	protected function validate_submission() {
61
62
		$submission = $this->payment_form_submission;
63
		$data       = $submission->get_data();
64
65
		// Do we have an error?
66
        if ( ! empty( $submission->last_error ) ) {
67
			wp_send_json_error( $submission->last_error );
68
        }
69
70
		// We need a billing email.
71
        if ( ! $submission->has_billing_email() ) {
72
            wp_send_json_error( __( 'Provide a valid billing email.', 'invoicing' ) );
73
		}
74
75
		// Non-recurring gateways should not be allowed to process recurring invoices.
76
		if ( $submission->should_collect_payment_details() && $submission->has_recurring && ! wpinv_gateway_support_subscription( $data['wpi-gateway'] ) ) {
77
			wp_send_json_error( __( 'The selected payment gateway does not support subscription payments.', 'invoicing' ) );
78
		}
79
80
		// Ensure the gateway is active.
81
		if ( $submission->should_collect_payment_details() && ! wpinv_is_gateway_active( $data['wpi-gateway'] ) ) {
82
			wpinv_set_error( 'invalid_gateway', __( 'The selected payment gateway is not active', 'invoicing' ) );
83
		}
84
85
		// Clear any existing errors.
86
		wpinv_clear_errors();
87
88
		// Allow themes and plugins to hook to errors
89
		do_action( 'getpaid_checkout_error_checks', $submission );
90
91
		// Do we have any errors?
92
        if ( wpinv_get_errors() ) {
93
            wp_send_json_error( getpaid_get_errors_html() );
94
		}
95
96
	}
97
98
	/**
99
	 * Retrieves submission items.
100
	 *
101
	 * @return GetPaid_Form_Item[]
102
	 */
103
	protected function get_submission_items() {
104
105
		$items = $this->payment_form_submission->get_items();
106
107
        // Ensure that we have items.
108
        if ( empty( $items ) && ! $this->payment_form_submission->has_fees() ) {
109
            wp_send_json_error( __( 'Please provide at least one item or amount.', 'invoicing' ) );
110
		}
111
112
		return $items;
113
	}
114
115
	/**
116
	 * Retrieves submission invoice.
117
	 *
118
	 * @return WPInv_Invoice
119
	 */
120
	protected function get_submission_invoice() {
121
		$submission = $this->payment_form_submission;
122
123
		if ( ! $submission->has_invoice() ) {
124
			$invoice = new WPInv_Invoice();
125
			$invoice->created_via( 'payment_form' );
126
			return $invoice;
127
        }
128
129
		$invoice = $submission->get_invoice();
130
131
		// Make sure that it is neither paid or refunded.
132
		if ( $invoice->is_paid() || $invoice->is_refunded() ) {
133
			wp_send_json_error( __( 'This invoice has already been paid for.', 'invoicing' ) );
134
		}
135
136
		return $invoice;
137
	}
138
139
	/**
140
	 * Processes the submission invoice.
141
	 *
142
	 * @param WPInv_Invoice $invoice
143
	 * @param GetPaid_Form_Item[] $items
144
	 * @return WPInv_Invoice
145
	 */
146
	protected function process_submission_invoice( $invoice, $items ) {
147
148
		$submission = $this->payment_form_submission;
149
		$data       = $submission->get_data();
150
151
		// Set-up the invoice details.
152
		$invoice->set_email( sanitize_email( $submission->get_billing_email() ) );
153
		$invoice->set_user_id( $this->get_submission_customer() );
154
		$invoice->set_payment_form( absint( $submission->get_payment_form()->get_id() ) );
155
        $invoice->set_items( $items );
156
        $invoice->set_fees( $submission->get_fees() );
157
        $invoice->set_taxes( $submission->get_taxes() );
158
		$invoice->set_discounts( $submission->get_discounts() );
159
		$invoice->set_gateway( $data['wpi-gateway'] );
160
161
		if ( $submission->has_discount_code() ) {
162
            $invoice->set_discount_code( $submission->get_discount_code() );
163
		}
164
165
		getpaid_maybe_add_default_address( $invoice );
166
		return $invoice;
167
	}
168
169
	/**
170
	 * Retrieves the submission's customer.
171
	 *
172
	 * @return int The customer id.
173
	 */
174
	protected function get_submission_customer() {
175
		$submission = $this->payment_form_submission;
176
177
		// If this is an existing invoice...
178
		if ( $submission->has_invoice() ) {
179
			return $submission->get_invoice()->get_user_id();
180
		}
181
182
		// (Maybe) create the user.
183
        $user = get_current_user_id();
184
185
        if ( empty( $user ) ) {
186
            $user = get_user_by( 'email', $submission->get_billing_email() );
187
        }
188
189
        if ( empty( $user ) ) {
190
            $user = wpinv_create_user( $submission->get_billing_email() );
191
        }
192
193
        if ( is_wp_error( $user ) ) {
194
            wp_send_json_error( $user->get_error_message() );
195
        }
196
197
        if ( is_numeric( $user ) ) {
198
            return $user;
199
		}
200
201
		return $user->ID;
0 ignored issues
show
Bug introduced by
The property ID does not seem to exist on WP_Error.
Loading history...
202
203
	}
204
205
	/**
206
     * Prepares submission data for saving to the database.
207
     *
208
	 * @return array
209
     */
210
    public function prepare_submission_data_for_saving() {
211
212
		$submission = $this->payment_form_submission;
213
214
		// Prepared submission details.
215
        $prepared = array();
216
217
        // Raw submission details.
218
		$data     = $submission->get_data();
219
220
		// Loop through the submitted details.
221
        foreach ( $submission->get_payment_form()->get_elements() as $field ) {
222
223
			// Skip premade fields.
224
            if ( ! empty( $field['premade'] ) || $field['type'] == 'address' ) {
225
                continue;
226
            }
227
228
            // If it is required and not set, abort.
229
            if ( ! $submission->is_required_field_set( $field ) ) {
230
                wp_send_json_error( __( 'Please fill all required fields.', 'invoicing' ) );
231
            }
232
233
            // Handle misc fields.
234
            if ( isset( $data[ $field['id'] ] ) ) {
235
                $label = $field['id'];
236
237
                if ( isset( $field['label'] ) ) {
238
                    $label = $field['label'];
239
                }
240
241
				$prepared[ wpinv_clean( $label ) ] = wp_kses_post( $data[ $field['id'] ] );
242
243
            }
244
245
		}
246
247
		return $prepared;
248
249
	}
250
251
	/**
252
     * Retrieves address details.
253
     *
254
	 * @return array
255
	 * @param WPInv_Invoice $invoice
256
	 * @param string $type
257
     */
258
    public function prepare_address_details( $invoice, $type = 'billing' ) {
259
260
		$data     = $this->payment_form_submission->get_data();
261
		$type     = sanitize_key( $type );
262
		$address  = array();
263
		$prepared = array();
264
265
		if ( ! empty( $data[ $type ] ) ) {
266
			$address = $data[ $type ];
267
		}
268
269
		// Clean address details.
270
		foreach ( $address as $key => $value ) {
271
			$key             = sanitize_key( $key );
272
			$key             = str_replace( 'wpinv_', '', $key );
273
			$value           = wpinv_clean( $value );
274
			$prepared[ $key] = apply_filters( "getpaid_checkout_{$type}_address_$key", $value, $this->payment_form_submission, $invoice );
275
		}
276
277
		// Filter address details.
278
		$prepared = apply_filters( "getpaid_checkout_{$type}_address", $prepared, $this->payment_form_submission, $invoice );
279
280
		// Remove non-whitelisted values.
281
		return array_filter( $prepared, 'getpaid_is_address_field_whitelisted', ARRAY_FILTER_USE_KEY );
282
283
	}
284
285
	/**
286
     * Prepares the billing details.
287
     *
288
	 * @return array
289
	 * @param WPInv_Invoice $invoice
290
     */
291
    protected function prepare_billing_info( &$invoice ) {
292
293
		$billing_address = $this->prepare_address_details( $invoice, 'billing' );
294
295
		// Update the invoice with the billing details.
296
		$invoice->set_props( $billing_address );
297
298
	}
299
300
	/**
301
     * Prepares the shipping details.
302
     *
303
	 * @return array
304
	 * @param WPInv_Invoice $invoice
305
     */
306
    protected function prepare_shipping_info( $invoice ) {
307
308
		$data = $this->payment_form_submission->get_data();
309
310
		if ( empty( $data['same-shipping-address'] ) ) {
311
			return $this->prepare_address_details( $invoice, 'shipping' );
312
		}
313
314
		return $this->prepare_address_details( $invoice, 'billing' );
315
316
	}
317
318
	/**
319
	 * Confirms the submission is valid and send users to the gateway.
320
	 *
321
	 * @param WPInv_Invoice $invoice
322
	 * @param array $prepared_payment_form_data
323
	 * @param array $shipping
324
	 */
325
	protected function post_process_submission( $invoice, $prepared_payment_form_data, $shipping ) {
326
327
		// Ensure the invoice exists.
328
        if ( ! $invoice->exists() ) {
329
            wp_send_json_error( __( 'An error occured while saving your invoice. Please try again.', 'invoicing' ) );
330
        }
331
332
        // Save payment form data.
333
        if ( ! empty( $prepared_payment_form_data ) ) {
334
            update_post_meta( $invoice->get_id(), 'payment_form_data', $prepared_payment_form_data );
335
		}
336
337
		// Save payment form data.
338
        if ( ! empty( $shipping ) ) {
339
            update_post_meta( $invoice->get_id(), 'shipping_address', $shipping );
340
		}
341
342
		// Backwards compatibility.
343
        add_filter( 'wp_redirect', array( $this, 'send_redirect_response' ) );
344
345
		$this->process_payment( $invoice );
346
347
        // If we are here, there was an error.
348
		wpinv_send_back_to_checkout();
349
350
	}
351
352
	/**
353
	 * Processes the actual payment.
354
	 *
355
	 * @param WPInv_Invoice $invoice
356
	 */
357
	protected function process_payment( $invoice ) {
358
359
		// Clear any checkout errors.
360
		wpinv_clear_errors();
361
362
		// No need to send free invoices to the gateway.
363
		if ( $invoice->is_free() ) {
364
			$this->process_free_payment( $invoice );
365
		}
366
367
		$submission = $this->payment_form_submission;
368
369
		// Fires before sending to the gateway.
370
		do_action( 'getpaid_checkout_before_gateway', $invoice, $submission );
371
372
		// Allow the sumission data to be modified before it is sent to the gateway.
373
		$submission_data    = $submission->get_data();
374
		$submission_gateway = apply_filters( 'getpaid_gateway_submission_gateway', $invoice->get_gateway(), $submission, $invoice );
375
		$submission_data    = apply_filters( 'getpaid_gateway_submission_data', $submission_data, $submission, $invoice );
376
377
		// Validate the currency.
378
		if ( ! apply_filters( "getpaid_gateway_{$submission_gateway}_is_valid_for_currency", true, $invoice->get_currency() ) ) {
379
			wpinv_set_error( 'invalid_currency', __( 'The chosen payment gateway does not support this currency', 'invoicing' ) );
380
		}
381
382
		// Check to see if we have any errors.
383
		if ( wpinv_get_errors() ) {
384
			wpinv_send_back_to_checkout();
385
		}
386
387
		// Send info to the gateway for payment processing
388
		do_action( "getpaid_gateway_$submission_gateway", $invoice, $submission_data, $submission );
389
390
		// Backwards compatibility.
391
		wpinv_send_to_gateway( $submission_gateway, $invoice );
0 ignored issues
show
Deprecated Code introduced by
The function wpinv_send_to_gateway() has been deprecated. ( Ignorable by Annotation )

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

391
		/** @scrutinizer ignore-deprecated */ wpinv_send_to_gateway( $submission_gateway, $invoice );
Loading history...
392
393
	}
394
395
	/**
396
	 * Marks the invoice as paid in case the checkout is free.
397
	 *
398
	 * @param WPInv_Invoice $invoice
399
	 */
400
	protected function process_free_payment( $invoice ) {
401
402
		$invoice->set_gateway( 'none' );
403
		$invoice->add_note( __( "This is a free invoice and won't be sent to the payment gateway", 'invoicing' ), false, false, true );
404
		$invoice->mark_paid();
405
		wpinv_send_to_success_page( array( 'invoice_key' => $invoice->get_key() ) );
406
407
	}
408
409
	/**
410
     * Sends a redrect response to payment details.
411
     *
412
     */
413
    public function send_redirect_response( $url ) {
414
        $url = urlencode( $url );
415
        wp_send_json_success( $url );
416
    }
417
418
}
419