Merge branch 'dev' of https: refs #8463//gitea.verdnatura.es/verdnatura/salix-front into 8463-CardDescriptor_useCard
gitea/salix-front/pipeline/pr-dev This commit is unstable
Details
gitea/salix-front/pipeline/pr-dev This commit is unstable
Details
This commit is contained in:
commit
4c980cb805
|
@ -115,6 +115,7 @@ pipeline {
|
|||
steps {
|
||||
script {
|
||||
sh 'rm -f junit/e2e-*.xml'
|
||||
sh 'rm -rf test/cypress/screenshots'
|
||||
env.COMPOSE_TAG = PROTECTED_BRANCH.contains(env.CHANGE_TARGET) ? env.CHANGE_TARGET : 'dev'
|
||||
|
||||
def image = docker.build('lilium-dev', '-f docs/Dockerfile.dev docs')
|
||||
|
@ -125,13 +126,14 @@ pipeline {
|
|||
sh "docker-compose ${env.COMPOSE_PARAMS} up -d"
|
||||
|
||||
image.inside("--network ${env.COMPOSE_PROJECT}_default -e CI -e TZ --init") {
|
||||
sh 'sh test/cypress/cypressParallel.sh 2'
|
||||
sh 'sh test/cypress/cypressParallel.sh 1'
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
sh "docker-compose ${env.COMPOSE_PARAMS} down -v"
|
||||
archiveArtifacts artifacts: 'test/cypress/screenshots/**/*', allowEmptyArchive: true
|
||||
junit(
|
||||
testResults: 'junit/e2e-*.xml',
|
||||
allowEmptyResults: true
|
||||
|
|
|
@ -140,7 +140,7 @@ const $props = defineProps({
|
|||
},
|
||||
dataCy: {
|
||||
type: String,
|
||||
default: 'vn-table',
|
||||
default: 'vnTable',
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -684,7 +684,7 @@ const rowCtrlClickFunction = computed(() => {
|
|||
@update:selected="emit('update:selected', $event)"
|
||||
@selection="(details) => handleSelection(details, rows)"
|
||||
:hide-selected-banner="true"
|
||||
:data-cy="$props.dataCy ?? 'vnTable'"
|
||||
:data-cy
|
||||
>
|
||||
<template #top-left v-if="!$props.withoutHeader">
|
||||
<slot name="top-left"> </slot>
|
||||
|
@ -781,6 +781,7 @@ const rowCtrlClickFunction = computed(() => {
|
|||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
"
|
||||
:data-cy="`vnTableCell_${col.name}`"
|
||||
>
|
||||
<slot
|
||||
:name="`column-${col.name}`"
|
||||
|
|
|
@ -27,7 +27,11 @@ const checkboxModel = computed({
|
|||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<QCheckbox v-bind="$attrs" v-model="checkboxModel" />
|
||||
<QCheckbox
|
||||
v-bind="$attrs"
|
||||
v-model="checkboxModel"
|
||||
:data-cy="$attrs['data-cy'] ?? `vnCheckbox${$attrs['label'] ?? ''}`"
|
||||
/>
|
||||
<QIcon
|
||||
v-if="info"
|
||||
v-bind="$attrs"
|
||||
|
|
|
@ -107,7 +107,7 @@ const manageDate = (date) => {
|
|||
@click="isPopupOpen = !isPopupOpen"
|
||||
@keydown="isPopupOpen = false"
|
||||
hide-bottom-space
|
||||
:data-cy="$attrs.dataCy ?? $attrs.label + '_inputDate'"
|
||||
:data-cy="($attrs['data-cy'] ?? $attrs.label) + '_inputDate'"
|
||||
>
|
||||
<template #append>
|
||||
<QIcon
|
||||
|
|
|
@ -10,7 +10,7 @@ import { useColor } from 'src/composables/useColor';
|
|||
import { useCapitalize } from 'src/composables/useCapitalize';
|
||||
import { useValidator } from 'src/composables/useValidator';
|
||||
import VnAvatar from '../ui/VnAvatar.vue';
|
||||
import VnJsonValue from '../common/VnJsonValue.vue';
|
||||
import VnLogValue from './VnLogValue.vue';
|
||||
import FetchData from '../FetchData.vue';
|
||||
import VnSelect from './VnSelect.vue';
|
||||
import VnUserLink from '../ui/VnUserLink.vue';
|
||||
|
@ -560,10 +560,11 @@ watch(
|
|||
value.nameI18n
|
||||
}}:
|
||||
</span>
|
||||
<VnJsonValue
|
||||
<VnLogValue
|
||||
:value="
|
||||
value.val.val
|
||||
"
|
||||
:name="value.name"
|
||||
/>
|
||||
</QItem>
|
||||
</QCardSection>
|
||||
|
@ -614,7 +615,11 @@ watch(
|
|||
>
|
||||
{{ prop.nameI18n }}:
|
||||
</span>
|
||||
<VnJsonValue :value="prop.val.val" />
|
||||
<VnLogValue
|
||||
:value="prop.val.val"
|
||||
:name="prop.name"
|
||||
/>
|
||||
<VnIconLink />
|
||||
<span
|
||||
v-if="
|
||||
propIndex <
|
||||
|
@ -642,8 +647,9 @@ watch(
|
|||
{{ prop.nameI18n }}:
|
||||
</span>
|
||||
<span v-if="log.action == 'update'">
|
||||
<VnJsonValue
|
||||
<VnLogValue
|
||||
:value="prop.old.val"
|
||||
:name="prop.name"
|
||||
/>
|
||||
<span
|
||||
v-if="prop.old.id"
|
||||
|
@ -652,8 +658,9 @@ watch(
|
|||
#{{ prop.old.id }}
|
||||
</span>
|
||||
→
|
||||
<VnJsonValue
|
||||
<VnLogValue
|
||||
:value="prop.val.val"
|
||||
:name="prop.name"
|
||||
/>
|
||||
<span
|
||||
v-if="prop.val.id"
|
||||
|
@ -663,8 +670,9 @@ watch(
|
|||
</span>
|
||||
</span>
|
||||
<span v-else="prop.old.val">
|
||||
<VnJsonValue
|
||||
<VnLogValue
|
||||
:value="prop.val.val"
|
||||
:name="prop.name"
|
||||
/>
|
||||
<span
|
||||
v-if="prop.old.id"
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
<script setup>
|
||||
import { useDescriptorStore } from 'src/stores/useDescriptorStore';
|
||||
import VnJsonValue from './VnJsonValue.vue';
|
||||
import { computed } from 'vue';
|
||||
const descriptorStore = useDescriptorStore();
|
||||
|
||||
const $props = defineProps({
|
||||
name: { type: [String], default: undefined },
|
||||
});
|
||||
|
||||
const descriptor = computed(() => descriptorStore.has($props.name));
|
||||
</script>
|
||||
<template>
|
||||
<VnJsonValue v-bind="$attrs" />
|
||||
<QIcon
|
||||
name="launch"
|
||||
class="link"
|
||||
v-if="$attrs.value && descriptor"
|
||||
:data-cy="'iconLaunch-' + $props.name"
|
||||
/>
|
||||
<component :is="descriptor" :id="$attrs.value" v-if="$attrs.value && descriptor" />
|
||||
</template>
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { ref, toRefs, computed, watch, onMounted, useAttrs } from 'vue';
|
||||
import { ref, toRefs, computed, watch, onMounted, useAttrs, nextTick } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useArrayData } from 'src/composables/useArrayData';
|
||||
import { useRequired } from 'src/composables/useRequired';
|
||||
|
@ -247,6 +247,7 @@ async function fetchFilter(val) {
|
|||
}
|
||||
|
||||
async function filterHandler(val, update) {
|
||||
if (isLoading.value) return update();
|
||||
if (!val && lastVal.value === val) {
|
||||
lastVal.value = val;
|
||||
return update();
|
||||
|
@ -294,6 +295,7 @@ async function onScroll({ to, direction, from, index }) {
|
|||
await arrayData.loadMore();
|
||||
setOptions(arrayData.store.data);
|
||||
vnSelectRef.value.scrollTo(lastIndex);
|
||||
await nextTick();
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import VnLogValue from 'src/components/common/VnLogValue.vue';
|
||||
import { createWrapper } from 'app/test/vitest/helper';
|
||||
|
||||
const buildComponent = (props) => {
|
||||
return createWrapper(VnLogValue, {
|
||||
props,
|
||||
global: {},
|
||||
}).wrapper;
|
||||
};
|
||||
|
||||
describe('VnLogValue', () => {
|
||||
const id = 1;
|
||||
it('renders without descriptor', async () => {
|
||||
expect(getIcon('inventFk').exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('renders with descriptor', async () => {
|
||||
expect(getIcon('claimFk').text()).toBe('launch');
|
||||
});
|
||||
|
||||
function getIcon(name) {
|
||||
const wrapper = buildComponent({ value: { val: id }, name });
|
||||
return wrapper.find('.q-icon');
|
||||
}
|
||||
});
|
|
@ -25,9 +25,9 @@ const $props = defineProps({
|
|||
type: String,
|
||||
default: 'md-width',
|
||||
},
|
||||
module: {
|
||||
toModule: {
|
||||
type: String,
|
||||
default: '',
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -39,10 +39,11 @@ const { viewSummary } = useSummaryDialog();
|
|||
const DESCRIPTOR_PROXY = 'DescriptorProxy';
|
||||
const moduleName = ref();
|
||||
const isSameModuleName = route.matched[1].meta.moduleName !== moduleName.value;
|
||||
defineExpose({ getData });
|
||||
|
||||
function getName() {
|
||||
let name = $props.module;
|
||||
if (name.includes(DESCRIPTOR_PROXY)) {
|
||||
let name = $props.dataKey;
|
||||
if ($props.dataKey.includes(DESCRIPTOR_PROXY)) {
|
||||
name = name.split(DESCRIPTOR_PROXY)[0];
|
||||
}
|
||||
return name;
|
||||
|
@ -76,6 +77,9 @@ const emit = defineEmits(['onFetch']);
|
|||
|
||||
const iconModule = computed(() => {
|
||||
moduleName.value = getName();
|
||||
if ($props.toModule) {
|
||||
return router.getRoutes().find((r) => r.name === $props.toModule.name).meta.icon;
|
||||
}
|
||||
if (isSameModuleName) {
|
||||
return router.options.routes[1].children.find((r) => r.name === moduleName.value)
|
||||
?.meta?.icon;
|
||||
|
@ -86,9 +90,10 @@ const iconModule = computed(() => {
|
|||
|
||||
const toModule = computed(() => {
|
||||
moduleName.value = getName();
|
||||
if ($props.toModule) return $props.toModule;
|
||||
if (isSameModuleName) {
|
||||
return router.options.routes[1].children.find((r) => r.name === moduleName.value)
|
||||
?.children[0]?.redirect;
|
||||
?.redirect;
|
||||
} else {
|
||||
return route.matched[1].path.split('/').length > 2
|
||||
? route.matched[1].redirect
|
||||
|
|
|
@ -249,7 +249,7 @@ const getLocale = (label) => {
|
|||
:key="chip.label"
|
||||
:removable="!unremovableParams?.includes(chip.label)"
|
||||
@remove="remove(chip.label)"
|
||||
data-cy="vnFilterPanelChip"
|
||||
:data-cy="`vnFilterPanelChip_${chip.label}`"
|
||||
>
|
||||
<slot
|
||||
name="tags"
|
||||
|
|
|
@ -28,7 +28,7 @@ function copyValueText() {
|
|||
const val = computed(() => $props.value);
|
||||
</script>
|
||||
<template>
|
||||
<div class="vn-label-value">
|
||||
<div class="vn-label-value" :data-cy="`${$attrs['data-cy'] ?? 'vnLv'}${label ?? ''}`">
|
||||
<QCheckbox
|
||||
v-if="typeof value === 'boolean'"
|
||||
v-model="val"
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
{{ $t('components.cardDescriptor.moreOptions') }}
|
||||
</QTooltip>
|
||||
<QMenu ref="menuRef" data-cy="descriptor-more-opts-menu">
|
||||
<QList>
|
||||
<QList data-cy="descriptor-more-opts_list">
|
||||
<slot name="menu" :menu-ref="$refs.menuRef" />
|
||||
</QList>
|
||||
</QMenu>
|
||||
|
|
|
@ -892,6 +892,8 @@ components:
|
|||
VnLv:
|
||||
copyText: '{copyValue} has been copied to the clipboard'
|
||||
iban_tooltip: 'IBAN: ES21 1234 5678 90 0123456789'
|
||||
VnNotes:
|
||||
clientWithoutPhone: 'The following clients do not have a phone number and the message will not be sent to them: {clientWithoutPhone}'
|
||||
weekdays:
|
||||
sun: Sunday
|
||||
mon: Monday
|
||||
|
|
|
@ -976,6 +976,8 @@ components:
|
|||
VnLv:
|
||||
copyText: '{copyValue} se ha copiado al portapepeles'
|
||||
iban_tooltip: 'IBAN: ES21 1234 5678 90 0123456789'
|
||||
VnNotes:
|
||||
clientWithoutPhone: 'Estos clientes no tienen asociado número de télefono y el sms no les será enviado: {clientWithoutPhone}'
|
||||
weekdays:
|
||||
sun: Domingo
|
||||
mon: Lunes
|
||||
|
|
|
@ -53,6 +53,7 @@ const removeAlias = () => {
|
|||
:url="`MailAliases/${entityId}`"
|
||||
data-key="Alias"
|
||||
title="alias"
|
||||
:to-module="{ name: 'AccountAlias' }"
|
||||
>
|
||||
<template #menu>
|
||||
<QItem v-ripple clickable @click="removeAlias()">
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<script setup>
|
||||
import AccountDescriptor from './AccountDescriptor.vue';
|
||||
import AccountSummary from './AccountSummary.vue';
|
||||
</script>
|
||||
<template>
|
||||
<QPopupProxy style="max-width: 10px">
|
||||
<AccountDescriptor
|
||||
v-if="$attrs.id"
|
||||
v-bind="$attrs.id"
|
||||
:summary="AccountSummary"
|
||||
:proxy-render="true"
|
||||
/>
|
||||
</QPopupProxy>
|
||||
</template>
|
|
@ -37,6 +37,7 @@ const removeRole = async () => {
|
|||
:filter="{ where: { id: entityId } }"
|
||||
data-key="Role"
|
||||
:summary="$props.summary"
|
||||
:to-module="{ name: 'AccountRoles' }"
|
||||
>
|
||||
<template #menu>
|
||||
<QItem v-ripple clickable @click="removeRole()">
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<script setup>
|
||||
import ClaimDescriptor from './ClaimDescriptor.vue';
|
||||
import ClaimSummary from './ClaimSummary.vue';
|
||||
</script>
|
||||
<template>
|
||||
<QPopupProxy style="max-width: 10px">
|
||||
<ClaimDescriptor
|
||||
v-if="$attrs.id"
|
||||
v-bind="$attrs.id"
|
||||
:summary="ClaimSummary"
|
||||
:proxy-render="true"
|
||||
/>
|
||||
</QPopupProxy>
|
||||
</template>
|
|
@ -121,25 +121,40 @@ function deleteFile(dmsFk) {
|
|||
hide-selected
|
||||
:is-clearable="false"
|
||||
:required="true"
|
||||
data-cy="invoiceInBasicDataSupplier"
|
||||
/>
|
||||
<VnInput
|
||||
clearable
|
||||
clear-icon="close"
|
||||
:label="t('invoiceIn.supplierRef')"
|
||||
v-model="data.supplierRef"
|
||||
data-cy="invoiceInBasicDataSupplierRef"
|
||||
/>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<VnInputDate :label="t('Expedition date')" v-model="data.issued" />
|
||||
<VnInputDate
|
||||
:label="t('Expedition date')"
|
||||
v-model="data.issued"
|
||||
data-cy="invoiceInBasicDataIssued"
|
||||
/>
|
||||
<VnInputDate
|
||||
:label="t('Operation date')"
|
||||
v-model="data.operated"
|
||||
autofocus
|
||||
data-cy="invoiceInBasicDataOperated"
|
||||
/>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<VnInputDate :label="t('Entry date')" v-model="data.bookEntried" />
|
||||
<VnInputDate :label="t('Accounted date')" v-model="data.booked" />
|
||||
<VnInputDate
|
||||
:label="t('Entry date')"
|
||||
v-model="data.bookEntried"
|
||||
data-cy="invoiceInBasicDatabookEntried"
|
||||
/>
|
||||
<VnInputDate
|
||||
:label="t('Accounted date')"
|
||||
v-model="data.booked"
|
||||
data-cy="invoiceInBasicDataBooked"
|
||||
/>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<VnSelect
|
||||
|
@ -149,7 +164,7 @@ function deleteFile(dmsFk) {
|
|||
option-value="id"
|
||||
option-label="id"
|
||||
:filter-options="['id', 'name']"
|
||||
data-cy="UnDeductibleVatSelect"
|
||||
data-cy="invoiceInBasicDataDeductibleExpenseFk"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
|
@ -182,6 +197,7 @@ function deleteFile(dmsFk) {
|
|||
padding="xs"
|
||||
round
|
||||
@click="downloadFile(data.dmsFk)"
|
||||
data-cy="invoiceInBasicDataDmsDownload"
|
||||
/>
|
||||
<QBtn
|
||||
:class="{
|
||||
|
@ -197,6 +213,7 @@ function deleteFile(dmsFk) {
|
|||
documentDialogRef.dms = data.dms;
|
||||
}
|
||||
"
|
||||
data-cy="invoiceInBasicDataDmsEdit"
|
||||
>
|
||||
<QTooltip>{{ t('Edit document') }}</QTooltip>
|
||||
</QBtn>
|
||||
|
@ -210,6 +227,7 @@ function deleteFile(dmsFk) {
|
|||
padding="xs"
|
||||
round
|
||||
@click="deleteFile(data.dmsFk)"
|
||||
data-cy="invoiceInBasicDataDmsDelete"
|
||||
/>
|
||||
</div>
|
||||
<QBtn
|
||||
|
@ -224,7 +242,7 @@ function deleteFile(dmsFk) {
|
|||
delete documentDialogRef.dms;
|
||||
}
|
||||
"
|
||||
data-cy="dms-create"
|
||||
data-cy="invoiceInBasicDataDmsAdd"
|
||||
>
|
||||
<QTooltip>{{ t('Create document') }}</QTooltip>
|
||||
</QBtn>
|
||||
|
@ -237,9 +255,9 @@ function deleteFile(dmsFk) {
|
|||
:label="t('Currency')"
|
||||
v-model="data.currencyFk"
|
||||
:options="currencies"
|
||||
option-value="id"
|
||||
option-label="code"
|
||||
sort-by="id"
|
||||
data-cy="invoiceInBasicDataCurrencyFk"
|
||||
/>
|
||||
|
||||
<VnSelect
|
||||
|
@ -249,8 +267,8 @@ function deleteFile(dmsFk) {
|
|||
:label="t('Company')"
|
||||
v-model="data.companyFk"
|
||||
:options="companies"
|
||||
option-value="id"
|
||||
option-label="code"
|
||||
data-cy="invoiceInBasicDataCompanyFk"
|
||||
/>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
|
@ -260,6 +278,7 @@ function deleteFile(dmsFk) {
|
|||
:options="sageWithholdings"
|
||||
option-value="id"
|
||||
option-label="withholding"
|
||||
data-cy="invoiceInBasicDataWithholdingSageFk"
|
||||
/>
|
||||
</VnRow>
|
||||
</template>
|
||||
|
|
|
@ -1,22 +1,16 @@
|
|||
<script setup>
|
||||
import { ref, computed, capitalize } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useArrayData } from 'src/composables/useArrayData';
|
||||
import CrudModel from 'src/components/CrudModel.vue';
|
||||
import FetchData from 'src/components/FetchData.vue';
|
||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
|
||||
const arrayData = useArrayData();
|
||||
const invoiceIn = computed(() => arrayData.store.data);
|
||||
const invoiceInCorrectionRef = ref();
|
||||
const filter = {
|
||||
include: { relation: 'invoiceIn' },
|
||||
where: { correctingFk: route.params.id },
|
||||
};
|
||||
const columns = computed(() => [
|
||||
{
|
||||
name: 'origin',
|
||||
|
@ -92,7 +86,8 @@ const requiredFieldRule = (val) => val || t('globals.requiredField');
|
|||
v-if="invoiceIn"
|
||||
data-key="InvoiceInCorrection"
|
||||
url="InvoiceInCorrections"
|
||||
:filter="filter"
|
||||
:user-filter="{ include: { relation: 'invoiceIn' } }"
|
||||
:filter="{ where: { correctingFk: $route.params.id } }"
|
||||
auto-load
|
||||
primary-key="correctingFk"
|
||||
:default-remove="false"
|
||||
|
@ -115,6 +110,7 @@ const requiredFieldRule = (val) => val || t('globals.requiredField');
|
|||
:option-label="col.optionLabel"
|
||||
:disable="row.invoiceIn.isBooked"
|
||||
:filter-options="['description']"
|
||||
data-cy="invoiceInCorrective_type"
|
||||
>
|
||||
<template #option="{ opt, itemProps }">
|
||||
<QItem v-bind="itemProps">
|
||||
|
@ -137,6 +133,7 @@ const requiredFieldRule = (val) => val || t('globals.requiredField');
|
|||
:rules="[requiredFieldRule]"
|
||||
:filter-options="['code', 'description']"
|
||||
:disable="row.invoiceIn.isBooked"
|
||||
data-cy="invoiceInCorrective_class"
|
||||
>
|
||||
<template #option="{ opt, itemProps }">
|
||||
<QItem v-bind="itemProps">
|
||||
|
@ -161,6 +158,7 @@ const requiredFieldRule = (val) => val || t('globals.requiredField');
|
|||
:option-label="col.optionLabel"
|
||||
:rules="[requiredFieldRule]"
|
||||
:disable="row.invoiceIn.isBooked"
|
||||
data-cy="invoiceInCorrective_reason"
|
||||
/>
|
||||
</QTd>
|
||||
</template>
|
||||
|
|
|
@ -17,10 +17,6 @@ const { t } = useI18n();
|
|||
const cardDescriptorRef = ref();
|
||||
const entityId = computed(() => $props.id || +currentRoute.value.params.id);
|
||||
const totalAmount = ref();
|
||||
const config = ref();
|
||||
const cplusRectificationTypes = ref([]);
|
||||
const siiTypeInvoiceIns = ref([]);
|
||||
const invoiceCorrectionTypes = ref([]);
|
||||
const invoiceInCorrection = reactive({ correcting: [], corrected: null });
|
||||
const routes = reactive({
|
||||
getSupplier: (id) => {
|
||||
|
@ -30,7 +26,7 @@ const routes = reactive({
|
|||
return {
|
||||
name: 'InvoiceInList',
|
||||
query: {
|
||||
params: JSON.stringify({ supplierFk: id }),
|
||||
table: JSON.stringify({ supplierFk: id }),
|
||||
},
|
||||
};
|
||||
},
|
||||
|
@ -39,7 +35,7 @@ const routes = reactive({
|
|||
return {
|
||||
name: 'InvoiceInList',
|
||||
query: {
|
||||
params: JSON.stringify({ correctedFk: entityId.value }),
|
||||
table: JSON.stringify({ correctedFk: entityId.value }),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -108,7 +104,7 @@ async function setInvoiceCorrection(id) {
|
|||
<VnLv :label="t('invoiceIn.list.amount')" :value="toCurrency(totalAmount)" />
|
||||
<VnLv :label="t('invoiceIn.list.supplier')">
|
||||
<template #value>
|
||||
<span class="link">
|
||||
<span class="link" data-cy="invoiceInDescriptor_supplier">
|
||||
{{ entity?.supplier?.nickname }}
|
||||
<SupplierDescriptorProxy :id="entity?.supplierFk" />
|
||||
</span>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { ref, computed, toRefs, reactive } from 'vue';
|
||||
import { ref, computed, toRefs, reactive, onBeforeMount } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useQuasar } from 'quasar';
|
||||
|
@ -111,10 +111,9 @@ async function cloneInvoice() {
|
|||
}
|
||||
|
||||
const isAgricultural = () => {
|
||||
if (!config.value) return false;
|
||||
return (
|
||||
invoiceIn.value?.supplier?.sageFarmerWithholdingFk ===
|
||||
config?.value[0]?.sageWithholdingFk
|
||||
invoiceIn.value?.supplier?.sageWithholdingFk ==
|
||||
config.value?.sageFarmerWithholdingFk
|
||||
);
|
||||
};
|
||||
function showPdfInvoice() {
|
||||
|
@ -153,162 +152,183 @@ const createInvoiceInCorrection = async () => {
|
|||
);
|
||||
push({ path: `/invoice-in/${correctingId}/summary` });
|
||||
};
|
||||
|
||||
onBeforeMount(async () => {
|
||||
config.value = (
|
||||
await axios.get('invoiceinConfigs/findOne', {
|
||||
params: { fields: ['sageFarmerWithholdingFk'] },
|
||||
})
|
||||
).data;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData
|
||||
url="InvoiceCorrectionTypes"
|
||||
@on-fetch="(data) => (invoiceCorrectionTypes = data)"
|
||||
auto-load
|
||||
/>
|
||||
<FetchData
|
||||
url="CplusRectificationTypes"
|
||||
@on-fetch="(data) => (cplusRectificationTypes = data)"
|
||||
auto-load
|
||||
/>
|
||||
<FetchData
|
||||
url="SiiTypeInvoiceIns"
|
||||
:where="{ code: { like: 'R%' } }"
|
||||
@on-fetch="(data) => (siiTypeInvoiceIns = data)"
|
||||
auto-load
|
||||
/>
|
||||
<FetchData
|
||||
url="InvoiceInConfigs"
|
||||
:where="{ fields: ['sageWithholdingFk'] }"
|
||||
auto-load
|
||||
@on-fetch="(data) => (config = data)"
|
||||
/>
|
||||
<InvoiceInToBook>
|
||||
<template #content="{ book }">
|
||||
<QItem
|
||||
v-if="!invoice?.isBooked && canEditProp('toBook')"
|
||||
v-ripple
|
||||
clickable
|
||||
@click="book(entityId)"
|
||||
<template v-if="config">
|
||||
<FetchData
|
||||
url="InvoiceCorrectionTypes"
|
||||
@on-fetch="(data) => (invoiceCorrectionTypes = data)"
|
||||
auto-load
|
||||
/>
|
||||
<FetchData
|
||||
url="CplusRectificationTypes"
|
||||
@on-fetch="(data) => (cplusRectificationTypes = data)"
|
||||
auto-load
|
||||
/>
|
||||
<FetchData
|
||||
url="SiiTypeInvoiceIns"
|
||||
:where="{ code: { like: 'R%' } }"
|
||||
@on-fetch="(data) => (siiTypeInvoiceIns = data)"
|
||||
auto-load
|
||||
/>
|
||||
<InvoiceInToBook>
|
||||
<template #content="{ book }">
|
||||
<QItem
|
||||
v-if="!invoice?.isBooked && canEditProp('toBook')"
|
||||
v-ripple
|
||||
clickable
|
||||
@click="book(entityId)"
|
||||
>
|
||||
<QItemSection>{{ t('invoiceIn.descriptorMenu.book') }}</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</InvoiceInToBook>
|
||||
<QItem
|
||||
v-if="invoice?.isBooked && canEditProp('toUnbook')"
|
||||
v-ripple
|
||||
clickable
|
||||
@click="triggerMenu('unbook')"
|
||||
>
|
||||
<QItemSection>
|
||||
{{ t('invoiceIn.descriptorMenu.unbook') }}
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem
|
||||
v-if="canEditProp('deleteById')"
|
||||
v-ripple
|
||||
clickable
|
||||
@click="triggerMenu('delete')"
|
||||
>
|
||||
<QItemSection>{{ t('invoiceIn.descriptorMenu.deleteInvoice') }}</QItemSection>
|
||||
</QItem>
|
||||
<QItem
|
||||
v-if="canEditProp('clone')"
|
||||
v-ripple
|
||||
clickable
|
||||
@click="triggerMenu('clone')"
|
||||
>
|
||||
<QItemSection>{{ t('invoiceIn.descriptorMenu.cloneInvoice') }}</QItemSection>
|
||||
</QItem>
|
||||
<QItem v-if="isAgricultural()" v-ripple clickable @click="triggerMenu('showPdf')">
|
||||
<QItemSection>{{
|
||||
t('invoiceIn.descriptorMenu.showAgriculturalPdf')
|
||||
}}</QItemSection>
|
||||
</QItem>
|
||||
<QItem v-if="isAgricultural()" v-ripple clickable @click="triggerMenu('sendPdf')">
|
||||
<QItemSection
|
||||
>{{ t('invoiceIn.descriptorMenu.sendAgriculturalPdf') }}...</QItemSection
|
||||
>
|
||||
<QItemSection>{{ t('invoiceIn.descriptorMenu.book') }}</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</InvoiceInToBook>
|
||||
<QItem
|
||||
v-if="invoice?.isBooked && canEditProp('toUnbook')"
|
||||
v-ripple
|
||||
clickable
|
||||
@click="triggerMenu('unbook')"
|
||||
>
|
||||
<QItemSection>
|
||||
{{ t('invoiceIn.descriptorMenu.unbook') }}
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem
|
||||
v-if="canEditProp('deleteById')"
|
||||
v-ripple
|
||||
clickable
|
||||
@click="triggerMenu('delete')"
|
||||
>
|
||||
<QItemSection>{{ t('invoiceIn.descriptorMenu.deleteInvoice') }}</QItemSection>
|
||||
</QItem>
|
||||
<QItem v-if="canEditProp('clone')" v-ripple clickable @click="triggerMenu('clone')">
|
||||
<QItemSection>{{ t('invoiceIn.descriptorMenu.cloneInvoice') }}</QItemSection>
|
||||
</QItem>
|
||||
<QItem v-if="isAgricultural()" v-ripple clickable @click="triggerMenu('showPdf')">
|
||||
<QItemSection>{{
|
||||
t('invoiceIn.descriptorMenu.showAgriculturalPdf')
|
||||
}}</QItemSection>
|
||||
</QItem>
|
||||
<QItem v-if="isAgricultural()" v-ripple clickable @click="triggerMenu('sendPdf')">
|
||||
<QItemSection
|
||||
>{{ t('invoiceIn.descriptorMenu.sendAgriculturalPdf') }}...</QItemSection
|
||||
</QItem>
|
||||
<QItem
|
||||
v-if="!invoiceInCorrection.corrected"
|
||||
v-ripple
|
||||
clickable
|
||||
@click="triggerMenu('correct')"
|
||||
data-cy="createCorrectiveItem"
|
||||
>
|
||||
</QItem>
|
||||
<QItem
|
||||
v-if="!invoiceInCorrection.corrected"
|
||||
v-ripple
|
||||
clickable
|
||||
@click="triggerMenu('correct')"
|
||||
data-cy="createCorrectiveItem"
|
||||
>
|
||||
<QItemSection
|
||||
>{{ t('invoiceIn.descriptorMenu.createCorrective') }}...</QItemSection
|
||||
<QItemSection
|
||||
>{{ t('invoiceIn.descriptorMenu.createCorrective') }}...</QItemSection
|
||||
>
|
||||
</QItem>
|
||||
<QItem
|
||||
v-if="invoice.dmsFk"
|
||||
v-ripple
|
||||
clickable
|
||||
@click="downloadFile(invoice.dmsFk)"
|
||||
>
|
||||
</QItem>
|
||||
<QItem v-if="invoice.dmsFk" v-ripple clickable @click="downloadFile(invoice.dmsFk)">
|
||||
<QItemSection>{{ t('components.smartCard.downloadFile') }}</QItemSection>
|
||||
</QItem>
|
||||
<QDialog ref="correctionDialogRef">
|
||||
<QCard>
|
||||
<QCardSection>
|
||||
<QItem class="q-px-none">
|
||||
<span class="text-primary text-h6 full-width">
|
||||
{{ t('Create rectificative invoice') }}
|
||||
</span>
|
||||
<QBtn icon="close" flat round dense v-close-popup />
|
||||
</QItem>
|
||||
</QCardSection>
|
||||
<QCardSection>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<QInput
|
||||
:label="t('Original invoice')"
|
||||
v-model="entityId"
|
||||
readonly
|
||||
/>
|
||||
<VnSelect
|
||||
:label="`${useCapitalize(t('globals.class'))}`"
|
||||
v-model="correctionFormData.invoiceClass"
|
||||
:options="siiTypeInvoiceIns"
|
||||
option-value="id"
|
||||
option-label="code"
|
||||
:required="true"
|
||||
/>
|
||||
</QItemSection>
|
||||
<QItemSection>
|
||||
<VnSelect
|
||||
:label="`${useCapitalize(t('globals.type'))}`"
|
||||
v-model="correctionFormData.invoiceType"
|
||||
:options="cplusRectificationTypes"
|
||||
option-value="id"
|
||||
option-label="description"
|
||||
:required="true"
|
||||
>
|
||||
<template #option="{ itemProps, opt }">
|
||||
<QItem v-bind="itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel
|
||||
>{{ opt.id }} -
|
||||
{{ opt.description }}</QItemLabel
|
||||
>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<div></div>
|
||||
</template>
|
||||
</VnSelect>
|
||||
<QItemSection>{{ t('components.smartCard.downloadFile') }}</QItemSection>
|
||||
</QItem>
|
||||
<QDialog ref="correctionDialogRef">
|
||||
<QCard data-cy="correctiveInvoiceDialog">
|
||||
<QCardSection>
|
||||
<QItem class="q-px-none">
|
||||
<span class="text-primary text-h6 full-width">
|
||||
{{ t('Create rectificative invoice') }}
|
||||
</span>
|
||||
<QBtn icon="close" flat round dense v-close-popup />
|
||||
</QItem>
|
||||
</QCardSection>
|
||||
<QCardSection>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<QInput
|
||||
:label="t('Original invoice')"
|
||||
v-model="entityId"
|
||||
readonly
|
||||
/>
|
||||
<VnSelect
|
||||
:label="`${useCapitalize(t('globals.class'))}`"
|
||||
v-model="correctionFormData.invoiceClass"
|
||||
:options="siiTypeInvoiceIns"
|
||||
option-value="id"
|
||||
option-label="code"
|
||||
:required="true"
|
||||
data-cy="invoiceInDescriptorMenu_class"
|
||||
/>
|
||||
</QItemSection>
|
||||
<QItemSection>
|
||||
<VnSelect
|
||||
:label="`${useCapitalize(t('globals.type'))}`"
|
||||
v-model="correctionFormData.invoiceType"
|
||||
:options="cplusRectificationTypes"
|
||||
option-value="id"
|
||||
option-label="description"
|
||||
:required="true"
|
||||
data-cy="invoiceInDescriptorMenu_type"
|
||||
>
|
||||
<template #option="{ itemProps, opt }">
|
||||
<QItem v-bind="itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel
|
||||
>{{ opt.id }} -
|
||||
{{ opt.description }}</QItemLabel
|
||||
>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<div></div>
|
||||
</template>
|
||||
</VnSelect>
|
||||
|
||||
<VnSelect
|
||||
:label="`${useCapitalize(t('globals.reason'))}`"
|
||||
v-model="correctionFormData.invoiceReason"
|
||||
:options="invoiceCorrectionTypes"
|
||||
option-value="id"
|
||||
option-label="description"
|
||||
:required="true"
|
||||
/>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</QCardSection>
|
||||
<QCardActions class="justify-end q-mr-sm">
|
||||
<QBtn flat :label="t('globals.close')" color="primary" v-close-popup />
|
||||
<QBtn
|
||||
:label="t('globals.save')"
|
||||
color="primary"
|
||||
v-close-popup
|
||||
@click="createInvoiceInCorrection"
|
||||
:disable="isNotFilled"
|
||||
/>
|
||||
</QCardActions>
|
||||
</QCard>
|
||||
</QDialog>
|
||||
<VnSelect
|
||||
:label="`${useCapitalize(t('globals.reason'))}`"
|
||||
v-model="correctionFormData.invoiceReason"
|
||||
:options="invoiceCorrectionTypes"
|
||||
option-value="id"
|
||||
option-label="description"
|
||||
:required="true"
|
||||
data-cy="invoiceInDescriptorMenu_reason"
|
||||
/>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</QCardSection>
|
||||
<QCardActions class="justify-end q-mr-sm">
|
||||
<QBtn
|
||||
flat
|
||||
:label="t('globals.close')"
|
||||
color="primary"
|
||||
v-close-popup
|
||||
/>
|
||||
<QBtn
|
||||
:label="t('globals.save')"
|
||||
color="primary"
|
||||
v-close-popup
|
||||
@click="createInvoiceInCorrection"
|
||||
:disable="isNotFilled"
|
||||
data-cy="saveCorrectiveInvoice"
|
||||
/>
|
||||
</QCardActions>
|
||||
</QCard>
|
||||
</QDialog>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
en:
|
||||
isNotLinked: The entry {bookEntry} has been deleted with {accountingEntries} entries
|
||||
|
|
|
@ -198,6 +198,7 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
|
|||
color="orange-11"
|
||||
text-color="black"
|
||||
@click="book(entityId)"
|
||||
data-cy="invoiceInSummary_book"
|
||||
/>
|
||||
</template>
|
||||
</InvoiceIntoBook>
|
||||
|
@ -219,7 +220,7 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
|
|||
:value="entity.supplier?.name"
|
||||
>
|
||||
<template #value>
|
||||
<span class="link">
|
||||
<span class="link" data-cy="invoiceInSummary_supplier">
|
||||
{{ entity.supplier?.name }}
|
||||
<SupplierDescriptorProxy :id="entity.supplierFk" />
|
||||
</span>
|
||||
|
|
|
@ -202,6 +202,9 @@ function setCursor(ref) {
|
|||
:option-label="col.optionLabel"
|
||||
:filter-options="['id', 'name']"
|
||||
:tooltip="t('Create a new expense')"
|
||||
:acls="[
|
||||
{ model: 'Expense', props: '*', accessType: 'WRITE' },
|
||||
]"
|
||||
@keydown.tab.prevent="
|
||||
autocompleteExpense(
|
||||
$event,
|
||||
|
|
|
@ -7,6 +7,7 @@ import VnInputNumber from 'src/components/common/VnInputNumber.vue';
|
|||
import { dateRange } from 'src/filters';
|
||||
import { date } from 'quasar';
|
||||
import VnSelectSupplier from 'src/components/common/VnSelectSupplier.vue';
|
||||
import VnCheckbox from 'src/components/common/VnCheckbox.vue';
|
||||
|
||||
defineProps({ dataKey: { type: String, required: true } });
|
||||
const dateFormat = 'YYYY-MM-DDTHH:mm:ss.SSSZ';
|
||||
|
@ -147,13 +148,13 @@ function handleDaysAgo(params, daysAgo) {
|
|||
</QItem>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<QCheckbox
|
||||
<VnCheckbox
|
||||
:label="$t('invoiceIn.isBooked')"
|
||||
v-model="params.isBooked"
|
||||
@update:model-value="searchFn()"
|
||||
toggle-indeterminate
|
||||
/>
|
||||
<QCheckbox
|
||||
<VnCheckbox
|
||||
:label="getLocale('params.correctingFk')"
|
||||
v-model="params.correctingFk"
|
||||
@update:model-value="searchFn()"
|
||||
|
|
|
@ -4,7 +4,7 @@ import { useQuasar } from 'quasar';
|
|||
import { useI18n } from 'vue-i18n';
|
||||
import VnConfirm from 'src/components/ui/VnConfirm.vue';
|
||||
import { useArrayData } from 'src/composables/useArrayData';
|
||||
import qs from 'qs';
|
||||
|
||||
const { notify, dialog } = useQuasar();
|
||||
const { t } = useI18n();
|
||||
|
||||
|
@ -61,17 +61,15 @@ async function checkToBook(id) {
|
|||
}
|
||||
|
||||
async function toBook(id) {
|
||||
let type = 'positive';
|
||||
let message = t('globals.dataSaved');
|
||||
|
||||
let err = false;
|
||||
try {
|
||||
await axios.post(`InvoiceIns/${id}/toBook`);
|
||||
store.data.isBooked = true;
|
||||
} catch (e) {
|
||||
type = 'negative';
|
||||
message = t('It was not able to book the invoice');
|
||||
err = true;
|
||||
throw e;
|
||||
} finally {
|
||||
notify({ type, message });
|
||||
if (!err) notify({ type: 'positive', message: t('globals.dataSaved') });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -30,6 +30,7 @@ const entityId = computed(() => {
|
|||
:filter="filter"
|
||||
title="code"
|
||||
data-key="ItemType"
|
||||
:to-module="{ name: 'ItemTypeList' }"
|
||||
>
|
||||
<template #body="{ entity }">
|
||||
<VnLv :label="$t('itemType.shared.code')" :value="entity.code" />
|
||||
|
|
|
@ -26,6 +26,7 @@ const card = computed(() => store.data);
|
|||
:url="`Agencies/${entityId}`"
|
||||
:title="card?.name"
|
||||
:subtitle="props.id"
|
||||
:to-module="{ name: 'RouteAgency' }"
|
||||
>
|
||||
<template #body="{ entity: agency }">
|
||||
<VnLv :label="t('globals.name')" :value="agency.name" />
|
||||
|
|
|
@ -35,6 +35,7 @@ const entityId = computed(() => {
|
|||
:filter="filter"
|
||||
data-key="Roadmap"
|
||||
:summary="summary"
|
||||
:to-module="{ name: 'RouteRoadmap' }"
|
||||
>
|
||||
<template #body="{ entity }">
|
||||
<VnLv :label="t('Roadmap')" :value="entity?.name" />
|
||||
|
|
|
@ -199,12 +199,22 @@ const confirmRemove = (ticket) => {
|
|||
const openSmsDialog = async () => {
|
||||
const clientsId = [];
|
||||
const clientsPhone = [];
|
||||
|
||||
const clientWithoutPhone = [];
|
||||
for (let ticket of selectedRows.value) {
|
||||
clientsId.push(ticket?.clientFk);
|
||||
const { data: client } = await axios.get(`Clients/${ticket?.clientFk}`);
|
||||
if (!client.phone) {
|
||||
clientWithoutPhone.push(ticket?.clientFk);
|
||||
continue;
|
||||
}
|
||||
clientsPhone.push(client.phone);
|
||||
}
|
||||
if (clientWithoutPhone.length) {
|
||||
quasar.notify({
|
||||
type: 'warning',
|
||||
message: t('components.VnNotes.clientWithoutPhone', { clientWithoutPhone }),
|
||||
});
|
||||
}
|
||||
|
||||
quasar.dialog({
|
||||
component: SendSmsDialog,
|
||||
|
|
|
@ -24,6 +24,7 @@ const entityId = computed(() => props.id || route.params.id);
|
|||
:url="`Vehicles/${entityId}`"
|
||||
data-key="Vehicle"
|
||||
title="numberPlate"
|
||||
:to-module="{ name: 'RouteVehicle' }"
|
||||
>
|
||||
<template #menu="{ entity }">
|
||||
<QItem
|
||||
|
|
|
@ -21,7 +21,7 @@ const entityId = computed(() => props.id || route.params.id);
|
|||
:url="`Parkings/${entityId}`"
|
||||
title="code"
|
||||
:filter="filter"
|
||||
:to-module="{ name: 'ParkingList' }"
|
||||
:to-module="{ name: 'ParkingMain' }"
|
||||
>
|
||||
<template #body="{ entity }">
|
||||
<VnLv :label="$t('globals.code')" :value="entity.code" />
|
||||
|
|
|
@ -190,9 +190,3 @@ const handlePhotoUpdated = (evt = false) => {
|
|||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
|
||||
<i18n>
|
||||
es:
|
||||
Click to allow the user to be disabled: Marcar para deshabilitar
|
||||
Click to exclude the user from getting disabled: Marcar para no deshabilitar
|
||||
</i18n>
|
||||
|
|
|
@ -63,3 +63,8 @@ const showChangePasswordDialog = () => {
|
|||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
<i18n>
|
||||
es:
|
||||
Click to allow the user to be disabled: Marcar para deshabilitar
|
||||
Click to exclude the user from getting disabled: Marcar para no deshabilitar
|
||||
</i18n>
|
||||
|
|
|
@ -16,6 +16,7 @@ const $props = defineProps({
|
|||
v-if="$props.id"
|
||||
:id="$props.id"
|
||||
:summary="DepartmentSummary"
|
||||
data-key="DepartmentDescriptorProxy"
|
||||
/>
|
||||
</QPopupProxy>
|
||||
</template>
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
<script setup>
|
||||
import { ref, computed, onMounted, reactive } from 'vue';
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useQuasar } from 'quasar';
|
||||
import axios from 'axios';
|
||||
import moment from 'moment';
|
||||
|
||||
import VnRow from 'components/ui/VnRow.vue';
|
||||
import FormPopup from 'components/FormPopup.vue';
|
||||
import ZoneLocationsTree from './ZoneLocationsTree.vue';
|
||||
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
||||
|
||||
import { useArrayData } from 'src/composables/useArrayData';
|
||||
import { useVnConfirm } from 'composables/useVnConfirm';
|
||||
import axios from 'axios';
|
||||
import { toDateFormat } from 'src/filters/date';
|
||||
|
||||
const props = defineProps({
|
||||
date: {
|
||||
|
@ -34,18 +36,25 @@ const props = defineProps({
|
|||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
isMasiveEdit: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
zoneIds: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['onSubmit', 'closeForm']);
|
||||
|
||||
const quasar = useQuasar();
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
const { openConfirmationModal } = useVnConfirm();
|
||||
|
||||
const isNew = computed(() => props.isNewMode);
|
||||
const dated = reactive(props.date);
|
||||
const dated = ref(props.date || Date.vnNew());
|
||||
const tickedNodes = ref();
|
||||
|
||||
const _excludeType = ref('all');
|
||||
const excludeType = computed({
|
||||
get: () => _excludeType.value,
|
||||
|
@ -63,16 +72,46 @@ const exclusionGeoCreate = async () => {
|
|||
geoIds: tickedNodes.value,
|
||||
};
|
||||
await axios.post('Zones/exclusionGeo', params);
|
||||
quasar.notify({
|
||||
message: t('globals.dataSaved'),
|
||||
type: 'positive',
|
||||
});
|
||||
await refetchEvents();
|
||||
};
|
||||
|
||||
const exclusionCreate = async () => {
|
||||
const url = `Zones/${route.params.id}/exclusions`;
|
||||
const defaultMonths = await axios.get('ZoneConfigs');
|
||||
const nMonths = defaultMonths.data[0].defaultMonths;
|
||||
const body = {
|
||||
dated,
|
||||
dated: dated.value,
|
||||
};
|
||||
if (isNew.value || props.event?.type) await axios.post(`${url}`, [body]);
|
||||
else await axios.put(`${url}/${props.event?.id}`, body);
|
||||
const zoneIds = props.zoneIds?.length ? props.zoneIds : [route.params.id];
|
||||
for (const id of zoneIds) {
|
||||
const url = `Zones/${id}/exclusions`;
|
||||
let today = moment(dated.value);
|
||||
let lastDay = today.clone().add(nMonths, 'months').endOf('month');
|
||||
|
||||
const { data } = await axios.get(`Zones/getEventsFiltered`, {
|
||||
params: {
|
||||
zoneFk: id,
|
||||
started: today,
|
||||
ended: lastDay,
|
||||
},
|
||||
});
|
||||
const existsEvent = data.events.find(
|
||||
(event) => toDateFormat(event.dated) === toDateFormat(dated.value),
|
||||
);
|
||||
if (existsEvent) {
|
||||
await axios.delete(`Zones/${existsEvent?.zoneFk}/events/${existsEvent?.id}`);
|
||||
}
|
||||
|
||||
if (isNew.value || props.event?.type) await axios.post(`${url}`, [body]);
|
||||
else await axios.put(`${url}/${props.event?.id}`, body);
|
||||
}
|
||||
quasar.notify({
|
||||
message: t('globals.dataSaved'),
|
||||
type: 'positive',
|
||||
});
|
||||
await refetchEvents();
|
||||
};
|
||||
|
||||
|
@ -129,6 +168,7 @@ onMounted(() => {
|
|||
:label="t('eventsExclusionForm.all')"
|
||||
/>
|
||||
<QRadio
|
||||
v-if="!props.isMasiveEdit"
|
||||
v-model="excludeType"
|
||||
dense
|
||||
val="specificLocations"
|
||||
|
|
|
@ -2,6 +2,13 @@
|
|||
import { ref, computed, onMounted } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useQuasar } from 'quasar';
|
||||
import axios from 'axios';
|
||||
import moment from 'moment';
|
||||
|
||||
import { useArrayData } from 'src/composables/useArrayData';
|
||||
import { useWeekdayStore } from 'src/stores/useWeekdayStore';
|
||||
import { useVnConfirm } from 'composables/useVnConfirm';
|
||||
|
||||
import VnRow from 'components/ui/VnRow.vue';
|
||||
import FormPopup from 'components/FormPopup.vue';
|
||||
|
@ -9,11 +16,7 @@ import VnInputDate from 'src/components/common/VnInputDate.vue';
|
|||
import VnWeekdayPicker from 'src/components/common/VnWeekdayPicker.vue';
|
||||
import VnInputTime from 'components/common/VnInputTime.vue';
|
||||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
|
||||
import { useArrayData } from 'src/composables/useArrayData';
|
||||
import { useWeekdayStore } from 'src/stores/useWeekdayStore';
|
||||
import { useVnConfirm } from 'composables/useVnConfirm';
|
||||
import axios from 'axios';
|
||||
import { toDateFormat } from 'src/filters/date';
|
||||
|
||||
const props = defineProps({
|
||||
date: {
|
||||
|
@ -32,6 +35,14 @@ const props = defineProps({
|
|||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
isMasiveEdit: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
zoneIds: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['onSubmit', 'closeForm']);
|
||||
|
@ -40,10 +51,10 @@ const route = useRoute();
|
|||
const { t } = useI18n();
|
||||
const weekdayStore = useWeekdayStore();
|
||||
const { openConfirmationModal } = useVnConfirm();
|
||||
|
||||
const quasar = useQuasar();
|
||||
const isNew = computed(() => props.isNewMode);
|
||||
const eventInclusionFormData = ref({ wdays: [] });
|
||||
|
||||
const dated = ref(props.date || Date.vnNew());
|
||||
const _inclusionType = ref('indefinitely');
|
||||
const inclusionType = computed({
|
||||
get: () => _inclusionType.value,
|
||||
|
@ -56,8 +67,12 @@ const inclusionType = computed({
|
|||
const arrayData = useArrayData('ZoneEvents');
|
||||
|
||||
const createEvent = async () => {
|
||||
const defaultMonths = await axios.get('ZoneConfigs');
|
||||
const nMonths = defaultMonths.data[0].defaultMonths;
|
||||
|
||||
eventInclusionFormData.value.weekDays = weekdayStore.toSet(
|
||||
eventInclusionFormData.value.wdays,
|
||||
eventInclusionFormData.value.wdays,
|
||||
);
|
||||
|
||||
if (inclusionType.value == 'day') eventInclusionFormData.value.weekDays = '';
|
||||
|
@ -68,14 +83,43 @@ const createEvent = async () => {
|
|||
eventInclusionFormData.value.ended = null;
|
||||
}
|
||||
|
||||
if (isNew.value)
|
||||
await axios.post(`Zones/${route.params.id}/events`, eventInclusionFormData.value);
|
||||
else
|
||||
await axios.put(
|
||||
`Zones/${route.params.id}/events/${props.event?.id}`,
|
||||
eventInclusionFormData.value,
|
||||
);
|
||||
const zoneIds = props.zoneIds?.length ? props.zoneIds : [route.params.id];
|
||||
for (const id of zoneIds) {
|
||||
let today = eventInclusionFormData.value.dated
|
||||
? moment(eventInclusionFormData.value.dated)
|
||||
: moment(dated.value);
|
||||
let lastDay = today.clone().add(nMonths, 'months').endOf('month');
|
||||
|
||||
const { data } = await axios.get(`Zones/getEventsFiltered`, {
|
||||
params: {
|
||||
zoneFk: id,
|
||||
started: today,
|
||||
ended: lastDay,
|
||||
},
|
||||
});
|
||||
const existsExclusion = data.exclusions.find(
|
||||
(exclusion) =>
|
||||
toDateFormat(exclusion.dated) ===
|
||||
toDateFormat(eventInclusionFormData.value.dated),
|
||||
);
|
||||
if (existsExclusion) {
|
||||
await axios.delete(
|
||||
`Zones/${existsExclusion?.zoneFk}/exclusions/${existsExclusion?.id}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (isNew.value)
|
||||
await axios.post(`Zones/${id}/events`, eventInclusionFormData.value);
|
||||
else
|
||||
await axios.put(
|
||||
`Zones/${id}/events/${props.event?.id}`,
|
||||
eventInclusionFormData.value,
|
||||
);
|
||||
}
|
||||
quasar.notify({
|
||||
message: t('globals.dataSaved'),
|
||||
type: 'positive',
|
||||
});
|
||||
await refetchEvents();
|
||||
emit('onSubmit');
|
||||
};
|
||||
|
@ -97,9 +141,11 @@ const refetchEvents = async () => {
|
|||
|
||||
onMounted(() => {
|
||||
if (props.event) {
|
||||
dated.value = props.event?.dated;
|
||||
eventInclusionFormData.value = { ...props.event };
|
||||
inclusionType.value = props.event?.type || 'day';
|
||||
} else if (props.date) {
|
||||
dated.value = props.date;
|
||||
eventInclusionFormData.value.dated = props.date;
|
||||
inclusionType.value = 'day';
|
||||
} else inclusionType.value = 'indefinitely';
|
||||
|
@ -125,6 +171,7 @@ onMounted(() => {
|
|||
data-cy="ZoneEventInclusionDayRadio"
|
||||
/>
|
||||
<QRadio
|
||||
v-if="!props.isMasiveEdit"
|
||||
v-model="inclusionType"
|
||||
dense
|
||||
val="indefinitely"
|
||||
|
@ -132,6 +179,7 @@ onMounted(() => {
|
|||
data-cy="ZoneEventInclusionIndefinitelyRadio"
|
||||
/>
|
||||
<QRadio
|
||||
v-if="!props.isMasiveEdit"
|
||||
v-model="inclusionType"
|
||||
dense
|
||||
val="range"
|
||||
|
|
|
@ -34,9 +34,10 @@ const onSelected = async (val, node) => {
|
|||
node.selected
|
||||
? '--checked'
|
||||
: node.selected == false
|
||||
? '--unchecked'
|
||||
: '--indeterminate',
|
||||
? '--unchecked'
|
||||
: '--indeterminate',
|
||||
]"
|
||||
data-cy="ZoneLocationTreeCheckbox"
|
||||
/>
|
||||
</template>
|
||||
</ZoneLocationsTree>
|
||||
|
|
|
@ -42,7 +42,7 @@ const refreshEvents = () => {
|
|||
days.value = {};
|
||||
if (!data.value) return;
|
||||
|
||||
let day = new Date(firstDay.value.getTime());
|
||||
let day = new Date(firstDay?.value?.getTime());
|
||||
|
||||
while (day <= lastDay.value) {
|
||||
let stamp = day.getTime();
|
||||
|
@ -156,7 +156,7 @@ watch(
|
|||
(value) => {
|
||||
data.value = value;
|
||||
},
|
||||
{ immediate: true }
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
const getMonthNameAndYear = (date) => {
|
||||
|
|
|
@ -14,7 +14,11 @@ import VnTable from 'src/components/VnTable/VnTable.vue';
|
|||
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
import VnInputTime from 'src/components/common/VnInputTime.vue';
|
||||
|
||||
import VnSection from 'src/components/common/VnSection.vue';
|
||||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
||||
import ZoneEventInclusionForm from './Card/ZoneEventInclusionForm.vue';
|
||||
import ZoneEventExclusionForm from './Card/ZoneEventExclusionForm.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
|
@ -24,6 +28,11 @@ const { openConfirmationModal } = useVnConfirm();
|
|||
const tableRef = ref();
|
||||
const warehouseOptions = ref([]);
|
||||
const dataKey = 'ZoneList';
|
||||
const selectedRows = ref([]);
|
||||
const hasSelectedRows = computed(() => selectedRows.value.length > 0);
|
||||
const openInclusionForm = ref();
|
||||
const showZoneEventForm = ref(false);
|
||||
const zoneIds = ref({});
|
||||
const tableFilter = {
|
||||
include: [
|
||||
{
|
||||
|
@ -191,6 +200,16 @@ const exprBuilder = (param, value) => {
|
|||
};
|
||||
}
|
||||
};
|
||||
|
||||
function openForm(value, rows) {
|
||||
zoneIds.value = rows.map((row) => row.id);
|
||||
openInclusionForm.value = value;
|
||||
showZoneEventForm.value = true;
|
||||
}
|
||||
|
||||
const closeEventForm = () => {
|
||||
showZoneEventForm.value = false;
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -206,6 +225,28 @@ const exprBuilder = (param, value) => {
|
|||
}"
|
||||
>
|
||||
<template #body>
|
||||
<VnSubToolbar>
|
||||
<template #st-actions>
|
||||
<QBtnGroup style="column-gap: 10px">
|
||||
<QBtn
|
||||
color="primary"
|
||||
icon-right="event_available"
|
||||
:disable="!hasSelectedRows"
|
||||
@click="openForm(true, selectedRows)"
|
||||
>
|
||||
<QTooltip>{{ t('list.includeEvent') }}</QTooltip>
|
||||
</QBtn>
|
||||
<QBtn
|
||||
color="primary"
|
||||
icon-right="event_busy"
|
||||
:disable="!hasSelectedRows"
|
||||
@click="openForm(false, selectedRows)"
|
||||
>
|
||||
<QTooltip>{{ t('list.excludeEvent') }}</QTooltip>
|
||||
</QBtn>
|
||||
</QBtnGroup>
|
||||
</template>
|
||||
</VnSubToolbar>
|
||||
<div class="table-container">
|
||||
<div class="column items-center">
|
||||
<VnTable
|
||||
|
@ -220,6 +261,11 @@ const exprBuilder = (param, value) => {
|
|||
formInitialData: {},
|
||||
}"
|
||||
table-height="85vh"
|
||||
v-model:selected="selectedRows"
|
||||
:table="{
|
||||
'row-key': 'id',
|
||||
selection: 'multiple',
|
||||
}"
|
||||
>
|
||||
<template #column-addressFk="{ row }">
|
||||
{{ dashIfEmpty(formatRow(row)) }}
|
||||
|
@ -271,6 +317,21 @@ const exprBuilder = (param, value) => {
|
|||
</div>
|
||||
</template>
|
||||
</VnSection>
|
||||
<QDialog v-model="showZoneEventForm" @hide="closeEventForm()">
|
||||
<ZoneEventInclusionForm
|
||||
v-if="openInclusionForm"
|
||||
:event="'event'"
|
||||
:is-masive-edit="true"
|
||||
:zone-ids="zoneIds"
|
||||
@close-form="closeEventForm"
|
||||
/>
|
||||
<ZoneEventExclusionForm
|
||||
v-else
|
||||
:zone-ids="zoneIds"
|
||||
:is-masive-edit="true"
|
||||
@close-form="closeEventForm"
|
||||
/>
|
||||
</QDialog>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
@ -25,6 +25,7 @@ list:
|
|||
agency: Agency
|
||||
close: Close
|
||||
price: Price
|
||||
priceOptimum: Optimal price
|
||||
create: Create zone
|
||||
openSummary: Details
|
||||
searchZone: Search zones
|
||||
|
@ -37,6 +38,8 @@ list:
|
|||
createZone: Create zone
|
||||
zoneSummary: Summary
|
||||
addressFk: Address
|
||||
includeEvent: Include event
|
||||
excludeEvent: Exclude event
|
||||
create:
|
||||
name: Name
|
||||
closingHour: Closing hour
|
||||
|
|
|
@ -39,6 +39,8 @@ list:
|
|||
createZone: Crear zona
|
||||
zoneSummary: Resumen
|
||||
addressFk: Consignatario
|
||||
includeEvent: Incluir evento
|
||||
excludeEvent: Excluir evento
|
||||
create:
|
||||
closingHour: Hora de cierre
|
||||
itemMaxSize: Medida máxima
|
||||
|
|
|
@ -271,12 +271,14 @@ export default {
|
|||
path: 'department',
|
||||
name: 'Department',
|
||||
redirect: { name: 'WorkerDepartment' },
|
||||
component: () => import('src/pages/Worker/WorkerDepartment.vue'),
|
||||
meta: { title: 'department', icon: 'vn:greuge' },
|
||||
children: [
|
||||
{
|
||||
component: () =>
|
||||
import('src/pages/Worker/WorkerDepartment.vue'),
|
||||
meta: { title: 'department', icon: 'vn:greuge' },
|
||||
name: 'WorkerDepartment',
|
||||
path: 'list',
|
||||
meta: { title: 'department', icon: 'vn:greuge' },
|
||||
},
|
||||
departmentCard,
|
||||
],
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
import { describe, expect, it, beforeEach } from 'vitest';
|
||||
import 'app/test/vitest/helper';
|
||||
|
||||
import { useDescriptorStore } from 'src/stores/useDescriptorStore';
|
||||
import { useStateStore } from 'stores/useStateStore';
|
||||
|
||||
describe('useDescriptorStore', () => {
|
||||
const { get, has } = useDescriptorStore();
|
||||
const stateStore = useStateStore();
|
||||
|
||||
beforeEach(() => {
|
||||
stateStore.setDescriptors({});
|
||||
});
|
||||
|
||||
function getDescriptors() {
|
||||
return stateStore.descriptors;
|
||||
}
|
||||
|
||||
it('should get descriptors in stateStore', async () => {
|
||||
expect(Object.keys(getDescriptors()).length).toBe(0);
|
||||
get();
|
||||
expect(Object.keys(getDescriptors()).length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should find ticketDescriptor if search ticketFk', async () => {
|
||||
expect(has('ticketFk')).toBeDefined();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,35 @@
|
|||
import { defineAsyncComponent } from 'vue';
|
||||
import { defineStore } from 'pinia';
|
||||
import { useStateStore } from 'stores/useStateStore';
|
||||
|
||||
export const useDescriptorStore = defineStore('descriptorStore', () => {
|
||||
const { descriptors, setDescriptors } = useStateStore();
|
||||
function get() {
|
||||
if (Object.keys(descriptors).length) return descriptors;
|
||||
|
||||
const currentDescriptors = {};
|
||||
const files = import.meta.glob(`/src/**/*DescriptorProxy.vue`);
|
||||
const moduleParser = {
|
||||
account: 'user',
|
||||
client: 'customer',
|
||||
};
|
||||
for (const file in files) {
|
||||
const name = file.split('/').at(-1).slice(0, -19).toLowerCase();
|
||||
const descriptor = moduleParser[name] ?? name;
|
||||
currentDescriptors[descriptor + 'Fk'] = defineAsyncComponent(
|
||||
() => import(/* @vite-ignore */ file),
|
||||
);
|
||||
}
|
||||
setDescriptors(currentDescriptors);
|
||||
return currentDescriptors;
|
||||
}
|
||||
|
||||
function has(name) {
|
||||
return get()[name];
|
||||
}
|
||||
|
||||
return {
|
||||
has,
|
||||
get,
|
||||
};
|
||||
});
|
|
@ -8,6 +8,7 @@ export const useStateStore = defineStore('stateStore', () => {
|
|||
const rightAdvancedDrawer = ref(false);
|
||||
const subToolbar = ref(false);
|
||||
const cardDescriptor = ref(null);
|
||||
const descriptors = ref({});
|
||||
|
||||
function cardDescriptorChangeValue(descriptor) {
|
||||
cardDescriptor.value = descriptor;
|
||||
|
@ -52,6 +53,10 @@ export const useStateStore = defineStore('stateStore', () => {
|
|||
return subToolbar.value;
|
||||
}
|
||||
|
||||
function setDescriptors(value) {
|
||||
descriptors.value = value;
|
||||
}
|
||||
|
||||
return {
|
||||
cardDescriptor,
|
||||
cardDescriptorChangeValue,
|
||||
|
@ -68,5 +73,7 @@ export const useStateStore = defineStore('stateStore', () => {
|
|||
isSubToolbarShown,
|
||||
toggleSubToolbar,
|
||||
rightDrawerChangeValue,
|
||||
descriptors,
|
||||
setDescriptors,
|
||||
};
|
||||
});
|
||||
|
|
|
@ -77,14 +77,14 @@ export const useWeekdayStore = defineStore('weekdayStore', () => {
|
|||
const locales = {};
|
||||
for (let code of localeOrder.es) {
|
||||
const weekDay = weekdaysMap[code];
|
||||
const locale = t(`weekdays.${weekdaysMap[code].code}`);
|
||||
const locale = t(`weekdays.${weekDay?.code}`);
|
||||
const obj = {
|
||||
...weekDay,
|
||||
locale,
|
||||
localeChar: locale.substr(0, 1),
|
||||
localeAbr: locale.substr(0, 3),
|
||||
};
|
||||
locales[weekDay.code] = obj;
|
||||
locales[weekDay?.code] = obj;
|
||||
}
|
||||
return locales;
|
||||
});
|
||||
|
|
|
@ -55,9 +55,9 @@ describe('OrderCatalog', () => {
|
|||
it('removes a secondary tag', () => {
|
||||
cy.get(':nth-child(1) > [data-cy="catalogFilterCategory"]').click();
|
||||
cy.selectOption('[data-cy="catalogFilterType"]', 'Anthurium');
|
||||
cy.dataCy('vnFilterPanelChip').should('exist');
|
||||
cy.dataCy('vnFilterPanelChip_typeFk').should('exist');
|
||||
cy.get('[data-cy="catalogFilterCustomTag"] > .q-chip__icon--remove').click();
|
||||
cy.dataCy('vnFilterPanelChip').should('not.exist');
|
||||
cy.dataCy('vnFilterPanelChip_typeFk').should('not.exist');
|
||||
});
|
||||
|
||||
it('Removes category tag', () => {
|
||||
|
|
|
@ -53,7 +53,7 @@ describe.skip('Client list', () => {
|
|||
it('Client founded create ticket', () => {
|
||||
const search = 'Jessica Jones';
|
||||
cy.searchByLabel('Name', search);
|
||||
cy.openActionDescriptor('Create ticket');
|
||||
cy.selectDescriptorOption();
|
||||
cy.waitForElement('#formModel');
|
||||
cy.waitForElement('.q-form');
|
||||
cy.checkValueForm(1, search);
|
||||
|
|
|
@ -1,26 +1,40 @@
|
|||
/// <reference types="cypress" />
|
||||
import moment from 'moment';
|
||||
describe('InvoiceInBasicData', () => {
|
||||
const firstFormSelect = '.q-card > .vn-row:nth-child(1) > .q-select';
|
||||
const dialogInputs = '.q-dialog input';
|
||||
const resetBtn = '.q-btn-group--push > .q-btn--flat';
|
||||
const getDocumentBtns = (opt) => `[data-cy="dms-buttons"] > :nth-child(${opt})`;
|
||||
const futureDate = moment().add(1, 'days').format('DD-MM-YYYY');
|
||||
const mock = {
|
||||
invoiceInBasicDataSupplier: { val: 'Bros nick', type: 'select' },
|
||||
invoiceInBasicDataSupplierRef_input: 'mockInvoice41',
|
||||
invoiceInBasicDataIssued: { val: futureDate, type: 'date' },
|
||||
invoiceInBasicDataOperated: { val: futureDate, type: 'date' },
|
||||
invoiceInBasicDatabookEntried: { val: futureDate, type: 'date' },
|
||||
invoiceInBasicDataBooked: {
|
||||
val: moment().add(5, 'days').format('DD-MM-YYYY'),
|
||||
type: 'date',
|
||||
},
|
||||
invoiceInBasicDataDeductibleExpenseFk: {
|
||||
val: '4751000000',
|
||||
type: 'select',
|
||||
},
|
||||
invoiceInBasicDataCurrencyFk: { val: 'USD', type: 'select' },
|
||||
invoiceInBasicDataCompanyFk: { val: 'CCs', type: 'select' },
|
||||
invoiceInBasicDataWithholdingSageFk: {
|
||||
val: 'Arrendamiento y subarrendamiento',
|
||||
type: 'select',
|
||||
},
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
cy.login('developer');
|
||||
cy.login('administrative');
|
||||
cy.visit(`/#/invoice-in/1/basic-data`);
|
||||
});
|
||||
|
||||
it('should edit the provideer and supplier ref', () => {
|
||||
cy.dataCy('UnDeductibleVatSelect').type('4751000000');
|
||||
cy.get('.q-menu .q-item').contains('4751000000').click();
|
||||
cy.get(resetBtn).click();
|
||||
|
||||
cy.waitForElement('#formModel').within(() => {
|
||||
cy.dataCy('vnSupplierSelect').type('Bros nick');
|
||||
})
|
||||
cy.get('.q-menu .q-item').contains('Bros nick').click();
|
||||
it('should edit every field', () => {
|
||||
cy.fillInForm(mock, { attr: 'data-cy' });
|
||||
cy.saveCard();
|
||||
cy.get(`${firstFormSelect} input`).invoke('val').should('eq', 'Bros nick');
|
||||
cy.validateForm(mock, { attr: 'data-cy' });
|
||||
});
|
||||
|
||||
it('should edit, remove and create the dms data', () => {
|
||||
|
@ -44,7 +58,7 @@ describe('InvoiceInBasicData', () => {
|
|||
cy.checkNotification('Data saved');
|
||||
|
||||
//create
|
||||
cy.get('[data-cy="dms-create"]').eq(0).click();
|
||||
cy.get('[data-cy="invoiceInBasicDataDmsAdd"]').eq(0).click();
|
||||
cy.get('[data-cy="VnDms_inputFile"').selectFile(
|
||||
'test/cypress/fixtures/image.jpg',
|
||||
{
|
||||
|
|
|
@ -1,22 +1,59 @@
|
|||
/// <reference types="cypress" />
|
||||
describe('InvoiceInCorrective', () => {
|
||||
const saveDialog = '.q-card > .q-card__actions > .q-btn--standard ';
|
||||
describe('invoiceInCorrective', () => {
|
||||
beforeEach(() => cy.login('administrative'));
|
||||
|
||||
it('should create a correcting invoice', () => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('developer');
|
||||
cy.visit(`/#/invoice-in/1/summary`);
|
||||
it('should modify the invoice', () => {
|
||||
cy.visit('/#/invoice-in/1/summary');
|
||||
cy.intercept('POST', '/api/InvoiceIns/corrective').as('corrective');
|
||||
cy.intercept('POST', '/api/InvoiceInCorrections/crud').as('crud');
|
||||
cy.intercept('GET', /InvoiceInCorrections\?filter=.+/).as('getCorrective');
|
||||
|
||||
cy.openActionsDescriptor();
|
||||
cy.selectDescriptorOption(4);
|
||||
cy.dataCy('saveCorrectiveInvoice').click();
|
||||
|
||||
cy.dataCy('createCorrectiveItem').click();
|
||||
cy.get(saveDialog).click();
|
||||
cy.wait('@corrective').then((interception) => {
|
||||
const correctingId = interception.response.body;
|
||||
cy.url().should('include', `/invoice-in/${correctingId}/summary`);
|
||||
cy.visit(`/#/invoice-in/${correctingId}/corrective`);
|
||||
cy.wait('@corrective').then(({ response }) => {
|
||||
const correctingFk = response.body;
|
||||
cy.url().should('include', `/invoice-in/${correctingFk}/summary`);
|
||||
cy.visit(`/#/invoice-in/${correctingFk}/corrective`);
|
||||
cy.selectOption('[data-cy="invoiceInCorrective_class"]', 'r4');
|
||||
cy.selectOption('[data-cy="invoiceInCorrective_type"]', 'sustitución');
|
||||
cy.selectOption('[data-cy="invoiceInCorrective_reason"]', 'vat');
|
||||
cy.dataCy('crudModelDefaultSaveBtn').click();
|
||||
|
||||
cy.wait('@crud');
|
||||
cy.reload();
|
||||
cy.wait('@getCorrective');
|
||||
cy.validateRow('tbody > :nth-of-type(1)', [
|
||||
,
|
||||
'S – Por sustitución',
|
||||
'R4',
|
||||
'Error in VAT calculation',
|
||||
]);
|
||||
});
|
||||
cy.get('tbody > tr:visible').should('have.length', 1);
|
||||
});
|
||||
|
||||
it('should not be able to modify the invoice if the original invoice is booked', () => {
|
||||
cy.intercept('POST', '/api/InvoiceIns/corrective').as('corrective');
|
||||
cy.visit('/#/invoice-in/4/summary');
|
||||
cy.selectDescriptorOption();
|
||||
cy.dataCy('VnConfirm_confirm').click();
|
||||
cy.selectDescriptorOption(4);
|
||||
cy.dataCy('saveCorrectiveInvoice').click();
|
||||
|
||||
cy.wait('@corrective').then(({ response }) => {
|
||||
const correctingFk = response.body;
|
||||
cy.url().should('include', `/invoice-in/${correctingFk}/summary`);
|
||||
cy.visit(`/#/invoice-in/${correctingFk}/corrective`);
|
||||
|
||||
cy.dataCy('invoiceInCorrective_class').should('be.disabled');
|
||||
cy.dataCy('invoiceInCorrective_type').should('be.disabled');
|
||||
cy.dataCy('invoiceInCorrective_reason').should('be.disabled');
|
||||
});
|
||||
});
|
||||
|
||||
it('should show/hide the section if it is a corrective invoice', () => {
|
||||
cy.visit('/#/invoice-in/1/summary');
|
||||
cy.get('[data-cy="InvoiceInCorrective-menu-item"]').should('not.exist');
|
||||
cy.clicDescriptorAction(4);
|
||||
cy.get('[data-cy="InvoiceInCorrective-menu-item"]').should('exist');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,21 +1,147 @@
|
|||
describe('InvoiceInDescriptor', () => {
|
||||
const book = '.summaryHeader > .no-wrap > .q-btn';
|
||||
const firstDescritorOpt = '.q-menu > .q-list > :nth-child(5) > .q-item__section';
|
||||
const checkbox = ':nth-child(5) > .q-checkbox';
|
||||
beforeEach(() => cy.login('administrative'));
|
||||
|
||||
it('should booking and unbooking the invoice properly', () => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('developer');
|
||||
cy.visit('/#/invoice-in/1/summary');
|
||||
cy.waitForElement('.q-page');
|
||||
describe('more options', () => {
|
||||
it('should booking and unbooking the invoice properly', () => {
|
||||
const checkbox = '[data-cy="vnLvIs booked"] > .q-checkbox';
|
||||
cy.visit('/#/invoice-in/2/summary');
|
||||
cy.selectDescriptorOption();
|
||||
cy.dataCy('VnConfirm_confirm').click();
|
||||
cy.validateCheckbox(checkbox);
|
||||
cy.selectDescriptorOption();
|
||||
cy.dataCy('VnConfirm_confirm').click();
|
||||
cy.validateCheckbox(checkbox, false);
|
||||
});
|
||||
|
||||
cy.get(book).click();
|
||||
cy.dataCy('VnConfirm_confirm').click();
|
||||
cy.get(checkbox).invoke('attr', 'aria-checked').should('eq', 'true');
|
||||
it('should delete the invoice properly', () => {
|
||||
cy.visit('/#/invoice-in/2/summary');
|
||||
cy.selectDescriptorOption(2);
|
||||
cy.clickConfirm();
|
||||
cy.checkNotification('invoice deleted');
|
||||
});
|
||||
|
||||
cy.dataCy('descriptor-more-opts').first().click();
|
||||
cy.get(firstDescritorOpt).click();
|
||||
cy.dataCy('VnConfirm_confirm').click();
|
||||
cy.get(checkbox).invoke('attr', 'aria-checked').should('eq', 'false');
|
||||
it('should clone the invoice properly', () => {
|
||||
cy.visit('/#/invoice-in/3/summary');
|
||||
cy.selectDescriptorOption(3);
|
||||
cy.clickConfirm();
|
||||
cy.checkNotification('Invoice cloned');
|
||||
});
|
||||
|
||||
it('should show the agricultural PDF properly', () => {
|
||||
cy.visit('/#/invoice-in/6/summary');
|
||||
cy.validatePdfDownload(
|
||||
/api\/InvoiceIns\/6\/invoice-in-pdf\?access_token=.*/,
|
||||
() => cy.selectDescriptorOption(4),
|
||||
);
|
||||
});
|
||||
|
||||
it('should send the agricultural PDF properly', () => {
|
||||
cy.intercept('POST', 'api/InvoiceIns/6/invoice-in-email').as('sendEmail');
|
||||
cy.visit('/#/invoice-in/6/summary');
|
||||
cy.selectDescriptorOption(5);
|
||||
|
||||
cy.dataCy('SendEmailNotifiactionDialogInput_input').type(
|
||||
'{selectall}jorgito@gmail.mx',
|
||||
);
|
||||
cy.clickConfirm();
|
||||
cy.checkNotification('Notification sent');
|
||||
cy.wait('@sendEmail').then(({ request, response }) => {
|
||||
expect(request.body).to.deep.equal({
|
||||
recipientId: 2,
|
||||
recipient: 'jorgito@gmail.mx',
|
||||
});
|
||||
expect(response.statusCode).to.equal(200);
|
||||
});
|
||||
});
|
||||
// https://redmine.verdnatura.es/issues/8767
|
||||
it.skip('should download the file properly', () => {
|
||||
cy.visit('/#/invoice-in/1/summary');
|
||||
cy.validateDownload(() => cy.selectDescriptorOption(5));
|
||||
});
|
||||
});
|
||||
|
||||
describe('buttons', () => {
|
||||
beforeEach(() => cy.visit('/#/invoice-in/1/summary'));
|
||||
|
||||
it('should navigate to the supplier summary', () => {
|
||||
cy.clicDescriptorAction(1);
|
||||
cy.url().should('to.match', /supplier\/\d+\/summary/);
|
||||
});
|
||||
|
||||
it('should navigate to the entry summary', () => {
|
||||
cy.clicDescriptorAction(2);
|
||||
cy.url().should('to.match', /entry\/\d+\/summary/);
|
||||
});
|
||||
|
||||
it('should navigate to the invoiceIn list', () => {
|
||||
cy.clicDescriptorAction(3);
|
||||
cy.url().should('to.match', /invoice-in\/list\?table=\{.*supplierFk.+\}/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('corrective', () => {
|
||||
const originalId = 4;
|
||||
|
||||
beforeEach(() => cy.visit(`/#/invoice-in/${originalId}/summary`));
|
||||
|
||||
it('should create a correcting invoice and redirect to original invoice', () => {
|
||||
createCorrective();
|
||||
redirect(originalId);
|
||||
});
|
||||
|
||||
it('should create a correcting invoice and navigate to list filtered by corrective', () => {
|
||||
createCorrective();
|
||||
redirect(originalId);
|
||||
|
||||
cy.clicDescriptorAction(4);
|
||||
cy.validateVnTableRows({
|
||||
cols: [
|
||||
{
|
||||
name: 'supplierRef',
|
||||
val: '1237',
|
||||
operation: 'include',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('link', () => {
|
||||
it('should open the supplier descriptor popup', () => {
|
||||
cy.visit('/#/invoice-in/1/summary');
|
||||
cy.intercept('GET', /Suppliers\/\d+/).as('getSupplier');
|
||||
|
||||
cy.dataCy('invoiceInDescriptor_supplier').then(($el) => {
|
||||
const alias = $el.text().trim();
|
||||
$el.click();
|
||||
cy.wait('@getSupplier').then(() =>
|
||||
cy.validateDescriptor({ listbox: { 1: alias }, popup: true }),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function createCorrective() {
|
||||
cy.intercept('POST', '/api/InvoiceIns/corrective').as('corrective');
|
||||
|
||||
cy.selectDescriptorOption(4);
|
||||
cy.dataCy('saveCorrectiveInvoice').click();
|
||||
|
||||
cy.wait('@corrective').then(({ response }) => {
|
||||
const correctingId = response.body;
|
||||
cy.url().should('include', `/invoice-in/${correctingId}/summary`);
|
||||
cy.visit(`/#/invoice-in/${correctingId}/corrective`);
|
||||
cy.dataCy('invoiceInCorrective_class').should('contain.value', 'R2');
|
||||
cy.dataCy('invoiceInCorrective_type').should('contain.value', 'diferencias');
|
||||
cy.dataCy('invoiceInCorrective_reason').should('contain.value', 'sales details');
|
||||
});
|
||||
}
|
||||
|
||||
function redirect(subtitle) {
|
||||
const regex = new RegExp(`InvoiceIns/${subtitle}\\?filter=.*`);
|
||||
cy.intercept('GET', regex).as('getOriginal');
|
||||
cy.clicDescriptorAction(4);
|
||||
cy.wait('@getOriginal');
|
||||
cy.validateDescriptor({ subtitle });
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ describe('InvoiceInDueDay', () => {
|
|||
const addBtn = '.q-page-sticky > div > .q-btn > .q-btn__content';
|
||||
|
||||
beforeEach(() => {
|
||||
cy.login('developer');
|
||||
cy.login('administrative');
|
||||
cy.visit(`/#/invoice-in/6/due-day`);
|
||||
});
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ describe('InvoiceInIntrastat', () => {
|
|||
const firstRowAmount = `${firstRow} > :nth-child(3)`;
|
||||
|
||||
beforeEach(() => {
|
||||
cy.login('developer');
|
||||
cy.login('administrative');
|
||||
cy.visit(`/#/invoice-in/1/intrastat`);
|
||||
});
|
||||
|
||||
|
|
|
@ -1,13 +1,21 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
describe('InvoiceInList', () => {
|
||||
const firstRow = 'tbody.q-virtual-scroll__content tr:nth-child(1)';
|
||||
const firstId = `${firstRow} > td:nth-child(2) span`;
|
||||
const firstDetailBtn = `${firstRow} .q-btn:nth-child(1)`;
|
||||
const summaryHeaders = '.summaryBody .header-link';
|
||||
const mockInvoiceRef = `createMockInvoice${Math.floor(Math.random() * 100)}`;
|
||||
const mock = {
|
||||
vnSupplierSelect: { val: 'farmer king', type: 'select' },
|
||||
'Invoice nº_input': mockInvoiceRef,
|
||||
Company_select: { val: 'orn', type: 'select' },
|
||||
'Expedition date_inputDate': '16-11-2001',
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
cy.viewport(1920, 1080);
|
||||
cy.login('developer');
|
||||
cy.login('administrative');
|
||||
cy.visit(`/#/invoice-in/list`);
|
||||
cy.get('#searchbar input').type('{enter}');
|
||||
});
|
||||
|
@ -27,4 +35,18 @@ describe('InvoiceInList', () => {
|
|||
cy.get(summaryHeaders).eq(1).contains('Basic data');
|
||||
cy.get(summaryHeaders).eq(4).contains('Vat');
|
||||
});
|
||||
|
||||
it('should create a new Invoice', () => {
|
||||
cy.dataCy('vnTableCreateBtn').click();
|
||||
cy.fillInForm({ ...mock }, { attr: 'data-cy' });
|
||||
cy.dataCy('FormModelPopup_save').click();
|
||||
cy.intercept('GET', /\/api\/InvoiceIns\/\d+\/getTotals$/).as('invoice');
|
||||
cy.wait('@invoice').then(() =>
|
||||
cy.validateDescriptor({
|
||||
title: mockInvoiceRef,
|
||||
listBox: { 0: '11/16/2001', 3: 'The farmer' },
|
||||
}),
|
||||
);
|
||||
cy.get('[data-cy="vnLvCompany"]').should('contain.text', 'ORN');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
describe('InvoiceInSerial', () => {
|
||||
beforeEach(() => {
|
||||
cy.login('administrative');
|
||||
cy.visit('#/invoice-in/serial');
|
||||
});
|
||||
|
||||
it('should filter by serial number', () => {
|
||||
cy.dataCy('serial_input').type('R{enter}');
|
||||
cy.validateVnTableRows({ cols: [{ name: 'serial', val: 'r' }] });
|
||||
});
|
||||
|
||||
it('should filter by last days ', () => {
|
||||
let before;
|
||||
cy.dataCy('vnTableCell_total')
|
||||
.invoke('text')
|
||||
.then((total) => (before = +total));
|
||||
|
||||
cy.dataCy('Last days_input').type('{selectall}1{enter}');
|
||||
cy.dataCy('vnTableCell_total')
|
||||
.invoke('text')
|
||||
.then((total) => expect(+total).to.be.lessThan(before));
|
||||
});
|
||||
});
|
|
@ -0,0 +1,24 @@
|
|||
describe('InvoiceInSummary', () => {
|
||||
beforeEach(() => {
|
||||
cy.login('administrative');
|
||||
cy.visit('/#/invoice-in/3/summary');
|
||||
});
|
||||
|
||||
it('should booking and unbooking the invoice properly', () => {
|
||||
const checkbox = '[data-cy="vnLvIs booked"] > .q-checkbox';
|
||||
cy.dataCy('invoiceInSummary_book').click();
|
||||
cy.dataCy('VnConfirm_confirm').click();
|
||||
cy.validateCheckbox(checkbox);
|
||||
});
|
||||
|
||||
it('should open the supplier descriptor popup', () => {
|
||||
cy.intercept('GET', /Suppliers\/\d+/).as('getSupplier');
|
||||
cy.dataCy('invoiceInSummary_supplier').then(($el) => {
|
||||
const description = $el.text().trim();
|
||||
$el.click();
|
||||
cy.wait('@getSupplier').then(() =>
|
||||
cy.validateDescriptor({ description, popup: true }),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -8,7 +8,7 @@ describe('InvoiceInVat', () => {
|
|||
const randomInt = Math.floor(Math.random() * 100);
|
||||
|
||||
beforeEach(() => {
|
||||
cy.login('developer');
|
||||
cy.login('administrative');
|
||||
cy.visit(`/#/invoice-in/1/vat`);
|
||||
});
|
||||
|
||||
|
|
|
@ -22,4 +22,10 @@ describe('VnLog', () => {
|
|||
cy.get('.q-page').click();
|
||||
cy.validateContent(chips[0], 'Claim');
|
||||
});
|
||||
|
||||
it('should show claimDescriptor', () => {
|
||||
cy.dataCy('iconLaunch-claimFk').first().click();
|
||||
cy.dataCy('cardDescriptor_subtitle').contains('1');
|
||||
cy.dataCy('iconLaunch-claimFk').first().click();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
describe('ZoneCalendar', () => {
|
||||
const addEventBtn = '.q-page-sticky > div > .q-btn';
|
||||
const submitBtn = '.q-mt-lg > .q-btn--standard';
|
||||
const deleteBtn = '[data-cy="ZoneEventsPanelDeleteBtn"]';
|
||||
const deleteBtn = 'ZoneEventsPanelDeleteBtn';
|
||||
|
||||
beforeEach(() => {
|
||||
cy.login('developer');
|
||||
cy.viewport(1920, 1080);
|
||||
cy.visit(`/#/zone/13/events`);
|
||||
});
|
||||
|
||||
|
@ -14,7 +13,7 @@ describe('ZoneCalendar', () => {
|
|||
cy.dataCy('ZoneEventInclusionDayRadio').click();
|
||||
cy.get('.q-card > :nth-child(5)').type('01/01/2001');
|
||||
cy.get(submitBtn).click();
|
||||
cy.get(deleteBtn).click();
|
||||
cy.dataCy(deleteBtn).click();
|
||||
cy.dataCy('VnConfirm_confirm').click();
|
||||
});
|
||||
|
||||
|
@ -23,7 +22,7 @@ describe('ZoneCalendar', () => {
|
|||
cy.get('.flex > .q-gutter-x-sm > :nth-child(1)').click();
|
||||
cy.get('.flex > .q-gutter-x-sm > :nth-child(2)').click();
|
||||
cy.get(submitBtn).click();
|
||||
cy.get(deleteBtn).click();
|
||||
cy.dataCy(deleteBtn).click();
|
||||
cy.dataCy('VnConfirm_confirm').click();
|
||||
});
|
||||
|
||||
|
@ -34,7 +33,7 @@ describe('ZoneCalendar', () => {
|
|||
cy.dataCy('From_inputDate').type('01/01/2001');
|
||||
cy.dataCy('To_inputDate').type('31/01/2001');
|
||||
cy.get(submitBtn).click();
|
||||
cy.get(deleteBtn).click();
|
||||
cy.dataCy(deleteBtn).click();
|
||||
cy.dataCy('VnConfirm_confirm').click();
|
||||
});
|
||||
|
||||
|
|
|
@ -37,7 +37,6 @@ describe('ZoneDeliveryDays', () => {
|
|||
cy.get('@focusedElement').blur();
|
||||
}
|
||||
});
|
||||
cy.get('.q-menu').should('not.exist');
|
||||
|
||||
cy.dataCy('ZoneDeliveryDaysAgencySelect').type(agency);
|
||||
cy.get('.q-menu .q-item').contains(agency).click();
|
||||
|
@ -49,7 +48,6 @@ describe('ZoneDeliveryDays', () => {
|
|||
cy.get('@focusedElement').blur();
|
||||
}
|
||||
});
|
||||
cy.get('.q-menu').should('not.exist');
|
||||
|
||||
cy.get(submitForm).click();
|
||||
cy.wait('@events').then((interception) => {
|
||||
|
|
|
@ -1,26 +1,59 @@
|
|||
describe.skip('ZoneLocations', () => {
|
||||
const data = {
|
||||
Warehouse: { val: 'Warehouse One', type: 'select' },
|
||||
};
|
||||
|
||||
const postalCode =
|
||||
'[style=""] > :nth-child(1) > :nth-child(1) > :nth-child(2) > :nth-child(1) > :nth-child(1) > :nth-child(2) > :nth-child(1) > .q-tree__node--parent > .q-tree__node-collapsible > .q-tree__children';
|
||||
|
||||
describe('ZoneLocations', () => {
|
||||
const cp = 46680;
|
||||
const searchIcon = '.router-link-active > .q-icon';
|
||||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('developer');
|
||||
cy.visit(`/#/zone/2/location`);
|
||||
});
|
||||
|
||||
it('should show all locations on entry', () => {
|
||||
it('should be able to search by postal code', () => {
|
||||
cy.get('.q-tree > :nth-child(1) > :nth-child(2) > :nth-child(1)')
|
||||
.children()
|
||||
.should('have.length', 9);
|
||||
.should('exist')
|
||||
.should('be.visible');
|
||||
|
||||
cy.intercept('GET', '**/api/Zones/2/getLeaves*', (req) => {
|
||||
req.headers['cache-control'] = 'no-cache';
|
||||
req.headers['pragma'] = 'no-cache';
|
||||
req.headers['expires'] = '0';
|
||||
|
||||
req.on('response', (res) => {
|
||||
delete res.headers['if-none-match'];
|
||||
delete res.headers['if-modified-since'];
|
||||
});
|
||||
}).as('location');
|
||||
cy.get('#searchbarForm').type(cp);
|
||||
cy.get(searchIcon).click();
|
||||
cy.wait('@location').then((interception) => {
|
||||
const data = interception.response.body;
|
||||
expect(data).to.include(cp);
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to search by postal code', () => {
|
||||
cy.get('#searchbarForm').type('46680');
|
||||
cy.get('.router-link-active > .q-icon').click();
|
||||
cy.get(postalCode).should('include.text', '46680');
|
||||
it('should check, uncheck, and set a location to mixed state', () => {
|
||||
cy.get('#searchbarForm').type(cp);
|
||||
cy.get(searchIcon).click();
|
||||
|
||||
cy.get('.q-tree > :nth-child(1) > :nth-child(2) > :nth-child(1)')
|
||||
.as('tree')
|
||||
.within(() => {
|
||||
cy.get('[data-cy="ZoneLocationTreeCheckbox"] > .q-checkbox__inner')
|
||||
.last()
|
||||
.as('lastCheckbox');
|
||||
|
||||
const verifyCheckboxState = (state) => {
|
||||
cy.get('@lastCheckbox')
|
||||
.parents('.q-checkbox')
|
||||
.should('have.attr', 'aria-checked', state);
|
||||
};
|
||||
|
||||
cy.get('@lastCheckbox').click();
|
||||
verifyCheckboxState('true');
|
||||
|
||||
cy.get('@lastCheckbox').click();
|
||||
verifyCheckboxState('false');
|
||||
|
||||
cy.get('@lastCheckbox').click();
|
||||
verifyCheckboxState('mixed');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -27,8 +27,9 @@
|
|||
// DO NOT REMOVE
|
||||
// Imports Quasar Cypress AE predefined commands
|
||||
// import { registerCommands } from '@quasar/quasar-app-extension-testing-e2e-cypress';
|
||||
|
||||
import moment from 'moment';
|
||||
import waitUntil from './waitUntil';
|
||||
|
||||
Cypress.Commands.add('waitUntil', { prevSubject: 'optional' }, waitUntil);
|
||||
|
||||
Cypress.Commands.add('resetDB', () => {
|
||||
|
@ -122,9 +123,10 @@ function selectItem(selector, option, ariaControl, hasWrite = true) {
|
|||
cy.waitSpinner();
|
||||
|
||||
getItems(ariaControl).then((items) => {
|
||||
const matchingItem = items
|
||||
.toArray()
|
||||
.find((item) => item.innerText.includes(option));
|
||||
const matchingItem = items.toArray().find((item) => {
|
||||
const val = typeof option == 'string' ? option.toLowerCase() : option;
|
||||
return item.innerText.toLowerCase().includes(val);
|
||||
});
|
||||
if (matchingItem) return cy.wrap(matchingItem).click();
|
||||
|
||||
if (hasWrite) cy.get(selector).clear().type(option);
|
||||
|
@ -160,14 +162,20 @@ Cypress.Commands.add('countSelectOptions', (selector, option) => {
|
|||
cy.get('.q-menu .q-item').should('have.length', option);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('fillInForm', (obj, form = '.q-form > .q-card') => {
|
||||
Cypress.Commands.add('fillInForm', (obj, opts = {}) => {
|
||||
cy.waitSpinner();
|
||||
const { form = '.q-form > .q-card', attr = 'aria-label' } = opts;
|
||||
cy.waitForElement(form);
|
||||
cy.get(`${form} input`).each(([el]) => {
|
||||
cy.wrap(el)
|
||||
.invoke('attr', 'aria-label')
|
||||
.then((ariaLabel) => {
|
||||
const field = obj[ariaLabel];
|
||||
.invoke('attr', attr)
|
||||
.then((key) => {
|
||||
const field = obj[key];
|
||||
if (!field) return;
|
||||
if (typeof field == 'string')
|
||||
return cy
|
||||
.wrap(el)
|
||||
.type(`{selectall}{backspace}${field}`, { delay: 0 });
|
||||
|
||||
const { type, val } = field;
|
||||
switch (type) {
|
||||
|
@ -175,7 +183,9 @@ Cypress.Commands.add('fillInForm', (obj, form = '.q-form > .q-card') => {
|
|||
cy.selectOption(el, val);
|
||||
break;
|
||||
case 'date':
|
||||
cy.get(el).type(val.split('-').join(''));
|
||||
cy.get(el).type(
|
||||
`{selectall}{backspace}${val.split('-').join('')}`,
|
||||
);
|
||||
break;
|
||||
case 'time':
|
||||
cy.get(el).click();
|
||||
|
@ -191,6 +201,40 @@ Cypress.Commands.add('fillInForm', (obj, form = '.q-form > .q-card') => {
|
|||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('validateForm', (obj, opts = {}) => {
|
||||
const { form = '.q-form > .q-card', attr = 'data-cy' } = opts;
|
||||
cy.waitForElement(form);
|
||||
cy.get(`${form} input`).each(([el]) => {
|
||||
cy.wrap(el)
|
||||
.invoke('attr', attr)
|
||||
.then((key) => {
|
||||
const field = obj[key];
|
||||
if (!field) return;
|
||||
|
||||
const { type, val } = field;
|
||||
cy.get(el)
|
||||
.invoke('val')
|
||||
.then((elVal) => {
|
||||
if (typeof field == 'string')
|
||||
expect(elVal.toLowerCase()).to.equal(field.toLowerCase());
|
||||
else
|
||||
switch (type) {
|
||||
case 'date':
|
||||
const elDate = moment(elVal, 'DD-MM-YYYY');
|
||||
const mockDate = moment(val, 'DD-MM-YYYY');
|
||||
expect(elDate.isSame(mockDate, 'day')).to.be.true;
|
||||
break;
|
||||
default:
|
||||
expect(elVal.toLowerCase()).to.equal(
|
||||
val.toLowerCase(),
|
||||
);
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('checkOption', (selector) => {
|
||||
cy.get(selector).find('.q-checkbox__inner').click();
|
||||
});
|
||||
|
@ -207,14 +251,17 @@ Cypress.Commands.add('saveCard', () => {
|
|||
Cypress.Commands.add('resetCard', () => {
|
||||
cy.get('[title="Reset"]').click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('removeCard', () => {
|
||||
cy.get('[title="Remove"]').click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('addCard', () => {
|
||||
cy.waitForElement('tbody');
|
||||
cy.waitForElement('.q-page-sticky > div > .q-btn');
|
||||
cy.get('.q-page-sticky > div > .q-btn').click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('clickConfirm', () => {
|
||||
cy.waitForElement('.q-dialog__inner > .q-card');
|
||||
cy.get('.q-card__actions > .q-btn--unelevated > .q-btn__content > .block').click();
|
||||
|
@ -295,6 +342,7 @@ Cypress.Commands.add('removeRow', (rowIndex) => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('openListSummary', (row) => {
|
||||
cy.get('.card-list-body .actions .q-btn:nth-child(2)').eq(row).click();
|
||||
});
|
||||
|
@ -322,20 +370,8 @@ Cypress.Commands.add('validateContent', (selector, expectedValue) => {
|
|||
cy.get(selector).should('have.text', expectedValue);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('openActionDescriptor', (opt) => {
|
||||
cy.openActionsDescriptor();
|
||||
const listItem = '[role="menu"] .q-list .q-item';
|
||||
cy.contains(listItem, opt).click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('openActionsDescriptor', () => {
|
||||
cy.get('[data-cy="descriptor-more-opts"]').click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('clickButtonDescriptor', (id) => {
|
||||
cy.get(`.actions > .q-card__actions> .q-btn:nth-child(${id})`)
|
||||
.invoke('removeAttr', 'target')
|
||||
.click();
|
||||
cy.get('[data-cy="cardDescriptor"] [data-cy="descriptor-more-opts"]').click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('openUserPanel', () => {
|
||||
|
@ -424,3 +460,137 @@ Cypress.Commands.add('searchBtnFilterPanel', () => {
|
|||
Cypress.Commands.add('waitRequest', (alias, cb) => {
|
||||
cy.wait(alias).then(cb);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('validateDescriptor', (toCheck = {}) => {
|
||||
const { title, description, subtitle, listbox = {}, popup = false } = toCheck;
|
||||
|
||||
const popupSelector = popup ? '[role="menu"] ' : '';
|
||||
|
||||
if (title) cy.get(`${popupSelector}[data-cy="cardDescriptor_title"]`).contains(title);
|
||||
if (description)
|
||||
cy.get(`${popupSelector}[data-cy="cardDescriptor_description"]`).contains(
|
||||
description,
|
||||
);
|
||||
if (subtitle)
|
||||
cy.get(`${popupSelector}[data-cy="cardDescriptor_subtitle"]`).contains(subtitle);
|
||||
|
||||
for (const index in listbox)
|
||||
cy.get(`${popupSelector}[data-cy="cardDescriptor_listbox"] > *`)
|
||||
.eq(index)
|
||||
.should('contain.text', listbox[index]);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('validateVnTableRows', (opts = {}) => {
|
||||
let { cols = [], rows = [] } = opts;
|
||||
if (!Array.isArray(cols)) cols = [cols];
|
||||
const rowSelector = rows.length
|
||||
? rows.map((row) => `> :nth-child(${row})`).join(', ')
|
||||
: '> *';
|
||||
cy.get(`[data-cy="vnTable"] .q-virtual-scroll__content`).within(() => {
|
||||
cy.get(`${rowSelector}`).each(($el) => {
|
||||
for (const { name, type = 'string', val, operation = 'equal' } of cols) {
|
||||
cy.wrap($el)
|
||||
.find(`[data-cy="vnTableCell_${name}"]`)
|
||||
.invoke('text')
|
||||
.then((text) => {
|
||||
if (type === 'string')
|
||||
expect(text.trim().toLowerCase()).to[operation](
|
||||
val.toLowerCase(),
|
||||
);
|
||||
if (type === 'number') cy.checkNumber(text, val, operation);
|
||||
if (type === 'date') cy.checkDate(text, val, operation);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('checkDate', (rawDate, expectedVal, operation) => {
|
||||
const date = moment(rawDate.trim(), 'MM/DD/YYYY');
|
||||
const compareDate = moment(expectedVal, 'DD/MM/YYYY');
|
||||
|
||||
switch (operation) {
|
||||
case 'equal':
|
||||
expect(text.trim()).to.equal(compareDate);
|
||||
break;
|
||||
case 'before':
|
||||
expect(date.isBefore(compareDate)).to.be.true;
|
||||
break;
|
||||
case 'after':
|
||||
expect(date.isAfter(compareDate)).to.be.true;
|
||||
}
|
||||
});
|
||||
|
||||
Cypress.Commands.add('selectDescriptorOption', (opt = 1) => {
|
||||
const listItem = '[data-cy="descriptor-more-opts_list"]';
|
||||
cy.get('body').then(($body) => {
|
||||
if (!$body.find(listItem).length) cy.openActionsDescriptor();
|
||||
});
|
||||
|
||||
cy.waitForElement(listItem);
|
||||
cy.get(`${listItem} > :not(template):nth-of-type(${opt})`).click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('validateCheckbox', (selector, expectedVal = 'true') => {
|
||||
cy.get(selector).should('have.attr', 'aria-checked', expectedVal.toString());
|
||||
});
|
||||
|
||||
Cypress.Commands.add('validateDownload', (trigger, opts = {}) => {
|
||||
const {
|
||||
url = /api\/dms\/\d+\/downloadFile\?access_token=.+/,
|
||||
types = ['text/plain', 'image/jpeg'],
|
||||
alias = 'download',
|
||||
} = opts;
|
||||
cy.intercept('GET', url).as(alias);
|
||||
trigger().then(() => {
|
||||
cy.wait(`@${alias}`).then(({ response }) => {
|
||||
expect(response.statusCode).to.equal(200);
|
||||
const isValidType = types.some((type) =>
|
||||
response.headers['content-type'].includes(type),
|
||||
);
|
||||
expect(isValidType).to.be.true;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('validatePdfDownload', (match, trigger) => {
|
||||
cy.window().then((win) => {
|
||||
cy.stub(win, 'open')
|
||||
.callsFake(() => null)
|
||||
.as('pdf');
|
||||
});
|
||||
trigger();
|
||||
cy.get('@pdf')
|
||||
.should('be.calledOnce')
|
||||
.then((stub) => {
|
||||
const [url] = stub.getCall(0).args;
|
||||
expect(url).to.match(match);
|
||||
cy.request(url).then((response) =>
|
||||
expect(response.headers['content-type']).to.include('application/pdf'),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('clicDescriptorAction', (index = 1) => {
|
||||
cy.get(`[data-cy="descriptor_actions"] .q-btn:nth-of-type(${index})`).click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('checkQueryParams', (expectedParams = {}) => {
|
||||
cy.url().then((url) => {
|
||||
const urlParams = new URLSearchParams(url.split('?')[1]);
|
||||
|
||||
for (const key in expectedParams) {
|
||||
const expected = expectedParams[key];
|
||||
const param = JSON.parse(decodeURIComponent(urlParams.get(key)));
|
||||
|
||||
if (typeof expected === 'object') {
|
||||
const { subkey, val } = expected;
|
||||
expect(param[subkey]).to.equal(val);
|
||||
} else expect(param).to.equal(expected);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('waitTableScrollLoad', () =>
|
||||
cy.waitForElement('[data-q-vs-anchor]'),
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue