worldpay.php (16832B)
1 <?php 2 3 class ModelExtensionPaymentWorldpay extends Model { 4 5 public function getMethod($address, $total) { 6 $this->load->language('extension/payment/worldpay'); 7 8 $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "zone_to_geo_zone WHERE geo_zone_id = '" . (int)$this->config->get('worldpay_geo_zone_id') . "' AND country_id = '" . (int)$address['country_id'] . "' AND (zone_id = '" . (int)$address['zone_id'] . "' OR zone_id = '0')"); 9 10 if ($this->config->get('payment_worldpay_total') > 0 && $this->config->get('payment_worldpay_total') > $total) { 11 $status = false; 12 } elseif (!$this->config->get('worldpay_geo_zone_id')) { 13 $status = true; 14 } elseif ($query->num_rows) { 15 $status = true; 16 } else { 17 $status = false; 18 } 19 20 $method_data = array(); 21 22 if ($status) { 23 $method_data = array( 24 'code' => 'worldpay', 25 'title' => $this->language->get('text_title'), 26 'terms' => '', 27 'sort_order' => $this->config->get('worldpay_sort_order') 28 ); 29 } 30 31 return $method_data; 32 } 33 34 public function getCards($customer_id) { 35 36 $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "worldpay_card WHERE customer_id = '" . (int)$customer_id . "'"); 37 38 $card_data = array(); 39 40 $this->load->model('account/address'); 41 42 foreach ($query->rows as $row) { 43 44 $card_data[] = array( 45 'card_id' => $row['card_id'], 46 'customer_id' => $row['customer_id'], 47 'token' => $row['token'], 48 'digits' => $row['digits'], 49 'expiry' => $row['expiry'], 50 'type' => $row['type'], 51 ); 52 } 53 return $card_data; 54 } 55 56 public function addCard($order_id, $card_data) { 57 $this->db->query("INSERT into " . DB_PREFIX . "worldpay_card SET customer_id = '" . $this->db->escape($card_data['customer_id']) . "', order_id = '" . $this->db->escape($order_id) . "', digits = '" . $this->db->escape($card_data['Last4Digits']) . "', expiry = '" . $this->db->escape($card_data['ExpiryDate']) . "', type = '" . $this->db->escape($card_data['CardType']) . "', token = '" . $this->db->escape($card_data['Token']) . "'"); 58 } 59 60 public function deleteCard($token) { 61 $this->db->query("DELETE FROM " . DB_PREFIX . "worldpay_card WHERE customer_id = '" . $this->customer->isLogged() . "' AND token = '" . $this->db->escape($token) . "'"); 62 63 if ($this->db->countAffected() > 0) { 64 return true; 65 } else { 66 return false; 67 } 68 } 69 70 public function addOrder($order_info, $order_code) { 71 $this->db->query("INSERT INTO `" . DB_PREFIX . "worldpay_order` SET `order_id` = '" . (int)$order_info['order_id'] . "', `order_code` = '" . $this->db->escape($order_code) . "', `date_added` = now(), `date_modified` = now(), `currency_code` = '" . $this->db->escape($order_info['currency_code']) . "', `total` = '" . $this->currency->format($order_info['total'], $order_info['currency_code'], false, false) . "'"); 72 73 return $this->db->getLastId(); 74 } 75 76 public function getOrder($order_id) { 77 $qry = $this->db->query("SELECT * FROM `" . DB_PREFIX . "worldpay_order` WHERE `order_id` = '" . (int)$order_id . "' LIMIT 1"); 78 79 if ($qry->num_rows) { 80 $order = $qry->row; 81 $order['transactions'] = $this->getTransactions($order['worldpay_order_id']); 82 83 return $order; 84 } else { 85 return false; 86 } 87 } 88 89 public function addTransaction($worldpay_order_id, $type, $order_info) { 90 $this->db->query("INSERT INTO `" . DB_PREFIX . "worldpay_order_transaction` SET `worldpay_order_id` = '" . (int)$worldpay_order_id . "', `date_added` = now(), `type` = '" . $this->db->escape($type) . "', `amount` = '" . $this->currency->format($order_info['total'], $order_info['currency_code'], false, false) . "'"); 91 } 92 93 public function getTransactions($worldpay_order_id) { 94 $qry = $this->db->query("SELECT * FROM `" . DB_PREFIX . "worldpay_order_transaction` WHERE `worldpay_order_id` = '" . (int)$worldpay_order_id . "'"); 95 96 if ($qry->num_rows) { 97 return $qry->rows; 98 } else { 99 return false; 100 } 101 } 102 103 public function recurringPayment($item, $order_id_rand, $token) { 104 105 $this->load->model('checkout/recurring'); 106 $this->load->model('extension/payment/worldpay'); 107 //trial information 108 if ($item['recurring']['trial'] == 1) { 109 $price = $item['recurring']['trial_price']; 110 $trial_amt = $this->currency->format($this->tax->calculate($item['recurring']['trial_price'], $item['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency'], false, false) * $item['quantity'] . ' ' . $this->session->data['currency']; 111 $trial_text = sprintf($this->language->get('text_trial'), $trial_amt, $item['recurring']['trial_cycle'], $item['recurring']['trial_frequency'], $item['recurring']['trial_duration']); 112 } else { 113 $price = $item['recurring']['price']; 114 $trial_text = ''; 115 } 116 117 $recurring_amt = $this->currency->format($this->tax->calculate($item['recurring']['price'], $item['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency'], false, false) * $item['quantity'] . ' ' . $this->session->data['currency']; 118 $recurring_description = $trial_text . sprintf($this->language->get('text_recurring'), $recurring_amt, $item['recurring']['cycle'], $item['recurring']['frequency']); 119 120 if ($item['recurring']['duration'] > 0) { 121 $recurring_description .= sprintf($this->language->get('text_length'), $item['recurring']['duration']); 122 } 123 124 $order_recurring_id = $this->model_checkout_recurring->addRecurring($this->session->data['order_id'], $recurring_description, $item['recurring']); 125 126 $this->model_checkout_recurring->editReference($order_recurring_id, $order_id_rand); 127 128 $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); 129 130 $order = array( 131 "token" => $token, 132 "orderType" => 'RECURRING', 133 "amount" => (int)($price * 100), 134 "currencyCode" => $order_info['currency_code'], 135 "name" => $order_info['firstname'] . ' ' . $order_info['lastname'], 136 "orderDescription" => $order_info['store_name'] . ' - ' . date('Y-m-d H:i:s'), 137 "customerOrderCode" => 'orderRecurring-' . $order_recurring_id 138 ); 139 140 $this->model_extension_payment_worldpay->logger($order); 141 142 $response_data = $this->model_extension_payment_worldpay->sendCurl('orders', $order); 143 144 $this->model_extension_payment_worldpay->logger($response_data); 145 146 $next_payment = new DateTime('now'); 147 $trial_end = new DateTime('now'); 148 $subscription_end = new DateTime('now'); 149 150 if ($item['recurring']['trial'] == 1 && $item['recurring']['trial_duration'] != 0) { 151 $next_payment = $this->calculateSchedule($item['recurring']['trial_frequency'], $next_payment, $item['recurring']['trial_cycle']); 152 $trial_end = $this->calculateSchedule($item['recurring']['trial_frequency'], $trial_end, $item['recurring']['trial_cycle'] * $item['recurring']['trial_duration']); 153 } elseif ($item['recurring']['trial'] == 1) { 154 $next_payment = $this->calculateSchedule($item['recurring']['trial_frequency'], $next_payment, $item['recurring']['trial_cycle']); 155 $trial_end = new DateTime('0000-00-00'); 156 } 157 158 if ($trial_end > $subscription_end && $item['recurring']['duration'] != 0) { 159 $subscription_end = new DateTime(date_format($trial_end, 'Y-m-d H:i:s')); 160 $subscription_end = $this->calculateSchedule($item['recurring']['frequency'], $subscription_end, $item['recurring']['cycle'] * $item['recurring']['duration']); 161 } elseif ($trial_end == $subscription_end && $item['recurring']['duration'] != 0) { 162 $next_payment = $this->calculateSchedule($item['recurring']['frequency'], $next_payment, $item['recurring']['cycle']); 163 $subscription_end = $this->calculateSchedule($item['recurring']['frequency'], $subscription_end, $item['recurring']['cycle'] * $item['recurring']['duration']); 164 } elseif ($trial_end > $subscription_end && $item['recurring']['duration'] == 0) { 165 $subscription_end = new DateTime('0000-00-00'); 166 } elseif ($trial_end == $subscription_end && $item['recurring']['duration'] == 0) { 167 $next_payment = $this->calculateSchedule($item['recurring']['frequency'], $next_payment, $item['recurring']['cycle']); 168 $subscription_end = new DateTime('0000-00-00'); 169 } 170 171 if (isset($response_data->paymentStatus) && $response_data->paymentStatus == 'SUCCESS') { 172 $this->addRecurringOrder($order_info, $response_data->orderCode, $token, $price, $order_recurring_id, date_format($trial_end, 'Y-m-d H:i:s'), date_format($subscription_end, 'Y-m-d H:i:s')); 173 174 $this->updateRecurringOrder($order_recurring_id, date_format($next_payment, 'Y-m-d H:i:s')); 175 176 $this->addProfileTransaction($order_recurring_id, $response_data->orderCode, $price, 1); 177 } else { 178 $this->addProfileTransaction($order_recurring_id, '', $price, 4); 179 } 180 } 181 182 public function cronPayment() { 183 184 $this->load->model('account/order'); 185 $this->load->model('checkout/order'); 186 $profiles = $this->getProfiles(); 187 $cron_data = array(); 188 $i = 1; 189 foreach ($profiles as $profile) { 190 $recurring_order = $this->getRecurringOrder($profile['order_recurring_id']); 191 192 $today = new DateTime('now'); 193 $unlimited = new DateTime('0000-00-00'); 194 $next_payment = new DateTime($recurring_order['next_payment']); 195 $trial_end = new DateTime($recurring_order['trial_end']); 196 $subscription_end = new DateTime($recurring_order['subscription_end']); 197 198 $order_info = $this->model_checkout_order->getOrder($profile['order_id']); 199 200 if (($today > $next_payment) && ($trial_end > $today || $trial_end == $unlimited)) { 201 $price = $this->currency->format($profile['trial_price'], $order_info['currency_code'], false, false); 202 $frequency = $profile['trial_frequency']; 203 $cycle = $profile['trial_cycle']; 204 } elseif (($today > $next_payment) && ($subscription_end > $today || $subscription_end == $unlimited)) { 205 $price = $this->currency->format($profile['recurring_price'], $order_info['currency_code'], false, false); 206 $frequency = $profile['recurring_frequency']; 207 $cycle = $profile['recurring_cycle']; 208 } else { 209 continue; 210 } 211 212 $order = array( 213 "token" => $recurring_order['token'], 214 "orderType" => 'RECURRING', 215 "amount" => (int)($price * 100), 216 "currencyCode" => $order_info['currency_code'], 217 "name" => $order_info['firstname'] . ' ' . $order_info['lastname'], 218 "orderDescription" => $order_info['store_name'] . ' - ' . date('Y-m-d H:i:s'), 219 "customerOrderCode" => 'orderRecurring-' . $profile['order_recurring_id'] . '-repeat-' . $i++ 220 ); 221 222 $this->model_extension_payment_worldpay->logger($order); 223 224 $response_data = $this->model_extension_payment_worldpay->sendCurl('orders', $order); 225 226 $this->model_extension_payment_worldpay->logger($response_data); 227 228 $cron_data[] = $response_data; 229 230 if (isset($response_data->paymentStatus) && $response_data->paymentStatus == 'SUCCESS') { 231 $this->addProfileTransaction($profile['order_recurring_id'], $response_data->orderCode, $price, 1); 232 $next_payment = $this->calculateSchedule($frequency, $next_payment, $cycle); 233 $next_payment = date_format($next_payment, 'Y-m-d H:i:s'); 234 $this->updateRecurringOrder($profile['order_recurring_id'], $next_payment); 235 } else { 236 $this->addProfileTransaction($profile['order_recurring_id'], '', $price, 4); 237 } 238 } 239 $log = new Log('worldpay_recurring_orders.log'); 240 $log->write(print_r($cron_data, 1)); 241 return $cron_data; 242 } 243 244 private function calculateSchedule($frequency, $next_payment, $cycle) { 245 if ($frequency == 'semi_month') { 246 $day = date_format($next_payment, 'd'); 247 $value = 15 - $day; 248 $isEven = false; 249 if ($cycle % 2 == 0) { 250 $isEven = true; 251 } 252 253 $odd = ($cycle + 1) / 2; 254 $plus_even = ($cycle / 2) + 1; 255 $minus_even = $cycle / 2; 256 257 if ($day == 1) { 258 $odd = $odd - 1; 259 $plus_even = $plus_even - 1; 260 $day = 16; 261 } 262 263 if ($day <= 15 && $isEven) { 264 $next_payment->modify('+' . $value . ' day'); 265 $next_payment->modify('+' . $minus_even . ' month'); 266 } elseif ($day <= 15) { 267 $next_payment->modify('first day of this month'); 268 $next_payment->modify('+' . $odd . ' month'); 269 } elseif ($day > 15 && $isEven) { 270 $next_payment->modify('first day of this month'); 271 $next_payment->modify('+' . $plus_even . ' month'); 272 } elseif ($day > 15) { 273 $next_payment->modify('+' . $value . ' day'); 274 $next_payment->modify('+' . $odd . ' month'); 275 } 276 } else { 277 $next_payment->modify('+' . $cycle . ' ' . $frequency); 278 } 279 return $next_payment; 280 } 281 282 private function addRecurringOrder($order_info, $order_code, $token, $price, $order_recurring_id, $trial_end, $subscription_end) { 283 $this->db->query("INSERT INTO `" . DB_PREFIX . "worldpay_order_recurring` SET `order_id` = '" . (int)$order_info['order_id'] . "', `order_recurring_id` = '" . (int)$order_recurring_id . "', `order_code` = '" . $this->db->escape($order_code) . "', `token` = '" . $this->db->escape($token) . "', `date_added` = now(), `date_modified` = now(), `next_payment` = now(), `trial_end` = '" . $trial_end . "', `subscription_end` = '" . $subscription_end . "', `currency_code` = '" . $this->db->escape($order_info['currency_code']) . "', `total` = '" . $this->currency->format($price, $order_info['currency_code'], false, false) . "'"); 284 } 285 286 private function updateRecurringOrder($order_recurring_id, $next_payment) { 287 $this->db->query("UPDATE `" . DB_PREFIX . "worldpay_order_recurring` SET `next_payment` = '" . $next_payment . "', `date_modified` = now() WHERE `order_recurring_id` = '" . (int)$order_recurring_id . "'"); 288 } 289 290 private function getRecurringOrder($order_recurring_id) { 291 $qry = $this->db->query("SELECT * FROM " . DB_PREFIX . "worldpay_order_recurring WHERE order_recurring_id = '" . (int)$order_recurring_id . "'"); 292 return $qry->row; 293 } 294 295 private function addProfileTransaction($order_recurring_id, $order_code, $price, $type) { 296 $this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$order_recurring_id . "', `date_added` = NOW(), `amount` = '" . (float)$price . "', `type` = '" . (int)$type . "', `reference` = '" . $this->db->escape($order_code) . "'"); 297 } 298 299 private function getProfiles() { 300 $sql = " 301 SELECT `or`.order_recurring_id 302 FROM `" . DB_PREFIX . "order_recurring` `or` 303 JOIN `" . DB_PREFIX . "order` `o` USING(`order_id`) 304 WHERE o.payment_code = 'worldpay'"; 305 306 $qry = $this->db->query($sql); 307 308 $order_recurring = array(); 309 310 foreach ($qry->rows as $profile) { 311 $order_recurring[] = $this->getProfile($profile['order_recurring_id']); 312 } 313 return $order_recurring; 314 } 315 316 private function getProfile($order_recurring_id) { 317 $qry = $this->db->query("SELECT * FROM " . DB_PREFIX . "order_recurring WHERE order_recurring_id = " . (int)$order_recurring_id); 318 return $qry->row; 319 } 320 321 public function getWorldpayOrder($worldpay_order_id) { 322 $qry = $this->db->query("SELECT * FROM " . DB_PREFIX . "worldpay_order WHERE order_code = " . (int)$worldpay_order_id); 323 return $qry->row; 324 } 325 326 public function updateCronJobRunTime() { 327 $this->db->query("DELETE FROM `" . DB_PREFIX . "setting` WHERE `code` = 'worldpay' AND `key` = 'worldpay_last_cron_job_run'"); 328 $this->db->query("INSERT INTO `" . DB_PREFIX . "setting` (`store_id`, `code`, `key`, `value`, `serialized`) VALUES (0, 'worldpay', 'worldpay_last_cron_job_run', NOW(), 0)"); 329 } 330 331 public function sendCurl($url, $order = null) { 332 $curl = curl_init(); 333 curl_setopt($curl, CURLOPT_URL, 'https://api.worldpay.com/v1/' . $url); 334 $content_length = 0; 335 if ($order) { 336 $json = json_encode($order); 337 $content_length = strlen($json); 338 curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST'); 339 curl_setopt($curl, CURLOPT_POSTFIELDS, $json); 340 } 341 curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); 342 curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 0); 343 curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 344 curl_setopt($curl, CURLOPT_TIMEOUT, 10); 345 curl_setopt( 346 $curl, CURLOPT_HTTPHEADER, array( 347 "Authorization: " . $this->config->get('payment_worldpay_service_key'), 348 "Content-Type: application/json", 349 "Content-Length: " . $content_length 350 ) 351 ); 352 353 $result = json_decode(curl_exec($curl)); 354 curl_close($curl); 355 return $result; 356 } 357 358 public function logger($data) { 359 if ($this->config->get('worldpay_debug')) { 360 $log = new Log('worldpay_debug.log'); 361 $backtrace = debug_backtrace(); 362 $log->write($backtrace[6]['class'] . '::' . $backtrace[6]['function'] . ' Data: ' . print_r($data, 1)); 363 } 364 } 365 366 public function recurringPayments() { 367 /* 368 * Used by the checkout to state the module 369 * supports recurring profiles. 370 */ 371 return true; 372 } 373 374 }