public function applyRule(ISC_QUOTE $quote)
	{
		if (!customerIsSignedIn()) {
			return null;
		}

		$customerId = getClass('ISC_CUSTOMER')->getCustomerId();
		$query = "
			SELECT COUNT(*)
			FROM [|PREFIX|]orders
			WHERE ordcustid='".$customerId."' AND ordstatus > 0 AND deleted = 0
			LIMIT 1
		";
		$orderCount = $GLOBALS['ISC_CLASS_DB']->fetchOne($query);

		// Discount does not apply
		if($orderCount <= $this->orders) {
			return false;
		}

		$items = $quote->getItems();
		$totalDiscount = 0;
		// The discount needs to come off each item, so that tax is also affected.
		foreach($items as $item) {
			$discountAmount = $item->getDiscountedBaseTotal() * ($this->amount / 100);
			$item->addDiscount($this->getDbId(), $discountAmount);
			$totalDiscount += $discountAmount;
		}

		$quote->addDiscount($this->getDbId(), $totalDiscount);
		$this->banners[] = sprintf(getLang($this->getName().'DiscountMessage'), $this->amount);
		return true;
	}
示例#2
0
	/**
	 * Create the pending order in the database with the customers selected payment details, etc.
	 *
	 * @return array An array containing information about what needs to be done next.
	 */
	public function SavePendingOrder()
	{
		$provider = null;
		$verifyPaymentProvider = true;
		$redirectToFinishOrder = false;
		$providerId = '';

		$pendingOrderResult = array();
		$creditUsed = 0;
		$giftCertificates = array();

		$orderTotal = $this->getQuote()->getGrandTotal();

		// store the discounted subtotal in the session for affiliate tracking
		$incTax = (getConfig('taxDefaultTaxDisplayOrders') == TAX_PRICES_DISPLAY_INCLUSIVE);
		$_SESSION['LAST_ORDER_DISCOUNTED_SUBTOTAL'] = $this->getQuote()->getDiscountedSubTotal($incTax);

		// Find out what currency we are using. We'll need this later to display their previous orders in the currency that they have selected
		$selectedCurrency = GetCurrencyById($GLOBALS['CurrentCurrency']);

		$giftCertificates = $this->getQuote()->getAppliedGiftCertificates();
		if(!empty($giftCertificates)) {
			$badCertificates = array();
			$remainingBalance = 0;
			$totalWithoutCertificates =
				$this->getQuote()->getGrandTotalWithoutGiftCertificates();
			$giftCertificateAmount =
				$this->getQuote()->getGiftCertificateTotal();
			getClass('ISC_GIFTCERTIFICATES')
				->giftCertificatesApplicableToOrder(
					$totalWithoutCertificates,
					$giftCertificates,
					$remainingBalance,
					$badCertificates);

			// One or more gift certificates were invalid so this order is now invalid
			if(!empty($badCertificates)) {
				$badCertificatesList = '<strong>'.GetLang('BadGiftCertificates').'</strong><ul>';
				foreach($badCertificates as $code => $reason) {
					if(is_array($reason) && $reason[0] == "expired") {
						$reason = sprintf(GetLang('BadGiftCertificateExpired'), CDate($reason[1]));
					}
					else {
						$reason = GetLang('BadGiftCertificate'.ucfirst($reason));
					}
					$badCertificatesList .= sprintf("<li>%s - %s", isc_html_escape($code), $reason);
				}
				$badCertificatesList .= "</ul>";
				$pendingOrderResult = array(
					'error' => GetLang('OrderContainedInvalidGiftCertificates'),
					'errorDetails' => $badCertificatesList
				);
				return $pendingOrderResult;
			}
			// This order was entirely paid for using gift certificates but the totals don't add up
			else if($totalWithoutCertificates == $giftCertificateAmount && $remainingBalance > 0) {
				$pendingOrderResult = array(
					'error' => GetLang('OrderTotalStillRemainingCertificates')
				);
				return $pendingOrderResult;
			}
			// Order was entirely paid for using gift certificates
			else if($totalWithoutCertificates == $giftCertificateAmount) {
				$providerId = 'giftcertificate';
				$verifyPaymentProvider = false;
				$redirectToFinishOrder = true;
			}
		}

		// If the order total is 0, then we just forward the user on to the "Thank You" page and set the payment provider to ''
		if($orderTotal == 0) {
			$providerId = '';
			$verifyPaymentProvider = false;
			$redirectToFinishOrder = true;
		}

		$selected_provider = '';
		if($verifyPaymentProvider) {
			$candidate = '';
			if (isset($_POST['checkout_provider']) && $_POST['checkout_provider'] != '') {
				$candidate = $_POST['checkout_provider'];
			} else if (isset($_POST['credit_checkout_provider']) && $_POST['credit_checkout_provider'] != '') {
				// used by paypal
				$candidate = $_POST['credit_checkout_provider'];
			}

			// Check if the chosen checkout method is valid
			$providers = GetCheckoutModulesThatCustomerHasAccessTo(true);
			foreach ($providers as $p) {
				if ($p['id'] == $candidate) {
					$selected_provider = $candidate;
				}
			}

			// If there's only one payment provider, then they're paying via that
			if($selected_provider == '' && count($providers) == 1) {
				$selected_provider = $providers[0]['object']->GetId();
			}

			// Are we using our store credit?
			$customer = getClass('ISC_CUSTOMER')->getCustomerDataByToken();
			if (isset($_POST['store_credit']) && $_POST['store_credit'] == 1
				&& $customer['custstorecredit'] > 0) {
					// User has not chosen a payment provider and can't afford this order using only store credit, throw back as error
					if ($selected_provider == '' && $customer['custstorecredit'] < $orderTotal) {
						return false;
					}
					// Otherwise we can use the store credit.
					// Subtract store credit from users account and send them to the finished page
					else {
						$onlyCredit = false;
						$updateExtra = '';
						// If we're only using store credit
						$creditToUse = $orderTotal;
						if ($customer['custstorecredit'] >= $creditToUse) {
							// Set the checkout provider
							$providerId = 'storecredit';
							$verifyPaymentProvider = false;
							$redirectToFinishOrder = true;
							$creditUsed = $creditToUse;
							$onlyCredit = true;
						}
						else {
							// Using all of our store credit to pay for this order and we owe more.
							$creditUsed = $customer['custstorecredit'];
						}
					}
			}
		}

		$orderStatus = ORDER_STATUS_INCOMPLETE;

		// Now with round 2, do we still need to verify the payment provider?
		if($verifyPaymentProvider) {
			// If there's more than one provider and one wasn't selected on the order confirmation screen then there's a problem
			if ((count($providers) == 0 ||
				(count($providers) > 1 && $selected_provider == '')) &&
					!isset($_SESSION['CHECKOUT']['ProviderListHTML'])) {
					return false;
			}

			// Is the payment provider selected actually valid?
			if (!GetModuleById('checkout', $provider, $selected_provider)) {
				return false;
			}
			$providerId = $provider->GetId();
		}

		if(isset($_COOKIE['SHOP_TOKEN'])) {
			$customerToken = $_COOKIE['SHOP_TOKEN'];
		}
		else {
			$customerToken = '';
		}

		$orderComments = '';
		if(isset($_REQUEST['ordercomments'])) {
			$orderComments = $_POST['ordercomments'];
		}

		// Set up the order to be created
		$this->getQuote()
			->setAppliedStoreCredit($creditUsed)
			->setCustomerMessage($orderComments);
			;

		$newOrder = array(
			'orderpaymentmodule' => $providerId,
			'ordcurrencyid' => $selectedCurrency['currencyid'],
			'ordcurrencyexchangerate' => $selectedCurrency['currencyexchangerate'],
			'ordipaddress' => getIp(),
			'ordstatus' => $orderStatus,
			'extraInfo' => array(),

			'quote' => $this->getQuote(),
		);


		// OK, we're successful down to here - do they want to create an account? If so then assign it to
		// a session so we can create the actual record on a successful order
		if(!empty($_SESSION['CHECKOUT']['CREATE_ACCOUNT']) ||
			!customerIsSignedIn() && getConfig('GuestCheckoutCreateAccounts')) {
				$createAccount = array(
					'addresses' => array()
				);
				if(!empty($_SESSION['CHECKOUT']['CREATE_ACCOUNT'])) {
					$createAccount['password'] = $_SESSION['CHECKOUT']['CREATE_ACCOUNT']['password'];
					$createAccount['customFormFields'] = $_SESSION['CHECKOUT']['CREATE_ACCOUNT']['customFields'];
				}
				else {
					$createAccount['autoCreated'] = 1;
				}

				// Handle saving of addresses for new customers
				foreach($this->getQuote()->getAllAddresses() as $address) {
					if($address->getSaveAddress()) {
						$customerAddress = $address->getAsArray();
						$customFields = $address->getCustomFields();
						if(!empty($customFields)) {
							$customerAddress['customFormFields'] = $customFields;

							// Shipping fields need to be mapped back to billing so they can be stored
							if($address->getType() == ISC_QUOTE_ADDRESS::TYPE_SHIPPING) {
								$newCustomFields = array();
								$map = $GLOBALS['ISC_CLASS_FORM']->mapAddressFieldList(FORMFIELDS_FORM_SHIPPING, array_keys($customFields));
								foreach($map as $oldId => $newId) {
									$newCustomFields[$newId] = $customFields[$oldId];
								}
								$customerAddress['customFormFields'] = $newCustomFields;
							}
						}

						$createAccount['addresses'][] = $customerAddress;
					}
				}

				$newOrder['extraInfo']['createAccount'] = $createAccount;
		}

		// Did they agree to signup to any mailing lists?
		if (isset($_POST['join_mailing_list'])) {
			$newOrder['extraInfo']['join_mailing_list'] = true;
		}

		if (isset($_POST['join_order_list'])) {
			$newOrder['extraInfo']['join_order_list'] = true;
		}

		if (isset($_POST['join_mailing_list']) || isset($_POST['join_order_list'])) {
			if (isset($_POST['mail_format_preference'])) {
				$newOrder['extraInfo']['mail_format_preference'] = (int)$_POST['mail_format_preference'];
			} else {
				$newOrder['extraInfo']['mail_format_preference'] = Interspire_EmailIntegration_Subscription::FORMAT_PREF_NONE;
			}
			$newOrder['extraInfo']['join_order_list'] = true;
		}


		if(isset($_POST['ordermessage'])) {
			$newOrder['ordermessage'] = $_POST['ordermessage'];
		} else {
			$newOrder['ordermessage'] = '';
		}

		$entity = new ISC_ENTITY_ORDER();
		$orderId = $entity->add($newOrder);

		// Failed to create the order
		if(!$orderId) {
			return false;
		}

		$order = getOrder($orderId);

		// Persist the pending order token as a cookie for 24 hours
		ISC_SetCookie("SHOP_ORDER_TOKEN", $order['ordtoken'], time() + (3600*24), true);
		$_COOKIE['SHOP_ORDER_TOKEN'] = $order['ordtoken'];

		// Redirecting to finish order page?
		if($redirectToFinishOrder) {
			return array(
				'redirectToFinishOrder' => true
			);
		}

		// Otherwise, the gateway want's to do something
		$orderData = LoadPendingOrdersByToken($order['ordtoken']);
		$provider->SetOrderData($orderData);

		// Is this an online payment provider? It would like to do something
		if($provider->GetPaymentType() == PAYMENT_PROVIDER_ONLINE || method_exists($provider, "ShowPaymentForm")) {
			// Call the checkout process for the selected provider
			if(method_exists($provider, "ShowPaymentForm")) {
				return array(
					'provider' => $provider,
					'showPaymentForm' => true
				);
			}
			else {
				return array(
					'provider' => $provider
				);
			}
		}
		// If an offline method, we throw them to the "Thank you for your order" page
		else {
			return array(
				'provider' => $provider
			);
		}
	}
