diff --git a/src/composables/inputSelectFilterFn.js b/src/composables/inputSelectFilterFn.js new file mode 100644 index 000000000..778d78a2a --- /dev/null +++ b/src/composables/inputSelectFilterFn.js @@ -0,0 +1,33 @@ +/** + * Filtra las opciones basadas en un valor de entrada y actualiza las opciones filtradas. + * + * @param {string} val - El valor de entrada para filtrar las opciones. (la emite el evento @filter del componente QSelect) + * @param {Function} update - Función de actualización que debe ser llamada para actualizar las opciones filtradas.(la provee el evento @filter del componente QSelect) + * @param {Function} abort - Función que puede ser llamada para abortar o cancelar el filtrado actual. (la provee el evento @filter del componente QSelect) + * @param {Object} optionsToFilter - Objeto que contiene las opciones originales y filtradas. + */ + +function normalizeString(text) { + return text + .toLowerCase() + .normalize('NFD') + .replace(/[\u0300-\u036f]/g, ''); +} + +export function inputSelectFilter(val, update, abort, optionsToFilter) { + if (val === '') { + update(() => { + optionsToFilter.filtered = JSON.parse( + JSON.stringify(optionsToFilter.original) + ); + }); + return; + } + + update(() => { + const searchQuery = val.toLowerCase(); + optionsToFilter.filtered = optionsToFilter.original.filter((option) => + normalizeString(option.label).includes(normalizeString(searchQuery)) + ); + }); +} diff --git a/src/i18n/en/index.js b/src/i18n/en/index.js index 01a54cfbb..1314666c8 100644 --- a/src/i18n/en/index.js +++ b/src/i18n/en/index.js @@ -424,7 +424,7 @@ export default { comercial: 'Comercial', }, }, - shelving:{ + shelving: { pageTitles: { shelving: 'Shelving', shelvingList: 'Shelving List', @@ -441,14 +441,14 @@ export default { parking: 'Parking', priority: 'Priority', worker: 'Worker', - recyclable: 'Recyclable' + recyclable: 'Recyclable', }, basicData: { code: 'Code', parking: 'Parking', priority: 'Priority', - recyclable: 'Recyclable' - } + recyclable: 'Recyclable', + }, }, worker: { pageTitles: { @@ -607,6 +607,41 @@ export default { supplierName: 'Supplier name', }, }, + travel: { + shared: { + reference: 'Reference', + agency: 'Agency', + wareHouseOut: 'Warehouse Out', + wareHouseIn: 'Warehouse In', + landed: 'Landed', + shipped: 'Shipped', + totalEntries: 'Total entries', + }, + pageTitles: { + travel: 'Travels', + list: 'List', + create: 'Create', + summary: 'Summary', + }, + list: { + clone: 'Clone', + addEntry: 'Add entry', + preview: 'Preview', + }, + summary: { + confirmed: 'Confirmed', + entryId: 'Entry Id', + supplier: 'Supplier', + freight: 'Freight', + package: 'Package', + delivered: 'Delivered', + received: 'Received', + entries: 'Entries', + cloneShipping: 'Clone travel', + CloneTravelAndEntries: 'Clone travel and his entries', + AddEntry: 'Add entry', + }, + }, components: { topbar: {}, userPanel: { diff --git a/src/i18n/es/index.js b/src/i18n/es/index.js index 829fe6221..edb20feb7 100644 --- a/src/i18n/es/index.js +++ b/src/i18n/es/index.js @@ -426,7 +426,7 @@ export default { comercial: 'Comercial', }, }, - shelving:{ + shelving: { pageTitles: { shelving: 'Carros', shelvingList: 'Listado de carros', @@ -443,14 +443,14 @@ export default { parking: 'Parking', priority: 'Prioridad', worker: 'Trabajador', - recyclable: 'Reciclable' + recyclable: 'Reciclable', }, basicData: { code: 'Código', parking: 'Parking', priority: 'Prioridad', - recyclable: 'Reciclable' - } + recyclable: 'Reciclable', + }, }, worker: { pageTitles: { @@ -609,6 +609,41 @@ export default { supplierName: 'Nombre del proveedor', }, }, + travel: { + shared: { + reference: 'Referencia', + agency: 'Agencia', + wareHouseOut: 'Alm. salida', + wareHouseIn: 'Alm. entrada', + landed: 'F. entrega', + shipped: 'F. envío', + totalEntries: 'Ent. totales', + }, + pageTitles: { + travel: 'Envíos', + list: 'Listado', + create: 'Crear', + summary: 'Resumen', + }, + list: { + clone: 'Clonar', + addEntry: 'Añadir entrada', + preview: 'Vista previa', + }, + summary: { + confirmed: 'Confirmado', + entryId: 'Id entrada', + supplier: 'Proveedor', + freight: 'Porte', + package: 'Embalaje', + delivered: 'Enviada', + received: 'Recibida', + entries: 'Entradas', + cloneShipping: 'Clonar envío', + CloneTravelAndEntries: 'Clonar travel y sus entradas', + AddEntry: 'Añadir entrada', + }, + }, components: { topbar: {}, userPanel: { diff --git a/src/pages/InvoiceOut/InvoiceOutNegativeBases.vue b/src/pages/InvoiceOut/InvoiceOutNegativeBases.vue index e4b8f4f89..b148d98bb 100644 --- a/src/pages/InvoiceOut/InvoiceOutNegativeBases.vue +++ b/src/pages/InvoiceOut/InvoiceOutNegativeBases.vue @@ -3,7 +3,7 @@ import { onMounted, computed, ref } from 'vue'; import { useI18n } from 'vue-i18n'; /* import { QBadge, QBtn } from 'quasar'; import CustomerDescriptor from 'src/pages/Customer/Card/CustomerDescriptor.vue'; */ -import invoiceOutService from 'src/services/InvoiceOut.service'; +import invoiceOutService from 'src/services/invoiceOut.service'; import { toCurrency } from 'src/filters'; import { QBadge, QCheckbox, exportFile } from 'quasar'; diff --git a/src/pages/Supplier/Card/SupplierSummary.vue b/src/pages/Supplier/Card/SupplierSummary.vue index 120ae8713..c04c76234 100644 --- a/src/pages/Supplier/Card/SupplierSummary.vue +++ b/src/pages/Supplier/Card/SupplierSummary.vue @@ -51,7 +51,9 @@ const isAdministrative = computed(() => { @on-fetch="(data) => setData(data)" > - + + + {{ supplier.name }} - {{ supplier.id }} diff --git a/src/pages/Supplier/SupplierCreate.vue b/src/pages/Supplier/SupplierCreate.vue index a27c6fd37..e68e7ea8a 100644 --- a/src/pages/Supplier/SupplierCreate.vue +++ b/src/pages/Supplier/SupplierCreate.vue @@ -1,9 +1,10 @@ @@ -30,7 +31,11 @@ const createSupplier = async () => { - + +import { useI18n } from 'vue-i18n'; +import { useStateStore } from 'stores/useStateStore'; +import VnSearchbar from 'src/components/ui/VnSearchbar.vue'; + +const stateStore = useStateStore(); +const { t } = useI18n(); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/pages/Travel/Card/TravelSummary.vue b/src/pages/Travel/Card/TravelSummary.vue new file mode 100644 index 000000000..9fe4b8902 --- /dev/null +++ b/src/pages/Travel/Card/TravelSummary.vue @@ -0,0 +1,305 @@ + + + + setTravelData(data)" + > + + + + + + + {{ travel.ref }} - {{ travel.id }} + + + + + + {{ t('components.cardDescriptor.moreOptions') }} + + + + + {{ option.name }} + + + + + + + + + + + + + + + + + + + + + + + {{ t('travel.summary.entries') }} + + + + + + + {{ props.value }} + {{ + props.col.toolTip + }} + + + + + + + + + diff --git a/src/pages/Travel/Card/TravelSummaryDialog.vue b/src/pages/Travel/Card/TravelSummaryDialog.vue new file mode 100644 index 000000000..8351d6e5b --- /dev/null +++ b/src/pages/Travel/Card/TravelSummaryDialog.vue @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/src/pages/Travel/TravelCreate.vue b/src/pages/Travel/TravelCreate.vue new file mode 100644 index 000000000..6529e3bb2 --- /dev/null +++ b/src/pages/Travel/TravelCreate.vue @@ -0,0 +1,178 @@ + + + + onFetchAgencies(data)" auto-load /> + onFetchWarehouses(data)" auto-load /> + + + + + + inputSelectFilter(val, update, abort, agenciesOptions) + " + :label="t('travel.shared.agency')" + transition-show="jump-up" + transition-hide="jump-up" + style="max-width: 100%" + /> + + + + inputSelectFilter(val, update, abort, warehousesOptions) + " + :label="t('travel.shared.wareHouseOut')" + transition-show="jump-up" + transition-hide="jump-up" + /> + + inputSelectFilter(val, update, abort, warehousesOptions) + " + :label="t('travel.shared.wareHouseIn')" + transition-show="jump-up" + transition-hide="jump-up" + /> + + + + + + + + + + + + + + diff --git a/src/pages/Travel/TravelFilter.vue b/src/pages/Travel/TravelFilter.vue new file mode 100644 index 000000000..117b770e9 --- /dev/null +++ b/src/pages/Travel/TravelFilter.vue @@ -0,0 +1,380 @@ + + + + onFetchWarehouses(data)" auto-load /> + onFetchContinents(data)" auto-load /> + onFetchAgencies(data)" auto-load /> + + + + + {{ t(`params.${tag.label}`) }}: + {{ formatFn(tag.value) }} + + + + + + + + + + + + + + inputSelectFilter(val, update, abort, agenciesOptions) + " + v-model="params.agencyModeFk" + /> + + + + + + inputSelectFilter( + val, + update, + abort, + warehousesOptions + ) + " + v-model="params.warehouseOutFk" + /> + + + + + + inputSelectFilter( + val, + update, + abort, + warehousesOptions + ) + " + v-model="params.warehouseInFk" + /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + inputSelectFilter( + val, + update, + abort, + continentsOptions + ) + " + v-model="params.continent" + /> + + + + + + + + + + + + + + + + + + + + + { + "en": { + "params": { + "search": "Id/Reference", + "agencyModeFk": "Agency", + "wareHouseIn": "Warehouse In", + "wareHouseOut": "Warehouse Out", + "scopeDays": "Days onward", + "landedFrom": "Landed from", + "landedTo": "Landed to", + "continent": "Continent out", + "totalEntries": "Total entries" + }, + }, + "es": { + "params":{ + "search": "Id/Referencia", + "agencyModeFk": "Agencia", + "wareHouseIn": "Alm. entrada", + "wareHouseOut": "Alm. salida", + "scopeDays": "Días adelante", + "landedFrom": "Llegada desde", + "landedTo": "Llegada hasta", + "continent": "Cont. Salida", + "totalEntries": "Ent. totales" + }, + } + } + diff --git a/src/pages/Travel/TravelList.vue b/src/pages/Travel/TravelList.vue new file mode 100644 index 000000000..2a4f312a1 --- /dev/null +++ b/src/pages/Travel/TravelList.vue @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{ t('supplier.list.newSupplier') }} + + + + + + + + + + diff --git a/src/pages/Travel/TravelMain.vue b/src/pages/Travel/TravelMain.vue new file mode 100644 index 000000000..66ce78f23 --- /dev/null +++ b/src/pages/Travel/TravelMain.vue @@ -0,0 +1,17 @@ + + + + + + + + + + + + diff --git a/src/router/modules/index.js b/src/router/modules/index.js index f93a38da2..156f0d104 100644 --- a/src/router/modules/index.js +++ b/src/router/modules/index.js @@ -3,9 +3,21 @@ import Ticket from './ticket'; import Claim from './claim'; import InvoiceOut from './invoiceOut'; import Worker from './worker'; -import Shelving from "./shelving"; +import Shelving from './shelving'; import Wagon from './wagon'; import Route from './route'; import Supplier from './Supplier'; +import Travel from './travel'; -export default [Customer, Ticket, Claim, InvoiceOut, Worker, Shelving, Wagon, Route, Supplier]; +export default [ + Customer, + Ticket, + Claim, + InvoiceOut, + Worker, + Shelving, + Wagon, + Route, + Supplier, + Travel, +]; diff --git a/src/router/modules/invoiceOut.js b/src/router/modules/invoiceOut.js index ec30e4fc0..084cf6ac3 100644 --- a/src/router/modules/invoiceOut.js +++ b/src/router/modules/invoiceOut.js @@ -34,7 +34,7 @@ export default { name: 'InvoiceOutGlobal', meta: { title: 'globalInvoicing', - icon: 'view_list', + icon: 'contact_support', }, component: () => import('src/pages/InvoiceOut/InvoiceOutGlobal.vue'), }, diff --git a/src/router/modules/travel.js b/src/router/modules/travel.js new file mode 100644 index 000000000..9ba10380e --- /dev/null +++ b/src/router/modules/travel.js @@ -0,0 +1,59 @@ +import { RouterView } from 'vue-router'; + +export default { + path: '/travel', + name: 'Travel', + meta: { + title: 'travel', + icon: 'vn:package', + }, + component: RouterView, + redirect: { name: 'TravelMain' }, + menus: { + main: ['TravelList'], + card: [], + }, + children: [ + { + path: '', + name: 'TravelMain', + component: () => import('src/pages/Travel/TravelMain.vue'), + redirect: { name: 'TravelList' }, + children: [ + { + path: 'list', + name: 'TravelList', + meta: { + title: 'list', + icon: 'view_list', + }, + component: () => import('src/pages/Travel/TravelList.vue'), + }, + { + path: 'create', + name: 'TravelCreate', + meta: { + title: 'create', + }, + component: () => import('src/pages/Travel/TravelCreate.vue'), + }, + ], + }, + { + name: 'TravelCard', + path: ':id', + component: () => import('src/pages/Travel/Card/TravelCard.vue'), + redirect: { name: 'TravelSummary' }, + children: [ + { + name: 'TravelSummary', + path: 'summary', + meta: { + title: 'summary', + }, + component: () => import('src/pages/Travel/Card/TravelSummary.vue'), + }, + ], + }, + ], +}; diff --git a/src/router/routes.js b/src/router/routes.js index cf96631f7..25d605af8 100644 --- a/src/router/routes.js +++ b/src/router/routes.js @@ -6,7 +6,8 @@ import invoiceOut from './modules/invoiceOut'; import wagon from './modules/wagon'; import supplier from './modules/Supplier'; import route from './modules/route'; -import shelving from "src/router/modules/shelving"; +import travel from './modules/travel'; +import shelving from 'src/router/modules/shelving'; const routes = [ { @@ -55,6 +56,7 @@ const routes = [ wagon, route, supplier, + travel, { path: '/:catchAll(.*)*', name: 'NotFound', diff --git a/src/services/InvoiceOut.service.js b/src/services/invoiceOut.service.js similarity index 100% rename from src/services/InvoiceOut.service.js rename to src/services/invoiceOut.service.js diff --git a/src/services/Suppliers.service.js b/src/services/suppliers.service.js similarity index 100% rename from src/services/Suppliers.service.js rename to src/services/suppliers.service.js diff --git a/src/services/travel.service.js b/src/services/travel.service.js new file mode 100644 index 000000000..606e2eb48 --- /dev/null +++ b/src/services/travel.service.js @@ -0,0 +1,32 @@ +import axios from 'axios'; + +const travelService = { + getTravels: async (filter = {}) => { + try { + return await axios.get('Travels/filter', filter); + } catch (err) { + console.error(`Error fetching travels`, err); + return err.response; + } + }, + + createTravel: async (params) => { + try { + return await axios.patch('Travels', params); + } catch (err) { + console.error(`Error creating travel`, err); + return err.response; + } + }, + + getTravelEntries: async (param) => { + try { + return await axios.get(`Travels/${param}/getEntries`); + } catch (err) { + console.error(`Error fetching travel entries`, err); + return err.response; + } + }, +}; + +export default travelService; diff --git a/src/stores/invoiceOutGlobal.js b/src/stores/invoiceOutGlobal.js index 7223f7655..128d5a397 100644 --- a/src/stores/invoiceOutGlobal.js +++ b/src/stores/invoiceOutGlobal.js @@ -1,6 +1,6 @@ import { defineStore } from 'pinia'; import { useUserConfig } from 'src/composables/useUserConfig'; -import invoiceOutService from 'src/services/InvoiceOut.service.js'; +import invoiceOutService from 'src/services/invoiceOut.service'; import useNotify from 'src/composables/useNotify.js'; const { notify } = useNotify(); diff --git a/src/stores/travel.js b/src/stores/travel.js new file mode 100644 index 000000000..799c773e8 --- /dev/null +++ b/src/stores/travel.js @@ -0,0 +1,36 @@ +import { defineStore } from 'pinia'; +import travelService from 'src/services/travel.service'; + +export const useTravelStore = defineStore({ + id: 'travel', + + state: () => ({ + initialDataLoading: true, + travels: [], + }), + actions: { + async init() { + await this.fetchAllData(); + }, + + async fetchAllData() { + const { data } = await travelService.getTravels(); + this.travels = data || []; + }, + + async createTravel(travelData) { + const params = { + ref: travelData.ref, + agencyModeFk: travelData.agencyModeFk.value, + warehouseOutFk: travelData.warehouseOutFk.value, + warehouseInFk: travelData.warehouseInFk.value, + landed: new Date(travelData.landed), + shipped: new Date(travelData.shipped), + }; + + return await travelService.createTravel(params); + }, + }, + + getters: {}, +}); diff --git a/src/stores/useNavigationStore.js b/src/stores/useNavigationStore.js index b5b85c4b1..b4882c685 100644 --- a/src/stores/useNavigationStore.js +++ b/src/stores/useNavigationStore.js @@ -16,6 +16,7 @@ export const useNavigationStore = defineStore('navigationStore', () => { 'wagon', 'route', 'supplier', + 'travel', ]; const pinnedModules = ref([]); const role = useRole();