feature/cierres (#25)

Varios cambios

Co-authored-by: Juan Pablo Vial <jpvialb@incoviba.cl>
Reviewed-on: #25
This commit is contained in:
2025-07-22 13:18:00 +00:00
parent ba57cad514
commit 307f2ac7d7
418 changed files with 20045 additions and 984 deletions

View File

@ -7,11 +7,11 @@ use Incoviba\Model\Inmobiliaria\TipoSociedad;
class Inmobiliaria extends Model
{
public int $rut;
public ?string $dv;
public ?string $razon;
public ?string $abreviacion;
public ?TipoSociedad $tipoSociedad;
public string $sigla;
public ?string $dv = null;
public ?string $razon = null;
public ?string $abreviacion = null;
public ?TipoSociedad $tipoSociedad = null;
public ?string $sigla = null;
public function rut(): string
{
@ -37,7 +37,7 @@ class Inmobiliaria extends Model
'razon' => $this->razon ?? '',
'abreviacion' => $this->abreviacion ?? '',
'tipo_sociedad' => $this->tipoSociedad ?? '',
'sigla' => $this->sigla,
'sigla' => $this->sigla ?? '',
];
}
}

20
app/src/Model/Job.php Normal file
View File

@ -0,0 +1,20 @@
<?php
namespace Incoviba\Model;
use Incoviba\Common\Ideal;
class Job extends Ideal\Model
{
public array $configuration;
public bool $executed = false;
public int $retries = 0;
protected function jsonComplement(): array
{
return [
'configuration' => $this->configuration,
'executed' => $this->executed,
'retries' => $this->retries
];
}
}

View File

