<?php
namespace App\Service\Royalties;
use App\DTO\MMPZ\Royalty\ConsolidationDTO;
use App\DTO\MMPZ\Royalty\EarningByCountryDTO;
use App\DTO\MMPZ\Royalty\EarningByCountryResponseDTO;
use App\DTO\MMPZ\Royalty\EarningByCompositionDTO;
use App\DTO\MMPZ\Royalty\EarningByCompositionResponseDTO;
use App\DTO\MMPZ\Royalty\EarningByMonthDTO;
use App\DTO\MMPZ\Royalty\EarningByMonthResponseDTO;
use App\DTO\MMPZ\Royalty\EarningByPlatformDTO;
use App\DTO\MMPZ\Royalty\EarningByPlatformResponseDTO;
use App\DTO\MMPZ\Royalty\EarningDTO;
use App\DTO\MMPZ\Royalty\PublisherAdministratorEarningDTO;
use App\DTO\MMPZ\Royalty\ServiceEarningDTO;
use App\DTO\MMPZ\Song\DownloadSongParametersDTO;
use App\Entity\App\Country;
use App\Entity\App\Currency;
use App\Entity\App\File;
use App\Entity\ClickHouse\IncomeRawDataCH;
use App\Entity\ClickHouse\RawDataCH;
use App\Entity\ClickHouse\RawDataIncompleteCH;
use App\Entity\Composition\Composition;
use App\Entity\Composition\SongWriter;
use App\Entity\Profile\Profile;
use App\Entity\Profile\ProfileInformation;
use App\Entity\Profile\Splits\RoyaltyDue;
use App\Entity\Profile\Splits\RoyaltyDueAdjust;
use App\Entity\Profile\Splits\RoyaltyImporterFile;
use App\Entity\Profile\Splits\RoyaltySplits;
use App\Entity\Publishing\Platform;
use App\Entity\Song\Song;
use App\Entity\User\User;
use App\Enums\Constants;
use App\Enums\Platforms;
use App\Enums\RoyaltyDueType;
use App\Enums\RoyaltyImporterFileStatus;
use App\Enums\RoyaltyImporterFileType;
use App\Enums\RoyaltyRawDataStatus;
use App\Factory\EntityFactory;
use App\Repository\App\CountryRepository;
use App\Repository\Composition\CompositionRepository;
use App\Repository\Composition\SongWriterRepository;
use App\Repository\Profile\Splits\RoyaltyConsolidationRepository;
use App\Repository\Profile\Splits\RoyaltyDueAdjustRepository;
use App\Repository\Profile\Splits\RoyaltyDueRepository;
use App\Repository\Profile\Splits\RoyaltyImporterFileRepository;
use App\Repository\Publishing\PlatformRepository;
use App\Service\ClickHouse\DataManager\IncomeRawDataCHManagerService;
use App\Service\ClickHouse\DataManager\RawDataDailyCHManagerService;
use App\Service\ClickHouse\DataManager\RawDataIncompleteCHManagerService;
use App\Service\Feeds\MLC\MLCFeedService;
use App\Service\FileService;
use App\Service\GeneralService;
use App\Service\ProfileService;
use App\Service\RedisCaching\RedisDataManagerService;
use App\Service\SongService;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Ramsey\Uuid\Uuid;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
use Symfony\Component\Serializer\SerializerInterface;
class RoyaltyImporterFileService
{
/** @var array */
private $dataConsolidated = [];
/** @var array */
private $rawDataProcessed = [];
/** @var array */
private $incomeDataConsolidated = [];
/** @var EntityManagerInterface */
private $entityManager;
/** @var SerializerInterface */
private $serializer;
/** @var EntityFactory */
private $entityFactory;
/** @var RoyaltyImporterFileRepository */
private $royaltyImporterFileRepository;
/** @var RoyaltyDueRepository */
private $royaltyDueRepository;
/** @var RoyaltyConsolidationRepository */
private $royaltyConsolidationRepository;
/** @var RoyaltyDueAdjustRepository */
private $royaltyDueAdjustRepository;
/** @var PlatformRepository */
private $platformRepository;
/** @var CountryRepository */
private $countryRepository;
/** @var SongWriterRepository */
private $songWriterRepository;
/** @var CompositionRepository */
private $compositionRepository;
/** @var GeneralService */
private $generalService;
/** @var FileService */
private $fileService;
/** @var RedisDataManagerService */
private $redisDataManagerService;
/** @var RawDataDailyCHManagerService */
private $rawDataDailyCHManagerService;
/** @var RawDataIncompleteCHManagerService */
private $rawDataIncompleteCHManagerService;
/** @var IncomeRawDataCHManagerService */
private $incomeRawDataCHManagerService;
/** @var RoyaltyImporterFileMCPSService */
private $royaltyImporterFileMCPSService;
/** @var RoyaltyImporterFileMLCService */
private $royaltyImporterFileMLCService;
/** @var RoyaltyImporterFilePRSService */
private $royaltyImporterFilePRSService;
/** @var SongService */
private $songService;
/** @var LoggerInterface */
private $logger;
public function __construct(
SerializerInterface $serializer,
EntityManagerInterface $entityManager,
EntityFactory $entityFactory,
RoyaltyImporterFileRepository $royaltyImporterFileRepository,
RoyaltyDueRepository $royaltyDueRepository,
RoyaltyDueAdjustRepository $royaltyDueAdjustRepository,
RoyaltyConsolidationRepository $royaltyConsolidationRepository,
PlatformRepository $platformRepository,
CountryRepository $countryRepository,
SongWriterRepository $songWriterRepository,
CompositionRepository $compositionRepository,
FileService $fileService,
GeneralService $generalService,
SongService $songService,
LoggerInterface $logger,
RedisDataManagerService $redisDataManagerService,
RawDataDailyCHManagerService $rawDataDailyCHManagerService,
RawDataIncompleteCHManagerService $rawDataIncompleteCHManagerService,
IncomeRawDataCHManagerService $incomeRawDataCHManagerService,
RoyaltyImporterFileMCPSService $royaltyImporterFileMCPSService,
RoyaltyImporterFileMLCService $royaltyImporterFileMLCService,
RoyaltyImporterFilePRSService $royaltyImporterFilePRSService
)
{
$this->serializer = $serializer;
$this->entityManager = $entityManager;
$this->entityFactory = $entityFactory;
$this->royaltyImporterFileRepository = $royaltyImporterFileRepository;
$this->royaltyDueRepository = $royaltyDueRepository;
$this->royaltyDueAdjustRepository = $royaltyDueAdjustRepository;
$this->royaltyConsolidationRepository = $royaltyConsolidationRepository;
$this->platformRepository = $platformRepository;
$this->countryRepository = $countryRepository;
$this->songWriterRepository = $songWriterRepository;
$this->compositionRepository = $compositionRepository;
$this->fileService = $fileService;
$this->generalService = $generalService;
$this->songService = $songService;
$this->logger = $logger;
$this->redisDataManagerService = $redisDataManagerService;
$this->rawDataDailyCHManagerService = $rawDataDailyCHManagerService;
$this->rawDataIncompleteCHManagerService = $rawDataIncompleteCHManagerService;
$this->incomeRawDataCHManagerService = $incomeRawDataCHManagerService;
$this->royaltyImporterFileMCPSService = $royaltyImporterFileMCPSService;
$this->royaltyImporterFileMLCService = $royaltyImporterFileMLCService;
$this->royaltyImporterFilePRSService = $royaltyImporterFilePRSService;
}
/**
* @param array $data
* @param User $user
* @param Profile $profile
* @return RoyaltyImporterFile
*/
public function processToCreateRoyaltyImporterFile(
array $data,
User $user,
Profile $profile
): RoyaltyImporterFile
{
/** @var Platform $platform */
$platform = $this->platformRepository->findOneBy(["id" => $data['platform']['id']]);
/** @var RoyaltyImporterFile $royaltyImporterFile */
$royaltyImporterFile = $this->entityFactory->createFromJson(
json_encode($data),
RoyaltyImporterFile::class,
["royalty-importer-file:create"]
);
$royaltyImporterFile->setProfile($profile);
$royaltyImporterFile->setCreatedBy($user);
$royaltyImporterFile->setPlatform($platform);
switch ($platform->getName()){
case Platforms::MCPS:
case Platforms::MLC:
$royaltyImporterFile->setType(RoyaltyImporterFileType::M);
break;
case Platforms::PRS:
$royaltyImporterFile->setType(RoyaltyImporterFileType::P);
break;
}
/** @var RoyaltyImporterFile $royaltyImporterFile */
$royaltyImporterFile = $this->royaltyImporterFileRepository->save($royaltyImporterFile);
return $royaltyImporterFile;
}
/**
* @param UploadedFile $uploadedFile
* @param RoyaltyImporterFile $royaltyImporterFile
* @return RoyaltyImporterFile
* @throws \League\Flysystem\FilesystemException
*/
public function processToUploadTheFile(
RoyaltyImporterFile $royaltyImporterFile,
UploadedFile $uploadedFile = null,
array $dataToReProcess = null
)
{
$data = [];
if(!is_null($uploadedFile)){
/** @var File $file */
$file = $this->fileService->upload(
$uploadedFile,
$royaltyImporterFile->getId(),
RoyaltyImporterFile::class
);
/** @var RoyaltyImporterFile $royaltyImporterFileOlds */
foreach ($royaltyImporterFile->getProfile()->getRoyaltyImporterFiles() as $royaltyImporterFileOlds) {
if (!is_null($royaltyImporterFileOlds->getFile())) {
if ($royaltyImporterFileOlds->getFile()->getOriginalName() === $file->getOriginalName()) {
$royaltyImporterFile->setStatus(RoyaltyImporterFileStatus::ERROR);
$this->royaltyImporterFileRepository->flush($royaltyImporterFile);
$this->processToDeleteRoyaltyImporterFile($royaltyImporterFile);
throw new BadRequestHttpException("File already exists");
}
}
}
if ($file->getExtension() === "csv" || $file->getExtension() === "CSV") {
$data = $this->processCsvFile($file);
} else {
$data = $this->processTsvFile($file);
}
$royaltyImporterFile->setFile($file);
}
if(!is_null($dataToReProcess)){
$data = $dataToReProcess;
}
$dataToCH = [];
$dataProcessed = [];
try {
switch ($royaltyImporterFile->getPlatform()->getName()) {
case Platforms::MCPS:
$this->royaltyImporterFileMCPSService->setDataFromFile($data);
$dataProcessed = $this->royaltyImporterFileMCPSService->processData($royaltyImporterFile);
break;
case Platforms::MLC:
$this->royaltyImporterFileMLCService->setDataFromFile($data);
$dataProcessed = $this->royaltyImporterFileMLCService->processData($royaltyImporterFile);
break;
case Platforms::PRS:
$this->royaltyImporterFilePRSService->setDataFromFile($data);
$dataProcessed = $this->royaltyImporterFilePRSService->processData($royaltyImporterFile);
break;
}
}catch (\Exception $exception){
$royaltyImporterFile->setStatus(RoyaltyImporterFileStatus::ERROR);
$this->royaltyImporterFileRepository->flush($royaltyImporterFile);
throw new BadRequestHttpException("Please check the file");
$this->logger->info($e->getMessage() . " on line ". $e->getLine(). " in " . $e->getCode());
}
if(!is_null($dataToReProcess)){
if(count($dataToReProcess) <= count($dataProcessed['error'])){
throw new BadRequestHttpException("The errors were not fixed");
}
}
$quantitySumImported = 0;
$incomeSumImported = 0;
/** @var RawDataCH $rawDataDailyCH */
foreach ($dataProcessed['success'] as $rawDataDailyCH) {
$quantitySumImported += (int)$rawDataDailyCH->getPerfNumber();
$incomeSumImported += (float)$rawDataDailyCH->getIncome();
$rawDataDailyCH = json_decode(
$this->serializer->serialize($rawDataDailyCH, "json", ['groups' => 'clickhouse:raw-data']),
true
);
try {
$this->rawDataDailyCHManagerService->insertData(
RawDataCH::TABLE_NAME,
$rawDataDailyCH
);
}catch (\Exception $exception){
}
}
$quantitySumError = 0;
$incomeSumError = 0.00;
/** @var RawDataIncompleteCH $rawDataIncompleteCH */
foreach ($dataProcessed['error'] as $rawDataIncompleteCH) {
$quantitySumError += (int)$rawDataIncompleteCH->getPerfNumber();
$incomeSumError += (float)$rawDataIncompleteCH->getIncome();
$rawDataIncompleteCH = json_decode(
$this->serializer->serialize($rawDataIncompleteCH, "json", ['groups' => 'clickhouse:raw-data']),
true
);
try {
$this->rawDataIncompleteCHManagerService->insertData(
RawDataIncompleteCH::TABLE_NAME,
$rawDataIncompleteCH
);
}catch (\Exception $exception){
}
}
if(!is_null($uploadedFile)){
$royaltyImporterFile->setTotalRows(count($data))
->setImportedRows(count($dataProcessed['success']))
->setErrorRows(count($dataProcessed['error']))
->setQuantitySumImported($quantitySumImported)
->setIncomeSumImported($incomeSumImported)
->setQuantitySumError($quantitySumError)
->setIncomeSumError($incomeSumError)
->setQuantitySum($quantitySumError + $quantitySumImported)
->setIncomeSum($incomeSumError + $incomeSumImported);
if(count($dataProcessed['rowWithErrors']) > 0 && $dataProcessed['error'] > 0){
$royaltyImporterFile->setErrorFile($this->processToCreateAnErrorFile(
$dataProcessed['rowWithErrors'],
$dataProcessed['error'],
$royaltyImporterFile
));
}
}
if(!is_null($dataToReProcess)){
$errorRows = $royaltyImporterFile->getErrorRows() - count($dataProcessed['success']);
$quantitySumError = $royaltyImporterFile->getQuantitySumError() - $quantitySumImported;
$incomeSumError = $royaltyImporterFile->getIncomeSumError() - $incomeSumImported;
$royaltyImporterFile->setImportedRows($royaltyImporterFile->getImportedRows() + count($dataProcessed['success']))
->setErrorRows($errorRows)
->setQuantitySumImported($royaltyImporterFile->getQuantitySumImported() + $quantitySumImported)
->setIncomeSumImported($royaltyImporterFile->getIncomeSumImported() + $incomeSumImported)
->setQuantitySumError($quantitySumError)
->setIncomeSumError($incomeSumError);
if(count($dataProcessed['rowWithErrors']) > 0 && $dataProcessed['error'] > 0){
$royaltyImporterFile->setErrorFile($this->processToCreateAnErrorFile(
$dataProcessed['rowWithErrors'],
$dataProcessed['error'],
$royaltyImporterFile
));
}
}
if($royaltyImporterFile->getTotalRows() === $royaltyImporterFile->getErrorRows()){
$royaltyImporterFile->setStatus(RoyaltyImporterFileStatus::ERROR);
}else{
if(is_null($dataToReProcess)){
$royaltyImporterFile->setStatus(RoyaltyImporterFileStatus::IMPORTED);
}
}
$this->royaltyImporterFileRepository->flush($royaltyImporterFile);
/** @var RoyaltyImporterFile $royaltyImporterFile */
$royaltyImporterFile = $this->royaltyImporterFileRepository->find($royaltyImporterFile->getId());
return $royaltyImporterFile;
}
/**
* @param RoyaltyImporterFile $royaltyImporterFile
* @param array $data
* @return RoyaltyImporterFile
*/
public function processToEditRoyaltyImporterFile(
RoyaltyImporterFile $royaltyImporterFile,
array $data
): RoyaltyImporterFile
{
/** @var RoyaltyImporterFile $royaltyImporterFile */
$royaltyImporterFile = $this->entityFactory->createFromJson(
json_encode($data),
RoyaltyImporterFile::class,
["royalty-importer-file:edit"],
[AbstractObjectNormalizer::OBJECT_TO_POPULATE => $royaltyImporterFile,]
);
if(!isset($data['tax_country'])){
throw new BadRequestHttpException("Tax Country is required");
}
$country = $this->countryRepository->find($data['tax_country']['id']);
$royaltyImporterFile->setTaxPercentage($royaltyImporterFile->getTaxPercentage()/100);
$royaltyImporterFile->setTaxCountry($country);
$royaltyImporterFile->setIncomeConversionRate($royaltyImporterFile->getGbp() / $royaltyImporterFile->getIncomeSumImported());
$royaltyImporterFile->setStatus(RoyaltyImporterFileStatus::DISTRIBUTED);
$this->royaltyImporterFileRepository->flush($royaltyImporterFile);
/** @var RoyaltyImporterFile $royaltyImporterFile */
$royaltyImporterFile = $this->royaltyImporterFileRepository->find($royaltyImporterFile->getId());
return $royaltyImporterFile;
}
/**
* @param RoyaltyImporterFile $royaltyImporterFile
* @param bool $reImportation
* @return void
*/
public function processToDeleteRoyaltyImporterFile(
RoyaltyImporterFile $royaltyImporterFile,
bool $reImportation = false
): void
{
$this->rawDataDailyCHManagerService->deleteData(
RawDataCH::TABLE_NAME,
['report_id' => $royaltyImporterFile->getId()]
);
$this->rawDataIncompleteCHManagerService->deleteData(
RawDataIncompleteCH::TABLE_NAME,
['report_id' => $royaltyImporterFile->getId()]
);
$this->incomeRawDataCHManagerService->deleteData(
IncomeRawDataCH::TABLE_NAME,
['report_id' => $royaltyImporterFile->getId()]
);
/** @var RoyaltyDue $rawDataDue */
foreach ($this->royaltyDueRepository->findBy(['royaltyImporterFile' => $royaltyImporterFile]) as $rawDataDue) {
$this->royaltyDueRepository->remove($rawDataDue);
$this->royaltyDueRepository->flush();
}
$file = $royaltyImporterFile->getFile();
$errorFile = $royaltyImporterFile->getErrorFile();
if(!$reImportation){
$this->royaltyImporterFileRepository->remove($royaltyImporterFile);
$this->royaltyImporterFileRepository->flush();
}else{
$royaltyImporterFile->setFile(null);
$royaltyImporterFile->setErrorFile(null);
$this->royaltyImporterFileRepository->flush();
}
/*if($file){
$this->fileService->delete($file);
}
if($errorFile){
$this->fileService->delete($errorFile);
}*/
}
/**
* @param RoyaltyImporterFile $royaltyImporterFile
* @return void
*/
public function processToCalculateRoyalties(RoyaltyImporterFile $royaltyImporterFile)
{
$royaltySE = null;
$royaltyPA = null;
$royaltySW = null;
$royaltyPU = null;
$data = $this->rawDataDailyCHManagerService->getDataFromTable(
RawDataDailyCHManagerService::NAME,
['*'],
[
'report_id' => $royaltyImporterFile->getId(),
'status' => RoyaltyRawDataStatus::READING,
]
);
$taxPercentege = (is_null($royaltyImporterFile->getTaxPercentage())) ? 0 : $royaltyImporterFile->getTaxPercentage();
$taxAmount = (is_null($royaltyImporterFile->getTaxAmount())) ? 0 : $royaltyImporterFile->getTaxAmount();
foreach($data as $raw => $value){
$income = (float)$value['income'] * $royaltyImporterFile->getIncomeConversionRate();
$incomeGBP = $income;
$incomePA = 0;
$incomePU = 0;
$incomeSW = 0;
$incomeSe = 0;
$songwritersArray = json_decode($value['songwriters'], true);
$incomeExternal = 0.00;
foreach ($songwritersArray['external'] as $songwriterId){
$songwriterRedis = $this->redisDataManagerService->getSongWriterById($songwriterId);
/** income here is updated with the percentage to songwriter, this is calculated with the songwriter composition share */
$incomeExternal += $income * ((float)$songwriterRedis['share'] / 100);
}
foreach ($songwritersArray['internal'] as $songwriterId){
$songwriterRedis = $this->redisDataManagerService->getSongWriterById($songwriterId);
/** @var Profile $profile */
$profile = $this->generalService->findProfileById($songwriterRedis['profile_id']);
/** @var Profile $profilePAMysql */
$profilePAMysql = $this->generalService->findProfileById($profile->getPublisherAdministratorData()['id']);
$royaltyPA = $profilePAMysql->getRoyaltySplits();
/** income here is updated with the percentage to songwriter, this is calculated with the songwriter composition share */
if(count($songwritersArray['internal']) > 0){
$income = ($income * ((float)$songwriterRedis['share'] / 100)) + ($incomeExternal / count($songwritersArray['internal']));
}else{
$income = $income * ((float)$songwriterRedis['share'] / 100);
}
$incomeShare = $income;
/** incomeSe is the value that this publisher administrator share with the Service */
$incomeService = $income * ($this->getRoyaltyPercentage($royaltyImporterFile, $royaltyPA, true) / 100);
$income -= $incomeService;
$id = $value['id'] + $raw + 1;
$incomeRawData = (new IncomeRawDataCH())
->setId($id)
->setRawDataId($value['id'])
->setReportId($value['report_id'])
->setOldId($value['old_id'])
->setCompositionId($value['composition_id'])
->setSongWriterId($songwriterRedis['id'])
->setProfileId($profile->getId())
->setIncomeTotalGbp($incomeGBP)
->setShare((float)$songwriterRedis['share'] / 100)
->setIncomeTotalGbpShare($incomeShare)
->setTaxPercentage($taxPercentege)
->setTaxAmount($incomeShare * $taxPercentege)
->setIncomeTotalGbpShareNet($incomeShare - ($incomeShare * $taxPercentege))
->setIncomeSE($incomeService)
->setIncomeSeNet($incomeService - ($incomeService * $taxPercentege))
->setConsolidated(0);
$royaltySW = $profile->getRoyaltySplits();
if(is_null($royaltySW)){
throw new BadRequestHttpException("Royalty SPLIT is not set for the profile {$profile->getProfileInformation()->getName()}");
}
if($profile->getParent()->getProfileType()->getName() === Constants::PROFILE_TYPE_PUBLISHER){
$royaltyPU = $profile->getParent()->getRoyaltySplits();
/** incomePA is the value that this publisher share with the Publisher Administrator */
$incomePA = $income * ($this->getRoyaltyPercentage($royaltyImporterFile, $royaltyPU, true) / 100);
$income -= $incomePA;
/** incomeSW is the songwriter income */
$incomeSW = $income * ($this->getRoyaltyPercentage($royaltyImporterFile, $royaltySW) / 100);
$income -= $incomeSW;
/** incomePU is the value that this songwriter share with the Publisher */
$incomePU = $income;
}else{
/** incomePA is the value that this songwriter share with the Publisher Administrator */
$incomePA = $income * ($this->getRoyaltyPercentage($royaltyImporterFile, $royaltySW, true) / 100);
$income -= $incomePA;
/** incomeSW is the songwriter income */
$incomeSW = $income;
}
$incomeRawData->setIncomePA($incomePA)
->setIncomePaNet($incomePA - ($incomePA * $taxPercentege))
->setIncomeSW($incomeSW)
->setIncomeSWNet($incomeSW - ($incomeSW * $taxPercentege))
->setIncomePU($incomePU)
->setIncomePUNet($incomePU - ($incomePU * $taxPercentege));
$incomeRawData = $this->serializer->serialize(
$incomeRawData,
"json",
['groups' => 'clickhouse:income-raw-data']
);
$incomeRawData = json_decode($incomeRawData, true);
$this->incomeRawDataCHManagerService->insertData(
IncomeRawDataCH::TABLE_NAME,
$incomeRawData
);
$royaltyPU = null;
$royaltySW = null;
/** The income return to the initial value to do the calculation to the next songwriter */
$income = $incomeGBP;
}
}
$this->flushRawDateProcessed($royaltyImporterFile);
}
/**
* @param RoyaltyImporterFile $royaltyImporterFile
* @return void
*/
public function processToCalculateRoyaltiesForPRS(RoyaltyImporterFile $royaltyImporterFile)
{
$royaltySE = null;
$royaltyPA = null;
$royaltySW = null;
$royaltyPU = null;
$data = $this->rawDataDailyCHManagerService->getDataFromTable(
RawDataDailyCHManagerService::NAME,
['*'],
[
'report_id' => $royaltyImporterFile->getId(),
'status' => RoyaltyRawDataStatus::READING,
]
);
$taxPercentege = (is_null($royaltyImporterFile->getTaxPercentage())) ? 0 : $royaltyImporterFile->getTaxPercentage();
$taxAmount = (is_null($royaltyImporterFile->getTaxAmount())) ? 0 : $royaltyImporterFile->getTaxAmount();
foreach($data as $raw => $value){
$income = (float)$value['income'] * $royaltyImporterFile->getIncomeConversionRate();
$incomeGBP = $income;
$incomePA = 0;
$incomePU = 0;
$incomeSW = 0;
$incomeSe = 0;
$incomeRawDataArray = [];
$songwritersArray = json_decode($value['songwriters'], true);
$incomeExternal = 0.00;
foreach ($songwritersArray['external'] as $songwriterId){
$songwriterRedis = $this->redisDataManagerService->getSongWriterById($songwriterId);
/** income here is updated with the percentage to songwriter, this is calculated with the songwriter composition share */
$incomeExternal += $income * ((float)$songwriterRedis['share'] / 100);
}
foreach ($songwritersArray['internal'] as $songwriterId){
$songwriterRedis = $this->redisDataManagerService->getSongWriterById($songwriterId);
if(!is_null($songwriterRedis['profile_id']) && !empty($songwriterRedis['profile_id'])){
/** @var Profile $profile */
$profile = $this->generalService->findProfileById($songwriterRedis['profile_id']);
/** @var Profile $profilePAMysql */
$profilePAMysql = $this->generalService->findProfileById($profile->getPublisherAdministratorData()['id']);
$royaltyPA = $profilePAMysql->getRoyaltySplits();
/** income here is updated with the percentage to songwriter, this is calculated with the songwriter composition share */
$income = (($income) * ((float)$songwriterRedis['share'] / 100)) + ($incomeExternal / count($songwritersArray['internal']));
$incomeShare = $income;
/** incomeSe is the value that this publisher administrator share with the Service */
$incomeService = $income * ($this->getRoyaltyPercentage($royaltyImporterFile, $royaltyPA, true) / 100);
$income -= $incomeService;
$id = $value['id'] + $raw + 1;
$incomeRawData = (new IncomeRawDataCH())
->setId($id)
->setRawDataId($value['id'])
->setReportId($value['report_id'])
->setOldId($value['old_id'])
->setCompositionId($value['composition_id'])
->setSongWriterId($songwriterRedis['id'])
->setProfileId($profile->getId())
->setIncomeTotalGbp($incomeGBP)
->setShare((float)$songwriterRedis['share'] / 100)
->setIncomeTotalGbpShare($incomeShare)
->setTaxPercentage($taxPercentege)
->setTaxAmount($incomeShare * $taxPercentege)
->setIncomeTotalGbpShareNet($incomeShare - ($incomeShare * $taxPercentege))
->setIncomeSE($incomeService)
->setIncomeSeNet($incomeService - ($incomeService * $taxPercentege))
->setConsolidated(0);
$royaltySW = $profile->getRoyaltySplits();
if(is_null($royaltySW)){
throw new BadRequestHttpException("Royalty SPLIT is not set for the profile {$profile->getProfileInformation()->getName()}");
}
if($profile->getParent()->getProfileType()->getName() === Constants::PROFILE_TYPE_PUBLISHER){
$royaltyPU = $profile->getParent()->getRoyaltySplits();
if((float)$value['publisher_administrator_share'] === 100.00){
/** incomePA is the value that this publisher share with the Publisher Administrator */
$incomePA = $income * ($this->getRoyaltyPercentage($royaltyImporterFile, $royaltyPU, true) / 100);
$income -= $incomePA;
/** incomeSW is the songwriter income */
$incomeSW = $income * ($this->getRoyaltyPercentage($royaltyImporterFile, $royaltySW) / 100);
$income -= $incomeSW;
/** incomePU is the value that this songwriter share with the Publisher */
$incomePU = $income;
}else{
/** incomePA is the value that this publisher share with the Publisher Administrator */
$incomePA = $income;
}
}else{
if((float)$value['publisher_administrator_share'] === 100.00){
/** incomePA is the value that this songwriter share with the Publisher Administrator */
$incomePA = $income * ($this->getRoyaltyPercentage($royaltyImporterFile, $royaltySW, true) / 100);
$income -= $incomePA;
/** incomeSW is the songwriter income */
$incomeSW = $income;
}else{
/** incomePA is the value that this songwriter share with the Publisher Administrator */
$incomePA = $income;
}
}
$incomeRawData->setIncomePA($incomePA)
->setIncomePaNet($incomePA - ($incomePA * $taxPercentege))
->setIncomeSW($incomeSW)
->setIncomeSWNet($incomeSW - ($incomeSW * $taxPercentege))
->setIncomePU($incomePU)
->setIncomePUNet($incomePU - ($incomePU * $taxPercentege));
$incomeRawData = $this->serializer->serialize(
$incomeRawData,
"json",
['groups' => 'clickhouse:income-raw-data']
);
$incomeRawData = json_decode($incomeRawData, true);
$incomeRawDataArray[] = $incomeRawData;
$this->incomeRawDataCHManagerService->insertData(
IncomeRawDataCH::TABLE_NAME,
$incomeRawData
);
}
$royaltyPU = null;
$royaltySW = null;
/** The income return to the initial value to do the calculation to the next songwriter */
$income = $incomeGBP;
}
}
$this->flushRawDateProcessed($royaltyImporterFile);
}
/**
* @param RoyaltyImporterFile $royaltyImporterFile
* @param bool $reImport
* @return void
*/
public function processToConsolidateOutstandingRoyalties(
RoyaltyImporterFile $royaltyImporterFile,
bool $reImport = false
): void
{
$data = $this->incomeRawDataCHManagerService->getDataFromTable(
IncomeRawDataCHManagerService::NAME,
['*'],
[
'report_id' => $royaltyImporterFile->getId(),
'consolidated' => 0
]
);
foreach($data as $raw => $value){
//echo $raw."\n";
$grossIncome = (float)$value['income_total_gbp'];
$income = (float)$value['income_total_gbp_share'];
$incomeNet = (float)$value['income_total_gbp_share_net'];
$profile = $this->generalService->findProfileById((int)$value['profile_id']);
$royaltyDue = $this->processToCreateOrUpdateRoyaltyConsolidation(
$profile,
$royaltyImporterFile,
[
'type' => RoyaltyDueType::IMPORTED,
'amount' => (float)$value['income_sw'],
'amountNet' => (float)$value['income_sw_net'],
'description' => "Imported Royalties for {$royaltyImporterFile->getDateFrom()->format("M")} {$royaltyImporterFile->getDateFrom()->format("Y")}",
'grossIncome' => $grossIncome,
'income' => $income,
'incomeNet' => $incomeNet
]
);
$allParentProfile = $this->generalService->findAllParentProfiles($profile);
/** @var Profile $parentProfile */
foreach ($allParentProfile as $parentProfile){
$dataDue = [];
if($parentProfile->getProfileType()->getName() === Constants::PROFILE_TYPE_PUBLISHER){
$dataDue = [
'type' => RoyaltyDueType::IMPORTED,
'amount' => (float)$value['income_pu'],
'amountNet' => (float)$value['income_pu_net'],
'description' => "Imported Royalties for {$royaltyImporterFile->getDateFrom()->format("M")} {$royaltyImporterFile->getDateFrom()->format("Y")}",
'grossIncome' => $grossIncome,
'income' => $income,
'incomeNet' => $incomeNet
];
}else if($parentProfile->getProfileType()->getName() === Constants::PROFILE_TYPE_PUBLISHER_ADMINISTRATOR){
$dataDue = [
'type' => RoyaltyDueType::IMPORTED,
'amount' => (float)$value['income_pa'],
'amountNet' => (float)$value['income_pa_net'],
'description' => "Imported Royalties for {$royaltyImporterFile->getDateFrom()->format("M")} {$royaltyImporterFile->getDateFrom()->format("Y")}",
'grossIncome' => $grossIncome,
'income' => $income,
'incomeNet' => $incomeNet
];
}else{
$dataDue = [
'type' => RoyaltyDueType::IMPORTED,
'amount' => (float)$value['income_se'],
'amountNet' => (float)$value['income_se_net'],
'description' => "Imported Royalties for {$royaltyImporterFile->getDateFrom()->format("M")} {$royaltyImporterFile->getDateFrom()->format("Y")}",
'grossIncome' => $grossIncome,
'income' => $income,
'incomeNet' => $incomeNet
];
}
$royaltyDue = $this->processToCreateOrUpdateRoyaltyConsolidation(
$parentProfile,
$royaltyImporterFile,
$dataDue
);
}
}
$this->flushDataConsolidated($royaltyImporterFile);
$this->flushIncomeDataConsolidated($royaltyImporterFile);
if($reImport){
if($royaltyImporterFile->getPlatform()->getName() === Platforms::MLC){
$income = 0;
$incomeNet = 0;
/** @var RoyaltyDue $royaltyDue */
foreach ($this->royaltyDueRepository->findBy(['royaltyImporterFile' => $royaltyImporterFile]) as $royaltyDue){
if($royaltyDue->getProfile()->getProfileType()->getName() === Constants::PROFILE_TYPE_SERVICE){
$income = $royaltyDue->getIncomeAmount();
$incomeNet = $royaltyDue->getIncomeAmountNet();
}
}
/** @var RoyaltyDue $royaltyDue */
foreach ($this->royaltyDueRepository->findBy(['royaltyImporterFile' => $royaltyImporterFile]) as $royaltyDue){
if($royaltyDue->getProfile()->getProfileType()->getName() === Constants::PROFILE_TYPE_PUBLISHER_ADMINISTRATOR){
$royaltyDue->setIncomeAmountNet($incomeNet);
$royaltyDue->setIncomeAmount($income);
$this->royaltyDueRepository->flush($royaltyDue);
}
}
}
}
}
/**
* @param Profile $profile
* @param RoyaltyImporterFile $royaltyImporterFile
* @param array $data
* @return RoyaltyDue|object|null
*/
public function processToCreateOrUpdateRoyaltyConsolidation(
Profile $profile,
RoyaltyImporterFile $royaltyImporterFile,
array $data
)
{
$year = (int)$royaltyImporterFile->getEnteredAt()->format("Y");
$month = (int)$royaltyImporterFile->getEnteredAt()->format("m");
$cacheKey = sprintf('%d-%d-%d', $profile->getId(), $royaltyImporterFile->getId(), $year * 100 + $month);
if (!isset($this->dataConsolidated[$cacheKey])) {
$royaltyDue = $this->royaltyDueRepository->findOneBy([
'profile' => $profile,
'royaltyImporterFile' => $royaltyImporterFile,
'year' => $year,
'month' => $month
]);
$this->dataConsolidated[$cacheKey] = $royaltyDue ?: 'none';
}
$royaltyDue = $this->dataConsolidated[$cacheKey] !== 'none' ? $this->dataConsolidated[$cacheKey] : null;
if(
$profile->getProfileType()->getName() === Constants::PROFILE_TYPE_SONGWRITER ||
$profile->getProfileType()->getName() === Constants::PROFILE_TYPE_PUBLISHER
){
if($royaltyImporterFile->getPlatform()->getName() === Platforms::PRS){
if($data['amount'] === 0.00){
return $royaltyDue;
}
}
}
if(is_null($royaltyDue)){
$royaltyDue = (new RoyaltyDue())
->setProfile($profile)
->setRoyaltyImporterFile($royaltyImporterFile)
->setType($data['type'])
->setEarningAmount($data['amount'])
->setEarningAmountNet($data['amountNet'])
->setIncomeAmount($data['income'])
->setIncomeAmountNet($data['incomeNet'])
->setDescription($data['description'])
->setMonth((int)$royaltyImporterFile->getEnteredAt()->format("m"))
->setYear((int)$royaltyImporterFile->getEnteredAt()->format("Y"))
->setDatePaid($royaltyImporterFile->getEnteredAt());
$royaltyDue = $this->royaltyDueRepository->save($royaltyDue);
$this->dataConsolidated[$cacheKey] = $royaltyDue;
}else{
$amount = $royaltyDue->getEarningAmount() + $data['amount'];
$amountNet = $royaltyDue->getEarningAmountNet() + $data['amountNet'];
$income = $royaltyDue->getIncomeAmount() + $data['income'];
$incomeNet = $royaltyDue->getIncomeAmountNet() + $data['incomeNet'];
$royaltyDue->setIncomeAmount($income);
$royaltyDue->setIncomeAmountNet($incomeNet);
$royaltyDue->setEarningAmount($amount);
$royaltyDue->setEarningAmountNet($amountNet);
$this->dataConsolidated[$cacheKey] = $royaltyDue;
}
/*if($profile->getId() === 2) {
echo "{$data['income']},{$data['incomeNet']},{$royaltyDue->getIncomeAmount()} \n";
}*/
return $royaltyDue;
}
/**
* @param array $data
* @param Profile $profile
* @return RoyaltyDueAdjust
*/
public function processToCreateRoyaltyDueAdjust(array $data, Profile $profile): RoyaltyDueAdjust
{
/** @var RoyaltyDueAdjust $royaltyDueAdjust */
$royaltyDueAdjust = $this->entityFactory->createFromJson(
json_encode($data),
RoyaltyDueAdjust::class,
["royalty-adjust:create"]
);
$royaltyDueAdjust->setPayerUser($this->generalService->findTheCurrentUser());
$publisherAdministrator = null;
/** @var Profile $parentProfile */
foreach ($this->generalService->findAllParentProfiles($profile) as $parentProfile){
if($profile->getProfileType()->getName() === Constants::PROFILE_TYPE_SONGWRITER ||
$profile->getProfileType()->getName() === Constants::PROFILE_TYPE_PUBLISHER){
if($parentProfile->getProfileType()->getName() === Constants::PROFILE_TYPE_PUBLISHER_ADMINISTRATOR){
$publisherAdministrator = $parentProfile;
}
}else{
if($parentProfile->getProfileType()->getName() === Constants::PROFILE_TYPE_SERVICE){
$publisherAdministrator = $parentProfile;
}
}
}
if($profile->getProfileType()->getName() === Constants::PROFILE_TYPE_SERVICE){
$publisherAdministrator = $profile;
}
switch ($data['type']){
case RoyaltyDueType::PAYMENT:
case RoyaltyDueType::OTHER_PAYMENT:
case RoyaltyDueType::ROYALTY_PAYMENT:
$royaltyDueAdjust->setPayerProfile($profile);
$royaltyDueAdjust->setReceiverProfile($publisherAdministrator);
break;
case RoyaltyDueType::RETURN_PAYMENT:
case RoyaltyDueType::OTHER_RECEIVED_PAYMENT:
$royaltyDueAdjust->setPayerProfile($publisherAdministrator);
$royaltyDueAdjust->setReceiverProfile($profile);
break;
}
/** @var RoyaltyDueAdjust $royaltyDueAdjust */
$royaltyDueAdjust =$this->royaltyDueAdjustRepository->save($royaltyDueAdjust);
return $royaltyDueAdjust;
}
/**
* @param int $id
* @return RoyaltyDue|null
*/
public function getRoyaltyDueById(int $id)
{
return $this->royaltyDueRepository->find($id);
}
/**
* @param int $id
* @return RoyaltyDueAdjust|null
*/
public function getRoyaltyAdjustById(int $id)
{
return $this->royaltyDueAdjustRepository->find($id);
}
/**
* @param int $id
* @param Profile $profile
* @return array
*/
public function getDateIntervalInRoyaltyAdjust(int $id, Profile $profile)
{
$currentAdjust = $this->getRoyaltyAdjustById($id);
$adjustCollection = $this->royaltyDueAdjustRepository->createQueryBuilder("rda")
->where('rda.payerProfile = :payerProfile')
->andWhere('rda.type = :type')
->andWhere('rda.datePaid < :value')
->setParameter('payerProfile', $profile)
->setParameter('type', $currentAdjust->getType())
->setParameter('value', $currentAdjust->getDatePaid())
->orderBy('rda.datePaid', 'DESC')
->getQuery()
->getResult();
if(isset($adjustCollection[0])){
return [
'from' => $adjustCollection[0]->getDatePaid(),
'to' => $currentAdjust->getDatePaid(),
];
}else{
$dueCollection = $this->royaltyDueRepository->createQueryBuilder("rda")
->where('rda.profile = :profile')
->setParameter('profile', $profile)
->orderBy('rda.datePaid', 'ASC')
->getQuery()
->getResult();
if(isset($dueCollection[0])){
$firstDay = $dueCollection[0]->getDatePaid();
$lastDay = $currentAdjust->getDatePaid();
if($firstDay->format("Y-m-d") === $lastDay->format("Y-m-d")){
$firstDay->modify("-1 day");
$lastDay->modify('+1 day');
}
return [
'from' => $firstDay,
'to' => $lastDay,
];
}
throw new BadRequestHttpException("We don't find registers");
}
}
/**
* @param Profile $profile
* @return array
*/
public function getRoyaltiesConsolidations(Profile $profile): array
{
return $this->royaltyConsolidationRepository->findBy(['profile' => $profile]);
}
/**
* @param array $data
* @param Profile $profile
* @return array
*/
public function getEarningPaymentDetails(array $data, Profile $profile)
{
$dataToFile = [];
$dataEarnings = [];
if(isset($data['from']) && isset($data['to'])){
/** @var RoyaltyDue $royaltyDue */
$royaltyDueCollection = $this->royaltyDueRepository->createQueryBuilder('r')
->where('r.profile = :profile')
->andWhere('r.datePaid BETWEEN :startDate AND :endDate')
->setParameter('profile', $profile)
->setParameter('startDate', $data['from'])
->setParameter('endDate', $data['to'])
->getQuery()
->getResult();
}else{
$royaltyDueCollection = $this->royaltyDueRepository->findBy(['id' => $data['objectId']]);
}
if(count($royaltyDueCollection) <= 0){
throw new BadRequestHttpException("We don't found registers");
}
$totalAmountPaidByPlatform = 0.00;
$totalServiceAmount = 0.00;
$totalPublisherAdministratorAmount = 0.00;
$totalAmountLeftAfterDeduction = 0.00;
$totalPayableShareToSubProfile = 0.00;
$totalPublisherAmount = 0.00;
$totalSongWriterAmount = 0.00;
$totalTaxAmountDeduced = 0.00;
$totalTotal = 0.00;
$platform = null;
$dataRaw = null;
/** @var RoyaltyDue $royaltyDue */
foreach ($royaltyDueCollection as $royaltyDue){
$royaltyImporterFileYear = (int)$royaltyDue->getRoyaltyImporterFile()->getEnteredAt()->format('Y');
$royaltyImporterFileMonth = (int)$royaltyDue->getRoyaltyImporterFile()->getEnteredAt()->format('m');
$dataIncome = $this->incomeRawDataCHManagerService->getDataFromTable(
IncomeRawDataCHManagerService::NAME,
['*'],
['report_id' => $royaltyDue->getRoyaltyImporterFile()->getId()]
);
$platform = $royaltyDue->getRoyaltyImporterFile()->getPlatform();
foreach ($dataIncome as $income) {
/** @var SongWriter $songWriter */
$songWriter = $this->songWriterRepository->findOneBy([
'id' => $income['song_writer_id']
]);
$ruleToIf = false;
if($profile->getProfileType()->getName() === Constants::PROFILE_TYPE_SONGWRITER){
$ruleToIf = ($profile->getId() === $songWriter->getProfile()->getId());
}else if($profile->getProfileType()->getName() === Constants::PROFILE_TYPE_PUBLISHER){
$ruleToIf = ($profile->getId() === $songWriter->getProfile()->getParent()->getId());
}else if($profile->getProfileType()->getName() === Constants::PROFILE_TYPE_PUBLISHER_ADMINISTRATOR){
$profileParents = $this->generalService->findAllParentProfiles($songWriter->getProfile());
$profileParentAux = null;
/** @var Profile $profileParent */
foreach ($profileParents as $profileParent){
if($profileParent->getProfileType()->getName() === Constants::PROFILE_TYPE_PUBLISHER_ADMINISTRATOR){
$profileParentAux = $profileParent;
}
}
if(!is_null($profileParentAux)){
$ruleToIf = ($profile->getId() === $profileParentAux->getId());
}
}else{
$ruleToIf = !$ruleToIf;
}
if($ruleToIf){
$dataRaw = $this->rawDataDailyCHManagerService->getDataFromTable(
RawDataDailyCHManagerService::NAME,
['*'],
['id' => $income['raw_data_id']]
//[] TODO: Order by
);
$dataRaw = $dataRaw[0];
/** @var Country $country */
$country = $this->countryRepository->findOneBy(['id' => $dataRaw['country_id']]);
/** @var \App\Entity\Composition\Composition $composition */
$composition = $this->compositionRepository->findOneBy(['id' => $income['composition_id']]);
$reportingPeriod = $royaltyDue->getRoyaltyImporterFile()->getDateFrom()->format("Y-m-d")." to ".
$royaltyDue->getRoyaltyImporterFile()->getDateTo()->format("Y-m-d");
$publisherAdministratorPercentage = 0;
$publisherSharePercentage = 0;
$songWriterSharePercentage = 0;
if($royaltyDue->getRoyaltyImporterFile()->getProfile()->getProfileType()->getName() !== Constants::PROFILE_TYPE_SERVICE){
$royaltyPA = $royaltyDue->getRoyaltyImporterFile()->getProfile()->getRoyaltySplits();
$servicePercentage = $this->getRoyaltyPercentage($royaltyDue->getRoyaltyImporterFile(), $royaltyPA, true);
if($songWriter->getProfile()->getParent()->getId() !== $royaltyDue->getRoyaltyImporterFile()->getProfile()->getId()){
/** @var RoyaltySplits $royaltyPU */
$royaltyPU = $songWriter->getProfile()->getParent()->getRoyaltySplits();
$publisherAdministratorPercentage = $this->getRoyaltyPercentage(
$royaltyDue->getRoyaltyImporterFile(),
$royaltyPU,
true
);
$publisherSharePercentage = $this->getRoyaltyPercentage(
$royaltyDue->getRoyaltyImporterFile(),
$songWriter->getProfile()->getRoyaltySplits(),
true
);
}else{
$publisherAdministratorPercentage = $this->getRoyaltyPercentage(
$royaltyDue->getRoyaltyImporterFile(),
$songWriter->getProfile()->getRoyaltySplits(),
true
);
}
}else{
$publisherAdministratorByProfileChild = $this->generalService->findPublisherAdministratorByProfileChild($songWriter->getProfile());
if(!is_null($publisherAdministratorByProfileChild)){
$royaltyPA = $publisherAdministratorByProfileChild->getRoyaltySplits();
$servicePercentage = $this->getRoyaltyPercentage($royaltyDue->getRoyaltyImporterFile(), $royaltyPA, true);
if($songWriter->getProfile()->getParent()->getId() !== $publisherAdministratorByProfileChild->getId()){
/** @var RoyaltySplits $royaltyPU */
$royaltyPU = $songWriter->getProfile()->getParent()->getRoyaltySplits();
$publisherAdministratorPercentage = $this->getRoyaltyPercentage(
$royaltyDue->getRoyaltyImporterFile(),
$royaltyPU,
true
);
$publisherSharePercentage = $this->getRoyaltyPercentage(
$royaltyDue->getRoyaltyImporterFile(),
$songWriter->getProfile()->getRoyaltySplits(),
true
);
}else{
$publisherAdministratorPercentage = $this->getRoyaltyPercentage(
$royaltyDue->getRoyaltyImporterFile(),
$songWriter->getProfile()->getRoyaltySplits(),
true
);
}
}
}
$songWriterSharePercentage = $this->getRoyaltyPercentage(
$royaltyDue->getRoyaltyImporterFile(),
$songWriter->getProfile()->getRoyaltySplits()
);
$taxPercentage = $royaltyDue->getRoyaltyImporterFile()->getTaxPercentage() ?? 0;
$taxPercentage = $taxPercentage * 100;
switch ($profile->getProfileType()->getName()){
case Constants::PROFILE_TYPE_PUBLISHER_ADMINISTRATOR:
$earning = (new PublisherAdministratorEarningDTO())
->setSongWriterId($songWriter->getId())
->setReportDate($dataRaw['year_month'])
->setDateEntered($royaltyDue->getRoyaltyImporterFile()->getEnteredAt())
->setReportPeriod($reportingPeriod)
->setPlatform($royaltyDue->getRoyaltyImporterFile()->getPlatform()->getName())
->setPlatformType($dataRaw['rights_type'])
->setCountryOfSale($country->getCode())
->setPublisherProfile($royaltyDue->getRoyaltyImporterFile()->getProfile()->getProfileInformation()->getName())
->setSongWriterProfile($songWriter->getProfile()->getProfileInformation()->getName())
->setSongWriter($songWriter->getProfile()->getProfileInformation()->getName())
->setSongTitle($composition->getTitle())
->setIswc($composition->getIswc())
->setTunecode($composition->getTunecode())
->setIsrc(" ")//TODO: get the correct ISRC
->setQuantity($dataRaw['perf_number'])
->setAmountPaidByPlatform($income['income_total_gbp_share'])
->setServicePercentage($servicePercentage)
->setServiceAmount($income['income_se'])
->setAmountLeftAfterDeduction((float)$income['income_total_gbp_share'] - (float)$income['income_se'])
->setPublisherAdministratorPercentage($publisherAdministratorPercentage)
->setPublisherAdministratorAmount($income['income_pa'])
->setTaxCountry($royaltyDue->getRoyaltyImporterFile()->getTaxCountry()->getCode() ?? "")
->setTaxPercentage($taxPercentage)
->setTaxAmountDeduced($income['income_pa'] - $income['income_pa_net'])
->setTotal($income['income_pa_net']);
$totalAmountPaidByPlatform += $income['income_total_gbp_share'];
$totalServiceAmount += $income['income_se'];
$totalAmountLeftAfterDeduction += ((float)$income['income_total_gbp_share'] - (float)$income['income_se']);
$totalPublisherAdministratorAmount += $income['income_pa'];
$totalTaxAmountDeduced += ($income['income_pa'] - $income['income_pa_net']);
$totalTotal += $income['income_pa_net'];
break;
case Constants::PROFILE_TYPE_PUBLISHER:
case Constants::PROFILE_TYPE_SONGWRITER:
case Constants::PROFILE_TYPE_SERVICE:
$taxAmountDeduced = $income['income_sw'] - $income['income_sw_net'];
$total = $income['income_sw_net'];
if($profile->getProfileType()->getName() === Constants::PROFILE_TYPE_SERVICE){
$taxAmountDeduced = $income['income_se'] - $income['income_se_net'];
$total = $income['income_se_net'];
}else if($profile->getProfileType()->getName() === Constants::PROFILE_TYPE_PUBLISHER){
$taxAmountDeduced = $income['income_pu'] - $income['income_pu_net'];
$total = $income['income_pu_net'];
}
$earning = (new EarningDTO())
->setSongWriterId($songWriter->getId())
->setShare((float)$dataRaw['publisher_administrator_share'])
->setReportDate($dataRaw['year_month'])
->setDateEntered($royaltyDue->getRoyaltyImporterFile()->getEnteredAt())
->setReportPeriod($reportingPeriod)
->setPlatform($royaltyDue->getRoyaltyImporterFile()->getPlatform()->getName())
->setPlatformType($dataRaw['rights_type'])
->setCountryOfSale($country->getCode())
->setPublisherProfile($royaltyDue->getRoyaltyImporterFile()->getProfile()->getProfileInformation()->getName())
->setSongWriterProfile($songWriter->getProfile()->getProfileInformation()->getName())
->setSongWriter($songWriter->getProfile()->getProfileInformation()->getName())
->setSongTitle($composition->getTitle())
->setIswc($composition->getIswc())
->setTunecode($composition->getTunecode())
->setIsrc(" ")//TODO: get the correct ISRC
->setQuantity($dataRaw['perf_number'])
->setAmountPaidByPlatform($income['income_total_gbp_share'])
->setServicePercentage($servicePercentage)
->setServiceAmount($income['income_se'])
->setPublisherAdministratorPercentage($publisherAdministratorPercentage)
->setSongWriterSharePercentage($songWriterSharePercentage)
->setPublisherSharePercentage($publisherSharePercentage)
->setPublisherAdministratorAmount($income['income_pa'])
->setPayableShareToSubProfile((float)$income['income_pu'] + (float)$income['income_sw'])
->setPublisherAmount($income['income_pu'])
->setSongWriterAmount($income['income_sw'])
->setTaxCountry($royaltyDue->getRoyaltyImporterFile()->getTaxCountry()->getCode() ?? "")
->setTaxPercentage($taxPercentage)
->setTaxAmountDeduced($taxAmountDeduced)
->setTotal($total);
$totalAmountPaidByPlatform += $income['income_total_gbp_share'];
$totalServiceAmount += $income['income_se'];
$totalPublisherAdministratorAmount += $income['income_pa'];
$totalPayableShareToSubProfile += ((float)$income['income_pu'] + (float)$income['income_sw']);
$totalPublisherAmount += $income['income_pu'];
$totalSongWriterAmount += $income['income_sw'];
$totalTaxAmountDeduced += $taxAmountDeduced;
$totalTotal += $total;
if(
$platform->getName() === Platforms::PRS &&
$profile->getProfileType()->getName() === Constants::PROFILE_TYPE_SONGWRITER &&
(float)$dataRaw['publisher_administrator_share'] < 100.00
){
$totalAmountPaidByPlatform -= $income['income_total_gbp_share'];
$totalServiceAmount -= $income['income_se'];
$totalPublisherAdministratorAmount -= $income['income_pa'];
$totalPayableShareToSubProfile -= ((float)$income['income_pu'] + (float)$income['income_sw']);
$totalPublisherAmount -= $income['income_pu'];
$totalSongWriterAmount -= $income['income_sw'];
$totalTaxAmountDeduced -= $taxAmountDeduced;
$totalTotal -= $total;
}
break;
}
$dataEarnings[] = $earning;
}
}
}
if(!is_null($platform) && !is_null($dataRaw)){
foreach ($dataEarnings as $key => $earning) {
if(
$platform->getName() === Platforms::PRS &&
$profile->getProfileType()->getName() === Constants::PROFILE_TYPE_SONGWRITER &&
$earning->getShare() < 100.00
){
unset($dataEarnings[$key]);
}
}
}
switch ($profile->getProfileType()->getName()){
case Constants::PROFILE_TYPE_PUBLISHER_ADMINISTRATOR:
$earningResult = (new PublisherAdministratorEarningDTO())
->setAmountPaidByPlatform($totalAmountPaidByPlatform)
->setServiceAmount($totalServiceAmount)
->setAmountLeftAfterDeduction($totalAmountLeftAfterDeduction)
->setPublisherAdministratorAmount($totalPublisherAdministratorAmount)
->setTaxAmountDeduced($totalTaxAmountDeduced)
->setTotal($totalTotal);
break;
case Constants::PROFILE_TYPE_PUBLISHER:
case Constants::PROFILE_TYPE_SONGWRITER:
case Constants::PROFILE_TYPE_SERVICE:
$earningResult = (new EarningDTO())
->setAmountPaidByPlatform($totalAmountPaidByPlatform)
->setServiceAmount($totalServiceAmount)
->setPublisherAdministratorAmount($totalPublisherAdministratorAmount)
->setPayableShareToSubProfile($totalPayableShareToSubProfile)
->setPublisherAmount($totalPublisherAmount)
->setSongWriterAmount($totalSongWriterAmount)
->setTaxAmountDeduced($totalTaxAmountDeduced)
->setTotal($totalTotal);
break;
}
if(count($dataEarnings) > 0){
$dataEarnings[] = $earningResult;
$dataToFile = [
'earnings' => $dataEarnings,
'royaltyDues' => $royaltyDueCollection,
];
if(isset($data['from']) && isset($data['to'])){
$dataToFile['from'] = $data['from'];
$dataToFile['to'] = $data['to'];
}
}
return $dataToFile;
}
/**
* @param array $row
* @param Profile $profile
* @param string $type
* @return File|object
* @throws \League\Flysystem\FilesystemException
*/
public function processToBuildEarningPaymentCsv(array $row, Profile $profile, string $type)
{
$data = [];
$dataResponse = [];
/** @var RoyaltyDue $royaltyDue */
$royaltyDue = $row['royaltyDues'][0];
foreach ($row['earnings'] as $earning) {
$json = $this->serializer->serialize($earning, 'json', ['groups' => 'royalty:earning']);
$data[] = json_decode($json, true);
}
$tempFile = tempnam(sys_get_temp_dir(), 'csv_');
$fileHandle = fopen($tempFile, 'w');
$key = array_keys($data[0]);
fputcsv($fileHandle, $key);
foreach ($data as $rowFile) {
$formattedRow = array_map(function ($value) {
if (is_numeric($value)) {
return sprintf('%.10f', $value); // Format numbers with 10 decimal places
}
return $value;
}, $rowFile);
fputcsv($fileHandle, $formattedRow);
}
fclose($fileHandle);
if($type === RoyaltyDueType::IMPORTED){
$fileName = $profile->getProfileInformation()->getName()."-Earnings Report-".$royaltyDue->getYear()."-".$royaltyDue->getMonth().".csv";
}else{
$fileName = $profile->getProfileInformation()->getName()."-Royalty Payment-".
$row['from']->format("Ymd")."-".
$row['to']->format("Ymd").".csv";
}
$mimeType = 'text/csv';
$uploadedFile = new UploadedFile(
$tempFile,
$fileName,
$mimeType,
null,
true
);
return $this->fileService->upload(
$uploadedFile,
$royaltyDue->getId(),
get_class($royaltyDue)
);
}
/**
* @param array $row
* @param Profile $profile
* @param int $reason
* @return File|object
* @throws \League\Flysystem\FilesystemException
*/
public function processToBuildEarningSummaryCsv(array $rows, Profile $profile, int $reason = 1)
{
$data = [];
foreach ($rows as $earning) {
switch ($reason){
case 1:
$json = $this->serializer->serialize($earning, 'json', ['groups' => 'royalty:earning-summary']);
break;
case 2:
$json = $this->serializer->serialize($earning, 'json', ['groups' => 'royalty:earning-by-country-response']);
break;
case 3:
$json = $this->serializer->serialize($earning, 'json', ['groups' => 'royalty:earning-by-composition-response']);
break;
case 4:
$json = $this->serializer->serialize($earning, 'json', ['groups' => 'royalty:earning-by-platform-response']);
break;
case 5:
$json = $this->serializer->serialize($earning, 'json', ['groups' => 'royalty:earning-by-month-response']);
break;
}
$data[] = json_decode($json, true);
}
$tempFile = tempnam(sys_get_temp_dir(), 'csv_');
$fileHandle = fopen($tempFile, 'w');
switch ($reason){
case 1:
$key = ["Profile Type", "Profile Name", "Email", "Minimum Payment", "Paid Total", "Seek Total", "Current Due", "Currency"];
break;
case 2:
$key = ["Country", "earnings"];
break;
case 3:
$key = ["Composition", "earnings"];
break;
case 4:
$key = ["Platform", "earnings"];
break;
case 5:
$key = ["Month", "Year", "earnings"];
break;
}
fputcsv($fileHandle, $key);
foreach ($data as $rowFile) {
switch ($reason){
case 1:
$formattedRow = array_map(function ($value) {
return $value;
}, $rowFile);
fputcsv($fileHandle, $formattedRow);
break;
case 2:
$formattedRow = [$rowFile['country']['country'], $rowFile['total_income_net']];
fputcsv($fileHandle, $formattedRow);
break;
case 3:
$formattedRow = [$rowFile['composition']['title'], $rowFile['total_income_net']];
fputcsv($fileHandle, $formattedRow);
break;
case 4:
$formattedRow = [$rowFile['platform']['name'], $rowFile['total_income_net']];
fputcsv($fileHandle, $formattedRow);
break;
case 5:
$formattedRow = [$rowFile['month'], $rowFile['year'], $rowFile['total_income_net']];
fputcsv($fileHandle, $formattedRow);
break;
}
}
fclose($fileHandle);
switch ($reason){
case 1:
$fileName = $profile->getProfileInformation()->getName()."-Earnings Summary-".date("Ymd").".csv";
break;
case 2:
$fileName = $profile->getProfileInformation()->getName()."-Country Earnings-".date("Ymd").".csv";
break;
case 3:
$fileName = $profile->getProfileInformation()->getName()."-Composition Earnings-".date("Ymd").".csv";
break;
case 4:
$fileName = $profile->getProfileInformation()->getName()."-Platforms Earnings-".date("Ymd").".csv";
break;
case 5:
$fileName = $profile->getProfileInformation()->getName()."-Months Earnings-".date("Ymd").".csv";
break;
}
$mimeType = 'text/csv';
$uploadedFile = new UploadedFile(
$tempFile,
$fileName,
$mimeType,
null,
true
);
return $this->fileService->upload(
$uploadedFile,
$profile->getId(),
get_class($profile)
);
}
/**
* @param UploadedFile $uploadedFile
* @param \DateTime $dateEntered
* @return array
*/
public function processToUploadPaymentFile(UploadedFile $uploadedFile, \DateTime $dateEntered)
{
$dataToReturn = [];
$filePath = $uploadedFile->getPathname();
$tempFilePath = '/tmp/' . uniqid() . '.csv';
$uploadedFile->move(dirname($tempFilePath), basename($tempFilePath));
$data = $this->processCsvFileByPath($tempFilePath);
foreach ($data as $row) {
/** @var ProfileInformation $profileInformation */
$profileInformation = $this->generalService->findProfileInformationByName($row['Profile Name']);
/** @var Currency $currency */
$currency = $this->generalService->getCurrencyByCode($row['Currency Code']);
$receiverProfile = $this->generalService->findLastAccessedProfileForUser($this->generalService->findTheCurrentUser());
$royaltyAdjust = (new RoyaltyDueAdjust())
->setDescription($row['Message to Recipient'])
->setType(RoyaltyDueType::ROYALTY_PAYMENT)
->setDatePaid($dateEntered)
->setPayerUser($this->generalService->findTheCurrentUser())
->setPayerProfile($profileInformation->getProfile())
->setReceiverProfile($receiverProfile)
->setAmount($row['Amount']);
$royaltyAdjust = $this->royaltyDueAdjustRepository->save($royaltyAdjust);
$dataToReturn[] = $royaltyAdjust;
}
return $dataToReturn;
}
/**
* @param RoyaltyImporterFile $royaltyImporterFile
* @return array
*/
public function reProcessErrorRows(RoyaltyImporterFile $royaltyImporterFile)
{
$originalFile = $royaltyImporterFile->getFile();
$dataOriginalFile = [];
switch ($originalFile->getExtension()) {
case 'csv':
case 'CSV':
$dataOriginalFile = $this->processCsvFile($originalFile);
break;
case 'tsv':
case 'TSV':
$dataOriginalFile = $this->processTsvFile($originalFile);
break;
}
$dataToReProcess = [];
$data = $this->rawDataIncompleteCHManagerService->getDataFromTable(
RawDataIncompleteCH::TABLE_NAME,
['*'],
['report_id' => $royaltyImporterFile->getId()]
);
foreach ($data as $errorRow) {
if($royaltyImporterFile->getPlatform()->getName() === Platforms::MLC){
$dataToReProcess[] = $dataOriginalFile[$errorRow['old_id'] - 1];
$this->rawDataIncompleteCHManagerService->deleteData(
RawDataIncompleteCH::TABLE_NAME,
['id' => $errorRow['id']]
);
}else{
$key = array_search($errorRow['old_id'], array_column($dataOriginalFile, 'Record Number'));
if(!is_bool($key)){
$dataToReProcess[] = $dataOriginalFile[$key];
$this->rawDataIncompleteCHManagerService->deleteData(
RawDataIncompleteCH::TABLE_NAME,
['id' => $errorRow['id']]
);
}
}
}
return $dataToReProcess;
}
/**
* @param Profile $profile
* @return array
*/
public function getCompositionEarningsByProfile(Profile $profile)
{
$downloadSongParametersDTO = new DownloadSongParametersDTO();
$IncomeRawData = $this->incomeRawDataCHManagerService->getIncomeByComposition($profile->getProfileType());
$result = [];
$counter = 1;
$songs = $this->songService->findAllUnderProfile($profile, $downloadSongParametersDTO);
$compositions = [];
/** @var Song $song */
foreach ($songs as $song){
if(!in_array($song->getComposition(), $compositions)){
$compositions[] = $song->getComposition();
$resultByComposition =[
'composition' => [
'id' => $song->getComposition()->getId(),
'title' => $song->getComposition()->getTitle(),
],
'earning' => 0.00,
'id' => $song->getId(),
];
foreach ($IncomeRawData as $IncomeRawDataRegister){
if($song->getComposition()->getId() === $IncomeRawDataRegister['composition_id']){
$resultByComposition['earning'] += (float)$IncomeRawDataRegister['total_income_total_gbp_share_net'];
$result[] = $resultByComposition;
}
}
}
}
unset($compositions);
usort($result, function ($a, $b) {
return $b['earning'] <=> $a['earning'];
});
foreach ($result as $key => $row){
if($counter > 5){
unset($result[$key]);
}
$counter++;
}
return $result;
}
/**
* @param Profile $profile
* @param EarningByCountryDTO $earningByCountryDTO
* @return array|\mixed[][]
*/
public function getEarningsByCountry(Profile $profile, EarningByCountryDTO $earningByCountryDTO)
{
$profileArray = [];
if(
$profile->getProfileType()->getName() === Constants::PROFILE_TYPE_SERVICE ||
$profile->getProfileType()->getName() === Constants::PROFILE_TYPE_PUBLISHER_ADMINISTRATOR ||
$profile->getProfileType()->getName() === Constants::PROFILE_TYPE_PUBLISHER
){
$profileArray = $this->generalService->findAllSubProfiles($profile);
}else{
$profileArray[] = $profile;
}
$criteria = [
'countries' => null,
'start_date' => null,
'end_date' => null,
'limit' => 5,
'page' => 1
];
if(!is_null($earningByCountryDTO->getCountries())){
$aux = [];
/** @var Country $country */
foreach ($earningByCountryDTO->getCountries() as $country){
$aux[] = $country->getId();
}
if(count($aux) > 0){
$criteria['countries'] = $aux;
}
}
if(!is_null($earningByCountryDTO->getStartDate())){
$criteria['start_date'] = $earningByCountryDTO->getStartDate()->format('Y-m-d');
}
if(!is_null($earningByCountryDTO->getEndDate())){
$criteria['end_date'] = $earningByCountryDTO->getEndDate()->format('Y-m-d');
}
if(!is_null($earningByCountryDTO->getLimit())){
$criteria['limit'] = $earningByCountryDTO->getLimit();
}
if(!is_null($earningByCountryDTO->getPage())){
$criteria['page'] = $earningByCountryDTO->getPage();
}
$finalResultAux = [];
/** @var Profile $subProfile */
foreach ($profileArray as $subProfile){
$clickHouseResults = $this->rawDataDailyCHManagerService->getEarningsByCountryAndProfile(
$subProfile,
$profile->getProfileType(),
$criteria
);
foreach ($clickHouseResults as $clickHouseResult){
if(!isset($finalResultAux[(int)$clickHouseResult['country_id']])){
$finalResultAux[(int)$clickHouseResult['country_id']] = $clickHouseResult;
$finalResultAux[(int)$clickHouseResult['country_id']]['country_id'] = (int)$clickHouseResult['country_id'];
$finalResultAux[(int)$clickHouseResult['country_id']]['total_income_net'] = (float)$clickHouseResult['total_income_net'];
}else{
$finalResultAux[(int)$clickHouseResult['country_id']]['total_income_net'] += (float)$clickHouseResult['total_income_net'];
}
}
}
$finalResult = [];
$orderCounter = 1;
foreach ($finalResultAux as $key => $row){
$earningByCountryResponseDTO = new EarningByCountryResponseDTO();
$earningByCountryResponseDTO->setId((int)$key)
->setOrder($orderCounter)
->setCountry($this->countryRepository->find($row['country_id']))
->setTotalIncomeNet($row['total_income_net']);
$orderCounter++;
$finalResult[] = $earningByCountryResponseDTO;
}
return $finalResult;
}
/**
* @param Profile $profile
* @param EarningByCompositionDTO $earningByCompositionDTO
* @return array|\mixed[][]
*/
public function getEarningsByComposition(Profile $profile, EarningByCompositionDTO $earningByCompositionDTO)
{
$profileArray = [];
if(
$profile->getProfileType()->getName() === Constants::PROFILE_TYPE_SERVICE ||
$profile->getProfileType()->getName() === Constants::PROFILE_TYPE_PUBLISHER_ADMINISTRATOR ||
$profile->getProfileType()->getName() === Constants::PROFILE_TYPE_PUBLISHER
){
$profileArray = $this->generalService->findAllSubProfiles($profile);
}else{
$profileArray[] = $profile;
}
$criteria = [
'compositions' => null,
'start_date' => null,
'end_date' => null,
'limit' => 5,
'page' => 1
];
if(!is_null($earningByCompositionDTO->getCompositions())){
$aux = [];
/** @var Composition $composition */
foreach ($earningByCompositionDTO->getCompositions() as $composition){
$aux[] = $composition->getId();
}
if(count($aux) > 0){
$criteria['compositions'] = $aux;
}
}
if(!is_null($earningByCompositionDTO->getStartDate())){
$criteria['start_date'] = $earningByCompositionDTO->getStartDate()->format('Y-m-d');
}
if(!is_null($earningByCompositionDTO->getEndDate())){
$criteria['end_date'] = $earningByCompositionDTO->getEndDate()->format('Y-m-d');
}
if(!is_null($earningByCompositionDTO->getLimit())){
$criteria['limit'] = $earningByCompositionDTO->getLimit();
}
if(!is_null($earningByCompositionDTO->getPage())){
$criteria['page'] = $earningByCompositionDTO->getPage();
}
$finalResultAux = [];
/** @var Profile $subProfile */
foreach ($profileArray as $subProfile){
$clickHouseResults = $this->rawDataDailyCHManagerService->getEarningsByCompositionAndProfile(
$subProfile,
$profile->getProfileType(),
$criteria
);
foreach ($clickHouseResults as $clickHouseResult){
if(!isset($finalResultAux[(int)$clickHouseResult['composition_identifier']])){
$finalResultAux[(int)$clickHouseResult['composition_identifier']] = $clickHouseResult;
$finalResultAux[(int)$clickHouseResult['composition_identifier']]['composition_identifier'] = (int)$clickHouseResult['composition_identifier'];
$finalResultAux[(int)$clickHouseResult['composition_identifier']]['total_income_net'] = (float)$clickHouseResult['total_income_net'];
}else{
$finalResultAux[(int)$clickHouseResult['composition_identifier']]['total_income_net'] += (float)$clickHouseResult['total_income_net'];
}
}
}
$finalResult = [];
$counter = 1;
foreach ($finalResultAux as $key => $row){
$earningByCountryResponseDTO = new EarningByCompositionResponseDTO();
$earningByCountryResponseDTO->setId((int)$key)
->setOrder($counter)
->setComposition($this->compositionRepository->find($row['composition_identifier']))
->setTotalIncomeNet($row['total_income_net']);
$finalResult[] = $earningByCountryResponseDTO;
$counter ++;
}
return $finalResult;
}
/**
* @param Profile $profile
* @param EarningByPlatformDTO $earningByPlatformDTO
* @return array|\mixed[][]
*/
public function getEarningsByPlatform(Profile $profile, EarningByPlatformDTO $earningByPlatformDTO)
{
$profileArray = [];
if(
$profile->getProfileType()->getName() === Constants::PROFILE_TYPE_SERVICE ||
$profile->getProfileType()->getName() === Constants::PROFILE_TYPE_PUBLISHER_ADMINISTRATOR ||
$profile->getProfileType()->getName() === Constants::PROFILE_TYPE_PUBLISHER
){
$profileArray = $this->generalService->findAllSubProfiles($profile);
}else{
$profileArray[] = $profile;
}
$criteria = [
'platforms' => null,
'start_date' => null,
'end_date' => null,
'limit' => 5,
'page' => 1
];
if(!is_null($earningByPlatformDTO->getPlatforms())){
$aux = [];
/** @var Platform $platform */
foreach ($earningByPlatformDTO->getPlatforms() as $platform){
$aux[] = $platform->getId();
}
if(count($aux) > 0){
$criteria['platforms'] = $aux;
}
}
if(!is_null($earningByPlatformDTO->getStartDate())){
$criteria['start_date'] = $earningByPlatformDTO->getStartDate()->format('Y-m-d');
}
if(!is_null($earningByPlatformDTO->getEndDate())){
$criteria['end_date'] = $earningByPlatformDTO->getEndDate()->format('Y-m-d');
}
if(!is_null($earningByPlatformDTO->getLimit())){
$criteria['limit'] = $earningByPlatformDTO->getLimit();
}
if(!is_null($earningByPlatformDTO->getPage())){
$criteria['page'] = $earningByPlatformDTO->getPage();
}
$platformIds = [];
$finalResultAux = [];
foreach ($this->platformRepository->findAll() as $platform) {
$platformIds[] = $platform->getId();
$finalResultAux[(int)$platform->getId()] = [
'platform_identifier' => $platform->getId(),
'total_income_net' => 0
];
}
/** @var Profile $subProfile */
foreach ($profileArray as $subProfile){
$clickHouseResults = $this->rawDataDailyCHManagerService->getEarningsByPlatformAndProfile(
$subProfile,
$profile->getProfileType(),
$platformIds,
$criteria
);
foreach ($clickHouseResults as $key => $clickHouseResult){
$finalResultAux[$key]['total_income_net'] += (float)$clickHouseResult['total_income_net'];
}
}
$finalResult = [];
$counter = 1;
foreach ($finalResultAux as $key => $row){
if ($row['total_income_net'] > 0) {
$earningByCountryResponseDTO = new EarningByPlatformResponseDTO();
$earningByCountryResponseDTO->setId((int)$key)
->setOrder($counter)
->setPlatform($this->platformRepository->find($row['platform_identifier']))
->setTotalIncomeNet($row['total_income_net']);
$finalResult[] = $earningByCountryResponseDTO;
$counter ++;
}
}
return $finalResult;
}
/**
* @param Profile $profile
* @param EarningByMonthDTO $earningByMonthDTO
* @return array|\mixed[][]
*/
public function getEarningsByMonth(Profile $profile, EarningByMonthDTO $earningByMonthDTO)
{
$profileArray = [];
if(
$profile->getProfileType()->getName() === Constants::PROFILE_TYPE_SERVICE ||
$profile->getProfileType()->getName() === Constants::PROFILE_TYPE_PUBLISHER_ADMINISTRATOR ||
$profile->getProfileType()->getName() === Constants::PROFILE_TYPE_PUBLISHER
){
$profileArray = $this->generalService->findAllSubProfiles($profile);
}else{
$profileArray[] = $profile;
}
$criteria = [
'start_date' => null,
'end_date' => null,
'limit' => 5,
'page' => 1
];
if(!is_null($earningByMonthDTO->getStartDate())){
$criteria['start_date'] = $earningByMonthDTO->getStartDate()->format('Y-m-d');
}
if(!is_null($earningByMonthDTO->getEndDate())){
$criteria['end_date'] = $earningByMonthDTO->getEndDate()->format('Y-m-d');
}
if(!is_null($earningByMonthDTO->getLimit())){
$criteria['limit'] = $earningByMonthDTO->getLimit();
}
if(!is_null($earningByMonthDTO->getPage())){
$criteria['page'] = $earningByMonthDTO->getPage();
}
$finalResultAux = [];
/** @var Profile $subProfile */
foreach ($profileArray as $subProfile){
$clickHouseResults = $this->rawDataDailyCHManagerService->getEarningsByMonthAndProfile(
$subProfile,
$profile->getProfileType(),
$criteria
);
foreach ($clickHouseResults as $clickHouseResult){
if(!isset($finalResultAux[$clickHouseResult['month_period']])){
$finalResultAux[$clickHouseResult['month_period']] = $clickHouseResult;
$finalResultAux[$clickHouseResult['month_period']]['month_period'] = $clickHouseResult['month_period'];
$finalResultAux[$clickHouseResult['month_period']]['total_income_net'] = (float)$clickHouseResult['total_income_net'];
}else{
$finalResultAux[$clickHouseResult['month_period']]['total_income_net'] += (float)$clickHouseResult['total_income_net'];
}
}
}
$finalResult = [];
$counter = 1;
foreach ($finalResultAux as $key => $row){
$yearMonthArray = explode("-", $row['month_period']);
$earningByCountryResponseDTO = new EarningByMonthResponseDTO();
$earningByCountryResponseDTO->setId((int)$yearMonthArray[1] + (int)$yearMonthArray[0])
->setOrder($counter)
->setMonth($yearMonthArray[1])
->setYear($yearMonthArray[0])
->setTotalIncomeNet($row['total_income_net']);
$finalResult[] = $earningByCountryResponseDTO;
$counter ++;
}
return $finalResult;
}
//-------------------------------PRIVATE FUNCTIONS--------------------------------------------------------//
/**
* @param File $file
* @return array
*/
private function processCsvFile(File $file)
{
$data = array_map('str_getcsv', file($file->getUrl(), FILE_SKIP_EMPTY_LINES));
$keys = array_shift($data);
foreach ($data as $i => $row) {
$data[$i] = array_combine($keys, $row);
}
return $data;
}
/**
* @param File $file
* @return array
*/
private function processTsvFile(File $file)
{
$array = [];
$newArray = [];
if (($handle = fopen($file->getUrl(), 'r')) !== false) {
while (($data = fgetcsv($handle, null, "\t")) !== false) {
$array[] = $data;
}
fclose($handle);
$keys = $array[0];
unset($array[0]);
foreach ($array as $i => $row) {
$newArray[] = array_combine($keys, $row);
}
} else {
throw new BadRequestHttpException("Unable to open " . $file->getUrl());
}
return $newArray;
}
/**
* @param array $data
* @param array $dataErrorArrayObjects
* @param RoyaltyImporterFile $royaltyImporterFile
* @return File|object
* @throws \League\Flysystem\FilesystemException
*/
private function processToCreateAnErrorFile(
array $data, array $dataErrorArrayObjects, RoyaltyImporterFile $royaltyImporterFile
)
{
$tempFile = tempnam(sys_get_temp_dir(), 'csv_');
$fileHandle = fopen($tempFile, 'w');
$key = array_keys($data[0]);
$key[] = "observation";
fputcsv($fileHandle, $key);
foreach ($data as $key => $row) {
/** @var RawDataIncompleteCH $rawDataIncomplete */
$rawDataIncomplete = $dataErrorArrayObjects[$key];
switch ($rawDataIncomplete->getErrorNumber()){
case 1:
$row[] = "Please check the IPI name number";
break;
case 2:
if($royaltyImporterFile->getPlatform()->getName() === Platforms::MLC){
$row[] = "Please check the composition Tunecode, ISWC OR ISRC";
}else{
$row[] = "Please check the composition Tunecode or ISWC";
}
break;
case 3:
$row[] = "Please check the songwriter information";
break;
case 4:
$row[] = "Please check the row information, general error in the register";
case 5:
$row[] = "Composition could not be found by ISWC OR ISRC";
case 6:
$row[] = "Composition is not published or taken down";
break;
}
fputcsv($fileHandle, $row);
}
fclose($fileHandle);
$arrFileName = explode('.', $royaltyImporterFile->getFile()->getOriginalName());
$fileName = $arrFileName[0]."_errors.".$arrFileName[1];
$mimeType = 'text/csv';
$uploadedFile = new UploadedFile(
$tempFile,
$fileName,
$mimeType,
null,
true
);
return $this->fileService->upload(
$uploadedFile,
$royaltyImporterFile->getId(),
get_class($royaltyImporterFile)
);
}
/**
* @param Profile $profile
* @return float|int|mixed|string
*/
private function getPaymentAndReceiverPayer(Profile $profile)
{
return $this->royaltyDueAdjustRepository->createQueryBuilder('r')
->where('r.payerProfile = :profileId')
->orWhere('r.receiverProfile = :profileId')
->setParameter('profileId', $profile->getId())
->getQuery()
->getResult();
}
/**
* @param string $path
* @return array
*/
private function processCsvFileByPath(string $path)
{
$data = array_map('str_getcsv', file($path, FILE_SKIP_EMPTY_LINES));
$keys = array_shift($data);
foreach ($data as $i => $row) {
$data[$i] = array_combine($keys, $row);
}
return $data;
}
/**
* @param RoyaltyImporterFile $royaltyImporterFile
* @param RoyaltySplits $royaltySplits
* @param bool $parent
* @return float|int|null
*/
private function getRoyaltyPercentage(
RoyaltyImporterFile $royaltyImporterFile,
RoyaltySplits $royaltySplits,
bool $parent = false
)
{
$percentage = 0;
switch ($royaltyImporterFile->getType()){
case RoyaltyImporterFileType::M:
$percentage = ($parent) ? $royaltySplits->getMechanicalRoyaltySplitParent() : $royaltySplits->getMechanicalRoyaltySplitProfile();
break;
case RoyaltyImporterFileType::L:
$percentage = ($parent) ? $royaltySplits->getLyricsRoyaltySplitParent() : $royaltySplits->getLyricsRoyaltySplitProfile();
break;
case RoyaltyImporterFileType::P:
$percentage = ($parent) ? $royaltySplits->getPerformanceRoyaltySplitParent() : $royaltySplits->getPerformanceRoyaltySplitProfile();
break;
case RoyaltyImporterFileType::S:
$percentage = ($parent) ? $royaltySplits->getSyncRoyaltySplitParent() : $royaltySplits->getSyncRoyaltySplitProfile();
break;
}
return $percentage;
}
/**
* @param RoyaltyImporterFile $royaltyImporterFile
* @return void
*/
private function flushDataConsolidated(RoyaltyImporterFile $royaltyImporterFile)
{
if($royaltyImporterFile->getPlatform()->getName() === Platforms::MLC){
$income = 0;
$incomeNet = 0;
/**
* @var $key
* @var RoyaltyDue $royaltyDue
*/
foreach ($this->dataConsolidated as $key => $royaltyDue) {
if($royaltyDue->getProfile()->getProfileType()->getName() === Constants::PROFILE_TYPE_SERVICE){
$income = $royaltyDue->getIncomeAmount();
$incomeNet = $royaltyDue->getIncomeAmountNet();
}
}
/**
* @var $key
* @var RoyaltyDue $royaltyDue
*/
foreach ($this->dataConsolidated as $key => $royaltyDue) {
if($royaltyDue->getProfile()->getProfileType()->getName() === Constants::PROFILE_TYPE_PUBLISHER_ADMINISTRATOR){
$this->dataConsolidated[$key]->setIncomeAmountNet($incomeNet);
$this->dataConsolidated[$key]->setIncomeAmount($income);
}
}
}
foreach ($this->dataConsolidated as $royaltyDue) {
if ($royaltyDue instanceof RoyaltyDue) {
$this->entityManager->persist($royaltyDue);
}
}
$this->entityManager->flush();
$this->dataConsolidated = [];
}
/**
* @param RoyaltyImporterFile $royaltyImporterFile
* @return void
*/
private function flushRawDateProcessed(RoyaltyImporterFile $royaltyImporterFile)
{
$this->rawDataDailyCHManagerService->updateSingleField(
RawDataDailyCHManagerService::NAME,
"status",
RoyaltyRawDataStatus::PROCESSED,
['report_id' => $royaltyImporterFile->getId()]
);
}
/**
* @param RoyaltyImporterFile $royaltyImporterFile
* @return void
*/
private function flushIncomeDataConsolidated(RoyaltyImporterFile $royaltyImporterFile)
{
$this->incomeRawDataCHManagerService->updateSingleField(
IncomeRawDataCH::TABLE_NAME,
"consolidated",
1,
['report_id' => $royaltyImporterFile->getId()]
);
}
}