File: D:/HostingSpaces/SBogers10/topswtw.komma.pro/app/KommaApp/Shop/Customers/CustomerService.php
<?php
namespace KommaApp\Shop\Customers;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Validator;
use Komma\Kms\Products\Models\Product;
use KommaApp\Shop\Customers\Customer;
use KommaApp\Shop\Checkout\CheckoutSession\CheckoutSession;
use KommaApp\Shop\FormValidation\UpdateCustomerForm;
use KommaApp\Shop\Orders\Order;
use KommaApp\Shop\FormValidation\CustomerForm;
use KommaApp\Shop\FormValidation\FullCustomerForm;
use KommaApp\Shop\FormValidation\LoginForm;
use KommaApp\Shop\Mailers\CustomerMailer;
use TijsVerkoyen\CssToInlineStyles\Exception;
class CustomerService
{
/**
* @var FullCustomerForm
*/
private $fullCustomerForm;
/**
* @var CustomerForm
*/
private $customerForm;
/**
* @var Customer
*/
private $customer;
/**
* @var CheckoutSession
*/
private $checkoutSession;
/**
* @var LoginForm
*/
private $loginForm;
private $customerMailer;
/**
* @param Customer $customer
* @param FullCustomerForm $fullCustomerForm
* @param UpdateCustomerForm $updateCustomerForm
* @param CustomerForm $customerForm
* @param LoginForm $loginForm
* @param CheckoutSession $checkoutSession
* @param CustomerMailer $customerMailer
*/
public function __construct(
Customer $customer,
FullCustomerForm $fullCustomerForm,
UpdateCustomerForm $updateCustomerForm,
CustomerForm $customerForm,
LoginForm $loginForm,
CheckoutSession $checkoutSession,
CustomerMailer $customerMailer
)
{
$this->fullCustomerForm = $fullCustomerForm;
$this->updateCustomerForm = $updateCustomerForm;
$this->customerForm = $customerForm;
$this->customer = $customer;
$this->checkoutSession = $checkoutSession;
$this->loginForm = $loginForm;
$this->customerMailer = $customerMailer;
}
public function updateCustomer(array $input, $page = 'customer')
{
//todo: this is not the way to go, the lang should be set in the contruct
//Translate the messages
$this->updateCustomerForm->translateMessages();
//Not logged in so new customer
if (!$currentCustomer = $this->getLoggedInCustomer()) return $this->storeNewCustomer($input);
// Validate the form
if (!$this->updateCustomerForm->isValid($input))
return \Redirect::back()
->withInput()
->withErrors($this->updateCustomerForm->errorMessages());
if (!$currentCustomer = $this->getLoggedInCustomer())
throw new \Exception('Update failed: Can\'t find current user.');
// Prepare input data for update
$input['username'] = $input['email'];
if ($input['company'] == '') $input['company_vat'] = '';
$input['title'] == 'mr' ? $input['gender'] = 'male' : $input['female'] = 'male';
if ($input['password'] == '') {
unset($input['password']);
} else {
$input['password'] = \Hash::make($input['password']);
}
// Save the customer
$currentCustomer->fill($input);
$currentCustomer->save();
return \Redirect::to(\Shop::getPageService()->page($page)->route);
}
public function storeNewCustomerFromToken($orderToken, $password)
{
$order = Order::where('order_token', $orderToken)->first();
$data = [
'username' => $order->invoice_email,
'email' => $order->invoice_email,
'password' => $password,
'password_confirmation' => $password,
'gender' => $order->invoice_gender,
'title' => $order->invoice_title,
'first_name' => $order->invoice_first_name,
'last_name' => $order->invoice_last_name,
'name_insertion' => $order->invoice_name_insertion,
'company' => $order->invoice_company,
'company_vat' => $order->invoice_company_vat,
'postal' => $order->invoice_postal,
'city' => $order->invoice_city,
'street' => $order->invoice_street,
'house_number' => $order->invoice_house_number,
'house_number_suffix' => $order->invoice_house_number_suffix,
'country' => $order->invoice_country,
'order_id' => $order->id,
];
return $this->storeNewCustomer($data);
}
/**
* @param array $input
*/
public function storeNewCustomer(array $input)
{
$input['username'] = $input['email'];
if (isset($input['company_vat'])) {
$input['company_vat'] = strtoupper($input['company_vat']);
$input['company_vat'] = preg_replace("/[^a-zA-Z0-9]/", "", $input['company_vat']);
}
//todo: this is not the wat to, the lang should be set in the contruct
//Translate the messages
$this->fullCustomerForm->translateMessages();
// Validate the form
if (!$this->fullCustomerForm->isValid($input)) {
return \Redirect::back()
->withInput()
->withErrors($this->fullCustomerForm->errorMessages());
}
//TODO: Als een klant registreert, niet activeert, registreert activeert, kan hij meerdere accounts de hetzelfde email hebben
if ($currentCustomer = Customer::where('email', $input['email'])->where('shop_id', \Shop::getId())->first()) {
if ($this->customer->active == 1) {
return \Lang::get('customer/create.error_user_exists');
}
$this->customer = $currentCustomer;
}
$input['shop_id'] = \Shop::getId();
$input['password'] = \Hash::make($input['password']);
$input['title'] == 'mr' ? $input['gender'] = 'male' : $input['female'] = 'male';
do { // Ensure that validate_token is unique
$input['validate_token'] = str_random(32);
} while (!$this->customer->where('validate_token', $input['validate_token'])->get());
$input['customer_number'] = Customer::getNewCustomerNumber();
// Create Customer
if (!$this->customer
->fill($input)
->save()
) {
// Todo: With error / flash message
return \Redirect::back()
->withInput();
};
if (isset($input['order_id'])) {
$order = Order::find($input['order_id']);
$order->customer()->associate($this->customer);
$order->save();
}
try {
$this->customerMailer->sendCustomerValidation($input);
} catch (\Exception $e) {
// Todo: With error / flash message
return \Redirect::back();
}
return \View::make( viewPrefix() . 'customers.sendValidation', ['email' => $input['email']]);
}
/**
* Duplicate of store new customer,
* I don't want to change the flow a week befor live
* Todo: fix this and make it in one function
*
* @param $input
* @return mixed
*
*/
public function streamLinedStoreNewCustomer($input)
{
//Clean up the VAt if it is set
if (isset($input['company_vat'])) {
$input['company_vat'] = strtoupper($input['company_vat']);
$input['company_vat'] = preg_replace("/[^a-zA-Z0-9]/", "", $input['company_vat']);
}
$input['shop_id'] = \Shop::getId();
if (isset($input['password'])) {
$input['password'] = \Hash::make($input['password']);
}
$input['title'] == 'mr' ? $input['gender'] = 'male' : $input['female'] = 'male';
do { // Ensure that validate_token is unique
$input['validate_token'] = str_random(32);
} while (!$this->customer->where('validate_token', $input['validate_token'])->get());
$input['customer_number'] = Customer::getNewCustomerNumber();
if (!isset($input['username'])) {
$input['username'] = $input['customer_number'];
}
$input['email'] = $input['customer_email'];
// Create Customer
if (!$this->customer
->fill($input)
->save()
) {
return false;
};
return $this->customer;
}
public function activateCustomer($token)
{
if ($this->customer->where('validate_token', $token)->first() && $this->customer->where('validate_token', $token)->first()->active == 1) {
return \View::make( viewPrefix() . 'customers.invalidLink');
}
if (!($customer = $this->customer->where('validate_token', $token)->first())) {
return \View::make( viewPrefix() . 'customers.invalidLink');
}
$customer->active = 1;
$customer->validate_token = null;
$customer->save();
return \View::make( viewPrefix() . 'customers.activated');
}
/**
* @param $input
*/
public function store($input)
{
if (isset($input['company_vat'])) {
$input['company_vat'] = strtoupper($input['company_vat']);
$input['company_vat'] = preg_replace("/[^a-zA-Z0-9]/", "", $input['company_vat']);
}
// Validate the form
if (!$this->customerForm->isValid($input)) {
return \Redirect::back()
->withErrors($this->customerForm->errorMessages());
}
// Create data array
$data = [];
// check for unique email
if ($currentCustomer = Customer::where('email', $input['email'])->where('shop_id', \Shop::getId())->first()) {
if ($this->customer->active == 1) {
return \Lang::get('customer/create.error_user_exists');
}
$this->customer = $currentCustomer;
}
// Get user data from the checkoutSession
/*
foreach($this->checkoutSession->customer()->get() as $invoiceField => $value)
{
$dbKey = str_replace('invoice-','',$invoiceField);
$dbKey = str_replace('-','_',$dbKey);
$data[$dbKey] = $value;
}
*/
// Other data
$data['shop_id'] = \Shop::getId();
$data['username'] = $data['email'];
$data['customer_number'] = Customer::getNewCustomerNumber();
// Set password
$this->customer->password = \Hash::make($input['password']);
$this->customer->remember_token = $data['remember_token'];
// Set validation token
do { // Ensure that validate_token is unique
$input['validate_token'] = str_random(32);
} while (!$this->customer->where('validate_token', $input['validate_token'])->get());
$data['validate_token'] = $this->customer->validate_token = $input['validate_token'];
// Mass assign data and save order
if (!$this->customer
->fill($data)
->save()
) {
// Todo message
// Bevestigings mail
return \Redirect::back();
};
if (isset($input['order_id'])) {
$order = Order::find(\Input::get('order_id'));
$order->customer()->associate($this->customer);
$order->save();
}
try {
$this->customerMailer->sendCustomerValidation($input);
} catch (\Exception $e) {
// Todo: With error / flash message
return \Redirect::back();
}
return \View::make( viewPrefix() . 'customers.sendValidation', ['email' => $input['email']]);
}
public function isLoggedIn()
{
return \Auth::customer()->check();
}
public function authorizeLogin($input, $pageSlug = 'customer', $anchor = '')
{
// Is the form valid
$messages = [
'email.exists' => \Lang::get('customer/login.email_exists'),
'email.activated' => \Lang::get('customer/login.email_activated'),
];
$this->loginForm->setMessages($messages);
if (!$this->loginForm->isValid($input)) {
return \Redirect::back()
->withInput($input)
->withErrors(['loginError' => \Lang::get('customer/login.loginError')]);
}
$input['active'] = 1;
$input['shop_id'] = \Shop::getId();
// Does the user exists
if (!\Auth::customer()->attempt($input)) {
return \Redirect::back()
->withInput($input)
->withErrors(['loginError' => \Lang::get('customer/login.loginError')]);
// Todo errors
}
// Redirect to checkout data
$this->checkoutSession->customer()->fillAfterLogin();
return \Redirect::to(\Shop::getPageService()->page($pageSlug)->route);
}
public function getLoggedInCustomer()
{
if (!$this->isLoggedIn()) {
return null;
}
return \Auth::customer()->get();
}
public function checkEmailAddress($email)
{
$customer = $this->customer
->where('email', $email)
->where('shop_id', \Shop::getId())
->where('active', 1)
->first();
if ($customer == null) return false;
return true;
}
public function getReminderService()
{
return $this->reminderService;
}
public function getCustomerByEmail($email)
{
$customer = Customer::
where('email', '=', $email)
->where('shop_id', '=', \Shop::getId())
->where('active', '=', 1)
->first();
return $customer;
}
/**
* In this Method we will activate the account based on an order token
* We'll check if there is an customer for the order and link this
* We are going to activate this account and set token to null
*
* @param $orderToken
* @param $password
* @return array|bool
*
*/
public function LinkAccountFromOrder($orderToken, $password)
{
//Load order by Token
if (!$order = \App::make('KommaApp\Shop\Orders\OrderService')->getOrderByToken($orderToken)) {
//No order found, return with error message
}
//load customer from order
if (!$customer = $order->customer) {
//No customer found, this is normaly not possible todo: create customer from token?
return ['error' => 'Oops Something went wrong'];
}
$this->activateCustomerAndSetPassword($customer, $password);
return true;
}
/**
* In this Method we will activate the account based on an order token
* We'll check if there is an customer for the order and link this
* We are going to activate this account and set token to null
*
* @param $orderToken
* @param $password
* @return array|bool
*
*/
public function linkAccountFromMaintenanceOrder($maintenanceOrder, $password)
{
//Load the customer from the order
if (!$customer = $maintenanceOrder->customer) {
//No customer found, this is normally not possible
return ['error' => 'Oops Something went wrong'];
}
//Activate the customer and set the password
$this->activateCustomerAndSetPassword($customer, $password);
return true;
}
public function activateCustomerAndSetPassword($customer, $password)
{
//Set password
$customer->password = \Hash::make($password);
//Set username, use the customer email (is our default)
$customer->username = $customer->email;
//set account active
$customer->active = 1;
//Set validate_token to null
$customer->validate_token = null;
//save the customer
$customer->save();
}
public function validateCustomerForMaintenance()
{
$customerInput = $this->prepareMaintenanceCustomerInput();
//Edit the validation rules
unset($this->fullCustomerForm->rules['company']);
unset($this->fullCustomerForm->rules['username']);
unset($this->fullCustomerForm->rules['password']);
unset($this->fullCustomerForm->rules['email']);
unset($this->fullCustomerForm->rules['company_vat']);
$this->fullCustomerForm->rules['maintenance_type'] = 'required';
$this->fullCustomerForm->rules['telephone'] = 'required';
$this->fullCustomerForm->rules['customer_email'] = 'required|email';
$this->fullCustomerForm->rules['agree'] = 'required';
$validator = Validator::make($customerInput, $this->fullCustomerForm->rules);
if ($validator->fails()) {
return \Redirect::back()->withErrors($validator)->withInput();
}
return false;
}
public function prepareMaintenanceCustomerInput()
{
$customerInput = \Input::all();
$customerInput['company'] = null;
$customerInput['company_vat'] = null;
return $customerInput;
}
public function validateLogin($input)
{
$rules = [
'email' => 'required|exists:customers,email|activated',
'password' => 'required',
];
$messages = [
'email.exists' => \Lang::get('customer/login/email.exists'),
'email.activated' => \Lang::get('customer/login/email.activated'),
];
$validator = Validator::make($input, $rules, $messages);
if ($validator->fails()) return \Redirect::back()->withInput()->withErrors($validator);
}
public function mergeDuplicateCustomers()
{
set_time_limit(0);
// $mergeOnAttributes = ['email', 'postal'];
$mergeOnAttributes = ['email'];
$duplicateUsersArray = $this->findDuplicateCustomersByCertainAttributes($mergeOnAttributes);
$total = count($duplicateUsersArray);
$count = 1;
foreach ($duplicateUsersArray as $duplicateUserReference => $duplicateUserIds) {
$customerIdToMergeInto = array_shift($duplicateUserIds);
$customerToMergeInto = Customer::find($customerIdToMergeInto);
$customersToMerge = Customer::whereIn('id', $duplicateUserIds)->get();
echo '<br>Merging customers with id\'s "'.implode(', ', $duplicateUserIds).'" into user with id "'.$customerIdToMergeInto.'"<br/>';
echo 'Merging orders<br>';
$this->moveCustomersOrdersToOtherCustomer($customersToMerge, $customerToMergeInto);
echo 'Merging maintenance orders<br>';
$this->moveCustomersMaintenanceOrdersToOtherCustomer($customersToMerge, $customerToMergeInto);
echo 'Merging attributes<br>';
$this->mergeCustomersIntoCustomer($customersToMerge, $customerToMergeInto);
echo 'Customer '.$count.' of '.$total.' done processing.<br><br>';
$count++;
}
echo "done";
}
/**
* Put a string into a predictable state
*
* @param string $value
* @return string
*/
public function normalize($value) {
$value = trim($value);
$value = str_replace(' ', '', $value);
$value = strtolower($value);
return $value;
}
/**
* Returns an array of arrays that contain duplicate customers ids. The ids are sorted descending.
*
* @param array $duplicateAttributes. The attributes to search duplicates with. For example: [email, postal]
* @return null
*/
public function findDuplicateCustomersByCertainAttributes($duplicateAttributes) //gerrit@altac.nl
{
$columnNames = $duplicateAttributes;
if(!in_array('id', $columnNames, true)) $columnNames[] = 'id';
$customers = Customer::orderBy('id', 'DESC')->get($columnNames);
$duplicateCustomers = [];
$customers->each(function($customer) use(&$duplicateCustomers, $duplicateAttributes) {
$attributeValues = [];
foreach ($duplicateAttributes as $duplicateAttribute) $attributeValues[] = $customer->$duplicateAttribute;
$currentCustomerAttributesString = $this->getAttributesString($attributeValues);
if(!isset($duplicateCustomers[$currentCustomerAttributesString])) $duplicateCustomers[$currentCustomerAttributesString] = [];
$duplicateCustomers[$currentCustomerAttributesString][] = $customer->id;
});
foreach($duplicateCustomers as $key => $duplicateCustomerIds)
{
if(count($duplicateCustomerIds) <= 1) unset($duplicateCustomers[$key]);
}
return $duplicateCustomers;
}
/**
* converts an array of values to a string. Formatting the values in a way they are easy to compare.
*
* @param $attributeValues
* @return string
*/
private function getAttributesString($attributeValues)
{
foreach($attributeValues as $index => $attributeValue)
{
$attributeValues[$index] = $this->normalize($attributeValue);
}
return implode('|', $attributeValues);
}
/**
* Gets an array of attribute names and values for a customer and returns a customer if it exists. null otherwise
*
* @param $attributesAndValues
* @return null|Customer
*/
public function getCustomerIfExists($attributesAndValues)
{
$columnNames = array_keys($attributesAndValues);
if(!in_array('id', $columnNames, true)) $columnNames[] = 'id';
$customers = Customer::orderBy('id', 'DESC')->get($columnNames);
foreach($customers as $customer)
{
$found = true;
foreach($attributesAndValues as $expectedAttribute => $expectedValue)
{
if($expectedAttribute == "postal") {
$expectedValue = $this->normalize($expectedValue);
$customer->postal = $this->normalize($customer->postal);
}
if($customer->$expectedAttribute !== $expectedValue) {
$found = false;
break;
}
}
if($found) return $customer;
}
return null;
}
/**
* Merges a collection of customers into a customer and deletes the mergedCustomers if the last parameter is set to tree
*
* @param Collection $customers
* @param Customer $customerToMergeInto
* @param bool $deleteMergedCustomers
* @return string $log string
*/
public function mergeCustomersIntoCustomer($customers, $customerToMergeInto, $deleteMergedCustomers = true)
{
$customers->each(function($customerToMerge) use (&$customerToMergeInto, &$log, $deleteMergedCustomers) {
$attributes = $customerToMerge->getAttributes();
$excludedAttributes = ['password', 'active','created_at', 'updated_at'];
foreach($attributes as $attributeName => $value)
{
//Merge attributes
if(in_array($attributeName, $excludedAttributes, true)) break;
if($customerToMerge->$attributeName !== '' && $customerToMerge->$attributeName !== null && ($customerToMergeInto->$attributeName == "" || $customerToMergeInto->$attributeName == null)) {
$customerToMergeInto->$attributeName = $value;
echo 'Merged "'.$attributeName.'" value "'.$value.'" of customer "'.$customerToMerge->id.'" into customer with id: '.$customerToMergeInto->id.'<br>';
}
}
if($deleteMergedCustomers) $customerToMerge->delete();
});
$customerToMergeInto->save();
}
public function moveCustomersOrdersToOtherCustomer($sourceCustomerCollection, $customerToMergeInto)
{
$sourceCustomerCollection->each(function($customerToMerge) use (&$customerToMergeInto, &$log) {
/** @var Customer $customerToMerge */
/** @var Customer $customerToMergeInto */
$orders = $customerToMerge->orders()->get(['id']);
$orders->each(function ($order) use (&$customerToMergeInto, &$customerToMerge, &$log) {
/** @var Order $order */
echo 'Moving order with id "'.$order->id.'" from customer with id "'.$customerToMerge->id.'" to customer with id "'.$customerToMergeInto->id.'"<br/>';
$order->customer()->associate($customerToMergeInto);
$order->save();
});
});
}
public function moveCustomersMaintenanceOrdersToOtherCustomer($sourceCustomerCollection, $customerToMergeInto)
{
$sourceCustomerCollection->each(function($customerToMerge) use (&$customerToMergeInto, &$log) {
/** @var Customer $customerToMerge */
/** @var Customer $customerToMergeInto */
$orders = $customerToMerge->maintenanceOrders()->get(['id']);
$orders->each(function ($order) use (&$customerToMergeInto, &$customerToMerge, &$log) {
/** @var Order $order */
echo 'Moving maintenanceOrder with id "'.$order->id.'" from customer with id "'.$customerToMerge->id.'" to customer with id "'.$customerToMergeInto->id.'"<br/>';
$order->customer()->associate($customerToMergeInto);
$order->save();
});
});
}
}