<?php
namespace App\Controller\Risk;
use App\Builder\RiskModelBuilder;
use App\Constant\BusinessActivityTypes;
use App\Constant\BusinessLinesType;
use App\Constant\CountryListConstant;
use App\Constant\RiskNaturalPerson;
use App\Constant\SourceOfFundsType;
use App\Form\Model\Instance\InstanceFilterModel;
use App\Form\Model\Merchant\MerchantFilterModel;
use App\Form\Model\Risk\Person\PersonRiskLevelModel;
use App\Form\Model\Risk\Person\RiskLevelModel;
use App\Form\Model\Risk\Person\RisksPersonModel;
use App\Form\Type\Risk\Person\PersonRiskLevelType;
use App\RequestManager\Application\BusinessActivityRequestManager;
use App\RequestManager\InstanceRequestManager;
use App\RequestManager\MerchantRequestManager;
use App\RequestManager\RiskRequestManager;
use App\RequestManager\RiskV3RequestManager;
use GuzzleHttp\Exception\GuzzleException;
use JsonException;
use App\Controller\BaseController;
use Paynetics\Exception\ApiException;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Serializer\Exception\ExceptionInterface;
/**
* Class DashboardController
* @package App\Controller
*/
class RiskController extends BaseController
{
/**
* @var RiskRequestManager
* @required
*/
public RiskRequestManager $riskRequestManager;
/**
* @required
*/
public RiskV3RequestManager $riskV3RequestManager;
/**
* @var MerchantRequestManager
* @required
*/
public MerchantRequestManager $merchantRequestManager;
/**
* @var InstanceRequestManager
* @required
*/
public InstanceRequestManager $instanceRequestManager;
/**
* @var BusinessActivityRequestManager
* @required
*/
public BusinessActivityRequestManager $businessActivityRequestManager;
/**
* @var CacheItemPoolInterface
* @required
*/
public CacheItemPoolInterface $cache;
/**
* @var RiskModelBuilder
* @required
*/
public RiskModelBuilder $builder;
/**
* @param Request $request
* @return Response
*/
public function show(Request $request, string $code): Response
{
$this->isGranted(['ROLE_RISK_MANAGER']);
$risk = $this->riskRequestManager->show($code);
/**
* @var object $model
*/
$model = $this->builder->build($code, $risk);
$formFullName = str_replace('Model', 'Type', get_class($model));
$form = $this->createForm($formFullName, $model);
$form->handleRequest($request);
$instances = [];
$merchants = [];
if ($code == 'instance') {
try {
$filter = new InstanceFilterModel();
$instances = $this->instanceRequestManager->getInstances(1, 1000, $filter)['items'];
$instances = array_column($instances, 'name', 'token');
} catch (GuzzleException|ExceptionInterface|\Exception $e) {
$message = 'An error occurred. Code: ' . $e->getCode();
$this->addFlash('error', $message);
return $this->redirectToRoute('risk_show', compact('code'));
}
} else if ($code == 'merchant') {
try {
$filter = new MerchantFilterModel();
$filter->setIsMaster(true);
$merchants = $this->merchantRequestManager->getMerchants(1, 1000, $filter)['items'];
$merchants = array_column($merchants, 'name', 'token');
} catch (GuzzleException|\Exception $e) {
$message = 'An error occurred. Code: ' . $e->getCode();
$this->addFlash('error', $message);
return $this->redirectToRoute('risk_show', compact('code'));
}
}
if ($form->isSubmitted() && $form->isValid()) {
$data = $this->builder->build($code, $form->getData(), true);
$this->handleUpdate($data, $risk, $code);
return $this->redirectToRoute('risk_show', compact('code'));
}
return $this->renderForm("risk/$code.html.twig", ['form' => $form, 'sourceOfFunds' => SourceOfFundsType::TYPES, 'countries_list' => CountryListConstant::COUNTRIES_ARRAY_ISO_2, 'activities' => BusinessActivityTypes::TYPES, 'lines' => BusinessLinesType::TYPES, 'instances' => $instances, 'merchants' => $merchants]);
}
/**
* @param $token
* @return Response
* @throws ApiException
* @throws GuzzleException
* @throws JsonException
*/
public function showMerchantDetailsRisk($token): Response
{
$risk = $this->riskV3RequestManager->loadMerchantScore($token);
$cacheItem = $this->cache->getItem('risk');
if ($cacheItem->isHit()) {
$risksArray = $cacheItem->get();
} else {
$risksArray = $this->riskRequestManager->checks();
$cacheItem->set($risksArray);
$cacheItem->expiresAfter(7200);
$this->cache->save($cacheItem);
}
$risks = array_column($risksArray, 'description', 'code');
$merchant = $this->merchantRequestManager->getMerchant($token);
return $this->render('merchant/risk.html.twig', [
'merchant' => $merchant,
'risk' => $risk,
'risks' => $risks
]);
}
/**
* @throws ApiException
* @throws GuzzleException
* @throws JsonException
*/
public function showPersonLevel(Request $request)
{
$risk = $this->riskRequestManager->showLevels();
$levels = new PersonRiskLevelModel();
$result = [];
foreach ($risk as $riskElement) {
$model = new RiskLevelModel();
$model->setId($riskElement['id']);
$model->setLevel($riskElement['level']);
$model->setRiskLowValue($riskElement['riskLowValue']);
$model->setRiskHighValue($riskElement['riskHighValue']);
$result[] = $model;
}
$levels->setLevels($result);
$form = $this->createForm(PersonRiskLevelType::class, $levels);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$formData = $form->getData();
$this->riskRequestManager->updateLevels($formData);
return $this->redirectToRoute('risk_person_level_show');
}
return $this->renderForm("risk/person/level.html.twig", ['form' => $form]);
}
public function showPerson(Request $request, $type)
{
$typeId = RiskNaturalPerson::TYPES[$type];
$risk = $this->riskRequestManager->showPersonRisk($typeId);
/**
* @var object $model
*/
$model = $this->builder->buildPerson($type, $risk);
$formFullName = str_replace('Model', 'Type', get_class($model));
$form = $this->createForm($formFullName, $model);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->handleUpdatePerson($form->getData(), $risk, $type);
return $this->redirectToRoute('risk_person_show', compact('type'));
}
return $this->renderForm("risk/person/{$type}.html.twig", ['form' => $form]);
}
private function handleUpdate(array $array, $originalArray, $code = null)
{
$key = (isset($originalArray['values'][0]['score']) ? 'score' : (isset($originalArray['values'][0]['entity']))) ? 'entity' : 'range';
$keyGeneral = isset($originalArray['general'][0]['range']) ? 'range' : 'score';
$originalValues = array_column($originalArray['values'] ?? [], $key, 'id');
$formValues = array_column($array, $key, 'id');
$forUpdate = array_diff_assoc($formValues, $originalValues);
$arrayCopy = $array;
$hasEntity = false;
$hasScore = false;
$hasRange = false;
foreach ($arrayCopy as $key => $value) {
if (!isset($value['entity']) && !(isset($value['score']) && isset($value['range']))) {
unset($arrayCopy[$key]);
}
if (isset($value['entity'])) {
$hasEntity = true;
}
if (isset($value['score']) && !isset($originalArray['general'][0]['score'])) {
$hasScore = true;
}
if (isset($value['range'])) {
$hasRange = true;
}
}
if ($hasScore) {
$originalScoreValues = array_column($originalArray['values'] ?? [], 'score', 'id');
$formScoreValues = array_column($array, 'score', 'id');
$forUpdateScores = array_diff_assoc($formScoreValues, $originalScoreValues);
$forUpdate += $forUpdateScores;
}
if ($hasRange) {
$originalRangeValues = array_column($originalArray['values'] ?? [], 'range', 'id');
$formRangeValues = array_column($array, 'range', 'id');
$forUpdateScores = array_diff_assoc($formRangeValues, $originalRangeValues);
$forUpdate += $forUpdateScores;
}
$forDelete = [];
foreach ($array as $item) {
if (isset($item['id']) && isset($item['entity']) && (!isset($item['risk']) && !isset($item['score']) && !isset($item['range']))
|| (isset($item['id'])) && isset($item['risk']) && !isset($item['score']) && !isset($item['entity']) && !isset($item['range'])) {
$forDelete[$item['id']] = null;
}
}
$forUpdateNomenclature = [];
if ($hasEntity) {
$formValues = array_column($arrayCopy, 'risk', 'entity');
$formValues += array_column($arrayCopy, 'score', 'entity');
$originalValues = array_column($originalArray['nomenclature'] ?? [], 'risk', 'entity');
$forUpdateNomenclature = array_diff($formValues, $originalValues);
$forUpdateNomenclature2 = array_diff_assoc($formValues, $originalValues);
if (array_diff($forUpdateNomenclature, $forUpdateNomenclature2) || array_diff($forUpdateNomenclature2, $forUpdateNomenclature)) {
$forUpdateNomenclature = array_merge($forUpdateNomenclature2, $forUpdateNomenclature);
}
}
$forUpdateGeneral = [];
if (isset($originalArray['general'])) {
$originalValues = array_column($originalArray['general'], $keyGeneral, 'id');
$formValues = array_column($array, $keyGeneral, 'id');
$forUpdateGeneral = array_diff_assoc($formValues, $originalValues);
}
$successMessage = '';
foreach ($array as $item) {
if (isset($item['id'])) {
if ((array_key_exists($item['id'], $forUpdate) && $forUpdate[$item['id']] !== null && !isset($item['entity']))//risk is present and changed
|| (isset($item['entity']) && array_key_exists($item['entity'], $forUpdateNomenclature) && $forUpdateNomenclature[$item['entity']] !== null) //nomenclature is present and changed
|| (array_key_exists($item['id'], $forUpdateNomenclature) && $forUpdateNomenclature[$item['id']] !== null) //values is present and changed
|| (array_key_exists($item['id'], $forUpdateGeneral) && $forUpdateGeneral[$item['id']] !== null)) { //general is present and changed
try {
$this->riskRequestManager->update($item);
} catch (GuzzleException|\Exception $e) {
$message = 'An error occurred. Code: ' . $e->getCode();
if ($e->getCode() === 8002) {
$message = 'This range/token already exists';
}
$this->addFlash('error', $message);
return;
}
$successMessage = 'Successfully Updated!';
} else if ((isset($item['risk']) && array_key_exists($item['id'], $forUpdate) && $forUpdate[$item['id']] === null && !isset($item['entity']))
|| (array_key_exists($item['id'], $forUpdateGeneral) && $forUpdateGeneral[$item['id']] === null)
|| (isset($item['entity']) && array_key_exists($item['entity'], $forUpdateNomenclature) && $forUpdateNomenclature[$item['entity']] === null)
|| (array_key_exists($item['id'], $forDelete) && $forDelete[$item['id']] === null)
) {
try {
$this->riskRequestManager->remove($item['id']);
} catch (GuzzleException|\Exception $e) {
$message = 'An error occurred. Code: ' . $e->getCode();
$this->addFlash('error', $message);
return;
}
$successMessage = 'Successfully Deleted!';
}
} else {//no id set
if ((isset($item['score']))
|| (isset($item['risk']) && (isset($item['entity']) || isset($item['range'])))
|| (isset($item['entity']) && isset($item['range']))) {//create
$item['type'] = $code;
try {
$this->riskRequestManager->create($item);
} catch (GuzzleException|\Exception $e) {
$message = 'An error occurred. Code: ' . $e->getCode();
if ($e->getCode() === 8002) {
$message = 'This range/token already exists';
}
$this->addFlash('error', $message);
return;
}
$successMessage = 'Successfully Created!';
}
}
}
if (strlen($successMessage) > 0) {
$this->addFlash('success', $successMessage);
}
}
private function handleUpdatePerson(RisksPersonModel $array, $originalArray, $type = null)
{
foreach ($array->getValues() as $item) {
if ($item->getId() === null) {
$item->setRiskType(RiskNaturalPerson::TYPES[$type]);
try {
$this->riskRequestManager->createPerson($item);
} catch (\Exception $exception) {
$message = 'An error occurred. Code: ' . $exception->getCode();
if ($exception->getCode() === 8002) {
$message = 'This configuration already exists';
}
$this->addFlash('error', $message);
continue;
}
$successMessage = 'Successfully Created!';
$this->addFlash('success', $successMessage);
continue;
}
foreach ($originalArray as $value) {
if ($value['id'] == $item->getId()) {
if ($item->getRisk() !== null && isset($value['risk']) && $value['risk'] != $item->getRisk()
|| ($item->getDescription() !== null && isset($value['description']) && $value['description'] != $item->getDescription())
|| ($item->getCode() !== null && $value['code'] != $item->getCode())) {
try {
$this->riskRequestManager->updatePerson($item, $item->getId());
} catch (\Exception $exception) {
$message = 'An error occurred. Code: ' . $exception->getCode();
if ($exception->getCode() === 8002) {
$message = 'This configuration already exists';
}
$this->addFlash('error', $message);
continue;
}
$successMessage = 'Successfully Updated!';
$this->addFlash('success', $successMessage);
break;
} else if ($item->getCode() === null && $item->getDescription() === null) {
try {
$this->riskRequestManager->removePerson($item->getId());
} catch (\Exception $exception) {
$message = 'An error occurred. Code: ' . $exception->getCode();
$this->addFlash('error', $message);
continue;
}
$successMessage = 'Successfully Deleted!';
$this->addFlash('success', $successMessage);
break;
}
}
}
}
return $this->redirectToRoute('risk_person_show', compact('type'));
}
public function delete(string $code, int $id): Response
{
$this->isGranted(['ROLE_RISK_MANAGER']);
try {
$this->riskRequestManager->remove($id);
} catch (GuzzleException|ApiException $e) {
$message = 'An error occurred. Code: ' . $e->getCode();
$this->addFlash('error', $message);
return $this->redirectToRoute('risk_show', compact('code'));
}
$this->addFlash('success', 'Successfully Deleted!');
return $this->redirectToRoute('risk_show', compact('code'));
}
public function deletePerson($type, $id): RedirectResponse
{
$this->isGranted(['ROLE_RISK_MANAGER']);
try {
$this->riskRequestManager->removePerson($id);
} catch (GuzzleException|ApiException $e) {
$message = 'An error occurred. Code: ' . $e->getCode();
$this->addFlash('error', $message);
return $this->redirectToRoute('risk_person_show', compact('type'));
}
$this->addFlash('success', 'Successfully Deleted!');
return $this->redirectToRoute('risk_person_show', compact('type'));
}
}