6 Commits

Author SHA1 Message Date
742de657c5 develop (#45)
Co-authored-by: Juan Pablo Vial <jpvialb@incoviba.cl>
Reviewed-on: #45
2025-10-04 11:40:52 -03:00
6ddc48ec60 Merge branch 'develop' 2024-03-13 16:31:34 -03:00
331ee1e584 Merge branch 'develop' 2023-06-22 23:18:13 -04:00
24c17debf3 Merge branch 'develop' 2023-02-15 18:30:09 -03:00
552fd0aa06 Merge branch 'develop' 2023-02-14 20:50:42 -03:00
60faf293d4 Merge branch 'develop' 2023-02-13 17:18:41 -03:00
25 changed files with 488 additions and 134 deletions

View File

@ -0,0 +1,68 @@
<?php
namespace Incoviba\Common\Implement\Log\Processor;
use Throwable;
use Monolog\LogRecord;
use Monolog\Processor\ProcessorInterface;
class Exception implements ProcessorInterface
{
public function __invoke(LogRecord $record): LogRecord
{
$context = $record->context;
$changed = false;
array_walk_recursive($context, function (&$item) use (&$changed) {
if (is_a($item, Throwable::class)) {
$item = $this->processException($item);
$changed = true;
}
});
if ($changed) {
$new_record = new LogRecord(
$record->datetime,
$record->channel,
$record->level,
$record->message,
$context,
$record->extra
);
$record = $new_record;
}
if (is_a($record->message, Throwable::class)) {
$exception = $record->message;
$output = $this->processException($exception);
$message = $output['message'];
if (array_key_exists('exception', $context)) {
$context['other_exception'] = $context['exception'];
}
$context['exception'] = $output;
$new_record = new LogRecord(
$record->datetime,
$record->channel,
$record->level,
$message,
$context,
$record->extra
);
$record = $new_record;
}
return $record;
}
protected function processException(Throwable $exception): array
{
$output = [
'class' => get_class($exception),
'code' => $exception->getCode(),
'message' => $exception->getMessage(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'trace' => $exception->getTraceAsString(),
];
if ($exception->getPrevious() !== null) {
$output['previous'] = $this->processException($exception);
}
return $output;
}
}

View File

@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class AddCommentsToReservations 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('reservations')
->addColumn('comments', 'text')
->update();
}
}

View File

@ -19,7 +19,7 @@
<div class="header"> <div class="header">
{{$inmobiliaria->abreviacion}} {{$inmobiliaria->abreviacion}}
</div> </div>
<div class="description">{{$inmobiliaria->razon}} {{$inmobiliaria->tipoSociedad->descripcion}}</div> <div class="description">{{$inmobiliaria->razon}} {{$inmobiliaria->tipoSociedad?->descripcion ?? ''}}</div>
<div class="meta">{{$inmobiliaria->rut()}}</div> <div class="meta">{{$inmobiliaria->rut()}}</div>
</div> </div>
</div> </div>

View File

@ -6,7 +6,12 @@
@section('venta_content') @section('venta_content')
<div class="ui segment"> <div class="ui segment">
El departamento {{$venta->propiedad()->departamentos()[0]->descripcion}}:<br /> @if (count($venta->propiedad()->departamentos()) > 0)
El departamento {{$venta->propiedad()->departamentos()[0]->descripcion}}:<br />
@else
La unidad {{ ucwords($venta->propiedad()->principal()?->proyectoTipoUnidad->tipoUnidad->descripcion) }}
{{ $venta->propiedad()->principal()?->descripcion }}:<br />
@endif
@php @php
$estacionamientos = $venta->propiedad()->estacionamientos(); $estacionamientos = $venta->propiedad()->estacionamientos();
@endphp @endphp

View File

