<?php
namespace App\Service;
use App\DTO\MMPZ\PaymentMethod\PaymentGatewayAuthorizationDTO;
use App\DTO\MMPZ\PaymentMethod\Paypal\Order\PaypalOrderDTO;
use App\DTO\MMPZ\PaymentMethod\Paypal\PaypalWebHookDTO;
use App\DTO\MMPZ\PaymentMethod\Paypal\Subscription\PaypalSubscriptionDTO;
use App\DTO\Request\ManualInvoice;
use App\Entity\App\File;
use App\Entity\Package\Invoice;
use App\Entity\Package\Package;
use App\Entity\Package\PackageSongWriter;
use App\Entity\Package\PackageTransaction;
use App\Entity\Package\ReactivationAttempts;
use App\Entity\Profile\PaymentMethod\PaymentGateway;
use App\Entity\Profile\PaymentMethod\PaymentGatewayEvent;
use App\Entity\Profile\Profile;
use App\Entity\Profile\ProfileType;
use App\Entity\User\User;
use App\Enums\Constants;
use App\Enums\PackageSongwriterStatus;
use App\Enums\PackageType;
use App\Enums\PaypalWebHookList;
use App\Enums\StripeApiInvoiceStatus;
use App\Enums\StripeWebHookList;
use App\Enums\TransactionPlatform;
use App\Enums\TransactionPlatformStatus;
use App\Event\Package\PackageCreatedEvent;
use App\Event\Package\PackageDeletedEvent;
use App\Event\Package\PackageTransactionApprovedEvent;
use App\Event\Package\PackageTransactionSubscriptionCanceledEvent;
use App\Event\Package\PackageTransactionSubscriptionInactivatedEvent;
use App\Event\Package\PackageTransactionSubscriptionReactivatedEvent;
use App\Event\Package\PackageUpdatedEvent;
use App\Factory\EntityFactory;
use App\Repository\Package\InvoiceRepository;
use App\Repository\Package\PackageRepository;
use App\Repository\Package\PackageSongwriterRepository;
use App\Repository\Package\PackageTransactionRepository;
use App\Repository\Package\ReactiveAttemptsRepository;
use App\Repository\Profile\PaymentMethod\PaymentGatewayEventRepository;
use App\Repository\Profile\PaymentMethod\PaymentGatewayRepository;
use App\Service\PaymentMethod\PaymentMethodService;
use App\Service\PaymentMethod\ProfileForPaymentMethodService;
use App\Service\PaymentMethod\Stripe\StripeService;
use Doctrine\DBAL\Types\DateTimeType;
use Stripe\Checkout\Session;
use Stripe\Subscription;
use Stripe\Webhook;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
use Symfony\Component\Serializer\SerializerInterface;
use function Aws\flatmap;
class PackageService
{
/** @var EntityFactory */
private $entityFactory;
/** @var SerializerInterface */
private $serializer;
/** @var EventDispatcherInterface */
private $eventDispatcher;
/** @var PackageRepository */
private $packageRepository;
/** @var PackageTransactionRepository */
private $packageTransactionRepository;
/** @var PackageSongwriterRepository */
private $packageSongwriterRepository;
/** @var PaymentGatewayRepository */
private $paymentGatewayRepository;
/** @var PaymentGatewayEventRepository */
private $paymentGatewayEventRepository;
/** @var InvoiceRepository */
private $invoiceRepository;
/** @var ReactiveAttemptsRepository */
private $reactiveAttemptsRepository;
/** @var PaymentMethodService */
private $paymentMethodService;
/** @var ProfileForPaymentMethodService */
private $profileForPaymentMethodService;
/** @var StripeService */
private $stripeService;
/**
* @param EntityFactory $entityFactory
* @param SerializerInterface $serializer
* @param EventDispatcherInterface $eventDispatcher
* @param PackageRepository $packageRepository
* @param PackageTransactionRepository $packageTransactionRepository
* @param PackageSongwriterRepository $packageSongwriterRepository
* @param PaymentGatewayEventRepository $paymentGatewayEventRepository
* @param PaymentGatewayRepository $paymentGatewayRepository
* @param InvoiceRepository $invoiceRepository
* @param ReactiveAttemptsRepository $reactiveAttemptsRepository
* @param PaymentMethodService $paymentMethodService
* @param ProfileForPaymentMethodService $profileForPaymentMethodService
* @param StripeService $stripeService
*/
public function __construct(
EntityFactory $entityFactory,
SerializerInterface $serializer,
EventDispatcherInterface $eventDispatcher,
PackageRepository $packageRepository,
PackageTransactionRepository $packageTransactionRepository,
PackageSongwriterRepository $packageSongwriterRepository,
PaymentGatewayRepository $paymentGatewayRepository,
PaymentGatewayEventRepository $paymentGatewayEventRepository,
InvoiceRepository $invoiceRepository,
ReactiveAttemptsRepository $reactiveAttemptsRepository,
PaymentMethodService $paymentMethodService,
ProfileForPaymentMethodService $profileForPaymentMethodService,
StripeService $stripeService
)
{
$this->entityFactory = $entityFactory;
$this->serializer = $serializer;
$this->eventDispatcher = $eventDispatcher;
$this->packageRepository = $packageRepository;
$this->packageTransactionRepository = $packageTransactionRepository;
$this->packageSongwriterRepository = $packageSongwriterRepository;
$this->paymentGatewayRepository = $paymentGatewayRepository;
$this->paymentGatewayEventRepository = $paymentGatewayEventRepository;
$this->invoiceRepository = $invoiceRepository;
$this->reactiveAttemptsRepository = $reactiveAttemptsRepository;
$this->paymentMethodService = $paymentMethodService;
$this->profileForPaymentMethodService = $profileForPaymentMethodService;
$this->stripeService = $stripeService;
}
/**
* @param ProfileType $profileType
* @param User $user
* @return Profile|null
*/
public function findProfileForProcess(ProfileType $profileType, User $user)
{
/** @var Profile $profile in that case the songWriter Profile or the publisher who buy the package */
if($_ENV['CWR_ENVIROMENT'] === "local"){
$profile = $this->profileForPaymentMethodService->getTestProfileByProfiletype($profileType);
}else{
$profile = $this->profileForPaymentMethodService->findLastAccessedProfileForUser($user);
}
return $profile;
}
/**
* @param Profile $profile
* @return array
*/
public function getAllPackageByProfile(Profile $profile)
{
return $this->packageRepository->findBy([
'profile' => $profile,
'type' => PackageType::PRIMARY,
'parent' => null
]);
}
/**
* @param Profile $profile
* @return array
*/
public function getAllSubscriptionByProfile(Profile $profile)
{
return $this->packageRepository->findBy([
'profile' => $profile,
'type' => PackageType::SUBSCRIPTION,
'parent' => null
]);
}
/**
* @param Profile $profile
* @param Profile $parentProfile
* @param bool $isAdminUser
* @return array
*/
public function getAllPackageAndSubscriptionByClient(Profile $profile, Profile $parentProfile, bool $isAdminUser)
{
$packages = $this->packageRepository->findBy([
'profile' => $parentProfile,
'profileType' => $profile->getProfileType(),
'parent' => null
]);
$relationProfileSubscriptions = $this->getRelationsProfileSubscriptions($profile);
if(count($relationProfileSubscriptions) === 0){
/** @var Package $package */
foreach($packages as $key => $package){
if(!$package->isBasic()){
unset($packages[$key]);
}
}
}else{
/** @var PackageSongWriter $activeRelation */
$activeRelation = null;
/** @var PackageSongWriter $relation */
foreach ($relationProfileSubscriptions as $relation) {
if($relation->getStatus() === PackageSongwriterStatus::ACTIVE){
$activeRelation = $relation;
break;
}
}
/** @var Package $package */
foreach ($packages as $key => $package) {
if (!$package->isEnabled() || !$package->isVisible()) {
unset($packages[$key]);
}
if(!$isAdminUser && $package->isVisibleToAdminOnly()){
unset($packages[$key]);
}
if($profile->getProfileType()->getName() === Constants::PROFILE_TYPE_PUBLISHER){
$validProfileCounter = $this->profileForPaymentMethodService->countNotClosureSubProfiles($profile);
if($validProfileCounter > $package->getSubprofileLimit() && !is_null($activeRelation)){
if(!is_null($activeRelation->getPackage()->getstandardPackageData()) || !is_null($activeRelation->getPackage()->getPlusPackageData())){
if(!is_null($activeRelation->getPackage()->getstandardPackageData())){
if($activeRelation->getPackage()->getstandardPackageData()['id'] !== $package->getId()){
$operation = $validProfileCounter - $package->getSubprofileLimit();
$reason = "This subscription allows a maximum of {$package->getSubprofileLimit()} songwriter(s). Currently,
there are {$validProfileCounter} not closed songwriters under your publisher profile.
Please close {$operation} in order to downgrade";
$package->setCanBePurchased(false);
$package->setCanNotBePurchasedReason($reason);
$packages[$key] = $package;
}
}
if(!is_null($activeRelation->getPackage()->getPlusPackageData())){
if($activeRelation->getPackage()->getPlusPackageData()['id'] !== $package->getId()){
$operation = $validProfileCounter - $package->getSubprofileLimit();
$reason = "This subscription allows a maximum of {$package->getSubprofileLimit()} songwriter(s). Currently,
there are {$validProfileCounter} not closed songwriters under your publisher profile.
Please close {$operation} in order to downgrade";
$package->setCanBePurchased(false);
$package->setCanNotBePurchasedReason($reason);
$packages[$key] = $package;
}
}
}else{
$operation = $validProfileCounter - $package->getSubprofileLimit();
$reason = "This subscription allows a maximum of {$package->getSubprofileLimit()} songwriter(s). Currently,
there are {$validProfileCounter} not closed songwriters under your publisher profile.
Please close {$operation} in order to downgrade";
$package->setCanBePurchased(false);
$package->setCanNotBePurchasedReason($reason);
$packages[$key] = $package;
}
}
}
if(!is_null($activeRelation)){
if($activeRelation->getPackage()->getId() === $package->getId()){
$package->setCanBePurchased(false);
$package->setCanNotBePurchasedReason("This is the active subscription");
$packages[$key] = $package;
}else if(!is_null($activeRelation->getPackage()->getParent())){
if($activeRelation->getPackage()->getParent()->getId() === $package->getId()){
$package->setCanBePurchased(false);
$package->setCanNotBePurchasedReason("This is the active subscription");
$packages[$key] = $package;
}
}
$reason = "Upgrade from monthly->yearly and yearly->monthly is not possible without cancellations of ongoing subscription.";
if($activeRelation->getPackage()->isMonthly() && $package->isAnnual()){
$package->setCanBePurchased(false);
$package->setCanNotBePurchasedReason($reason);
}
if($activeRelation->getPackage()->isAnnual() && $package->isMonthly()){
$package->setCanBePurchased(false);
$package->setCanNotBePurchasedReason($reason);
}
}
if(
$profile->getProfileType()->getName() === Constants::PROFILE_TYPE_SONGWRITER &&
$profile->getParent()->getProfileType()->getName() === Constants::PROFILE_TYPE_PUBLISHER
){
unset($packages[$key]);
}
}
}
return $packages;
}
/**
* @param int $id
* @return Package
*/
public function getASubscriptionOrPackageById(int $id)
{
return $this->packageRepository->findOneBy(['id' => $id]);
}
/**
* @param array $data
* @param Profile $profile
* @param ProfileType $profileType
* @param Package $parent
* @param bool $isBasic
* @return Package
*/
public function processToCreateAPackage(
array $data,
Profile $profile,
ProfileType $profileType,
Package $parent = null,
bool $isBasic = false
)
{
/** @var Package $entity */
$entity = $this->entityFactory->createFromJson(
json_encode($data),
Package::class,
['package:create']
);
$entity->setProfile($profile);
$entity->setProfileType($profileType);
$entity->setIsBasic($isBasic);
$entity->setParent($parent);
$this->packageRepository->save($entity);
/** @var Package $package */
$package = $this->packageRepository->findOneBy(['id' => $entity->getId()]);
$package = $this->paymentMethodService->processToCreateAProductInThePaymentPlatform($package);
$this->packageRepository->flush($package);
/** @var Package $package */
$package = $this->packageRepository->findOneBy(['id' => $entity->getId()]);
if($_ENV['CWR_ENVIROMENT'] !== "local"){
$this->eventDispatcher->dispatch(new PackageCreatedEvent($package, $profile));
}
return $package;
}
/**
* @param Package $package
* @param array $data
* @param Profile $profile
* @param ProfileType $profileType
* @param File $file
* @param Package|null $parent
* @param bool $isBasic
* @return Package
*/
public function processToUpdateAPackage(
Package $package,
array $data,
Profile $profile,
ProfileType $profileType,
File $file,
Package $parent = null,
bool $isBasic = false
)
{
$totalAmountAfter = (float)$package->getPrice() - ((float)$package->getPrice() * (float)$package->getDiscount());
/** @var Package $entity */
$entity = $this->entityFactory->createFromJson(
json_encode($data),
Package::class,
['package:edit'],
[
AbstractObjectNormalizer::OBJECT_TO_POPULATE => $package
]
);
$entity->setProfile($profile);
$entity->setProfileType($profileType);
$entity->setFile($file);
$entity = $this->packageRepository->merge($entity);
/** @var Package $package */
$package = $this->packageRepository->findOneBy(['id' => $entity->getId()]);
$totalAmountBefore = (float)$package->getPrice() - ((float)$package->getPrice() * (float)$package->getDiscount());
if($totalAmountAfter != $totalAmountBefore && $package->getType() === PackageType::SUBSCRIPTION){
$externalPlatformResults = $this->paymentMethodService->processToUpdateAPlanPriceProductInThePaymentPlatform($package);
if(!is_null($externalPlatformResults[TransactionPlatform::PAYPAL])){
$package->setPaypalPlanId($externalPlatformResults[TransactionPlatform::PAYPAL]->getId());
}
if(!is_null($externalPlatformResults[TransactionPlatform::STRIPE])){
$package->setStripePlanId($externalPlatformResults[TransactionPlatform::STRIPE]->id);
}
$this->packageRepository->flush($package);
/** @var Package $package */
$package = $this->packageRepository->findOneBy(['id' => $entity->getId()]);
}
$this->eventDispatcher->dispatch(new PackageUpdatedEvent($package));
return $package;
}
/**
* @param PackageTransaction $packageTransaction
* @return Package
*/
public function processToUpdateTheChildPackagePrice(PackageTransaction $packageTransaction)
{
$package = $packageTransaction->getPackage();
if(!is_null($package->getParent())){
$package->setPrice($package->getParent()->getPrice());
$package->setDiscount($package->getParent()->getDiscount());
$this->packageRepository->flush($package);
/** @var Package $package */
$package = $this->packageRepository->findOneBy(['id' => $package->getId()]);
if(!is_null($package->getStripePlanId()) || !is_null($package->getPaypalPlanId())){
$externalPlatformResults = $this->paymentMethodService->processToUpdateAPlanPriceProductInThePaymentPlatform($package);
if(!is_null($externalPlatformResults[TransactionPlatform::PAYPAL])){
$package->setPaypalPlanId($externalPlatformResults[TransactionPlatform::PAYPAL]->getId());
}
if(!is_null($externalPlatformResults[TransactionPlatform::STRIPE])){
$package->setStripePlanId($externalPlatformResults[TransactionPlatform::STRIPE]->id);
$this->paymentMethodService->processToUpdateStripePriceSusbcription($packageTransaction);
}
$this->packageRepository->flush($package);
/** @var Package $package */
$package = $this->packageRepository->findOneBy(['id' => $package->getId()]);
}
}
return $package;
}
/**
* @param Package $package
* @param array $data
* @return Package
*/
public function processToCreateAPlusPackage(Package $package, array $data): Package
{
if($package->isHasPlus()){
/** @var Package $pp */
$pp = $this->packageRepository->findOneBy(['id' => $package->getPackagePlus()->getId()]);
if(!is_null($pp)){
throw new BadRequestHttpException("The subscription already has a plus");
}
}
/** @var Package $newPackagePlus */
$newPackagePlus = $this->entityFactory->createFromJson(
json_encode($data),
Package::class,
['package:create']
);
$newPackagePlus->setName($package->getName()." Plus");
$newPackagePlus->setDescription($package->getDescription()." Plus");
$newPackagePlus->setIsBasic($package->isBasic());
$newPackagePlus->setParent($package->getParent());
$newPackagePlus->setProfile($package->getProfile());
$newPackagePlus->setProfileType($package->getProfileType());
$newPackagePlus->setHasStandard(true);
$newPackagePlus->setPackageStandard($package);
$this->packageRepository->save($newPackagePlus);
/** @var Package $newPackagePlus */
$newPackagePlus = $this->packageRepository->findOneBy(['id' => $newPackagePlus->getId()]);
$newPackagePlus = $this->paymentMethodService->processToCreateAProductInThePaymentPlatform($newPackagePlus);
$this->packageRepository->flush($newPackagePlus);
/** @var Package $newPackagePlus */
$newPackagePlus = $this->packageRepository->findOneBy(['id' => $newPackagePlus->getId()]);
if($_ENV['CWR_ENVIROMENT'] !== "local"){
$this->eventDispatcher->dispatch(new PackageCreatedEvent($newPackagePlus, $newPackagePlus->getProfile()));
}
$package->setHasPlus(true);
$package->setPackagePlus($newPackagePlus);
$this->packageRepository->flush($package);
return $newPackagePlus;
}
/**
* @param Package $package
* @return Package
*/
public function processToDeleteAPackage(Package $package)
{
$package->setEnabled(false);
if($package->isHasStandard()){//this is when is deleted a package plus
/** @var Package $packageStandard */
$packageStandard = $this->packageRepository->findOneBy([
'id' => $package->getPackageStandard()->getId()
]);
$packageStandard->setPackagePlus(null);
$packageStandard->setHasPlus(false);
$package->setHasStandard(false);
$package->setPackageStandard(null);
}else if($package->isHasPlus()){//this is when is deleted a package standard
/** @var Package $packagePlus */
$packagePlus = $this->packageRepository->findOneBy([
'id' => $package->getPackagePlus()->getId()
]);
$packagePlus->setPackageStandard(null);
$packagePlus->setHasStandard(false);
$package->setHasPlus(false);
$package->setPackagePlus(null);
}
$this->packageRepository->flush($package);
$this->eventDispatcher->dispatch(new PackageDeletedEvent($package));
/** @var Package $package */
$package = $this->packageRepository->findOneBy(['id' => $package->getId()]);
return $package;
}
/**
* @param array $data
* @param Profile $profile
* @param Package $package
* @return float
* @throws \GuzzleHttp\Exception\GuzzleException
* @throws \Stripe\Exception\ApiErrorException
*/
public function processToShowPriceToUpgrade(
array $data,
Profile $profile,
Package $package
)
{
/** @var PaymentGateway $paymentGateway */
$paymentGateway = $this->paymentGatewayRepository->findOneBy(['id' => $data['payment_gateway']['id']]);
$customPriceToUpgrade = $package->getPrice() - ($package->getPrice() * $package->getDiscount());
/** @var PackageSongWriter $packageSongWriter */
$packageSongWriter = $this->processToCheckActiveInactiveSubscription($profile);
if(!is_null($packageSongWriter)){
$this->processToCheckOldPackageNewPackage($packageSongWriter->getPackage(), $package);
$oldPackage = (is_null($packageSongWriter->getPackage()->getParent())) ?
$packageSongWriter->getPackage() :
$packageSongWriter->getPackage()->getParent();
if($package->getPrice() <= $oldPackage->getPrice()){
if($this->profileForPaymentMethodService->countNotClosureSubProfiles($profile) > $package->getSubprofileLimit()){
throw new BadRequestHttpException(
"Please, check your sub-profiles, you need to have at most {$package->getSubprofileLimit()} non-closed subprofiles"
);
}
}else{
$customPriceToUpgrade = $this->calculatePriceToUpgrade(
$package,
$packageSongWriter
);
if(
$package->isHasStandard() &&
$package->getPackageStandard()->getId() === $oldPackage->getId()
){
$oldPrice = (float)$oldPackage->getPrice() - ((float)$oldPackage->getPrice() * (float)$oldPackage->getDiscount());
$customPriceToUpgrade = $package->getPrice() - ($package->getPrice() * $package->getDiscount());
$customPriceToUpgrade = $customPriceToUpgrade - $oldPrice;
}
}
}
return $customPriceToUpgrade;
}
/**
* @param Profile $profile
* @return array
*/
public function getTransactionsByProfile(Profile $profile)
{
return $this->packageTransactionRepository->findBy(
['profile' => $profile]
);
}
/**
* @param Profile $profile
* @return array
*/
public function getRelationsProfileSubscriptions(Profile $profile)
{
return $this->packageSongwriterRepository->findBy(['profile' => $profile]);
}
/**
* @param array $data
* @param Profile $profile
* @param Package $package
* @param string $manual
* @return PackageTransaction
* @throws \GuzzleHttp\Exception\GuzzleException
* @throws \Stripe\Exception\ApiErrorException
*/
public function processtoCreateTransaction(
array $data,
Profile $profile,
Package $package,
string $manual = ""
)
{
/** @var PaymentGateway $paymentGateway */
$paymentGateway = $this->paymentGatewayRepository->findOneBy(['id' => $data['payment_gateway']['id']]);
/** @var PackageTransaction $entity */
$entity = $this->entityFactory->createFromJson(
json_encode($data),
PackageTransaction::class,
['package-transaction:create']
);
$entity->setProfile($profile);
$entity->setPackage($package);
$entity->setPaymentGateway($paymentGateway);
/** @var PackageSongWriter $packageSongWriter */
$packageSongWriter = $this->processToCheckActiveInactiveSubscription($profile);
if(!is_null($packageSongWriter)){
$this->processToCheckOldPackageNewPackage($packageSongWriter->getPackage(), $package);
$entity->setTransitionTransaction($packageSongWriter->getPackageTransaction());
$oldPackage = (is_null($packageSongWriter->getPackage()->getParent())) ?
$packageSongWriter->getPackage() :
$packageSongWriter->getPackage()->getParent();
if($package->getPrice() <= $oldPackage->getPrice()){//Process for downgrade
if($this->profileForPaymentMethodService->countNotClosureSubProfiles($profile) > $package->getSubprofileLimit()){
throw new BadRequestHttpException(
"Please, check your sub-profiles, you need to have at most {$package->getSubprofileLimit()} non-closed subprofiles"
);
}
/*if(
$package->isHasPlus() &&
$package->getPackagePlus()->getId() === $oldPackage->getId()
){
$customPriceToDowngrade = (float)$package->getPrice() - ((float)$package->getPrice() * (float)$package->getDiscount());
$oldPrice = (float)$oldPackage->getPrice() - ((float)$oldPackage->getPrice() * (float)$oldPackage->getDiscount());
$customPriceToDowngrade = $oldPrice - $customPriceToDowngrade;
$newPackageData = $this->buildAPackageArray(
$customPriceToDowngrade,
$package,
$oldPackage
);
$package = $this->processToCreateAPackage(
$newPackageData,
$package->getProfile(),
$package->getProfileType(),
$package,
false
);
$entity->setPackage($package);
}*/
$entity->setTransitionReason(Constants::DOWNGRADE_SUBSCRIPTION);
}else{//Process for upgrade
$arrExtPackTranId = explode("-", $packageSongWriter->getPackageTransaction()->getPaymentGatewayExternalId());
$manualProcess = false;
if($arrExtPackTranId[0] === Constants::MANUAL_INVOICE_IDENTIFIER || $arrExtPackTranId[0] === Constants::FREE_INVOICE_IDENTIFIER){
$manualProcess = !$manualProcess;
}
$customPriceToUpgrade = $this->calculatePriceToUpgrade(
$package,
$packageSongWriter
);
if(
$package->isHasStandard() &&
$package->getPackageStandard()->getId() === $oldPackage->getId()
){
$customPriceToUpgrade = (float)$package->getPrice() - ((float)$package->getPrice() * (float)$package->getDiscount());
$oldPrice = (float)$oldPackage->getPrice() - ((float)$oldPackage->getPrice() * (float)$oldPackage->getDiscount());
$customPriceToUpgrade = $customPriceToUpgrade - $oldPrice;
}
$newPackageData = $this->buildAPackageArray(
$customPriceToUpgrade,
$package,
$oldPackage
);
$package = $this->processToCreateAPackage(
$newPackageData,
$package->getProfile(),
$package->getProfileType(),
$package,
false
);
$entity->setTransitionReason(Constants::UPGRADE_SUBSCRIPTION);
//Here it is set again the new package created to can register the price of the diference Btwn the
// new package and the old package
$entity->setPackage($package);
}
}
if((float)$package->getPrice() > 0 && $manual === ""){
if($paymentGateway->getPaymentType()->getName() === TransactionPlatform::PAYPAL){
switch ($package->getType()){
case PackageType::PRIMARY:
/** @var PaypalOrderDTO $paypalOderDTO */
$paypalOderDTO = $this->paymentMethodService->processToCreatePackageOrder($entity);
$entity->setPaymentGatewayExternalId($paypalOderDTO->getId());
$entity->setPaymentGatewayCreate($this->serializer->serialize($paypalOderDTO, "json", ['groups' => 'paypal:order']));
break;
case PackageType::SUBSCRIPTION:
/** @var PaypalSubscriptionDTO $paypalSubscriptionDTO */
$paypalSubscriptionDTO = $this->paymentMethodService->processToCreateSubscription($entity);
$entity->setPaymentGatewayExternalId($paypalSubscriptionDTO->getId());
$entity->setPaymentGatewayCreate($this->serializer->serialize($paypalSubscriptionDTO, "json", ['groups' => 'paypal:subscription']));
break;
}
//echo $this->serializer->serialize($entity, "json", ['groups' => 'package-transaction:show']); exit();
}else if($paymentGateway->getPaymentType()->getName() === TransactionPlatform::STRIPE){
switch ($package->getType()){
case PackageType::PRIMARY:
/** @var Session $stripeCharge */
$stripeCharge = $this->paymentMethodService->processToCreatePackageOrder($entity);
$entity->setPaymentGatewayExternalId($stripeCharge->id);
$entity->setPaymentGatewayCreate($stripeCharge->toJSON());
break;
case PackageType::SUBSCRIPTION:
/** @var Session $stripeSubscription */
$stripeSubscription = $this->paymentMethodService->processToCreateSubscription($entity);
$entity->setPaymentGatewayExternalId($stripeSubscription->id);
$entity->setPaymentGatewayCreate($stripeSubscription->toJSON());
break;
}
}
}else{
if($manual === Constants::MANUAL_PROCESS_CREATE_SUBCRIPTION){
$entity->setPaymentGatewayExternalId(
Constants::MANUAL_INVOICE_IDENTIFIER."-".$package->getId()."-".date("YmdHis")
);
}else{
$entity->setPaymentGatewayExternalId(
Constants::FREE_INVOICE_IDENTIFIER."-".$package->getId()."-".date("YmdHis")
);
}
}
$entity->setCreatedAt(new \DateTime());
/** @var PackageTransaction $packageTransaction */
$packageTransaction = $this->packageTransactionRepository->save($entity);
return $packageTransaction;
}
/**
* @param array $data
* @param Profile $profile
* @param Package $package
* @param PackageTransaction $packageTransaction
* @param string $manual
* @return PackageTransaction
* @throws \GuzzleHttp\Exception\GuzzleException
* @throws \Stripe\Exception\ApiErrorException
*/
public function processToEditTransaction(
array $data,
Profile $profile,
Package $package,
PackageTransaction $packageTransaction,
string $manual = ""
)
{
/** @var PaymentGateway $paymentGateway */
$paymentGateway = $this->paymentGatewayRepository->findOneBy(['id' => $data['payment_gateway']['id']]);
$packageTransaction->setStatus(TransactionPlatformStatus::COMPLETED);
if((float)$package->getPrice() > 0 && $manual === ""){
if($paymentGateway->getPaymentType()->getName() === TransactionPlatform::PAYPAL){
switch ($package->getType()){
case PackageType::PRIMARY:
/** @var PaypalOrderDTO $paypalOderDTO */
$paypalOderDTO = $this->paymentMethodService->processToConfirmPackageOrder($packageTransaction);
$packageTransaction->setPaymentGatewayProcess($this->serializer->serialize($paypalOderDTO, "json", ['groups' => 'paypal:order']));
break;
case PackageType::SUBSCRIPTION:
/** @var PaypalSubscriptionDTO $paypalSubscriptionDTO */
$paypalSubscriptionDTO = $this->paymentMethodService->processToConfirmSubscription($packageTransaction);
$packageTransaction->setPaymentGatewayProcess($this->serializer->serialize($paypalSubscriptionDTO, "json", ['groups' => 'paypal:subscription']));
break;
}
}else if($paymentGateway->getPaymentType()->getName() === TransactionPlatform::STRIPE){
switch ($package->getType()){
case PackageType::PRIMARY:
/** @var Session $stripeCharge */
$stripeCharge = $this->paymentMethodService->processToConfirmPackageOrder($packageTransaction);
$packageTransaction->setPaymentGatewayProcess($stripeCharge->toJSON());
break;
case PackageType::SUBSCRIPTION:
/** @var Subscription $stripeSubscription */
$stripeSubscription = $this->paymentMethodService->processToConfirmSubscription($packageTransaction);
$packageTransaction->setPaymentGatewayProcess($stripeSubscription->toJSON());
$packageTransaction->setPaymentGatewayExternalId($stripeSubscription->id);
$data['payment_gateway_external_id'] = $stripeSubscription->id;
break;
}
}
}else{
$packageTransaction->setManual(true);
}
$packageTransaction->setProcessedAt(new \DateTime());
$this->packageTransactionRepository->flush($packageTransaction);
/** @var PackageTransaction $packageTransaction */
$packageTransaction = $this->packageTransactionRepository->findOneBy([
'paymentGatewayExternalId' => $data['payment_gateway_external_id']
]);
if(!is_null($packageTransaction->getTransitionTransaction())){
$packageTransactionOld = $this->processToCancelASubscription(
$packageTransaction->getTransitionReason(),
$packageTransaction->getTransitionTransaction()
);
}
return $packageTransaction;
}
/**
* @param PackageTransaction $packageTransaction
* @param string $manual
* @return PackageSongWriter
* @throws \Exception
*/
public function processtoCreateRelationPackageProfile(
PackageTransaction $packageTransaction,
string $manual = ""
)
{
$credentials = $this->getCredentialFOrPaymentGateway($packageTransaction->getProfile());
$packageSongwriter = (new PackageSongWriter())
->setPackage($packageTransaction->getPackage())
->setProfile($packageTransaction->getProfile())
->setPackageTransaction($packageTransaction)
->setActive(true)
->setStatus(PackageSongwriterStatus::ACTIVE)
->setTypeSubcription("normal");
if((float)$packageTransaction->getPackage()->getPrice() > 0 && $manual === ""){
if($packageTransaction->getPackage()->getType() === PackageType::SUBSCRIPTION){
switch ($packageTransaction->getPaymentGateway()->getPaymentType()->getName()){
case TransactionPlatform::STRIPE:
/** @var Subscription $stripeSubscription */
$stripeSubscription = $this->paymentMethodService->processToGetSubscriptionTransactionInformation(
$packageTransaction
);
$packageSongwriter->setAvialableOn(\DateTime::createFromFormat('U', $stripeSubscription->current_period_start));
$packageSongwriter->setAvialableOff(\DateTime::createFromFormat('U', $stripeSubscription->current_period_end));
break;
case TransactionPlatform::PAYPAL:
/** @var PaypalSubscriptionDTO $paypalSubscription */
$paypalSubscription = $this->paymentMethodService->processToGetSubscriptionTransactionInformation(
$packageTransaction
);
$startDate = \DateTime::createFromFormat(
'Y-m-d\TH:i:s\Z',
$paypalSubscription->getUpdateTime()
);
$packageSongwriter->setAvialableOn($startDate);
$endDate = \DateTime::createFromFormat(
'Y-m-d\TH:i:s\Z',
$paypalSubscription->getBillingInfo()->getNextBillingTime()
);
$packageSongwriter->setAvialableOff($endDate);
break;
}
}else{
}
}else{
if($manual !== Constants::MANUAL_PROCESS_CREATE_SUBCRIPTION){
$startDate = new \DateTime();
$packageSongwriter->setAvialableOn($startDate);
$endDate = new \DateTime();
$endDate = ($packageTransaction->getPackage()->isMonthly()) ? $endDate->modify("+1 month") : $endDate->modify('+1 year');
$packageSongwriter->setAvialableOff($endDate);
}else{
$packageSongwriter->setAvialableOn($packageTransaction->getProcessedAt());
$endDate =$packageTransaction->getProcessedAt();
$endDate = ($packageTransaction->getPackage()->isMonthly()) ? $endDate->modify("+1 month") : $endDate->modify('+1 year');
$packageSongwriter->setAvialableOff($endDate);
}
}
$packageSongwriter = $this->packageSongwriterRepository->save($packageSongwriter);
/** @var PackageSongWriter $packageSongwriter */
$packageSongwriter = $this->packageSongwriterRepository->findOneBy(['id' => $packageSongwriter->getId()]);
return $packageSongwriter;
}
/**
* @param \DateTime $dateBegin
* @param PackageTransaction $packageTransaction
* @return PackageTransaction
*/
public function processToCheckDateForManualPaymentInTransaction(
\DateTime $dateBegin,
PackageTransaction $packageTransaction
)
{
$currentDate = new \DateTime();
if($dateBegin->getTimestamp() > $currentDate->getTimestamp()){
$packageTransaction->setStatus(TransactionPlatformStatus::CREATED);
}
$packageTransaction->setCreatedAt($dateBegin);
$packageTransaction->setProcessedAt($dateBegin);
$this->packageTransactionRepository->flush($packageTransaction);
return $packageTransaction;
}
/**
* @param PackageTransaction $packageTransaction
* @param PackageSongWriter $packageSongWriter
* @return Invoice
*/
public function processToCreateInvoice(
PackageTransaction $packageTransaction,
PackageSongWriter $packageSongWriter
)
{
$invoice = (new Invoice())
->setPackageSongWriter($packageSongWriter)
->setNumber($packageTransaction->getId().$packageSongWriter->getId()."-".$this->invoiceCounter($packageSongWriter))
->setBillingDate($packageTransaction->getCreatedAt())
->setSubTotal($packageTransaction->getPackage()->getPrice())
->setDiscount($packageTransaction->getPackage()->getDiscount() * $packageTransaction->getPackage()->getPrice())
->setTaxes(0)
->setStatus(PackageSongwriterStatus::ACTIVE)
->setAvialableOn($packageSongWriter->getAvialableOn())
->setAvialableOff($packageSongWriter->getAvialableOff());
$invoiceItems = [
$this->serializer->serialize($packageTransaction->getPackage(), "json", ['groups' => 'invoice:json'])
];
$invoice->setItems(json_encode($invoiceItems));
$totalAmount = (float)$packageTransaction->getPackage()->getPrice() - ((float)$packageTransaction->getPackage()->getDiscount() * (float)$packageTransaction->getPackage()->getPrice());
$invoice->setTotal($totalAmount);
$invoice = $this->invoiceRepository->save($invoice);
/** @var Invoice $invoice */
$invoice = $this->invoiceRepository->findOneBy(['id' => $invoice->getId()]);
return $invoice;
}
/**
* @param PackageSongWriter $packageSongWriter
* @return int
*/
public function invoiceCounter(PackageSongWriter $packageSongWriter, $to = "create")
{
$invoices = $this->invoiceRepository->findBy(['packageSongWriter' => $packageSongWriter]);
if($to === "create"){
return count($invoices) + 1;
}else{
return count($invoices);
}
}
/**
* @param Profile $profile
* @return PackageSongWriter|null
*/
public function processToCheckActiveInactiveSubscription(Profile $profile)
{
/** @var PackageSongWriter $packageSongwriter */
foreach ($this->packageSongwriterRepository->findBy(['profile' => $profile]) as $packageSongwriter){
if(
$packageSongwriter->getActive() &&
($packageSongwriter->getStatus() === PackageSongwriterStatus::ACTIVE ||
$packageSongwriter->getStatus() === PackageSongwriterStatus::INACTIVE) &&
$packageSongwriter->getPackage()->getType() === PackageType::SUBSCRIPTION
){
return $packageSongwriter;
}
}
return null;
}
/*
* Get only Active subscription
* @param Profile $profile
* @return PackageSongWriter|null
*/
public function processToCheckActiveSubscription(Profile $profile)
{
/** @var PackageSongWriter $packageSongwriter */
foreach ($this->packageSongwriterRepository->findBy(['profile' => $profile]) as $packageSongwriter){
if(
$packageSongwriter->getActive() &&
$packageSongwriter->getStatus() === PackageSongwriterStatus::ACTIVE &&
$packageSongwriter->getPackage()->getType() === PackageType::SUBSCRIPTION
){
return $packageSongwriter;
}
}
return null;
}
/**
* @param PackageTransaction $packageTransaction
* @return object|null
*/
public function processToCancelAPackageTransactionWithPackage(PackageTransaction $packageTransaction)
{
if($packageTransaction->getPackage()->getType() === PackageType::PRIMARY){
$packageTransaction->setStatus(TransactionPlatformStatus::CANCELED);
$this->packageTransactionRepository->flush($packageTransaction);
/** @var PackageSongWriter $packageSongWriter */
$packageSongWriter = $this->packageSongwriterRepository->findOneBy(['packageTransaction' => $packageTransaction]);
$packageSongWriter->setActive(false);
$packageSongWriter->setStatus(PackageSongwriterStatus::CANCELLED);
$this->packageSongwriterRepository->flush($packageSongWriter);
//Set the invoice status as cancelled
$this->updateTheInvoiceStatus($packageSongWriter, PackageSongwriterStatus::CANCELLED);
}
return $this->packageTransactionRepository->findOneBy(['id' => $packageTransaction->getId()]);
}
/**
* @param string $comment
* @param PackageTransaction $packageTransaction
* @param string $from
* @return object|null
*/
public function processToCancelASubscription(
string $comment,
PackageTransaction $packageTransaction,
string $from = "web"
)
{
if($from === "web" && (float)$packageTransaction->getPackage()->getPrice() > 0 && !$packageTransaction->isManual()){
if($packageTransaction->getCancelUrl() !== "" && $packageTransaction->getReturnUrl() !== ""){
if($packageTransaction->getPaymentGateway()->getPaymentType()->getName() === TransactionPlatform::PAYPAL){
/** @var PaypalSubscriptionDTO $paypalSubscriptionDTO */
$paypalSubscriptionDTO = $this->paymentMethodService->processToCancelSubscription(
$packageTransaction,
$comment
);
$packageTransaction->setPaymentGatewayProcess($this->serializer->serialize(
$paypalSubscriptionDTO,
"json",
['groups' => 'paypal:subscription']
));
}else if($packageTransaction->getPaymentGateway()->getPaymentType()->getName() === TransactionPlatform::STRIPE){
/** @var Subscription $stripeSubscription */
$stripeSubscription = $this->paymentMethodService->processToCancelSubscription(
$packageTransaction,
$comment
);
$packageTransaction->setPaymentGatewayProcess($stripeSubscription->toJSON());
}
}
}
$packageTransaction->setStatus(TransactionPlatformStatus::CANCELED);
$this->packageTransactionRepository->flush($packageTransaction);
/** @var PackageSongWriter $packageSongWriter */
$packageSongWriter = $this->packageSongwriterRepository->findOneBy(['packageTransaction' => $packageTransaction]);
$packageSongWriter->setActive(false);
$packageSongWriter->setStatus(PackageSongwriterStatus::CANCELLED);
$this->packageSongwriterRepository->flush($packageSongWriter);
//Set the invoice status as cancelled
$this->updateTheInvoiceStatus($packageSongWriter, PackageSongwriterStatus::CANCELLED);
$this->eventDispatcher->dispatch(new PackageTransactionSubscriptionCanceledEvent($packageTransaction, $from));
return $this->packageTransactionRepository->findOneBy(['id' => $packageTransaction->getId()]);
}
/**
* @param string $comment
* @param string $paymentGatewayStatus
* @param PackageTransaction $packageTransaction
* @param string $from
* @return object|null
*/
public function processToInactiveASubscription(
string $comment,
string $paymentGatewayStatus,
PackageTransaction $packageTransaction,
string $from = "web"
)
{
/** @var ReactivationAttempts $lastReactivationAttempt */
$lastReactivationAttempt = $this->getReactivationAttempts($packageTransaction);
$currentDate = new \DateTime();
$tryAgain = false;
if(is_null($lastReactivationAttempt)){
$tryAgain = true;
}else if($currentDate->getTimestamp() >= $lastReactivationAttempt->getNextAttemptDate()->getTimestamp()){
$tryAgain = true;
}
if($packageTransaction->getReactivationAttempts()->count() < 3 && $tryAgain){
if($from === "web" && (float)$packageTransaction->getPackage()->getPrice() > 0){
if($packageTransaction->getCancelUrl() !== "" && $packageTransaction->getReturnUrl() !== ""){
if($packageTransaction->getPaymentGateway()->getPaymentType()->getName() === TransactionPlatform::PAYPAL){
/** @var PaypalSubscriptionDTO $paypalSubscriptionDTO */
$paypalSubscriptionDTO = $this->paymentMethodService->processToSuspendSubscription(
$packageTransaction,
$comment
);
$packageTransaction->setPaymentGatewayProcess($this->serializer->serialize(
$paypalSubscriptionDTO,
"json",
['groups' => 'paypal:subscription']
));
}else if($packageTransaction->getPaymentGateway()->getPaymentType()->getName() === TransactionPlatform::STRIPE){
/** @var Subscription $stripeSubscription */
$stripeSubscription = $this->paymentMethodService->processToSuspendSubscription(
$packageTransaction,
$comment
);
$packageTransaction->setPaymentGatewayProcess($stripeSubscription->toJSON());
}
}
}
$packageTransaction->setStatus(TransactionPlatformStatus::INACTIVE);
$this->packageTransactionRepository->flush($packageTransaction);
/** @var PackageSongWriter $packageSongWriter */
$packageSongWriter = $this->packageSongwriterRepository->findOneBy(['packageTransaction' => $packageTransaction]);
$packageSongWriter->setActive(true);
$packageSongWriter->setStatus(PackageSongwriterStatus::INACTIVE);
$this->packageSongwriterRepository->flush($packageSongWriter);
if($from === "command" || $from === "webhook"){
$reactiveAttempt= (new ReactivationAttempts())
->setPackageTransaction($packageTransaction)
->setPaymentGatewayName($packageTransaction->getPaymentGateway()->getPaymentType()->getName())
->setPaymentGatewayStatus($paymentGatewayStatus)
->setAttemptDate(new \DateTime());
$nextAttemptDate = new \DateTime();
$nextAttemptDate->modify("+5 day");
$reactiveAttempt->setNextAttemptDate($nextAttemptDate);
$reactiveAttempt->setAttemptMessageSent(true);
$this->reactiveAttemptsRepository->save($reactiveAttempt);
$this->eventDispatcher->dispatch(new PackageTransactionSubscriptionInactivatedEvent($packageTransaction, $from));
}
}
return $this->packageTransactionRepository->findOneBy(['id' => $packageTransaction->getId()]);
}
/**
* @param ManualInvoice $manualInvoice
* @param PackageTransaction $packageTransaction
* @param string $manual
* @param string $from
* @return object|null
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function processToReactiveASubscription(
ManualInvoice $manualInvoice,
PackageTransaction $packageTransaction,
string $from = "command"
)
{
$currentDate = new \DateTime();
$packageTransaction->setStatus(TransactionPlatformStatus::COMPLETED);
$packageTransaction->setManual(true);
$this->packageTransactionRepository->flush($packageTransaction);
/** @var PackageSongWriter $packageSongWriter */
$packageSongWriter = $this->packageSongwriterRepository->findOneBy(['packageTransaction' => $packageTransaction]);
$packageSongWriter->setActive(true);
$packageSongWriter->setStatus(PackageSongwriterStatus::ACTIVE);
$packageSongWriter->setAvialableOn($manualInvoice->getDateBegin());
$packageSongWriter->setAvialableOff($manualInvoice->getDateEnd());
if($packageSongWriter->getAvialableOn()->getTimestamp() > $currentDate->getTimestamp()){
$packageSongWriter->setStatus(PackageSongwriterStatus::PENDING);
}
$this->packageSongwriterRepository->flush($packageSongWriter);
$this->activeTheLastInvoice($packageSongWriter, $manualInvoice);
if(!$packageTransaction->isResumeMessageSent()){
$packageTransaction->setResumeMessageSent(true);
/*$this->eventDispatcher->dispatch(new PackageTransactionSubscriptionReactivatedEvent(
$packageTransaction,
$from
));*/
}
return $this->packageTransactionRepository->findOneBy(['id' => $packageTransaction->getId()]);
}
/**
* @param PackageTransaction $packageTransaction
* @param ManualInvoice $manualIncoive
* @return void
*/
public function processToAddAnInvoiceManually(
PackageTransaction $packageTransaction,
ManualInvoice $manualInvoice
)
{
$currentDate = new \DateTime();
/** @var PackageSongWriter $packageSongWriter */
$packageSongWriter = $this->packageSongwriterRepository->findOneBy(['packageTransaction' => $packageTransaction]);
$packageSongWriter->setAvialableOn($manualInvoice->getDateBegin());
$packageSongWriter->setAvialableOff($manualInvoice->getDateEnd());
if($packageSongWriter->getAvialableOn()->getTimestamp() > $currentDate->getTimestamp()){
$packageSongWriter->setStatus(PackageSongwriterStatus::PENDING);
}
$this->packageSongwriterRepository->flush($packageSongWriter);
/** @var PackageSongWriter $packageSongWriter */
$packageSongWriter = $this->packageSongwriterRepository->findOneBy(['id' => $packageSongWriter->getId()]);
$invoice = (new Invoice())
->setPackageSongWriter($packageSongWriter)
->setNumber($packageTransaction->getId().$packageSongWriter->getId()."-".$this->invoiceCounter($packageSongWriter))
->setHorusNumber($manualInvoice->getIdentifier())
->setBillingDate($manualInvoice->getDateBegin())
->setSubTotal($packageTransaction->getPackage()->getPrice())
->setDiscount($packageTransaction->getPackage()->getDiscount() * $packageTransaction->getPackage()->getPrice())
->setTaxes(0)
->setStatus($packageSongWriter->getStatus())
->setAvialableOn($manualInvoice->getDateBegin())
->setAvialableOff($manualInvoice->getDateEnd());
$invoiceItems = [
$this->serializer->serialize($packageTransaction->getPackage(), "json", ['groups' => 'invoice:json'])
];
$invoice->setItems(json_encode($invoiceItems));
$totalAmount = (float)$packageTransaction->getPackage()->getPrice() - ((float)$packageTransaction->getPackage()->getDiscount() * (float)$packageTransaction->getPackage()->getPrice());
$invoice->setTotal($totalAmount);
$invoice = $this->invoiceRepository->save($invoice);
}
/**
* This function is used in the command to check if the subscription are pending and they need to change to active
* @return array
*/
public function processToActivePendingSubscription()
{
$dataPackageProfiles = [];
$currentDate = new \DateTime();
/** @var PackageSongWriter $packageSongWriter */
foreach ($this->packageSongwriterRepository->findAll() as $packageSongWriter){
if($packageSongWriter->getStatus() === PackageSongwriterStatus::PENDING){
if($packageSongWriter->getAvialableOn()->getTimestamp() <= $currentDate->getTimestamp()){
$packageSongWriter->setStatus(PackageSongwriterStatus::ACTIVE);
$this->packageSongwriterRepository->flush($packageSongWriter);
/** @var Invoice $invoice */
foreach ($this->invoiceRepository->findBy(['packageSongWriter' => $packageSongWriter]) as $invoice){
$invoice->setStatus(PackageSongwriterStatus::ACTIVE);
$this->invoiceRepository->flush($invoice);
}
$packageTransaction = $packageSongWriter->getPackageTransaction();
$packageTransaction->setStatus(TransactionPlatformStatus::COMPLETED);
$this->packageTransactionRepository->flush($packageTransaction);
$dataPackageProfiles[] = $this->packageSongwriterRepository->findOneBy([
'id' => $packageSongWriter->getId()
]);
}
}
}
return $dataPackageProfiles;
}
/**
* @param PackageSongWriter $packageSongWriter
* @param Object $objectQuery this can be an object for a Paypal subscription or an object for a Stripe subscription
* @return object|null
*/
public function processToUpdateDatesTransaction(
PackageSongWriter $packageSongWriter,
Object $objectQuery
)
{
echo $packageSongWriter->getId()."\n";
$update = false;
$packageTransaction = $packageSongWriter->getPackageTransaction();
/*if($packageTransaction->getPaymentGateway()->getPaymentType()->getName() === TransactionPlatform::PAYPAL){
$objectQuery = $objectQuery;
$beginDate = \DateTime::createFromFormat('Y-m-d\TH:i:s\Z', $objectQuery->getUpdateTime());
$endDate = \DateTime::createFromFormat('Y-m-d\TH:i:s\Z', $objectQuery->getBillingInfo()->getNextBillingTime());
if($beginDate->getTimestamp() > $packageSongWriter->getAvialableOn()->getTimestamp()){
if($beginDate->format('Y-m-d') != $packageSongWriter->getAvialableOn()->format('Y-m-d')){
$update = !$update;
}
}
}else if($packageTransaction->getPaymentGateway()->getPaymentType()->getName() === TransactionPlatform::STRIPE){
$objectQuery = $objectQuery;
$beginDate = \DateTime::createFromFormat('U', $objectQuery->current_period_start);
$endDate = \DateTime::createFromFormat('U', $objectQuery->current_period_end);
if($beginDate->getTimestamp() > $packageSongWriter->getAvialableOn()->getTimestamp()){
$stripeInvoice = $this->paymentMethodService->processtoGetInvoiceInformation(
$packageTransaction,
$objectQuery->latest_invoice
);
$invoiceBeginDate = \DateTime::createFromFormat('U', $stripeInvoice->period_start);
if($invoiceBeginDate->format('Y-m-d') != $packageSongWriter->getAvialableOn()->format('Y-m-d')){
if($stripeInvoice->status === StripeApiInvoiceStatus::PAID){
$update = !$update;
}
}
}
}
if($update){
$packageSongWriter->setAvialableOn($beginDate);
$packageSongWriter->setAvialableOff($endDate);
$this->packageSongwriterRepository->flush($packageSongWriter);
$this->updateTheInvoiceStatus($packageSongWriter, PackageSongwriterStatus::INACTIVE);
$invoice = (new Invoice())
->setPackageSongWriter($packageSongWriter)
->setNumber($packageTransaction->getId().$packageSongWriter->getId()."-".$this->invoiceCounter($packageSongWriter))
->setBillingDate($beginDate)
->setSubTotal($packageTransaction->getPackage()->getPrice())
->setDiscount($packageTransaction->getPackage()->getDiscount() * $packageTransaction->getPackage()->getPrice())
->setTaxes(0)
->setStatus(PackageSongwriterStatus::ACTIVE)
->setAvialableOn($packageSongWriter->getAvialableOn())
->setAvialableOff($packageSongWriter->getAvialableOff());
$invoiceItems = [
$this->serializer->serialize($packageTransaction->getPackage(), "json", ['groups' => 'invoice:json'])
];
$invoice->setItems(json_encode($invoiceItems));
$totalAmount = (float)$packageTransaction->getPackage()->getPrice() - ((float)$packageTransaction->getPackage()->getDiscount() * (float)$packageTransaction->getPackage()->getPrice());
$invoice->setTotal($totalAmount);
$invoice = $this->invoiceRepository->save($invoice);
$this->eventDispatcher->dispatch(new PackageTransactionApprovedEvent(
$packageTransaction,
"command"
));
}*/
return $this->packageTransactionRepository->findOneBy(['id' => $packageTransaction->getId()]);
}
/**
* @param PackageSongWriter $packageSongWriter
* @param string $status
*/
public function updateTheInvoiceStatus(PackageSongWriter $packageSongWriter, string $status)
{
/** @var Invoice $invoice */
foreach ($this->invoiceRepository->findBy(['packageSongWriter' => $packageSongWriter]) as $invoice){
$invoice->setStatus($status);
$this->invoiceRepository->flush($invoice);
}
}
/**
* @param PackageTransaction $packageTransaction
* @return ReactivationAttempts|null
*/
public function getReactivationAttempts(PackageTransaction $packageTransaction)
{
$result = null;
/** @var ReactivationAttempts $reactivationAttempt */
foreach ($this->reactiveAttemptsRepository->findBy(['packageTransaction' => $packageTransaction]) as $reactivationAttempt){
if(is_null($result)){
$result = $reactivationAttempt;
}else if($result->getNextAttemptDate()->getTimestamp() <= $reactivationAttempt->getNextAttemptDate()->getTimestamp()){
$result = $reactivationAttempt;
}
}
return $result;
}
/**
* @param string $data
* @param PaymentGateway $paymentGateway
* @param string $sigHeader
* @return void
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function processingWebHook(string $data, PaymentGateway $paymentGateway, string $sigHeader)
{
$result = $this->paymentMethodService->processToGetWebHook($paymentGateway, $data, $sigHeader);
$event = (new PaymentGatewayEvent())
->setPaymentGateway($paymentGateway)
->setInformation($data);
if($paymentGateway->getPaymentType()->getName() === TransactionPlatform::PAYPAL){
/** @var PaypalWebHookDTO $result */
$result = $result;
$event->setEvent($result->getEventType())
->setExternalId($result->getId());
$objectArray = $result->getResource();
switch ($result->getEventType()){
case PaypalWebHookList::PAYMENT_SALE_COMPLETED:
if(isset($objectArray['billing_agreement_id'])){
$packageTransaction = $this->getTransactionByExternalId($objectArray['billing_agreement_id']);
/** @var PaypalSubscriptionDTO $paypalSubscription */
$paypalSubscription = $this->paymentMethodService->processToGetSubscriptionTransactionInformation(
$packageTransaction
);
$beginDate = \DateTime::createFromFormat('Y-m-d\TH:i:s\Z', $paypalSubscription->getUpdateTIme());
$endDate = \DateTime::createFromFormat('Y-m-d\TH:i:s\Z', $paypalSubscription->getBillingInfo()->getNextBillingTime());
$packageSongwriter = $this->getRelationByPackageTransaction($packageTransaction);
if($packageSongwriter->getAvialableOn()->format("Y-m-d") !== $beginDate->format("Y-m-d")){
$packageTransaction = $this->updateTransactionDates(
$packageTransaction,
$packageSongwriter,
$beginDate,
$endDate
);
}
}
break;
case PaypalWebHookList::BILLING_SUBSCRIPTION_CANCELLED:
$packageTransaction = $this->getTransactionByExternalId($objectArray['id']);
$packageTransaction = $this->processToCancelASubscription(
"From Webhook",
$packageTransaction,
"webhook"
);
break;
case PaypalWebHookList::BILLING_SUBSCRIPTION_SUSPENDED:
case PaypalWebHookList::PAYMENT_SALE_DENIED:
case PaypalWebHookList::BILLING_SUBSCRIPTION_PAYMENT_FAILED:
$packageTransaction = $this->getTransactionByExternalId($objectArray['id']);
$packageTransaction = $this->processToInactiveASubscription(
"From Webhook",
$objectArray['status'],
$packageTransaction,
"webhook"
);
break;
case PaypalWebHookList::BILLING_SUBSCRIPTION_ACTIVATED:
/*$packageTransaction = $this->getTransactionByExternalId($objectArray['id']);
$paypalSubscription = $this->paymentMethodService->processToGetSubscriptionTransactionInformation(
$packageTransaction
);
$beginDate = \DateTime::createFromFormat('Y-m-d\TH:i:s\Z', $paypalSubscription->getStatusUpdateTime());
$endDate = \DateTime::createFromFormat('Y-m-d\TH:i:s\Z', $paypalSubscription->getBillingInfo()->getNextBillingTime());
$packageSongwriter = $this->getRelationByPackageTransaction($packageTransaction);
if($beginDate->getTimestamp() > $packageSongwriter->getAvialableOn()->getTimestamp()){
$packageTransaction = $this->processToReactiveASubscription(
"From Webhook",
$packageTransaction,
"webhook"
);
}
if($packageSongwriter->getAvialableOn()->getTimestamp() !== $beginDate->getTimestamp()){
$packageTransaction = $this->updateTransactionDates(
$packageTransaction,
$packageSongwriter,
$beginDate,
$endDate
);
}*/
break;
}
}else if($paymentGateway->getPaymentType()->getName() === TransactionPlatform::STRIPE){
/** @var \Stripe\Event $result */
$result = $result;
$arrayResult = json_decode($result->toJSON(), true);
$arrayResult = $arrayResult['data']['object'];
$f = fopen("uploads/webhook.txt", 'a+');
fwrite($f, json_encode($arrayResult)."\n");
fwrite($f, json_encode($result->type)."\n");
fclose($f);
$event->setEvent($result->type)
->setExternalId($result->id);
switch ($result->type){
case StripeWebHookList::INVOICE_PAID:
if(isset($arrayResult['subscription']) && !is_null($arrayResult['subscription'])){
$packageTransaction = $this->getTransactionByExternalId($arrayResult['subscription']);
/** @var Subscription $stripeSubscription */
$stripeSubscription = $this->paymentMethodService->processToGetSubscriptionTransactionInformation(
$packageTransaction
);
$beginDate = \DateTime::createFromFormat('U', $stripeSubscription->current_period_start);
$endDate = \DateTime::createFromFormat('U', $stripeSubscription->current_period_end);
$f = fopen("uploads/webhook.txt", 'a+');
fwrite($f, $beginDate->getTimestamp()."\n");
fwrite($f, $stripeSubscription->latest_invoice."\n");
fclose($f);
/** @var \Stripe\Invoice $stripeInvoice */
$stripeInvoice = $this->paymentMethodService->processtoGetInvoiceInformation(
$packageTransaction,
$stripeSubscription->latest_invoice
);
if($stripeInvoice->status === StripeApiInvoiceStatus::PAID && $arrayResult['id'] === $stripeInvoice->id){
$packageSongWriter = $this->getRelationByPackageTransaction($packageTransaction);
if($packageSongWriter->getAvialableOn()->format("Y-m-d") !== $beginDate->format("Y-m-d")){
$packageTransaction = $this->updateTransactionDates(
$packageTransaction,
$packageSongWriter,
$beginDate,
$endDate
);
}
}
}
break;
case StripeWebHookList::SUBSCRIPTION_DELETED:
$packageTransaction = $this->getTransactionByExternalId($arrayResult['id']);
$packageTransaction = $this->processToCancelASubscription(
"From Webhook",
$packageTransaction,
"webhook"
);
break;
case StripeWebHookList::SUBSCRIPTION_PAUSED:
case StripeWebHookList::INVOICE_PAYMENT_FAILED:
case StripeWebHookList::INVOICE_OVERDUE:
$packageTransaction = $this->getTransactionByExternalId($arrayResult['id']);
$packageTransaction = $this->processToInactiveASubscription(
"From Webhook",
$arrayResult['status']." ".$arrayResult['pause_collection'],
$packageTransaction,
"webhook"
);
break;
case StripeWebHookList::SUBSCRIPTION_RESUMED:
/*$packageTransaction = $this->getTransactionByExternalId($arrayResult['id']);
$packageTransaction = $this->processToReactiveASubscription(
"From Webhook",
$packageTransaction,
"webhook"
);
$stripeSubscription = $this->paymentMethodService->processToGetSubscriptionTransactionInformation(
$packageTransaction
);
$beginDate = \DateTime::createFromFormat('U', $stripeSubscription->current_period_start);
$endDate = \DateTime::createFromFormat('U', $stripeSubscription->current_period_end);
$packageSongwriter = $this->getRelationByPackageTransaction($packageTransaction);
if($packageSongwriter->getAvialableOn()->getTimestamp() !== $beginDate->getTimestamp()){
$packageTransaction = $this->updateTransactionDates(
$packageTransaction,
$packageSongwriter,
$beginDate,
$endDate
);
}*/
break;
}
}
$this->paymentGatewayEventRepository->save($event);
}
//------------------------------------------PRIVATE FUNCTIONS-------------------------------------------------------
/**
* @param $externalId
* @return PackageTransaction
*/
private function getTransactionByExternalId($externalId)
{
/** @var PackageTransaction $packageTransaction */
$packageTransaction = $this->packageTransactionRepository->findOneBy([
'paymentGatewayExternalId' => $externalId
]);
if(is_null($packageTransaction)){
throw new BadRequestHttpException("The transaction does not exist");
}
return $packageTransaction;
}
/**
* @param PackageTransaction $packageTransaction
* @return PackageSongWriter
*/
private function getRelationByPackageTransaction(PackageTransaction $packageTransaction)
{
/** @var PackageSongWriter $packageSongwriter */
$packageSongwriter = $this->packageSongwriterRepository->findOneBy([
'packageTransaction' => $packageTransaction
]);
if(is_null($packageSongwriter)){
throw new BadRequestHttpException("The relation does not exist");
}
return $packageSongwriter;
}
/**
* @param Profile $profile
* @return array|mixed
*/
private function getCredentialFOrPaymentGateway(Profile $profile)
{
$credentials = [];
if($profile->getProfileType()->getName() === Constants::PROFILE_TYPE_PUBLISHER_ADMINISTRATOR){
$credentials = $this->profileForPaymentMethodService->getParentPaymentGateways($profile);
}else if($profile->getProfileType()->getName() === Constants::PROFILE_TYPE_PUBLISHER
|| $profile->getProfileType()->getName() === Constants::PROFILE_TYPE_SONGWRITER){
$publisherAdministrator = $this->profileForPaymentMethodService->findPublisherAdministratorForProfile($profile);
$credentials = $this->profileForPaymentMethodService->getParentPaymentGateways($publisherAdministrator);
}
return $credentials;
}
/**
* @param Package $package
* @param PackageSongWriter $oldPackageSongWriter
* @return string
*/
public function calculatePriceToUpgrade(
Package $package,
PackageSongWriter $oldPackageSongWriter
)
{
$currentDate= (new \DateTime());
$amountNewPackage = (float)$package->getPrice() - ((float)$package->getPrice() * (float)$package->getDiscount());
$amountOldPackage = 0.00;
$oldPackage = (is_null($oldPackageSongWriter->getPackage()->getParent())) ?
$oldPackageSongWriter->getPackage():
$oldPackageSongWriter->getPackage()->getParent();
$amountOldPackage = (float)$oldPackage->getPrice() - ((float)$oldPackage->getPrice() * (float)$oldPackage->getDiscount());
if($oldPackageSongWriter->getPackageTransaction()->getProcessedAt()->format("Y-m-d") !== $currentDate->format("Y-m-d")){
$amountOldPackageDivided = ($oldPackage->isAnnual()) ? ($amountOldPackage / 365) : ($amountOldPackage / 30);
$interval = $oldPackageSongWriter->getAvialableOn()->diff($currentDate);
$days = ($interval->d <= 0) ? 1 : $interval->d;
$amountOldPackage = $amountOldPackageDivided * $days;
}
$customPriceToUpgrade = $amountNewPackage - $amountOldPackage;
return number_format($customPriceToUpgrade, 2, ".", "");
}
/**
* @param float $customPriceToUpgrade
* @param Package $package
* @param Package $oldPackage
* @return mixed
*/
private function buildAPackageArray(float $customPriceToUpgrade, Package $package, Package $oldPackage)
{
$jsonData = '{
"name": "'.$package->getName().' from '.$oldPackage->getName().'",
"description": "Upgrade to '.$package->getName().' from '.$oldPackage->getName().'",
"duration": '.$package->getDuration().',
"is_monthly": '.(($package->isMonthly()) ? "true" : "false").',
"composition_limit": '.$package->getCompositionLimit().',
"subprofile_limit": '.$package->getSubprofileLimit().',
"is_semester": '.(($package->isSemester()) ? "true" : "false").',
"is_annual": '.(($package->isAnnual()) ? "true" : "false").',
"admin_percentage": '.$package->getAdminPercentage().',
"price": '.$customPriceToUpgrade.',
"quantity_sold": 0,
"impressions_count": 0,
"type": "'.$package->getType().'",
"discount": '.$package->getDiscount().',
"allow_extras": '.(($package->isAllowExtras()) ? "true" : "false").',
"visible_to_admin_only": true,
"has_standard": false,
"has_plus": false,
"package_standard": null,
"package_plus": null,
"visible": false,
"profile_type": {
"id": '.$package->getProfileType()->getId().',
"name": "'.$package->getProfileType()->getName().'"
}
}';
return json_decode($jsonData, true);
}
/**
* @param Package $oldPackage
* @param Package $newPackage
* @return void
*/
private function processToCheckOldPackageNewPackage(Package $oldPackage, Package $newPackage)
{
$error = true;
if($oldPackage->isAnnual()){
if($newPackage->isAnnual()){
$error = false;
}
}else if($oldPackage->isMonthly()){
if($newPackage->isMonthly()){
$error = false;
}
}
if($error){
throw new BadRequestHttpException(
"Upgrade from monthly->yearly and yearly->monthly is not possible without cancellations of ongoing subscription."
);
}
}
/**
* @param PackageTransaction $packageTransaction
* @param PackageSongWriter $packageSongWriter
* @param \DateTime $beginDate
* @param \DateTime $endDate
* @return PackageTransaction
*/
private function updateTransactionDates(
PackageTransaction $packageTransaction,
PackageSongWriter $packageSongWriter,
\DateTime $beginDate,
\DateTime $endDate
)
{
$packageSongWriter->setAvialableOn($beginDate);
$packageSongWriter->setAvialableOff($endDate);
$packageSongWriter->setStatus(PackageSongwriterStatus::ACTIVE);
$this->packageSongwriterRepository->flush($packageSongWriter);
$this->updateTheInvoiceStatus($packageSongWriter, PackageSongwriterStatus::INACTIVE);
$invoice = (new Invoice())
->setPackageSongWriter($packageSongWriter)
->setNumber($packageTransaction->getId().$packageSongWriter->getId()."-".$this->invoiceCounter($packageSongWriter))
->setBillingDate($beginDate)
->setSubTotal($packageTransaction->getPackage()->getPrice())
->setDiscount($packageTransaction->getPackage()->getDiscount() * $packageTransaction->getPackage()->getPrice())
->setTaxes(0)
->setStatus(PackageSongwriterStatus::ACTIVE)
->setAvialableOn($packageSongWriter->getAvialableOn())
->setAvialableOff($packageSongWriter->getAvialableOff());
$invoiceItems = [
$this->serializer->serialize($packageTransaction->getPackage(), "json", ['groups' => 'invoice:json'])
];
$invoice->setItems(json_encode($invoiceItems));
$totalAmount = (float)$packageTransaction->getPackage()->getPrice() - ((float)$packageTransaction->getPackage()->getDiscount() * (float)$packageTransaction->getPackage()->getPrice());
$invoice->setTotal($totalAmount);
$invoice = $this->invoiceRepository->save($invoice);
$this->eventDispatcher->dispatch(new PackageTransactionApprovedEvent(
$packageTransaction,
"command"
));
return $this->packageTransactionRepository->findOneBy(['id' => $packageTransaction->getId()]);
}
/**
* @param PackageSongWriter $packageSongWriter
* @param ManualInvoice $manualInvoice
* @return Invoice|null
*/
private function activeTheLastInvoice(PackageSongWriter $packageSongWriter, ManualInvoice $manualInvoice)
{
$currentDate = new \DateTime();
$invoiceCounter = 0;
$lastInvoice = null;
/** @var Invoice $invoice */
foreach ($this->invoiceRepository->findBy(['packageSongWriter' => $packageSongWriter]) as $invoice){
if($invoiceCounter == 0){
$lastInvoice = $invoice;
}else{
if($invoice->getAvialableOn()->getTimestamp() > $lastInvoice->getAvialableOn()->getTimestamp()){
$lastInvoice = $invoice;
}
}
}
$lastInvoice->setStatus(PackageSongwriterStatus::ACTIVE);
$lastInvoice->setAvialableOn($manualInvoice->getDateBegin());
$lastInvoice->setAvialableOff($manualInvoice->getDateEnd());
if($lastInvoice->getAvialableOn()->getTimestamp() > $currentDate->getTimestamp()){
$lastInvoice->setStatus(PackageSongwriterStatus::PENDING);
}
$this->invoiceRepository->flush($lastInvoice);
return $lastInvoice;
}
}