diff --git a/.eslintrc.js b/.eslintrc.js index c8bdecb1a..1d09a896f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -58,7 +58,7 @@ module.exports = { rules: { 'prefer-promise-reject-errors': 'off', 'no-unused-vars': 'warn', - + "vue/no-multiple-template-root": "off" , // allow debugger during development only 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', }, diff --git a/Jenkinsfile b/Jenkinsfile index 437332c4e..9dd72ccc3 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -96,4 +96,4 @@ pipeline { } } } -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index 6a60c95c6..ce9c4d7c1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@quasar/extras": "^1.16.4", "axios": "^1.4.0", "chromium": "^3.0.3", + "croppie": "^2.6.5", "pinia": "^2.1.3", "quasar": "^2.12.0", "validator": "^13.9.0", @@ -3169,6 +3170,11 @@ "node": ">= 10" } }, + "node_modules/croppie": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/croppie/-/croppie-2.6.5.tgz", + "integrity": "sha512-IlChnVUGG5T3w2gRZIaQgBtlvyuYnlUWs2YZIXXR3H9KrlO1PtBT3j+ykxvy9eZIWhk+V5SpBmhCQz5UXKrEKQ==" + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", diff --git a/package.json b/package.json index c4f5b828a..27ba190a6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "salix-front", - "version": "24.02.01", + "version": "24.8.0", "description": "Salix frontend", "productName": "Salix", "author": "Verdnatura", @@ -19,13 +19,13 @@ "@quasar/extras": "^1.16.4", "axios": "^1.4.0", "chromium": "^3.0.3", + "croppie": "^2.6.5", "pinia": "^2.1.3", "quasar": "^2.12.0", "validator": "^13.9.0", "vue": "^3.3.4", "vue-i18n": "^9.2.2", - "vue-router": "^4.2.1", - "vue-router-mock": "^0.2.0" + "vue-router": "^4.2.1" }, "devDependencies": { "@intlify/unplugin-vue-i18n": "^0.8.1", diff --git a/src/components/CreateBankEntityForm.vue b/src/components/CreateBankEntityForm.vue index 2a1385945..106dbec3a 100644 --- a/src/components/CreateBankEntityForm.vue +++ b/src/components/CreateBankEntityForm.vue @@ -1,6 +1,7 @@ + + + (allowedContentTypes = data.join(', '))" + auto-load + /> + + + + + + {{ t('Edit photo') }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{ + t( + 'components.editPictureForm.allowedFilesText', + { + allowedContentTypes: + allowedContentTypes, + } + ) + }} + + + + + + + + + + + + + + + + + + + + + + + + +es: + Edit photo: Editar foto + Select from computer: Seleccionar desde ordenador + Import from external URL: Importar desde URL externa + Vertical: Vertical + Normal: Normal + Panoramic: Panorámica + Orientation: Orientación + File: Fichero + This photo provider doesn't allow remote downloads: Este proveedor de fotos no permite descargas remotas + Rotate left: Girar a la izquierda + Rotate right: Girar a la derecha + Select an image: Selecciona una imagen + diff --git a/src/components/EditTableCellValueForm.vue b/src/components/EditTableCellValueForm.vue index 1b8bc4747..34c8f314c 100644 --- a/src/components/EditTableCellValueForm.vue +++ b/src/components/EditTableCellValueForm.vue @@ -50,7 +50,6 @@ const submitData = async () => { try { isLoading.value = true; const rowsToEdit = $props.rows.map((row) => ({ id: row.id, itemFk: row.itemFk })); - console.log('submit:: '); const payload = { field: formData.field, newValue: formData.newValue, diff --git a/src/components/FetchData.vue b/src/components/FetchData.vue index 137f751db..4f5d7a57d 100644 --- a/src/components/FetchData.vue +++ b/src/components/FetchData.vue @@ -45,7 +45,7 @@ onMounted(async () => { async function fetch(fetchFilter = {}) { try { const filter = Object.assign(fetchFilter, $props.filter); // eslint-disable-line vue/no-dupe-keys - if ($props.where) filter.where = $props.where; + if ($props.where && !fetchFilter.where) filter.where = $props.where; if ($props.sortBy) filter.order = $props.sortBy; if ($props.limit) filter.limit = $props.limit; @@ -54,6 +54,7 @@ async function fetch(fetchFilter = {}) { }); emit('onFetch', data); + return data; } catch (e) { // } diff --git a/src/components/FilterTravelForm.vue b/src/components/FilterTravelForm.vue index 0c5ee7f4f..5b59d9700 100644 --- a/src/components/FilterTravelForm.vue +++ b/src/components/FilterTravelForm.vue @@ -119,7 +119,6 @@ const closeForm = () => { }; const selectTravel = ({ id }) => { - console.log('row:: ', id); emit('travelSelected', id); closeForm(); }; diff --git a/src/components/FormModel.vue b/src/components/FormModel.vue index d612719c1..9fd16088c 100644 --- a/src/components/FormModel.vue +++ b/src/components/FormModel.vue @@ -186,13 +186,6 @@ watch(formUrl, async () => { }); - - - {{ t('globals.changesToSave') }} - +import { reactive, ref } from 'vue'; +import { useI18n } from 'vue-i18n'; + +import VnSelectFilter from 'src/components/common/VnSelectFilter.vue'; +import FetchData from 'components/FetchData.vue'; +import VnRow from 'components/ui/VnRow.vue'; +import FormModelPopup from './FormModelPopup.vue'; + +const emit = defineEmits(['onDataSaved']); + +const props = defineProps({ + itemFk: { + type: Number, + default: null, + }, + warehouseFk: { + type: Boolean, + default: null, + }, +}); + +const { t } = useI18n(); + +const regularizeFormData = reactive({ + itemFk: props.itemFk, + warehouseFk: props.warehouseFk, + quantity: null, +}); + +const warehousesOptions = ref([]); + +const onDataSaved = (data) => { + emit('onDataSaved', data); +}; + + + + (warehousesOptions = data)" + auto-load + /> + + + + + + + + + + + + + + + + + +es: + Warehouse: Almacén + Type the visible quantity: Introduce la cantidad visible + Regularize stock: Regularizar stock + diff --git a/src/components/UserPanel.vue b/src/components/UserPanel.vue index f512ac4c4..e0b6b86ed 100644 --- a/src/components/UserPanel.vue +++ b/src/components/UserPanel.vue @@ -1,19 +1,19 @@ @@ -129,8 +125,12 @@ function copyUserToken(){ {{ user.nickname }} - @{{ user.name }} - + + @{{ user.name }} + diff --git a/src/components/common/VnLocation.vue b/src/components/common/VnLocation.vue new file mode 100644 index 000000000..17dd3d37b --- /dev/null +++ b/src/components/common/VnLocation.vue @@ -0,0 +1,137 @@ + + + handleFetch(data)" + /> + + + + + + + + {{ opt.code }} + {{ showLabel(opt) }} + + + + + + + + +en: + search_by_postalcode: Search by postalcode, town, province or country +es: + Location: Ubicación + search_by_postalcode: Buscar por código postal, ciudad o país + diff --git a/src/components/common/VnLog.vue b/src/components/common/VnLog.vue index 781d78ba8..4265d02e9 100644 --- a/src/components/common/VnLog.vue +++ b/src/components/common/VnLog.vue @@ -168,17 +168,17 @@ function getLogTree(data) { let originLog = null; let userLog = null; let modelLog = null; - let prevLog; let nLogs; - data.forEach((log) => { + for (let i = 0; i < data.length; i++) { + let log = data[i]; + let prevLog = i > 0 ? data[i - 1] : null; const locale = validations[log.changedModel]?.locale || {}; // Origin const originChanged = !prevLog || log.originFk != prevLog.originFk; if (originChanged) { logs.push((originLog = { originFk: log.originFk, logs: [] })); - prevLog = log; } // User const userChanged = originChanged || log.userFk != prevLog.userFk; @@ -197,6 +197,7 @@ function getLogTree(data) { log.changedModel != prevLog.changedModel || log.changedModelId != prevLog.changedModelId || nLogs >= 6; + if (modelChanged) { userLog.logs.push( (modelLog = { @@ -221,7 +222,7 @@ function getLogTree(data) { propNames = [...new Set(propNames)]; log.props = parseProps(propNames, locale, vals, olds); - }); + } return logs; } @@ -320,7 +321,6 @@ function selectFilter(type, dateType) { } if (type === 'action' && selectedFilters.value.changedModel === null) { selectedFilters.value.changedModel = undefined; - reload = false; } if (type === 'userRadio') { selectedFilters.value.userFk = userRadio.value; @@ -415,18 +415,19 @@ setLogTree(); - + @@ -663,9 +664,9 @@ setLogTree(); :label="t('globals.entity')" v-model="selectedFilters.changedModel" option-label="locale" + option-value="value" :options="actions" @update:model-value="selectFilter('action')" - @clear="() => selectFilter('action')" hide-selected /> @@ -823,14 +824,30 @@ setLogTree(); .q-item { min-height: 0px; } +.q-menu { + display: block; + & > .loading { + display: flex; + justify-content: center; + } + & > .q-card { + min-width: 180px; + max-width: 400px; + + & > .header { + color: $dark; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + } +} .origin-log { &:first-child > .origin-info { margin-top: 0; } & > .origin-info { - width: 100%; - max-width: 42em; margin-top: 28px; gap: 6px; @@ -847,14 +864,15 @@ setLogTree(); } } .user-log { + display: flex; width: 100%; max-width: 40em; - & > .timeline { position: relative; - padding-right: 5px; - width: 50px; + padding-right: 1px; + width: 38px; min-width: 38px; + flex-grow: auto; & > .arrow { height: 8px; width: 8px; @@ -874,7 +892,7 @@ setLogTree(); position: absolute; background-color: $primary; width: 2px; - left: 23px; + left: 19px; z-index: -1; top: 0; bottom: -8px; @@ -893,6 +911,7 @@ setLogTree(); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; + min-height: 22px; .model-value { font-style: italic; } @@ -984,25 +1003,6 @@ setLogTree(); } } } -.q-menu { - display: block; - - & > .loading { - display: flex; - justify-content: center; - } - & > .q-card { - min-width: 180px; - max-width: 400px; - - & > .header { - color: $dark; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } - } -} en: diff --git a/src/components/common/VnSelectFilter.vue b/src/components/common/VnSelectFilter.vue index 377a39a0e..accf92fc6 100644 --- a/src/components/common/VnSelectFilter.vue +++ b/src/components/common/VnSelectFilter.vue @@ -1,4 +1,6 @@ + setOptions(data)" + :where="where || { [optionValue]: value }" + :limit="limit" + :order-by="orderBy" + :fields="fields" + /> { () => $props.url, async (newUrl, lastUrl) => { if (newUrl == lastUrl) return; - entity.value = null; await getData(); } ); @@ -62,7 +61,6 @@ async function getData() { skip: 0, }); const { data } = await arrayData.fetch({ append: false, updateRouter: false }); - entity.value = data; emit('onFetch', data); } const emit = defineEmits(['onFetch']); @@ -81,6 +79,7 @@ function viewSummary(id) { + {{ t('components.cardDescriptor.moreOptions') }} diff --git a/src/components/ui/VnAvatar.vue b/src/components/ui/VnAvatar.vue index 8915eba2c..5a5483084 100644 --- a/src/components/ui/VnAvatar.vue +++ b/src/components/ui/VnAvatar.vue @@ -1,19 +1,37 @@ - + + {{ title.charAt(0) }} diff --git a/src/components/ui/VnFilterPanel.vue b/src/components/ui/VnFilterPanel.vue index 708a170a2..7504e819e 100644 --- a/src/components/ui/VnFilterPanel.vue +++ b/src/components/ui/VnFilterPanel.vue @@ -64,10 +64,12 @@ onMounted(() => { }); const isLoading = ref(false); - async function search() { isLoading.value = true; const params = { ...userParams.value }; + store.userParamsChanged = true; + store.filter.skip = 0; + store.skip = 0; const { params: newParams } = await arrayData.addFilter({ params }); userParams.value = newParams; @@ -89,7 +91,9 @@ async function reload() { async function clearFilters() { isLoading.value = true; - + store.userParamsChanged = true; + store.filter.skip = 0; + store.skip = 0; // Filtrar los params no removibles const removableFilters = Object.keys(userParams.value).filter((param) => props.unremovableParams.includes(param) diff --git a/src/components/ui/VnLv.vue b/src/components/ui/VnLv.vue index 665404afc..0e4a055eb 100644 --- a/src/components/ui/VnLv.vue +++ b/src/components/ui/VnLv.vue @@ -2,6 +2,7 @@ import { computed } from 'vue'; import { dashIfEmpty } from 'src/filters'; +import { useClipboard } from 'src/composables/useClipboard'; const $props = defineProps({ label: { type: String, default: null }, value: { @@ -10,8 +11,19 @@ const $props = defineProps({ }, info: { type: String, default: null }, dash: { type: Boolean, default: true }, + copy: { type: Boolean, default: false }, }); const isBooleanValue = computed(() => typeof $props.value === 'boolean'); + +const { copyText } = useClipboard(); + +function copyValueText() { + copyText($props.value, { + component: { + copyValue: $props.value, + }, + }); +} diff --git a/src/components/ui/VnPaginate.vue b/src/components/ui/VnPaginate.vue index 1aa99ea0c..4c38c1c1a 100644 --- a/src/components/ui/VnPaginate.vue +++ b/src/components/ui/VnPaginate.vue @@ -104,6 +104,8 @@ async function paginate() { await arrayData.loadMore(); if (!arrayData.hasMoreData.value) { + if (store.userParamsChanged) arrayData.hasMoreData.value = true; + store.userParamsChanged = false; isLoading.value = false; return; } @@ -129,9 +131,9 @@ async function onLoad(...params) { pagination.value.page = pagination.value.page + 1; await paginate(); - - const endOfPages = !arrayData.hasMoreData.value; - done(endOfPages); + let isDone = false; + if (store.userParamsChanged) isDone = !arrayData.hasMoreData.value; + done(isDone); } @@ -172,7 +174,7 @@ async function onLoad(...params) { v-if="store.data" @load="onLoad" :offset="offset" - class="full-width full-height overflow-auto" + class="full-width full-height" > diff --git a/src/components/ui/VnSearchbar.vue b/src/components/ui/VnSearchbar.vue index 8220aa3db..eca957092 100644 --- a/src/components/ui/VnSearchbar.vue +++ b/src/components/ui/VnSearchbar.vue @@ -87,15 +87,10 @@ async function search() { }); if (!props.redirect) return; - const rows = store.data; - const module = route.matched[1]; - if (rows.length === 1) { - const [firstRow] = rows; - await router.push({ path: `${module.path}/${firstRow.id}` }); - } else if (route.matched.length > 3) { - await router.push({ path: `/${module.path}` }); - arrayData.updateStateParams(); - } + const { matched: matches } = route; + const { path } = matches[matches.length-1]; + const newRoute = path.replace(':id', searchText.value); + await router.push(newRoute); } diff --git a/src/components/ui/VnSubToolbar.vue b/src/components/ui/VnSubToolbar.vue index 81a1820f1..1a6549856 100644 --- a/src/components/ui/VnSubToolbar.vue +++ b/src/components/ui/VnSubToolbar.vue @@ -1,6 +1,7 @@ - - + + + + - + + + + diff --git a/src/composables/tMobile.js b/src/composables/tMobile.js index a6a000b81..61b8e87b4 100644 --- a/src/composables/tMobile.js +++ b/src/composables/tMobile.js @@ -4,5 +4,5 @@ import { useI18n } from 'vue-i18n'; export function tMobile(...args) { const quasar = useQuasar(); const { t } = useI18n(); - if (!quasar.platform.is.mobile) return t(...args); + if (!quasar.screen.xs) return t(...args); } diff --git a/src/composables/useArrayData.js b/src/composables/useArrayData.js index 9f66a0e89..3f031f1d1 100644 --- a/src/composables/useArrayData.js +++ b/src/composables/useArrayData.js @@ -142,7 +142,8 @@ export function useArrayData(key, userOptions) { userParams = sanitizerParams(userParams, store?.exprBuilder); store.userParams = userParams; - + store.skip = 0; + store.filter.skip = 0; await fetch({ append: false }); return { filter, params }; } diff --git a/src/composables/useClipboard.js b/src/composables/useClipboard.js new file mode 100644 index 000000000..008c24fa1 --- /dev/null +++ b/src/composables/useClipboard.js @@ -0,0 +1,17 @@ +import { useQuasar } from 'quasar'; +import { useI18n } from 'vue-i18n'; + +export function useClipboard() { + const quasar = useQuasar(); + const { t } = useI18n(); + /** + * + * @param {String} value Value to send to clipboardAPI + * @param {Object} {label, component} Refer to Quasar notify configuration. Label is the text to translate + */ + function copyText(value, { label = 'components.VnLv.copyText', component = {} }) { + navigator.clipboard.writeText(value); + quasar.notify({ type: 'positive', message: t(label, component) }); + } + return { copyText }; +} diff --git a/src/composables/useState.js b/src/composables/useState.js index 1c797e992..6ad8eb22c 100644 --- a/src/composables/useState.js +++ b/src/composables/useState.js @@ -25,6 +25,7 @@ export function useState() { lang: user.value.lang, darkMode: user.value.darkMode, companyFk: user.value.companyFk, + warehouseFk: user.value.warehouseFk, }; }); } @@ -37,6 +38,7 @@ export function useState() { lang: data.lang, darkMode: data.darkMode, companyFk: data.companyFk, + warehouseFk: data.warehouseFk, }; } diff --git a/src/composables/useUserConfig.js b/src/composables/useUserConfig.js index e05d7fb5c..a33779be7 100644 --- a/src/composables/useUserConfig.js +++ b/src/composables/useUserConfig.js @@ -12,6 +12,7 @@ export function useUserConfig() { const user = state.getUser().value; user.darkMode = data.darkMode; user.companyFk = data.companyFk; + user.warehouseFk = data.warehouseFk; state.setUser(user); return data; diff --git a/src/css/app.scss b/src/css/app.scss index e7be2ddf2..57031b21d 100644 --- a/src/css/app.scss +++ b/src/css/app.scss @@ -52,6 +52,10 @@ body.body--dark { color: var(--vn-text); } +.color-vn-white { + color: $white; +} + .vn-card { background-color: var(--vn-gray); color: var(--vn-text); diff --git a/src/i18n/en/index.js b/src/i18n/en/index.js index 9c25d2b16..b4b72ee0e 100644 --- a/src/i18n/en/index.js +++ b/src/i18n/en/index.js @@ -1098,6 +1098,25 @@ export default { totalEntries: 'Total entries', }, }, + item: { + pageTitles: { + items: 'Items', + list: 'List', + diary: 'Diary', + tags: 'Tags', + }, + descriptor: { + item: 'Item', + buyer: 'Buyer', + color: 'Color', + category: 'Category', + stems: 'Stems', + visible: 'Visible', + available: 'Available', + warehouseText: 'Calculated on the warehouse of { warehouseName }', + itemDiary: 'Item diary', + }, + }, components: { topbar: {}, userPanel: { @@ -1121,5 +1140,12 @@ export default { addToPinned: 'Add to pinned', removeFromPinned: 'Remove from pinned', }, + editPictureForm: { + allowedFilesText: 'Allowed file types: { allowedContentTypes }', + }, + VnLv: { + copyText: '{copyValue} has been copied to the clipboard', + }, + iban_tooltip: 'IBAN: ES21 1234 5678 90 0123456789', }, }; diff --git a/src/i18n/es/index.js b/src/i18n/es/index.js index 65f555877..b494eb549 100644 --- a/src/i18n/es/index.js +++ b/src/i18n/es/index.js @@ -1098,6 +1098,25 @@ export default { totalEntries: 'Ent. totales', }, }, + item: { + pageTitles: { + items: 'Artículos', + list: 'Listado', + diary: 'Histórico', + tags: 'Etiquetas', + }, + descriptor: { + item: 'Artículo', + buyer: 'Comprador', + color: 'Color', + category: 'Categoría', + stems: 'Tallos', + visible: 'Visible', + available: 'Disponible', + warehouseText: 'Calculado sobre el almacén de { warehouseName }', + itemDiary: 'Registro de compra-venta', + }, + }, components: { topbar: {}, userPanel: { @@ -1121,5 +1140,12 @@ export default { addToPinned: 'Añadir a fijados', removeFromPinned: 'Eliminar de fijados', }, + editPictureForm: { + allowedFilesText: 'Tipos de archivo permitidos: { allowedContentTypes }', + }, + VnLv: { + copyText: '{copyValue} se ha copiado al portapepeles', + }, + iban_tooltip: 'IBAN: ES21 1234 5678 90 0123456789', }, }; diff --git a/src/pages/Claim/Card/ClaimAction.vue b/src/pages/Claim/Card/ClaimAction.vue index e92e65fc7..59409e432 100644 --- a/src/pages/Claim/Card/ClaimAction.vue +++ b/src/pages/Claim/Card/ClaimAction.vue @@ -37,6 +37,7 @@ const marker_labels = [ { value: DEFAULT_MIN_RESPONSABILITY, label: t('claim.summary.company') }, { value: DEFAULT_MAX_RESPONSABILITY, label: t('claim.summary.person') }, ]; +const multiplicatorValue = ref(); const columns = computed(() => [ { @@ -134,17 +135,7 @@ async function regularizeClaim() { message: t('globals.dataSaved'), type: 'positive', }); - if (claim.value.responsibility >= Math.ceil(DEFAULT_MAX_RESPONSABILITY) / 2) { - quasar - .dialog({ - component: VnConfirm, - componentProps: { - title: t('confirmGreuges'), - message: t('confirmGreugesMessage'), - }, - }) - .onOk(async () => await onUpdateGreugeAccept()); - } + await onUpdateGreugeAccept(); } async function onUpdateGreugeAccept() { @@ -153,9 +144,9 @@ async function onUpdateGreugeAccept() { filter: { where: { code: 'freightPickUp' } }, }) ).data.id; - const freightPickUpPrice = (await axios.get(`GreugeConfigs/findOne`)).data - .freightPickUpPrice; - + const freightPickUpPrice = + (await axios.get(`GreugeConfigs/findOne`)).data.freightPickUpPrice * + multiplicatorValue.value; await axios.post(`Greuges`, { clientFk: claim.value.clientFk, description: `${t('ClaimGreugeDescription')} ${claimId}`.toUpperCase(), @@ -226,10 +217,10 @@ async function importToNewRefundTicket() { show-if-above v-if="claim" > - + {{ `${t('Total claimed')}: ${toCurrency(totalClaimed)}` }} - + @@ -250,13 +241,31 @@ async function importToNewRefundTicket() { - - save({ isChargedToMana: value })" + + + save({ isChargedToMana: value })" + /> + {{ t('mana') }} + + + + - {{ t('mana') }} - + diff --git a/src/pages/Claim/Card/ClaimCard.vue b/src/pages/Claim/Card/ClaimCard.vue index b6c948c96..64cf736a9 100644 --- a/src/pages/Claim/Card/ClaimCard.vue +++ b/src/pages/Claim/Card/ClaimCard.vue @@ -1,27 +1,13 @@ diff --git a/src/pages/Claim/Card/ClaimDescriptor.vue b/src/pages/Claim/Card/ClaimDescriptor.vue index 4f2703e71..deaed94f8 100644 --- a/src/pages/Claim/Card/ClaimDescriptor.vue +++ b/src/pages/Claim/Card/ClaimDescriptor.vue @@ -2,7 +2,7 @@ import { ref, computed } from 'vue'; import { useRoute } from 'vue-router'; import { useI18n } from 'vue-i18n'; -import { toDate } from 'src/filters'; +import { toDate, toPercentage } from 'src/filters'; import { useState } from 'src/composables/useState'; import TicketDescriptorProxy from 'pages/Ticket/Card/TicketDescriptorProxy.vue'; import ClaimDescriptorMenu from 'pages/Claim/Card/ClaimDescriptorMenu.vue'; @@ -32,7 +32,16 @@ const filter = { { relation: 'client', scope: { - include: { relation: 'salesPersonUser' }, + include: [ + { relation: 'salesPersonUser' }, + { + relation: 'claimsRatio', + scope: { + fields: ['claimingRate'], + limit: 1, + }, + }, + ], }, }, { @@ -135,6 +144,10 @@ const setData = (entity) => { :value="entity.ticket?.address?.province?.name" /> + @@ -163,3 +176,9 @@ const setData = (entity) => { margin-top: 0; } + + en: + claimRate: Claming rate + es: + claimRate: Ratio de reclamación + diff --git a/src/pages/Claim/Card/ClaimLines.vue b/src/pages/Claim/Card/ClaimLines.vue index e7f67bcc2..5190c9932 100644 --- a/src/pages/Claim/Card/ClaimLines.vue +++ b/src/pages/Claim/Card/ClaimLines.vue @@ -4,12 +4,11 @@ import { ref, computed } from 'vue'; import { useI18n } from 'vue-i18n'; import { useQuasar } from 'quasar'; import { useRoute } from 'vue-router'; -import { useArrayData } from 'composables/useArrayData'; import { useStateStore } from 'stores/useStateStore'; +import { useArrayData } from 'composables/useArrayData'; +import { toDate, toCurrency, toPercentage } from 'filters/index'; import CrudModel from 'components/CrudModel.vue'; import FetchData from 'components/FetchData.vue'; - -import { toDate, toCurrency, toPercentage } from 'filters/index'; import VnDiscount from 'components/common/vnDiscount.vue'; import ClaimLinesImport from './ClaimLinesImport.vue'; @@ -158,23 +157,21 @@ function showImportDialog() { - - - - {{ t('Amount') }} - - {{ toCurrency(amount) }} - - - - - {{ t('Amount Claimed') }} - - {{ toCurrency(amountClaimed) }} - - + + + {{ t('Amount') }} + + {{ toCurrency(amount) }} + - + + + {{ t('Amount Claimed') }} + + {{ toCurrency(amountClaimed) }} + + + - - + - + {{ row.clientName }} - + - + + + getBankEntities()); +const filter = { + fields: ['id', 'bic', 'name'], + order: 'bic ASC', + limit: 30, +}; -const getBankEntities = async () => { - const filter = { fields: ['id', 'bic', 'name'], order: 'bic ASC', limit: 30 }; - const { data } = await axios.get('BankEntities', { filter }); - bankEntitiesOptions.value = data; +const getBankEntities = () => { + bankEntitiesRef.value.fetch(); }; (payMethods = data)" auto-load url="PayMethods" /> + (bankEntitiesOptions = data)" + :filter="filter" + auto-load + url="BankEntities" + /> { - + + + + {{ t('components.iban_tooltip') }} + + + { const balanceDueWarning = computed(() => (balanceDue.value ? 'negative' : '')); const claimRate = computed(() => { - return customer.value.claimsRatio.claimingRate * 100; + return customer.value.claimsRatio.claimingRate; }); const priceIncreasingRate = computed(() => { @@ -81,7 +81,7 @@ const creditWarning = computed(() => { - + { - await postcodeFetchDataRef.value.fetch(); - await townsFetchDataRef.value.fetch(); - formData.postcode = code; - formData.provinceFk = provinceFk; - formData.city = citiesLocationOptions.value.find((town) => town.id === townFk).name; - formData.countryFk = countryFk; -}; +function handleLocation(data, location) { + const { town, code, provinceFk, countryFk } = location ?? {}; + data.postcode = code; + data.city = town; + data.provinceFk = provinceFk; + data.countryFk = countryFk; +} @@ -54,33 +47,11 @@ const onPostcodeCreated = async ({ code, provinceFk, townFk, countryFk }, formDa auto-load url="Workers/search?departmentCodes" /> - (postcodesOptions = data)" - auto-load - /> (businessTypesOptions = data)" auto-load url="BusinessTypes" /> - (citiesLocationOptions = data)" - auto-load - url="Towns/location" - /> - (provincesLocationOptions = data)" - auto-load - url="Provinces/location" - /> - (countriesOptions = data)" - auto-load - url="Countries" - /> - handleLocation(data, location) + " > - - - - - - - {{ scope.opt.code }} - {{ scope.opt.code }} - - {{ scope.opt.town.name }} ({{ - scope.opt.town.province.name - }}, - {{ - scope.opt.town.province.country.country - }}) - - - - - - - - - - - - {{ scope.opt.name }} - - {{ - `${scope.opt.name}, ${scope.opt.province.name} (${scope.opt.province.country.country})` - }} - - - - - - - - - - - - - - {{ - `${scope.opt.name} (${scope.opt.country.country})` - }} - - - - - - - + + diff --git a/src/pages/Customer/Defaulter/CustomerDefaulter.vue b/src/pages/Customer/Defaulter/CustomerDefaulter.vue index bf7480985..1dfd331e2 100644 --- a/src/pages/Customer/Defaulter/CustomerDefaulter.vue +++ b/src/pages/Customer/Defaulter/CustomerDefaulter.vue @@ -12,6 +12,7 @@ import CustomerNotificationsFilter from './CustomerDefaulterFilter.vue'; import CustomerBalanceDueTotal from './CustomerBalanceDueTotal.vue'; import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue'; import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue'; +import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue'; import CustomerDefaulterAddObservation from './CustomerDefaulterAddObservation.vue'; const { t } = useI18n(); @@ -206,8 +207,8 @@ const refreshData = () => { - - + + { @click.stop="viewAddObservation(selected)" /> - - + + { /> - - - + + { visibleColumns = ['customerStatus', ...$event, 'actions'] " /> - - - - + + { }; const removeDepartment = () => { - console.log('entityId: ', entityId.value); quasar .dialog({ title: 'Are you sure you want to delete it?', @@ -90,17 +89,15 @@ const removeDepartment = () => { - - + + diff --git a/src/pages/Entry/EntryLatestBuys.vue b/src/pages/Entry/EntryLatestBuys.vue index ca91fa188..4291abcaf 100644 --- a/src/pages/Entry/EntryLatestBuys.vue +++ b/src/pages/Entry/EntryLatestBuys.vue @@ -211,7 +211,6 @@ const columns = computed(() => [ const openEditTableCellDialog = () => { editTableCellDialogRef.value.show(); - console.log('open edit row form: ', rowsSelected.value); }; const onEditCellDataSaved = async () => { diff --git a/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue b/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue index a46978458..2f8435166 100644 --- a/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue +++ b/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue @@ -4,11 +4,12 @@ import { useRoute } from 'vue-router'; import { useI18n } from 'vue-i18n'; import { useQuasar } from 'quasar'; import { useArrayData } from 'src/composables/useArrayData'; - import { downloadFile } from 'src/composables/downloadFile'; -import FetchData from 'src/components/FetchData.vue'; + import FormModel from 'components/FormModel.vue'; import VnSelectFilter from 'src/components/common/VnSelectFilter.vue'; +import FetchData from 'src/components/FetchData.vue'; + import axios from 'axios'; const quasar = useQuasar(); @@ -21,9 +22,6 @@ const arrayData = useArrayData('InvoiceIn'); const invoiceIn = computed(() => arrayData.store.data); const userConfig = ref(null); -const suppliers = ref([]); -const suppliersRef = ref(); -const suppliersRefFilter = ref({ fields: ['id', 'nickname'], limit: 30 }); const currencies = ref([]); const currenciesRef = ref(); const companies = ref([]); @@ -131,31 +129,13 @@ async function upsert() { }); } } - -function supplierRefFilter(val) { - let where = { limit: 30 }; - let params = {}; - let key = 'nickname'; - - if (new RegExp(/\d/g).test(val)) { - key = 'id'; - } - params = { [key]: { like: `%${val}%` } }; - where = Object.assign(where, params); - suppliersRef.value.fetch({ where }); -} - (suppliers = data)" - /> (currencies = data)" auto-load /> @@ -163,7 +143,7 @@ function supplierRefFilter(val) { ref="companiesRef" url="Companies" :filter="{ fields: ['id', 'code'] }" - order="code" + sort-by="code" @on-fetch="(data) => (companies = data)" auto-load /> @@ -171,7 +151,7 @@ function supplierRefFilter(val) { ref="dmsTypesRef" url="DmsTypes" :filter="{ fields: ['id', 'name'] }" - order="name" + sort-by="name" @on-fetch="(data) => (dmsTypes = data)" auto-load /> @@ -179,7 +159,7 @@ function supplierRefFilter(val) { ref="warehousesRef" url="Warehouses" :filter="{ fields: ['id', 'name'] }" - order="name" + sort-by="name" @on-fetch="(data) => (warehouses = data)" auto-load /> @@ -199,15 +179,13 @@ function supplierRefFilter(val) { @@ -418,7 +396,6 @@ function supplierRefFilter(val) { { url="InvoiceOuts/filter" > - - + + { :model-value="selectedCards.size === rows.length" class="q-mr-md" /> - - + + +import LeftMenu from 'components/LeftMenu.vue'; +import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue'; +import ItemDescriptor from './ItemDescriptor.vue'; + +import { useStateStore } from 'stores/useStateStore'; + +const stateStore = useStateStore(); + + + + + + + + + + + + + + + + + diff --git a/src/pages/Item/Card/ItemDescriptor.vue b/src/pages/Item/Card/ItemDescriptor.vue new file mode 100644 index 000000000..362fcfc67 --- /dev/null +++ b/src/pages/Item/Card/ItemDescriptor.vue @@ -0,0 +1,316 @@ + + + + { + item = data; + setData(data); + } + " + > + + + + {{ t('Regularize stock') }} + + + + + + + + {{ t('Clone') }} + + + + + + + + + + + + + + {{ t('item.descriptor.item') }} + + + + + + + + + + + + + + + + + {{ t('item.descriptor.visible') }} + + {{ + visible + }} + + + + {{ t('item.descriptor.available') }} + + {{ + available + }} + + + + {{ warehouseText }} + + + + + + + + + {{ t('item.descriptor.buyer') }} + + + + + + + + + + + + {{ t('item.descriptor.itemDiary') }} + + + + + + + +es: + Regularize stock: Regularizar stock + Clone: Clonar + All it's properties will be copied: Todas sus propiedades serán copiadas + Do you want to clone this item?: ¿Desea clonar este artículo? + + + diff --git a/src/pages/Item/Card/ItemDescriptorProxy.vue b/src/pages/Item/Card/ItemDescriptorProxy.vue new file mode 100644 index 000000000..58471dc83 --- /dev/null +++ b/src/pages/Item/Card/ItemDescriptorProxy.vue @@ -0,0 +1,26 @@ + + + + + + + diff --git a/src/pages/Item/Card/ItemDiary.vue b/src/pages/Item/Card/ItemDiary.vue new file mode 100644 index 000000000..21249349f --- /dev/null +++ b/src/pages/Item/Card/ItemDiary.vue @@ -0,0 +1 @@ +Item diary (CREAR CUANDO SE DESARROLLE EL MODULO DE ITEMS) diff --git a/src/pages/Item/Card/ItemSummary.vue b/src/pages/Item/Card/ItemSummary.vue new file mode 100644 index 000000000..567fbf32b --- /dev/null +++ b/src/pages/Item/Card/ItemSummary.vue @@ -0,0 +1 @@ +Item summary diff --git a/src/pages/Item/Card/ItemSummaryDialog.vue b/src/pages/Item/Card/ItemSummaryDialog.vue new file mode 100644 index 000000000..4af617fd9 --- /dev/null +++ b/src/pages/Item/Card/ItemSummaryDialog.vue @@ -0,0 +1,5 @@ + + Item summary dialog (A DESARROLLAR CUANDO SE CREE EL MODULO DE ITEMS) + diff --git a/src/pages/Item/Card/ItemTags.vue b/src/pages/Item/Card/ItemTags.vue new file mode 100644 index 000000000..95f4380e4 --- /dev/null +++ b/src/pages/Item/Card/ItemTags.vue @@ -0,0 +1 @@ +Item tags (CREAR CUANDO SE DESARROLLE EL MODULO DE ITEMS) diff --git a/src/pages/Item/ItemList.vue b/src/pages/Item/ItemList.vue new file mode 100644 index 000000000..49a5dbb64 --- /dev/null +++ b/src/pages/Item/ItemList.vue @@ -0,0 +1 @@ +Item list diff --git a/src/pages/Item/ItemMain.vue b/src/pages/Item/ItemMain.vue new file mode 100644 index 000000000..c1f2a31db --- /dev/null +++ b/src/pages/Item/ItemMain.vue @@ -0,0 +1,18 @@ + + + + + + + + + + + + diff --git a/src/pages/Order/Card/OrderCatalogItem.vue b/src/pages/Order/Card/OrderCatalogItem.vue index 140a4c349..ee73bcffb 100644 --- a/src/pages/Order/Card/OrderCatalogItem.vue +++ b/src/pages/Order/Card/OrderCatalogItem.vue @@ -1,10 +1,13 @@ (paymethodsOptions = data)" auto-load /> - (payDemsOptions = data)" auto-load /> + formatPayDems(data)" auto-load /> @@ -49,7 +55,6 @@ const payDemsOptions = ref([]); option-value="id" option-label="payDem" hide-selected - map-options :rules="validate('supplier.payDemFk')" /> diff --git a/src/pages/Supplier/Card/SupplierConsumption.vue b/src/pages/Supplier/Card/SupplierConsumption.vue index 0cf66fe25..59dd2281c 100644 --- a/src/pages/Supplier/Card/SupplierConsumption.vue +++ b/src/pages/Supplier/Card/SupplierConsumption.vue @@ -7,8 +7,9 @@ import { useQuasar } from 'quasar'; import FetchedTags from 'components/ui/FetchedTags.vue'; import SendEmailDialog from 'components/common/SendEmailDialog.vue'; import SupplierConsumptionFilter from './SupplierConsumptionFilter.vue'; +import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue'; -import { toDate, toDateString } from 'src/filters'; +import { toDate } from 'src/filters'; import { dashIfEmpty } from 'src/filters'; import { usePrintService } from 'composables/usePrintService'; import useNotify from 'src/composables/useNotify.js'; @@ -31,23 +32,26 @@ const arrayData = useArrayData('SupplierConsumption', { const store = arrayData.store; -const userParams = computed(() => { - const minDate = Date.vnNew(); - minDate.setHours(0, 0, 0, 0); - minDate.setMonth(minDate.getMonth() - 2); - - const maxDate = Date.vnNew(); - maxDate.setHours(23, 59, 59, 59); - - return { - from: toDateString(minDate), - to: toDateString(maxDate), +const dateRanges = computed(() => { + const ranges = { + from: null, + to: null, }; + + if (route.query && route.query.params) { + const params = JSON.parse(route.query.params); + if (params.from && params.to) { + ranges.from = params.from; + ranges.to = params.to; + } + } + + return ranges; }); const reportParams = computed(() => ({ recipientId: Number(route.params.id), - ...userParams.value, + ...dateRanges.value, })); async function getSupplierConsumptionData() { @@ -101,10 +105,8 @@ const sendCampaignMetricsEmail = ({ address }) => { }); }; -const calculateTotal = (buysArray) => { - if (!buysArray || !buysArray.length > 0) return; - return buysArray.reduce((accumulator, { total }) => accumulator + total, 0); -}; +const calculateTotal = (buysArray = []) => + buysArray.reduce((accumulator, { total }) => accumulator + total, 0); onMounted(async () => { stateStore.rightDrawer = true; @@ -113,35 +115,31 @@ onMounted(async () => { - - - - - {{ t('Open as PDF') }} - - - - - {{ t('Send to email') }} - - - - - - + + + + {{ t('Open as PDF') }} + + + + + {{ t('Send to email') }} + + + @@ -151,11 +149,11 @@ onMounted(async () => { @@ -171,7 +169,10 @@ onMounted(async () => { {{ row.invoiceNumber }} - {{ buy.itemName }} + + {{ buy.itemName }} + + {{ buy.subName }} diff --git a/src/pages/Supplier/Card/SupplierConsumptionFilter.vue b/src/pages/Supplier/Card/SupplierConsumptionFilter.vue index 4835b7663..339a9d0d9 100644 --- a/src/pages/Supplier/Card/SupplierConsumptionFilter.vue +++ b/src/pages/Supplier/Card/SupplierConsumptionFilter.vue @@ -50,18 +50,14 @@ const itemCategoriesOptions = ref([]); @on-fetch="(data) => (itemCategoriesOptions = data)" auto-load /> - + {{ t(`params.${tag.label}`) }}: {{ formatFn(tag.value) }} - + @@ -149,8 +149,9 @@ const itemCategoriesOptions = ref([]); diff --git a/src/pages/Supplier/Card/SupplierDescriptor.vue b/src/pages/Supplier/Card/SupplierDescriptor.vue index 43857fd1e..83bad87d2 100644 --- a/src/pages/Supplier/Card/SupplierDescriptor.vue +++ b/src/pages/Supplier/Card/SupplierDescriptor.vue @@ -1,10 +1,14 @@ @@ -73,6 +103,22 @@ const setData = (entity) => { @on-fetch="setData" data-key="Supplier" > + + + + {{ t('Go to module index') }} + + + @@ -87,8 +133,69 @@ const setData = (entity) => { + + + + {{ t('Inactive supplier') }} + + + {{ t('Unverified supplier') }} + + + + + + + {{ t('All entries with current supplier') }} + + + {{ t('Go to client') }} + + + {{ t('Create invoiceIn') }} + + + - + +es: + All entries with current supplier: Todas las entradas con proveedor actual + Go to client: Ir a cliente + Create invoiceIn: Crear factura recibida + Go to module index: Ir al índice del módulo + Inactive supplier: Proveedor inactivo + Unverified supplier: Proveedor no verificado diff --git a/src/pages/Supplier/SupplierCreate.vue b/src/pages/Supplier/SupplierCreate.vue index ebe0518f2..8424ae68c 100644 --- a/src/pages/Supplier/SupplierCreate.vue +++ b/src/pages/Supplier/SupplierCreate.vue @@ -1,6 +1,8 @@ @@ -34,6 +41,7 @@ const newSupplierForm = reactive({ url-create="Suppliers/newSupplier" model="supplier" :form-initial-data="newSupplierForm" + @on-data-saved="redirectToSupplierFiscalData" > diff --git a/src/pages/Supplier/SupplierList.vue b/src/pages/Supplier/SupplierList.vue index d504e127a..f4875fc99 100644 --- a/src/pages/Supplier/SupplierList.vue +++ b/src/pages/Supplier/SupplierList.vue @@ -1,13 +1,16 @@ + + + (provincesOptions = data)" + auto-load + /> + (countriesOptions = data)" + auto-load + /> + + + + {{ t(`params.${tag.label}`) }}: + {{ formatFn(tag.value) }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +en: + params: + search: General search + nickname: Alias + nif: Tax number + provinceFk: Province + countryFk: Country +es: + params: + search: Búsqueda general + nickname: Alias + nif: NIF/CIF + provinceFk: Provincia + countryFk: País + diff --git a/src/pages/Ticket/Card/TicketSummary.vue b/src/pages/Ticket/Card/TicketSummary.vue index 65523bb82..fe7dcee9a 100644 --- a/src/pages/Ticket/Card/TicketSummary.vue +++ b/src/pages/Ticket/Card/TicketSummary.vue @@ -58,7 +58,7 @@ function formattedAddress() { function isEditable() { try { - return !ticket.value.ticketState.state.alertLevel; + return !ticket.value.ticketState?.state?.alertLevel; } catch (e) { console.error(e); } @@ -153,8 +153,8 @@ async function changeState(value) { - - {{ ticket.ticketState.state.name }} + + {{ ticket.ticketState?.state?.name }} diff --git a/src/pages/Travel/ExtraCommunity.vue b/src/pages/Travel/ExtraCommunity.vue index 18824503f..2dcd4bb51 100644 --- a/src/pages/Travel/ExtraCommunity.vue +++ b/src/pages/Travel/ExtraCommunity.vue @@ -17,6 +17,7 @@ import { useArrayData } from 'composables/useArrayData'; import { toDate } from 'src/filters'; import { usePrintService } from 'composables/usePrintService'; import travelService from 'src/services/travel.service'; +import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue'; const router = useRouter(); const stateStore = useStateStore(); @@ -259,10 +260,8 @@ onMounted(async () => { /> - - - - + + { {{ t('Open as PDF') }} - - + + diff --git a/src/pages/Worker/Card/WorkerDescriptor.vue b/src/pages/Worker/Card/WorkerDescriptor.vue index f089c0022..bec56bee7 100644 --- a/src/pages/Worker/Card/WorkerDescriptor.vue +++ b/src/pages/Worker/Card/WorkerDescriptor.vue @@ -101,7 +101,7 @@ const setData = (entity) => { - + - + { bankEntitiesOptions.value.push(data); }; -const onPostcodeCreated = async ({ code, provinceFk, townFk }, formData) => { - await postcodeFetchDataRef.value.fetch(); - await townsFetchDataRef.value.fetch(); - formData.postcode = code; - formData.provinceFk = provinceFk; - formData.city = townsOptions.value.find((town) => town.id === townFk).name; -}; +function handleLocation(data, location) { + const { town, postcode: code, provinceFk, countryFk } = location ?? {}; + data.postcode = code; + data.city = town; + data.provinceFk = provinceFk; + data.countryFk = countryFk; +} onMounted(async () => { const userInfo = await useUserConfig().fetch(); @@ -88,25 +77,7 @@ onMounted(async () => { :filter="workerConfigFilter" auto-load /> - (postcodesOptions = data)" - auto-load - /> - (provincesOptions = data)" - :filter="provincesFilter" - auto-load - /> - (townsOptions = data)" - :filter="townsFilter" - auto-load - /> + (companiesOptions = data)" @@ -184,77 +155,19 @@ onMounted(async () => { - handleLocation(data, location) + " > - - - - - - - {{ scope.opt.code }} - {{ scope.opt.code }} - - {{ scope.opt.town.name }} ({{ - scope.opt.town.province.name - }}, - {{ - scope.opt.town.province.country.country - }}) - - - - - - - + - - - - - - {{ scope.opt.name }} - {{ scope.opt.name }}, - {{ scope.opt.province.name }} ({{ - scope.opt.province.country.country - }}) - - - - - { v-model="data.iban" :label="t('worker.create.iban')" :rules="validate('Worker.iban')" - /> + > + + + {{ + t('components.iban_tooltip') + }} + + + import('src/pages/Item/ItemMain.vue'), + redirect: { name: 'Itemlist' }, + children: [ + { + path: 'list', + name: 'ItemList', + meta: { + title: 'list', + icon: 'view_list', + }, + component: () => import('src/pages/Item/ItemList.vue'), + }, + ], + }, + { + name: 'ItemCard', + path: ':id', + component: () => import('src/pages/Item/Card/ItemCard.vue'), + redirect: { name: 'ItemSummary' }, + children: [ + { + name: 'ItemSummary', + path: 'summary', + meta: { + title: 'summary', + icon: 'launch', + }, + component: () => import('src/pages/Item/Card/ItemSummary.vue'), + }, + { + path: 'diary', + name: 'ItemDiary', + meta: { + title: 'diary', + icon: 'vn:transaction', + }, + component: () => import('src/pages/Item/Card/ItemDiary.vue'), + }, + { + path: 'tags', + name: 'ItemTags', + meta: { + title: 'Tags', + icon: 'vn:tags', + }, + component: () => import('src/pages/Item/Card/ItemTags.vue'), + }, + ], + }, + ], +}; diff --git a/src/router/routes.js b/src/router/routes.js index 6a2fa6a97..d1027955f 100644 --- a/src/router/routes.js +++ b/src/router/routes.js @@ -1,3 +1,4 @@ +import item from './modules/item'; import customer from './modules/customer'; import ticket from './modules/ticket'; import claim from './modules/claim'; @@ -51,6 +52,7 @@ const routes = [ component: () => import('../pages/Dashboard/DashboardMain.vue'), }, // Module routes + item, customer, ticket, claim, diff --git a/src/stores/useArrayDataStore.js b/src/stores/useArrayDataStore.js index 223406a33..115c161dd 100644 --- a/src/stores/useArrayDataStore.js +++ b/src/stores/useArrayDataStore.js @@ -19,6 +19,7 @@ export const useArrayDataStore = defineStore('arrayDataStore', () => { order: '', data: ref(), isLoading: false, + userParamsChanged: false, exprBuilder: null, }; } diff --git a/src/stores/useNavigationStore.js b/src/stores/useNavigationStore.js index 2eda6f686..568063d1d 100644 --- a/src/stores/useNavigationStore.js +++ b/src/stores/useNavigationStore.js @@ -7,19 +7,19 @@ import routes from 'src/router/modules'; export const useNavigationStore = defineStore('navigationStore', () => { const modules = [ - 'customer', - 'claim', - 'ticket', - 'invoiceOut', - 'invoiceIn', - 'worker', 'shelving', 'order', - 'wagon', - 'route', - 'supplier', - 'travel', + 'customer', 'entry', + 'travel', + 'invoiceOut', + 'invoiceIn', + 'supplier', + 'claim', + 'route', + 'ticket', + 'worker', + 'wagon', ]; const pinnedModules = ref([]); const role = useRole(); diff --git a/test/cypress/integration/VnLocation.spec.js b/test/cypress/integration/VnLocation.spec.js new file mode 100644 index 000000000..fe0ecee68 --- /dev/null +++ b/test/cypress/integration/VnLocation.spec.js @@ -0,0 +1,31 @@ +const inputLocation = ':nth-child(3) > :nth-child(1) > .q-field > .q-field__inner > .q-field__control'; +const locationOptions ='[role="listbox"] > div.q-virtual-scroll__content > .q-item' +describe('VnLocation', () => { + beforeEach(() => { + cy.viewport(1280, 720); + cy.login('developer'); + cy.visit('/#/worker/create'); + cy.waitForElement('.q-card'); + }); + + it('Show all options', function() { + cy.get(inputLocation).click(); + cy.get(locationOptions).should('have.length',5); + }); + + it('input filter location as "al"', function() { + cy.get(inputLocation).click(); + cy.get(inputLocation).clear(); + cy.get(inputLocation).type('al'); + cy.get(locationOptions).should('have.length',3); + }); + it('input filter location as "ecuador"', function() { + cy.get(inputLocation).click(); + cy.get(inputLocation).clear(); + cy.get(inputLocation).type('ecuador'); + cy.get(locationOptions).should('have.length',1); + cy.get(`${locationOptions}:nth-child(1)`).click(); + cy.get(':nth-child(3) > :nth-child(1) > .q-field > .q-field__inner > .q-field__control > :nth-child(2) > .q-icon').click(); + + }); +}) diff --git a/test/cypress/integration/claim/claimAction.spec.js b/test/cypress/integration/claim/claimAction.spec.js index f181722fa..685e120ce 100644 --- a/test/cypress/integration/claim/claimAction.spec.js +++ b/test/cypress/integration/claim/claimAction.spec.js @@ -31,7 +31,6 @@ describe('ClaimAction', () => { it('should regularize', () => { cy.get('[title="Regularize"]').click(); - cy.clickConfirm(); }); it('should remove the line', () => { diff --git a/test/cypress/integration/invoiceIn/invoiceInBasicData.spec.js b/test/cypress/integration/invoiceIn/invoiceInBasicData.spec.js index 0013df343..7617a69d1 100644 --- a/test/cypress/integration/invoiceIn/invoiceInBasicData.spec.js +++ b/test/cypress/integration/invoiceIn/invoiceInBasicData.spec.js @@ -16,11 +16,12 @@ describe('InvoiceInBasicData', () => { cy.get(selects).eq(0).type('Bros'); cy.get(selects).eq(0).type('{enter}'); + cy.get('[title="Reset"]').click(); cy.get(appendBtns).eq(0).click(); cy.get('input').eq(2).type(4739); cy.saveCard(); - cy.get(`${selects} input`).eq(0).invoke('val').should('eq', 'Bros nick'); + cy.get(`${selects} input`).eq(0).invoke('val').should('eq', 'Plants nick'); cy.get('input').eq(2).invoke('val').should('eq', '4739'); }); diff --git a/test/cypress/integration/invoiceIn/invoiceInList.spec.js b/test/cypress/integration/invoiceIn/invoiceInList.spec.js index 60d8c5be1..9d3adbc73 100644 --- a/test/cypress/integration/invoiceIn/invoiceInList.spec.js +++ b/test/cypress/integration/invoiceIn/invoiceInList.spec.js @@ -9,6 +9,7 @@ describe('InvoiceInList', () => { beforeEach(() => { cy.login('developer'); cy.visit(`/#/invoice-in`); + cy.clickFilterSearchBtn(); }); it('should redirect on clicking a invoice', () => { diff --git a/test/cypress/integration/vnSearchBar.spec.js b/test/cypress/integration/vnSearchBar.spec.js new file mode 100644 index 000000000..d6dea0780 --- /dev/null +++ b/test/cypress/integration/vnSearchBar.spec.js @@ -0,0 +1,19 @@ +/// +describe('VnSearchBar', () => { + beforeEach(() => { + cy.login('developer'); + cy.visit('/'); + }); + + it('should redirect to new customer', () => { + cy.visit('#/customer/1112/basic-data') + cy.openLeftMenu(); + cy.get('.q-item > .q-item__label').should('have.text',' #1112') + cy.closeLeftMenu(); + cy.clearSearchbar(); + cy.writeSearchbar('1{enter}'); + cy.openLeftMenu(); + cy.get('.q-item > .q-item__label').should('have.text',' #1') + cy.closeLeftMenu(); + }); +}); diff --git a/test/cypress/support/commands.js b/test/cypress/support/commands.js index fc3a593ad..e4d1cebe1 100755 --- a/test/cypress/support/commands.js +++ b/test/cypress/support/commands.js @@ -163,7 +163,28 @@ Cypress.Commands.add('openRightMenu', (element) => { cy.get('#actions-append').click(); }); +Cypress.Commands.add('openLeftMenu', (element) => { + if (element) cy.waitForElement(element); + cy.get('.q-toolbar > .q-btn--round.q-btn--dense > .q-btn__content > .q-icon').click(); +}); +Cypress.Commands.add('closeLeftMenu', (element) => { + if (element) cy.waitForElement(element); + cy.get('.fullscreen').click(); +}); + +Cypress.Commands.add('clearSearchbar', (element) => { + if (element) cy.waitForElement(element); + cy.get('#searchbar > form > label > div:nth-child(1) input').clear(); +}); + +Cypress.Commands.add('writeSearchbar', (value) => { + cy.get('#searchbar > form > label > div:nth-child(1) input').type(value); +}); Cypress.Commands.add('validateContent', (selector, expectedValue) => { cy.get(selector).should('have.text', expectedValue); }); + +Cypress.Commands.add('clickFilterSearchBtn', () => { + cy.get('.q-item__section > .q-btn > .q-btn__content > .q-icon').click(); +}); // registerCommands(); diff --git a/test/vitest/__tests__/components/Paginate.spec.js b/test/vitest/__tests__/components/Paginate.spec.js index af9fb41a1..2a22ce438 100644 --- a/test/vitest/__tests__/components/Paginate.spec.js +++ b/test/vitest/__tests__/components/Paginate.spec.js @@ -119,7 +119,7 @@ describe('VnPaginate', () => { await vm.onLoad(index, done); expect(vm.pagination.page).toEqual(2); - expect(done).toHaveBeenCalledWith(true); + expect(done).toHaveBeenCalledWith(false); }); }); }); diff --git a/test/vitest/__tests__/components/common/VnSearchBar.spec.js b/test/vitest/__tests__/components/common/VnSearchBar.spec.js new file mode 100644 index 000000000..fd0a026ef --- /dev/null +++ b/test/vitest/__tests__/components/common/VnSearchBar.spec.js @@ -0,0 +1,53 @@ +import { vi, describe, expect, it, beforeAll, beforeEach, afterEach } from 'vitest'; +import { createWrapper, axios } from 'app/test/vitest/helper'; +import VnSearchbar from 'components/ui/VnSearchbar.vue'; + + +describe('VnSearchBar', () => { + let vm; + let wrapper; + + beforeAll(() => { + wrapper = createWrapper(VnSearchbar, { + propsData: { + dataKey: 'CustomerList', + label: 'Search customer', + info: 'Info customer', + }, + }); + vm = wrapper.vm; + vm.route.matched = [ + { + path: '/', + }, + { + path: '/customer', + }, + { + path: '/customer/:id', + }, + { + path: '/customer/:id/basic-data', + }, + ]; + }); + + afterEach(() => { + vi.clearAllMocks(); + }); + it('should be defined', async () => { + expect(vm.searchText).toBeDefined(); + expect(vm.searchText).toEqual(''); + }); + it('should redirect', async () => { + vi.spyOn(vm.router,'push'); + vm.searchText = '1'; + await vm.search(); + expect(vm.router.push).toHaveBeenCalledWith('/customer/1/basic-data'); + vm.searchText = '1112'; + expect(vm.searchText).toEqual('1112'); + vi.spyOn(vm.router,'push'); + await vm.search(); + expect(vm.router.push).toHaveBeenCalledWith('/customer/1112/basic-data'); + }); +});
@@ -250,13 +241,31 @@ async function importToNewRefundTicket() {