Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 6067-vverifyEmailSection

This commit is contained in:
Alex Moreno 2023-10-18 07:47:25 +02:00
commit 4193876917
12 changed files with 140 additions and 43 deletions

2
package-lock.json generated
View File

@ -1,6 +1,6 @@
{
"name": "salix-front",
"version": "23.36.01",
"version": "23.40.01",
"lockfileVersion": 3,
"requires": true,
"packages": {

View File

@ -1,6 +1,6 @@
{
"name": "salix-front",
"version": "23.36.01",
"version": "23.40.01",
"description": "Salix frontend",
"productName": "Salix",
"author": "Verdnatura",
@ -9,7 +9,7 @@
"lint": "eslint --ext .js,.vue ./",
"format": "prettier --write \"**/*.{js,vue,scss,html,md,json}\" --ignore-path .gitignore",
"test:e2e": "cypress open",
"test:e2e:ci": "cypress run --browser chromium",
"test:e2e:ci": "cd ../salix && gulp docker && cd ../salix-front && cypress run --browser chromium",
"test": "echo \"See package.json => scripts for available tests.\" && exit 0",
"test:unit": "vitest",
"test:unit:ci": "vitest run"

View File

@ -46,7 +46,7 @@ const onResponseError = (error) => {
message = responseError.message;
}
switch (response.status) {
switch (response?.status) {
case 500:
message = 'errors.statusInternalServerError';
break;
@ -58,7 +58,7 @@ const onResponseError = (error) => {
break;
}
if (session.isLoggedIn() && response.status === 401) {
if (session.isLoggedIn() && response?.status === 401) {
session.destroy();
const hash = window.location.hash;
const url = hash.slice(1);

View File

@ -8,6 +8,7 @@ import { useStateStore } from 'stores/useStateStore';
import VnPaginate from 'components/ui/VnPaginate.vue';
import VnConfirm from 'components/ui/VnConfirm.vue';
import SkeletonTable from 'components/ui/SkeletonTable.vue';
import { tMobile } from 'src/composables/tMobile';
const quasar = useQuasar();
const stateStore = useStateStore();
@ -62,9 +63,10 @@ const hasChanges = ref(false);
const originalData = ref();
const vnPaginateRef = ref();
const formData = ref();
const saveButtonRef = ref(null);
const formUrl = computed(() => $props.url);
const emit = defineEmits(['onFetch', 'update:selected']);
const emit = defineEmits(['onFetch', 'update:selected', 'saveChanges']);
defineExpose({
reload,
@ -73,12 +75,9 @@ defineExpose({
onSubmit,
reset,
hasChanges,
saveChanges,
});
function tMobile(...args) {
if (!quasar.platform.is.mobile) return t(...args);
}
async function fetch(data) {
if (data && Array.isArray(data)) {
let $index = 0;
@ -135,6 +134,7 @@ async function saveChanges(data) {
hasChanges.value = false;
isLoading.value = false;
emit('saveChanges', data);
}
async function insert() {
@ -269,7 +269,7 @@ watch(formUrl, async () => {
<SkeletonTable v-if="!formData" />
<Teleport to="#st-actions" v-if="stateStore?.isSubToolbarShown()">
<QBtnGroup push class="q-gutter-x-sm">
<slot name="moreActions" />
<slot name="moreBeforeActions" />
<QBtn
:label="tMobile('globals.remove')"
color="primary"
@ -292,6 +292,7 @@ watch(formUrl, async () => {
/>
<QBtn
:label="tMobile('globals.save')"
ref="saveButtonRef"
color="primary"
icon="save"
@click="onSubmit"
@ -299,6 +300,7 @@ watch(formUrl, async () => {
:title="t('globals.save')"
v-if="$props.defaultSave"
/>
<slot name="moreAfterActions" />
</QBtnGroup>
</Teleport>
<QInnerLoading

View File

@ -19,6 +19,8 @@ const $props = defineProps({
const { optionLabel, options } = toRefs($props);
const myOptions = ref([]);
const myOptionsOriginal = ref([]);
const vnSelectRef = ref(null);
function setOptions(data) {
myOptions.value = JSON.parse(JSON.stringify(data));
myOptionsOriginal.value = JSON.parse(JSON.stringify(data));
@ -29,6 +31,7 @@ const filter = (val, options) => {
const search = val.toLowerCase();
if (val === '') return options;
return options.filter((row) => {
const id = row.id;
const name = row[$props.optionLabel].toLowerCase();
@ -41,9 +44,17 @@ const filter = (val, options) => {
};
const filterHandler = (val, update) => {
update(() => {
myOptions.value = filter(val, myOptionsOriginal.value);
});
update(
() => {
myOptions.value = filter(val, myOptionsOriginal.value);
},
(ref) => {
if (val !== '' && ref.options.length > 0) {
ref.setOptionIndex(-1);
ref.moveOptionSelection(1, true);
}
}
);
};
watch(options, (newValue) => {
@ -70,7 +81,15 @@ const value = computed({
map-options
use-input
@filter="filterHandler"
clearable
clear-icon="close"
/>
hide-selected
fill-input
ref="vnSelectRef"
>
<template #append>
<QIcon name="close" @click.stop="value = null" class="cursor-pointer" />
</template>
<template v-for="(_, slotName) in $slots" #[slotName]="slotData">
<slot :name="slotName" v-bind="slotData" />
</template>
</QSelect>
</template>

View File

@ -140,14 +140,6 @@ async function onLoad(...params) {
{{ t('No data to display') }}
</h5>
</div>
<div
v-if="store.data && store.data.length === 0 && !isLoading"
class="info-row q-pa-md text-center"
>
<h5>
{{ t('No results found') }}
</h5>
</div>
<div
v-if="props.skeleton && props.autoLoad && !store.data"
class="card-list q-gutter-y-md"

View File

@ -0,0 +1,8 @@
import { useQuasar } from 'quasar';
import { useI18n } from 'vue-i18n';
export function tMobile(...args) {
const quasar = useQuasar();
const { t } = useI18n();
if (!quasar.platform.is.mobile) return t(...args);
}

View File

@ -1,12 +1,15 @@
<script setup>
import { ref, computed } from 'vue';
import { ref, computed, onMounted } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
import CrudModel from 'components/CrudModel.vue';
import FetchData from 'components/FetchData.vue';
import VnSelectFilter from 'components/common/VnSelectFilter.vue';
import { getUrl } from 'composables/getUrl';
import { tMobile } from 'composables/tMobile';
const route = useRoute();
const { t } = useI18n();
const claimDevelopmentForm = ref();
@ -16,6 +19,12 @@ const claimResponsibles = ref([]);
const claimRedeliveries = ref([]);
const workers = ref([]);
const selected = ref([]);
const insertButtonRef = ref();
let salixUrl;
onMounted(async () => {
salixUrl = await getUrl(`claim/${route.params.id}`);
});
const developmentsFilter = {
fields: [
@ -43,6 +52,7 @@ const columns = computed(() => [
model: 'claimReasonFk',
optionValue: 'id',
optionLabel: 'description',
tabIndex: 1,
},
{
name: 'claimResult',
@ -54,6 +64,7 @@ const columns = computed(() => [
model: 'claimResultFk',
optionValue: 'id',
optionLabel: 'description',
tabIndex: 2,
},
{
name: 'claimResponsible',
@ -65,6 +76,7 @@ const columns = computed(() => [
model: 'claimResponsibleFk',
optionValue: 'id',
optionLabel: 'description',
tabIndex: 3,
},
{
name: 'worker',
@ -75,6 +87,7 @@ const columns = computed(() => [
model: 'workerFk',
optionValue: 'id',
optionLabel: 'nickname',
tabIndex: 4,
},
{
name: 'claimRedelivery',
@ -86,8 +99,13 @@ const columns = computed(() => [
model: 'claimRedeliveryFk',
optionValue: 'id',
optionLabel: 'description',
tabIndex: 5,
},
]);
function goToAction() {
location.href = `${salixUrl}/action`;
}
</script>
<template>
<FetchData
@ -115,8 +133,9 @@ const columns = computed(() => [
auto-load
/>
<FetchData
url="Workers/activeWithInheritedRole"
:where="{ role: 'employee' }"
url="Workers/search"
:where="{ active: 1 }"
order="name ASC"
@on-fetch="(data) => (workers = data)"
auto-load
/>
@ -129,6 +148,8 @@ const columns = computed(() => [
:data-required="{ claimFk: route.params.id }"
v-model:selected="selected"
auto-load
@save-changes="goToAction"
:default-save="false"
>
<template #body="{ rows }">
<QTable
@ -142,19 +163,40 @@ const columns = computed(() => [
:grid="$q.screen.lt.md"
>
<template #body-cell="{ row, col }">
<QTd auto-width>
<QTd
auto-width
@keyup.ctrl.enter.stop="claimDevelopmentForm.saveChanges()"
>
<VnSelectFilter
:label="col.label"
v-model="row[col.model]"
:options="col.options"
:option-value="col.optionValue"
:option-label="col.optionLabel"
/>
:autofocus="col.tabIndex == 1"
input-debounce="0"
>
<template #option="scope" v-if="col.name == 'worker'">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>{{ scope.opt?.name }}</QItemLabel>
<QItemLabel caption>
{{ scope.opt?.nickname }}
{{ scope.opt?.code }}
</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelectFilter>
</QTd>
</template>
<template #item="props">
<div class="q-pa-xs col-xs-12 col-sm-6 grid-style-transition">
<QCard bordered flat>
<QCard
bordered
flat
@keyup.ctrl.enter.stop="claimDevelopmentForm?.saveChanges()"
>
<QCardSection>
<QCheckbox v-model="props.selected" dense />
</QCardSection>
@ -169,6 +211,8 @@ const columns = computed(() => [
:option-value="col.optionValue"
:option-label="col.optionLabel"
dense
input-debounce="0"
:autofocus="col.tabIndex == 1"
/>
</QItemSection>
</QItem>
@ -178,9 +222,28 @@ const columns = computed(() => [
</template>
</QTable>
</template>
<template #moreAfterActions>
<QBtn
:label="tMobile('globals.save')"
ref="saveButtonRef"
color="primary"
icon="save"
:disable="!claimDevelopmentForm?.hasChanges"
@click="claimDevelopmentForm?.onSubmit"
:title="t('globals.save')"
/>
</template>
</CrudModel>
<QPageSticky position="bottom-right" :offset="[25, 25]">
<QBtn fab color="primary" icon="add" @click="claimDevelopmentForm.insert()" />
<QBtn
ref="insertButtonRef"
fab
color="primary"
icon="add"
@click="claimDevelopmentForm.insert()"
@keydown.ctrl.enter.stop="claimDevelopmentForm.saveChanges()"
@keydown.enter.stop
/>
</QPageSticky>
</template>

View File

@ -40,7 +40,6 @@ const claimLinesForm = ref();
const claim = ref(null);
async function onFetchClaim(data) {
claim.value = data;
fetchMana();
}
@ -147,8 +146,11 @@ function showImportDialog() {
quasar
.dialog({
component: ClaimLinesImport,
componentProps: {
ticketId: claim.value.ticketFk,
},
})
.onOk(() => arrayData.refresh());
.onOk(() => claimLinesForm.value.reload());
}
</script>
<template>

View File

@ -14,6 +14,13 @@ const route = useRoute();
const quasar = useQuasar();
const { t } = useI18n();
const $props = defineProps({
ticketId: {
type: Number,
required: true,
},
});
const columns = computed(() => [
{
name: 'delivered',
@ -99,7 +106,7 @@ function cancel() {
</script>
<template>
<FetchData
url="Sales/getClaimableFromTicket?ticketFk=16"
:url="`Sales/getClaimableFromTicket?ticketFk=${$props.ticketId}`"
@on-fetch="(data) => (claimableSales = data)"
auto-load
/>

View File

@ -13,15 +13,17 @@ describe('ClaimDevelopment', () => {
it('should reset line', () => {
cy.selectOption(firstLineReason, 'Novato');
cy.resetCard();
cy.getValue(firstLineReason).should('have.text', 'Prisas');
cy.getValue(firstLineReason).should('have.value', 'Prisas');
});
it('should edit line', () => {
cy.selectOption(firstLineReason, 'Novato');
cy.saveCard();
cy.reload();
cy.getValue(firstLineReason).should('have.text', 'Novato');
cy.saveCard();
cy.login('developer');
cy.visit(`/#/claim/${claimId}/development`);
cy.getValue(firstLineReason).should('have.value', 'Novato');
//Restart data
cy.selectOption(firstLineReason, 'Prisas');
@ -29,13 +31,16 @@ describe('ClaimDevelopment', () => {
});
it('should add and remove new line', () => {
//add row
cy.addCard();
cy.get(thirdRow).should('exist');
const rowData = [false, 'Novato', 'Roces', 'Compradores', 'employeeNick', 'Tour'];
cy.fillRow(thirdRow, rowData);
cy.saveCard();
cy.login('developer');
cy.visit(`/#/claim/${claimId}/development`);
cy.validateRow(thirdRow, rowData);
cy.reload();

View File

@ -54,7 +54,7 @@ Cypress.Commands.add('getValue', (selector) => {
else if ($el.find('.q-select__dropdown-icon').length) {
return cy.get(
selector +
'> .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native > span'
'> .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native > input'
);
} else {
// Puedes añadir un log o lanzar un error si el elemento no es reconocido
@ -76,7 +76,6 @@ Cypress.Commands.add('checkOption', (selector) => {
// Global buttons
Cypress.Commands.add('saveCard', () => {
cy.get('[title="Save"]').click();
cy.get('[title="Save"]').should('have.class', 'disabled');
});
Cypress.Commands.add('resetCard', () => {
cy.get('[title="Reset"]').click();
@ -123,7 +122,7 @@ Cypress.Commands.add('validateRow', (rowSelector, expectedValues) => {
cy.getValue(`:nth-child(${index + 1})`).should(`${prefix}be.checked`);
continue;
}
cy.getValue(`:nth-child(${index + 1})`).should('have.text', value);
cy.getValue(`:nth-child(${index + 1})`).should('have.value', value);
}
});
});