780 lines
27 KiB
PHP
780 lines
27 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace External\ZNZBundle\Synchronizers;
|
|
|
|
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
|
|
use External\ZNZBundle\Exception\ZNZException;
|
|
use External\ZNZBundle\Util\ZNZApi;
|
|
use External\ZNZBundle\Util\ZNZUtil;
|
|
use KupShop\AdminBundle\Util\ActivityLog;
|
|
use KupShop\KupShopBundle\Context\ContextManager;
|
|
use KupShop\KupShopBundle\Context\CountryContext;
|
|
use KupShop\KupShopBundle\Context\LanguageContext;
|
|
use KupShop\KupShopBundle\Email\PasswordResetAdminEmail;
|
|
use KupShop\KupShopBundle\Util\Contexts;
|
|
use KupShop\KupShopBundle\Util\Database\QueryHint;
|
|
use KupShop\KupShopBundle\Util\System\TokenGenerator;
|
|
use KupShop\SynchronizationBundle\Exception\RabbitRetryMessageException;
|
|
use Query\Operator;
|
|
use Query\QueryBuilder;
|
|
use Symfony\Contracts\Service\Attribute\Required;
|
|
|
|
class UserSynchronizer extends BaseSynchronizer implements SynchronizerOutInterface
|
|
{
|
|
protected static string $type = 'user';
|
|
public static string $typeGroups = 'users_group';
|
|
|
|
#[Required]
|
|
public ZNZApi $znzApi;
|
|
#[Required]
|
|
public TokenGenerator $tokenGenerator;
|
|
#[Required]
|
|
public ContextManager $contextManager;
|
|
#[Required]
|
|
public PasswordResetAdminEmail $passwordResetAdminEmail;
|
|
|
|
public static function getPriority(): int
|
|
{
|
|
return 99;
|
|
}
|
|
|
|
public static function getHandledTables(): array
|
|
{
|
|
return [
|
|
'ZakaznickaSkupina' => 'processUserGroup',
|
|
'Zakaznici' => 'processUser',
|
|
'Adresy' => 'processUserAddress',
|
|
'CenoveUrovneVazby' => 'processUserGroupPriceListRelation',
|
|
];
|
|
}
|
|
|
|
public function useTestConnection(): bool
|
|
{
|
|
return !$this->configuration->useProductionHelios();
|
|
}
|
|
|
|
public static function getIdField(): ?string
|
|
{
|
|
return 'IdZakaznik';
|
|
}
|
|
|
|
public function processToHelios(): void
|
|
{
|
|
if (isLocalDevelopment()) {
|
|
return;
|
|
}
|
|
|
|
$lastSyncTime = $this->getLastSyncTime();
|
|
|
|
$orSpecs = ['zu.id_znz IS NULL'];
|
|
if ($lastSyncTime) {
|
|
$orSpecs[] = 'u.date_updated IS NOT NULL AND u.date_updated > :filterDate';
|
|
}
|
|
|
|
$qb = sqlQueryBuilder()
|
|
->select('u.*, zu.id_znz, zu.id_znz_invoice, zu.id_znz_delivery')
|
|
->from('users', 'u')
|
|
->leftJoin('u', 'znz_users', 'zu', 'zu.id_user = u.id')
|
|
->andWhere(
|
|
Operator::andX(
|
|
$this->getUsersToHeliosSpec(),
|
|
// podminky pro zapis uzivatele
|
|
Operator::orX($orSpecs)
|
|
)
|
|
)
|
|
// order by date_updated with newly registered at the beginning
|
|
->orderBySql('zu.id_znz IS NULL DESC, u.date_updated ASC')
|
|
->groupBy('u.id');
|
|
|
|
if ($lastSyncTime) {
|
|
$qb->setParameter('filterDate', $lastSyncTime->format('Y-m-d H:i:s'));
|
|
}
|
|
|
|
// max 250 per one sync run
|
|
$qb->setMaxResults(250);
|
|
|
|
$updateLastSyncTime = null;
|
|
foreach ($qb->execute() as $item) {
|
|
$user = new \User();
|
|
$user->loadData($item);
|
|
|
|
$userData = $this->getUserData($user, !empty($item['id_znz']) ? (int) $item['id_znz'] : null);
|
|
|
|
// save date_updated of last synchronized item
|
|
if (!empty($item['id_znz']) && !empty($item['date_updated'])) {
|
|
$updateLastSyncTime = (new \DateTime($item['date_updated']))->getTimestamp();
|
|
}
|
|
|
|
try {
|
|
$znzId = ZNZUtil::withRetryStrategy(fn () => $this->getZNZApi()->updateUser($userData), false);
|
|
} catch (\Exception $e) {
|
|
$this->logger->log($e);
|
|
continue;
|
|
}
|
|
|
|
if (empty($item['id_znz'])) {
|
|
$this->znzUtil->createMapping(self::$type, $znzId, (int) $item['id']);
|
|
}
|
|
|
|
$addresses = $this->getUserAddresses(
|
|
$user,
|
|
!empty($item['id_znz_invoice']) ? (int) $item['id_znz_invoice'] : null,
|
|
!empty($item['id_znz_delivery']) ? (int) $item['id_znz_delivery'] : null
|
|
);
|
|
|
|
$invoiceAddress = $addresses['invoice'];
|
|
$deliveryAddress = $addresses['delivery'];
|
|
|
|
// pokud uz je fakturacni adresa v Heliosu zalozena, nebo je vyplnena adresa na e-shopu
|
|
if ($item['id_znz_invoice'] || !empty($invoiceAddress['firstname'])) {
|
|
try {
|
|
$znzInvoiceId = ZNZUtil::withRetryStrategy(fn () => $this->getZNZApi()->updateUserAddress($invoiceAddress), false);
|
|
} catch (\Exception $e) {
|
|
$this->logger->log($e);
|
|
}
|
|
|
|
if (empty($item['id_znz_invoice']) && isset($znzInvoiceId)) {
|
|
sqlQueryBuilder()
|
|
->update('znz_users')
|
|
->directValues(['id_znz_invoice' => $znzInvoiceId])
|
|
->where(Operator::equals(['id_user' => $user->id]))
|
|
->execute();
|
|
}
|
|
}
|
|
|
|
// pokud uz je dorucovaci adresa v Heliosu zalozena, nebo je vyplnena adresa na e-shopu
|
|
if ($item['id_znz_delivery'] || !empty($deliveryAddress['firstname'])) {
|
|
try {
|
|
$znzDeliveryId = ZNZUtil::withRetryStrategy(fn () => $this->getZNZApi()->updateUserAddress($deliveryAddress), false);
|
|
} catch (\Exception $e) {
|
|
$this->logger->log($e);
|
|
}
|
|
|
|
if (empty($item['id_znz_delivery']) && isset($znzDeliveryId)) {
|
|
sqlQueryBuilder()
|
|
->update('znz_users')
|
|
->directValues(['id_znz_delivery' => $znzDeliveryId])
|
|
->where(Operator::equals(['id_user' => $user->id]))
|
|
->execute();
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($updateLastSyncTime) {
|
|
$this->updateLastSyncTime($updateLastSyncTime);
|
|
}
|
|
}
|
|
|
|
public function getUserData(\User $user, ?int $znzId = null): array
|
|
{
|
|
$user->fetchAddresses();
|
|
|
|
$data = [
|
|
'email' => $user->email,
|
|
'firstname' => $user->invoice['name'],
|
|
'middlename' => '',
|
|
'lastname' => $user->invoice['surname'],
|
|
'group_id' => $this->getUserGroupId($user),
|
|
'_website' => $this->getUserWebsite($user),
|
|
'helios_customer_id' => $znzId,
|
|
'helios_activity_type' => null,
|
|
'helios_legal_form' => 2, // 0=Právnická osoba 1=Fyzická osoba 2=Soukromá osoba 3=Neurčeno
|
|
];
|
|
|
|
return $data;
|
|
}
|
|
|
|
protected function processUser(array $item): void
|
|
{
|
|
$userId = $this->znzUtil->getMapping(self::$type, $item['IdZakaznik']);
|
|
|
|
if ($item['meta']['delete']) {
|
|
if ($userId) {
|
|
sqlQueryBuilder()
|
|
->delete('users')
|
|
->where(Operator::equals(['id' => $userId]))
|
|
->execute();
|
|
|
|
$this->logger->activity(sprintf('Proběhlo smazání uživatele: %s (%s)', $userId, $item['email'] ?? ''), [
|
|
'item' => $item,
|
|
]);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (empty($item['email'])) {
|
|
return;
|
|
}
|
|
|
|
if (!$userId) {
|
|
$registrationData = [
|
|
'email' => $item['email'],
|
|
'passw' => !empty($item['HashHeslo']) ? $item['HashHeslo'] : '',
|
|
'date_reg' => (new \DateTime())->format('Y-m-d H:i:s'),
|
|
];
|
|
|
|
try {
|
|
$userId = sqlGetConnection()->transactional(function () use ($item, $registrationData) {
|
|
sqlQueryBuilder()
|
|
->insert('users')
|
|
->directValues($registrationData)
|
|
->execute();
|
|
|
|
$userId = (int) sqlInsertId();
|
|
|
|
$this->znzUtil->createMapping(self::$type, $item['IdZakaznik'], $userId);
|
|
|
|
return $userId;
|
|
});
|
|
} catch (UniqueConstraintViolationException $e) {
|
|
if ($this->tryMergeWithNewsletterUser($userId, $registrationData)) {
|
|
$this->znzUtil->createMapping(self::$type, $item['IdZakaznik'], $userId);
|
|
} else {
|
|
throw new ZNZException(
|
|
sprintf('Unable to create user because of duplicated email: %s:%s', $item['IdZakaznik'], $item['email']),
|
|
[
|
|
'user' => $item,
|
|
]
|
|
);
|
|
}
|
|
}
|
|
|
|
if ($this->configuration->isB2BShop()) {
|
|
$this->activateUserB2BFeeds($userId);
|
|
}
|
|
}
|
|
|
|
$hasEmptyPassword = sqlQueryBuilder()
|
|
->select('1')
|
|
->from('users')
|
|
->where(Operator::equals(['id' => $userId, 'passw' => '']))
|
|
->execute()->fetchOne();
|
|
|
|
$update = [
|
|
'id_language' => $this->getUserLanguageByWebsite($item['IdWebsite']),
|
|
'email' => $item['email'],
|
|
];
|
|
|
|
// pokud se nejedna o B2B shop, tak aktualizuju i figure zakaznika
|
|
if (!$this->configuration->isB2BShop()) {
|
|
$update['figure'] = $item['Aktivni'] ? 'Y' : 'N';
|
|
}
|
|
|
|
if ($hasEmptyPassword && !empty($item['HashHeslo'])) {
|
|
$update['passw'] = $item['HashHeslo'];
|
|
}
|
|
|
|
try {
|
|
sqlQueryBuilder()
|
|
->update('users')
|
|
->directValues($update)
|
|
->where(Operator::equals(['id' => $userId]))
|
|
->execute();
|
|
} catch (UniqueConstraintViolationException $e) {
|
|
if (!$this->tryMergeWithNewsletterUser($userId, $update)) {
|
|
throw new ZNZException(
|
|
sprintf('Unable to update user "%s" because of duplicated email: %s:%s', $userId, $item['IdZakaznik'], $item['email']),
|
|
[
|
|
'item' => $item,
|
|
'userId' => $userId,
|
|
]
|
|
);
|
|
}
|
|
}
|
|
|
|
$this->updateUserGroup($userId, $item['IdZakaznickaSkupina']);
|
|
$this->updateUserData($userId, $item);
|
|
|
|
if ($this->configuration->isB2BShop()) {
|
|
$this->activateB2BUser($userId, $item);
|
|
}
|
|
}
|
|
|
|
protected function processUserAddress(array $item): void
|
|
{
|
|
if (!($mapping = $this->znzUtil->getUserMapping($item['IdZakaznik']))) {
|
|
return;
|
|
}
|
|
|
|
if ($item['meta']['delete']) {
|
|
return;
|
|
}
|
|
|
|
$prefix = '';
|
|
$mappingField = 'id_znz_invoice';
|
|
if (!$item['Fakturacni']) {
|
|
$prefix = 'delivery_';
|
|
$mappingField = 'id_znz_delivery';
|
|
}
|
|
|
|
$userName = $this->znzUtil->getUserNameParts($item['Nazev']);
|
|
|
|
$update = [
|
|
$prefix.'name' => $userName['name'],
|
|
$prefix.'surname' => $userName['surname'],
|
|
$prefix.'firm' => $item['DruhyNazev'],
|
|
$prefix.'city' => $item['Misto'],
|
|
$prefix.'street' => $item['Ulice'],
|
|
$prefix.'zip' => $item['PSC'],
|
|
$prefix.'country' => $this->znzUtil->getCountryCodeForHelios($item['IdZeme'] ?? Contexts::get(CountryContext::class)->getDefaultId()),
|
|
$prefix.'phone' => $item['Telefon'],
|
|
];
|
|
|
|
if ($item['Fakturacni']) {
|
|
if (!empty($item['DIC'])) {
|
|
$update[$prefix.'dic'] = trim($item['DIC']);
|
|
}
|
|
|
|
// fakturacni email
|
|
if (!empty($item['Email'])) {
|
|
$update['copy_email'] = $item['Email'];
|
|
}
|
|
}
|
|
|
|
sqlQueryBuilder()
|
|
->update('users')
|
|
->directValues($update)
|
|
->where(Operator::equals(['id' => $mapping['id_user']]))
|
|
->execute();
|
|
|
|
if (empty($mapping['id_znz_invoice'])) {
|
|
sqlQueryBuilder()
|
|
->update('znz_users')
|
|
->directValues(
|
|
[
|
|
$mappingField => $item['IdAdresa'],
|
|
]
|
|
)
|
|
->where(Operator::equals(['id_user' => $mapping['id_user']]))
|
|
->execute();
|
|
}
|
|
}
|
|
|
|
protected function processUserGroup(array $item): void
|
|
{
|
|
if ($this->isDeleteMessage($item)) {
|
|
if ($userGroupId = $this->znzUtil->getMapping(self::$typeGroups, $item['meta']['unique_id'])) {
|
|
sqlQueryBuilder()
|
|
->delete('users_groups')
|
|
->where(Operator::equals(['id' => $userGroupId]))
|
|
->execute();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (!($userGroupId = $this->znzUtil->getMapping(self::$typeGroups, $item['IdZakaznickaSkupina']))) {
|
|
sqlGetConnection()->transactional(function () use ($item) {
|
|
sqlQueryBuilder()
|
|
->insert('users_groups')
|
|
->directValues(
|
|
[
|
|
'name' => $item['Nazev'],
|
|
]
|
|
)->execute();
|
|
|
|
$userGroupId = (int) sqlInsertId();
|
|
|
|
$this->znzUtil->createMapping(self::$typeGroups, $item['IdZakaznickaSkupina'], $userGroupId);
|
|
|
|
return $userGroupId;
|
|
});
|
|
}
|
|
|
|
try {
|
|
sqlQueryBuilder()
|
|
->update('users_groups')
|
|
->directValues(
|
|
[
|
|
'name' => $item['Nazev'],
|
|
'descr' => $item['Cislo'],
|
|
]
|
|
)
|
|
->where(Operator::equals(['id' => $userGroupId]))
|
|
->execute();
|
|
} catch (UniqueConstraintViolationException $e) {
|
|
sqlQueryBuilder()
|
|
->update('users_groups')
|
|
->directValues(
|
|
[
|
|
'name' => "{$item['Nazev']} (2)",
|
|
'descr' => $item['Cislo'],
|
|
]
|
|
)
|
|
->where(Operator::equals(['id' => $userGroupId]))
|
|
->execute();
|
|
}
|
|
}
|
|
|
|
public function processUserGroupPriceListRelation(array $item): void
|
|
{
|
|
// pokud se nejedna o B2B rezim a poradi je vetsi jak 1, tak to ignoruju
|
|
if (!$this->configuration->isB2BMode() && ($item['Poradi'] ?? null) > 1) {
|
|
return;
|
|
}
|
|
|
|
if (!($userGroupId = $this->znzUtil->getMapping(self::$typeGroups, $item['IdZakaznickaSkupina']))) {
|
|
throw new RabbitRetryMessageException('User group not found');
|
|
}
|
|
|
|
if (!($priceListId = $this->znzUtil->getMapping(PriceListSynchronizer::getType(), $item['CenovaUroven']))) {
|
|
throw new RabbitRetryMessageException('Price list not found');
|
|
}
|
|
|
|
$update = ['id_pricelist' => $priceListId];
|
|
|
|
if ($this->configuration->isB2BShop()) {
|
|
$data = $this->getUserGroupData($userGroupId);
|
|
$data['znz']['stores'][$item['Poradi'] ?? 0] = null;
|
|
if (!empty($item['IdSklad'])) {
|
|
if ($storeId = $this->znzUtil->getMapping('store', $item['IdSklad'])) {
|
|
$data['znz']['stores'][$item['Poradi'] ?? 0] = $storeId;
|
|
}
|
|
}
|
|
$update['data'] = json_encode($data);
|
|
}
|
|
|
|
sqlQueryBuilder()
|
|
->update('users_groups')
|
|
->directValues($update)
|
|
->where(Operator::equals(['id' => $userGroupId]))
|
|
->execute();
|
|
}
|
|
|
|
public function getUserAddresses(\User $user, ?int $znzInvoiceId = null, ?int $znzDeliveryId = null): array
|
|
{
|
|
// nacitam z masteru, protoze se stalo, ze se uzivatel registrovat v 14:40:58 a v 14:41:00 se spustila sync, ktera
|
|
// ho zacala odesilat, ale fetchAddresses sel na slave, kde ten uzivatel jeste chybel a timpadem se udaje nenacetly
|
|
QueryHint::withRouteToMaster(fn () => $user->fetchAddresses());
|
|
|
|
return [
|
|
'invoice' => $this->getUserAddress($user, $znzInvoiceId),
|
|
'delivery' => $this->getUserAddress($user, $znzDeliveryId, 'delivery'),
|
|
];
|
|
}
|
|
|
|
private function getUserGroupId(\User $user): int
|
|
{
|
|
$groupIds = $this->configuration->getSettings()['user']['groupId'] ?? [];
|
|
|
|
$groupId = $groupIds[$user->id_language] ?? null;
|
|
if (empty($groupId)) {
|
|
$groupId = reset($groupIds);
|
|
if (!empty($groupId)) {
|
|
return (int) $groupId;
|
|
}
|
|
|
|
return 80;
|
|
}
|
|
|
|
return (int) $groupId;
|
|
}
|
|
|
|
private function getUserAddress(\User $user, ?int $znzId, string $type = 'invoice'): array
|
|
{
|
|
return [
|
|
'helios_addr_id' => $znzId,
|
|
'firstname' => $user->{$type}['name'],
|
|
'middlename' => '',
|
|
'lastname' => $user->{$type}['surname'],
|
|
'company' => $user->{$type}['firm'],
|
|
'street' => $user->{$type}['street'],
|
|
'city' => $user->{$type}['city'],
|
|
'postcode' => $user->{$type}['zip'],
|
|
'telephone' => $user->{$type}['phone'],
|
|
'vat_id' => $user->invoice['dic'],
|
|
'helios_company_registration_number' => $user->invoice['ico'],
|
|
'region_id' => '',
|
|
'country_id' => $this->getUserCountry($user, $type),
|
|
'_email' => $user->invoice['email'],
|
|
'_website' => $this->getUserWebsite($user),
|
|
'_address_default_billing_' => $type === 'invoice' ? 1 : 0,
|
|
'_address_default_shipping_' => $type === 'delivery' ? 1 : 0,
|
|
];
|
|
}
|
|
|
|
private function getUserWebsite(\User $user): string
|
|
{
|
|
return $this->znzUtil->getCurrentWebsite(
|
|
$this->getUserLanguage($user)
|
|
);
|
|
}
|
|
|
|
private function getUserLanguage(\User $user): string
|
|
{
|
|
$language = $user->id_language ?: Contexts::get(LanguageContext::class)->getDefaultId();
|
|
if (empty($user->id_language) && !empty($user->invoice['country'])) {
|
|
$language = match ($user->invoice['country']) {
|
|
'CZ' => 'cs',
|
|
'SK' => 'sk',
|
|
'IT' => 'it',
|
|
'FR' => 'fr',
|
|
'DE' => 'de',
|
|
default => Contexts::get(LanguageContext::class)->getDefaultId(),
|
|
};
|
|
}
|
|
|
|
return $language;
|
|
}
|
|
|
|
private function getUserCountry(\User $user, string $type): string
|
|
{
|
|
$country = $user->{$type}['country'];
|
|
|
|
if (empty($country)) {
|
|
$country = match ($this->getUserLanguage($user)) {
|
|
'cs' => 'CZ',
|
|
'sk' => 'SK',
|
|
'it' => 'IT',
|
|
'fr' => 'FR',
|
|
'de' => 'DE',
|
|
default => Contexts::get(CountryContext::class)->getDefaultId(),
|
|
};
|
|
}
|
|
|
|
return $this->znzUtil->getCountryCodeForHelios($country);
|
|
}
|
|
|
|
private function getUserLanguageByWebsite(string $website): string
|
|
{
|
|
$websites = $this->configuration->getSupportedWebsites();
|
|
|
|
$language = reset($websites)['language'] ?? Contexts::get(LanguageContext::class)->getDefaultId();
|
|
if ($websites[$website] ?? false) {
|
|
$language = $websites[$website]['language'] ?? $language;
|
|
}
|
|
|
|
if (is_array($language)) {
|
|
$language = reset($language);
|
|
}
|
|
|
|
return $language;
|
|
}
|
|
|
|
private function updateUserData(int $userId, array $item): void
|
|
{
|
|
$turnoverData = [];
|
|
if (!empty($item['SlevoveMeze'])) {
|
|
$turnoverData = [
|
|
'slevaProcentem' => $item['slevaProcentem'],
|
|
'MenaObratu' => $item['MenaObratu'],
|
|
'Obrat' => $item['Obrat'],
|
|
'SledovatObratDnu' => $item['SledovatObratDnu'],
|
|
'SlevoveMeze' => json_decode($item['SlevoveMeze'] ?: '', true) ?: [],
|
|
];
|
|
}
|
|
|
|
$data = [
|
|
'feeds' => [
|
|
'ObrazkyPovoleny' => $item['ObrazkyPovoleny'] ?? false,
|
|
'PopiskyPovoleny' => $item['PopiskyPovoleny'] ?? false,
|
|
],
|
|
'turnoverData' => $turnoverData,
|
|
];
|
|
|
|
$user = new \User();
|
|
$user->id = $userId;
|
|
$user->setCustomData('znz', $data);
|
|
}
|
|
|
|
private function updateUserGroup(int $userId, $znzUserGroupId): void
|
|
{
|
|
$znzGroups = array_map(fn ($x) => $x['id_users_group'], sqlQueryBuilder()
|
|
->select('id_users_group')
|
|
->from('znz_users_groups')
|
|
->execute()->fetchAllAssociative());
|
|
|
|
if (!empty($znzGroups)) {
|
|
sqlQueryBuilder()
|
|
->delete('users_groups_relations')
|
|
->andWhere(Operator::equals(['id_user' => $userId]))
|
|
->andWhere(Operator::inIntArray($znzGroups, 'id_group'))
|
|
->execute();
|
|
}
|
|
|
|
$userGroupId = $this->znzUtil->getMapping(self::$typeGroups, $znzUserGroupId);
|
|
|
|
// pokud mam ZNZ Group ID, ale nepodarilo se najit skupinu na shopu, tak zaloguju chybu do activity logu
|
|
if (!empty($znzUserGroupId) && !$userGroupId) {
|
|
$this->logger->activity(
|
|
sprintf('Uživatele "%s" se nepodařilo zařadit do skupiny "%s", protože skupina neexistuje!', $userId, $znzUserGroupId),
|
|
[
|
|
'userId' => $userId,
|
|
'znzGroupId' => $znzUserGroupId,
|
|
]
|
|
);
|
|
}
|
|
|
|
if ($userGroupId) {
|
|
$this->setUserGroup($userId, $userGroupId);
|
|
}
|
|
}
|
|
|
|
private function setUserGroup(int $userId, int $userGroupId): void
|
|
{
|
|
try {
|
|
sqlQueryBuilder()
|
|
->insert('users_groups_relations')
|
|
->directValues(
|
|
[
|
|
'id_user' => $userId,
|
|
'id_group' => $userGroupId,
|
|
]
|
|
)->execute();
|
|
} catch (UniqueConstraintViolationException) {
|
|
}
|
|
}
|
|
|
|
private function tryMergeWithNewsletterUser(?int &$userId, array $data): bool
|
|
{
|
|
$duplicatedUser = sqlQueryBuilder()
|
|
->select('id, figure, get_news, date_subscribe, date_unsubscribe')
|
|
->from('users')
|
|
->where(Operator::equals(['email' => $data['email']]))
|
|
->execute()->fetchAssociative();
|
|
|
|
if ($duplicatedUser['id'] === $userId) {
|
|
return false;
|
|
}
|
|
|
|
$isNewsletterUser = false;
|
|
// je to newsletter user
|
|
if ($duplicatedUser['figure'] === 'N' && $duplicatedUser['get_news'] === 'Y') {
|
|
$isNewsletterUser = true;
|
|
}
|
|
|
|
if (!$isNewsletterUser) {
|
|
return false;
|
|
}
|
|
|
|
$data['get_news'] = $duplicatedUser['get_news'];
|
|
$data['date_subscribe'] = $duplicatedUser['date_subscribe'];
|
|
$data['date_unsubscribe'] = $duplicatedUser['date_unsubscribe'];
|
|
|
|
$deleteDuplicatedUser = true;
|
|
if ($userId === null && $duplicatedUser['id']) {
|
|
$userId = $duplicatedUser['id'];
|
|
$deleteDuplicatedUser = false;
|
|
}
|
|
|
|
sqlGetConnection()->transactional(function () use ($duplicatedUser, $userId, $deleteDuplicatedUser, $data) {
|
|
if ($deleteDuplicatedUser) {
|
|
sqlQueryBuilder()
|
|
->delete('users')
|
|
->where(Operator::equals(['id' => $duplicatedUser['id']]))
|
|
->execute();
|
|
}
|
|
|
|
sqlQueryBuilder()
|
|
->update('users')
|
|
->directValues($data)
|
|
->where(Operator::equals(['id' => $userId]))
|
|
->execute();
|
|
});
|
|
|
|
return true;
|
|
}
|
|
|
|
private function getUserGroupData(int $userGroupId): array
|
|
{
|
|
$data = sqlQueryBuilder()
|
|
->select('data')
|
|
->from('users_groups')
|
|
->where(Operator::equals(['id' => $userGroupId]))
|
|
->execute()->fetchOne();
|
|
|
|
return json_decode($data ?: '', true) ?? [];
|
|
}
|
|
|
|
private function activateB2BUser(int $userId, array $item): void
|
|
{
|
|
// activate inactive user if they need to be assigned to a group
|
|
if (!$this->isUserActive($userId) && !empty($item['IdZakaznickaSkupina'])) {
|
|
sqlQueryBuilder()
|
|
->update('users')
|
|
->directValues(['figure' => 'Y'])
|
|
->where(Operator::equals(['id' => $userId]))
|
|
->execute();
|
|
|
|
$this->sendPasswordEmail($userId);
|
|
|
|
$this->logger->activity(
|
|
message: "Provedena aktivace B2B účtu `{$item['email']}` a odeslán mail pro nastavení hesla",
|
|
data: ['userId' => $userId],
|
|
severity: ActivityLog::SEVERITY_NOTICE
|
|
);
|
|
}
|
|
|
|
// activate B2B feeds
|
|
$this->activateUserB2BFeeds($userId);
|
|
// assign user to B2B group
|
|
$this->setUserGroup($userId, $this->configuration->getB2BGroup());
|
|
}
|
|
|
|
private function sendPasswordEmail(int $userId): void
|
|
{
|
|
if (!($user = \User::createFromId($userId))) {
|
|
return;
|
|
}
|
|
|
|
$emailService = clone $this->passwordResetAdminEmail;
|
|
|
|
$this->contextManager->activateContexts(
|
|
[LanguageContext::class => $user->id_language ?: Contexts::get(LanguageContext::class)->getDefaultId()],
|
|
function () use ($emailService, $user) {
|
|
$message = $emailService->getEmail();
|
|
$message['to'] = $user->email;
|
|
|
|
$emailService->sendEmail($message);
|
|
}
|
|
);
|
|
}
|
|
|
|
private function activateUserB2BFeeds(int $userId): void
|
|
{
|
|
if (!findModule(\Modules::XML_FEEDS_B2B)) {
|
|
return;
|
|
}
|
|
|
|
// prvotni aktivace feedu pro B2B uzivatele (vygenerovat token pokud jeste neexistuje)
|
|
sqlQueryBuilder()
|
|
->update('users')
|
|
->directValues(['feed_token' => $this->tokenGenerator->generate(15)])
|
|
->andWhere(Operator::equals(['id' => $userId]))
|
|
->andWhere('feed_token IS NULL')
|
|
->execute();
|
|
}
|
|
|
|
private function isUserActive(int $userId): bool
|
|
{
|
|
return sqlQueryBuilder()
|
|
->select('figure')
|
|
->from('users')
|
|
->where(Operator::equals(['id' => $userId]))
|
|
->sendToMaster()
|
|
->execute()->fetchOne() === 'Y';
|
|
}
|
|
|
|
private function getUsersToHeliosSpec(): callable
|
|
{
|
|
if ($this->configuration->isB2BShop()) {
|
|
// v pripade B2B uzivatele neresime viditelnost uzivatele
|
|
// protoze chceme zapsat i neaktivniho uzivatele, kterej vytvoril pozadavek na registraci
|
|
return function (QueryBuilder $qb) {
|
|
$qb->leftJoin('u', 'users_groups_relations', 'ugr', 'ugr.id_user = u.id');
|
|
|
|
return Operator::inIntArray(
|
|
array_filter([$this->configuration->getB2BGroup(), $this->configuration->getB2BRegistrationGroup()]),
|
|
'ugr.id_group'
|
|
);
|
|
};
|
|
}
|
|
|
|
// v pripade B2C zapisujeme pouze viditelne uzivatele
|
|
return Operator::equals(['u.figure' => 'Y']);
|
|
}
|
|
}
|