' : print_r($address_arr, true)));
// Do we require a "confirmed" shipping address ?
if (MODULE_PAYMENT_PAYPALWPP_CONFIRMED_ADDRESS == 'Yes') {
$options['REQCONFIRMSHIPPING'] = 1;
}
}
// if we know customer's email address, supply it, so as to pre-fill the signup box at PayPal (useful for new PayPal accounts only)
if (!empty($_SESSION['customer_first_name']) && !empty($_SESSION['customer_id'])) {
$sql = "select * from " . TABLE_CUSTOMERS . " where customers_id = :custID ";
$sql = $db->bindVars($sql, ':custID', $_SESSION['customer_id'], 'integer');
$zc_getemail = $db->Execute($sql);
if ($zc_getemail->RecordCount() > 0 && $zc_getemail->fields['customers_email_address'] != '') {
$options['EMAIL'] = $zc_getemail->fields['customers_email_address'];
}
if ($zc_getemail->RecordCount() > 0 && $zc_getemail->fields['customers_telephone'] != '' && (!isset($options['ADDROVERRIDE']) || isset($options['ADDROVERRIDE']) && $options['ADDROVERRIDE'] != 1)) {
$options['SHIPTOPHONENUM'] = $zc_getemail->fields['customers_telephone'];
}
}
if (!isset($options['AMT'])) $options['AMT'] = number_format($order_amount, 2);
$this->zcLog('ec_step1 - 2 -submit', print_r(array_merge($options, array('RETURNURL' => $return_url, 'CANCELURL' => $cancel_url)), true));
/**
* Ask PayPal for the token with which to initiate communications
*/
$response = $doPayPal->SetExpressCheckout($return_url, $cancel_url, $options);
$submissionCheckOne = TRUE;
$submissionCheckTwo = TRUE;
if ($submissionCheckOne) {
// If there's an error on line-item details, remove tax values and resubmit, since the most common cause of 10413 is tax mismatches
if ($response['L_ERRORCODE0'] == '10413') {
$this->zcLog('ec_step1 - 3 - removing tax portion', 'Tax Subtotal does not match sum of taxes for line-items. Tax details removed from line-item submission data.' . "\n" . print_r($options, true));
//echo '1st submission REJECTED. {'.$response['L_ERRORCODE0'].'}'.print_r($options, true) . urldecode(print_r($response, true));
$tsubtotal = 0;
foreach ($options as $key=>$value) {
if (substr($key, 0, 8) == 'L_TAXAMT') {
$tsubtotal += preg_replace('/[^0-9.\-]/', '', $value);
unset($options[$key]);
}
}
$options['TAXAMT'] = $tsubtotal;
$amt = preg_replace('/[^0-9.%]/', '', $options['AMT']);
// echo 'oldAMT:'.$amt;
// echo ' newTAXAMT:'.$tsubtotal;
$taxamt = preg_replace('/[^0-9.%]/', '', $options['TAXAMT']);
$shipamt = preg_replace('/[^0-9.%]/', '', $options['SHIPPINGAMT']);
$itemamt = preg_replace('/[^0-9.%]/', '', $options['ITEMAMT']);
$calculatedAmount = $itemamt + $taxamt + $shipamt;
if ($amt != $calculatedAmount) $amt = $calculatedAmount;
// echo ' newAMT:'.$amt;
$options['AMT'] = $amt;
$response = $doPayPal->SetExpressCheckout($return_url, $cancel_url, $options);
//echo '
2nd submission. {'.$response['L_ERRORCODE0'].'}'.print_r($options, true);
}
if ($submissionCheckTwo) {
if ($response['L_ERRORCODE0'] == '10413') {
$this->zcLog('ec_step1 - 4 - removing line-item details', 'PayPal designed their own mathematics rules. Dumbing it down for them.' . "\n" . print_r($options, true));
//echo '2nd submission REJECTED. {'.$response['L_ERRORCODE0'].'}'.print_r($options, true) . urldecode(print_r($response, true));
foreach ($options as $key=>$value) {
if (substr($key, 0, 2) == 'L_') {
unset($options[$key]);
}
}
$amt = preg_replace('/[^0-9.%]/', '', $options['AMT']);
$taxamt = preg_replace('/[^0-9.%]/', '', $options['TAXAMT']);
$shipamt = preg_replace('/[^0-9.%]/', '', $options['SHIPPINGAMT']);
$itemamt = preg_replace('/[^0-9.%]/', '', $options['ITEMAMT']);
$calculatedAmount = $itemamt + $taxamt + $shipamt;
if ($amt != $calculatedAmount) $amt = $calculatedAmount;
$options['AMT'] = $amt;
$response = $doPayPal->SetExpressCheckout($return_url, $cancel_url, $options);
//echo '
3rd submission. {'.$response['L_ERRORCODE0'].'}'.print_r($options, true);
}
}
}
/**
* Determine result of request for token -- if error occurred, the errorHandler will redirect accordingly
*/
$error = $this->_errorHandler($response, 'SetExpressCheckout');
// Success, so read the EC token
$_SESSION['paypal_ec_token'] = preg_replace('/[^0-9.A-Z\-]/', '', urldecode($response['TOKEN']));
// prepare to redirect to PayPal so the customer can log in and make their selections
$paypal_url = $this->getPayPalLoginServer();
// Set the name of the displayed "continue" button on the PayPal site.
// 'commit' = "Pay Now" || 'continue' = "Review Payment"
$orderReview = true;
if ($_SESSION['paypal_ec_markflow'] == 1) $orderReview = false;
$userActionKey = "&useraction=" . ((int)$orderReview == false ? 'commit' : 'continue');
// This is where we actually redirect the customer's browser to PayPal. Upon return from PayPal, they go to ec_step2
header("HTTP/1.1 302 Object Moved");
zen_redirect($paypal_url . "?cmd=_express-checkout&token=" . $_SESSION['paypal_ec_token'] . $userActionKey);
// this should never be reached:
return $error;
}
/**
* This method is for step 2 of the express checkout option. This
* retrieves from PayPal the data set by step one and sets the Zen Cart
* data accordingly depending on admin settings.
*/
function ec_step2() {
// Visitor just came back from PayPal and so we collect all
// the info returned, create an account if necessary, then log
// them in, and then send them to the appropriate page.
if (empty($_SESSION['paypal_ec_token'])) {
// see if the token is set -- if not, we cannot continue -- ideally the token should match the session token
if (isset($_GET['token'])) {
// we have a token, so we will proceed
$_SESSION['paypal_ec_token'] = $_GET['token'];
// sanitize this
$_SESSION['paypal_ec_token'] = preg_replace('/[^0-9.A-Z\-]/', '', $_GET['token']);
} else {
// no token -- not ready for this step -- send them back to checkout page with error
$this->terminateEC(MODULE_PAYMENT_PAYPALWPP_INVALID_RESPONSE, true);
}
}
// debug
//$this->zcLog('PayPal test Log - ec_step2 $_REQUEST data', "In function: ec_step2()\r\nData in \$_REQUEST = \r\n" . print_r($_REQUEST, true));
// Initialize the paypal caller object.
global $doPayPal;
$doPayPal = $this->paypal_init();
// with the token we retrieve the data about this user
$response = $doPayPal->GetExpressCheckoutDetails($_SESSION['paypal_ec_token']);
//$this->zcLog('ec_step2 - GetExpressCheckout response', print_r($response, true));
/**
* Determine result of request for data -- if error occurred, the errorHandler will redirect accordingly
*/
$error = $this->_errorHandler($response, 'GetExpressCheckoutDetails');
// Check for blank address -- if address received from PayPal is blank, ask the customer to register in the store first and then resume checkout
if ($_SESSION['cart']->get_content_type() != 'virtual')
if ($response['SHIPTONAME'] . $response['SHIPTOSTREET'] . $response['SHIPTOSTREET2'] . $response['SHIPTOCITY'] . $response['SHIPTOSTATE'] . $response['SHIPTOZIP'] . $response['SHIPTOCOUNTRYCODE'] == '') {
$this->terminateEC(MODULES_PAYMENT_PAYPALWPP_TEXT_BLANK_ADDRESS, true, FILENAME_CREATE_ACCOUNT);
}
// will we be creating an account for this customer? We must if the cart contents are virtual, so can login to download etc.
if ($_SESSION['cart']->get_content_type('true') > 0 || in_array($_SESSION['cart']->content_type, array('mixed', 'virtual'))) $this->new_acct_notify = 'Yes';
// get the payer_id from the customer's info as returned from PayPal
$_SESSION['paypal_ec_payer_id'] = $response['PAYERID'];
$this->notify('NOTIFY_PAYPAL_EXPRESS_CHECKOUT_PAYERID_DETERMINED', $response['PAYERID']);
$gender = '';
if (urldecode($response['SALUTATION'] == 'Mr')) $gender = 'm';
if (in_array(urldecode($response['SALUTATION']), array('Ms', 'Mrs'))) $gender = 'f';
// prepare the information to pass to the ec_step2_finish() function, which does the account creation, address build, etc
$step2_payerinfo = array('payer_id' => $response['PAYERID'],
'payer_email' => urldecode($response['EMAIL']),
'payer_salutation'=> urldecode($response['SALUTATION']),
'payer_gender' => $gender,
'payer_firstname' => urldecode($response['FIRSTNAME']),
'payer_lastname' => urldecode($response['LASTNAME']),
'payer_business' => urldecode($response['BUSINESS']),
'payer_status' => $response['PAYERSTATUS'],
'ship_country_code' => urldecode($response['COUNTRYCODE']),
'ship_address_status' => urldecode($response['ADDRESSSTATUS']),
'ship_phone' => urldecode($response['SHIPTOPHONENUM'] != '' ? $response['SHIPTOPHONENUM'] : $response['PHONENUM']),
'order_comment' => urldecode($response['NOTETEXT']),
);
// if (strtoupper($response['ADDRESSSTATUS']) == 'NONE' || !isset($response['SHIPTOSTREET']) || $response['SHIPTOSTREET'] == '') {
// $step2_shipto = array();
// } else {
// accomodate PayPal bug which repeats 1st line of address for 2nd line if 2nd line is empty.
if ($response['SHIPTOSTREET2'] == $response['SHIPTOSTREET1']) $response['SHIPTOSTREET2'] = '';
// accomodate PayPal bug which incorrectly treats 'Yukon Territory' as YK instead of ISO standard of YT.
if ($response['SHIPTOSTATE'] == 'YK') $response['SHIPTOSTATE'] = 'YT';
// same with Newfoundland
if ($response['SHIPTOSTATE'] == 'NF') $response['SHIPTOSTATE'] = 'NL';
// process address details supplied
$step2_shipto = array('ship_name' => urldecode($response['SHIPTONAME']),
'ship_street_1' => urldecode($response['SHIPTOSTREET']),
'ship_street_2' => urldecode($response['SHIPTOSTREET2']),
'ship_city' => urldecode($response['SHIPTOCITY']),
'ship_state' => (isset($response['SHIPTOSTATE']) && $response['SHIPTOSTATE'] !='' ? urldecode($response['SHIPTOSTATE']) : urldecode($response['SHIPTOCITY'])),
'ship_postal_code' => urldecode($response['SHIPTOZIP']),
'ship_country_code' => urldecode($response['SHIPTOCOUNTRYCODE']),
'ship_country_name' => (isset($response['SHIPTOCOUNTRY']) ? urldecode($response['SHIPTOCOUNTRY']) : urldecode($response['SHIPTOCOUNTRYNAME'])));
// }
// reset all previously-selected shipping choices, because cart contents may have been changed
if (!(isset($_SESSION['paypal_ec_markflow']) && $_SESSION['paypal_ec_markflow'] == 1)) unset($_SESSION['shipping']);
// set total temporarily based on amount returned from PayPal, so validations continue to work properly
global $order, $order_totals;
if (!isset($order) || !isset($order->info) || !is_array($order->info) || !zen_not_null($order)) {
$this->zcLog('ec_step2 ', 'Re-instantiating $order object.');
// init new order object
if (!class_exists('order')) require(DIR_WS_CLASSES . 'order.php');
$order = new order;
// load the selected shipping module so that shipping taxes can be assessed
if (!class_exists('shipping')) require(DIR_WS_CLASSES . 'shipping.php');
$shipping_modules = new shipping($_SESSION['shipping']);
// load OT modules so that discounts and taxes can be assessed
if (!class_exists('order_total')) require(DIR_WS_CLASSES . 'order_total.php');
$order_total_modules = new order_total;
$order_totals = $order_total_modules->pre_confirmation_check();
$order_totals = $order_total_modules->process();
$this->zcLog('ec_step2 ', 'Instantiated $order object contents: ' . print_r($order, true));
}
$order->info['total'] = urldecode($response['AMT']);
//$this->zcLog('ec_step2 - processed info', print_r(array_merge($step2_payerinfo, $step2_shipto), true));
// send data off to build account, log in, set addresses, place order
$this->ec_step2_finish(array_merge($step2_payerinfo, $step2_shipto), $this->new_acct_notify);
}
/**
* Complete the step2 phase by creating accounts if needed, linking data, placing order, etc.
*/
function ec_step2_finish($paypal_ec_payer_info, $new_acct_notify) {
global $db, $order;
// register the payer_info in the session
$_SESSION['paypal_ec_payer_info'] = $paypal_ec_payer_info;
// debug
$this->zcLog('ec_step2_finish - 1', 'START: paypal_ec_payer_info= ' . print_r($_SESSION['paypal_ec_payer_info'], true));
/**
* Building customer zone/address from returned data
*/
// set some defaults, which will be updated later:
$country_id = '223';
$address_format_id = 2;
$state_id = 0;
$acct_exists = false;
// store default address id for later use/reference
$original_default_address_id = $_SESSION['customer_default_address_id'];
// Get the customer's country ID based on name or ISO code
$sql = "SELECT countries_id, address_format_id, countries_iso_code_2, countries_iso_code_3
FROM " . TABLE_COUNTRIES . "
WHERE countries_iso_code_2 = :countryId
OR countries_name = :countryId
LIMIT 1";
$sql1 = $db->bindVars($sql, ':countryId', $paypal_ec_payer_info['ship_country_name'], 'string');
$country1 = $db->Execute($sql1);
$sql2 = $db->bindVars($sql, ':countryId', $paypal_ec_payer_info['ship_country_code'], 'string');
$country2 = $db->Execute($sql2);
// see if we found a record, if yes, then use it instead of default American format
if ($country1->RecordCount() > 0) {
$country_id = $country1->fields['countries_id'];
if (!isset($paypal_ec_payer_info['ship_country_code']) || $paypal_ec_payer_info['ship_country_code'] == '') $paypal_ec_payer_info['ship_country_code'] = $country1->fields['countries_iso_code_2'];
$country_code3 = $country1->fields['countries_iso_code_3'];
$address_format_id = (int)$country1->fields['address_format_id'];
} elseif ($country2->RecordCount() > 0) {
// if didn't find it based on name, check using ISO code (ie: in case of no-shipping-address required/supplied)
$country_id = $country2->fields['countries_id'];
$country_code3 = $country2->fields['countries_iso_code_3'];
$address_format_id = (int)$country2->fields['address_format_id'];
} else {
// if defaulting to US, make sure US is valid
$sql = "SELECT countries_id FROM " . TABLE_COUNTRIES . " WHERE countries_id = :countryId: LIMIT 1";
$sql = $db->bindVars($sql, ':countryId:', $country_id, 'integer');
$result = $db->Execute($sql);
if ($result->EOF) {
$this->notify('NOTIFY_PAYPAL_CUSTOMER_ATTEMPT_TO_USE_INVALID_COUNTRY_CODE');
$this->zcLog('ec-step2-finish - 1b', 'Cannot use address due to country lookup/match failure.');
$this->terminateEC(MODULE_PAYMENT_PAYPALWPP_TEXT_INVALID_ZONE_ERROR, true, FILENAME_SHOPPING_CART);
}
}
// Need to determine zone, based on zone name first, and then zone code if name fails check. Otherwise uses 0.
$sql = "SELECT zone_id
FROM " . TABLE_ZONES . "
WHERE zone_country_id = :zCountry
AND zone_code = :zoneCode
OR zone_name = :zoneCode
LIMIT 1";
$sql = $db->bindVars($sql, ':zCountry', $country_id, 'integer');
$sql = $db->bindVars($sql, ':zoneCode', $paypal_ec_payer_info['ship_state'], 'string');
$states = $db->Execute($sql);
if ($states->RecordCount() > 0) {
$state_id = $states->fields['zone_id'];
}
/**
* Using the supplied data from PayPal, set the data into the order record
*/
// customer
$order->customer['name'] = $paypal_ec_payer_info['payer_firstname'] . ' ' . $paypal_ec_payer_info['payer_lastname'];
$order->customer['company'] = $paypal_ec_payer_info['payer_business'];
$order->customer['street_address'] = $paypal_ec_payer_info['ship_street_1'];
$order->customer['suburb'] = $paypal_ec_payer_info['ship_street_2'];
$order->customer['city'] = $paypal_ec_payer_info['ship_city'];
$order->customer['postcode'] = $paypal_ec_payer_info['ship_postal_code'];
$order->customer['state'] = $paypal_ec_payer_info['ship_state'];
$order->customer['country'] = array('id' => $country_id, 'title' => $paypal_ec_payer_info['ship_country_name'], 'iso_code_2' => $paypal_ec_payer_info['ship_country_code'], 'iso_code_3' => $country_code3);
$order->customer['format_id'] = $address_format_id;
$order->customer['email_address'] = $paypal_ec_payer_info['payer_email'];
$order->customer['telephone'] = $paypal_ec_payer_info['ship_phone'];
$order->customer['zone_id'] = $state_id;
// billing
$order->billing['name'] = $paypal_ec_payer_info['payer_firstname'] . ' ' . $paypal_ec_payer_info['payer_lastname'];
$order->billing['company'] = $paypal_ec_payer_info['payer_business'];
$order->billing['street_address'] = $paypal_ec_payer_info['ship_street_1'];
$order->billing['suburb'] = $paypal_ec_payer_info['ship_street_2'];
$order->billing['city'] = $paypal_ec_payer_info['ship_city'];
$order->billing['postcode'] = $paypal_ec_payer_info['ship_postal_code'];
$order->billing['state'] = $paypal_ec_payer_info['ship_state'];
$order->billing['country'] = array('id' => $country_id, 'title' => $paypal_ec_payer_info['ship_country_name'], 'iso_code_2' => $paypal_ec_payer_info['ship_country_code'], 'iso_code_3' => $country_code3);
$order->billing['format_id'] = $address_format_id;
$order->billing['zone_id'] = $state_id;
// delivery
if (strtoupper($_SESSION['paypal_ec_payer_info']['ship_address_status']) != 'NONE') {
$order->delivery['name'] = $paypal_ec_payer_info['ship_name'];
$order->delivery['company'] = trim($paypal_ec_payer_info['ship_name'] . ' ' . $paypal_ec_payer_info['payer_business']);
$order->delivery['street_address']= $paypal_ec_payer_info['ship_street_1'];
$order->delivery['suburb'] = $paypal_ec_payer_info['ship_street_2'];
$order->delivery['city'] = $paypal_ec_payer_info['ship_city'];
$order->delivery['postcode'] = $paypal_ec_payer_info['ship_postal_code'];
$order->delivery['state'] = $paypal_ec_payer_info['ship_state'];
$order->delivery['country'] = array('id' => $country_id, 'title' => $paypal_ec_payer_info['ship_country_name'], 'iso_code_2' => $paypal_ec_payer_info['ship_country_code'], 'iso_code_3' => $country_code3);
$order->delivery['country_id'] = $country_id;
$order->delivery['format_id'] = $address_format_id;
$order->delivery['zone_id'] = $state_id;
}
// process submitted customer notes
if (isset($paypal_ec_payer_info['order_comment']) && $paypal_ec_payer_info['order_comment'] != '') {
$_SESSION['comments'] = (isset($_SESSION['comments']) && $_SESSION['comments'] != '' ? $_SESSION['comments'] . "\n" : '') . $paypal_ec_payer_info['order_comment'];
$order->info['comments'] = $_SESSION['comments'];
}
// debug
$this->zcLog('ec_step2_finish - 2', 'country_id = ' . $country_id . ' ' . $paypal_ec_payer_info['ship_country_name'] . ' ' . $paypal_ec_payer_info['ship_country_code'] ."\naddress_format_id = " . $address_format_id . "\nstate_id = " . $state_id . ' (original state tested: ' . $paypal_ec_payer_info['ship_state'] . ')' . "\ncountry1->fields['countries_id'] = " . $country1->fields['countries_id'] . "\ncountry2->fields['countries_id'] = " . $country2->fields['countries_id'] . "\n" . '$order->customer = ' . print_r($order->customer, true));
// check to see whether PayPal should still be offered to this customer, based on the zone of their address:
$this->update_status();
if (!$this->enabled) {
$this->terminateEC(MODULE_PAYMENT_PAYPALWPP_TEXT_INVALID_ZONE_ERROR, true, FILENAME_SHOPPING_CART);
}
// see if the user is logged in
if (!empty($_SESSION['customer_first_name']) && !empty($_SESSION['customer_id']) && $_SESSION['customer_id'] > 0) {
// They're logged in, so forward them straight to checkout stages, depending on address needs etc
$order->customer['id'] = $_SESSION['customer_id'];
// set the session value for express checkout temp
$_SESSION['paypal_ec_temp'] = false;
// if no address required for shipping, leave shipping portion alone
if (strtoupper($_SESSION['paypal_ec_payer_info']['ship_address_status']) != 'NONE' && $_SESSION['paypal_ec_payer_info']['ship_street_1'] != '') {
// set the session info for the sendto
$_SESSION['sendto'] = $_SESSION['customer_default_address_id'];
// This is the address matching section
// try to match it first
// note: this is by no means 100%
$address_book_id = $this->findMatchingAddressBookEntry($_SESSION['customer_id'], (isset($order->delivery) ? $order->delivery : $order->billing));
// no match, so add the record
if (!$address_book_id) {
$address_book_id = $this->addAddressBookEntry($_SESSION['customer_id'], (isset($order->delivery) ? $order->delivery : $order->billing), false);
}
// if couldn't add the record, perhaps due to removed country, or some other error, abort with message
if (!$address_book_id) {
$this->terminateEC(MODULE_PAYMENT_PAYPALWPP_TEXT_INVALID_ZONE_ERROR, true, FILENAME_SHOPPING_CART);
}
// set the address for use
$_SESSION['sendto'] = $address_book_id;
}
// set the users billto information (default address)
if (!isset($_SESSION['billto'])) {
$_SESSION['billto'] = $_SESSION['customer_default_address_id'];
}
// debug
$this->zcLog('ec_step2_finish - 3', 'Exiting ec_step2_finish logged-in mode.' . "\n" . 'Selected address: ' . $address_book_id . "\nOriginal was: " . $original_default_address_id);
// select a shipping method, based on cheapest available option
if (MODULE_PAYMENT_PAYPALWPP_AUTOSELECT_CHEAPEST_SHIPPING == 'Yes') $this->setShippingMethod();
// send the user on
if ($_SESSION['paypal_ec_markflow'] == 1) {
$this->terminateEC('', false, FILENAME_CHECKOUT_PROCESS);
} else {
$this->terminateEC('', false, FILENAME_CHECKOUT_CONFIRMATION);
}
} else {
// They're not logged in. Create an account if necessary, and then log them in.
// First, see if they're an existing customer, and log them in automatically
// If Paypal didn't supply us an email address, something went wrong
if (trim($paypal_ec_payer_info['payer_email']) == '') $this->terminateEC(MODULE_PAYMENT_PAYPALWPP_INVALID_RESPONSE, true);
// attempt to obtain the user information using the payer_email from the info returned from PayPal, via email address
$sql = "SELECT customers_id, customers_firstname, customers_lastname, customers_paypal_payerid, customers_paypal_ec
FROM " . TABLE_CUSTOMERS . "
WHERE customers_email_address = :emailAddress ";
$sql = $db->bindVars($sql, ':emailAddress', $paypal_ec_payer_info['payer_email'], 'string');
$check_customer = $db->Execute($sql);
// debug
$this->zcLog('ec_step2_finish - 4', 'Not logged in. Looking for account.' . "\n" . (int)$check_customer->RecordCount() . ' matching customer records found.');
if (!$check_customer->EOF) {
$acct_exists = true;
// see if this was only a temp account -- if so, remove it
if ($check_customer->fields['customers_paypal_ec'] == '1') {
// Delete the existing temporary account
$this->ec_delete_user($check_customer->fields['customers_id']);
$acct_exists = false;
// debug
$this->zcLog('ec_step2_finish - 5', 'Found temporary account - deleting it.');
}
}
// Create an account, if the account does not exist
if (!$acct_exists) {
// debug
$this->zcLog('ec_step2_finish - 6', 'No ZC account found for this customer. Creating new account.' . "\n" . '$this->new_acct_notify =' . $this->new_acct_notify);
// Generate a random 8-char password
$password = zen_create_random_value(8);
$sql_data_array = array();
// set the customer information in the array for the table insertion
$sql_data_array = array(
'customers_firstname' => $paypal_ec_payer_info['payer_firstname'],
'customers_lastname' => $paypal_ec_payer_info['payer_lastname'],
'customers_email_address' => $paypal_ec_payer_info['payer_email'],
'customers_email_format' => (ACCOUNT_EMAIL_PREFERENCE == '1' ? 'HTML' : 'TEXT'),
'customers_telephone' => $paypal_ec_payer_info['ship_phone'],
'customers_fax' => '',
'customers_gender' => $paypal_ec_payer_info['payer_gender'],
'customers_newsletter' => '0',
'customers_password' => zen_encrypt_password($password),
'customers_paypal_payerid' => $_SESSION['paypal_ec_payer_id']);
// insert the data
$result = zen_db_perform(TABLE_CUSTOMERS, $sql_data_array);
// grab the customer_id (last insert id)
$customer_id = $db->Insert_ID();
// set the Guest customer ID -- for PWA purposes
$_SESSION['customer_guest_id'] = $customer_id;
// set the customer address information in the array for the table insertion
$sql_data_array = array(
'customers_id' => $customer_id,
'entry_gender' => $paypal_ec_payer_info['payer_gender'],
'entry_firstname' => $paypal_ec_payer_info['payer_firstname'],
'entry_lastname' => $paypal_ec_payer_info['payer_lastname'],
'entry_street_address' => $paypal_ec_payer_info['ship_street_1'],
'entry_suburb' => $paypal_ec_payer_info['ship_street_2'],
'entry_city' => $paypal_ec_payer_info['ship_city'],
'entry_zone_id' => $state_id,
'entry_postcode' => $paypal_ec_payer_info['ship_postal_code'],
'entry_country_id' => $country_id);
if (isset($paypal_ec_payer_info['ship_name']) && $paypal_ec_payer_info['ship_name'] != '' && $paypal_ec_payer_info['ship_name'] != $paypal_ec_payer_info['payer_firstname'] . ' ' . $paypal_ec_payer_info['payer_lastname']) {
$sql_data_array['entry_company'] = $paypal_ec_payer_info['ship_name'];
}
if ($state_id > 0) {
$sql_data_array['entry_zone_id'] = $state_id;
$sql_data_array['entry_state'] = '';
} else {
$sql_data_array['entry_zone_id'] = 0;
$sql_data_array['entry_state'] = $paypal_ec_payer_info['ship_state'];
}
// insert the data
zen_db_perform(TABLE_ADDRESS_BOOK, $sql_data_array);
// grab the address_id (last insert id)
$address_id = $db->Insert_ID();
// set the address id lookup for the customer
$sql = "UPDATE " . TABLE_CUSTOMERS . "
SET customers_default_address_id = :addrID
WHERE customers_id = :custID";
$sql = $db->bindVars($sql, ':addrID', $address_id, 'integer');
$sql = $db->bindVars($sql, ':custID', $customer_id, 'integer');
$db->Execute($sql);
// insert the new customer_id into the customers info table for consistency
$sql = "INSERT INTO " . TABLE_CUSTOMERS_INFO . "
(customers_info_id, customers_info_number_of_logons, customers_info_date_account_created, customers_info_date_of_last_logon)
VALUES (:custID, 1, now(), now())";
$sql = $db->bindVars($sql, ':custID', $customer_id, 'integer');
$db->Execute($sql);
// send Welcome Email if appropriate
if ($this->new_acct_notify == 'Yes') {
// require the language file
global $language_page_directory, $template_dir;
if (!isset($language_page_directory)) $language_page_directory = DIR_WS_LANGUAGES . $_SESSION['language'] . '/';
if (file_exists($language_page_directory . $template_dir . '/create_account.php')) {
$template_dir_select = $template_dir . '/';
} else {
$template_dir_select = '';
}
require($language_page_directory . $template_dir_select . '/create_account.php');
// set the mail text
$email_text = sprintf(EMAIL_GREET_NONE, $paypal_ec_payer_info['payer_firstname']) . EMAIL_WELCOME . "\n\n" . EMAIL_TEXT;
$email_text .= "\n\n" . EMAIL_EC_ACCOUNT_INFORMATION . "\nUsername: " . $paypal_ec_payer_info['payer_email'] . "\nPassword: " . $password . "\n\n";
$email_text .= EMAIL_CONTACT;
// include create-account-specific disclaimer
$email_text .= "\n\n" . sprintf(EMAIL_DISCLAIMER_NEW_CUSTOMER, STORE_OWNER_EMAIL_ADDRESS). "\n\n";
$email_html = array();
$email_html['EMAIL_GREETING'] = sprintf(EMAIL_GREET_NONE, $paypal_ec_payer_info['payer_firstname']) ;
$email_html['EMAIL_WELCOME'] = EMAIL_WELCOME;
$email_html['EMAIL_MESSAGE_HTML'] = nl2br(EMAIL_TEXT . "\n\n" . EMAIL_EC_ACCOUNT_INFORMATION . "\nUsername: " . $paypal_ec_payer_info['payer_email'] . "\nPassword: " . $password . "\n\n");
$email_html['EMAIL_CONTACT_OWNER'] = EMAIL_CONTACT;
$email_html['EMAIL_CLOSURE'] = nl2br(EMAIL_GV_CLOSURE);
$email_html['EMAIL_DISCLAIMER'] = sprintf(EMAIL_DISCLAIMER_NEW_CUSTOMER, ''. STORE_OWNER_EMAIL_ADDRESS .' ');
// send the mail
if (trim(EMAIL_SUBJECT) != 'n/a') zen_mail($paypal_ec_payer_info['payer_firstname'] . " " . $paypal_ec_payer_info['payer_lastname'], $paypal_ec_payer_info['payer_email'], EMAIL_SUBJECT, $email_text, STORE_OWNER, STORE_OWNER_EMAIL_ADDRESS, $email_html, 'welcome');
// set the express checkout temp -- false means the account is no longer "only" for EC ... it'll be permanent
$_SESSION['paypal_ec_temp'] = false;
} else {
// Make it a temporary account that'll be deleted once they've checked out
$sql = "UPDATE " . TABLE_CUSTOMERS . "
SET customers_paypal_ec = 1
WHERE customers_id = :custID ";
$sql = $db->bindVars($sql, ':custID', $customer_id, 'integer');
$db->Execute($sql);
// set the boolean ec temp value since we created account strictly for EC purposes
$_SESSION['paypal_ec_temp'] = true;
}
// hook notifier class vis a vis account-creation
$this->notify('NOTIFY_LOGIN_SUCCESS_VIA_CREATE_ACCOUNT');
} else {
// set the boolean ec temp value for the account to false, since we didn't have to create one
$_SESSION['paypal_ec_temp'] = false;
}
// log the user in with the email sent back from paypal response
$this->user_login($_SESSION['paypal_ec_payer_info']['payer_email'], false);
// debug
$this->zcLog('ec_step2_finish - 7', 'Auto-Logged customer in. (' . $_SESSION['paypal_ec_payer_info']['payer_email'] . ') (' . $_SESSION['customer_id'] . ')' . "\n" . '$_SESSION[paypal_ec_temp]=' . $_SESSION['paypal_ec_temp']);
// This is the address matching section
// try to match it first
// note: this is by no means 100%
$address_book_id = $this->findMatchingAddressBookEntry($_SESSION['customer_id'], (isset($order->delivery) ? $order->delivery : $order->billing));
// no match add the record
if (!$address_book_id) {
$address_book_id = $this->addAddressBookEntry($_SESSION['customer_id'], (isset($order->delivery) ? $order->delivery : $order->billing), false);
if (!$address_book_id) {
$address_book_id = $_SESSION['customer_default_address_id'];
}
}
// if couldn't add the record, perhaps due to removed country, or some other error, abort with message
if ($address_book_id == FALSE) {
$this->terminateEC(MODULE_PAYMENT_PAYPALWPP_TEXT_INVALID_ZONE_ERROR, true, FILENAME_SHOPPING_CART);
}
// set the sendto to the address
$_SESSION['sendto'] = $address_book_id;
// set billto in the session
$_SESSION['billto'] = $_SESSION['customer_default_address_id'];
// select a shipping method, based on cheapest available option
if (MODULE_PAYMENT_PAYPALWPP_AUTOSELECT_CHEAPEST_SHIPPING == 'Yes') $this->setShippingMethod();
// debug
$this->zcLog('ec_step2_finish - 8', 'Exiting via terminateEC (from originally-not-logged-in mode).' . "\n" . 'Selected address: ' . $address_book_id . "\nOriginal was: " . (int)$original_default_address_id . "\nprepared data: " . print_r($order->customer, true));
// send the user on
if ($_SESSION['paypal_ec_markflow'] == 1) {
$this->terminateEC('', false, FILENAME_CHECKOUT_PROCESS);
} else {
$this->terminateEC('', false, FILENAME_CHECKOUT_CONFIRMATION);
}
}
}
/**
* Determine the appropriate shipping method if applicable
* By default, selects the lowest-cost quote
*/
function setShippingMethod() {
global $total_count, $total_weight;
// ensure that cart contents is calculated properly for weight and value
if (!isset($total_weight)) $total_weight = $_SESSION['cart']->show_weight();
if (!isset($total_count)) $total_count = $_SESSION['cart']->count_contents();
// set the shipping method if one is not already set
// defaults to the cheapest shipping method
if ( !$_SESSION['shipping'] || ( $_SESSION['shipping'] && ($_SESSION['shipping'] == false) && (zen_count_shipping_modules() > 1) ) ) {
require_once(DIR_WS_CLASSES . 'http_client.php');
require_once(DIR_WS_CLASSES . 'shipping.php');
$shipping_Obj = new shipping;
// generate the quotes
$shipping_Obj->quote();
// set the cheapest one
$_SESSION['shipping'] = $shipping_Obj->cheapest();
}
}
/**
* Get Override Address (uses sendto if set, otherwise uses customer's primary address)
*/
function getOverrideAddress() {
global $db;
// Only proceed IF *in* markflow mode AND logged-in (have to be logged in to get to markflow mode anyway)
if (!empty($_GET['markflow']) && isset($_SESSION['customer_id']) && $_SESSION['customer_id']) {
// From now on for this user we will edit addresses in Zen Cart, not by going to PayPal.
$_SESSION['paypal_ec_markflow'] = 1;
// debug
$this->zcLog('getOverrideAddress - 1', 'Now in markflow mode.' . "\n" . 'SESSION[sendto] = ' . (int)$_SESSION['sendto']);
// find the users default address id
if (!empty($_SESSION['sendto'])) {
$address_id = $_SESSION['sendto'];
} else {
$sql = "SELECT customers_default_address_id
FROM " . TABLE_CUSTOMERS . "
WHERE customers_id = :customerId";
$sql = $db->bindVars($sql, ':customerId', $_SESSION['customer_id'], 'integer');
$default_address_id_arr = $db->Execute($sql);
if (!$default_address_id_arr->EOF) {
$address_id = $default_address_id_arr->fields['customers_default_address_id'];
} else {
// couldn't find an address.
return false;
}
}
// now grab the address from the database and set it as the overridden address
$sql = "SELECT entry_firstname, entry_lastname, entry_company,
entry_street_address, entry_suburb, entry_city, entry_postcode,
entry_country_id, entry_zone_id, entry_state
FROM " . TABLE_ADDRESS_BOOK . "
WHERE address_book_id = :addressId
AND customers_id = :customerId
LIMIT 1";
$sql = $db->bindVars($sql, ':addressId', $address_id, 'integer');
$sql = $db->bindVars($sql, ':customerId', $_SESSION['customer_id'], 'integer');
$address_arr = $db->Execute($sql);
// see if we found a record, if not then we have nothing to override with
if (!$address_arr->EOF) {
// get the state/prov code
$sql = "SELECT zone_code
FROM " . TABLE_ZONES . "
WHERE zone_id = :zoneId";
$sql = $db->bindVars($sql, ':zoneId', $address_arr->fields['entry_zone_id'], 'integer');
$state_code_arr = $db->Execute($sql);
if ($state_code_arr->EOF) {
$state_code_arr->fields['zone_code'] = '';
}
if ($state_code_arr->fields['zone_code'] == '' && $address_arr->fields['entry_state'] != '') {
$state_code_arr->fields['zone_code'] = $address_arr->fields['entry_state'];
}
$address_arr->fields['zone_code'] = $state_code_arr->fields['zone_code'];
// get the country code
// ISO 3166 standard country code
$sql = "SELECT countries_iso_code_2
FROM " . TABLE_COUNTRIES . "
WHERE countries_id = :countryId";
$sql = $db->bindVars($sql, ':countryId', $address_arr->fields['entry_country_id'], 'integer');
$country_code_arr = $db->Execute($sql);
if ($country_code_arr->EOF) {
// default to US if not found
$country_code_arr->fields['countries_iso_code_2'] = 'US';
}
$address_arr->fields['countries_iso_code_2'] = $country_code_arr->fields['countries_iso_code_2'];
// debug
$this->zcLog('getOverrideAddress - 2', '$address_arr->fields = ' . print_r($address_arr->fields, true));
// return address data.
return $address_arr->fields;
}
// debug
$this->zcLog('getOverrideAddress - 3', 'no override record found');
}
// debug
$this->zcLog('getOverrideAddress - 4', 'not logged in and not in markflow mode - nothing to override');
return false;
}
/**
* This method attempts to match items in an address book, to avoid
* duplicate entries to the address book. On a successful match it
* returns the address_book_id(int) - on failure it returns false.
*
* @param int $customer_id
* @param array $address_question_arr
* @return int|boolean
*/
function findMatchingAddressBookEntry($customer_id, $address_question_arr) {
global $db;
// if address is blank, don't do any matching
if ($address_question_arr['street_address'] == '') return false;
// default
$country_id = '223';
$address_format_id = 2; //2 is the American format
// first get the zone id's from the 2 digit iso codes
// country first
$sql = "SELECT countries_id, address_format_id
FROM " . TABLE_COUNTRIES . "
WHERE countries_iso_code_2 = :countryCode:
OR countries_name = :countryName:
OR countries_iso_code_2 = :countryName:
OR countries_name = :countryCode:
LIMIT 1";
$sql = $db->bindVars($sql, ':countryCode:', $address_question_arr['country']['iso_code_2'], 'string');
$sql = $db->bindVars($sql, ':countryName:', $address_question_arr['country']['title'], 'string');
$country = $db->Execute($sql);
// see if we found a record, if not default to American format
if (!$country->EOF) {
$country_id = $country->fields['countries_id'];
$address_format_id = $country->fields['address_format_id'];
}
// see if the country code has a state
$sql = "SELECT zone_id
FROM " . TABLE_ZONES . "
WHERE zone_country_id = :zoneId
LIMIT 1";
$sql = $db->bindVars($sql, ':zoneId', $country_id, 'integer');
$country_zone_check = $db->Execute($sql);
$check_zone = $country_zone_check->RecordCount();
$zone_id = 0;
$logMsg = array('zone_id' => '-not found-');
// now try and find the zone_id (state/province code)
// use the country id above
if ($check_zone) {
$sql = "SELECT zone_id
FROM " . TABLE_ZONES . "
WHERE zone_country_id = :zoneId
AND (zone_code = :zoneCode
OR zone_name = :zoneCode )
LIMIT 1";
$sql = $db->bindVars($sql, ':zoneId', $country_id, 'integer');
$sql = $db->bindVars($sql, ':zoneCode', $address_question_arr['state'], 'string');
$zone = $db->Execute($sql);
if (!$zone->EOF) {
// grab the id
$zone_id = $zone->fields['zone_id'];
$logMsg = $zone->fields;
} else {
$check_zone = false;
}
}
// debug
$this->zcLog('findMatchingAddressBookEntry - 1-stats', 'lookups:' . "\n" . print_r(array_merge($country->fields, array('zone_country_id' => $country_zone_check->fields['zone_id']), $logMsg), true) . "\n" . 'check_zone: ' . $check_zone . "\n" . 'zone:' . $zone_id . "\nSubmittedAddress:".print_r($address_question_arr, TRUE));
// do a match on address, street, street2, city
$sql = "SELECT address_book_id, entry_street_address, entry_suburb, entry_city, entry_company, entry_firstname, entry_lastname
FROM " . TABLE_ADDRESS_BOOK . "
WHERE customers_id = :customerId
AND entry_country_id = :countryId";
if ($check_zone) {
$sql .= " AND entry_zone_id = :zoneId";
}
$sql = $db->bindVars($sql, ':zoneId', $zone_id, 'integer');
$sql = $db->bindVars($sql, ':countryId', $country_id, 'integer');
$sql = $db->bindVars($sql, ':customerId', $customer_id, 'integer');
$answers_arr = $db->Execute($sql);
// debug
$this->zcLog('findMatchingAddressBookEntry - 2-read for match', "\nLookup RecordCount = " . $answers_arr->RecordCount());
if (!$answers_arr->EOF) {
// build a base string to compare street+suburb+city content
//$matchQuestion = str_replace("\n", '', $address_question_arr['company']);
//$matchQuestion = str_replace("\n", '', $address_question_arr['name']);
$matchQuestion = str_replace("\n", '', $address_question_arr['street_address']);
$matchQuestion = trim($matchQuestion);
$matchQuestion = $matchQuestion . str_replace("\n", '', $address_question_arr['suburb']);
$matchQuestion = $matchQuestion . str_replace("\n", '', $address_question_arr['city']);
$matchQuestion = str_replace("\t", '', $matchQuestion);
$matchQuestion = trim($matchQuestion);
$matchQuestion = strtolower($matchQuestion);
$matchQuestion = str_replace(' ', '', $matchQuestion);
// go through the data
while (!$answers_arr->EOF) {
// now the matching logic
// first from the db
$fromDb = '';
// $fromDb = str_replace("\n", '', $answers_arr->fields['entry_company']);
/// $fromDb = str_replace("\n", '', $answers_arr->fields['entry_firstname'].$answers_arr->fields['entry_lastname']);
$fromDb = str_replace("\n", '', $answers_arr->fields['entry_street_address']);
$fromDb = trim($fromDb);
$fromDb = $fromDb . str_replace("\n", '', $answers_arr->fields['entry_suburb']);
$fromDb = $fromDb . str_replace("\n", '', $answers_arr->fields['entry_city']);
$fromDb = str_replace("\t", '', $fromDb);
$fromDb = trim($fromDb);
$fromDb = strtolower($fromDb);
$fromDb = str_replace(' ', '', $fromDb);
// debug
$this->zcLog('findMatchingAddressBookEntry - 3a', "From PayPal:\r\n" . $matchQuestion . "\r\n\r\nFrom DB:\r\n" . $fromDb . "\r\n". print_r($answers_arr->fields, true));
// check the strings
if (strlen($fromDb) == strlen($matchQuestion)) {
if ($fromDb == $matchQuestion) {
// exact match return the id
// debug
$this->zcLog('findMatchingAddressBookEntry - 3b', "Exact match:\n" . print_r($answers_arr->fields, true));
return $answers_arr->fields['address_book_id'];
}
} elseif (strlen($fromDb) > strlen($matchQuestion)) {
if (substr($fromDb, 0, strlen($matchQuestion)) == $matchQuestion) {
// we have a match return it (PP)
// debug
$this->zcLog('findMatchingAddressBookEntry - 3b', "partial match (PP):\n" . print_r($answers_arr->fields, true));
return $answers_arr->fields['address_book_id'];
}
} else {
if ($fromDb == substr($matchQuestion, 0, strlen($fromDb))) {
// we have a match return it (DB)
// debug
$this->zcLog('findMatchingAddressBookEntry - 3b', "partial match (DB):\n" . print_r($answers_arr->fields, true));
return $answers_arr->fields['address_book_id'];
}
}
$answers_arr->MoveNext();
}
}
// debug
$this->zcLog('findMatchingAddressBookEntry - 4', "no match");
// no matches found
return false;
}
/**
* This method adds an address book entry to the database, this allows us to add addresses
* that we get back from PayPal that are not in Zen Cart
*
* @param int $customer_id
* @param array $address_question_arr
* @return int
*/
function addAddressBookEntry($customer_id, $address_question_arr, $make_default = false) {
global $db;
// debug
$this->zcLog('addAddressBookEntry - 1', 'address to add: ' . "\n" . print_r($address_question_arr, true));
// if address is blank, don't do any matching
if ($address_question_arr['street_address'] == '') return false;
// set some defaults
$country_id = '223';
$address_format_id = 2; //2 is the American format
// first get the zone id's from the 2 digit iso codes
// country first
$sql = "SELECT countries_id, address_format_id
FROM " . TABLE_COUNTRIES . "
WHERE countries_iso_code_2 = :countryCode:
OR countries_name = :countryName:
OR countries_iso_code_2 = :countryName:
OR countries_name = :countryCode:
LIMIT 1";
$sql = $db->bindVars($sql, ':countryCode:', $address_question_arr['country']['iso_code_2'], 'string');
$sql = $db->bindVars($sql, ':countryName:', $address_question_arr['country']['title'], 'string');
$country = $db->Execute($sql);
// see if we found a record, if not default to American format
if (!$country->EOF) {
$country_id = $country->fields['countries_id'];
$address_format_id = (int)$country->fields['address_format_id'];
} else {
// if defaulting to US, make sure US is valid
$sql = "SELECT countries_id FROM " . TABLE_COUNTRIES . " WHERE countries_id = :countryId LIMIT 1";
$sql = $db->bindVars($sql, ':countryId', $country_id, 'integer');
$result = $db->Execute($sql);
if ($result->EOF) {
$this->notify('NOTIFY_HEADER_ADDRESS_BOOK_ADD_ENTRY_INVALID_ATTEMPT');
$this->zcLog('addAddressBookEntry - 3', 'Failed to add address due to country restrictions');
return FALSE;
}
}
// see if the country code has a state
$sql = "SELECT zone_id
FROM " . TABLE_ZONES . "
WHERE zone_country_id = :zoneId
LIMIT 1";
$sql = $db->bindVars($sql, ':zoneId', $country_id, 'integer');
$country_zone_check = $db->Execute($sql);
$check_zone = $country_zone_check->RecordCount();
// now try and find the zone_id (state/province code)
// use the country id above
if ($check_zone) {
$sql = "SELECT zone_id
FROM " . TABLE_ZONES . "
WHERE zone_country_id = :zoneId
AND (zone_code = :zoneCode
OR zone_name = :zoneCode )
LIMIT 1";
$sql = $db->bindVars($sql, ':zoneId', $country_id, 'integer');
$sql = $db->bindVars($sql, ':zoneCode', $address_question_arr['state'], 'string');
$zone = $db->Execute($sql);
if (!$zone->EOF) {
// grab the id
$zone_id = $zone->fields['zone_id'];
} else {
$zone_id = 0;
}
}
// now run the insert
// this isn't the best way to get fname/lname but it will get the majority of cases
list($fname, $lname) = explode(' ', $address_question_arr['name']);
$sql_data_array= array(array('fieldName'=>'entry_firstname', 'value'=>$fname, 'type'=>'string'),
array('fieldName'=>'entry_lastname', 'value'=>$lname, 'type'=>'string'),
array('fieldName'=>'entry_street_address', 'value'=>$address_question_arr['street_address'], 'type'=>'string'),
array('fieldName'=>'entry_postcode', 'value'=>$address_question_arr['postcode'], 'type'=>'string'),
array('fieldName'=>'entry_city', 'value'=>$address_question_arr['city'], 'type'=>'string'),
array('fieldName'=>'entry_country_id', 'value'=>$country_id, 'type'=>'integer'));
if ($address_question_arr['company'] != '' && $address_question_arr['company'] != $address_question_arr['name']) array('fieldName'=>'entry_company', 'value'=>$address_question_arr['company'], 'type'=>'string');
$sql_data_array[] = array('fieldName'=>'entry_gender', 'value'=>$address_question_arr['payer_gender'], 'type'=>'enum:m|f');
$sql_data_array[] = array('fieldName'=>'entry_suburb', 'value'=>$address_question_arr['suburb'], 'type'=>'string');
if ($zone_id > 0) {
$sql_data_array[] = array('fieldName'=>'entry_zone_id', 'value'=>$zone_id, 'type'=>'integer');
$sql_data_array[] = array('fieldName'=>'entry_state', 'value'=>'', 'type'=>'string');
} else {
$sql_data_array[] = array('fieldName'=>'entry_zone_id', 'value'=>'0', 'type'=>'integer');
$sql_data_array[] = array('fieldName'=>'entry_state', 'value'=>$address_question_arr['state'], 'type'=>'string');
}
$sql_data_array[] = array('fieldName'=>'customers_id', 'value'=>$customer_id, 'type'=>'integer');
$db->perform(TABLE_ADDRESS_BOOK, $sql_data_array);
$new_address_book_id = $db->Insert_ID();
$this->notify('NOTIFY_HEADER_ADDRESS_BOOK_ADD_ENTRY_DONE');
// make default if set, update
if ($make_default) {
$sql_data_array = array();
$sql_data_array[] = array('fieldName'=>'customers_default_address_id', 'value'=>$new_address_book_id, 'type'=>'integer');
$where_clause = "customers_id = :customersID";
$where_clause = $db->bindVars($where_clause, ':customersID', $customer_id, 'integer');
$db->perform(TABLE_CUSTOMERS, $sql_data_array, 'update', $where_clause);
$_SESSION['customer_default_address_id'] = $new_address_book_id;
}
// set the sendto
$_SESSION['sendto'] = $new_address_book_id;
// debug
$this->zcLog('addAddressBookEntry - 2', 'added address #' . $new_address_book_id. "\n" . 'SESSION[sendto] is now set to ' . $_SESSION['sendto']);
// return the address_id
return $new_address_book_id;
}
/**
* If we created an account for the customer, this logs them in and notes that the record was created for PayPal EC purposes
*/
function user_login($email_address, $redirect = true) {
global $db, $order, $messageStack;
global $session_started;
if ($session_started == false) {
zen_redirect(zen_href_link(FILENAME_COOKIE_USAGE));
}
$sql = "SELECT * FROM " . TABLE_CUSTOMERS . "
WHERE customers_email_address = :custEmail ";
$sql = $db->bindVars($sql, ':custEmail', $email_address, 'string');
$check_customer = $db->Execute($sql);
if ($check_customer->EOF) {
$this->terminateEC(MODULE_PAYMENT_PAYPALWPP_TEXT_BAD_LOGIN, true);
}
if (SESSION_RECREATE == 'True') {
zen_session_recreate();
}
$sql = "SELECT entry_country_id, entry_zone_id
FROM " . TABLE_ADDRESS_BOOK . "
WHERE customers_id = :custID
AND address_book_id = :addrID ";
$sql = $db->bindVars($sql, ':custID', $check_customer->fields['customers_id'], 'integer');
$sql = $db->bindVars($sql, ':addrID', $check_customer->fields['customers_default_address_id'], 'integer');
$check_country = $db->Execute($sql);
$_SESSION['customer_id'] = (int)$check_customer->fields['customers_id'];
$_SESSION['customer_default_address_id'] = $check_customer->fields['customers_default_address_id'];
$_SESSION['customer_first_name'] = $check_customer->fields['customers_firstname'];
$_SESSION['customer_country_id'] = $check_country->fields['entry_country_id'];
$_SESSION['customer_zone_id'] = $check_country->fields['entry_zone_id'];
$order->customer['id'] = $_SESSION['customer_id'];
$sql = "UPDATE " . TABLE_CUSTOMERS_INFO . "
SET customers_info_date_of_last_logon = now(),
customers_info_number_of_logons = customers_info_number_of_logons+1
WHERE customers_info_id = :custID ";
$sql = $db->bindVars($sql, ':custID', $_SESSION['customer_id'], 'integer');
$db->Execute($sql);
// bof: contents merge notice
// save current cart contents count if required
if (SHOW_SHOPPING_CART_COMBINED > 0) {
$zc_check_basket_before = $_SESSION['cart']->count_contents();
}
// bof: not require part of contents merge notice
// restore cart contents
$_SESSION['cart']->restore_contents();
// eof: not require part of contents merge notice
// check current cart contents count if required
if (SHOW_SHOPPING_CART_COMBINED > 0 && $zc_check_basket_before > 0) {
$zc_check_basket_after = $_SESSION['cart']->count_contents();
if (($zc_check_basket_before != $zc_check_basket_after) && $_SESSION['cart']->count_contents() > 0 && SHOW_SHOPPING_CART_COMBINED > 0) {
if (SHOW_SHOPPING_CART_COMBINED == 2) {
// warning only do not send to cart
$messageStack->add_session('header', WARNING_SHOPPING_CART_COMBINED, 'caution');
}
if (SHOW_SHOPPING_CART_COMBINED == 1) {
// show warning and send to shopping cart for review
$messageStack->add_session('shopping_cart', WARNING_SHOPPING_CART_COMBINED, 'caution');
zen_redirect(zen_href_link(FILENAME_SHOPPING_CART, '', 'NONSSL'));
}
}
}
// eof: contents merge notice
if ($redirect) {
$this->terminateEC();
}
return true;
}
/**
* If the account was created only for temporary purposes to place the PayPal order, delete it.
*/
function ec_delete_user($cid) {
global $db;
unset($_SESSION['customer_id']);
unset($_SESSION['customer_default_address_id']);
unset($_SESSION['customer_first_name']);
unset($_SESSION['customer_country_id']);
unset($_SESSION['customer_zone_id']);
unset($_SESSION['comments']);
unset($_SESSION['customer_guest_id']);
$cid = (int)$cid;
$sql = "delete from " . TABLE_ADDRESS_BOOK . " where customers_id = " . $cid;
$db->Execute($sql);
$sql = "delete from " . TABLE_CUSTOMERS . " where customers_id = " . $cid;
$db->Execute($sql);
$sql = "delete from " . TABLE_CUSTOMERS_INFO . " where customers_info_id = " . $cid;
$db->Execute($sql);
$sql = "delete from " . TABLE_CUSTOMERS_BASKET . " where customers_id = " . $cid;
$db->Execute($sql);
$sql = "delete from " . TABLE_CUSTOMERS_BASKET_ATTRIBUTES . " where customers_id = " . $cid;
$db->Execute($sql);
$sql = "delete from " . TABLE_WHOS_ONLINE . " where customer_id = " . $cid;
$db->Execute($sql);
}
/**
* If the EC flow has to be interrupted for any reason, this does the appropriate cleanup and displays status/error messages.
*/
function terminateEC($error_msg = '', $kill_sess_vars = false, $goto_page = '') {
global $messageStack, $order, $order_total_modules;
$error_msg = trim($error_msg);
if (substr($error_msg, -1) == '-') $error_msg = trim(substr($error_msg, 0, strlen($error_msg) - 1));
$stackAlert = 'header';
// debug
$this->_doDebug('PayPal test Log - terminateEC-A', "goto page: " . $goto_page . "\nerror_msg: " . $error_msg . "\n\nSession data: " . print_r($_SESSION, true));
if ($kill_sess_vars) {
if (!empty($_SESSION['paypal_ec_temp'])) {
$this->ec_delete_user($_SESSION['customer_id']);
}
// Unregister the paypal session variables, making the user start over.
unset($_SESSION['paypal_ec_temp']);
unset($_SESSION['paypal_ec_token']);
unset($_SESSION['paypal_ec_payer_id']);
unset($_SESSION['paypal_ec_payer_info']);
unset($_SESSION['paypal_ec_final']);
unset($_SESSION['paypal_ec_markflow']);
// debug
$this->zcLog('termEC-1', 'Killed the session vars as requested');
}
$this->zcLog('termEC-2', 'BEFORE: $this->showPaymentPage = ' . (int)$this->showPaymentPage . "\nToken Data:" . $_SESSION['paypal_ec_token']);
// force display of payment page if GV/DC active for this customer
if (MODULE_ORDER_TOTAL_INSTALLED && $this->showPaymentPage !== true && isset($_SESSION['paypal_ec_token']) ) {
require_once(DIR_WS_CLASSES . 'order.php');
$order = new order;
require_once(DIR_WS_CLASSES . 'order_total.php');
$order_total_modules = new order_total;
$order_totals = $order_total_modules->process();
$selection = $order_total_modules->credit_selection();
if (sizeof($selection)>0) $this->showPaymentPage = true;
}
// if came from Payment page, don't go back to it
if ($_SESSION['paypal_ec_markflow'] == 1) $this->showPaymentPage = false;
// if in DP mode, don't go to payment page ... we've already been there to get here
if ($goto_page == FILENAME_CHECKOUT_PROCESS) $this->showPaymentPage = false;
// debug
$this->zcLog('termEC-3', 'AFTER: $this->showPaymentPage = ' . (int)$this->showPaymentPage);
if (!empty($_SESSION['customer_first_name']) && !empty($_SESSION['customer_id'])) {
if ($this->showPaymentPage === true || $goto_page == FILENAME_CHECKOUT_PAYMENT) {
// debug
$this->zcLog('termEC-4', 'We ARE logged in, and $this->showPaymentPage === true');
// if no shipping selected or if shipping cost is < 0 goto shipping page
if ((!$_SESSION['shipping'] || $_SESSION['shipping'] == '') || $_SESSION['shipping']['cost'] < 0) {
// debug
$this->zcLog('termEC-5', 'Have no shipping method selected, or shipping < 0 so set FILENAME_CHECKOUT_SHIPPING');
$redirect_path = FILENAME_CHECKOUT_SHIPPING;
$stackAlert = 'checkout_shipping';
} else {
// debug
$this->zcLog('termEC-6', 'We DO have a shipping method selected, so goto PAYMENT');
$redirect_path = FILENAME_CHECKOUT_PAYMENT;
$stackAlert = 'checkout_payment';
}
} elseif ($goto_page) {
// debug
$this->zcLog('termEC-7', '$this->showPaymentPage NOT true, and have custom page parameter: ' . $goto_page);
$redirect_path = $goto_page;
$stackAlert = 'header';
if ($goto_page == FILENAME_SHOPPING_CART) $stackAlert = 'shopping_cart';
} else {
// debug
$this->zcLog('termEC-8', '$this->showPaymentPage NOT true, and NO custom page selected ... using SHIPPING as default');
$redirect_path = FILENAME_CHECKOUT_SHIPPING;
$stackAlert = 'checkout_shipping';
}
} else {
// debug
$this->zcLog('termEC-9', 'We are NOT logged in, so set snapshot to Shipping page, and redirect to login');
$_SESSION['navigation']->set_snapshot(FILENAME_CHECKOUT_SHIPPING);
$redirect_path = FILENAME_LOGIN;
$stackAlert = 'login';
}
if ($error_msg) {
$messageStack->add_session($stackAlert, $error_msg, 'error');
}
// debug
$this->zcLog('termEC-10', 'Redirecting to ' . $redirect_path . ' - Stack: ' . $stackAlert . "\n" . 'Message: ' . $error_msg . "\nSession Data: " . print_r($_SESSION, true));
zen_redirect(zen_href_link($redirect_path, '', 'SSL', true, false));
}
/**
* Error / exception handling
*/
function _errorHandler($response, $operation = '', $ignore_codes = '') {
global $messageStack, $doPayPal;
$gateway_mode = (isset($response['PNREF']) && $response['PNREF'] != '');
$basicError = (!$response || (isset($response['RESULT']) && $response['RESULT'] != 0) || (isset($response['ACK']) && !strstr($response['ACK'], 'Success')) || (!isset($response['RESULT']) && !isset($response['ACK'])));
$ignoreList = explode(',', str_replace(' ', '', $ignore_codes));
foreach($ignoreList as $key=>$value) {
if ($value != '' && $response['L_ERRORCODE0'] == $value) $basicError = false;
}
/** Handle unilateral **/
if ($response['RESULT'] == 'Unauthorized: Unilateral') {
$errorText = $response['RESULT'] . MODULE_PAYMENT_PAYPALWPP_TEXT_UNILATERAL;
$messageStack->add_session($errorText, 'error');
}
/** Handle FMF Scenarios **/
if (in_array($operation, array('DoExpressCheckoutPayment', 'DoDirectPayment')) && $response['PAYMENTSTATUS'] == 'Pending' && $response['L_ERRORCODE0'] == 11610) {
$this->fmfResponse = urldecode($response['L_SHORTMESSAGE0']);
$this->fmfErrors = array();
if ($response['ACK'] == 'SuccessWithWarning' && isset($response['L_FMFPENDINGID0'])) {
for ($i=0; $i<20; $i++) {
$this->fmfErrors[] = array('key' => $response['L_FMFPENDINGID' . $i], 'status' => $response['L_FMFPENDINGID' . $i], 'desc' => $response['L_FMFPENDINGDESCRIPTION' . $i]);
}
}
return (sizeof($this->fmfErrors)>0) ? $this->fmfErrors : FALSE;
}
if (!isset($response['L_SHORTMESSAGE0']) && isset($response['RESPMSG']) && $response['RESPMSG'] != '') $response['L_SHORTMESSAGE0'] = $response['RESPMSG'];
//echo '
basicError='.$basicError.'
' . urldecode(print_r($response,true)); die('halted');
$errorInfo = "\n\nProblem occurred while customer " . $_SESSION['customer_id'] . ' ' . $_SESSION['customer_first_name'] . ' ' . $_SESSION['customer_last_name'] . ' was attempting checkout with PayPal Express Checkout.';
switch($operation) {
case 'SetExpressCheckout':
if ($basicError) {
// if error, display error message. If debug options enabled, email dump to store owner
if ($this->enableDebugging) {
$this->_doDebug('PayPal Error Log - ec_step1()', "In function: ec_step1()\r\n\r\nValue List:\r\n" . str_replace('&',"\r\n", $doPayPal->_sanitizeLog($doPayPal->_parseNameValueList($doPayPal->lastParamList))) . "\r\n\r\nResponse:\r\n" . print_r($response, true));
}
$errorText = MODULE_PAYMENT_PAYPALWPP_TEXT_GEN_ERROR;
$errorNum = urldecode($response['L_ERRORCODE0'] . $response['RESULT']);
if ($response['RESULT'] == 25) $errorText = MODULE_PAYMENT_PAYPALWPP_TEXT_NOT_WPP_ACCOUNT_ERROR;
if ($response['L_ERRORCODE0'] == 10002) $errorText = MODULE_PAYMENT_PAYPALWPP_TEXT_SANDBOX_VS_LIVE_ERROR;
if ($response['L_ERRORCODE0'] == 10565) {
$errorText = MODULE_PAYMENT_PAYPALWPP_TEXT_WPP_BAD_COUNTRY_ERROR;
$_SESSION['payment'] = '';
}
if ($response['L_ERRORCODE0'] == 10736) $errorText = MODULE_PAYMENT_PAYPALWPP_TEXT_ADDR_ERROR;
if ($response['L_ERRORCODE0'] == 10752) $errorText = MODULE_PAYMENT_PAYPALWPP_TEXT_DECLINED;
$detailedMessage = ($errorText == MODULE_PAYMENT_PAYPALWPP_TEXT_GEN_ERROR || (int)trim($errorNum) > 0 || $this->enableDebugging || $response['CURL_ERRORS'] != '' || $this->emailAlerts) ? $errorNum . ' ' . urldecode(' ' . $response['L_SHORTMESSAGE0'] . ' - ' . $response['L_LONGMESSAGE0'] . (isset($response['RESPMSG']) ? ' ' . $response['RESPMSG'] : '') . ' ' . $response['CURL_ERRORS']) : '';
$detailedEmailMessage = ($detailedMessage == '') ? '' : MODULE_PAYMENT_PAYPALWPP_TEXT_EMAIL_ERROR_MESSAGE . urldecode($response['L_ERRORCODE0'] . "\n" . $response['L_SHORTMESSAGE0'] . "\n" . $response['L_LONGMESSAGE0'] . $response['L_ERRORCODE1'] . "\n" . $response['L_SHORTMESSAGE1'] . "\n" . $response['L_LONGMESSAGE1'] . $response['L_ERRORCODE2'] . "\n" . $response['L_SHORTMESSAGE2'] . "\n" . $response['L_LONGMESSAGE2'] . ($response['CURL_ERRORS'] != '' ? "\n" . $response['CURL_ERRORS'] : '') . "\n\n" . 'Zen Cart message: ' . $errorText) . $errorInfo;
if (!isset($response['L_ERRORCODE0']) && isset($response['RESULT'])) $detailedEmailMessage .= "\n\n" . print_r($response, TRUE);
if ($detailedEmailMessage != '') zen_mail(STORE_NAME, STORE_OWNER_EMAIL_ADDRESS, MODULE_PAYMENT_PAYPALWPP_TEXT_EMAIL_ERROR_SUBJECT . ' (' . zen_uncomment($errorNum) . ')', zen_uncomment($detailedEmailMessage), STORE_OWNER, STORE_OWNER_EMAIL_ADDRESS, array('EMAIL_MESSAGE_HTML'=>zen_uncomment($detailedMessage)), 'paymentalert');
$this->terminateEC($errorText . ' (' . $errorNum . ') ' . $detailedMessage, true);
return true;
}
break;
case 'GetExpressCheckoutDetails':
if ($basicError || $_SESSION['paypal_ec_token'] != urldecode($response['TOKEN'])) {
// if response indicates an error, send the customer back to checkout and display the error. Debug to store owner if active.
if ($this->enableDebugging) {
$this->_doDebug('PayPal Error Log - ec_step2()', "In function: ec_step2()\r\n\r\nValue List:\r\n" . str_replace('&',"\r\n", urldecode($doPayPal->_sanitizeLog($doPayPal->_parseNameValueList($doPayPal->lastParamList)))) . "\r\n\r\nResponse:\r\n" . urldecode(print_r($response, true)));
}
$this->terminateEC(MODULE_PAYMENT_PAYPALWPP_TEXT_GEN_ERROR . ' (' . $response['L_ERRORCODE0'] . ' ' . urldecode($response['L_SHORTMESSAGE0'] . $response['RESULT']) . ')', true);
return true;
}
break;
case 'DoExpressCheckoutPayment':
if ($basicError || $_SESSION['paypal_ec_token'] != urldecode($response['TOKEN'])) {
// there's an error, so alert customer, and if debug is on, notify storeowner
if ($this->enableDebugging) {
$this->_doDebug('PayPal Error Log - before_process() - EC', "In function: before_process() - Express Checkout\r\n\r\nValue List:\r\n" . str_replace('&',"\r\n", $doPayPal->_sanitizeLog($doPayPal->_parseNameValueList($doPayPal->lastParamList))) . "\r\n\r\nResponse:\r\n" . print_r($response, true));
}
// if funding source problem occurred, must send back to re-select alternate funding source
if ($response['L_ERRORCODE0'] == 10422) {
$paypal_url = $this->getPayPalLoginServer();
zen_redirect($paypal_url . "?cmd=_express-checkout&token=" . $_SESSION['paypal_ec_token']);
die();
}
// some other error condition
$errorText = MODULE_PAYMENT_PAYPALWPP_INVALID_RESPONSE;
$errorNum = urldecode($response['L_ERRORCODE0'] . $response['RESULT']);
if ($response['L_ERRORCODE0'] == 10415) $errorText = MODULE_PAYMENT_PAYPALWPP_TEXT_ORDER_ALREADY_PLACED_ERROR;
if ($response['L_ERRORCODE0'] == 10417) $errorText = MODULE_PAYMENT_PAYPALWPP_TEXT_INSUFFICIENT_FUNDS_ERROR;
if ($response['L_ERRORCODE0'] == 10474) $errorText .= urldecode($response['L_LONGMESSAGE0']);
$detailedMessage = ($errorText == MODULE_PAYMENT_PAYPALWPP_INVALID_RESPONSE || (int)trim($errorNum) > 0 || $this->enableDebugging || $response['CURL_ERRORS'] != '' || $this->emailAlerts) ? $errorNum . ' ' . urldecode(' ' . $response['L_SHORTMESSAGE0'] . ' - ' . $response['L_LONGMESSAGE0'] . $response['RESULT'] . ' ' . $response['CURL_ERRORS']) : '';
$detailedEmailMessage = ($detailedMessage == '') ? '' : MODULE_PAYMENT_PAYPALWPP_TEXT_EMAIL_ERROR_MESSAGE . urldecode($response['L_ERRORCODE0'] . "\n" . $response['L_SHORTMESSAGE0'] . "\n" . $response['L_LONGMESSAGE0'] . $response['L_ERRORCODE1'] . "\n" . $response['L_SHORTMESSAGE1'] . "\n" . $response['L_LONGMESSAGE1'] . $response['L_ERRORCODE2'] . "\n" . $response['L_SHORTMESSAGE2'] . "\n" . $response['L_LONGMESSAGE2'] . ($response['CURL_ERRORS'] != '' ? "\n" . $response['CURL_ERRORS'] : '') . "\n\n" . 'Zen Cart message: ' . $errorText) . $errorInfo;
if (!isset($response['L_ERRORCODE0']) && isset($response['RESULT'])) $detailedEmailMessage .= "\n\n" . print_r($response, TRUE);
if ($detailedEmailMessage != '') zen_mail(STORE_NAME, STORE_OWNER_EMAIL_ADDRESS, MODULE_PAYMENT_PAYPALWPP_TEXT_EMAIL_ERROR_SUBJECT . ' (' . zen_uncomment($errorNum) . ')', zen_uncomment($detailedEmailMessage), STORE_OWNER, STORE_OWNER_EMAIL_ADDRESS, array('EMAIL_MESSAGE_HTML'=>zen_uncomment($detailedMessage)), 'paymentalert');
$this->terminateEC(($detailedEmailMessage == '' ? $errorText . ' (' . urldecode($response['L_SHORTMESSAGE0'] . $response['RESULT']) . ') ' : $detailedMessage), true);
return true;
}
break;
case 'DoRefund':
if ($basicError || (!isset($response['RESPMSG']) && !isset($response['REFUNDTRANSACTIONID']))) {
// if error, display error message. If debug options enabled, email dump to store owner
if ($this->enableDebugging) {
$this->_doDebug('PayPal Error Log - ' . $operation, "Value List:\r\n" . str_replace('&',"\r\n", $doPayPal->_sanitizeLog($doPayPal->_parseNameValueList($doPayPal->lastParamList))) . "\r\n\r\nResponse:\r\n" . print_r($response, true));
}
$errorText = MODULE_PAYMENT_PAYPALWPP_TEXT_REFUND_ERROR;
if ($response['L_ERRORCODE0'] == 10009) $errorText = MODULE_PAYMENT_PAYPALWPP_TEXT_REFUNDFULL_ERROR;
if ($response['RESULT'] == 105 || isset($response['RESPMSG'])) $response['L_SHORTMESSAGE0'] = $response['RESULT'] . ' ' . $response['RESPMSG'];
if (urldecode($response['L_LONGMESSAGE0']) == 'This transaction has already been fully refunded') $response['L_SHORTMESSAGE0'] = urldecode($response['L_LONGMESSAGE0']);
if (urldecode($response['L_LONGMESSAGE0']) == 'Can not do a full refund after a partial refund') $response['L_SHORTMESSAGE0'] = urldecode($response['L_LONGMESSAGE0']);
if (urldecode($response['L_LONGMESSAGE0']) == 'The partial refund amount must be less than or equal to the remaining amount') $response['L_SHORTMESSAGE0'] = urldecode($response['L_LONGMESSAGE0']);
if (urldecode($response['L_LONGMESSAGE0']) == 'You can not refund this type of transaction') $response['L_SHORTMESSAGE0'] = urldecode($response['L_LONGMESSAGE0']);
$errorText .= ' (' . urldecode($response['L_SHORTMESSAGE0']) . ') ' . $response['L_ERRORCODE0'];
$messageStack->add_session($errorText, 'error');
return true;
}
break;
case 'DoAuthorization':
case 'DoReauthorization':
if ($basicError) {
// if error, display error message. If debug options enabled, email dump to store owner
if ($this->enableDebugging) {
$this->_doDebug('PayPal Error Log - ' . $operation, "Value List:\r\n" . str_replace('&',"\r\n", $doPayPal->_sanitizeLog($doPayPal->_parseNameValueList($doPayPal->lastParamList))) . "\r\n\r\nResponse:\r\n" . print_r($response, true));
}
$errorText = MODULE_PAYMENT_PAYPALWPP_TEXT_AUTH_ERROR;
$errorText .= ' (' . urldecode($response['L_SHORTMESSAGE0']) . ') ' . $response['L_ERRORCODE0'];
$messageStack->add_session($errorText, 'error');
return true;
}
break;
case 'DoCapture':
if ($basicError) {
// if error, display error message. If debug options enabled, email dump to store owner
if ($this->enableDebugging) {
$this->_doDebug('PayPal Error Log - ' . $operation, "Value List:\r\n" . str_replace('&',"\r\n", $doPayPal->_sanitizeLog($doPayPal->_parseNameValueList($doPayPal->lastParamList))) . "\r\n\r\nResponse:\r\n" . print_r($response, true));
}
$errorText = MODULE_PAYMENT_PAYPALWPP_TEXT_CAPT_ERROR;
if ($response['RESULT'] == 111) $response['L_SHORTMESSAGE0'] = $response['RESULT'] . ' ' . $response['RESPMSG'];
$errorText .= ' (' . urldecode($response['L_SHORTMESSAGE0']) . ') ' . $response['L_ERRORCODE0'];
$messageStack->add_session($errorText, 'error');
return true;
}
break;
case 'DoVoid':
if ($basicError) {
// if error, display error message. If debug options enabled, email dump to store owner
if ($this->enableDebugging) {
$this->_doDebug('PayPal Error Log - ' . $operation, "Value List:\r\n" . str_replace('&',"\r\n", $doPayPal->_sanitizeLog($doPayPal->_parseNameValueList($doPayPal->lastParamList))) . "\r\n\r\nResponse:\r\n" . print_r($response, true));
}
$errorText = MODULE_PAYMENT_PAYPALWPP_TEXT_VOID_ERROR;
if ($response['RESULT'] == 12) $response['L_SHORTMESSAGE0'] = $response['RESULT'] . ' ' . $response['RESPMSG'];
if ($response['RESULT'] == 108) $response['L_SHORTMESSAGE0'] = $response['RESULT'] . ' ' . $response['RESPMSG'];
$errorText .= ' (' . urldecode($response['L_SHORTMESSAGE0']) . ') ' . $response['L_ERRORCODE0'];
$messageStack->add_session($errorText, 'error');
return true;
}
break;
case 'GetTransactionDetails':
if ($basicError) {
// if error, display error message. If debug options enabled, email dump to store owner
if ($this->enableDebugging) {
$this->_doDebug('PayPal Error Log - ' . $operation, "Value List:\r\n" . str_replace('&',"\r\n", $doPayPal->_sanitizeLog($doPayPal->_parseNameValueList($doPayPal->lastParamList))) . "\r\n\r\nResponse:\r\n" . print_r($response, true));
}
$errorText = MODULE_PAYMENT_PAYPALWPP_TEXT_GETDETAILS_ERROR;
$errorText .= ' (' . urldecode($response['L_SHORTMESSAGE0']) . ') ' . $response['L_ERRORCODE0'];
$messageStack->add_session($errorText, 'error');
return true;
}
break;
case 'TransactionSearch':
if ($basicError) {
// if error, display error message. If debug options enabled, email dump to store owner
if ($this->enableDebugging) {
$this->_doDebug('PayPal Error Log - ' . $operation, "Value List:\r\n" . str_replace('&',"\r\n", $doPayPal->_sanitizeLog($doPayPal->_parseNameValueList($doPayPal->lastParamList))) . "\r\n\r\nResponse:\r\n" . print_r($response, true));
}
$errorText = MODULE_PAYMENT_PAYPALWPP_TEXT_TRANSSEARCH_ERROR;
$errorText .= ' (' . urldecode($response['L_SHORTMESSAGE0']) . ') ' . $response['L_ERRORCODE0'];
$messageStack->add_session($errorText, 'error');
return true;
}
break;
default:
if ($basicError) {
// if error, display error message. If debug options enabled, email dump to store owner
if ($this->enableDebugging) {
$this->_doDebug('PayPal Error Log - ' . $operation, "Value List:\r\n" . str_replace('&',"\r\n", $doPayPal->_sanitizeLog($doPayPal->_parseNameValueList($doPayPal->lastParamList))) . "\r\n\r\nResponse:\r\n" . print_r($response, true));
}
$errorText = MODULE_PAYMENT_PAYPALWPP_TEXT_GEN_API_ERROR;
$errorNum .= ' (' . urldecode($response['L_SHORTMESSAGE0'] . ' ) ' . $response['L_ERRORCODE0'];
$detailedMessage = ($errorText == MODULE_PAYMENT_PAYPALWPP_TEXT_GEN_API_ERROR || $errorText == MODULE_PAYMENT_PAYPALWPP_TEXT_DECLINED || (int)trim($errorNum) > 0 || $this->enableDebugging || $response['CURL_ERRORS'] != '' || $this->emailAlerts) ? urldecode(' ' . $response['L_SHORTMESSAGE0'] . ' - ' . $response['L_LONGMESSAGE0'] . ' ' . $response['CURL_ERRORS']) : '';
$detailedEmailMessage = ($detailedMessage == '') ? '' : MODULE_PAYMENT_PAYPALWPP_TEXT_EMAIL_ERROR_MESSAGE . ' ' . $response['RESPMSG'] . urldecode($response['L_ERRORCODE0'] . "\n" . $response['L_SHORTMESSAGE0'] . "\n" . $response['L_LONGMESSAGE0'] . $response['L_ERRORCODE1'] . "\n" . $response['L_SHORTMESSAGE1'] . "\n" . $response['L_LONGMESSAGE1'] . $response['L_ERRORCODE2'] . "\n" . $response['L_SHORTMESSAGE2'] . "\n" . $response['L_LONGMESSAGE2'] . ($response['CURL_ERRORS'] != '' ? "\n" . $response['CURL_ERRORS'] : '') . "\n\n" . 'Zen Cart message: ' . $detailedMessage . "\n\n" . 'Transaction Response Details: ' . print_r($response, true) . "\n\n" . 'Transaction Submission: ' . urldecode($doPayPal->_sanitizeLog($doPayPal->_parseNameValueList($doPayPal->lastParamList), true)));
if ($detailedEmailMessage != '') zen_mail(STORE_NAME, STORE_OWNER_EMAIL_ADDRESS, MODULE_PAYMENT_PAYPALWPP_TEXT_EMAIL_ERROR_SUBJECT . ' (' . zen_uncomment($errorNum) . ')', zen_uncomment($detailedMessage), STORE_OWNER, STORE_OWNER_EMAIL_ADDRESS, array('EMAIL_MESSAGE_HTML'=>nl2br(zen_uncomment($detailedEmailMessage))), 'paymentalert');
$messageStack->add_session($errorText . $errorNum . $detailedMessage, 'error');
return true;
}
break;
}
}
function tableCheckup() {
global $db, $sniffer;
$fieldOkay1 = (method_exists($sniffer, 'field_type')) ? $sniffer->field_type(TABLE_PAYPAL, 'txn_id', 'varchar(20)', true) : -1;
$fieldOkay2 = ($sniffer->field_exists(TABLE_PAYPAL, 'module_name')) ? true : -1;
$fieldOkay3 = ($sniffer->field_exists(TABLE_PAYPAL, 'order_id')) ? true : -1;
if ($fieldOkay1 == -1) {
$sql = "show fields from " . TABLE_PAYPAL;
$result = $db->Execute($sql);
while (!$result->EOF) {
if ($result->fields['Field'] == 'txn_id') {
if ($result->fields['Type'] == 'varchar(20)') {
$fieldOkay1 = true; // exists and matches required type, so skip to other checkup
} else {
$fieldOkay1 = $result->fields['Type']; // doesn't match, so return what it "is"
break;
}
}
$result->MoveNext();
}
}
if ($fieldOkay1 !== true) {
// temporary fix to table structure for v1.3.7.x -- may remove in later release
$db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE payment_type payment_type varchar(40) NOT NULL default ''");
$db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE txn_type txn_type varchar(40) NOT NULL default ''");
$db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE payment_status payment_status varchar(32) NOT NULL default ''");
$db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE reason_code reason_code varchar(40) default NULL");
$db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE pending_reason pending_reason varchar(32) default NULL");
$db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE invoice invoice varchar(128) default NULL");
$db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE payer_business_name payer_business_name varchar(128) default NULL");
$db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE address_name address_name varchar(64) default NULL");
$db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE address_street address_street varchar(254) default NULL");
$db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE address_city address_city varchar(120) default NULL");
$db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE address_state address_state varchar(120) default NULL");
$db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE payer_email payer_email varchar(128) NOT NULL default ''");
$db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE business business varchar(128) NOT NULL default ''");
$db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE receiver_email receiver_email varchar(128) NOT NULL default ''");
$db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE txn_id txn_id varchar(20) NOT NULL default ''");
$db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE parent_txn_id parent_txn_id varchar(20) default NULL");
}
if ($fieldOkay2 !== true) {
$db->Execute("ALTER TABLE " . TABLE_PAYPAL . " ADD COLUMN module_name varchar(40) NOT NULL default '' after txn_type");
$db->Execute("ALTER TABLE " . TABLE_PAYPAL . " ADD COLUMN module_mode varchar(40) NOT NULL default '' after module_name");
}
if ($fieldOkay3 !== true) {
$db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE zen_order_id order_id int(11) NOT NULL default '0'");
}
}
}