@ -47,9 +47,9 @@
</div> </div>
</div> </div>
<div class="ui top attached tabular menu" id="tabs"> <div class="ui top attached tabular menu" id="tabs">
<div class="yellow active item" data-tab="pending">Pendientes</div> <div class="yellow active item link" data-tab="pending">Pendientes</div>
<div class="green item" data-tab="active">Activas</div> <div class="green item link" data-tab="active">Activas</div>
<div class="red item" data-tab="rejected">Rechazadas</div> <div class="red item link" data-tab="rejected">Rechazadas</div>
</div> </div>
<div class="ui bottom attached tab fitted segment active" data-tab="pending"> <div class="ui bottom attached tab fitted segment active" data-tab="pending">
<table class="ui yellow striped table" id="pending_reservations"> <table class="ui yellow striped table" id="pending_reservations">
@ -102,12 +102,13 @@
</div> </div>
@include('ventas.reservations.modal.add') @include('ventas.reservations.modal.add')
@include('ventas.reservations.modal.comment')
@endsection @endsection
@push('page_styles') @push('page_styles')
<style> <style>
.item.link { .item.link {
cursor: pointer; cursor: pointer !important;
text-decoration: underline; text-decoration: underline;
} }
</style> </style>
@ -293,10 +294,10 @@
return this return this
} }
} }
columnsData() { get columnsData() {
return this.reservations.map(reservation => { return this.reservations.map(reservation => {
const date = new Date(Date.parse(reservation.date) + 24 * 60 * 60 * 1000) const date = new Date(Date.parse(reservation.date) + 24 * 60 * 60 * 1000)
return { return {
id: reservation.id, id: reservation.id,
unidades: reservation.summary, unidades: reservation.summary,
cliente: reservation.buyer.nombreCompleto, cliente: reservation.buyer.nombreCompleto,
@ -314,7 +315,7 @@
} }
const tbody = this.component.querySelector('tbody') const tbody = this.component.querySelector('tbody')
tbody.innerHTML = '' tbody.innerHTML = ''
this.columnsData().forEach(column => { this.columnsData.forEach(column => {
const tr = document.createElement('tr') const tr = document.createElement('tr')
const contents = [] const contents = []
const id = column.id const id = column.id
@ -376,6 +377,9 @@
hide() { hide() {
this.component.style.display = 'none' this.component.style.display = 'none'
} }
find(id) {
return this.reservations.find(reservation => reservation.id === parseInt(id))
}
send = { send = {
get(url) { get(url) {
return APIClient.fetch(url).then(response => response.json()).then(json => { return APIClient.fetch(url).then(response => response.json()).then(json => {
@ -392,14 +396,6 @@
} }
}) })
}, },
delete(url) {
const method = 'delete'
return APIClient.fetch(url, {method}).then(response => response.json()).then(json => {
if (json.success) {
window.location.reload()
}
})
}
} }
actions = {} actions = {}
} }
@ -409,10 +405,10 @@
super({component_id, formatters}) super({component_id, formatters})
} }
columnsData() { get columnsData() {
const data = super.columnsData(); const data = super.columnsData;
return data.map(row => { return data.map(row => {
delete (row['valida']) delete(row['valida'])
return row return row
}) })
} }
@ -436,9 +432,12 @@
}, },
remove: event => { remove: event => {
event.preventDefault() event.preventDefault()
const id = event.currentTarget.dataset.id const reservation_id = event.currentTarget.dataset.id
const url = `{{ $urls->api }}/ventas/reservation/${id}/remove` const url = `{{ $urls->api }}/ventas/reservation/${reservation_id}/remove`
this.send.delete(url) const method = 'delete'
const action = 'Cancelar'
const reservation_data = this.find(reservation_id)
reservations.components.modals.comment.show({reservation_id, action, url, method, reservation_data})
return false return false
} }
} }
@ -459,9 +458,12 @@
}, },
reject: event => { reject: event => {
event.preventDefault() event.preventDefault()
const id = event.currentTarget.dataset.id const reservation_id = event.currentTarget.dataset.id
const url = `{{ $urls->api }}/ventas/reservation/${id}/reject` const url = `{{ $urls->api }}/ventas/reservation/${reservation_id}/reject`
this.send.get(url) const method = 'delete'
const action = 'Rechazar'
const reservation_data = this.find(reservation_id)
reservations.components.modals.comment.show({reservation_id, action, url, method, reservation_data})
return false return false
} }
} }
@ -472,11 +474,11 @@
super({component_id, formatters}) super({component_id, formatters})
} }
columnsData() { get columnsData() {
const data = super.columnsData() const data = super.columnsData
return this.reservations.map((reservation, idx) => { return this.reservations.map((reservation, idx) => {
data[idx]['estado'] = reservation.state.charAt(0).toUpperCase() + reservation.state.slice(1) data[idx]['estado'] = this.mapState(reservation.current_state)
data[idx]['comentarios'] = reservation.comments?.join('<br />\n') ?? '' data[idx]['comentarios'] = reservation.comments ?? ''
return data[idx] return data[idx]
}) })
} }
@ -484,6 +486,13 @@
return '' return ''
} }
watch() {} watch() {}
mapState(state) {
return {
'canceled': 'Cancelado',
'rejected': 'Rechazado'
}[state.toLowerCase()]
}
} }
const reservations = { const reservations = {
@ -498,7 +507,8 @@
rejected: null rejected: null
}, },
modals: { modals: {
add: null add: null,
comment: null,
} }
}, },
display: { display: {
@ -638,6 +648,7 @@
this.show.projects() this.show.projects()
this.components.modals.add = new AddReservationModal(configuration.ids.projects) this.components.modals.add = new AddReservationModal(configuration.ids.projects)
this.components.modals.comment = new CommentModal()
const project_id = {{ $project_id ?? 'null' }}; const project_id = {{ $project_id ?? 'null' }};
if (project_id !== null) { if (project_id !== null) {
@ -645,6 +656,7 @@
} }
} }
} }
$(document).ready(() => { $(document).ready(() => {
reservations.setup({ reservations.setup({
ids: { ids: {

View File

@ -238,6 +238,7 @@
} }
} }
class AddModalUnits { class AddModalUnits {
parent = null
ids = { ids = {
buttons_holder: '', buttons_holder: '',
units: '' units: ''
@ -252,7 +253,8 @@
units: null, units: null,
} }
constructor() { constructor(parent) {
this.parent = parent
this.ids = { this.ids = {
buttons_holder: 'add_unit_buttons', buttons_holder: 'add_unit_buttons',
units: 'add_units' units: 'add_units'
@ -265,6 +267,9 @@
} }
this.setup() this.setup()
} }
get promotions() {
return this.parent.data.promotions[this.parent.data.current_project]
}
draw = { draw = {
button: type => { button: type => {
return [ return [
@ -293,36 +298,25 @@
return return
} }
this.components.units.innerHTML = this.data.units.map(unit => { this.components.units.innerHTML = this.data.units.map(unit => {
return [ return this.draw.unit(unit)
'<div class="fields">',
'<div class="four wide field">',
`<label>${unit.type.charAt(0).toUpperCase() + unit.type.slice(1)}</label>`,
`<div class="ui search selection dropdown">`,
'<input type="hidden" name="add_units[]" />',
'<i class="dropdown icon"></i>',
`<div class="default text">${unit.type.charAt(0).toUpperCase() + unit.type.slice(1)}</div>`,
'<div class="menu">',
this.data.types[unit.type].map(unit => {
return `<div class="item" data-value="${unit.value}">${unit.name}</div>`
}).join(''),
'</div>',
'</div>',
'</div>',
'<div class="three wide field">',
'<label>Valor</label>',
'<div class="ui right labeled input">',
'<input type="number" name="add_units_value[]" placeholder="Valor" />',
'<div class="ui basic label">UF</div>',
'</div>',
'</div>',
'<div class="field">',
'<label></label>',
`<button class="ui red tiny icon button remove_unit" type="button" data-id="${unit.idx}"><i class="trash icon"></i></button>`,
'</div>',
'</div>',
].join('')
}).join('') }).join('')
this.components.units.querySelectorAll('.dropdown').forEach(dropdown => { this.components.units.querySelectorAll('.dropdown.add_units').forEach(dropdown => {
$(dropdown).dropdown({
onChange: (value, text, $selectedItem) => {
const unitPromotions = this.promotions.filter(promotion => promotion.units.length > 0)
const promotions = unitPromotions.filter(promotion => promotion.units.filter(unit => unit.id === parseInt(value)).length > 0)
$selectedItem.parent().parent().parent().parent().find('.add_promotions_unit')
.dropdown('change values', promotions.map(promotion => {
return {
value: promotion.id,
name: promotion.description,
text: promotion.description,
}
}))
}
})
})
this.components.units.querySelectorAll('.dropdown.add_promotions_unit').forEach(dropdown => {
$(dropdown).dropdown() $(dropdown).dropdown()
}) })
this.components.units.querySelectorAll('.remove_unit').forEach(button => { this.components.units.querySelectorAll('.remove_unit').forEach(button => {
@ -331,6 +325,54 @@
this.remove(idx) this.remove(idx)
}) })
}) })
},
unit: unit => {
let promotions = ''
if (unit.type === 'departamento') {
if (this.promotions.filter(promotion => promotion.units.length > 0).length > 0) {
promotions = [
'<div class="three wide field">',
'<label>Promociones</label>',
'<div class="ui multiple search selection dropdown add_promotions_unit">',
'<input type="hidden" name="add_units_promotions[]" />',
'<i class="dropdown icon"></i>',
'<div class="default text">Promociones</div>',
'<div class="menu">',
'</div>',
'</div>',
'</div>'
].join('')
}
}
return [
'<div class="fields">',
'<div class="four wide field">',
`<label>${unit.type.charAt(0).toUpperCase() + unit.type.slice(1)}</label>`,
`<div class="ui search selection dropdown add_units">`,
'<input type="hidden" name="add_units[]" />',
'<i class="dropdown icon"></i>',
`<div class="default text">${unit.type.charAt(0).toUpperCase() + unit.type.slice(1)}</div>`,
'<div class="menu">',
this.data.types[unit.type].map(unit => {
return `<div class="item" data-value="${unit.value}">${unit.name}</div>`
}).join(''),
'</div>',
'</div>',
'</div>',
'<div class="three wide field">',
'<label>Valor</label>',
'<div class="ui right labeled input">',
'<input type="number" name="add_units_value[]" placeholder="Valor" />',
'<div class="ui basic label">UF</div>',
'</div>',
'</div>',
promotions,
'<div class="field">',
'<label></label>',
`<button class="ui red tiny icon button remove_unit" type="button" data-id="${unit.idx}"><i class="trash icon"></i></button>`,
'</div>',
'</div>',
].join('')
} }
} }
reset() { reset() {
@ -436,11 +478,30 @@
this.get.brokers(project_id) this.get.brokers(project_id)
this.get.promotions(project_id).then(promotions => { this.get.promotions(project_id).then(promotions => {
this.components.promotions.data.promotions = promotions this.components.promotions.data.promotions = promotions.map(promotion => {
return {
text: promotion.name,
name: promotion.name,
value: promotion.id
}
})
this.components.promotions.draw.promotions() this.components.promotions.draw.promotions()
}) })
this.get.units(project_id).then(units => { this.get.units(project_id).then(unitTypes => {
this.components.units.data.types = units Object.entries(unitTypes).map(([type, units]) => {
units = units.map(unit => {
return {
text: unit.descripcion,
name: unit.descripcion,
value: unit.id
}
})
units.sort((a, b) => {
return parseInt(a.text) - parseInt(b.text)
})
unitTypes[type] = units
})
this.components.units.data.types = unitTypes
this.components.units.draw.buttons() this.components.units.draw.buttons()
}) })
} }
@ -564,13 +625,7 @@
if (json.promotions.length === 0) { if (json.promotions.length === 0) {
return this.data.promotions[project_id] = [] return this.data.promotions[project_id] = []
} }
return this.data.promotions[project_id] = json.promotions.map(promotion => { return this.data.promotions[project_id] = json.promotions
return {
text: promotion.name,
name: promotion.name,
value: promotion.id
}
})
}) })
}, },
units: project_id => { units: project_id => {
@ -593,18 +648,9 @@
if (!(type in this.data.units[project_id])) { if (!(type in this.data.units[project_id])) {
this.data.units[project_id][type] = [] this.data.units[project_id][type] = []
} }
this.data.units[project_id][type].push({ this.data.units[project_id][type].push(unit)
text: unit.descripcion,
name: unit.descripcion,
value: unit.id
})
})
Object.entries(this.data.units[project_id]).forEach(([type, units]) => {
units.sort((a, b) => {
return parseInt(a.text) - parseInt(b.text)
})
this.data.units[project_id][type] = units
}) })
return this.data.units[project_id] return this.data.units[project_id]
}) })
}, },
@ -706,7 +752,7 @@
this.components.promotions = new AddModalPromotions() this.components.promotions = new AddModalPromotions()
this.components.projects = document.getElementById(this.ids.projects) this.components.projects = document.getElementById(this.ids.projects)
this.components.project_name = document.getElementById(this.ids.project_name) this.components.project_name = document.getElementById(this.ids.project_name)
this.components.units = new AddModalUnits() this.components.units = new AddModalUnits(this)
this.components.$modal.modal({ this.components.$modal.modal({
onApprove: () => { onApprove: () => {

View File

@ -0,0 +1,157 @@
<div class="ui modal" id="comment_modal">
<div class="header">
Comentar Cierre y <span id="comment_action"></span>
</div>
<div class="content">
<form class="ui form" id="comment_form">
<input type="hidden" name="reservation_id" id="comment_reservation_id" />
<input type="hidden" name="user_id" id="comment_user_id" />
<table class="ui collapsing table">
<tbody>
<tr>
<td>Unidades</td>
<td id="comment_units"></td>
</tr>
<tr>
<td>Cliente</td>
<td id="comment_client"></td>
</tr>
<tr>
<td>Fecha</td>
<td id="comment_date"></td>
</tr>
</tbody>
</table>
<div class="field">
<label>Comentario</label>
<textarea name="comment"></textarea>
</div>
</form>
</div>
<div class="actions">
<div class="ui cancel button">
Cancelar
</div>
<div class="ui green ok button">
Comentar y Guardar
</div>
</div>
</div>
@push('page_scripts')
<script>
class CommentModal {
ids = {
modal: 'comment_modal',
action: 'comment_action',
form: 'comment_form',
reservation_id: 'comment_reservation_id',
user_id: 'comment_user_id',
units: 'comment_units',
client: 'comment_client',
date: 'comment_date',
}
components = {
$modal: null,
action: null,
form: null,
reservation: null,
user: null,
units: null,
client: null,
date: null,
comment: null,
}
data = {
reservation_id: null,
url: '',
action: '',
method: 'delete',
reservation_data: {
units: '',
client: '',
date: '',
}
}
constructor() {
this.ids = {
modal: 'comment_modal',
action: 'comment_action',
form: 'comment_form',
reservation_id: 'comment_reservation_id',
user_id: 'comment_user_id',
units: 'comment_units',
client: 'comment_client',
date: 'comment_date',
}
this.setup()
}
show({reservation_id, reservation_data, url, action, method}) {
this.data.reservation_id = reservation_id
this.data.url = url
this.data.action = action
this.data.method = method
this.components.action.innerHTML = action
const date = new Date(Date.parse(reservation_data.date) + 24 * 60 * 60 * 1000)
const formatter = new Intl.DateTimeFormat('es-CL', {dateStyle: 'medium'})
this.data.reservation_data = {
units: reservation_data.summary,
client: reservation_data.buyer.nombreCompleto,
date: formatter.format(date),
}
this.components.reservation.value = this.data.reservation_id
this.components.units.innerHTML = this.data.reservation_data.units
this.components.client.innerHTML = this.data.reservation_data.client
this.components.date.innerHTML = this.data.reservation_data.date
this.components.$modal.modal('show')
}
hide() {
this.components.$modal.modal('hide')
}
submit() {
const url = this.data.url
const method = this.data.method
const body = new FormData(this.components.form)
return APIClient.fetch(url, {method, body}).then(response => response.json()).then(json => {
if (json.success) {
window.location.reload()
}
})
}
setup() {
this.components = {
$modal: $(`#${this.ids.modal}`),
action: document.getElementById(this.ids.action),
form: document.getElementById(this.ids.form),
reservation: document.getElementById(this.ids.reservation_id),
user: document.getElementById(this.ids.user_id),
units: document.getElementById(this.ids.units),
client: document.getElementById(this.ids.client),
date: document.getElementById(this.ids.date),
comment: null,
}
this.components.comment = this.components.form.querySelector('textarea[name="comment"]')
this.components.user.value = '{{ $user->id }}'
this.components.$modal.modal({
onApprove: $element => {
this.submit()
}
})
this.components.form.addEventListener('submit', event => {
event.preventDefault()
this.submit()
return false
})
}
}
</script>
@endpush

View File

@ -25,6 +25,7 @@ return [
$container->get(Monolog\Processor\MemoryPeakUsageProcessor::class), $container->get(Monolog\Processor\MemoryPeakUsageProcessor::class),
$container->get(Monolog\Processor\PsrLogMessageProcessor::class), $container->get(Monolog\Processor\PsrLogMessageProcessor::class),
$container->get(Monolog\Processor\UidProcessor::class), $container->get(Monolog\Processor\UidProcessor::class),
$container->get(Incoviba\Common\Implement\Log\Processor\Exception::class),
]; ];
}, },
'baseDefaultHandlers' => function(ContainerInterface $container) { 'baseDefaultHandlers' => function(ContainerInterface $container) {

View File

@ -125,13 +125,7 @@ return [
'headers' => $request->getHeaders(), 'headers' => $request->getHeaders(),
'body' => $request->getBody()->getContents(), 'body' => $request->getBody()->getContents(),
]); ]);
})); return $request;
$stack->push(GuzzleHttp\Middleware::mapResponse(function(Psr\Http\Message\ResponseInterface $response) use ($logger) {
$logger->info('Toku Response', [
'status' => $response->getStatusCode(),
'headers' => $response->getHeaders(),
'body' => $response->getBody()->getContents(),
]);
})); }));
return new GuzzleHttp\Client([ return new GuzzleHttp\Client([
'handler' => $stack, 'handler' => $stack,

View File

@ -53,7 +53,7 @@ class Money
} }
try { try {
$this->data[$provider] = (array) $this->fetchRedis($redisService, $redisKey); $this->data[$provider] = (array) $this->fetchRedis($redisService, $redisKey);
if (!isset($this->data[$provider][$date->format('Y-m-d')])) { if (!isset($this->data[$provider][$date->format('Y-m-d')]) or $this->data[$provider][$date->format('Y-m-d')] === 0) {
throw new EmptyRedis($redisKey); throw new EmptyRedis($redisKey);
} }
} catch (EmptyRedis) { } catch (EmptyRedis) {

View File

@ -71,9 +71,9 @@ class Reservations
$output['errors'] []= $this->parseError($exception); $output['errors'] []= $this->parseError($exception);
}*/ }*/
if (count($input['reservations']) === count($output['reservations'])) { /*if (count($input['reservations']) === count($output['reservations'])) {
$output['success'] = true; $output['success'] = true;
} }*/
return $this->withJson($response, $output); return $this->withJson($response, $output);
} }

View File

@ -117,6 +117,8 @@ class Reservation extends Common\Ideal\Model
return $base >= $price; return $base >= $price;
} }
public string $comments;
protected function jsonComplement(): array protected function jsonComplement(): array
{ {
return [ return [
@ -131,7 +133,10 @@ class Reservation extends Common\Ideal\Model
'base' => $this->base(), 'base' => $this->base(),
'price' => $this->price(), 'price' => $this->price(),
'valid' => $this->valid(), 'valid' => $this->valid(),
'summary' => $this->summary() 'summary' => $this->summary(),
'states' => $this->states() ?? [],
'current_state' => $this->currentState()?->type?->name ?? null,
'comments' => $this->comments ?? '',
]; ];
} }
} }

