feature/cierres (#25)
Varios cambios Co-authored-by: Juan Pablo Vial <jpvialb@incoviba.cl> Reviewed-on: #25
This commit is contained in:
@ -280,7 +280,7 @@ class Cartola extends Service
|
||||
try {
|
||||
return $this->movimientoRepository->save($movimiento);
|
||||
} catch (PDOException $exception) {
|
||||
$this->logger->critical(var_export($data,true));
|
||||
$this->logger->critical($exception, ['data' => $data]);
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ class Mes extends Banco
|
||||
}
|
||||
try {
|
||||
$reader = PhpSpreadsheet\IOFactory::createReader('Xlsx');
|
||||
} catch (PhpSpreadsheet\Reader\Exception $exception) {
|
||||
} catch (PhpSpreadsheet\Reader\Exception) {
|
||||
return false;
|
||||
}
|
||||
$xlsx = $reader->load($filename);
|
||||
|
@ -1,7 +1,6 @@
|
||||
<?php
|
||||
namespace Incoviba\Service\Contabilidad\Informe\Tesoreria\Input\Excel;
|
||||
|
||||
use stdClass;
|
||||
use PhpOffice\PhpSpreadsheet;
|
||||
|
||||
class DAPyFFMM extends Sheet
|
||||
|
52
app/src/Service/External.php
Normal file
52
app/src/Service/External.php
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
namespace Incoviba\Service;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Incoviba\Common\Ideal;
|
||||
|
||||
class External extends Ideal\Service
|
||||
{
|
||||
public function __construct(LoggerInterface $logger, protected Queue $queueService)
|
||||
{
|
||||
parent::__construct($logger);
|
||||
}
|
||||
|
||||
protected array $externalServices;
|
||||
public function register($service): self
|
||||
{
|
||||
if (!isset($this->externalServices)) {
|
||||
$this->externalServices = [$service];
|
||||
return $this;
|
||||
}
|
||||
if (!in_array($service, $this->externalServices)) {
|
||||
$this->externalServices []= $service;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function check(bool $update = false): bool
|
||||
{
|
||||
$errors = [];
|
||||
foreach ($this->externalServices as $externalService) {
|
||||
if (!method_exists($externalService, 'check')) {
|
||||
continue;
|
||||
}
|
||||
$queueData = [
|
||||
'type' => 'checkExternal',
|
||||
'service' => get_class($externalService),
|
||||
'action' => 'check',
|
||||
];
|
||||
if ($update) {
|
||||
$queueData['args'] = ['update' => true];
|
||||
}
|
||||
if (!$this->queueService->enqueue($queueData)) {
|
||||
$errors []= get_class($externalService);
|
||||
}
|
||||
}
|
||||
if (count($errors) > 0) {
|
||||
$this->logger->error('Could not enqueue check of external services', ['services' => $errors]);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
16
app/src/Service/HMAC.php
Normal file
16
app/src/Service/HMAC.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
namespace Incoviba\Service;
|
||||
|
||||
use Incoviba\Common\Ideal;
|
||||
|
||||
class HMAC extends Ideal\Service
|
||||
{
|
||||
public function validate(string $timestamp, string $requestSignature, string $requestId, string $secret): bool
|
||||
{
|
||||
$message = "{$timestamp}.{$requestId}";
|
||||
$encodedSecret = mb_convert_encoding($secret, 'UTF-8');
|
||||
$encodedMessage = mb_convert_encoding($message, 'UTF-8');
|
||||
$hmacObject = hash_hmac('sha256', $encodedMessage, $encodedSecret);
|
||||
return hash_equals($hmacObject, $requestSignature);
|
||||
}
|
||||
}
|
135
app/src/Service/Job.php
Normal file
135
app/src/Service/Job.php
Normal file
@ -0,0 +1,135 @@
|
||||
<?php
|
||||
namespace Incoviba\Service;
|
||||
|
||||
use DateInvalidTimeZoneException;
|
||||
use DateMalformedStringException;
|
||||
use DateTimeImmutable;
|
||||
use DateTimeZone;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Incoviba\Common\Ideal;
|
||||
use Incoviba\Exception\MQTT as MQTTException;
|
||||
use Incoviba\Exception\ServiceAction\{Create, Delete, Read, Update};
|
||||
use Incoviba\Model;
|
||||
use Incoviba\Repository;
|
||||
|
||||
class Job extends Ideal\Service
|
||||
{
|
||||
public function __construct(LoggerInterface $logger, protected MQTT $mqttService,
|
||||
protected Repository\Job $jobRepository)
|
||||
{
|
||||
parent::__construct($logger);
|
||||
}
|
||||
|
||||
public function isPending(): bool
|
||||
{
|
||||
try {
|
||||
return $this->mqttService->exists();
|
||||
} catch (MQTTException $exception) {
|
||||
$this->logger->error($exception->getMessage(), ['exception' => $exception]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Model\Job
|
||||
* @throws Read
|
||||
*/
|
||||
public function get(): Model\Job
|
||||
{
|
||||
try {
|
||||
return $this->load(json_decode($this->mqttService->get(), true));
|
||||
} catch (MQTTException $exception) {
|
||||
$this->logger->error($exception->getMessage(), ['exception' => $exception]);
|
||||
throw new Read(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $configuration
|
||||
* @return Model\Job
|
||||
* @throws Create
|
||||
*/
|
||||
public function add(array $configuration): Model\Job
|
||||
{
|
||||
try {
|
||||
$now = (new DateTimeImmutable('now', new DateTimeZone($_ENV['TZ'] ?? 'America/Santiago')));
|
||||
} catch (DateMalformedStringException | DateInvalidTimeZoneException $exception) {
|
||||
$this->logger->warning($exception->getMessage(), ['exception' => $exception]);
|
||||
$now = new DateTimeImmutable();
|
||||
}
|
||||
$data = [
|
||||
'id' => $now->format('Uu'),
|
||||
'configuration' => $configuration,
|
||||
'executed' => false,
|
||||
'created_at' => $now->format('Y-m-d H:i:s'),
|
||||
'updated_at' => null,
|
||||
'retries' => 0
|
||||
];
|
||||
try {
|
||||
$this->mqttService->set(json_encode($data));
|
||||
} catch (MQTTException $exception) {
|
||||
throw new Create(__CLASS__, $exception);
|
||||
}
|
||||
return $this->load($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model\Job $job
|
||||
* @return void
|
||||
* @throws Update
|
||||
*/
|
||||
public function update(Model\Job $job): void
|
||||
{
|
||||
try {
|
||||
$now = (new DateTimeImmutable('now', new DateTimeZone($_ENV['TZ'] ?? 'America/Santiago')));
|
||||
} catch (DateMalformedStringException | DateInvalidTimeZoneException) {
|
||||
$now = new DateTimeImmutable();
|
||||
}
|
||||
$data = json_decode(json_encode($job), true);
|
||||
$data['updated_at'] = $now->format('Y-m-d H:i:s');
|
||||
|
||||
try {
|
||||
$this->mqttService->update(json_encode($data));
|
||||
} catch (MQTTException $exception) {
|
||||
throw new Update(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model\Job $job
|
||||
* @throws Delete
|
||||
*/
|
||||
public function remove(Model\Job $job): void
|
||||
{
|
||||
try {
|
||||
$this->mqttService->remove();
|
||||
} catch (MQTTException $exception) {
|
||||
throw new Delete(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model\Job $job
|
||||
* @return bool
|
||||
*/
|
||||
public function execute(Model\Job $job): bool
|
||||
{
|
||||
try {
|
||||
$this->mqttService->remove();
|
||||
return true;
|
||||
} catch (MQTTException $exception) {
|
||||
$this->logger->error($exception->getMessage(), ['exception' => $exception]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected function load(array $data, ?int $id = null): Model\Job
|
||||
{
|
||||
$job = new Model\Job();
|
||||
$job->id = $id ?? $data['id'] ?? null;
|
||||
$job->configuration = $data['configuration'] ?? [];
|
||||
$job->executed = $data['executed'] ?? false;
|
||||
$job->retries = $data['retries'] ?? 0;
|
||||
return $job;
|
||||
}
|
||||
}
|
@ -6,6 +6,10 @@ use DateTimeImmutable;
|
||||
use DateInterval;
|
||||
use Exception;
|
||||
use PDOException;
|
||||
use Incoviba\Exception\ServiceAction\Create;
|
||||
use Incoviba\Exception\ServiceAction\Delete;
|
||||
use Incoviba\Exception\ServiceAction\Read;
|
||||
use Incoviba\Exception\ServiceAction\Update;
|
||||
use Incoviba\Common\Implement\Exception\EmptyResult;
|
||||
use Incoviba\Repository;
|
||||
use Incoviba\Model;
|
||||
@ -40,6 +44,11 @@ class Login
|
||||
} catch (PDOException|EmptyResult) {}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Model\User
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getUser(): Model\User
|
||||
{
|
||||
$login = $this->repository->fetchActiveBySelector($this->selector);
|
||||
@ -57,20 +66,90 @@ class Login
|
||||
return $this->cookie_separator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return Model\User
|
||||
* @throws Create
|
||||
* @throws Read
|
||||
*/
|
||||
public function addUser(array $data): Model\User
|
||||
{
|
||||
try {
|
||||
return $this->userRepository->fetchByName($data['name']);
|
||||
} catch (EmptyResult) {
|
||||
list($passphrase, $encrypted) = $this->splitPassword($data['password']);
|
||||
$password = $this->cryptoJs_aes_decrypt($encrypted, $passphrase);
|
||||
try {
|
||||
$password = $this->cryptoJs_aes_decrypt($encrypted, $passphrase);
|
||||
} catch (Exception $exception) {
|
||||
throw new Read(__CLASS__, $exception);
|
||||
}
|
||||
$password = password_hash($password, PASSWORD_DEFAULT);
|
||||
$user = $this->userRepository->create([
|
||||
'name' => $data['name'],
|
||||
'password' => $password,
|
||||
'enabled' => $data['enabled'] ?? 1
|
||||
]);
|
||||
return $this->userRepository->save($user);
|
||||
try {
|
||||
return $this->userRepository->save($user);
|
||||
} catch (PDOException $exception) {
|
||||
throw new Create(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $user_id
|
||||
* @param array $data
|
||||
* @return Model\User
|
||||
* @throws Read
|
||||
* @throws Update
|
||||
*/
|
||||
public function editUser(int $user_id, array $data): Model\User
|
||||
{
|
||||
try {
|
||||
$user = $this->userRepository->fetchById($user_id);
|
||||
} catch (EmptyResult $exception) {
|
||||
throw new Read(__CLASS__, $exception);
|
||||
}
|
||||
if (!isset($data['force']) and !$user->validate($data['old_password'])) {
|
||||
throw new Read(__CLASS__);
|
||||
}
|
||||
list($passphrase, $encrypted) = $this->splitPassword($data['password']);
|
||||
try {
|
||||
$password = $this->cryptoJs_aes_decrypt($encrypted, $passphrase);
|
||||
} catch (Exception $exception) {
|
||||
throw new Read(__CLASS__, $exception);
|
||||
}
|
||||
$password = password_hash($password, PASSWORD_DEFAULT);
|
||||
$userData = [
|
||||
'password' => $password
|
||||
];
|
||||
try {
|
||||
$user = $this->userRepository->edit($user, $userData);
|
||||
} catch (PDOException | EmptyResult $exception) {
|
||||
throw new Update(__CLASS__, $exception);
|
||||
}
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $user_id
|
||||
* @return Model\User
|
||||
* @throws Delete
|
||||
* @throws Read
|
||||
*/
|
||||
public function deleteUser(int $user_id): Model\User
|
||||
{
|
||||
try {
|
||||
$user = $this->userRepository->fetchById($user_id);
|
||||
} catch (EmptyResult $exception) {
|
||||
throw new Read(__CLASS__, $exception);
|
||||
}
|
||||
try {
|
||||
$this->userRepository->remove($user);
|
||||
return $user;
|
||||
} catch (PDOException | EmptyResult $exception) {
|
||||
throw new Delete(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
public function validateUser(Model\User $user, string $encryptedPassword): bool
|
||||
@ -88,7 +167,13 @@ class Login
|
||||
try {
|
||||
$login = $this->repository->fetchActiveByUser($user->id);
|
||||
$this->logout($login->user);
|
||||
} catch (PDOException|EmptyResult) {
|
||||
} catch (EmptyResult $exception) {
|
||||
$message []= "No logins for user {$user->name}";
|
||||
$message []= $exception->getMessage();
|
||||
$message []= $exception->getTraceAsString();
|
||||
error_log(implode(PHP_EOL, $message).PHP_EOL, 3, '/logs/login-exception.log');
|
||||
} catch (PDOException $exception) {
|
||||
error_log($exception.PHP_EOL, 3, '/logs/login-exception.log');
|
||||
}
|
||||
|
||||
try {
|
||||
@ -104,7 +189,8 @@ class Login
|
||||
$this->repository->save($login);
|
||||
$this->saveCookie($selector, $token, $login->dateTime->add(new DateInterval("PT{$this->max_login_time}H")));
|
||||
return true;
|
||||
} catch (PDOException|Exception) {
|
||||
} catch (PDOException | Exception $exception) {
|
||||
error_log($exception.PHP_EOL, 3, '/logs/login-exception.log');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
102
app/src/Service/MQTT.php
Normal file
102
app/src/Service/MQTT.php
Normal file
@ -0,0 +1,102 @@
|
||||
<?php
|
||||
namespace Incoviba\Service;
|
||||
|
||||
use Incoviba\Exception\MQTT as MQTTException;
|
||||
use Incoviba\Service\MQTT\MQTTInterface;
|
||||
|
||||
class MQTT implements MQTTInterface
|
||||
{
|
||||
protected array $clients = [];
|
||||
public function register(string $name, MQTTInterface $client): self
|
||||
{
|
||||
$this->clients[$name] = $client;
|
||||
return $this;
|
||||
}
|
||||
public function clientExists(string $name): bool
|
||||
{
|
||||
return isset($this->clients[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $name
|
||||
* @return MQTTInterface
|
||||
* @throws MQTTException/MissingClient
|
||||
*/
|
||||
public function getClient(?string $name = null): MQTTInterface
|
||||
{
|
||||
if ($name === null) {
|
||||
$name = array_keys($this->clients)[0];
|
||||
}
|
||||
if (!$this->clientExists($name)) {
|
||||
throw new MQTTException\MissingClient($name);
|
||||
}
|
||||
return $this->clients[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $host
|
||||
* @return bool
|
||||
* @throws MQTTException/MissingClient
|
||||
* @throws MQTTException/MissingJob
|
||||
*/
|
||||
public function exists(?string $host = null): bool
|
||||
{
|
||||
$client = $this->getClient($host);
|
||||
return $client->exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $host
|
||||
* @return string
|
||||
* @throws MQTTException/MissingClient
|
||||
* @throws MQTTException/MissingJob
|
||||
*/
|
||||
public function get(?string $host = null): string
|
||||
{
|
||||
$client = $this->getClient($host);
|
||||
return $client->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
* @param int $delay
|
||||
* @param string|null $host
|
||||
* @return $this
|
||||
* @throws MQTTException/MissingClient
|
||||
* @throws MQTTException/SetJob
|
||||
*/
|
||||
public function set(string $value, int $delay = 0, ?string $host = null): self
|
||||
{
|
||||
$client = $this->getClient($host);
|
||||
$client->set($value, $delay);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $jobId
|
||||
* @param string|null $host
|
||||
* @return $this
|
||||
* @throws MQTTException/MissingJob
|
||||
* @throws MQTTException/RemoveJob
|
||||
*/
|
||||
public function remove(?int $jobId = null, ?string $host = null): self
|
||||
{
|
||||
$this->getClient($host)->remove($jobId);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $newPayload
|
||||
* @param int|null $jobId
|
||||
* @param string|null $host
|
||||
* @return $this
|
||||
* @throws MQTTException/MissingJob
|
||||
* @throws MQTTException/RemoveJob
|
||||
* @throws MQTTException/SetJob
|
||||
*/
|
||||
public function update(string $newPayload, ?int $jobId = null, ?string $host = null): self
|
||||
{
|
||||
$this->getClient($host)->update($newPayload, $jobId);
|
||||
return $this;
|
||||
}
|
||||
}
|
111
app/src/Service/MQTT/Beanstalkd.php
Normal file
111
app/src/Service/MQTT/Beanstalkd.php
Normal file
@ -0,0 +1,111 @@
|
||||
<?php
|
||||
namespace Incoviba\Service\MQTT;
|
||||
|
||||
use Exception;
|
||||
use Incoviba\Exception\MQTT\MissingJob;
|
||||
use Incoviba\Exception\MQTT\RemoveJob;
|
||||
use Incoviba\Exception\MQTT\SetJob;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use xobotyi\beansclient;
|
||||
use xobotyi\beansclient\Exception\ClientException;
|
||||
use xobotyi\beansclient\Exception\CommandException;
|
||||
use xobotyi\beansclient\Exception\JobException;
|
||||
|
||||
class Beanstalkd implements MQTTInterface
|
||||
{
|
||||
/**
|
||||
* @throws JobException
|
||||
* @throws ClientException
|
||||
* @throws CommandException
|
||||
*/
|
||||
public function __construct(protected LoggerInterface $logger, protected beansclient\BeansClient $client,
|
||||
protected string $tube = 'default', protected int $ttr = beansclient\BeansClient::DEFAULT_TTR,
|
||||
protected int $priority = 1)
|
||||
{
|
||||
$this->client->watchTube($this->tube);
|
||||
}
|
||||
|
||||
public function exists(): bool
|
||||
{
|
||||
try {
|
||||
$stats = $this->client->statsTube($this->tube);
|
||||
return $stats['current-jobs-ready'] > 0;
|
||||
} catch (Exception $exception) {
|
||||
$this->logger->error($exception->getMessage(), ['exception' => $exception]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected ?beansclient\Job $currentJob = null;
|
||||
public function get(): string
|
||||
{
|
||||
if (!$this->exists()) {
|
||||
throw new MissingJob();
|
||||
}
|
||||
try {
|
||||
$job = $this->client->watchTube($this->tube)->reserve();
|
||||
$this->currentJob = $job;
|
||||
return $job->payload;
|
||||
} catch (Exception $exception) {
|
||||
$this->logger->error($exception->getMessage(), ['exception' => $exception]);
|
||||
throw new MissingJob($exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
* @param int $delay
|
||||
* @return $this
|
||||
* @throws SetJob
|
||||
*/
|
||||
public function set(string $value, int $delay = 0): self
|
||||
{
|
||||
try {
|
||||
$this->client->useTube($this->tube)->put($value, $this->priority, $delay, $this->ttr ?? 0);
|
||||
} catch (Exception $exception) {
|
||||
$this->logger->error($exception->getMessage(), ['payload' => $value, 'delay' => $delay, 'exception' => $exception]);
|
||||
throw new SetJob($value, $exception);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $newPayload
|
||||
* @param int|null $jobId
|
||||
* @return self
|
||||
* @throws RemoveJob
|
||||
* @throws SetJob
|
||||
*/
|
||||
public function update(string $newPayload, ?int $jobId = null): self
|
||||
{
|
||||
if ($jobId === null) {
|
||||
$jobId = $this->currentJob->id;
|
||||
}
|
||||
return $this->remove($jobId)
|
||||
->set($newPayload);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $jobId
|
||||
* @return $this
|
||||
* @throws RemoveJob
|
||||
*/
|
||||
public function remove(?int $jobId = null): self
|
||||
{
|
||||
if ($jobId === null) {
|
||||
$jobId = $this->currentJob->id;
|
||||
}
|
||||
try {
|
||||
if (!$this->client->useTube($this->tube)->delete($jobId)) {
|
||||
throw new JobException("Failed to delete job {$jobId}");
|
||||
}
|
||||
if ($this->currentJob !== null && $this->currentJob->id === $jobId) {
|
||||
$this->currentJob = null;
|
||||
}
|
||||
} catch (Exception $exception) {
|
||||
$this->logger->error($exception->getMessage(), ['jobId' => $jobId, 'exception' => $exception]);
|
||||
throw new RemoveJob($jobId, $exception);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
}
|
25
app/src/Service/MQTT/MQTTInterface.php
Normal file
25
app/src/Service/MQTT/MQTTInterface.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
namespace Incoviba\Service\MQTT;
|
||||
|
||||
use Incoviba\Exception\MQTT\MissingJob;
|
||||
|
||||
interface MQTTInterface {
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function exists(): bool;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws MissingJob
|
||||
*/
|
||||
public function get(): string;
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
* @param int $delay
|
||||
* @return self
|
||||
*/
|
||||
public function set(string $value, int $delay = 0): self;
|
||||
public function remove(?int $jobId = null): self;
|
||||
}
|
59
app/src/Service/MQTT/Pheanstalk.php
Normal file
59
app/src/Service/MQTT/Pheanstalk.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
namespace Incoviba\Service\MQTT;
|
||||
|
||||
use Incoviba\Common\Ideal\Service;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Pheanstalk as PBA;
|
||||
|
||||
class Pheanstalk extends Service implements MQTTInterface
|
||||
{
|
||||
const string DEFAULT_TUBE = 'default';
|
||||
const int DEFAULT_TTR = 60;
|
||||
const int DEFAULT_PRIORITY = 1_024;
|
||||
|
||||
public function __construct(LoggerInterface $logger, protected PBA\Pheanstalk $client, string $tubeName = self::DEFAULT_TUBE)
|
||||
{
|
||||
parent::__construct($logger);
|
||||
$this->tube = new PBA\Values\TubeName($tubeName);
|
||||
}
|
||||
|
||||
protected PBA\Values\TubeName $tube;
|
||||
|
||||
public function set(string $value, int $delay = 0): self
|
||||
{
|
||||
$this->client->useTube($this->tube);
|
||||
$this->client->put($value, self::DEFAULT_PRIORITY, $delay, self::DEFAULT_TTR);
|
||||
return $this;
|
||||
}
|
||||
public function exists(): bool
|
||||
{
|
||||
$stats = $this->client->statsTube($this->tube);
|
||||
return $stats->currentJobsReady > 0;
|
||||
}
|
||||
protected int $currentJobId;
|
||||
public function get(): string
|
||||
{
|
||||
$this->client->useTube($this->tube);
|
||||
$job = $this->client->reserve();
|
||||
$this->currentJobId = $job->getId();
|
||||
return $job->getData();
|
||||
}
|
||||
public function update(string $newPayload, ?int $jobId = null): self
|
||||
{
|
||||
if ($jobId === null) {
|
||||
$jobId = $this->currentJobId;
|
||||
}
|
||||
$this->remove($jobId);
|
||||
$this->set($newPayload);
|
||||
return $this;
|
||||
}
|
||||
public function remove(?int $jobId = null): self
|
||||
{
|
||||
if ($jobId === null) {
|
||||
$jobId = $this->currentJobId;
|
||||
}
|
||||
$this->client->useTube($this->tube);
|
||||
$this->client->delete(new PBA\Values\JobId($jobId));
|
||||
return $this;
|
||||
}
|
||||
}
|
@ -5,60 +5,89 @@ use DateTimeInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Incoviba\Common\Define\Money\Provider;
|
||||
use Incoviba\Common\Implement\Exception\EmptyResponse;
|
||||
use Incoviba\Service\Money\MiIndicador;
|
||||
|
||||
class Money
|
||||
{
|
||||
const UF = 'uf';
|
||||
const USD = 'usd';
|
||||
const IPC = 'ipc';
|
||||
|
||||
public function __construct(protected LoggerInterface $logger) {}
|
||||
|
||||
protected array $providers;
|
||||
public function register(string $name, Provider $provider): Money
|
||||
{
|
||||
if (isset($this->providers) and isset($this->providers[$name]) and $this->providers[$name] === $provider) {
|
||||
if (isset($this->providers) and isset($this->providers[$name]) and in_array($provider, $this->providers[$name])) {
|
||||
return $this;
|
||||
}
|
||||
$this->providers[$name] = $provider;
|
||||
if (!isset($this->providers[$name])) {
|
||||
$this->providers[$name] = [];
|
||||
}
|
||||
$this->providers[$name] []= $provider;
|
||||
return $this;
|
||||
}
|
||||
public function getProvider(string $name): Provider
|
||||
public function getProviders(string $name): array
|
||||
{
|
||||
return $this->providers[$name];
|
||||
}
|
||||
|
||||
public function get(string $provider, DateTimeInterface $dateTime): float
|
||||
{
|
||||
try {
|
||||
return $this->getProvider($provider)->get(MiIndicador::getSymbol($provider), $dateTime);
|
||||
} catch (EmptyResponse) {
|
||||
return 0;
|
||||
$providers = $this->getProviders($provider);
|
||||
foreach ($providers as $provider) {
|
||||
try {
|
||||
return $provider->get(self::getSymbol($provider), $dateTime);
|
||||
} catch (EmptyResponse $exception) {
|
||||
$this->logger->notice($exception);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
public function getUF(DateTimeInterface $dateTime): float
|
||||
public function getUF(?DateTimeInterface $dateTime = null): float
|
||||
{
|
||||
try {
|
||||
return $this->getProvider('uf')->get(MiIndicador::UF, $dateTime);
|
||||
} catch (EmptyResponse) {
|
||||
return 0;
|
||||
$providers = $this->getProviders('uf');
|
||||
foreach ($providers as $provider) {
|
||||
try {
|
||||
return $provider->get(self::UF, $dateTime);
|
||||
} catch (EmptyResponse $exception) {
|
||||
$this->logger->notice($exception);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
public function getIPC(DateTimeInterface $start, DateTimeInterface $end): float
|
||||
{
|
||||
if ($start >= $end) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
return $this->getProvider('ipc')->getVar($start, $end);
|
||||
} catch (EmptyResponse) {
|
||||
return 0;
|
||||
$providers = $this->getProviders('ipc');
|
||||
foreach ($providers as $provider) {
|
||||
try {
|
||||
return $provider->getVar($start, $end);
|
||||
} catch (EmptyResponse $exception) {
|
||||
$this->logger->notice($exception);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
public function getUSD(DateTimeInterface $dateTime): float
|
||||
{
|
||||
try {
|
||||
return $this->getProvider('usd')->get(MiIndicador::USD, $dateTime);
|
||||
} catch (EmptyResponse $exception) {
|
||||
$this->logger->critical($exception);
|
||||
return 0;
|
||||
$providers = $this->getProviders('usd');
|
||||
foreach ($providers as $provider) {
|
||||
try {
|
||||
return $provider->get(self::USD, $dateTime);
|
||||
} catch (EmptyResponse $exception) {
|
||||
$this->logger->notice($exception);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static function getSymbol(string $identifier): string
|
||||
{
|
||||
$upper = strtoupper($identifier);
|
||||
$output = '';
|
||||
eval("\$output = self::{$upper};");
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
@ -5,8 +5,8 @@ use Exception;
|
||||
use DateTimeInterface;
|
||||
use DateTimeImmutable;
|
||||
use DateInterval;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use Psr\Http\Client\ClientInterface;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use Incoviba\Common\Implement\Exception\EmptyResponse;
|
||||
use Incoviba\Common\Define\Money\Provider;
|
||||
|
||||
@ -19,8 +19,11 @@ class Ine implements Provider
|
||||
* @throws EmptyResponse
|
||||
* @throws Exception
|
||||
*/
|
||||
public function get(string $money_symbol, DateTimeInterface $dateTime): float
|
||||
public function get(string $money_symbol, ?DateTimeInterface $dateTime = null): float
|
||||
{
|
||||
if ($dateTime === null) {
|
||||
$dateTime = new DateTimeImmutable();
|
||||
}
|
||||
$end = new DateTimeImmutable($dateTime->format('Y-m-1'));
|
||||
$start = $end->sub(new DateInterval('P1M'));
|
||||
return $this->getVar($start, $end);
|
||||
@ -42,9 +45,6 @@ class Ine implements Provider
|
||||
$request_uri = implode('?', [
|
||||
$this->uri,
|
||||
http_build_query($request_query),
|
||||
/*implode('&', array_map(function($val, $key) {
|
||||
return "{$key}={$val}";
|
||||
}, $request_query, array_keys($request_query)))*/
|
||||
]);
|
||||
try {
|
||||
$response = $this->client->get($request_uri);
|
||||
|
@ -9,18 +9,17 @@ use Incoviba\Common\Implement\Exception\EmptyResponse;
|
||||
|
||||
class MiIndicador implements Provider
|
||||
{
|
||||
const UF = 'uf';
|
||||
const IPC = 'ipc';
|
||||
const USD = 'dolar';
|
||||
|
||||
public function __construct(protected ClientInterface $client) {}
|
||||
|
||||
/**
|
||||
* @throws EmptyResponse
|
||||
*/
|
||||
public function get(string $money_symbol, DateTimeInterface $dateTime): float
|
||||
public function get(string $money_symbol, ?DateTimeInterface $dateTime = null): float
|
||||
{
|
||||
$request_uri = "{$money_symbol}/{$dateTime->format('d-m-Y')}";
|
||||
$request_uri = "{$money_symbol}";
|
||||
if ($dateTime !== null) {
|
||||
$request_uri = "{$money_symbol}/{$dateTime->format('d-m-Y')}";
|
||||
}
|
||||
try {
|
||||
$response = $this->client->get($request_uri);
|
||||
} catch (GuzzleException) {
|
||||
@ -39,11 +38,4 @@ class MiIndicador implements Provider
|
||||
}
|
||||
return $json->serie[0]->valor;
|
||||
}
|
||||
public static function getSymbol(string $identifier): string
|
||||
{
|
||||
$upper = strtoupper($identifier);
|
||||
$output = '';
|
||||
eval("\$output = self::{$upper};");
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
144
app/src/Service/Money/SII.php
Normal file
144
app/src/Service/Money/SII.php
Normal file
@ -0,0 +1,144 @@
|
||||
<?php
|
||||
namespace Incoviba\Service\Money;
|
||||
|
||||
use DateTimeInterface;
|
||||
use DateTimeImmutable;
|
||||
use PDO;
|
||||
use PDOException;
|
||||
use Psr\Http\Client\ClientInterface;
|
||||
use Dom\HTMLDocument;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use Incoviba\Common\Implement\Exception\EmptyResponse;
|
||||
use Incoviba\Common\Define;
|
||||
use Incoviba\Repository;
|
||||
use Incoviba\Service;
|
||||
|
||||
class SII implements Define\Money\Provider
|
||||
{
|
||||
public function __construct(protected ClientInterface $client,
|
||||
protected Repository\UF $ufRepository) {}
|
||||
|
||||
public function get(string $money_symbol, ?DateTimeInterface $dateTime = null): float
|
||||
{
|
||||
if ($money_symbol === Service\Money::UF) {
|
||||
return $this->getUF($dateTime);
|
||||
}
|
||||
$class = __CLASS__;
|
||||
throw new EmptyResponse("{$money_symbol} not found in {$class}");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DateTimeInterface|null $dateTime
|
||||
* @return float
|
||||
* @throws EmptyResponse
|
||||
*/
|
||||
protected function getUF(?DateTimeInterface $dateTime = null): float
|
||||
{
|
||||
if ($dateTime === null) {
|
||||
$dateTime = new DateTimeImmutable();
|
||||
}
|
||||
$year = $this->getUFYear($dateTime);
|
||||
|
||||
if (!isset($year[$dateTime->format('Y-m-d')])) {
|
||||
throw new EmptyResponse("{$dateTime->format('Y-m-d')} not found");
|
||||
}
|
||||
return $year[$dateTime->format('Y-m-d')];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DateTimeImmutable|null $dateTime
|
||||
* @return array
|
||||
* @throws EmptyResponse
|
||||
*/
|
||||
protected function getUFYear(?DateTimeImmutable $dateTime = null): array
|
||||
{
|
||||
if ($dateTime === null) {
|
||||
$dateTime = new DateTimeImmutable();
|
||||
}
|
||||
if ($dateTime->format('Y') > (new DateTimeImmutable())->format('Y')) {
|
||||
throw new EmptyResponse("{$dateTime->format('Y')} not found");
|
||||
}
|
||||
$request_uri = "uf/uf{$dateTime->format('Y')}.htm";
|
||||
try {
|
||||
$response = $this->client->get($request_uri);
|
||||
} catch (GuzzleException) {
|
||||
throw new EmptyResponse($request_uri);
|
||||
}
|
||||
if ((int) floor($response->getStatusCode() / 100) !== 2) {
|
||||
throw new EmptyResponse($request_uri);
|
||||
}
|
||||
$body = $response->getBody();
|
||||
$contents = $body->getContents();
|
||||
if (trim($contents) === '') {
|
||||
throw new EmptyResponse($request_uri);
|
||||
}
|
||||
$domHandler = HTMLDocument::createFromString($contents);
|
||||
$table = $domHandler->querySelector('div#mes_all');
|
||||
$tbody = $table->querySelector('tbody');
|
||||
$trs = $tbody->querySelectorAll('tr');
|
||||
/**
|
||||
* [th Dia, th Ene, Feb, Mar, Abr, May, Jun, Jul, Ago, Sep, Oct, Nov, Dic]
|
||||
* [th 1, td #, #, #, #, #, #, #, #, #, #, #, #]
|
||||
*/
|
||||
$year = [];
|
||||
$trim = mb_chr(160);
|
||||
foreach ($trs as $i => $tr) {
|
||||
$tds = $tr->querySelectorAll('td');
|
||||
foreach ($tds as $j => $td) {
|
||||
$value = $td->textContent;
|
||||
if (trim($value, "{$trim} ") === '') {
|
||||
continue;
|
||||
}
|
||||
$m = str_pad($j + 1, 2, '0', STR_PAD_LEFT);
|
||||
$d = str_pad($i + 1, 2, '0', STR_PAD_LEFT);
|
||||
$date = "{$dateTime->format('Y')}-{$m}-{$d}";
|
||||
$value = $this->clean($value);
|
||||
$year[$date] = $value;
|
||||
}
|
||||
}
|
||||
$this->saveUFs($year);
|
||||
return $year;
|
||||
}
|
||||
protected function saveUFs(array $ufs): void
|
||||
{
|
||||
$dates = array_keys($ufs);
|
||||
$dateString = "'" . implode("', '", $dates) . "'";
|
||||
|
||||
$query1 = $this->ufRepository->getConnection()->getQueryBuilder()
|
||||
->select('DISTINCT fecha')
|
||||
->from($this->ufRepository->getTable())
|
||||
->where("fecha IN ({$dateString})");
|
||||
try {
|
||||
$statement = $this->ufRepository->getConnection()->query($query1);
|
||||
$results = $statement->fetchAll(PDO::FETCH_ASSOC);
|
||||
foreach ($results as $row) {
|
||||
if (isset($ufs[$row['fecha']])) {
|
||||
unset($ufs[$row['fecha']]);
|
||||
}
|
||||
}
|
||||
} catch (PDOException) {
|
||||
return;
|
||||
}
|
||||
$values = [];
|
||||
foreach ($ufs as $fecha => $value) {
|
||||
$values []= [$fecha, $value];
|
||||
}
|
||||
$valueString = implode(', ', array_fill(0, count($values), '(?, ?)'));
|
||||
$query2 = "INSERT INTO {$this->ufRepository->getTable()} (fecha, valor) VALUES {$valueString}";
|
||||
$this->ufRepository->getConnection()->getPDO()->beginTransaction();
|
||||
try {
|
||||
$this->ufRepository->getConnection()->execute($query2, $values);
|
||||
if ($this->ufRepository->getConnection()->getPDO()->inTransaction()) {
|
||||
$this->ufRepository->getConnection()->getPDO()->commit();
|
||||
}
|
||||
} catch (PDOException) {
|
||||
if ($this->ufRepository->getConnection()->getPDO()->inTransaction()) {
|
||||
$this->ufRepository->getConnection()->getPDO()->rollBack();
|
||||
}
|
||||
}
|
||||
}
|
||||
protected function clean(string $value): float
|
||||
{
|
||||
return trim(str_replace(',', '.', str_replace(['.', '$'], '', $value)));
|
||||
}
|
||||
}
|
@ -1,12 +1,14 @@
|
||||
<?php
|
||||
namespace Incoviba\Service;
|
||||
|
||||
use PDOException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Incoviba\Common\Ideal;
|
||||
use Incoviba\Common\Implement;
|
||||
use Incoviba\Exception\ServiceAction\Create;
|
||||
use Incoviba\Exception\ServiceAction\Read;
|
||||
use Incoviba\Model;
|
||||
use Incoviba\Repository;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class Persona extends Ideal\Service
|
||||
{
|
||||
@ -18,19 +20,42 @@ class Persona extends Ideal\Service
|
||||
parent::__construct($logger);
|
||||
}
|
||||
|
||||
public function getAll(null|string|array $orderBy = null): array
|
||||
{
|
||||
try {
|
||||
try {
|
||||
$ruts = $this->personaRepository->fetchMissing();
|
||||
$this->addMissingPropietarios($ruts);
|
||||
} catch (Implement\Exception\EmptyResult | Read | Create) {}
|
||||
return array_map([$this, 'process'], $this->personaRepository->fetchAll($orderBy));
|
||||
} catch (Implement\Exception\EmptyResult) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param int $rut
|
||||
* @return Model\Persona
|
||||
* @throws Read
|
||||
* @throws Read|Create
|
||||
*/
|
||||
public function getById(int $rut): Model\Persona
|
||||
{
|
||||
try {
|
||||
return $this->process($this->personaRepository->fetchById($rut));
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Read(__CLASS__, $exception);
|
||||
} catch (Implement\Exception\EmptyResult) {
|
||||
try {
|
||||
$this->propietarioRepository->fetchById($rut);
|
||||
return $this->add(compact('rut'));
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Read(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return Model\Persona
|
||||
* @throws Create
|
||||
*/
|
||||
public function add(array $data): Model\Persona
|
||||
{
|
||||
try {
|
||||
@ -38,13 +63,20 @@ class Persona extends Ideal\Service
|
||||
} catch (Implement\Exception\EmptyResult) {
|
||||
try {
|
||||
$propietario = $this->propietarioRepository->fetchById($data['rut']);
|
||||
$data['nombres'] = $propietario->nombres;
|
||||
$data['apellido_paterno'] = $propietario->apellidos['paterno'];
|
||||
$data['apellido_materno'] = $propietario->apellidos['materno'];
|
||||
$data['direccion_id'] = $propietario->datos->direccion->id;
|
||||
} catch (Implement\Exception\EmptyResult) {}
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Create(__CLASS__, $exception);
|
||||
}
|
||||
$data['rut'] = $propietario->rut;
|
||||
$data['digito'] = $propietario->dv;
|
||||
$data['nombres'] = $propietario->nombres;
|
||||
$data['apellido_paterno'] = $propietario->apellidos['paterno'];
|
||||
$data['apellido_materno'] = $propietario->apellidos['materno'] ?? '';
|
||||
$persona = $this->personaRepository->create($data);
|
||||
$persona = $this->personaRepository->save($persona);
|
||||
try {
|
||||
$persona = $this->personaRepository->save($persona);
|
||||
} catch (PDOException $exception) {
|
||||
throw new Create(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
if (isset($data['direccion_id']) or isset($data['email']) or isset($data['telefono'])) {
|
||||
$datosData = ['persona_rut' => $persona->rut];
|
||||
@ -62,11 +94,69 @@ class Persona extends Ideal\Service
|
||||
$this->datosPersonaRepository->edit($datos, $data);
|
||||
} catch (Implement\Exception\EmptyResult) {
|
||||
$datos = $this->datosPersonaRepository->create($datosData);
|
||||
$this->datosPersonaRepository->save($datos);
|
||||
try {
|
||||
$this->datosPersonaRepository->save($datos);
|
||||
} catch (PDOException $exception) {
|
||||
throw new Create(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->process($persona);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $ruts
|
||||
* @param bool $load
|
||||
* @return array|null
|
||||
* @throws Create
|
||||
* @throws Read
|
||||
*/
|
||||
public function addMissingPropietarios(array $ruts, bool $load = false): ?array
|
||||
{
|
||||
try {
|
||||
$propietarios = $this->propietarioRepository->fetchByRuts($ruts);
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Read(__CLASS__, $exception);
|
||||
}
|
||||
$data = [];
|
||||
$datos = [];
|
||||
foreach ($propietarios as $propietario) {
|
||||
$data []= [
|
||||
'rut' => $propietario->rut,
|
||||
'digito' => $propietario->dv,
|
||||
'nombres' => $propietario->nombres,
|
||||
'apellido_paterno' => $propietario->apellidos['paterno'],
|
||||
'apellido_materno' => $propietario->apellidos['materno'] ?? '',
|
||||
];
|
||||
$datos []= [
|
||||
'persona_rut' => $propietario->rut,
|
||||
'direccion_id' => $propietario->datos?->direccion_id,
|
||||
'email' => $propietario->datos?->email,
|
||||
'telefono' => $propietario->datos?->telefono,
|
||||
];
|
||||
}
|
||||
|
||||
try {
|
||||
$personas = $this->personaRepository->saveMissing($data);
|
||||
} catch (PDOException|Implement\Exception\EmptyResult $exception) {
|
||||
throw new Create(__CLASS__, $exception);
|
||||
}
|
||||
$personasRuts = array_map(function(Model\Persona $persona) {
|
||||
return $persona->rut;
|
||||
}, $personas);
|
||||
$datos = array_filter($datos, function($row) use ($personasRuts) {
|
||||
return in_array($row['persona_rut'], $personasRuts);
|
||||
});
|
||||
try {
|
||||
$this->datosPersonaRepository->saveMissing($datos);
|
||||
} catch (PDOException $exception) {
|
||||
throw new Create(__CLASS__, $exception);
|
||||
}
|
||||
if ($load) {
|
||||
return array_map([$this, 'process'], $personas);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public function edit(Model\Persona $persona, array $data): Model\Persona
|
||||
{
|
||||
$filteredData = $this->personaRepository->filterData($data);
|
||||
|
@ -11,14 +11,33 @@ class Proyecto
|
||||
protected Repository\Proyecto $proyectoRepository,
|
||||
protected Repository\Proyecto\EstadoProyecto $estadoProyecto
|
||||
) {}
|
||||
public function getVendibles(): array
|
||||
|
||||
/**
|
||||
* @param string|array|null $orderBy
|
||||
* @return array
|
||||
*/
|
||||
public function getAll(null|string|array $orderBy = null): array
|
||||
{
|
||||
return $this->proyectoRepository->fetchAllActive();
|
||||
try {
|
||||
return array_map([$this, 'process'], $this->proyectoRepository->fetchAll($orderBy));
|
||||
} catch (Implement\Exception\EmptyResult) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
public function getVendibles(null|string|array $orderBy = null): array
|
||||
{
|
||||
return $this->proyectoRepository->fetchAllActive($orderBy);
|
||||
}
|
||||
public function getEscriturando(): array
|
||||
{
|
||||
return $this->proyectoRepository->fetchAllEscriturando();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $proyecto_id
|
||||
* @return Model\Proyecto
|
||||
* @throws Implement\Exception\EmptyResult
|
||||
*/
|
||||
public function getById(int $proyecto_id): Model\Proyecto
|
||||
{
|
||||
return $this->process($this->proyectoRepository->fetchById($proyecto_id));
|
||||
|
210
app/src/Service/Proyecto/Broker.php
Normal file
210
app/src/Service/Proyecto/Broker.php
Normal file
@ -0,0 +1,210 @@
|
||||
<?php
|
||||
namespace Incoviba\Service\Proyecto;
|
||||
|
||||
use PDOException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Incoviba\Common\Ideal;
|
||||
use Incoviba\Common\Implement\Exception\EmptyResult;
|
||||
use Incoviba\Common\Implement\Repository\Factory;
|
||||
use Incoviba\Exception\ServiceAction;
|
||||
use Incoviba\Model;
|
||||
use Incoviba\Repository;
|
||||
use Incoviba\Service;
|
||||
|
||||
class Broker extends Ideal\Service
|
||||
{
|
||||
public function __construct(LoggerInterface $logger,
|
||||
protected Repository\Proyecto\Broker $brokerRepository,
|
||||
protected Repository\Proyecto\Broker\Data $dataRepository,
|
||||
protected Repository\Proyecto\Broker\Contact $contactRepository,
|
||||
protected Repository\Proyecto\Broker\Contract $contractRepository,
|
||||
protected Service\Proyecto\Broker\Contract $contractService)
|
||||
{
|
||||
parent::__construct($logger);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return Model\Proyecto\Broker
|
||||
* @throws ServiceAction\Create
|
||||
*/
|
||||
public function add(array $data): Model\Proyecto\Broker
|
||||
{
|
||||
try {
|
||||
$broker = $this->brokerRepository->fetchById($data['rut']);
|
||||
} catch (EmptyResult) {
|
||||
$filteredData = $this->brokerRepository->filterData($data);
|
||||
try {
|
||||
$broker = $this->brokerRepository->create($filteredData);
|
||||
$broker = $this->brokerRepository->save($broker);
|
||||
} catch (PDOException $exception) {
|
||||
throw new ServiceAction\Create(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
$this->addData($broker, $data);
|
||||
return $this->process($broker);
|
||||
}
|
||||
/**
|
||||
* @param int $id
|
||||
* @return Model\Proyecto\Broker
|
||||
* @throws ServiceAction\Read
|
||||
*/
|
||||
public function get(int $id): Model\Proyecto\Broker
|
||||
{
|
||||
try {
|
||||
return $this->process($this->brokerRepository->fetchById($id));
|
||||
} catch (EmptyResult $exception) {
|
||||
throw new ServiceAction\Read(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param null|string|array $orderBy
|
||||
* @return array
|
||||
*/
|
||||
public function getAll(null|string|array $orderBy = null): array
|
||||
{
|
||||
try {
|
||||
return array_map([$this, 'process'], $this->brokerRepository->fetchAll($orderBy));
|
||||
} catch (EmptyResult) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param array $data
|
||||
* @return Model\Proyecto\Broker
|
||||
* @throws ServiceAction\Update
|
||||
*/
|
||||
public function edit(array $data): Model\Proyecto\Broker
|
||||
{
|
||||
try {
|
||||
$broker = $this->brokerRepository->fetchById($data['rut']);
|
||||
} catch (EmptyResult $exception) {
|
||||
throw new ServiceAction\Update(__CLASS__, $exception);
|
||||
}
|
||||
$filteredData = $this->brokerRepository->filterData($data);
|
||||
try {
|
||||
$broker = $this->brokerRepository->edit($broker, $filteredData);
|
||||
$this->editData($broker, $data);
|
||||
} catch (PDOException | EmptyResult) {
|
||||
} finally {
|
||||
return $this->process($broker);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param int $broker_rut
|
||||
* @return Model\Proyecto\Broker
|
||||
* @throws ServiceAction\Delete
|
||||
*/
|
||||
public function delete(int $broker_rut): Model\Proyecto\Broker
|
||||
{
|
||||
try {
|
||||
$broker = $this->brokerRepository->fetchById($broker_rut);
|
||||
} catch (EmptyResult $exception) {
|
||||
throw new ServiceAction\Delete(__CLASS__, $exception);
|
||||
}
|
||||
try {
|
||||
$this->brokerRepository->remove($broker);
|
||||
} catch (PDOException $exception) {
|
||||
throw new ServiceAction\Delete(__CLASS__, $exception);
|
||||
} finally {
|
||||
return $broker;
|
||||
}
|
||||
}
|
||||
|
||||
protected function process(Model\Proyecto\Broker $broker): Model\Proyecto\Broker
|
||||
{
|
||||
$broker->addFactory('data', (new Factory())
|
||||
->setArgs(['broker_rut' => $broker->rut])
|
||||
->setCallable([$this->dataRepository, 'fetchByBroker']))
|
||||
->addFactory('contracts', (new Factory())
|
||||
->setArgs(['broker_rut' => $broker->rut])
|
||||
->setCallable([$this->contractService, 'getByBroker']));
|
||||
|
||||
return $broker;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model\Proyecto\Broker $broker
|
||||
* @param array $data
|
||||
* @return Model\Proyecto\Broker\Data
|
||||
* @throws ServiceAction\Create
|
||||
*/
|
||||
protected function addData(Model\Proyecto\Broker $broker, array $data): Model\Proyecto\Broker\Data
|
||||
{
|
||||
$data['broker_rut'] = $broker->rut;
|
||||
$filteredData = $this->dataRepository->filterData($data);
|
||||
if (isset($data['contact'])) {
|
||||
try {
|
||||
$representative = $this->contactRepository->fetchByName($data['contact']);
|
||||
$filteredData['representative_id'] = $representative->id;
|
||||
} catch (EmptyResult) {
|
||||
$representativeData = $this->contactRepository->filterData($data);
|
||||
$representativeData['name'] = $data['contact'];
|
||||
$representative = $this->contactRepository->create($representativeData);
|
||||
try {
|
||||
$representative = $this->contactRepository->save($representative);
|
||||
$filteredData['representative_id'] = $representative->id;
|
||||
} catch (PDOException) {
|
||||
unset($representative);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($filteredData['representative_id'])) {
|
||||
try {
|
||||
$this->contactRepository->fetchById($filteredData['representative_id']);
|
||||
} catch (EmptyResult) {
|
||||
unset($filteredData['representative_id']);
|
||||
}
|
||||
}
|
||||
try {
|
||||
$brokerData = $this->dataRepository->fetchByBroker($broker->rut);
|
||||
return $this->dataRepository->edit($brokerData, $filteredData);
|
||||
} catch (EmptyResult) {}
|
||||
try {
|
||||
$brokerData = $this->dataRepository->create($filteredData);
|
||||
return $this->dataRepository->save($brokerData);
|
||||
} catch (PDOException $exception) {
|
||||
throw new ServiceAction\Create(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model\Proyecto\Broker $broker
|
||||
* @param array $data
|
||||
* @return Model\Proyecto\Broker\Data
|
||||
* @throws ServiceAction\Update
|
||||
*/
|
||||
protected function editData(Model\Proyecto\Broker $broker, array $data): Model\Proyecto\Broker\Data
|
||||
{
|
||||
try {
|
||||
$brokerData = $this->dataRepository->fetchByBroker($broker->rut);
|
||||
} catch (EmptyResult $exception) {
|
||||
throw new ServiceAction\Update(__CLASS__, $exception);
|
||||
}
|
||||
if (isset($data['contact'])) {
|
||||
try {
|
||||
$representative = $this->contactRepository->fetchByName($data['contact']);
|
||||
$data['representative_id'] = $representative->id;
|
||||
} catch (EmptyResult) {
|
||||
$representativeData = $this->contactRepository->filterData($data);
|
||||
$representativeData['name'] = $data['contact'];
|
||||
try {
|
||||
$representative = $this->contactRepository->create($representativeData);
|
||||
$representative = $this->contactRepository->save($representative);
|
||||
$data['representative_id'] = $representative->id;
|
||||
} catch (PDOException) {
|
||||
unset($representative);
|
||||
unset($data['contact']);
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
$data['broker_rut'] = $broker->rut;
|
||||
$filteredData = $this->dataRepository->filterData($data);
|
||||
$brokerData = $this->dataRepository->edit($brokerData, $filteredData);
|
||||
return $this->dataRepository->save($brokerData);
|
||||
} catch (PDOException | EmptyResult) {
|
||||
return $brokerData;
|
||||
}
|
||||
}
|
||||
}
|
154
app/src/Service/Proyecto/Broker/Contract.php
Normal file
154
app/src/Service/Proyecto/Broker/Contract.php
Normal file
@ -0,0 +1,154 @@
|
||||
<?php
|
||||
namespace Incoviba\Service\Proyecto\Broker;
|
||||
|
||||
use DateTimeInterface;
|
||||
use DateTimeImmutable;
|
||||
use DateMalformedStringException;
|
||||
use PDOException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Incoviba\Common\Ideal;
|
||||
use Incoviba\Common\Implement;
|
||||
use Incoviba\Exception\ServiceAction;
|
||||
use Incoviba\Model;
|
||||
use Incoviba\Repository;
|
||||
|
||||
class Contract extends Ideal\Service
|
||||
{
|
||||
public function __construct(LoggerInterface $logger,
|
||||
protected Repository\Proyecto\Broker\Contract $contractRepository,
|
||||
protected Repository\Proyecto\Broker\Contract\State $stateRepository,
|
||||
protected Repository\Venta\Promotion $promotionRepository)
|
||||
{
|
||||
parent::__construct($logger);
|
||||
}
|
||||
|
||||
public function getAll(): array
|
||||
{
|
||||
try {
|
||||
return array_map([$this, 'process'], $this->contractRepository->fetchAll());
|
||||
} catch (Implement\Exception\EmptyResult) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $project_id
|
||||
* @return array
|
||||
* @throws ServiceAction\Read
|
||||
*/
|
||||
public function getByProject(int $project_id): array
|
||||
{
|
||||
try {
|
||||
return array_map([$this, 'process'], $this->contractRepository->fetchByProject($project_id));
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new ServiceAction\Read(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $broker_rut
|
||||
* @return array
|
||||
* @throws ServiceAction\Read
|
||||
*/
|
||||
public function getByBroker(int $broker_rut): array
|
||||
{
|
||||
try {
|
||||
return array_map([$this, 'process'], $this->contractRepository->fetchByBroker($broker_rut));
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new ServiceAction\Read(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ServiceAction\Read
|
||||
*/
|
||||
public function getById(int $id): Model\Proyecto\Broker\Contract
|
||||
{
|
||||
try {
|
||||
return $this->process($this->contractRepository->fetchById($id));
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new ServiceAction\Read(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ServiceAction\Create
|
||||
*/
|
||||
public function add(array $data): Model\Proyecto\Broker\Contract
|
||||
{
|
||||
try {
|
||||
return $this->process($this->contractRepository->fetchActiveByProjectAndBroker($data['project_id'], $data['broker_rut']));
|
||||
} catch (Implement\Exception\EmptyResult) {}
|
||||
|
||||
try {
|
||||
$filteredData = $this->contractRepository->filterData($data);
|
||||
$contract = $this->contractRepository->create($filteredData);
|
||||
$contract = $this->contractRepository->save($contract);
|
||||
$type = Model\Proyecto\Broker\Contract\State\Type::ACTIVE->value;
|
||||
$date = new DateTimeImmutable();
|
||||
if (isset($data['date'])) {
|
||||
try {
|
||||
$date = new DateTimeImmutable($data['date']);
|
||||
} catch (DateMalformedStringException) {}
|
||||
}
|
||||
$state = $this->stateRepository->create(['contract_id' => $contract->id, 'date' => $date, 'type' => $type]);
|
||||
$this->stateRepository->save($state);
|
||||
return $this->process($contract);
|
||||
} catch (PDOException $exception) {
|
||||
throw new ServiceAction\Create(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ServiceAction\Update
|
||||
*/
|
||||
public function edit(Model\Proyecto\Broker\Contract $contract, array $data): Model\Proyecto\Broker\Contract
|
||||
{
|
||||
try {
|
||||
$filteredData = $this->contractRepository->filterData($data);
|
||||
return $this->process($this->contractRepository->edit($contract, $filteredData));
|
||||
} catch (PDOException | Implement\Exception\EmptyResult) {
|
||||
throw new ServiceAction\Update(__CLASS__);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ServiceAction\Delete
|
||||
*/
|
||||
public function delete(int $id): Model\Proyecto\Broker\Contract
|
||||
{
|
||||
try {
|
||||
$contract = $this->contractRepository->fetchById($id);
|
||||
$this->contractRepository->remove($contract);
|
||||
return $contract;
|
||||
} catch (PDOException | Implement\Exception\EmptyResult $exception) {
|
||||
throw new ServiceAction\Delete(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ServiceAction\Update
|
||||
*/
|
||||
public function inactive(Model\Proyecto\Broker\Contract $contract, DateTimeInterface $date = new DateTimeImmutable()): Model\Proyecto\Broker\Contract
|
||||
{
|
||||
try {
|
||||
$type = Model\Proyecto\Broker\Contract\State\Type::INACTIVE;
|
||||
$state = $this->stateRepository->create(['contract_id' => $contract->id, 'date' => $date, 'type' => $type]);
|
||||
$this->stateRepository->save($state);
|
||||
return $this->process($contract);
|
||||
} catch (PDOException $exception) {
|
||||
throw new ServiceAction\Update(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
protected function process(Model\Proyecto\Broker\Contract $contract): Model\Proyecto\Broker\Contract
|
||||
{
|
||||
$contract->addFactory('states', (new Implement\Repository\Factory())
|
||||
->setCallable([$this->stateRepository, 'fetchByContract'])
|
||||
->setArgs(['contract_id' => $contract->id]));
|
||||
$contract->addFactory('promotions', (new Implement\Repository\Factory())
|
||||
->setCallable([$this->promotionRepository, 'fetchByContract'])
|
||||
->setArgs(['contract_id' => $contract->id]));
|
||||
return $contract;
|
||||
}
|
||||
}
|
114
app/src/Service/Queue.php
Normal file
114
app/src/Service/Queue.php
Normal file
@ -0,0 +1,114 @@
|
||||
<?php
|
||||
namespace Incoviba\Service;
|
||||
|
||||
use Exception;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Incoviba\Common\Ideal;
|
||||
use Incoviba\Exception\ServiceAction\{Create, Delete, Read, Update};
|
||||
use Incoviba\Service;
|
||||
use Incoviba\Model;
|
||||
|
||||
class Queue extends Ideal\Service
|
||||
{
|
||||
public function __construct(LoggerInterface $logger, protected Service\Job $jobService, Worker $defaultWorker,
|
||||
protected int $maxRetries = 5)
|
||||
{
|
||||
parent::__construct($logger);
|
||||
$this->register('default', $defaultWorker);
|
||||
}
|
||||
|
||||
protected array $workers;
|
||||
public function register(string $name, Worker $worker): self
|
||||
{
|
||||
$this->workers[strtolower($name)] = $worker;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function enqueue(array $configuration): bool
|
||||
{
|
||||
try {
|
||||
$this->jobService->add($configuration);
|
||||
return true;
|
||||
} catch (Create $exception) {
|
||||
$final = new Exception("Could not enqueue job", 0, $exception);
|
||||
$this->logger->warning($final);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public function push(array $configuration): bool
|
||||
{
|
||||
return $this->enqueue($configuration);
|
||||
}
|
||||
|
||||
public function runJob(Model\Job $job, ?RequestInterface $request = null): bool
|
||||
{
|
||||
$type = 'default';
|
||||
if (isset($job->configuration['type'])) {
|
||||
$type = strtolower($job->configuration['type']);
|
||||
}
|
||||
if (!isset($this->workers[$type])) {
|
||||
$type = 'default';
|
||||
}
|
||||
|
||||
$worker = $this->workers[$type];
|
||||
if (is_a($worker, Service\Worker\Request::class) and $request !== null) {
|
||||
$worker->setRequest($request);
|
||||
}
|
||||
|
||||
try {
|
||||
if (!$worker->execute($job)) {
|
||||
$this->logger->debug("Could not execute job {$job->id}");
|
||||
$job->retries++;
|
||||
$this->jobService->update($job);
|
||||
return false;
|
||||
}
|
||||
if (!$this->jobService->execute($job)) {
|
||||
$this->logger->debug("Could not remove job {$job->id}");
|
||||
return false;
|
||||
}
|
||||
} catch (Exception $exception) {
|
||||
$this->logger->warning("Could not run job {$job->id}", ['exception' => $exception]);
|
||||
$job->retries++;
|
||||
try {
|
||||
$this->jobService->update($job);
|
||||
} catch (Update $exception) {
|
||||
$this->logger->error($exception->getMessage(), ['job' => $job, 'exception' => $exception]);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public function run(?RequestInterface $request = null): bool
|
||||
{
|
||||
if (!$this->jobService->isPending()) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
$job = $this->jobService->get();
|
||||
} catch (Read $exception) {
|
||||
$this->logger->error($exception->getMessage(), ['exception' => $exception]);
|
||||
return false;
|
||||
}
|
||||
if ($job->retries >= $this->maxRetries) {
|
||||
try {
|
||||
$this->jobService->remove($job);
|
||||
} catch (Delete $exception) {
|
||||
$this->logger->error($exception->getMessage(), ['job' => $job, 'exception' => $exception]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
$this->runJob($job, $request);
|
||||
} catch (Exception) {
|
||||
$job->retries ++;
|
||||
try {
|
||||
$this->jobService->update($job);
|
||||
} catch (Update $exception) {
|
||||
$this->logger->error($exception->getMessage(), ['job' => $job, 'exception' => $exception]);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -28,7 +28,12 @@ class Redis
|
||||
public function set(string $name, mixed $value, int $expirationTTL = 60 * 60 * 24): void
|
||||
{
|
||||
try {
|
||||
$this->client->set($name, $value, 'EX', $expirationTTL);
|
||||
$resolution = 'EX';
|
||||
if ($expirationTTL === -1) {
|
||||
$resolution = null;
|
||||
$expirationTTL = null;
|
||||
}
|
||||
$this->client->set($name, $value, $resolution, $expirationTTL);
|
||||
} catch (ConnectionException) {
|
||||
return;
|
||||
}
|
||||
|
@ -3,36 +3,52 @@ namespace Incoviba\Service;
|
||||
|
||||
use DateTimeInterface;
|
||||
use DateTimeImmutable;
|
||||
use Incoviba\Common\Implement\Exception\EmptyRedis;
|
||||
use PDOException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Incoviba\Common\Implement\Exception\{EmptyRedis, EmptyResult};
|
||||
use Incoviba\Repository;
|
||||
|
||||
class UF
|
||||
{
|
||||
protected string $redisKey = 'uf';
|
||||
|
||||
public function __construct(protected Redis $redisService, protected Money $moneyService,
|
||||
protected Repository\UF $ufRepository,
|
||||
protected LoggerInterface $logger) {}
|
||||
|
||||
public function get(?DateTimeInterface $date = null): float
|
||||
{
|
||||
$today = new DateTimeImmutable();
|
||||
if ($date === null) {
|
||||
$date = new DateTimeImmutable();
|
||||
}
|
||||
$ufs = [];
|
||||
if ($date->diff($today)->days < 0) {
|
||||
return 0.0;
|
||||
}
|
||||
/**
|
||||
* 1 - Redis
|
||||
* 2 - DB
|
||||
* 3 - Fetch from web
|
||||
*/
|
||||
try {
|
||||
$ufs = json_decode($this->redisService->get($this->redisKey), JSON_OBJECT_AS_ARRAY);
|
||||
$ufs = $this->getRedisUFs();
|
||||
if (!isset($ufs[$date->format('Y-m-d')])) {
|
||||
throw new EmptyRedis($this->redisKey);
|
||||
}
|
||||
$uf = $ufs[$date->format('Y-m-d')];
|
||||
return $ufs[$date->format('Y-m-d')];
|
||||
} catch (EmptyRedis) {
|
||||
$uf = $this->moneyService->getUF($date);
|
||||
if ($uf === 0.0) {
|
||||
return 0.0;
|
||||
try {
|
||||
$model = $this->ufRepository->fetchByFecha($date);
|
||||
return $model->valor;
|
||||
} catch (EmptyResult) {
|
||||
$uf = $this->moneyService->getUF($date);
|
||||
|
||||
if ($uf === 0.0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
$this->saveUF($date, $uf);
|
||||
}
|
||||
$ufs[$date->format('Y-m-d')] = $uf;
|
||||
ksort($ufs);
|
||||
$this->redisService->set($this->redisKey, json_encode($ufs), 60 * 60 * 24 * 30);
|
||||
}
|
||||
return $uf;
|
||||
}
|
||||
@ -49,6 +65,7 @@ class UF
|
||||
if ($uf === 0.0) {
|
||||
continue;
|
||||
}
|
||||
$this->saveUF($date, $uf);
|
||||
$updated[$date->format('Y-m-d')] = $uf;
|
||||
$ufs[$date->format('Y-m-d')] = $this->moneyService->getUF($date);
|
||||
}
|
||||
@ -63,4 +80,44 @@ class UF
|
||||
$uf = $this->get($date);
|
||||
return $input * (($from === 'uf') ? $uf : 1/$uf);
|
||||
}
|
||||
protected array $redisUFs;
|
||||
public function getRedisUFs(): array
|
||||
{
|
||||
if (!isset($this->redisUFs)) {
|
||||
try {
|
||||
$this->redisUFs = json_decode($this->redisService->get($this->redisKey), JSON_OBJECT_AS_ARRAY);
|
||||
} catch (EmptyRedis) {
|
||||
$this->redisUFs = [];
|
||||
}
|
||||
}
|
||||
return $this->redisUFs;
|
||||
}
|
||||
protected function saveUF(DateTimeInterface $date, float $value): void
|
||||
{
|
||||
$this->saveUFinRedis($date, $value);
|
||||
$this->saveUFinDB($date, $value);
|
||||
}
|
||||
protected function saveUFinRedis(DateTimeInterface $date, float $value): void
|
||||
{
|
||||
$ufs = $this->redisUFs;
|
||||
|
||||
$ufs[$date->format('Y-m-d')] = $value;
|
||||
if (count($ufs) > 1) {
|
||||
ksort($ufs);
|
||||
}
|
||||
|
||||
$this->redisUFs = $ufs;
|
||||
$this->redisService->set($this->redisKey, json_encode($ufs), 60 * 60 * 24 * 30);
|
||||
}
|
||||
protected function saveUFinDB(DateTimeInterface $date, float $value): void
|
||||
{
|
||||
try {
|
||||
$this->ufRepository->fetchByFecha($date);
|
||||
} catch (EmptyResult) {
|
||||
try {
|
||||
$model = $this->ufRepository->create(['fecha' => $date->format('Y-m-d'), 'valor' => $value]);
|
||||
$this->ufRepository->save($model);
|
||||
} catch (PDOException) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ namespace Incoviba\Service;
|
||||
use DateTimeInterface;
|
||||
use DateTimeImmutable;
|
||||
use DateMalformedStringException;
|
||||
use function PHPUnit\Framework\countOf;
|
||||
|
||||
class Valor
|
||||
{
|
||||
@ -11,15 +12,22 @@ class Valor
|
||||
|
||||
public function clean(string|float|int $value): float
|
||||
{
|
||||
if ((float) $value == $value) {
|
||||
if (!is_string($value)) {
|
||||
return (float) $value;
|
||||
}
|
||||
return (float) str_replace(['.', ','], ['', '.'], $value);
|
||||
if ((int) $value == $value) {
|
||||
return (float) $value;
|
||||
}
|
||||
|
||||
if ($this->isUS($value)) {
|
||||
return $this->formatUS($value);
|
||||
}
|
||||
return $this->formatCL($value);
|
||||
}
|
||||
public function toPesos(string $value, null|string|DateTimeInterface $date = null, bool $force = false): int
|
||||
{
|
||||
$date = $this->getDateTime($date);
|
||||
if (abs((float) $value - (int) $value) > 0 or $force) {
|
||||
if ($this->inUF($value) or $force) {
|
||||
return round($value * $this->ufService->get($date));
|
||||
}
|
||||
return (int) $value;
|
||||
@ -27,7 +35,7 @@ class Valor
|
||||
public function toUF(string $value, null|string|DateTimeInterface $date = null, bool $force = false): float
|
||||
{
|
||||
$date = $this->getDateTime($date);
|
||||
if (abs((float) $value - (int) $value) > 0 and !$force) {
|
||||
if ($this->inUF($value) and !$force) {
|
||||
return (float) $value;
|
||||
}
|
||||
return $value / $this->ufService->get($date);
|
||||
@ -47,4 +55,64 @@ class Valor
|
||||
}
|
||||
return $date;
|
||||
}
|
||||
|
||||
protected function isUS(string $value): bool
|
||||
{
|
||||
/*
|
||||
* Chile
|
||||
* 1.000.000,00
|
||||
* 10000,000
|
||||
* 10,53
|
||||
* 1.000,00
|
||||
* 1.000 imposible! se asume US si # antes de . < 10
|
||||
*
|
||||
* 1,000,000.00
|
||||
* 10000.00
|
||||
* 1,000.000
|
||||
* 10.53
|
||||
* 1,000 imposible! se asume CL
|
||||
*/
|
||||
if (str_contains($value, '.')) {
|
||||
$parts = explode('.', $value);
|
||||
if (count($parts) > 2) { // 1.000.000 || 1.000.000,00
|
||||
return false;
|
||||
}
|
||||
if (strlen($parts[0]) > 3) { // 1000.000 || 1,000.000
|
||||
return true;
|
||||
}
|
||||
if (strlen($parts[1]) < 3) { // #####.00
|
||||
return true;
|
||||
}
|
||||
if (str_contains($value, ',')) {
|
||||
if (strpos($value, ',') > strpos($value, '.')) { // 1.000,000
|
||||
return false;
|
||||
}
|
||||
return true; // 1,000.000
|
||||
}
|
||||
if ((int) $parts[0] < 10) { // 1.000
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
protected function formatCL(string $value): float
|
||||
{
|
||||
return (float) str_replace(',', '.', (str_replace('.', '', $value)));
|
||||
}
|
||||
protected function formatUS(string $value): float
|
||||
{
|
||||
return (float) str_replace(',', '', $value);
|
||||
}
|
||||
protected function inUF(string|int|float $value, float $check = 10000): bool
|
||||
{
|
||||
if (!is_string($value)) {
|
||||
if ($value >= $check) { // Valor arbitrario mayor que el cual no es UF
|
||||
return false;
|
||||
}
|
||||
return is_float($value);
|
||||
}
|
||||
$cleaned = $this->clean($value);
|
||||
return round($cleaned) !== $cleaned;
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,18 @@
|
||||
<?php
|
||||
namespace Incoviba\Service;
|
||||
|
||||
use Exception;
|
||||
use DateTimeImmutable;
|
||||
use DateMalformedStringException;
|
||||
use Incoviba\Exception\ServiceAction\{Create, Read, Update};
|
||||
use Incoviba\Common\Define;
|
||||
use PDOException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Incoviba\Common\Ideal\Service;
|
||||
use Incoviba\Common\Implement;
|
||||
use Incoviba\Repository;
|
||||
use Incoviba\Model;
|
||||
|
||||
class Venta extends Service
|
||||
class Venta extends Service\Repository
|
||||
{
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
@ -30,15 +32,24 @@ class Venta extends Service
|
||||
protected Venta\BonoPie $bonoPieService,
|
||||
protected Venta\Pago $pagoService,
|
||||
protected Proyecto\Terreno $terrenoService,
|
||||
protected Money $moneyService,
|
||||
protected UF $ufService,
|
||||
protected Valor $valorService
|
||||
) {
|
||||
parent::__construct($logger);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $venta_id
|
||||
* @return Model\Venta
|
||||
* @throws Read
|
||||
*/
|
||||
public function getById(int $venta_id): Model\Venta
|
||||
{
|
||||
return $this->process($this->ventaRepository->fetchById($venta_id));
|
||||
try {
|
||||
return $this->process($this->ventaRepository->fetchById($venta_id));
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Read(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
public function getByProyecto(int $proyecto_id): array
|
||||
{
|
||||
@ -59,14 +70,55 @@ class Venta extends Service
|
||||
$venta = $this->ventaRepository->fetchByProyectoAndUnidad($proyecto_nombre, $unidad_descripcion);
|
||||
return $this->process($venta);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $unidad
|
||||
* @param string $tipo
|
||||
* @return array
|
||||
* @throws Read
|
||||
*/
|
||||
public function getByUnidad(string $unidad, string $tipo): array
|
||||
{
|
||||
$ventas = $this->ventaRepository->fetchByUnidad($unidad, $tipo);
|
||||
return array_map([$this, 'process'], $ventas);
|
||||
try {
|
||||
$ventas = $this->ventaRepository->fetchByUnidad($unidad, $tipo);
|
||||
return array_map([$this, 'process'], $ventas);
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Read(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
public function getByUnidadId(int $unidad_id): Model\Venta
|
||||
|
||||
/**
|
||||
* @param int $unidad_id
|
||||
* @return Model\Venta
|
||||
* @throws Read
|
||||
*/
|
||||
public function getActiveByUnidadId(int $unidad_id): Model\Venta
|
||||
{
|
||||
return $this->process($this->ventaRepository->fetchByUnidadId($unidad_id));
|
||||
try {
|
||||
return $this->process($this->ventaRepository->fetchActiveByUnidadId($unidad_id));
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Read(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $unidad_ids
|
||||
* @return array
|
||||
* @throws Read
|
||||
*/
|
||||
public function getActiveByUnidadIds(array $unidad_ids): array
|
||||
{
|
||||
try {
|
||||
$ventas = $this->ventaRepository->fetchActiveArrayByUnidadIds($unidad_ids);
|
||||
return array_map(function($data) {
|
||||
return [
|
||||
'unidad_id' => $data['unidad_id'],
|
||||
'venta' => $this->processSimple($data['venta'])
|
||||
];
|
||||
}, $ventas);
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Read(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
public function getByPropietario(string $propietario): array
|
||||
{
|
||||
@ -124,8 +176,35 @@ class Venta extends Service
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @throws Read
|
||||
*/
|
||||
public function getAllWithCuotaPending(): array
|
||||
{
|
||||
try {
|
||||
return array_map([$this, 'process'],$this->ventaRepository->fetchAllWithCuotaPending());
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Read(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
public function getRepository(): Define\Repository
|
||||
{
|
||||
return $this->ventaRepository;
|
||||
}
|
||||
|
||||
protected function process(Model\Venta $venta): Model\Venta
|
||||
{
|
||||
if ($venta->uf === 0.0) {
|
||||
$uf = $this->ufService->get($venta->fecha);
|
||||
if ($uf > 0.0) {
|
||||
try {
|
||||
$venta = $this->ventaRepository->edit($venta, ['uf' => $uf]);
|
||||
} catch (Implement\Exception\EmptyResult) {}
|
||||
}
|
||||
}
|
||||
|
||||
$venta->addFactory('formaPago', (new Implement\Repository\Factory())
|
||||
->setCallable([$this->formaPagoService, 'getByVenta'])
|
||||
->setArgs(['venta_id' => $venta->id]));
|
||||
@ -135,19 +214,41 @@ class Venta extends Service
|
||||
$venta->addFactory('currentEstado', (new Implement\Repository\Factory())
|
||||
->setCallable([$this->estadoVentaRepository, 'fetchCurrentByVenta'])
|
||||
->setArgs([$venta->id]));
|
||||
|
||||
return $venta;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
* @param array $venta
|
||||
* @return array
|
||||
* @throws Read
|
||||
*/
|
||||
protected function processSimple(array $venta): array
|
||||
{
|
||||
$output = $venta;
|
||||
$output['propiedad'] = $this->propiedadService->getArrayById($venta['propiedad']);
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Create|Update
|
||||
*/
|
||||
public function add(array $data): Model\Venta
|
||||
{
|
||||
$fecha = new DateTimeImmutable($data['fecha_venta']);
|
||||
$data['uf'] = $this->moneyService->getUF($fecha);
|
||||
try {
|
||||
$fecha = new DateTimeImmutable($data['fecha_venta']);
|
||||
} catch (DateMalformedStringException $exception) {
|
||||
throw new Create(__CLASS__, $exception);
|
||||
}
|
||||
$data['uf'] = $this->ufService->get($fecha);
|
||||
|
||||
$propietario = $this->addPropietario($data);
|
||||
$propiedad = $this->addPropiedad($data);
|
||||
$formaPago = $this->addFormaPago($data);
|
||||
|
||||
try {
|
||||
$formaPago = $this->addFormaPago($data);
|
||||
} catch (Create) {}
|
||||
|
||||
$venta_data = [
|
||||
'propietario' => $propietario->rut,
|
||||
'propiedad' => $propiedad->id,
|
||||
@ -156,31 +257,46 @@ class Venta extends Service
|
||||
'fecha_ingreso' => (new DateTimeImmutable())->format('Y-m-d'),
|
||||
'uf' => $data['uf']
|
||||
];
|
||||
$map = ['pie', 'subsidio', 'credito', 'bono_pie'];
|
||||
foreach ($map as $field) {
|
||||
$name = lcfirst(str_replace(' ', '', ucwords(str_replace('_', ' ', $field))));
|
||||
if (isset($formaPago->{$name})) {
|
||||
$venta_data[$field] = $formaPago->{$name}->id;
|
||||
|
||||
if (isset($formaPago)) {
|
||||
$map = ['pie', 'subsidio', 'credito', 'bono_pie'];
|
||||
foreach ($map as $field) {
|
||||
$name = lcfirst(str_replace(' ', '', ucwords(str_replace('_', ' ', $field))));
|
||||
if (isset($formaPago->{$name})) {
|
||||
$venta_data[$field] = $formaPago->{$name}->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
return $this->ventaRepository->fetchByPropietarioAndPropiedad($propietario->rut, $propiedad->id);
|
||||
} catch (Implement\Exception\EmptyResult) {
|
||||
$venta = $this->ventaRepository->create($venta_data);
|
||||
$venta->setFormaPago($formaPago);
|
||||
if (isset($formaPago)) {
|
||||
$venta->setFormaPago($formaPago);
|
||||
}
|
||||
$venta = $this->ventaRepository->save($venta);
|
||||
|
||||
$tipoEstado = $this->tipoEstadoVentaRepository->fetchByDescripcion('vigente');
|
||||
$estado = $this->estadoVentaRepository->create([
|
||||
'venta' => $venta->id,
|
||||
'estado' => $tipoEstado->id,
|
||||
'fecha' => $venta->fecha->format('Y-m-d')
|
||||
]);
|
||||
$this->estadoVentaRepository->save($estado);
|
||||
try {
|
||||
$tipoEstado = $this->tipoEstadoVentaRepository->fetchByDescripcion('vigente');
|
||||
try {
|
||||
$estado = $this->estadoVentaRepository->create([
|
||||
'venta' => $venta->id,
|
||||
'estado' => $tipoEstado->id,
|
||||
'fecha' => $venta->fecha->format('Y-m-d')
|
||||
]);
|
||||
$this->estadoVentaRepository->save($estado);
|
||||
} catch (PDOException) {}
|
||||
} catch (Implement\Exception\EmptyResult) {}
|
||||
|
||||
return $venta;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return Model\Venta\Propietario
|
||||
* @throws Create|Update
|
||||
*/
|
||||
protected function addPropietario(array $data): Model\Venta\Propietario
|
||||
{
|
||||
if (isset($data['natural_uno'])) {
|
||||
@ -191,9 +307,15 @@ class Venta extends Service
|
||||
}
|
||||
return $this->addSociedad($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return Model\Venta\Propietario
|
||||
* @throws Create
|
||||
*/
|
||||
protected function addUnPropietario(array $data): Model\Venta\Propietario
|
||||
{
|
||||
$fields = array_fill_keys([
|
||||
$fields = array_flip([
|
||||
'rut',
|
||||
'nombres',
|
||||
'apellido_paterno',
|
||||
@ -201,14 +323,22 @@ class Venta extends Service
|
||||
'calle',
|
||||
'numero',
|
||||
'extra',
|
||||
'comuna'
|
||||
], 0);
|
||||
'comuna',
|
||||
'email',
|
||||
'telefono'
|
||||
]);
|
||||
$filtered_data = array_intersect_key($data, $fields);
|
||||
return $this->propietarioService->addPropietario($filtered_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return Model\Venta\Propietario
|
||||
* @throws Create
|
||||
*/
|
||||
protected function addDosPropietarios(array $data): Model\Venta\Propietario
|
||||
{
|
||||
$fields = array_fill_keys([
|
||||
$fields = array_flip([
|
||||
'rut_otro',
|
||||
'nombres_otro',
|
||||
'apellido_paterno_otro',
|
||||
@ -216,8 +346,10 @@ class Venta extends Service
|
||||
'calle_otro',
|
||||
'numero_otro',
|
||||
'extra_otro',
|
||||
'comuna_otro'
|
||||
], 0);
|
||||
'comuna_otro',
|
||||
'email_otro',
|
||||
'telefono_otro'
|
||||
]);
|
||||
$filtered_data = array_intersect_key($data, $fields);
|
||||
$mapped_data = array_combine([
|
||||
'rut',
|
||||
@ -227,12 +359,14 @@ class Venta extends Service
|
||||
'calle',
|
||||
'numero',
|
||||
'extra',
|
||||
'comuna'
|
||||
'comuna',
|
||||
'email',
|
||||
'telefono'
|
||||
], $filtered_data);
|
||||
$otro = $this->propietarioService->addPropietario($mapped_data);
|
||||
|
||||
$data['otro'] = $otro->rut;
|
||||
$fields = array_fill_keys([
|
||||
$fields = array_flip([
|
||||
'rut',
|
||||
'nombres',
|
||||
'apellido_paterno',
|
||||
@ -241,17 +375,26 @@ class Venta extends Service
|
||||
'numero',
|
||||
'extra',
|
||||
'comuna',
|
||||
'otro'
|
||||
], 0);
|
||||
'otro',
|
||||
'email',
|
||||
'telefono'
|
||||
]);
|
||||
$filtered_data = array_intersect_key($data, $fields);
|
||||
return $this->propietarioService->addPropietario($filtered_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return Model\Venta\Propietario
|
||||
* @throws Create
|
||||
* @throws Update
|
||||
*/
|
||||
protected function addSociedad(array $data): Model\Venta\Propietario
|
||||
{
|
||||
$representante = $this->addUnPropietario($data);
|
||||
|
||||
$data['representante'] = $representante->rut;
|
||||
$fields = array_fill_keys([
|
||||
$fields = array_flip([
|
||||
'rut_sociedad',
|
||||
'razon_social',
|
||||
'calle_comercial',
|
||||
@ -259,7 +402,7 @@ class Venta extends Service
|
||||
'extra_comercial',
|
||||
'comuna_comercial',
|
||||
'representante'
|
||||
], 0);
|
||||
]);
|
||||
$filtered_data = array_intersect_key($data, $fields);
|
||||
$mapped_data = array_combine([
|
||||
'rut',
|
||||
@ -272,6 +415,12 @@ class Venta extends Service
|
||||
], $filtered_data);
|
||||
return $this->propietarioService->addSociedad($mapped_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return Model\Venta\Propiedad
|
||||
* @throws Create
|
||||
*/
|
||||
protected function addPropiedad(array $data): Model\Venta\Propiedad
|
||||
{
|
||||
$ids = array_filter($data, function($key) {
|
||||
@ -280,11 +429,33 @@ class Venta extends Service
|
||||
|
||||
return $this->propiedadService->addPropiedad($ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return Model\Venta\FormaPago
|
||||
* @throws Create
|
||||
*/
|
||||
protected function addFormaPago(array $data): Model\Venta\FormaPago
|
||||
{
|
||||
return $this->formaPagoService->add($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model\Venta $venta
|
||||
* @param array $data
|
||||
* @return Model\Venta
|
||||
* @throws Update
|
||||
*/
|
||||
public function edit(Model\Venta $venta, array $data): Model\Venta
|
||||
{
|
||||
try {
|
||||
$filteredData = $this->ventaRepository->filterData($data);
|
||||
return $this->ventaRepository->edit($venta, $filteredData);
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Update(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
protected function addEstado(Model\Venta $venta, Model\Venta\TipoEstadoVenta $tipoEstadoVenta, array $data): void
|
||||
{
|
||||
try {
|
||||
@ -366,7 +537,7 @@ class Venta extends Service
|
||||
} catch (DateMalformedStringException) {
|
||||
$fecha = new DateTimeImmutable();
|
||||
}
|
||||
$uf = $this->moneyService->getUF($fecha);
|
||||
$uf = $this->ufService->get($fecha);
|
||||
$valor = $data['valor_pago_ufs'] !== '' ? $this->valorService->clean($data['valor_pago_ufs']) * $uf : $this->valorService->clean($data['valor_pago_pesos']);
|
||||
$pagoData = [
|
||||
'valor' => $valor,
|
||||
@ -392,7 +563,7 @@ class Venta extends Service
|
||||
} catch (DateMalformedStringException) {
|
||||
$fecha = new DateTimeImmutable();
|
||||
}
|
||||
$uf = $this->moneyService->getUF($fecha);
|
||||
$uf = $this->ufService->get($fecha);
|
||||
$subsidioData = [
|
||||
'fecha_venta' => $fecha->format('Y-m-d'),
|
||||
'ahorro' => $this->valorService->clean($data['valor_ahorro']),
|
||||
@ -410,7 +581,7 @@ class Venta extends Service
|
||||
} catch (DateMalformedStringException) {
|
||||
$fecha = new DateTimeImmutable();
|
||||
}
|
||||
$uf = $this->moneyService->getUF($fecha);
|
||||
$uf = $this->ufService->get($fecha);
|
||||
$valor = $this->valorService->clean($data['valor_credito']) * $uf;
|
||||
if ($venta->formaPago()->credito === null) {
|
||||
if ($data['valor_credito'] === 0) {
|
||||
|
@ -1,12 +1,15 @@
|
||||
<?php
|
||||
namespace Incoviba\Service\Venta;
|
||||
|
||||
use DateMalformedStringException;
|
||||
use Exception;
|
||||
use DateTimeImmutable;
|
||||
use Incoviba\Common\Implement\Exception\EmptyResult;
|
||||
use Incoviba\Exception\ServiceAction\Read;
|
||||
use PDOException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Incoviba\Common\Ideal;
|
||||
use Incoviba\Common\Implement\Exception\EmptyResult;
|
||||
use Incoviba\Exception\ServiceAction\Create;
|
||||
use Incoviba\Exception\ServiceAction\Read;
|
||||
use Incoviba\Repository;
|
||||
use Incoviba\Model;
|
||||
use Incoviba\Service;
|
||||
@ -41,26 +44,44 @@ class Credito extends Ideal\Service
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
* @param array $data
|
||||
* @return Model\Venta\Credito
|
||||
* @throws Create
|
||||
*/
|
||||
public function add(array $data): Model\Venta\Credito
|
||||
{
|
||||
$fecha = new DateTimeImmutable($data['fecha']);
|
||||
try {
|
||||
$fecha = new DateTimeImmutable($data['fecha']);
|
||||
} catch (DateMalformedStringException) {
|
||||
$fecha = new DateTimeImmutable();
|
||||
}
|
||||
$uf = $this->valorService->clean($data['uf']) ?? $this->moneyService->getUF($fecha);
|
||||
$tipoPago = $this->tipoPagoRepository->fetchByDescripcion('carta de resguardo');
|
||||
try {
|
||||
$tipoPago = $this->tipoPagoRepository->fetchByDescripcion('carta de resguardo');
|
||||
} catch (EmptyResult $exception) {
|
||||
throw new Create(__CLASS__, $exception);
|
||||
}
|
||||
$valor = $this->valorService->clean($data['valor']);
|
||||
$pago = $this->pagoService->add([
|
||||
'fecha' => $fecha->format('Y-m-d'),
|
||||
'valor' => $valor * $uf,
|
||||
'valor' => round($valor * $uf),
|
||||
'uf' => $uf,
|
||||
'tipo' => $tipoPago->id
|
||||
]);
|
||||
$credito = $this->creditoRepository->create([
|
||||
'valor' => $valor,
|
||||
'fecha' => $fecha->format('Y-m-d'),
|
||||
'pago' => $pago->id
|
||||
]);
|
||||
return $this->creditoRepository->save($credito);
|
||||
try {
|
||||
$credito = $this->creditoRepository->create([
|
||||
'valor' => $valor,
|
||||
'fecha' => $fecha->format('Y-m-d'),
|
||||
'pago' => $pago->id
|
||||
]);
|
||||
} catch (EmptyResult $exception) {
|
||||
throw new Create(__CLASS__, $exception);
|
||||
}
|
||||
try {
|
||||
return $this->creditoRepository->save($credito);
|
||||
} catch (PDOException $exception) {
|
||||
throw new Create(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,12 +1,15 @@
|
||||
<?php
|
||||
namespace Incoviba\Service\Venta;
|
||||
|
||||
use PDOException;
|
||||
use DateTimeImmutable;
|
||||
use DateInterval;
|
||||
use Incoviba\Common\Implement\Exception\EmptyResult;
|
||||
use IntlDateFormatter;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Incoviba\Common\Ideal;
|
||||
use Incoviba\Common\Implement\Exception\EmptyResult;
|
||||
use Incoviba\Exception\ServiceAction\Create;
|
||||
use Incoviba\Exception\ServiceAction\Read;
|
||||
use Incoviba\Repository;
|
||||
use Incoviba\Model;
|
||||
|
||||
@ -21,6 +24,20 @@ class Cuota extends Ideal\Service
|
||||
parent::__construct($logger);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $cuota_id
|
||||
* @return Model\Venta\Cuota
|
||||
* @throws Read
|
||||
*/
|
||||
public function getById(int $cuota_id): Model\Venta\Cuota
|
||||
{
|
||||
try {
|
||||
return $this->process($this->cuotaRepository->fetchById($cuota_id));
|
||||
} catch (EmptyResult $exception) {
|
||||
throw new Read(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
public function pendientes(): array
|
||||
{
|
||||
$cuotas = $this->cuotaRepository->fetchPendientes();
|
||||
@ -92,9 +109,18 @@ class Cuota extends Ideal\Service
|
||||
return $this->cuotaRepository->fetchVigenteByPie($pie_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return Model\Venta\Cuota
|
||||
* @throws Create
|
||||
*/
|
||||
public function add(array $data): Model\Venta\Cuota
|
||||
{
|
||||
$tipoPago = $this->tipoPagoRepository->fetchByDescripcion('cheque');
|
||||
try {
|
||||
$tipoPago = $this->tipoPagoRepository->fetchByDescripcion('cheque');
|
||||
} catch (EmptyResult $exception) {
|
||||
throw new Create(__CLASS__, $exception);
|
||||
}
|
||||
$fields = array_flip([
|
||||
'fecha',
|
||||
'banco',
|
||||
@ -112,8 +138,16 @@ class Cuota extends Ideal\Service
|
||||
$mapped_data = $filtered_data;
|
||||
$mapped_data['valor_$'] = $mapped_data['valor'];
|
||||
unset($mapped_data['valor']);
|
||||
$cuota = $this->cuotaRepository->create($mapped_data);
|
||||
$this->cuotaRepository->save($cuota);
|
||||
try {
|
||||
$cuota = $this->cuotaRepository->create($mapped_data);
|
||||
return $this->cuotaRepository->save($cuota);
|
||||
} catch (PDOException $exception) {
|
||||
throw new Create(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
protected function process(Model\Venta\Cuota $cuota): Model\Venta\Cuota
|
||||
{
|
||||
return $cuota;
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,12 @@
|
||||
namespace Incoviba\Service\Venta;
|
||||
|
||||
use Error;
|
||||
use Incoviba\Exception\ServiceAction\Read;
|
||||
use Exception;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Incoviba\Common\Implement;
|
||||
use Incoviba\Common\Ideal;
|
||||
use Incoviba\Exception\ServiceAction\Create;
|
||||
use Incoviba\Exception\ServiceAction\Read;
|
||||
use Incoviba\Model;
|
||||
use Incoviba\Repository;
|
||||
use Incoviba\Service\Valor;
|
||||
@ -53,6 +55,10 @@ class FormaPago extends Ideal\Service
|
||||
return $formaPago;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return Model\Venta\FormaPago
|
||||
*/
|
||||
public function add(array $data): Model\Venta\FormaPago
|
||||
{
|
||||
$fields = [
|
||||
@ -68,6 +74,9 @@ class FormaPago extends Ideal\Service
|
||||
$method = 'add' . str_replace(' ', '', ucwords(str_replace('_', ' ', $name)));
|
||||
$obj = $this->{$method}($data);
|
||||
$forma_pago->{$name} = $obj;
|
||||
} catch (Create $exception) {
|
||||
$this->logger->warning($exception);
|
||||
continue;
|
||||
} catch (Error $error) {
|
||||
$this->logger->critical($error);
|
||||
}
|
||||
@ -76,14 +85,19 @@ class FormaPago extends Ideal\Service
|
||||
return $forma_pago;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return Model\Venta\Pie
|
||||
* @throws Create
|
||||
*/
|
||||
protected function addPie(array $data): Model\Venta\Pie
|
||||
{
|
||||
$fields = array_fill_keys([
|
||||
$fields = array_flip([
|
||||
'fecha_venta',
|
||||
'pie',
|
||||
'cuotas',
|
||||
'uf'
|
||||
], 0);
|
||||
]);
|
||||
$filtered_data = array_intersect_key($data, $fields);
|
||||
$mapped_data = array_combine([
|
||||
'fecha',
|
||||
@ -94,14 +108,20 @@ class FormaPago extends Ideal\Service
|
||||
$mapped_data['valor'] = $this->valorService->clean($mapped_data['valor']);
|
||||
return $this->pieService->add($mapped_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return Model\Venta\Subsidio
|
||||
* @throws Create
|
||||
*/
|
||||
protected function addSubsidio(array $data): Model\Venta\Subsidio
|
||||
{
|
||||
$fields = array_fill_keys([
|
||||
$fields = array_flip([
|
||||
'fecha_venta',
|
||||
'ahorro',
|
||||
'subsidio',
|
||||
'uf'
|
||||
], 0);
|
||||
]);
|
||||
$filtered_data = array_intersect_key($data, $fields);
|
||||
$mapped_data = array_combine([
|
||||
'fecha',
|
||||
@ -113,13 +133,19 @@ class FormaPago extends Ideal\Service
|
||||
$mapped_data['subsidio'] = $this->valorService->clean($mapped_data['subsidio']);
|
||||
return $this->subsidioService->add($mapped_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return Model\Venta\Credito
|
||||
* @throws Create
|
||||
*/
|
||||
protected function addCredito(array $data): Model\Venta\Credito
|
||||
{
|
||||
$fields = array_fill_keys([
|
||||
$fields = array_flip([
|
||||
'fecha_venta',
|
||||
'credito',
|
||||
'uf'
|
||||
], 0);
|
||||
]);
|
||||
$filtered_data = array_intersect_key($data, $fields);
|
||||
$mapped_data = array_combine([
|
||||
'fecha',
|
||||
@ -129,12 +155,18 @@ class FormaPago extends Ideal\Service
|
||||
$mapped_data['valor'] = $this->valorService->clean($mapped_data['valor']);
|
||||
return $this->creditoService->add($mapped_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return Model\Venta\BonoPie
|
||||
* @throws Create
|
||||
*/
|
||||
protected function addBonoPie(array $data): Model\Venta\BonoPie
|
||||
{
|
||||
$fields = array_fill_keys([
|
||||
$fields = array_flip([
|
||||
'fecha_venta',
|
||||
'bono_pie'
|
||||
], 0);
|
||||
]);
|
||||
$filtered_data = array_intersect_key($data, $fields);
|
||||
$mapped_data = array_combine([
|
||||
'fecha',
|
||||
|
214
app/src/Service/Venta/MediosPago/AbstractEndPoint.php
Normal file
214
app/src/Service/Venta/MediosPago/AbstractEndPoint.php
Normal file
@ -0,0 +1,214 @@
|
||||
<?php
|
||||
namespace Incoviba\Service\Venta\MediosPago;
|
||||
|
||||
use PDOException;
|
||||
use Psr\Http\Client\ClientExceptionInterface;
|
||||
use Psr\Http\Client\ClientInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Incoviba\Common\Define\Repository;
|
||||
use Incoviba\Common\Ideal\LoggerEnabled;
|
||||
use Incoviba\Common\Implement\Exception\{EmptyResponse, EmptyResult, HttpException};
|
||||
use Incoviba\Exception\InvalidResult;
|
||||
|
||||
abstract class AbstractEndPoint extends LoggerEnabled implements EndPoint
|
||||
{
|
||||
public function __construct(protected ClientInterface $client) {}
|
||||
|
||||
/**
|
||||
* @param ResponseInterface $response
|
||||
* @param string $request_uri
|
||||
* @param array $validStatus
|
||||
* @param array $invalidStatus
|
||||
* @return void
|
||||
* @throws EmptyResponse
|
||||
*/
|
||||
protected function validateResponse(ResponseInterface $response, string $request_uri, array $validStatus, array $invalidStatus): void
|
||||
{
|
||||
$status = $response->getStatusCode();
|
||||
$reason = $response->getReasonPhrase();
|
||||
|
||||
if (in_array($status, $invalidStatus)) {
|
||||
$contents = $response->getBody()->getContents();
|
||||
$this->logger->warning('Invalid Status', [
|
||||
'uri' => $request_uri,
|
||||
'code' => $status,
|
||||
'reason' => $reason,
|
||||
'contents' => $contents
|
||||
]);
|
||||
$exception = new HttpException("{$reason}\n{$contents}", $status);
|
||||
throw new EmptyResponse($request_uri, $exception);
|
||||
}
|
||||
if (!in_array($status, $validStatus)) {
|
||||
$contents = $response->getBody()->getContents();
|
||||
$this->logger->warning('Not Valid Status', [
|
||||
'uri' => $request_uri,
|
||||
'code' => $status,
|
||||
'reason' => $reason,
|
||||
'contents' => $contents
|
||||
]);
|
||||
$exception = new HttpException("{$reason}\n{$contents}", $status);
|
||||
throw new EmptyResponse($request_uri, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $request_uri
|
||||
* @param array $validStatus
|
||||
* @param array $invalidStatus
|
||||
* @return array
|
||||
* @throws EmptyResponse
|
||||
*/
|
||||
protected function sendGet(string $request_uri, array $validStatus, array $invalidStatus): array
|
||||
{
|
||||
try {
|
||||
$response = $this->client->get($request_uri);
|
||||
} catch (ClientExceptionInterface $exception) {
|
||||
throw new EmptyResponse($request_uri, $exception);
|
||||
}
|
||||
|
||||
$this->validateResponse($response, $request_uri, $validStatus, $invalidStatus);
|
||||
|
||||
return json_decode($response->getBody()->getContents(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $request_uri
|
||||
* @param array $data
|
||||
* @param array $validStatus
|
||||
* @param array $invalidStatus
|
||||
* @param string|null $accountKey
|
||||
* @return bool
|
||||
* @throws EmptyResponse
|
||||
*/
|
||||
protected function sendAdd(string $request_uri, array $data, array $validStatus, array $invalidStatus, ?string $accountKey = null): bool
|
||||
{
|
||||
$params = $this->mapParams($data);
|
||||
$this->logger->info('Send Add', ['uri' => $request_uri, 'params' => $params]);
|
||||
try {
|
||||
$options = [
|
||||
'json' => $params
|
||||
];
|
||||
if ($accountKey !== null) {
|
||||
$options['headers'] = [
|
||||
'X-Account-Key' => $accountKey
|
||||
];
|
||||
}
|
||||
$response = $this->client->post($request_uri, $options);
|
||||
} catch (ClientExceptionInterface $exception) {
|
||||
throw new EmptyResponse($request_uri, $exception);
|
||||
}
|
||||
$this->validateResponse($response, $request_uri, $validStatus, $invalidStatus);
|
||||
|
||||
$contents = $response->getBody()->getContents();
|
||||
if (trim($contents) === '') {
|
||||
$this->logger->warning("Empty contents", [
|
||||
'uri' => $request_uri,
|
||||
'data' => $data,
|
||||
'code' => $response->getStatusCode(),
|
||||
'reason' => $response->getReasonPhrase(),
|
||||
'contents' => $contents
|
||||
]);
|
||||
throw new EmptyResponse($request_uri);
|
||||
}
|
||||
$json = json_decode($contents, true);
|
||||
$this->logger->info('Add Response', $json);
|
||||
return $this->save($json);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $request_uri
|
||||
* @param array $data
|
||||
* @param array $validStatus
|
||||
* @param array $invalidStatus
|
||||
* @param string|null $accountKey
|
||||
* @return bool
|
||||
* @throws EmptyResponse
|
||||
*/
|
||||
protected function sendEdit(string $request_uri, array $data, array $validStatus, array $invalidStatus, ?string $accountKey = null): bool
|
||||
{
|
||||
$params = $this->mapParams($data);
|
||||
try {
|
||||
$options = [
|
||||
'json' => $params
|
||||
];
|
||||
if ($accountKey !== null) {
|
||||
$options['headers'] = [
|
||||
'X-Account-Key' => $accountKey
|
||||
];
|
||||
}
|
||||
$response = $this->client->put($request_uri, $options);
|
||||
} catch (ClientExceptionInterface $exception) {
|
||||
throw new EmptyResponse($request_uri, $exception);
|
||||
}
|
||||
|
||||
$this->validateResponse($response, $request_uri, $validStatus, $invalidStatus);
|
||||
|
||||
$contents = $response->getBody()->getContents();
|
||||
$json = json_decode($contents, true);
|
||||
return $this->save($json);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $request_uri
|
||||
* @param array $validStatus
|
||||
* @param array $invalidStatus
|
||||
* @param array|null $data
|
||||
* @return void
|
||||
* @throws EmptyResponse
|
||||
*/
|
||||
protected function sendDelete(string $request_uri, array $validStatus, array $invalidStatus, ?array $data = null): void
|
||||
{
|
||||
$this->logger->info('Send Delete', ['uri' => $request_uri]);
|
||||
try {
|
||||
$options = [];
|
||||
if ($data !== null) {
|
||||
$options = ['json' => $data];
|
||||
}
|
||||
$response = $this->client->delete($request_uri, $options);
|
||||
} catch (ClientExceptionInterface $exception) {
|
||||
throw new EmptyResponse($request_uri, $exception);
|
||||
}
|
||||
|
||||
$this->validateResponse($response, $request_uri, $validStatus, $invalidStatus);
|
||||
$this->logger->info('Delete Response', ['request_uri' => $request_uri]);
|
||||
}
|
||||
protected function doSave(Repository $repository, array $data): bool
|
||||
{
|
||||
try {
|
||||
$repository->fetchByTokuId($data['id']);
|
||||
return true;
|
||||
} catch (EmptyResult) {
|
||||
$mappedData = $this->mapSave($data);
|
||||
$filteredData = $repository->filterData($mappedData);
|
||||
$model = $repository->create($filteredData);
|
||||
try {
|
||||
$repository->save($model);
|
||||
return true;
|
||||
} catch (PDOException $exception) {
|
||||
$this->logger->warning($exception);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable $callable
|
||||
* @param string $id
|
||||
* @param string $message
|
||||
* @return array
|
||||
* @throws InvalidResult
|
||||
*/
|
||||
protected function doGetById(callable $callable, string $id, string $message): array
|
||||
{
|
||||
try {
|
||||
$model = $callable($id);
|
||||
return json_decode(json_encode($model), true);
|
||||
} catch (EmptyResult $exception) {
|
||||
throw new InvalidResult($message, 404, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
abstract public function save(array $data): bool;
|
||||
abstract protected function mapParams(array $data): array;
|
||||
abstract protected function mapSave(array $data): array;
|
||||
}
|
59
app/src/Service/Venta/MediosPago/EndPoint.php
Normal file
59
app/src/Service/Venta/MediosPago/EndPoint.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
namespace Incoviba\Service\Venta\MediosPago;
|
||||
|
||||
use Incoviba\Common\Implement\Exception\EmptyResponse;
|
||||
use Incoviba\Exception\InvalidResult;
|
||||
|
||||
interface EndPoint
|
||||
{
|
||||
/**
|
||||
* @param string $id
|
||||
* @return array
|
||||
* @throws InvalidResult
|
||||
*/
|
||||
public function getById(string $id): array;
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @return array
|
||||
* @throws InvalidResult
|
||||
*/
|
||||
public function getByExternalId(string $id): array;
|
||||
/**
|
||||
* @param string $id
|
||||
* @return array
|
||||
* @throws EmptyResponse
|
||||
*/
|
||||
public function get(string $id): array;
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param string|null $accountKey
|
||||
* @return bool
|
||||
* @throws EmptyResponse
|
||||
*/
|
||||
public function add(array $data, ?string $accountKey = null): bool;
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param array $data
|
||||
* @param string|null $accountKey
|
||||
* @return bool
|
||||
* @throws EmptyResponse
|
||||
*/
|
||||
public function edit(string $id, array $data, ?string $accountKey = null): bool;
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @return void
|
||||
* @throws EmptyResponse
|
||||
*/
|
||||
public function delete(string $id): void;
|
||||
|
||||
/**
|
||||
* @param array $skip
|
||||
* @return array
|
||||
* @throws InvalidResult
|
||||
*/
|
||||
public function reset(array $skip = []): array;
|
||||
}
|
526
app/src/Service/Venta/MediosPago/Toku.php
Normal file
526
app/src/Service/Venta/MediosPago/Toku.php
Normal file
@ -0,0 +1,526 @@
|
||||
<?php
|
||||
namespace Incoviba\Service\Venta\MediosPago;
|
||||
|
||||
use Incoviba\Common\Implement\Exception\EmptyResult;
|
||||
use InvalidArgumentException;
|
||||
use PDO;
|
||||
use PDOException;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Incoviba\Common\Define\Connection;
|
||||
use Incoviba\Common\Ideal;
|
||||
use Incoviba\Common\Implement\Exception\EmptyResponse;
|
||||
use Incoviba\Exception\InvalidResult;
|
||||
use Incoviba\Exception\ServiceAction\Read;
|
||||
use Incoviba\Model;
|
||||
use Incoviba\Model\Persona;
|
||||
use Incoviba\Model\Venta\Propietario;
|
||||
use Incoviba\Service\HMAC;
|
||||
use Incoviba\Service\Venta\MediosPago\Toku\{Customer,Subscription,Invoice};
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Throwable;
|
||||
|
||||
class Toku extends Ideal\Service
|
||||
{
|
||||
const string CUSTOMER = 'customer';
|
||||
const string SUBSCRIPTION = 'subscription';
|
||||
const string INVOICE = 'invoice';
|
||||
|
||||
protected Customer $customer;
|
||||
protected Subscription $subscription;
|
||||
protected Invoice $invoice;
|
||||
|
||||
public function __construct(LoggerInterface $logger, protected Connection $connection, protected HMAC $hmac)
|
||||
{
|
||||
parent::__construct($logger);
|
||||
}
|
||||
|
||||
public function register(string $type, EndPoint $endPoint): self
|
||||
{
|
||||
if (!in_array(strtolower($type), ['customer', 'subscription', 'invoice'])) {
|
||||
throw new InvalidArgumentException("{$type} is not a valid type of EndPoint for " . __CLASS__);
|
||||
}
|
||||
$this->{strtolower($type)} = $endPoint;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Persona|Propietario $persona
|
||||
* @return array
|
||||
* @throws InvalidResult
|
||||
*/
|
||||
public function sendPersona(Model\Persona|Model\Venta\Propietario $persona): array
|
||||
{
|
||||
$rut = implode('', [$persona->rut, strtoupper($persona->dv)]);
|
||||
try {
|
||||
return $this->customer->getById($rut);
|
||||
} catch (InvalidResult $exception) {
|
||||
$datos = $persona->datos;
|
||||
$customerData = [
|
||||
'rut' => $rut,
|
||||
'nombreCompleto' => $persona->nombreCompleto(),
|
||||
'email' => $datos?->email ?? '',
|
||||
'telefono' => $datos?->telefono ?? ''
|
||||
];
|
||||
try {
|
||||
if (!$this->customer->add($customerData)) {
|
||||
throw new InvalidResult("Could not save Customer for Persona {$rut}", 409, $exception);
|
||||
}
|
||||
} catch (EmptyResponse $exception) {
|
||||
throw new InvalidResult("Could not save Customer for Persona {$rut}", 409, $exception);
|
||||
}
|
||||
return $this->customer->getById($rut);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param Model\Venta $venta
|
||||
* @return array
|
||||
* @throws InvalidResult
|
||||
*/
|
||||
public function sendVenta(Model\Venta $venta): array
|
||||
{
|
||||
$customer = $this->sendPersona($venta->propietario());
|
||||
try {
|
||||
return $this->subscription->getById($venta->id);
|
||||
} catch (InvalidResult $exception) {
|
||||
$inmobiliaria = $venta->proyecto()->inmobiliaria();
|
||||
$accountKey = null;
|
||||
try {
|
||||
$accountKey = $this->getAccountKey($inmobiliaria->rut);
|
||||
} catch (EmptyResult) {}
|
||||
$subscriptionData = [
|
||||
'customer' => $customer['toku_id'],
|
||||
'product_id' => $venta->id,
|
||||
'venta' => $venta
|
||||
];
|
||||
try {
|
||||
if (!$this->subscription->add($subscriptionData, $accountKey)) {
|
||||
throw new InvalidResult("Could not save Subscription for Venta {$venta->id}", 409, $exception);
|
||||
}
|
||||
} catch (EmptyResponse $exception) {
|
||||
throw new InvalidResult("Could not save Subscription for Venta {$venta->id}", 409, $exception);
|
||||
}
|
||||
return $this->subscription->getById($venta->id);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param Model\Venta $venta
|
||||
* @param array $cuotas_ids
|
||||
* @return array
|
||||
* @throws InvalidResult
|
||||
*/
|
||||
public function sendCuotas(Model\Venta $venta, array $cuotas_ids = []): array
|
||||
{
|
||||
$customer = $this->sendPersona($venta->propietario());
|
||||
$subscription = $this->sendVenta($venta);
|
||||
|
||||
$customerInvoices = [];
|
||||
try {
|
||||
$customerInvoices = $this->invoice->getByCustomer($customer['toku_id']);
|
||||
$customerInvoices = array_filter($customerInvoices, function($invoiceRow) use ($subscription) {
|
||||
return $invoiceRow['subscription'] === $subscription['toku_id'];
|
||||
});
|
||||
} catch (EmptyResponse) {}
|
||||
|
||||
$inmobiliaria = $venta->proyecto()->inmobiliaria();
|
||||
$accountKey = null;
|
||||
try {
|
||||
$accountKey = $this->getAccountKey($inmobiliaria->rut);
|
||||
} catch (EmptyResult) {}
|
||||
|
||||
$invoices = [];
|
||||
$errors = [];
|
||||
foreach ($venta->formaPago()->pie->cuotas() as $cuota) {
|
||||
if (count($cuotas_ids) > 0 and !in_array($cuota->id, $cuotas_ids)) {
|
||||
continue;
|
||||
}
|
||||
if (count($customerInvoices) and in_array($cuota->id, array_column($customerInvoices, 'invoice_external_id'))) {
|
||||
$invoice = array_find($customerInvoices, function($invoiceRow) use ($cuota) {
|
||||
return $invoiceRow['invoice_external_id'] === $cuota->id;
|
||||
});
|
||||
if ($invoice !== null) {
|
||||
$invoices []= $invoice;
|
||||
$this->invoice->save($invoice);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
try {
|
||||
$invoices []= $this->invoice->getById($cuota->id);
|
||||
} catch (InvalidResult $exception) {
|
||||
try {
|
||||
$invoiceData = [
|
||||
'customer' => $customer['toku_id'],
|
||||
'product_id' => $venta->id,
|
||||
'subscription' => $subscription['toku_id'],
|
||||
'cuota' => $cuota,
|
||||
'venta' => $venta
|
||||
];
|
||||
if (!$this->invoice->add($invoiceData, $accountKey)) {
|
||||
throw new EmptyResponse("Could not add Invoice for Cuota {$cuota->id}", $exception);
|
||||
}
|
||||
$invoices []= $this->invoice->getById($cuota->id);
|
||||
} catch (EmptyResponse $exception) {
|
||||
$this->logger->warning($exception);
|
||||
$errors []= $exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count($errors) > 0) {
|
||||
$this->logger->warning("Revisar el envío de cuotas de la Venta {$venta->id}");
|
||||
}
|
||||
return $invoices;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $input
|
||||
* @return bool
|
||||
* @throws InvalidResult
|
||||
*/
|
||||
public function successEvent(array $input): bool
|
||||
{
|
||||
$validEvents = ['payment_intent.succeeded', 'payment.succeeded', 'transaction.success',
|
||||
'transaction.bulk_success', 'payment_intent.succeeded_batch'];
|
||||
if (!in_array($input['event_type'], $validEvents)) {
|
||||
$this->logger->warning("{$input['event_type']} is not a valid event");
|
||||
throw new InvalidResult("{$input['event_type']} is not a valid event", 422);
|
||||
}
|
||||
switch ($input['event_type']) {
|
||||
case 'payment_intent.succeeded_batch':
|
||||
case 'transaction.bulk_success':
|
||||
return $this->successBulk($input);
|
||||
case 'transaction.success':
|
||||
return $this->successTransaction($input);
|
||||
default:
|
||||
$paymentData = $this->mapEventData($input);
|
||||
return $this->updatePago($paymentData);
|
||||
}
|
||||
}
|
||||
public function check(bool $update = false): array
|
||||
{
|
||||
try {
|
||||
list('existingSubscriptions' => $existingSubscriptions, 'missingVentas' => $missingVentas) = $this->subscription->check();
|
||||
} catch (Read) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$queues = [];
|
||||
if (count($missingVentas) > 0) {
|
||||
foreach ($missingVentas as $venta) {
|
||||
$cuotas = $venta->formaPago()->pie->cuotas();
|
||||
if (count($cuotas) === 0) {
|
||||
continue;
|
||||
}
|
||||
$queueData = [
|
||||
'type' => 'request',
|
||||
'url' => "/api/external/toku/cuotas/{$venta->id}",
|
||||
'method' => 'post',
|
||||
'body' => ['cuotas' => array_map(function(Model\Venta\Cuota $cuota) {return $cuota->id;}, $cuotas)]
|
||||
];
|
||||
$queues []= $queueData;
|
||||
}
|
||||
}
|
||||
if ($update and count($existingSubscriptions) > 0) {
|
||||
foreach ($existingSubscriptions as $subscription) {
|
||||
$cuotas = $subscription->venta->formaPago()->pie->cuotas();
|
||||
if (count($cuotas) === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$propietario = $subscription->venta->propietario();
|
||||
try {
|
||||
$customer = $this->customer->getById($propietario->rut());
|
||||
} catch (InvalidResult) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
$editData = [
|
||||
'rut' => $customer['rut'],
|
||||
'nombreCompleto' => $propietario->nombreCompleto(),
|
||||
'email' => $propietario->datos?->email ?? '',
|
||||
'telefono' => $propietario->datos?->telefono ?? ''
|
||||
];
|
||||
$this->customer->edit($customer['toku_id'], $editData);
|
||||
} catch (EmptyResponse $exception) {
|
||||
$this->logger->warning($exception);
|
||||
}
|
||||
foreach ($cuotas as $cuota) {
|
||||
try {
|
||||
$invoice = $this->invoice->getById($cuota->id);
|
||||
$editData = [
|
||||
'customer' => $customer['toku_id'],
|
||||
'product_id' => $subscription->venta->id,
|
||||
'subscription' => $subscription->toku_id,
|
||||
'cuota' => $cuota,
|
||||
'venta' => $subscription->venta
|
||||
];
|
||||
try {
|
||||
$this->invoice->edit($invoice['toku_id'], $editData);
|
||||
} catch (EmptyResponse) {}
|
||||
} catch (InvalidResult) {
|
||||
$invoiceData = [
|
||||
'customer' => $customer['toku_id'],
|
||||
'product_id' => $subscription->venta->id,
|
||||
'subscription' => $subscription->toku_id,
|
||||
'cuota' => $cuota,
|
||||
'venta' => $subscription->venta
|
||||
];
|
||||
try {
|
||||
$this->invoice->add($invoiceData);
|
||||
} catch (EmptyResponse) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $queues;
|
||||
}
|
||||
public function reset(array $skips = []): array
|
||||
{
|
||||
$output = [];
|
||||
try {
|
||||
$output['customer'] = $this->customer->reset($skips['customer'] ?? []);
|
||||
$output['subscription'] = $this->subscription->reset($skips['subscription'] ?? []);
|
||||
$output['payments'] = $this->invoice->resetPayments();
|
||||
$output['invoice'] = $this->invoice->reset($skips['invoice'] ?? []);
|
||||
} catch (InvalidResult $exception) {
|
||||
$this->logger->warning($exception);
|
||||
return [];
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
public function queue(array $venta_ids): array
|
||||
{
|
||||
$queues = [];
|
||||
foreach ($venta_ids as $venta_id) {
|
||||
if ($this->subscription->queue($venta_id)) {
|
||||
$queues []= [
|
||||
'type' => 'request',
|
||||
'url' => "/api/external/toku/cuotas/{$venta_id}",
|
||||
'method' => 'post',
|
||||
'body' => []
|
||||
];
|
||||
}
|
||||
}
|
||||
return $queues;
|
||||
}
|
||||
|
||||
public function update(array $ids, ?string $type = null): array
|
||||
{
|
||||
if ($type === null) {
|
||||
$types = [
|
||||
'customers',
|
||||
'subscriptions',
|
||||
'invoices'
|
||||
];
|
||||
$results = [];
|
||||
foreach ($types as $type) {
|
||||
$results[$type] = $this->update($ids[$type], $type);
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
$results = [];
|
||||
switch ($type) {
|
||||
case 'subscriptions':
|
||||
try {
|
||||
$results['subscription'] = $this->subscription->update($ids);
|
||||
} catch (EmptyResult | EmptyResponse $exception) {
|
||||
$this->logger->error($exception);
|
||||
}
|
||||
break;
|
||||
case 'invoices':
|
||||
try {
|
||||
$results['invoice'] = $this->invoice->updateAll($ids);
|
||||
} catch (EmptyResult $exception) {
|
||||
$this->logger->error($exception);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ServerRequestInterface $request
|
||||
* @param array $tokenConfig
|
||||
* @return bool
|
||||
*/
|
||||
public function validateToken(ServerRequestInterface $request, array $tokenConfig): bool
|
||||
{
|
||||
if (!$request->hasHeader('User-Agent') or !str_starts_with($request->getHeaderLine('User-Agent'), 'Toku-Webhooks')) {
|
||||
return false;
|
||||
}
|
||||
if (!$request->hasHeader('X-Datadog-Tags') or !$request->hasHeader('Tracestate')) {
|
||||
return false;
|
||||
}
|
||||
if (!$request->hasHeader('Toku-Signature')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$tokuSignature = $request->getHeaderLine('Toku-Signature');
|
||||
try {
|
||||
list($timestamp, $signature) = array_map(function($elem) {
|
||||
return explode('=', $elem)[1];
|
||||
}, explode(',', $tokuSignature));
|
||||
$body = $request->getBody()->getContents();
|
||||
$json = json_decode($body, true);
|
||||
if (!is_array($json)) {
|
||||
return false;
|
||||
}
|
||||
if (!array_key_exists('id', $json)) {
|
||||
return false;
|
||||
}
|
||||
$eventId = $json['id'];
|
||||
$eventType = $json['event_type'];
|
||||
|
||||
$query = $this->connection->getQueryBuilder()
|
||||
->select('secret')
|
||||
->from('toku_webhooks')
|
||||
->where('enabled = ? AND JSON_SEARCH(events, "one", ?) IS NOT NULL');
|
||||
$params = [true, $eventType];
|
||||
$statement = $this->connection->prepare($query);
|
||||
$statement->execute($params);
|
||||
$results = $statement->fetchAll(PDO::FETCH_COLUMN);
|
||||
if (count($results) === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (array_any($results, fn($secret) => $this->hmac->validate($timestamp, $signature, $eventId, $secret))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
} catch (Throwable $throwable) {
|
||||
$this->logger->error($throwable);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $request
|
||||
* @return bool
|
||||
* @throws InvalidResult
|
||||
*/
|
||||
protected function updatePago(array $request): bool
|
||||
{
|
||||
# If $customer is not found, it will throw an exception and stop
|
||||
$customer = $this->customer->getByExternalId($request['customer']);
|
||||
$invoice = $this->invoice->getByExternalId($request['invoice']);
|
||||
|
||||
return $this->invoice->update($invoice['toku_id'], $request);
|
||||
}
|
||||
protected function successTransaction(array $input): bool
|
||||
{
|
||||
$intents = $this->mapMultiplePaymentIntentsData($input);
|
||||
$errors = [];
|
||||
foreach ($intents as $intent) {
|
||||
if (!$this->updatePago($intent)) {
|
||||
$errors []= $intent;
|
||||
}
|
||||
}
|
||||
if (array_key_exists('wallet_movements', $input)) {
|
||||
foreach ($input['wallet_movements'] as $walletMovement) {
|
||||
if (array_key_exists('type', $walletMovement) and $walletMovement['type'] === 'SURPLUS') {
|
||||
$this->logger->alert('Revisar el envío de cuotas de la Venta ' . $walletMovement['product_id']);
|
||||
}
|
||||
}
|
||||
}
|
||||
return count($errors) === 0;
|
||||
}
|
||||
/**
|
||||
* @param array $input
|
||||
* @return bool
|
||||
* @throws InvalidResult
|
||||
*/
|
||||
protected function successBulk(array $input): bool
|
||||
{
|
||||
return match($input['event_type']) {
|
||||
'payment_intent.succeeded_batch' => $this->successBulkPaymentIntent($input),
|
||||
'transaction.bulk_success' => $this->successBulkTransaction($input),
|
||||
default => false
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @param array $input
|
||||
* @return bool
|
||||
* @throws InvalidResult
|
||||
*/
|
||||
protected function successBulkTransaction(array $input): bool
|
||||
{
|
||||
$errors = [];
|
||||
foreach($input['events'] as $event) {
|
||||
$event['event_type'] = 'transaction.success';
|
||||
if (!$this->successEvent($event)) {
|
||||
$errors []= $event;
|
||||
}
|
||||
}
|
||||
return count($errors) === 0;
|
||||
}
|
||||
/**
|
||||
* @param array $input
|
||||
* @return bool
|
||||
* @throws InvalidResult
|
||||
*/
|
||||
protected function successBulkPaymentIntent(array $input): bool
|
||||
{
|
||||
$errors = [];
|
||||
foreach($input['payment_intent'] as $intent) {
|
||||
$intent['event_type'] = 'payment_intent.succeeded';
|
||||
$intent['payment_intent'] = $input['payment_intents'];
|
||||
unset($intent['payment_intents']);
|
||||
if (!$this->successEvent($intent)) {
|
||||
$errors []= $intent;
|
||||
}
|
||||
}
|
||||
return count($errors) === 0;
|
||||
}
|
||||
protected function mapEventData(array $input): array
|
||||
{
|
||||
return match ($input['event_type']) {
|
||||
'payment_intent.succeeded' => $this->mapPaymentIntentData($input),
|
||||
'payment.succeeded' => $this->mapPaymentEventData($input),
|
||||
default => [],
|
||||
};
|
||||
}
|
||||
protected function mapMultiplePaymentIntentsData(array $input): array
|
||||
{
|
||||
$output = [];
|
||||
foreach ($input['payment_intents'] as $intent) {
|
||||
$intent['transaction_date'] = $input['transaction']['transaction_date'];
|
||||
$intent['customer'] = $input['customer']['id'];
|
||||
$intent['invoice'] = $intent['id_invoice'];
|
||||
$intent['subscription'] = $intent['id_subscription'];
|
||||
$intent['cuota_id'] = $intent['invoice_external_id'];
|
||||
$o = $this->mapPaymentIntentData($intent);
|
||||
$output []= $o;
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
protected function mapPaymentEventData(array $input): array
|
||||
{
|
||||
$data = $input['payment'];
|
||||
if (!array_key_exists('amount', $data) and array_key_exists('payment_amount', $data)) {
|
||||
$data['amount'] = $data['payment_amount'];
|
||||
}
|
||||
$data['status'] = 'AUTHORIZED';
|
||||
$data['date'] = $data['payment_date'];
|
||||
return $data;
|
||||
}
|
||||
protected function mapPaymentIntentData(array $input): array
|
||||
{
|
||||
$data = $input['payment_intent'];
|
||||
$data['date'] = $data['transaction_date'];
|
||||
return $data;
|
||||
}
|
||||
protected function getAccountKey(int $sociedad_rut): string
|
||||
{
|
||||
$query = $this->connection->getQueryBuilder()
|
||||
->select('account_key')
|
||||
->from('toku_accounts')
|
||||
->where('enabled = ? AND sociedad_rut = ?');
|
||||
$params = [true, $sociedad_rut];
|
||||
try {
|
||||
$statement = $this->connection->prepare($query);
|
||||
$statement->execute($params);
|
||||
return $statement->fetchColumn();
|
||||
} catch (PDOException $exception) {
|
||||
$this->logger->error($exception);
|
||||
throw new EmptyResult($query, $exception);
|
||||
}
|
||||
}
|
||||
}
|
132
app/src/Service/Venta/MediosPago/Toku/Customer.php
Normal file
132
app/src/Service/Venta/MediosPago/Toku/Customer.php
Normal file
@ -0,0 +1,132 @@
|
||||
<?php
|
||||
namespace Incoviba\Service\Venta\MediosPago\Toku;
|
||||
|
||||
use PDOException;
|
||||
use Psr\Http\Client\ClientInterface;
|
||||
use Incoviba\Common\Implement\Exception\EmptyResponse;
|
||||
use Incoviba\Common\Implement\Exception\EmptyResult;
|
||||
use Incoviba\Repository;
|
||||
use Incoviba\Service\Venta\MediosPago\AbstractEndPoint;
|
||||
|
||||
class Customer extends AbstractEndPoint
|
||||
{
|
||||
public function __construct(ClientInterface $client,
|
||||
protected Repository\Venta\MediosPago\Toku\Customer $customerRepository)
|
||||
{
|
||||
parent::__construct($client);
|
||||
}
|
||||
|
||||
public function getById(string $id): array
|
||||
{
|
||||
return $this->doGetById([$this->customerRepository, 'fetchByRut'], $id, "No existe toku_id para Persona {$id}");
|
||||
}
|
||||
public function getByExternalId(string $id): array
|
||||
{
|
||||
return $this->doGetById([$this->customerRepository, 'fetchByTokuId'], $id, "No existe Customer para toku_id {$id}");
|
||||
}
|
||||
public function get(string $id): array
|
||||
{
|
||||
$request_uri = "/customers/{$id}";
|
||||
return $this->sendGet($request_uri, [200], [404, 422]);
|
||||
}
|
||||
public function add(array $data, ?string $accountKey = null): bool
|
||||
{
|
||||
$request_uri = "/customers";
|
||||
return $this->sendAdd($request_uri, $data, [200, 201], [400, 422], $accountKey);
|
||||
}
|
||||
public function edit(string $id, array $data, ?string $accountKey = null): bool
|
||||
{
|
||||
$request_uri = "customers/{$id}";
|
||||
return $this->sendEdit($request_uri, $data, [200], [400, 404, 422], $accountKey);
|
||||
}
|
||||
public function delete(string $id): void
|
||||
{
|
||||
$request_uri = "/customers/{$id}";
|
||||
$this->sendDelete($request_uri, [204], [404, 409]);
|
||||
}
|
||||
public function reset(array $skip = []): array
|
||||
{
|
||||
try {
|
||||
$tokuIds = $this->customerRepository->fetchAllTokuIds();
|
||||
$tokuIds = array_filter($tokuIds, function (string $tokuId) use ($skip) {
|
||||
return !in_array($tokuId, $skip);
|
||||
});
|
||||
} catch (EmptyResult $exception) {
|
||||
$this->logger->warning($exception);
|
||||
return [];
|
||||
}
|
||||
$this->logger->info('Resetando ' . count($tokuIds) . ' clientes');
|
||||
foreach ($tokuIds as $tokuId) {
|
||||
try {
|
||||
$this->delete($tokuId);
|
||||
$this->customerRepository->removeByTokuId($tokuId);
|
||||
} catch (EmptyResponse | PDOException $exception) {
|
||||
$this->logger->warning($exception, ['customer->toku_id' => $tokuId]);
|
||||
}
|
||||
}
|
||||
return $tokuIds;
|
||||
}
|
||||
|
||||
public function save(array $data): bool
|
||||
{
|
||||
return $this->doSave($this->customerRepository, $data);
|
||||
}
|
||||
protected function mapParams(array $data): array
|
||||
{
|
||||
$paramsMap = [
|
||||
'government_id' => 'rut',
|
||||
'external_id' => 'rut',
|
||||
'mail' => 'email',
|
||||
'name' => 'nombreCompleto',
|
||||
'phone_number' => 'telefono',
|
||||
'pac_mandate_id' => null,
|
||||
'default_agent' => 'contacto@incoviba.cl',
|
||||
'send_mail' => false,
|
||||
'agent_phone_number' => null,
|
||||
'rfc' => null,
|
||||
'tax_zip_code' => null,
|
||||
'fiscal_regime' => null,
|
||||
'default_receipt_type' => null,
|
||||
'secondary_emails' => null,
|
||||
'silenced_until' => null,
|
||||
'metadata' => null
|
||||
];
|
||||
|
||||
$params = [];
|
||||
foreach ($paramsMap as $key => $ref) {
|
||||
if ($ref === null) {
|
||||
continue;
|
||||
}
|
||||
if ($ref === 'telefono') {
|
||||
$value = $data[$ref];
|
||||
if ($value === '' or $value === null or $value === '0') {
|
||||
continue;
|
||||
}
|
||||
if (!str_starts_with($value, '+')) {
|
||||
$value = "+56{$value}";
|
||||
}
|
||||
$params[$key] = $value;
|
||||
continue;
|
||||
}
|
||||
if (array_key_exists($ref, $data) and $data[$ref] !== '' and $data[$ref] !== null) {
|
||||
$params[$key] = $data[$ref];
|
||||
}
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
protected function mapSave(array $data): array
|
||||
{
|
||||
$responseMap = [
|
||||
'government_id' => 'rut',
|
||||
'id' => 'toku_id'
|
||||
];
|
||||
$mappedData = [];
|
||||
foreach ($responseMap as $responseKey => $dataKey) {
|
||||
if (isset($data[$responseKey])) {
|
||||
$mappedData[$dataKey] = $data[$responseKey];
|
||||
}
|
||||
}
|
||||
return $mappedData;
|
||||
}
|
||||
}
|
335
app/src/Service/Venta/MediosPago/Toku/Invoice.php
Normal file
335
app/src/Service/Venta/MediosPago/Toku/Invoice.php
Normal file
@ -0,0 +1,335 @@
|
||||
<?php
|
||||
namespace Incoviba\Service\Venta\MediosPago\Toku;
|
||||
|
||||
use DateMalformedStringException;
|
||||
use DateTimeImmutable;
|
||||
use DateTimeZone;
|
||||
use PDO;
|
||||
use PDOException;
|
||||
use Psr\Http\Client\ClientInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Incoviba\Common\Implement\Exception\EmptyResponse;
|
||||
use Incoviba\Common\Implement\Exception\EmptyResult;
|
||||
use Incoviba\Exception\InvalidResult;
|
||||
use Incoviba\Model;
|
||||
use Incoviba\Repository;
|
||||
use Incoviba\Service\UF;
|
||||
use Incoviba\Service\Venta\MediosPago\AbstractEndPoint;
|
||||
use Incoviba\Service\Venta\Pago;
|
||||
|
||||
class Invoice extends AbstractEndPoint
|
||||
{
|
||||
public function __construct(ClientInterface $client,
|
||||
protected Repository\Venta\MediosPago\Toku\Invoice $invoiceRepository,
|
||||
protected Pago $pagoService,
|
||||
protected UF $ufService)
|
||||
{
|
||||
parent::__construct($client);
|
||||
}
|
||||
|
||||
public function getById(string $id): array
|
||||
{
|
||||
return $this->doGetById([$this->invoiceRepository, 'fetchByCuota'], $id, "No existe toku_id para Cuota {$id}");
|
||||
}
|
||||
public function getByExternalId(string $id): array
|
||||
{
|
||||
return $this->doGetById([$this->invoiceRepository, 'fetchByTokuId'], $id, "No existe Invoice para toku_id {$id}");
|
||||
}
|
||||
public function get(string $id): array
|
||||
{
|
||||
$request_uri = "/invoices/{$id}";
|
||||
return $this->sendGet($request_uri, [200], [404]);
|
||||
}
|
||||
public function add(array $data, ?string $accountKey = null): bool
|
||||
{
|
||||
$request_uri = "/invoices";
|
||||
return $this->sendAdd($request_uri, $data, [200, 201], [400, 409, 422], $accountKey);
|
||||
}
|
||||
public function edit(string $id, array $data, ?string $accountKey = null): bool
|
||||
{
|
||||
$request_uri = "/invoices/{$id}";
|
||||
return $this->sendEdit($request_uri, $data, [200], [400, 404, 409, 422], $accountKey);
|
||||
}
|
||||
public function delete(string $id): void
|
||||
{
|
||||
$request_uri = "/invoices/{$id}";
|
||||
$this->sendDelete($request_uri, [204], [404, 409]);
|
||||
}
|
||||
public function reset(array $skip = []): array
|
||||
{
|
||||
try {
|
||||
$tokuIds = $this->invoiceRepository->fetchAllTokuIds();
|
||||
$tokuIds = array_filter($tokuIds, function (string $tokuId) use ($skip) {
|
||||
return !in_array($tokuId, $skip);
|
||||
});
|
||||
} catch (EmptyResult $exception) {
|
||||
$this->logger->warning($exception);
|
||||
return [];
|
||||
}
|
||||
foreach ($tokuIds as $tokuId) {
|
||||
try {
|
||||
$this->delete($tokuId);
|
||||
$this->invoiceRepository->removeByTokuId($tokuId);
|
||||
} catch (EmptyResponse | PDOException $exception) {
|
||||
$this->logger->warning($exception, ['invoice->toku_id' => $tokuId]);
|
||||
}
|
||||
}
|
||||
return $tokuIds;
|
||||
}
|
||||
public function resetPayments(): array
|
||||
{
|
||||
$page = 1;
|
||||
$pageSize = 1000;
|
||||
$totalPayments = [];
|
||||
while (true) {
|
||||
if ($page > 100) {
|
||||
break;
|
||||
}
|
||||
try {
|
||||
$request_uri = "/organization/payments?page=1&page_size=1000";
|
||||
$payments = $this->sendGet($request_uri, [200], [404, 422]);
|
||||
} catch (EmptyResponse $exception) {
|
||||
$this->logger->warning($exception, ['request_uri' => $request_uri]);
|
||||
return [];
|
||||
}
|
||||
if (array_key_exists('message', $payments)) {
|
||||
break;
|
||||
}
|
||||
$this->altLogger->info('Reset Payments', ['count' => count($payments), 'payments' => $payments]);
|
||||
$query = [];
|
||||
/*
|
||||
"id": "pay_79zh1OU1pVV5g0V0I6kShf5AF-I24cUn",
|
||||
"created_at": "2025-06-07T07:08:51+0000",
|
||||
"deleted_at": null,
|
||||
"invoice": "in_IhbKbT21x0ADlnKRCbV57sn2DDI8neq0",
|
||||
"customer": "cus_bTXPBVopZxKOqTOWzRZkhvDEM9XXtvWh",
|
||||
"government_id": "175181431",
|
||||
"name": "Augusto Felipe Schilfferli Rojas",
|
||||
"product_id": "1304-d1749582981383358",
|
||||
"due_date": "2024-11-01",
|
||||
"transaction_date": "2025-06-07T07:08:51+0000",
|
||||
"payment_amount": 14.4822,
|
||||
"buy_order": null,
|
||||
"processed_by_toku": false,
|
||||
"payment_method": null,
|
||||
"card_type": null,
|
||||
"card_number": null,
|
||||
"payment_type": null,
|
||||
"authorization_code": null,
|
||||
"mc_order_id": null,
|
||||
"amount_paid": 14.4822
|
||||
*/
|
||||
foreach ($payments as $payment) {
|
||||
$query[] = [
|
||||
'payment_amount' => $payment['payment_amount'],
|
||||
'payment_date' => $payment['transaction_date'],
|
||||
'payment_method' => $payment['payment_method'],
|
||||
'product_id' => $payment['product_id'],
|
||||
'due_date' => $payment['due_date'],
|
||||
];
|
||||
}
|
||||
try {
|
||||
$request_uri = "/payments";
|
||||
$this->sendDelete($request_uri, [204], [404, 422], ['payments' => $query]);
|
||||
} catch (EmptyResponse $exception) {
|
||||
$this->logger->warning($exception, ['request_uri' => $request_uri]);
|
||||
return [];
|
||||
}
|
||||
$this->altLogger->info('Reset Payments Payload', ['count' => count($payments), 'payments' => $query]);
|
||||
$totalPayments = array_merge($totalPayments, $payments);
|
||||
if (count($payments) < $pageSize) {
|
||||
break;
|
||||
}
|
||||
$page++;
|
||||
}
|
||||
return $totalPayments;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $customer_id
|
||||
* @return array
|
||||
* @throws EmptyResponse
|
||||
*/
|
||||
public function getByCustomer(string $customer_id): array
|
||||
{
|
||||
$request_uri = "/invoices/customer/{$customer_id}";
|
||||
return $this->sendGet($request_uri, [200], [404]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $invoice_toku_id
|
||||
* @param array $data
|
||||
* @return bool
|
||||
* @throws InvalidResult
|
||||
*/
|
||||
public function update(string $invoice_toku_id, array $data): bool
|
||||
{
|
||||
try {
|
||||
$invoice = $this->invoiceRepository->fetchByTokuId($invoice_toku_id);
|
||||
} catch (EmptyResult $exception) {
|
||||
$this->logger->warning($exception, ['invoice_toku_id' => $invoice_toku_id, 'data' => $data]);
|
||||
throw new InvalidResult("No existe Invoice para toku_id {$invoice_toku_id}", 404, $exception);
|
||||
}
|
||||
if ($data['status'] !== 'AUTHORIZED') {
|
||||
$this->logger->warning("Pago no autorizado", ['invoice_toku_id' => $invoice_toku_id, 'data' => $data]);
|
||||
throw new InvalidResult("Pago no autorizado", 422);
|
||||
}
|
||||
$dateString = $data['date'];
|
||||
try {
|
||||
$date = new DateTimeImmutable($dateString);
|
||||
} catch (DateMalformedStringException $exception) {
|
||||
$this->logger->warning($exception, ['invoice_toku_id' => $invoice_toku_id, 'data' => $data]);
|
||||
throw new InvalidResult("Fecha no válida: {$dateString}", 422, $exception);
|
||||
}
|
||||
$uf = $this->ufService->get($date);
|
||||
if ($uf === 0.0) {
|
||||
$this->logger->warning("No hay UF para la fecha: {$dateString}", ['invoice_toku_id' => $invoice_toku_id, 'data' => $data]);
|
||||
throw new InvalidResult("No hay UF para la fecha: {$dateString}", 422);
|
||||
}
|
||||
$valor = $data['amount'];
|
||||
if ($valor > 1000) {
|
||||
$valor = $data['amount'] / $uf;
|
||||
}
|
||||
if (abs($valor - $invoice->cuota->pago->valor()) >= 0.0001) {
|
||||
$this->logger->warning("Valor en UF no coincide: {$data['amount']}, {$valor} <=> {$invoice->cuota->pago->valor()}", ['invoice_toku_id' => $invoice_toku_id, 'data' => $data]);
|
||||
throw new InvalidResult("Valor en UF no coincide: {$data['amount']}, {$valor} <=> {$invoice->cuota->pago->valor()}", 422);
|
||||
}
|
||||
if ($invoice->cuota->pago->isPagado()) {
|
||||
return true;
|
||||
}
|
||||
return $this->pagoService->depositar($invoice->cuota->pago, $date);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $idsData
|
||||
* @return array
|
||||
* @throws EmptyResult
|
||||
*/
|
||||
public function updateAll(array $idsData): array
|
||||
{
|
||||
$tokuIds = array_column($idsData, 'toku_id');
|
||||
$oldIds = array_column($idsData, 'product_id');
|
||||
|
||||
$placeholders = array_map(fn($id) => "id{$id}", array_keys($oldIds));
|
||||
$placeholdersString = implode(', ', array_map(fn($id) => ":{$id}", $placeholders));
|
||||
$query = $this->pagoService->getRepository()->getConnection()->getQueryBuilder()
|
||||
->select('pago.id, CONCAT_WS("-", unidad.descripcion, CONCAT_WS("-", propietario.rut, propietario.dv)) AS old_pid')
|
||||
->from('pago')
|
||||
->joined('JOIN cuota ON cuota.pago = pago.id')
|
||||
->joined('JOIN venta ON venta.pie = cuota.pie')
|
||||
->joined('JOIN propietario ON propietario.rut = venta.propietario')
|
||||
->joined('JOIN propiedad_unidad pu ON pu.propiedad = venta.propiedad')
|
||||
->joined('JOIN unidad ON pu.unidad = unidad.id')
|
||||
->having("old_pid IN ({$placeholdersString})");
|
||||
$values = array_combine($placeholders, $oldIds);
|
||||
try {
|
||||
$statement = $this->pagoService->getRepository()->getConnection()->execute($query, $values);
|
||||
$results = $statement->fetchAll(PDO::FETCH_ASSOC);
|
||||
} catch (PDOException $exception) {
|
||||
$this->logger->error($exception);
|
||||
throw new EmptyResult($query, $exception);
|
||||
}
|
||||
|
||||
$ids = array_column($results, 'pago.id');
|
||||
$newIds = array_combine($ids, $tokuIds);
|
||||
return array_map(fn($id) => ['product_id' => $id, 'toku_id' => $newIds[$id]], $ids);
|
||||
}
|
||||
|
||||
public function save(array $data): bool
|
||||
{
|
||||
return $this->doSave($this->invoiceRepository, $data);
|
||||
}
|
||||
|
||||
protected LoggerInterface $altLogger;
|
||||
public function setAltLogger(LoggerInterface $altLogger): self
|
||||
{
|
||||
$this->altLogger = $altLogger;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function mapParams(array $data): array
|
||||
{
|
||||
$paramsMap = [
|
||||
'customer' => 'customer',
|
||||
'product_id' => 'cuota_id',
|
||||
'due_date' => 'fecha',
|
||||
'subscription' => 'subscription',
|
||||
'amount' => 'valor',
|
||||
'is_paid' => 'isPagada',
|
||||
'is_void' => 'isRechazada',
|
||||
'link_payment' => null,
|
||||
'metadata' => 'datosCuota',
|
||||
'receipt_type' => null,
|
||||
'id_receipt' => null,
|
||||
'disable_automatic_payment' => null,
|
||||
'currency_code' => 'CLF',
|
||||
'invoice_external_id' => 'cuota_id'
|
||||
];
|
||||
|
||||
$today = new DateTimeImmutable('now', new DateTimeZone('America/Santiago'));
|
||||
|
||||
$params = [];
|
||||
foreach ($paramsMap as $key => $ref) {
|
||||
if ($ref === null) {
|
||||
continue;
|
||||
}
|
||||
if ($ref === 'fecha') {
|
||||
$params[$key] = $data['cuota']->pago->fecha->format('Y-m-d');
|
||||
continue;
|
||||
}
|
||||
if ($ref === 'valor') {
|
||||
/*$valor = 0;
|
||||
if ($data['cuota']->pago->fecha <= $today) {
|
||||
$valor = $data['cuota']->pago->valor();
|
||||
}
|
||||
if ($valor === 0) {
|
||||
$valor = $data['cuota']->pago->valor / $data['venta']->uf;
|
||||
}
|
||||
$params[$key] = $valor;*/
|
||||
$params[$key] = $data['cuota']->pago->valor;
|
||||
continue;
|
||||
}
|
||||
if ($ref === 'datosCuota') {
|
||||
$params[$key] = $this->datosCuota($data['cuota']);
|
||||
continue;
|
||||
}
|
||||
if ($ref === 'isPagada') {
|
||||
$params[$key] = $data['cuota']->isPagada();
|
||||
}
|
||||
if ($ref === 'isRechazada') {
|
||||
$params[$key] = $data['cuota']->isRechazada();
|
||||
}
|
||||
if ($ref === 'cuota_id') {
|
||||
$params[$key] = $data['cuota']->id;
|
||||
continue;
|
||||
}
|
||||
if (array_key_exists($ref, $data) and $data[$ref] !== '' and $data[$ref] !== null) {
|
||||
$params[$key] = $data[$ref];
|
||||
}
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
protected function mapSave(array $data): array
|
||||
{
|
||||
$responseMap = [
|
||||
'invoice_external_id' => 'cuota_id',
|
||||
'id' => 'toku_id'
|
||||
];
|
||||
$mappedData = [];
|
||||
foreach ($responseMap as $responseKey => $dataKey) {
|
||||
if (isset($data[$responseKey])) {
|
||||
$mappedData[$dataKey] = $data[$responseKey];
|
||||
}
|
||||
}
|
||||
return $mappedData;
|
||||
}
|
||||
|
||||
protected function datosCuota(Model\Venta\Cuota $cuota): array
|
||||
{
|
||||
return [
|
||||
'Numero' => $cuota->numero,
|
||||
'Monto_CLP' => $cuota->pago->valor
|
||||
];
|
||||
}
|
||||
}
|
302
app/src/Service/Venta/MediosPago/Toku/Subscription.php
Normal file
302
app/src/Service/Venta/MediosPago/Toku/Subscription.php
Normal file
@ -0,0 +1,302 @@
|
||||
<?php
|
||||
namespace Incoviba\Service\Venta\MediosPago\Toku;
|
||||
|
||||
use PDO;
|
||||
use PDOException;
|
||||
use Psr\Http\Client\ClientInterface;
|
||||
use Incoviba\Common\Implement\Exception\EmptyResponse;
|
||||
use Incoviba\Common\Implement\Exception\EmptyResult;
|
||||
use Incoviba\Exception\ServiceAction\Read;
|
||||
use Incoviba\Model\Venta;
|
||||
use Incoviba\Repository;
|
||||
use Incoviba\Service;
|
||||
use Incoviba\Service\Venta\MediosPago\AbstractEndPoint;
|
||||
|
||||
class Subscription extends AbstractEndPoint
|
||||
{
|
||||
public function __construct(ClientInterface $client,
|
||||
protected Repository\Venta\MediosPago\Toku\Subscription $subscriptionRepsitory,
|
||||
protected Service\Venta $ventaService)
|
||||
{
|
||||
parent::__construct($client);
|
||||
}
|
||||
|
||||
public function getById(string $id): array
|
||||
{
|
||||
return $this->doGetById([$this->subscriptionRepsitory, 'fetchByVenta'], $id, "No existe toku_id para Venta {$id}");
|
||||
}
|
||||
public function getByExternalId(string $id): array
|
||||
{
|
||||
return $this->doGetById([$this->subscriptionRepsitory, 'fetchByTokuId'], $id, "No existe Subscription para toku_id {$id}");
|
||||
}
|
||||
|
||||
public function get(string $id): array
|
||||
{
|
||||
$request_uri = "/subscriptions/{$id}";
|
||||
return $this->sendGet($request_uri, [200], [401, 404, 422]);
|
||||
}
|
||||
public function add(array $data, ?string $accountKey = null): bool
|
||||
{
|
||||
$request_uri = '/subscriptions';
|
||||
return $this->sendAdd($request_uri, $data, [200, 201], [401, 404, 409, 422], $accountKey);
|
||||
}
|
||||
public function edit(string $id, array $data, ?string $accountKey = null): bool
|
||||
{
|
||||
$request_uri = "/subscriptions/{$id}";
|
||||
return $this->sendEdit($request_uri, $data, [200], [401, 404, 409, 422], $accountKey);
|
||||
}
|
||||
public function delete(string $id): void
|
||||
{
|
||||
$request_uri = "/subscriptions/{$id}";
|
||||
$this->sendDelete($request_uri, [204], [404, 409]);
|
||||
}
|
||||
public function reset(array $skip = []): array
|
||||
{
|
||||
try {
|
||||
$tokuIds = $this->subscriptionRepsitory->fetchAllTokuIds();
|
||||
$tokuIds = array_filter($tokuIds, function (string $tokuId) use ($skip) {
|
||||
return !in_array($tokuId, $skip);
|
||||
});
|
||||
} catch (EmptyResult $exception) {
|
||||
$this->logger->warning($exception);
|
||||
return [];
|
||||
}
|
||||
foreach ($tokuIds as $tokuId) {
|
||||
try {
|
||||
$this->delete($tokuId);
|
||||
$this->subscriptionRepsitory->removeByTokuId($tokuId);
|
||||
} catch (EmptyResponse | PDOException $exception) {
|
||||
$this->logger->warning($exception, ['subscription->toku_id' => $tokuId]);
|
||||
}
|
||||
}
|
||||
return $tokuIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @throws Read
|
||||
*/
|
||||
public function check(): array
|
||||
{
|
||||
$ventas = $this->ventaService->getAllWithCuotaPending();
|
||||
$ids = array_column($ventas, 'id');
|
||||
$existingSubscriptions = [];
|
||||
try {
|
||||
$existingSubscriptions = $this->subscriptionRepsitory->fetchByVentas($ids);
|
||||
array_walk($existingSubscriptions, function(&$subscription) {
|
||||
$subscription->venta = $this->ventaService->getById($subscription->venta->id);
|
||||
});
|
||||
} catch (EmptyResult) {}
|
||||
if (count($existingSubscriptions) === 0) {
|
||||
$missingVentas = $ventas;
|
||||
} else {
|
||||
$missingVentas = array_filter($ventas, function($venta) use ($existingSubscriptions) {
|
||||
return !array_any($existingSubscriptions, fn($subscription) => $subscription->venta->id === $venta->id);
|
||||
});
|
||||
}
|
||||
return compact('existingSubscriptions', 'missingVentas');
|
||||
}
|
||||
public function queue(int $venta_id): bool
|
||||
{
|
||||
try {
|
||||
$venta = $this->ventaService->getById($venta_id);
|
||||
} catch (Read $exception) {
|
||||
$this->logger->warning($exception);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
$subscription = $this->subscriptionRepsitory->fetchByVenta($venta_id);
|
||||
return false;
|
||||
} catch (EmptyResult) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $idsData
|
||||
* @return array
|
||||
* @throws EmptyResult
|
||||
* @throws EmptyResponse
|
||||
*/
|
||||
public function update(array $idsData): array
|
||||
{
|
||||
$tokuIds = array_column($idsData, 'toku_id');
|
||||
$oldPids = array_column($idsData, 'product_id');
|
||||
|
||||
$placeholders = array_map(fn($id) => "id{$id}", array_keys($oldPids));
|
||||
$placeholdersString = implode(', ', array_map(fn($id) => ":{$id}", $placeholders));
|
||||
$query = $this->ventaService->getRepository()->getConnection()->getQueryBuilder()
|
||||
->select('venta.id, CONCAT_WS("-", unidad.descripcion, CONCAT_WS("-", propietario.rut, propietario.dv)) AS old_pid')
|
||||
->from('venta')
|
||||
->joined('JOIN propietario ON propietario.rut = venta.propietario')
|
||||
->joined('JOIN propiedad_unidad pu ON pu.propiedad = venta.propiedad')
|
||||
->joined('JOIN unidad ON pu.unidad = unidad.id')
|
||||
->having("old_pid IN ({$placeholdersString})");
|
||||
$values = array_combine($placeholders, $oldPids);
|
||||
try {
|
||||
$statement = $this->ventaService->getRepository()->getConnection()->execute($query, $values);
|
||||
$results = $statement->fetchAll(PDO::FETCH_ASSOC);
|
||||
} catch (PDOException $exception) {
|
||||
$this->logger->error($exception->getMessage(), [
|
||||
'query' => $query,
|
||||
'values' => $values,
|
||||
'ids' => $idsData,
|
||||
'exception' => $exception]);
|
||||
throw new EmptyResult($query, $exception);
|
||||
}
|
||||
|
||||
$accountKeys = $this->getAccountKey(array_column($results, 'id'));
|
||||
|
||||
$newPids = [];
|
||||
$keys = [];
|
||||
foreach ($results as $result) {
|
||||
$idx = array_search($result['old_pid'], $oldPids);
|
||||
$newPids[$idx] = $result['id'];
|
||||
if (array_key_exists($result['id'], $accountKeys)) {
|
||||
$keys[$idx] = $accountKeys[$result['id']];
|
||||
}
|
||||
}
|
||||
$output = [];
|
||||
foreach ($tokuIds as $idx => $tokuId) {
|
||||
if (!isset($newPids[$idx])) {
|
||||
continue;
|
||||
}
|
||||
$data = [
|
||||
'product_id' => $newPids[$idx],
|
||||
];
|
||||
try {
|
||||
if (!$this->edit($tokuId, $data, array_key_exists($idx, $keys) ? $keys[$idx] : null)) {
|
||||
$this->logger->error('Error while updating Toku', [
|
||||
'toku_id' => $tokuId,
|
||||
'old_pid' => $oldPids[$idx],
|
||||
'product_id' => $newPids[$idx],
|
||||
'account_key' => array_key_exists($idx, $keys) ? $keys[$idx] : null]);
|
||||
$output[] = [
|
||||
'toku_id' => $tokuId,
|
||||
'old_pid' => $oldPids[$idx],
|
||||
'product_id' => $newPids[$idx],
|
||||
'account_key' => array_key_exists($idx, $keys) ? $keys[$idx] : null,
|
||||
'error' => 'Error while updating Toku'
|
||||
];
|
||||
continue;
|
||||
}
|
||||
} catch (EmptyResponse $exception) {
|
||||
$this->logger->error($exception->getMessage(), [
|
||||
'toku_id' => $tokuId,
|
||||
'old_pid' => $oldPids[$idx],
|
||||
'product_id' => $newPids[$idx],
|
||||
'account_key' => array_key_exists($idx, $keys) ? $keys[$idx] : null,
|
||||
'exception' => $exception]);
|
||||
$output[] = [
|
||||
'toku_id' => $tokuId,
|
||||
'old_pid' => $oldPids[$idx],
|
||||
'product_id' => $newPids[$idx],
|
||||
'account_key' => array_key_exists($idx, $keys) ? $keys[$idx] : null,
|
||||
'error' => $exception->getMessage()
|
||||
];
|
||||
continue;
|
||||
}
|
||||
$output[] = [
|
||||
'toku_id' => $tokuId,
|
||||
'old_pid' => $oldPids[$idx],
|
||||
'product_id' => $newPids[$idx],
|
||||
'account_key' => array_key_exists($idx, $keys) ? $keys[$idx] : null
|
||||
];
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function save(array $data): bool
|
||||
{
|
||||
return $this->doSave($this->subscriptionRepsitory, $data);
|
||||
}
|
||||
protected function mapParams(array $data): array
|
||||
{
|
||||
$paramsMap = [
|
||||
'customer' => 'customer',
|
||||
'product_id' => 'product_id',
|
||||
'pac_mandate_id' => null,
|
||||
'is_recurring' => null,
|
||||
'due_day' => null,
|
||||
'amount' => 'pieValor',
|
||||
'receipt_product_code' => null,
|
||||
'metadata' => 'datosVenta'
|
||||
];
|
||||
|
||||
$params = [];
|
||||
foreach ($paramsMap as $key => $ref) {
|
||||
if ($ref === null) {
|
||||
continue;
|
||||
}
|
||||
if ($ref === 'pieValor' and array_key_exists('venta', $data)) {
|
||||
$params[$key] = $data['venta']?->formaPago()?->pie?->valor ?? 0;
|
||||
continue;
|
||||
}
|
||||
if ($ref === 'datosVenta' and array_key_exists('venta', $data)) {
|
||||
$params[$key] = $this->datosVenta($data['venta']);
|
||||
continue;
|
||||
}
|
||||
if (array_key_exists($ref, $data) and $data[$ref] !== '' and $data[$ref] !== null) {
|
||||
$params[$key] = $data[$ref];
|
||||
}
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
protected function mapSave(array $data): array
|
||||
{
|
||||
$responseMap = [
|
||||
'product_id' => 'venta_id',
|
||||
'id' => 'toku_id'
|
||||
];
|
||||
$mappedData = [];
|
||||
foreach ($responseMap as $responseKey => $dataKey) {
|
||||
if (isset($data[$responseKey])) {
|
||||
$mappedData[$dataKey] = $data[$responseKey];
|
||||
}
|
||||
}
|
||||
return $mappedData;
|
||||
}
|
||||
protected function datosVenta(Venta $venta): array
|
||||
{
|
||||
return [
|
||||
'Proyecto' => $venta->proyecto()->descripcion,
|
||||
'Unidades' => $venta->propiedad()->summary()
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $ventaIds
|
||||
* @return array
|
||||
* @throws EmptyResult
|
||||
*/
|
||||
protected function getAccountKey(array $ventaIds): array
|
||||
{
|
||||
$placeholders = array_map(fn($id) => "id{$id}", array_keys($ventaIds));
|
||||
$placeholdersString = implode(', ', array_map(fn($id) => ":{$id}", $placeholders));
|
||||
$query = $this->ventaService->getRepository()->getConnection()->getQueryBuilder()
|
||||
->select('account_key, venta.id AS venta_id')
|
||||
->from('toku_accounts')
|
||||
->joined('JOIN proyecto ON proyecto.inmobiliaria = toku_accounts.sociedad_rut')
|
||||
->joined('JOIN proyecto_tipo_unidad ptu ON ptu.proyecto = proyecto.id')
|
||||
->joined('JOIN unidad ON unidad.pt = ptu.id')
|
||||
->joined('JOIN propiedad_unidad pu ON pu.unidad = unidad.id')
|
||||
->joined('JOIN venta ON venta.propiedad = pu.propiedad')
|
||||
->where("venta.id IN ({$placeholdersString}) AND toku_accounts.enabled = 1");
|
||||
$values = array_combine($placeholders, $ventaIds);
|
||||
try {
|
||||
$statement = $this->ventaService->getRepository()->getConnection()->execute($query, $values);
|
||||
$results = $statement->fetchAll(PDO::FETCH_ASSOC);
|
||||
} catch (PDOException $exception) {
|
||||
$this->logger->error($exception->getMessage(), [
|
||||
'query' => $query,
|
||||
'values' => $values,
|
||||
'exception' => $exception]);
|
||||
throw new EmptyResult($query, $exception);
|
||||
}
|
||||
$keys = array_column($results, 'account_key');
|
||||
$ids = array_column($results, 'venta_id');
|
||||
return array_combine($ids, $keys);
|
||||
}
|
||||
}
|
@ -1,27 +1,40 @@
|
||||
<?php
|
||||
namespace Incoviba\Service\Venta;
|
||||
|
||||
use Exception;
|
||||
use DateTimeInterface;
|
||||
use DateTimeImmutable;
|
||||
use DateMalformedStringException;
|
||||
use Incoviba\Common\Define;
|
||||
use Incoviba\Exception\ServiceAction\Create;
|
||||
use Incoviba\Exception\ServiceAction\Read;
|
||||
use Incoviba\Exception\ServiceAction\Update;
|
||||
use PDOException;
|
||||
use Incoviba\Common\Ideal;
|
||||
use Incoviba\Common\Implement\Exception\EmptyResult;
|
||||
use Incoviba\Repository;
|
||||
use Incoviba\Model;
|
||||
use Incoviba\Service;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class Pago
|
||||
class Pago extends Ideal\Service\Repository
|
||||
{
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
protected Repository\Venta\Pago $pagoRepository,
|
||||
protected Repository\Venta\EstadoPago $estadoPagoRepository,
|
||||
protected Repository\Venta\TipoEstadoPago $tipoEstadoPagoRepository,
|
||||
protected Service\UF $ufService,
|
||||
protected Service\Valor $valorService
|
||||
) {}
|
||||
protected Service\Valor $valorService,
|
||||
protected Service\Queue $queueService
|
||||
)
|
||||
{
|
||||
parent::__construct($logger);
|
||||
}
|
||||
|
||||
public function getRepository(): Define\Repository
|
||||
{
|
||||
return $this->pagoRepository;
|
||||
}
|
||||
|
||||
public function depositar(Model\Venta\Pago $pago, DateTimeInterface $fecha): bool
|
||||
{
|
||||
@ -37,7 +50,7 @@ class Pago
|
||||
$pago = $this->process($this->pagoRepository->fetchById($pago->id));
|
||||
$this->getUF($pago);
|
||||
return true;
|
||||
} catch (PDOException) {
|
||||
} catch (PDOException | EmptyResult) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -89,13 +102,23 @@ class Pago
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $pago_id
|
||||
* @return Model\Venta\Pago|null
|
||||
* @throws Read
|
||||
*/
|
||||
public function getById(?int $pago_id): ?Model\Venta\Pago
|
||||
{
|
||||
if ($pago_id === null) {
|
||||
return null;
|
||||
}
|
||||
$pago = $this->pagoRepository->fetchById($pago_id);
|
||||
return $this->process($pago);
|
||||
try {
|
||||
$pago = $this->pagoRepository->fetchById($pago_id);
|
||||
return $this->process($pago);
|
||||
} catch (EmptyResult) {
|
||||
throw new Read(__CLASS__);
|
||||
}
|
||||
}
|
||||
|
||||
public function getByVenta(int $venta_id): array
|
||||
@ -130,6 +153,11 @@ class Pago
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return Model\Venta\Pago
|
||||
* @throws Create
|
||||
*/
|
||||
public function add(array $data): Model\Venta\Pago
|
||||
{
|
||||
if (array_key_exists('fecha', $data)) {
|
||||
@ -139,24 +167,32 @@ class Pago
|
||||
$fecha = new DateTimeImmutable();
|
||||
}
|
||||
$data['fecha'] = $fecha->format('Y-m-d');
|
||||
if (!array_key_exists('uf', $data)) {
|
||||
$data['uf'] = $this->ufService->get($fecha);
|
||||
}
|
||||
}
|
||||
$data['valor'] = $this->valorService->toPesos($this->valorService->clean($data['valor']), $data['fecha']);
|
||||
|
||||
$filtered_data = $this->pagoRepository->filterData($data);
|
||||
|
||||
$pago = $this->pagoRepository->create($filtered_data);
|
||||
$pago = $this->pagoRepository->save($pago);
|
||||
try {
|
||||
$pago = $this->pagoRepository->create($filtered_data);
|
||||
$pago = $this->pagoRepository->save($pago);
|
||||
} catch (PDOException $exception) {
|
||||
throw new Create(__CLASS__, $exception);
|
||||
}
|
||||
if (!array_key_exists('uf', $data)) {
|
||||
$this->getUFAsync($pago);
|
||||
}
|
||||
|
||||
$tipoEstado = $this->tipoEstadoPagoRepository->fetchByDescripcion('no pagado');
|
||||
$estado = $this->estadoPagoRepository->create([
|
||||
'pago' => $pago->id,
|
||||
'fecha' => $pago->fecha->format('Y-m-d'),
|
||||
'estado' => $tipoEstado->id
|
||||
]);
|
||||
$estado = $this->estadoPagoRepository->save($estado);
|
||||
try {
|
||||
$estado = $this->estadoPagoRepository->create([
|
||||
'pago' => $pago->id,
|
||||
'fecha' => $pago->fecha->format('Y-m-d'),
|
||||
'estado' => $tipoEstado->id
|
||||
]);
|
||||
$estado = $this->estadoPagoRepository->save($estado);
|
||||
} catch (PDOException $exception) {
|
||||
throw new Create(__CLASS__, $exception);
|
||||
}
|
||||
$pago->currentEstado = $estado;
|
||||
return $pago;
|
||||
}
|
||||
@ -213,6 +249,21 @@ class Pago
|
||||
|
||||
return $this->process($this->pagoRepository->fetchById($pago->id));
|
||||
}
|
||||
public function updateUF(int $pago_id): bool
|
||||
{
|
||||
try {
|
||||
$pago = $this->getById($pago_id);
|
||||
} catch (Read) {
|
||||
return false;
|
||||
}
|
||||
$uf = $this->ufService->get($pago->currentEstado->fecha);
|
||||
try {
|
||||
$this->pagoRepository->edit($pago, ['uf' => $uf]);
|
||||
return true;
|
||||
} catch (EmptyResult | PDOException) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected function process($pago): Model\Venta\Pago
|
||||
{
|
||||
@ -232,13 +283,27 @@ class Pago
|
||||
return $uf;
|
||||
}
|
||||
if ($uf !== 0.0) {
|
||||
$this->pagoRepository->edit($pago, ['uf' => $uf]);
|
||||
try {
|
||||
$this->pagoRepository->edit($pago, ['uf' => $uf]);
|
||||
} catch (EmptyResult) {}
|
||||
return $uf;
|
||||
}
|
||||
} elseif ($pago->uf === 0.0) {
|
||||
$this->pagoRepository->edit($pago, ['uf' => null]);
|
||||
try {
|
||||
$this->pagoRepository->edit($pago, ['uf' => null]);
|
||||
} catch (EmptyResult) {}
|
||||
return null;
|
||||
}
|
||||
return $pago->uf;
|
||||
}
|
||||
protected function getUFAsync(Model\Venta\Pago $pago): void
|
||||
{
|
||||
$queueData = [
|
||||
'type' => 'service',
|
||||
'service' => __CLASS__,
|
||||
'method' => 'updateUF',
|
||||
'params' => ['pago_id' => $pago->id]
|
||||
];
|
||||
$this->queueService->push($queueData);
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,22 @@
|
||||
<?php
|
||||
namespace Incoviba\Service\Venta;
|
||||
|
||||
use PDOException;
|
||||
use DateTimeImmutable;
|
||||
use DateMalformedStringException;
|
||||
use Incoviba\Common\Implement\Exception\EmptyResult;
|
||||
use Incoviba\Common\Implement\Repository\Factory;
|
||||
use Incoviba\Exception\ServiceAction\Read;
|
||||
use Incoviba\Repository;
|
||||
use Incoviba\Exception\ServiceAction\{Create, Read};
|
||||
use Incoviba\Model;
|
||||
use Incoviba\Repository;
|
||||
use Incoviba\Service\UF;
|
||||
|
||||
class Pie
|
||||
{
|
||||
public function __construct(
|
||||
protected Repository\Venta\Pie $pieRepository,
|
||||
protected Cuota $cuotaService,
|
||||
protected Pago $pagoService
|
||||
protected Pago $pagoService,
|
||||
protected UF $ufService
|
||||
) {}
|
||||
|
||||
public function getById(int $pie_id): Model\Venta\Pie
|
||||
@ -28,12 +32,33 @@ class Pie
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return Model\Venta\Pie
|
||||
* @throws Create
|
||||
*/
|
||||
public function add(array $data): Model\Venta\Pie
|
||||
{
|
||||
$filteredData = $this->pieRepository->filterData($data);
|
||||
$pie = $this->pieRepository->create($filteredData);
|
||||
return $this->pieRepository->save($pie);
|
||||
try {
|
||||
$filteredData = $this->pieRepository->filterData($data);
|
||||
if (!isset($filteredData['uf'])) {
|
||||
try {
|
||||
$date = new DateTimeImmutable($filteredData['fecha']);
|
||||
$filteredData['uf'] = $this->ufService->get($date);
|
||||
} catch (DateMalformedStringException) {}
|
||||
}
|
||||
$pie = $this->pieRepository->create($filteredData);
|
||||
return $this->pieRepository->save($pie);
|
||||
} catch (PDOException $exception) {
|
||||
throw new Create(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return Model\Venta\Cuota
|
||||
* @throws Create
|
||||
*/
|
||||
public function addCuota(array $data): Model\Venta\Cuota
|
||||
{
|
||||
return $this->cuotaService->add($data);
|
||||
@ -58,6 +83,12 @@ class Pie
|
||||
if (isset($pie->asociado)) {
|
||||
$pie->asociado = $this->getById($pie->asociado->id);
|
||||
}
|
||||
if (($pie->uf === null or $pie->uf === 0.0) and $pie->fecha <= new DateTimeImmutable()) {
|
||||
$pie->uf = $this->ufService->get($pie->fecha);
|
||||
try {
|
||||
$this->pieRepository->edit($pie, ['uf' => $pie->uf]);
|
||||
} catch (EmptyResult) {}
|
||||
}
|
||||
return $pie;
|
||||
}
|
||||
}
|
||||
|
464
app/src/Service/Venta/Promotion.php
Normal file
464
app/src/Service/Venta/Promotion.php
Normal file
@ -0,0 +1,464 @@
|
||||
<?php
|
||||
namespace Incoviba\Service\Venta;
|
||||
|
||||
use Incoviba\Controller\API\Ventas\Promotions;
|
||||
use PDOException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Incoviba\Common\Ideal;
|
||||
use Incoviba\Common\Implement;
|
||||
use Incoviba\Exception;
|
||||
use Incoviba\Model;
|
||||
use Incoviba\Repository;
|
||||
use Incoviba\Service;
|
||||
|
||||
class Promotion extends Ideal\Service
|
||||
{
|
||||
public function __construct(LoggerInterface $logger,
|
||||
protected Repository\Venta\Promotion $promotionRepository,
|
||||
protected Repository\Proyecto $projectRepository,
|
||||
protected Repository\Proyecto\Broker\Contract $contractRepository,
|
||||
protected Repository\Proyecto\Broker $brokerRepository,
|
||||
protected Repository\Proyecto\TipoUnidad $tipoUnidadRepository,
|
||||
protected Repository\Proyecto\ProyectoTipoUnidad $proyectoTipoUnidadRepository,
|
||||
protected Repository\Venta\Unidad $unidadRepository)
|
||||
{
|
||||
parent::__construct($logger);
|
||||
}
|
||||
|
||||
public function getAll(null|string|array $order = null): array
|
||||
{
|
||||
try {
|
||||
return array_map([$this, 'process'], $this->promotionRepository->fetchAll($order));
|
||||
} catch (Implement\Exception\EmptyResult) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $promotion_id
|
||||
* @return Model\Venta\Promotion
|
||||
* @throws Exception\ServiceAction\Read
|
||||
*/
|
||||
public function getById(int $promotion_id): Model\Venta\Promotion
|
||||
{
|
||||
try {
|
||||
return $this->process($this->promotionRepository->fetchById($promotion_id));
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Exception\ServiceAction\Read(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $contract_id
|
||||
* @return array
|
||||
*/
|
||||
public function getByContract(int $contract_id): array
|
||||
{
|
||||
try {
|
||||
return array_map([$this, 'process'], $this->promotionRepository->fetchByContract($contract_id));
|
||||
} catch (Implement\Exception\EmptyResult) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $contract_id
|
||||
* @return array
|
||||
*/
|
||||
public function getActiveByContract(int $contract_id): array
|
||||
{
|
||||
try {
|
||||
return array_map([$this, 'process'], $this->promotionRepository->fetchActiveByContract($contract_id));
|
||||
} catch (Implement\Exception\EmptyResult) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return Model\Venta\Promotion
|
||||
* @throws Exception\ServiceAction\Create
|
||||
*/
|
||||
public function add(array $data): Model\Venta\Promotion
|
||||
{
|
||||
try {
|
||||
$filteredData = $this->promotionRepository->filterData($data);
|
||||
$promotion = $this->promotionRepository->create($filteredData);
|
||||
return $this->process($this->promotionRepository->save($promotion));
|
||||
} catch (PDOException $exception) {
|
||||
throw new Exception\ServiceAction\Create(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model\Venta\Promotion $promotion
|
||||
* @param array $data
|
||||
* @return Model\Venta\Promotion
|
||||
* @throws Exception\ServiceAction\Update
|
||||
*/
|
||||
public function edit(Model\Venta\Promotion $promotion, array $data): Model\Venta\Promotion
|
||||
{
|
||||
try {
|
||||
$filteredData = $this->promotionRepository->filterData($data);
|
||||
$promotion = $this->promotionRepository->edit($promotion, $filteredData);
|
||||
return $this->process($promotion);
|
||||
} catch (PDOException | Implement\Exception\EmptyResult $exception) {
|
||||
throw new Exception\ServiceAction\Update(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $promotion_id
|
||||
* @return Model\Venta\Promotion
|
||||
* @throws Exception\ServiceAction\Delete
|
||||
*/
|
||||
public function remove(int $promotion_id): Model\Venta\Promotion
|
||||
{
|
||||
try {
|
||||
$promotion = $this->promotionRepository->fetchById($promotion_id);
|
||||
$this->promotionRepository->remove($promotion);
|
||||
return $promotion;
|
||||
} catch (PDOException | Implement\Exception\EmptyResult $exception) {
|
||||
throw new Exception\ServiceAction\Delete(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $promotion_id
|
||||
* @param int $project_id
|
||||
* @return Model\Venta\Promotion
|
||||
* @throws Exception\ServiceAction\Create
|
||||
*/
|
||||
public function addProject(int $promotion_id, int $project_id): Model\Venta\Promotion
|
||||
{
|
||||
try {
|
||||
$promotion = $this->promotionRepository->fetchById($promotion_id);
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Exception\ServiceAction\Create(__CLASS__, $exception);
|
||||
}
|
||||
try {
|
||||
$project = $this->projectRepository->fetchById($project_id);
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Exception\ServiceAction\Create(__CLASS__, $exception);
|
||||
}
|
||||
if (in_array($project, $promotion->projects())) {
|
||||
return $this->process($promotion);
|
||||
}
|
||||
try {
|
||||
$this->promotionRepository->insertProjectForPromotion($promotion, $project->id);
|
||||
return $this->process($promotion);
|
||||
} catch (PDOException $exception) {
|
||||
throw new Exception\ServiceAction\Create(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $promotion_id
|
||||
* @param int $broker_rut
|
||||
* @return Model\Venta\Promotion
|
||||
* @throws Exception\ServiceAction\Create
|
||||
*/
|
||||
public function addBroker(int $promotion_id, int $broker_rut): Model\Venta\Promotion
|
||||
{
|
||||
try {
|
||||
$promotion = $this->promotionRepository->fetchById($promotion_id);
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Exception\ServiceAction\Create(__CLASS__, $exception);
|
||||
}
|
||||
try {
|
||||
$broker = $this->brokerRepository->fetchById($broker_rut);
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Exception\ServiceAction\Create(__CLASS__, $exception);
|
||||
}
|
||||
if (in_array($broker, $promotion->brokers())) {
|
||||
return $this->process($promotion);
|
||||
}
|
||||
try {
|
||||
$this->promotionRepository->insertBrokerForPromotion($promotion, $broker->rut);
|
||||
return $this->process($promotion);
|
||||
} catch (PDOException $exception) {
|
||||
throw new Exception\ServiceAction\Create(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $promotion_id
|
||||
* @param int $project_id
|
||||
* @param int $unitType_id
|
||||
* @return Model\Venta\Promotion
|
||||
* @throws Exception\ServiceAction\Create
|
||||
*/
|
||||
public function addUnitType(int $promotion_id, int $project_id, int $unitType_id): Model\Venta\Promotion
|
||||
{
|
||||
try {
|
||||
$promotion = $this->promotionRepository->fetchById($promotion_id);
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Exception\ServiceAction\Create(__CLASS__, $exception);
|
||||
}
|
||||
try {
|
||||
$project = $this->projectRepository->fetchById($project_id);
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Exception\ServiceAction\Create(__CLASS__, $exception);
|
||||
}
|
||||
try {
|
||||
$unitType = $this->tipoUnidadRepository->fetchById($unitType_id);
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Exception\ServiceAction\Create(__CLASS__, $exception);
|
||||
}
|
||||
if (in_array(['project' => $project, 'unitType' => $unitType], $promotion->unitTypes())) {
|
||||
return $this->process($promotion);
|
||||
}
|
||||
try {
|
||||
$this->promotionRepository->insertUnitTypeForPromotion($promotion, $project->id, $unitType->id);
|
||||
return $this->process($promotion);
|
||||
} catch (PDOException $exception) {
|
||||
throw new Exception\ServiceAction\Create(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $promotion_id
|
||||
* @param int $unit_line_id
|
||||
* @return Model\Venta\Promotion
|
||||
* @throws Exception\ServiceAction\Create
|
||||
*/
|
||||
public function addUnitLine(int $promotion_id, int $unit_line_id): Model\Venta\Promotion
|
||||
{
|
||||
try {
|
||||
$promotion = $this->promotionRepository->fetchById($promotion_id);
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Exception\ServiceAction\Create(__CLASS__, $exception);
|
||||
}
|
||||
try {
|
||||
$unitLine = $this->proyectoTipoUnidadRepository->fetchById($unit_line_id);
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Exception\ServiceAction\Create(__CLASS__, $exception);
|
||||
}
|
||||
if (in_array($unitLine, $promotion->unitLines())) {
|
||||
return $this->process($promotion);
|
||||
}
|
||||
try {
|
||||
$this->promotionRepository->insertUnitLineForPromotion($promotion, $unitLine->id);
|
||||
return $this->process($promotion);
|
||||
} catch (PDOException $exception) {
|
||||
throw new Exception\ServiceAction\Create(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $promotion_id
|
||||
* @param int $unit_id
|
||||
* @return Model\Venta\Promotion
|
||||
* @throws Exception\ServiceAction\Create
|
||||
*/
|
||||
public function addUnit(int $promotion_id, int $unit_id): Model\Venta\Promotion
|
||||
{
|
||||
try {
|
||||
$promotion = $this->promotionRepository->fetchById($promotion_id);
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Exception\ServiceAction\Create(__CLASS__, $exception);
|
||||
}
|
||||
try {
|
||||
$unit = $this->unidadRepository->fetchById($unit_id);
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Exception\ServiceAction\Create(__CLASS__, $exception);
|
||||
}
|
||||
if (in_array($unit, $promotion->units())) {
|
||||
return $this->process($promotion);
|
||||
}
|
||||
try {
|
||||
$this->promotionRepository->insertUnitForPromotion($promotion, $unit->id);
|
||||
return $this->process($promotion);
|
||||
} catch (PDOException $exception) {
|
||||
throw new Exception\ServiceAction\Create(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $promotion_id
|
||||
* @param int $project_id
|
||||
* @return void
|
||||
* @throws Exception\ServiceAction\Delete
|
||||
*/
|
||||
public function removeProject(int $promotion_id, int $project_id): void
|
||||
{
|
||||
try {
|
||||
$promotion = $this->promotionRepository->fetchById($promotion_id);
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Exception\ServiceAction\Delete(__CLASS__, $exception);
|
||||
}
|
||||
try {
|
||||
$project = $this->projectRepository->fetchById($project_id);
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Exception\ServiceAction\Delete(__CLASS__, $exception);
|
||||
}
|
||||
try {
|
||||
$this->promotionRepository->removeProjectForPromotion($promotion, $project->id);
|
||||
} catch (PDOException $exception) {
|
||||
throw new Exception\ServiceAction\Delete(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $promotion_id
|
||||
* @param int $broker_rut
|
||||
* @return void
|
||||
* @throws Exception\ServiceAction\Delete
|
||||
*/
|
||||
public function removeBroker(int $promotion_id, int $broker_rut): void
|
||||
{
|
||||
try {
|
||||
$promotion = $this->promotionRepository->fetchById($promotion_id);
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Exception\ServiceAction\Delete(__CLASS__, $exception);
|
||||
}
|
||||
try {
|
||||
$broker = $this->brokerRepository->fetchById($broker_rut);
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Exception\ServiceAction\Delete(__CLASS__, $exception);
|
||||
}
|
||||
try {
|
||||
$this->promotionRepository->removeBrokerForPromotion($promotion, $broker->rut);
|
||||
} catch (PDOException $exception) {
|
||||
throw new Exception\ServiceAction\Delete(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $promotion_id
|
||||
* @param int $project_id
|
||||
* @param int $unitType_id
|
||||
* @return void
|
||||
* @throws Exception\ServiceAction\Delete
|
||||
*/
|
||||
public function removeUnitType(int $promotion_id, int $project_id, int $unitType_id): void
|
||||
{
|
||||
try {
|
||||
$promotion = $this->promotionRepository->fetchById($promotion_id);
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Exception\ServiceAction\Delete(__CLASS__, $exception);
|
||||
}
|
||||
try {
|
||||
$project = $this->projectRepository->fetchById($project_id);
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Exception\ServiceAction\Delete(__CLASS__, $exception);
|
||||
}
|
||||
try {
|
||||
$unitType = $this->tipoUnidadRepository->fetchById($unitType_id);
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Exception\ServiceAction\Delete(__CLASS__, $exception);
|
||||
}
|
||||
try {
|
||||
$this->promotionRepository->removeUnitTypeForPromotion($promotion, $project->id, $unitType->id);
|
||||
} catch (PDOException $exception) {
|
||||
throw new Exception\ServiceAction\Delete(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $promotion_id
|
||||
* @param int $unit_line_id
|
||||
* @return void
|
||||
* @throws Exception\ServiceAction\Delete
|
||||
*/
|
||||
public function removeUnitLine(int $promotion_id, int $unit_line_id): void
|
||||
{
|
||||
try {
|
||||
$promotion = $this->promotionRepository->fetchById($promotion_id);
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Exception\ServiceAction\Delete(__CLASS__, $exception);
|
||||
}
|
||||
try {
|
||||
$unitLine = $this->proyectoTipoUnidadRepository->fetchById($unit_line_id);
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Exception\ServiceAction\Delete(__CLASS__, $exception);
|
||||
}
|
||||
try {
|
||||
$this->promotionRepository->removeUnitLineForPromotion($promotion, $unitLine->id);
|
||||
} catch (PDOException $exception) {
|
||||
throw new Exception\ServiceAction\Delete(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $promotion_id
|
||||
* @param int $unit_id
|
||||
* @return void
|
||||
* @throws Exception\ServiceAction\Delete
|
||||
*/
|
||||
public function removeUnit(int $promotion_id, int $unit_id): void
|
||||
{
|
||||
try {
|
||||
$promotion = $this->promotionRepository->fetchById($promotion_id);
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Exception\ServiceAction\Delete(__CLASS__, $exception);
|
||||
}
|
||||
try {
|
||||
$unit = $this->unidadRepository->fetchById($unit_id);
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new Exception\ServiceAction\Delete(__CLASS__, $exception);
|
||||
}
|
||||
try {
|
||||
$this->promotionRepository->removeUnitForPromotion($promotion, $unit->id);
|
||||
} catch (PDOException $exception) {
|
||||
throw new Exception\ServiceAction\Delete(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
protected function process(Model\Venta\Promotion $model): Model\Venta\Promotion
|
||||
{
|
||||
$model->addFactory('projects', (new Implement\Repository\Factory())
|
||||
->setCallable(function($promotion_id) {
|
||||
try {
|
||||
return $this->projectRepository->fetchByPromotion($promotion_id);
|
||||
} catch (Implement\Exception\EmptyResult) {
|
||||
return [];
|
||||
}
|
||||
})
|
||||
->setArgs(['promotion_id' => $model->id]));
|
||||
$model->addFactory('brokers', (new Implement\Repository\Factory())
|
||||
->setCallable(function($promotion_id) {
|
||||
try {
|
||||
return $this->brokerRepository->fetchByPromotion($promotion_id);
|
||||
} catch (Implement\Exception\EmptyResult) {
|
||||
return [];
|
||||
}
|
||||
})
|
||||
->setArgs(['promotion_id' => $model->id]));
|
||||
$model->addFactory('unitTypes', (new Implement\Repository\Factory())
|
||||
->setCallable(function($promotion_id) {
|
||||
try {
|
||||
return array_map(function(array $ids) {
|
||||
return [
|
||||
'project' => $this->projectRepository->fetchById($ids['project_id']),
|
||||
'unitType' => $this->tipoUnidadRepository->fetchById($ids['id'])
|
||||
];
|
||||
}, $this->tipoUnidadRepository->fetchByPromotion($promotion_id));
|
||||
} catch (Implement\Exception\EmptyResult) {
|
||||
return [];
|
||||
}
|
||||
})
|
||||
->setArgs(['promotion_id' => $model->id])
|
||||
);
|
||||
$model->addFactory('unitLines', (new Implement\Repository\Factory())
|
||||
->setCallable(function($promotion_id) {
|
||||
try {
|
||||
return $this->proyectoTipoUnidadRepository->fetchByPromotion($promotion_id);
|
||||
} catch (Implement\Exception\EmptyResult) {
|
||||
return [];
|
||||
}
|
||||
})
|
||||
->setArgs(['promotion_id' => $model->id])
|
||||
);
|
||||
$model->addFactory('units', (new Implement\Repository\Factory())
|
||||
->setCallable(function($promotion_id) {
|
||||
try {
|
||||
return $this->unidadRepository->fetchByPromotion($promotion_id);
|
||||
} catch (Implement\Exception\EmptyResult) {
|
||||
return [];
|
||||
}
|
||||
})
|
||||
->setArgs(['promotion_id' => $model->id]));
|
||||
return $model;
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ use Psr\Log\LoggerInterface;
|
||||
use Incoviba\Common\Define;
|
||||
use Incoviba\Common\Ideal\Service;
|
||||
use Incoviba\Common\Implement\Exception\EmptyResult;
|
||||
use Incoviba\Exception;
|
||||
use Incoviba\Repository;
|
||||
use Incoviba\Model;
|
||||
|
||||
@ -21,11 +22,48 @@ class Propiedad extends Service
|
||||
parent::__construct($logger);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $propiedad_id
|
||||
* @return Model\Venta\Propiedad
|
||||
* @throws Exception\ServiceAction\Read
|
||||
*/
|
||||
public function getById(int $propiedad_id): Model\Venta\Propiedad
|
||||
{
|
||||
try {
|
||||
return $this->process($this->propiedadRepository->fetchById($propiedad_id));
|
||||
} catch (EmptyResult $exception) {
|
||||
throw new Exception\ServiceAction\Read(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $propiedad_id
|
||||
* @return array
|
||||
* @throws Exception\ServiceAction\Read
|
||||
*/
|
||||
public function getArrayById(int $propiedad_id): array
|
||||
{
|
||||
try {
|
||||
return $this->propiedadRepository->fetchArrayById($propiedad_id);
|
||||
} catch (EmptyResult $exception) {
|
||||
throw new Exception\ServiceAction\Read(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $ids
|
||||
* @return Model\Venta\Propiedad
|
||||
* @throws Exception\ServiceAction\Create
|
||||
*/
|
||||
public function addPropiedad(array $ids): Model\Venta\Propiedad
|
||||
{
|
||||
$unidades = [];
|
||||
foreach ($ids as $unidad_id) {
|
||||
$unidades []= $this->unidadRepository->fetchById($unidad_id);
|
||||
try {
|
||||
$unidades []= $this->unidadRepository->fetchById($unidad_id);
|
||||
} catch (EmptyResult $exception) {
|
||||
$this->logger->warning($exception);
|
||||
}
|
||||
}
|
||||
usort($unidades, function(Model\Venta\Unidad $a, Model\Venta\Unidad $b) {
|
||||
$t = $a->proyectoTipoUnidad->tipoUnidad->orden - $b->proyectoTipoUnidad->tipoUnidad->orden;
|
||||
@ -42,13 +80,25 @@ class Propiedad extends Service
|
||||
'unidad_principal' => $unidades[0]->id,
|
||||
'estado' => 1
|
||||
]);
|
||||
$propiedad = $this->propiedadRepository->save($propiedad);
|
||||
try {
|
||||
$propiedad = $this->propiedadRepository->save($propiedad);
|
||||
} catch (PDOException $exception) {
|
||||
throw new Exception\ServiceAction\Create(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
$this->addUnidades($propiedad, $unidades);
|
||||
$this->cleanUpUnidades($propiedad, $unidades);
|
||||
try {
|
||||
$this->cleanUpUnidades($propiedad, $unidades);
|
||||
} catch (Exception\ServiceAction\Read|Exception\ServiceAction\Delete) {}
|
||||
|
||||
return $propiedad;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model\Venta\Propiedad $propiedad
|
||||
* @param array $unidades
|
||||
* @return void
|
||||
*/
|
||||
protected function addUnidades(Model\Venta\Propiedad $propiedad, array $unidades): void
|
||||
{
|
||||
$query = "SELECT 1 FROM `propiedad_unidad` WHERE `propiedad` = ? AND `unidad` = ?";
|
||||
@ -63,19 +113,33 @@ class Propiedad extends Service
|
||||
throw new EmptyResult($query);
|
||||
}
|
||||
} catch (PDOException|EmptyResult) {
|
||||
$insert->execute([$propiedad->id, $unidad->id, ($ix === 0) ? 1 : 0]);
|
||||
try {
|
||||
$insert->execute([$propiedad->id, $unidad->id, ($ix === 0) ? 1 : 0]);
|
||||
} catch (PDOException) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model\Venta\Propiedad $propiedad
|
||||
* @param array $unidades
|
||||
* @return void
|
||||
* @throws Exception\ServiceAction\Delete
|
||||
* @throws Exception\ServiceAction\Read
|
||||
*/
|
||||
protected function cleanUpUnidades(Model\Venta\Propiedad $propiedad, array $unidades): void
|
||||
{
|
||||
$query = "SELECT `unidad` FROM `propiedad_unidad` WHERE `propiedad` = ?";
|
||||
$statement = $this->connection->prepare($query);
|
||||
$statement->execute([$propiedad->id]);
|
||||
$results = $statement->fetchAll(PDO::FETCH_ASSOC);
|
||||
try {
|
||||
$statement = $this->connection->prepare($query);
|
||||
$statement->execute([$propiedad->id]);
|
||||
$results = $statement->fetchAll(PDO::FETCH_ASSOC);
|
||||
} catch (PDOException $exception) {
|
||||
throw new Exception\ServiceAction\Read(__CLASS__, $exception);
|
||||
}
|
||||
|
||||
if (!$results) {
|
||||
return;
|
||||
throw new Exception\ServiceAction\Read(__CLASS__);
|
||||
}
|
||||
|
||||
$all_ids = array_map(function($row) {return $row['unidad'];}, $results);
|
||||
@ -85,9 +149,19 @@ class Propiedad extends Service
|
||||
return;
|
||||
}
|
||||
$query = "DELETE FROM `propiedad_unidad` WHERE `propiedad` = ? AND `unidad` = ?";
|
||||
$statement = $this->connection->prepare($query);
|
||||
try {
|
||||
$statement = $this->connection->prepare($query);
|
||||
} catch (PDOException $exception) {
|
||||
throw new Exception\ServiceAction\Delete(__CLASS__, $exception);
|
||||
}
|
||||
foreach ($diff as $id) {
|
||||
$statement->execute([$propiedad->id, $id]);
|
||||
try {
|
||||
$statement->execute([$propiedad->id, $id]);
|
||||
} catch (PDOException) {}
|
||||
}
|
||||
}
|
||||
protected function process(Model\Venta\Propiedad $propiedad): Model\Venta\Propiedad
|
||||
{
|
||||
return $propiedad;
|
||||
}
|
||||
}
|
||||
|
@ -1,33 +1,70 @@
|
||||
<?php
|
||||
namespace Incoviba\Service\Venta;
|
||||
|
||||
use PDOException;
|
||||
use Incoviba\Common\Implement\Exception\EmptyResult;
|
||||
use Incoviba\Exception\ServiceAction\Read;
|
||||
use Incoviba\Exception\ServiceAction\{Create, Read, Update};
|
||||
use Incoviba\Model;
|
||||
use Incoviba\Repository;
|
||||
use Incoviba\Service;
|
||||
use Incoviba\Model;
|
||||
|
||||
class PropiedadUnidad
|
||||
{
|
||||
public function __construct(protected Repository\Venta\PropiedadUnidad $propiedadUnidadRepository,
|
||||
protected Repository\Venta\Unidad $unidadRepository,
|
||||
protected Precio $precioService) {}
|
||||
protected Precio $precioService, protected Service\Valor $valorService) {}
|
||||
|
||||
/**
|
||||
* @param int $unidad_id
|
||||
* @return Model\Venta\PropiedadUnidad
|
||||
* @throws Read
|
||||
*/
|
||||
public function getById(int $unidad_id): Model\Venta\PropiedadUnidad
|
||||
{
|
||||
return $this->process($this->propiedadUnidadRepository->fetchById($unidad_id));
|
||||
try {
|
||||
return $this->process($this->propiedadUnidadRepository->fetchById($unidad_id));
|
||||
} catch (EmptyResult $exception) {
|
||||
throw new Read(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
public function getByVenta(int $venta_id): array
|
||||
{
|
||||
return array_map([$this, 'process'], $this->propiedadUnidadRepository->fetchByVenta($venta_id));
|
||||
try {
|
||||
return array_map([$this, 'process'], $this->propiedadUnidadRepository->fetchByVenta($venta_id));
|
||||
} catch (EmptyResult) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
public function getByPropiedad(int $propiedad_id): array
|
||||
{
|
||||
return array_map([$this, 'process'], $this->propiedadUnidadRepository->fetchByPropiedad($propiedad_id));
|
||||
try {
|
||||
return array_map([$this, 'process'], $this->propiedadUnidadRepository->fetchByPropiedad($propiedad_id));
|
||||
} catch (EmptyResult) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
public function getArrayByPropiedad(int $propiedad_id): array
|
||||
{
|
||||
try {
|
||||
return $this->propiedadUnidadRepository->fetchArrayByPropiedad($propiedad_id);
|
||||
} catch (EmptyResult) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return Model\Venta\PropiedadUnidad
|
||||
* @throws Create
|
||||
* @throws Read
|
||||
*/
|
||||
public function add(array $data): Model\Venta\PropiedadUnidad
|
||||
{
|
||||
$unidad = $this->unidadRepository->fetchById($data['unidad']);
|
||||
try {
|
||||
$unidad = $this->unidadRepository->fetchById($data['unidad']);
|
||||
} catch (EmptyResult $exception) {
|
||||
throw new Read(__CLASS__, $exception);
|
||||
}
|
||||
$temp = json_decode(json_encode($unidad), JSON_OBJECT_AS_ARRAY);
|
||||
$columnMap = [
|
||||
'proyecto_tipo_unidad' => 'pt'
|
||||
@ -40,11 +77,31 @@ class PropiedadUnidad
|
||||
$temp['propiedad'] = $data['propiedad'];
|
||||
$temp['valor'] = $data['valor'];
|
||||
$pu = $this->propiedadUnidadRepository->create($temp);
|
||||
return $this->process($this->propiedadUnidadRepository->save($pu));
|
||||
try {
|
||||
return $this->process($this->propiedadUnidadRepository->save($pu));
|
||||
} catch (PDOException $exception) {
|
||||
throw new Create(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model\Venta\PropiedadUnidad $propiedadUnidad
|
||||
* @param array $data
|
||||
* @return Model\Venta\PropiedadUnidad
|
||||
* @throws EmptyResult
|
||||
* @throws Update
|
||||
*/
|
||||
public function edit(Model\Venta\PropiedadUnidad $propiedadUnidad, array $data): Model\Venta\PropiedadUnidad
|
||||
{
|
||||
return $this->process($this->propiedadUnidadRepository->edit($propiedadUnidad, $data));
|
||||
try {
|
||||
$filteredData = $this->propiedadUnidadRepository->filterData($data);
|
||||
if (array_key_exists('valor', $filteredData)) {
|
||||
$filteredData['valor'] = $this->valorService->clean($filteredData['valor']);
|
||||
}
|
||||
return $this->process($this->propiedadUnidadRepository->edit($propiedadUnidad, $filteredData));
|
||||
} catch (PDOException $exception) {
|
||||
throw new Update(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
protected function process(Model\Venta\PropiedadUnidad $unidad): Model\Venta\PropiedadUnidad
|
||||
@ -52,7 +109,7 @@ class PropiedadUnidad
|
||||
try {
|
||||
$unidad->precios = $this->precioService->getByUnidad($unidad->id);
|
||||
$unidad->currentPrecio = $this->precioService->getVigenteByUnidad($unidad->id);
|
||||
if ($unidad->valor === null or $unidad->valor === 0) {
|
||||
if ($unidad->valor === null) {
|
||||
$unidad->valor = $unidad->currentPrecio->valor;
|
||||
}
|
||||
} catch (Read) {}
|
||||
|
@ -3,8 +3,12 @@ namespace Incoviba\Service\Venta;
|
||||
|
||||
use Incoviba\Common\Ideal\Service;
|
||||
use Incoviba\Common\Implement\Exception\EmptyResult;
|
||||
use Incoviba\Exception\ServiceAction\Create;
|
||||
use Incoviba\Exception\ServiceAction\Read;
|
||||
use Incoviba\Exception\ServiceAction\Update;
|
||||
use Incoviba\Repository;
|
||||
use Incoviba\Model;
|
||||
use PDOException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class Propietario extends Service
|
||||
@ -17,10 +21,27 @@ class Propietario extends Service
|
||||
parent::__construct($logger);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $rut
|
||||
* @return Model\Venta\Propietario
|
||||
* @throws Read
|
||||
*/
|
||||
public function getByRut(int $rut): Model\Venta\Propietario
|
||||
{
|
||||
return $this->propietarioRepository->fetchById($rut);
|
||||
try {
|
||||
return $this->propietarioRepository->fetchById($rut);
|
||||
} catch (EmptyResult $exception) {
|
||||
throw new Read(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model\Venta\Propietario $propietario
|
||||
* @param array $data
|
||||
* @return Model\Venta\Propietario
|
||||
* @throws Create
|
||||
* @throws Update
|
||||
*/
|
||||
public function edit(Model\Venta\Propietario $propietario, array $data): Model\Venta\Propietario
|
||||
{
|
||||
if (isset($data['calle']) or isset($data['numero']) or isset($data['extra']) or isset($data['comuna'])) {
|
||||
@ -28,8 +49,18 @@ class Propietario extends Service
|
||||
$data['direccion'] = $direccion->id;
|
||||
}
|
||||
$filteredData = $this->propietarioRepository->filterData($data);
|
||||
return $this->propietarioRepository->edit($propietario, $filteredData);
|
||||
try {
|
||||
return $this->propietarioRepository->edit($propietario, $filteredData);
|
||||
} catch (PDOException | EmptyResult $exception) {
|
||||
throw new Update(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return Model\Venta\Propietario
|
||||
* @throws Create
|
||||
*/
|
||||
public function addPropietario(array $data): Model\Venta\Propietario
|
||||
{
|
||||
$direccion = $this->addDireccion($data);
|
||||
@ -42,14 +73,16 @@ class Propietario extends Service
|
||||
$data['dv'] = $dv;
|
||||
}
|
||||
|
||||
$fields = array_fill_keys([
|
||||
$fields = array_flip([
|
||||
'rut',
|
||||
'dv',
|
||||
'nombres',
|
||||
'apellido_paterno',
|
||||
'apellido_materno',
|
||||
'direccion'
|
||||
], 0);
|
||||
'direccion',
|
||||
'email',
|
||||
'telefono'
|
||||
]);
|
||||
$filtered_data = array_intersect_key($data, $fields);
|
||||
|
||||
try {
|
||||
@ -60,11 +93,22 @@ class Propietario extends Service
|
||||
}
|
||||
$propietario = $this->propietarioRepository->edit($propietario, $edits);
|
||||
} catch (EmptyResult) {
|
||||
$propietario = $this->propietarioRepository->create($filtered_data);
|
||||
$propietario = $this->propietarioRepository->save($propietario);
|
||||
try {
|
||||
$propietario = $this->propietarioRepository->create($filtered_data);
|
||||
$propietario = $this->propietarioRepository->save($propietario);
|
||||
} catch (PDOException $exception) {
|
||||
throw new Create(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
return $propietario;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return Model\Venta\Propietario
|
||||
* @throws Create
|
||||
* @throws Update
|
||||
*/
|
||||
public function addSociedad(array $data): Model\Venta\Propietario
|
||||
{
|
||||
$direccion = $this->addDireccion($data);
|
||||
@ -74,12 +118,12 @@ class Propietario extends Service
|
||||
$data['rut'] = explode('-', $data['rut'])[0];
|
||||
}
|
||||
|
||||
$fields = array_fill_keys([
|
||||
$fields = array_flip([
|
||||
'rut',
|
||||
'razon_social',
|
||||
'direccion',
|
||||
'representante'
|
||||
], 0);
|
||||
]);
|
||||
$filtered_data = array_intersect_key($data, $fields);
|
||||
$mapped_data = array_combine([
|
||||
'rut',
|
||||
@ -97,27 +141,45 @@ class Propietario extends Service
|
||||
if ($sociedad->contacto->rut !== $mapped_data['representante']) {
|
||||
$edits['representante'] = $mapped_data['representante'];
|
||||
}
|
||||
$sociedad = $this->propietarioRepository->edit($sociedad, $edits);
|
||||
try {
|
||||
$sociedad = $this->propietarioRepository->edit($sociedad, $edits);
|
||||
} catch (PDOException $exception) {
|
||||
throw new Update(__CLASS__, $exception);
|
||||
}
|
||||
} catch (EmptyResult) {
|
||||
$sociedad = $this->propietarioRepository->create($mapped_data);
|
||||
$sociedad = $this->propietarioRepository->save($sociedad);
|
||||
try {
|
||||
$sociedad = $this->propietarioRepository->create($mapped_data);
|
||||
$sociedad = $this->propietarioRepository->save($sociedad);
|
||||
} catch (PDOException $exception) {
|
||||
throw new Create(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
return $sociedad;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return Model\Direccion
|
||||
* @throws Create
|
||||
*/
|
||||
protected function addDireccion(array $data): Model\Direccion
|
||||
{
|
||||
$fields = array_fill_keys([
|
||||
$fields = array_flip([
|
||||
'calle',
|
||||
'numero',
|
||||
'extra',
|
||||
'comuna'
|
||||
], 0);
|
||||
]);
|
||||
$filtered_data = array_intersect_key($data, $fields);
|
||||
try {
|
||||
$direccion = $this->direccionRepository->fetchByCalleAndNumeroAndExtraAndComuna($filtered_data['calle'], $filtered_data['numero'], $filtered_data['extra'], $filtered_data['comuna']);
|
||||
} catch (EmptyResult) {
|
||||
$direccion = $this->direccionRepository->create($filtered_data);
|
||||
$direccion = $this->direccionRepository->save($direccion);
|
||||
try {
|
||||
$direccion = $this->direccionRepository->create($filtered_data);
|
||||
$direccion = $this->direccionRepository->save($direccion);
|
||||
} catch (PDOException $exception) {
|
||||
throw new Create(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
return $direccion;
|
||||
}
|
||||
|
81
app/src/Service/Venta/Reservation.php
Normal file
81
app/src/Service/Venta/Reservation.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
namespace Incoviba\Service\Venta;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use DateMalformedStringException;
|
||||
use PDOException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Incoviba\Common\Define;
|
||||
use Incoviba\Common\Ideal;
|
||||
use Incoviba\Common\Implement;
|
||||
use Incoviba\Exception\ServiceAction;
|
||||
use Incoviba\Model;
|
||||
use Incoviba\Repository;
|
||||
|
||||
class Reservation extends Ideal\Service\API
|
||||
{
|
||||
public function __construct(LoggerInterface $logger, protected Repository\Venta\Reservation $reservationRepository)
|
||||
{
|
||||
parent::__construct($logger);
|
||||
}
|
||||
|
||||
public function getAll(null|string|array $order = null): array
|
||||
{
|
||||
try {
|
||||
return $this->reservationRepository->fetchAll($order);
|
||||
} catch (Implement\Exception\EmptyResult) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
public function get(int $id): Model\Venta\Reservation
|
||||
{
|
||||
try {
|
||||
return $this->process($this->reservationRepository->fetchById($id));
|
||||
} catch (Implement\Exception\EmptyResult $exception) {
|
||||
throw new ServiceAction\Read(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
public function add(array $data): Model\Venta\Reservation
|
||||
{
|
||||
try {
|
||||
$date = new DateTimeImmutable();
|
||||
try {
|
||||
$date = new DateTimeImmutable($data['date']);
|
||||
} catch (DateMalformedStringException) {}
|
||||
return $this->process($this->reservationRepository->fetchByBuyerAndDate($data['buyer_rut'], $date));
|
||||
} catch (Implement\Exception\EmptyResult) {}
|
||||
|
||||
try {
|
||||
$reservationData = $this->reservationRepository->filterData($data);
|
||||
$reservation = $this->reservationRepository->create($reservationData);
|
||||
$this->reservationRepository->save($reservation);
|
||||
return $this->process($reservation);
|
||||
} catch (PDOException $exception) {
|
||||
throw new ServiceAction\Create(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
public function edit(Define\Model $model, array $new_data): Model\Venta\Reservation
|
||||
{
|
||||
try {
|
||||
return $this->process($this->reservationRepository->edit($model, $new_data));
|
||||
} catch (PDOException | Implement\Exception\EmptyResult $exception) {
|
||||
throw new ServiceAction\Update(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
public function delete(int $id): Model\Venta\Reservation
|
||||
{
|
||||
try {
|
||||
$reservation = $this->reservationRepository->fetchById($id);
|
||||
$this->reservationRepository->remove($reservation);
|
||||
return $reservation;
|
||||
} catch (PDOException | Implement\Exception\EmptyResult $exception) {
|
||||
throw new ServiceAction\Delete(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
protected function process(Define\Model $model): Model\Venta\Reservation
|
||||
{
|
||||
return $model;
|
||||
}
|
||||
}
|
@ -2,7 +2,10 @@
|
||||
namespace Incoviba\Service\Venta;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use DateMalformedStringException;
|
||||
use PDOException;
|
||||
use Incoviba\Common\Implement\Exception\EmptyResult;
|
||||
use Incoviba\Exception\ServiceAction\Create;
|
||||
use Incoviba\Exception\ServiceAction\Read;
|
||||
use Incoviba\Repository;
|
||||
use Incoviba\Model;
|
||||
@ -35,16 +38,29 @@ class Subsidio
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
* @param array $data
|
||||
* @return Model\Venta\Subsidio
|
||||
* @throws Create
|
||||
*/
|
||||
public function add(array $data): Model\Venta\Subsidio
|
||||
{
|
||||
$fecha = new DateTimeImmutable($data['fecha']);
|
||||
$fecha = new DateTimeImmutable();
|
||||
try {
|
||||
$fecha = new DateTimeImmutable($data['fecha']);
|
||||
} catch (DateMalformedStringException) {}
|
||||
$uf = $data['uf'] ?? $this->moneyService->getUF($fecha);
|
||||
$tipoPago = $this->tipoPagoRepository->fetchByDescripcion('vale vista');
|
||||
try {
|
||||
$tipoPago = $this->tipoPagoRepository->fetchByDescripcion('vale vista');
|
||||
} catch (EmptyResult $exception) {
|
||||
throw new Create(__CLASS__, $exception);
|
||||
}
|
||||
$ahorro = $this->pagoService->add(['fecha' => $fecha->format('Y-m-d'), 'valor' => $this->valorService->clean($data['ahorro']) * $uf, 'uf' => $uf, 'tipo' => $tipoPago->id]);
|
||||
$subsidioPago = $this->pagoService->add(['fecha' => $fecha->format('Y-m-d'), 'valor' => $this->valorService->clean($data['subsidio']) * $uf, 'uf' => $uf, 'tipo' => $tipoPago->id]);
|
||||
$subsidio = $this->subsidioRepository->create(['pago' => $ahorro->id, 'subsidio' => $subsidioPago->id]);
|
||||
return $this->subsidioRepository->save($subsidio);
|
||||
try {
|
||||
return $this->subsidioRepository->save($subsidio);
|
||||
} catch (PDOException $exception) {
|
||||
throw new Create(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
<?php
|
||||
namespace Incoviba\Service\Venta;
|
||||
|
||||
use Incoviba\Exception\ServiceAction\Read;
|
||||
use PDOException;
|
||||
use Incoviba\Common\Implement\Repository\Factory;
|
||||
use Incoviba\Common\Implement\Exception\EmptyResult;
|
||||
use Incoviba\Exception\ServiceAction\Read;
|
||||
use Incoviba\Repository;
|
||||
use Incoviba\Service;
|
||||
use Incoviba\Model;
|
||||
|
||||
class Unidad
|
||||
@ -16,9 +16,18 @@ class Unidad
|
||||
protected Precio $precioService
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @param int $unidad_id
|
||||
* @return Model\Venta\Unidad
|
||||
* @throws Read
|
||||
*/
|
||||
public function getById(int $unidad_id): Model\Venta\Unidad
|
||||
{
|
||||
return $this->process($this->unidadRepository->fetchById($unidad_id));
|
||||
try {
|
||||
return $this->process($this->unidadRepository->fetchById($unidad_id));
|
||||
} catch (EmptyResult $exception) {
|
||||
throw new Read(__CLASS__, $exception);
|
||||
}
|
||||
}
|
||||
public function getByVenta(int $venta_id): array
|
||||
{
|
||||
@ -32,6 +41,10 @@ class Unidad
|
||||
{
|
||||
return array_map([$this, 'process'], $this->unidadRepository->fetchByCierre($cierre_id));
|
||||
}
|
||||
public function getByProyecto(int $proyecto_id): array
|
||||
{
|
||||
return array_map([$this, 'process'], $this->unidadRepository->fetchByProyecto($proyecto_id));
|
||||
}
|
||||
public function getDisponiblesByProyecto(int $proyecto_id): array
|
||||
{
|
||||
return $this->unidadRepository->fetchDisponiblesByProyecto($proyecto_id);
|
||||
@ -63,6 +76,10 @@ class Unidad
|
||||
$unidad->precios = $this->precioService->getByUnidad($unidad->id);
|
||||
$unidad->currentPrecio = $this->precioService->getVigenteByUnidad($unidad->id);
|
||||
} catch (Read) {}
|
||||
$unidad->addFactory('sold', (new Factory())
|
||||
->setCallable([$this->unidadRepository, 'fetchSoldByUnidad'])
|
||||
->setArgs(['unidad_id' => $unidad->id])
|
||||
);
|
||||
return $unidad;
|
||||
}
|
||||
}
|
||||
|
9
app/src/Service/Worker.php
Normal file
9
app/src/Service/Worker.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
namespace Incoviba\Service;
|
||||
|
||||
use Incoviba\Model;
|
||||
|
||||
interface Worker
|
||||
{
|
||||
public function execute(Model\Job $job): bool;
|
||||
}
|
51
app/src/Service/Worker/CheckExternal.php
Normal file
51
app/src/Service/Worker/CheckExternal.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
namespace Incoviba\Service\Worker;
|
||||
|
||||
use Psr\Container\ContainerExceptionInterface;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Incoviba\Common\Ideal;
|
||||
use Incoviba\Model;
|
||||
use Incoviba\Service;
|
||||
|
||||
class CheckExternal extends Ideal\Service implements Service\Worker
|
||||
{
|
||||
public function __construct(LoggerInterface $logger, protected ContainerInterface $container)
|
||||
{
|
||||
parent::__construct($logger);
|
||||
}
|
||||
protected Service\Queue $queueService;
|
||||
|
||||
public function execute(Model\Job $job): bool
|
||||
{
|
||||
$configuration = $job->configuration;
|
||||
$serviceClass = $configuration['service'];
|
||||
if (!$this->container->has($serviceClass)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
$service = $this->container->get($serviceClass);
|
||||
} catch (NotFoundExceptionInterface | ContainerExceptionInterface) {
|
||||
return false;
|
||||
}
|
||||
$method = $configuration['method'] ?? 'check';
|
||||
|
||||
if (!method_exists($service, $method)) {
|
||||
return false;
|
||||
}
|
||||
if (!isset($this->queueService)) {
|
||||
$this->queueService = $this->container->get(Service\Queue::class);
|
||||
}
|
||||
if (isset($configuration['args'])) {
|
||||
$args = $configuration['args'];
|
||||
$queues = call_user_func_array([$service, $method], $args);
|
||||
} else {
|
||||
$queues = call_user_func([$service, $method]);
|
||||
}
|
||||
foreach ($queues as $queue) {
|
||||
$this->queueService->enqueue($queue);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
17
app/src/Service/Worker/Dummy.php
Normal file
17
app/src/Service/Worker/Dummy.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
namespace Incoviba\Service\Worker;
|
||||
|
||||
use Incoviba\Common\Ideal;
|
||||
use Incoviba\Model;
|
||||
use Incoviba\Service;
|
||||
|
||||
class Dummy extends Ideal\Service implements Service\Worker
|
||||
{
|
||||
|
||||
public function execute(Model\Job $job): bool
|
||||
{
|
||||
$configuration = $job->configuration;
|
||||
$this->logger->info('Dummy worker executed', ['configuration' => $configuration]);
|
||||
return true;
|
||||
}
|
||||
}
|
62
app/src/Service/Worker/Request.php
Normal file
62
app/src/Service/Worker/Request.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
namespace Incoviba\Service\Worker;
|
||||
|
||||
use Incoviba\Common\Implement\Exception\EmptyResponse;
|
||||
use Incoviba\Service\Worker;
|
||||
use Psr\Http\Client\ClientExceptionInterface;
|
||||
use Psr\Http\Client\ClientInterface;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Incoviba\Common\Ideal;
|
||||
use Incoviba\Model;
|
||||
|
||||
class Request extends Ideal\Service implements Worker
|
||||
{
|
||||
public function __construct(LoggerInterface $logger, protected ClientInterface $client)
|
||||
{
|
||||
parent::__construct($logger);
|
||||
}
|
||||
|
||||
protected RequestInterface $request;
|
||||
public function setRequest(RequestInterface $request): self
|
||||
{
|
||||
$this->request = $request;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model\Job $job
|
||||
* @return bool
|
||||
* @throws EmptyResponse
|
||||
*/
|
||||
public function execute(Model\Job $job): bool
|
||||
{
|
||||
$url = $job->configuration['url'] ?? $job->configuration['action'];
|
||||
$method = strtolower($job->configuration['method']) ?? 'get';
|
||||
$body = $job->configuration['body'];
|
||||
|
||||
try {
|
||||
$response = $this->client->{$method}($url, [
|
||||
'json' => $body,
|
||||
'headers' => [
|
||||
'Authorization' => $this->request->getHeaderLine('Authorization')
|
||||
]
|
||||
]);
|
||||
} catch (ClientExceptionInterface $exception) {
|
||||
throw new EmptyResponse($url, $exception);
|
||||
}
|
||||
|
||||
$statusCode = $response->getStatusCode();
|
||||
if ((int) floor($statusCode / 100) !== 2) {
|
||||
throw new EmptyResponse($url);
|
||||
}
|
||||
if ($statusCode !== 204) {
|
||||
$contents = $response->getBody()->getContents();
|
||||
$data = json_decode($contents, true);
|
||||
if (!isset($data['success']) or !$data['success']) {
|
||||
throw new EmptyResponse($url);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
50
app/src/Service/Worker/Service.php
Normal file
50
app/src/Service/Worker/Service.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
namespace Incoviba\Service\Worker;
|
||||
|
||||
use Exception;
|
||||
use Psr\Container\ContainerExceptionInterface;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Incoviba\Common\Ideal;
|
||||
use Incoviba\Model;
|
||||
use Incoviba\Service\Worker;
|
||||
|
||||
class Service extends Ideal\Service implements Worker
|
||||
{
|
||||
public function __construct(protected ContainerInterface $container ,LoggerInterface $logger)
|
||||
{
|
||||
parent::__construct($logger);
|
||||
}
|
||||
|
||||
public function execute(Model\Job $job): bool
|
||||
{
|
||||
$configuration = $job->configuration;
|
||||
$serviceClass = $configuration['service'];
|
||||
$method = $configuration['method'];
|
||||
$params = $configuration['params'] ?? [];
|
||||
try {
|
||||
$service = $this->container->get($serviceClass);
|
||||
} catch (NotFoundExceptionInterface | ContainerExceptionInterface $exception) {
|
||||
$this->logger->error($exception->getMessage());
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
$result = call_user_func_array([$service, $method], $params);
|
||||
} catch (Exception $exception) {
|
||||
$this->logger->error($exception->getMessage(), [
|
||||
'Worker' => __CLASS__,
|
||||
'job_id' => $job->id,
|
||||
'service' => $serviceClass,
|
||||
'method' => $method,
|
||||
'params' => $params,
|
||||
'exception' => $exception
|
||||
]);
|
||||
return false;
|
||||
}
|
||||
if (is_bool($result)) {
|
||||
return $result;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user