· 7 years ago · Feb 23, 2019, 03:46 PM
1<?php
2class ControllerPaymentPPExpress extends Controller {
3 public function index() {
4 $this->language->load('payment/pp_express');
5
6 $data['button_continue'] = $this->language->get('button_continue');
7 $data['button_continue_action'] = $this->url->link('payment/pp_express/checkout', '', 'SSL');
8
9 /**
10 * if there is any other paypal session data, clear it
11 */
12 unset($this->session->data['paypal']);
13
14 if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/payment/pp_express.tpl')) {
15 return $this->load->view($this->config->get('config_template') . '/template/payment/pp_express.tpl', $data);
16 } else {
17 return $this->load->view('default/template/payment/pp_express.tpl', $data);
18 }
19 }
20
21 public function express() {
22 if ((!$this->cart->hasProducts() && empty($this->session->data['vouchers'])) || (!$this->cart->hasStock() && !$this->config->get('config_stock_checkout'))) {
23 $this->log->write('No product redirect');
24
25 $this->response->redirect($this->url->link('checkout/cart'));
26 }
27
28 if ($this->customer->isLogged()) {
29 /**
30 * If the customer is already logged in
31 */
32 $this->session->data['paypal']['guest'] = false;
33
34 unset($this->session->data['guest']);
35 } else {
36 if ($this->config->get('config_checkout_guest') && !$this->config->get('config_customer_price') && !$this->cart->hasDownload() && !$this->cart->hasRecurringProducts()) {
37 /**
38 * If the guest checkout is allowed (config ok, no login for price and doesn't have downloads)
39 */
40 $this->session->data['paypal']['guest'] = true;
41 } else {
42 /**
43 * If guest checkout disabled or login is required before price or order has downloads
44 *
45 * Send them to the normal checkout flow.
46 */
47 unset($this->session->data['guest']);
48
49 $this->response->redirect($this->url->link('checkout/checkout', '', 'SSL'));
50 }
51 }
52
53 unset($this->session->data['shipping_method']);
54 unset($this->session->data['shipping_methods']);
55 unset($this->session->data['payment_method']);
56 unset($this->session->data['payment_methods']);
57
58 $this->load->model('payment/pp_express');
59 $this->load->model('tool/image');
60
61 if ($this->cart->hasShipping()) {
62 $shipping = 2;
63 } else {
64 $shipping = 1;
65 }
66
67 $max_amount = $this->cart->getTotal() * 1.5;
68 $max_amount = $this->currency->format($max_amount, $this->currency->getCode(), '', false);
69
70 $data = array(
71 'METHOD' => 'SetExpressCheckout',
72 'MAXAMT' => $max_amount,
73 'RETURNURL' => $this->url->link('payment/pp_express/expressReturn', '', 'SSL'),
74 'CANCELURL' => $this->url->link('checkout/cart', '', 'SSL'),
75 'REQCONFIRMSHIPPING' => 0,
76 'NOSHIPPING' => $shipping,
77 'ALLOWNOTE' => $this->config->get('pp_express_allow_note'),
78 'LOCALECODE' => 'EN',
79 'LANDINGPAGE' => 'Login',
80 'HDRIMG' => $this->model_tool_image->resize($this->config->get('pp_express_logo'), 790, 90),
81 'PAYFLOWCOLOR' => $this->config->get('pp_express_page_colour'),
82 'CHANNELTYPE' => 'Merchant'
83 );
84
85 if (isset($this->session->data['pp_login']['seamless']['access_token']) && (isset($this->session->data['pp_login']['seamless']['customer_id']) && $this->session->data['pp_login']['seamless']['customer_id'] == $this->customer->getId()) && $this->config->get('pp_login_seamless')) {
86 $data['IDENTITYACCESSTOKEN'] = $this->session->data['pp_login']['seamless']['access_token'];
87 }
88
89 $data = array_merge($data, $this->model_payment_pp_express->paymentRequestInfo());
90
91 $result = $this->model_payment_pp_express->call($data);
92
93 /**
94 * If a failed PayPal setup happens, handle it.
95 */
96 if (!isset($result['TOKEN'])) {
97 $this->session->data['error'] = $result['L_LONGMESSAGE0'];
98 /**
99 * Unable to add error message to user as the session errors/success are not
100 * used on the cart or checkout pages - need to be added?
101 * If PayPal debug log is off then still log error to normal error log.
102 */
103 if ($this->config->get('pp_express_debug') == 1) {
104 $this->log->write(serialize($result));
105 }
106
107 $this->response->redirect($this->url->link('checkout/checkout', '', 'SSL'));
108 }
109
110 $this->session->data['paypal']['token'] = $result['TOKEN'];
111
112 if ($this->config->get('pp_express_test') == 1) {
113 header('Location: https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=' . $result['TOKEN']);
114 } else {
115 header('Location: https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=' . $result['TOKEN']);
116 }
117 }
118
119 public function expressReturn() {
120 /**
121 * This is the url when PayPal has completed the auth.
122 *
123 * It has no output, instead it sets the data and locates to checkout
124 */
125 $this->load->model('payment/pp_express');
126 $data = array(
127 'METHOD' => 'GetExpressCheckoutDetails',
128 'TOKEN' => $this->session->data['paypal']['token']
129 );
130
131 $result = $this->model_payment_pp_express->call($data);
132 $this->session->data['paypal']['payerid'] = $result['PAYERID'];
133 $this->session->data['paypal']['result'] = $result;
134
135 $this->session->data['comment'] = '';
136 if (isset($result['PAYMENTREQUEST_0_NOTETEXT'])) {
137 $this->session->data['comment'] = $result['PAYMENTREQUEST_0_NOTETEXT'];
138 }
139
140 if ($this->session->data['paypal']['guest'] == true) {
141
142 $this->session->data['guest']['customer_group_id'] = $this->config->get('config_customer_group_id');
143 $this->session->data['guest']['firstname'] = trim($result['FIRSTNAME']);
144 $this->session->data['guest']['lastname'] = trim($result['LASTNAME']);
145 $this->session->data['guest']['email'] = trim($result['EMAIL']);
146
147 if (isset($result['PHONENUM'])) {
148 $this->session->data['guest']['telephone'] = $result['PHONENUM'];
149 } else {
150 $this->session->data['guest']['telephone'] = '';
151 }
152
153 $this->session->data['guest']['fax'] = '';
154
155 $this->session->data['guest']['payment']['firstname'] = trim($result['FIRSTNAME']);
156 $this->session->data['guest']['payment']['lastname'] = trim($result['LASTNAME']);
157
158 if (isset($result['BUSINESS'])) {
159 $this->session->data['guest']['payment']['company'] = $result['BUSINESS'];
160 } else {
161 $this->session->data['guest']['payment']['company'] = '';
162 }
163
164 $this->session->data['guest']['payment']['company_id'] = '';
165 $this->session->data['guest']['payment']['tax_id'] = '';
166
167 if ($this->cart->hasShipping()) {
168 $shipping_name = explode(' ', trim($result['PAYMENTREQUEST_0_SHIPTONAME']));
169 $shipping_first_name = $shipping_name[0];
170 unset($shipping_name[0]);
171 $shipping_last_name = implode(' ', $shipping_name);
172
173 $this->session->data['guest']['payment']['address_1'] = $result['PAYMENTREQUEST_0_SHIPTOSTREET'];
174 if (isset($result['PAYMENTREQUEST_0_SHIPTOSTREET2'])) {
175 $this->session->data['guest']['payment']['address_2'] = $result['PAYMENTREQUEST_0_SHIPTOSTREET2'];
176 } else {
177 $this->session->data['guest']['payment']['address_2'] = '';
178 }
179
180 $this->session->data['guest']['payment']['postcode'] = $result['PAYMENTREQUEST_0_SHIPTOZIP'];
181 $this->session->data['guest']['payment']['city'] = $result['PAYMENTREQUEST_0_SHIPTOCITY'];
182
183 $this->session->data['guest']['shipping']['firstname'] = $shipping_first_name;
184 $this->session->data['guest']['shipping']['lastname'] = $shipping_last_name;
185 $this->session->data['guest']['shipping']['company'] = '';
186 $this->session->data['guest']['shipping']['address_1'] = $result['PAYMENTREQUEST_0_SHIPTOSTREET'];
187
188 if (isset($result['PAYMENTREQUEST_0_SHIPTOSTREET2'])) {
189 $this->session->data['guest']['shipping']['address_2'] = $result['PAYMENTREQUEST_0_SHIPTOSTREET2'];
190 } else {
191 $this->session->data['guest']['shipping']['address_2'] = '';
192 }
193
194 $this->session->data['guest']['shipping']['postcode'] = $result['PAYMENTREQUEST_0_SHIPTOZIP'];
195 $this->session->data['guest']['shipping']['city'] = $result['PAYMENTREQUEST_0_SHIPTOCITY'];
196
197 $this->session->data['shipping_postcode'] = $result['PAYMENTREQUEST_0_SHIPTOZIP'];
198
199 $country_info = $this->db->query("SELECT * FROM `" . DB_PREFIX . "country` WHERE `iso_code_2` = '" . $this->db->escape($result['PAYMENTREQUEST_0_SHIPTOCOUNTRYCODE']) . "' AND `status` = '1' LIMIT 1")->row;
200
201 if ($country_info) {
202 $this->session->data['guest']['shipping']['country_id'] = $country_info['country_id'];
203 $this->session->data['guest']['shipping']['country'] = $country_info['name'];
204 $this->session->data['guest']['shipping']['iso_code_2'] = $country_info['iso_code_2'];
205 $this->session->data['guest']['shipping']['iso_code_3'] = $country_info['iso_code_3'];
206 $this->session->data['guest']['shipping']['address_format'] = $country_info['address_format'];
207 $this->session->data['guest']['payment']['country_id'] = $country_info['country_id'];
208 $this->session->data['guest']['payment']['country'] = $country_info['name'];
209 $this->session->data['guest']['payment']['iso_code_2'] = $country_info['iso_code_2'];
210 $this->session->data['guest']['payment']['iso_code_3'] = $country_info['iso_code_3'];
211 $this->session->data['guest']['payment']['address_format'] = $country_info['address_format'];
212 $this->session->data['shipping_country_id'] = $country_info['country_id'];
213 } else {
214 $this->session->data['guest']['shipping']['country_id'] = '';
215 $this->session->data['guest']['shipping']['country'] = '';
216 $this->session->data['guest']['shipping']['iso_code_2'] = '';
217 $this->session->data['guest']['shipping']['iso_code_3'] = '';
218 $this->session->data['guest']['shipping']['address_format'] = '';
219 $this->session->data['guest']['payment']['country_id'] = '';
220 $this->session->data['guest']['payment']['country'] = '';
221 $this->session->data['guest']['payment']['iso_code_2'] = '';
222 $this->session->data['guest']['payment']['iso_code_3'] = '';
223 $this->session->data['guest']['payment']['address_format'] = '';
224 $this->session->data['shipping_country_id'] = '';
225 }
226
227 if (isset($result['PAYMENTREQUEST_0_SHIPTOSTATE'])) {
228 $returned_shipping_zone = $result['PAYMENTREQUEST_0_SHIPTOSTATE'];
229 } else {
230 $returned_shipping_zone = '';
231 }
232
233 $zone_info = $this->db->query("SELECT * FROM `" . DB_PREFIX . "zone` WHERE (`name` = '" . $this->db->escape($returned_shipping_zone) . "' OR `code` = '" . $this->db->escape($returned_shipping_zone) . "') AND `status` = '1' AND `country_id` = '" . (int)$country_info['country_id'] . "' LIMIT 1")->row;
234
235 if ($zone_info) {
236 $this->session->data['guest']['shipping']['zone'] = $zone_info['name'];
237 $this->session->data['guest']['shipping']['zone_code'] = $zone_info['code'];
238 $this->session->data['guest']['shipping']['zone_id'] = $zone_info['zone_id'];
239 $this->session->data['guest']['payment']['zone'] = $zone_info['name'];
240 $this->session->data['guest']['payment']['zone_code'] = $zone_info['code'];
241 $this->session->data['guest']['payment']['zone_id'] = $zone_info['zone_id'];
242 $this->session->data['shipping_zone_id'] = $zone_info['zone_id'];
243 } else {
244 $this->session->data['guest']['shipping']['zone'] = '';
245 $this->session->data['guest']['shipping']['zone_code'] = '';
246 $this->session->data['guest']['shipping']['zone_id'] = '';
247 $this->session->data['guest']['payment']['zone'] = '';
248 $this->session->data['guest']['payment']['zone_code'] = '';
249 $this->session->data['guest']['payment']['zone_id'] = '';
250 $this->session->data['shipping_zone_id'] = '';
251 }
252
253 $this->session->data['guest']['shipping_address'] = true;
254 } else {
255 $this->session->data['guest']['payment']['address_1'] = '';
256 $this->session->data['guest']['payment']['address_2'] = '';
257 $this->session->data['guest']['payment']['postcode'] = '';
258 $this->session->data['guest']['payment']['city'] = '';
259 $this->session->data['guest']['payment']['country_id'] = '';
260 $this->session->data['guest']['payment']['country'] = '';
261 $this->session->data['guest']['payment']['iso_code_2'] = '';
262 $this->session->data['guest']['payment']['iso_code_3'] = '';
263 $this->session->data['guest']['payment']['address_format'] = '';
264 $this->session->data['guest']['payment']['zone'] = '';
265 $this->session->data['guest']['payment']['zone_code'] = '';
266 $this->session->data['guest']['payment']['zone_id'] = '';
267 $this->session->data['guest']['shipping_address'] = false;
268 }
269
270 $this->session->data['account'] = 'guest';
271
272 unset($this->session->data['shipping_method']);
273 unset($this->session->data['shipping_methods']);
274 unset($this->session->data['payment_method']);
275 unset($this->session->data['payment_methods']);
276 } else {
277 unset($this->session->data['guest']);
278 /**
279 * if the user is logged in, add the address to the account and set the ID.
280 */
281
282 if ($this->cart->hasShipping()) {
283 $this->load->model('account/address');
284
285 $addresses = $this->model_account_address->getAddresses();
286
287 /**
288 * Compare all of the user addresses and see if there is a match
289 */
290 $match = false;
291 foreach($addresses as $address) {
292 if (trim(strtolower($address['address_1'])) == trim(strtolower($result['PAYMENTREQUEST_0_SHIPTOSTREET'])) && trim(strtolower($address['postcode'])) == trim(strtolower($result['PAYMENTREQUEST_0_SHIPTOZIP']))) {
293 $match = true;
294
295 $this->session->data['payment_address_id'] = $address['address_id'];
296 $this->session->data['payment_country_id'] = $address['country_id'];
297 $this->session->data['payment_zone_id'] = $address['zone_id'];
298
299 $this->session->data['shipping_address_id'] = $address['address_id'];
300 $this->session->data['shipping_country_id'] = $address['country_id'];
301 $this->session->data['shipping_zone_id'] = $address['zone_id'];
302 $this->session->data['shipping_postcode'] = $address['postcode'];
303
304 break;
305 }
306 }
307
308 /**
309 * If there is no address match add the address and set the info.
310 */
311 if ($match == false) {
312
313 $shipping_name = explode(' ', trim($result['PAYMENTREQUEST_0_SHIPTONAME']));
314 $shipping_first_name = $shipping_name[0];
315 unset($shipping_name[0]);
316 $shipping_last_name = implode(' ', $shipping_name);
317
318 $country_info = $this->db->query("SELECT * FROM `" . DB_PREFIX . "country` WHERE `iso_code_2` = '" . $this->db->escape($result['PAYMENTREQUEST_0_SHIPTOCOUNTRYCODE']) . "' AND `status` = '1' LIMIT 1")->row;
319 $zone_info = $this->db->query("SELECT * FROM `" . DB_PREFIX . "zone` WHERE `name` = '" . $this->db->escape($result['PAYMENTREQUEST_0_SHIPTOSTATE']) . "' AND `status` = '1' AND `country_id` = '" . (int)$country_info['country_id'] . "'")->row;
320
321 $address_data = array(
322 'firstname' => $shipping_first_name,
323 'lastname' => $shipping_last_name,
324 'company' => '',
325 'company_id' => '',
326 'tax_id' => '',
327 'address_1' => $result['PAYMENTREQUEST_0_SHIPTOSTREET'],
328 'address_2' => (isset($result['PAYMENTREQUEST_0_SHIPTOSTREET2']) ? $result['PAYMENTREQUEST_0_SHIPTOSTREET2'] : ''),
329 'postcode' => $result['PAYMENTREQUEST_0_SHIPTOZIP'],
330 'city' => $result['PAYMENTREQUEST_0_SHIPTOCITY'],
331 'zone_id' => (isset($zone_info['zone_id']) ? $zone_info['zone_id'] : 0),
332 'country_id' => (isset($country_info['country_id']) ? $country_info['country_id'] : 0)
333 );
334
335 $address_id = $this->model_account_address->addAddress($address_data);
336
337 $this->session->data['payment_address_id'] = $address_id;
338 $this->session->data['payment_country_id'] = $address_data['country_id'];
339 $this->session->data['payment_zone_id'] = $address_data['zone_id'];
340
341 $this->session->data['shipping_address_id'] = $address_id;
342 $this->session->data['shipping_country_id'] = $address_data['country_id'];
343 $this->session->data['shipping_zone_id'] = $address_data['zone_id'];
344 $this->session->data['shipping_postcode'] = $address_data['postcode'];
345 }
346 } else {
347 $this->session->data['payment_address_id'] = '';
348 $this->session->data['payment_country_id'] = '';
349 $this->session->data['payment_zone_id'] = '';
350 }
351 }
352
353 $this->response->redirect($this->url->link('payment/pp_express/expressConfirm', '', 'SSL'));
354 }
355
356 public function expressConfirm() {
357 $this->language->load('payment/pp_express');
358 $this->language->load('checkout/cart');
359
360 $this->load->model('tool/image');
361
362 // Coupon
363 if (isset($this->request->post['coupon']) && $this->validateCoupon()) {
364 $this->session->data['coupon'] = $this->request->post['coupon'];
365
366 $this->session->data['success'] = $this->language->get('text_coupon');
367
368 $this->response->redirect($this->url->link('payment/pp_express/expressConfirm', '', 'SSL'));
369 }
370
371 // Voucher
372 if (isset($this->request->post['voucher']) && $this->validateVoucher()) {
373 $this->session->data['voucher'] = $this->request->post['voucher'];
374
375 $this->session->data['success'] = $this->language->get('text_voucher');
376
377 $this->response->redirect($this->url->link('payment/pp_express/expressConfirm', '', 'SSL'));
378 }
379
380 // Reward
381 if (isset($this->request->post['reward']) && $this->validateReward()) {
382 $this->session->data['reward'] = abs($this->request->post['reward']);
383
384 $this->session->data['success'] = $this->language->get('text_reward');
385
386 $this->response->redirect($this->url->link('payment/pp_express/expressConfirm', '', 'SSL'));
387 }
388
389 $this->document->setTitle($this->language->get('express_text_title'));
390
391 $data['heading_title'] = $this->language->get('express_text_title');
392
393 $data['breadcrumbs'] = array();
394
395 $data['breadcrumbs'][] = array(
396 'href' => $this->url->link('common/home'),
397 'text' => $this->language->get('text_home')
398 );
399
400 $data['breadcrumbs'][] = array(
401 'href' => $this->url->link('payment/pp_express/express'),
402 'text' => $this->language->get('text_title')
403 );
404
405 $data['breadcrumbs'][] = array(
406 'href' => $this->url->link('payment/pp_express/expressConfirm'),
407 'text' => $this->language->get('express_text_title')
408 );
409
410 $points = $this->customer->getRewardPoints();
411
412 $points_total = 0;
413
414 foreach ($this->cart->getProducts() as $product) {
415 if ($product['points']) {
416 $points_total += $product['points'];
417 }
418 }
419
420 $data['text_trial'] = $this->language->get('text_trial');
421 $data['text_recurring'] = $this->language->get('text_recurring');
422 $data['text_length'] = $this->language->get('text_length');
423 $data['text_recurring_item'] = $this->language->get('text_recurring_item');
424 $data['text_payment_recurring'] = $this->language->get('text_payment_recurring');
425 $data['text_until_cancelled'] = $this->language->get('text_until_cancelled');
426
427 $data['column_name'] = $this->language->get('column_name');
428 $data['column_model'] = $this->language->get('column_model');
429 $data['column_quantity'] = $this->language->get('column_quantity');
430 $data['column_price'] = $this->language->get('column_price');
431 $data['column_total'] = $this->language->get('column_total');
432
433 $data['button_shipping'] = $this->language->get('button_express_shipping');
434 $data['button_confirm'] = $this->language->get('button_express_confirm');
435
436 if (isset($this->request->post['next'])) {
437 $data['next'] = $this->request->post['next'];
438 } else {
439 $data['next'] = '';
440 }
441
442 $data['action'] = $this->url->link('payment/pp_express/expressConfirm', '', 'SSL');
443
444 $products = $this->cart->getProducts();
445
446 foreach ($products as $product) {
447 $product_total = 0;
448
449 foreach ($products as $product_2) {
450 if ($product_2['product_id'] == $product['product_id']) {
451 $product_total += $product_2['quantity'];
452 }
453 }
454
455 if ($product['minimum'] > $product_total) {
456 $data['error_warning'] = sprintf($this->language->get('error_minimum'), $product['name'], $product['minimum']);
457 }
458
459 if ($product['image']) {
460 $image = $this->model_tool_image->resize($product['image'], $this->config->get('config_image_cart_width'), $this->config->get('config_image_cart_height'));
461 } else {
462 $image = '';
463 }
464
465 $option_data = array();
466
467 foreach ($product['option'] as $option) {
468 if ($option['type'] != 'file') {
469 $value = $option['option_value'];
470 } else {
471 $filename = $this->encryption->decrypt($option['option_value']);
472
473 $value = utf8_substr($filename, 0, utf8_strrpos($filename, '.'));
474 }
475
476 $option_data[] = array(
477 'name' => $option['name'],
478 'value' => (utf8_strlen($value) > 20 ? utf8_substr($value, 0, 20) . '..' : $value)
479 );
480 }
481
482 // Display prices
483 if (($this->config->get('config_customer_price') && $this->customer->isLogged()) || !$this->config->get('config_customer_price')) {
484 $price = $this->currency->format($this->tax->calculate($product['price'], $product['tax_class_id'], $this->config->get('config_tax')));
485 } else {
486 $price = false;
487 }
488
489 // Display prices
490 if (($this->config->get('config_customer_price') && $this->customer->isLogged()) || !$this->config->get('config_customer_price')) {
491 $total = $this->currency->format($this->tax->calculate($product['price'], $product['tax_class_id'], $this->config->get('config_tax')) * $product['quantity']);
492 } else {
493 $total = false;
494 }
495
496 $recurring_description = '';
497
498 if ($product['recurring']) {
499 $frequencies = array(
500 'day' => $this->language->get('text_day'),
501 'week' => $this->language->get('text_week'),
502 'semi_month' => $this->language->get('text_semi_month'),
503 'month' => $this->language->get('text_month'),
504 'year' => $this->language->get('text_year'),
505 );
506
507 if ($product['recurring']['trial']) {
508 $recurring_price = $this->currency->format($this->tax->calculate($product['recurring']['trial_price'] * $product['quantity'], $product['tax_class_id'], $this->config->get('config_tax')));
509 $recurring_description = sprintf($this->language->get('text_trial_description'), $recurring_price, $product['recurring']['trial_cycle'], $frequencies[$product['recurring']['trial_frequency']], $product['recurring']['trial_duration']) . ' ';
510 }
511
512 $recurring_price = $this->currency->format($this->tax->calculate($product['recurring']['price'] * $product['quantity'], $product['tax_class_id'], $this->config->get('config_tax')));
513
514 if ($product['recurring']['duration']) {
515 $recurring_description .= sprintf($this->language->get('text_payment_description'), $recurring_price, $product['recurring']['cycle'], $frequencies[$product['recurring']['frequency']], $product['recurring']['duration']);
516 } else {
517 $recurring_description .= sprintf($this->language->get('text_payment_cancel'), $recurring_price, $product['recurring']['cycle'], $frequencies[$product['recurring']['frequency']], $product['recurring']['duration']);
518 }
519 }
520
521 $data['products'][] = array(
522 'key' => $product['key'],
523 'thumb' => $image,
524 'name' => $product['name'],
525 'model' => $product['model'],
526 'option' => $option_data,
527 'quantity' => $product['quantity'],
528 'stock' => $product['stock'] ? true : !(!$this->config->get('config_stock_checkout') || $this->config->get('config_stock_warning')),
529 'reward' => ($product['reward'] ? sprintf($this->language->get('text_points'), $product['reward']) : ''),
530 'price' => $price,
531 'total' => $total,
532 'href' => $this->url->link('product/product', 'product_id=' . $product['product_id']),
533 'remove' => $this->url->link('checkout/cart', 'remove=' . $product['key']),
534 'recurring' => $product['recurring'],
535 'recurring_name' => (isset($product['recurring']['recurring_name']) ? $product['recurring']['recurring_name'] : ''),
536 'recurring_description' => $recurring_description
537 );
538 }
539
540 $data['vouchers'] = array();
541
542 if ($this->cart->hasShipping()) {
543
544 $data['has_shipping'] = true;
545 /**
546 * Shipping services
547 */
548 if ($this->customer->isLogged()) {
549 $this->load->model('account/address');
550 $shipping_address = $this->model_account_address->getAddress($this->session->data['shipping_address_id']);
551 } elseif (isset($this->session->data['guest'])) {
552 $shipping_address = $this->session->data['guest']['shipping'];
553 }
554
555 if (!empty($shipping_address)) {
556 // Shipping Methods
557 $quote_data = array();
558
559 $this->load->model('extension/extension');
560
561 $results = $this->model_extension_extension->getExtensions('shipping');
562
563 if (!empty($results)) {
564 foreach ($results as $result) {
565 if ($this->config->get($result['code'] . '_status')) {
566 $this->load->model('shipping/' . $result['code']);
567
568 $quote = $this->{'model_shipping_' . $result['code']}->getQuote($shipping_address);
569
570 if ($quote) {
571 $quote_data[$result['code']] = array(
572 'title' => $quote['title'],
573 'quote' => $quote['quote'],
574 'sort_order' => $quote['sort_order'],
575 'error' => $quote['error']
576 );
577 }
578 }
579 }
580
581 if (!empty($quote_data)) {
582 $sort_order = array();
583
584 foreach ($quote_data as $key => $value) {
585 $sort_order[$key] = $value['sort_order'];
586 }
587
588 array_multisort($sort_order, SORT_ASC, $quote_data);
589
590 $this->session->data['shipping_methods'] = $quote_data;
591 $data['shipping_methods'] = $quote_data;
592
593 if (!isset($this->session->data['shipping_method'])) {
594 //default the shipping to the very first option.
595 $key1 = key($quote_data);
596 $key2 = key($quote_data[$key1]['quote']);
597 $this->session->data['shipping_method'] = $quote_data[$key1]['quote'][$key2];
598 }
599
600 $data['code'] = $this->session->data['shipping_method']['code'];
601 $data['action_shipping'] = $this->url->link('payment/pp_express/shipping', '', 'SSL');
602 } else {
603 unset($this->session->data['shipping_methods']);
604 unset($this->session->data['shipping_method']);
605 $data['error_no_shipping'] = $this->language->get('error_no_shipping');
606 }
607 } else {
608 unset($this->session->data['shipping_methods']);
609 unset($this->session->data['shipping_method']);
610 $data['error_no_shipping'] = $this->language->get('error_no_shipping');
611 }
612 }
613 } else {
614 $data['has_shipping'] = false;
615 }
616
617 // Totals
618 $this->load->model('extension/extension');
619
620 $total_data = array();
621 $total = 0;
622 $taxes = $this->cart->getTaxes();
623
624 // Display prices
625 if (($this->config->get('config_customer_price') && $this->customer->isLogged()) || !$this->config->get('config_customer_price')) {
626 $sort_order = array();
627
628 $results = $this->model_extension_extension->getExtensions('total');
629
630 foreach ($results as $key => $value) {
631 $sort_order[$key] = $this->config->get($value['code'] . '_sort_order');
632 }
633
634 array_multisort($sort_order, SORT_ASC, $results);
635
636 foreach ($results as $result) {
637 if ($this->config->get($result['code'] . '_status')) {
638 $this->load->model('total/' . $result['code']);
639
640 $this->{'model_total_' . $result['code']}->getTotal($total_data, $total, $taxes);
641 }
642 }
643
644 $sort_order = array();
645
646 foreach ($total_data as $key => $value) {
647 $sort_order[$key] = $value['sort_order'];
648 }
649
650 array_multisort($sort_order, SORT_ASC, $total_data);
651 }
652
653 $data['totals'] = array();
654
655 foreach ($total_data as $total) {
656 $data['totals'][] = array(
657 'title' => $total['title'],
658 'text' => $this->currency->format($total['value']),
659 );
660 }
661
662 /**
663 * Payment methods
664 */
665 if ($this->customer->isLogged() && isset($this->session->data['payment_address_id'])) {
666 $this->load->model('account/address');
667 $payment_address = $this->model_account_address->getAddress($this->session->data['payment_address_id']);
668 } elseif (isset($this->session->data['guest'])) {
669 $payment_address = $this->session->data['guest']['payment'];
670 }
671
672 $method_data = array();
673
674 $this->load->model('extension/extension');
675
676 $results = $this->model_extension_extension->getExtensions('payment');
677
678 foreach ($results as $result) {
679 if ($this->config->get($result['code'] . '_status')) {
680 $this->load->model('payment/' . $result['code']);
681
682 $method = $this->{'model_payment_' . $result['code']}->getMethod($payment_address, $total);
683
684 if ($method) {
685 $method_data[$result['code']] = $method;
686 }
687 }
688 }
689
690 $sort_order = array();
691
692 foreach ($method_data as $key => $value) {
693 $sort_order[$key] = $value['sort_order'];
694 }
695
696 array_multisort($sort_order, SORT_ASC, $method_data);
697
698 $this->session->data['payment_methods'] = $method_data;
699 $this->session->data['payment_method'] = $this->session->data['payment_methods']['pp_express'];
700
701 $data['action_confirm'] = $this->url->link('payment/pp_express/expressComplete', '', 'SSL');
702
703 if (isset($this->session->data['error_warning'])) {
704 $data['error_warning'] = $this->session->data['error_warning'];
705 unset($this->session->data['error_warning']);
706 } else {
707 $data['error_warning'] = '';
708 }
709
710 if (isset($this->session->data['success'])) {
711 $data['success'] = $this->session->data['success'];
712 unset($this->session->data['success']);
713 } else {
714 $data['success'] = '';
715 }
716
717 if (isset($this->session->data['attention'])) {
718 $data['attention'] = $this->session->data['attention'];
719 unset($this->session->data['attention']);
720 } else {
721 $data['attention'] = '';
722 }
723
724 $data['coupon'] = $this->load->controller('module/coupon');
725 $data['voucher'] = $this->load->controller('module/voucher');
726 $data['reward'] = $this->load->controller('module/reward');
727 $data['column_left'] = $this->load->controller('common/column_left');
728 $data['column_right'] = $this->load->controller('common/column_right');
729 $data['content_top'] = $this->load->controller('common/content_top');
730 $data['content_bottom'] = $this->load->controller('common/content_bottom');
731 $data['footer'] = $this->load->controller('common/footer');
732 $data['header'] = $this->load->controller('common/header');
733
734 if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/payment/pp_express_confirm.tpl')) {
735 $this->response->setOutput($this->load->view($this->config->get('config_template') . '/template/payment/pp_express_confirm.tpl', $data));
736 } else {
737 $this->response->setOutput($this->load->view('default/template/payment/pp_express_confirm.tpl', $data));
738 }
739 }
740
741 public function expressComplete() {
742 $this->language->load('payment/pp_express');
743 $redirect = '';
744
745 if ($this->cart->hasShipping()) {
746 // Validate if shipping address has been set.
747 $this->load->model('account/address');
748
749 if ($this->customer->isLogged() && isset($this->session->data['shipping_address_id'])) {
750 $shipping_address = $this->model_account_address->getAddress($this->session->data['shipping_address_id']);
751 } elseif (isset($this->session->data['guest'])) {
752 $shipping_address = $this->session->data['guest']['shipping'];
753 }
754
755 if (empty($shipping_address)) {
756 $redirect = $this->url->link('checkout/checkout', '', 'SSL');
757 }
758
759 // Validate if shipping method has been set.
760 if (!isset($this->session->data['shipping_method'])) {
761 $redirect = $this->url->link('checkout/checkout', '', 'SSL');
762 }
763 } else {
764 unset($this->session->data['shipping_method']);
765 unset($this->session->data['shipping_methods']);
766 }
767
768 // Validate if payment address has been set.
769 $this->load->model('account/address');
770
771 if ($this->customer->isLogged() && isset($this->session->data['payment_address_id'])) {
772 $payment_address = $this->model_account_address->getAddress($this->session->data['payment_address_id']);
773 } elseif (isset($this->session->data['guest'])) {
774 $payment_address = $this->session->data['guest']['payment'];
775 }
776
777 // Validate if payment method has been set.
778 if (!isset($this->session->data['payment_method'])) {
779 $redirect = $this->url->link('checkout/checkout', '', 'SSL');
780 }
781
782 // Validate cart has products and has stock.
783 if ((!$this->cart->hasProducts() && empty($this->session->data['vouchers'])) || (!$this->cart->hasStock() && !$this->config->get('config_stock_checkout'))) {
784 $redirect = $this->url->link('checkout/cart');
785 }
786
787 // Validate minimum quantity requirements.
788 $products = $this->cart->getProducts();
789
790 foreach ($products as $product) {
791 $product_total = 0;
792
793 foreach ($products as $product_2) {
794 if ($product_2['product_id'] == $product['product_id']) {
795 $product_total += $product_2['quantity'];
796 }
797 }
798
799 if ($product['minimum'] > $product_total) {
800 $redirect = $this->url->link('checkout/cart');
801
802 break;
803 }
804 }
805
806 if ($redirect == '') {
807 $total_data = array();
808 $total = 0;
809 $taxes = $this->cart->getTaxes();
810
811 $this->load->model('extension/extension');
812
813 $sort_order = array();
814
815 $results = $this->model_extension_extension->getExtensions('total');
816
817 foreach ($results as $key => $value) {
818 $sort_order[$key] = $this->config->get($value['code'] . '_sort_order');
819 }
820
821 array_multisort($sort_order, SORT_ASC, $results);
822
823 foreach ($results as $result) {
824 if ($this->config->get($result['code'] . '_status')) {
825 $this->load->model('total/' . $result['code']);
826
827 $this->{'model_total_' . $result['code']}->getTotal($total_data, $total, $taxes);
828 }
829 }
830
831 $sort_order = array();
832
833 foreach ($total_data as $key => $value) {
834 $sort_order[$key] = $value['sort_order'];
835 }
836
837 array_multisort($sort_order, SORT_ASC, $total_data);
838
839 $this->language->load('checkout/checkout');
840
841 $data = array();
842
843 $data['invoice_prefix'] = $this->config->get('config_invoice_prefix');
844 $data['store_id'] = $this->config->get('config_store_id');
845 $data['store_name'] = $this->config->get('config_name');
846
847 if ($data['store_id']) {
848 $data['store_url'] = $this->config->get('config_url');
849 } else {
850 $data['store_url'] = HTTP_SERVER;
851 }
852
853 if ($this->customer->isLogged() && isset($this->session->data['payment_address_id'])) {
854 $data['customer_id'] = $this->customer->getId();
855 $data['customer_group_id'] = $this->config->get('config_customer_group_id');
856 $data['firstname'] = $this->customer->getFirstName();
857 $data['lastname'] = $this->customer->getLastName();
858 $data['email'] = $this->customer->getEmail();
859 $data['telephone'] = $this->customer->getTelephone();
860 $data['fax'] = $this->customer->getFax();
861
862 $this->load->model('account/address');
863
864 $payment_address = $this->model_account_address->getAddress($this->session->data['payment_address_id']);
865 } elseif (isset($this->session->data['guest'])) {
866 $data['customer_id'] = 0;
867 $data['customer_group_id'] = $this->session->data['guest']['customer_group_id'];
868 $data['firstname'] = $this->session->data['guest']['firstname'];
869 $data['lastname'] = $this->session->data['guest']['lastname'];
870 $data['email'] = $this->session->data['guest']['email'];
871 $data['telephone'] = $this->session->data['guest']['telephone'];
872 $data['fax'] = $this->session->data['guest']['fax'];
873
874 $payment_address = $this->session->data['guest']['payment'];
875 }
876
877 $data['payment_firstname'] = isset($payment_address['firstname']) ? $payment_address['firstname'] : '';
878 $data['payment_lastname'] = isset($payment_address['lastname']) ? $payment_address['lastname'] : '';
879 $data['payment_company'] = isset($payment_address['company']) ? $payment_address['company'] : '';
880 $data['payment_company_id'] = isset($payment_address['company_id']) ? $payment_address['company_id'] : '';
881 $data['payment_tax_id'] = isset($payment_address['tax_id']) ? $payment_address['tax_id'] : '';
882 $data['payment_address_1'] = isset($payment_address['address_1']) ? $payment_address['address_1'] : '';
883 $data['payment_address_2'] = isset($payment_address['address_2']) ? $payment_address['address_2'] : '';
884 $data['payment_city'] = isset($payment_address['city']) ? $payment_address['city'] : '';
885 $data['payment_postcode'] = isset($payment_address['postcode']) ? $payment_address['postcode'] : '';
886 $data['payment_zone'] = isset($payment_address['zone']) ? $payment_address['zone'] : '';
887 $data['payment_zone_id'] = isset($payment_address['zone_id']) ? $payment_address['zone_id'] : '';
888 $data['payment_country'] = isset($payment_address['country']) ? $payment_address['country'] : '';
889 $data['payment_country_id'] = isset($payment_address['country_id']) ? $payment_address['country_id'] : '';
890 $data['payment_address_format'] = isset($payment_address['address_format']) ? $payment_address['address_format'] : '';
891
892 $data['payment_method'] = '';
893 if (isset($this->session->data['payment_method']['title'])) {
894 $data['payment_method'] = $this->session->data['payment_method']['title'];
895 }
896
897 $data['payment_code'] = '';
898 if (isset($this->session->data['payment_method']['code'])) {
899 $data['payment_code'] = $this->session->data['payment_method']['code'];
900 }
901
902 if ($this->cart->hasShipping()) {
903 if ($this->customer->isLogged()) {
904 $this->load->model('account/address');
905
906 $shipping_address = $this->model_account_address->getAddress($this->session->data['shipping_address_id']);
907 } elseif (isset($this->session->data['guest'])) {
908 $shipping_address = $this->session->data['guest']['shipping'];
909 }
910
911 $data['shipping_firstname'] = $shipping_address['firstname'];
912 $data['shipping_lastname'] = $shipping_address['lastname'];
913 $data['shipping_company'] = $shipping_address['company'];
914 $data['shipping_address_1'] = $shipping_address['address_1'];
915 $data['shipping_address_2'] = $shipping_address['address_2'];
916 $data['shipping_city'] = $shipping_address['city'];
917 $data['shipping_postcode'] = $shipping_address['postcode'];
918 $data['shipping_zone'] = $shipping_address['zone'];
919 $data['shipping_zone_id'] = $shipping_address['zone_id'];
920 $data['shipping_country'] = $shipping_address['country'];
921 $data['shipping_country_id'] = $shipping_address['country_id'];
922 $data['shipping_address_format'] = $shipping_address['address_format'];
923
924 $data['shipping_method'] = '';
925 if (isset($this->session->data['shipping_method']['title'])) {
926 $data['shipping_method'] = $this->session->data['shipping_method']['title'];
927 }
928
929 $data['shipping_code'] = '';
930 if (isset($this->session->data['shipping_method']['code'])) {
931 $data['shipping_code'] = $this->session->data['shipping_method']['code'];
932 }
933 } else {
934 $data['shipping_firstname'] = '';
935 $data['shipping_lastname'] = '';
936 $data['shipping_company'] = '';
937 $data['shipping_address_1'] = '';
938 $data['shipping_address_2'] = '';
939 $data['shipping_city'] = '';
940 $data['shipping_postcode'] = '';
941 $data['shipping_zone'] = '';
942 $data['shipping_zone_id'] = '';
943 $data['shipping_country'] = '';
944 $data['shipping_country_id'] = '';
945 $data['shipping_address_format'] = '';
946 $data['shipping_method'] = '';
947 $data['shipping_code'] = '';
948 }
949
950 $product_data = array();
951
952 foreach ($this->cart->getProducts() as $product) {
953 $option_data = array();
954
955 foreach ($product['option'] as $option) {
956 if ($option['type'] != 'file') {
957 $value = $option['option_value'];
958 } else {
959 $value = $this->encryption->decrypt($option['option_value']);
960 }
961
962 $option_data[] = array(
963 'product_option_id' => $option['product_option_id'],
964 'product_option_value_id' => $option['product_option_value_id'],
965 'option_id' => $option['option_id'],
966 'option_value_id' => $option['option_value_id'],
967 'name' => $option['name'],
968 'value' => $value,
969 'type' => $option['type']
970 );
971 }
972
973 $product_data[] = array(
974 'product_id' => $product['product_id'],
975 'name' => $product['name'],
976 'model' => $product['model'],
977 'option' => $option_data,
978 'download' => $product['download'],
979 'quantity' => $product['quantity'],
980 'subtract' => $product['subtract'],
981 'price' => $product['price'],
982 'total' => $product['total'],
983 'tax' => $this->tax->getTax($product['price'], $product['tax_class_id']),
984 'reward' => $product['reward']
985 );
986 }
987
988 // Gift Voucher
989 $voucher_data = array();
990
991 if (!empty($this->session->data['vouchers'])) {
992 foreach ($this->session->data['vouchers'] as $voucher) {
993 $voucher_data[] = array(
994 'description' => $voucher['description'],
995 'code' => substr(md5(mt_rand()), 0, 10),
996 'to_name' => $voucher['to_name'],
997 'to_email' => $voucher['to_email'],
998 'from_name' => $voucher['from_name'],
999 'from_email' => $voucher['from_email'],
1000 'voucher_theme_id' => $voucher['voucher_theme_id'],
1001 'message' => $voucher['message'],
1002 'amount' => $voucher['amount']
1003 );
1004 }
1005 }
1006
1007 $data['products'] = $product_data;
1008 $data['vouchers'] = $voucher_data;
1009 $data['totals'] = $total_data;
1010 $data['comment'] = $this->session->data['comment'];
1011 $data['total'] = $total;
1012
1013 if (isset($this->request->cookie['tracking'])) {
1014 $data['tracking'] = $this->request->cookie['tracking'];
1015
1016 $subtotal = $this->cart->getSubTotal();
1017
1018 // Affiliate
1019 $this->load->model('affiliate/affiliate');
1020
1021 $affiliate_info = $this->model_affiliate_affiliate->getAffiliateByCode($this->request->cookie['tracking']);
1022
1023 if ($affiliate_info) {
1024 $data['affiliate_id'] = $affiliate_info['affiliate_id'];
1025 $data['commission'] = ($subtotal / 100) * $affiliate_info['commission'];
1026 } else {
1027 $data['affiliate_id'] = 0;
1028 $data['commission'] = 0;
1029 }
1030
1031 // Marketing
1032 $this->load->model('checkout/marketing');
1033
1034 $marketing_info = $this->model_checkout_marketing->getMarketingByCode($this->request->cookie['tracking']);
1035
1036 if ($marketing_info) {
1037 $data['marketing_id'] = $marketing_info['marketing_id'];
1038 } else {
1039 $data['marketing_id'] = 0;
1040 }
1041 } else {
1042 $data['affiliate_id'] = 0;
1043 $data['commission'] = 0;
1044 $data['marketing_id'] = 0;
1045 $data['tracking'] = '';
1046 }
1047
1048 $data['language_id'] = $this->config->get('config_language_id');
1049 $data['currency_id'] = $this->currency->getId();
1050 $data['currency_code'] = $this->currency->getCode();
1051 $data['currency_value'] = $this->currency->getValue($this->currency->getCode());
1052 $data['ip'] = $this->request->server['REMOTE_ADDR'];
1053
1054 if (!empty($this->request->server['HTTP_X_FORWARDED_FOR'])) {
1055 $data['forwarded_ip'] = $this->request->server['HTTP_X_FORWARDED_FOR'];
1056 } elseif (!empty($this->request->server['HTTP_CLIENT_IP'])) {
1057 $data['forwarded_ip'] = $this->request->server['HTTP_CLIENT_IP'];
1058 } else {
1059 $data['forwarded_ip'] = '';
1060 }
1061
1062 if (isset($this->request->server['HTTP_USER_AGENT'])) {
1063 $data['user_agent'] = $this->request->server['HTTP_USER_AGENT'];
1064 } else {
1065 $data['user_agent'] = '';
1066 }
1067
1068 if (isset($this->request->server['HTTP_ACCEPT_LANGUAGE'])) {
1069 $data['accept_language'] = $this->request->server['HTTP_ACCEPT_LANGUAGE'];
1070 } else {
1071 $data['accept_language'] = '';
1072 }
1073
1074 $this->load->model('account/custom_field');
1075 $this->load->model('checkout/order');
1076
1077 $order_id = $this->model_checkout_order->addOrder($data);
1078 $this->session->data['order_id'] = $order_id;
1079
1080 $this->load->model('payment/pp_express');
1081
1082 $paypal_data = array(
1083 'TOKEN' => $this->session->data['paypal']['token'],
1084 'PAYERID' => $this->session->data['paypal']['payerid'],
1085 'METHOD' => 'DoExpressCheckoutPayment',
1086 'PAYMENTREQUEST_0_NOTIFYURL' => $this->url->link('payment/pp_express/ipn', '', 'SSL'),
1087 'RETURNFMFDETAILS' => 1
1088 );
1089
1090 $paypal_data = array_merge($paypal_data, $this->model_payment_pp_express->paymentRequestInfo());
1091
1092 $result = $this->model_payment_pp_express->call($paypal_data);
1093
1094 if ($result['ACK'] == 'Success') {
1095 //handle order status
1096 switch($result['PAYMENTINFO_0_PAYMENTSTATUS']) {
1097 case 'Canceled_Reversal':
1098 $order_status_id = $this->config->get('pp_express_canceled_reversal_status_id');
1099 break;
1100 case 'Completed':
1101 $order_status_id = $this->config->get('pp_express_completed_status_id');
1102 break;
1103 case 'Denied':
1104 $order_status_id = $this->config->get('pp_express_denied_status_id');
1105 break;
1106 case 'Expired':
1107 $order_status_id = $this->config->get('pp_express_expired_status_id');
1108 break;
1109 case 'Failed':
1110 $order_status_id = $this->config->get('pp_express_failed_status_id');
1111 break;
1112 case 'Pending':
1113 $order_status_id = $this->config->get('pp_express_pending_status_id');
1114 break;
1115 case 'Processed':
1116 $order_status_id = $this->config->get('pp_express_processed_status_id');
1117 break;
1118 case 'Refunded':
1119 $order_status_id = $this->config->get('pp_express_refunded_status_id');
1120 break;
1121 case 'Reversed':
1122 $order_status_id = $this->config->get('pp_express_reversed_status_id');
1123 break;
1124 case 'Voided':
1125 $order_status_id = $this->config->get('pp_express_voided_status_id');
1126 break;
1127 }
1128
1129 $this->model_checkout_order->addOrderHistory($order_id, $order_status_id);
1130
1131 //add order to paypal table
1132 $paypal_order_data = array(
1133 'order_id' => $order_id,
1134 'capture_status' => ($this->config->get('pp_express_method') == 'Sale' ? 'Complete' : 'NotComplete'),
1135 'currency_code' => $result['PAYMENTINFO_0_CURRENCYCODE'],
1136 'authorization_id' => $result['PAYMENTINFO_0_TRANSACTIONID'],
1137 'total' => $result['PAYMENTINFO_0_AMT']
1138 );
1139
1140 $paypal_order_id = $this->model_payment_pp_express->addOrder($paypal_order_data);
1141
1142 //add transaction to paypal transaction table
1143 $paypal_transaction_data = array(
1144 'paypal_order_id' => $paypal_order_id,
1145 'transaction_id' => $result['PAYMENTINFO_0_TRANSACTIONID'],
1146 'parent_transaction_id' => '',
1147 'note' => '',
1148 'msgsubid' => '',
1149 'receipt_id' => (isset($result['PAYMENTINFO_0_RECEIPTID']) ? $result['PAYMENTINFO_0_RECEIPTID'] : ''),
1150 'payment_type' => $result['PAYMENTINFO_0_PAYMENTTYPE'],
1151 'payment_status' => $result['PAYMENTINFO_0_PAYMENTSTATUS'],
1152 'pending_reason' => $result['PAYMENTINFO_0_PENDINGREASON'],
1153 'transaction_entity' => ($this->config->get('pp_express_method') == 'Sale' ? 'payment' : 'auth'),
1154 'amount' => $result['PAYMENTINFO_0_AMT'],
1155 'debug_data' => json_encode($result)
1156 );
1157
1158 $this->model_payment_pp_express->addTransaction($paypal_transaction_data);
1159
1160 $recurring_products = $this->cart->getRecurringProducts();
1161
1162 //loop through any products that are recurring items
1163 if ($recurring_products) {
1164 $this->language->load('payment/pp_express');
1165
1166 $this->load->model('checkout/recurring');
1167
1168 $billing_period = array(
1169 'day' => 'Day',
1170 'week' => 'Week',
1171 'semi_month' => 'SemiMonth',
1172 'month' => 'Month',
1173 'year' => 'Year'
1174 );
1175
1176 foreach($recurring_products as $item) {
1177 $data = array(
1178 'METHOD' => 'CreateRecurringPaymentsProfile',
1179 'TOKEN' => $this->session->data['paypal']['token'],
1180 'PROFILESTARTDATE' => gmdate("Y-m-d\TH:i:s\Z", gmmktime(gmdate("H"), gmdate("i")+5, gmdate("s"), gmdate("m"), gmdate("d"), gmdate("y"))),
1181 'BILLINGPERIOD' => $billing_period[$item['recurring']['frequency']],
1182 'BILLINGFREQUENCY' => $item['recurring']['cycle'],
1183 'TOTALBILLINGCYCLES' => $item['recurring']['duration'],
1184 'AMT' => $this->currency->format($this->tax->calculate($item['recurring']['price'], $item['tax_class_id'], $this->config->get('config_tax')), false, false, false) * $item['quantity'],
1185 'CURRENCYCODE' => $this->currency->getCode()
1186 );
1187
1188 //trial information
1189 if ($item['recurring']['trial']) {
1190 $data_trial = array(
1191 'TRIALBILLINGPERIOD' => $billing_period[$item['recurring']['trial_frequency']],
1192 'TRIALBILLINGFREQUENCY' => $item['recurring']['trial_cycle'],
1193 'TRIALTOTALBILLINGCYCLES' => $item['recurring']['trial_duration'],
1194 'TRIALAMT' => $this->currency->format($this->tax->calculate($item['recurring']['trial_price'], $item['tax_class_id'], $this->config->get('config_tax')), false, false, false) * $item['quantity']
1195 );
1196
1197 $trial_amt = $this->currency->format($this->tax->calculate($item['recurring']['trial_price'], $item['tax_class_id'], $this->config->get('config_tax')), false, false, false) * $item['quantity'] . ' ' . $this->currency->getCode();
1198 $trial_text = sprintf($this->language->get('text_trial'), $trial_amt, $item['recurring']['trial_cycle'], $item['recurring']['trial_frequency'], $item['recurring']['trial_duration']);
1199
1200 $data = array_merge($data, $data_trial);
1201 } else {
1202 $trial_text = '';
1203 }
1204
1205 $recurring_amt = $this->currency->format($this->tax->calculate($item['recurring']['price'], $item['tax_class_id'], $this->config->get('config_tax')), false, false, false) * $item['quantity'] . ' ' . $this->currency->getCode();
1206 $recurring_description = $trial_text . sprintf($this->language->get('text_recurring'), $recurring_amt, $item['recurring']['cycle'], $item['recurring']['frequency']);
1207
1208 if ($item['recurring']['duration'] > 0) {
1209 $recurring_description .= sprintf($this->language->get('text_length'), $item['recurring']['duration']);
1210 }
1211
1212 //create new recurring and set to pending status as no payment has been made yet.
1213 $recurring_id = $this->model_checkout_recurring->create($item, $order_id, $recurring_description);
1214
1215 $data['PROFILEREFERENCE'] = $recurring_id;
1216 $data['DESC'] = $recurring_description;
1217
1218 $result = $this->model_payment_pp_express->call($data);
1219
1220 if (isset($result['PROFILEID'])) {
1221 $this->model_checkout_recurring->addReference($recurring_id, $result['PROFILEID']);
1222 } else {
1223 // there was an error creating the recurring, need to log and also alert admin / user
1224
1225 }
1226 }
1227 }
1228
1229 $this->response->redirect($this->url->link('checkout/success'));
1230
1231 if (isset($result['REDIRECTREQUIRED']) && $result['REDIRECTREQUIRED'] == true) {
1232 //- handle german redirect here
1233 $this->response->redirect('https://www.paypal.com/cgi-bin/webscr?cmd=_complete-express-checkout&token=' . $this->session->data['paypal']['token']);
1234 }
1235 } else {
1236 if ($result['L_ERRORCODE0'] == '10486') {
1237 if (isset($this->session->data['paypal_redirect_count'])) {
1238
1239 if ($this->session->data['paypal_redirect_count'] == 2) {
1240 $this->session->data['paypal_redirect_count'] = 0;
1241 $this->session->data['error'] = $this->language->get('error_too_many_failures');
1242 $this->response->redirect($this->url->link('checkout/checkout', '', 'SSL'));
1243 } else {
1244 $this->session->data['paypal_redirect_count']++;
1245 }
1246 } else {
1247 $this->session->data['paypal_redirect_count'] = 1;
1248 }
1249
1250 if ($this->config->get('pp_express_test') == 1) {
1251 $this->response->redirect('https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=' . $this->session->data['paypal']['token']);
1252 } else {
1253 $this->response->redirect('https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=' . $this->session->data['paypal']['token']);
1254 }
1255 }
1256
1257 $this->session->data['error_warning'] = $result['L_LONGMESSAGE0'];
1258 $this->response->redirect($this->url->link('payment/pp_express/expressConfirm', '', 'SSL'));
1259 }
1260 } else {
1261 $this->response->redirect($redirect);
1262 }
1263 }
1264
1265 public function checkout() {
1266 if ((!$this->cart->hasProducts() && empty($this->session->data['vouchers'])) || (!$this->cart->hasStock() && !$this->config->get('config_stock_checkout'))) {
1267 $this->response->redirect($this->url->link('checkout/cart'));
1268 }
1269
1270 $this->load->model('payment/pp_express');
1271 $this->load->model('tool/image');
1272 $this->load->model('checkout/order');
1273
1274 $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']);
1275
1276 $max_amount = $this->cart->getTotal() * 1.5;
1277 $max_amount = $this->currency->format($max_amount, $this->currency->getCode(), '', false);
1278
1279 if ($this->cart->hasShipping()) {
1280 $shipping = 0;
1281 $data_shipping = array(
1282 'PAYMENTREQUEST_0_SHIPTONAME' => html_entity_decode($order_info['shipping_firstname'] . ' ' . $order_info['shipping_lastname'], ENT_QUOTES, 'UTF-8'),
1283 'PAYMENTREQUEST_0_SHIPTOSTREET' => html_entity_decode($order_info['shipping_address_1'], ENT_QUOTES, 'UTF-8'),
1284 'PAYMENTREQUEST_0_SHIPTOSTREET2' => html_entity_decode($order_info['shipping_address_2'], ENT_QUOTES, 'UTF-8'),
1285 'PAYMENTREQUEST_0_SHIPTOCITY' => html_entity_decode($order_info['shipping_city'], ENT_QUOTES, 'UTF-8'),
1286 'PAYMENTREQUEST_0_SHIPTOSTATE' => html_entity_decode($order_info['shipping_zone'], ENT_QUOTES, 'UTF-8'),
1287 'PAYMENTREQUEST_0_SHIPTOZIP' => html_entity_decode($order_info['shipping_postcode'], ENT_QUOTES, 'UTF-8'),
1288 'PAYMENTREQUEST_0_SHIPTOCOUNTRYCODE' => $order_info['shipping_iso_code_2']
1289 );
1290 } else {
1291 $shipping = 1;
1292 $data_shipping = array();
1293 }
1294
1295 $data = array(
1296 'METHOD' => 'SetExpressCheckout',
1297 'MAXAMT' => $max_amount,
1298 'RETURNURL' => $this->url->link('payment/pp_express/checkoutReturn', '', 'SSL'),
1299 'CANCELURL' => $this->url->link('checkout/checkout', '', 'SSL'),
1300 'REQCONFIRMSHIPPING' => 0,
1301 'NOSHIPPING' => $shipping,
1302 'LOCALECODE' => 'EN',
1303 'LANDINGPAGE' => 'Login',
1304 'HDRIMG' => $this->model_tool_image->resize($this->config->get('pp_express_logo'), 790, 90),
1305 'PAYFLOWCOLOR' => $this->config->get('pp_express_page_colour'),
1306 'CHANNELTYPE' => 'Merchant',
1307 'ALLOWNOTE' => $this->config->get('pp_express_allow_note')
1308 );
1309
1310 $data = array_merge($data, $data_shipping);
1311
1312 if (isset($this->session->data['pp_login']['seamless']['access_token']) && (isset($this->session->data['pp_login']['seamless']['customer_id']) && $this->session->data['pp_login']['seamless']['customer_id'] == $this->customer->getId()) && $this->config->get('pp_login_seamless')) {
1313 $data['IDENTITYACCESSTOKEN'] = $this->session->data['pp_login']['seamless']['access_token'];
1314 }
1315
1316 $data = array_merge($data, $this->model_payment_pp_express->paymentRequestInfo());
1317
1318 $result = $this->model_payment_pp_express->call($data);
1319
1320 /**
1321 * If a failed PayPal setup happens, handle it.
1322 */
1323 if (!isset($result['TOKEN'])) {
1324 $this->session->data['error'] = $result['L_LONGMESSAGE0'];
1325 /**
1326 * Unable to add error message to user as the session errors/success are not
1327 * used on the cart or checkout pages - need to be added?
1328 * If PayPal debug log is off then still log error to normal error log.
1329 */
1330 if ($this->config->get('pp_express_debug') == 1) {
1331 $this->log->write(serialize($result));
1332 }
1333
1334 $this->response->redirect($this->url->link('checkout/checkout', '', 'SSL'));
1335 }
1336
1337 $this->session->data['paypal']['token'] = $result['TOKEN'];
1338
1339 if ($this->config->get('pp_express_test') == 1) {
1340 header('Location: https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=' . $result['TOKEN'] . '&useraction=commit');
1341 } else {
1342 header('Location: https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=' . $result['TOKEN'] . '&useraction=commit');
1343 }
1344 }
1345
1346 public function checkoutReturn() {
1347 $this->language->load('payment/pp_express');
1348
1349 $this->load->model('payment/pp_express');
1350 $this->load->model('checkout/order');
1351
1352 $data = array(
1353 'METHOD' => 'GetExpressCheckoutDetails',
1354 'TOKEN' => $this->session->data['paypal']['token']
1355 );
1356
1357 $result = $this->model_payment_pp_express->call($data);
1358
1359 $this->session->data['paypal']['payerid'] = $result['PAYERID'];
1360 $this->session->data['paypal']['result'] = $result;
1361
1362 $order_id = $this->session->data['order_id'];
1363
1364 $paypal_data = array(
1365 'TOKEN' => $this->session->data['paypal']['token'],
1366 'PAYERID' => $this->session->data['paypal']['payerid'],
1367 'METHOD' => 'DoExpressCheckoutPayment',
1368 'PAYMENTREQUEST_0_NOTIFYURL' => $this->url->link('payment/pp_express/ipn', '', 'SSL'),
1369 'RETURNFMFDETAILS' => 1
1370 );
1371
1372 $paypal_data = array_merge($paypal_data, $this->model_payment_pp_express->paymentRequestInfo());
1373
1374 $result = $this->model_payment_pp_express->call($paypal_data);
1375
1376 if ($result['ACK'] == 'Success') {
1377 //handle order status
1378 switch($result['PAYMENTINFO_0_PAYMENTSTATUS']) {
1379 case 'Canceled_Reversal':
1380 $order_status_id = $this->config->get('pp_express_canceled_reversal_status_id');
1381 break;
1382 case 'Completed':
1383 $order_status_id = $this->config->get('pp_express_completed_status_id');
1384 break;
1385 case 'Denied':
1386 $order_status_id = $this->config->get('pp_express_denied_status_id');
1387 break;
1388 case 'Expired':
1389 $order_status_id = $this->config->get('pp_express_expired_status_id');
1390 break;
1391 case 'Failed':
1392 $order_status_id = $this->config->get('pp_express_failed_status_id');
1393 break;
1394 case 'Pending':
1395 $order_status_id = $this->config->get('pp_express_pending_status_id');
1396 break;
1397 case 'Processed':
1398 $order_status_id = $this->config->get('pp_express_processed_status_id');
1399 break;
1400 case 'Refunded':
1401 $order_status_id = $this->config->get('pp_express_refunded_status_id');
1402 break;
1403 case 'Reversed':
1404 $order_status_id = $this->config->get('pp_express_reversed_status_id');
1405 break;
1406 case 'Voided':
1407 $order_status_id = $this->config->get('pp_express_voided_status_id');
1408 break;
1409 }
1410
1411 $this->model_checkout_order->addOrderHistory($order_id, $order_status_id);
1412
1413 //add order to paypal table
1414 $paypal_order_data = array(
1415 'order_id' => $order_id,
1416 'capture_status' => ($this->config->get('pp_express_method') == 'Sale' ? 'Complete' : 'NotComplete'),
1417 'currency_code' => $result['PAYMENTINFO_0_CURRENCYCODE'],
1418 'authorization_id' => $result['PAYMENTINFO_0_TRANSACTIONID'],
1419 'total' => $result['PAYMENTINFO_0_AMT']
1420 );
1421
1422 $paypal_order_id = $this->model_payment_pp_express->addOrder($paypal_order_data);
1423
1424 //add transaction to paypal transaction table
1425 $paypal_transaction_data = array(
1426 'paypal_order_id' => $paypal_order_id,
1427 'transaction_id' => $result['PAYMENTINFO_0_TRANSACTIONID'],
1428 'parent_transaction_id' => '',
1429 'note' => '',
1430 'msgsubid' => '',
1431 'receipt_id' => (isset($result['PAYMENTINFO_0_RECEIPTID']) ? $result['PAYMENTINFO_0_RECEIPTID'] : ''),
1432 'payment_type' => $result['PAYMENTINFO_0_PAYMENTTYPE'],
1433 'payment_status' => $result['PAYMENTINFO_0_PAYMENTSTATUS'],
1434 'pending_reason' => $result['PAYMENTINFO_0_PENDINGREASON'],
1435 'transaction_entity' => ($this->config->get('pp_express_method') == 'Sale' ? 'payment' : 'auth'),
1436 'amount' => $result['PAYMENTINFO_0_AMT'],
1437 'debug_data' => json_encode($result)
1438 );
1439 $this->model_payment_pp_express->addTransaction($paypal_transaction_data);
1440
1441 $recurring_products = $this->cart->getRecurringProducts();
1442
1443 //loop through any products that are recurring items
1444 if ($recurring_products) {
1445 $this->load->model('checkout/recurring');
1446
1447 $billing_period = array(
1448 'day' => 'Day',
1449 'week' => 'Week',
1450 'semi_month' => 'SemiMonth',
1451 'month' => 'Month',
1452 'year' => 'Year'
1453 );
1454
1455 foreach ($recurring_products as $item) {
1456 $data = array(
1457 'METHOD' => 'CreateRecurringPaymentsProfile',
1458 'TOKEN' => $this->session->data['paypal']['token'],
1459 'PROFILESTARTDATE' => gmdate("Y-m-d\TH:i:s\Z", gmmktime(gmdate('H'), gmdate('i') + 5, gmdate('s'), gmdate('m'), gmdate('d'), gmdate('y'))),
1460 'BILLINGPERIOD' => $billing_period[$item['recurring']['frequency']],
1461 'BILLINGFREQUENCY' => $item['recurring']['cycle'],
1462 'TOTALBILLINGCYCLES' => $item['recurring']['duration'],
1463 'AMT' => $this->currency->format($this->tax->calculate($item['recurring']['price'], $item['tax_class_id'], $this->config->get('config_tax')), false, false, false) * $item['quantity'],
1464 'CURRENCYCODE' => $this->currency->getCode()
1465 );
1466
1467 //trial information
1468 if ($item['recurring']['trial'] == 1) {
1469 $data_trial = array(
1470 'TRIALBILLINGPERIOD' => $billing_period[$item['recurring']['trial_frequency']],
1471 'TRIALBILLINGFREQUENCY' => $item['recurring']['trial_cycle'],
1472 'TRIALTOTALBILLINGCYCLES' => $item['recurring']['trial_duration'],
1473 'TRIALAMT' => $this->currency->format($this->tax->calculate($item['recurring']['trial_price'], $item['tax_class_id'], $this->config->get('config_tax')), false, false, false) * $item['quantity']
1474 );
1475
1476 $trial_amt = $this->currency->format($this->tax->calculate($item['recurring']['trial_price'], $item['tax_class_id'], $this->config->get('config_tax')), false, false, false) * $item['quantity'] . ' ' . $this->currency->getCode();
1477 $trial_text = sprintf($this->language->get('text_trial'), $trial_amt, $item['recurring']['trial_cycle'], $item['recurring']['trial_frequency'], $item['recurring']['trial_duration']);
1478
1479 $data = array_merge($data, $data_trial);
1480 } else {
1481 $trial_text = '';
1482 }
1483
1484 $recurring_amt = $this->currency->format($this->tax->calculate($item['recurring']['price'], $item['tax_class_id'], $this->config->get('config_tax')), false, false, false) * $item['quantity'] . ' ' . $this->currency->getCode();
1485 $recurring_description = $trial_text . sprintf($this->language->get('text_recurring'), $recurring_amt, $item['recurring']['cycle'], $item['recurring']['frequency']);
1486
1487 if ($item['recurring']['duration'] > 0) {
1488 $recurring_description .= sprintf($this->language->get('text_length'), $item['recurring']['duration']);
1489 }
1490
1491 //create new recurring and set to pending status as no payment has been made yet.
1492 $recurring_id = $this->model_checkout_recurring->create($item, $order_id, $recurring_description);
1493
1494 $data['PROFILEREFERENCE'] = $recurring_id;
1495 $data['DESC'] = $recurring_description;
1496
1497 $result = $this->model_payment_pp_express->call($data);
1498
1499 if (isset($result['PROFILEID'])) {
1500 $this->model_checkout_recurring->addReference($recurring_id, $result['PROFILEID']);
1501 } else {
1502 // there was an error creating the recurring, need to log and also alert admin / user
1503
1504 }
1505 }
1506 }
1507
1508 if (isset($result['REDIRECTREQUIRED']) && $result['REDIRECTREQUIRED'] == true) {
1509 //- handle german redirect here
1510 $this->response->redirect('https://www.paypal.com/cgi-bin/webscr?cmd=_complete-express-checkout&token=' . $this->session->data['paypal']['token']);
1511 } else {
1512 $this->response->redirect($this->url->link('checkout/success'));
1513 }
1514 } else {
1515 if ($result['L_ERRORCODE0'] == '10486') {
1516 if (isset($this->session->data['paypal_redirect_count'])) {
1517
1518 if ($this->session->data['paypal_redirect_count'] == 2) {
1519 $this->session->data['paypal_redirect_count'] = 0;
1520 $this->session->data['error'] = $this->language->get('error_too_many_failures');
1521
1522 $this->response->redirect($this->url->link('checkout/checkout', '', 'SSL'));
1523 } else {
1524 $this->session->data['paypal_redirect_count']++;
1525 }
1526 } else {
1527 $this->session->data['paypal_redirect_count'] = 1;
1528 }
1529
1530 if ($this->config->get('pp_express_test') == 1) {
1531 $this->response->redirect('https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=' . $this->session->data['paypal']['token']);
1532 } else {
1533 $this->response->redirect('https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=' . $this->session->data['paypal']['token']);
1534 }
1535 }
1536
1537 $this->language->load('payment/pp_express');
1538
1539 $data['breadcrumbs'] = array();
1540
1541 $data['breadcrumbs'][] = array(
1542 'href' => $this->url->link('common/home'),
1543 'text' => $this->language->get('text_home')
1544 );
1545
1546 $data['breadcrumbs'][] = array(
1547 'href' => $this->url->link('checkout/cart'),
1548 'text' => $this->language->get('text_cart')
1549 );
1550
1551 $data['heading_title'] = $this->language->get('error_heading_title');
1552
1553 $data['text_error'] = '<div class="warning">' . $result['L_ERRORCODE0'] . ' : ' . $result['L_LONGMESSAGE0'] . '</div>';
1554
1555 $data['button_continue'] = $this->language->get('button_continue');
1556
1557 $data['continue'] = $this->url->link('checkout/cart');
1558
1559 unset($this->session->data['success']);
1560
1561 $this->response->addHeader($this->request->server['SERVER_PROTOCOL'] . ' 404 Not Found');
1562
1563 $data['column_left'] = $this->load->controller('common/column_left');
1564 $data['column_right'] = $this->load->controller('common/column_right');
1565 $data['content_top'] = $this->load->controller('common/content_top');
1566 $data['content_bottom'] = $this->load->controller('common/content_bottom');
1567 $data['footer'] = $this->load->controller('common/footer');
1568 $data['header'] = $this->load->controller('common/header');
1569
1570 if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/error/not_found.tpl')) {
1571 $this->response->setOutput($this->load->view($this->config->get('config_template') . '/template/error/not_found.tpl'));
1572 } else {
1573 $this->response->setOutput($this->load->view('default/template/error/not_found.tpl'));
1574 }
1575 }
1576 }
1577
1578 public function ipn() {
1579 $this->load->model('payment/pp_express');
1580 $this->load->model('account/recurring');
1581
1582 $request = 'cmd=_notify-validate';
1583
1584 foreach ($_POST as $key => $value) {
1585 $request .= '&' . $key . '=' . urlencode(html_entity_decode($value, ENT_QUOTES, 'UTF-8'));
1586 }
1587
1588 if ($this->config->get('pp_express_test') == 1) {
1589 $curl = curl_init('https://www.sandbox.paypal.com/cgi-bin/webscr');
1590 } else {
1591 $curl = curl_init('https://www.paypal.com/cgi-bin/webscr');
1592 }
1593
1594 curl_setopt($curl, CURLOPT_POST, true);
1595 curl_setopt($curl, CURLOPT_POSTFIELDS, $request);
1596 curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
1597 curl_setopt($curl, CURLOPT_HEADER, false);
1598 curl_setopt($curl, CURLOPT_TIMEOUT, 30);
1599 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
1600
1601 $response = trim(curl_exec($curl));
1602
1603 if (!$response) {
1604 $this->model_payment_pp_express->log(array('error' => curl_error($curl),'error_no' => curl_errno($curl)), 'Curl failed');
1605 }
1606
1607 $this->model_payment_pp_express->log(array('request' => $request,'response' => $response), 'IPN data');
1608
1609 if ((string)$response == "VERIFIED") {
1610
1611 if ($this->config->get('pp_express_debug') == 1) {
1612 $this->log->write((isset($this->request->post['transaction_entity']) ? $this->request->post['transaction_entity'] : ''));
1613 }
1614
1615 if (isset($this->request->post['txn_id'])) {
1616 $transaction = $this->model_payment_pp_express->getTransactionRow($this->request->post['txn_id']);
1617 } else {
1618 $transaction = false;
1619 }
1620
1621 if (isset($this->request->post['parent_txn_id'])) {
1622 $parent_transaction = $this->model_payment_pp_express->getTransactionRow($this->request->post['parent_txn_id']);
1623 } else {
1624 $parent_transaction = false;
1625 }
1626
1627 if ($transaction) {
1628 //transaction exists, check for cleared payment or updates etc
1629 if ($this->config->get('pp_express_debug') == 1) {
1630 $this->log->write('Transaction exists');
1631 }
1632
1633 //if the transaction is pending but the new status is completed
1634 if ($transaction['payment_status'] != $this->request->post['payment_status']) {
1635 $this->db->query("UPDATE `" . DB_PREFIX . "paypal_order_transaction` SET `payment_status` = '" . $this->request->post['payment_status'] . "' WHERE `transaction_id` = '" . $this->db->escape($transaction['transaction_id']) . "' LIMIT 1");
1636 } elseif ($transaction['payment_status'] == 'Pending' && ($transaction['pending_reason'] != $this->request->post['pending_reason'])) {
1637 //payment is still pending but the pending reason has changed, update it.
1638 $this->db->query("UPDATE `" . DB_PREFIX . "paypal_order_transaction` SET `pending_reason` = '" . $this->request->post['pending_reason'] . "' WHERE `transaction_id` = '" . $this->db->escape($transaction['transaction_id']) . "' LIMIT 1");
1639 }
1640 } else {
1641 if ($this->config->get('pp_express_debug') == 1) {
1642 $this->log->write('Transaction does not exist');
1643 }
1644
1645 if ($parent_transaction) {
1646 if ($this->config->get('pp_express_debug') == 1) {
1647 $this->log->write('Parent transaction exists');
1648 }
1649 //parent transaction exists
1650
1651 //add new related transaction
1652 $transaction = array(
1653 'paypal_order_id' => $parent_transaction['paypal_order_id'],
1654 'transaction_id' => $this->request->post['txn_id'],
1655 'parent_transaction_id' => $this->request->post['parent_txn_id'],
1656 'note' => '',
1657 'msgsubid' => '',
1658 'receipt_id' => (isset($this->request->post['receipt_id']) ? $this->request->post['receipt_id'] : ''),
1659 'payment_type' => (isset($this->request->post['payment_type']) ? $this->request->post['payment_type'] : ''),
1660 'payment_status' => (isset($this->request->post['payment_status']) ? $this->request->post['payment_status'] : ''),
1661 'pending_reason' => (isset($this->request->post['pending_reason']) ? $this->request->post['pending_reason'] : ''),
1662 'amount' => $this->request->post['mc_gross'],
1663 'debug_data' => json_encode($this->request->post),
1664 'transaction_entity' => (isset($this->request->post['transaction_entity']) ? $this->request->post['transaction_entity'] : '')
1665 );
1666
1667 $this->model_payment_pp_express->addTransaction($transaction);
1668
1669 /**
1670 * If there has been a refund, log this against the parent transaction.
1671 */
1672 if (isset($this->request->post['payment_status']) && $this->request->post['payment_status'] == 'Refunded') {
1673 if (($this->request->post['mc_gross'] * -1) == $parent_transaction['amount']) {
1674 $this->db->query("UPDATE `" . DB_PREFIX . "paypal_order_transaction` SET `payment_status` = 'Refunded' WHERE `transaction_id` = '" . $this->db->escape($parent_transaction['transaction_id']) . "' LIMIT 1");
1675 } else {
1676 $this->db->query("UPDATE `" . DB_PREFIX . "paypal_order_transaction` SET `payment_status` = 'Partially-Refunded' WHERE `transaction_id` = '" . $this->db->escape($parent_transaction['transaction_id']) . "' LIMIT 1");
1677 }
1678 }
1679
1680 /**
1681 * If the capture payment is now complete
1682 */
1683 if (isset($this->request->post['auth_status']) && $this->request->post['auth_status'] == 'Completed' && $parent_transaction['payment_status'] == 'Pending') {
1684 $captured = $this->currency->format($this->model_payment_pp_express->totalCaptured($parent_transaction['paypal_order_id']), false, false, false);
1685 $refunded = $this->currency->format($this->model_payment_pp_express->totalRefundedOrder($parent_transaction['paypal_order_id']), false, false, false);
1686 $remaining = $this->currency->format($parent_transaction['amount'] - $captured + $refunded, false, false, false);
1687
1688 if ($this->config->get('pp_express_debug') == 1) {
1689 $this->log->write('Captured: ' . $captured);
1690 $this->log->write('Refunded: ' . $refunded);
1691 $this->log->write('Remaining: ' . $remaining);
1692 }
1693
1694 if ($remaining > 0.00) {
1695 $transaction = array(
1696 'paypal_order_id' => $parent_transaction['paypal_order_id'],
1697 'transaction_id' => '',
1698 'parent_transaction_id' => $this->request->post['parent_txn_id'],
1699 'note' => '',
1700 'msgsubid' => '',
1701 'receipt_id' => '',
1702 'payment_type' => '',
1703 'payment_status' => 'Void',
1704 'pending_reason' => '',
1705 'amount' => '',
1706 'debug_data' => 'Voided after capture',
1707 'transaction_entity' => 'auth'
1708 );
1709
1710 $this->model_payment_pp_express->addTransaction($transaction);
1711 }
1712
1713 $this->model_payment_pp_express->updateOrder('Complete', $parent_transaction['order_id']);
1714 }
1715
1716 } else {
1717 //parent transaction doesn't exists, need to investigate?
1718 if ($this->config->get('pp_express_debug') == 1) {
1719 $this->log->write('Parent transaction not found');
1720 }
1721 }
1722 }
1723
1724 /*
1725 * Subscription payments
1726 *
1727 * recurring ID should always exist if its a recurring payment transaction.
1728 *
1729 * also the reference will match a recurring payment ID
1730 */
1731 if (isset($this->request->post['txn_type'])) {
1732 //payment
1733 if ($this->request->post['txn_type'] == 'recurring_payment') {
1734 $recurring = $this->model_account_recurring->getProfileByRef($this->request->post['recurring_payment_id']);
1735
1736 if ($recurring != false) {
1737 $this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "', `date_added` = NOW(), `amount` = '" . (float)$this->request->post['amount'] . "', `type` = '1'");
1738
1739 //as there was a payment the recurring is active, ensure it is set to active (may be been suspended before)
1740 if ($recurring['status'] != 1) {
1741 $this->db->query("UPDATE `" . DB_PREFIX . "order_recurring` SET `status` = 2 WHERE `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "'");
1742 }
1743 }
1744 }
1745
1746 //suspend
1747 if ($this->request->post['txn_type'] == 'recurring_payment_suspended') {
1748 $recurring = $this->model_account_recurring->getProfileByRef($this->request->post['recurring_payment_id']);
1749
1750 if ($recurring != false) {
1751 $this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "', `date_added` = NOW(), `type` = '6'");
1752 $this->db->query("UPDATE `" . DB_PREFIX . "order_recurring` SET `status` = 3 WHERE `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "' LIMIT 1");
1753 }
1754 }
1755
1756 //suspend due to max failed
1757 if ($this->request->post['txn_type'] == 'recurring_payment_suspended_due_to_max_failed_payment') {
1758 $recurring = $this->model_account_recurring->getProfileByRef($this->request->post['recurring_payment_id']);
1759
1760 if ($recurring != false) {
1761 $this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "', `date_added` = NOW(), `type` = '7'");
1762 $this->db->query("UPDATE `" . DB_PREFIX . "order_recurring` SET `status` = 3 WHERE `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "' LIMIT 1");
1763 }
1764 }
1765
1766 //payment failed
1767 if ($this->request->post['txn_type'] == 'recurring_payment_failed') {
1768 $recurring = $this->model_account_recurring->getProfileByRef($this->request->post['recurring_payment_id']);
1769
1770 if ($recurring != false) {
1771 $this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "', `date_added` = NOW(), `type` = '4'");
1772 }
1773 }
1774
1775 //outstanding payment failed
1776 if ($this->request->post['txn_type'] == 'recurring_payment_outstanding_payment_failed') {
1777 $recurring = $this->model_account_recurring->getProfileByRef($this->request->post['recurring_payment_id']);
1778
1779 if ($recurring != false) {
1780 $this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "', `date_added` = NOW(), `type` = '8'");
1781 }
1782 }
1783
1784 //outstanding payment
1785 if ($this->request->post['txn_type'] == 'recurring_payment_outstanding_payment') {
1786 $recurring = $this->model_account_recurring->getProfileByRef($this->request->post['recurring_payment_id']);
1787
1788 if ($recurring != false) {
1789 $this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "', `date_added` = NOW(), `amount` = '" . (float)$this->request->post['amount'] . "', `type` = '2'");
1790
1791 //as there was a payment the recurring is active, ensure it is set to active (may be been suspended before)
1792 if ($recurring['status'] != 1) {
1793 $this->db->query("UPDATE `" . DB_PREFIX . "order_recurring` SET `status` = 2 WHERE `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "'");
1794 }
1795 }
1796 }
1797
1798 //date_added
1799 if ($this->request->post['txn_type'] == 'recurring_payment_recurring_date_added') {
1800 $recurring = $this->model_account_recurring->getProfileByRef($this->request->post['recurring_payment_id']);
1801
1802 if ($recurring != false) {
1803 $this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "', `date_added` = NOW(), `type` = '0'");
1804
1805 if ($recurring['status'] != 1) {
1806 $this->db->query("UPDATE `" . DB_PREFIX . "order_recurring` SET `status` = 2 WHERE `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "'");
1807 }
1808 }
1809 }
1810
1811 //cancelled
1812 if ($this->request->post['txn_type'] == 'recurring_payment_recurring_cancel') {
1813 $recurring = $this->model_account_recurring->getProfileByRef($this->request->post['recurring_payment_id']);
1814
1815 if ($recurring != false && $recurring['status'] != 3) {
1816 $this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "', `date_added` = NOW(), `type` = '5'");
1817 $this->db->query("UPDATE `" . DB_PREFIX . "order_recurring` SET `status` = 4 WHERE `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "' LIMIT 1");
1818 }
1819 }
1820
1821 //skipped
1822 if ($this->request->post['txn_type'] == 'recurring_payment_skipped') {
1823 $recurring = $this->model_account_recurring->getProfileByRef($this->request->post['recurring_payment_id']);
1824
1825 if ($recurring != false) {
1826 $this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "', `date_added` = NOW(), `type` = '3'");
1827 }
1828 }
1829
1830 //expired
1831 if ($this->request->post['txn_type'] == 'recurring_payment_expired') {
1832 $recurring = $this->model_account_recurring->getProfileByRef($this->request->post['recurring_payment_id']);
1833
1834 if ($recurring != false) {
1835 $this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "', `date_added` = NOW(), `type` = '9'");
1836 $this->db->query("UPDATE `" . DB_PREFIX . "order_recurring` SET `status` = 5 WHERE `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "' LIMIT 1");
1837 }
1838 }
1839 }
1840 } elseif ((string)$response == "INVALID") {
1841 $this->model_payment_pp_express->log(array('IPN was invalid'), 'IPN fail');
1842 } else {
1843 if ($this->config->get('pp_express_debug') == 1) {
1844 $this->log->write('string unknown ');
1845 }
1846 }
1847
1848 header("HTTP/1.1 200 Ok");
1849 }
1850
1851 public function shipping() {
1852 $this->shippingValidate($this->request->post['shipping_method']);
1853
1854 $this->response->redirect($this->url->link('payment/pp_express/expressConfirm'));
1855 }
1856
1857 protected function shippingValidate($code) {
1858 $this->language->load('checkout/cart');
1859 $this->language->load('payment/pp_express');
1860
1861 if (empty($code)) {
1862 $this->session->data['error_warning'] = $this->language->get('error_shipping');
1863 return false;
1864 } else {
1865 $shipping = explode('.', $code);
1866
1867 if (!isset($shipping[0]) || !isset($shipping[1]) || !isset($this->session->data['shipping_methods'][$shipping[0]]['quote'][$shipping[1]])) {
1868 $this->session->data['error_warning'] = $this->language->get('error_shipping');
1869 return false;
1870 } else {
1871 $this->session->data['shipping_method'] = $this->session->data['shipping_methods'][$shipping[0]]['quote'][$shipping[1]];
1872 $this->session->data['success'] = $this->language->get('text_shipping_updated');
1873 return true;
1874 }
1875 }
1876 }
1877
1878 public function recurringCancel() {
1879 //cancel an active recurring
1880
1881 $this->load->model('account/recurring');
1882 $this->load->model('payment/pp_express');
1883 $this->language->load('account/recurring');
1884
1885 $recurring = $this->model_account_recurring->getProfile($this->request->get['recurring_id']);
1886
1887 if ($recurring && !empty($recurring['reference'])) {
1888
1889 $result = $this->model_payment_pp_express->recurringCancel($recurring['reference']);
1890
1891 if (isset($result['PROFILEID'])) {
1892 $this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "', `date_added` = NOW(), `type` = '5'");
1893 $this->db->query("UPDATE `" . DB_PREFIX . "order_recurring` SET `status` = 4 WHERE `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "' LIMIT 1");
1894
1895 $this->session->data['success'] = $this->language->get('text_cancelled');
1896 } else {
1897 $this->session->data['error'] = sprintf($this->language->get('error_not_cancelled'), $result['L_LONGMESSAGE0']);
1898 }
1899 } else {
1900 $this->session->data['error'] = $this->language->get('error_not_found');
1901 }
1902
1903 $this->response->redirect($this->url->link('account/recurring/info', 'recurring_id=' . $this->request->get['recurring_id'], 'SSL'));
1904 }
1905
1906 protected function validateCoupon() {
1907 $this->load->model('checkout/coupon');
1908
1909 $coupon_info = $this->model_checkout_coupon->getCoupon($this->request->post['coupon']);
1910
1911 $error = '';
1912
1913 if (!$coupon_info) {
1914 $error = $this->language->get('error_coupon');
1915 }
1916
1917 if (!$error) {
1918 return true;
1919 } else {
1920 $this->session->data['error_warning'] = $error;
1921 return false;
1922 }
1923 }
1924
1925 protected function validateVoucher() {
1926 $this->load->model('checkout/voucher');
1927
1928 $voucher_info = $this->model_checkout_voucher->getVoucher($this->request->post['voucher']);
1929
1930 $error = '';
1931
1932 if (!$voucher_info) {
1933 $error = $this->language->get('error_voucher');
1934 }
1935
1936 if (!$error) {
1937 return true;
1938 } else {
1939 $this->session->data['error_warning'] = $this->language->get('error_voucher');
1940 return false;
1941 }
1942 }
1943
1944 protected function validateReward() {
1945 $points = $this->customer->getRewardPoints();
1946
1947 $points_total = 0;
1948
1949 foreach ($this->cart->getProducts() as $product) {
1950 if ($product['points']) {
1951 $points_total += $product['points'];
1952 }
1953 }
1954
1955 $error = '';
1956
1957 if (empty($this->request->post['reward'])) {
1958 $error = $this->language->get('error_reward');
1959 }
1960
1961 if ($this->request->post['reward'] > $points) {
1962 $error = sprintf($this->language->get('error_points'), $this->request->post['reward']);
1963 }
1964
1965 if ($this->request->post['reward'] > $points_total) {
1966 $error = sprintf($this->language->get('error_maximum'), $points_total);
1967 }
1968
1969 if (!$error) {
1970 return true;
1971 } else {
1972 $this->session->data['error_warning'] = $error;
1973 return false;
1974 }
1975 }
1976
1977 public function recurringButtons() {
1978 $this->language->load('payment/pp_express');
1979
1980 $recurring = $this->model_account_recurring->getProfile($this->request->get['recurring_id']);
1981
1982 $data['buttons'] = array();
1983
1984 if ($recurring['status'] == 2 || $recurring['status'] == 3) {
1985 $data['buttons'][] = array(
1986 'text' => $this->language->get('button_cancel_recurring'),
1987 'link' => $this->url->link('payment/pp_express/recurringCancel', 'recurring_id=' . $this->request->get['recurring_id'], 'SSL')
1988 );
1989 }
1990
1991 $data['buttons'][] = array(
1992 'text' => $this->language->get('button_continue'),
1993 'link' => $this->url->link('account/recurring', '', 'SSL')
1994 );
1995
1996 if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/common/buttons.tpl')) {
1997 return $this->load->view($this->config->get('config_template') . '/template/common/buttons.tpl', $data);
1998 } else {
1999 return $this->load->view('default/template/common/buttons.tpl', $data);
2000 }
2001 }
2002}