Merge pull request 'feature/cuotas-abono-escritura' (#1) from feature/cuotas-abono-escritura into develop

Reviewed-on: #1
This commit is contained in:
2024-11-28 22:24:48 +00:00
30 changed files with 836 additions and 2123 deletions

View File

@ -2,454 +2,13 @@
use Phinx\Db\Adapter\MysqlAdapter;
class Incoviba2287310996733f7d5ac59c extends Phinx\Migration\AbstractMigration
class Incoviba17303572256733fad3df01b extends Phinx\Migration\AbstractMigration
{
public function change()
{
$this->execute('SET unique_checks=0; SET foreign_key_checks=0;');
$this->execute("ALTER DATABASE CHARACTER SET 'utf8mb3';");
$this->execute("ALTER DATABASE COLLATE='utf8mb3_general_ci';");
$this->table('movimientos_auxiliares', [
'id' => false,
'primary_key' => ['id'],
'engine' => 'InnoDB',
'encoding' => 'utf8mb3',
'collation' => 'utf8mb3_general_ci',
'comment' => '',
'row_format' => 'DYNAMIC',
])
->addColumn('id', 'integer', [
'null' => false,
'limit' => 10,
'signed' => false,
'identity' => true,
])
->addColumn('movimiento_id', 'integer', [
'null' => false,
'limit' => 10,
'signed' => false,
'after' => 'id',
])
->addColumn('cargo', 'integer', [
'null' => true,
'default' => null,
'limit' => 10,
'signed' => false,
'after' => 'movimiento_id',
])
->addColumn('abono', 'integer', [
'null' => true,
'default' => null,
'limit' => 10,
'signed' => false,
'after' => 'cargo',
])
->addIndex(['movimiento_id'], [
'name' => 'movimiento_id',
'unique' => false,
])
->addForeignKey('movimiento_id', 'movimientos', 'id', [
'constraint' => 'movimientos_auxiliares_ibfk_2',
'update' => 'CASCADE',
'delete' => 'CASCADE',
])
->create();
$this->table('datos_personas', [
'id' => false,
'primary_key' => ['persona_rut'],
'engine' => 'InnoDB',
'encoding' => 'utf8mb3',
'collation' => 'utf8mb3_general_ci',
'comment' => '',
'row_format' => 'DYNAMIC',
])
->addColumn('persona_rut', 'integer', [
'null' => false,
'limit' => 10,
'signed' => false,
])
->addColumn('direccion_id', 'integer', [
'null' => true,
'default' => null,
'limit' => 10,
'signed' => false,
'after' => 'persona_rut',
])
->addColumn('telefono', 'integer', [
'null' => true,
'default' => null,
'limit' => 10,
'signed' => false,
'after' => 'direccion_id',
])
->addColumn('email', 'string', [
'null' => true,
'default' => null,
'limit' => 100,
'collation' => 'utf8mb3_general_ci',
'encoding' => 'utf8mb3',
'after' => 'telefono',
])
->addColumn('sexo', 'enum', [
'null' => true,
'default' => null,
'limit' => 2,
'values' => ['M', 'F', 'NA'],
'after' => 'email',
])
->addColumn('fecha_nacimiento', 'date', [
'null' => true,
'default' => null,
'after' => 'sexo',
])
->addColumn('estado_civil', 'enum', [
'null' => true,
'default' => null,
'limit' => 10,
'values' => ['casado', 'soltero', 'divorciado'],
'after' => 'fecha_nacimiento',
])
->addColumn('nacionalidad', 'string', [
'null' => true,
'default' => null,
'limit' => 100,
'collation' => 'utf8mb3_general_ci',
'encoding' => 'utf8mb3',
'after' => 'estado_civil',
])
->addColumn('profesion', 'string', [
'null' => true,
'default' => null,
'limit' => 100,
'collation' => 'utf8mb3_general_ci',
'encoding' => 'utf8mb3',
'after' => 'nacionalidad',
])
->addIndex(['direccion_id'], [
'name' => 'direccion_id',
'unique' => false,
])
->addIndex(['telefono'], [
'name' => 'telefono',
'unique' => false,
])
->addForeignKey('direccion_id', 'direccion', 'id', [
'constraint' => 'datos_personas_ibfk_4',
'update' => 'SET_NULL',
'delete' => 'SET_NULL',
])
->addForeignKey('persona_rut', 'personas', 'rut', [
'constraint' => 'datos_personas_ibfk_7',
'update' => 'CASCADE',
'delete' => 'CASCADE',
])
->create();
$this->table('personas', [
'id' => false,
'primary_key' => ['rut'],
'engine' => 'InnoDB',
'encoding' => 'utf8mb3',
'collation' => 'utf8mb3_general_ci',
'comment' => '',
'row_format' => 'DYNAMIC',
])
->addColumn('rut', 'integer', [
'null' => false,
'limit' => 10,
'signed' => false,
])
->addColumn('digito', 'char', [
'null' => false,
'limit' => 1,
'collation' => 'utf8mb3_general_ci',
'encoding' => 'utf8mb3',
'after' => 'rut',
])
->addColumn('nombres', 'string', [
'null' => false,
'limit' => 100,
'collation' => 'utf8mb3_general_ci',
'encoding' => 'utf8mb3',
'after' => 'digito',
])
->addColumn('apellido_paterno', 'string', [
'null' => false,
'limit' => 100,
'collation' => 'utf8mb3_general_ci',
'encoding' => 'utf8mb3',
'after' => 'nombres',
])
->addColumn('apellido_materno', 'string', [
'null' => false,
'limit' => 100,
'collation' => 'utf8mb3_general_ci',
'encoding' => 'utf8mb3',
'after' => 'apellido_paterno',
])
->create();
$this->table('tipos_estados_facturas', [
'id' => false,
'primary_key' => ['id'],
'engine' => 'InnoDB',
'encoding' => 'utf8mb3',
'collation' => 'utf8mb3_general_ci',
'comment' => '',
'row_format' => 'DYNAMIC',
])
->addColumn('id', 'integer', [
'null' => false,
'limit' => 10,
'signed' => false,
'identity' => true,
])
->addColumn('descripcion', 'string', [
'null' => false,
'limit' => 100,
'collation' => 'utf8mb3_general_ci',
'encoding' => 'utf8mb3',
'after' => 'id',
])
->create();
$this->table('estados_facturas', [
'id' => false,
'primary_key' => ['id'],
'engine' => 'InnoDB',
'encoding' => 'utf8mb3',
'collation' => 'utf8mb3_general_ci',
'comment' => '',
'row_format' => 'DYNAMIC',
])
->addColumn('id', 'integer', [
'null' => false,
'limit' => 10,
'signed' => false,
'identity' => true,
])
->addColumn('factura_id', 'integer', [
'null' => false,
'limit' => 10,
'signed' => false,
'after' => 'id',
])
->addColumn('fecha', 'date', [
'null' => false,
'after' => 'factura_id',
])
->addColumn('tipo_id', 'integer', [
'null' => false,
'limit' => 10,
'signed' => false,
'after' => 'fecha',
])
->addIndex(['factura_id'], [
'name' => 'factura_id',
'unique' => false,
])
->addIndex(['tipo_id'], [
'name' => 'tipo_id',
'unique' => false,
])
->addForeignKey('factura_id', 'facturas', 'id', [
'constraint' => 'estados_facturas_ibfk_3',
'update' => 'CASCADE',
'delete' => 'CASCADE',
])
->addForeignKey('tipo_id', 'tipos_estados_facturas', 'id', [
'constraint' => 'estados_facturas_ibfk_4',
'update' => 'CASCADE',
'delete' => 'CASCADE',
])
->create();
$this->table('sociedades', [
'id' => false,
'primary_key' => ['rut'],
'engine' => 'InnoDB',
'encoding' => 'utf8mb3',
'collation' => 'utf8mb3_general_ci',
'comment' => '',
'row_format' => 'DYNAMIC',
])
->addColumn('rut', 'integer', [
'null' => false,
'limit' => 10,
'signed' => false,
])
->addColumn('digito', 'char', [
'null' => false,
'limit' => 1,
'collation' => 'utf8mb3_general_ci',
'encoding' => 'utf8mb3',
'after' => 'rut',
])
->addColumn('nombre', 'string', [
'null' => false,
'limit' => 100,
'collation' => 'utf8mb3_general_ci',
'encoding' => 'utf8mb3',
'after' => 'digito',
])
->addColumn('razon', 'text', [
'null' => false,
'limit' => 65535,
'collation' => 'utf8mb3_general_ci',
'encoding' => 'utf8mb3',
'after' => 'nombre',
])
->addColumn('tipo_sociedad_id', 'integer', [
'null' => false,
'limit' => 10,
'signed' => false,
'after' => 'razon',
])
->addColumn('contacto_rut', 'integer', [
'null' => false,
'limit' => 10,
'signed' => false,
'after' => 'tipo_sociedad_id',
])
->addIndex(['tipo_sociedad_id'], [
'name' => 'tipo_sociedad_id',
'unique' => false,
])
->addIndex(['contacto_rut'], [
'name' => 'representante_rut',
'unique' => false,
])
->addForeignKey('tipo_sociedad_id', 'tipo_sociedad', 'id', [
'constraint' => 'sociedades_ibfk_1',
'update' => 'RESTRICT',
'delete' => 'CASCADE',
])
->addForeignKey('contacto_rut', 'personas', 'rut', [
'constraint' => 'sociedades_ibfk_2',
'update' => 'RESTRICT',
'delete' => 'CASCADE',
])
->create();
$this->table('proveedores', [
'id' => false,
'primary_key' => ['id'],
'engine' => 'InnoDB',
'encoding' => 'utf8mb3',
'collation' => 'utf8mb3_general_ci',
'comment' => '',
'row_format' => 'DYNAMIC',
])
->addColumn('id', 'integer', [
'null' => false,
'limit' => 10,
'signed' => false,
'identity' => true,
])
->addColumn('inmobiliaria_rut', 'integer', [
'null' => false,
'limit' => 8,
'signed' => false,
'after' => 'id',
])
->addColumn('sociedad_rut', 'integer', [
'null' => false,
'limit' => 10,
'signed' => false,
'after' => 'inmobiliaria_rut',
])
->addIndex(['inmobiliaria_rut'], [
'name' => 'inmobiliaria_rut',
'unique' => false,
])
->addIndex(['sociedad_rut'], [
'name' => 'sociedad_rut',
'unique' => false,
])
->addForeignKey('inmobiliaria_rut', 'inmobiliaria', 'rut', [
'constraint' => 'proveedores_ibfk_1',
'update' => 'RESTRICT',
'delete' => 'CASCADE',
])
->addForeignKey('sociedad_rut', 'sociedades', 'rut', [
'constraint' => 'proveedores_ibfk_2',
'update' => 'RESTRICT',
'delete' => 'CASCADE',
])
->create();
$this->table('auxiliar_detalles', [
'id' => false,
'engine' => 'InnoDB',
'encoding' => 'utf8mb3',
'collation' => 'utf8mb3_general_ci',
'comment' => '',
'row_format' => 'DYNAMIC',
])
->addColumn('auxiliar_id', 'integer', [
'null' => false,
'limit' => 10,
'signed' => false,
])
->addColumn('centro_costo_id', 'integer', [
'null' => true,
'default' => null,
'limit' => 10,
'signed' => false,
'after' => 'auxiliar_id',
])
->addColumn('rut', 'integer', [
'null' => true,
'default' => null,
'limit' => 8,
'signed' => false,
'after' => 'centro_costo_id',
])
->addColumn('digito', 'char', [
'null' => true,
'default' => null,
'limit' => 1,
'collation' => 'utf8mb3_general_ci',
'encoding' => 'utf8mb3',
'after' => 'rut',
])
->addColumn('nombre', 'string', [
'null' => true,
'default' => null,
'limit' => 255,
'collation' => 'utf8mb3_general_ci',
'encoding' => 'utf8mb3',
'after' => 'digito',
])
->addColumn('categoria', 'string', [
'null' => true,
'default' => null,
'limit' => 100,
'collation' => 'utf8mb3_general_ci',
'encoding' => 'utf8mb3',
'after' => 'nombre',
])
->addColumn('detalle', 'text', [
'null' => true,
'default' => null,
'limit' => 65535,
'collation' => 'utf8mb3_general_ci',
'encoding' => 'utf8mb3',
'after' => 'categoria',
])
->addIndex(['auxiliar_id'], [
'name' => 'auxiliar_id',
'unique' => false,
])
->addIndex(['centro_costo_id'], [
'name' => 'centro_costo_id',
'unique' => false,
])
->addForeignKey('auxiliar_id', 'movimientos_auxiliares', 'id', [
'constraint' => 'auxiliar_detalles_ibfk_3',
'update' => 'CASCADE',
'delete' => 'CASCADE',
])
->addForeignKey('centro_costo_id', 'centros_costos', 'id', [
'constraint' => 'auxiliar_detalles_ibfk_5',
'update' => 'CASCADE',
'delete' => 'SET_NULL',
])
->create();
$this->table('tipo_estado_cierre', [
'id' => false,
'primary_key' => ['id'],

View File

@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class CreatePersonas extends AbstractMigration
{
/**
* Change Method.
*
* Write your reversible migrations using this method.
*
* More information on writing migrations is available here:
* https://book.cakephp.org/phinx/0/en/migrations.html#the-change-method
*
* Remember to call "create()" or "update()" and NOT "save()" when working
* with the Table class.
*/
public function change(): void
{
$this->table('personas', ['id' => false, 'primary_key' => ['rut', 'digito']])
->addColumn('rut', 'integer', ['identity' => true, 'signed' => false, 'null' => false])
->addColumn('digito', 'string', ['limit' => 1, 'null' => false])
->addColumn('nombres', 'string', ['limit' => 255, 'null' => false])
->addColumn('apellido_paterno', 'string', ['limit' => 255, 'null' => false])
->addColumn('apellido_materno', 'string', ['limit' => 255, 'null' => false])
->create();
}
}

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class CreateProveedores extends AbstractMigration
{
/**
* Change Method.
*
* Write your reversible migrations using this method.
*
* More information on writing migrations is available here:
* https://book.cakephp.org/phinx/0/en/migrations.html#the-change-method
*
* Remember to call "create()" or "update()" and NOT "save()" when working
* with the Table class.
*/
public function change(): void
{
$this->table('proveedores', ['id' => false, 'primary_key' => ['rut', 'digito']])
->addColumn('rut', 'integer', ['identity' => true, 'signed' => false, 'null' => false])
->addColumn('digito', 'string', ['limit' => 1, 'null' => false])
->addColumn('nombre', 'string', ['limit' => 255, 'null' => false])
->addColumn('razon', 'string', ['limit' => 255, 'null' => true])
->addColumn('contacto_rut', 'integer', ['signed' => false, 'null' => true])
->addForeignKey('contacto_rut', 'personas', ['rut'], ['delete' => 'CASCADE', 'update' => 'CASCADE'])
->create();
}
}

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class CreateDatosProveedores extends AbstractMigration
{
/**
* Change Method.
*
* Write your reversible migrations using this method.
*
* More information on writing migrations is available here:
* https://book.cakephp.org/phinx/0/en/migrations.html#the-change-method
*
* Remember to call "create()" or "update()" and NOT "save()" when working
* with the Table class.
*/
public function change(): void
{
$this->table('datos_proveedores')
->addColumn('proveedor_rut', 'integer', ['signed' => false, 'null' => false])
->addForeignKey('proveedor_rut', 'proveedores', ['rut'], ['delete' => 'CASCADE', 'update' => 'CASCADE'])
->addColumn('direccion_id', 'integer', ['signed' => false, 'null' => true])
->addForeignKey('direccion_id', 'direccion', ['id'], ['delete' => 'CASCADE', 'update' => 'CASCADE'])
->addColumn('telefono', 'string', ['limit' => 255, 'null' => true])
->addColumn('giro', 'string', ['limit' => 255, 'null' => true])
->create();
}
}

View File

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class CreateDatosPersonas extends AbstractMigration
{
/**
* Change Method.
*
* Write your reversible migrations using this method.
*
* More information on writing migrations is available here:
* https://book.cakephp.org/phinx/0/en/migrations.html#the-change-method
*
* Remember to call "create()" or "update()" and NOT "save()" when working
* with the Table class.
*/
public function change(): void
{
$this->table('datos_personas')
->addColumn('persona_rut', 'integer', ['signed' => false, 'null' => false])
->addForeignKey('persona_rut', 'personas', ['rut'], ['delete' => 'CASCADE', 'update' => 'CASCADE'])
->addColumn('direccion_id', 'integer', ['signed' => false, 'null' => true])
->addForeignKey('direccion_id', 'direccion', ['id'], ['delete' => 'CASCADE', 'update' => 'CASCADE'])
->addColumn('telefono', 'string', ['limit' => 255, 'null' => true])
->addColumn('email', 'string', ['limit' => 255, 'null' => true])
->addColumn('fecha_nacimiento', 'datetime', ['null' => true])
->addColumn('sexo', 'string', ['limit' => 255, 'null' => true])
->addColumn('estado_civil', 'string', ['limit' => 255, 'null' => true])
->addColumn('nacionalidad', 'string', ['limit' => 255, 'null' => true])
->addColumn('ocupacion', 'string', ['limit' => 255, 'null' => true])
->create();
}
}

View File

@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class CreateVentaAbonoCuota extends AbstractMigration
{
/**
* Change Method.
*
* Write your reversible migrations using this method.
*
* More information on writing migrations is available here:
* https://book.cakephp.org/phinx/0/en/migrations.html#the-change-method
*
* Remember to call "create()" or "update()" and NOT "save()" when working
* with the Table class.
*/
public function change(): void
{
$this->table('venta_abono_cuotas')
->addColumn('venta_id', 'integer', ['signed' => false, 'null' => false])
->addForeignKey('venta_id', 'venta', ['id'], ['delete' => 'CASCADE', 'update' => 'CASCADE'])
->addColumn('pago_id', 'integer', ['signed' => false, 'null' => false])
->addForeignKey('pago_id', 'pago', ['id'], ['delete' => 'CASCADE', 'update' => 'CASCADE'])
->addColumn('numero', 'integer', ['signed' => false, 'null' => false, 'default' => 1])
->create();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -32,7 +32,11 @@ $app->group('/venta/{venta_id:[0-9]+}', function($app) {
$app->get('/add[/]', [Ventas\Bonos::class, 'add']);
});
$app->group('/escritura', function($app) {
$app->group('/cuotas', function($app) {
$app->get('[/]', Ventas\Abono\Cuotas::class);
});
$app->get('/add[/]', [Ventas\Escrituras::class, 'add']);
$app->get('[/]', [Ventas\Escrituras::class, 'show']);
});
$app->group('/credito', function($app) {
$app->get('[/]', [Ventas\Creditos::class, 'show']);

View File

@ -35,6 +35,12 @@ $app->group('/venta/{venta_id}', function($app) {
$app->post('/add[/]', [Ventas\Bonos::class, 'add']);
});
$app->group('/escritura', function($app) {
$app->group('/cuotas', function($app) {
$app->post('/add[/]', [Ventas\Abonos\Cuotas::class, 'add']);
});
$app->group('/cuota/{cuota_id:[0-9]+}', function($app) {
$app->post('/edit[/]', [Ventas\Abonos\Cuotas::class, 'edit']);
});
$app->post('/add[/]', [Ventas\Escrituras::class, 'add']);
});
$app->group('/credito', function($app) {

View File

@ -0,0 +1,166 @@
@extends('ventas.base')
@section('venta_subtitle')
Cuotas - Abono a Escritura
@endsection
@section('venta_content')
<table class="ui table">
<thead>
<tr>
<th rowspan="2">#</th>
<th rowspan="2">Fecha</th>
<th colspan="2">Valor</th>
<th rowspan="2" colspan="2">Estado</th>
<th class="right aligned" rowspan="2">
<button class="ui tertiary green icon button" id="add_button">
<i class="plus icon"></i>
</button>
</th>
</tr>
<tr>
<th class="right aligned">$</th>
<th class="right aligned">UF</th>
</tr>
</thead>
<tbody id="cuotas">
@foreach ($cuotas as $cuota)
<tr data-id="{{$cuota->id}}">
<td class="numero" data-value="{{$cuota->numero}}">{{$cuota->numero}}</td>
<td class="fecha" data-value="{{$cuota->pago->fecha->format('Y-m-d')}}">{{$cuota->pago->fecha->format('d-m-Y')}}</td>
<td class="valor right aligned" data-value="{{$cuota->pago->valor}}">{{$format->pesos($cuota->pago->valor)}}</td>
<td class="valor_uf right aligned" data-value="{{$cuota->pago->valor()}}">{{$format->ufs($cuota->pago->valor())}}</td>
<td class="estado{{$cuota->pago->currentEstado->tipoEstadoPago->descripcion === 'no pagado' ? ' warning' :
($cuota->pago->currentEstado->tipoEstadoPago->descripcion === 'abonado' ? ' positive' : '')}}" rowspan="2"
data-value="{{$cuota->pago->currentEstado->tipoEstadoPago->id}}">
{{ucwords($cuota->pago->currentEstado->tipoEstadoPago->descripcion)}}
@if (in_array($cuota->pago->currentEstado->tipoEstadoPago->descripcion, ['abonado', 'depositado']))
<br />
{{$cuota->pago->currentEstado->fecha->format('d-m-Y')}}
@endif
</td>
<td class="collapsing">
@if (in_array($cuota->pago->currentEstado->tipoEstadoPago->descripcion, ['depositado', 'no pagado']))
<form class="ui compact form avance_pago_form" data-id="{{$cuota->id}}"
data-pago="{{$cuota->pago->id}}"
data-estado="{{$cuota->pago->currentEstado->tipoEstadoPago->descripcion}}">
<div class="inline field">
<div class="ui calendar">
<div class="ui icon input">
<input type="text" name="fecha_avance_pago{{$cuota->id}}" />
<i class="calendar icon"></i>
</div>
</div>
<button class="ui tertiary green icon button accept_button" data-id="{{$cuota->id}}"><i class="check icon"></i></button>
@if ($cuota->pago->currentEstado->tipoEstadoPago->descripcion === 'depositado')
<button class="ui tertiary red icon button cancel_button" data-id="{{$cuota->id}}"><i class="remove icon"></i></button>
@endif
</div>
</form>
@endif
</td>
<td class="right aligned">
<button class="ui tertiary icon button edit_button" data-id="{{$cuota->id}}">
<i class="edit icon"></i>
</button>
<button class="ui tertiary red icon button remove_button" data-id="{{$cuota->id}}">
<i class="remove icon"></i>
</button>
</td>
</tr>
@endforeach
</tbody>
</table>
@include('ventas.escrituras.abono.cuotas.add_modal')
@include('ventas.escrituras.abono.cuotas.edit_modal')
@endsection
@push('page_scripts')
<script>
$(document).ready(function () {
const addModal = new AddModal({
modal: '#add_cuota_modal',
form: 'add_cuota_form',
fecha: '#add_fecha',
})
const editModal = new EditModal({
table: 'cuotas',
modal: '#edit_cuota_modal',
form: 'edit_cuota_form',
fecha: '#edit_fecha',
estado: '#edit_estado'
})
document.getElementById('add_button').addEventListener('click', clickEvent => {
addModal.draw()
})
Array.from(document.getElementsByClassName('edit_button')).forEach(button => {
button.addEventListener('click', clickEvent => {
const id = $(clickEvent.currentTarget).data('id')
editModal.getData({cuota_id: id})
})
})
Array.from(document.getElementsByClassName('remove_button')).forEach(button => {
button.addEventListener('click', clickEvent => {
const id = $(clickEvent.currentTarget).data('id')
const url = `{{$urls->api}}/venta/{{$venta->id}}/cuota/${id}`
const method = 'delete'
console.debug(url)
})
})
Array.from(document.getElementsByClassName('avance_pago_form')).forEach(form => {
form.addEventListener('submit', submitEvent => {
submitEvent.preventDefault()
return false
})
const cdo = structuredClone(calendar_date_options)
cdo['initialDate'] = new Date()
cdo['maxDate'] = new Date()
@if ($cuota->pago->currentEstado->tipoEstadoPago->descripcion === 'depositado')
cdo['initialDate'] = new Date('{{$cuota->pago->currentEstado->fecha->format('Y-m-d')}}')
@endif
$(form).find('.ui.calendar').calendar(cdo)
})
Array.from(document.getElementsByClassName('accept_button')).forEach(button => {
button.addEventListener('click', clickEvent => {
const id = $(clickEvent.currentTarget).data('id')
const method = 'post'
const form = Array.from(document.getElementsByClassName('avance_pago_form')).filter(form => parseInt(form.dataset.id) === id)[0]
const pago = form.dataset.pago
const estado = form.dataset.estado
const newEstado = estado === 'depositado' ? 'abonar' : 'depositar'
const url = `{{$urls->api}}/ventas/pago/${pago}/${newEstado}`
const body = new FormData()
const fecha = $(form).find('.ui.calendar').calendar('get date')[0]
body.set('fecha', fecha.getFullYear() + '-' + (fecha.getMonth() + 1).toString().padStart(2, '0') + '-' + fecha.getDate().toString().padStart(2, '0'))
APIClient.fetch(url, {method, body}).then(response => {
if (response.ok) {
return response.json().then(json => {
if (json.success) {
window.location.reload()
}
})
}
})
})
})
Array.from(document.getElementsByClassName('cancel_button')).forEach(button => {
button.addEventListener('click', clickEvent => {
const id = $(clickEvent.currentTarget).data('id')
const method = 'post'
const form = Array.from(document.getElementsByClassName('avance_pago_form')).filter(form => parseInt(form.dataset.id) === id)[0]
const pago = form.dataset.pago
const url = `{{$urls->api}}/ventas/pago/${pago}/devolver`
const body = new FormData()
const fecha = $(form).find('.ui.calendar').calendar('get date')[0]
body.set('fecha', fecha.getFullYear() + '-' + (fecha.getMonth() + 1).toString().padStart(2, '0') + '-' + fecha.getDate().toString().padStart(2, '0'))
console.debug(url, body)
})
})
})
</script>
@endpush

View File

@ -0,0 +1,87 @@
<div class="ui modal" id="add_cuota_modal">
<div class="header">
Agregar Cuota
</div>
<div class="content">
<form class="ui form" id="add_cuota_form">
<input type="hidden" name="venta_id" value="{{$venta->id}}" />
<div class="two wide field">
<label>Número</label>
<input type="text" name="numero" />
</div>
<div class="three wide field">
<label>Fecha</label>
<div class="ui calendar" id="add_fecha">
<div class="ui icon input">
<i class="calendar icon"></i>
<input type="text" name="fecha" />
</div>
</div>
</div>
<div class="three wide field">
<label>Valor $</label>
<div class="ui left labeled input">
<div class="ui basic label">$</div>
<input type="text" name="valor" />
</div>
</div>
</form>
</div>
<div class="actions">
<div class="ui negative button">
Cancelar
</div>
<div class="ui positive right labeled icon button">
Agregar
<i class="add icon"></i>
</div>
</div>
</div>
@push('page_scripts')
<script>
class AddModal {
props
constructor(props) {
this.setup(props)
}
draw() {
$(this.props.modal).modal('show')
}
save() {
const form = document.getElementById(this.props.form)
const body = new FormData(form)
const fecha = $(this.props.fecha).calendar('get date')
body.set('fecha', fecha.getFullYear() + '-' + (fecha.getMonth() + 1).toString().padStart(2, '0') + '-' + fecha.getDate().toString().padStart(2, '0'))
const url = `{{$urls->api}}/venta/{{$venta->id}}/escritura/cuotas/add`
const method = 'post'
APIClient.fetch(url, {method, body}).then(response => {
if (!response) {
return
}
return response.json().then(json => {
if (json.success) {
window.location.reload()
}
})
})
}
setup(ids) {
this.props = ids
$(this.props.modal).modal({
onApprove: () => {
this.save()
}
})
$(this.props.form).submit(event => {
event.preventDefault()
this.save()
return false
})
$(this.props.fecha).calendar(calendar_date_options)
}
}
</script>
@endpush

View File

@ -0,0 +1,130 @@
<div class="ui modal" id="edit_cuota_modal">
<div class="header">
Editar Cuota <span class="numero"></span>
</div>
<div class="content">
<form class="ui form" id="edit_cuota_form">
<input type="hidden" name="id" />
<div class="two wide field">
<label>Número</label>
<input type="text" name="numero" />
</div>
<div class="three wide field">
<label>Fecha</label>
<div class="ui calendar" id="edit_fecha">
<div class="ui icon input">
<i class="calendar icon"></i>
<input type="text" name="fecha" />
</div>
</div>
</div>
<div class="three wide field">
<label>Valor $</label>
<div class="ui left labeled input">
<div class="ui basic label">$</div>
<input type="text" name="valor" />
</div>
</div>
<div class="three wide field">
<label>Estado</label>
<div class="ui selection search dropdown" id="edit_estado">
<i class="dropdown icon"></i>
<input type="hidden" name="tipo_estado_id" />
<div class="default text">Estado</div>
<div class="menu">
@foreach($estados as $estado)
<div class="item" data-value="{{$estado->id}}">{{$estado->descripcion}}</div>
@endforeach
</div>
</div>
</div>
</form>
</div>
<div class="actions">
<div class="ui negative button">
Cancelar
</div>
<div class="ui positive right labeled icon button">
Editar
<i class="edit icon"></i>
</div>
</div>
</div>
@push('page_scripts')
<script>
class EditModal {
props
data
constructor(props) {
this.setup(props)
this.data = null
}
getData({cuota_id}) {
const table = document.getElementById(this.props.table)
const row = table.querySelector(`tr[data-id='${cuota_id}']`)
const fecha = row.querySelector('.fecha').dataset.value.split('-')
this.data = {
id: cuota_id,
numero: row.querySelector('.numero').dataset.value,
fecha: new Date(fecha[0], fecha[1] - 1, fecha[2]),
valor: row.querySelector('.valor').dataset.value,
estado: row.querySelector('.estado').dataset.value
}
this.draw()
}
draw() {
const form = document.getElementById(this.props.form)
form.querySelector('input[name="id"]').value = this.data.id
form.querySelector('input[name="numero"]').value = this.data.numero
$(this.props.fecha).calendar('set date', this.data.fecha)
form.querySelector('input[name="valor"]').value = this.data.valor
$(this.props.estado).dropdown('set selected', this.data.estado)
$(this.props.modal).find('.header .numero').text(this.data.numero)
$(this.props.modal).modal('show')
}
save() {
const form = document.getElementById(this.props.form)
const body = new FormData(form)
const fecha = $(this.props.fecha).calendar('get date')
body.set('fecha', fecha.getFullYear() + '-' + (fecha.getMonth() + 1).toString().padStart(2, '0') + '-' + fecha.getDate().toString().padStart(2, '0'))
body.set('tipo_estado_id', $(this.props.estado).dropdown('get value'))
const url = `{{$urls->api}}/venta/{{$venta->id}}/escritura/cuota/${this.data.id}/edit`
const method = 'post'
APIClient.fetch(url, {method, body}).then(response => {
if (!response) {
return
}
return response.json().then(json => {
if (json.success) {
window.location.reload()
}
})
})
}
setup(ids) {
this.props = ids
$(this.props.modal).modal({
onApprove: () => {
this.save()
},
onHidden: () => {
this.data = null
}
})
$(this.props.form).submit(event => {
event.preventDefault()
this.save()
return false
})
$(this.props.fecha).calendar(calendar_date_options)
$(this.props.estado).dropdown()
}
}
</script>
@endpush

View File

@ -14,6 +14,7 @@
<p>Crédito {{$format->ufs($venta->formaPago()->credito->pago->valor())}}</p>
@endif
</div>
<a href="{{$urls->base}}/venta/{{$venta->id}}/escritura/cuotas" class="ui small green button"><i class="plus icon"></i> Agregar Cuotas</a>
<form class="ui form" id="add_form">
<div class="three wide field">
<label for="fecha">Fecha</label>

View File

@ -5,6 +5,24 @@
@endsection
@section('venta_content')
@if (count($venta->formaPago()->cuotasAbono) > 0)
<a href="{{$urls->base}}/venta/{{$venta->id}}/escritura/cuotas" class="ui tertiary green button">Ver Cuotas</a>
<div class="ui compact segment">
<div class="header">
Cuotas
</div>
<div class="ui horizontal list">
<div class="item">
{{$format->pesos($venta->formaPago()->cuotasAbono('pesos'))}}
</div>
<div class="item">
{{$format->ufs($venta->formaPago()->cuotasAbono())}}
</div>
</div>
</div>
@else
<a href="{{$urls->base}}/venta/{{$venta->id}}/escritura/cuotas" class="ui small green button"><i class="plus icon"></i> Agregar Cuotas</a>
@endif
<form class="ui form" id="edit_form">
<div class="three wide field">
<label for="fecha">Fecha</label>
@ -15,6 +33,26 @@
</div>
</div>
</div>
<div class="three wide field">
<label for="valor">Valor</label>
<div class="ui left labeled input">
<div class="ui basic label">$</div>
<input type="text" name="valor" value="{{$venta->formaPago()->escritura->pago->valor}}" />
</div>
</div>
<div class="three wide field">
<label>Estado</label>
<div class="ui selection dropdown" id="estado">
<input type="hidden" name="estado" />
<div class="default text">Estado</div>
<i class="dropdown icon"></i>
<div class="menu">
@foreach($estados as $estado)
<div class="item" data-value="{{$estado->id}}">{{ucwords($estado->descripcion)}}</div>
@endforeach
</div>
</div>
</div>
<button class="ui button">Guardar</button>
</form>
@endsection
@ -27,12 +65,13 @@
data.set('venta', {{$venta->id}})
const fecha = $('#fecha').calendar('get date')
data.set('fecha', fecha.toISOString())
data.set('estado', $('#estado').dropdown('get value'))
return fetchAPI(url, {method: 'post', body: data}).then(response => {
if (response.ok) {
return response.json()
}
}).then(json => {
if (!json.edited) {
if (!json.success) {
return
}
window.location = '{{$urls->base}}/venta/{{$venta->id}}'
@ -41,6 +80,8 @@
$(document).ready(() => {
calendar_date_options.initialDate = new Date({{$venta->currentEstado()->fecha->format('Y, m-1, j')}})
$('#fecha').calendar(calendar_date_options)
$('#estado').dropdown()
$('#estado').dropdown('set selected', '{{$venta->currentEstado()->id}}')
$('#edit_form').submit(event => {
event.preventDefault()
editEscritura()

View File

@ -15,8 +15,18 @@
</td>
@if ($escritura !== null)
<td></td>
<td class="right aligned">{{$format->ufs($escritura->pago->valor())}}</td>
<td class="right aligned">{{$format->pesos($escritura->pago->valor)}}</td>
<td class="right aligned">
{{$format->ufs($escritura->pago->valor())}}
@if (count($venta->formaPago()->cuotasAbono) > 0)
<br /> + (<a href="{{$urls->base}}/venta/{{$venta->id}}/escritura/cuotas">{{$format->ufs($venta->formaPago()->cuotasAbono())}}</a>)
@endif
</td>
<td class="right aligned">
{{$format->pesos($escritura->pago->valor)}}
@if (count($venta->formaPago()->cuotasAbono) > 0)
<br /> + (<a href="{{$urls->base}}/venta/{{$venta->id}}/escritura/cuotas">{{$format->pesos($venta->formaPago()->cuotasAbono('pesos'))}}</a>)
@endif
</td>
<td id="escritura_pago" class="{{$escritura->pago->currentEstado->tipoEstadoPago->descripcion === 'no pagado' ? 'warning' : ($escritura->pago->currentEstado->tipoEstadoPago->descripcion === 'depositado' ? 'positive' : '')}}">
<span class="text">{{$escritura->pago->currentEstado->fecha->format('d-m-Y')}}</span>
@if ($escritura->pago->currentEstado->tipoEstadoPago->descripcion === 'no pagado')

View File

@ -0,0 +1,79 @@
<?php
namespace Incoviba\Controller\API\Ventas\Abonos;
use DateTimeImmutable;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use Incoviba\Common\Ideal;
use Incoviba\Common\Implement;
use Incoviba\Controller\API;
use Incoviba\Repository;
use Incoviba\Service;
class Cuotas extends Ideal\Controller
{
use API\withJson;
public function add(ServerRequestInterface $request, ResponseInterface $response,
Service\Venta\Pago $pagoService,
Service\UF $ufService,
Service\Valor $valorService,
Repository\Venta\Abono\Cuota $cuotaRepository): ResponseInterface
{
$input = $request->getParsedBody();
$output = [
'input' => $input,
'cuota' => null,
'success' => false,
];
try {
$input['valor'] = $valorService->clean($input['valor']);
if (isset($input['uf']) and !empty($input['uf'])) {
$uf = $ufService->get(new DateTimeImmutable($input['fecha']));
$input['valor'] = $uf * $valorService->clean($input['uf']);
}
$pagoData = array_intersect_key($input, array_flip(['fecha', 'valor']));
$pago = $pagoService->add($pagoData);
$cuotaData = array_intersect_key($input, array_flip(['venta_id', 'numero']));
$cuotaData['pago_id'] = $pago->id;
$cuota = $cuotaRepository->create($cuotaData);
$output['cuota'] = $cuotaRepository->save($cuota);
$output['success'] = true;
} catch (Implement\Exception\EmptyResult) {}
return $this->withJson($response, $output);
}
public function edit(ServerRequestInterface $request, ResponseInterface $response,
Service\Venta\Pago $pagoService,
Repository\Venta\EstadoPago $estadoPagoRepository,
Service\UF $ufService,
Service\Valor $valorService,
Repository\Venta\Abono\Cuota $cuotaRepository, int $cuota_id): ResponseInterface
{
$input = $request->getParsedBody();
$output = [
'input' => $input,
'cuota' => null,
'success' => false,
];
try {
$cuota = $cuotaRepository->fetchById($cuota_id);
$input['valor'] = $valorService->clean($input['valor']);
if (isset($input['uf']) and !empty($input['uf'])) {
$uf = $ufService->get(new DateTimeImmutable($input['fecha']));
$input['valor'] = $uf * $valorService->clean($input['uf']);
}
$pagoData = array_intersect_key($input, array_flip(['fecha', 'valor']));
$pago = $pagoService->edit($cuota->pago, $pagoData);
if ($input['tipo_estado_id'] !== $pago->currentEstado->tipoEstadoPago->id) {
$estadoData = array_intersect_key($input, array_flip(['fecha']));
$estadoData['pago'] = $cuota->pago->id;
$estadoData['estado'] = $input['tipo_estado_id'];
$estado = $estadoPagoRepository->create($estadoData);
$estadoPagoRepository->save($estado);
}
$output['cuota'] = $cuota;
$output['success'] = true;
} catch (Implement\Exception\EmptyResult) {}
return $this->withJson($response, $output);
}
}

View File

@ -100,12 +100,13 @@ class Pagos
'pago_id' => $pago_id,
'input' => $body,
'pago' => null,
'depositado' => false
'depositado' => false,
'success' => false
];
try {
$pago = $pagoService->getById($pago_id);
$fecha = new DateTimeImmutable($body['fecha']);
$output['depositado'] = $pagoService->depositar($pago, $fecha);
$output['depositado'] = $output['success'] = $pagoService->depositar($pago, $fecha);
$output['pago'] = json_decode(json_encode($pagoService->getById($pago_id)), JSON_OBJECT_AS_ARRAY);
$output['pago']['valor_uf'] = $formatService->ufs($output['pago']['valor_uf']);
} catch (EmptyResult) {}
@ -129,12 +130,13 @@ class Pagos
'pago_id' => $pago_id,
'input' => $body,
'pago' => null,
'abonado' => false
'abonado' => false,
'success' => false,
];
try {
$pago = $pagoService->getById($pago_id);
$fecha = new DateTimeImmutable($body['fecha']);
$output['abonado'] = $pagoService->abonar($pago, $fecha);
$output['abonado'] = $output['success'] = $pagoService->abonar($pago, $fecha);
$output['pago'] = json_decode(json_encode($pagoService->getById($pago_id)), JSON_OBJECT_AS_ARRAY);
$output['pago']['valor_uf'] = $formatService->ufs($output['pago']['valor_uf']);
$output['input']['fecha'] = $fecha->format('d-m-Y');

View File

@ -0,0 +1,32 @@
<?php
namespace Incoviba\Controller\Ventas\Abono;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use Incoviba\Service;
use Incoviba\Repository;
use Incoviba\Common\Alias\View;
use Incoviba\Common\Implement\Exception\EmptyResult;
class Cuotas
{
public function __invoke(ServerRequestInterface $request, ResponseInterface $response,
Service\Venta $ventaService,
Repository\Venta\TipoEstadoPago $estadoPagoRepository,
Repository\Venta\Abono\Cuota $cuotaRepository, View $view, int $venta_id): ResponseInterface
{
$venta = null;
try {
$venta = $ventaService->getById($venta_id);
} catch (EmptyResult $e) {}
$cuotas = [];
try {
$cuotas = $cuotaRepository->fetchByVenta($venta_id);
} catch (EmptyResult $e) {}
$estados = [];
try {
$estados = $estadoPagoRepository->fetchAll();
} catch (EmptyResult $e) {}
return $view->render($response, 'ventas.escrituras.abono.cuotas', compact('venta', 'cuotas', 'estados'));
}
}

View File

@ -10,10 +10,12 @@ use Psr\Http\Message\ServerRequestInterface;
class Escrituras
{
public function show(ServerRequestInterface $request, ResponseInterface $response, View $view,
Repository\Venta\TipoEstadoPago $estadoPagoRepository,
Service\Venta $ventaService, int $venta_id): ResponseInterface
{
$venta = $ventaService->getById($venta_id);
return $view->render($response, 'ventas.escrituras.show', compact('venta'));
$estados = $estadoPagoRepository->fetchAll();
return $view->render($response, 'ventas.escrituras.show', compact('venta', 'estados'));
}
public function informe(ServerRequestInterface $request, ResponseInterface $response, View $view,
Service\Venta $ventaService, int $venta_id): ResponseInterface

View File

@ -14,7 +14,7 @@ class DatosPersona extends Ideal\Model
public ?string $sexo;
public ?string $estadoCivil;
public ?string $nacionalidad;
public ?string $profesion;
public ?string $ocupacion;
public function jsonSerialize(): mixed
{
@ -26,7 +26,7 @@ class DatosPersona extends Ideal\Model
'sexo' => $this->sexo,
'estadoCivil' => $this->estadoCivil,
'nacionalidad' => $this->nacionalidad,
'profesion' => $this->profesion,
'profesion' => $this->ocupacion,
];
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace Incoviba\Model\Venta\Abono;
use Incoviba\Common\Ideal;
use Incoviba\Model;
class Cuota extends Ideal\Model
{
public Model\Venta $venta;
public Model\Venta\Pago $pago;
public int $numero;
public function jsonSerialize(): mixed
{
return array_merge(parent::jsonSerialize(), [
'venta_id' => $this->venta->id,
'pago' => $this->pago
]);
}
}

View File

@ -11,6 +11,7 @@ class FormaPago implements JsonSerializable
public ?Subsidio $subsidio = null;
public ?Credito $credito = null;
public ?Pago $devolucion = null;
public ?array $cuotasAbono = null;
public function anticipo(string $moneda = Pago::UF): float
{
@ -24,6 +25,9 @@ class FormaPago implements JsonSerializable
if ($this->escritura !== null) {
$sum += $this->escritura->pago->valor($moneda);
}
if (count($this->cuotasAbono) > 0) {
$sum += $this->cuotasAbono($moneda);
}
return $sum;
}
public function prometido(string $moneda = Pago::UF): float
@ -52,6 +56,15 @@ class FormaPago implements JsonSerializable
}
return $sum;
}
public function cuotasAbono(string $moneda = Pago::UF): float
{
return array_reduce($this->cuotasAbono, function($sum, $cuota) use ($moneda) {
if ($cuota->currentEstado->tipoEstadoPago->descripcion === 'abonado') {
return $sum + $cuota->pago->valor($moneda);
}
return $sum;
}, 0);
}
public function ids(): array
{
return [
@ -72,7 +85,8 @@ class FormaPago implements JsonSerializable
'bono_pie' => $this->bonoPie ?? null,
'subsidio' => $this->subsidio ?? null,
'credito' => $this->credito ?? null,
'devolucion' => $this->devolucion ?? null
'devolucion' => $this->devolucion ?? null,
'cuotas_abono' => $this->cuotasAbono ?? []
];
}
}

View File

@ -58,7 +58,7 @@ class DatosPersona extends Ideal\Repository
'nacionalidad', 'profesion'
], [
$model->persona->rut, $model->direccion?->id, $model->telefono, $model->email, $model->fechaNacimiento,
$model->sexo, $model->estadoCivil, $model->nacionalidad, $model->profesion
$model->sexo, $model->estadoCivil, $model->nacionalidad, $model->ocupacion
]);
return $model;
}

View File

@ -0,0 +1,61 @@
<?php
namespace Incoviba\Repository\Venta\Abono;
use Incoviba\Common\Ideal;
use Incoviba\Common\Define;
use Incoviba\Common\Implement;
use Incoviba\Common\Implement\Exception\EmptyResult;
use Incoviba\Model;
use Incoviba\Repository;
use Incoviba\Service;
class Cuota extends Ideal\Repository
{
public function __construct(Define\Connection $connection, protected Repository\Venta $ventaRepository,
protected Service\Venta\Pago $pagoService)
{
parent::__construct($connection);
$this->setTable('venta_abono_cuotas');
}
public function create(?array $data = null): Model\Venta\Abono\Cuota
{
$map = (new Implement\Repository\MapperParser(['numero']))
->register('venta_id', (new Implement\Repository\Mapper())
->setProperty('venta')
->setFunction(function($data) {
return $this->ventaRepository->fetchById($data['venta_id']);
})
)
->register('pago_id', (new Implement\Repository\Mapper())
->setProperty('pago')
->setFunction(function($data) {
return $this->pagoService->getById($data['pago_id']);
})
);
return $this->parseData(new Model\Venta\Abono\Cuota(), $data, $map);
}
public function save(Define\Model $model): Model\Venta\Abono\Cuota
{
$model->id = $this->saveNew(['venta_id', 'pago_id', 'numero'], [$model->venta->id, $model->pago->id, $model->numero]);
return $model;
}
public function edit(Define\Model $model, array $new_data): Model\Venta\Abono\Cuota
{
return $this->update($model, ['venta_id', 'pago_id', 'numero'], $new_data);
}
/**
* @throws EmptyResult
*/
public function fetchByVenta(int $venta_id): array
{
$query = $this->connection->getQueryBuilder()
->select()
->from($this->getTable())
->where('venta_id = ?');
return $this->fetchMany($query, [$venta_id]);
}
}

View File

@ -16,6 +16,7 @@ class FormaPago extends Ideal\Service
protected Credito $creditoService,
protected Repository\Venta\Escritura $escrituraRepository,
protected Subsidio $subsidioService,
protected Repository\Venta\Abono\Cuota $cuotaRepository,
protected Pago $pagoService,
protected Valor $valorService)
{
@ -43,6 +44,9 @@ class FormaPago extends Ideal\Service
try {
$formaPago->devolucion = $this->pagoService->getDevolucionByVenta($venta_id);
} catch (Implement\Exception\EmptyResult) {}
try {
$formaPago->cuotasAbono = $this->cuotaRepository->fetchByVenta($venta_id);
} catch (Implement\Exception\EmptyResult) {}
return $formaPago;
}

View File

@ -1,17 +0,0 @@
<?php
namespace ProVM\Performance;
use GuzzleHttp\Client;
use PHPUnit\Framework;
class APITest extends Framework\TestCase
{
public function testLoad(): void
{
$client = new Client(['base_uri' => 'http://proxy']);
$start = microtime(true);
$response = $client->get('/api', ['headers' => ['Authorization' => 'Bearer ' . md5($_ENV['API_KEY'])]]);
$end = microtime(true);
$this->assertLessThanOrEqual(1000, $end - $start);
}
}

View File

@ -1,36 +0,0 @@
<?php
namespace ProVM\Test\Common\Alias;
use Incoviba\Common\Alias\View;
use PHPUnit\Framework\TestCase;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
class ViewTest extends TestCase
{
public function testRender(): void
{
$contents = <<<HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf8" />
<title>Test</title>
</head>
<body>
Test
</body>
</html>
HTML;
mkdir('/tmp/views');
mkdir('/tmp/cache', 777);
file_put_contents('/tmp/views/test.blade.php', $contents);
$view = new View('/tmp/views', '/tmp/cache');
$body = $this->getMockBuilder(StreamInterface::class)->getMock();
$body->method('getContents')->willReturn($contents);
$response = $this->getMockBuilder(ResponseInterface::class)->getMock();
$response->method('getBody')->willReturn($body);
$output = $view->render($response, 'test');
$this->assertEquals($contents, $output->getBody()->getContents());
}
}

View File

@ -1,8 +0,0 @@
<?php
namespace ProVM\Test\Common\Implement;
use PHPUnit\Framework\TestCase;
class ConnectionTest extends TestCase
{
}

View File

@ -1,50 +0,0 @@
<?php
namespace ProVM\Test\Service;
use PHPUnit\Framework\TestCase;
use Incoviba\Common\Define;
use Incoviba\Model;
use Incoviba\Repository;
use Incoviba\Service;
class MenuTest extends TestCase
{
public function testBuild(): void
{
$tests = mt_rand(10, 100);
for ($i = 0; $i < $tests; $i ++) {
list($expected, $menu) = $this->generateBuildTest();
$this->assertEquals($expected, $menu->build(1));
}
}
protected function generateBuildTest(): array
{
$modelCount = mt_rand(3, 100);
$expected = [];
$models = [];
for ($j = 0; $j < $modelCount; $j ++) {
$model = $this->generateModel();
$models []= $model;
$expected []= "<a class=\"item\" href=\"http://localhost/url{$model->id}\">title{$model->id}</a>";
}
$expected = implode(PHP_EOL, $expected);
$connection = $this->getMockBuilder(Define\Connection::class)->getMock();
$repository = $this->getMockBuilder(Repository\Menu::class)->setConstructorArgs(compact('connection'))->getMock();
$permissionsRepository = $this->getMockBuilder(Repository\Permission::class)->setConstructorArgs(compact('connection'))->getMock();
$permissions = $this->getMockBuilder(Service\Permission::class)->setConstructorArgs([$permissionsRepository])->getMock();
$repository->method('fetchByUser')->willReturn($models);
$menu = new Service\Menu($repository, $permissions, (object) ['base' => 'http://localhost']);
return [$expected, $menu];
}
protected function generateModel(): Model\Menu
{
$id = mt_rand(1, 100000);
$model = $this->getMockBuilder(Model\Menu::class)->getMock();
$model->id = $id;
$model->url = "url{$id}";
$model->title = "title{$id}";
return $model;
}
}

View File

@ -24,6 +24,12 @@ services:
env_file: ${APP_PATH:-.}/.test.db.env
volumes:
- test-db:/var/lib/mysql
networks:
- default
- adminer_network
volumes:
test-db: {}
networks:
adminer_network: {}