From 0ffa93019c9d99844d6be10f39dd8cf57e41eea2 Mon Sep 17 00:00:00 2001 From: Juan Felipe Zapata Moreno Date: Mon, 12 Jan 2026 14:49:08 -0600 Subject: [PATCH] =?UTF-8?q?add:=20agregar=20gesti=C3=B3n=20de=20clientes?= =?UTF-8?q?=20con=20interfaz=20y=20funcionalidad=20de=20registro?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/POS/ClientModal.vue | 251 +++++++++++++++++++++++++++++ src/lang/es.js | 5 + src/layouts/AppLayout.vue | 5 + src/pages/Dashboard/Index.vue | 2 +- src/pages/POS/Category/Index.vue | 1 - src/pages/POS/Clients/Index.vue | 104 ++++++++++++ src/pages/POS/Point.vue | 29 +++- src/router/Index.js | 5 + src/stores/cart.js | 5 +- 9 files changed, 399 insertions(+), 8 deletions(-) create mode 100644 src/components/POS/ClientModal.vue create mode 100644 src/pages/POS/Clients/Index.vue diff --git a/src/components/POS/ClientModal.vue b/src/components/POS/ClientModal.vue new file mode 100644 index 0000000..59d761c --- /dev/null +++ b/src/components/POS/ClientModal.vue @@ -0,0 +1,251 @@ + + + diff --git a/src/lang/es.js b/src/lang/es.js index 2011425..07c1578 100644 --- a/src/lang/es.js +++ b/src/lang/es.js @@ -458,6 +458,7 @@ export default { cashRegister: 'Caja', point: 'Punto de Venta', sales: 'Ventas', + clients: 'Clientes' }, cashRegister: { title: 'Caja Registradora', @@ -560,4 +561,8 @@ export default { noStock: 'No hay suficiente stock disponible', total: 'Total a pagar' }, + clients: { + title: 'Clientes', + description: 'Gestión de clientes', + } } \ No newline at end of file diff --git a/src/layouts/AppLayout.vue b/src/layouts/AppLayout.vue index a4bbfea..3b522b0 100644 --- a/src/layouts/AppLayout.vue +++ b/src/layouts/AppLayout.vue @@ -56,6 +56,11 @@ onMounted(() => { name="pos.sales" to="pos.sales.index" /> +
import { ref, onMounted, computed, watch } from 'vue'; import { useRouter } from 'vue-router'; +import { formatCurrency } from '@/utils/formatters'; import reportService from '@Services/reportService'; import useCashRegister from '@Stores/cashRegister'; import GoogleIcon from '@Shared/GoogleIcon.vue'; -import { formatCurrency } from '@/utils/formatters'; import OpenModal from '@/pages/POS/CashRegister/OpenModal.vue'; // State diff --git a/src/pages/POS/Category/Index.vue b/src/pages/POS/Category/Index.vue index 44fde4f..4489f9a 100644 --- a/src/pages/POS/Category/Index.vue +++ b/src/pages/POS/Category/Index.vue @@ -1,7 +1,6 @@ + + \ No newline at end of file diff --git a/src/pages/POS/Point.vue b/src/pages/POS/Point.vue index fad9618..4df8c66 100644 --- a/src/pages/POS/Point.vue +++ b/src/pages/POS/Point.vue @@ -3,6 +3,7 @@ import { onMounted, ref, computed } from 'vue'; import { useI18n } from 'vue-i18n'; import { useSearcher, apiURL } from '@Services/Api'; import { page } from '@Services/Page'; +import { formatCurrency } from '@/utils/formatters'; import useCart from '@Stores/cart'; import salesService from '@Services/salesService'; import ticketService from '@Services/ticketService'; @@ -11,6 +12,7 @@ import GoogleIcon from '@Shared/GoogleIcon.vue'; import ProductCard from '@Components/POS/ProductCard.vue'; import CartItem from '@Components/POS/CartItem.vue'; import CheckoutModal from '@Components/POS/CheckoutModal.vue'; +import ClientModal from '@Components/POS/ClientModal.vue'; import QRscan from '@Components/POS/QRscan.vue'; /** i18n */ @@ -25,6 +27,8 @@ const showCheckoutModal = ref(false); const searchQuery = ref(''); const processingPayment = ref(false); const scanMode = ref(false); +const showClientModal = ref(false); +const lastSaleData = ref(null); /** Buscador de productos */ const searcher = useSearcher({ @@ -193,6 +197,12 @@ const handleConfirmSale = async (paymentData) => { } } + lastSaleData.value = { + id: response.id, + total: saleData.total, + payment_method: saleData.payment_method + }; + // Limpiar carrito cart.clear(); @@ -202,6 +212,8 @@ const handleConfirmSale = async (paymentData) => { // Recargar productos para actualizar stock searcher.search(); + showClientModal.value = true; + } catch (error) { console.error('Error en venta:', error); @@ -217,6 +229,11 @@ const handleConfirmSale = async (paymentData) => { } }; +const closeClientModal = () => { + showClientModal.value = false; + lastSaleData.value = null; +}; + /** Ciclo de vida */ onMounted(() => { searcher.search(); @@ -361,11 +378,11 @@ onMounted(() => {
{{ $t('cart.subtotal') }} - ${{ cart.subtotal.toFixed(2) }} + ${{ formatCurrency(cart.subtotal) }}
IVA (16%) - ${{ cart.tax.toFixed(2) }} + ${{ formatCurrency(cart.tax) }}
@@ -373,7 +390,7 @@ onMounted(() => { {{ $t('cart.total') }} - ${{ cart.total.toFixed(2) }} + {{ formatCurrency(cart.total) }}
@@ -413,5 +430,11 @@ onMounted(() => { @close="closeCheckout" @confirm="handleConfirmSale" /> +
diff --git a/src/router/Index.js b/src/router/Index.js index 89722a9..d996309 100644 --- a/src/router/Index.js +++ b/src/router/Index.js @@ -70,6 +70,11 @@ const router = createRouter({ path: 'sales', name: 'pos.sales.index', component: () => import('@Pages/POS/Sales/Index.vue') + }, + { + path: 'clients', + name: 'pos.clients.index', + component: () => import('@Pages/POS/Clients/Index.vue') } ] }, diff --git a/src/stores/cart.js b/src/stores/cart.js index bd84487..3ad83c1 100644 --- a/src/stores/cart.js +++ b/src/stores/cart.js @@ -1,5 +1,4 @@ import { defineStore } from 'pinia'; -import Notify from '@Plugins/Notify'; const useCart = defineStore('cart', { state: () => ({ @@ -48,7 +47,7 @@ const useCart = defineStore('cart', { if (existingItem.quantity < product.stock) { existingItem.quantity++; } else { - Notify.warning('No hay suficiente stock disponible'); + window.Notify.warning('No hay suficiente stock disponible'); } } else { // Agregar nuevo item @@ -73,7 +72,7 @@ const useCart = defineStore('cart', { } else if (quantity <= item.max_stock) { item.quantity = quantity; } else { - Notify.warning('No hay suficiente stock disponible'); + window.Notify.warning('No hay suficiente stock disponible'); } } },