Your IP : 216.73.217.79


Current Path : /var/www/v3.cesa.co.za/tests/Unit/MemberBundle/
Upload File :
Current File : /var/www/v3.cesa.co.za/tests/Unit/MemberBundle/MemberFirmTransformationPortalServiceTest.php

<?php

namespace App\Tests\Unit\MemberBundle;

use App\MemberBundle\Entity\ADecMemberFirm;
use App\MemberBundle\Entity\ADecTransformation;
use App\MemberBundle\Entity\MemberFirm;
use App\MemberBundle\Form\Model\MemberFirmTransformationCapture;
use App\MemberBundle\Repository\ADecMemberFirmRepository;
use App\MemberBundle\Repository\ADecTransformationRepository;
use App\MemberBundle\Repository\MemberContactRepository;
use App\MemberBundle\Service\MemberFirmTransformationPortalService;
use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\TestCase;

class MemberFirmTransformationPortalServiceTest extends TestCase
{
    public function testPrepareDeclarationUsesCurrentYearWhenPresent(): void
    {
        $liveFirm = $this->createMock(MemberFirm::class);
        $liveFirm->method('getId')->willReturn(263);

        $adecFirm = $this->createMock(ADecMemberFirm::class);
        $adecFirm->method('getSmme')->willReturn('EME');
        $adecFirm->method('getBlackOwned')->willReturn('10%');
        $adecFirm->method('getBlackWomenOwned')->willReturn('5%');
        $adecFirm->method('getBbbeeLevel')->willReturn(4);
        $adecFirm->method('getTotalStaff')->willReturn(100);
        $adecFirm->method('getThreeYearsAverageTurnover')->willReturn('1000000');
        $adecFirm->method('getMemberTransformation')->willReturn(null);

        $adecTrans = $this->createMock(ADecTransformation::class);
        $adecTrans->method('getTransTopMa')->willReturn(1);

        $year = (int) date('Y');

        $adecFirmRepo = $this->createMock(ADecMemberFirmRepository::class);
        $adecFirmRepo->method('findOneByLiveFirmAndDeclarationYear')
            ->willReturnCallback(static function (int $firmId, int $y) use ($year, $adecFirm) {
                return $y === $year ? $adecFirm : null;
            });

        $adecTransRepo = $this->createMock(ADecTransformationRepository::class);
        $adecTransRepo->method('findOneByLiveFirmAndDeclarationYear')->willReturn($adecTrans);

        $em = $this->createMock(EntityManagerInterface::class);
        $em->method('getRepository')->willReturnCallback(
            static function (string $class) use ($adecFirmRepo, $adecTransRepo) {
                if ($class === ADecMemberFirm::class) {
                    return $adecFirmRepo;
                }
                if ($class === ADecTransformation::class) {
                    return $adecTransRepo;
                }

                throw new \RuntimeException('Unexpected repository: ' . $class);
            },
        );

        $service = new MemberFirmTransformationPortalService(
            $this->createMock(MemberContactRepository::class),
            $em,
        );

        $context = $service->prepareDeclarationCapture($liveFirm);

        $this->assertSame($year, $context->declarationYear);
        $this->assertTrue($context->hasCurrentYearDeclaration);
        $this->assertNull($context->prefilledFromYear);
        $this->assertSame('EME', $context->capture->smme);
    }

    public function testPrepareDeclarationPrefillsFromPriorYear(): void
    {
        $year = (int) date('Y');
        $priorYear = $year - 1;

        $liveFirm = $this->createMock(MemberFirm::class);
        $liveFirm->method('getId')->willReturn(263);
        $liveFirm->method('getMemberTransformation')->willReturn(null);
        $liveFirm->method('getSmme')->willReturn(null);

        $priorFirm = $this->createMock(ADecMemberFirm::class);
        $priorFirm->method('getSmme')->willReturn('PriorSMME');
        $priorFirm->method('getBlackOwned')->willReturn('20%');
        $priorFirm->method('getBlackWomenOwned')->willReturn('10%');
        $priorFirm->method('getBbbeeLevel')->willReturn(3);
        $priorFirm->method('getTotalStaff')->willReturn(50);
        $priorFirm->method('getThreeYearsAverageTurnover')->willReturn(null);
        $priorFirm->method('getMemberTransformation')->willReturn(null);

        $priorTrans = $this->createMock(ADecTransformation::class);
        $priorTrans->method('getTransTopMa')->willReturn(2);

        $adecFirmRepo = $this->createMock(ADecMemberFirmRepository::class);
        $adecFirmRepo->method('findOneByLiveFirmAndDeclarationYear')
            ->willReturnCallback(static function (int $firmId, int $y) use ($year, $priorYear, $priorFirm) {
                if ($y === $year) {
                    return null;
                }
                if ($y === $priorYear) {
                    return $priorFirm;
                }

                return null;
            });

        $adecTransRepo = $this->createMock(ADecTransformationRepository::class);
        $adecTransRepo->method('findOneByLiveFirmAndDeclarationYear')->willReturn($priorTrans);

        $em = $this->createMock(EntityManagerInterface::class);
        $em->method('getRepository')->willReturnCallback(
            static function (string $class) use ($adecFirmRepo, $adecTransRepo) {
                if ($class === ADecMemberFirm::class) {
                    return $adecFirmRepo;
                }
                if ($class === ADecTransformation::class) {
                    return $adecTransRepo;
                }

                throw new \RuntimeException('Unexpected repository: ' . $class);
            },
        );

        $service = new MemberFirmTransformationPortalService(
            $this->createMock(MemberContactRepository::class),
            $em,
        );

        $context = $service->prepareDeclarationCapture($liveFirm);

        $this->assertFalse($context->hasCurrentYearDeclaration);
        $this->assertSame($priorYear, $context->prefilledFromYear);
        $this->assertSame('PriorSMME', $context->capture->smme);
    }