View File

@ -16,7 +16,10 @@ class State extends Common\Ideal\Model
return [ return [
'reservation_id' => $this->reservation->id, 'reservation_id' => $this->reservation->id,
'date' => $this->date->format('Y-m-d'), 'date' => $this->date->format('Y-m-d'),
'type' => $this->type 'type' => [
'id' => $this->type->value,
'name' => $this->type->name,
]
]; ];
} }
} }

View File

@ -18,6 +18,6 @@ enum Type: int
} }
public static function getTypes(): array public static function getTypes(): array
{ {
return [self::ACTIVE->value, self::INACTIVE->value, self::REJECTED->value]; return [self::ACTIVE->value, self::INACTIVE->value, self::REJECTED->value, self::CANCELLED->value];
} }
} }

View File

@ -187,7 +187,7 @@ class Promotion extends Common\Ideal\Repository
->joined('LEFT OUTER JOIN proyecto_tipo_unidad ptu ON ptu.id = pul.unit_line_id') ->joined('LEFT OUTER JOIN proyecto_tipo_unidad ptu ON ptu.id = pul.unit_line_id')
->joined('LEFT OUTER JOIN promotion_units pu ON pu.promotion_id = a.id') ->joined('LEFT OUTER JOIN promotion_units pu ON pu.promotion_id = a.id')
->joined('LEFT OUTER JOIN unidad ON unidad.id = pu.unit_id') ->joined('LEFT OUTER JOIN unidad ON unidad.id = pu.unit_id')
->joined('LEFT OUTER JOIN proyecto_tipo_unidad ptu1 ON ptu.id = unidad.pt') ->joined('LEFT OUTER JOIN proyecto_tipo_unidad ptu1 ON ptu1.id = unidad.pt')
->where('pp.project_id = :project_id OR put.project_id = :project_id OR ptu.proyecto = :project_id OR ptu1.proyecto = :project_id') ->where('pp.project_id = :project_id OR put.project_id = :project_id OR ptu.proyecto = :project_id OR ptu1.proyecto = :project_id')
->group('a.id'); ->group('a.id');
return $this->fetchMany($query, ['project_id' => $project_id]); return $this->fetchMany($query, ['project_id' => $project_id]);