@ -1,6 +1,7 @@
<?php
namespace Incoviba\Model;
use InvalidArgumentException;
use Incoviba\Common\Ideal;
use Incoviba\Model\Persona\Datos;
@ -31,6 +32,20 @@ class Persona extends Ideal\Model
return $this->datos;
}
public function __get(string $name): mixed
{
if (property_exists($this, $name)) {
return $this->{$name};
}
if ($name === 'datos') {
return $this->datos();
}
if ($name === 'dv') {
return $this->digito;
}
throw new InvalidArgumentException("Property {$name} is not found in " . __CLASS__);
}
public function jsonSerialize(): mixed
{
return [

View File

@ -0,0 +1,45 @@
<?php
namespace Incoviba\Model\Proyecto;
use Incoviba\Common;
class Broker extends Common\Ideal\Model
{
public int $rut;
public string $digit;
public string $name;
protected ?Broker\Data $data;
public function data(): ?Broker\Data
{
if (!isset($this->data)) {
$this->data = $this->runFactory('data');
}
return $this->data;
}
protected array $contracts;
public function contracts(): ?array
{
if (!isset($this->contracts)) {
$this->contracts = $this->runFactory('contracts');
}
return $this->contracts;
}
public function rutFull(): string
{
return implode('-', [number_format($this->rut, 0, ',', '.'), $this->digit]);
}
public function jsonSerialize(): mixed
{
return [
'rut' => $this->rut,
'digit' => $this->digit,
'name' => $this->name,
'data' => $this->data(),
'rut_full' => $this->rutFull()
];
}
}

View File

@ -0,0 +1,24 @@
<?php
namespace Incoviba\Model\Proyecto\Broker;
use Incoviba\Common\Ideal;
use Incoviba\Model\Direccion;
use Incoviba\Model\Proyecto\Broker;
class Contact extends Ideal\Model
{
public string $name;
public ?string $email = null;
public ?string $phone = null;
public ?Direccion $address = null;
protected function jsonComplement(): array
{
return [
'name' => $this->name,
'email' => $this->email,
'phone' => $this->phone,
'address' => $this->address
];
}
}

View File

@ -0,0 +1,54 @@
<?php
namespace Incoviba\Model\Proyecto\Broker;
use Incoviba\Common;
use Incoviba\Model;
class Contract extends Common\Ideal\Model
{
public Model\Proyecto $project;
public Model\Proyecto\Broker $broker;
public float $commission;
protected ?array $states;
public function states(): ?array
{
if (!isset($this->states) or count($this->states) === 0) {
$this->states = $this->runFactory('states');
}
return $this->states;
}
protected ?Contract\State $current;
public function current(): ?Contract\State
{
if (!isset($this->current)) {
try {
$this->current = last($this->states());
} catch (\TypeError $error) {
$this->current = null;
}
}
return $this->current;
}
protected array $promotions = [];
public function promotions(): array
{
if (count($this->promotions) === 0) {
$this->promotions = $this->runFactory('promotions');
}
return $this->promotions;
}
protected function jsonComplement(): array
{
return [
'project_id' => $this->project->id,
'broker_rut' => $this->broker->rut,
'commission' => $this->commission,
'states' => $this->states(),
'current' => $this->current(),
];
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace Incoviba\Model\Proyecto\Broker\Contract;
use DateTimeInterface;
use Incoviba\Common;
use Incoviba\Model;
class State extends Common\Ideal\Model
{
public Model\Proyecto\Broker\Contract $contract;
public DateTimeInterface $date;
public State\Type $type;
protected function jsonComplement(): array
{
return [
'contract_id' => $this->contract->id,
'date' => $this->date->format('Y-m-d'),
'type' => [
'id' => $this->type->value,
'description' => $this->type->name
]
];
}
}

View File

@ -0,0 +1,17 @@
<?php
namespace Incoviba\Model\Proyecto\Broker\Contract\State;
enum Type: int
{
case ACTIVE = 1;
case INACTIVE = 0;
public static function name(int $type): string
{
return match ($type) {
self::ACTIVE => 'active',
self::INACTIVE => 'inactive',
default => throw new \InvalidArgumentException('Unexpected match value')
};
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace Incoviba\Model\Proyecto\Broker;
use Incoviba\Common;
use Incoviba\Model;
class Data extends Common\Ideal\Model
{
public Model\Proyecto\Broker $broker;
public ?Model\Proyecto\Broker\Contact $representative = null;
public ?string $legalName = null;
protected function jsonComplement(): array
{
return [
'broker_rut' => $this->broker->rut,
'representative' => $this->representative,
'legal_name' => $this->legalName
];
}
}

View File

@ -43,6 +43,15 @@ class ProyectoTipoUnidad extends Ideal\Model
return $this->abreviacion;
}
protected array $unidades;
public function unidades(): array
{
if (!isset($this->unidades)) {
$this->unidades = $this->runFactory('unidades');
}
return $this->unidades;
}
public function jsonSerialize(): mixed
{
return array_merge(parent::jsonSerialize(), [

19
app/src/Model/UF.php Normal file
View File

@ -0,0 +1,19 @@
<?php
namespace Incoviba\Model;
use DateTimeInterface;
use Incoviba\Common\Ideal;
class UF extends Ideal\Model
{
public DateTimeInterface $fecha;
public ?float $valor;
public function jsonSerialize(): array
{
return [
'fecha' => $this->fecha,
'valor' => $this->valor
];
}
}

View File

@ -19,6 +19,19 @@ class Cuota extends Model
public ?Pago $pago;
public ?int $numero;
public function isPagada(): bool
{
return $this->pago->isPagado();
}
public function isAbonada(): bool
{
return $this->pago->isAbonado();
}
public function isRechazada(): bool
{
return $this->pago->isRechazado();
}
public function jsonSerialize(): mixed
{
return array_merge(parent::jsonSerialize(), [

View File

@ -6,12 +6,12 @@ use Incoviba\Model\Direccion;
class Datos
{
public ?string $sexo;
public ?string $estado_civil;
public ?string $profesion;
public ?Direccion $direccion;
public ?int $telefono;
public ?string $email;
public ?string $sexo = null;
public ?string $estado_civil = null;
public ?string $profesion = null;
public ?Direccion $direccion = null;
public ?int $telefono = null;
public ?string $email = null;
public function jsonSerialize(): mixed
{

View File

@ -59,7 +59,7 @@ class FormaPago implements JsonSerializable
public function cuotasAbono(string $moneda = Pago::UF): float
{
return array_reduce($this->cuotasAbono, function($sum, $cuota) use ($moneda) {
if ($cuota->currentEstado->tipoEstadoPago->descripcion === 'abonado') {
if ($cuota->pago->currentEstado->tipoEstadoPago->descripcion === 'abonado') {
return $sum + $cuota->pago->valor($moneda);
}
return $sum;

View File

@ -0,0 +1,24 @@
<?php
namespace Incoviba\Model\Venta\MediosPago\Toku;
use Incoviba\Common\Ideal;
use Incoviba\Model\Persona;
class Customer extends Ideal\Model
{
public Persona $persona;
public string $toku_id;
public function rut(): string
{
return implode('', [$this->persona->rut, strtoupper($this->persona->digito)]);
}
protected function jsonComplement(): array
{
return [
'rut' => $this->rut(),
'toku_id' => $this->toku_id
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace Incoviba\Model\Venta\MediosPago\Toku;
use Incoviba\Common\Ideal;
use Incoviba\Model\Venta\Cuota;
class Invoice extends Ideal\Model
{
public Cuota $cuota;
public string $toku_id;
protected function jsonComplement(): array
{
return [
'cuota_id' => $this->cuota->id,
'toku_id' => $this->toku_id
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace Incoviba\Model\Venta\MediosPago\Toku;
use Incoviba\Common\Ideal;
use Incoviba\Model\Venta;
class Subscription extends Ideal\Model
{
public Venta $venta;
public string $toku_id;
protected function jsonComplement(): array
{
return [
'venta_id' => $this->venta->id,
'toku_id' => $this->toku_id
];
}
}

View File

@ -51,6 +51,19 @@ class Pago extends Model
return null;
}
public function isPagado(): bool
{
return in_array($this->currentEstado->tipoEstadoPago->descripcion, ['depositado', 'abonado']);
}
public function isAbonado(): bool
{
return $this->currentEstado->tipoEstadoPago->descripcion === 'abonado';
}
public function isRechazado(): bool
{
return in_array($this->currentEstado->tipoEstadoPago->descripcion, ['devuelto', 'reemplazado', 'anulado']);
}
public function jsonSerialize(): mixed
{
return array_merge(parent::jsonSerialize(), [

View File

@ -0,0 +1,87 @@
<?php
namespace Incoviba\Model\Venta;
use DateTimeInterface;
use Incoviba\Common;
use Incoviba\Model\Proyecto\Broker;
use Incoviba\Model\Venta\Promotion\State;
use Incoviba\Model\Venta\Promotion\Type;
class Promotion extends Common\Ideal\Model
{
public string $description;
public float $amount;
public DateTimeInterface $startDate;
public ?DateTimeInterface $endDate;
public ?DateTimeInterface $validUntil;
public Type $type;
public State $state = State::ACTIVE;
protected array $projects;
public function projects(): array
{
if (empty($this->projects)) {
$this->projects = $this->runFactory('projects') ?? [];
}
return $this->projects;
}
protected array $brokers;
public function brokers(): array
{
if (empty($this->brokers)) {
$this->brokers = $this->runFactory('brokers') ?? [];
}
return $this->brokers;
}
protected array $unitTypes;
public function unitTypes(): array
{
if (empty($this->unitTypes)) {
$this->unitTypes = $this->runFactory('unitTypes') ?? [];
}
return $this->unitTypes;
}
protected array $unitLines;
public function unitLines(): array
{
if (empty($this->unitLines)) {
$this->unitLines = $this->runFactory('unitLines') ?? [];
}
return $this->unitLines;
}
protected array $units;
public function units(): array
{
if (empty($this->units)) {
$this->units = $this->runFactory('units') ?? [];
}
return $this->units;
}
public function value(float $price): float
{
if ($this->type === Type::FIXED) {
return $price + $this->amount;
}
return $price / (1 - $this->amount);
}
protected function jsonComplement(): array
{
return [
'description' => $this->description,
'amount' => $this->amount,
'start_date' => $this->startDate->format('Y-m-d'),
'end_date' => $this->endDate?->format('Y-m-d'),
'valid_until' => $this->validUntil?->format('Y-m-d'),
'type' => $this->type,
'state' => $this->state,
'projects' => $this->projects() ?? [],
'contracts' => $this->brokers() ?? [],
'units' => $this->units() ?? []
];
}
}

View File

@ -0,0 +1,17 @@
<?php
namespace Incoviba\Model\Venta\Promotion;
enum State: int
{
case ACTIVE = 1;
case INACTIVE = 0;
public static function name(int $state): string
{
return match ($state) {
self::ACTIVE => 'active',
self::INACTIVE => 'inactive',
default => throw new \InvalidArgumentException('Unexpected match value')
};
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace Incoviba\Model\Venta\Promotion;
enum Type: int
{
case FIXED = 1;
case VARIABLE = 2;
public function name(): string
{
return match ($this) {
self::FIXED => 'fijo',
self::VARIABLE => 'variable'
};
}
}

View File

@ -9,7 +9,7 @@ class Propiedad extends Ideal\Model
public array $unidades = [];
public bool $estado;
public function principal(): Unidad
public function principal(): ?Unidad
{
if (count($this->departamentos()) > 0) {
return $this->departamentos()[0];

View File

@ -11,8 +11,8 @@ class Propietario extends Model
public string $nombres;
public array $apellidos;
public Datos $datos;
public ?Propietario $representante;
public ?bool $otro;
public ?Propietario $representante = null;
public ?bool $otro = null;
public function rut(): string
{

View File

@ -0,0 +1,83 @@
<?php
namespace Incoviba\Model\Venta;
use DateTimeInterface;
use Incoviba\Common;
use Incoviba\Model;
class Reservation extends Common\Ideal\Model
{
public Model\Persona $buyer;
public DateTimeInterface $date;
public array $units = [];
public array $promotions = [];
public ?Model\Proyecto\Broker $broker = null;
protected array $states = [];
public function states(): array
{
if (!isset($this->states)) {
$this->states = $this->runFactory('states');
}
return $this->states;
}
protected Model\Venta\Reservation\State $currentState;
public function currentState(): Model\Venta\Reservation\State
{
if (!isset($this->currentState)) {
$this->currentState = last($this->states());
}
return $this->currentState;
}
public function addUnit(Model\Venta\Unidad $unit, float $value): self
{
if (($i = $this->findUnit($unit->id)) !== null) {
$this->units[$i]['value'] = $value;
return $this;
}
$this->units[] = [
'unit' => $unit,
'value' => $value,
];
return $this;
}
public function removeUnit(int $unit_id): self
{
if (($i = $this->findUnit($unit_id)) === null) {
return $this;
}
unset($this->units[$i]);
$this->units = array_values($this->units);
return $this;
}
public function findUnit(int $unit_id): ?int
{
foreach ($this->units as $idx => $unit) {
if ($unit['unit']->id == $unit_id) {
return $idx;
}
}
return null;
}
public function hasUnit(int $unit_id): bool
{
return $this->findUnit($unit_id) !== null;
}
protected function jsonComplement(): array
{
return [
'buyer_rut' => $this->buyer->rut,
'date' => $this->date->format('Y-m-d'),
'units' => $this->units,
'promotions' => $this->promotions,
'broker_rut' => $this->broker?->rut,
];
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace Incoviba\Model\Venta\Reservation;
use DateTimeInterface;
use Incoviba\Common;
use Incoviba\Model;
class State extends Common\Ideal\Model
{
public Model\Venta\Reservation $reservation;
public DateTimeInterface $date;
public int $type;
protected function jsonComplement(): array
{
return [
'reservation_id' => $this->reservation->id,
'date' => $this->date->format('Y-m-d'),
'type' => [
'id' => $this->type,
'description' => State\Type::name($this->type)
]
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace Incoviba\Model\Venta\Reservation\State;
enum Type: int
{
case ACTIVE = 1;
case INACTIVE = 0;
case REJECTED = -1;
public static function name(int $type): string
{
return match ($type) {
self::ACTIVE => 'active',
self::INACTIVE => 'inactive',
self::REJECTED => 'rejected',
default => throw new \InvalidArgumentException('Unexpected match value')
};
}
}

View File

@ -45,6 +45,18 @@ class Unidad extends Ideal\Model
return $precio;
}
protected bool $sold;
public function sold(): bool
{
if (!isset($this->sold)) {
$this->sold = false;
try {
$this->sold = $this->runFactory('sold') ?? false;
} catch (EmptyResult) {}
}
return $this->sold;
}
public function jsonSerialize(): mixed
{
$output = array_merge(parent::jsonSerialize(), [
@ -59,6 +71,7 @@ class Unidad extends Ideal\Model
$output['precios'] = $this->precios;
$output['current_precio'] = $this->currentPrecio;
}
$output['sold'] = $this->sold() ?? false;
return $output;
}
}