    public function testSaveDeclarationPersistsOnlyAdecEntities(): void
    {
        $year = (int) date('Y');

        $liveFirm = $this->createMock(MemberFirm::class);
        $liveFirm->method('getId')->willReturn(263);
        $liveFirm->method('getFirmName')->willReturn('Test Firm');
        $liveFirm->method('getMemberStatus')->willReturn('Current');
        $liveFirm->method('getSmme')->willReturn('EME');
        $liveFirm->method('getBlackOwned')->willReturn('10%');
        $liveFirm->method('getBlackWomenOwned')->willReturn('5%');
        $liveFirm->method('getBbbeeLevel')->willReturn(4);
        $liveFirm->method('getTotalStaff')->willReturn(100);
        $liveFirm->method('getThreeYearsAverageTurnover')->willReturn('1000000');

        $capture = new MemberFirmTransformationCapture();
        $capture->smme = 'EME';
        $capture->blackOwned = '10%';
        $capture->blackWomenOwned = '5%';
        $capture->bbbeeLevel = 4;
        $capture->totalStaff = 1;
        $capture->threeYearsAverageTurnover = '1000000';
        $capture->trans = ['trans_top_ma' => 1];

        $adecFirmRepo = $this->createMock(ADecMemberFirmRepository::class);
        $adecFirmRepo->method('findOneByLiveFirmAndDeclarationYear')->willReturn(null);

        $adecTransRepo = $this->createMock(ADecTransformationRepository::class);
        $adecTransRepo->method('findOneByLiveFirmAndDeclarationYear')->willReturn(null);

        $persisted = [];
        $em = $this->createMock(EntityManagerInterface::class);
        $em->method('getRepository')->willReturnCallback(
            static function (string $class) use ($adecFirmRepo, $adecTransRepo) {
                if ($class === ADecMemberFirm::class) {
                    return $adecFirmRepo;
                }
                if ($class === ADecTransformation::class) {
                    return $adecTransRepo;
                }

                throw new \RuntimeException('Unexpected repository: ' . $class);
            },
        );
        $em->method('persist')->willReturnCallback(static function (object $entity) use (&$persisted): void {
            $persisted[] = $entity;
        });
        $em->expects($this->once())->method('flush');

        $service = new MemberFirmTransformationPortalService(
            $this->createMock(MemberContactRepository::class),
            $em,
        );

        $service->saveDeclaration($liveFirm, $capture);

        $adecFirms = array_values(array_filter($persisted, static fn (object $e): bool => $e instanceof ADecMemberFirm));
        $adecTrans = array_values(array_filter($persisted, static fn (object $e): bool => $e instanceof ADecTransformation));

        $this->assertNotEmpty($adecFirms);
        $this->assertNotEmpty($adecTrans);
        $adecFirm = $adecFirms[0];
        $adecTransformation = $adecTrans[0];
        $this->assertSame($year, $adecFirm->getDeclarationYear());
        $this->assertSame($year, $adecTransformation->getDeclarationYear());
        $this->assertSame(263, $adecTransformation->getPrevFirmId());
        foreach ($persisted as $entity) {
            $this->assertNotInstanceOf(MemberFirm::class, $entity);
        }
    }

    public function testSumTransformationHeadcountTotalsAllGridFields(): void
    {
        $service = new MemberFirmTransformationPortalService(
            $this->createMock(MemberContactRepository::class),
            $this->createMock(EntityManagerInterface::class),
        );

        $trans = array_fill_keys(MemberFirmTransformationPortalService::TRANSFORMATION_COUNT_FIELDS, 0);
        $trans['trans_top_ma'] = 3;
        $trans['trans_senior_fa'] = 2;

        $this->assertSame(5, $service->sumTransformationHeadcount($trans));
    }

    public function testValidateStaffHeadcountMatchesGridAcceptsMatchingTotals(): void
    {
        $service = new MemberFirmTransformationPortalService(
            $this->createMock(MemberContactRepository::class),
            $this->createMock(EntityManagerInterface::class),
        );

        $capture = new MemberFirmTransformationCapture();
        $capture->totalStaff = 4;
        $capture->trans = [
            'trans_top_ma' => 1,
            'trans_top_mc' => 1,
            'trans_senior_fa' => 2,
        ];

        $this->assertNull($service->validateStaffHeadcountMatchesGrid($capture));
    }

    public function testValidateStaffHeadcountMatchesGridRejectsMismatch(): void
    {
        $service = new MemberFirmTransformationPortalService(
            $this->createMock(MemberContactRepository::class),
            $this->createMock(EntityManagerInterface::class),
        );

        $capture = new MemberFirmTransformationCapture();
        $capture->totalStaff = 10;
        $capture->trans = ['trans_top_ma' => 3];

        $message = $service->validateStaffHeadcountMatchesGrid($capture);

        $this->assertNotNull($message);
        $this->assertStringContainsString('10', $message);
        $this->assertStringContainsString('3', $message);
    }

    public function testSaveDeclarationRejectsMismatchedHeadcount(): void
    {
        $liveFirm = $this->createMock(MemberFirm::class);

        $capture = new MemberFirmTransformationCapture();
        $capture->totalStaff = 5;
        $capture->trans = ['trans_top_ma' => 1];

        $service = new MemberFirmTransformationPortalService(
            $this->createMock(MemberContactRepository::class),
            $this->createMock(EntityManagerInterface::class),
        );

        $this->expectException(\InvalidArgumentException::class);
        $service->saveDeclaration($liveFirm, $capture);
    }
}