diff --git a/app/resources/routes/04_ventas.php b/app/resources/routes/04_ventas.php index 270c83b..8b09f44 100644 --- a/app/resources/routes/04_ventas.php +++ b/app/resources/routes/04_ventas.php @@ -10,6 +10,7 @@ $app->group('/ventas', function($app) { include_once $file->getRealPath(); } $app->get('/add[/]', [Ventas::class, 'add']); + $app->post('/add[/]', [Ventas::class, 'add']); $app->get('[/]', Ventas::class); })->add($app->getContainer()->get(Incoviba\Middleware\Authentication::class)); $app->group('/venta/{proyecto_nombre:[A-za-zÑñ\+\ %0-9]+}/{unidad_descripcion:[0-9]+}', function($app) { diff --git a/app/resources/views/ventas/add.blade.php b/app/resources/views/ventas/add.blade.php index 301f753..34d79e2 100644 --- a/app/resources/views/ventas/add.blade.php +++ b/app/resources/views/ventas/add.blade.php @@ -255,14 +255,18 @@ } class Comuna { id - data + data = { + region: 0, + provincias: [] + } + propietario + promises = { + provincias: null, + comunas: {} + } constructor(id) { this.id = id - this.data = { - region: 0, - provincias: [] - } $(this.id).dropdown({ forceSelection: true @@ -272,13 +276,23 @@ get() { return { provincias: () => { + if (this.data.region in this.propietario.data.comunas) { + this.promises.provincias = new Promise(resolve => resolve(this.propietario.data.comunas[this.data.region])).then(data => { + this.data.provincias = data.provincias + this.draw().comunas() + }) + return this.promises.provincias + } + this.propietario.data.comunas[this.data.region] = {region: this.data.region, provincias: []} const uri = '{{$urls->api}}/region/' + this.data.region + '/provincias' - return fetchAPI(uri).then(response => { + this.promises.provincias = APIClient.fetch(uri).then(response => { + this.promises.provincias = null if (response.ok) { return response.json() } }).then(data => { this.data.provincias = data.provincias + this.propietario.data.comunas[this.data.region].provincias = data.provincias const promises = [] this.data.provincias.forEach(provincia => { promises.push(this.get().comunas(provincia.id)) @@ -287,17 +301,21 @@ this.draw().comunas() }) }) + return this.data.provincias }, comunas: provincia_id => { const uri = '{{$urls->api}}/provincia/' + provincia_id + '/comunas' - return fetchAPI(uri).then(response => { + this.promises.comunas[provincia_id] = fetchAPI(uri).then(response => { if (response.ok) { return response.json() } }).then(data => { + this.promises.comunas[data.provincia_id] = null const i = this.data.provincias.findIndex(provincia => provincia.id === data.provincia_id) this.data.provincias[i].comunas = data.comunas + this.propietario.data.comunas[this.data.region].provincias[i].comunas = data.comunas }) + return this.promises.comunas[provincia_id] } } } @@ -347,6 +365,11 @@ } class PersonaNatural { valid + parent + components = { + rut: null, + region: null + } constructor({valid}) { this.valid = valid } @@ -418,9 +441,10 @@ return lines.join("\n") } activate() { - new RutHandler({id: '#rut', alert_id: '#alert_rut', valid: this.valid}) + this.components.rut = new RutHandler({id: '#rut', alert_id: '#alert_rut', valid: this.valid}) const comuna = new Comuna('#comuna') - new Region({id: '#region', comuna}) + comuna.propietario = this.parent + this.components.region = new Region({id: '#region', comuna}) } } class PersonaTributaria { @@ -572,6 +596,15 @@ } class Propietario { ids + components = { + persona: null + } + data = { + comunas: {} + } + promises = { + propietario: null + } constructor({id, id_tipo, id_cantidad}) { this.ids = { @@ -591,8 +624,6 @@ document.getElementById(this.ids.cantidad).disabled = !document.getElementById(this.ids.tipo).checked this.draw() - - $(this.ids.span).find('#rut') } get tipo() { return document.getElementById(this.ids.tipo).checked ? (document.getElementById(this.ids.cantidad).checked ? 2 : 0) : 1 @@ -613,7 +644,8 @@ return { propietario: rut => { const uri = '{{$urls->api}}/ventas/propietario/' + rut.split('-')[0] - return fetchAPI(uri).then(response => { + this.promises.propietario = APIClient.fetch(uri).then(response => { + this.promises.propietario = null if (response.ok) { return response.json() } @@ -627,7 +659,18 @@ parent.find("[name='numero']").val(data.propietario.direccion.numero) parent.find("[name='extra']").val(data.propietario.direccion.extra) parent.find('#region').dropdown('set selected', data.propietario.direccion.comuna.provincia.region.id) - parent.find('#comuna').dropdown('set selected', data.propietario.direccion.comuna.id) + let persona = this.components.persona + if (!('components' in persona)) { + persona = persona.persona + } + const promise = persona.components.region.comuna.promises.provincias + if (promise === null) { + parent.find('#comuna').dropdown('set selected', data.propietario.direccion.comuna.id) + } else { + promise.then(() => { + parent.find('#comuna').dropdown('set selected', data.propietario.direccion.comuna.id) + }) + } parent.find("[name='email']").val(data.propietario.email) parent.find("[name='telefono']").val(data.propietario.telefono) @@ -645,6 +688,8 @@ } draw() { const propietario = this.get().propietario(this.tipo) + this.components.persona = propietario + propietario.parent = this $(this.ids.span).html(propietario.draw()) propietario.activate() } @@ -655,6 +700,9 @@ data unidades added + promises = { + unidades: null + } constructor({unidades_id, proyecto_id}) { this.ids = { @@ -702,7 +750,8 @@ return { unidades: () => { const uri = '{{$urls->api}}/proyecto/' + this.data.id + '/unidades' - return fetchAPI(uri).then(response => { + this.promises.unidades = APIClient.fetch(uri).then(response => { + this.promises.unidades = null if (response.ok) { return response.json() } @@ -712,6 +761,7 @@ } this.unidades = data.unidades }) + return this.promises.unidades } } } @@ -733,6 +783,7 @@ ) ) ) + return unidad } remove(number) { number = parseInt(number) @@ -750,6 +801,9 @@ } class Unidad{ number + components = { + dropdown: null + } constructor({number}) { this.number = number } @@ -772,12 +826,16 @@ }) dropdown.append(menu) dropdown.dropdown() + this.components.dropdown = dropdown return dropdown } } class Payment { ids + components = { + checkbox: null + } constructor({id, checkbox_id}) { this.ids = { @@ -785,7 +843,8 @@ checkbox: checkbox_id } - document.getElementById(this.ids.checkbox).onchange = event => { + this.components.checkbox = document.getElementById(this.ids.checkbox) + this.components.checkbox.onchange = event => { this.toggle() } this.toggle() @@ -812,12 +871,110 @@ form: '' }, components: { - date: null, + $date: null, project: null, buyer: null, - payments: [], + payments: {}, $form: null }, + fill: { + reservation: () => { + venta.fill.date() + venta.fill.buyer() + venta.fill.project() + venta.fill.payments() + }, + date: () => { + const date = new Date('{{ $date?->format('Y-m-d') }}') + date.setDate(date.getDate() + 1) + venta.components.$date.calendar('set date', date) + }, + buyer: () => { + const buyer = $(venta.ids.buyerId) + const rut = buyer.find('#rut') + rut.val('{{ $propietario['full'] }}') + let persona = venta.components.buyer.components.persona + if (!('components' in persona)) { + persona = persona.persona + } + const promise = persona.components.region.comuna.promises.provincias + if (promise === null) { + venta.fill.buyerRut(buyer, rut) + return; + } + promise.then(() => { + venta.fill.buyerRut(buyer, rut) + }) + }, + buyerRut: (buyer, rut) => { + rut.trigger('change') + const promise = venta.components.buyer.promises.propietario + if (promise === null) { + venta.fill.buyerData(buyer) + return; + } + promise.then(() => { + venta.fill.buyerData(buyer) + }) + }, + buyerData: buyer => { + const email = buyer.find('[name="email"]') + if (email.val() === '') { + email.val('{{ $propietario['email'] ?? '' }}') + } + const telefono = buyer.find('[name="telefono"]') + if (telefono.val() === '') { + telefono.val('{{ $propietario['telefono'] ?? '' }}') + } + }, + project: () => { + $(venta.ids.projectId).dropdown('set selected', {{ $proyecto_id }}) + + const promise = venta.components.project.promises.unidades + if (promise === null) { + venta.fill.units() + return; + } + promise.then(() => { + venta.fill.units() + }) + }, + units: () => { + const unitTypes = JSON.parse('{!! json_encode($unidades) !!}') + Object.entries(unitTypes).forEach(([type, units]) => { + units.forEach(unit_id => { + const unit = venta.components.project.add(type) + unit.components.dropdown.dropdown('set selected', unit_id) + }) + }) + }, + payments: () => { + const formaPago = JSON.parse('{!! json_encode($forma_pago) !!}') + Object.entries(formaPago).forEach(([key, value]) => { + const payment = venta.components.payments[key] + const event = new Event('change', { + view: window, + bubbles: true, + cancelable: true + }) + payment.components.checkbox.dispatchEvent(event) + if (key in venta.fill.payment) { + venta.fill.payment[key](value) + return + } + console.debug(`No fill defined for payment ${key}`) + }) + }, + payment: { + pie: data => { + document.querySelector('[name="pie"]').value = data.valor + document.querySelector('[name="cuotas"]').value = data.cuotas + }, + credito: data => { + document.querySelector('[name="credito"]').value = data + } + } + }, setup({dateId, buyerId, buyerTypeId, buyerNId, unitsId, projectId, fromReservation = false}) { this.ids = { dateId, @@ -843,10 +1000,10 @@ 'bono_pie' ] payments.forEach(payment => { - this.components.payments.push(new Payment({ + this.components.payments[payment] = new Payment({ id: '#' + payment, checkbox_id: 'has_' + payment - })) + }) }) this.components.$form = $(this.ids.form) @@ -887,17 +1044,13 @@ }) if (fromReservation) { - const date = new Date('{{ $date?->format('Y-m-d') }}') - date.setDate(date.getDate() + 1) - this.components.$date.calendar('set date', date) - - $(this.ids.projectId).dropdown('set selection', {{ $proyecto_id }}) + this.fill.reservation() } } } $(document).ready(() => { - const fromReservation = '{{ $fromReservation ?? false }}' + const fromReservation = {{ $from_reservation ? 'true' : 'false' }}; venta.setup({ dateId: '#fecha_venta_calendar', buyerId: '#propietario', @@ -905,7 +1058,7 @@ buyerNId: 'cantidad_propietario', unitsId: '#unidades', projectId: '#proyecto', - fromReservation: fromReservation === 'true' + fromReservation: fromReservation }) }) diff --git a/app/src/Controller/Ventas.php b/app/src/Controller/Ventas.php index 0b78704..430f7ed 100644 --- a/app/src/Controller/Ventas.php +++ b/app/src/Controller/Ventas.php @@ -112,17 +112,24 @@ class Ventas // Check if this is a conversion from a reservation if ($request->getMethod() === 'POST') { $data = $request->getParsedBody(); - + if (isset($data['from_reservation']) && $data['from_reservation'] === 'true' && !empty($data['reservation_id'])) { try { - $reservation = $reservaService->get((int)$data['reservation_id']); - + $reservation = $reservaService->get((int) $data['reservation_id']); + $viewData['from_reservation'] = true; $viewData['reservation_id'] = $reservation->id; $viewData['date'] = $reservation->date; $viewData['comments'] = explode("\n", $reservation->comments); - $viewData['propietario_rut'] = $reservation->buyer->rut; + $viewData['propietario'] = [ + 'rut' => $reservation->buyer->rut, + 'digito' => $reservation->buyer->digito, + 'full' => $reservation->buyer->rutCompleto(), + 'email' => $reservation->buyer->datos()?->email, + 'telefono' => $reservation->buyer->datos()?->telefono, + 'comuna_id' => $reservation->buyer->datos()?->direccion?->comuna?->id + ]; // Add property data $viewData['proyecto_id'] = $reservation->project->id;