From a6037e4e1400f1192aa65aae29760abc3cd0dd8c Mon Sep 17 00:00:00 2001 From: Juan Pablo Vial Date: Thu, 13 Nov 2025 18:57:58 -0300 Subject: [PATCH] Edit modal, validation of whole data --- .../views/ventas/reservations.blade.php | 5 +- .../ventas/reservations/modal/add.blade.php | 14 ++- .../reservations/modal/common/form.blade.php | 2 +- .../modal/common/scripts/modal.blade.php | 53 ++++++++- .../modal/common/scripts/promotions.blade.php | 6 + .../modal/common/scripts/units.blade.php | 8 +- .../ventas/reservations/modal/edit.blade.php | 112 ++++++++++++++---- app/src/Repository/Venta/Reservation.php | 30 +++-- 8 files changed, 195 insertions(+), 35 deletions(-) diff --git a/app/resources/views/ventas/reservations.blade.php b/app/resources/views/ventas/reservations.blade.php index 94c604c..f6a9904 100644 --- a/app/resources/views/ventas/reservations.blade.php +++ b/app/resources/views/ventas/reservations.blade.php @@ -842,6 +842,7 @@ commission: formatter.format(contract.commission), name: '', text: '', + value: contract.broker_rut } }) const promises = [] @@ -855,7 +856,9 @@ return } const idx = reservations.data.brokers[project_id].findIndex(contract => contract.broker_rut === broker.rut) - reservations.data.brokers[project_id][idx].name = reservations.data.brokers[project_id][idx].text = `${broker.name} - ${reservations.data.brokers[project_id][idx].commission}` + const text = reservations.data.brokers[project_id][idx].text = `${broker.name} - ${reservations.data.brokers[project_id][idx].commission}` + reservations.data.brokers[project_id][idx].name = text + reservations.data.brokers[project_id][idx].text = text }) }) }) diff --git a/app/resources/views/ventas/reservations/modal/add.blade.php b/app/resources/views/ventas/reservations/modal/add.blade.php index 6b2e035..2482d2e 100644 --- a/app/resources/views/ventas/reservations/modal/add.blade.php +++ b/app/resources/views/ventas/reservations/modal/add.blade.php @@ -30,7 +30,7 @@ add() { const url = '/api/ventas/reservation/add' const form = document.getElementById(this.ids.form) - const body = new FormData(form) + let body = new FormData(form) const date = this.components.$date.calendar('get date') body.set(`${this.prefix}_date`, [date.getFullYear(), date.getMonth() + 1, date.getDate()].join('-')) body.set(`${this.prefix}_buyer_rut`, Rut.clean(this.components.rut.querySelector('input').value)) @@ -59,6 +59,18 @@ body.delete(`${this.prefix}_buyer_email_name`) body.delete(`${this.prefix}_buyer_email_domain`) + body.keys().forEach(key => { + if (body.get(key) === '') { + body.delete(key) + } + }) + + body = this.validateBody(body) + if (body.keys().toArray().length === 0) { + alert('No hay datos.') + return + } + const method = 'post' return APIClient.fetch(url, {method, body}).then(response => response.json()).then(json => { if (json.success) { diff --git a/app/resources/views/ventas/reservations/modal/common/form.blade.php b/app/resources/views/ventas/reservations/modal/common/form.blade.php index 3dbdaf1..174901f 100644 --- a/app/resources/views/ventas/reservations/modal/common/form.blade.php +++ b/app/resources/views/ventas/reservations/modal/common/form.blade.php @@ -149,7 +149,7 @@
- +
diff --git a/app/resources/views/ventas/reservations/modal/common/scripts/modal.blade.php b/app/resources/views/ventas/reservations/modal/common/scripts/modal.blade.php index f0dc269..7e1657e 100644 --- a/app/resources/views/ventas/reservations/modal/common/scripts/modal.blade.php +++ b/app/resources/views/ventas/reservations/modal/common/scripts/modal.blade.php @@ -153,7 +153,7 @@ this.fill.brokers() }) }, - broker: (broker_rut) => { + /*broker: (broker_rut) => { const uri = `/api/proyectos/broker/${broker_rut}` return APIClient.fetch(uri).then(response => response.json()).then(json => { if (!('broker' in json)) { @@ -161,7 +161,7 @@ } return json.broker }) - }, + },*/ promotions: project_id => { if (project_id in this.data.promotions) { return new Promise((resolve, reject) => { @@ -266,6 +266,55 @@ this.components.$loader.hide() } } + validateBody(body) { + const fieldMap = { + 'project_id': this.reservation.project_id, + 'date': this.reservation.date, + 'buyer_rut': this.reservation.buyer.rut.toString(), + 'buyer_digit': this.reservation.buyer.digito, + 'buyer_name': this.reservation.buyer.nombres, + 'buyer_last_name': this.reservation.buyer.apellidoPaterno, + 'buyer_last_name2': this.reservation.buyer.apellidoMaterno, + 'buyer_address_street': this.reservation.buyer.datos?.direccion?.calle, + 'buyer_address_number': this.reservation.buyer.datos?.direccion?.numero?.toString(), + 'buyer_address_extra': this.reservation.buyer.datos?.direccion?.extra, + 'buyer_address_comuna_id': this.reservation.buyer.datos?.direccion?.comuna?.id?.toString(), + 'buyer_phone': this.reservation.buyer.datos?.telefono, + 'buyer_email': this.reservation.buyer.datos?.email, + 'buyer_birthdate': this.reservation.buyer.datos?.fechaNacimiento, + 'buyer_marital_status': this.reservation.buyer.datos?.estadoCivil, + 'buyer_profession': this.reservation.buyer.datos?.ocupacion, + 'broker_rut': this.reservation.broker?.rut?.toString(), + 'payment_pie': this.reservation.payment?.pie, + 'payment_cuotas': this.reservation.payment?.cuotas?.toString(), + 'payment_credit': this.reservation.payment?.credit, + 'promotions[]': this.reservation.promotions?.map(p => p.id.toString()), + 'units[]': this.reservation.units?.map(u => u.unit.id.toString()), + 'units_value[]': this.reservation.units?.map(u => u.value.toString()), + } + Object.entries(fieldMap).forEach(([key, value]) => { + if (key.includes('[]') && body.has(`${this.prefix}_${key}`)) { + const values = body.getAll(`${this.prefix}_${key}`) + if (values.length !== value.length) { + return + } + const diff = values.some(v => !value.includes(v)) + if (diff.length > 0) { + return + } + if (JSON.stringify(values.sort()) !== JSON.stringify(value.sort())) { + return + } + body.delete(`${this.prefix}_${key}`) + return + } + if (body.has(`${this.prefix}_${key}`) && value === body.get(`${this.prefix}_${key}`)) { + body.delete(`${this.prefix}_${key}`) + } + }) + + return body + } show() { this.reset() this.components.$modal.modal('show') diff --git a/app/resources/views/ventas/reservations/modal/common/scripts/promotions.blade.php b/app/resources/views/ventas/reservations/modal/common/scripts/promotions.blade.php index 8cc8d39..84cdd70 100644 --- a/app/resources/views/ventas/reservations/modal/common/scripts/promotions.blade.php +++ b/app/resources/views/ventas/reservations/modal/common/scripts/promotions.blade.php @@ -91,8 +91,14 @@ if (reservations.locks.promotions !== null) { await reservations.locks.promotions } + const idxs = [] promotions.forEach(promotion => { const idx = this.add() + idxs.push(idx) + }) + let i = 0 + promotions.forEach(promotion => { + const idx = idxs[i ++] const dropdown = $(this.components.promotions.querySelector(`div.promotion[data-id="${idx}"]`).querySelector('div.dropdown')) dropdown.dropdown('set selected', promotion.id) }) diff --git a/app/resources/views/ventas/reservations/modal/common/scripts/units.blade.php b/app/resources/views/ventas/reservations/modal/common/scripts/units.blade.php index ab93216..17c7eef 100644 --- a/app/resources/views/ventas/reservations/modal/common/scripts/units.blade.php +++ b/app/resources/views/ventas/reservations/modal/common/scripts/units.blade.php @@ -165,12 +165,18 @@ if (reservations.locks.units !== null) { await reservations.locks.units } + const idxs = [] unitValues.forEach(unitValue => { const type = unitValue.unit.proyecto_tipo_unidad.tipo_unidad.descripcion const idx = this.add(type) + idxs.push(idx) + }) + let i = 0 + unitValues.forEach(unitValue => { + const idx = idxs[i ++] const field = this.components.units.querySelector(`div.unit[data-id="${idx}"]`) $(field.querySelector('div.dropdown.edit_units')).dropdown('set selected', unitValue.unit.id) - $(field.querySelector('div.input')).val(unitValue.value) + field.querySelector('div.input').querySelector('input').value = unitValue.value }) } setup() { diff --git a/app/resources/views/ventas/reservations/modal/edit.blade.php b/app/resources/views/ventas/reservations/modal/edit.blade.php index ec5efa0..7415984 100644 --- a/app/resources/views/ventas/reservations/modal/edit.blade.php +++ b/app/resources/views/ventas/reservations/modal/edit.blade.php @@ -18,6 +18,8 @@ } } class EditReservationModal extends ReservationModal { + reservation = null + constructor(projects_id) { super({projects_id, prefix: 'edit', components: { promotions: new EditModalPromotions(), @@ -31,22 +33,27 @@ super.show() this.fillReservation(reservation) } + reset() { + super.reset() + this.reservation = null + } + async fillReservation(reservation) { - console.debug(this.components, reservation) - this.components.form.querySelector('#edit_reservation_id').value = reservation.id + this.reservation = reservation + this.components.form.querySelector(`#${this.prefix}_reservation_id`).value = reservation.id const date = new Date(reservation.date) date.setDate(date.getDate() + 1) this.components.$date.calendar('set date', date) - this.components.rut.querySelector('input[name="edit_buyer_rut"]').value = Rut.format(reservation.buyer.rut) || '' + this.components.rut.querySelector(`input[name="${this.prefix}_buyer_rut"]`).value = Rut.format(reservation.buyer.rut) || '' this.components.digit.textContent = reservation.buyer.digito || '' - this.components.form.querySelector('[name="edit_buyer_name"]').value = reservation.buyer.nombres || '' - this.components.form.querySelector('[name="edit_buyer_last_name"]').value = reservation.buyer.apellidoPaterno || '' - this.components.form.querySelector('[name="edit_buyer_last_name2"]').value = reservation.buyer.apellidoMaterno || '' + this.components.form.querySelector(`[name="${this.prefix}_buyer_name"]`).value = reservation.buyer.nombres || '' + this.components.form.querySelector(`[name="${this.prefix}_buyer_last_name"]`).value = reservation.buyer.apellidoPaterno || '' + this.components.form.querySelector(`[name="${this.prefix}_buyer_last_name2"]`).value = reservation.buyer.apellidoMaterno || '' if ('datos' in reservation.buyer && reservation.buyer.datos !== null) { if ('direccion' in reservation.buyer.datos && reservation.buyer.datos.direccion !== null) { - this.components.form.querySelector('[name="edit_buyer_address_street"]').value = reservation.buyer.datos.direccion.calle - this.components.form.querySelector('[name="edit_buyer_address_number"]').value = reservation.buyer.datos.direccion.numero - this.components.form.querySelector('[name="edit_buyer_address_extra"]').value = reservation.buyer.datos.direccion.extra + this.components.form.querySelector(`[name="${this.prefix}_buyer_address_street"]`).value = reservation.buyer.datos.direccion.calle + this.components.form.querySelector(`[name="${this.prefix}_buyer_address_number"]`).value = reservation.buyer.datos.direccion.numero + this.components.form.querySelector(`[name="${this.prefix}_buyer_address_extra"]`).value = reservation.buyer.datos.direccion.extra this.components.$region.dropdown('set selected', reservation.buyer.datos.direccion.comuna.provincia.region.id) const delay = ms => new Promise(resolve => setTimeout(resolve, ms)) const waitComuna = async () => { @@ -55,20 +62,21 @@ } await waitComuna() } - this.components.form.querySelector('[name="edit_buyer_phone"]').value = reservation.buyer.datos.telefono || '' - if ('email' in reservation.buyer.datos && reservation.buyer.datos.email.includes('@') && reservation.buyer.datos.email.length > 1) { + this.components.form.querySelector(`[name="${this.prefix}_buyer_phone"]`).value = reservation.buyer.datos.telefono || '' + if ('email' in reservation.buyer.datos && reservation.buyer.datos.email !== null && reservation.buyer.datos.email.includes('@') && reservation.buyer.datos.email.length > 1) { const parts = reservation.buyer.datos.email.split('@') - this.components.form.querySelector('[name="edit_buyer_email_name"]').value = parts[0] - this.components.form.querySelector('[name="edit_buyer_email_domain"]').value = parts[1] + this.components.form.querySelector(`[name="${this.prefix}_buyer_email_name"]`).value = parts[0] + this.components.form.querySelector(`[name="${this.prefix}_buyer_email_domain"]`).value = parts[1] } - this.components.form.querySelector('[name="edit_buyer_marital_status"]').value = reservation.buyer.datos.estadoCivil || '' - this.components.form.querySelector('[name="edit_buyer_profession"]').value = reservation.buyer.datos.ocupacion || '' + this.components.form.querySelector(`[name="${this.prefix}_buyer_marital_status"]`).value = reservation.buyer.datos.estadoCivil || '' + this.components.form.querySelector(`[name="${this.prefix}_buyer_profession"]`).value = reservation.buyer.datos.ocupacion || '' if ('fechaNacimiento' in reservation.buyer.datos) { const birthdate = new Date(reservation.buyer.datos.fechaNacimiento) birthdate.setDate(birthdate.getDate() + 1) this.components.$birthdate.calendar('set date', birthdate) } } + if (reservation.broker !== null) { if (reservations.locks.brokers === null) { await reservations.locks.brokers @@ -81,11 +89,75 @@ if (reservation.units.length > 0) { this.components.units.fill(reservation.units) } - if ('formaPago' in reservation && reservation.formaPago !== null) { - this.components.payments.fill(reservation.formaPago) + if ('payment' in reservation && reservation.payment !== null) { + this.components.payments.fill(reservation.payment) } } - edit() {} + edit() { + const id = this.components.form.querySelector(`#${this.prefix}_reservation_id`).value + const url = `/api/ventas/reservation/${id}/edit` + const form = document.getElementById(this.ids.form) + let body = new FormData(form) + body.delete(`${this.prefix}_reservation_id`) + body.delete(`${this.prefix}_project_id`) + + const date = this.components.$date.calendar('get date') + body.set(`${this.prefix}_date`, [ + date.getFullYear(), + (date.getMonth() + 1).toString().padStart(2, '0'), + date.getDate().toString().padStart(2, '0')].join('-')) + body.set(`${this.prefix}_buyer_rut`, Rut.clean(this.components.rut.querySelector('input').value)) + body.set(`${this.prefix}_buyer_digit`, this.components.digit.textContent) + body.set(`${this.prefix}_buyer_address_comuna_id`, this.components.$comuna.dropdown('get value')) + let email = form.querySelector(`input[name='${this.prefix}_buyer_email_name']`).value + '@' + form.querySelector(`input[name='${this.prefix}_buyer_email_domain']`).value + if (email !== '@') { + body.set(`${this.prefix}_buyer_email`, email) + } + const birthdate = this.components.$birthdate.calendar('get date') + body.set(`${this.prefix}_buyer_birthdate`, [ + birthdate.getFullYear(), + (birthdate.getMonth() + 1).toString().padStart(2, '0'), + birthdate.getDate().toString().padStart(2, '0')].join('-')) + body.set(`${this.prefix}_broker_rut`, Rut.clean(this.components.$broker.dropdown('get value'))) + + if (this.components.payments.components.pie.$checkbox.checkbox('is unchecked')) { + body.delete(`${this.prefix}_payment_pie`) + body.delete(`${this.prefix}_payment_cuotas`) + } + body.delete(`${this.prefix}_payment_has_pie`) + if (this.components.payments.components.credit.$checkbox.checkbox('is unchecked')) { + body.delete(`${this.prefix}_payment_credit`) + } + body.delete(`${this.prefix}_payment_has_credit`) + + body.delete('comuna') + body.delete('region') + body.delete('broker') + body.delete(`${this.prefix}_broker`) + body.delete('birthdate') + body.delete(`${this.prefix}_buyer_email_name`) + body.delete(`${this.prefix}_buyer_email_domain`) + + const keys = body.keys().toArray() + keys.forEach(key => { + if (body.get(key) === '' || body.get(key) === null) { + body.delete(key) + } + }) + + body = this.validateBody(body) + if (body.keys().toArray().length === 0) { + alert('No hay cambios.') + return + } + + const method = 'post' + return APIClient.fetch(url, {method, body}).then(response => response.json()).then(json => { + if (json.success) { + window.location.reload() + } + }) + } setup() { super.setup() @@ -101,8 +173,8 @@ }) const idInput = document.createElement('input') idInput.type = 'hidden' - idInput.id = 'edit_reservation_id' - idInput.name = 'edit_reservation_id' + idInput.id = `${this.prefix}_reservation_id` + idInput.name = `${this.prefix}_reservation_id` this.components.form.appendChild(idInput) } } diff --git a/app/src/Repository/Venta/Reservation.php b/app/src/Repository/Venta/Reservation.php index e3135b4..0a19e11 100644 --- a/app/src/Repository/Venta/Reservation.php +++ b/app/src/Repository/Venta/Reservation.php @@ -3,21 +3,25 @@ namespace Incoviba\Repository\Venta; use DateTimeInterface; use DateInterval; +use Incoviba\Exception\ServiceAction\Read; use PDO; use PDOException; +use Psr\Log\LoggerInterface; use Incoviba\Common\Define; use Incoviba\Common\Implement\Exception\EmptyResult; use Incoviba\Exception\Model\InvalidState; use Incoviba\Common; use Incoviba\Model; use Incoviba\Repository; +use Incoviba\Service; class Reservation extends Common\Ideal\Repository { public function __construct(Common\Define\Connection $connection, + protected LoggerInterface $logger, protected Repository\Proyecto $proyectoRepository, protected Repository\Persona $personaRepository, - protected Repository\Proyecto\Broker $brokerRepository, + protected Service\Proyecto\Broker $brokerService, protected Unidad $unitRepository, protected Promotion $promotionRepository, protected Pie $advanceRepository, protected Credito $creditRepository, protected Subsidio $subsidyRepository) @@ -93,11 +97,15 @@ class Reservation extends Common\Ideal\Repository $this->fetchUnits($model, $data_row); try { $this->fetchBroker($model, $data_row); - } catch (EmptyResult) {} + } catch (EmptyResult $exception) { + $this->logger->notice(implode("::", [__CLASS__, __METHOD__]), ['data' => $data_row, 'exception' => $exception]); + } $this->fetchPromotions($model, $data_row); try { $this->fetchPayment($model, $data_row); - } catch (EmptyResult) {} + } catch (EmptyResult $exception) { + $this->logger->notice(implode("::", [__CLASS__, __METHOD__]), ['data' => $data_row, 'exception' => $exception]); + } return $model; } @@ -332,7 +340,7 @@ class Reservation extends Common\Ideal\Repository throw new PDOException(); } $new_id = $reservation->broker->rut; - $reservation->broker = $this->brokerRepository->fetchById($result['reference_id']); + $reservation->broker = $this->brokerService->fetchById($result['reference_id']); $this->editBroker($reservation, ['broker_rut' => $new_id]); } catch (EmptyResult | PDOException) { $queryInsert = $this->connection->getQueryBuilder() @@ -522,7 +530,7 @@ class Reservation extends Common\Ideal\Repository 'type' => Model\Venta\Reservation\Detail\Type::Broker->value, 'broker_rut' => $new_data['broker_rut'] ]); - $reservation->broker = $this->brokerRepository->fetchById($new_data['broker_rut']); + $reservation->broker = $this->brokerService->fetchById($new_data['broker_rut']); } catch (PDOException) {} } protected function editPromotions(Model\Venta\Reservation &$reservation, array $new_data): void @@ -629,14 +637,18 @@ class Reservation extends Common\Ideal\Repository if ($result === false) { throw new Common\Implement\Exception\EmptyResult($query); } - $reservation->broker = $this->brokerRepository->fetchById($result['reference_id']); - } catch (PDOException) {} + $reservation->broker = $this->brokerService->get($result['reference_id']); + } catch (PDOException | Read $exception) { + $this->logger->notice(implode("::", [__CLASS__, __METHOD__]), ['data' => $new_data, 'exception' => $exception]); + } return $reservation; } try { - $reservation->broker = $this->brokerRepository->fetchById($new_data['broker_id']); - } catch (Common\Implement\Exception\EmptyResult) {} + $reservation->broker = $this->brokerService->get($new_data['broker_id']); + } catch (Read $exception) { + $this->logger->notice(implode("::", [__CLASS__, __METHOD__]), ['data' => $new_data, 'exception' => $exception]); + } return $reservation; } protected function fetchPromotions(Model\Venta\Reservation &$reservation, array $new_data): Model\Venta\Reservation