/** * Process PayPal Instant Payment Notifications (IPN) * * @access public * @return void */ public function processPostSale() { $arrData = array(); foreach ($_POST as $k => $v) { $arrData[] = $k . '=' . urlencode($v); } $objRequest = new Request(); $objRequest->send('https://www.' . ($this->debug ? 'sandbox.' : '') . 'paypal.com/cgi-bin/webscr?cmd=_notify-validate', implode('&', $arrData), 'post'); if ($objRequest->hasError()) { $this->log('Request Error: ' . $objRequest->error, __METHOD__, TL_ERROR); exit; } elseif ($objRequest->response == 'VERIFIED' && ($this->Input->post('receiver_email', true) == $this->paypal_account || $this->debug)) { $objOrder = new IsotopeOrder(); if (!$objOrder->findBy('id', $this->Input->post('invoice'))) { $this->log('Order ID "' . $this->Input->post('invoice') . '" not found', __METHOD__, TL_ERROR); return; } // Validate payment data (see #2221) if ($objOrder->currency != $this->Input->post('mc_currency') || $objOrder->grandTotal != $this->Input->post('mc_gross')) { $this->log('IPN manipulation in payment from "' . $this->Input->post('payer_email') . '" !', __METHOD__, TL_ERROR); return; } if (!$objOrder->checkout()) { $this->log('IPN checkout for Order ID "' . $this->Input->post('invoice') . '" failed', __METHOD__, TL_ERROR); return; } // Load / initialize data $arrPayment = deserialize($objOrder->payment_data, true); // Store request data in order for future references $arrPayment['POSTSALE'][] = $_POST; $arrData = $objOrder->getData(); $arrData['old_payment_status'] = $arrPayment['status']; $arrPayment['status'] = $this->Input->post('payment_status'); $arrData['new_payment_status'] = $arrPayment['status']; // array('pending','processing','complete','on_hold', 'cancelled'), switch ($arrPayment['status']) { case 'Completed': $objOrder->date_paid = time(); break; case 'Canceled_Reversal': case 'Denied': case 'Expired': case 'Failed': case 'Voided': $objOrder->date_paid = ''; if ($objOrder->status == 'complete') { $objOrder->status = 'on_hold'; } break; case 'In-Progress': case 'Partially_Refunded': case 'Pending': case 'Processed': case 'Refunded': case 'Reversed': break; } $objOrder->payment_data = $arrPayment; $objOrder->save(); $this->log('PayPal IPN: data accepted', __METHOD__, TL_GENERAL); } else { $this->log('PayPal IPN: data rejected (' . $objRequest->response . ')', __METHOD__, TL_ERROR); } header('HTTP/1.1 200 OK'); exit; }
/** * Authorize or capture the payment * * @param int * @param float * @param array * @param bool * @access public * @return bool */ public function authCapturePayment($intOrderId, $fltOrderTotal, $blnCapture = false) { //Gather Order data and set IsotopeOrder object $objOrder = new IsotopeOrder(); if (!$objOrder->findBy('id', $intOrderId)) { $objOrder->uniqid = uniqid($this->Isotope->Config->orderPrefix, true); $objOrder->cart_id = $this->Isotope->Cart->id; $objOrder->findBy('id', $objOrder->save()); } $strLineItems = ''; $arrBilling = array(); $arrShipping = array(); $arrProducts = array(); $arrPaymentInfo = array(); //grab any existing payment data. If this is an order where a prior auth was made and a new total greater than the original exists, //we need to re-auth. Otherwise we simply use the old auth with the <= order total. $arrOrderPaymentData = deserialize($objOrder->payment_data, true); //Gather product and address data depending on FE(Cart) or BE(Order) if (TL_MODE == 'FE') { $arrBilling = $this->Isotope->Cart->billingAddress; $arrShipping = $this->Isotope->Cart->shippingAddress; $arrProducts = $this->Isotope->Cart->getProducts(); } else { $arrBilling = $objOrder->billingAddress; $arrShipping = $objOrder->shippingAddress; $arrProducts = $objOrder->getProducts(); } if (count($arrProducts)) { foreach ($arrProducts as $objProduct) { $arrItemData = array(); $arrItemData = array($objProduct->id, $objProduct->name, substr($objProduct->description, 0, 100), $objProduct->quantity_requested, $objProduct->price, $objProduct->tax_class ? 'Y' : 'N'); $arrLineItems[] = implode('<|>', $arrItemData); } $strLineItems .= implode('&', $arrLineItems); } //Authorization type $strAuthType = $blnCapture ? 'PRIOR_AUTH_CAPTURE' : 'AUTH_ONLY'; //Get Address Data $arrBillingSubdivision = explode('-', $arrBilling['subdivision']); $arrShippingSubdivision = explode('-', $arrShipping['subdivision']); //Set up basic request fields required by all transactions $authnet_values_default = array("x_version" => '3.1', "x_login" => $this->authorize_login, "x_tran_key" => $this->authorize_trans_key, "x_type" => $strAuthType, "x_delim_char" => $this->authorize_delimiter, "x_delim_data" => "TRUE", "x_relay_response" => "FALSE", "x_amount" => $fltOrderTotal, "x_test_request" => $this->debug ? "TRUE" : "FALSE"); switch ($strAuthType) { case 'AUTH_ONLY': $authnet_values_authonly = array("x_url" => "FALSE", "x_description" => "Order Number " . $this->Isotope->Config->orderPrefix . $objOrder->order_id, "x_invoice_num" => $objOrder->order_id, "x_first_name" => $arrBilling['firstname'], "x_last_name" => $arrBilling['lastname'], "x_company" => $arrBilling['company'], "x_address" => $arrBilling['street_1'] . "\n" . $arrBilling['street_2'] . "\n" . $arrBilling['street_3'], "x_city" => $arrBilling['city'], "x_state" => $arrBillingSubdivision[1], "x_zip" => $arrBilling['postal'], "x_email_customer" => "FALSE", "x_email" => $arrBilling['email'], "x_country" => $arrBilling['country'], "x_phone" => $arrBilling['phone'], "x_ship_to_first_name" => $arrShipping['firstname'], "x_ship_to_last_name" => $arrShipping['lastname'], "x_ship_to_company" => $arrShipping['company'], "x_ship_to_address" => $arrShipping['street_1'] . "\n" . $arrShipping['street_2'] . "\n" . $arrShipping['street_3'], "x_ship_to_city" => $arrShipping['city'], "x_ship_to_state" => $arrShippingSubdivision[1], "x_ship_to_zip" => $arrShipping['postal'], "x_ship_to_country" => $arrShipping['country']); $authnet_values = array_merge($authnet_values_default, $authnet_values_authonly); break; case 'PRIOR_AUTH_CAPTURE': $arrTransactionData = deserialize($objOrder->payment_data, true); $authnet_values = array_merge($authnet_values_default, array("x_trans_id" => $arrTransactionData['transaction-id'])); break; default: break; } if (!$blnCapture) { $arrPaymentInput = $this->Input->post('payment'); unset($_POST['payment']); $authnet_values["x_method"] = "CC"; $authnet_values["x_card_num"] = $arrPaymentInput['card_accountNumber']; $authnet_values["x_exp_date"] = $arrPaymentInput['card_expirationMonth'] . substr($arrPaymentInput['card_expirationYear'], 2, 2); if ($this->requireCCV) { $authnet_values["x_card_code"] = $arrPaymentInput['card_cvNumber']; } $arrPaymentInfo["x_card_num"] = $this->maskCC($arrData['card_accountNumber']); //PCI COMPLIANCE - MASK THE CC DATA $arrPaymentInfo["x_card_type"] = $GLOBALS['ISO_LANG']['CCT'][$arrData['card_cardType']]; } foreach ($authnet_values as $key => $value) { $fields .= "{$key}=" . urlencode($value) . "&"; } $fieldsFinal = rtrim($fields, '&'); //new auth required if one has been sent and the value of that was less than our new value. if (!count($arrOrderPaymentData) || $arrOrderPaymentData['transaction-status'] != 'Approved' || $blnCapture || !$blnCapture && count($arrOrderPaymentData) && $fltOrderTotal > $arrOrderPaymentData['grand-total']) { $objRequest = new Request(); $objRequest->send('https://' . ($this->debug ? 'test' : 'secure') . '.authorize.net/gateway/transact.dll', $fieldsFinal, 'post'); $arrResponses = $this->handleResponse($objRequest->response); $arrResponseCodes = $this->getResponseCodes($objRequest->response); unset($arrPaymentInput); //clear all cc input foreach (array_keys($arrResponses) as $key) { $arrReponseLabels[standardize($key)] = $key; } $this->loadLanguageFile('payment'); $this->strStatus = $arrResponses['transaction-status']; $this->strReason = $GLOBALS['TL_LANG']['MSG']['authorizedotnet'][$arrResponseCodes['response_type']][$arrResponseCodes['response_code']]; } else { //otherwise, if this isn't a capture, simply bypass/return true. If it is, we need to do some additional work below. if (!$blnCapture) { return true; } } if (!$blnCapture) { switch ($arrResponses['transaction-status']) { case 'Approved': $objOrder->status = $this->new_order_status; $blnFail = false; break; default: $objOrder->status = 'on_hold'; $blnFail = true; break; } } //Update payment data AKA Response Data. Transaction ID will not be saved during test mode. $arrPaymentInfo = count($arrOrderPaymentData) ? array_merge($arrOrderPaymentData, $arrResponses) : $arrResponses; $objOrder->payment_data = serialize($arrPaymentInfo); $objOrder->save(); //unlock the payment submit $_SESSION['CHECKOUT_DATA']['payment']['request_lockout'] = false; if ($blnFail) { $this->log(sprintf("Transaction failure. Transaction Status: %s, Reason: %s", $this->strStatus, $this->strReason), 'PaymentAuthorizeDotNet capturePayment()', TL_ERROR); return false; } return true; }
/** * Save the order * @return void */ protected function writeOrder() { $objOrder = new IsotopeOrder(); if (!$objOrder->findBy('cart_id', $this->Isotope->Cart->id)) { $objOrder->uniqid = uniqid($this->Isotope->Config->orderPrefix, true); $objOrder->cart_id = $this->Isotope->Cart->id; $objOrder->findBy('id', $objOrder->save()); } $objOrder->pid = FE_USER_LOGGED_IN === true ? $this->User->id : 0; $objOrder->date = time(); $objOrder->config_id = (int) $this->Isotope->Config->id; $objOrder->shipping_id = $this->Isotope->Cart->hasShipping ? $this->Isotope->Cart->Shipping->id : 0; $objOrder->payment_id = $this->Isotope->Cart->hasPayment ? $this->Isotope->Cart->Payment->id : 0; $objOrder->subTotal = $this->Isotope->Cart->subTotal; $objOrder->taxTotal = $this->Isotope->Cart->taxTotal; $objOrder->shippingTotal = $this->Isotope->Cart->shippingTotal; $objOrder->grandTotal = $this->Isotope->Cart->grandTotal; $objOrder->surcharges = $this->Isotope->Cart->getSurcharges(); $objOrder->checkout_info = $this->getCheckoutInfo(); $objOrder->status = ''; $objOrder->language = $GLOBALS['TL_LANGUAGE']; $objOrder->billing_address = $this->Isotope->Cart->billingAddress; $objOrder->shipping_address = $this->Isotope->Cart->shippingAddress; $objOrder->currency = $this->Isotope->Config->currency; $objOrder->iso_sales_email = $this->iso_sales_email ? $this->iso_sales_email : ($GLOBALS['TL_ADMIN_NAME'] != '' ? sprintf('%s <%s>', $GLOBALS['TL_ADMIN_NAME'], $GLOBALS['TL_ADMIN_EMAIL']) : $GLOBALS['TL_ADMIN_EMAIL']); $objOrder->iso_mail_admin = $this->iso_mail_admin; $objOrder->iso_mail_customer = $this->iso_mail_customer; $objOrder->iso_addToAddressbook = $this->iso_addToAddressbook; $objOrder->new_order_status = $this->Isotope->Cart->hasPayment ? $this->Isotope->Cart->Payment->new_order_status : 'pending'; $strCustomerName = ''; $strCustomerEmail = ''; if ($this->Isotope->Cart->billingAddress['email'] != '') { $strCustomerName = $this->Isotope->Cart->billingAddress['firstname'] . ' ' . $this->Isotope->Cart->billingAddress['lastname']; $strCustomerEmail = $this->Isotope->Cart->billingAddress['email']; } elseif ($this->Isotope->Cart->shippingAddress['email'] != '') { $strCustomerName = $this->Isotope->Cart->shippingAddress['firstname'] . ' ' . $this->Isotope->Cart->shippingAddress['lastname']; $strCustomerEmail = $this->Isotope->Cart->shippingAddress['email']; } elseif (FE_USER_LOGGED_IN === true && $this->User->email != '') { $strCustomerName = $this->User->firstname . ' ' . $this->User->lastname; $strCustomerEmail = $this->User->email; } if (trim($strCustomerName) != '') { $strCustomerEmail = sprintf('"%s" <%s>', IsotopeEmail::romanizeFriendlyName($strCustomerName), $strCustomerEmail); } $objOrder->iso_customer_email = $strCustomerEmail; $arrData = array_merge($this->arrOrderData, array('uniqid' => $objOrder->uniqid, 'items' => $this->Isotope->Cart->items, 'products' => $this->Isotope->Cart->products, 'subTotal' => $this->Isotope->formatPriceWithCurrency($this->Isotope->Cart->subTotal, false), 'taxTotal' => $this->Isotope->formatPriceWithCurrency($this->Isotope->Cart->taxTotal, false), 'shippingPrice' => $this->Isotope->formatPriceWithCurrency($this->Isotope->Cart->Shipping->price, false), 'paymentPrice' => $this->Isotope->formatPriceWithCurrency($this->Isotope->Cart->Payment->price, false), 'grandTotal' => $this->Isotope->formatPriceWithCurrency($this->Isotope->Cart->grandTotal, false), 'cart_text' => strip_tags($this->replaceInsertTags($this->Isotope->Cart->getProducts('iso_products_text'))), 'cart_html' => $this->replaceInsertTags($this->Isotope->Cart->getProducts('iso_products_html')))); $objOrder->email_data = $arrData; $objOrder->save(); }
/** * Process post-sale requestion from the Postfinance payment server. * * @access public * @return void */ public function processPostSale() { if ($this->getRequestData('NCERROR') > 0) { $this->log('Order ID "' . $this->getRequestData('orderID') . '" has NCERROR ' . $this->getRequestData('NCERROR'), __METHOD__, TL_ERROR); return; } $objOrder = new IsotopeOrder(); if (!$objOrder->findBy('id', $this->getRequestData('orderID'))) { $this->log('Order ID "' . $this->getRequestData('orderID') . '" not found', __METHOD__, TL_ERROR); return; } if (!$this->validateSHASign()) { $this->log('Received invalid postsale data for order ID "' . $objOrder->id . '"', __METHOD__, TL_ERROR); return; } // Validate payment data (see #2221) if ($objOrder->currency != $this->getRequestData('currency') || $objOrder->grandTotal != $this->getRequestData('amount')) { $this->log('Postsale checkout manipulation in payment for Order ID ' . $objOrder->id . '!', __METHOD__, TL_ERROR); return; } if (!$objOrder->checkout()) { $this->log('Post-Sale checkout for Order ID "' . $objOrder->id . '" failed', __METHOD__, TL_ERROR); return; } $objOrder->date_paid = time(); $objOrder->save(); }
/** * Button Callback for the MultipleShipping backend interface for label generation * * @access public * @param int * @return string */ public function backendInterfaceMultiple($intOrderId, $intPackageId = 0) { $objOrder = new IsotopeOrder(); $strFormId = 'ups_backend_interface'; //Check for valid order if (!$objOrder->findBy('id', $intOrderId)) { $this->log('Invalid order id.', __METHOD__, TL_ERROR); $this->redirect('contao/main.php?act=error'); } //Get the order's products $arrProducts = $objOrder->getProducts(); //Get the package data $objPackage = $this->Database->execute("SELECT * FROM tl_iso_packages WHERE id={$intPackageId}"); if (!$objPackage->numRows) { return '<p class="tl_gerror">' . $GLOBALS['TL_LANG']['ISO']['backendShippingNotFound'] . '</p>'; } //Build the initial compiled package data array $arrPackage = array('id' => $objPackage->id, 'address' => deserialize($objPackage->order_address, true), 'formattedaddress' => $this->Isotope->generateAddressString(deserialize($objPackage->order_address, true), $this->Isotope->Config->shipping_fields), 'status' => $GLOBALS['TL_LANG']['ISO']['multipleshipping'][$objPackage->status], 'formid' => $strFormId . '_' . $objPackage->id); //Check for an existing label thumbnail and create one if it has not been created if ($objPackage->ups_label) { //Set a cache name $strCacheName = 'system/html/ups_label_' . $objOrder->order_id . '_' . $objPackage->id . substr(md5($arrPackage['formattedaddress']), 0, 8) . '.gif'; $arrPackage['label'] = $this->getShippingLabelImage($objPackage->ups_label, $strCacheName, 75, 75, 'exact'); $arrPackage['labelLink'] = $this->Environment->request . '&printLabel=' . $arrPackage['formid']; //Now that we have the label created check for request to output to PDF if ($this->Input->get('printLabel') == $arrPackage['formid']) { $this->printShippingLabel($strCacheName, 'order_' . $objOrder->order_id . '_' . $intPackageId, true); } } //Add tracking number if (strlen($objPackage->ups_tracking_number)) { $arrPackage['tracking'] = $objPackage->ups_tracking_number; } //Add package products $arrShipmentProducts = $this->Database->execute("SELECT product_id FROM tl_iso_order_items WHERE package_id={$objPackage->id}")->fetchEach('product_id'); foreach ($arrProducts as $objProduct) { if (in_array($objProduct->id, $arrShipmentProducts)) { $arrPackage['products'][] = $objProduct; } } //Data has been submitted. Send request for tracking numbers and label if ($this->Input->post('FORM_SUBMIT') == $arrPackage['formid']) { $this->Shipment = $arrPackage; list($arrOrigin, $arrDestination, $arrShipment) = $this->buildShipment(); if ($this->isValidDestination($arrDestination)) { $objUPSAPI = new UpsAPIShipping($arrShipment, $arrOrigin, $arrOrigin, $arrDestination); $xmlShip = $objUPSAPI->buildRequest(); $arrResponse = $objUPSAPI->sendRequest($xmlShip); } //Request was successful - add the new data to the package if ((int) $arrResponse['ShipmentAcceptResponse']['Response']['ResponseStatusCode'] == 1) { $objOrder->ups_tracking_number = $arrResponse['ShipmentAcceptResponse']['ShipmentResults']['ShipmentIdentificationNumber']; $objOrder->ups_label = $arrResponse['ShipmentAcceptResponse']['ShipmentResults']['PackageResults']['LabelImage']['GraphicImage']; $objOrder->save(); if ($this->Database->tableExists('tl_iso_packages') && $arrPackage['formid'] != $strFormId . '_' . 'order') { $this->Database->prepare("UPDATE tl_iso_packages SET ups_tracking_number=?, ups_label=?, status='shipped' WHERE id=?")->execute($objOrder->ups_tracking_number, $objOrder->ups_label, $arrPackage['id']); } $strCacheName = 'system/html/ups_label_' . $objOrder->order_id . '_' . $objPackage->id . substr(md5($arrPackage['formattedaddress']), 0, 8) . '.gif'; $arrPackage['label'] = $this->getShippingLabelImage($objOrder->ups_label, $strCacheName); $arrPackage['tracking'] = $objOrder->ups_tracking_number; } elseif ($this->isValidDestination($arrDestination) == false) { } else { //Request returned an error $strDescription = $arrResponse['ShipmentAcceptResponse']["Response"]["ResponseStatusDescription"]; $strError = $arrResponse['ShipmentAcceptResponse']["Response"]["Error"]["ErrorDescription"]; $_SESSION['TL_ERROR'][] = $strDescription . ' - ' . $strError; $this->log(sprintf('Error in shipping digest: %s - %s', $strDescription, $strError), __METHOD__, TL_ERROR); $this->redirect('contao/main.php?act=error'); } } //Set template data $objTemplate = new IsotopeTemplate('be_iso_ups'); $objTemplate->setData($arrPackage); $objTemplate->labelHeader = $GLOBALS['TL_LANG']['MSC']['labelLabel']; $objTemplate->trackingHeader = $GLOBALS['TL_LANG']['MSC']['trackingNumberLabel']; $objTemplate->addressHeader = $GLOBALS['TL_LANG']['MSC']['shippingAddress']; $objTemplate->statusHeader = $GLOBALS['TL_LANG']['MSC']['shippingStatus']; $objTemplate->submitLabel = $objPackage->status != 'not_shipped' ? $GLOBALS['TL_LANG']['MSC']['re-ship'] : $GLOBALS['TL_LANG']['MSC']['ship']; return $objTemplate->parse(); }