mirror of
				https://github.com/crater-invoice/crater.git
				synced 2025-10-30 13:11:08 -04:00 
			
		
		
		
	fix conflicts
This commit is contained in:
		| @ -35,6 +35,8 @@ | ||||
|             <div v-if="$v.formData.price.$error"> | ||||
|               <span v-if="!$v.formData.price.required" class="text-danger">{{ $tc('validation.required') }}</span> | ||||
|               <span v-if="!$v.formData.price.numeric" class="text-danger">{{ $tc('validation.numbers_only') }}</span> | ||||
|               <span v-if="!$v.formData.price.maxLength" class="text-danger">{{ $t('validation.price_maxlength') }}</span> | ||||
|               <span v-if="!$v.formData.price.minValue" class="text-danger">{{ $t('validation.price_minvalue') }}</span> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
| @ -138,7 +140,8 @@ export default { | ||||
|       price: { | ||||
|         required, | ||||
|         numeric, | ||||
|         minValue: minValue(0.1) | ||||
|         minValue: minValue(0.1), | ||||
|         maxLength: maxLength(10) | ||||
|       }, | ||||
|       description: { | ||||
|         maxLength: maxLength(255) | ||||
|  | ||||
| @ -9,6 +9,7 @@ | ||||
| <script> | ||||
| import Chart from 'chart.js' | ||||
| import Utils from '../../helpers/utilities' | ||||
| import { mapGetters } from 'vuex' | ||||
|  | ||||
| export default { | ||||
|   props: { | ||||
| @ -46,9 +47,20 @@ export default { | ||||
|       type: Function, | ||||
|       require: false, | ||||
|       default: Function | ||||
|     }, | ||||
|     FormatGraphMoney: { | ||||
|       type: Function, | ||||
|       require: false, | ||||
|       default: Function | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   computed: { | ||||
|     ...mapGetters('currency', [ | ||||
|       'defaultCurrency' | ||||
|     ]) | ||||
|   }, | ||||
|  | ||||
|   watch: { | ||||
|     labels (val) { | ||||
|       this.update() | ||||
| @ -56,6 +68,7 @@ export default { | ||||
|   }, | ||||
|  | ||||
|   mounted () { | ||||
|     let self = this | ||||
|     let context = this.$refs.graph.getContext('2d') | ||||
|     let options = { | ||||
|       responsive: true, | ||||
| @ -64,7 +77,7 @@ export default { | ||||
|         enabled: true, | ||||
|         callbacks: { | ||||
|           label: function (tooltipItem, data) { | ||||
|             return Utils.formatGraphMoney(tooltipItem.value) | ||||
|             return self.FormatGraphMoney(tooltipItem.value, self.defaultCurrency) | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|  | ||||
| @ -228,6 +228,10 @@ export default { | ||||
|     save_estimate: 'Save Estimate', | ||||
|     confirm_conversion: 'You want to convert this Estimate into Invoice?', | ||||
|     conversion_message: 'Conversion successful', | ||||
|     confirm_send_estimate: 'This estimate will be sent via email to the customer', | ||||
|     confirm_mark_as_sent: 'This estimate will be marked as sent', | ||||
|     confirm_mark_as_accepted: 'This estimate will be marked as Accepted', | ||||
|     confirm_mark_as_rejected: 'This estimate will be marked as Rejected', | ||||
|     no_matching_estimates: 'There are no matching estimates!', | ||||
|     errors: { | ||||
|       required: 'Field is required' | ||||
| @ -551,6 +555,16 @@ export default { | ||||
|       action: 'Action', | ||||
|       add_currency: 'Add Currency' | ||||
|     }, | ||||
|     mail: { | ||||
|       host: 'Mail Host', | ||||
|       port: 'Mail Port', | ||||
|       driver: 'Mail Driver', | ||||
|       password: 'Mail Password', | ||||
|       username: 'Mail Username', | ||||
|       mail_config: 'Mail Configuration', | ||||
|       encryption: 'Mail Encryption', | ||||
|       mail_config_desc: 'Below details will be used to update the mail environment. Also you can change the details anytime after logging in.' | ||||
|     }, | ||||
|     pdf: { | ||||
|       title: 'PDF Setting', | ||||
|       footer_text: 'Footer Text', | ||||
| @ -616,6 +630,7 @@ export default { | ||||
|       created_message: 'Sales tax created successfully', | ||||
|       updated_message: 'Sales tax updated successfully', | ||||
|       deleted_message: 'Sales tax deleted successfully', | ||||
|       confirm_delete: 'You will not be able to recover this Tax Type', | ||||
|       already_in_use: 'Tax is already in use' | ||||
|     }, | ||||
|     expense_category: { | ||||
| @ -628,6 +643,7 @@ export default { | ||||
|       created_message: 'Category created successfully', | ||||
|       deleted_message: 'Expense category deleted successfully', | ||||
|       updated_message: 'Expense category updated successfully', | ||||
|       confirm_delete: 'You will not be able to recover this Expense Category', | ||||
|       already_in_use: 'Category is already in use' | ||||
|     }, | ||||
|     preferences: { | ||||
| @ -682,6 +698,7 @@ export default { | ||||
|     username: 'Username', | ||||
|     next: 'Next', | ||||
|     continue: 'Continue', | ||||
|     skip: 'Skip', | ||||
|     database: { | ||||
|       database: 'Site URL & Database', | ||||
|       connection: 'Database Connection', | ||||
| @ -752,7 +769,9 @@ export default { | ||||
|     payment_greater_than_due_amount: 'Entered Payment is more than due amount of this invoice.', | ||||
|     quantity_maxlength: 'Quantity should not be greater than 10 digits.', | ||||
|     price_maxlength: 'Price should not be greater than 10 digits.', | ||||
|     price_minvalue: 'Price should be greater than 0 digits', | ||||
|     amount_maxlength: 'Amount should not be greater than 10 digits.', | ||||
|     amount_minvalue: 'Amount should be greater than 0 digits', | ||||
|     description_maxlength: 'Description should not be greater than 255 characters.', | ||||
|     maximum_options_error: 'Maximum  of {max} options selected. First remove a selected option to select another.', | ||||
|     notes_maxlength: 'Notes should not be greater than 255 characters.', | ||||
|  | ||||
| @ -224,15 +224,19 @@ export default { | ||||
|     action: 'Acción', | ||||
|     notes: 'Notas', | ||||
|     tax: 'Impuesto', | ||||
|     send_estimate: 'Enviar presupuesto', | ||||
|     estimate_template: 'Plantilla de estimación', | ||||
|     convert_to_invoice: 'Convertir a factura', | ||||
|     mark_as_sent: 'Marcar como enviado', | ||||
|     send_estimate: 'Enviar presupuesto', | ||||
|     record_payment: 'Registro de pago', | ||||
|     add_estimate: 'Agregar presupuesto', | ||||
|     save_estimate: 'Guardar estimación', | ||||
|     confirm_conversion: '¿Quiere convertir esta estimación en factura?', | ||||
|     conversion_message: 'Conversión exitosa', | ||||
|     confirm_send_estimate: 'Esta estimación se enviará por correo electrónico al cliente', | ||||
|     confirm_mark_as_sent: 'Esta estimación se marcará como enviada', | ||||
|     confirm_mark_as_accepted: 'Esta estimación se marcará como Aceptada', | ||||
|     confirm_mark_as_rejected: 'Esta estimación se marcará como Rechazada', | ||||
|     errors: { | ||||
|       required: 'Se requiere campo' | ||||
|     }, | ||||
| @ -550,7 +554,7 @@ export default { | ||||
|       right: 'Derecho', | ||||
|       left: 'Izquierda', | ||||
|       action: 'Acción', | ||||
|       add_currency: 'Agregar moneda', | ||||
|       add_currency: 'Agregar moneda' | ||||
|     }, | ||||
|     pdf: { | ||||
|       title: 'Configuración de PDF', | ||||
| @ -597,8 +601,6 @@ export default { | ||||
|       estimate_viewed_desc: 'Cuando su cliente ve la estimación enviada a través del panel de control del cráter.', | ||||
|       save: 'Salvar', | ||||
|       email_save_message: 'Correo electrónico guardado con éxito', | ||||
|       invoice_viewed_message: 'Factura vista', | ||||
|       estimate_viewed_message: 'Estimación vista', | ||||
|       please_enter_email: 'Por favor, introduzca su correo electrónico' | ||||
|     }, | ||||
|     tax_types: { | ||||
| @ -616,6 +618,7 @@ export default { | ||||
|       created_message: 'Impuesto sobre las ventas creado con éxito', | ||||
|       updated_message: 'Impuesto sobre ventas actualizado con éxito', | ||||
|       deleted_message: 'Impuesto sobre las ventas eliminado con éxito', | ||||
|       confirm_delete: 'No podrá recuperar este tipo de impuesto', | ||||
|       already_in_use: 'El impuesto ya está en uso.' | ||||
|     }, | ||||
|     expense_category: { | ||||
| @ -628,6 +631,7 @@ export default { | ||||
|       created_message: 'Categoría creada con éxito', | ||||
|       deleted_message: 'Categoría de gastos eliminada correctamente', | ||||
|       updated_message: 'Categoría de gastos actualizada con éxito', | ||||
|       confirm_delete: 'No podrá recuperar esta categoría de gastos', | ||||
|       already_in_use: 'La categoría ya está en uso.' | ||||
|     }, | ||||
|     preferences: { | ||||
| @ -643,7 +647,6 @@ export default { | ||||
|       preference: 'Preferencia | Preferencias', | ||||
|       general_settings: 'Preferencias predeterminadas para el sistema.', | ||||
|       updated_message: 'Preferencias actualizadas exitosamente', | ||||
|       set_discount_per_item_message: 'Descuento establecido por artículo', | ||||
|       select_language: 'seleccione el idioma', | ||||
|       select_time_zone: 'selecciona la zona horaria', | ||||
|       select_date_formate: 'seleccione formato de fecha', | ||||
| @ -669,7 +672,7 @@ export default { | ||||
|     state: 'Estado', | ||||
|     city: 'Ciudad', | ||||
|     address: 'Habla a', | ||||
|     street: 'Calle1 '| 'Calle # 2', | ||||
|     street: 'Calle1 ' | 'Calle # 2', | ||||
|     phone: 'Teléfono', | ||||
|     zip_code: 'Código postal', | ||||
|     go_back: 'Regresa', | ||||
| @ -677,7 +680,52 @@ export default { | ||||
|     language: 'Idioma', | ||||
|     time_zone: 'Zona horaria', | ||||
|     fiscal_year: 'Año financiero', | ||||
|     date_format: 'Formato de fecha' | ||||
|     date_format: 'Formato de fecha', | ||||
|     from_address: 'De la Dirección', | ||||
|     username: 'Nombre de usuario', | ||||
|     next: 'Próximo', | ||||
|     continue: 'Hacer continuación', | ||||
|     database: { | ||||
|       database: 'URL del sitio y base de datose', | ||||
|       connection: 'Conexión de base de datos', | ||||
|       host: 'Database Host', | ||||
|       port: 'Host de base de datos', | ||||
|       password: 'Contraseña de base de datos', | ||||
|       app_url: 'URL de la aplicación', | ||||
|       username: 'Nombre de usuario de la base de datos', | ||||
|       db_name: 'Nombre de la base de datos', | ||||
|       desc: 'Cree una base de datos en su servidor y establezca las credenciales utilizando el siguiente formulario.' | ||||
|     }, | ||||
|     permissions: { | ||||
|       permissions: 'Permisos', | ||||
|       permission_desc: 'A continuación se muestra la lista de permisos de carpeta necesarios para que la aplicación funcione. Si la verificación de permisos falla, asegúrese de actualizar los permisos de su carpeta.' | ||||
|     }, | ||||
|     mail: { | ||||
|       host: 'Host de correo', | ||||
|       port: 'Puerto de correo', | ||||
|       driver: 'Conductor de correo', | ||||
|       password: 'Contraseña de correo', | ||||
|       username: 'Nombre de usuario de correo', | ||||
|       mail_config: 'Configuración de correo', | ||||
|       encryption: 'Cifrado de correo', | ||||
|       mail_config_desc: 'Los detalles a continuación se utilizarán para actualizar el entorno de correo. También puede cambiar los detalles en cualquier momento después de iniciar sesión.' | ||||
|     }, | ||||
|     req: { | ||||
|       system_req: 'Requisitos del sistema', | ||||
|       php_req_version: 'Php (versión {version} necesario)', | ||||
|       check_req: 'Consultar requisitos', | ||||
|       system_req_desc: 'Crater tiene algunos requisitos de servidor. Asegúrese de que su servidor tenga la versión de php requerida y todas las extensiones mencionadas a continuación.' | ||||
|     }, | ||||
|     errors: { | ||||
|       migrate_failed: 'La migración falló', | ||||
|       database_variables_save_error: 'No se puede conectar a la base de datos con los valores proporcionados.', | ||||
|       mail_variables_save_error: 'La configuración del correo electrónico ha fallado.', | ||||
|       connection_failed: 'Conexión de base de datos fallida' | ||||
|     }, | ||||
|     success: { | ||||
|       mail_variables_save_successfully: 'Correo electrónico configurado correctamente', | ||||
|       database_variables_save_successfully: 'Base de datos configurada con éxito.' | ||||
|     } | ||||
|   }, | ||||
|   layout_login: { | ||||
|     copyright_crater: 'Copyright @ Crater - 2019', | ||||
| @ -708,7 +756,9 @@ export default { | ||||
|     payment_greater_than_due_amount: 'El pago ingresado es mayor al monto adeudado de esta factura.', | ||||
|     quantity_maxlength: 'La cantidad no debe ser mayor de 10 dígitos.', | ||||
|     price_maxlength: 'El precio no debe ser mayor de 10 dígitos.', | ||||
|     price_minvalue: 'El precio debe ser mayor que 0 dígitos', | ||||
|     amount_maxlength: 'La cantidad no debe ser mayor de 10 dígitos.', | ||||
|     amount_minvalue: 'La cantidad debe ser mayor que 0 dígitos', | ||||
|     description_maxlength: 'La descripción no debe tener más de 255 caracteres.', | ||||
|     maximum_options_error: 'Máximo de {max} opciones seleccionadas. Primero elimine una opción seleccionada para seleccionar otra.', | ||||
|     notes_maxlength: 'Las notas no deben tener más de 255 caracteres.', | ||||
|  | ||||
| @ -233,6 +233,10 @@ export default { | ||||
|     save_estimate: 'Sauvegarder lestimation', | ||||
|     confirm_conversion: 'Vous souhaitez convertir cette estimation en facture?', | ||||
|     conversion_message: 'Conversion réussie', | ||||
|     confirm_send_estimate: 'Cette estimation sera envoyée par courrier électronique au client.', | ||||
|     confirm_mark_as_sent: 'Cette estimation sera marquée comme envoyé', | ||||
|     confirm_mark_as_accepted: 'Cette estimation sera marquée comme acceptée', | ||||
|     confirm_mark_as_rejected: 'Cette estimation sera marquée comme Rejetée', | ||||
|     errors: { | ||||
|       required: 'Champ requis' | ||||
|     }, | ||||
| @ -616,6 +620,7 @@ export default { | ||||
|       created_message: 'La taxe de vente créée avec succès', | ||||
|       updated_message: 'La taxe de vente a été mise à jour avec succès', | ||||
|       deleted_message: 'La taxe de vente a été supprimée avec succès', | ||||
|       confirm_delete: 'Vous ne pourrez pas récupérer ce type de taxe', | ||||
|       already_in_use: 'La taxe est déjà utilisée' | ||||
|     }, | ||||
|     expense_category: { | ||||
| @ -628,6 +633,7 @@ export default { | ||||
|       created_message: 'Catégorie créée avec succès', | ||||
|       deleted_message: 'La catégorie de dépenses a été supprimée avec succès', | ||||
|       updated_message: 'Catégorie de dépenses mise à jour avec succès', | ||||
|       confirm_delete: 'Vous ne pourrez pas récupérer cette catégorie de dépenses', | ||||
|       already_in_use: 'La catégorie est déjà utilisée' | ||||
|     }, | ||||
|     preferences: { | ||||
| @ -669,7 +675,7 @@ export default { | ||||
|     state: 'Etat', | ||||
|     city: 'Ville', | ||||
|     address: 'Adresse', | ||||
|     street: 'Street1 '| 'Rue # 2', | ||||
|     street: 'Street1 ' | 'Rue # 2', | ||||
|     phone: 'Téléphone', | ||||
|     zip_code: 'Code postal', | ||||
|     go_back: 'Retourner', | ||||
| @ -677,7 +683,52 @@ export default { | ||||
|     language: 'La langue', | ||||
|     time_zone: 'Fuseau horaire', | ||||
|     fiscal_year: 'Année financière', | ||||
|     date_format: 'Format de date' | ||||
|     date_format: 'Format de date', | ||||
|     from_address: "De l'adresse", | ||||
|     username: "Nom d'utilisateur", | ||||
|     next: 'Suivant', | ||||
|     continue: 'Continuer', | ||||
|     database: { | ||||
|       database: 'URL du site et base de données', | ||||
|       connection: 'Connexion à la base de données', | ||||
|       host: 'Hôte de base de données', | ||||
|       port: 'Port de base de données', | ||||
|       password: 'Mot de passe de base de données', | ||||
|       app_url: 'Application URL', | ||||
|       username: "Nom d'utilisateur de la base de données", | ||||
|       db_name: 'Nom de la base de données', | ||||
|       desc: "Créez une base de données sur votre serveur et définissez les informations d'identification à l'aide du formulaire ci-dessous." | ||||
|     }, | ||||
|     permissions: { | ||||
|       permissions: 'Les permissions', | ||||
|       permission_desc: "Vous trouverez ci-dessous la liste des autorisations de dossier requises pour le fonctionnement de l'application. Si la vérification des autorisations échoue, veillez à mettre à jour vos autorisations de dossier." | ||||
|     }, | ||||
|     mail: { | ||||
|       host: 'Mail Host', | ||||
|       port: 'Port mail', | ||||
|       driver: 'Pilote de courrier', | ||||
|       password: 'Mot de passe mail', | ||||
|       username: "Mail Nom d'utilisateur", | ||||
|       mail_config: 'Configuration du courrier', | ||||
|       encryption: 'Chiffrement du courrier', | ||||
|       mail_config_desc: "Les détails ci-dessous seront utilisés pour mettre à jour l'environnement de messagerie. Aussi, vous pouvez modifier les détails à tout moment après la connexion." | ||||
|     }, | ||||
|     req: { | ||||
|       system_req: 'Configuration requise', | ||||
|       php_req_version: 'Php (version {version} nécessaire)', | ||||
|       check_req: 'Vérifier les exigences', | ||||
|       system_req_desc: 'Crater a quelques exigences de serveur. Assurez-vous que votre serveur dispose de la version PHP requise et de toutes les extensions mentionnées ci-dessous.' | ||||
|     }, | ||||
|     errors: { | ||||
|       migrate_failed: 'Migration impossible', | ||||
|       database_variables_save_error: 'Impossible de se connecter à la base de données avec les valeurs fournies.', | ||||
|       mail_variables_save_error: 'La configuration du courrier électronique a échoué.', | ||||
|       connection_failed: 'La connexion à la base de données a échoué' | ||||
|     }, | ||||
|     success: { | ||||
|       mail_variables_save_successfully: 'Email configuré avec succès', | ||||
|       database_variables_save_successfully: 'Base de données configurée avec succès.' | ||||
|     } | ||||
|   }, | ||||
|   layout_login: { | ||||
|     copyright_crater: 'Copyright @ Crater - 2019', | ||||
| @ -708,7 +759,9 @@ export default { | ||||
|     payment_greater_than_due_amount: 'Le paiement entré est plus que le montant dû de cette facture.', | ||||
|     quantity_maxlength: 'La quantité ne doit pas dépasser 10 chiffres.', | ||||
|     price_maxlength: 'Le prix ne doit pas dépasser 10 chiffres.', | ||||
|     price_minvalue: 'Le prix doit être supérieur à 0 chiffre', | ||||
|     amount_maxlength: 'Le montant ne doit pas dépasser 10 chiffres.', | ||||
|     amount_minvalue: 'Le montant doit être supérieur à 0 chiffre', | ||||
|     description_maxlength: 'La description ne doit pas dépasser 255 caractères.', | ||||
|     maximum_options_error: 'Maximum de {max} options sélectionnées. Commencez par supprimer une option sélectionnée pour en sélectionner une autre.', | ||||
|     notes_maxlength: 'Les notes ne doivent pas dépasser 255 caractères.', | ||||
|  | ||||
| @ -71,6 +71,7 @@ import Preferences from './views/settings/Preferences.vue' | ||||
| import UserProfile from './views/settings/UserProfile.vue' | ||||
| import TaxTypes from './views/settings/TaxTypes.vue' | ||||
| import ExpenseCategory from './views/settings/ExpenseCategory.vue' | ||||
| import MailConfig from './views/settings/MailConfig.vue' | ||||
|  | ||||
| import Wizard from './views/wizard/Index.vue' | ||||
|  | ||||
| @ -327,6 +328,11 @@ const routes = [ | ||||
|             name: 'expense.category', | ||||
|             component: ExpenseCategory | ||||
|           }, | ||||
|           { | ||||
|             path: 'mail-configuration', | ||||
|             name: 'mailconfig', | ||||
|             component: MailConfig | ||||
|           }, | ||||
|           { | ||||
|             path: 'notifications', | ||||
|             name: 'notifications', | ||||
|  | ||||
| @ -130,7 +130,7 @@ export const markAsRejected = ({ commit, dispatch, state }, data) => { | ||||
|  | ||||
| export const markAsSent = ({ commit, dispatch, state }, data) => { | ||||
|   return new Promise((resolve, reject) => { | ||||
|     window.axios.post(`/api/estimates/sent`, data).then((response) => { | ||||
|     window.axios.post(`/api/estimates/mark-as-sent`, data).then((response) => { | ||||
|       // commit(types.UPDATE_INVOICE, response.data) | ||||
|       resolve(response) | ||||
|     }).catch((err) => { | ||||
|  | ||||
| @ -343,7 +343,7 @@ export default { | ||||
|       swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$tc('customers.confirm_delete'), | ||||
|         icon: 'error', | ||||
|         icon: '/assets/icon/trash-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (willDelete) => { | ||||
| @ -363,7 +363,7 @@ export default { | ||||
|       swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$tc('customers.confirm_delete', 2), | ||||
|         icon: 'error', | ||||
|         icon: '/assets/icon/trash-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (willDelete) => { | ||||
|  | ||||
| @ -96,6 +96,7 @@ | ||||
|               <line-chart | ||||
|                 v-if="isLoaded" | ||||
|                 :format-money="$utils.formatMoney" | ||||
|                 :format-graph-money="$utils.formatGraphMoney" | ||||
|                 :invoices="getChartInvoices" | ||||
|                 :expenses="getChartExpenses" | ||||
|                 :receipts="getReceiptTotals" | ||||
|  | ||||
| @ -688,7 +688,7 @@ export default { | ||||
|           isValid = false | ||||
|         } | ||||
|       }) | ||||
|       if (this.$v.newEstimate.$invalid === false && isValid === true) { | ||||
|       if (!this.$v.selectedCustomer.$invalid && this.$v.newEstimate.$invalid === false && isValid === true) { | ||||
|         return true | ||||
|       } | ||||
|       return false | ||||
|  | ||||
| @ -249,25 +249,25 @@ | ||||
|                   {{ $t('estimates.convert_to_invoice') }} | ||||
|                 </a> | ||||
|               </v-dropdown-item> | ||||
|               <v-dropdown-item> | ||||
|               <v-dropdown-item v-if="row.status !== 'SENT'"> | ||||
|                 <a class="dropdown-item" href="#" @click.self="onMarkAsSent(row.id)"> | ||||
|                   <font-awesome-icon icon="check-circle" class="dropdown-item-icon" /> | ||||
|                   {{ $t('estimates.mark_as_sent') }} | ||||
|                 </a> | ||||
|               </v-dropdown-item> | ||||
|               <v-dropdown-item> | ||||
|               <v-dropdown-item v-if="row.status !== 'SENT'"> | ||||
|                 <a class="dropdown-item" href="#" @click.self="sendEstimate(row.id)"> | ||||
|                   <font-awesome-icon icon="paper-plane" class="dropdown-item-icon" /> | ||||
|                   {{ $t('estimates.send_estimate') }} | ||||
|                 </a> | ||||
|               </v-dropdown-item> | ||||
|               <v-dropdown-item v-if="row.status === 'DRAFT'"> | ||||
|               <v-dropdown-item v-if="row.status === 'DRAFT' || row.status === 'REJECTED'"> | ||||
|                 <a class="dropdown-item" href="#" @click.self="onMarkAsAccepted(row.id)"> | ||||
|                   <font-awesome-icon icon="check-circle" class="dropdown-item-icon" /> | ||||
|                   {{ $t('estimates.mark_as_accepted') }} | ||||
|                 </a> | ||||
|               </v-dropdown-item> | ||||
|               <v-dropdown-item v-if="row.status === 'DRAFT'"> | ||||
|               <v-dropdown-item v-if="row.status === 'ACCEPTED' || row.status === 'DRAFT'"> | ||||
|                 <a class="dropdown-item" href="#" @click.self="onMarkAsRejected(row.id)"> | ||||
|                   <font-awesome-icon icon="times-circle" class="dropdown-item-icon" /> | ||||
|                   {{ $t('estimates.mark_as_rejected') }} | ||||
| @ -409,28 +409,48 @@ export default { | ||||
|       } | ||||
|     }, | ||||
|     async onMarkAsAccepted (id) { | ||||
|       const data = { | ||||
|         id: id | ||||
|       } | ||||
|       let response = await this.markAsAccepted(data) | ||||
|       this.refreshTable() | ||||
|       if (response.data) { | ||||
|         this.filters.status = 'ACCEPTED' | ||||
|         this.$refs.table.refresh() | ||||
|         window.toastr['success'](this.$tc('estimates.marked_as_rejected_message')) | ||||
|       } | ||||
|       swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$t('estimates.confirm_mark_as_accepted'), | ||||
|         icon: '/assets/icon/check-circle-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (markedAsRejected) => { | ||||
|         if (markedAsRejected) { | ||||
|           const data = { | ||||
|             id: id | ||||
|           } | ||||
|           let response = await this.markAsAccepted(data) | ||||
|           this.refreshTable() | ||||
|           if (response.data) { | ||||
|             this.filters.status = 'ACCEPTED' | ||||
|             this.$refs.table.refresh() | ||||
|             window.toastr['success'](this.$tc('estimates.marked_as_rejected_message')) | ||||
|           } | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     async onMarkAsRejected (id) { | ||||
|       const data = { | ||||
|         id: id | ||||
|       } | ||||
|       let response = await this.markAsRejected(data) | ||||
|       this.refreshTable() | ||||
|       if (response.data) { | ||||
|         this.filters.status = 'REJECTED' | ||||
|         this.$refs.table.refresh() | ||||
|         window.toastr['success'](this.$tc('estimates.marked_as_rejected_message')) | ||||
|       } | ||||
|       swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$t('estimates.confirm_mark_as_rejected'), | ||||
|         icon: '/assets/icon/times-circle-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (markedAsRejected) => { | ||||
|         if (markedAsRejected) { | ||||
|           const data = { | ||||
|             id: id | ||||
|           } | ||||
|           let response = await this.markAsRejected(data) | ||||
|           this.refreshTable() | ||||
|           if (response.data) { | ||||
|             this.filters.status = 'REJECTED' | ||||
|             this.$refs.table.refresh() | ||||
|             window.toastr['success'](this.$tc('estimates.marked_as_rejected_message')) | ||||
|           } | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     setFilters () { | ||||
|       this.filtersApplied = true | ||||
| @ -470,7 +490,7 @@ export default { | ||||
|       swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$tc('estimates.confirm_delete', 1), | ||||
|         icon: 'error', | ||||
|         icon: '/assets/icon/trash-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (willDelete) => { | ||||
| @ -491,7 +511,7 @@ export default { | ||||
|       swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$t('estimates.confirm_conversion'), | ||||
|         icon: 'error', | ||||
|         icon: '/assets/icon/envelope-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (willDelete) => { | ||||
| @ -510,7 +530,7 @@ export default { | ||||
|       swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$tc('estimates.confirm_delete', 2), | ||||
|         icon: 'error', | ||||
|         icon: '/assets/icon/trash-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (willDelete) => { | ||||
| @ -536,24 +556,44 @@ export default { | ||||
|       this.refreshTable() | ||||
|     }, | ||||
|     async onMarkAsSent (id) { | ||||
|       const data = { | ||||
|         id: id | ||||
|       } | ||||
|       let response = await this.markAsSent(data) | ||||
|       this.refreshTable() | ||||
|       if (response.data) { | ||||
|         window.toastr['success'](this.$tc('estimates.mark_as_sent')) | ||||
|       } | ||||
|       swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$t('estimates.confirm_mark_as_sent'), | ||||
|         icon: '/assets/icon/check-circle-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (willDelete) => { | ||||
|         if (willDelete) { | ||||
|           const data = { | ||||
|             id: id | ||||
|           } | ||||
|           let response = await this.markAsSent(data) | ||||
|           this.refreshTable() | ||||
|           if (response.data) { | ||||
|             window.toastr['success'](this.$tc('estimates.mark_as_sent')) | ||||
|           } | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     async sendEstimate (id) { | ||||
|       const data = { | ||||
|         id: id | ||||
|       } | ||||
|       let response = await this.sendEmail(data) | ||||
|       this.refreshTable() | ||||
|       if (response.data) { | ||||
|         window.toastr['success'](this.$tc('estimates.mark_as_sent')) | ||||
|       } | ||||
|       swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$t('estimates.confirm_send_estimate'), | ||||
|         icon: '/assets/icon/paper-plane-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (sendEstimate) => { | ||||
|         if (sendEstimate) { | ||||
|           const data = { | ||||
|             id: id | ||||
|           } | ||||
|           let response = await this.sendEmail(data) | ||||
|           this.refreshTable() | ||||
|           if (response.data) { | ||||
|             window.toastr['success'](this.$tc('estimates.mark_as_sent')) | ||||
|           } | ||||
|         } | ||||
|       }) | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -28,6 +28,7 @@ | ||||
|                   @select="onSelectItem" | ||||
|                   @deselect="deselectItem" | ||||
|                   @onDesriptionInput="$v.item.description.$touch()" | ||||
|                   @onSelectItem="isSelected = true" | ||||
|                 /> | ||||
|               </div> | ||||
|             </td> | ||||
| @ -193,13 +194,17 @@ export default { | ||||
|         prefix: '$ ', | ||||
|         precision: 2, | ||||
|         masked: false | ||||
|       } | ||||
|       }, | ||||
|       isSelected: false | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapGetters('item', [ | ||||
|       'items' | ||||
|     ]), | ||||
|     ...mapGetters('modal', [ | ||||
|       'modalActive' | ||||
|     ]), | ||||
|     ...mapGetters('currency', [ | ||||
|       'defaultCurrencyForInput' | ||||
|     ]), | ||||
| @ -284,6 +289,11 @@ export default { | ||||
|       if (this.item.discount_type === 'percentage') { | ||||
|         this.item.discount_val = (this.item.discount * newValue) / 100 | ||||
|       } | ||||
|     }, | ||||
|     modalActive (val) { | ||||
|       if (!val) { | ||||
|         this.isSelected = false | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   validations () { | ||||
| @ -313,7 +323,11 @@ export default { | ||||
|   }, | ||||
|   created () { | ||||
|     window.hub.$on('checkItems', this.validateItem) | ||||
|     window.hub.$on('newItem', this.onSelectItem) | ||||
|     window.hub.$on('newItem', (val) => { | ||||
|       if (!this.item.item_id && this.modalActive && this.isSelected) { | ||||
|         this.onSelectItem(val) | ||||
|       } | ||||
|     }) | ||||
|   }, | ||||
|   methods: { | ||||
|     updateTax (data) { | ||||
|  | ||||
| @ -126,6 +126,7 @@ export default { | ||||
|       this.$emit('search', val) | ||||
|     }, | ||||
|     openItemModal () { | ||||
|       this.$emit('onSelectItem') | ||||
|       this.openModal({ | ||||
|         'title': 'Add Item', | ||||
|         'componentName': 'ItemModal' | ||||
|  | ||||
| @ -92,13 +92,14 @@ | ||||
|                     <money | ||||
|                       v-model="amount" | ||||
|                       v-bind="defaultCurrencyForInput" | ||||
|                       :class="{'invalid' : $v.formData.amount.$error}" | ||||
|                       class="input-field" | ||||
|                       @input="$v.formData.amount.$touch()" | ||||
|                     /> | ||||
|                   </div> | ||||
|                   <div v-if="$v.formData.amount.$error"> | ||||
|                     <span v-if="!$v.formData.amount.required" class="text-danger">{{ $t('validation.required') }}</span> | ||||
|                     <span v-if="!$v.formData.amount.maxLength" class="text-danger">{{ $t('validation.amount_maxlength') }}</span> | ||||
|                     <span v-if="!$v.formData.amount.maxValue" class="text-danger">{{ $t('validation.amount_minvalue') }}</span> | ||||
|                   </div> | ||||
|                 </div> | ||||
|                 <div class="form-group col-sm-6"> | ||||
|  | ||||
| @ -358,7 +358,7 @@ export default { | ||||
|       swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$tc('expenses.confirm_delete'), | ||||
|         icon: 'error', | ||||
|         icon: '/assets/icon/trash-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (willDelete) => { | ||||
| @ -378,7 +378,7 @@ export default { | ||||
|       swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$tc('expenses.confirm_delete', 2), | ||||
|         icon: 'error', | ||||
|         icon: '/assets/icon/trash-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (willDelete) => { | ||||
|  | ||||
| @ -519,14 +519,6 @@ export default { | ||||
|     ...mapActions('item', [ | ||||
|       'fetchItems' | ||||
|     ]), | ||||
|     isEmpty (obj) { | ||||
|       for (let key in obj) { | ||||
|         if (obj.hasOwnProperty(key)) { | ||||
|           return false | ||||
|         } | ||||
|       } | ||||
|       return true | ||||
|     }, | ||||
|     selectFixed () { | ||||
|       if (this.newInvoice.discount_type === 'fixed') { | ||||
|         return | ||||
|  | ||||
| @ -496,7 +496,7 @@ export default { | ||||
|       swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$tc('invoices.confirm_delete'), | ||||
|         icon: 'error', | ||||
|         icon: '/assets/icon/trash-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (willDelete) => { | ||||
| @ -526,7 +526,7 @@ export default { | ||||
|       swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$tc('invoices.confirm_delete', 2), | ||||
|         icon: 'error', | ||||
|         icon: '/assets/icon/trash-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (willDelete) => { | ||||
|  | ||||
| @ -28,6 +28,7 @@ | ||||
|                   @select="onSelectItem" | ||||
|                   @deselect="deselectItem" | ||||
|                   @onDesriptionInput="$v.item.description.$touch()" | ||||
|                   @onSelectItem="isSelected = true" | ||||
|                 /> | ||||
|               </div> | ||||
|             </td> | ||||
| @ -194,13 +195,17 @@ export default { | ||||
|         prefix: '$ ', | ||||
|         precision: 2, | ||||
|         masked: false | ||||
|       } | ||||
|       }, | ||||
|       isSelected: false | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapGetters('item', [ | ||||
|       'items' | ||||
|     ]), | ||||
|     ...mapGetters('modal', [ | ||||
|       'modalActive' | ||||
|     ]), | ||||
|     ...mapGetters('currency', [ | ||||
|       'defaultCurrencyForInput' | ||||
|     ]), | ||||
| @ -285,6 +290,11 @@ export default { | ||||
|       if (this.item.discount_type === 'percentage') { | ||||
|         this.item.discount_val = (this.item.discount * newValue) / 100 | ||||
|       } | ||||
|     }, | ||||
|     modalActive (val) { | ||||
|       if (!val) { | ||||
|         this.isSelected = false | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   validations () { | ||||
| @ -314,7 +324,11 @@ export default { | ||||
|   }, | ||||
|   created () { | ||||
|     window.hub.$on('checkItems', this.validateItem) | ||||
|     window.hub.$on('newItem', this.onSelectItem) | ||||
|     window.hub.$on('newItem', (val) => { | ||||
|       if (!this.item.item_id && this.modalActive && this.isSelected) { | ||||
|         this.onSelectItem(val) | ||||
|       } | ||||
|     }) | ||||
|   }, | ||||
|   methods: { | ||||
|     updateTax (data) { | ||||
|  | ||||
| @ -115,6 +115,7 @@ export default { | ||||
|       this.$emit('search', val) | ||||
|     }, | ||||
|     openItemModal () { | ||||
|       this.$emit('onSelectItem') | ||||
|       this.openModal({ | ||||
|         'title': 'Add Item', | ||||
|         'componentName': 'ItemModal' | ||||
|  | ||||
| @ -34,16 +34,16 @@ | ||||
|                 <label>{{ $t('items.price') }}</label><span class="text-danger"> *</span> | ||||
|                 <div class="base-input"> | ||||
|                   <money | ||||
|                     :invalid="$v.formData.price.$error" | ||||
|                     :class="{'invalid' : $v.formData.price.$error}" | ||||
|                     v-model="price" | ||||
|                     v-bind="defaultCurrencyForInput" | ||||
|                     class="input-field" | ||||
|                     @input="$v.formData.price.$touch()" | ||||
|                   /> | ||||
|                 </div> | ||||
|                 <div v-if="$v.formData.price.$error"> | ||||
|                   <span v-if="!$v.formData.price.required" class="text-danger">{{ $t('validation.required') }} </span> | ||||
|                   <span v-if="!$v.formData.price.maxLength" class="text-danger">{{ $t('validation.price_maxlength') }}</span> | ||||
|                   <span v-if="!$v.formData.price.minValue" class="text-danger">{{ $t('validation.price_minvalue') }}</span> | ||||
|                 </div> | ||||
|               </div> | ||||
|               <div class="form-group"> | ||||
| @ -92,7 +92,8 @@ | ||||
| <script> | ||||
| import { validationMixin } from 'vuelidate' | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
| const { required, minLength, numeric, alpha, minValue, maxLength} = require('vuelidate/lib/validators') | ||||
| const { required, minLength, numeric, alpha, minValue, maxLength } = require('vuelidate/lib/validators') | ||||
|  | ||||
| export default { | ||||
|   mixins: { | ||||
|     validationMixin | ||||
|  | ||||
| @ -362,7 +362,7 @@ export default { | ||||
|       swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$tc('items.confirm_delete'), | ||||
|         icon: 'error', | ||||
|         icon: '/assets/icon/trash-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (willDelete) => { | ||||
| @ -388,7 +388,7 @@ export default { | ||||
|       swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$tc('items.confirm_delete', 2), | ||||
|         icon: 'error', | ||||
|         icon: '/assets/icon/trash-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (willDelete) => { | ||||
|  | ||||
| @ -101,7 +101,6 @@ | ||||
|                 </div> | ||||
|                 <div v-if="$v.formData.amount.$error"> | ||||
|                   <span v-if="!$v.formData.amount.required" class="text-danger">{{ $t('validation.required') }}</span> | ||||
|                   <span v-if="!$v.formData.amount.numeric" class="text-danger">{{ $t('validation.numbers_only') }}</span> | ||||
|                   <span v-if="!$v.formData.amount.between && $v.formData.amount.numeric && amount <= 0" class="text-danger">{{ $t('validation.payment_greater_than_zero') }}</span> | ||||
|                   <span v-if="!$v.formData.amount.between && amount > 0" class="text-danger">{{ $t('validation.payment_greater_than_due_amount') }}</span> | ||||
|                 </div> | ||||
| @ -156,7 +155,7 @@ import { mapActions, mapGetters } from 'vuex' | ||||
| import MultiSelect from 'vue-multiselect' | ||||
| import { validationMixin } from 'vuelidate' | ||||
| import moment from 'moment' | ||||
| const { required, numeric, between, maxLength } = require('vuelidate/lib/validators') | ||||
| const { required, between, maxLength } = require('vuelidate/lib/validators') | ||||
|  | ||||
| export default { | ||||
|   components: { MultiSelect }, | ||||
| @ -201,7 +200,6 @@ export default { | ||||
|         }, | ||||
|         amount: { | ||||
|           required, | ||||
|           numeric, | ||||
|           between: between(1, this.maxPayableAmount + 1) | ||||
|         }, | ||||
|         notes: { | ||||
|  | ||||
| @ -368,7 +368,7 @@ export default { | ||||
|       swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$tc('payments.confirm_delete'), | ||||
|         icon: 'error', | ||||
|         icon: '/assets/icon/trash-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (willDelete) => { | ||||
| @ -388,7 +388,7 @@ export default { | ||||
|       swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$tc('payments.confirm_delete', 2), | ||||
|         icon: 'error', | ||||
|         icon: '/assets/icon/trash-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (willDelete) => { | ||||
|  | ||||
| @ -48,7 +48,7 @@ | ||||
|     </div> | ||||
|     <div class="col-sm-8 reports-tab-container"> | ||||
|       <iframe :src="getReportUrl" class="reports-frame-style"/> | ||||
|       <a :href="getReportUrl" class="base-button btn btn-primary btn-lg report-view-button" target="_blank"> | ||||
|       <a class="base-button btn btn-primary btn-lg report-view-button" @click="viewReportsPDF"> | ||||
|         <font-awesome-icon icon="file-pdf" class="vue-icon icon-left svg-inline--fa fa-download fa-w-16 mr-2" /> <span>{{ $t('reports.view_pdf') }}</span> | ||||
|       </a> | ||||
|     </div> | ||||
| @ -179,6 +179,11 @@ export default { | ||||
|     setRangeToCustom () { | ||||
|       this.selectedRange = 'Custom' | ||||
|     }, | ||||
|     async viewReportsPDF () { | ||||
|       let data = await this.getReports() | ||||
|       window.open(this.getReportUrl, '_blank') | ||||
|       return data | ||||
|     }, | ||||
|     async getReports (isDownload = false) { | ||||
|       this.$v.range.$touch() | ||||
|       this.$v.formData.$touch() | ||||
|  | ||||
| @ -48,7 +48,7 @@ | ||||
|     </div> | ||||
|     <div class="col-sm-8 reports-tab-container"> | ||||
|       <iframe :src="getReportUrl" class="reports-frame-style"/> | ||||
|       <a :href="getReportUrl" class="base-button btn btn-primary btn-lg report-view-button" target="_blank"> | ||||
|       <a class="base-button btn btn-primary btn-lg report-view-button" @click="viewReportsPDF"> | ||||
|         <font-awesome-icon icon="file-pdf" class="vue-icon icon-left svg-inline--fa fa-download fa-w-16 mr-2" /> <span>{{ $t('reports.view_pdf') }}</span> | ||||
|       </a> | ||||
|     </div> | ||||
| @ -184,6 +184,11 @@ export default { | ||||
|     setRangeToCustom () { | ||||
|       this.selectedRange = 'Custom' | ||||
|     }, | ||||
|     async viewReportsPDF () { | ||||
|       let data = await this.getReports() | ||||
|       window.open(this.getReportUrl, '_blank') | ||||
|       return data | ||||
|     }, | ||||
|     async getReports (isDownload = false) { | ||||
|       this.$v.range.$touch() | ||||
|       this.$v.formData.$touch() | ||||
|  | ||||
| @ -70,7 +70,7 @@ | ||||
|     </div> | ||||
|     <div class="col-sm-8 reports-tab-container"> | ||||
|       <iframe :src="getReportUrl" class="reports-frame-style"/> | ||||
|       <a :href="getReportUrl" class="base-button btn btn-primary btn-lg report-view-button" target="_blank"> | ||||
|       <a class="base-button btn btn-primary btn-lg report-view-button" @click="viewReportsPDF"> | ||||
|         <font-awesome-icon icon="file-pdf" class="vue-icon icon-left svg-inline--fa fa-download fa-w-16 mr-2" /> <span>{{ $t('reports.view_pdf') }}</span> | ||||
|       </a> | ||||
|     </div> | ||||
| @ -217,6 +217,11 @@ export default { | ||||
|       this.url = `${this.itemsSiteURL}?from_date=${moment(this.formData.from_date).format('DD/MM/YYYY')}&to_date=${moment(this.formData.to_date).format('DD/MM/YYYY')}` | ||||
|       return true | ||||
|     }, | ||||
|     async viewReportsPDF () { | ||||
|       let data = await this.getReports() | ||||
|       window.open(this.getReportUrl, '_blank') | ||||
|       return data | ||||
|     }, | ||||
|     async getReports (isDownload = false) { | ||||
|       this.$v.range.$touch() | ||||
|       this.$v.formData.$touch() | ||||
|  | ||||
| @ -48,7 +48,7 @@ | ||||
|     </div> | ||||
|     <div class="col-sm-8 reports-tab-container"> | ||||
|       <iframe :src="getReportUrl" class="reports-frame-style"/> | ||||
|       <a :href="getReportUrl" class="base-button btn btn-primary btn-lg report-view-button" target="_blank"> | ||||
|       <a class="base-button btn btn-primary btn-lg report-view-button" @click="viewReportsPDF"> | ||||
|         <font-awesome-icon icon="file-pdf" class="vue-icon icon-left svg-inline--fa fa-download fa-w-16 mr-2" /> <span>{{ $t('reports.view_pdf') }}</span> | ||||
|       </a> | ||||
|     </div> | ||||
| @ -179,6 +179,11 @@ export default { | ||||
|     setRangeToCustom () { | ||||
|       this.selectedRange = 'Custom' | ||||
|     }, | ||||
|     async viewReportsPDF () { | ||||
|       let data = await this.getReports() | ||||
|       window.open(this.getReportUrl, '_blank') | ||||
|       return data | ||||
|     }, | ||||
|     async getReports (isDownload = false) { | ||||
|       this.$v.range.$touch() | ||||
|       this.$v.formData.$touch() | ||||
|  | ||||
| @ -101,13 +101,23 @@ export default { | ||||
|       'deleteCategory' | ||||
|     ]), | ||||
|     async removeExpenseCategory (id, index) { | ||||
|       let response = await this.deleteCategory(id) | ||||
|       if (response.data.success) { | ||||
|         window.toastr['success'](this.$tc('settings.expense_category.deleted_message')) | ||||
|         this.id = null | ||||
|         this.$refs.table.refresh() | ||||
|         return true | ||||
|       } window.toastr['success'](this.$t('settings.expense_category.already_in_use')) | ||||
|       swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$t('settings.expense_category.confirm_delete'), | ||||
|         icon: '/assets/icon/trash-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (willDelete) => { | ||||
|         if (willDelete) { | ||||
|           let response = await this.deleteCategory(id) | ||||
|           if (response.data.success) { | ||||
|             window.toastr['success'](this.$tc('settings.expense_category.deleted_message')) | ||||
|             this.id = null | ||||
|             this.$refs.table.refresh() | ||||
|             return true | ||||
|           } window.toastr['error'](this.$t('settings.expense_category.already_in_use')) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     openCategoryModal () { | ||||
|       this.openModal({ | ||||
|  | ||||
							
								
								
									
										213
									
								
								resources/assets/js/views/settings/MailConfig.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										213
									
								
								resources/assets/js/views/settings/MailConfig.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,213 @@ | ||||
| <template> | ||||
|   <div class="setting-main-container"> | ||||
|     <div class="card setting-card"> | ||||
|       <div class="page-header"> | ||||
|         <h3 class="page-title">{{ $t('settings.mail.mail_config') }}</h3> | ||||
|         <p class="page-sub-title"> | ||||
|           {{ $t('settings.mail.mail_config_desc') }} | ||||
|         </p> | ||||
|       </div> | ||||
|       <form action="" @submit.prevent="saveEmailConfig()"> | ||||
|         <div class="row my-2 mt-5"> | ||||
|           <div class="col-md-6 my-2"> | ||||
|             <label class="form-label">{{ $t('settings.mail.driver') }}</label> | ||||
|             <span class="text-danger"> *</span> | ||||
|             <base-select | ||||
|               v-model="mailConfigData.mail_driver" | ||||
|               :invalid="$v.mailConfigData.mail_driver.$error" | ||||
|               :options="mail_drivers" | ||||
|               :searchable="true" | ||||
|               :show-labels="false" | ||||
|               @change="$v.mailConfigData.mail_driver.$touch()" | ||||
|             /> | ||||
|             <div v-if="$v.mailConfigData.mail_driver.$error"> | ||||
|               <span v-if="!$v.mailConfigData.mail_driver.required" class="text-danger"> | ||||
|                 {{ $tc('validation.required') }} | ||||
|               </span> | ||||
|             </div> | ||||
|           </div> | ||||
|           <div class="col-md-6 my-2"> | ||||
|             <label class="form-label">{{ $t('settings.mail.host') }}</label> | ||||
|             <span class="text-danger"> *</span> | ||||
|             <base-input | ||||
|               :invalid="$v.mailConfigData.mail_host.$error" | ||||
|               v-model.trim="mailConfigData.mail_host" | ||||
|               type="text" | ||||
|               name="mail_host" | ||||
|               @input="$v.mailConfigData.mail_host.$touch()" | ||||
|             /> | ||||
|             <div v-if="$v.mailConfigData.mail_host.$error"> | ||||
|               <span v-if="!$v.mailConfigData.mail_host.required" class="text-danger"> | ||||
|                 {{ $tc('validation.required') }} | ||||
|               </span> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div class="row my-2"> | ||||
|           <div class="col-md-6 my-2"> | ||||
|             <label class="form-label">{{ $t('settings.mail.username') }}</label> | ||||
|             <span class="text-danger"> *</span> | ||||
|             <base-input | ||||
|               :invalid="$v.mailConfigData.mail_username.$error" | ||||
|               v-model.trim="mailConfigData.mail_username" | ||||
|               type="text" | ||||
|               name="db_name" | ||||
|               @input="$v.mailConfigData.mail_username.$touch()" | ||||
|             /> | ||||
|             <div v-if="$v.mailConfigData.mail_username.$error"> | ||||
|               <span v-if="!$v.mailConfigData.mail_username.required" class="text-danger"> | ||||
|                 {{ $tc('validation.required') }} | ||||
|               </span> | ||||
|             </div> | ||||
|           </div> | ||||
|           <div class="col-md-6 my-2"> | ||||
|             <label class="form-label">{{ $t('settings.mail.password') }}</label> | ||||
|             <span class="text-danger"> *</span> | ||||
|             <base-input | ||||
|               :invalid="$v.mailConfigData.mail_password.$error" | ||||
|               v-model.trim="mailConfigData.mail_password" | ||||
|               type="mail_password" | ||||
|               name="name" | ||||
|               @input="$v.mailConfigData.mail_password.$touch()" | ||||
|             /> | ||||
|             <div v-if="$v.mailConfigData.mail_password.$error"> | ||||
|               <span v-if="!$v.mailConfigData.mail_password.required" class="text-danger"> | ||||
|                 {{ $tc('validation.required') }} | ||||
|               </span> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div class="row my-2"> | ||||
|           <div class="col-md-6 my-2"> | ||||
|             <label class="form-label">{{ $t('settings.mail.port') }}</label> | ||||
|             <span class="text-danger"> *</span> | ||||
|             <base-input | ||||
|               :invalid="$v.mailConfigData.mail_port.$error" | ||||
|               v-model.trim="mailConfigData.mail_port" | ||||
|               type="text" | ||||
|               name="mail_port" | ||||
|               @input="$v.mailConfigData.mail_port.$touch()" | ||||
|             /> | ||||
|             <div v-if="$v.mailConfigData.mail_port.$error"> | ||||
|               <span v-if="!$v.mailConfigData.mail_port.required" class="text-danger"> | ||||
|                 {{ $tc('validation.required') }} | ||||
|               </span> | ||||
|               <span v-if="!$v.mailConfigData.mail_port.numeric" class="text-danger"> | ||||
|                 {{ $tc('validation.numbers_only') }} | ||||
|               </span> | ||||
|             </div> | ||||
|           </div> | ||||
|           <div class="col-md-6 my-2"> | ||||
|             <label class="form-label">{{ $t('settings.mail.encryption') }}</label> | ||||
|             <span class="text-danger"> *</span> | ||||
|             <base-input | ||||
|               :invalid="$v.mailConfigData.mail_encryption.$error" | ||||
|               v-model.trim="mailConfigData.mail_encryption" | ||||
|               type="text" | ||||
|               name="name" | ||||
|               @input="$v.mailConfigData.mail_encryption.$touch()" | ||||
|             /> | ||||
|             <div v-if="$v.mailConfigData.mail_encryption.$error"> | ||||
|               <span v-if="!$v.mailConfigData.mail_encryption.required" class="text-danger"> | ||||
|                 {{ $tc('validation.required') }} | ||||
|               </span> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|         <base-button | ||||
|           :loading="loading" | ||||
|           class="pull-right mt-5" | ||||
|           icon="save" | ||||
|           color="theme" | ||||
|           type="submit" | ||||
|         > | ||||
|           {{ $t('wizard.save_cont') }} | ||||
|         </base-button> | ||||
|       </form> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| <script> | ||||
| import MultiSelect from 'vue-multiselect' | ||||
| import { validationMixin } from 'vuelidate' | ||||
| import Ls from '../../services/ls' | ||||
| const { required, email, numeric } = require('vuelidate/lib/validators') | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     MultiSelect | ||||
|   }, | ||||
|   mixins: [validationMixin], | ||||
|   data () { | ||||
|     return { | ||||
|       mailConfigData: { | ||||
|         mail_driver: 'smtp', | ||||
|         mail_host: 'mailtrap.io', | ||||
|         mail_port: 2525, | ||||
|         mail_username: 'cc3c64516febd4', | ||||
|         mail_password: 'e6a0176301f587', | ||||
|         mail_encryption: 'tls' | ||||
|       }, | ||||
|       loading: false, | ||||
|       mail_drivers: [] | ||||
|     } | ||||
|   }, | ||||
|   validations: { | ||||
|     mailConfigData: { | ||||
|       mail_driver: { | ||||
|         required | ||||
|       }, | ||||
|       mail_host: { | ||||
|         required | ||||
|       }, | ||||
|       mail_port: { | ||||
|         required, | ||||
|         numeric | ||||
|       }, | ||||
|       mail_username: { | ||||
|         required | ||||
|       }, | ||||
|       mail_password: { | ||||
|         required | ||||
|       }, | ||||
|       mail_encryption: { | ||||
|         required | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   mounted () { | ||||
|     // this.getMailDrivers() | ||||
|   }, | ||||
|   methods: { | ||||
|     async getMailDrivers () { | ||||
|       this.loading = true | ||||
|  | ||||
|       let response = await window.axios.get('/api/admin/onboarding/environment/mail') | ||||
|  | ||||
|       if (response.data) { | ||||
|         this.mail_drivers = response.data | ||||
|         this.loading = false | ||||
|       } | ||||
|     }, | ||||
|     async saveEmailConfig () { | ||||
|       this.$v.mailConfigData.$touch() | ||||
|       if (this.$v.mailConfigData.$invalid) { | ||||
|         return true | ||||
|       } | ||||
|       this.loading = true | ||||
|       try { | ||||
|         let response = await window.axios.post('/api/admin/onboarding/environment/mail', this.mailConfigData) | ||||
|         if (response.data.success) { | ||||
|           window.toastr['success'](this.$t('wizard.success.' + response.data.success)) | ||||
|         } else { | ||||
|           window.toastr['error'](this.$t('wizard.errors.' + response.data.error)) | ||||
|         } | ||||
|         this.loading = false | ||||
|         return true | ||||
|       } catch (e) { | ||||
|         window.toastr['error']('Something went wrong') | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| @ -113,7 +113,11 @@ | ||||
|         <h3 class="page-title">{{ $t('settings.preferences.discount_setting') }}</h3> | ||||
|         <div class="flex-box"> | ||||
|           <div class="left"> | ||||
|             <base-switch v-model="discount_per_item" class="btn-switch" @change="setDiscount" /> | ||||
|             <base-switch | ||||
|               v-model="discount_per_item" | ||||
|               class="btn-switch" | ||||
|               @change="setDiscount" | ||||
|             /> | ||||
|           </div> | ||||
|           <div class="right ml-15"> | ||||
|             <p class="box-title">  {{ $t('settings.preferences.discount_per_item') }} </p> | ||||
|  | ||||
| @ -34,7 +34,7 @@ | ||||
|         > | ||||
|           <template slot-scope="row"> | ||||
|             <span>{{ $t('settings.tax_types.tax_name') }}</span> | ||||
|             <span class="tax-name"> | ||||
|             <span class="tax-name mt-3"> | ||||
|               {{ row.name }} | ||||
|             </span> | ||||
|           </template> | ||||
| @ -159,13 +159,23 @@ export default { | ||||
|       } | ||||
|     }, | ||||
|     async removeTax (id, index) { | ||||
|       let response = await this.deleteTaxType(id) | ||||
|       if (response.data.success) { | ||||
|         window.toastr['success'](this.$t('settings.tax_types.deleted_message')) | ||||
|         this.id = null | ||||
|         this.$refs.table.refresh() | ||||
|         return true | ||||
|       }window.toastr['success'](this.$t('settings.tax_types.already_in_use')) | ||||
|       swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$t('settings.tax_types.confirm_delete'), | ||||
|         icon: '/assets/icon/trash-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (willDelete) => { | ||||
|         if (willDelete) { | ||||
|           let response = await this.deleteTaxType(id) | ||||
|           if (response.data.success) { | ||||
|             window.toastr['success'](this.$t('settings.tax_types.deleted_message')) | ||||
|             this.id = null | ||||
|             this.$refs.table.refresh() | ||||
|             return true | ||||
|           }window.toastr['error'](this.$t('settings.tax_types.already_in_use')) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     openTaxModal () { | ||||
|       this.openModal({ | ||||
|  | ||||
| @ -63,6 +63,12 @@ export default { | ||||
|           icon: 'list-alt', | ||||
|           iconType: 'far' | ||||
|         }, | ||||
|         { | ||||
|           link: '/admin/settings/mail-configuration', | ||||
|           title: 'settings.mail.mail_config', | ||||
|           icon: 'envelope', | ||||
|           iconType: 'fa' | ||||
|         }, | ||||
|         { | ||||
|           link: '/admin/settings/notifications', | ||||
|           title: 'settings.menu_title.notifications', | ||||
|  | ||||
| @ -109,15 +109,26 @@ | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <base-button | ||||
|         :loading="loading" | ||||
|         class="pull-right mt-5" | ||||
|         icon="save" | ||||
|         color="theme" | ||||
|         type="submit" | ||||
|       > | ||||
|         {{ $t('wizard.save_cont') }} | ||||
|       </base-button> | ||||
|       <div class="row mt-5"> | ||||
|         <base-button | ||||
|           :loading="loading" | ||||
|           class="pull-right" | ||||
|           icon="save" | ||||
|           color="theme" | ||||
|           type="submit" | ||||
|         > | ||||
|           {{ $t('wizard.save_cont') }} | ||||
|         </base-button> | ||||
|         <base-button | ||||
|           :loading="loading" | ||||
|           class="pull-right ml-4" | ||||
|           outline | ||||
|           color="theme" | ||||
|           @click="$emit('next')" | ||||
|         > | ||||
|           {{ $t('wizard.skip') }} | ||||
|         </base-button> | ||||
|       </div> | ||||
|     </form> | ||||
|   </div> | ||||
| </template> | ||||
| @ -137,10 +148,10 @@ export default { | ||||
|       mailConfigData: { | ||||
|         mail_driver: 'smtp', | ||||
|         mail_host: 'mailtrap.io', | ||||
|         mail_port: 2525, | ||||
|         mail_username: 'cc3c64516febd4', | ||||
|         mail_password: 'e6a0176301f587', | ||||
|         mail_encryption: 'tls' | ||||
|         mail_port: null, | ||||
|         mail_username: null, | ||||
|         mail_password: null, | ||||
|         mail_encryption: null | ||||
|       }, | ||||
|       loading: false, | ||||
|       mail_drivers: [] | ||||
|  | ||||
		Reference in New Issue
	
	Block a user