/** * Hides away the curl request * * @param $url API Endpoint to send request to * @param $data Request parameters - sent as POST * @param bool $skip_ssl_verify Skip SSL verification - useful for development (and local testing) * @return mixed * @throws APIException */ public function request($url, $data, $skip_ssl_verify = FALSE) { if (is_string($data)) { $post_string = $data; } else { $post_string = http_build_query($data); } if (__DEBUG__) { ShopLogger::log('REQUEST ' . $url . ' ' . $post_string); } // Request $request = curl_init($url); curl_setopt($request, CURLOPT_HEADER, 0); curl_setopt($request, CURLOPT_RETURNTRANSFER, 1); curl_setopt($request, CURLOPT_POSTFIELDS, $post_string); if ($skip_ssl_verify) { curl_setopt($request, CURLOPT_SSL_VERIFYPEER, FALSE); } else { curl_setopt($request, CURLOPT_SSL_VERIFYPEER, TRUE); } $response = curl_exec($request); if (!$response) { $error = curl_error($request); throw new APIException("CURL error: " . $error); } if (__DEBUG__) { ShopLogger::log('RESPONSE ' . $response); } curl_close($request); return $response; }
/** * Constructor; logs the error message and the stack trace to the shop log * * @param string $message * @param int $code * @param Exception $previous */ public function __construct($message, $code = 0, Exception $previous = NULL) { $log_message = "APIException: <a href='#' class='logger_message_details'>" . $message . '</a>'; $log_message .= '<div style="display:none">' . $this->getTraceAsString() . '</br>'; $log_message .= print_r($_REQUEST, TRUE) . '</div>'; ShopLogger::log($log_message); parent::__construct($message, $code, $previous); }
/** * Constructor * * @param string $message * @param int $code * @param Exception $previous */ public function __construct($message, $code = 0, Exception $previous = NULL) { ShopLogger::log("ShopException: <a href='#' class='logger_message_details'>" . $message . '</a><div style="display:none">' . $this->getTraceAsString() . '</div>'); parent::__construct($message, $code, $previous); }
/** * Handle all incoming IPN notifications from 2checkout */ public function notify() { // Check the sender is 2Checkout $key = Context::get('md5_hash'); $sale_id = Context::get('sale_id'); $vendor_id = $this->sid; $invoice_id = Context::get('invoice_id'); $secret_word = $this->secret_word; $expected_key = strtoupper(md5($sale_id . $vendor_id . $invoice_id . $secret_word)); if(strtoupper($key) != $expected_key) { ShopLogger::log("Invalid 2checkout IPN message received - key " . $key . ' ' . print_r($_REQUEST, TRUE)); return; } $message_type = Context::get('message_type'); if($message_type != 'ORDER_CREATED') { ShopLogger::log("Unsupported IPN 2checkout message received: " . print_r($_REQUEST, TRUE)); return; } $cart_srl = Context::get('vendor_order_id'); $transaction_id = $sale_id; // Hopefully, this is order number $order_repository = new OrderRepository(); // Check if order has already been created for this transaction $order = $order_repository->getOrderByTransactionId($transaction_id); if(!$order) // If not, create it { $cart = new Cart($cart_srl); $this->createNewOrderAndDeleteExistingCart($cart, $transaction_id); } }
/** * Returns a plugin instance * * @param $name * @param $module_srl * @return mixed */ public function getPlugin($name, $module_srl) { $data = $this->getPluginInfoFromDatabase($name, $module_srl); // Update code; add module srl to plugins that have module_srl = 0 // TODO Remove this when releasing XE Shop if (!$data) { $data = $this->getPluginInfoFromDatabase($name, 0); if ($data) { ShopLogger::log("Upgrading plugin {$name} - setting module_srl from 0 to {$module_srl}"); $this->fixPlugin($data->name, 0, $module_srl); $data->module_srl = $module_srl; } } // If plugin exists in the database, return it as is if ($data) { return $this->getPluginInstanceFromProperties($data); } // Otherwise, initialize it with info from the extension class and insert in database $plugin = $this->getPluginInstanceByName($name, $module_srl); $this->insertPlugin($plugin); return $this->getPlugin($name, $module_srl); }
/** * Send email to new users */ public function triggerSendSignUpEmail($member_args) { $site_module_info = Context::get('site_module_info'); $module_srl = $site_module_info->index_module_srl; $shop = new ShopInfo($module_srl); // Don't send anything if sender and receiver email addresses are missing if(!$shop->getEmail() || !$member_args->email_address) { ShopLogger::log("Failed to send welcome email to user. Member email is not set." . print_r($member_args, TRUE)); return; } global $lang; $email_subject = sprintf($lang->new_member_email_subject , $shop->getShopTitle() ); $email_content = sprintf($lang->new_member_email_content , getFullSiteUrl('', 'act', 'dispShopHome') , $shop->getShopTitle() , getFullSiteUrl('', 'act', 'dispShopMyAccount') , getFullSiteUrl('', 'act', 'dispShopHome') , $shop->getShopTitle() ); $oMail = new Mail(); $oMail->setTitle($email_subject); $oMail->setContent($email_content); $oMail->setSender($shop->getShopTitle(), $shop->getShopEmail()); $oMail->setReceiptor(FALSE, $member_args->email_address); $oMail->send(); }
/** * Handles all IPN notifications from Paypal */ public function notify($cart) { // 1. Retrieve all POST data received and post back to paypal, to make sure // the request sender is not fake // Do not retrieve data with Context::getRequestVars() because it skips empty values // causing the Paypal validation to fail $args = $_POST; if(__DEBUG__) { ShopLogger::log("Received IPN Notification: " . http_build_query($args)); } $response = $this->postDataBackToPaypalToValidateSenderIdentity($args); if($response->isVerified()) { ShopLogger::log("Successfully validated IPN data"); $payment_info = $this->getIPNPaymentInfo($args); if(!$payment_info->isRelatedToCartPayment()) return; // 2. If the source of the POST is correct, we now need to check that data is also valid if(!$order = $this->orderCreatedForThisTransaction($payment_info->txn_id)) { // check that receiver_email is your Primary PayPal email if(!$payment_info->paymentReceiverIsMe($this->business_account)) { ShopLogger::log("Possible fraud - invalid receiver email: " . $payment_info->receiver_email); $this->markTransactionAsFailedInUserCart( $payment_info->cart_srl, $payment_info->txn_id, "There was a problem processing your payment. Your order could not be completed." ); return; } // check the payment_status is Completed if(!$payment_info->paymentIsComplete()) { ShopLogger::log("Payment is not completed. Payment status [" . $payment_info->payment_status. "] received"); $this->markTransactionAsFailedInUserCart( $payment_info->cart_srl, $payment_info->txn_id, "Your payment was not completed. Your order was not created." ); return; } $cart = new Cart($payment_info->cart_srl); if(!$payment_info->paymentIsForTheCorrectAmount($cart->getTotal(), $cart->getCurrency())) { ShopLogger::log("Invalid payment. " . PHP_EOL . "Payment amount [" . $payment_info->payment_amount . "] instead of " . $cart->getTotal() . PHP_EOL . "Payment currency [" . $payment_info->payment_currency . "] instead of " . $cart->getCurrency() ); $this->markTransactionAsFailedInUserCart( $payment_info->cart_srl, $payment_info->txn_id, "Your payment was invalid. Your order was not created." ); return; } // 3. If the source of the POST is correct, we can now use the data to create an order // based on the message received $this->createNewOrderAndDeleteExistingCart($cart, $payment_info->txn_id); } } else { ShopLogger::log("Invalid IPN data received: " . $response); } }
/** * Process the payment * * @param Cart $cart * @param $error_message * @return bool|mixed */ public function processPayment(Cart $cart, &$error_message) { $cc_number = Context::get('cc_number'); $cc_exp_month = Context::get('cc_exp_month'); $cc_exp_year = Context::get('cc_exp_year'); $cc_cvv = Context::get('cc_cvv'); // Unset credit card info so that XE won't put it in session Context::set('cc_number', NULL); Context::set('cc_exp_month', NULL); Context::set('cc_exp_year', NULL); Context::set('cc_cvv', NULL); if(!$cc_number) { $error_message = "Please enter you credit card number"; return FALSE; } if(!$cc_exp_month || !$cc_exp_year) { $error_message = "Please enter you credit card expiration date"; return FALSE; } if(!$cc_cvv) { $error_message = "Please enter you credit card verification number"; return FALSE; } $cc_number = str_replace(array(' ', '-'), '', $cc_number); if (!preg_match ('/^4[0-9]{12}(?:[0-9]{3})?$/', $cc_number) // Visa && !preg_match ('/^5[1-5][0-9]{14}$/', $cc_number) // MasterCard && !preg_match ('/^3[47][0-9]{13}$/', $cc_number) // American Express && !preg_match ('/^6(?:011|5[0-9]{2})[0-9]{12}$/', $cc_number) //Discover ){ $error_message = 'Please enter your credit card number!'; } $cc_exp = sprintf('%02d%d', $cc_exp_month, $cc_exp_year); $transaction = new AuthorizeNetAim($this->api_login_id, $this->transaction_key); // 1. Set payment info $transaction->amount = $cart->getTotal(); $transaction->card_num = $cc_number; $transaction->exp_date = $cc_exp; $transaction->invoice_num = $cart->cart_srl; // 2. Set billing address info $transaction->first_name = $cart->getCustomerFirstname(); $transaction->last_name = $cart->getCustomerLastname(); $transaction->company = $cart->getBillingAddress()->company; $transaction->address = $cart->getBillingAddress()->address; $transaction->city = $cart->getBillingAddress()->city; $transaction->zip = $cart->getBillingAddress()->postal_code; $transaction->country = $cart->getBillingAddress()->country; $transaction->email = $cart->getBillingAddress()->email; // 3. Set shipping address info $transaction->ship_to_first_name = $cart->getShippingAddress()->firstname; $transaction->ship_to_last_name = $cart->getShippingAddress()->lastname; $transaction->ship_to_company = $cart->getShippingAddress()->company; $transaction->ship_to_address = $cart->getShippingAddress()->address; $transaction->ship_to_city = $cart->getShippingAddress()->city; $transaction->ship_to_zip = $cart->getShippingAddress()->postal_code; $transaction->ship_to_country = $cart->getShippingAddress()->country; $response = $transaction->authorizeAndCapture(); if ($response->approved) { return TRUE; } else { ShopLogger::log("Authorize.NET transaction failed: " . print_r($response, TRUE)); $error_message = "There was a problem with charging your credit card; Please try again or try a different payment method"; return FALSE; } }
/** * Send email to user notifying him of the newly created order */ public static function sendNewOrderEmails($order_srl) { $repo = new OrderRepository(); $order = $repo->getOrderBySrl($order_srl); $shop = new ShopInfo($order->module_srl); // Don't send anything if shop email is not configured if (!$shop->getShopEmail()) { ShopLogger::log("Failed to send order email for order #{$order->order_srl}; Shop email is not configured"); return; } self::sendNewOrderMailToCustomer($shop, $order); self::sendNewOrderMailToAdministrator($shop, $order); }
/** * Calculates shipping rates * * @param Cart $cart Shipping cart for which to calculate shipping; includes shipping address * @param String $service Represents the specific service for which to calcualte shipping (e.g. Standard or Priority) * @return null */ public function calculateShipping(Cart $cart, $service = NULL) { /** @var $unit The thing we will compare to the table rates: price, weight or item count */ $unit = NULL; switch($this->type){ case TableRateShipping::TYPE_PRICE_DESTINATION: $unit = $cart->getItemTotal(); // TODO Check if maybe getTotalAfterDiscount should be used instead break; case TableRateShipping::TYPE_WEIGHT_DESTINATION: $unit = $cart->getTotalWeight(); break; case TableRateShipping::TYPE_ITEMS_COUNT_DESTINATION: $unit = count($cart->getProducts()); break; } $shipping_address = $cart->getShippingAddress(); $shipping_country = $shipping_address->country; $table_rates = $this->getTableRatesForCountry($shipping_country); $shipping_price = NULL; foreach($table_rates as $table_rate) { if($table_rate->unit <= $unit) { $shipping_price = $table_rate->price; } else { break; } } // If no shipping price was calculated, just take the last if(is_null($shipping_price)) { ShopLogger::log("Couldn't match any rules from the table;"); $shipping_price = $table_rate->price; } return $shipping_price; }