/** * Insert/Update the node with the response record * * Method will insert/update the node with the response record. Its made public so order syncing can you it also * * @access public * @param array $responseData The reponse data from QB * @param array $nodeData The optional node data array. If set then update, else insert * @return int The new or updtaed node ID on success, FALSE on error */ public function syncResponseRecord2Store($responseData, $nodeData=false) { static $_cacheHTTPHost = null; /** * Firstly, don't import if this has a customer type as it is a guest checkout customer */ if ($this->accounting->isCustomerGuestCheckout($responseData) || $this->accounting->isCustomerParent($responseData)) { return false; } /** * Set the fillin email address domain name */ if (is_null($_cacheHTTPHost)) { $parts = parse_url(GetConfig("ShopPath")); if (!$parts || !isset($parts["host"]) || trim($parts["host"]) == '') { if (function_exists("apache_getenv")) { $_cacheHTTPHost = @apache_getenv("HTTP_HOST"); } if (!$_cacheHTTPHost) { $_cacheHTTPHost = @$_SERVER["HTTP_HOST"]; } } else { $_cacheHTTPHost = $parts["host"]; } } if (!is_array($responseData)) { $xargs = func_get_args(); throw new QBException("Invalid arguments when syncing customer record from QB", $xargs); } /** * Check to see if this is a customer short name. Only do this if $nodeData is empty */ if (!is_array($nodeData) && $this->accounting->isCustomerShortName($responseData["Name"])) { $customerParts = $this->accounting->qbCustomerShortName2CustomerNameId($responseData["Name"]); if (is_array($customerParts) && isset($customerParts["customerid"]) && isId($customerParts["customerid"])) { $nodeData = $this->entityAPI->get($customerParts["customerid"]); } } /** * We need to fill in the blanks with our node data if we have one */ if (is_array($nodeData)) { $map = array( "custconfirstname" => "FirstName", "custconlastname" => "LastName", "custconemail" => "Email", "custconphone" => "Phone", "custconcompany" => "CompanyName" ); foreach ($map as $nodeKey => $responseKey) { if (!array_key_exists($responseKey, $responseData) || trim($responseData[$responseKey]) == '') { $responseData[$responseKey] = $nodeData[$nodeKey]; } } } /** * Create a fillin for the email address if it is not set */ if (!array_key_exists("Email", $responseData) || trim($responseData["Email"]) == '' || !is_email_address($responseData["Email"])) { $emailAddress = self::emailPreFixFillin . mt_rand(10000, 99999) . "@" . $_cacheHTTPHost; /** * Else check to see if it is unique */ } else if (!$this->checkEmailIsUnique($responseData["Email"], $nodeData)) { $emailAddress = self::emailPreFixFillin . mt_rand(10000, 99999) . "@" . $_cacheHTTPHost; $this->accounting->logWarning("The QuickBooks customer '" . $responseData["FirstName"] . " " . $responseData["LastName"] . "' has a non-unique email address. Changing their email address to " . $emailAddress); /** * Its all cool */ } else { $emailAddress = $responseData["Email"]; } /** * If the first or last name are 25 chanracters then use the original values. This is because QBWC puts a 25 character * limit on those fields and will cut it off if it is exceeded, so best to be safe than sorry */ if (is_array($nodeData)) { if (strlen($responseData["FirstName"]) == 25) { $this->accounting->logWarning("The QuickBooks customer '" . $responseData["FirstName"] . " " . $responseData["LastName"] . "' has had their first name truncated. Defaulting to the original first name of '" . $nodeData["custconfirstname"] . "'"); $responseData["FirstName"] = $nodeData["custconfirstname"]; } if (strlen($responseData["LastName"]) == 25) { $this->accounting->logWarning("The QuickBooks customer '" . $responseData["FirstName"] . " " . $responseData["LastName"] . "' has had their last name truncated. Defaulting to the original last name of '" . $nodeData["custconlastname"] . "'"); $responseData["LastName"] = $nodeData["custconlastname"]; } } $savedata = array( "custconfirstname" => @$responseData["FirstName"], "custconlastname" => @$responseData["LastName"], "custconemail" => $emailAddress, "custconphone" => @$responseData["Phone"], "custconcompany" => @$responseData["CompanyName"] ); /** * The addresses */ $addresses = array(); foreach (array("BillAddress", "ShipAddress") as $addressType) { if (!array_key_exists($addressType, $responseData) || !is_array($responseData[$addressType])) { continue; } if (trim(@$responseData[$addressType]["Addr1"]) !== '') { /** * Firstly lets check to see if we already have this addressd */ $shipId = ''; if (is_array($nodeData) && isset($nodeData["addresses"]) && is_array($nodeData["addresses"])) { foreach ($nodeData["addresses"] as $address) { if (isc_strtolower(trim($address["shipaddress1"])) == isc_strtolower(trim(@$responseData[$addressType]["Addr1"]))) { $shipId = $address["shipid"]; /** * Now fill in the blanks */ $map = array( "shipaddress1" => "Addr1", "shipaddress2" => "Addr2", "shipcity" => "City", "shipstate" => "State", "shipzip" => "PostalCode", "shipcountry" => "Country" ); foreach ($map as $nodeKey => $responseKey) { if (!array_key_exists($responseKey, $responseData[$addressType]) || trim($responseData[$addressType][$responseKey]) == '') { $responseData[$addressType][$responseKey] = $address[$nodeKey]; } } } } } /** * Find the country and state IDs */ $countryId = $this->getCountryId(@$responseData[$addressType]["Country"], $properCountryName); $stateId = ''; if (isId($countryId) && trim(@$responseData[$addressType]["State"]) !== '') { $responseData[$addressType]["Country"] = $properCountryName; $stateId = $this->getStateId($responseData[$addressType]["State"], $countryId, $properStateName); if (!isId($stateId)) { $stateId = ''; } else if (trim($properStateName) !== '') { $responseData[$addressType]["State"] = $properStateName; } } else { $countryId = ''; } $addresses[] = array( "shipid" => $shipId, "shipfirstname" => @$responseData["FirstName"], "shiplastname" => @$responseData["LastName"], "shipcompany" => @$responseData["CompanyName"], "shipaddress1" => @$responseData[$addressType]["Addr1"], "shipaddress2" => @$responseData[$addressType]["Addr2"], "shipcity" => @$responseData[$addressType]["City"], "shipstate" => @$responseData[$addressType]["State"], "shipzip" => @$responseData[$addressType]["PostalCode"], "shipcountry" => @$responseData[$addressType]["Country"], "shipphone" => @$responseData["Phone"], "shipstateid" => $stateId, "shipcountryid" => $countryId ); /** * Set something to each field if it is NULL as the database can't handle NULL values for this schema */ foreach ($addresses[count($addresses)-1] as $addKey => $addVal) { if (is_null($addVal)) { $addresses[count($addresses)-1][$addKey] = ''; } } } } if (!empty($addresses)) { $savedata["addresses"] = $addresses; } $this->accounting->logDebug("The formatted customer data from QB", array("Savedata" => $savedata, "Response" => $responseData)); /** * Got all the info, now create the database record */ $customerId = false; if (is_array($nodeData) && array_key_exists("customerid", $nodeData) && isId($nodeData["customerid"])) { $savedata["customerid"] = $nodeData["customerid"]; if ($this->entityAPI->edit($savedata, false, true) !== false) { $customerId = $nodeData["customerid"]; } } else { $savedata["password"] = Interspire_String::generateReadablePassword(); $customerId = $this->entityAPI->add($savedata); } if (!isId($customerId)) { throw new QBException("Cannot save customer record with data from QB", array("SaveData" => $savedata, "NodeData" => $nodeData, "DB" => $GLOBALS["ISC_CLASS_DB"]->GetError())); } return $customerId; }
/** * Save the new password for the customer's account (via link in reset password email) */ private function SaveNewPassword() { if (isset($_GET['c']) && isset($_GET['t'])) { $customerId = (int)isc_html_escape($_GET['c']); $customerHash = isc_html_escape($_GET['t']); $query = "SELECT * FROM [|PREFIX|]customers WHERE customerid=" . $customerId; $result = $GLOBALS['ISC_CLASS_DB']->Query($query); $customer = $GLOBALS['ISC_CLASS_DB']->Fetch($result); // Can't find them in the database if (!isId($customerId) || !$customer) { return $this->ResetPassword("invalid_link", 1); } // Also check to see if our salted string matches this customer if (!$this->checkCustomerHash($customerHash, $customer['customerpasswordresettoken'], $customerId)) { return $this->ResetPassword("invalid_link", 1); } // OK, all the arguments are cool. Now we generate a password for them $password = Interspire_String::generateReadablePassword(); $updateData = array( 'customerpasswordresettoken' => '', 'customerpasswordresetemail' => '', ); if ($GLOBALS['ISC_CLASS_DB']->UpdateQuery('customers', $updateData, 'customerid=' . $customerId) === false) { return $this->ResetPassword("internal_error", 1); } $entity = new ISC_ENTITY_CUSTOMER(); $entity->updatePassword($customerId, $password); // Send the email $store_name = GetConfig('StoreName'); $email_message = sprintf(GetLang('ForgotPasswordEmailConfirmed'), $store_name, $password); // Create a new email API object to send the email require_once(ISC_BASE_PATH . "/lib/email.php"); $obj_email = GetEmailClass(); $obj_email->Set('CharSet', GetConfig('CharacterSet')); $obj_email->From(GetConfig('OrderEmail'), $store_name); $obj_email->Set("Subject", sprintf(GetLang('ForgotPasswordEmailConfirmedSubject'), $store_name)); $obj_email->AddBody("html", $email_message); $obj_email->AddRecipient($customer['customerpasswordresetemail'], "", "h"); $email_result = $obj_email->Send(); if ($email_result['success']) { return $this->ShowLoginPage(sprintf(GetLang('ForgotPasswordChanged'), $customer['customerpasswordresetemail']), 0, true); } else { return $this->ResetPassword("internal_error", 1); } } else { $this->ShowLoginPage(); } }