Feat: Create Customer Modal
This commit is contained in:
		@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M64 32C28.7 32 0 60.7 0 96L0 416c0 35.3 28.7 64 64 64l384 0c35.3 0 64-28.7 64-64l0-320c0-35.3-28.7-64-64-64L64 32zM175 175c9.4-9.4 24.6-9.4 33.9 0l47 47 47-47c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-47 47 47 47c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-47-47-47 47c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l47-47-47-47c-9.4-9.4-9.4-24.6 0-33.9z"/></svg>
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 576 B  | 
@@ -0,0 +1,86 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <v-dialog v-model="showModal" max-width="600px">
 | 
				
			||||||
 | 
					    <v-card>
 | 
				
			||||||
 | 
					      <v-card-title>
 | 
				
			||||||
 | 
					        <span class="headline">Información del Cliente</span>
 | 
				
			||||||
 | 
					      </v-card-title>
 | 
				
			||||||
 | 
					      <v-card-text>
 | 
				
			||||||
 | 
					        <v-form ref="form" v-model="valid">
 | 
				
			||||||
 | 
					          <v-text-field
 | 
				
			||||||
 | 
					            v-model="customer.name"
 | 
				
			||||||
 | 
					            label="Nombre"
 | 
				
			||||||
 | 
					            :rules="[rules.required]"
 | 
				
			||||||
 | 
					            required
 | 
				
			||||||
 | 
					          ></v-text-field>
 | 
				
			||||||
 | 
					          <v-text-field
 | 
				
			||||||
 | 
					            v-model="customer.email"
 | 
				
			||||||
 | 
					            label="Correo Electrónico"
 | 
				
			||||||
 | 
					            :rules="[rules.required, rules.email]"
 | 
				
			||||||
 | 
					            required
 | 
				
			||||||
 | 
					          ></v-text-field>
 | 
				
			||||||
 | 
					          <v-text-field
 | 
				
			||||||
 | 
					            v-model="customer.phone"
 | 
				
			||||||
 | 
					            label="Teléfono"
 | 
				
			||||||
 | 
					            :rules="[rules.required]"
 | 
				
			||||||
 | 
					            required
 | 
				
			||||||
 | 
					          ></v-text-field>
 | 
				
			||||||
 | 
					        </v-form>
 | 
				
			||||||
 | 
					      </v-card-text>
 | 
				
			||||||
 | 
					      <v-card-actions>
 | 
				
			||||||
 | 
					        <v-spacer></v-spacer>
 | 
				
			||||||
 | 
					        <v-btn color="blue darken-1" text @click="closeModal">Cancelar</v-btn>
 | 
				
			||||||
 | 
					        <v-btn color="blue darken-1" text @click="submitForm">Guardar</v-btn>
 | 
				
			||||||
 | 
					      </v-card-actions>
 | 
				
			||||||
 | 
					    </v-card>
 | 
				
			||||||
 | 
					  </v-dialog>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					 export default {
 | 
				
			||||||
 | 
					     data() {
 | 
				
			||||||
 | 
					         return {
 | 
				
			||||||
 | 
					             showModal: false,
 | 
				
			||||||
 | 
					             valid: false,
 | 
				
			||||||
 | 
					             customer: {
 | 
				
			||||||
 | 
					                 name: '',
 | 
				
			||||||
 | 
					                 email: '',
 | 
				
			||||||
 | 
					                 phone: ''
 | 
				
			||||||
 | 
					             },
 | 
				
			||||||
 | 
					             rules: {
 | 
				
			||||||
 | 
					                 required: value => !!value || 'Este campo es requerido.',
 | 
				
			||||||
 | 
					                 email: value => {
 | 
				
			||||||
 | 
					                     const pattern = /^[^ ]+@[^ ]+\.[a-z]{2,3}$/;
 | 
				
			||||||
 | 
					                     return pattern.test(value) || 'El correo no es válido.';
 | 
				
			||||||
 | 
					                 }
 | 
				
			||||||
 | 
					             }
 | 
				
			||||||
 | 
					         };
 | 
				
			||||||
 | 
					     },
 | 
				
			||||||
 | 
					     methods: {
 | 
				
			||||||
 | 
					         openModal() {
 | 
				
			||||||
 | 
					             this.showModal = true;
 | 
				
			||||||
 | 
					         },
 | 
				
			||||||
 | 
					         closeModal() {
 | 
				
			||||||
 | 
					             this.showModal = false;
 | 
				
			||||||
 | 
					             this.resetForm();
 | 
				
			||||||
 | 
					         },
 | 
				
			||||||
 | 
					         submitForm() {
 | 
				
			||||||
 | 
					             if (this.$refs.form.validate()) {
 | 
				
			||||||
 | 
					                 // Aquí puedes manejar el envío del formulario
 | 
				
			||||||
 | 
					                 console.log('Cliente guardado:', this.customer);
 | 
				
			||||||
 | 
					                 this.closeModal();
 | 
				
			||||||
 | 
					             }
 | 
				
			||||||
 | 
					         },
 | 
				
			||||||
 | 
					         resetForm() {
 | 
				
			||||||
 | 
					             this.customer = {
 | 
				
			||||||
 | 
					                 name: '',
 | 
				
			||||||
 | 
					                 email: '',
 | 
				
			||||||
 | 
					                 phone: ''
 | 
				
			||||||
 | 
					             };
 | 
				
			||||||
 | 
					             this.$refs.form.reset();
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					     }
 | 
				
			||||||
 | 
					 };
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div class="modal">
 | 
				
			||||||
 | 
					      <div class="head">
 | 
				
			||||||
 | 
					          <p>Nuevo Movimiento</p>
 | 
				
			||||||
 | 
					          <img @click="close" src="@/assets/close-icon.svg" alt="cerrar"/>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div class="body">
 | 
				
			||||||
 | 
					          <slot></slot>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script setup>
 | 
				
			||||||
 | 
					 import { defineEmits } from "vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 const emit = defineEmits(["close"]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 const close = () => emit("close");
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
@@ -15,10 +15,12 @@
 | 
				
			|||||||
              required
 | 
					              required
 | 
				
			||||||
              class="mr-4"
 | 
					              class="mr-4"
 | 
				
			||||||
            ></v-autocomplete>
 | 
					            ></v-autocomplete>
 | 
				
			||||||
 | 
					            <v-btn color="primary" @click="openModal">Agregar Cliente</v-btn>
 | 
				
			||||||
 | 
					            <CreateCustomerModal ref="customerModal" />
 | 
				
			||||||
          </v-col>
 | 
					          </v-col>
 | 
				
			||||||
          <v-col
 | 
					          <v-col
 | 
				
			||||||
            lg="2"
 | 
					            lg="2"
 | 
				
			||||||
            >
 | 
					          >
 | 
				
			||||||
          <v-text-field
 | 
					          <v-text-field
 | 
				
			||||||
            v-model="purchase.date"
 | 
					            v-model="purchase.date"
 | 
				
			||||||
            label="Fecha"
 | 
					            label="Fecha"
 | 
				
			||||||
@@ -112,141 +114,149 @@
 | 
				
			|||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script>
 | 
					<script>
 | 
				
			||||||
  export default {
 | 
					 import CustomerForm from './CreateCustomerModal.vue';
 | 
				
			||||||
    name: 'DonConfiao',
 | 
					 | 
				
			||||||
    props: {
 | 
					 | 
				
			||||||
      msg: String
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    data() {
 | 
					 | 
				
			||||||
      return {
 | 
					 | 
				
			||||||
        valid: false,
 | 
					 | 
				
			||||||
        client_search: '',
 | 
					 | 
				
			||||||
        product_search: '',
 | 
					 | 
				
			||||||
        purchase: {
 | 
					 | 
				
			||||||
          date: this.getCurrentDate(),
 | 
					 | 
				
			||||||
          client: null,
 | 
					 | 
				
			||||||
          notes: '',
 | 
					 | 
				
			||||||
          saleline_set: [{product:'', unit_price: 0, quantity: 0}],
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        rules: {
 | 
					 | 
				
			||||||
          required: value => !!value || 'Requerido.',
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        menuItems: [
 | 
					 | 
				
			||||||
          { title: 'Inicio', route: '/'},
 | 
					 | 
				
			||||||
          { title: 'Compras', route:'/compras'},
 | 
					 | 
				
			||||||
        ],
 | 
					 | 
				
			||||||
        clients: [],
 | 
					 | 
				
			||||||
        products: [],
 | 
					 | 
				
			||||||
      };
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    created() {
 | 
					 | 
				
			||||||
      this.fetchClients();
 | 
					 | 
				
			||||||
      this.fetchProducts();
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    watch: {
 | 
					 | 
				
			||||||
      group () {
 | 
					 | 
				
			||||||
        this.drawer = false
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    computed: {
 | 
					 | 
				
			||||||
      calculateTotal() {
 | 
					 | 
				
			||||||
        return this.purchase.saleline_set.reduce((total, saleline) => {
 | 
					 | 
				
			||||||
          return total + this.calculateSubtotal(saleline);
 | 
					 | 
				
			||||||
        }, 0);
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      filteredClients() {
 | 
					 | 
				
			||||||
        return this.clients.filter(client => {
 | 
					 | 
				
			||||||
          if (this.client_search === '') {
 | 
					 | 
				
			||||||
            return [];
 | 
					 | 
				
			||||||
          } else {
 | 
					 | 
				
			||||||
            return client.name.toLowerCase().includes(this.client_search.toLowerCase());
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      filteredProducts() {
 | 
					 | 
				
			||||||
        return this.products.filter(product => {
 | 
					 | 
				
			||||||
          if (this.product_search === '') {
 | 
					 | 
				
			||||||
            return [];
 | 
					 | 
				
			||||||
          } else {
 | 
					 | 
				
			||||||
            return product.name.toLowerCase().includes(this.product_search.toLowerCase());
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    methods: {
 | 
					 | 
				
			||||||
      getCurrentDate() {
 | 
					 | 
				
			||||||
        const today = new Date();
 | 
					 | 
				
			||||||
        const yyyy = today.getFullYear();
 | 
					 | 
				
			||||||
        const mm = String(today.getMonth() + 1).padStart(2, '0');
 | 
					 | 
				
			||||||
        const dd = String(today.getDate()).padStart(2, '0');
 | 
					 | 
				
			||||||
        return `${yyyy}-${mm}-${dd}`;
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      onProductChange(index) {
 | 
					 export default {
 | 
				
			||||||
        const selectedProductId = this.purchase.saleline_set[index].product;
 | 
					   name: 'DonConfiao',
 | 
				
			||||||
        const selectedProduct = this.products.find(p => p.id == selectedProductId);
 | 
					   components: {
 | 
				
			||||||
        this.purchase.saleline_set[index].unit_price = selectedProduct.price;
 | 
					     CustomerForm
 | 
				
			||||||
      },
 | 
					   },
 | 
				
			||||||
      fetchClients() {
 | 
					   props: {
 | 
				
			||||||
        fetch('/don_confiao/api/customers/')
 | 
					     msg: String
 | 
				
			||||||
          .then(response => response.json())
 | 
					   },
 | 
				
			||||||
          .then(data => {
 | 
					   data() {
 | 
				
			||||||
            this.clients = data;
 | 
					     return {
 | 
				
			||||||
          })
 | 
					       valid: false,
 | 
				
			||||||
          .catch(error => {
 | 
					       client_search: '',
 | 
				
			||||||
            console.error(error);
 | 
					       product_search: '',
 | 
				
			||||||
          });
 | 
					       purchase: {
 | 
				
			||||||
      },
 | 
					         date: this.getCurrentDate(),
 | 
				
			||||||
      fetchProducts() {
 | 
					         client: null,
 | 
				
			||||||
        fetch('/don_confiao/api/products/')
 | 
					         notes: '',
 | 
				
			||||||
          .then(response => response.json())
 | 
					         saleline_set: [{product:'', unit_price: 0, quantity: 0}],
 | 
				
			||||||
          .then(data => {
 | 
					       },
 | 
				
			||||||
            console.log(data);
 | 
					       rules: {
 | 
				
			||||||
            this.products = data;
 | 
					         required: value => !!value || 'Requerido.',
 | 
				
			||||||
          })
 | 
					       },
 | 
				
			||||||
          .catch(error => {
 | 
					       menuItems: [
 | 
				
			||||||
            console.error(error);
 | 
					         { title: 'Inicio', route: '/'},
 | 
				
			||||||
          });
 | 
					         { title: 'Compras', route:'/compras'},
 | 
				
			||||||
      },
 | 
					       ],
 | 
				
			||||||
      addLine() {
 | 
					       clients: [],
 | 
				
			||||||
        this.purchase.saleline_set.push({ product: '', unit_price: 0, quantity:0 });
 | 
					       products: [],
 | 
				
			||||||
      },
 | 
					     };
 | 
				
			||||||
      removeLine(index) {
 | 
					   },
 | 
				
			||||||
        this.purchase.saleline_set.splice(index, 1);
 | 
					   created() {
 | 
				
			||||||
      },
 | 
					     this.fetchClients();
 | 
				
			||||||
      calculateSubtotal(line) {
 | 
					     this.fetchProducts();
 | 
				
			||||||
        return line.unit_price * line.quantity;
 | 
					   },
 | 
				
			||||||
      },
 | 
					   watch: {
 | 
				
			||||||
      async submit() {
 | 
					     group () {
 | 
				
			||||||
        if (this.$refs.form.validate()) {
 | 
					       this.drawer = false
 | 
				
			||||||
          try {
 | 
					     },
 | 
				
			||||||
            const response = await fetch('/don_confiao/api/sales/', {
 | 
					   },
 | 
				
			||||||
              method: 'POST',
 | 
					   computed: {
 | 
				
			||||||
              headers: {
 | 
					     calculateTotal() {
 | 
				
			||||||
                'Content-Type': 'application/json',
 | 
					       return this.purchase.saleline_set.reduce((total, saleline) => {
 | 
				
			||||||
              },
 | 
					         return total + this.calculateSubtotal(saleline);
 | 
				
			||||||
              body: JSON.stringify(this.purchase),
 | 
					       }, 0);
 | 
				
			||||||
            });
 | 
					     },
 | 
				
			||||||
            if (response.ok) {
 | 
					     filteredClients() {
 | 
				
			||||||
              const data = await response.json();
 | 
					       return this.clients.filter(client => {
 | 
				
			||||||
              console.log('Compra enviada:', data);
 | 
					         if (this.client_search === '') {
 | 
				
			||||||
              this.$router.push("SummaryPurchase");
 | 
					           return [];
 | 
				
			||||||
            } else {
 | 
					         } else {
 | 
				
			||||||
              console.error('Error al enviar la compra:', response.statusText);
 | 
					           return client.name.toLowerCase().includes(this.client_search.toLowerCase());
 | 
				
			||||||
            }
 | 
					         }
 | 
				
			||||||
          } catch (error) {
 | 
					       });
 | 
				
			||||||
            console.error('Error de red:', error);
 | 
					     },
 | 
				
			||||||
          }
 | 
					     filteredProducts() {
 | 
				
			||||||
        }
 | 
					       return this.products.filter(product => {
 | 
				
			||||||
      },
 | 
					         if (this.product_search === '') {
 | 
				
			||||||
      navigate(route) {
 | 
					           return [];
 | 
				
			||||||
        this.$router.push(route);
 | 
					         } else {
 | 
				
			||||||
      },
 | 
					           return product.name.toLowerCase().includes(this.product_search.toLowerCase());
 | 
				
			||||||
      formatPrice(price) {
 | 
					         }
 | 
				
			||||||
        return new Intl.NumberFormat('es-ES', { style: 'currency', currency: 'COP' }).format(price);
 | 
					       });
 | 
				
			||||||
      },
 | 
					     },
 | 
				
			||||||
    },
 | 
					   },
 | 
				
			||||||
  };
 | 
					   methods: {
 | 
				
			||||||
 | 
					     openModal() {
 | 
				
			||||||
 | 
					      this.$refs.customerModal.openModal();
 | 
				
			||||||
 | 
					     },
 | 
				
			||||||
 | 
					     getCurrentDate() {
 | 
				
			||||||
 | 
					       const today = new Date();
 | 
				
			||||||
 | 
					       const yyyy = today.getFullYear();
 | 
				
			||||||
 | 
					       const mm = String(today.getMonth() + 1).padStart(2, '0');
 | 
				
			||||||
 | 
					       const dd = String(today.getDate()).padStart(2, '0');
 | 
				
			||||||
 | 
					       return `${yyyy}-${mm}-${dd}`;
 | 
				
			||||||
 | 
					     },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     onProductChange(index) {
 | 
				
			||||||
 | 
					       const selectedProductId = this.purchase.saleline_set[index].product;
 | 
				
			||||||
 | 
					       const selectedProduct = this.products.find(p => p.id == selectedProductId);
 | 
				
			||||||
 | 
					       this.purchase.saleline_set[index].unit_price = selectedProduct.price;
 | 
				
			||||||
 | 
					     },
 | 
				
			||||||
 | 
					     fetchClients() {
 | 
				
			||||||
 | 
					       fetch('/don_confiao/api/customers/')
 | 
				
			||||||
 | 
					         .then(response => response.json())
 | 
				
			||||||
 | 
					         .then(data => {
 | 
				
			||||||
 | 
					           this.clients = data;
 | 
				
			||||||
 | 
					         })
 | 
				
			||||||
 | 
					         .catch(error => {
 | 
				
			||||||
 | 
					           console.error(error);
 | 
				
			||||||
 | 
					         });
 | 
				
			||||||
 | 
					     },
 | 
				
			||||||
 | 
					     fetchProducts() {
 | 
				
			||||||
 | 
					       fetch('/don_confiao/api/products/')
 | 
				
			||||||
 | 
					         .then(response => response.json())
 | 
				
			||||||
 | 
					         .then(data => {
 | 
				
			||||||
 | 
					           console.log(data);
 | 
				
			||||||
 | 
					           this.products = data;
 | 
				
			||||||
 | 
					         })
 | 
				
			||||||
 | 
					         .catch(error => {
 | 
				
			||||||
 | 
					           console.error(error);
 | 
				
			||||||
 | 
					         });
 | 
				
			||||||
 | 
					     },
 | 
				
			||||||
 | 
					     addLine() {
 | 
				
			||||||
 | 
					       this.purchase.saleline_set.push({ product: '', unit_price: 0, quantity:0 });
 | 
				
			||||||
 | 
					     },
 | 
				
			||||||
 | 
					     removeLine(index) {
 | 
				
			||||||
 | 
					       this.purchase.saleline_set.splice(index, 1);
 | 
				
			||||||
 | 
					     },
 | 
				
			||||||
 | 
					     calculateSubtotal(line) {
 | 
				
			||||||
 | 
					       return line.unit_price * line.quantity;
 | 
				
			||||||
 | 
					     },
 | 
				
			||||||
 | 
					     async submit() {
 | 
				
			||||||
 | 
					       if (this.$refs.form.validate()) {
 | 
				
			||||||
 | 
					         try {
 | 
				
			||||||
 | 
					           const response = await fetch('/don_confiao/api/sales/', {
 | 
				
			||||||
 | 
					             method: 'POST',
 | 
				
			||||||
 | 
					             headers: {
 | 
				
			||||||
 | 
					               'Content-Type': 'application/json',
 | 
				
			||||||
 | 
					             },
 | 
				
			||||||
 | 
					             body: JSON.stringify(this.purchase),
 | 
				
			||||||
 | 
					           });
 | 
				
			||||||
 | 
					           if (response.ok) {
 | 
				
			||||||
 | 
					             const data = await response.json();
 | 
				
			||||||
 | 
					             console.log('Compra enviada:', data);
 | 
				
			||||||
 | 
					             this.$router.push("SummaryPurchase");
 | 
				
			||||||
 | 
					           } else {
 | 
				
			||||||
 | 
					             console.error('Error al enviar la compra:', response.statusText);
 | 
				
			||||||
 | 
					           }
 | 
				
			||||||
 | 
					         } catch (error) {
 | 
				
			||||||
 | 
					           console.error('Error de red:', error);
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					       }
 | 
				
			||||||
 | 
					     },
 | 
				
			||||||
 | 
					     navigate(route) {
 | 
				
			||||||
 | 
					       this.$router.push(route);
 | 
				
			||||||
 | 
					     },
 | 
				
			||||||
 | 
					     formatPrice(price) {
 | 
				
			||||||
 | 
					       return new Intl.NumberFormat('es-ES', { style: 'currency', currency: 'COP' }).format(price);
 | 
				
			||||||
 | 
					     },
 | 
				
			||||||
 | 
					   },
 | 
				
			||||||
 | 
					 };
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
<style>
 | 
					<style>
 | 
				
			||||||
</style>
 | 
					</style>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user