first commit
This commit is contained in:
300
bundles/External/HannahBundle/SAP/Synchronizer/UserSynchronizer.php
vendored
Normal file
300
bundles/External/HannahBundle/SAP/Synchronizer/UserSynchronizer.php
vendored
Normal file
@@ -0,0 +1,300 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace External\HannahBundle\SAP\Synchronizer;
|
||||
|
||||
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
|
||||
use External\HannahBundle\SAP\Exception\SAPException;
|
||||
use External\HannahBundle\SAP\Exception\SAPManyException;
|
||||
use External\HannahBundle\SAP\MappingType;
|
||||
use External\HannahBundle\SAP\Util\DataFactory\UserDataFactory;
|
||||
use External\HannahBundle\SAP\Util\SAPClient;
|
||||
use KupShop\AdminBundle\Util\ActivityLog;
|
||||
use Query\Operator;
|
||||
|
||||
class UserSynchronizer extends BaseSynchronizer
|
||||
{
|
||||
private const RETRY_COUNT_MAX = 4;
|
||||
|
||||
protected static $type = 'user';
|
||||
|
||||
/** @var SAPClient */
|
||||
private $sapClient;
|
||||
|
||||
/** @var UserDataFactory */
|
||||
private $userDataFactory;
|
||||
|
||||
/**
|
||||
* @required
|
||||
*/
|
||||
public function setUserDataFactory(UserDataFactory $userDataFactory): void
|
||||
{
|
||||
$this->userDataFactory = $userDataFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @required
|
||||
*/
|
||||
public function setSAPClient(SAPClient $sapClient): void
|
||||
{
|
||||
$this->sapClient = $sapClient;
|
||||
}
|
||||
|
||||
public function processToSAP(): void
|
||||
{
|
||||
if (isLocalDevelopment()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$lastSyncTime = $this->getLastSyncTime();
|
||||
|
||||
$orX = ['su.id_sap IS NULL'];
|
||||
if ($lastSyncTime) {
|
||||
$orX[] = 'u.date_updated IS NOT NULL AND u.date_updated >= :lastSync';
|
||||
} else {
|
||||
$orX[] = 'u.date_updated IS NOT NULL';
|
||||
}
|
||||
|
||||
$qb = sqlQueryBuilder()
|
||||
->select('u.id, su.id_sap')
|
||||
->from('users', 'u')
|
||||
->leftJoin('u', 'sap_users', 'su', 'u.id = su.id_user')
|
||||
->andWhere(Operator::equals(['u.figure' => 'Y']))
|
||||
// pokud neni vyplnene jmeno a prijmeni, tak SAP hazi chybu a nechce ho zapsat
|
||||
->andWhere('u.name != "" AND u.surname != ""')
|
||||
->andWhere(Operator::orX($orX));
|
||||
|
||||
if ($lastSyncTime) {
|
||||
$qb->addParameters(
|
||||
[
|
||||
'lastSync' => date('Y-m-d H:i:s', $lastSyncTime),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
$newlyAddedUsers = [];
|
||||
|
||||
foreach ($qb->execute() as $item) {
|
||||
if ($result = $this->updateUserToSAP($item)) {
|
||||
[$user, $isNewlyAddedUser] = $result;
|
||||
|
||||
if ($isNewlyAddedUser) {
|
||||
$newlyAddedUsers[] = $user;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->updateLastSyncTime();
|
||||
|
||||
if (!empty($newlyAddedUsers)) {
|
||||
sleep(3);
|
||||
// update data of newly added users to SAP (bcs of price level definition)
|
||||
foreach ($newlyAddedUsers as $user) {
|
||||
$this->updateNewlyAddedUserFromSAP($user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Zalozi nebo aktualizuje uzivatele v SAPu.
|
||||
*/
|
||||
public function updateUserToSAP(array $item, bool $force = false): ?array
|
||||
{
|
||||
$user = \User::createFromId($item['id']);
|
||||
|
||||
if ($force === false && $this->getUserTryCount($user) > self::RETRY_COUNT_MAX) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$isNewlyAddedUser = false;
|
||||
|
||||
try {
|
||||
$passwordInSap = $user->getCustomData()['passwordInSap'] ?? null;
|
||||
if ($item['id_sap']) {
|
||||
$this->logUserUpdate($user, 'updateUserToSAP::customerUpdate');
|
||||
// obecny update uzivatele
|
||||
$this->sapClient->customerUpdate(
|
||||
$item['id_sap'],
|
||||
$this->userDataFactory->getData(['user' => $user, 'type' => UserDataFactory::DATA_UPDATE]),
|
||||
$this->configuration->getProcessByUser($user)
|
||||
);
|
||||
|
||||
// aktualizovat heslo uzivatele, protoze si ho na shopu zmenil
|
||||
if (!empty($user->passw) && $user->passw !== $passwordInSap) {
|
||||
$this->logUserUpdate($user, 'updateUserToSAP::customerChangePassword');
|
||||
$this->sapClient->customerChangePassword($item['id_sap'], $user->passw);
|
||||
$user->setCustomData('passwordInSap', $user->passw);
|
||||
}
|
||||
|
||||
// resetovat counter pro sapUpdateTry
|
||||
$user->setCustomData('sapUpdateTry', null);
|
||||
} else {
|
||||
// zalozeni uzivatele
|
||||
try {
|
||||
$this->logUserUpdate($user, 'updateUserToSAP::customerCreate');
|
||||
$result = $this->sapClient->customerCreate(
|
||||
$this->userDataFactory->getData(['user' => $user]),
|
||||
$this->configuration->getProcessByUser($user)
|
||||
);
|
||||
// resetovat counter pro sapUpdateTry
|
||||
$user->setCustomData('sapUpdateTry', null);
|
||||
} catch (SAPManyException $e) {
|
||||
if ($e->hasExceptionWithCode(['477'])) {
|
||||
$sapUserData = $user->getCustomData()['sap'] ?? [];
|
||||
$sapUserData['cards'] = [];
|
||||
$user->setCustomData('sap', $sapUserData);
|
||||
}
|
||||
|
||||
// zalogovat chybu do Activity logu
|
||||
if (!$e->hasExceptionWithCode(['020', '095'])) {
|
||||
$this->handleActivityLogError(
|
||||
$user,
|
||||
sprintf('[SAP] Chyba během zakládání uživatele "%s" v SAPu: %s', $user->email, $e->getMessage())
|
||||
);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// pokusit se nacist uz existujiciho uzivatele
|
||||
$this->logUserUpdate($user, 'updateUserToSAP::customerValidate');
|
||||
if ($result = $this->sapClient->customerValidate($user->email, $user->passw, $this->configuration->getProcessByUser($user))) {
|
||||
$result = $result->CustomerData;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($result->CustomerId)) {
|
||||
$this->createUserMapping($user, $result);
|
||||
$isNewlyAddedUser = true;
|
||||
}
|
||||
|
||||
$user->setCustomData('passwordInSap', $user->passw);
|
||||
}
|
||||
} catch (SAPException $e) {
|
||||
if (isLocalDevelopment()) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
if ($e instanceof SAPManyException) {
|
||||
// autofix duplicated sap_users
|
||||
if ($item['id_sap'] && $e->hasExceptionWithCode(['020'])) {
|
||||
$sapUsersCount = sqlQueryBuilder()
|
||||
->select('id_sap')
|
||||
->from('sap_users')
|
||||
->where(Operator::equals(['id_user' => $user->id]))
|
||||
->execute()->rowCount();
|
||||
|
||||
if ($sapUsersCount > 1) {
|
||||
sqlQueryBuilder()
|
||||
->delete('sap_users')
|
||||
->where(Operator::equals(['id_user' => $user->id, 'id_sap' => $item['id_sap']]))
|
||||
->execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->handleActivityLogError(
|
||||
$user,
|
||||
sprintf('[SAP] Nepodařilo se synchronizovat uživatele "%s": %s', $user->email, $e->getMessage())
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
$this->sentryLogger->captureException($e);
|
||||
}
|
||||
|
||||
return [$user, $isNewlyAddedUser];
|
||||
}
|
||||
|
||||
public function updateNewlyAddedUserFromSAP(\User $user): void
|
||||
{
|
||||
try {
|
||||
$this->logUserUpdate($user, 'updateNewlyAddedUserFromSAP::customerValidate');
|
||||
$result = $this->sapClient->customerValidate(
|
||||
mb_strtolower($user->email),
|
||||
$user->passw,
|
||||
$this->configuration->getProcessByUser($user)
|
||||
);
|
||||
} catch (SAPManyException $e) {
|
||||
$this->sentryLogger->captureException($e);
|
||||
|
||||
return;
|
||||
} finally {
|
||||
$this->logger->notice('updateNewlyAddedUserFromSAP result', ['UserId' => $user->id, 'UserData' => $result ?? null]);
|
||||
}
|
||||
|
||||
$customer = $result->CustomerData;
|
||||
|
||||
$this->sapUtil->updateUser($user, $customer);
|
||||
}
|
||||
|
||||
protected function getHandledFields(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
private function createUserMapping(\User $user, object $sapCustomer): void
|
||||
{
|
||||
try {
|
||||
$this->sapUtil->createMapping(MappingType::USERS, $sapCustomer->CustomerId, (int) $user->id);
|
||||
} catch (UniqueConstraintViolationException $e) {
|
||||
// pokud SAP ID pro daneho uzivatele uz ma nastavene nekdo jiny
|
||||
$duplicatedUser = sqlQueryBuilder()
|
||||
->select('u.id, u.email')
|
||||
->from('users', 'u')
|
||||
->join('u', 'sap_users', 'su', 'su.id_user = u.id')
|
||||
->andWhere(Operator::equals(['su.id_sap' => $sapCustomer->CustomerId]))
|
||||
->execute()->fetchAssociative();
|
||||
|
||||
if (!$duplicatedUser) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
if ($duplicatedUser['email'] !== $sapCustomer->PersonalData->Email) {
|
||||
sqlGetConnection()->transactional(function () use ($duplicatedUser, $user, $sapCustomer) {
|
||||
$this->sapUtil->deleteMapping(MappingType::USERS, $duplicatedUser['id']);
|
||||
$this->createUserMapping($user, $sapCustomer);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function handleActivityLogError(\User $user, string $message): void
|
||||
{
|
||||
$tryCount = $this->getUserTryCount($user);
|
||||
|
||||
// prestavam zapisivat activity log, dokud se nepodari zapis, aby to nespamovalo silene moc
|
||||
if ($tryCount > self::RETRY_COUNT_MAX) {
|
||||
return;
|
||||
}
|
||||
|
||||
// zapisu do activity logu
|
||||
$this->activityLog->addActivityLog(
|
||||
ActivityLog::SEVERITY_ERROR,
|
||||
ActivityLog::TYPE_SYNC,
|
||||
$message
|
||||
);
|
||||
|
||||
// updatuju counter na uzivateli
|
||||
$user->setCustomData('sapUpdateTry', ++$tryCount);
|
||||
}
|
||||
|
||||
private function getUserTryCount(\User $user): int
|
||||
{
|
||||
return (int) ($user->getCustomData(true)['sapUpdateTry'] ?? 1);
|
||||
}
|
||||
|
||||
private function logUserUpdate(\User $user, string $source): void
|
||||
{
|
||||
if (isLocalDevelopment()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->logger->notice(
|
||||
message: 'SAP: User update to SAP; ID: '.$user->id,
|
||||
context: [
|
||||
'userId' => $user->id,
|
||||
'email' => $user->email,
|
||||
'source' => $source,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user