示例#3
0
		/**
		 * Save the billing address for a customer checking out via express checkout.
		 */
		public function saveExpressCheckoutBillingAddress()
		{
			// If the customer is not logged in and guest checkout is enabled, then don't go any further
			if(!customerIsSignedIn() && !getConfig('GuestCheckoutEnabled') &&
				empty($_POST['createAccount'])) {
					$response = array(
						'status' => 0,
						'changeStep' => 'AccountDetails',
						'errorMessage' => getLang('GuestCheckoutDisabledError')
					);
					echo isc_json_encode($response);
					exit;
			}

			$addressDetails =  null;
			$shipToBilling = false;

			// If the customer isn't signed in then they've just entered an address that we need to validate
			if(isset($_REQUEST['BillingAddressType']) && $_REQUEST['BillingAddressType'] == 'new') {
				$errors = array();
				// An invalid address was entered, show the form again
				$addressDetails = getClass('ISC_CHECKOUT')->validateGuestCheckoutAddress('billing', $errors);
				if(!$addressDetails) {
					$response = array(
						'status' => 0,
						'changeStep' => 'BillingAddress',
						'errorMessage' => implode("\n", $errors)
					);
					echo isc_json_encode($response);
					exit;
				}

				// Make sure the email address isn't already in use if the customer is
				// creating a new account.
				// Plus if it's guess checkout and creation of account after the checkout process is enabled
				if(!customerIsSignedIn() && (!empty($_POST['createAccount']) || (getConfig('GuestCheckoutEnabled') && getConfig('GuestCheckoutCreateAccounts')))) {
					$emailField = $GLOBALS['ISC_CLASS_FORM']->getFormField(FORMFIELDS_FORM_ACCOUNT, '1', '', true);
					$email = $emailField->getValue();

					// Check that this email address isn't already in use by a customer
					$customer = GetClass('ISC_CUSTOMER');
					if($customer->AccountWithEmailAlreadyExists($email)) {
						$response = array(
							'status' => 0,
							'changeStep' => 'BillingAddress',
							'errorMessage' => getLang('CheckoutEmailAddressInUseAjax'),
							'focus' => '#'.$emailField->getFieldId(),
						);
						echo isc_json_encode($response);
						exit;
					}
				}

				if(!empty($_POST['ship_to_billing_new'])) {
					$shipToBilling = true;
				}
			}
			else {
				// We've just selected an address
				if(isset($_POST['sel_billing_address'])) {
					$addressDetails = (int)$_POST['sel_billing_address'];
				}

				if(!empty($_POST['ship_to_billing_existing'])) {
					$shipToBilling = true;
				}
			}

			// There was a problem saving the selected billing address
			if(!getClass('ISC_CHECKOUT')->setOrderBillingAddress($addressDetails)) {
				$response = array(
					'status' => 0,
					'changeStep' => 'BillingAddress',
					'errorMessage' => getLang('UnableSaveOrderBillingAddress'),
				);

				echo isc_json_encode($response);
				exit;
			}

			if(!empty($_POST['save_billing_address'])) {
				getCustomerQuote()->getBillingAddress()->setSaveAddress(true);
			}

			$completedSteps = array(
				array(
					'id' => 'BillingAddress',
					'message' => $this->getCheckoutAddressPreview(
						getCustomerQuote()->getBillingAddress()
					),
				)
			);

			// If creating an account, store the account creation fields
			unset($_SESSION['CHECKOUT']['CREATE_ACCOUNT']);
			if(!empty($_POST['createAccount'])) {
				$accountFields = $GLOBALS['ISC_CLASS_FORM']->getFormFields(FORMFIELDS_FORM_ACCOUNT, true);
				$accountSession = array(
					'customFields' => array()
				);
				foreach($accountFields as $fieldId => $formField) {
					if($formField->record['formfieldprivateid'] == 'Password') {
						$accountSession['password'] = $formField->getValue();
					}
					// Apart from the password, only interested in CUSTOM fields
					else if(!$formField->record['formfieldprivateid']) {
						$accountSession['customFields'][$fieldId] = $formField->getValue();
					}
				}
				$_SESSION['CHECKOUT']['CREATE_ACCOUNT'] = $accountSession;
			}

			// If a digital order, skip right to the order confirmation
			if(getCustomerQuote()->isDigital()) {
				$this->getExpressCheckoutConfirmation($completedSteps);
				exit;
			}

			// Otherwise, proceed with shipping

			// Shipping to the billing address so save it as well
			if($shipToBilling) {
				if(!getClass('ISC_CHECKOUT')->setOrderShippingAddress($addressDetails, true)) {
					$response = array(
						'status' => 0,
						'changeStep' => 'ShippingAddress',
						'errorMessage' => getLang('UnableSaveOrderShippingAddress'),
					);

					echo isc_json_encode($response);
					exit;
				}

				// If we're shipping to the billing address, then reload the shipping address
				// quote block, because it could contain updated values.
				$stepContent = array(array(
					'id' => 'ShippingAddress',
					'content' => getClass('ISC_CHECKOUT')->expressCheckoutChooseAddress('shipping', true),
				));
				$this->getExpressCheckoutShippers($completedSteps, $stepContent);
				exit;
			}

			$response = array(
				'status' => 1,
				'changeStep' => 'ShippingAddress',
				'completedSteps' => $completedSteps,
				'resetSteps' => true,
			);
			echo isc_json_encode($response);
			exit;
		}