diff --git a/config/xml/Bitrix24.Lib.ApplicationInstallations.Entity.ApplicationInstallation.dcm.xml b/config/xml/Bitrix24.Lib.ApplicationInstallations.Entity.ApplicationInstallation.dcm.xml
new file mode 100644
index 0000000..9e8c92c
--- /dev/null
+++ b/config/xml/Bitrix24.Lib.ApplicationInstallations.Entity.ApplicationInstallation.dcm.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/config/xml/Bitrix24.Lib.Bitrix24Accounts.Entity.Bitrix24Account.dcm.xml b/config/xml/Bitrix24.Lib.Bitrix24Accounts.Entity.Bitrix24Account.dcm.xml
index c2e57d9..d4baa42 100644
--- a/config/xml/Bitrix24.Lib.Bitrix24Accounts.Entity.Bitrix24Account.dcm.xml
+++ b/config/xml/Bitrix24.Lib.Bitrix24Accounts.Entity.Bitrix24Account.dcm.xml
@@ -12,6 +12,8 @@
+
+
@@ -24,6 +26,8 @@
+
+
diff --git a/config/xml/Bitrix24.SDK.Application.ApplicationStatus.dcm.xml b/config/xml/Bitrix24.SDK.Application.ApplicationStatus.dcm.xml
new file mode 100644
index 0000000..2a89139
--- /dev/null
+++ b/config/xml/Bitrix24.SDK.Application.ApplicationStatus.dcm.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/ApplicationInstallations/Entity/ApplicationInstallation.php b/src/ApplicationInstallations/Entity/ApplicationInstallation.php
new file mode 100644
index 0000000..3aba323
--- /dev/null
+++ b/src/ApplicationInstallations/Entity/ApplicationInstallation.php
@@ -0,0 +1,447 @@
+applicationInstalled($applicationToken);
+ * $applicationInstallation->applicationInstalled($applicationToken);.
+ */
+class ApplicationInstallation extends AggregateRoot implements ApplicationInstallationInterface
+{
+ private ?string $applicationToken = null;
+
+ private readonly CarbonImmutable $createdAt;
+
+ private CarbonImmutable $updatedAt;
+
+ private ApplicationInstallationStatus $status = ApplicationInstallationStatus::new;
+
+ public function __construct(
+ private readonly Uuid $id,
+ private readonly Uuid $bitrix24AccountId,
+ private ApplicationStatus $applicationStatus,
+ private PortalLicenseFamily $portalLicenseFamily,
+ private ?int $portalUsersCount,
+ private ?Uuid $contactPersonId,
+ private ?Uuid $bitrix24PartnerContactPersonId,
+ private ?Uuid $bitrix24PartnerId,
+ private ?string $externalId,
+ private ?string $comment = null,
+ private $isEmitApplicationInstallationCreatedEvent = false
+ ) {
+ $this->createdAt = new CarbonImmutable();
+ $this->updatedAt = new CarbonImmutable();
+ $this->addApplicationCreatedEventIfNeeded($this->isEmitApplicationInstallationCreatedEvent);
+ }
+
+ #[\Override]
+ public function getId(): Uuid
+ {
+ return $this->id;
+ }
+
+ #[\Override]
+ public function getCreatedAt(): CarbonImmutable
+ {
+ return $this->createdAt;
+ }
+
+ #[\Override]
+ public function getUpdatedAt(): CarbonImmutable
+ {
+ return $this->updatedAt;
+ }
+
+ #[\Override]
+ public function getBitrix24AccountId(): Uuid
+ {
+ return $this->bitrix24AccountId;
+ }
+
+ #[\Override]
+ public function getContactPersonId(): ?Uuid
+ {
+ return $this->contactPersonId;
+ }
+
+ #[\Override]
+ public function getBitrix24PartnerContactPersonId(): ?Uuid
+ {
+ return $this->bitrix24PartnerContactPersonId;
+ }
+
+ #[\Override]
+ public function getBitrix24PartnerId(): ?Uuid
+ {
+ return $this->bitrix24PartnerId;
+ }
+
+ #[\Override]
+ public function getExternalId(): ?string
+ {
+ return $this->externalId;
+ }
+
+ #[\Override]
+ public function setExternalId(?string $externalId): void
+ {
+ if ('' === $externalId) {
+ throw new InvalidArgumentException('ExternalId cannot be empty string');
+ }
+
+ $this->externalId = $externalId;
+ }
+
+ #[\Override]
+ public function getStatus(): ApplicationInstallationStatus
+ {
+ return $this->status;
+ }
+
+ #[\Override]
+ public function applicationInstalled(?string $applicationToken = null): void
+ {
+ if (
+ ApplicationInstallationStatus::new !== $this->status
+ && ApplicationInstallationStatus::blocked !== $this->status
+ ) {
+ throw new LogicException(
+ sprintf(
+ 'installation was interrupted because status must be in new or blocked,but your status is %s',
+ $this->status->value
+ )
+ );
+ }
+
+ if (null !== $applicationToken) {
+ $this->guardEmptyToken($applicationToken);
+ $this->applicationToken = $applicationToken;
+ }
+
+ $this->status = ApplicationInstallationStatus::active;
+ $this->updatedAt = new CarbonImmutable();
+
+ $this->events[] = new ApplicationInstallationFinishedEvent(
+ $this->id,
+ $this->updatedAt,
+ $this->bitrix24AccountId,
+ $this->portalLicenseFamily,
+ $this->contactPersonId,
+ $this->bitrix24PartnerContactPersonId,
+ $this->bitrix24PartnerId
+ );
+ }
+
+ #[\Override]
+ public function applicationUninstalled(?string $applicationToken = null): void
+ {
+ if (
+ ApplicationInstallationStatus::active !== $this->status
+ && ApplicationInstallationStatus::blocked !== $this->status
+ ) {
+ throw new LogicException(
+ sprintf(
+ 'installation was interrupted because status must be in active or blocked, but your status is %s',
+ $this->status->value
+ )
+ );
+ }
+
+ if (null !== $applicationToken) {
+ $this->guardEmptyToken($applicationToken);
+ $this->guardTokenMismatch($applicationToken);
+ }
+
+ $this->status = ApplicationInstallationStatus::deleted;
+ $this->updatedAt = new CarbonImmutable();
+
+ $this->events[] = new ApplicationInstallationUninstalledEvent(
+ $this->id,
+ $this->updatedAt,
+ $this->bitrix24AccountId,
+ $this->contactPersonId,
+ $this->bitrix24PartnerId,
+ $this->bitrix24PartnerId,
+ $this->externalId
+ );
+ }
+
+ #[\Override]
+ public function markAsActive(?string $comment): void
+ {
+ if (ApplicationInstallationStatus::blocked !== $this->status) {
+ throw new LogicException(
+ sprintf(
+ 'you must be in status blocked to complete the installation, now status is «%s»',
+ $this->status->value
+ )
+ );
+ }
+
+ $this->status = ApplicationInstallationStatus::active;
+ $this->comment = $comment;
+ $this->updatedAt = new CarbonImmutable();
+
+ $this->events[] = new ApplicationInstallationUnblockedEvent(
+ $this->id,
+ $this->updatedAt,
+ $this->comment
+ );
+ }
+
+ #[\Override]
+ public function markAsBlocked(?string $comment): void
+ {
+ if (
+ ApplicationInstallationStatus::new !== $this->status
+ && ApplicationInstallationStatus::active !== $this->status
+ ) {
+ throw new LogicException(sprintf(
+ 'You can block application installation only in status new or active,but your status is «%s»',
+ $this->status->value
+ ));
+ }
+
+ $this->status = ApplicationInstallationStatus::blocked;
+ $this->comment = $comment;
+ $this->updatedAt = new CarbonImmutable();
+
+ $this->events[] = new ApplicationInstallationBlockedEvent(
+ $this->id,
+ new CarbonImmutable(),
+ $this->comment
+ );
+ }
+
+ #[\Override]
+ public function getApplicationStatus(): ApplicationStatus
+ {
+ return $this->applicationStatus;
+ }
+
+ #[\Override]
+ public function changeApplicationStatus(ApplicationStatus $applicationStatus): void
+ {
+ if ($this->applicationStatus !== $applicationStatus) {
+ $this->applicationStatus = $applicationStatus;
+ $this->updatedAt = new CarbonImmutable();
+
+ $this->events[] = new Events\ApplicationInstallationApplicationStatusChangedEvent(
+ $this->id,
+ $this->updatedAt,
+ $applicationStatus
+ );
+ }
+ }
+
+ #[\Override]
+ public function getPortalLicenseFamily(): PortalLicenseFamily
+ {
+ return $this->portalLicenseFamily;
+ }
+
+ #[\Override]
+ public function changePortalLicenseFamily(PortalLicenseFamily $portalLicenseFamily): void
+ {
+ if ($this->portalLicenseFamily !== $portalLicenseFamily) {
+ $this->updatedAt = new CarbonImmutable();
+ $this->portalLicenseFamily = $portalLicenseFamily;
+
+ $this->events[] = new Events\ApplicationInstallationPortalLicenseFamilyChangedEvent(
+ $this->id,
+ $this->updatedAt,
+ $this->portalLicenseFamily,
+ $portalLicenseFamily
+ );
+ }
+ }
+
+ #[\Override]
+ public function getPortalUsersCount(): ?int
+ {
+ return $this->portalUsersCount;
+ }
+
+ #[\Override]
+ public function changePortalUsersCount(int $usersCount): void
+ {
+ if ($usersCount < 0) {
+ throw new \InvalidArgumentException('Users count can not be negative');
+ }
+
+ if ($this->portalUsersCount !== $usersCount) {
+ $this->portalUsersCount = $usersCount;
+ $this->updatedAt = new CarbonImmutable();
+
+ $this->events[] = new Events\ApplicationInstallationPortalUsersCountChangedEvent(
+ $this->id,
+ $this->updatedAt,
+ $this->portalUsersCount,
+ $usersCount
+ );
+ }
+ }
+
+ #[\Override]
+ public function getComment(): ?string
+ {
+ return $this->comment;
+ }
+
+ #[\Override]
+ public function isApplicationTokenValid(string $applicationToken): bool
+ {
+ return $this->applicationToken === $applicationToken;
+ }
+
+ #[\Override]
+ public function setApplicationToken(string $applicationToken): void
+ {
+ $this->guardEmptyToken($applicationToken);
+
+ $this->updatedAt = new CarbonImmutable();
+ $this->applicationToken = $applicationToken;
+ }
+
+ #[\Override]
+ public function linkContactPerson(Uuid $uuid): void
+ {
+ $this->updatedAt = new CarbonImmutable();
+ $this->contactPersonId = $uuid;
+
+ $this->events[] = new ApplicationInstallationContactPersonLinkedEvent(
+ $this->id,
+ $this->updatedAt,
+ $this->contactPersonId
+ );
+ }
+
+ #[\Override]
+ public function unlinkContactPerson(): void
+ {
+ $this->updatedAt = new CarbonImmutable();
+
+ $this->events[] = new Events\ApplicationInstallationContactPersonUnlinkedEvent(
+ $this->id,
+ $this->updatedAt,
+ $this->contactPersonId
+ );
+
+ $this->contactPersonId = null;
+ }
+
+ #[\Override]
+ public function linkBitrix24PartnerContactPerson(Uuid $uuid): void
+ {
+ $this->updatedAt = new CarbonImmutable();
+ $this->bitrix24PartnerContactPersonId = $uuid;
+
+ $this->events[] = new Events\ApplicationInstallationBitrix24PartnerContactPersonLinkedEvent(
+ $this->id,
+ $this->updatedAt,
+ $this->bitrix24PartnerContactPersonId
+ );
+ }
+
+ #[\Override]
+ public function unlinkBitrix24PartnerContactPerson(): void
+ {
+ $this->updatedAt = new CarbonImmutable();
+
+ $this->events[] = new Events\ApplicationInstallationBitrix24PartnerContactPersonUnlinkedEvent(
+ $this->id,
+ $this->updatedAt,
+ $this->bitrix24PartnerContactPersonId
+ );
+
+ $this->bitrix24PartnerContactPersonId = null;
+ }
+
+ #[\Override]
+ public function linkBitrix24Partner(Uuid $uuid): void
+ {
+ $this->updatedAt = new CarbonImmutable();
+ $this->bitrix24PartnerId = $uuid;
+
+ $this->events[] = new Events\ApplicationInstallationBitrix24PartnerLinkedEvent(
+ $this->id,
+ $this->updatedAt,
+ $this->bitrix24PartnerId
+ );
+ }
+
+ #[\Override]
+ public function unlinkBitrix24Partner(): void
+ {
+ $this->updatedAt = new CarbonImmutable();
+
+ $this->events[] = new Events\ApplicationInstallationBitrix24PartnerUnlinkedEvent(
+ $this->id,
+ $this->updatedAt,
+ $this->bitrix24PartnerId
+ );
+
+ $this->bitrix24PartnerId = null;
+ }
+
+ private function addApplicationCreatedEventIfNeeded(bool $isEmitCreatedEvent): void
+ {
+ if ($isEmitCreatedEvent) {
+ // Создание события и добавление его в массив событий
+ $this->events[] = new ApplicationInstallationCreatedEvent(
+ $this->id,
+ $this->createdAt,
+ $this->bitrix24AccountId
+ );
+ }
+ }
+
+ private function guardTokenMismatch(string $applicationToken): void
+ {
+ if (!$this->isApplicationTokenValid($applicationToken)) {
+ throw new InvalidArgumentException(
+ sprintf(
+ 'application token «%s» mismatch with application token «%s» for application installation «%s»',
+ $applicationToken,
+ $this->applicationToken,
+ $this->id->toRfc4122()
+ )
+ );
+ }
+ }
+
+ private function guardEmptyToken(string $applicationToken): void
+ {
+ if ('' === $applicationToken) {
+ throw new InvalidArgumentException('application token cannot be empty');
+ }
+ }
+}
diff --git a/src/ApplicationInstallations/Infrastructure/Doctrine/ApplicationInstallationRepository.php b/src/ApplicationInstallations/Infrastructure/Doctrine/ApplicationInstallationRepository.php
new file mode 100644
index 0000000..df950b4
--- /dev/null
+++ b/src/ApplicationInstallations/Infrastructure/Doctrine/ApplicationInstallationRepository.php
@@ -0,0 +1,165 @@
+getClassMetadata(ApplicationInstallation::class));
+ }
+
+ #[\Override]
+ public function save(ApplicationInstallationInterface $applicationInstallation): void
+ {
+ $this->getEntityManager()->persist($applicationInstallation);
+ }
+
+ #[\Override]
+ public function getById(Uuid $uuid): ApplicationInstallationInterface
+ {
+ $applicationInstallation = $this->getEntityManager()->getRepository(ApplicationInstallation::class)
+ ->createQueryBuilder('appInstallation')
+ ->where('appInstallation.id = :uuid')
+ ->andWhere('appInstallation.status != :status')
+ ->setParameter('uuid', $uuid)
+ ->setParameter('status', ApplicationInstallationStatus::deleted)
+ ->getQuery()
+ ->getOneOrNullResult()
+ ;
+
+ if (null === $applicationInstallation) {
+ throw new ApplicationInstallationNotFoundException(
+ sprintf('application installed not found by id %s', $uuid->toRfc4122())
+ );
+ }
+
+ return $applicationInstallation;
+ }
+
+ #[\Override]
+ public function delete(Uuid $uuid): void
+ {
+ $applicationInstallation = $this->getEntityManager()->getRepository(ApplicationInstallation::class)->find($uuid);
+
+ if (null == $applicationInstallation) {
+ throw new ApplicationInstallationNotFoundException(
+ sprintf('Application installation with uuid %s not found', $uuid->toRfc4122())
+ );
+ }
+
+ if (ApplicationInstallationStatus::deleted !== $applicationInstallation->getStatus()) {
+ throw new InvalidArgumentException(
+ sprintf('you cannot delete application installed because you status must be deleted your status %s', $applicationInstallation->getStatus()->name)
+ );
+ }
+
+ $this->save($applicationInstallation);
+ }
+
+ #[\Override]
+ // У нас в установке аккаунтId это констрейнт, так что возращать мы должны сущность.
+ public function findByBitrix24AccountId(Uuid $uuid): ?ApplicationInstallationInterface
+ {
+ return $this->getEntityManager()->getRepository(ApplicationInstallation::class)
+ ->createQueryBuilder('appInstallation')
+ ->where('appInstallation.bitrix24AccountId = :bitrix24AccountId')
+ ->orderBy('appInstallation.createdAt', 'DESC')
+ ->setParameter('bitrix24AccountId', $uuid)
+ ->getQuery()
+ ->getOneOrNullResult()
+ ;
+ }
+
+ #[\Override]
+ public function findByExternalId(string $externalId): array
+ {
+ if ('' === trim($externalId)) {
+ throw new InvalidArgumentException('external id cannot be empty');
+ }
+
+ return $this->getEntityManager()->getRepository(ApplicationInstallation::class)
+ ->createQueryBuilder('appInstallation')
+ ->where('appInstallation.externalId = :externalId')
+ ->orderBy('appInstallation.createdAt', 'DESC')
+ ->setParameter('externalId', $externalId)
+ ->getQuery()
+ ->getResult()
+ ;
+ }
+
+ public function findActiveByAccountId(Uuid $uuid): ?ApplicationInstallationInterface
+ {
+ $activeStatuses = [
+ ApplicationInstallationStatus::new,
+ ApplicationInstallationStatus::active,
+ ];
+
+ return $this->getEntityManager()->getRepository(ApplicationInstallation::class)
+ ->createQueryBuilder('applicationInstallation')
+ ->where('applicationInstallation.bitrix24AccountId = :b24AccountId')
+ ->andWhere('applicationInstallation.status IN (:statuses)')
+ ->setParameter('b24AccountId', $uuid)
+ ->setParameter('statuses', $activeStatuses)
+ ->getQuery()
+ ->getOneOrNullResult()
+ ;
+ }
+
+ public function findActiveByApplicationToken(string $applicationToken): ?ApplicationInstallationInterface
+ {
+ $activeStatuses = [
+ ApplicationInstallationStatus::new,
+ ApplicationInstallationStatus::active,
+ ];
+
+ return $this->getEntityManager()->getRepository(ApplicationInstallation::class)
+ ->createQueryBuilder('applicationInstallation')
+ ->where('applicationInstallation.applicationToken = :applicationToken')
+ ->andWhere('applicationInstallation.status IN (:statuses)')
+ ->setParameter('applicationToken', $applicationToken)
+ ->setParameter('statuses', $activeStatuses)
+ ->getQuery()
+ ->getOneOrNullResult()
+ ;
+ }
+
+ /**
+ * Получаем активную установку приложения с помощью аккаунта.
+ *
+ * @return null|ApplicationInstallation
+ */
+ public function findActiveInstallationWithAccountByMemberId(string $memberId): ?ApplicationInstallationInterface
+ {
+ $queryBuilder = $this->createQueryBuilder('ai');
+
+ return $queryBuilder->leftJoin(
+ Bitrix24Account::class,
+ 'b24',
+ Join::WITH,
+ 'ai.bitrix24AccountId = b24.id AND b24.isMasterAccount = true'
+ )
+ ->where('b24.memberId = :memberId')
+ ->andWhere('b24.isMasterAccount = true')
+ ->andWhere('ai.status != :status')
+ ->setParameter('memberId', $memberId)
+ ->setParameter('status', ApplicationInstallationStatus::deleted)
+ ->getQuery()
+ ->getOneOrNullResult()
+ ;
+ }
+}
diff --git a/src/ApplicationInstallations/UseCase/Install/Command.php b/src/ApplicationInstallations/UseCase/Install/Command.php
new file mode 100644
index 0000000..120f803
--- /dev/null
+++ b/src/ApplicationInstallations/UseCase/Install/Command.php
@@ -0,0 +1,84 @@
+applicationInstalled($applicationToken);
+ * $applicationInstallation->applicationInstalled($applicationToken);.
+ */
+readonly class Command
+{
+ public function __construct(
+ public ApplicationStatus $applicationStatus,
+ public PortalLicenseFamily $portalLicenseFamily,
+ public ?int $portalUsersCount,
+ public ?Uuid $contactPersonId,
+ public ?Uuid $bitrix24PartnerContactPersonId,
+ public ?Uuid $bitrix24PartnerId,
+ public ?string $externalId,
+ public ?string $comment,
+ public int $bitrix24UserId,
+ public bool $isBitrix24UserAdmin,
+ public string $memberId,
+ public Domain $domain,
+ public AuthToken $authToken,
+ public int $applicationVersion,
+ public Scope $applicationScope,
+ public ?string $applicationToken = null,
+ ) {
+ $this->validate();
+ }
+
+ private function validate(): void
+ {
+ if ($this->portalUsersCount <= 0) {
+ throw new InvalidArgumentException('Portal Users count must be a positive integer.');
+ }
+
+ if ('' === $this->externalId) {
+ throw new InvalidArgumentException('External ID must be a non-empty string.');
+ }
+
+ if ('' === $this->comment) {
+ throw new InvalidArgumentException('Comment must be a non-empty string.');
+ }
+
+ if ($this->bitrix24UserId <= 0) {
+ throw new InvalidArgumentException('Bitrix24 User ID must be a positive integer.');
+ }
+
+ if ('' === $this->memberId) {
+ throw new InvalidArgumentException('Member ID must be a non-empty string.');
+ }
+
+ if ($this->applicationVersion <= 0) {
+ throw new InvalidArgumentException('Application version must be a positive integer.');
+ }
+
+ if (null !== $this->applicationToken && '' === trim($this->applicationToken)) {
+ throw new InvalidArgumentException('Application token must be a non-empty string.');
+ }
+ }
+}
diff --git a/src/ApplicationInstallations/UseCase/Install/Handler.php b/src/ApplicationInstallations/UseCase/Install/Handler.php
new file mode 100644
index 0000000..1000e54
--- /dev/null
+++ b/src/ApplicationInstallations/UseCase/Install/Handler.php
@@ -0,0 +1,124 @@
+logger->info('ApplicationInstallations.Install.start', [
+ 'externalId' => $command->externalId,
+ 'bitrix24UserId' => $command->bitrix24UserId,
+ 'isBitrix24UserAdmin' => $command->isBitrix24UserAdmin,
+ 'memberId' => $command->memberId,
+ 'applicationToken' => $command->applicationToken,
+ ]);
+
+ /** @var null|AggregateRootEventsEmitterInterface|ApplicationInstallationInterface $activeInstallation */
+ $activeInstallation = $this->applicationInstallationRepository->findActiveInstallationWithAccountByMemberId($command->memberId);
+
+ if (null !== $activeInstallation) {
+ $entitiesToFlush = [];
+
+ $activeInstallation->applicationUninstalled();
+
+ $this->applicationInstallationRepository->save($activeInstallation);
+
+ $entitiesToFlush[] = $activeInstallation;
+
+ /** @var AggregateRootEventsEmitterInterface|Bitrix24AccountInterface[] $b24Accounts */
+ $b24Accounts = $this->bitrix24AccountRepository->findByMemberId($command->memberId);
+
+ if ([] !== $b24Accounts) {
+ foreach ($b24Accounts as $b24Account) {
+ $b24Account->applicationUninstalled(null);
+ $this->bitrix24AccountRepository->save($b24Account);
+ $entitiesToFlush[] = $b24Account;
+ }
+ }
+
+ /*
+ Здесь сразу флашим так как это условие не всегда работает , и лучше сначало разобраться с аккаунтами и установщиками
+ которые нужно деактивировать , а после уже работаем с новыми сущностями.
+ */
+ $this->flusher->flush(...$entitiesToFlush);
+ }
+
+ $uuidV7 = Uuid::v7();
+ $applicationInstallationId = Uuid::v7();
+
+ $bitrix24Account = new Bitrix24Account(
+ $uuidV7,
+ $command->bitrix24UserId,
+ $command->isBitrix24UserAdmin,
+ $command->memberId,
+ $command->domain->value,
+ $command->authToken,
+ $command->applicationVersion,
+ $command->applicationScope,
+ true,
+ true
+ );
+
+ $bitrix24Account->applicationInstalled($command->applicationToken);
+
+ $this->bitrix24AccountRepository->save($bitrix24Account);
+
+ $applicationInstallation = new ApplicationInstallation(
+ $applicationInstallationId,
+ $uuidV7,
+ $command->applicationStatus,
+ $command->portalLicenseFamily,
+ $command->portalUsersCount,
+ $command->contactPersonId,
+ $command->bitrix24PartnerContactPersonId,
+ $command->bitrix24PartnerId,
+ $command->externalId,
+ $command->comment,
+ true
+ );
+
+ $applicationInstallation->applicationInstalled($command->applicationToken);
+
+ $this->applicationInstallationRepository->save($applicationInstallation);
+
+ $this->flusher->flush($applicationInstallation, $bitrix24Account);
+
+ $this->logger->info(
+ 'ApplicationInstallations.Install.Finish',
+ [
+ 'applicationId' => $applicationInstallationId,
+ 'bitrix24AccountId' => $uuidV7,
+ ]
+ );
+ }
+}
diff --git a/src/ApplicationInstallations/UseCase/OnAppInstall/Command.php b/src/ApplicationInstallations/UseCase/OnAppInstall/Command.php
new file mode 100644
index 0000000..2658e2f
--- /dev/null
+++ b/src/ApplicationInstallations/UseCase/OnAppInstall/Command.php
@@ -0,0 +1,39 @@
+validate();
+ }
+
+ private function validate(): void
+ {
+ if ('' === $this->memberId) {
+ throw new \InvalidArgumentException('Member ID must be a non-empty string.');
+ }
+
+ if ('' === $this->applicationToken) {
+ throw new \InvalidArgumentException('ApplicationToken must be a non-empty string.');
+ }
+
+ if ('' === $this->applicationStatus) {
+ throw new \InvalidArgumentException('ApplicationStatus must be a non-empty string.');
+ }
+ }
+}
diff --git a/src/ApplicationInstallations/UseCase/OnAppInstall/Handler.php b/src/ApplicationInstallations/UseCase/OnAppInstall/Handler.php
new file mode 100644
index 0000000..667a5c2
--- /dev/null
+++ b/src/ApplicationInstallations/UseCase/OnAppInstall/Handler.php
@@ -0,0 +1,64 @@
+logger->info('ApplicationInstallation.OnAppInstall.start', [
+ 'b24_domain_url' => $command->domainUrl,
+ 'b24_member_id' => $command->memberId,
+ 'b24_application_id' => $command->applicationToken,
+ 'application_status' => $command->applicationStatus,
+ ]);
+
+ /** @var null|AggregateRootEventsEmitterInterface|ApplicationInstallationInterface $applicationInstallation */
+ $applicationInstallation = $this->applicationInstallationRepository->findActiveInstallationWithAccountByMemberId($command->memberId);
+
+ $applicationStatus = new ApplicationStatus($command->applicationStatus);
+
+ $applicationInstallation->changeApplicationStatus($applicationStatus);
+
+ $applicationInstallation->setApplicationToken($command->applicationToken);
+
+ $this->applicationInstallationRepository->save($applicationInstallation);
+
+ /** @var AggregateRootEventsEmitterInterface|Bitrix24AccountInterface $bitrix24Account */
+ $bitrix24Account = $this->bitrix24AccountRepository->findMasterByMemberId(
+ $command->memberId,
+ Bitrix24AccountStatus::active,
+ );
+
+ $bitrix24Account->setApplicationToken($command->applicationToken);
+
+ $this->bitrix24AccountRepository->save($bitrix24Account);
+
+ $this->flusher->flush($applicationInstallation, $bitrix24Account);
+
+ $this->logger->info('ApplicationInstallation.OnAppInstall.finish');
+ }
+}
diff --git a/src/ApplicationInstallations/UseCase/Uninstall/Command.php b/src/ApplicationInstallations/UseCase/Uninstall/Command.php
new file mode 100644
index 0000000..84debaa
--- /dev/null
+++ b/src/ApplicationInstallations/UseCase/Uninstall/Command.php
@@ -0,0 +1,29 @@
+validate();
+ }
+
+ private function validate(): void
+ {
+ if ('' === $this->applicationToken) {
+ throw new \InvalidArgumentException('applicationToken must be a non-empty string.');
+ }
+
+ if ('' === $this->memberId) {
+ throw new \InvalidArgumentException('Member ID must be a non-empty string.');
+ }
+ }
+}
diff --git a/src/ApplicationInstallations/UseCase/Uninstall/Handler.php b/src/ApplicationInstallations/UseCase/Uninstall/Handler.php
new file mode 100644
index 0000000..273c2ba
--- /dev/null
+++ b/src/ApplicationInstallations/UseCase/Uninstall/Handler.php
@@ -0,0 +1,92 @@
+logger->info('ApplicationInstallations.Uninstall.start', [
+ 'domainUrl' => $command->domainUrl,
+ 'memberId' => $command->memberId,
+ 'applicationToken' => $command->applicationToken,
+ ]);
+
+ /** @var AggregateRootEventsEmitterInterface|ApplicationInstallationInterface $activeInstallation */
+ $activeInstallation = $this->applicationInstallationRepository->findActiveByApplicationToken($command->applicationToken);
+
+ if (null !== $activeInstallation) {
+ $this->logger->info(
+ 'ApplicationInstallations.Uninstall.Start'
+ );
+
+ $entitiesToFlush = [];
+
+ $activeInstallation->applicationUninstalled($command->applicationToken);
+
+ $this->applicationInstallationRepository->save($activeInstallation);
+
+ $entitiesToFlush[] = $activeInstallation;
+
+ /** @var AggregateRootEventsEmitterInterface|Bitrix24AccountInterface[] $b24Accounts */
+ $b24Accounts = $this->bitrix24AccountRepository->findByMemberId($command->memberId);
+
+ if ([] !== $b24Accounts) {
+ foreach ($b24Accounts as $b24Account) {
+ $b24Account->applicationUninstalled(null);
+ $this->bitrix24AccountRepository->save($b24Account);
+ $entitiesToFlush[] = $b24Account;
+ }
+ }
+
+ $this->flusher->flush(...$entitiesToFlush);
+
+ $this->logger->info('ApplicationInstallations.Uninstall.completed', [
+ 'installationId' => $activeInstallation->getId(),
+ 'applicationToken' => $command->applicationToken,
+ 'flushedEntitiesCount' => count($entitiesToFlush),
+ ]);
+ } else {
+ $this->logger->info('ApplicationInstallations.Uninstall.false_request', [
+ 'applicationToken' => $command->applicationToken,
+ 'memberId' => $command->memberId,
+ 'domainUrl' => $command->domainUrl,
+ 'message' => 'No active installation found for uninstall request',
+ ]);
+ }
+
+ $this->logger->info(
+ 'ApplicationInstallations.Uninstall.Finish'
+ );
+ }
+}
diff --git a/src/Bitrix24Accounts/Entity/Bitrix24Account.php b/src/Bitrix24Accounts/Entity/Bitrix24Account.php
index 616f75d..ec1f651 100644
--- a/src/Bitrix24Accounts/Entity/Bitrix24Account.php
+++ b/src/Bitrix24Accounts/Entity/Bitrix24Account.php
@@ -33,7 +33,11 @@ class Bitrix24Account extends AggregateRoot implements Bitrix24AccountInterface
{
private ?string $applicationToken = null;
- private ?string $comment = null;
+ private readonly CarbonImmutable $createdAt;
+
+ private CarbonImmutable $updatedAt;
+
+ private Bitrix24AccountStatus $status = Bitrix24AccountStatus::new;
public function __construct(
private readonly Uuid $id,
@@ -42,15 +46,16 @@ public function __construct(
/** bitrix24 portal unique id */
private readonly string $memberId,
private string $domainUrl,
- private Bitrix24AccountStatus $status,
private AuthToken $authToken,
- private readonly CarbonImmutable $createdAt,
- private CarbonImmutable $updatedAt,
private int $applicationVersion,
private Scope $applicationScope,
- bool $isEmitBitrix24AccountCreatedEvent = false,
+ private readonly bool $isMasterAccount = false,
+ private $isEmitBitrix24AccountCreatedEvent = false,
+ private ?string $comment = null
) {
- $this->addAccountCreatedEventIfNeeded($isEmitBitrix24AccountCreatedEvent);
+ $this->createdAt = new CarbonImmutable();
+ $this->updatedAt = new CarbonImmutable();
+ $this->addAccountCreatedEventIfNeeded($this->isEmitBitrix24AccountCreatedEvent);
}
#[\Override]
@@ -170,7 +175,7 @@ public function changeDomainUrl(string $newDomainUrl): void
* @throws InvalidArgumentException
*/
#[\Override]
- public function applicationInstalled(string $applicationToken): void
+ public function applicationInstalled(?string $applicationToken): void
{
if (Bitrix24AccountStatus::new !== $this->status) {
throw new InvalidArgumentException(
@@ -181,12 +186,12 @@ public function applicationInstalled(string $applicationToken): void
);
}
- if ('' === $applicationToken) {
- throw new InvalidArgumentException('application token cannot be empty');
+ if (null !== $applicationToken) {
+ $this->guardEmptyToken($applicationToken);
+ $this->applicationToken = $applicationToken;
}
$this->status = Bitrix24AccountStatus::active;
- $this->applicationToken = $applicationToken;
$this->updatedAt = new CarbonImmutable();
$this->events[] = new Bitrix24AccountApplicationInstalledEvent(
$this->id,
@@ -194,21 +199,25 @@ public function applicationInstalled(string $applicationToken): void
);
}
- /**
- * @throws InvalidArgumentException
- */
#[\Override]
- public function applicationUninstalled(string $applicationToken): void
+ public function applicationUninstalled(?string $applicationToken): void
{
- $this->guardEmptyToken($applicationToken);
- $this->guardTokenMismatch($applicationToken);
- $this->guardApplicationIsActive();
- $this->status = Bitrix24AccountStatus::deleted;
- $this->updatedAt = new CarbonImmutable();
- $this->events[] = new Bitrix24AccountApplicationUninstalledEvent(
- $this->id,
- new CarbonImmutable()
- );
+ if (
+ Bitrix24AccountStatus::new == $this->status
+ || Bitrix24AccountStatus::active == $this->status
+ ) {
+ if (null !== $applicationToken) {
+ $this->guardEmptyToken($applicationToken);
+ $this->guardTokenMismatch($applicationToken);
+ }
+
+ $this->status = Bitrix24AccountStatus::deleted;
+ $this->updatedAt = new CarbonImmutable();
+ $this->events[] = new Bitrix24AccountApplicationUninstalledEvent(
+ $this->id,
+ new CarbonImmutable()
+ );
+ }
}
#[\Override]
@@ -283,6 +292,21 @@ public function markAsActive(?string $comment): void
$this->updatedAt = new CarbonImmutable();
}
+ #[\Override]
+ public function isMasterAccount(): bool
+ {
+ return $this->isMasterAccount;
+ }
+
+ #[\Override]
+ public function setApplicationToken(string $applicationToken): void
+ {
+ $this->guardEmptyToken($applicationToken);
+
+ $this->updatedAt = new CarbonImmutable();
+ $this->applicationToken = $applicationToken;
+ }
+
/**
* @throws InvalidArgumentException
*/
@@ -331,18 +355,6 @@ private function guardTokenMismatch(string $applicationToken): void
}
}
- private function guardApplicationIsActive(): void
- {
- if (Bitrix24AccountStatus::active !== $this->status) {
- throw new InvalidArgumentException(
- sprintf(
- 'for uninstall account must be in status «active», current status - «%s»',
- $this->status->name
- )
- );
- }
- }
-
private function addAccountCreatedEventIfNeeded(bool $isEmitCreatedEvent): void
{
if ($isEmitCreatedEvent) {
diff --git a/src/Bitrix24Accounts/Infrastructure/Doctrine/Bitrix24AccountRepository.php b/src/Bitrix24Accounts/Infrastructure/Doctrine/Bitrix24AccountRepository.php
index 5fb37ad..6f71eae 100644
--- a/src/Bitrix24Accounts/Infrastructure/Doctrine/Bitrix24AccountRepository.php
+++ b/src/Bitrix24Accounts/Infrastructure/Doctrine/Bitrix24AccountRepository.php
@@ -56,6 +56,7 @@ public function existsById(Uuid $uuid): bool
->createQueryBuilder('b24')
->where('b24.id = :id')
->andWhere('b24.status != :status')
+ ->orderBy('b24.createdAt', 'DESC')
->setParameter('id', $uuid)
->setParameter('status', Bitrix24AccountStatus::deleted)
->getQuery()
@@ -105,6 +106,64 @@ public function findByMemberId(
return $this->findBy($criteria);
}
+ /**
+ * @phpstan-return Bitrix24AccountInterface|null
+ *
+ * @throws InvalidArgumentException
+ */
+ public function findMasterByMemberId(
+ string $memberId,
+ ?Bitrix24AccountStatus $bitrix24AccountStatus = null,
+ ?int $bitrix24UserId = null,
+ ?bool $isAdmin = null
+ ): ?Bitrix24AccountInterface {
+ if ('' === trim($memberId)) {
+ throw new InvalidArgumentException('memberId cannot be empty');
+ }
+
+ $criteria = [
+ 'memberId' => $memberId,
+ 'isMasterAccount' => true,
+ ];
+
+ if ($bitrix24AccountStatus instanceof Bitrix24AccountStatus) {
+ $criteria['status'] = $bitrix24AccountStatus->name;
+ }
+
+ if (null !== $bitrix24UserId) {
+ $criteria['bitrix24UserId'] = $bitrix24UserId;
+ }
+
+ if (null !== $isAdmin) {
+ $criteria['isBitrix24UserAdmin'] = $isAdmin;
+ }
+
+ return $this->findOneBy($criteria);
+ }
+
+ public function findActiveByMemberId(string $memberId): array
+ {
+ if ('' === trim($memberId)) {
+ throw new InvalidArgumentException('memberId cannot be empty');
+ }
+
+ $activeStatuses = [
+ Bitrix24AccountStatus::new,
+ Bitrix24AccountStatus::active,
+ ];
+
+ return $this->getEntityManager()->getRepository(Bitrix24Account::class)
+ ->createQueryBuilder('b24')
+ ->where('b24.memberId = :memberId')
+ ->andWhere('b24.status IN (:statuses)')
+ ->orderBy('b24.createdAt', 'DESC')
+ ->setParameter('memberId', $memberId)
+ ->setParameter('statuses', $activeStatuses)
+ ->getQuery()
+ ->getResult()
+ ;
+ }
+
#[\Override]
public function delete(Uuid $uuid): void
{
@@ -163,9 +222,9 @@ public function findByApplicationToken(string $applicationToken): array
}
/**
- * @throws InvalidArgumentException
- *
* @phpstan-return Bitrix24AccountInterface&AggregateRootEventsEmitterInterface
+ *
+ * @throws InvalidArgumentException
*/
#[\Override]
public function findOneAdminByMemberId(string $memberId): ?Bitrix24AccountInterface
@@ -184,10 +243,10 @@ public function findOneAdminByMemberId(string $memberId): ?Bitrix24AccountInterf
}
/**
- * @phpstan-return array
- *
* @return array
*
+ * @phpstan-return array
+ *
* @throws InvalidArgumentException
*/
#[\Override]
diff --git a/src/Bitrix24Accounts/UseCase/InstallFinish/Handler.php b/src/Bitrix24Accounts/UseCase/InstallFinish/Handler.php
index e5b805d..f8518cf 100644
--- a/src/Bitrix24Accounts/UseCase/InstallFinish/Handler.php
+++ b/src/Bitrix24Accounts/UseCase/InstallFinish/Handler.php
@@ -39,7 +39,7 @@ public function handle(Command $command): void
/** @var AggregateRootEventsEmitterInterface|Bitrix24AccountInterface $bitrix24Account */
$bitrix24Account = $this->getSingleAccountByMemberId($command->domain->value, $command->memberId, $command->bitrix24UserId);
- $bitrix24Account->applicationInstalled($command->applicationToken);
+ $bitrix24Account->applicationInstalled(null);
$this->bitrix24AccountRepository->save($bitrix24Account);
$this->flusher->flush($bitrix24Account);
@@ -49,7 +49,6 @@ public function handle(Command $command): void
[
'b24_domain_url' => $command->domain,
'b24_member_id' => $command->memberId,
- 'b24_application_id' => $command->applicationToken,
'b24_user_id' => $command->bitrix24UserId,
]
);
diff --git a/src/Bitrix24Accounts/UseCase/InstallStart/Handler.php b/src/Bitrix24Accounts/UseCase/InstallStart/Handler.php
index 01e7ee0..ece0c7d 100644
--- a/src/Bitrix24Accounts/UseCase/InstallStart/Handler.php
+++ b/src/Bitrix24Accounts/UseCase/InstallStart/Handler.php
@@ -6,10 +6,8 @@
use Bitrix24\Lib\Bitrix24Accounts\Entity\Bitrix24Account;
use Bitrix24\Lib\Services\Flusher;
-use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountStatus;
use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Exceptions\Bitrix24AccountNotFoundException;
use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Repository\Bitrix24AccountRepositoryInterface;
-use Carbon\CarbonImmutable;
use Psr\Log\LoggerInterface;
readonly class Handler
@@ -34,12 +32,10 @@ public function handle(Command $command): void
$command->isBitrix24UserAdmin,
$command->memberId,
$command->domain->value,
- Bitrix24AccountStatus::new,
$command->authToken,
- new CarbonImmutable(),
- new CarbonImmutable(),
$command->applicationVersion,
$command->applicationScope,
+ false,
true
);
diff --git a/src/Bitrix24Accounts/UseCase/Uninstall/Handler.php b/src/Bitrix24Accounts/UseCase/Uninstall/Handler.php
index 516126b..b2e0182 100644
--- a/src/Bitrix24Accounts/UseCase/Uninstall/Handler.php
+++ b/src/Bitrix24Accounts/UseCase/Uninstall/Handler.php
@@ -30,9 +30,10 @@ public function handle(Command $command): void
/** @var AggregateRootEventsEmitterInterface[]|Bitrix24AccountInterface[] $accounts */
$accounts = $this->bitrix24AccountRepository->findByApplicationToken($command->applicationToken);
+
$accountsCount = count($accounts);
foreach ($accounts as $account) {
- $account->applicationUninstalled($command->applicationToken);
+ $account->applicationUninstalled(null);
$this->bitrix24AccountRepository->save($account);
}
diff --git a/src/Bitrix24Accounts/ValueObjects/Domain.php b/src/Bitrix24Accounts/ValueObjects/Domain.php
index a399ee7..e172b22 100644
--- a/src/Bitrix24Accounts/ValueObjects/Domain.php
+++ b/src/Bitrix24Accounts/ValueObjects/Domain.php
@@ -14,16 +14,44 @@ public function __construct(string $domain)
$this->value = $domain;
}
+ /*
+ * @return void
+ *
+ * Validates a domain name based on three main criteria:
+ * 1. **Allowed characters**:
+ * - Latin, Cyrillic, digits, and hyphens.
+ * - Hyphens are prohibited at the start/end of each label (regex: `$patternValidChars`).
+ * - Supports IDN (Internationalized Domain Names).
+ * 2. **Overall domain length**:
+ * - Not more than 255 characters (regex: `$patternLengthCheck`).
+ * 3. **Length of each label**:
+ * - From 1 to 63 characters (regex: `$patternLengthEachLabel`).
+ * - Maximum number of labels: 127 (as per RFC 1035).
+ *
+ * Complies with the requirements of:
+ * - RFC 1035 (basic domain name rules) [1].
+ * - RFC 5891 (IDN) [2].
+ *
+ * Examples of valid domains:
+ * - `example.com`
+ * - `кириллический-домен.рф`
+ *
+ * Composed of three patterns for simplicity and clarity.
+ * @throws \InvalidArgumentException If the domain fails any of the checks.
+ *
+ * [1] https://www.rfc-editor.org/rfc/rfc1035
+ * [2] https://www.rfc-editor.org/rfc/rfc5891
+ */
private function validate(string $domain): void
{
- // Регулярное выражение для проверки допустимых символов (латиница и кириллица)
+ // Regular expression for checking available symbol (Latin and Cyrillic)
$patternValidChars = '/^((?!-)[A-Za-zА-Яа-яЁё0-9-]{1,63}(?id = Uuid::v7();
+ $this->bitrix24AccountId = Uuid::v7();
+ $this->bitrix24PartnerContactPersonId = Uuid::v7();
+ $this->contactPersonId = Uuid::v7();
+ $this->bitrix24PartnerId = Uuid::v7();
+ $this->portalUsersCount = random_int(1, 1_000_000);
+ }
+
+ public function withExternalId(string $externalId): self
+ {
+ $this->externalId = $externalId;
+
+ return $this;
+ }
+
+ public function withApplicationToken(string $applicationToken): self
+ {
+ $this->applicationToken = $applicationToken;
+
+ return $this;
+ }
+
+ public function withApplicationStatusInstallation(ApplicationInstallationStatus $applicationInstallationStatus): self
+ {
+ $this->status = $applicationInstallationStatus;
+
+ return $this;
+ }
+
+ public function withApplicationStatus(ApplicationStatus $applicationStatus): self
+ {
+ $this->applicationStatus = $applicationStatus;
+
+ return $this;
+ }
+
+ public function withBitrix24AccountId(Uuid $uuid): self
+ {
+ $this->bitrix24AccountId = $uuid;
+
+ return $this;
+ }
+
+ public function withPortalLicenseFamily(PortalLicenseFamily $portalLicenseFamily): self
+ {
+ $this->portalLicenseFamily = $portalLicenseFamily;
+
+ return $this;
+ }
+
+ public function build(): ApplicationInstallation
+ {
+ $applicationInstallation = new ApplicationInstallation(
+ $this->id,
+ $this->bitrix24AccountId,
+ $this->applicationStatus,
+ $this->portalLicenseFamily,
+ $this->portalUsersCount,
+ $this->contactPersonId,
+ $this->bitrix24PartnerContactPersonId,
+ $this->bitrix24PartnerId,
+ $this->externalId,
+ $this->comment
+ );
+
+ if (!empty($this->status) && $this->status == ApplicationInstallationStatus::active) {
+ if ($this->applicationToken !== null && $this->applicationToken !== '') {
+ $applicationInstallation->applicationInstalled($this->applicationToken);
+ } else {
+ $applicationInstallation->applicationInstalled();
+ }
+ }
+
+ return $applicationInstallation;
+ }
+
+
+}
\ No newline at end of file
diff --git a/tests/Functional/ApplicationInstallations/Infrastructure/Doctrine/ApplicationInstallationRepositoryTest.php b/tests/Functional/ApplicationInstallations/Infrastructure/Doctrine/ApplicationInstallationRepositoryTest.php
new file mode 100644
index 0000000..925d0ac
--- /dev/null
+++ b/tests/Functional/ApplicationInstallations/Infrastructure/Doctrine/ApplicationInstallationRepositoryTest.php
@@ -0,0 +1,76 @@
+
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace Bitrix24\Lib\Tests\Functional\ApplicationInstallations\UseCase\Install;
+
+
+use Bitrix24\Lib\Bitrix24Accounts;
+
+use Bitrix24\Lib\Bitrix24Accounts\ValueObjects\Domain;
+use Bitrix24\Lib\Services\Flusher;
+use Bitrix24\Lib\ApplicationInstallations;
+use Bitrix24\Lib\Tests\EntityManagerFactory;
+
+use Bitrix24\Lib\Tests\Functional\ApplicationInstallations\Builders\ApplicationInstallationBuilder;
+use Bitrix24\Lib\Tests\Functional\Bitrix24Accounts\Builders\Bitrix24AccountBuilder;
+use Bitrix24\SDK\Application\ApplicationStatus;
+use Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Entity\ApplicationInstallationInterface;
+use Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Entity\ApplicationInstallationStatus;
+use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountStatus;
+use Bitrix24\SDK\Application\Contracts\Events\AggregateRootEventsEmitterInterface;
+use Bitrix24\SDK\Application\PortalLicenseFamily;
+use Bitrix24\SDK\Core\Credentials\Scope;
+use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException;
+
+use PHPUnit\Framework\Attributes\CoversClass;
+use PHPUnit\Framework\Attributes\Test;
+use PHPUnit\Framework\TestCase;
+use Psr\Log\NullLogger;
+
+use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher;
+use Symfony\Component\EventDispatcher\EventDispatcher;
+use Symfony\Component\Stopwatch\Stopwatch;
+
+use Bitrix24\Lib\ApplicationInstallations\Infrastructure\Doctrine\ApplicationInstallationRepository;
+use Bitrix24\Lib\ApplicationInstallations\UseCase\Install\Handler;
+
+use Bitrix24\Lib\Bitrix24Accounts\Infrastructure\Doctrine\Bitrix24AccountRepository;
+use Symfony\Component\Uid\Uuid;
+
+/**
+ * @internal
+ */
+#[CoversClass(ApplicationInstallations\UseCase\Install\Handler::class)]
+class HandlerTest extends TestCase
+{
+ private Handler $handler;
+
+ private Flusher $flusher;
+
+ private ApplicationInstallationRepository $repository;
+
+ private Bitrix24AccountRepository $bitrix24accountRepository;
+
+ private TraceableEventDispatcher $eventDispatcher;
+
+ #[\Override]
+ protected function setUp(): void
+ {
+ $entityManager = EntityManagerFactory::get();
+ $this->eventDispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());
+ $this->repository = new ApplicationInstallationRepository($entityManager);
+ $this->flusher = new Flusher($entityManager, $this->eventDispatcher);
+ $this->bitrix24accountRepository = new Bitrix24AccountRepository($entityManager);
+ $this->handler = new Handler(
+ $this->bitrix24accountRepository,
+ $this->repository,
+ $this->flusher,
+ new NullLogger()
+ );
+
+ }
+
+ /**
+ * @throws InvalidArgumentException
+ */
+ #[Test]
+ public function testNewInstallation(): void
+ {
+ $bitrix24AccountBuilder = (new Bitrix24AccountBuilder())
+ ->withApplicationScope(new Scope(['crm']))
+ ->build();
+
+
+ $applicationInstallationBuilder = (new ApplicationInstallationBuilder())
+ ->withApplicationStatus(new ApplicationStatus('F'))
+ ->withPortalLicenseFamily(PortalLicenseFamily::free)
+ ->build();
+
+
+ $this->handler->handle(
+ new ApplicationInstallations\UseCase\Install\Command(
+ $applicationInstallationBuilder->getApplicationStatus(),
+ $applicationInstallationBuilder->getPortalLicenseFamily(),
+ $applicationInstallationBuilder->getPortalUsersCount(),
+ $applicationInstallationBuilder->getContactPersonId(),
+ $applicationInstallationBuilder->getBitrix24PartnerContactPersonId(),
+ $applicationInstallationBuilder->getBitrix24PartnerId(),
+ $applicationInstallationBuilder->getExternalId(),
+ $applicationInstallationBuilder->getComment(),
+ $bitrix24AccountBuilder->getBitrix24UserId(),
+ $bitrix24AccountBuilder->isBitrix24UserAdmin(),
+ $bitrix24AccountBuilder->getMemberId(),
+ new Domain($bitrix24AccountBuilder->getDomainUrl()),
+ $bitrix24AccountBuilder->getAuthToken(),
+ $bitrix24AccountBuilder->getApplicationVersion(),
+ $bitrix24AccountBuilder->getApplicationScope()
+ )
+ );
+
+ $dispatchedEvents = $this->eventDispatcher->getOrphanedEvents();
+
+ $this->assertContains(\Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Events\Bitrix24AccountCreatedEvent::class, $dispatchedEvents);
+ $this->assertContains(\Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Events\ApplicationInstallationCreatedEvent::class, $dispatchedEvents);
+ $this->assertContains(\Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Events\Bitrix24AccountApplicationInstalledEvent::class, $dispatchedEvents);
+ $this->assertContains(\Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Events\ApplicationInstallationFinishedEvent::class, $dispatchedEvents);
+ }
+
+ /**
+ * @throws InvalidArgumentException
+ */
+ #[Test]
+ public function testNewInstallationWithToken(): void
+ {
+ $bitrix24AccountBuilder = (new Bitrix24AccountBuilder())
+ ->withApplicationScope(new Scope(['crm']))
+ ->build();
+
+
+ $applicationInstallationBuilder = (new ApplicationInstallationBuilder())
+ ->withApplicationStatus(new ApplicationStatus('F'))
+ ->withPortalLicenseFamily(PortalLicenseFamily::free)
+ ->build();
+
+ $newApplicationToken = Uuid::v7()->toRfc4122();
+
+ $this->handler->handle(
+ new ApplicationInstallations\UseCase\Install\Command(
+ $applicationInstallationBuilder->getApplicationStatus(),
+ $applicationInstallationBuilder->getPortalLicenseFamily(),
+ $applicationInstallationBuilder->getPortalUsersCount(),
+ $applicationInstallationBuilder->getContactPersonId(),
+ $applicationInstallationBuilder->getBitrix24PartnerContactPersonId(),
+ $applicationInstallationBuilder->getBitrix24PartnerId(),
+ $applicationInstallationBuilder->getExternalId(),
+ $applicationInstallationBuilder->getComment(),
+ $bitrix24AccountBuilder->getBitrix24UserId(),
+ $bitrix24AccountBuilder->isBitrix24UserAdmin(),
+ $bitrix24AccountBuilder->getMemberId(),
+ new Domain($bitrix24AccountBuilder->getDomainUrl()),
+ $bitrix24AccountBuilder->getAuthToken(),
+ $bitrix24AccountBuilder->getApplicationVersion(),
+ $bitrix24AccountBuilder->getApplicationScope(),
+ $newApplicationToken
+ )
+ );
+
+ $activeInstallation = $this->repository->findActiveByApplicationToken($newApplicationToken);
+ $this->assertNotNull($activeInstallation);
+
+ $dispatchedEvents = $this->eventDispatcher->getOrphanedEvents();
+
+ $this->assertContains(\Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Events\Bitrix24AccountCreatedEvent::class, $dispatchedEvents);
+ $this->assertContains(\Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Events\ApplicationInstallationCreatedEvent::class, $dispatchedEvents);
+ $this->assertContains(\Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Events\Bitrix24AccountApplicationInstalledEvent::class, $dispatchedEvents);
+ $this->assertContains(\Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Events\ApplicationInstallationFinishedEvent::class, $dispatchedEvents);
+ }
+
+ /**
+ * @throws InvalidArgumentException
+ */
+ #[Test]
+ public function testNewInstallationWithEmptyToken(): void
+ {
+ $bitrix24AccountBuilder = (new Bitrix24AccountBuilder())
+ ->withApplicationScope(new Scope(['crm']))
+ ->build();
+
+
+ $applicationInstallationBuilder = (new ApplicationInstallationBuilder())
+ ->withApplicationStatus(new ApplicationStatus('F'))
+ ->withPortalLicenseFamily(PortalLicenseFamily::free)
+ ->build();
+
+ $this->expectException(InvalidArgumentException::class);
+ $this->handler->handle(
+ new ApplicationInstallations\UseCase\Install\Command(
+ $applicationInstallationBuilder->getApplicationStatus(),
+ $applicationInstallationBuilder->getPortalLicenseFamily(),
+ $applicationInstallationBuilder->getPortalUsersCount(),
+ $applicationInstallationBuilder->getContactPersonId(),
+ $applicationInstallationBuilder->getBitrix24PartnerContactPersonId(),
+ $applicationInstallationBuilder->getBitrix24PartnerId(),
+ $applicationInstallationBuilder->getExternalId(),
+ $applicationInstallationBuilder->getComment(),
+ $bitrix24AccountBuilder->getBitrix24UserId(),
+ $bitrix24AccountBuilder->isBitrix24UserAdmin(),
+ $bitrix24AccountBuilder->getMemberId(),
+ new Domain($bitrix24AccountBuilder->getDomainUrl()),
+ $bitrix24AccountBuilder->getAuthToken(),
+ $bitrix24AccountBuilder->getApplicationVersion(),
+ $bitrix24AccountBuilder->getApplicationScope(),
+ ''
+ )
+ );
+ }
+
+ /**
+ * @throws InvalidArgumentException
+ */
+ #[Test]
+ public function testReinstallInstallation(): void
+ {
+
+ $memberId = Uuid::v4()->toRfc4122();
+
+ //Загружаем в базу данных аккаунт и установку приложения для тестирования переустановки.
+ $applicationToken = Uuid::v7()->toRfc4122();
+ $currentBitrix24Account = (new Bitrix24AccountBuilder())
+ ->withApplicationScope(new Scope(['crm']))
+ ->withStatus(Bitrix24AccountStatus::new)
+ ->withApplicationToken($applicationToken)
+ ->withMemberId($memberId)
+ ->withMaster(true)
+ ->build();
+
+
+ $applicationInstallation = (new ApplicationInstallationBuilder())
+ ->withApplicationStatus(new ApplicationStatus('F'))
+ ->withPortalLicenseFamily(PortalLicenseFamily::free)
+ ->withBitrix24AccountId($currentBitrix24Account->getId())
+ ->withApplicationStatusInstallation(ApplicationInstallationStatus::active)
+ ->build();
+
+ $this->bitrix24accountRepository->save($currentBitrix24Account);
+ $this->repository->save($applicationInstallation);
+ $this->flusher->flush();
+
+ $bitrix24AccountBuilder = (new Bitrix24AccountBuilder())
+ ->withApplicationScope(new Scope(['crm']))
+ ->withMemberId($memberId)
+ ->build();
+
+ $applicationInstallationBuilder = (new ApplicationInstallationBuilder())
+ ->withApplicationStatus(new ApplicationStatus('F'))
+ ->withPortalLicenseFamily(PortalLicenseFamily::free)
+ ->build();
+
+ $this->handler->handle(
+ new ApplicationInstallations\UseCase\Install\Command(
+ $applicationInstallationBuilder->getApplicationStatus(),
+ $applicationInstallationBuilder->getPortalLicenseFamily(),
+ $applicationInstallationBuilder->getPortalUsersCount(),
+ $applicationInstallationBuilder->getContactPersonId(),
+ $applicationInstallationBuilder->getBitrix24PartnerContactPersonId(),
+ $applicationInstallationBuilder->getBitrix24PartnerId(),
+ $applicationInstallationBuilder->getExternalId(),
+ $applicationInstallationBuilder->getComment(),
+ $bitrix24AccountBuilder->getBitrix24UserId(),
+ $bitrix24AccountBuilder->isBitrix24UserAdmin(),
+ $bitrix24AccountBuilder->getMemberId(),
+ new Domain($bitrix24AccountBuilder->getDomainUrl()),
+ $bitrix24AccountBuilder->getAuthToken(),
+ $bitrix24AccountBuilder->getApplicationVersion(),
+ $bitrix24AccountBuilder->getApplicationScope()
+ )
+ );
+
+ $dispatchedEvents = $this->eventDispatcher->getOrphanedEvents();
+
+ $this->assertContains(\Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Events\Bitrix24AccountCreatedEvent::class, $dispatchedEvents);
+ $this->assertContains(\Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Events\ApplicationInstallationCreatedEvent::class, $dispatchedEvents);
+ $this->assertContains(\Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Events\Bitrix24AccountApplicationInstalledEvent::class, $dispatchedEvents);
+ $this->assertContains(\Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Events\ApplicationInstallationFinishedEvent::class, $dispatchedEvents);
+ }
+
+ /**
+ * @throws InvalidArgumentException
+ */
+ #[Test]
+ public function testFewInstallationsOnOneAccount(): void
+ {
+
+ $memberId = Uuid::v4()->toRfc4122();
+
+ //Загружаем в базу данных аккаунт и установку приложения для тестирования переустановки.
+ $applicationToken = Uuid::v7()->toRfc4122();
+ $currentBitrix24Account = (new Bitrix24AccountBuilder())
+ ->withApplicationScope(new Scope(['crm']))
+ ->withStatus(Bitrix24AccountStatus::new)
+ ->withApplicationToken($applicationToken)
+ ->withMemberId($memberId)
+ ->build();
+
+
+ $applicationInstallation = (new ApplicationInstallationBuilder())
+ ->withApplicationStatus(new ApplicationStatus('F'))
+ ->withPortalLicenseFamily(PortalLicenseFamily::free)
+ ->withBitrix24AccountId($currentBitrix24Account->getId())
+ ->withApplicationStatusInstallation(ApplicationInstallationStatus::active)
+ ->build();
+
+ $this->bitrix24accountRepository->save($currentBitrix24Account);
+ $this->repository->save($applicationInstallation);
+ $this->flusher->flush();
+
+ $applicationInstallationBuilder = (new ApplicationInstallationBuilder())
+ ->withApplicationStatus(new ApplicationStatus('F'))
+ ->withPortalLicenseFamily(PortalLicenseFamily::free)
+ ->build();
+
+ $this->handler->handle(
+ new ApplicationInstallations\UseCase\Install\Command(
+ $applicationInstallationBuilder->getApplicationStatus(),
+ $applicationInstallationBuilder->getPortalLicenseFamily(),
+ $applicationInstallationBuilder->getPortalUsersCount(),
+ $applicationInstallationBuilder->getContactPersonId(),
+ $applicationInstallationBuilder->getBitrix24PartnerContactPersonId(),
+ $applicationInstallationBuilder->getBitrix24PartnerId(),
+ $applicationInstallationBuilder->getExternalId(),
+ $applicationInstallationBuilder->getComment(),
+ $currentBitrix24Account->getBitrix24UserId(),
+ $currentBitrix24Account->isBitrix24UserAdmin(),
+ $currentBitrix24Account->getMemberId(),
+ new Domain($currentBitrix24Account->getDomainUrl()),
+ $currentBitrix24Account->getAuthToken(),
+ $currentBitrix24Account->getApplicationVersion(),
+ $currentBitrix24Account->getApplicationScope()
+ )
+ );
+
+ $dispatchedEvents = $this->eventDispatcher->getOrphanedEvents();
+
+ $this->assertContains(\Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Events\Bitrix24AccountCreatedEvent::class, $dispatchedEvents);
+ $this->assertContains(\Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Events\ApplicationInstallationCreatedEvent::class, $dispatchedEvents);
+ $this->assertContains(\Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Events\Bitrix24AccountApplicationInstalledEvent::class, $dispatchedEvents);
+ $this->assertContains(\Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Events\ApplicationInstallationFinishedEvent::class, $dispatchedEvents);
+ }
+
+}
diff --git a/tests/Functional/ApplicationInstallations/UseCase/OnAppInstall/HandlerTest.php b/tests/Functional/ApplicationInstallations/UseCase/OnAppInstall/HandlerTest.php
new file mode 100644
index 0000000..ea179a5
--- /dev/null
+++ b/tests/Functional/ApplicationInstallations/UseCase/OnAppInstall/HandlerTest.php
@@ -0,0 +1,133 @@
+
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace Bitrix24\Lib\Tests\Functional\ApplicationInstallations\UseCase\OnAppInstall;
+
+
+use Bitrix24\Lib\Bitrix24Accounts;
+
+use Bitrix24\Lib\Bitrix24Accounts\ValueObjects\Domain;
+use Bitrix24\Lib\Services\Flusher;
+use Bitrix24\Lib\ApplicationInstallations;
+use Bitrix24\Lib\Tests\EntityManagerFactory;
+
+use Bitrix24\Lib\Tests\Functional\ApplicationInstallations\Builders\ApplicationInstallationBuilder;
+use Bitrix24\Lib\Tests\Functional\Bitrix24Accounts\Builders\Bitrix24AccountBuilder;
+use Bitrix24\SDK\Application\ApplicationStatus;
+use Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Entity\ApplicationInstallationStatus;
+use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountStatus;
+use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Exceptions\Bitrix24AccountNotFoundException;
+use Bitrix24\SDK\Application\PortalLicenseFamily;
+use Bitrix24\SDK\Core\Credentials\Scope;
+use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException;
+
+use PHPUnit\Framework\Attributes\CoversClass;
+use PHPUnit\Framework\Attributes\Test;
+use PHPUnit\Framework\TestCase;
+use Psr\Log\NullLogger;
+
+use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher;
+use Symfony\Component\EventDispatcher\EventDispatcher;
+use Symfony\Component\Stopwatch\Stopwatch;
+
+use Bitrix24\Lib\ApplicationInstallations\Infrastructure\Doctrine\ApplicationInstallationRepository;
+use Bitrix24\Lib\ApplicationInstallations\UseCase\OnAppInstall\Handler;
+
+use Bitrix24\Lib\Bitrix24Accounts\Infrastructure\Doctrine\Bitrix24AccountRepository;
+use Symfony\Component\Uid\Uuid;
+
+/**
+ * @internal
+ */
+#[CoversClass(ApplicationInstallations\UseCase\OnAppInstall\Handler::class)]
+class HandlerTest extends TestCase
+{
+ private Handler $handler;
+
+ private Flusher $flusher;
+
+ private ApplicationInstallationRepository $applicationInstallationRepository;
+
+ private Bitrix24AccountRepository $bitrix24accountRepository;
+
+ private TraceableEventDispatcher $eventDispatcher;
+
+ #[\Override]
+ protected function setUp(): void
+ {
+ $entityManager = EntityManagerFactory::get();
+ $this->eventDispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());
+ $this->applicationInstallationRepository = new ApplicationInstallationRepository($entityManager);
+ $this->flusher = new Flusher($entityManager, $this->eventDispatcher);
+ $this->bitrix24accountRepository = new Bitrix24AccountRepository($entityManager);
+ $this->handler = new Handler(
+ $this->bitrix24accountRepository,
+ $this->applicationInstallationRepository,
+ $this->flusher,
+ new NullLogger()
+ );
+
+ }
+
+ /**
+ * @throws InvalidArgumentException|Bitrix24AccountNotFoundException
+ */
+ #[Test]
+ public function testEventOnAppInstall(): void
+ {
+ $memberId = Uuid::v4()->toRfc4122();
+ $domainUrl = Uuid::v4()->toRfc4122().'-example.com';
+ $applicationToken = Uuid::v7()->toRfc4122();
+ $applicationStatus = 'T';
+
+ $bitrix24Account = (new Bitrix24AccountBuilder())
+ ->withApplicationScope(new Scope(['crm']))
+ ->withStatus(Bitrix24AccountStatus::new)
+ ->withMemberId($memberId)
+ ->withDomainUrl($domainUrl)
+ ->withInstalled()
+ ->withMaster(true)
+ ->build();
+
+ $applicationInstallationBuilder = (new ApplicationInstallationBuilder())
+ ->withApplicationStatus(new ApplicationStatus('F'))
+ ->withPortalLicenseFamily(PortalLicenseFamily::free)
+ ->withBitrix24AccountId($bitrix24Account->getId())
+ ->withApplicationStatusInstallation(ApplicationInstallationStatus::active)
+ ->build();
+
+ $this->bitrix24accountRepository->save($bitrix24Account);
+ $this->applicationInstallationRepository->save($applicationInstallationBuilder);
+ $this->flusher->flush();
+
+ $this->handler->handle(
+ new ApplicationInstallations\UseCase\OnAppInstall\Command(
+ $memberId,
+ new Domain($domainUrl),
+ $applicationToken,
+ $applicationStatus
+ )
+ );
+
+ $updated = $this->bitrix24accountRepository->getById($bitrix24Account->getId());
+
+ $this->assertTrue(
+ $updated->isApplicationTokenValid($applicationToken),
+ sprintf(
+ 'failed application token «%s» validation for bitrix24 account with id «%s»',
+ $applicationToken,
+ $bitrix24Account->getId()->toString()
+ )
+ );
+ }
+}
diff --git a/tests/Functional/ApplicationInstallations/UseCase/Uninstall/HandlerTest.php b/tests/Functional/ApplicationInstallations/UseCase/Uninstall/HandlerTest.php
new file mode 100644
index 0000000..8cbad0a
--- /dev/null
+++ b/tests/Functional/ApplicationInstallations/UseCase/Uninstall/HandlerTest.php
@@ -0,0 +1,241 @@
+
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace Bitrix24\Lib\Tests\Functional\ApplicationInstallations\UseCase\Uninstall;
+
+
+use Bitrix24\Lib\Bitrix24Accounts;
+
+use Bitrix24\Lib\Bitrix24Accounts\ValueObjects\Domain;
+use Bitrix24\Lib\Services\Flusher;
+use Bitrix24\Lib\ApplicationInstallations;
+use Bitrix24\Lib\Tests\EntityManagerFactory;
+
+use Bitrix24\Lib\Tests\Functional\ApplicationInstallations\Builders\ApplicationInstallationBuilder;
+use Bitrix24\Lib\Tests\Functional\Bitrix24Accounts\Builders\Bitrix24AccountBuilder;
+use Bitrix24\SDK\Application\ApplicationStatus;
+use Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Entity\ApplicationInstallationStatus;
+use Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Exceptions\ApplicationInstallationNotFoundException;
+use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountStatus;
+use Bitrix24\SDK\Application\PortalLicenseFamily;
+use Bitrix24\SDK\Core\Credentials\Scope;
+use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException;
+
+use PHPUnit\Framework\Attributes\CoversClass;
+use PHPUnit\Framework\Attributes\Test;
+use PHPUnit\Framework\TestCase;
+use Psr\Log\NullLogger;
+
+use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher;
+use Symfony\Component\EventDispatcher\EventDispatcher;
+use Symfony\Component\Stopwatch\Stopwatch;
+
+use Bitrix24\Lib\ApplicationInstallations\Infrastructure\Doctrine\ApplicationInstallationRepository;
+use Bitrix24\Lib\ApplicationInstallations\UseCase\Uninstall\Handler;
+
+use Bitrix24\Lib\Bitrix24Accounts\Infrastructure\Doctrine\Bitrix24AccountRepository;
+use Symfony\Component\Uid\Uuid;
+
+
+/**
+ * @internal
+ */
+#[CoversClass(ApplicationInstallations\UseCase\Uninstall\Handler::class)]
+class HandlerTest extends TestCase
+{
+ private Handler $handler;
+
+ private Flusher $flusher;
+
+ private ApplicationInstallationRepository $repository;
+
+ private Bitrix24AccountRepository $bitrix24accountRepository;
+
+ private TraceableEventDispatcher $eventDispatcher;
+
+ #[\Override]
+ protected function setUp(): void
+ {
+ $entityManager = EntityManagerFactory::get();
+ $this->eventDispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());
+ $this->repository = new ApplicationInstallationRepository($entityManager);
+ $this->flusher = new Flusher($entityManager, $this->eventDispatcher);
+ $this->bitrix24accountRepository = new Bitrix24AccountRepository($entityManager);
+ $this->handler = new Handler(
+ $this->bitrix24accountRepository,
+ $this->repository,
+ $this->flusher,
+ new NullLogger()
+ );
+ }
+
+ /**
+ * @throws InvalidArgumentException
+ */
+ #[Test]
+ public function testUninstall(): void
+ {
+ //Загружаем в базу данных аккаунт и установку приложения для их деинсталяции.
+ $applicationToken = Uuid::v7()->toRfc4122();
+ $oldBitrix24Account = (new Bitrix24AccountBuilder())
+ ->withApplicationScope(new Scope(['crm']))
+ ->withStatus(Bitrix24AccountStatus::new)
+ ->withApplicationToken($applicationToken)
+ ->withMaster(true)
+ ->withSetToken()
+ ->withInstalled()
+ ->build();
+
+ $this->bitrix24accountRepository->save($oldBitrix24Account);
+
+ $oldApplicationInstallation = (new ApplicationInstallationBuilder())
+ ->withApplicationStatus(new ApplicationStatus('F'))
+ ->withPortalLicenseFamily(PortalLicenseFamily::free)
+ ->withBitrix24AccountId($oldBitrix24Account->getId())
+ ->withApplicationStatusInstallation(ApplicationInstallationStatus::active)
+ ->withApplicationToken($applicationToken)
+ ->build();
+
+ $this->repository->save($oldApplicationInstallation);
+
+ $this->flusher->flush();
+
+ $this->handler->handle(
+ new ApplicationInstallations\UseCase\Uninstall\Command(
+ new Domain($oldBitrix24Account->getDomainUrl()),
+ $oldBitrix24Account->getMemberId(),
+ $applicationToken
+ )
+ );
+
+ $dispatchedEvents = $this->eventDispatcher->getOrphanedEvents();
+ $this->assertContains(\Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Events\Bitrix24AccountApplicationUninstalledEvent::class, $dispatchedEvents);
+
+ $this->expectException(ApplicationInstallationNotFoundException::class);
+ $this->repository->getById($oldApplicationInstallation->getId());
+ }
+
+ /**
+ * @throws InvalidArgumentException
+ */
+ #[Test]
+ public function testUninstallWithNotValidToken(): void
+ {
+ $applicationToken = Uuid::v7()->toRfc4122();
+ $oldBitrix24Account = (new Bitrix24AccountBuilder())
+ ->withApplicationScope(new Scope(['crm']))
+ ->withStatus(Bitrix24AccountStatus::new)
+ ->withApplicationToken($applicationToken)
+ ->withMaster(true)
+ ->withSetToken()
+ ->withInstalled()
+ ->build();
+
+ $this->bitrix24accountRepository->save($oldBitrix24Account);
+
+ $oldApplicationInstallation = (new ApplicationInstallationBuilder())
+ ->withApplicationStatus(new ApplicationStatus('F'))
+ ->withPortalLicenseFamily(PortalLicenseFamily::free)
+ ->withBitrix24AccountId($oldBitrix24Account->getId())
+ ->withApplicationStatusInstallation(ApplicationInstallationStatus::active)
+ ->withApplicationToken($applicationToken)
+ ->build();
+
+ $this->repository->save($oldApplicationInstallation);
+
+ $this->flusher->flush();
+
+ $this->handler->handle(
+ new ApplicationInstallations\UseCase\Uninstall\Command(
+ new Domain($oldBitrix24Account->getDomainUrl()),
+ $oldBitrix24Account->getMemberId(),
+ 'testNotValidToken'
+ )
+ );
+
+ $applicationInstallation = $this->repository->getById($oldApplicationInstallation->getId());
+
+ $this->assertEquals(ApplicationInstallationStatus::active, $applicationInstallation->getStatus());
+ $this->assertEquals($oldApplicationInstallation->getUpdatedAt(), $applicationInstallation->getUpdatedAt());
+
+ $bitrix24Account = $this->bitrix24accountRepository->getById($oldBitrix24Account->getId());
+
+ $this->assertEquals(Bitrix24AccountStatus::active, $bitrix24Account->getStatus());
+ $this->assertEquals($oldBitrix24Account->getUpdatedAt(), $bitrix24Account->getUpdatedAt());
+ }
+
+ public function testUninstallWithFewAccount(): void
+ {
+ $memberId = Uuid::v4()->toRfc4122();
+ //Загружаем в базу данных аккаунт и установку приложения для их деинсталяции.
+ $applicationToken = Uuid::v7()->toRfc4122();
+ $oldBitrix24Account = (new Bitrix24AccountBuilder())
+ ->withApplicationScope(new Scope(['crm']))
+ ->withStatus(Bitrix24AccountStatus::new)
+ ->withApplicationToken($applicationToken)
+ ->withMaster(true)
+ ->withMemberId($memberId)
+ ->withSetToken()
+ ->build();
+
+ $this->bitrix24accountRepository->save($oldBitrix24Account);
+
+ $bitrix24Account = (new Bitrix24AccountBuilder())
+ ->withApplicationScope(new Scope(['crm']))
+ ->withStatus(Bitrix24AccountStatus::new)
+ ->withMemberId($memberId)
+ ->build();
+
+ $this->bitrix24accountRepository->save($bitrix24Account);
+
+ $oldApplicationInstallation = (new ApplicationInstallationBuilder())
+ ->withApplicationStatus(new ApplicationStatus('F'))
+ ->withPortalLicenseFamily(PortalLicenseFamily::free)
+ ->withBitrix24AccountId($oldBitrix24Account->getId())
+ ->withApplicationStatusInstallation(ApplicationInstallationStatus::active)
+ ->withApplicationToken($applicationToken)
+ ->build();
+
+ $this->repository->save($oldApplicationInstallation);
+
+ $this->flusher->flush();
+
+ $this->handler->handle(
+ new ApplicationInstallations\UseCase\Uninstall\Command(
+ new Domain($oldBitrix24Account->getDomainUrl()),
+ $oldBitrix24Account->getMemberId(),
+ $applicationToken
+ )
+ );
+
+ $dispatchedEvents = $this->eventDispatcher->getOrphanedEvents();
+
+ $this->assertContains(\Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Events\Bitrix24AccountApplicationUninstalledEvent::class, $dispatchedEvents);
+
+ $applicationInstallation = $this->repository->find($oldApplicationInstallation->getId());
+
+ $this->assertEquals(ApplicationInstallationStatus::deleted, $applicationInstallation->getStatus());
+
+ $bitrix24Accounts = $this->bitrix24accountRepository->findByMemberId($memberId);
+
+ foreach ($bitrix24Accounts as $bitrix24Account) {
+ $this->assertSame(
+ Bitrix24AccountStatus::deleted,
+ $bitrix24Account->getStatus(),
+ sprintf('Account %s не в статусе "удалён"', $bitrix24Account->getId())
+ );
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/tests/Functional/Bitrix24Accounts/Builders/Bitrix24AccountBuilder.php b/tests/Functional/Bitrix24Accounts/Builders/Bitrix24AccountBuilder.php
index bff547e..77b6bed 100644
--- a/tests/Functional/Bitrix24Accounts/Builders/Bitrix24AccountBuilder.php
+++ b/tests/Functional/Bitrix24Accounts/Builders/Bitrix24AccountBuilder.php
@@ -14,9 +14,7 @@
namespace Bitrix24\Lib\Tests\Functional\Bitrix24Accounts\Builders;
use Bitrix24\Lib\Bitrix24Accounts\Entity\Bitrix24Account;
-use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountInterface;
use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountStatus;
-use Bitrix24\SDK\Application\Contracts\Events\AggregateRootEventsEmitterInterface;
use Bitrix24\SDK\Core\Credentials\AuthToken;
use Bitrix24\SDK\Core\Credentials\Scope;
use Carbon\CarbonImmutable;
@@ -35,20 +33,22 @@ class Bitrix24AccountBuilder
private string $domainUrl;
- private Bitrix24AccountStatus $status = Bitrix24AccountStatus::active;
+ private Bitrix24AccountStatus $status;
private readonly AuthToken $authToken;
- private readonly CarbonImmutable $createdAt;
-
- private readonly CarbonImmutable $updatedAt;
-
private readonly int $applicationVersion;
private Scope $applicationScope;
private ?string $applicationToken = null;
+ private bool $isMasterAccount = false;
+
+ private bool $isSetToken = false;
+
+ private bool $isInstalled = false;
+
public function __construct()
{
$this->id = Uuid::v7();
@@ -57,8 +57,6 @@ public function __construct()
$this->memberId = Uuid::v4()->toRfc4122();
$this->domainUrl = Uuid::v4()->toRfc4122().'-example.com';
$this->authToken = new AuthToken('old_1', 'old_2', 3600);
- $this->createdAt = CarbonImmutable::now();
- $this->updatedAt = CarbonImmutable::now();
$this->applicationVersion = 1;
$this->applicationScope = new Scope();
}
@@ -98,6 +96,27 @@ public function withStatus(Bitrix24AccountStatus $bitrix24AccountStatus): self
return $this;
}
+ public function withSetToken(): self
+ {
+ $this->isSetToken = true;
+
+ return $this;
+ }
+
+ public function withMaster(bool $isMaster): self
+ {
+ $this->isMasterAccount = $isMaster;
+
+ return $this;
+ }
+
+ public function withInstalled(): self
+ {
+ $this->isInstalled = true;
+
+ return $this;
+ }
+
public function build(): Bitrix24Account
{
$bitrix24Account = new Bitrix24Account(
@@ -106,18 +125,22 @@ public function build(): Bitrix24Account
$this->isBitrix24UserAdmin,
$this->memberId,
$this->domainUrl,
- $this->status,
$this->authToken,
- $this->createdAt,
- $this->updatedAt,
$this->applicationVersion,
- $this->applicationScope
+ $this->applicationScope,
+ $this->isMasterAccount
);
- if ($this->applicationToken !== null && Bitrix24AccountStatus::new == $this->status) {
- $bitrix24Account->applicationInstalled($this->applicationToken);
+ if ($this->isInstalled && Bitrix24AccountStatus::new == $this->status) {
+ $bitrix24Account->applicationInstalled(null);
+ }
+
+ if ($this->isSetToken && $this->applicationToken !== null) {
+ $bitrix24Account->setApplicationToken($this->applicationToken);
}
+
+
return $bitrix24Account;
}
}
diff --git a/tests/Functional/Bitrix24Accounts/Infrastructure/Doctrine/Bitrix24AccountRepositoryTest.php b/tests/Functional/Bitrix24Accounts/Infrastructure/Doctrine/Bitrix24AccountRepositoryTest.php
index 4736e55..6d4c1ac 100644
--- a/tests/Functional/Bitrix24Accounts/Infrastructure/Doctrine/Bitrix24AccountRepositoryTest.php
+++ b/tests/Functional/Bitrix24Accounts/Infrastructure/Doctrine/Bitrix24AccountRepositoryTest.php
@@ -41,12 +41,10 @@ protected function createBitrix24AccountImplementation(
Uuid $uuid,
int $bitrix24UserId,
bool $isBitrix24UserAdmin,
+ bool $isMasterAccount,
string $memberId,
string $domainUrl,
- Bitrix24AccountStatus $bitrix24AccountStatus,
AuthToken $authToken,
- CarbonImmutable $createdAt,
- CarbonImmutable $updatedAt,
int $applicationVersion,
Scope $applicationScope
): Bitrix24AccountInterface {
@@ -56,12 +54,10 @@ protected function createBitrix24AccountImplementation(
$isBitrix24UserAdmin,
$memberId,
$domainUrl,
- $bitrix24AccountStatus,
$authToken,
- $createdAt,
- $updatedAt,
$applicationVersion,
- $applicationScope
+ $applicationScope,
+ $isMasterAccount
);
}
diff --git a/tests/Functional/Bitrix24Accounts/UseCase/InstallFinish/HandlerTest.php b/tests/Functional/Bitrix24Accounts/UseCase/InstallFinish/HandlerTest.php
index f0d1ac0..5d84d7e 100644
--- a/tests/Functional/Bitrix24Accounts/UseCase/InstallFinish/HandlerTest.php
+++ b/tests/Functional/Bitrix24Accounts/UseCase/InstallFinish/HandlerTest.php
@@ -86,14 +86,6 @@ public function testFinishInstallationApplication(): void
$updated = $this->repository->getById($bitrix24Account->getId());
$this->assertEquals(Bitrix24AccountStatus::active, $updated->getStatus(), 'expected status is active');
- $this->assertTrue(
- $updated->isApplicationTokenValid($applicationToken),
- sprintf(
- 'failed application token «%s» validation for bitrix24 account with id «%s»',
- $applicationToken,
- $bitrix24Account->getId()->toString()
- )
- );
$this->assertTrue(
in_array(Bitrix24AccountApplicationInstalledEvent::class, $this->eventDispatcher->getOrphanedEvents(), true),
sprintf(
diff --git a/tests/Functional/Bitrix24Accounts/UseCase/RenewAuthToken/HandlerTest.php b/tests/Functional/Bitrix24Accounts/UseCase/RenewAuthToken/HandlerTest.php
index 31a5855..479f2cb 100644
--- a/tests/Functional/Bitrix24Accounts/UseCase/RenewAuthToken/HandlerTest.php
+++ b/tests/Functional/Bitrix24Accounts/UseCase/RenewAuthToken/HandlerTest.php
@@ -20,6 +20,7 @@
use Bitrix24\Lib\Tests\EntityManagerFactory;
use Bitrix24\Lib\Tests\Functional\Bitrix24Accounts\Builders\Bitrix24AccountBuilder;
use Bitrix24\SDK\Application\ApplicationStatus;
+use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountStatus;
use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Repository\Bitrix24AccountRepositoryInterface;
use Bitrix24\SDK\Core\Credentials\AuthToken;
use Bitrix24\SDK\Core\Response\DTO\RenewedAuthToken;
@@ -30,6 +31,7 @@
use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\Stopwatch\Stopwatch;
+use Symfony\Component\Uid\Uuid;
/**
* @internal
@@ -64,7 +66,11 @@ protected function setUp(): void
#[Test]
public function testRenewAuthTokenWithoutBitrix24UserId(): void
{
+ $applicationToken = Uuid::v7()->toRfc4122();
$bitrix24Account = (new Bitrix24AccountBuilder())
+ ->withStatus(Bitrix24AccountStatus::new)
+ ->withApplicationToken($applicationToken)
+ ->withInstalled()
->build();
$this->repository->save($bitrix24Account);
$this->flusher->flush();
diff --git a/tests/Functional/Bitrix24Accounts/UseCase/Uninstall/HandlerTest.php b/tests/Functional/Bitrix24Accounts/UseCase/Uninstall/HandlerTest.php
index a902791..d761e60 100644
--- a/tests/Functional/Bitrix24Accounts/UseCase/Uninstall/HandlerTest.php
+++ b/tests/Functional/Bitrix24Accounts/UseCase/Uninstall/HandlerTest.php
@@ -75,11 +75,12 @@ public function testUninstallApplication(): void
$bitrix24Account = (new Bitrix24AccountBuilder())
->withStatus(Bitrix24AccountStatus::new)
->withApplicationToken($applicationToken)
+ ->withInstalled()
+ ->withSetToken()
->build();
$this->repository->save($bitrix24Account);
$this->flusher->flush();
-
$this->handler->handle(new Bitrix24Accounts\UseCase\Uninstall\Command($applicationToken));
$this->expectException(Bitrix24AccountNotFoundException::class);
diff --git a/tests/Functional/Bitrix24Accounts/UseCase/UpdateVersion/HandlerTest.php b/tests/Functional/Bitrix24Accounts/UseCase/UpdateVersion/HandlerTest.php
index 8147815..12412d7 100644
--- a/tests/Functional/Bitrix24Accounts/UseCase/UpdateVersion/HandlerTest.php
+++ b/tests/Functional/Bitrix24Accounts/UseCase/UpdateVersion/HandlerTest.php
@@ -69,8 +69,9 @@ public function testSuccessUpdateVersion(): void
$applicationToken = Uuid::v7()->toRfc4122();
$bitrix24Account = (new Bitrix24AccountBuilder())
- ->withStatus(Bitrix24AccountStatus::active)
+ ->withStatus(Bitrix24AccountStatus::new)
->withApplicationToken($applicationToken)
+ ->withInstalled()
->build();
$this->repository->save($bitrix24Account);
@@ -98,7 +99,7 @@ public function testNotFoundBitrix24AccountForUpdateVersion(): void
$applicationToken = Uuid::v7()->toRfc4122();
$bitrix24Account = (new Bitrix24AccountBuilder())
- ->withStatus(Bitrix24AccountStatus::active)
+ ->withStatus(Bitrix24AccountStatus::new)
->withApplicationToken($applicationToken)
->build();
@@ -126,8 +127,11 @@ public function testNotFoundBitrix24AccountForUpdateVersion(): void
#[Test]
public function testNotValidVersionForUpdateVersion(): void
{
+ $applicationToken = Uuid::v7()->toRfc4122();
$bitrix24Account = (new Bitrix24AccountBuilder())
- ->withStatus(Bitrix24AccountStatus::active)
+ ->withStatus(Bitrix24AccountStatus::new)
+ ->withApplicationToken($applicationToken)
+ ->withInstalled()
->build();
diff --git a/tests/Unit/ApplicationInstallations/Entity/ApplicationInstallationTest.php b/tests/Unit/ApplicationInstallations/Entity/ApplicationInstallationTest.php
new file mode 100644
index 0000000..98a4f27
--- /dev/null
+++ b/tests/Unit/ApplicationInstallations/Entity/ApplicationInstallationTest.php
@@ -0,0 +1,49 @@
+withPortalLicenseFamily(PortalLicenseFamily::free)
+ ->withApplicationStatus(new ApplicationStatus('F'))
+ ->build();
+ $applicationInstallation->changePortalLicenseFamily(PortalLicenseFamily::basic);
+ $this->assertEquals(PortalLicenseFamily::basic, $applicationInstallation->getPortalLicenseFamily());
+ }
+
+ public function testNotEqualsChangePortalLicenseFamily(): void
+ {
+ $applicationInstallation = (new ApplicationInstallationBuilder)
+ ->withPortalLicenseFamily(PortalLicenseFamily::free)
+ ->withApplicationStatus(new ApplicationStatus('F'))
+ ->build();
+ $initialUpdatedAt = $applicationInstallation->getUpdatedAt();
+ $applicationInstallation->changePortalLicenseFamily(PortalLicenseFamily::free);
+ $this->assertEquals($initialUpdatedAt, $applicationInstallation->getUpdatedAt());
+ }
+}
diff --git a/tests/Unit/ApplicationInstallations/UseCase/Install/CommandTest.php b/tests/Unit/ApplicationInstallations/UseCase/Install/CommandTest.php
new file mode 100644
index 0000000..aae26c7
--- /dev/null
+++ b/tests/Unit/ApplicationInstallations/UseCase/Install/CommandTest.php
@@ -0,0 +1,256 @@
+expectException($expectedException);
+ }
+
+ $command = new Command(
+ $applicationStatus,
+ $portalLicenseFamily,
+ $portalUsersCount,
+ $contactPersonId,
+ $bitrix24PartnerContactPersonId,
+ $bitrix24PartnerId,
+ $externalId,
+ $comment,
+ $bitrix24UserId,
+ $isBitrix24UserAdmin,
+ $memberId,
+ $domain,
+ $authToken,
+ $applicationVersion,
+ $applicationScope,
+ $applicationToken,
+ );
+
+ if (null === $expectedException) {
+ // Проверяем, что объект создан и является экземпляром нужного класса
+ $this->assertInstanceOf(Command::class, $command);
+ }
+ }
+
+ public static function dataForCommand(): \Generator
+ {
+ $applicationInstallationBuilder = (new ApplicationInstallationBuilder())
+ ->withApplicationStatus(new ApplicationStatus('F'))
+ ->withPortalLicenseFamily(PortalLicenseFamily::free)
+ ->build();
+
+ $bitrix24AccountBuilder = (new Bitrix24AccountBuilder())
+ ->withApplicationScope(new Scope(['crm']))
+ ->build();
+
+ yield 'validCommand' => [
+ $applicationInstallationBuilder->getApplicationStatus(),
+ $applicationInstallationBuilder->getPortalLicenseFamily(),
+ $applicationInstallationBuilder->getPortalUsersCount(),
+ $applicationInstallationBuilder->getContactPersonId(),
+ $applicationInstallationBuilder->getBitrix24PartnerContactPersonId(),
+ $applicationInstallationBuilder->getBitrix24PartnerId(),
+ $applicationInstallationBuilder->getExternalId(),
+ $applicationInstallationBuilder->getComment(),
+ $bitrix24AccountBuilder->getBitrix24UserId(),
+ $bitrix24AccountBuilder->isBitrix24UserAdmin(),
+ $bitrix24AccountBuilder->getMemberId(),
+ new Domain($bitrix24AccountBuilder->getDomainUrl()),
+ $bitrix24AccountBuilder->getAuthToken(),
+ $bitrix24AccountBuilder->getApplicationVersion(),
+ $bitrix24AccountBuilder->getApplicationScope(),
+ null,
+ null,
+ ];
+
+ yield 'invalidPortalUsersCount' => [
+ $applicationInstallationBuilder->getApplicationStatus(),
+ $applicationInstallationBuilder->getPortalLicenseFamily(),
+ 0,
+ $applicationInstallationBuilder->getContactPersonId(),
+ $applicationInstallationBuilder->getBitrix24PartnerContactPersonId(),
+ $applicationInstallationBuilder->getBitrix24PartnerId(),
+ $applicationInstallationBuilder->getExternalId(),
+ $applicationInstallationBuilder->getComment(),
+ $bitrix24AccountBuilder->getBitrix24UserId(),
+ $bitrix24AccountBuilder->isBitrix24UserAdmin(),
+ $bitrix24AccountBuilder->getMemberId(),
+ new Domain($bitrix24AccountBuilder->getDomainUrl()),
+ $bitrix24AccountBuilder->getAuthToken(),
+ $bitrix24AccountBuilder->getApplicationVersion(),
+ $bitrix24AccountBuilder->getApplicationScope(),
+ null,
+ InvalidArgumentException::class,
+ ];
+
+ yield 'emptyExternalId' => [
+ $applicationInstallationBuilder->getApplicationStatus(),
+ $applicationInstallationBuilder->getPortalLicenseFamily(),
+ $applicationInstallationBuilder->getPortalUsersCount(),
+ $applicationInstallationBuilder->getContactPersonId(),
+ $applicationInstallationBuilder->getBitrix24PartnerContactPersonId(),
+ $applicationInstallationBuilder->getBitrix24PartnerId(),
+ '',
+ $applicationInstallationBuilder->getComment(),
+ $bitrix24AccountBuilder->getBitrix24UserId(),
+ $bitrix24AccountBuilder->isBitrix24UserAdmin(),
+ $bitrix24AccountBuilder->getMemberId(),
+ new Domain($bitrix24AccountBuilder->getDomainUrl()),
+ $bitrix24AccountBuilder->getAuthToken(),
+ $bitrix24AccountBuilder->getApplicationVersion(),
+ $bitrix24AccountBuilder->getApplicationScope(),
+ null,
+ InvalidArgumentException::class,
+ ];
+
+ yield 'emptyComment' => [
+ $applicationInstallationBuilder->getApplicationStatus(),
+ $applicationInstallationBuilder->getPortalLicenseFamily(),
+ $applicationInstallationBuilder->getPortalUsersCount(),
+ $applicationInstallationBuilder->getContactPersonId(),
+ $applicationInstallationBuilder->getBitrix24PartnerContactPersonId(),
+ $applicationInstallationBuilder->getBitrix24PartnerId(),
+ $applicationInstallationBuilder->getExternalId(),
+ '',
+ $bitrix24AccountBuilder->getBitrix24UserId(),
+ $bitrix24AccountBuilder->isBitrix24UserAdmin(),
+ $bitrix24AccountBuilder->getMemberId(),
+ new Domain($bitrix24AccountBuilder->getDomainUrl()),
+ $bitrix24AccountBuilder->getAuthToken(),
+ $bitrix24AccountBuilder->getApplicationVersion(),
+ $bitrix24AccountBuilder->getApplicationScope(),
+ null,
+ InvalidArgumentException::class,
+ ];
+
+
+ yield 'invalidBitrix24UserId' => [
+ $applicationInstallationBuilder->getApplicationStatus(),
+ $applicationInstallationBuilder->getPortalLicenseFamily(),
+ $applicationInstallationBuilder->getPortalUsersCount(),
+ $applicationInstallationBuilder->getContactPersonId(),
+ $applicationInstallationBuilder->getBitrix24PartnerContactPersonId(),
+ $applicationInstallationBuilder->getBitrix24PartnerId(),
+ $applicationInstallationBuilder->getExternalId(),
+ $applicationInstallationBuilder->getComment(),
+ 0,
+ $bitrix24AccountBuilder->isBitrix24UserAdmin(),
+ $bitrix24AccountBuilder->getMemberId(),
+ new Domain($bitrix24AccountBuilder->getDomainUrl()),
+ $bitrix24AccountBuilder->getAuthToken(),
+ $bitrix24AccountBuilder->getApplicationVersion(),
+ $bitrix24AccountBuilder->getApplicationScope(),
+ null,
+ InvalidArgumentException::class,
+ ];
+
+ // Пустой memberId
+ yield 'emptyMemberId' => [
+ $applicationInstallationBuilder->getApplicationStatus(),
+ $applicationInstallationBuilder->getPortalLicenseFamily(),
+ $applicationInstallationBuilder->getPortalUsersCount(),
+ $applicationInstallationBuilder->getContactPersonId(),
+ $applicationInstallationBuilder->getBitrix24PartnerContactPersonId(),
+ $applicationInstallationBuilder->getBitrix24PartnerId(),
+ $applicationInstallationBuilder->getExternalId(),
+ $applicationInstallationBuilder->getComment(),
+ $bitrix24AccountBuilder->getBitrix24UserId(),
+ $bitrix24AccountBuilder->isBitrix24UserAdmin(),
+ '',
+ new Domain($bitrix24AccountBuilder->getDomainUrl()),
+ $bitrix24AccountBuilder->getAuthToken(),
+ $bitrix24AccountBuilder->getApplicationVersion(),
+ $bitrix24AccountBuilder->getApplicationScope(),
+ null,
+ InvalidArgumentException::class,
+ ];
+
+ // Некорректная версия приложения
+ yield 'invalidApplicationVersion' => [
+ $applicationInstallationBuilder->getApplicationStatus(),
+ $applicationInstallationBuilder->getPortalLicenseFamily(),
+ $applicationInstallationBuilder->getPortalUsersCount(),
+ $applicationInstallationBuilder->getContactPersonId(),
+ $applicationInstallationBuilder->getBitrix24PartnerContactPersonId(),
+ $applicationInstallationBuilder->getBitrix24PartnerId(),
+ $applicationInstallationBuilder->getExternalId(),
+ $applicationInstallationBuilder->getComment(),
+ $bitrix24AccountBuilder->getBitrix24UserId(),
+ $bitrix24AccountBuilder->isBitrix24UserAdmin(),
+ $bitrix24AccountBuilder->getMemberId(),
+ new Domain($bitrix24AccountBuilder->getDomainUrl()),
+ $bitrix24AccountBuilder->getAuthToken(),
+ 0,
+ $bitrix24AccountBuilder->getApplicationScope(),
+ null,
+ InvalidArgumentException::class,
+ ];
+
+ yield 'emptyApplicationToken' => [
+ $applicationInstallationBuilder->getApplicationStatus(),
+ $applicationInstallationBuilder->getPortalLicenseFamily(),
+ $applicationInstallationBuilder->getPortalUsersCount(),
+ $applicationInstallationBuilder->getContactPersonId(),
+ $applicationInstallationBuilder->getBitrix24PartnerContactPersonId(),
+ $applicationInstallationBuilder->getBitrix24PartnerId(),
+ $applicationInstallationBuilder->getExternalId(),
+ $applicationInstallationBuilder->getComment(),
+ $bitrix24AccountBuilder->getBitrix24UserId(),
+ $bitrix24AccountBuilder->isBitrix24UserAdmin(),
+ $bitrix24AccountBuilder->getMemberId(),
+ new Domain($bitrix24AccountBuilder->getDomainUrl()),
+ $bitrix24AccountBuilder->getAuthToken(),
+ $bitrix24AccountBuilder->getApplicationVersion(),
+ $bitrix24AccountBuilder->getApplicationScope(),
+ '',
+ InvalidArgumentException::class
+ ];
+
+ }
+}
\ No newline at end of file
diff --git a/tests/Unit/ApplicationInstallations/UseCase/OnAppInstall/CommandTest.php b/tests/Unit/ApplicationInstallations/UseCase/OnAppInstall/CommandTest.php
new file mode 100644
index 0000000..fcf556b
--- /dev/null
+++ b/tests/Unit/ApplicationInstallations/UseCase/OnAppInstall/CommandTest.php
@@ -0,0 +1,109 @@
+expectException($expectedException);
+ }
+
+ $command = new Command(
+ $memberId,
+ $domain,
+ $applicationToken,
+ $applicationStatus
+ );
+
+ if (null === $expectedException) {
+ $this->assertInstanceOf(Command::class, $command);
+ }
+ }
+
+ public static function dataForCommand(): \Generator
+ {
+ $applicationToken = Uuid::v7()->toRfc4122();
+ $applicationStatus = 'T';
+
+ (new ApplicationInstallationBuilder())
+ ->withApplicationStatus(new ApplicationStatus('F'))
+ ->withPortalLicenseFamily(PortalLicenseFamily::free)
+ ->withApplicationToken($applicationToken)
+ ->withApplicationStatusInstallation(ApplicationInstallationStatus::active)
+ ->build();
+
+ $bitrix24AccountBuilder = (new Bitrix24AccountBuilder())
+ ->withApplicationScope(new Scope(['crm']))
+ ->withInstalled()
+ ->withApplicationToken($applicationToken)
+ ->withStatus(Bitrix24AccountStatus::active)
+ ->build();
+
+ // Валидный кейс
+ yield 'validCommand' => [
+ $bitrix24AccountBuilder->getMemberId(),
+ new Domain($bitrix24AccountBuilder->getDomainUrl()),
+ $applicationToken,
+ $applicationStatus,
+ null,
+ ];
+
+ // Пустой memberId
+ yield 'emptyMemberId' => [
+ '',
+ new Domain($bitrix24AccountBuilder->getDomainUrl()),
+ $applicationToken,
+ $applicationStatus,
+ \InvalidArgumentException::class,
+ ];
+
+ // Пустой applicationToken
+ yield 'emptyApplicationToken' => [
+ $bitrix24AccountBuilder->getMemberId(),
+ new Domain($bitrix24AccountBuilder->getDomainUrl()),
+ '',
+ $applicationStatus,
+ \InvalidArgumentException::class,
+ ];
+
+ // Пустой applicationStatus
+ yield 'emptyApplicationStatus' => [
+ $bitrix24AccountBuilder->getMemberId(),
+ new Domain($bitrix24AccountBuilder->getDomainUrl()),
+ $applicationToken,
+ '',
+ \InvalidArgumentException::class,
+ ];
+ }
+}
\ No newline at end of file
diff --git a/tests/Unit/ApplicationInstallations/UseCase/Uninstall/CommandTest.php b/tests/Unit/ApplicationInstallations/UseCase/Uninstall/CommandTest.php
new file mode 100644
index 0000000..97fd0d7
--- /dev/null
+++ b/tests/Unit/ApplicationInstallations/UseCase/Uninstall/CommandTest.php
@@ -0,0 +1,83 @@
+expectException($expectedException);
+ }
+
+ $command = new Command(
+ $domain,
+ $memberId,
+ $applicationToken
+ );
+
+ if (null === $expectedException) {
+ $this->assertInstanceOf(Command::class, $command);
+ }
+ }
+
+ public static function dataForCommand(): \Generator
+ {
+ $applicationToken = Uuid::v7()->toRfc4122();
+
+ $bitrix24AccountBuilder = (new Bitrix24AccountBuilder())
+ ->withApplicationScope(new Scope(['crm']))
+ ->withInstalled()
+ ->withApplicationToken($applicationToken)
+ ->withStatus(Bitrix24AccountStatus::active)
+ ->build();
+
+ // Валидный кейс
+ yield 'validCommand' => [
+ $bitrix24AccountBuilder->getMemberId(),
+ new Domain($bitrix24AccountBuilder->getDomainUrl()),
+ $applicationToken,
+ null,
+ ];
+
+ // Пустой memberId
+ yield 'emptyMemberId' => [
+ '',
+ new Domain($bitrix24AccountBuilder->getDomainUrl()),
+ $applicationToken,
+ \InvalidArgumentException::class,
+ ];
+
+ // Пустой applicationToken
+ yield 'emptyApplicationToken' => [
+ $bitrix24AccountBuilder->getMemberId(),
+ new Domain($bitrix24AccountBuilder->getDomainUrl()),
+ '',
+ \InvalidArgumentException::class,
+ ];
+ }
+}
\ No newline at end of file
diff --git a/tests/Unit/Bitrix24Accounts/Entity/Bitrix24AccountTest.php b/tests/Unit/Bitrix24Accounts/Entity/Bitrix24AccountTest.php
index 3671674..66d5bf3 100644
--- a/tests/Unit/Bitrix24Accounts/Entity/Bitrix24AccountTest.php
+++ b/tests/Unit/Bitrix24Accounts/Entity/Bitrix24AccountTest.php
@@ -34,12 +34,10 @@ protected function createBitrix24AccountImplementation(
Uuid $uuid,
int $bitrix24UserId,
bool $isBitrix24UserAdmin,
+ bool $isMasterAccount,
string $memberId,
string $domainUrl,
- Bitrix24AccountStatus $bitrix24AccountStatus,
AuthToken $authToken,
- CarbonImmutable $createdAt,
- CarbonImmutable $updatedAt,
int $applicationVersion,
Scope $applicationScope
): Bitrix24AccountInterface {
@@ -49,12 +47,10 @@ protected function createBitrix24AccountImplementation(
$isBitrix24UserAdmin,
$memberId,
$domainUrl,
- $bitrix24AccountStatus,
$authToken,
- $createdAt,
- $updatedAt,
$applicationVersion,
- $applicationScope
+ $applicationScope,
+ $isMasterAccount
);
}
}
diff --git a/tests/Unit/Bitrix24Accounts/UseCase/ChangeDomainUrl/CommandTest.php b/tests/Unit/Bitrix24Accounts/UseCase/ChangeDomainUrl/CommandTest.php
index bb3646f..d5d023a 100644
--- a/tests/Unit/Bitrix24Accounts/UseCase/ChangeDomainUrl/CommandTest.php
+++ b/tests/Unit/Bitrix24Accounts/UseCase/ChangeDomainUrl/CommandTest.php
@@ -54,16 +54,6 @@ public function testValidateInvalidDomain(
public static function dataForValidateValidDomain(): \Generator
{
- // Примеры допустимых доменов
- /*$arrValidDomains = [
- ['oldDomain' => 'example.com', 'newDomain' => 'example.org'],
- ['oldDomain' => 'пример.рф', 'newDomain' => 'пример.рус'],
- ['oldDomain' => 'test-site.org', 'newDomain' => 'test-site.ru'],
- ['oldDomain' => 'valid-domain.co.uk', 'newDomain' => 'valid-domain.net'],
- ['oldDomain' => 'subdomain.example.com', 'newDomain' => 'subdomain2.example.com'],
- ['oldDomain' => 'тест.рус', 'newDomain' => 'тест2.рус'], // Пример с кириллицей
- ];*/
-
yield 'validDomain1' => [
'example.com',
'example.org',
diff --git a/tests/Unit/Bitrix24Accounts/UseCase/InstallStart/CommandTest.php b/tests/Unit/Bitrix24Accounts/UseCase/InstallStart/CommandTest.php
index 3369550..d9d3b05 100644
--- a/tests/Unit/Bitrix24Accounts/UseCase/InstallStart/CommandTest.php
+++ b/tests/Unit/Bitrix24Accounts/UseCase/InstallStart/CommandTest.php
@@ -80,7 +80,7 @@ public static function dataForCommand(): \Generator
'Member ID must be a non-empty string.'
];
- yield 'validDomainUrl' => [
+ yield 'emptyDomainUrl' => [
$bitrix24Account->getId(),
$bitrix24Account->getBitrix24UserId(),
$bitrix24Account->isBitrix24UserAdmin(),
@@ -93,7 +93,7 @@ public static function dataForCommand(): \Generator
sprintf('Invalid domain: %s', '')
];
- yield 'validBitrix24UserId' => [
+ yield 'invalidBitrix24UserId' => [
$bitrix24Account->getId(),
0,
$bitrix24Account->isBitrix24UserAdmin(),
@@ -106,7 +106,7 @@ public static function dataForCommand(): \Generator
'Bitrix24 User ID must be a positive integer.'
];
- yield 'validApplicationToken' => [
+ yield 'invalidApplicationVersion' => [
$bitrix24Account->getId(),
$bitrix24Account->getBitrix24UserId(),
$bitrix24Account->isBitrix24UserAdmin(),