PluginProbe ʕ •ᴥ•ʔ
VikAppointments Services Booking Calendar / trunk
VikAppointments Services Booking Calendar vtrunk
trunk 1.2.17 1.2.18 1.2.19
vikappointments / site / controllers / subscrpayment.php
vikappointments / site / controllers Last commit date
calendarweek.php 3 years ago cart.php 1 month ago confirmapp.php 2 years ago empattachser.php 4 years ago empeditcoupon.php 4 years ago empeditcustfield.php 4 years ago empeditlocation.php 4 years ago empeditpay.php 4 years ago empeditprofile.php 5 months ago empeditservice.php 4 years ago empeditwdays.php 4 years ago emplocwdays.php 4 years ago emplogin.php 2 years ago employeesearch.php 2 years ago employeeslist.php 4 years ago empmakerecur.php 1 month ago empmanres.php 1 month ago empsettings.php 2 years ago empsubscr.php 4 years ago empsubscrorder.php 1 year ago index.html 6 years ago modules.php 1 year ago order.php 5 months ago packages.php 4 years ago packagesconfirm.php 4 years ago packagesorder.php 1 year ago servicesearch.php 2 years ago subscriptions.php 4 years ago subscrpayment.php 1 year ago userprofile.php 5 months ago waitinglist.php 4 years ago
subscrpayment.php
345 lines
1 <?php
2 /**
3 * @package VikAppointments
4 * @subpackage core
5 * @author E4J s.r.l.
6 * @copyright Copyright (C) 2021 E4J s.r.l. All Rights Reserved.
7 * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
8 * @link https://vikwp.com
9 */
10
11 // No direct access
12 defined('ABSPATH') or die('No script kiddies please!');
13
14 VAPLoader::import('libraries.mvc.controllers.admin');
15
16 /**
17 * VikAppointments user subscription payment controller.
18 *
19 * @since 1.7
20 */
21 class VikAppointmentsControllerSubscrpayment extends VAPControllerAdmin
22 {
23 /**
24 * Saves the subscription that has been registered within the cart.
25 *
26 * @return boolean
27 */
28 public function saveorder()
29 {
30 $app = JFactory::getApplication();
31 $input = $app->input;
32
33 $itemid = $input->getUint('Itemid');
34
35 // prepare redirect URL
36 $this->setRedirect(JRoute::rewrite('index.php?option=com_vikappointments&view=subscriptions' . ($itemid ? '&Itemid=' . $itemid : ''), false));
37
38 /**
39 * Validate session token before to proceed.
40 *
41 * @since 1.7
42 */
43 if (!JSession::checkToken())
44 {
45 // invalid token, back to confirm page
46 $app->enqueueMessage(JText::translate('JINVALID_TOKEN'), 'error');
47 return false;
48 }
49
50 // load arguments from request
51 $args = array();
52 $args['itemid'] = $itemid;
53
54 // get view model
55 $model = $this->getModel();
56
57 // try to save the subscription and get landing page
58 $url = $model->save($args);
59
60 // make sure we haven't faced any errors
61 if (!$url)
62 {
63 // get all registered errors
64 $errors = $model->getErrors();
65
66 foreach ($errors as $err)
67 {
68 // enqueue error message
69 $app->enqueueMessage($err, 'error');
70 }
71
72 return false;
73 }
74
75 // update redirect URL to reach the landing page
76 $this->setRedirect($url);
77 return true;
78 }
79
80 /**
81 * This is the end-point used by the gateway to validate a payment transaction.
82 * It is mandatory to send the following parameters (via GET or POST) in order to
83 * retrieve the correct details of the order transaction.
84 *
85 * @param integer ordnum The order number (ID).
86 * @param string ordkey The order key (SID).
87 *
88 * @return void
89 */
90 public function notifypayment()
91 {
92 $dispatcher = VAPFactory::getEventDispatcher();
93
94 $app = JFactory::getApplication();
95 $input = $app->input;
96
97 $oid = $input->getUint('ordnum');
98 $sid = $input->getAlnum('ordkey');
99
100 // Get order details (filter by ID and SID).
101 // In case the order doesn't exist, an exception will be thrown.
102 VAPLoader::import('libraries.order.factory');
103 $order = VAPOrderFactory::getCustomerSubscription($oid, null, array('sid' => $sid));
104
105 /**
106 * This event is triggered every time a payment tries to validate a transaction made.
107 *
108 * DOES NOT trigger in case the order doesn't exist.
109 *
110 * @param mixed $order The details of the purchased subscription.
111 *
112 * @return void
113 *
114 * @since 1.6
115 */
116 $dispatcher->trigger('onReceivePaymentNotification', array($order));
117
118 // build return and error URL
119 $return_url = "index.php?option=com_vikappointments&view=subscrpayment&ordnum={$oid}&ordkey={$sid}";
120 $error_url = "index.php?option=com_vikappointments&view=subscrpayment&ordnum={$oid}&ordkey={$sid}";
121
122 /**
123 * If we are trying to validate an order already paid/confirmed, auto-redirect to
124 * the return URL instead of throwing an exception.
125 *
126 * @since 1.7.1
127 */
128 if ($order->statusRole == 'APPROVED')
129 {
130 $this->setRedirect(JRoute::rewrite($return_url, false));
131 return;
132 }
133
134 // make sure the order can be paid
135 if ($order->statusRole != 'PENDING')
136 {
137 // status not allowed
138 throw new Exception('The current status of the order does not allow any payments.', 403);
139 }
140
141 if (!$order->payment)
142 {
143 // payment method not found
144 throw new Exception('The selected payment does not exist', 404);
145 }
146
147 // reload payment details to access the parameters
148 $payment = JModelVAP::getInstance('payment')->getItem($order->payment->id);
149
150 $vik = VAPApplication::getInstance();
151
152 $config = VAPFactory::getConfig();
153
154 // fetch transaction data
155 $paymentData = array();
156
157 // the payment URLs are correctly routed for external usage
158 $return_url = $vik->routeForExternalUse($return_url, false);
159 $error_url = $vik->routeForExternalUse($error_url, false);
160
161 // include the Notification URL in both the PLAIN and ROUTED formats
162 $notify_url = "index.php?option=com_vikappointments&task=subscrpayment.notifypayment&ordnum={$oid}&ordkey={$sid}";
163
164 // subtract amount already paid
165 $total_to_pay = max(array(0, $order->totals->gross - $order->totals->paid));
166
167 $paymentData['type'] = 'subscriptions';
168 $paymentData['action'] = 'validate';
169 $paymentData['oid'] = $order->id;
170 $paymentData['sid'] = $order->sid;
171 $paymentData['attempt'] = $order->payment_attempt;
172 $paymentData['transaction_name'] = JText::sprintf('VAPTRANSACTIONNAMESUBSCR', $order->subscription->name, $config->get('agencyname'));
173 $paymentData['transaction_currency'] = $config->get('currencyname');
174 $paymentData['currency_symb'] = $config->get('currencysymb');
175 $paymentData['tax'] = 0;
176 $paymentData['return_url'] = $return_url;
177 $paymentData['error_url'] = $error_url;
178 $paymentData['notify_url'] = $vik->routeForExternalUse($notify_url, false);
179 $paymentData['notify_url_plain'] = JUri::root() . $notify_url;
180 $paymentData['total_to_pay'] = $total_to_pay;
181 $paymentData['total_net_price'] = $total_to_pay;
182 $paymentData['total_tax'] = 0;
183 $paymentData['payment_info'] = $payment;
184 $paymentData['billing'] = $order->billing;
185 $paymentData['details'] = array(
186 'purchaser_nominative' => $order->billing->billing_name,
187 'purchaser_mail' => $order->billing->billing_mail,
188 'purchaser_phone' => $order->billing->billing_phone,
189 );
190
191 /**
192 * Trigger event to manipulate the payment details.
193 *
194 * @param array &$order The transaction details.
195 * @param array &$params The payment configuration array.
196 *
197 * @return void
198 *
199 * @since 1.6
200 */
201 $dispatcher->trigger('onInitPaymentTransaction', array(&$paymentData, &$payment->params));
202
203 /**
204 * Instantiate the payment using the platform handler.
205 *
206 * @since 1.6.3
207 */
208 $obj = $vik->getPaymentInstance($payment->file, $paymentData, $payment->params);
209
210 try
211 {
212 // validate payment transaction
213 $result = $obj->validatePayment();
214 }
215 catch (Exception $e)
216 {
217 // catch any exceptions that might have been thrown by the gateway
218 $result = [];
219 $result['verified'] = 0;
220 $result['log'] = $e->getMessage();
221 }
222
223 // get order model
224 $model = JModelVAP::getInstance('subscrorder');
225
226 // successful response
227 if ($result['verified'])
228 {
229 if (!empty($result['tot_paid']))
230 {
231 // increase total amount paid
232 $order->totals->paid += (float) $result['tot_paid'];
233 }
234
235 if ($order->totals->paid >= $order->totals->gross)
236 {
237 // the whole amount has been paid, use the apposite PAID status
238 $order->status = JHtml::fetch('vaphtml.status.paid', 'subscriptions', 'code');
239 }
240 else
241 {
242 // a deposit have been left, use CONFIRMED status
243 $order->status = JHtml::fetch('vaphtml.status.confirmed', 'subscriptions', 'code');
244 }
245
246 // prepare data to save
247 $data = array(
248 'id' => $order->id,
249 'status' => $order->status,
250 'status_comment' => 'VAP_STATUS_CHANGED_FROM_PAY',
251 'tot_paid' => $order->totals->paid,
252 'paid' => $order->paid,
253 );
254
255 $model->save($data);
256
257 // $mailOptions = array();
258 // validate e-mail rules before sending
259 // $mailOptions['check'] = true;
260
261 // send e-mail notification to the customer
262 // $model->sendEmailNotification($order->id, $mailOptions);
263
264 // send e-mail notification to the administrator(s)
265 // $mailOptions['client'] = 'subscradmin';
266 // $model->sendEmailNotification($order->id, $mailOptions);
267
268 // try to auto-generate the invoice
269 VikAppointments::generateInvoice($order->id, 'subscriptions');
270
271 /**
272 * Trigger event after the validation of a successful transaction.
273 *
274 * @param array $order The transaction details.
275 * @param array $args The response array.
276 *
277 * @return void
278 *
279 * @since 1.6
280 */
281 $dispatcher->trigger('onSuccessPaymentTransaction', array($paymentData, $result));
282 }
283 // failure response
284 else
285 {
286 // check if the payment registered any logs
287 if (!empty($result['log']))
288 {
289 $text = array(
290 'Order #' . $order->id . '-' . $order->sid . ' (Subscription)',
291 nl2br($result['log']),
292 );
293
294 // send error logs to administrator(s)
295 VikAppointments::sendAdminMailPaymentFailed($order->id, $text);
296
297 // get current date and time
298 $timeformat = preg_replace("/:i/", ':i:s', $config->get('timeformat'));
299 $now = JHtml::fetch('date', 'now', $config->get('dateformat') . ' ' . $timeformat, $app->get('offset', 'UTC'));
300
301 // build log string
302 $log = str_repeat('-', strlen($now) + 4) . "\n";
303 $log .= "| $now |\n";
304 $log .= str_repeat('-', strlen($now) + 4) . "\n";
305 $log .= "\n" . $result['log'];
306
307 if (!empty($order->log))
308 {
309 // always prepend new logs at the beginning
310 $log = $log . "\n\n" . $order->log;
311 }
312
313 // prepare save data
314 $data = array(
315 'id' => $order->id,
316 'log' => $log,
317 'payment_attempt' => ++$order->payment_attempt,
318 );
319
320 // update order logs
321 $model->save($data);
322 }
323
324 /**
325 * Trigger event after the validation of a failed transaction.
326 *
327 * @param array $order The transaction details.
328 * @param array $args The response array.
329 *
330 * @return void
331 *
332 * @since 1.6
333 */
334 $dispatcher->trigger('onFailPaymentTransaction', array($paymentData, $result));
335 }
336
337 // check whether the payment instance supports a method
338 // to be executed after the validation
339 if (method_exists($obj, 'afterValidation'))
340 {
341 $obj->afterValidation($result['verified'] ? 1 : 0);
342 }
343 }
344 }
345