feat: #7103 created test for VnSearchbar #1256
|
@ -34,5 +34,7 @@ module.exports = defineConfig({
|
||||||
require('cypress-mochawesome-reporter/plugin')(on);
|
require('cypress-mochawesome-reporter/plugin')(on);
|
||||||
// implement node event listeners here
|
// implement node event listeners here
|
||||||
},
|
},
|
||||||
|
viewportWidth: 1280,
|
||||||
|
viewportHeight: 720,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
16
package.json
16
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "salix-front",
|
"name": "salix-front",
|
||||||
"version": "25.04.0",
|
"version": "25.06.0",
|
||||||
"description": "Salix frontend",
|
"description": "Salix frontend",
|
||||||
"productName": "Salix",
|
"productName": "Salix",
|
||||||
"author": "Verdnatura",
|
"author": "Verdnatura",
|
||||||
|
@ -21,24 +21,24 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@quasar/cli": "^2.3.0",
|
"@quasar/cli": "^2.3.0",
|
||||||
"@quasar/extras": "^1.16.9",
|
"@quasar/extras": "^1.16.14",
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
"chromium": "^3.0.3",
|
"chromium": "^3.0.3",
|
||||||
"croppie": "^2.6.5",
|
"croppie": "^2.6.5",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"pinia": "^2.1.3",
|
"pinia": "^2.1.3",
|
||||||
"quasar": "^2.14.5",
|
"quasar": "^2.17.4",
|
||||||
"validator": "^13.9.0",
|
"validator": "^13.9.0",
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.5.13",
|
||||||
"vue-i18n": "^9.2.2",
|
"vue-i18n": "^9.3.0",
|
||||||
"vue-router": "^4.2.1"
|
"vue-router": "^4.2.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^19.2.1",
|
"@commitlint/cli": "^19.2.1",
|
||||||
"@commitlint/config-conventional": "^19.1.0",
|
"@commitlint/config-conventional": "^19.1.0",
|
||||||
"@intlify/unplugin-vue-i18n": "^0.8.1",
|
"@intlify/unplugin-vue-i18n": "^0.8.1",
|
||||||
"@pinia/testing": "^0.1.2",
|
"@pinia/testing": "^0.1.2",
|
||||||
"@quasar/app-vite": "^1.7.3",
|
"@quasar/app-vite": "^1.11.0",
|
||||||
"@quasar/quasar-app-extension-qcalendar": "4.0.0-beta.15",
|
"@quasar/quasar-app-extension-qcalendar": "4.0.0-beta.15",
|
||||||
"@quasar/quasar-app-extension-testing-unit-vitest": "^0.4.0",
|
"@quasar/quasar-app-extension-testing-unit-vitest": "^0.4.0",
|
||||||
"@vue/test-utils": "^2.4.4",
|
"@vue/test-utils": "^2.4.4",
|
||||||
|
@ -52,7 +52,7 @@
|
||||||
"husky": "^8.0.0",
|
"husky": "^8.0.0",
|
||||||
"postcss": "^8.4.23",
|
"postcss": "^8.4.23",
|
||||||
"prettier": "^2.8.8",
|
"prettier": "^2.8.8",
|
||||||
"vitest": "^0.31.1"
|
"vitest": "^0.34.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^20 || ^18 || ^16",
|
"node": "^20 || ^18 || ^16",
|
||||||
|
|
1079
pnpm-lock.yaml
1079
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,9 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import quasarLang from 'src/utils/quasarLang';
|
||||||
|
|
||||||
import { onMounted, computed, ref } from 'vue';
|
import { onMounted, computed, ref } from 'vue';
|
||||||
import { Dark, Quasar } from 'quasar';
|
|
||||||
|
import { Dark } from 'quasar';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
@ -31,14 +34,7 @@ const userLocale = computed({
|
||||||
|
|
||||||
value = localeEquivalence[value] ?? value;
|
value = localeEquivalence[value] ?? value;
|
||||||
|
|
||||||
try {
|
quasarLang(value);
|
||||||
/* @vite-ignore */
|
|
||||||
import(`../../node_modules/quasar/lang/${value}.mjs`).then((lang) => {
|
|
||||||
Quasar.lang.set(lang.default);
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
import { describe, expect, it, beforeEach, afterEach, vi } from 'vitest';
|
||||||
|
import { createWrapper } from 'app/test/vitest/helper';
|
||||||
|
import VnVisibleColumn from '../VnVisibleColumn.vue';
|
||||||
|
import { axios } from 'app/test/vitest/helper';
|
||||||
|
|
||||||
|
describe('VnVisibleColumns', () => {
|
||||||
|
let wrapper;
|
||||||
|
let vm;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = createWrapper(VnVisibleColumn, {
|
||||||
|
propsData: {
|
||||||
|
tableCode: 'testTable',
|
||||||
|
skip: ['skippedColumn'],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
vm = wrapper.vm;
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('setUserConfigViewData()', () => {
|
||||||
|
it('should initialize localColumns with visible configuration', () => {
|
||||||
|
vm.columns = [
|
||||||
|
{ name: 'columnMockName', label: undefined },
|
||||||
|
{ name: 'columnMockAddress', label: undefined },
|
||||||
|
{ name: 'columnMockId', label: undefined },
|
||||||
|
];
|
||||||
|
const configuration = {
|
||||||
|
columnMockName: true,
|
||||||
|
columnMockAddress: false,
|
||||||
|
columnMockId: true,
|
||||||
|
};
|
||||||
|
const expectedColumns = [
|
||||||
|
{ name: 'columnMockName', label: undefined, visible: true },
|
||||||
|
{ name: 'columnMockAddress', label: undefined, visible: false },
|
||||||
|
{ name: 'columnMockId', label: undefined, visible: true },
|
||||||
|
];
|
||||||
|
|
||||||
|
vm.setUserConfigViewData(configuration, false);
|
||||||
|
|
||||||
|
expect(vm.localColumns).toEqual(expectedColumns);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should skip columns based on props', () => {
|
||||||
|
vm.columns = [
|
||||||
|
{ name: 'columnMockName', label: undefined },
|
||||||
|
{ name: 'columnMockId', label: undefined },
|
||||||
|
{ name: 'skippedColumn', label: 'Skipped Column' },
|
||||||
|
];
|
||||||
|
const configuration = {
|
||||||
|
columnMockName: true,
|
||||||
|
skippedColumn: false,
|
||||||
|
columnMockId: true,
|
||||||
|
};
|
||||||
|
const expectedColumns = [
|
||||||
|
{ name: 'columnMockName', label: undefined, visible: true },
|
||||||
|
{ name: 'columnMockId', label: undefined, visible: true },
|
||||||
|
];
|
||||||
|
|
||||||
|
vm.setUserConfigViewData(configuration, false);
|
||||||
|
|
||||||
|
expect(vm.localColumns).toEqual(expectedColumns);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('toggleMarkAll()', () => {
|
||||||
|
it('should set all localColumns to visible=true', () => {
|
||||||
|
vm.localColumns = [
|
||||||
|
{ name: 'columnMockName', visible: false },
|
||||||
|
{ name: 'columnMockId', visible: false },
|
||||||
|
];
|
||||||
|
|
||||||
|
vm.toggleMarkAll(true);
|
||||||
|
|
||||||
|
expect(vm.localColumns.every((col) => col.visible)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set all localColumns to visible=false', () => {
|
||||||
|
vm.localColumns = [
|
||||||
|
{ name: 'columnMockName', visible: true },
|
||||||
|
{ name: 'columnMockId', visible: true },
|
||||||
|
];
|
||||||
|
|
||||||
|
vm.toggleMarkAll(false);
|
||||||
|
|
||||||
|
expect(vm.localColumns.every((col) => col.visible)).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('saveConfig()', () => {
|
||||||
|
it('should call setUserConfigViewData and axios.post with correct params', async () => {
|
||||||
|
const mockAxiosPost = vi.spyOn(axios, 'post').mockResolvedValue({
|
||||||
|
data: [{ id: 1 }],
|
||||||
|
});
|
||||||
|
|
||||||
|
vm.localColumns = [
|
||||||
|
{ name: 'columnMockName', visible: true },
|
||||||
|
{ name: 'columnMockId', visible: false },
|
||||||
|
];
|
||||||
|
|
||||||
|
await vm.saveConfig();
|
||||||
|
|
||||||
|
expect(mockAxiosPost).toHaveBeenCalledWith('UserConfigViews/crud', {
|
||||||
|
creates: [
|
||||||
|
{
|
||||||
|
userFk: vm.user.id,
|
||||||
|
tableCode: vm.tableCode,
|
||||||
|
tableConfig: vm.tableCode,
|
||||||
|
configuration: {
|
||||||
|
columnMockName: true,
|
||||||
|
columnMockId: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -299,11 +299,12 @@ defineExpose({
|
||||||
:url="$props.model"
|
:url="$props.model"
|
||||||
:user-filter="dmsFilter"
|
:user-filter="dmsFilter"
|
||||||
:order="['dmsFk DESC']"
|
:order="['dmsFk DESC']"
|
||||||
:auto-load="true"
|
auto-load
|
||||||
@on-fetch="setData"
|
@on-fetch="setData"
|
||||||
>
|
>
|
||||||
<template #body>
|
<template #body>
|
||||||
<QTable
|
<QTable
|
||||||
|
v-if="rows"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:rows="rows"
|
:rows="rows"
|
||||||
class="full-width q-mt-md"
|
class="full-width q-mt-md"
|
||||||
|
|
|
@ -70,9 +70,6 @@ const handleModelValue = (data) => {
|
||||||
<VnSelectDialog
|
<VnSelectDialog
|
||||||
v-model="modelValue"
|
v-model="modelValue"
|
||||||
option-filter-value="search"
|
option-filter-value="search"
|
||||||
:option-label="
|
|
||||||
(opt) => (typeof modelValue === 'string' ? modelValue : showLabel(opt))
|
|
||||||
"
|
|
||||||
url="Postcodes/filter"
|
url="Postcodes/filter"
|
||||||
@update:model-value="handleModelValue"
|
@update:model-value="handleModelValue"
|
||||||
:use-like="false"
|
:use-like="false"
|
||||||
|
|
|
@ -52,7 +52,8 @@ const sectionValue = computed(() => $props.section ?? $props.dataKey);
|
||||||
const isMainSection = computed(() => {
|
const isMainSection = computed(() => {
|
||||||
const isSame = sectionValue.value == route.name;
|
const isSame = sectionValue.value == route.name;
|
||||||
if (!isSame && arrayData) {
|
if (!isSame && arrayData) {
|
||||||
arrayData.reset(['userParams', 'userFilter']);
|
arrayData.reset(['userParams', 'filter']);
|
||||||
|
arrayData.setCurrentFilter();
|
||||||
}
|
}
|
||||||
return isSame;
|
return isSame;
|
||||||
});
|
});
|
||||||
|
|
|
@ -232,12 +232,15 @@ async function fetchFilter(val) {
|
||||||
} else defaultWhere = { [key]: getVal(val) };
|
} else defaultWhere = { [key]: getVal(val) };
|
||||||
const where = { ...(val ? defaultWhere : {}), ...$props.where };
|
const where = { ...(val ? defaultWhere : {}), ...$props.where };
|
||||||
$props.exprBuilder && Object.assign(where, $props.exprBuilder(key, val));
|
$props.exprBuilder && Object.assign(where, $props.exprBuilder(key, val));
|
||||||
const fetchOptions = { where, include, limit };
|
const filterOptions = { where, include, limit };
|
||||||
if (fields) fetchOptions.fields = fields;
|
if (fields) filterOptions.fields = fields;
|
||||||
if (sortBy) fetchOptions.order = sortBy;
|
if (sortBy) filterOptions.order = sortBy;
|
||||||
arrayData.resetPagination();
|
arrayData.resetPagination();
|
||||||
|
|
||||||
const { data } = await arrayData.applyFilter({ filter: fetchOptions });
|
const { data } = await arrayData.applyFilter(
|
||||||
|
{ filter: filterOptions },
|
||||||
|
{ updateRouter: false }
|
||||||
|
);
|
||||||
setOptions(data);
|
setOptions(data);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ const url = computed(() => {
|
||||||
sort-by="nickname ASC"
|
sort-by="nickname ASC"
|
||||||
>
|
>
|
||||||
<template #prepend v-if="$props.hasAvatar">
|
<template #prepend v-if="$props.hasAvatar">
|
||||||
<VnAvatar :worker-id="value" color="primary" :title="title" />
|
<VnAvatar :worker-id="value" color="primary" v-bind="$attrs" />
|
||||||
</template>
|
</template>
|
||||||
<template #append v-if="$props.hasInfo">
|
<template #append v-if="$props.hasInfo">
|
||||||
<QIcon name="info" class="cursor-pointer">
|
<QIcon name="info" class="cursor-pointer">
|
||||||
|
@ -72,7 +72,8 @@ const url = computed(() => {
|
||||||
{{ scope.opt.nickname }}
|
{{ scope.opt.nickname }}
|
||||||
</QItemLabel>
|
</QItemLabel>
|
||||||
<QItemLabel caption v-else>
|
<QItemLabel caption v-else>
|
||||||
#{{ scope.opt.id }}, {{ scope.opt.nickname }}, {{ scope.opt.code }}
|
#{{ scope.opt.id }}, {{ scope.opt.nickname }},
|
||||||
|
{{ scope.opt.code }}
|
||||||
</QItemLabel>
|
</QItemLabel>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
|
|
|
@ -175,7 +175,7 @@ async function fetch() {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
.header.link:hover {
|
.header.link:hover {
|
||||||
color: lighten($primary, 20%);
|
color: rgba(var(--q-primary), 0.8);
|
||||||
}
|
}
|
||||||
.q-checkbox {
|
.q-checkbox {
|
||||||
& .q-checkbox__label {
|
& .q-checkbox__label {
|
||||||
|
|
|
@ -113,23 +113,20 @@ onMounted(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
async function search() {
|
async function search() {
|
||||||
const staticParams = Object.keys(store.userParams ?? {}).length
|
|
||||||
? store.userParams
|
|
||||||
: store.defaultParams;
|
|
||||||
arrayData.resetPagination();
|
arrayData.resetPagination();
|
||||||
|
|
||||||
const filter = {
|
let filter = { params: { search: searchText.value } };
|
||||||
params: {
|
|
||||||
search: searchText.value,
|
|
||||||
},
|
|
||||||
filter: props.filter,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!props.searchRemoveParams || !searchText.value) {
|
if (!props.searchRemoveParams || !searchText.value) {
|
||||||
filter.params = {
|
filter = {
|
||||||
...staticParams,
|
params: {
|
||||||
|
...store.userParams,
|
||||||
search: searchText.value,
|
search: searchText.value,
|
||||||
|
},
|
||||||
|
filter: store.filter,
|
||||||
};
|
};
|
||||||
|
} else {
|
||||||
|
arrayData.reset(['currentFilter', 'userParams']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.whereFilter) {
|
if (props.whereFilter) {
|
||||||
|
|
|
@ -33,10 +33,11 @@ export function useArrayData(key, userOptions) {
|
||||||
: JSON.parse(params?.filter ?? '{}');
|
: JSON.parse(params?.filter ?? '{}');
|
||||||
delete params.filter;
|
delete params.filter;
|
||||||
|
|
||||||
store.userParams = { ...store.userParams, ...params };
|
store.userParams = params;
|
||||||
store.filter = { ...filter, ...store.userFilter };
|
store.filter = { ...filter, ...store.userFilter };
|
||||||
if (filter?.order) store.order = filter.order;
|
if (filter?.order) store.order = filter.order;
|
||||||
}
|
}
|
||||||
|
setCurrentFilter();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (key && userOptions) setOptions();
|
if (key && userOptions) setOptions();
|
||||||
|
@ -78,11 +79,7 @@ export function useArrayData(key, userOptions) {
|
||||||
|
|
||||||
cancelRequest();
|
cancelRequest();
|
||||||
canceller = new AbortController();
|
canceller = new AbortController();
|
||||||
const { params, limit } = getCurrentFilter();
|
const { params, limit } = setCurrentFilter();
|
||||||
|
|
||||||
store.currentFilter = JSON.parse(JSON.stringify(params));
|
|
||||||
delete store.currentFilter.filter.include;
|
|
||||||
store.currentFilter.filter = JSON.stringify(store.currentFilter.filter);
|
|
||||||
|
|
||||||
let exprFilter;
|
let exprFilter;
|
||||||
if (store?.exprBuilder) {
|
if (store?.exprBuilder) {
|
||||||
|
@ -107,7 +104,7 @@ export function useArrayData(key, userOptions) {
|
||||||
store.hasMoreData = limit && response.data.length >= limit;
|
store.hasMoreData = limit && response.data.length >= limit;
|
||||||
|
|
||||||
if (!append && !isDialogOpened() && updateRouter) {
|
if (!append && !isDialogOpened() && updateRouter) {
|
||||||
if (updateStateParams(response.data)?.redirect) return;
|
if (updateStateParams(response.data)?.redirect && !store.keepData) return;
|
||||||
}
|
}
|
||||||
store.isLoading = false;
|
store.isLoading = false;
|
||||||
canceller = null;
|
canceller = null;
|
||||||
|
@ -142,12 +139,12 @@ export function useArrayData(key, userOptions) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function applyFilter({ filter, params }) {
|
async function applyFilter({ filter, params }, fetchOptions = {}) {
|
||||||
if (filter) store.userFilter = filter;
|
if (filter) store.userFilter = filter;
|
||||||
store.filter = {};
|
store.filter = {};
|
||||||
if (params) store.userParams = { ...params };
|
if (params) store.userParams = { ...params };
|
||||||
|
|
||||||
const response = await fetch({});
|
const response = await fetch(fetchOptions);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,14 +273,14 @@ export function useArrayData(key, userOptions) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCurrentFilter() {
|
function getCurrentFilter() {
|
||||||
|
if (!Object.keys(store.userParams).length)
|
||||||
|
store.userParams = store.defaultParams ?? {};
|
||||||
|
|
||||||
const filter = {
|
const filter = {
|
||||||
limit: store.limit,
|
limit: store.limit,
|
||||||
|
...store.userFilter,
|
||||||
};
|
};
|
||||||
|
|
||||||
let userParams = { ...store.userParams };
|
|
||||||
|
|
||||||
Object.assign(filter, store.userFilter);
|
|
||||||
|
|
||||||
let where;
|
let where;
|
||||||
if (filter?.where || store.filter?.where)
|
if (filter?.where || store.filter?.where)
|
||||||
where = Object.assign(filter?.where ?? {}, store.filter?.where ?? {});
|
where = Object.assign(filter?.where ?? {}, store.filter?.where ?? {});
|
||||||
|
@ -291,7 +288,7 @@ export function useArrayData(key, userOptions) {
|
||||||
filter.where = where;
|
filter.where = where;
|
||||||
const params = { filter };
|
const params = { filter };
|
||||||
|
|
||||||
Object.assign(params, userParams);
|
Object.assign(params, store.userParams);
|
||||||
if (params.filter) params.filter.skip = store.skip;
|
if (params.filter) params.filter.skip = store.skip;
|
||||||
if (store?.order && typeof store?.order == 'string') store.order = [store.order];
|
if (store?.order && typeof store?.order == 'string') store.order = [store.order];
|
||||||
if (store.order?.length) params.filter.order = [...store.order];
|
if (store.order?.length) params.filter.order = [...store.order];
|
||||||
|
@ -300,6 +297,14 @@ export function useArrayData(key, userOptions) {
|
||||||
return { filter, params, limit: filter.limit };
|
return { filter, params, limit: filter.limit };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setCurrentFilter() {
|
||||||
|
const { params, limit } = getCurrentFilter();
|
||||||
|
store.currentFilter = JSON.parse(JSON.stringify(params));
|
||||||
|
delete store.currentFilter.filter.include;
|
||||||
|
store.currentFilter.filter = JSON.stringify(store.currentFilter.filter);
|
||||||
|
return { params, limit };
|
||||||
|
}
|
||||||
|
|
||||||
function processData(data, { map = true, append = true }) {
|
function processData(data, { map = true, append = true }) {
|
||||||
if (!append) {
|
if (!append) {
|
||||||
store.data = [];
|
store.data = [];
|
||||||
|
@ -333,6 +338,7 @@ export function useArrayData(key, userOptions) {
|
||||||
applyFilter,
|
applyFilter,
|
||||||
addFilter,
|
addFilter,
|
||||||
getCurrentFilter,
|
getCurrentFilter,
|
||||||
|
setCurrentFilter,
|
||||||
addFilterWhere,
|
addFilterWhere,
|
||||||
addOrder,
|
addOrder,
|
||||||
deleteOrder,
|
deleteOrder,
|
||||||
|
|
|
@ -29,8 +29,12 @@ export function useFilterParams(key) {
|
||||||
orders.value = orderObject;
|
orders.value = orderObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setUserParams(watchedParams) {
|
function setUserParams(watchedParams = {}) {
|
||||||
if (!watchedParams || Object.keys(watchedParams).length == 0) return;
|
if (Object.keys(watchedParams).length == 0) {
|
||||||
|
params.value = {};
|
||||||
|
orders.value = {};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof watchedParams == 'string') watchedParams = JSON.parse(watchedParams);
|
if (typeof watchedParams == 'string') watchedParams = JSON.parse(watchedParams);
|
||||||
if (typeof watchedParams?.filter == 'string')
|
if (typeof watchedParams?.filter == 'string')
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
import { Dark, Quasar } from 'quasar';
|
import { Dark, Quasar } from 'quasar';
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { localeEquivalence } from 'src/i18n/index';
|
||||||
|
import quasarLang from 'src/utils/quasarLang';
|
||||||
|
|
||||||
const { t, locale } = useI18n();
|
const { t, locale } = useI18n();
|
||||||
|
|
||||||
|
@ -12,18 +14,9 @@ const userLocale = computed({
|
||||||
set(value) {
|
set(value) {
|
||||||
locale.value = value;
|
locale.value = value;
|
||||||
|
|
||||||
if (value === 'en') value = 'en-GB';
|
value = localeEquivalence[value] ?? value;
|
||||||
|
|
||||||
// FIXME: Dynamic imports from absolute paths are not compatible with vite:
|
quasarLang(value);
|
||||||
// https://github.com/rollup/plugins/tree/master/packages/dynamic-import-vars#limitations
|
|
||||||
try {
|
|
||||||
const langList = import.meta.glob('../../node_modules/quasar/lang/*.mjs');
|
|
||||||
langList[`../../node_modules/quasar/lang/${value}.mjs`]().then((lang) => {
|
|
||||||
Quasar.lang.set(lang.default);
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -90,6 +90,11 @@ const columns = computed(() => [
|
||||||
field: (row) => row.foreignValue,
|
field: (row) => row.foreignValue,
|
||||||
align: 'left',
|
align: 'left',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'total',
|
||||||
|
label: 'Total',
|
||||||
|
align: 'left',
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const filter = {
|
const filter = {
|
||||||
|
@ -131,6 +136,24 @@ function autocompleteExpense(evt, row, col) {
|
||||||
|
|
||||||
expenseRef.value.vnSelectDialogRef.vnSelectRef.toggleOption(lookup);
|
expenseRef.value.vnSelectDialogRef.vnSelectRef.toggleOption(lookup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const taxableBaseTotal = computed(() => {
|
||||||
|
return getTotal(invoiceInFormRef.value.formData, 'taxableBase', );
|
||||||
|
});
|
||||||
|
|
||||||
|
const taxRateTotal = computed(() => {
|
||||||
|
return getTotal(invoiceInFormRef.value.formData, null, {
|
||||||
|
cb: taxRate,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const combinedTotal = computed(() => {
|
||||||
|
return +taxableBaseTotal.value + +taxRateTotal.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<FetchData
|
<FetchData
|
||||||
|
@ -272,26 +295,20 @@ function autocompleteExpense(evt, row, col) {
|
||||||
<QTd />
|
<QTd />
|
||||||
<QTd />
|
<QTd />
|
||||||
<QTd>
|
<QTd>
|
||||||
{{ getTotal(rows, 'taxableBase', { currency: 'default' }) }}
|
{{ toCurrency(taxableBaseTotal) }}
|
||||||
</QTd>
|
</QTd>
|
||||||
<QTd />
|
<QTd />
|
||||||
<QTd />
|
<QTd />
|
||||||
<QTd>
|
<QTd>
|
||||||
{{
|
{{ toCurrency(taxRateTotal) }}
|
||||||
getTotal(rows, null, { cb: taxRate, currency: 'default' })
|
</QTd>
|
||||||
}}</QTd
|
<QTd />
|
||||||
>
|
|
||||||
<QTd>
|
<QTd>
|
||||||
<template v-if="isNotEuro(invoiceIn.currency.code)">
|
{{ toCurrency(combinedTotal) }}
|
||||||
{{
|
|
||||||
getTotal(rows, 'foreignValue', {
|
|
||||||
currency: invoiceIn.currency.code,
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
</template>
|
|
||||||
</QTd>
|
</QTd>
|
||||||
</QTr>
|
</QTr>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #item="props">
|
<template #item="props">
|
||||||
<div class="q-pa-xs col-xs-12 col-sm-6 grid-style-transition">
|
<div class="q-pa-xs col-xs-12 col-sm-6 grid-style-transition">
|
||||||
<QCard bordered flat class="q-my-xs">
|
<QCard bordered flat class="q-my-xs">
|
||||||
|
|
|
@ -7,6 +7,7 @@ import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
|
||||||
import VnInput from 'src/components/common/VnInput.vue';
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
import VnInputDate from 'components/common/VnInputDate.vue';
|
import VnInputDate from 'components/common/VnInputDate.vue';
|
||||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
|
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
@ -81,15 +82,12 @@ const getGroupedStates = (data) => {
|
||||||
</QItem>
|
</QItem>
|
||||||
<QItem>
|
<QItem>
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<VnSelect
|
<VnSelectWorker
|
||||||
:label="t('Salesperson')"
|
:label="t('globals.salesPerson')"
|
||||||
v-model="params.salesPersonFk"
|
v-model="params.salesPersonFk"
|
||||||
url="Workers/activeWithInheritedRole"
|
:params="{
|
||||||
:where="{ role: 'salesPerson' }"
|
departmentCodes: ['VT'],
|
||||||
option-value="id"
|
}"
|
||||||
option-label="firstName"
|
|
||||||
:use-like="false"
|
|
||||||
sort-by="firstName ASC"
|
|
||||||
dense
|
dense
|
||||||
outlined
|
outlined
|
||||||
rounded
|
rounded
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
const langList = import.meta.glob('../../node_modules/quasar/lang/*.js');
|
||||||
|
import { Quasar } from 'quasar';
|
||||||
|
|
||||||
|
export default function (value) {
|
||||||
|
try {
|
||||||
|
langList[`../../node_modules/quasar/lang/${value}.js`]().then((lang) => {
|
||||||
|
Quasar.lang.set(lang.default);
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,7 +9,6 @@ describe('InvoiceOut summary', () => {
|
||||||
cy.viewport(1920, 1080);
|
cy.viewport(1920, 1080);
|
||||||
cy.login('developer');
|
cy.login('developer');
|
||||||
cy.visit(`/#/invoice-out/list`);
|
cy.visit(`/#/invoice-out/list`);
|
||||||
cy.typeSearchbar('{enter}');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should generate the invoice PDF', () => {
|
it('should generate the invoice PDF', () => {
|
||||||
|
@ -19,13 +18,12 @@ describe('InvoiceOut summary', () => {
|
||||||
cy.dataCy('VnConfirm_confirm').click();
|
cy.dataCy('VnConfirm_confirm').click();
|
||||||
cy.checkNotification('The invoice PDF document has been regenerated');
|
cy.checkNotification('The invoice PDF document has been regenerated');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should refund the invoice ', () => {
|
it('should refund the invoice ', () => {
|
||||||
cy.typeSearchbar('T1111111{enter}');
|
cy.typeSearchbar('T1111111{enter}');
|
||||||
cy.dataCy('descriptor-more-opts').click();
|
cy.dataCy('descriptor-more-opts').click();
|
||||||
cy.get('.q-menu > .q-list > :nth-child(7)').click();
|
cy.get('.q-menu > .q-list > :nth-child(7)').click();
|
||||||
cy.get('#q-portal--menu--3 > .q-menu > .q-list > :nth-child(2)').click();
|
cy.get('#q-portal--menu--3 > .q-menu > .q-list > :nth-child(2)').click();
|
||||||
cy.checkNotification('The following refund ticket have been created 1000000');
|
cy.checkNotification('The following refund ticket have been created');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should delete an invoice ', () => {
|
it('should delete an invoice ', () => {
|
||||||
|
@ -35,8 +33,7 @@ describe('InvoiceOut summary', () => {
|
||||||
cy.dataCy('VnConfirm_confirm').click();
|
cy.dataCy('VnConfirm_confirm').click();
|
||||||
cy.checkNotification('InvoiceOut deleted');
|
cy.checkNotification('InvoiceOut deleted');
|
||||||
});
|
});
|
||||||
// https://redmine.verdnatura.es/issues/8415
|
it('should transfer the invoice ', () => {
|
||||||
it.skip('should transfer the invoice ', () => {
|
|
||||||
cy.typeSearchbar('T1111111{enter}');
|
cy.typeSearchbar('T1111111{enter}');
|
||||||
cy.dataCy('descriptor-more-opts').click();
|
cy.dataCy('descriptor-more-opts').click();
|
||||||
cy.get('.q-menu > .q-list > :nth-child(1)').click();
|
cy.get('.q-menu > .q-list > :nth-child(1)').click();
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
const c = require('croppie');
|
|
||||||
|
|
||||||
describe('TicketSale', () => {
|
describe('TicketSale', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.login('developer');
|
cy.login('developer');
|
||||||
|
|
|
@ -49,12 +49,12 @@ describe('VnLocation', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.viewport(1280, 720);
|
cy.viewport(1280, 720);
|
||||||
cy.login('developer');
|
cy.login('developer');
|
||||||
cy.visit('/#/worker/create', { timeout: 5000 });
|
cy.visit('/#/worker/list', { timeout: 5000 });
|
||||||
|
cy.dataCy('vnTableCreateBtn').click();
|
||||||
cy.waitForElement('.q-card');
|
cy.waitForElement('.q-card');
|
||||||
cy.get(inputLocation).click();
|
cy.get(inputLocation).click();
|
||||||
});
|
});
|
||||||
// https://redmine.verdnatura.es/issues/8436
|
it('Show all options', function () {
|
||||||
it.skip('Show all options', function () {
|
|
||||||
cy.get(locationOptions).should('have.length.at.least', 5);
|
cy.get(locationOptions).should('have.length.at.least', 5);
|
||||||
});
|
});
|
||||||
it('input filter location as "al"', function () {
|
it('input filter location as "al"', function () {
|
||||||
|
|
|
@ -10,8 +10,8 @@ describe('WorkerList', () => {
|
||||||
|
|
||||||
it('should open the worker summary', () => {
|
it('should open the worker summary', () => {
|
||||||
cy.get(inputName).type('jessica{enter}');
|
cy.get(inputName).type('jessica{enter}');
|
||||||
cy.get(searchBtn).click();
|
|
||||||
cy.intercept('GET', /\/api\/Workers\/summary+/).as('worker');
|
cy.intercept('GET', /\/api\/Workers\/summary+/).as('worker');
|
||||||
|
cy.get(searchBtn).click();
|
||||||
cy.wait('@worker').then(() =>
|
cy.wait('@worker').then(() =>
|
||||||
cy.get(descriptorTitle).should('include.text', 'Jessica')
|
cy.get(descriptorTitle).should('include.text', 'Jessica')
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue