3 Commits

Author SHA1 Message Date
52de72b507 Sumar cuotas. 2024-11-28 17:38:21 -03:00
f4b8634cb4 Agregar y editar abono cuotas. 2024-11-28 17:12:35 -03:00
4f0a56c711 FIX: migracion 2024-11-28 15:12:30 -03:00
13 changed files with 153 additions and 18 deletions

View File

@ -20,10 +20,10 @@ final class CreateVentaAbonoCuota extends AbstractMigration
public function change(): void
{
$this->table('venta_abono_cuotas')
->addColumn('venta_id', 'integer', ['size' => 10, 'signed' => false, 'null' => false])
->addForeignKey('venta_id', 'ventas', ['id'], ['delete' => 'CASCADE', 'update' => 'CASCADE'])
->addColumn('pago_id', 'integer', ['size' => 10, 'signed' => false, 'null' => false])
->addForeignKey('pago_id', 'pagos', ['id'], ['delete' => 'CASCADE', 'update' => 'CASCADE'])
->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();
}

View File

@ -36,6 +36,7 @@ $app->group('/venta/{venta_id:[0-9]+}', 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,9 @@ $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->post('/add[/]', [Ventas\Escrituras::class, 'add']);
});
$app->group('/credito', function($app) {

View File

@ -14,7 +14,7 @@
<th>UF</th>
<th rowspan="2">Estado</th>
<th class="right aligned">
<button class="ui green icon button" id="add_button">
<button class="ui tertiary green icon button" id="add_button">
<i class="plus icon"></i>
</button>
</th>
@ -50,13 +50,13 @@
$(document).ready(function () {
const addModal = new AddModal({
modal: '#add_cuota_modal',
form: '#add_cuota_form',
form: 'add_cuota_form',
fecha: '#add_fecha',
})
const editModal = new EditModal({
table: 'cuotas',
modal: '#edit_cuota_modal',
form: '#edit_cuota_form',
form: 'edit_cuota_form',
fecha: '#edit_fecha',
estado: '#edit_estado'
})

View File

@ -4,7 +4,7 @@
</div>
<div class="content">
<form class="ui form" id="add_cuota_form">
<input type="hidden" name="id" />
<input type="hidden" name="venta_id" value="{{$venta->id}}" />
<div class="two wide field">
<label>Número</label>
<input type="text" name="numero" />

View File

@ -36,11 +36,11 @@
<label>Estado</label>
<div class="ui selection search dropdown" id="edit_estado">
<i class="dropdown icon"></i>
<input type="hidden" name="estado" />
<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->nombre}}</div>
<div class="item" data-value="{{$estado->id}}">{{$estado->descripcion}}</div>
@endforeach
</div>
</div>
@ -100,7 +100,7 @@
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('estado', $(this.props.estado).dropdown('get value'))
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 => {

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,60 @@
<?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, 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);
$output['cuota'] = $cuotaRepository->edit($cuota, $input);
$output['success'] = true;
} catch (Implement\Exception\EmptyResult) {}
return $this->withJson($response, $output);
}
}

View File

@ -12,6 +12,7 @@ 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;
@ -22,6 +23,10 @@ class Cuotas
try {
$cuotas = $cuotaRepository->fetchByVenta($venta_id);
} catch (EmptyResult $e) {}
return $view->render($response, 'ventas.escrituras.abono.cuotas', compact('venta', 'cuotas'));
$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

@ -25,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
@ -53,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 [

View File

@ -7,11 +7,12 @@ 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 Repository\Venta\Pago $pagoRepository)
protected Service\Venta\Pago $pagoService)
{
parent::__construct($connection);
$this->setTable('venta_abono_cuotas');
@ -29,7 +30,7 @@ class Cuota extends Ideal\Repository
->register('pago_id', (new Implement\Repository\Mapper())
->setProperty('pago')
->setFunction(function($data) {
return $this->pagoRepository->fetchById($data['pago_id']);
return $this->pagoService->getById($data['pago_id']);
})
);
return $this->parseData(new Model\Venta\Abono\Cuota(), $data, $map);