View File

@ -4,6 +4,7 @@ namespace Incoviba\Repository\Venta;
use DateTimeInterface; use DateTimeInterface;
use DateInterval; use DateInterval;
use Incoviba\Common\Define; use Incoviba\Common\Define;
use Incoviba\Common\Implement\Exception\EmptyResult;
use Incoviba\Exception\Model\InvalidState; use Incoviba\Exception\Model\InvalidState;
use PDO; use PDO;
use Incoviba\Common; use Incoviba\Common;
@ -29,7 +30,7 @@ class Reservation extends Common\Ideal\Repository
public function create(?array $data = null): Model\Venta\Reservation public function create(?array $data = null): Model\Venta\Reservation
{ {
$map = (new Common\Implement\Repository\MapperParser()) $map = (new Common\Implement\Repository\MapperParser(['comments']))
->register('project_id', (new Common\Implement\Repository\Mapper()) ->register('project_id', (new Common\Implement\Repository\Mapper())
->setProperty('project') ->setProperty('project')
->setFunction(function($data) { ->setFunction(function($data) {
@ -91,18 +92,57 @@ class Reservation extends Common\Ideal\Repository
/** /**
* @param int $buyer_rut * @param int $buyer_rut
* @param int $unit_id
* @param DateTimeInterface $date * @param DateTimeInterface $date
* @return Model\Venta\Reservation * @return Model\Venta\Reservation
* @throws Common\Implement\Exception\EmptyResult * @throws EmptyResult
*/ */
public function fetchByBuyerAndDate(int $buyer_rut, DateTimeInterface $date): Model\Venta\Reservation public function fetchByBuyerAndUnitAndDate(int $buyer_rut, int $unit_id, DateTimeInterface $date): Model\Venta\Reservation
{
$query = $this->connection->getQueryBuilder()
->select('a.*')
->from('reservations a')
->joined('INNER JOIN reservation_details rd ON a.id = rd.reservation_id')
->where('a.buyer_rut = :buyer_rut AND rd.unit_id = :unit_id AND a.date >= :date');
return $this->fetchOne($query, ['buyer_rut' => $buyer_rut, 'unit_id' => $unit_id, 'date' => $date->sub(new DateInterval('P10D'))->format('Y-m-d')]);
}
/**
* @param int $buyer_rut
* @param int $project_id
* @param DateTimeInterface $date
* @return array
* @throws EmptyResult
*/
public function fetchByBuyerAndProjectAndDate(int $buyer_rut, int $project_id, DateTimeInterface $date): array
{
$query = $this->connection->getQueryBuilder()
->select()
->from('reservations')
->where('buyer_rut = :buyer_rut AND project_id = :project_id AND date >= :date');
return $this->fetchMany($query, ['buyer_rut' => $buyer_rut, 'project_id' => $project_id, 'date' => $date->sub(new DateInterval('P10D'))->format('Y-m-d')]);
}
/**
* @param int $buyer_rut
* @param DateTimeInterface $date
* @return array
* @throws EmptyResult
*/
public function fetchByBuyerAndDate(int $buyer_rut, DateTimeInterface $date): array
{ {
$query = $this->connection->getQueryBuilder() $query = $this->connection->getQueryBuilder()
->select() ->select()
->from('reservations') ->from('reservations')
->where('buyer_rut = :buyer_rut AND date >= :date'); ->where('buyer_rut = :buyer_rut AND date >= :date');
return $this->fetchOne($query, ['buyer_rut' => $buyer_rut, 'date' => $date->sub(new DateInterval('P10D'))->format('Y-m-d')]); return $this->fetchMany($query, ['buyer_rut' => $buyer_rut, 'date' => $date->sub(new DateInterval('P10D'))->format('Y-m-d')]);
} }
/**
* @param int $project_id
* @return array
* @throws EmptyResult
*/
public function fetchByProject(int $project_id): array public function fetchByProject(int $project_id): array
{ {
$query = $this->connection->getQueryBuilder() $query = $this->connection->getQueryBuilder()
@ -114,13 +154,16 @@ class Reservation extends Common\Ideal\Repository
/** /**
* @param int $project_id * @param int $project_id
* @param int $state * @param int|string $state
* @return array * @return array
* @throws Common\Implement\Exception\EmptyResult * @throws EmptyResult
* @throws InvalidState * @throws InvalidState
*/ */
public function fetchState(int $project_id, int $state): array public function fetchState(int $project_id, int|string $state): array
{ {
if (is_string($state)) {
$state = Model\Venta\Reservation\State\Type::from($state)->value;
}
if (!in_array($state, Model\Venta\Reservation\State\Type::getTypes())) { if (!in_array($state, Model\Venta\Reservation\State\Type::getTypes())) {
throw new InvalidState(); throw new InvalidState();
} }
@ -141,6 +184,7 @@ class Reservation extends Common\Ideal\Repository
return $this->fetchMany($query, ['project_id' => $project_id, return $this->fetchMany($query, ['project_id' => $project_id,
'state' => $state]); 'state' => $state]);
} }
/** /**
* @param int $project_id * @param int $project_id
* @return array * @return array

View File

@ -21,7 +21,7 @@ class IPC
$ipcs = []; $ipcs = [];
try { try {
$ipcs = json_decode($this->redisService->get($this->redisKey), JSON_OBJECT_AS_ARRAY); $ipcs = json_decode($this->redisService->get($this->redisKey), JSON_OBJECT_AS_ARRAY);
if (!isset($ipcs[$dateKey])) { if (!isset($ipcs[$dateKey]) or $ipcs[$dateKey] === 0) {
throw new EmptyRedis($this->redisKey); throw new EmptyRedis($this->redisKey);
} }
} catch (EmptyRedis) { } catch (EmptyRedis) {

View File

@ -48,8 +48,8 @@ class Ine implements Provider
]); ]);
try { try {
$response = $this->client->get($request_uri); $response = $this->client->get($request_uri);
} catch (GuzzleException) { } catch (GuzzleException $exception) {
throw new EmptyResponse($request_uri); throw new EmptyResponse($request_uri, $exception);
} }
$body = $response->getBody(); $body = $response->getBody();
$json = json_decode($body->getContents()); $json = json_decode($body->getContents());

View File

@ -79,13 +79,7 @@ class Queue extends Ideal\Service
try { try {
$this->jobService->update($job); $this->jobService->update($job);
} catch (Update $exception) { } catch (Update $exception) {
$this->logger->error($exception->getMessage(), ['job' => $job, 'exception' => [ $this->logger->error($exception->getMessage(), ['job' => $job, 'exception' => $exception]);
'code' => $exception->getCode(),
'message' => $exception->getMessage(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'trace' => $exception->getTraceAsString(),
]]);
} }
return false; return false;
} }

View File

@ -22,7 +22,7 @@ class UF
if ($date === null) { if ($date === null) {
$date = new DateTimeImmutable(); $date = new DateTimeImmutable();
} }
if ($date->diff($today)->days < 0) { if ($date->diff($today)->invert === 1) {
return 0.0; return 0.0;
} }
/** /**
@ -32,7 +32,7 @@ class UF
*/ */
try { try {
$ufs = $this->getRedisUFs(); $ufs = $this->getRedisUFs();
if (!isset($ufs[$date->format('Y-m-d')])) { if (!isset($ufs[$date->format('Y-m-d')]) or $ufs[$date->format('Y-m-d')] === 0) {
throw new EmptyRedis($this->redisKey); throw new EmptyRedis($this->redisKey);
} }
return $ufs[$date->format('Y-m-d')]; return $ufs[$date->format('Y-m-d')];
@ -54,12 +54,16 @@ class UF
} }
public function updateMany(array $dates): array public function updateMany(array $dates): array
{ {
$today = new DateTimeImmutable();
$ufs = []; $ufs = [];
try { try {
$ufs = json_decode($this->redisService->get($this->redisKey), JSON_OBJECT_AS_ARRAY); $ufs = json_decode($this->redisService->get($this->redisKey), JSON_OBJECT_AS_ARRAY);
} catch (EmptyRedis) {} } catch (EmptyRedis) {}
$updated = []; $updated = [];
foreach ($dates as $date) { foreach ($dates as $date) {
if ($date->diff($today)->invert === 1) {
continue;
}
if (!isset($ufs[$date->format('Y-m-d')]) or $ufs[$date->format('Y-m-d')] === 0) { if (!isset($ufs[$date->format('Y-m-d')]) or $ufs[$date->format('Y-m-d')] === 0) {
$uf = $this->moneyService->getUF($date); $uf = $this->moneyService->getUF($date);
if ($uf === 0.0) { if ($uf === 0.0) {

View File

@ -19,7 +19,7 @@ class USD
$usds = []; $usds = [];
try { try {
$usds = json_decode($this->redisService->get($this->redisKey), JSON_OBJECT_AS_ARRAY); $usds = json_decode($this->redisService->get($this->redisKey), JSON_OBJECT_AS_ARRAY);
if (!isset($usds[$date->format('Y-m-d')])) { if (!isset($usds[$date->format('Y-m-d')]) or $usds[$date->format('Y-m-d')] === 0) {
throw new EmptyRedis($this->redisKey); throw new EmptyRedis($this->redisKey);
} }
$usd = $usds[$date->format('Y-m-d')]; $usd = $usds[$date->format('Y-m-d')];

View File

@ -251,7 +251,7 @@ class Invoice extends AbstractEndPoint
{ {
$paramsMap = [ $paramsMap = [
'customer' => 'customer', 'customer' => 'customer',
'product_id' => 'cuota_id', 'product_id' => 'venta_id',
'due_date' => 'fecha', 'due_date' => 'fecha',
'subscription' => 'subscription', 'subscription' => 'subscription',
'amount' => 'valor', 'amount' => 'valor',
@ -266,8 +266,6 @@ class Invoice extends AbstractEndPoint
'invoice_external_id' => 'cuota_id' 'invoice_external_id' => 'cuota_id'
]; ];
$today = new DateTimeImmutable('now', new DateTimeZone('America/Santiago'));
$params = []; $params = [];
foreach ($paramsMap as $key => $ref) { foreach ($paramsMap as $key => $ref) {
if ($ref === null) { if ($ref === null) {
@ -278,14 +276,6 @@ class Invoice extends AbstractEndPoint
continue; continue;
} }
if ($ref === 'valor') { 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; $params[$key] = $data['cuota']->pago->valor;
continue; continue;
} }
@ -303,6 +293,10 @@ class Invoice extends AbstractEndPoint
$params[$key] = $data['cuota']->id; $params[$key] = $data['cuota']->id;
continue; continue;
} }
if ($ref === 'product_id') {
$params[$key] = $data['venta']->id;
continue;
}
if (array_key_exists($ref, $data) and $data[$ref] !== '' and $data[$ref] !== null) { if (array_key_exists($ref, $data) and $data[$ref] !== '' and $data[$ref] !== null) {
$params[$key] = $data[$ref]; $params[$key] = $data[$ref];
} }

View File

@ -99,13 +99,13 @@ class Subscription extends AbstractEndPoint
public function queue(int $venta_id): bool public function queue(int $venta_id): bool
{ {
try { try {
$venta = $this->ventaService->getById($venta_id); $this->ventaService->getById($venta_id);
} catch (Read $exception) { } catch (Read $exception) {
$this->logger->warning($exception); $this->logger->warning($exception);
return false; return false;
} }
try { try {
$subscription = $this->subscriptionRepsitory->fetchByVenta($venta_id); $this->subscriptionRepsitory->fetchByVenta($venta_id);
return false; return false;
} catch (EmptyResult) { } catch (EmptyResult) {
return true; return true;

View File

@ -181,7 +181,8 @@ class Propietario extends Service
]); ]);
$filtered_data = array_intersect_key($data, $fields); $filtered_data = array_intersect_key($data, $fields);
try { try {
$direccion = $this->direccionRepository->fetchByCalleAndNumeroAndExtraAndComuna($filtered_data['calle'], $filtered_data['numero'], $filtered_data['extra'], $filtered_data['comuna']); $direccion = $this->direccionRepository->fetchByCalleAndNumeroAndExtraAndComuna($filtered_data['calle'],
$filtered_data['numero'], $filtered_data['extra'], (int) $filtered_data['comuna']);
} catch (EmptyResult) { } catch (EmptyResult) {
try { try {
$direccion = $this->direccionRepository->create($filtered_data); $direccion = $this->direccionRepository->create($filtered_data);

View File

@ -123,7 +123,7 @@ class Reservation extends Ideal\Service\API
$date = new DateTimeImmutable($data['date']); $date = new DateTimeImmutable($data['date']);
} catch (DateMalformedStringException) {} } catch (DateMalformedStringException) {}
try { try {
$reservation = $this->reservationRepository->fetchByBuyerAndDate($data['buyer_rut'], $date); $reservation = $this->reservationRepository->fetchByBuyerAndUnitAndDate($data['buyer_rut'], (int) $data['units'][0], $date);
if (array_key_exists('broker_rut', $data) and $data['broker_rut'] !== '') { if (array_key_exists('broker_rut', $data) and $data['broker_rut'] !== '') {
try { try {
@ -174,7 +174,7 @@ class Reservation extends Ideal\Service\API
$this->reservationRepository->getConnection()->getPDO()->commit(); $this->reservationRepository->getConnection()->getPDO()->commit();
} }
} catch (PDOException $exception) { } catch (PDOException $exception) {
$this->logger->warning($exception->getMessage(), ['exception' => $exception->getTraceAsString()]); $this->logger->warning($exception->getMessage(), ['exception' => $exception]);
if ($this->reservationRepository->getConnection()->getPDO()->inTransaction()) { if ($this->reservationRepository->getConnection()->getPDO()->inTransaction()) {
$this->reservationRepository->getConnection()->getPDO()->rollBack(); $this->reservationRepository->getConnection()->getPDO()->rollBack();
} }