PluginProbe
SureCart – Ecommerce Made Easy For Selling Physical Products, Digital Downloads, Subscriptions, Donations, & Payments / 1.2.5
SureCart – Ecommerce Made Easy For Selling Physical Products, Digital Downloads, Subscriptions, Donations, & Payments v1.2.5
4.7.2 4.7.1 4.7.0 4.6.6 4.6.5 4.6.4 4.6.3 4.6.2 4.6.1 4.6.0 4.5.1 4.5.0 4.4.2 4.4.1 4.4.0 4.3.3 4.3.2 4.3.1 4.3.0 4.2.3 4.2.2 4.2.1 1.0.3 1.0.4 1.0.5 All 281 releases
surecart / app / src / Controllers / Rest / CheckoutsController.php

CheckoutsController.php in SureCart – Ecommerce Made Easy For Selling Physical Products, Digital Downloads, Subscriptions, Donations, & Payments 1.2.5, at app/src/Controllers/Rest/CheckoutsController.php

348 lines 9.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace SureCart\Controllers\Rest;
4
5 use SureCart\Models\Checkout;
6 use SureCart\Models\Form;
7 use SureCart\Models\User;
8 use SureCart\WordPress\Users\CustomerLinkService;
9 use SureCart\WordPress\RecaptchaValidationService;
10
11 /**
12 * Handle price requests through the REST API
13 */
14 class CheckoutsController extends RestController {
15 /**
16 * Class to make the requests.
17 *
18 * @var string
19 */
20 protected $class = Checkout::class;
21
22 /**
23 * Middleware before we make the request.
24 *
25 * @param \SureCart\Models\Model $class Model class instance.
26 * @param \WP_REST_Request $request Request object.
27 *
28 * @return \SureCart\Models\Model|\WP_Error
29 */
30 protected function middleware( $class, \WP_REST_Request $request ) {
31 $class = $this->setMode( $class, $request );
32 if ( is_wp_error( $class ) ) {
33 return $class;
34 }
35 $class = $this->maybeSetUser( $class, $request );
36
37 return $class;
38 }
39
40 /**
41 * Edit model.
42 *
43 * @param \WP_REST_Request $request Rest Request.
44 *
45 * @return \WP_REST_Response|\WP_Error
46 */
47 public function edit( \WP_REST_Request $request ) {
48 // if we have a password, hash it and set it in a transient.
49 // we need to do this because some processors will redirect and we will lose this form data.
50 if ( ! empty( $request->get_param( 'password' ) ) ) {
51 set_transient( 'sc_checkout_password_hash_' . $request['id'], wp_hash_password( $request->get_param( 'password' ) ), DAY_IN_SECONDS );
52 }
53
54 // edit the checkout.
55 $response = parent::edit( $request );
56
57 // check if the email exists and set on record.
58 if ( apply_filters( 'surecart/checkout/finduser', true ) ) {
59 if ( ! empty( $response->email ) ) {
60 $response->email_exists = (bool) email_exists( $response->email );
61 }
62 }
63
64 return $response;
65 }
66
67 /**
68 * Let's set the customer's email and name if they are already logged in.
69 *
70 * @param \SureCart\Models\Model $class Model class instance.
71 * @param \WP_REST_Request $request Request object.
72 *
73 * @return \SureCart\Models\Model|\WP_Error
74 */
75 protected function maybeSetUser( \SureCart\Models\Model $class, \WP_REST_Request $request ) {
76 // we only care about new sessions for now.
77 if ( $request->get_method() !== 'POST' ) {
78 return $class;
79 }
80
81 // get current user.
82 $user = User::current();
83
84 // must be logged in.
85 if ( ! $user ) {
86 return $class;
87 }
88
89 // fetch the user's customer object.
90 $customer = $user->customerId( ! empty( $request['live_mode'] ) ? 'live' : 'test' );
91
92 if ( ! empty( $customer->id ) ) {
93 $class['customer'] = $customer->id;
94 }
95
96 $class['email'] = $customer->email ?? $user->user_email;
97 $class['name'] = $customer->name ?? $user->display_name;
98
99 return $class;
100 }
101
102 /**
103 * We run middleware to make sure the form is in "Test" mode
104 * if a test payment is requested. This prevents the spamming of any
105 * forms on your site that are not in test mode.
106 *
107 * @param \SureCart\Models\Model $class Model class instance.
108 * @param \WP_REST_Request $request Request object.
109 *
110 * @return \SureCart\Models\Model|\WP_Error
111 */
112 protected function setMode( \SureCart\Models\Model $class, \WP_REST_Request $request ) {
113 $mode = 'live';
114 if ( false === $request['live_mode'] && ! current_user_can( 'edit_sc_orders' ) ) {
115 $mode = isset( $request['form_id'] ) ? $this->getFormMode( $request['form_id'] ) : 'live';
116 if ( 'test' !== $mode ) {
117 return new \WP_Error( 'invalid_mode', 'The form is set to live mode, but the request is for test mode.', [ 'status' => 400 ] );
118 }
119 $mode = 'test';
120 }
121 return $class;
122 }
123
124 /**
125 * Get the form mode
126 *
127 * @param integer $id ID of the form.
128 * @return string Mode of the form.
129 */
130 protected function getFormMode( $id ) {
131 return Form::getMode( (int) $id );
132 }
133
134 /**
135 * Manually pay an order.
136 *
137 * @param \WP_REST_Request $request Rest Request.
138 *
139 * @return \SureCart\Models\Checkout|\WP_Error
140 */
141 public function manuallyPay( \WP_REST_Request $request ) {
142 $checkout = $this->middleware( new $this->class( $request['id'] ), $request );
143 if ( is_wp_error( $checkout ) ) {
144 return $checkout;
145 }
146
147 if ( ! empty( $this->with ) ) {
148 $checkout = $checkout->with( $this->with );
149 }
150
151 $paid = $checkout->where( $request->get_query_params() )->with(
152 [
153 'purchases', // Important: we need to make sure we expand the purchase to provide access.
154 ]
155 )->manuallyPay();
156
157 // purchase created.
158 if ( ! empty( $paid->purchases->data ) ) {
159 foreach ( $paid->purchases->data as $purchase ) {
160 if ( empty( $purchase->revoked ) ) {
161 // broadcast the webhook.
162 do_action( 'surecart/purchase_created', $purchase );
163 }
164 }
165 }
166 return $paid;
167 }
168
169 /**
170 * Finalize an order.
171 *
172 * @param \WP_REST_Request $request Rest Request.
173 *
174 * @return \SureCart\Models\Checkout|\WP_Error
175 */
176 public function finalize( \WP_REST_Request $request ) {
177 $args = $request->get_params();
178
179 // validate form fields and password input.
180 $errors = $this->validate( $args, $request );
181
182 // return early if errors.
183 if ( $errors->has_errors() ) {
184 return $errors;
185 }
186
187 // finalize the order.
188 $checkout = new $this->class( [ 'id' => $request['id'] ] );
189 $finalized = $checkout->where( $request->get_query_params() )
190 ->finalize( $request->get_body_params() );
191
192 // bail if error.
193 if ( is_wp_error( $finalized ) ) {
194 return $finalized;
195 }
196
197 // return the order.
198 return $finalized;
199 }
200
201 /**
202 * Confirm an order.
203 *
204 * This force-fetches the order from the API, runs any automations
205 * and creates the user account tied to the customer.
206 *
207 * @param \WP_REST_Request $request Rest Request.
208 *
209 * @return \SureCart\Models\Checkout|\WP_Error
210 */
211 public function confirm( \WP_REST_Request $request ) {
212 $checkout = $this->middleware( new $this->class(), $request );
213 if ( is_wp_error( $checkout ) ) {
214 return $checkout;
215 }
216
217 $checkout = $checkout->where(
218 array_merge(
219 $request->get_query_params(),
220 [ 'refresh_status' => true ] // Important: Do not remove. This will force syncing with the processor.
221 )
222 )->with(
223 [
224 'purchases', // Important: we need to make sure we expand the purchase to provide access.
225 'customer', // Important: we need to use this to create the WP User with the same info.
226 ]
227 )->find( $request['id'] );
228
229 // bail if error.
230 if ( is_wp_error( $checkout ) ) {
231 return $checkout;
232 }
233
234 // Create a user account for the customer.
235 $linked = $this->linkCustomerId( $checkout );
236 if ( is_wp_error( $linked ) ) {
237 return $linked;
238 }
239
240 // purchase created.
241 if ( ! empty( $checkout->purchases->data ) ) {
242 foreach ( $checkout->purchases->data as $purchase ) {
243 if ( empty( $purchase->revoked ) ) {
244 // broadcast the webhook.
245 do_action( 'surecart/purchase_created', $purchase );
246 }
247 }
248 }
249
250 // the order is confirmed.
251 do_action( 'surecart/checkout_confirmed', $checkout, $request );
252
253 // return the order.
254 return $checkout;
255 }
256
257 /**
258 * Link the customer id to the order.
259 *
260 * @param \SureCart\Models\Checkout $checkout Checkout model.
261 * @return \WP_User|\WP_Error
262 */
263 public function linkCustomerId( $checkout ) {
264 // get transient.
265 $password_hash = get_transient( 'sc_checkout_password_hash_' . $checkout->id );
266 // delete transient.
267 delete_transient( 'sc_checkout_password_hash_' . $checkout->id );
268 // link customer.
269 $service = new CustomerLinkService( $checkout, $password_hash );
270 return $service->link();
271 }
272
273 /**
274 * Validate the form.
275 *
276 * @param array $args Arguments.
277 * @param object $request Request.
278 * @return \WP_Error Errors.
279 */
280 public function validate( $args, $request ) {
281 $errors = new \WP_Error();
282
283 // check if they are trying to sign in.
284 $valid_login = $this->maybeValidateLoginCreds( $request->get_param( 'email' ), $request->get_param( 'password' ) );
285 if ( is_wp_error( $valid_login ) ) {
286 $errors->add( $valid_login->get_error_code(), $valid_login->get_error_message() );
287 }
288
289 // Check if honeypot checkbox checked or not.
290 $metadata = $request->get_param( 'metadata' );
291 if ( $metadata && ! empty( $metadata['get_feedback'] ) ) {
292 $errors->add( 'invalid', __( 'Invalid request. Please try again.', 'surecart' ) );
293 }
294
295 // check recaptcha.
296 $service = new RecaptchaValidationService();
297 if ( $service->isEnabled() ) {
298 $recaptcha = $service->validate( $request->get_param( 'grecaptcha' ) );
299 if ( is_wp_error( $recaptcha ) ) {
300 $errors->add( $recaptcha->get_error_code(), $recaptcha->get_error_message() );
301 }
302 }
303
304 return apply_filters( 'surecart/checkout/validate', $errors, $args, $request );
305 }
306
307 /**
308 * Check if the user is trying to sign in.
309 * If so, validate credentials before finalizing.
310 *
311 * @param string $email Email.
312 * @param string $password Password.
313 *
314 * @return true|\WP_Error
315 */
316 public function maybeValidateLoginCreds( $email = '', $password = '' ) {
317 // check if the person is signing in using a password and sign them in.
318 if ( $password && $email ) {
319 // user exists, try signing in with password.
320 $user = get_user_by( 'email', $email );
321 // if there's a user, check the username and password before we submit the order.
322 if ( false !== $user ) {
323 return wp_authenticate_username_password( null, $user->user_login, $password );
324 }
325 }
326 return true;
327 }
328
329 /**
330 * Create or login the user.
331 *
332 * @param string $user_email Username.
333 * @param string $password User password.
334 * @return \WP_Error|true
335 */
336 protected function maybeLoginUser( $user_email, $password = '' ) {
337 if ( empty( $password ) ) {
338 return;
339 }
340 return wp_signon(
341 [
342 'user_login' => $user_email,
343 'user_password' => $password,
344 ]
345 );
346 }
347 }
348