<?php
namespace EADPlataforma\Services;
use Doctrine\ORM\EntityManagerInterface;
use EADPlataforma\Entity\Enrollment;
use EADPlataforma\Entity\Course;
use EADPlataforma\Entity\CourseTeam;
use EADPlataforma\Entity\Group;
use EADPlataforma\Entity\Product;
use EADPlataforma\Entity\ProductOffer;
use EADPlataforma\Entity\Transaction;
use EADPlataforma\Entity\Trash;
use EADPlataforma\Entity\UserSubscription;
use EADPlataforma\Entity\User;
use EADPlataforma\Services\GeneralService;
use EADPlataforma\Enum\EnrollmentEnum;
use EADPlataforma\Enum\GroupEnum;
use EADPlataforma\Enum\ProductEnum;
use EADPlataforma\Enum\CourseEnum;
use EADPlataforma\Enum\TagsMarketingEnum;
use EADPlataforma\Enum\NotificationEnum;
use EADPlataforma\Enum\TrashEnum;
use EADPlataforma\Enum\UserPermissionEnum;
use EADPlataforma\Enum\WebhookEnum;
/**
* Enrollment Service
*/
class EnrollmentService
{
/**
* @var SchoolEntityManager $em
*/
protected $em;
/**
* @var GeneralService $generalService
*/
protected $generalService;
/**
* @var ConfigurationService $configuration
*/
protected $configuration;
/**
* @var Repository $repository
*/
protected $repository;
/**
* @var EntityUtil $entityUtil
*/
protected $entityUtil;
/**
* @var bool
*/
protected $notification = false;
/**
* @var bool
*/
protected $email = false;
/**
* @var int
*/
protected $origin = EnrollmentEnum::ORIGIN_FREE;
/**
* @var int|null
*/
protected $certificate = EnrollmentEnum::NO;
/**
* @var int|null
*/
protected $accessPeriod;
/**
* @var int|null
*/
protected $supportPeriod;
/**
* @var Date|null
*/
protected $accessDate;
/**
* @var Date|null
*/
protected $supportDate;
/**
* @var string|null
*
*/
private $couponKey;
/**
* @var \Group|null
*/
protected $group;
/**
* @var \UserSubscription|null
*/
protected $userSubscription;
/**
* @var \Transaction|null
*/
protected $transaction;
/**
* @var LogService
*/
private $logService;
/**
* @var MarketingService $marketingService
*/
protected $marketingService;
/**
* @var EmailService $emailService
*/
protected $emailService;
/**
* @var NotificationService $notificationService
*/
protected $notificationService;
/**
* @var int|null
*/
private $deleted;
/**
* @var string
*/
protected $lifetimeDate = "9999-09-09 00:00:00";
/**
* @var Bool
*/
protected $debug = false;
/**
* Constructor
*
* @param GeneralService $generalService
*/
public function __construct(GeneralService $generalService)
{
$this->generalService = $generalService;
$this->configuration = $this->generalService->getService('ConfigurationService');
$this->em = $this->generalService->getService('SchoolEntityManager');
$this->logService = $this->generalService->getService('LogService');
$this->repository = $this->em->getRepository(Enrollment::class);
$this->entityUtil = $this->generalService->getUtil('EntityUtil');
$this->marketingService = $this->generalService->getService(
'Marketing\\MarketingService'
);
$this->emailService = $this->generalService->getService('EmailService');
$this->notificationService = $this->generalService->getService('NotificationService');
}
public function setNotification(bool $notification): self
{
$this->notification = $notification;
return $this;
}
public function getNotification(): bool
{
return $this->notification;
}
public function setEmail(bool $email): self
{
$this->email = $email;
return $this;
}
public function getEmail(): bool
{
return $this->email;
}
public function setOrigin(int $origin): self
{
$this->origin = $origin;
return $this;
}
public function getOrigin(): int
{
return $this->origin;
}
public function setCertificate(?int $certificate): self
{
$this->certificate = $certificate;
return $this;
}
public function getCertificate(): ?int
{
return $this->certificate;
}
public function setAccessPeriod(?int $accessPeriod): self
{
$this->accessPeriod = $accessPeriod;
return $this;
}
public function getAccessPeriod(): ?int
{
return $this->accessPeriod;
}
public function setSupportPeriod(?int $supportPeriod): self
{
$this->supportPeriod = $supportPeriod;
return $this;
}
public function getSupportPeriod(): ?int
{
return $this->supportPeriod;
}
public function setAccessDate($accessDate): self
{
$this->accessDate = $accessDate;
return $this;
}
public function getAccessDate()
{
return $this->accessDate;
}
public function setSupportDate($supportDate): self
{
$this->supportDate = $supportDate;
return $this;
}
public function getSupportDate()
{
return $this->supportDate;
}
public function setCouponKey(?string $couponKey): self
{
$this->couponKey = $couponKey;
return $this;
}
public function getCouponKey(): ?string
{
return $this->couponKey;
}
public function setGroup(?Group $group): self
{
$this->group = $group;
return $this;
}
public function getGroup(): ?Group
{
return $this->group;
}
public function setUserSubscription(?UserSubscription $userSubscription): self
{
$this->userSubscription = $userSubscription;
return $this;
}
public function getUserSubscription(): ?UserSubscription
{
return $this->userSubscription;
}
public function setTransaction(?Transaction $transaction): self
{
$this->transaction = $transaction;
return $this;
}
public function getTransaction(): ?Transaction
{
return $this->transaction;
}
public function restore(int $deleted): self
{
$this->deleted = $deleted;
return $this;
}
public function isDelete(): int
{
return $this->deleted;
}
public function setDebug(?bool $debug)
{
$this->debug = $debug;
return $this;
}
public function enrollUserByProduct(
User $user,
Product $product,
?Course $course = null,
?array $courses = null
)
{
try {
if((empty($course) && empty($courses)) && $product->isTypeResource()){
return;
}
if($product->getType() == ProductEnum::CERTIFICATE){
$this->setCertificate(EnrollmentEnum::YES);
}else if($product->getType() == ProductEnum::PERIOD){
$this->setAccessPeriod($product->getCycleItem()->getDays());
}else if($product->getType() == ProductEnum::SUPPORT){
$this->setSupportPeriod($product->getCycleItem()->getDays());
}
$processGeneralService = $this->generalService->getService(
'Transaction\\ProcessGeneral'
);
$processGeneralService->deleteUserLists($user, $product);
if(empty($courses)){
$courses = $product->getCourse();
if(!empty($courseItem)){
$courses = [ $course ];
}
}
foreach ($courses as $key => $courseItem){
$this->enrollUser(
$user,
$courseItem,
false,
$product->isTypeResource()
);
}
} catch (Exception $e) {
if($this->debug){
$discordService = $this->generalService->getService('DiscordService');
$discordService->setChannel('debug');
$discordService->setMessage($e->getMessage());
$discordService->sendDiscord();
}
}
}
public function blockEnrollUserByProduct(
User $user,
Product $product,
?Course $course = null,
?array $courses = null
)
{
try {
if(empty($courses)){
$courses = $product->getCourse();
if(!empty($courseItem)){
$courses = [ $course ];
}
}
foreach ($courses as $key => $course){
$this->revertEnroll($user, $course, $product);
}
} catch (Exception $e) {
if($this->debug){
$discordService = $this->generalService->getService('DiscordService');
$discordService->setChannel('debug');
$discordService->setMessage($e->getMessage());
$discordService->sendDiscord();
}
}
}
public function revertEnroll(User $user, Course $course, Product $product)
{
$enrollment = $this->repository->findOneBy([
"user" => $user->getId(),
"course" => $course->getId(),
], [ "id" => "DESC" ]);
if(!$enrollment){
return;
}
if($product->getType() == ProductEnum::CERTIFICATE){
$enrollment->setCertificate(EnrollmentEnum::NO);
}else if($product->getType() == ProductEnum::PERIOD){
$accessPeriod = $course->getAccessPeriod();
$datePeriod = date('Y-m-d H:i:s', strtotime("+ {$accessPeriod} day"));
$enrollment->setDatePeriod($datePeriod);
}else if($product->getType() == ProductEnum::SUPPORT){
$supportPeriod = $course->getSupportPeriod();
$dateSupport = date('Y-m-d H:i:s', strtotime("+ {$supportPeriod} day"));
$enrollment->setDateSupport($dateSupport);
}else{
$enrollment->setStatus(EnrollmentEnum::STATUS_CANCELED);
}
$this->em->flush();
return;
}
public function getEnrollmentDates(Course $course)
{
$today = date('Y-m-d H:i:s');
$accessPeriod = $this->getAccessPeriod();
$supportPeriod = $this->getSupportPeriod();
if(empty($accessPeriod)){
$accessPeriod = $course->getAccessPeriod();
}
if(empty($supportPeriod)){
$supportPeriod = $course->getSupportPeriod();
}
$datePeriod = date('Y-m-d H:i:s', strtotime("+ {$accessPeriod} day"));
$dateSupport = date('Y-m-d H:i:s', strtotime("+ {$supportPeriod} day"));
if(
empty($this->userSubscription) &&
$course->getLifetimePeriod() == CourseEnum::YES
){
$datePeriod = $this->lifetimeDate;
}
if(
empty($this->userSubscription) &&
$course->getLifetimeSupport() == CourseEnum::YES
){
$dateSupport = $this->lifetimeDate;
}
$dateRelease = $course->getDateRelease();
if($dateRelease > $today){
$datePeriod = strtotime("+ {$accessPeriod} day", strtotime($dateRelease));
$datePeriod = date('Y-m-d H:i:s', $datePeriod);
$dateSupport = strtotime("+ {$supportPeriod} day", strtotime($dateRelease));
$dateSupport = date('Y-m-d H:i:s', $dateSupport);
}
if(!empty($this->getAccessDate())){
$datePeriod = $this->getAccessDate();
$datePeriod = date('Y-m-d H:i:s', strtotime($datePeriod));
}
if(!empty($this->getSupportDate())){
$dateSupport = $this->getSupportDate();
$dateSupport = date('Y-m-d H:i:s', strtotime($dateSupport));
}
return (object)[
"datePeriod" => $datePeriod,
"dateSupport" => $dateSupport,
];
}
public function enrollUserInSubscription(
Product $product,
array $subscriptions,
?array $courses = []
)
{
if (empty($courses)) {
$courses = $product->getCourse();
}
$this->setOrigin(EnrollmentEnum::ORIGIN_SUBSCRIPTION);
$unlimitedCourse = $this->configuration->checkModuleIsAbleOnPlan('unlimitedCourseFunction');
$courseTeamRepository = $this->em->getRepository(CourseTeam::class);
$productOfferRepository = $this->em->getRepository(ProductOffer::class);
$newArray = [];
foreach ($subscriptions as $userSubscription){
$user = $userSubscription->getUser();
$this->setUserSubscription($userSubscription);
$this->setAccessDate($userSubscription->getDateNextPayment());
$this->setSupportDate($userSubscription->getDateNextPayment());
foreach ($courses as $course){
try{
//$this->enrollUser($user, $course);
if(!$unlimitedCourse){
$isInTeam = $courseTeamRepository->userExistInCourseTeam(
$course,
$user
);
if($course->getStatus() == CourseEnum::DRAFT && !$isInTeam){
continue;
}
}
$certificateOffer = null;
if(
$course->getCertificate() == CourseEnum::YES &&
$this->certificate == EnrollmentEnum::NO
){
$certificateOffer = $productOfferRepository->getProductOfferCertificateByCourse(
$course
);
}
$enrollment = $this->repository->findOneBy([
"user" => $user->getId(),
"course" => $course->getId(),
], [ "id" => "DESC" ]);
$info = $this->setEnrollmentUser(
$user,
$course,
$enrollment,
$certificateOffer
);
$new = $info->new;
$enrollment = $info->enrollment;
$dates = $this->getEnrollmentDates($course);
$datePeriod = $dates->datePeriod;
$dateSupport = $dates->dateSupport;
$oldDatePeriod = $enrollment->getDatePeriod('Y-m-d H:i:s');
$oldDateSupport = $enrollment->getDateSupport('Y-m-d H:i:s');
if($datePeriod > $oldDatePeriod){
$enrollment->setDatePeriod($datePeriod);
}
if($dateSupport > $oldDateSupport){
$enrollment->setDateSupport($dateSupport);
}
$errors = $this->entityUtil->setEntity($enrollment)->validateEntity();
if($errors){
continue;
}
if($new){
$this->em->persist($enrollment);
$newArray[] = $enrollment;
}
} catch (Exception $e) {
if($this->debug){
$discordService = $this->generalService->getService('DiscordService');
$discordService->setChannel('debug');
$discordService->setMessage($e->getMessage());
$discordService->sendDiscord();
}
}
}
}
$this->em->flush();
foreach ($newArray as $key => $enrollment) {
$this->repository->sendWebhook($enrollment);
if($this->getNotification()){
$this->sendNotification($enrollment);
}
if($this->getEmail()){
$this->sendEmail($enrollment);
}
$this->enrollmentMarketingTag($enrollment);
}
}
public function enrollUserInGroup(Group $group, ?array $users = [], ?array $courses = [])
{
if(empty($users)){
$users = $group->getUser();
}
if (empty($courses)) {
$courses = $group->getCourse();
}
$this->setOrigin(EnrollmentEnum::ORIGIN_GROUP);
$this->setGroup($group);
if($group->getTypeDateAccess() == GroupEnum::TYPE_DATE_FIXED){
$this->setAccessDate($group->getDateAccessConclusion());
}else if($group->getTypeDateAccess() == GroupEnum::TYPE_DATE_PERIOD) {
$this->setAccessPeriod($group->getDateAccessDays());
}
if($group->getTypeDateSupport() == GroupEnum::TYPE_DATE_FIXED){
$this->setSupportDate($group->getDateSupportConclusion());
}else if($group->getTypeDateSupport() == GroupEnum::TYPE_DATE_PERIOD) {
$this->setSupportPeriod($group->getDateSupportDays());
}
$unlimitedCourse = $this->configuration->checkModuleIsAbleOnPlan('unlimitedCourseFunction');
$courseTeamRepository = $this->em->getRepository(CourseTeam::class);
$productOfferRepository = $this->em->getRepository(ProductOffer::class);
$newArray = [];
foreach ($users as $user){
foreach ($courses as $course){
try{
//$this->enrollUser($user, $course);
if(!$unlimitedCourse){
$isInTeam = $courseTeamRepository->userExistInCourseTeam(
$course,
$user
);
if($course->getStatus() == CourseEnum::DRAFT && !$isInTeam){
continue;
}
}
$certificateOffer = null;
if(
$course->getCertificate() == CourseEnum::YES &&
$this->certificate == EnrollmentEnum::NO
){
$certificateOffer = $productOfferRepository->getProductOfferCertificateByCourse(
$course
);
}
$enrollment = $this->repository->findOneBy([
"user" => $user->getId(),
"course" => $course->getId(),
], [ "id" => "DESC" ]);
$info = $this->setEnrollmentUser(
$user,
$course,
$enrollment,
$certificateOffer
);
$new = $info->new;
$enrollment = $info->enrollment;
$dates = $this->getEnrollmentDates($course);
$datePeriod = $dates->datePeriod;
$dateSupport = $dates->dateSupport;
$oldDatePeriod = $enrollment->getDatePeriod('Y-m-d H:i:s');
$oldDateSupport = $enrollment->getDateSupport('Y-m-d H:i:s');
if($datePeriod > $oldDatePeriod){
$enrollment->setDatePeriod($datePeriod);
}
if($dateSupport > $oldDateSupport){
$enrollment->setDateSupport($dateSupport);
}
$errors = $this->entityUtil->setEntity($enrollment)->validateEntity();
if($errors){
continue;
}
if($new){
$this->em->persist($enrollment);
$newArray[] = $enrollment;
}
} catch (Exception $e) {
if($this->debug){
$discordService = $this->generalService->getService('DiscordService');
$discordService->setChannel('debug');
$discordService->setMessage($e->getMessage());
$discordService->sendDiscord();
}
}
}
}
$this->em->flush();
foreach ($newArray as $key => $enrollment) {
$this->repository->sendWebhook($enrollment);
if($this->getNotification()){
$this->sendNotification($enrollment);
}
if($this->getEmail()){
$this->sendEmail($enrollment);
}
$this->enrollmentMarketingTag($enrollment);
}
}
public function setEnrollmentUser(
User $user,
Course $course,
?Enrollment $enrollment = null,
?ProductOffer $certificateOffer = null,
?bool $api = false
): object
{
$new = false;
if(!$enrollment || ($api && ($enrollment->isDeleted() || $enrollment->isOnTrash()))){
$new = true;
$enrollment = new Enrollment();
}else{
$this->repository->restore($enrollment, TrashEnum::ENROLLMENT);
}
$enrollment->setStatus(EnrollmentEnum::STATUS_ACTIVE);
$enrollment->setCouponKey($this->getCouponKey());
$enrollment->setGroup($this->getGroup());
$enrollment->setUserSubscription($this->getUserSubscription());
$certificate = $enrollment->getCertificate();
if($this->getTransaction()){
$enrollment->addTransaction($this->getTransaction());
}
if($new){
$enrollment->setOrigin($this->getOrigin());
$enrollment->setUser($user);
$enrollment->setCourse($course);
$enrollment->setCourseCertificateTemplate(
$course->getCourseCertificateTemplate()
);
$enrollment->setDateRegister(date('Y-m-d H:i:s'));
$certificate = $course->getCertificate();
if($certificateOffer){
$productCertificate = $certificateOffer->getProduct();
$allowOrigin = json_decode(
$productCertificate->getCertificateEnrollmentOrigin()
);
$certificate = EnrollmentEnum::NO;
if(!empty($allowOrigin) && is_array($allowOrigin)){
if(in_array($enrollment->getOrigin(), $allowOrigin)){
$certificate = EnrollmentEnum::YES;
}
}
}
}
if(!empty($this->certificate)){
$certificate = $this->certificate;
}
$enrollment->setCertificate($certificate);
return (object)[
"new" => $new,
"enrollment" => $enrollment,
];
}
public function enrollUser(
User $user,
Course $course,
?bool $manual = false,
?bool $onlyExist = false,
?bool $api = false
)
{
try{
if(!$this->configuration->checkModuleIsAbleOnPlan('unlimitedCourseFunction')){
$courseTeamRepository = $this->em->getRepository(CourseTeam::class);
$isInTeam = $courseTeamRepository->userExistInCourseTeam(
$course,
$user
);
if($course->getStatus() == CourseEnum::DRAFT && !$isInTeam){
return (object)[
"errors" => [ "course" ],
"enrollment" => null,
];
}
}
$enrollment = $this->repository->findOneBy([
"user" => $user->getId(),
"course" => $course->getId(),
], [ "id" => "DESC" ]);
if(
$onlyExist &&
(empty($enrollment) || $enrollment->isDeleted() || $enrollment->isOnTrash())
){
return;
}
$certificateOffer = null;
if(
$course->getCertificate() == CourseEnum::YES &&
$this->certificate == EnrollmentEnum::NO
){
$productOfferRepository = $this->em->getRepository(ProductOffer::class);
$certificateOffer = $productOfferRepository->getProductOfferCertificateByCourse(
$course
);
}
$info = $this->setEnrollmentUser(
$user,
$course,
$enrollment,
$certificateOffer,
$api
);
$new = $info->new;
$enrollment = $info->enrollment;
$dates = $this->getEnrollmentDates($course);
$datePeriod = $dates->datePeriod;
$dateSupport = $dates->dateSupport;
$oldDatePeriod = $enrollment->getDatePeriod('Y-m-d H:i:s');
$oldDateSupport = $enrollment->getDateSupport('Y-m-d H:i:s');
if($datePeriod > $oldDatePeriod){
$enrollment->setDatePeriod($datePeriod);
}
if($dateSupport > $oldDateSupport){
$enrollment->setDateSupport($dateSupport);
}
$errors = $this->entityUtil->setEntity($enrollment)->validateEntity();
if($errors){
if($this->debug){
$discordService = $this->generalService->getService('DiscordService');
$discordService->setChannel('debug');
$discordService->setMessage(json_encode($errors));
$discordService->sendDiscord();
}
return (object)[
"errors" => $errors,
"enrollment" => null,
];
}
if($new){
$this->em->persist($enrollment);
}
$this->em->flush();
if($new){
$this->repository->sendWebhook($enrollment);
if($this->getNotification()){
$this->sendNotification($enrollment);
}
if($this->getEmail()){
$this->sendEmail($enrollment);
}
$this->logService->logInsert(
"enrollment",
$enrollment->getId(),
$enrollment->toReturn()
);
$this->enrollmentMarketingTag($enrollment, $manual);
}else{
$this->logService->logUpdate(
"enrollment",
$enrollment->getId(),
$enrollment->toReturn()
);
}
return (object)[
"errors" => false,
"enrollment" => $enrollment,
];
} catch (Exception $e) {
if($this->debug){
$discordService = $this->generalService->getService('DiscordService');
$discordService->setChannel('debug');
$discordService->setMessage($e->getMessage());
$discordService->sendDiscord();
}
}
return (object)[
"errors" => true,
"enrollment" => false,
];
}
public function sendNotification(Enrollment $enrollment)
{
$this->notificationService->create(
$enrollment->getUser(),
$enrollment->getCourse()->getUser(),
NotificationEnum::ORIGIN_ENROLLMENT_NEW,
$enrollment->getId()
);
$this->notificationService->create(
$enrollment->getCourse()->getUser(),
$enrollment->getUser(),
NotificationEnum::ORIGIN_ENROLLMENT_NEW,
$enrollment->getId()
);
}
public function sendEmail(Enrollment $enrollment)
{
$user = $enrollment->getUser();
if(!$this->emailService->checkUserToSend($user)){
return;
}
$this->emailService->setToEmail($user->getEmail());
$this->emailService->setToName($user->getName());
$subject1 = $this->configuration->getLanguage('enrollment.subject1', 'email');
$subject2 = $this->configuration->getLanguage('enrollment.subject2', 'email');
$client = $this->configuration->getClient();
$course = $enrollment->getCourse();
$subject = $subject1." ". $course->getTitle()." ". $subject2;
$this->emailService->setSubject($subject);
$this->emailService->setData([
"userName" => $enrollment->getUser()->getName(),
"courseTitle" => $course->getTitle(),
"btnLink" => "https://{$client->getDomainPrimary()}/course/index/{$course->getId()}"
]);
$this->emailService->setTemplateBody("enrollment");
$this->emailService->send();
}
public function enrollmentMarketingTag(Enrollment $enrollment, bool $manual = false){
$userSubscription = $enrollment->getUserSubscription();
$group = $enrollment->getGroup();
$user = $enrollment->getUser();
if($manual){
$this->marketingService->setTag(TagsMarketingEnum::TAG_ENROLLMENT_MANUALLY);
$this->marketingService->setTextComplement($enrollment->getCourse()->getTitle());
}else if($enrollment->getOrigin() == EnrollmentEnum::ORIGIN_FREE){
$this->marketingService->setTag(TagsMarketingEnum::TAG_FREE_COURSE_ACCESS);
$this->marketingService->setTextComplement($enrollment->getCourse()->getTitle());
}else if($group){
$this->marketingService->setTag(TagsMarketingEnum::TAG_ENROLLMENT_GROUP);
$this->marketingService->setTextComplement($enrollment->getCourse()->getTitle());
}else if($enrollment->getCouponKey()){
$this->marketingService->setTag(TagsMarketingEnum::TAG_ENROLLMENT_COUPON);
$this->marketingService->setTextComplement($enrollment->getCouponKey());
}else if($userSubscription){
$this->marketingService->setTag(TagsMarketingEnum::TAG_ENROLLMENT_SUBSCRIPTION);
$this->marketingService->setTextComplement(
$userSubscription->getProduct()->getTitle()
);
}
$this->marketingService->setUser($user);
$this->marketingService->send();
}
}