diff --git a/src/components/ItemsFilterPanel.vue b/src/components/ItemsFilterPanel.vue index f7f07a5b0..94adfe0ff 100644 --- a/src/components/ItemsFilterPanel.vue +++ b/src/components/ItemsFilterPanel.vue @@ -5,7 +5,7 @@ import { useI18n } from 'vue-i18n'; import VnInput from 'components/common/VnInput.vue'; import FetchData from 'components/FetchData.vue'; import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue'; -import VnSelectFilter from 'components/common/VnSelectFilter.vue'; +import VnSelect from 'components/common/VnSelect.vue'; import VnFilterPanelChip from 'components/ui/VnFilterPanelChip.vue'; import axios from 'axios'; @@ -207,7 +207,7 @@ const removeTag = (index, params, search) => { - { - + @@ -246,7 +246,7 @@ const removeTag = (index, params, search) => { class="q-mt-md filter-value" > - { /> - + > + + + + + {{ `${opt.id}: ${opt.bank}` }} + + + + + +import VnPaginate from 'src/components/ui/VnPaginate.vue'; +import CardList from 'src/components/ui/CardList.vue'; +import VnSearchbar from 'src/components/ui/VnSearchbar.vue'; +import { useStateStore } from 'stores/useStateStore'; +import { useRouter } from 'vue-router'; +import { useI18n } from 'vue-i18n'; + +const { t } = useI18n(); +const router = useRouter(); +const stateStore = useStateStore(); +function navigate(id) { + router.push({ path: `/agency/${id}` }); +} +function exprBuilder(param, value) { + if (!value) return; + if (param !== 'search') return; + + if (!isNaN(value)) return { id: value }; + + return { name: { like: `%${value}%` } }; +} + + + + + + + + + + + + + + + + + + + + + + + + es: + isOwn: Tiene propietario + isAnyVolumeAllowed: Permite cualquier volumen + Search agency: Buscar agencia + You can search by name: Puedes buscar por nombre + en: + isOwn: Has owner + isAnyVolumeAllowed: Allows any volume + diff --git a/src/pages/Agency/Card/AgencyBasicData.vue b/src/pages/Agency/Card/AgencyBasicData.vue new file mode 100644 index 000000000..599058b3e --- /dev/null +++ b/src/pages/Agency/Card/AgencyBasicData.vue @@ -0,0 +1,52 @@ + + + (warehouses = data)" + auto-load + /> + + + + + + + + + + + + + + + + + diff --git a/src/pages/Agency/Card/AgencyCard.vue b/src/pages/Agency/Card/AgencyCard.vue new file mode 100644 index 000000000..e78d1cc55 --- /dev/null +++ b/src/pages/Agency/Card/AgencyCard.vue @@ -0,0 +1,35 @@ + + + + diff --git a/src/pages/Agency/Card/AgencyDescriptor.vue b/src/pages/Agency/Card/AgencyDescriptor.vue new file mode 100644 index 000000000..0fa89d07d --- /dev/null +++ b/src/pages/Agency/Card/AgencyDescriptor.vue @@ -0,0 +1,35 @@ + + + + + + + + diff --git a/src/pages/Agency/Card/AgencyLog.vue b/src/pages/Agency/Card/AgencyLog.vue new file mode 100644 index 000000000..d4769a676 --- /dev/null +++ b/src/pages/Agency/Card/AgencyLog.vue @@ -0,0 +1,6 @@ + + + + diff --git a/src/pages/Agency/Card/AgencyModes.vue b/src/pages/Agency/Card/AgencyModes.vue new file mode 100644 index 000000000..4fb81914a --- /dev/null +++ b/src/pages/Agency/Card/AgencyModes.vue @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + es: + isOwn: Tiene propietario + isAnyVolumeAllowed: Permite cualquier volumen + Search agency: Buscar agencia + You can search by name: Puedes buscar por nombre + deliveryMethod: Método de entrega + inflation: Inflación + en: + isOwn: Has owner + isAnyVolumeAllowed: Allows any volume + diff --git a/src/pages/Agency/Card/AgencySummary.vue b/src/pages/Agency/Card/AgencySummary.vue new file mode 100644 index 000000000..a4a6a2a18 --- /dev/null +++ b/src/pages/Agency/Card/AgencySummary.vue @@ -0,0 +1,55 @@ + + + + + + {{ agency.name }} + + + + + + + + + + + + + diff --git a/src/pages/Agency/Card/AgencyWorkcenter.vue b/src/pages/Agency/Card/AgencyWorkcenter.vue new file mode 100644 index 000000000..f5beaab53 --- /dev/null +++ b/src/pages/Agency/Card/AgencyWorkcenter.vue @@ -0,0 +1,136 @@ + + + + (warehouses = data)" + auto-load + /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{ t('globals.new') }} + + + + + + es: + workCenter removed successfully: Centro de trabajo eliminado correctamente + This workCenter is already assigned to this agency: Este workCenter ya está asignado a esta agencia + Add work center: Añadir centro de trabajo + workCenter: Centro de trabajo + diff --git a/src/pages/Agency/locale/en.yml b/src/pages/Agency/locale/en.yml new file mode 100644 index 000000000..3cc3d69e8 --- /dev/null +++ b/src/pages/Agency/locale/en.yml @@ -0,0 +1,11 @@ +agency: + isOwn: Own + isAnyVolumeAllowed: Any volume allowed + notification: + removeItemError: Error removing agency + removeItem: WorkCenter removed successfully + pageTitles: + agency: Agency + searchBar: + info: You can search by agency code + label: Search agency... diff --git a/src/pages/Agency/locale/es.yml b/src/pages/Agency/locale/es.yml new file mode 100644 index 000000000..2607472bd --- /dev/null +++ b/src/pages/Agency/locale/es.yml @@ -0,0 +1,12 @@ +agency: + isOwn: Propio + isAnyVolumeAllowed: Cualquier volumen + removeItem: Agencia eliminada correctamente + notification: + removeItemError: Error al eliminar la agencia + removeItem: Centro de trabajo eliminado correctamente + pageTitles: + agency: Agencia + searchBar: + info: Puedes buscar por nombre o id + label: Buscar agencia... diff --git a/src/pages/Customer/components/CustomerCreditCreate.vue b/src/pages/Customer/components/CustomerCreditCreate.vue index ae6d4de89..729deb258 100644 --- a/src/pages/Customer/components/CustomerCreditCreate.vue +++ b/src/pages/Customer/components/CustomerCreditCreate.vue @@ -13,7 +13,6 @@ const router = useRouter(); const initialData = ref({}); const setClient = (data) => { - console.log(data.credit); initialData.value.credit = data.credit; }; diff --git a/src/pages/Item/Card/CreateGenusForm.vue b/src/pages/Item/Card/CreateGenusForm.vue new file mode 100644 index 000000000..637a1137e --- /dev/null +++ b/src/pages/Item/Card/CreateGenusForm.vue @@ -0,0 +1,50 @@ + + + + + + + + + + + + + +es: + New genus: Nuevo genus + Latin genus name: Nombre del genus en latín + diff --git a/src/pages/Item/Card/CreateSpecieForm.vue b/src/pages/Item/Card/CreateSpecieForm.vue new file mode 100644 index 000000000..2731820ba --- /dev/null +++ b/src/pages/Item/Card/CreateSpecieForm.vue @@ -0,0 +1,50 @@ + + + + + + + + + + + + + +es: + New species: Nueva especie + Latin species name: Nombre de la especie en latín + diff --git a/src/pages/Item/Card/ItemBotanical.vue b/src/pages/Item/Card/ItemBotanical.vue index a2a39d9df..15492de9f 100644 --- a/src/pages/Item/Card/ItemBotanical.vue +++ b/src/pages/Item/Card/ItemBotanical.vue @@ -1 +1,114 @@ -Item Botanical + + + (itemBotanicals = data)" + /> + (itemGenusOptions = data)" + auto-load + /> + (itemSpeciesOptions = data)" + auto-load + /> + + + + + + + onGenusCreated(requestResponse, data) + " + /> + + + + + + onSpecieCreated(requestResponse, data) + " + /> + + + + + + + + +es: + Genus: Genus + Species: Especie + diff --git a/src/pages/Item/ItemFixedPrice.vue b/src/pages/Item/ItemFixedPrice.vue index 0dd7ca07d..2a753a3a5 100644 --- a/src/pages/Item/ItemFixedPrice.vue +++ b/src/pages/Item/ItemFixedPrice.vue @@ -5,7 +5,7 @@ import { useI18n } from 'vue-i18n'; import FetchData from 'components/FetchData.vue'; import FetchedTags from 'components/ui/FetchedTags.vue'; import VnInput from 'src/components/common/VnInput.vue'; -import VnSelectFilter from 'src/components/common/VnSelectFilter.vue'; +import VnSelect from 'src/components/common/VnSelect.vue'; import VnInputDate from 'src/components/common/VnInputDate.vue'; import EditTableCellValueForm from 'src/components/EditTableCellValueForm.vue'; import ItemFixedPriceFilter from './ItemFixedPriceFilter.vue'; @@ -178,7 +178,7 @@ const columns = computed(() => [ name: 'warehouse', ...defaultColumnAttrs, columnFilter: { - component: VnSelectFilter, + component: VnSelect, type: 'select', filterValue: null, event: getColumnInputEvents, @@ -434,7 +434,7 @@ onUnmounted(() => (stateStore.rightDrawer = false)); - (stateStore.rightDrawer = false)); - + @@ -531,7 +531,7 @@ onUnmounted(() => (stateStore.rightDrawer = false)); - - - { - { - { - { - + @@ -261,7 +261,7 @@ const decrement = (paramsObj, key) => { - -import { computed, onMounted } from 'vue'; import { useRoute } from 'vue-router'; +import { computed, onMounted, watch, onUnmounted, ref } from 'vue'; import { useI18n } from 'vue-i18n'; import { useQuasar } from 'quasar'; - import FetchedTags from 'components/ui/FetchedTags.vue'; import SendEmailDialog from 'components/common/SendEmailDialog.vue'; import SupplierConsumptionFilter from './SupplierConsumptionFilter.vue'; @@ -15,15 +14,17 @@ import { usePrintService } from 'composables/usePrintService'; import useNotify from 'src/composables/useNotify.js'; import axios from 'axios'; import { useStateStore } from 'stores/useStateStore'; +import { useState } from 'src/composables/useState'; import { useArrayData } from 'composables/useArrayData'; +const state = useState(); const stateStore = useStateStore(); const { t } = useI18n(); const route = useRoute(); const { openReport, sendEmail } = usePrintService(); const quasar = useQuasar(); const { notify } = useNotify(); - +const totalRows = ref({}); const arrayData = useArrayData('SupplierConsumption', { url: 'Suppliers/consumption', order: ['itemTypeFk', 'itemName', 'itemSize'], @@ -32,6 +33,7 @@ const arrayData = useArrayData('SupplierConsumption', { const store = arrayData.store; +onUnmounted(() => state.unset('SupplierConsumption')); const dateRanges = computed(() => { const { from, to } = arrayData.store?.userParams || {}; return { from, to }; @@ -46,7 +48,9 @@ async function getSupplierConsumptionData() { await arrayData.fetch({ append: false }); } -const rows = computed(() => store.data || []); +const rows = computed(() => { + return totalEntryPrice(store.data) || []; +}); const openReportPdf = () => { openReport(`Suppliers/${route.params.id}/campaign-metrics-pdf`, reportParams.value); @@ -93,8 +97,25 @@ const sendCampaignMetricsEmail = ({ address }) => { }); }; -const calculateTotal = (buysArray = []) => - buysArray.reduce((accumulator, { total }) => accumulator + total, 0); +const totalEntryPrice = (rows) => { + let totalPrice = 0; + let totalQuantity = 0; + if (!rows) return totalPrice; + for (const row of rows) { + let total = 0; + let quantity = 0; + for (const buy of row.buys) { + total = total + buy.total; + quantity = quantity + buy.quantity; + } + row.total = total; + row.quantity = quantity; + totalPrice = totalPrice + total; + totalQuantity = totalQuantity + quantity; + } + totalRows.value = { totalPrice, totalQuantity }; + return rows; +}; onMounted(async () => { stateStore.rightDrawer = true; @@ -128,6 +149,23 @@ onMounted(async () => { + + + + {{ t('Total entries') }}: + + {{ totalRows.totalPrice }} € + + + + + {{ t('Total stems entries') }}: + + {{ totalRows.totalQuantity }} + + + + @@ -143,20 +181,24 @@ onMounted(async () => { > - {{ - t('supplier.consumption.entry') - }} - {{ row.id }} - {{ t('supplier.consumption.date') }} - {{ toDate(row.shipped) }} - {{ - t('supplier.consumption.reference') - }} - {{ row.invoiceNumber }} + + {{ t('supplier.consumption.entry') }}: + {{ row.id }} + + + {{ t('supplier.consumption.date') }}: + {{ toDate(row.shipped) }} + + {{ t('supplier.consumption.reference') }}: + + {{ row.invoiceNumber }} + - {{ buy.itemName }} + {{ buy.itemName }} @@ -169,9 +211,13 @@ onMounted(async () => { {{ dashIfEmpty(buy.total) }} - + {{ t('Total entry') }}: - {{ calculateTotal(row.buys) }} + {{ row.total }} € + + + {{ t('Total stems') }}: + {{ row.quantity }} @@ -188,6 +234,9 @@ onMounted(async () => { es: Total entry: Total entrada + Total entries: Total de las entradas + Total stems entries: Total de tallos de las entradas + Total stems: Total tallos Open as PDF: Abrir como PDF Send to email: Enviar por email This supplier does not have a contact with an email address: Este proveedor no tiene un email de contacto diff --git a/src/pages/Ticket/TicketCreate.vue b/src/pages/Ticket/TicketCreate.vue index cb3e46d6a..16f5a2a40 100644 --- a/src/pages/Ticket/TicketCreate.vue +++ b/src/pages/Ticket/TicketCreate.vue @@ -73,7 +73,6 @@ const fetchAddresses = async (formData) => { const { defaultAddress } = selectedClient.value; formData.addressId = defaultAddress.id; - console.log(); } catch (err) { console.error(`Error fetching addresses`, err); return err.response; diff --git a/src/router/modules/agency.js b/src/router/modules/agency.js new file mode 100644 index 000000000..6f281e21d --- /dev/null +++ b/src/router/modules/agency.js @@ -0,0 +1,88 @@ +import { RouterView } from 'vue-router'; + +export default { + path: '/agency', + name: 'Agency', + meta: { + title: 'agency', + icon: 'garage_home', + moduleName: 'Agency', + }, + component: RouterView, + redirect: { name: 'AgencyCard' }, + menus: { + main: [], + card: ['AgencyBasicData', 'AgencyModes', 'AgencyWorkCenters', 'AgencyLog'], + }, + children: [ + { + path: '/agency/:id', + name: 'AgencyCard', + component: () => import('src/pages/Agency/Card/AgencyCard.vue'), + redirect: { name: 'AgencySummary' }, + children: [ + { + name: 'AgencySummary', + path: 'summary', + meta: { + title: 'summary', + icon: 'view_list', + }, + component: () => import('src/pages/Agency/Card/AgencySummary.vue'), + }, + { + name: 'AgencyBasicData', + path: 'basic-data', + meta: { + title: 'basicData', + icon: 'vn:settings', + }, + component: () => import('pages/Agency/Card/AgencyBasicData.vue'), + }, + { + path: 'workCenter', + name: 'AgencyWorkCenterCard', + redirect: { name: 'AgencyWorkCenters' }, + children: [ + { + path: '', + name: 'AgencyWorkCenters', + meta: { + icon: 'apartment', + title: 'workCenters', + }, + component: () => + import('src/pages/Agency/Card/AgencyWorkcenter.vue'), + }, + ], + }, + { + path: 'modes', + name: 'AgencyModesCard', + redirect: { name: 'AgencyModes' }, + children: [ + { + path: '', + name: 'AgencyModes', + meta: { + icon: 'format_list_bulleted', + title: 'modes', + }, + component: () => + import('src/pages/Agency/Card/AgencyModes.vue'), + }, + ], + }, + { + name: 'AgencyLog', + path: 'log', + meta: { + title: 'log', + icon: 'history', + }, + component: () => import('src/pages/Agency/Card/AgencyLog.vue'), + }, + ], + }, + ], +}; diff --git a/src/router/modules/index.js b/src/router/modules/index.js index 302ba7fe0..6f4b0b35e 100644 --- a/src/router/modules/index.js +++ b/src/router/modules/index.js @@ -15,6 +15,7 @@ import Department from './department'; import Entry from './entry'; import roadmap from './roadmap'; import Parking from './parking'; +import Agency from './agency'; export default [ Item, @@ -34,4 +35,5 @@ export default [ Entry, roadmap, Parking, + Agency, ]; diff --git a/src/router/modules/item.js b/src/router/modules/item.js index ee5ab5d16..bc1e72a94 100644 --- a/src/router/modules/item.js +++ b/src/router/modules/item.js @@ -121,15 +121,6 @@ export default { }, component: () => import('src/pages/Item/Card/ItemTax.vue'), }, - { - path: 'botanical', - name: 'ItemBotanical', - meta: { - title: 'botanical', - icon: 'vn:botanical', - }, - component: () => import('src/pages/Item/Card/ItemBotanical.vue'), - }, { path: 'barcode', name: 'ItemBarcode', @@ -157,6 +148,15 @@ export default { }, component: () => import('src/pages/Item/Card/ItemLog.vue'), }, + { + path: 'botanical', + name: 'ItemBotanical', + meta: { + title: 'botanical', + icon: 'vn:botanical', + }, + component: () => import('src/pages/Item/Card/ItemBotanical.vue'), + }, ], }, ], diff --git a/src/router/modules/route.js b/src/router/modules/route.js index f8ededf55..8e08d7222 100644 --- a/src/router/modules/route.js +++ b/src/router/modules/route.js @@ -11,7 +11,7 @@ export default { component: RouterView, redirect: { name: 'RouteMain' }, menus: { - main: ['RouteList', 'RouteAutonomous', 'RouteRoadmap', 'CmrList'], + main: ['RouteList', 'RouteAutonomous', 'RouteRoadmap', 'CmrList', 'AgencyList'], card: ['RouteBasicData', 'RouteTickets', 'RouteLog'], }, children: [ @@ -75,6 +75,21 @@ export default { }, component: () => import('src/pages/Route/Cmr/CmrList.vue'), }, + { + path: '/agency', + redirect: { name: 'AgencyList' }, + children: [ + { + path: 'list', + name: 'AgencyList', + meta: { + title: 'agencyList', + icon: 'view_list', + }, + component: () => import('src/pages/Agency/AgencyList.vue'), + }, + ], + }, ], }, { diff --git a/src/router/routes.js b/src/router/routes.js index 51e726a62..ca52441e7 100644 --- a/src/router/routes.js +++ b/src/router/routes.js @@ -15,6 +15,7 @@ import order from 'src/router/modules/order'; import entry from 'src/router/modules/entry'; import roadmap from 'src/router/modules/roadmap'; import parking from 'src/router/modules/parking'; +import agency from 'src/router/modules/agency'; const routes = [ { @@ -71,6 +72,7 @@ const routes = [ roadmap, entry, parking, + agency, { path: '/:catchAll(.*)*', name: 'NotFound', diff --git a/test/cypress/integration/agency/agencyWorkCenter.spec.js b/test/cypress/integration/agency/agencyWorkCenter.spec.js new file mode 100644 index 000000000..ff3c53214 --- /dev/null +++ b/test/cypress/integration/agency/agencyWorkCenter.spec.js @@ -0,0 +1,50 @@ +describe('AgencyWorkCenter', () => { + beforeEach(() => { + cy.viewport(1920, 1080); + cy.login('developer'); + cy.visit(`/#/agency`); + }); + + it('assign workCenter', () => { + cy.visit(`/#/agency`); + cy.get(':nth-child(1) > :nth-child(1) > .card-list-body > .list-items').click(); + cy.get('[href="#/agency/11/workCenter"] > .q-item__section--main').click(); + cy.get('.q-page-sticky > div > .q-btn > .q-btn__content > .q-icon').click(); + cy.get( + '.vn-row > .q-field > .q-field__inner > .q-field__control > .q-field__control-container' + ).type('workCenterOne{enter}'); + cy.get('.q-btn--standard > .q-btn__content > .block').click(); + cy.get('.q-notification__message').should('have.text', 'Data created'); + }); + + it('delete workCenter', () => { + cy.get(':nth-child(1) > :nth-child(1) > .card-list-body > .list-items').click(); + cy.get('[href="#/agency/11/workCenter"] > .q-item__section--main').click(); + cy.get('.q-item__section--side > .q-btn > .q-btn__content > .q-icon').click(); + cy.get('.q-notification__message').should( + 'have.text', + 'WorkCenter removed successfully' + ); + }); + + it('error on duplicate workCenter', () => { + cy.visit(`/#/agency`); + cy.get(':nth-child(1) > :nth-child(1) > .card-list-body > .list-items').click(); + cy.get('[href="#/agency/11/workCenter"] > .q-item__section--main').click(); + cy.get('.q-page-sticky > div > .q-btn > .q-btn__content > .q-icon').click(); + cy.get( + '.vn-row > .q-field > .q-field__inner > .q-field__control > .q-field__control-container' + ).type('workCenterOne{enter}'); + cy.get('.q-btn--standard > .q-btn__content > .block').click(); + cy.get('.q-notification__message').should('have.text', 'Data created'); + cy.get('.q-page-sticky > div > .q-btn > .q-btn__content > .q-icon').click(); + cy.get( + '.vn-row > .q-field > .q-field__inner > .q-field__control > .q-field__control-container' + ).type('workCenterOne{enter}'); + cy.get('.q-btn--standard > .q-btn__content > .block').click(); + + cy.get( + ':nth-child(2) > .q-notification__wrapper > .q-notification__content > .q-notification__message' + ).should('have.text', 'This workCenter is already assigned to this agency'); + }); +}); diff --git a/test/vitest/setup-file.js b/test/vitest/setup-file.js index 499204981..288f80beb 100644 --- a/test/vitest/setup-file.js +++ b/test/vitest/setup-file.js @@ -1 +1 @@ -// This file will be run before each test file +// This file will be run before each test file, don't delete or vitest will not work.