Skip to content

Instantly share code, notes, and snippets.

@caovillanueva
Created March 2, 2023 14:48
Show Gist options
  • Save caovillanueva/cd9218814cd249f158d5692565e8c43b to your computer and use it in GitHub Desktop.
Save caovillanueva/cd9218814cd249f158d5692565e8c43b to your computer and use it in GitHub Desktop.
[PS17 Add extra fields for costumers in 1.7.8] Display fields in front and backend 100%Symphony for ver. 1.7.8. Do not use this tutorial with previous versions. #ps17
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
*/
use PrestaShop\PrestaShop\Adapter\CoreException;
use PrestaShop\PrestaShop\Adapter\ServiceLocator;
/***
* Class CustomerCore
*/
class Customer extends CustomerCore
{
public $retail;
public $addressC;
public $cityC;
public $stateC;
public $countryC;
public $zipC;
public $phoneC;
public $mobileC;
public $aboutus;
public $extrainfo;
/**
* @see ObjectModel::$definition
*/
public static $definition = [
'table' => 'customer',
'primary' => 'id_customer',
'fields' => [
'secure_key' => ['type' => self::TYPE_STRING, 'validate' => 'isMd5', 'copy_post' => false],
'lastname' => ['type' => self::TYPE_STRING, 'validate' => 'isCustomerName', 'required' => true, 'size' => 255],
'firstname' => ['type' => self::TYPE_STRING, 'validate' => 'isCustomerName', 'required' => true, 'size' => 255],
'email' => ['type' => self::TYPE_STRING, 'validate' => 'isEmail', 'required' => true, 'size' => 255],
'passwd' => ['type' => self::TYPE_STRING, 'validate' => 'isPasswd', 'required' => true, 'size' => 255],
'last_passwd_gen' => ['type' => self::TYPE_STRING, 'copy_post' => false],
'id_gender' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedId'],
'birthday' => ['type' => self::TYPE_DATE, 'validate' => 'isBirthDate'],
'newsletter' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool'],
'newsletter_date_add' => ['type' => self::TYPE_DATE, 'copy_post' => false],
'ip_registration_newsletter' => ['type' => self::TYPE_STRING, 'copy_post' => false],
'optin' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool'],
'website' => ['type' => self::TYPE_STRING, 'validate' => 'isUrl'],
'company' => ['type' => self::TYPE_STRING, 'validate' => 'isGenericName'],
//MM_ new fields
'retail' => array('type' => self::TYPE_STRING, 'validate' => 'isGenericName'),
'addressC' => array('type' => self::TYPE_STRING,),
'aboutus' => array('type' => self::TYPE_STRING,),
'extrainfo' => array('type' => self::TYPE_STRING,),
'stateC' => array('type' => self::TYPE_STRING,),
'countryC' => array('type' => self::TYPE_STRING,),
'zipC' => array('type' => self::TYPE_STRING,),
'cityC' => array('type' => self::TYPE_STRING,),
'phoneC' => array('type' => self::TYPE_STRING,),
'mobileC' => array('type' => self::TYPE_STRING,),
//End mm_
'siret' => ['type' => self::TYPE_STRING, 'validate' => 'isGenericName'],
'ape' => ['type' => self::TYPE_STRING, 'validate' => 'isApe'],
'outstanding_allow_amount' => ['type' => self::TYPE_FLOAT, 'validate' => 'isFloat', 'copy_post' => false],
'show_public_prices' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool', 'copy_post' => false],
'id_risk' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedInt', 'copy_post' => false],
'max_payment_days' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedInt', 'copy_post' => false],
'active' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool', 'copy_post' => false],
'deleted' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool', 'copy_post' => false],
'note' => ['type' => self::TYPE_HTML, 'size' => 65000, 'copy_post' => false],
'is_guest' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool', 'copy_post' => false],
'id_shop' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'copy_post' => false],
'id_shop_group' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'copy_post' => false],
'id_default_group' => ['type' => self::TYPE_INT, 'copy_post' => false],
'id_lang' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'copy_post' => false],
'date_add' => ['type' => self::TYPE_DATE, 'validate' => 'isDate', 'copy_post' => false],
'date_upd' => ['type' => self::TYPE_DATE, 'validate' => 'isDate', 'copy_post' => false],
'reset_password_token' => ['type' => self::TYPE_STRING, 'validate' => 'isSha1', 'size' => 40, 'copy_post' => false],
'reset_password_validity' => ['type' => self::TYPE_DATE, 'validate' => 'isDateOrNull', 'copy_post' => false],
],
];
}
<?php
/**
* @Override CustomerFormatter
*/
use Symfony\Component\Translation\TranslatorInterface;
class CustomerFormatter extends CustomerFormatterCore
{
private $translator;
private $language;
private $ask_for_birthdate = true;
private $ask_for_partner_optin = true;
private $partner_optin_is_required = true;
private $ask_for_password = true;
private $password_is_required = true;
private $ask_for_new_password = false;
public function __construct(
TranslatorInterface $translator,
Language $language
) {
$this->translator = $translator;
$this->language = $language;
}
public function setAskForBirthdate($ask_for_birthdate)
{
$this->ask_for_birthdate = $ask_for_birthdate;
return $this;
}
public function setAskForPartnerOptin($ask_for_partner_optin)
{
$this->ask_for_partner_optin = $ask_for_partner_optin;
return $this;
}
public function setPartnerOptinRequired($partner_optin_is_required)
{
$this->partner_optin_is_required = $partner_optin_is_required;
return $this;
}
public function setAskForPassword($ask_for_password)
{
$this->ask_for_password = $ask_for_password;
return $this;
}
public function setAskForNewPassword($ask_for_new_password)
{
$this->ask_for_new_password = $ask_for_new_password;
return $this;
}
public function setPasswordRequired($password_is_required)
{
$this->password_is_required = $password_is_required;
return $this;
}
public function getFormat()
{
$format = [];
$genders = Gender::getGenders($this->language->id);
if ($genders->count() > 0) {
$genderField = (new FormField())
->setName('id_gender')
->setType('radio-buttons')
->setLabel(
$this->translator->trans(
'Social title',
[],
'Shop.Forms.Labels'
)
);
foreach ($genders as $gender) {
$genderField->addAvailableValue($gender->id, $gender->name);
}
$format[$genderField->getName()] = $genderField;
}
$format['firstname'] = (new FormField())
->setName('firstname')
->setLabel(
$this->translator->trans(
'First name',
[],
'Shop.Forms.Labels'
)
)
->setRequired(true)
->addAvailableValue(
'comment',
$this->translator->trans('Only letters and the dot (.) character, followed by a space, are allowed.', [], 'Shop.Forms.Help')
);
$format['lastname'] = (new FormField())
->setName('lastname')
->setLabel(
$this->translator->trans(
'Last name',
[],
'Shop.Forms.Labels'
)
)
->setRequired(true)
->addAvailableValue(
'comment',
$this->translator->trans('Only letters and the dot (.) character, followed by a space, are allowed.', [], 'Shop.Forms.Help')
);
if (Configuration::get('PS_B2B_ENABLE')) {
$format['company'] = (new FormField())
->setName('company')
->setType('text')
->setLabel($this->translator->trans(
'Company',
[],
'Shop.Forms.Labels'
));
$format['siret'] = (new FormField())
->setName('siret')
->setType('text')
->setLabel($this->translator->trans(
// Please localize this string with the applicable registration number type in your country. For example : "SIRET" in France and "Código fiscal" in Spain.
'Identification number',
[],
'Shop.Forms.Labels'
));
}
$format['email'] = (new FormField())
->setName('email')
->setType('email')
->setLabel(
$this->translator->trans(
'Email',
[],
'Shop.Forms.Labels'
)
)
->setRequired(true);
if ($this->ask_for_password) {
$format['password'] = (new FormField())
->setName('password')
->setType('password')
->setLabel(
$this->translator->trans(
'Password',
[],
'Shop.Forms.Labels'
)
)
->setRequired($this->password_is_required);
}
if ($this->ask_for_new_password) {
$format['new_password'] = (new FormField())
->setName('new_password')
->setType('password')
->setLabel(
$this->translator->trans(
'New password',
[],
'Shop.Forms.Labels'
)
);
}
//////////////////////////////////////////////
//MM_ New
//Adding extrafields
//Unfortunatelly the translation feature in backend does not work well. We need to put conditionals here to make it work.
//////////////////////////////////////////////
//Translations (the native translations does not work well anymore, use this instead.)
if ($this->language->id == 1){//EN
$Op_TypeC = ["I'm residential customer",
"I'm a residential builder or contractor",
"I'm an architect or designer",
"I'm a commercial general contractor",
"Other"];
$Op_Company = 'Company';
$Op_State = 'State / Province';
$Op_Zip = 'Zip / Postal Code';
$Op_How = 'How did you hear about us?';
$Op_mobileC = 'Cell Phone';
$Op_website = 'Website';
$Op_HowOP = ["Online Search","Online Ads","Print Ads","Word of mouth","i'm already a client","Other"];
$Op_ExtraIn = 'Additional Information';
}
if ($this->language->id == 2){//FR
$Op_TypeC = ['Je suis un client résidentiel',
'Je suis un constructeur résidentiel ou un entrepreneur',
'Je suis architecte ou designer',
'Je suis un entrepreneur général commercial',
'Autre'];
$Op_Company = 'Entreprise';
$Op_State = 'Province';
$Op_Zip = 'Code postal';
$Op_How = 'Comment avez-vous entendu parler de nous?';
$Op_mobileC = 'Cellulaire';
$Op_website = 'Site Web';
$Op_HowOP = ["Recherche en ligne","Annonces en ligne","Annonces imprimées (magazines, journaux, etc.)","Bouche à oreille","Je suis déjà client","Autre"];
$Op_ExtraIn = 'Information additionnelle';
}
$format['retail'] = (new FormField)
->setName('retail')
->setType('select')
->setLabel(
$this->translator->trans(
'Client type', [], 'Shop.Forms.MM'
)
)
->addAvailableValue('Residential customer', $Op_TypeC[0])
->addAvailableValue('Residential builder', $Op_TypeC[1])
->addAvailableValue('Architect', $Op_TypeC[2])
->addAvailableValue('General contractor', $Op_TypeC[3])
->addAvailableValue('other', $Op_TypeC[4])
->setRequired(true)
;
$format['company'] = (new FormField)
->setName('company')
->setLabel(
$this->translator->trans(
$Op_Company, [], 'Shop.Forms.Labels'
)
)
->setRequired(false)
;
$format['addressC'] = (new FormField)
->setName('addressC')
->setLabel(
$this->translator->trans(
'Address', [], 'Shop.Forms.Labels'
)
)
->setRequired(true)
;
$format['cityC'] = (new FormField)
->setName('cityC')
->setLabel(
$this->translator->trans(
'City', [], 'Shop.Forms.Labels'
)
)
->setRequired(true)
;
$format['countryC'] = (new FormField)
->setName('countryC')
->setType('countrySelect')
->setLabel(
$this->translator->trans(
'Country', [], 'Shop.Forms.Labels'
)
)
->addAvailableValue('Canada', $this->translator->trans(
'Canada', [], 'Shop.Forms.Labels'
))
->addAvailableValue('United States', $this->translator->trans(
'United States', [], 'Shop.Forms.Labels'
))
->setRequired(true)
;
$format['stateC'] = (new FormField)
->setName('stateC')
->setLabel(
$this->translator->trans(
$Op_State,[],'Shop.Forms.Labels'
)
)
->setRequired(true)
;
$format['zipC'] = (new FormField)
->setName('zipC')
->setLabel(
$this->translator->trans(
$Op_Zip,[],'Shop.Forms.Labels'
)
)
->setRequired(true)
;
$format['phoneC'] = (new FormField)
->setName('phoneC')
->setType('text')
->setLabel(
$this->translator->trans(
'Phone', [], 'Shop.Forms.Labels'
)
)
->setRequired(true)
;
$format['mobileC'] = (new FormField)
->setName('mobileC')
->setType('text')
->setLabel($Op_mobileC)
->setRequired(false)
;
$format['website'] = (new FormField)
->setName('website')
->setType("UrlType")
->setLabel($Op_website)
->setRequired(false)
;
$format['aboutus'] = (new FormField)
->setName('aboutus')
->setType('select')
->setLabel($Op_How)
->addAvailableValue('Online Search',$Op_HowOP[0])
->addAvailableValue('Online Ads',$Op_HowOP[1])
->addAvailableValue('Print Ads',$Op_HowOP[2])
->addAvailableValue('Word of mouth',$Op_HowOP[3])
->addAvailableValue("i'm already a client",$Op_HowOP[4])
->addAvailableValue("Other",$Op_HowOP[5])
->setRequired(true)
;
$format['extrainfo'] = (new FormField)
->setName('extrainfo')
->setType('textarea')
->setLabel($Op_ExtraIn)
->setRequired(false)
;
////////////////////////////////////////////////////////
//End MM_
////////////////////////////////////////////////////////
if ($this->ask_for_birthdate) {
$format['birthday'] = (new FormField())
->setName('birthday')
->setType('text')
->setLabel(
$this->translator->trans(
'Birthdate',
[],
'Shop.Forms.Labels'
)
)
->addAvailableValue('placeholder', Tools::getDateFormat())
->addAvailableValue(
'comment',
$this->translator->trans('(E.g.: %date_format%)', ['%date_format%' => Tools::formatDateStr('31 May 1970')], 'Shop.Forms.Help')
);
}
if ($this->ask_for_partner_optin) {
$format['optin'] = (new FormField())
->setName('optin')
->setType('checkbox')
->setLabel(
$this->translator->trans(
'Receive offers from our partners',
[],
'Shop.Theme.Customeraccount'
)
)
->setRequired($this->partner_optin_is_required);
}
// ToDo, replace the hook exec with HookFinder when the associated PR will be merged
$additionalCustomerFormFields = Hook::exec('additionalCustomerFormFields', ['fields' => &$format], null, true);
if (is_array($additionalCustomerFormFields)) {
foreach ($additionalCustomerFormFields as $moduleName => $additionnalFormFields) {
if (!is_array($additionnalFormFields)) {
continue;
}
foreach ($additionnalFormFields as $formField) {
$formField->moduleName = $moduleName;
$format[$moduleName . '_' . $formField->getName()] = $formField;
}
}
}
// TODO: TVA etc.?
return $this->addConstraints($format);
}
private function addConstraints(array $format)
{
$constraints = Customer::$definition['fields'];
foreach ($format as $field) {
if (!empty($constraints[$field->getName()]['validate'])) {
$field->addConstraint(
$constraints[$field->getName()]['validate']
);
}
}
return $format;
}
}
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
*
*/
use PrestaShop\PrestaShop\Core\Crypto\Hashing as Crypto;
use Symfony\Component\Translation\TranslatorInterface;
class CustomerPersister extends CustomerPersisterCore
{
private $errors = [];
private $context;
private $crypto;
private $translator;
private $guest_allowed;
public function __construct(
Context $context,
Crypto $crypto,
TranslatorInterface $translator,
$guest_allowed
) {
$this->context = $context;
$this->crypto = $crypto;
$this->translator = $translator;
$this->guest_allowed = $guest_allowed;
}
public function getErrors()
{
return $this->errors;
}
public function save(Customer $customer, $clearTextPassword, $newPassword = '', $passwordRequired = true)
{
if ($customer->id) {
return $this->update($customer, $clearTextPassword, $newPassword, $passwordRequired);
}
return $this->create($customer, $clearTextPassword);
}
private function update(Customer $customer, $clearTextPassword, $newPassword, $passwordRequired = true)
{
if (!$customer->is_guest && $passwordRequired && !$this->crypto->checkHash(
$clearTextPassword,
$customer->passwd,
_COOKIE_KEY_
)) {
$msg = $this->translator->trans(
'Invalid email/password combination',
[],
'Shop.Notifications.Error'
);
$this->errors['email'][] = $msg;
$this->errors['password'][] = $msg;
return false;
}
if (!$customer->is_guest) {
$customer->passwd = $this->crypto->hash(
$newPassword ? $newPassword : $clearTextPassword,
_COOKIE_KEY_
);
}
if ($customer->is_guest || !$passwordRequired) {
// TODO SECURITY: Audit requested
if ($customer->id != $this->context->customer->id) {
// Since we're updating a customer without
// checking the password, we need to check that
// the customer being updated is the one from the
// current session.
// The error message is not great,
// but it should only be displayed to hackers
// so it should not be an issue :)
$this->errors['email'][] = $this->translator->trans(
'There seems to be an issue with your account, please contact support',
[],
'Shop.Notifications.Error'
);
return false;
}
}
$guest_to_customer = false;
if ($clearTextPassword && $customer->is_guest) {
$guest_to_customer = true;
$customer->is_guest = false;
$customer->passwd = $this->crypto->hash(
$clearTextPassword,
_COOKIE_KEY_
);
}
if ($customer->is_guest || $guest_to_customer) {
// guest cannot update their email to that of an existing real customer
if (Customer::customerExists($customer->email, false, true)) {
$this->errors['email'][] = $this->translator->trans(
'An account was already registered with this email address',
[],
'Shop.Notifications.Error'
);
return false;
}
}
if ($customer->email != $this->context->customer->email) {
$customer->removeResetPasswordToken();
}
$ok = $customer->save();
if ($ok) {
$this->context->updateCustomer($customer);
$this->context->cart->update();
Hook::exec('actionCustomerAccountUpdate', [
'customer' => $customer,
]);
if ($guest_to_customer) {
$this->sendConfirmationMail($customer);
$this->sendConfirmationAdminMail($customer);
}
}
return $ok;
}
private function create(Customer $customer, $clearTextPassword)
{
if (!$clearTextPassword) {
if (!$this->guest_allowed) {
$this->errors['password'][] = $this->translator->trans(
'Password is required',
[],
'Shop.Notifications.Error'
);
return false;
}
/**
* Warning: this is only safe provided
* that guests cannot log in even with the generated
* password. That's the case at least at the time of writing.
*/
$clearTextPassword = $this->crypto->hash(
microtime(),
_COOKIE_KEY_
);
$customer->is_guest = true;
}
$customer->passwd = $this->crypto->hash(
$clearTextPassword,
_COOKIE_KEY_
);
if (Customer::customerExists($customer->email, false, true)) {
$this->errors['email'][] = $this->translator->trans(
'An account was already registered with this email address',
[],
'Shop.Notifications.Error'
);
return false;
}
$ok = $customer->save();
if ($ok) {
$this->context->updateCustomer($customer);
$this->context->cart->update();
$this->sendConfirmationMail($customer);
Hook::exec('actionCustomerAccountAdd', [
'newCustomer' => $customer,
]);
}
return $ok;
}
private function sendConfirmationMail(Customer $customer)
{
if ($customer->is_guest || !Configuration::get('PS_CUSTOMER_CREATION_EMAIL')) {
return true;
}
return Mail::Send(
$this->context->language->id,
'account',
$this->translator->trans(
'Welcome!',
[],
'Emails.Subject'
),
[
'{firstname}' => $customer->firstname,
'{lastname}' => $customer->lastname,
'{email}' => $customer->email,
],
$customer->email,
$customer->firstname . ' ' . $customer->lastname
);
}
private function sendConfirmationAdminMail(Customer $customer)
{
if ($customer->is_guest || !Configuration::get('PS_CUSTOMER_CREATION_EMAIL')) {
return true;
}
return Mail::Send(
$this->context->language->id,
'account_for_admin',
$this->translator->trans(
'New Client!',
array(),
'Emails.Subject'
),
array(
'{firstname}' => $customer->firstname,
'{lastname}' => $customer->lastname,
'{type}' => $customer->retail,
'{email}' => $customer->email,
'{company}' => $customer->company,
'{website}' => $customer->website,
'{phone}' => $customer->phoneC,
'{mobil}' => $customer->mobileC,
'{address}' => $customer->addressC,
'{zip}' => $customer->zipC,
'{city}' => $customer->cityC,
'{state}' => $customer->stateC,
'{country}' => $customer->countryC,
'{about}' => $customer->aboutus,
'{extrainfo}' => $customer->extrainfo
),
'prestigemetalseo@gmail.com',
Configuration::get('PS_SHOP_NAME')
);
}
}
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
namespace PrestaShop\PrestaShop\Core\Grid\Query;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Query\QueryBuilder;
use PrestaShop\PrestaShop\Core\Grid\Search\SearchCriteriaInterface;
/**
* Class CustomerQueryBuilder builds queries to fetch data for customers grid.
*/
final class CustomerQueryBuilder extends AbstractDoctrineQueryBuilder
{
/**
* @var int
*/
private $contextLangId;
/**
* @var int[]
*/
private $contextShopIds;
/**
* @var DoctrineSearchCriteriaApplicatorInterface
*/
private $criteriaApplicator;
/**
* @param Connection $connection
* @param string $dbPrefix
* @param DoctrineSearchCriteriaApplicatorInterface $criteriaApplicator
* @param int $contextLangId
* @param int[] $contextShopIds
*/
public function __construct(
Connection $connection,
$dbPrefix,
DoctrineSearchCriteriaApplicatorInterface $criteriaApplicator,
$contextLangId,
array $contextShopIds
) {
parent::__construct($connection, $dbPrefix);
$this->contextLangId = $contextLangId;
$this->contextShopIds = $contextShopIds;
$this->criteriaApplicator = $criteriaApplicator;
}
/**
* {@inheritdoc}
*/
public function getSearchQueryBuilder(SearchCriteriaInterface $searchCriteria)
{
$searchQueryBuilder = $this->getCustomerQueryBuilder($searchCriteria)
->select('c.id_customer, c.firstname, c.lastname, c.email, c.active, c.newsletter, c.optin,c.website')
->addSelect('c.date_add, gl.name as social_title, s.name as shop_name, c.company'); //MM_ added website field.
$this->appendTotalSpentQuery($searchQueryBuilder);
$this->appendLastVisitQuery($searchQueryBuilder);
$this->applySorting($searchQueryBuilder, $searchCriteria);
$this->criteriaApplicator->applyPagination(
$searchCriteria,
$searchQueryBuilder
);
return $searchQueryBuilder;
}
/**
* {@inheritdoc}
*/
public function getCountQueryBuilder(SearchCriteriaInterface $searchCriteria)
{
$countQueryBuilder = $this->getCustomerQueryBuilder($searchCriteria)
->select('COUNT(*)');
return $countQueryBuilder;
}
/**
* @param SearchCriteriaInterface $searchCriteria
*
* @return QueryBuilder
*/
private function getCustomerQueryBuilder(SearchCriteriaInterface $searchCriteria)
{
$queryBuilder = $this->connection->createQueryBuilder()
->from($this->dbPrefix . 'customer', 'c')
->leftJoin(
'c',
$this->dbPrefix . 'gender_lang',
'gl',
'c.id_gender = gl.id_gender AND gl.id_lang = :context_lang_id'
)
->leftJoin(
'c',
$this->dbPrefix . 'shop',
's',
'c.id_shop = s.id_shop'
)
->where('c.deleted = 0')
->andWhere('c.id_shop IN (:context_shop_ids)')
->setParameter('context_shop_ids', $this->contextShopIds, Connection::PARAM_INT_ARRAY)
->setParameter('context_lang_id', $this->contextLangId);
$this->applyFilters($searchCriteria->getFilters(), $queryBuilder);
return $queryBuilder;
}
/**
* @param QueryBuilder $queryBuilder
*/
private function appendTotalSpentQuery(QueryBuilder $queryBuilder)
{
$totalSpentQueryBuilder = $this->connection->createQueryBuilder()
->select('SUM(total_paid_real / conversion_rate)')
->from($this->dbPrefix . 'orders', 'o')
->where('o.id_customer = c.id_customer')
->andWhere('o.id_shop IN (:context_shop_ids)')
->andWhere('o.valid = 1')
->setParameter('context_shop_ids', $this->contextShopIds, Connection::PARAM_INT_ARRAY);
$queryBuilder->addSelect('(' . $totalSpentQueryBuilder->getSQL() . ') as total_spent');
}
/**
* Append "last visit" column to customers query builder.
*
* @param QueryBuilder $queryBuilder
*/
private function appendLastVisitQuery(QueryBuilder $queryBuilder)
{
$lastVisitQueryBuilder = $this->connection->createQueryBuilder()
->select('con.date_add')
->from($this->dbPrefix . 'guest', 'g')
->leftJoin('g', $this->dbPrefix . 'connections', 'con', 'con.id_guest = g.id_guest')
->where('g.id_customer = c.id_customer')
->orderBy('con.date_add', 'DESC')
->setMaxResults(1);
$queryBuilder->addSelect('(' . $lastVisitQueryBuilder->getSQL() . ') as connect');
}
/**
* Apply filters to customers query builder.
*
* @param array $filters
* @param QueryBuilder $qb
*/
private function applyFilters(array $filters, QueryBuilder $qb)
{
$allowedFilters = [
'id_customer',
'social_title',
'firstname',
'lastname',
'email',
'website',//MM_
'active',
'newsletter',
'optin',
'date_add',
'company',
];
foreach ($filters as $filterName => $filterValue) {
if (!in_array($filterName, $allowedFilters)) {
continue;
}
if (in_array($filterName, ['active', 'newsletter', 'optin', 'id_customer'])) {
$qb->andWhere('c.`' . $filterName . '` = :' . $filterName);
$qb->setParameter($filterName, $filterValue);
continue;
}
if ('social_title' === $filterName) {
$qb->andWhere('gl.id_gender = :' . $filterName);
$qb->setParameter($filterName, $filterValue);
continue;
}
if ('date_add' === $filterName) {
if (isset($filterValue['from'])) {
$qb->andWhere('c.date_add >= :date_from');
$qb->setParameter('date_from', sprintf('%s 0:0:0', $filterValue['from']));
}
if (isset($filterValue['to'])) {
$qb->andWhere('c.date_add <= :date_to');
$qb->setParameter('date_to', sprintf('%s 23:59:59', $filterValue['to']));
}
continue;
}
$qb->andWhere('c.`' . $filterName . '` LIKE :' . $filterName);
$qb->setParameter($filterName, '%' . $filterValue . '%');
}
}
/**
* Apply sorting so search query builder for customers.
*
* @param QueryBuilder $searchQueryBuilder
* @param SearchCriteriaInterface $searchCriteria
*/
private function applySorting(QueryBuilder $searchQueryBuilder, SearchCriteriaInterface $searchCriteria)
{
switch ($searchCriteria->getOrderBy()) {
case 'id_customer':
case 'firstname':
case 'lastname':
case 'email':
case 'website': //MM_
case 'date_add':
case 'company':
case 'active':
case 'newsletter':
case 'optin':
$orderBy = 'c.' . $searchCriteria->getOrderBy();
break;
case 'social_title':
$orderBy = 'gl.name';
break;
case 'connect':
case 'total_spent':
$orderBy = $searchCriteria->getOrderBy();
break;
default:
return;
}
$searchQueryBuilder->orderBy($orderBy, $searchCriteria->getOrderWay());
}
}
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
namespace PrestaShop\PrestaShop\Adapter\Customer\QueryHandler;
use Carrier;
use Cart;
use CartRule;
use Category;
use Context;
use Currency;
use Customer;
use CustomerThread;
use Db;
use Gender;
use Group;
use Language;
use Link;
use Order;
use PrestaShop\PrestaShop\Adapter\LegacyContext;
use PrestaShop\PrestaShop\Core\Domain\Customer\Exception\CustomerNotFoundException;
use PrestaShop\PrestaShop\Core\Domain\Customer\Query\GetCustomerForViewing;
use PrestaShop\PrestaShop\Core\Domain\Customer\QueryHandler\GetCustomerForViewingHandlerInterface;
use PrestaShop\PrestaShop\Core\Domain\Customer\QueryResult\AddressInformation;
use PrestaShop\PrestaShop\Core\Domain\Customer\QueryResult\BoughtProductInformation;
use PrestaShop\PrestaShop\Core\Domain\Customer\QueryResult\CartInformation;
use PrestaShop\PrestaShop\Core\Domain\Customer\QueryResult\DiscountInformation;
use PrestaShop\PrestaShop\Core\Domain\Customer\QueryResult\GeneralInformation;
use PrestaShop\PrestaShop\Core\Domain\Customer\QueryResult\GroupInformation;
use PrestaShop\PrestaShop\Core\Domain\Customer\QueryResult\LastConnectionInformation;
use PrestaShop\PrestaShop\Core\Domain\Customer\QueryResult\MessageInformation;
use PrestaShop\PrestaShop\Core\Domain\Customer\QueryResult\OrderInformation;
use PrestaShop\PrestaShop\Core\Domain\Customer\QueryResult\OrdersInformation;
use PrestaShop\PrestaShop\Core\Domain\Customer\QueryResult\PersonalInformation;
use PrestaShop\PrestaShop\Core\Domain\Customer\QueryResult\ProductsInformation;
use PrestaShop\PrestaShop\Core\Domain\Customer\QueryResult\ReferrerInformation;
use PrestaShop\PrestaShop\Core\Domain\Customer\QueryResult\SentEmailInformation;
use PrestaShop\PrestaShop\Core\Domain\Customer\QueryResult\Subscriptions;
use PrestaShop\PrestaShop\Core\Domain\Customer\QueryResult\ViewableCustomer;
use PrestaShop\PrestaShop\Core\Domain\Customer\QueryResult\ViewedProductInformation;
use PrestaShop\PrestaShop\Core\Domain\Customer\ValueObject\CustomerId;
use PrestaShop\PrestaShop\Core\Localization\Locale;
use Product;
use Referrer;
use Shop;
use Symfony\Component\Translation\TranslatorInterface;
use Tools;
use Validate;
/**
* Handles commands which gets customer for viewing in Back Office.
*
* @internal
*/
final class GetCustomerForViewingHandler implements GetCustomerForViewingHandlerInterface
{
/**
* @var LegacyContext
*/
private $context;
/**
* @var int
*/
private $contextLangId;
/**
* @var TranslatorInterface
*/
private $translator;
/**
* @var Link
*/
private $link;
/**
* @var Locale
*/
private $locale;
/**
* @param TranslatorInterface $translator
* @param int $contextLangId
* @param Link $link
* @param Locale $locale
*/
public function __construct(
TranslatorInterface $translator,
$contextLangId,
Link $link,
Locale $locale
) {
$this->context = new LegacyContext();
$this->contextLangId = $contextLangId;
$this->translator = $translator;
$this->link = $link;
$this->locale = $locale;
}
/**
* {@inheritdoc}
*/
public function handle(GetCustomerForViewing $query)
{
$customerId = $query->getCustomerId();
$customer = new Customer($customerId->getValue());
$this->assertCustomerWasFound($customerId, $customer);
Context::getContext()->customer = $customer;
return new ViewableCustomer(
$customerId,
$this->getGeneralInformation($customer),
$this->getPersonalInformation($customer),
$this->getCustomerOrders($customer),
$this->getCustomerCarts($customer),
$this->getCustomerProducts($customer),
$this->getCustomerMessages($customer),
$this->getCustomerDiscounts($customer),
$this->getLastEmailsSentToCustomer($customer),
$this->getLastCustomerConnections($customer),
$this->getCustomerGroups($customer),
$this->getCustomerReferrers($customer),
$this->getCustomerAddresses($customer)
);
}
/**
* @param Customer $customer
*
* @return GeneralInformation
*/
private function getGeneralInformation(Customer $customer)
{
return new GeneralInformation(
$customer->note,
Customer::customerExists($customer->email)
);
}
/**
* @param Customer $customer
*
* @return PersonalInformation
*/
private function getPersonalInformation(Customer $customer)
{
$customerStats = $customer->getStats();
$gender = new Gender($customer->id_gender, $this->contextLangId);
$socialTitle = $gender->name ?: $this->translator->trans('Unknown', [], 'Admin.Orderscustomers.Feature');
if ($customer->birthday && '0000-00-00' !== $customer->birthday) {
$birthday = sprintf(
$this->translator->trans('%1$d years old (birth date: %2$s)', [], 'Admin.Orderscustomers.Feature'),
$customerStats['age'],
Tools::displayDate($customer->birthday)
);
} else {
$birthday = $this->translator->trans('Unknown', [], 'Admin.Orderscustomers.Feature');
}
$registrationDate = Tools::displayDate($customer->date_add, null, true);
$lastUpdateDate = Tools::displayDate($customer->date_upd, null, true);
$lastVisitDate = $customerStats['last_visit'] ?
Tools::displayDate($customerStats['last_visit'], null, true) :
$this->translator->trans('Never', [], 'Admin.Global');
$customerShop = new Shop($customer->id_shop);
$customerLanguage = new Language($customer->id_lang);
$customerSubscriptions = new Subscriptions(
(bool) $customer->newsletter,
(bool) $customer->optin
);
return new PersonalInformation(
$customer->aboutus,
$customer->lastname,
$customer->email,
$customer->isGuest(),
$socialTitle,
$birthday,
$customer->retail, //MM_
$customer->company, //MM_
$customer->addressC, //MM_
$customer->cityC, //MM_
$customer->countryC, //MM_
$customer->stateC, //MM_
$customer->zipC, //MM_
$customer->phoneC, //MM_
$customer->mobileC, //MM_
$customer->website, //MM_
$customer->aboutus, //MM_
$customer->extrainfo, //MM_
$registrationDate,
$lastUpdateDate,
$lastVisitDate,
$this->getCustomerRankBySales($customer->id),
$customerShop->name,
$customerLanguage->name,
$customerSubscriptions,
(bool) $customer->active
);
}
/**
* @param int $customerId
*
* @return int|null customer rank or null if customer is not ranked
*/
private function getCustomerRankBySales($customerId)
{
$sql = 'SELECT SUM(total_paid_real) FROM ' . _DB_PREFIX_ . 'orders WHERE id_customer = ' . (int) $customerId . ' AND valid = 1';
if ($totalPaid = Db::getInstance()->getValue($sql)) {
$sql = '
SELECT SQL_CALC_FOUND_ROWS COUNT(*)
FROM ' . _DB_PREFIX_ . 'orders
WHERE valid = 1
AND id_customer != ' . (int) $customerId . '
GROUP BY id_customer
HAVING SUM(total_paid_real) > ' . (int) $totalPaid;
Db::getInstance()->getValue($sql);
return (int) Db::getInstance()->getValue('SELECT FOUND_ROWS()') + 1;
}
return null;
}
/**
* @param Customer $customer
*
* @return OrdersInformation
*/
private function getCustomerOrders(Customer $customer)
{
$validOrders = [];
$invalidOrders = [];
$orders = Order::getCustomerOrders($customer->id, true);
$totalSpent = 0;
foreach ($orders as $order) {
$order['total_paid_real_not_formated'] = $order['total_paid_real'];
$order['total_paid_real'] = $this->locale->formatPrice(
$order['total_paid_real'],
Currency::getIsoCodeById((int) $order['id_currency'])
);
if (!isset($order['order_state'])) {
$order['order_state'] = $this->translator->trans(
'There is no status defined for this order.',
[],
'Admin.Orderscustomers.Notification'
);
}
$customerOrderInformation = new OrderInformation(
(int) $order['id_order'],
Tools::displayDate($order['date_add']),
$order['payment'],
$order['order_state'],
(int) $order['nb_products'],
$order['total_paid_real']
);
if ($order['valid']) {
$validOrders[] = $customerOrderInformation;
$totalSpent += $order['total_paid_real_not_formated'] / $order['conversion_rate'];
} else {
$invalidOrders[] = $customerOrderInformation;
}
}
return new OrdersInformation(
$this->locale->formatPrice($totalSpent, $this->context->getContext()->currency->iso_code),
$validOrders,
$invalidOrders
);
}
/**
* @param Customer $customer
*
* @return CartInformation[]
*/
private function getCustomerCarts(Customer $customer)
{
$carts = Cart::getCustomerCarts($customer->id);
$customerCarts = [];
foreach ($carts as $cart) {
$cart = new Cart((int) $cart['id_cart']);
Context::getContext()->cart = $cart;
$currency = new Currency($cart->id_currency);
Context::getContext()->currency = $currency;
$carrier = new Carrier($cart->id_carrier);
$summary = $cart->getSummaryDetails();
$customerCarts[] = new CartInformation(
sprintf('%06d', $cart->id),
Tools::displayDate($cart->date_add, null, true),
$this->locale->formatPrice($summary['total_price'], $currency->iso_code),
$carrier->name
);
}
Context::getContext()->currency = Currency::getDefaultCurrency();
return $customerCarts;
}
/**
* @param Customer $customer
*
* @return ProductsInformation
*/
private function getCustomerProducts(Customer $customer)
{
$boughtProducts = [];
$viewedProducts = [];
$products = $customer->getBoughtProducts();
foreach ($products as $product) {
$boughtProducts[] = new BoughtProductInformation(
(int) $product['id_order'],
Tools::displayDate($product['date_add'], null, false),
$product['product_name'],
$product['product_quantity']
);
}
$sql = '
SELECT DISTINCT cp.id_product, c.id_cart, c.id_shop, cp.id_shop AS cp_id_shop
FROM ' . _DB_PREFIX_ . 'cart_product cp
JOIN ' . _DB_PREFIX_ . 'cart c ON (c.id_cart = cp.id_cart)
JOIN ' . _DB_PREFIX_ . 'product p ON (cp.id_product = p.id_product)
WHERE c.id_customer = ' . (int) $customer->id . '
AND NOT EXISTS (
SELECT 1
FROM ' . _DB_PREFIX_ . 'orders o
JOIN ' . _DB_PREFIX_ . 'order_detail od ON (o.id_order = od.id_order)
WHERE product_id = cp.id_product AND o.valid = 1 AND o.id_customer = ' . (int) $customer->id . '
)
';
$viewedProductsData = Db::getInstance()->executeS($sql);
foreach ($viewedProductsData as $productData) {
$product = new Product(
$productData['id_product'],
false,
$this->contextLangId,
$productData['id_shop']
);
if (!Validate::isLoadedObject($product)) {
continue;
}
$productUrl = $this->link->getProductLink(
$product->id,
$product->link_rewrite,
Category::getLinkRewrite($product->id_category_default, $this->contextLangId),
null,
null,
$productData['cp_id_shop']
);
$viewedProducts[] = new ViewedProductInformation(
(int) $product->id,
$product->name,
$productUrl
);
}
return new ProductsInformation(
$boughtProducts,
$viewedProducts
);
}
/**
* @param Customer $customer
*
* @return MessageInformation[]
*/
private function getCustomerMessages(Customer $customer)
{
$customerMessages = [];
$messages = CustomerThread::getCustomerMessages((int) $customer->id);
$messageStatuses = [
'open' => $this->translator->trans('Open', [], 'Admin.Orderscustomers.Feature'),
'closed' => $this->translator->trans('Closed', [], 'Admin.Orderscustomers.Feature'),
'pending1' => $this->translator->trans('Pending 1', [], 'Admin.Orderscustomers.Feature'),
'pending2' => $this->translator->trans('Pending 2', [], 'Admin.Orderscustomers.Feature'),
];
foreach ($messages as $message) {
$status = isset($messageStatuses[$message['status']]) ?
$messageStatuses[$message['status']] :
$message['status'];
$customerMessages[] = new MessageInformation(
(int) $message['id_customer_thread'],
substr(strip_tags(html_entity_decode($message['message'], ENT_NOQUOTES, 'UTF-8')), 0, 75),
$status,
Tools::displayDate($message['date_add'], null, true)
);
}
return $customerMessages;
}
/**
* @param Customer $customer
*
* @return DiscountInformation[]
*/
private function getCustomerDiscounts(Customer $customer)
{
$discounts = CartRule::getCustomerCartRules($this->contextLangId, $customer->id, false, false);
$customerDiscounts = [];
foreach ($discounts as $discount) {
$availableQuantity = $discount['quantity'] > 0 ? (int) $discount['quantity_for_user'] : 0;
$customerDiscounts[] = new DiscountInformation(
(int) $discount['id_cart_rule'],
$discount['code'],
$discount['name'],
(bool) $discount['active'],
$availableQuantity
);
}
return $customerDiscounts;
}
/**
* @param Customer $customer
*
* @return SentEmailInformation[]
*/
private function getLastEmailsSentToCustomer(Customer $customer)
{
$emails = $customer->getLastEmails();
$customerEmails = [];
foreach ($emails as $email) {
$customerEmails[] = new SentEmailInformation(
Tools::displayDate($email['date_add'], null, true),
$email['language'],
$email['subject'],
$email['template']
);
}
return $customerEmails;
}
/**
* @param Customer $customer
*
* @return LastConnectionInformation[]
*/
private function getLastCustomerConnections(Customer $customer)
{
$connections = $customer->getLastConnections();
$lastConnections = [];
if (!is_array($connections)) {
$connections = [];
}
foreach ($connections as $connection) {
$httpReferer = $connection['http_referer'] ?
preg_replace('/^www./', '', parse_url($connection['http_referer'], PHP_URL_HOST)) :
$this->translator->trans('Direct link', [], 'Admin.Orderscustomers.Notification');
$lastConnections[] = new LastConnectionInformation(
$connection['id_connections'],
Tools::displayDate($connection['date_add']),
$connection['pages'],
$connection['time'],
$httpReferer,
$connection['ipaddress']
);
}
return $lastConnections;
}
/**
* @param Customer $customer
*
* @return GroupInformation[]
*/
private function getCustomerGroups(Customer $customer)
{
$groups = $customer->getGroups();
$customerGroups = [];
foreach ($groups as $groupId) {
$group = new Group($groupId);
$customerGroups[] = new GroupInformation(
(int) $group->id,
$group->name[$this->contextLangId]
);
}
return $customerGroups;
}
/**
* @param Customer $customer
*
* @return ReferrerInformation[]
*/
private function getCustomerReferrers(Customer $customer)
{
$referrers = Referrer::getReferrers($customer->id);
$customerReferrers = [];
foreach ($referrers as $referrer) {
$customerReferrers[] = new ReferrerInformation(
Tools::displayDate($referrer['date_add'], null, true),
$referrer['name'],
$referrer['shop_name']
);
}
return $customerReferrers;
}
/**
* @param Customer $customer
*
* @return AddressInformation[]
*/
private function getCustomerAddresses(Customer $customer)
{
$addresses = $customer->getAddresses($this->contextLangId);
$customerAddresses = [];
foreach ($addresses as $address) {
$company = $address['company'] ?: '--';
$fullAddress = sprintf(
'%s %s %s %s',
$address['address1'],
$address['address2'] ?: '',
$address['postcode'],
$address['city']
);
$customerAddresses[] = new AddressInformation(
(int) $address['id_address'],
$company,
sprintf('%s %s', $address['firstname'], $address['lastname']),
$fullAddress,
$address['country'],
(string) $address['phone'],
(string) $address['phone_mobile']
);
}
return $customerAddresses;
}
/**
* @param CustomerId $customerId
* @param Customer $customer
*
* @throws CustomerNotFoundException
*/
private function assertCustomerWasFound(CustomerId $customerId, Customer $customer)
{
if (!$customer->id) {
throw new CustomerNotFoundException($customerId, sprintf('Customer with id "%s" was not found.', $customerId->getValue()));
}
}
}
Files for Backend:
src\PrestaShopBundle\Resources\views\Admin\Sell\Customer\Blocks\View\personal_information.html.twig (Display information in Customer details)
src\Core\Domain\Customer\QueryResult\PersonalInformation.php (Get personal customer info)
src\Core\Grid\Query\CustomerQueryBuilder.php (Add the new fields to queries.)
src\Adapter\Customer\QueryHandler\GetCustomerForViewingHandler.php
Overrides:
override\classes\form\CustomerFormatter.php
override\classes\form\CustomerPersister.php
override\classes\Customer.php
====== ARCHIVOS PARA AGREGAR UN NUEVO CLIENTE ===========
public_html/src/PrestaShopBundle/Form/Admin/Sell/Customer
* CustomerType.php
## INPUTS--> la comparte con el formulario de edición
public_html/src/PrestaShopBundle/Resources/views/Admin/Sell/Customer/Blocks
* form.html.twig
## LABELS -> la comparte con el formulario de edicion //
public_html/src/Adapter/Customer/CommandHandler
* AddCustomerHandler.php
public_html/src/Core/Domain/Customer/Command
* AddCustomerCommand.php
public_html/src/Core/Form/IdentifiableObject/DataHandler
* CustomerFormDataHandler.php
======= ARCHIVOS PARA EDITAR UN CLIENTE ===================
public_html/src/PrestaShopBundle/Form/Admin/Sell/Customer
* CustomerType.php
public_html/src/PrestaShopBundle/Resources/views/Admin/Sell/Customer/Blocks
* form.html.twig
public_html/src/Adapter/Customer/QueryHandler
* GetCustomerForEditingHandler.php
public_html/src/Adapter/Customer/CommandHandler
* EditCustomerHandler.php
public_html/src/Core/Domain/Customer/QueryResult
* EditableCustomer.php
public_html/src/Core/Domain/Customer/Command
* EditCustomerCommand.php
public_html/src/Core/Form/IdentifiableObject/DataHandler
* CustomerFormDataHandler.php
public_html/src/Core/Form/IdentifiableObject/DataProvider
* CustomerFormDataProvider.php
======= vista de datos desde el panel de PRINCIPAL DE CLIENTES =====================
### -----------> (se agregaron las variables y metodos)
public_html/src/Core/Domain/Customer/QueryResult/PersonalInformation.php
### -----------> (obtiene los valores para la vista)
public_html/src/Adapter/Customer/QueryHandler/GetCustomerForViewingHandler.php
### -----------> (muestra en info del cliente los datos obtenidos)
public_html/src/PrestaShopBundle/Resources/views/Admin/Sell/Customer/Blocks/View/personal_information.html.twig
More info here:
https://www.prestashop.com/forums/topic/1046689-a%C3%B1adir-campos-a-formulario-de-registro-en-front-y-back-version-1771/
{#**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*#}
<div class="card customer-personal-informations-card">
<h3 class="card-header">
<i class="material-icons">person</i>
{{ customerInformation.personalInformation.firstName }}
{{ customerInformation.personalInformation.lastName }}
{{ '[%06d]'|format(customerInformation.customerId.value) }}
-
<a href="mailto:{{ customerInformation.personalInformation.email }}">
{{ customerInformation.personalInformation.email }}
</a>
<a href="{{ getAdminLink('AdminCustomers', true, {'id_customer': customerInformation.customerId.value, 'updatecustomer': 1, 'back': app.request.uri}) }}"
class="tooltip-link float-right edit-link"
data-toggle="pstooltip"
title=""
data-placement="top"
data-original-title="{{ 'Edit'|trans({}, 'Admin.Actions') }}"
>
<i class="material-icons">edit</i>
</a>
</h3>
<div class="card-body">
<div class="row mb-1">
<div class="col-4 text-right">
{{ 'Social Title'|trans({}, 'Admin.Global') }}
</div>
<div class="customer-social-title col-8">
{{ customerInformation.personalInformation.socialTitle }}
</div>
</div>
<div class="row mb-1">
<div class="col-4 text-right">
{{ 'Age'|trans({}, 'Admin.Orderscustomers.Feature') }}
</div>
<div class="col-8 customer-birthday">
{{ customerInformation.personalInformation.birthday }}
</div>
</div>
<!--MM_ Extra fields here:-->
<div class="row mb-1">
<div class="col-4 text-right">
{{ 'Company'|trans({}, 'Admin.Orderscustomers.Feature') }}
</div>
<div class="col-8 customer-birthday">
{{ customerInformation.personalInformation.company }}
</div>
</div>
<div class="row mb-1">
<div class="col-4 text-right">
{{ 'Phone'|trans({}, 'Admin.Orderscustomers.Feature') }}
</div>
<div class="col-8 customer-birthday">
{{ customerInformation.personalInformation.phoneC }}
</div>
</div>
<div class="row mb-1">
<div class="col-4 text-right">
{{ 'Mobile'|trans({}, 'Admin.Orderscustomers.Feature') }}
</div>
<div class="col-8 customer-birthday">
{{ customerInformation.personalInformation.mobileC }}
</div>
</div>
<div class="row mb-1">
<div class="col-4 text-right">
{{ 'Website'|trans({}, 'Admin.Orderscustomers.Feature') }}
</div>
<div class="col-8 customer-birthday">
{{ customerInformation.personalInformation.website }}
</div>
</div>
<div class="row mb-1">
<div class="col-4 text-right">
{{ 'Address'|trans({}, 'Admin.Orderscustomers.Feature') }}
</div>
<div class="col-8 customer-birthday">
{{ customerInformation.personalInformation.addressC }}
</div>
</div>
<div class="row mb-1">
<div class="col-4 text-right">
{{ 'Zip Code'|trans({}, 'Admin.Orderscustomers.Feature') }}
</div>
<div class="col-8 customer-birthday">
{{ customerInformation.personalInformation.zipC }}
</div>
</div>
<div class="row mb-1">
<div class="col-4 text-right">
{{ 'City'|trans({}, 'Admin.Orderscustomers.Feature') }}
</div>
<div class="col-8 customer-birthday">
{{ customerInformation.personalInformation.cityC }}
</div>
</div>
<div class="row mb-1">
<div class="col-4 text-right">
{{ 'State'|trans({}, 'Admin.Orderscustomers.Feature') }}
</div>
<div class="col-8 customer-birthday">
{{ customerInformation.personalInformation.stateC }}
</div>
</div>
<div class="row mb-1">
<div class="col-4 text-right">
{{ 'Country'|trans({}, 'Admin.Orderscustomers.Feature') }}
</div>
<div class="col-8 customer-birthday">
{{ customerInformation.personalInformation.countryC }}
</div>
</div>
<div class="row mb-1">
<div class="col-4 text-right">
{{ 'How did you hear about us?'|trans({}, 'Admin.Orderscustomers.Feature') }}
</div>
<div class="col-8 customer-birthday">
{{ customerInformation.personalInformation.aboutus }}
</div>
</div>
<div class="row mb-1">
<div class="col-4 text-right">
{{ 'Additional Information'|trans({}, 'Admin.Orderscustomers.Feature') }}
</div>
<div class="col-8 customer-birthday">
{{ customerInformation.personalInformation.extrainfo }}
</div>
</div>
<!--End MM_ -->
<div class="row mb-1">
<div class="col-4 text-right">
{{ 'Registration Date'|trans({}, 'Admin.Orderscustomers.Feature') }}
</div>
<div class="col-8 customer-registration-date">
{{ customerInformation.personalInformation.registrationDate }}
</div>
</div>
<div class="row mb-1">
<div class="col-4 text-right">
{{ 'Last Visit'|trans({}, 'Admin.Orderscustomers.Feature') }}
</div>
<div class="col-8 customer-last-visit-date">
{{ customerInformation.personalInformation.lastVisitDate }}
</div>
</div>
{% if customerInformation.personalInformation.rankBySales %}
<div class="row mb-1">
<div class="col-4 text-right">
{{ 'Best Customer Rank'|trans({}, 'Admin.Orderscustomers.Feature') }}
</div>
<div class="col-8 customer-sales-rank">
{{ customerInformation.personalInformation.rankBySales }}
</div>
</div>
{% endif %}
{% if isMultistoreEnabled %}
<div class="row mb-1">
<div class="col-4 text-right">
{{ 'Shop'|trans({}, 'Admin.Global') }}
</div>
<div class="customer-shop-name col-8">
{{ customerInformation.personalInformation.shopName }}
</div>
</div>
{% endif %}
<div class="row mb-1">
<div class="col-4 text-right">
{{ 'Language'|trans({}, 'Admin.Global') }}
</div>
<div class="col-8 customer-language-name">
{{ customerInformation.personalInformation.languageName }}
</div>
</div>
<div class="row mb-1">
<div class="col-4 text-right">
{{ 'Registrations'|trans({}, 'Admin.Orderscustomers.Feature') }}
</div>
<div class="col-8">
{% set isNewsletterSubscribed = customerInformation.personalInformation.subscriptions.newsletterSubscribed %}
{% set isPartnerOffersSubscribed = customerInformation.personalInformation.subscriptions.partnerOffersSubscribed %}
<span class="customer-newsletter-subscription-status badge badge-{% if isNewsletterSubscribed %}success{% else %}danger{% endif %} rounded">
<i class="material-icons">{% if isNewsletterSubscribed %}check{% else %}cancel{% endif %}</i>
{{ 'Newsletter'|trans({}, 'Admin.Global') }}
</span>
<span class="customer-partner-offers-status badge badge-{% if isPartnerOffersSubscribed %}success{% else %}danger{% endif %} rounded">
<i class="material-icons">{% if isPartnerOffersSubscribed %}check{% else %}cancel{% endif %}</i>
{{ 'Partner offers'|trans({}, 'Admin.Orderscustomers.Feature') }}
</span>
</div>
</div>
<div class="row mb-1">
<div class="col-4 text-right">
{{ 'Latest Update'|trans({}, 'Admin.Orderscustomers.Feature') }}
</div>
<div class="customer-latest-update col-8">
{{ customerInformation.personalInformation.lastUpdateDate }}
</div>
</div>
<div class="row mb-1">
<div class="col-4 text-right">
{{ 'Status'|trans({}, 'Admin.Global') }}
</div>
<div class="col-8">
{% set isCustomerActive = customerInformation.personalInformation.active %}
<span class="customer-status badge badge-{% if isCustomerActive %}success{% else %}danger{% endif %} rounded">
{% if isCustomerActive %}
<i class="material-icons">check</i>
{{ 'Active'|trans({}, 'Admin.Global') }}
{% else %}
<i class="material-icons">cancel</i>
{{ 'Inactive'|trans({}, 'Admin.Global') }}
{% endif %}
</span>
</div>
</div>
{% if customerInformation.personalInformation.guest %}
{% form_theme transferGuestAccountForm 'PrestaShopBundle:Admin/TwigTemplateForm:prestashop_ui_kit.html.twig' %}
<div class="customer-guest-status row mb-1">
<div class="col-4 text-right">
{{ 'This customer is registered as a Guest.'|trans({}, 'Admin.Orderscustomers.Feature') }}
</div>
<div class="col-8">
{% if customerInformation.generalInformation.customerBySameEmailExists %}
<p>{{ 'A registered customer account using the defined email address already exists. '|trans({}, 'Admin.Orderscustomers.Notification') }}</p>
{% else %}
{{ form_start(transferGuestAccountForm, {'action': path('admin_customers_transform_guest_to_customer', {'customerId': customerInformation.customerId.value})}) }}
{{ form_widget(transferGuestAccountForm.transfer_guest_account) }}
<p class="small-text">
{{ 'This feature generates a random password before sending an email to your customer.'|trans({}, 'Admin.Orderscustomers.Help') }}
</p>
{{ form_end(transferGuestAccountForm) }}
{% endif %}
</div>
</div>
{% endif %}
</div>
</div>
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
namespace PrestaShop\PrestaShop\Core\Domain\Customer\QueryResult;
/**
* Class PersonalInformation holds personal customer information.
*/
class PersonalInformation
{
/**
* @var string
*/
private $firstName;
/**
* @var string
*/
private $lastName;
/**
* @var string
*/
private $email;
/**
* @var bool
*/
private $isGuest;
/**
* @var string
*/
private $socialTitle;
/**
* @var string
*/
private $birthday;
/**
* @var string
*/
/**
* MM_Extrafields
*/
private $retail;
private $company;
private $addressC;
private $cityC;
private $countryC;
private $stateC;
private $zipC;
private $phoneC;
private $mobileC;
private $website;
private $aboutus;
private $extrainfo;
/**
* End MM_
*/
/**
* @var string
*/
private $registrationDate;
/**
* @var string
*/
private $lastUpdateDate;
/**
* @var string
*/
private $lastVisitDate;
/**
* @var string
*/
private $rankBySales;
/**
* @var string
*/
private $shopName;
/**
* @var string
*/
private $languageName;
/**
* @var Subscriptions
*/
private $subscriptions;
/**
* @var bool
*/
private $isActive;
/**
* @param string $firstName
* @param string $lastName
* @param string $email
* @param bool $isGuest
* @param string $socialTitle
* @param string $birthday
* @param string $registrationDate
* @param string $lastUpdateDate
* @param string $lastVisitDate
* @param string $rankBySales
* @param string $shopName
* @param string $languageName
* @param Subscriptions $subscriptions
* @param bool $isActive
*/
public function __construct(
$firstName,
$lastName,
$email,
$isGuest,
$socialTitle,
$birthday,
$retail,
$company,
$addressC,
$cityC,
$countryC,
$stateC,
$zipC,
$phoneC,
$mobileC,
$website,
$aboutus,
$extrainfo,
$registrationDate,
$lastUpdateDate,
$lastVisitDate,
$rankBySales,
$shopName,
$languageName,
Subscriptions $subscriptions,
$isActive
) {
$this->firstName = $firstName;
$this->lastName = $lastName;
$this->email = $email;
$this->isGuest = $isGuest;
$this->socialTitle = $socialTitle;
$this->birthday = $birthday;
$this->retail = $retail;
$this->company = $company;
$this->addressC = $addressC;
$this->cityC = $cityC;
$this->countryC = $countryC;
$this->stateC = $stateC;
$this->zipC = $zipC;
$this->phoneC = $phoneC;
$this->mobileC = $mobileC;
$this->website = $website;
$this->aboutus = $aboutus;
$this->extrainfo = $extrainfo;
$this->registrationDate = $registrationDate;
$this->lastUpdateDate = $lastUpdateDate;
$this->lastVisitDate = $lastVisitDate;
$this->rankBySales = $rankBySales;
$this->shopName = $shopName;
$this->languageName = $languageName;
$this->subscriptions = $subscriptions;
$this->isActive = $isActive;
}
/**
* @return string
*/
public function getFirstName()
{
return $this->firstName;
}
/**
* @return string
*/
public function getLastName()
{
return $this->lastName;
}
/**
* @return string
*/
public function getEmail()
{
return $this->email;
}
/**
* @return bool
*/
public function isGuest()
{
return $this->isGuest;
}
/**
* @return string
*/
public function getSocialTitle()
{
return $this->socialTitle;
}
/**
* @return string
*/
public function getBirthday()
{
return $this->birthday;
}
///////////////////////////////////////////////
public function getRetail()
{
return $this->retail;
}
public function getCompany()
{
return $this->company;
}
public function getAddressC()
{
return $this->addressC;
}
public function getCityC()
{
return $this->cityC;
}
public function getCountryC()
{
return $this->countryC;
}
public function getStateC()
{
return $this->stateC;
}
public function getZipC()
{
return $this->zipC;
}
public function getPhoneC()
{
return $this->phoneC;
}
public function getMobileC()
{
return $this->mobileC;
}
public function getWebsite()
{
return $this->website;
}
public function getAboutus()
{
return $this->aboutus;
}
public function getExtrainfo()
{
return $this->extrainfo;
}
/////////////////////////////////////////////////////
/**
* @return string
*/
public function getRegistrationDate()
{
return $this->registrationDate;
}
/**
* @return string
*/
public function getLastUpdateDate()
{
return $this->lastUpdateDate;
}
/**
* @return string
*/
public function getLastVisitDate()
{
return $this->lastVisitDate;
}
/**
* @return string
*/
public function getRankBySales()
{
return $this->rankBySales;
}
/**
* @return string
*/
public function getShopName()
{
return $this->shopName;
}
/**
* @return string
*/
public function getLanguageName()
{
return $this->languageName;
}
/**
* @return Subscriptions
*/
public function getSubscriptions()
{
return $this->subscriptions;
}
/**
* @return bool
*/
public function isActive()
{
return $this->isActive;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment