0
0
Fork 0

Merge branch 'dev' into 7632-useStateQuery

This commit is contained in:
Alex Moreno 2024-09-23 12:28:48 +00:00
commit 689adbc30d
19 changed files with 119 additions and 102 deletions

View File

@ -147,7 +147,7 @@ onMounted(() => {
quasar.platform.is.mobile && !$props.disableOption?.card quasar.platform.is.mobile && !$props.disableOption?.card
? CARD_MODE ? CARD_MODE
: $props.defaultMode; : $props.defaultMode;
stateStore.rightDrawer = true; stateStore.rightDrawer = quasar.screen.gt.xs;
columnsVisibilitySkipped.value = [ columnsVisibilitySkipped.value = [
...splittedColumns.value.columns ...splittedColumns.value.columns
.filter((c) => c.visible == false) .filter((c) => c.visible == false)

View File

@ -2,6 +2,7 @@
import { useStateStore } from 'stores/useStateStore'; import { useStateStore } from 'stores/useStateStore';
import LeftMenu from 'components/LeftMenu.vue'; import LeftMenu from 'components/LeftMenu.vue';
import { onMounted } from 'vue'; import { onMounted } from 'vue';
import { useQuasar } from 'quasar';
const stateStore = useStateStore(); const stateStore = useStateStore();
const $props = defineProps({ const $props = defineProps({
@ -10,7 +11,9 @@ const $props = defineProps({
default: true, default: true,
}, },
}); });
onMounted(() => (stateStore.leftDrawer = $props.leftDrawer)); onMounted(
() => (stateStore.leftDrawer = useQuasar().screen.gt.xs ? $props.leftDrawer : false)
);
</script> </script>
<template> <template>

View File

@ -38,6 +38,10 @@ const $props = defineProps({
type: [Array], type: [Array],
default: () => [], default: () => [],
}, },
exprBuilder: {
type: Function,
default: null,
},
isClearable: { isClearable: {
type: Boolean, type: Boolean,
default: true, default: true,
@ -179,6 +183,7 @@ async function fetchFilter(val) {
}, {}); }, {});
} else defaultWhere = { [key]: getVal(val) }; } else defaultWhere = { [key]: getVal(val) };
const where = { ...(val ? defaultWhere : {}), ...$props.where }; const where = { ...(val ? defaultWhere : {}), ...$props.where };
$props.exprBuilder && Object.assign(where, $props.exprBuilder(key, val));
const fetchOptions = { where, include, limit }; const fetchOptions = { where, include, limit };
if (fields) fetchOptions.fields = fields; if (fields) fetchOptions.fields = fields;
if (sortBy) fetchOptions.order = sortBy; if (sortBy) fetchOptions.order = sortBy;

View File

@ -1,15 +1,18 @@
import { useSession } from './useSession'; import { useSession } from './useSession';
import axios from 'axios'; import axios from 'axios';
import { useQuasar } from 'quasar'; import { useQuasar } from 'quasar';
import { useI18n } from 'vue-i18n';
export function usePrintService() { export function usePrintService() {
const quasar = useQuasar(); const quasar = useQuasar();
const { t } = useI18n();
const { getTokenMultimedia } = useSession(); const { getTokenMultimedia } = useSession();
function sendEmail(path, params) { function sendEmail(path, params) {
return axios.post(path, params).then(() => return axios.post(path, params).then(() =>
quasar.notify({ quasar.notify({
message: 'Notification sent', message: t('globals.notificationSent'),
type: 'positive', type: 'positive',
icon: 'check', icon: 'check',
}) })

View File

@ -16,7 +16,7 @@ import { useVnConfirm } from 'composables/useVnConfirm';
import VnTable from 'components/VnTable/VnTable.vue'; import VnTable from 'components/VnTable/VnTable.vue';
import VnInput from 'components/common/VnInput.vue'; import VnInput from 'components/common/VnInput.vue';
import VnSubToolbar from 'components/ui/VnSubToolbar.vue'; import VnSubToolbar from 'components/ui/VnSubToolbar.vue';
import VnFilter from 'components/VnTable/VnFilter.vue'; import VnSelect from 'src/components/common/VnSelect.vue';
import CustomerNewPayment from 'src/pages/Customer/components/CustomerNewPayment.vue'; import CustomerNewPayment from 'src/pages/Customer/components/CustomerNewPayment.vue';
import InvoiceOutDescriptorProxy from 'src/pages/InvoiceOut/Card/InvoiceOutDescriptorProxy.vue'; import InvoiceOutDescriptorProxy from 'src/pages/InvoiceOut/Card/InvoiceOutDescriptorProxy.vue';
@ -33,9 +33,9 @@ const stateStore = useStateStore();
const user = state.getUser(); const user = state.getUser();
const clientRisk = ref([]); const clientRisk = ref([]);
const companies = ref([]);
const tableRef = ref(); const tableRef = ref();
const companyId = ref(user.value.companyFk); const companyId = ref(user.value.companyFk);
const companyLastId = ref(user.value.companyFk);
const balances = ref([]); const balances = ref([]);
const vnFilterRef = ref({}); const vnFilterRef = ref({});
const filter = computed(() => { const filter = computed(() => {
@ -45,33 +45,6 @@ const filter = computed(() => {
}; };
}); });
const companyFilterColumn = {
align: 'left',
name: 'companyId',
label: t('Company'),
component: 'select',
attrs: {
url: 'Companies',
optionLabel: 'code',
sortBy: 'code',
limit: 0,
},
columnFilter: {
event: {
remove: () => (companyId.value = null),
'update:modelValue': (newCompanyFk) => {
if (!newCompanyFk) return;
vnFilterRef.value.addFilter(newCompanyFk);
companyLastId.value = newCompanyFk;
},
blur: () =>
!companyId.value &&
(companyId.value = companyLastId.value ?? user.value.companyFk),
},
},
visible: false,
};
const columns = computed(() => [ const columns = computed(() => [
{ {
align: 'right', align: 'right',
@ -166,6 +139,11 @@ onBeforeMount(() => {
}); });
async function getCurrentBalance(data) { async function getCurrentBalance(data) {
currentBalance.value[companyId.value] = {
amount: 0,
code: companies.value.find((c) => c.id === companyId.value)?.code,
};
for (const balance of data) { for (const balance of data) {
currentBalance.value[balance.companyFk] = { currentBalance.value[balance.companyFk] = {
code: balance.company.code, code: balance.company.code,
@ -192,14 +170,21 @@ const showBalancePdf = ({ id }) => {
<template> <template>
<FetchData <FetchData
url="Companies"
auto-load
@on-fetch="(data) => (companies = data)"
></FetchData>
<FetchData
v-if="companies.length > 0"
url="clientRisks" url="clientRisks"
:filter="{ :filter="{
include: { relation: 'company', scope: { fields: ['code'] } }, include: { relation: 'company', scope: { fields: ['code'] } },
where: { clientFk: route.params.id, companyFk: companyId }, where: { clientFk: route.params.id },
}" }"
auto-load auto-load
@on-fetch="getCurrentBalance" @on-fetch="getCurrentBalance"
></FetchData> ></FetchData>
<VnSubToolbar class="q-mb-md"> <VnSubToolbar class="q-mb-md">
<template #st-data> <template #st-data>
<div class="column justify-center q-px-md q-py-sm"> <div class="column justify-center q-px-md q-py-sm">
@ -212,13 +197,15 @@ const showBalancePdf = ({ id }) => {
</template> </template>
<template #st-actions> <template #st-actions>
<div> <div>
<VnFilter <VnSelect
:label="t('Company')"
ref="vnFilterRef" ref="vnFilterRef"
v-model="companyId" v-model="companyId"
data-key="CustomerBalance" data-key="CustomerBalance"
:column="companyFilterColumn" :options="companies"
search-url="balance" option-label="code"
/> option-value="id"
></VnSelect>
</div> </div>
</template> </template>
</VnSubToolbar> </VnSubToolbar>

View File

@ -16,6 +16,19 @@ const { t } = useI18n();
const businessTypes = ref([]); const businessTypes = ref([]);
const contactChannels = ref([]); const contactChannels = ref([]);
const title = ref(); const title = ref();
const handleSalesModelValue = (val) => ({
or: [
{ name: val },
{ nickname: { like: '%' + val + '%' } },
{ code: { like: `${val}%` } },
],
});
const exprBuilder = (param, value) => {
return {
and: [{ active: { neq: false } }, handleSalesModelValue(value)],
};
};
</script> </script>
<template> <template>
<FetchData <FetchData
@ -34,7 +47,7 @@ const title = ref();
<VnRow> <VnRow>
<VnInput <VnInput
:label="t('globals.name')" :label="t('globals.name')"
:rules="validate('client.socialName')" :rules="validate('client.name')"
autofocus autofocus
clearable clearable
v-model="data.name" v-model="data.name"
@ -99,7 +112,7 @@ const title = ref();
:fields="['id', 'nickname']" :fields="['id', 'nickname']"
sort-by="nickname ASC" sort-by="nickname ASC"
:rules="validate('client.salesPersonFk')" :rules="validate('client.salesPersonFk')"
:use-like="false" :expr-builder="exprBuilder"
emit-value emit-value
auto-load auto-load
> >

View File

@ -190,6 +190,18 @@ const setData = (entity) => (data.value = useCardDescription(entity?.name, entit
> >
<QTooltip>{{ t('Go to user') }}</QTooltip> <QTooltip>{{ t('Go to user') }}</QTooltip>
</QBtn> </QBtn>
<QBtn
v-if="entity.supplier"
:to="{
name: 'SupplierSummary',
params: { id: entity.supplier.id },
}"
size="md"
icon="vn:supplier"
color="primary"
>
<QTooltip>{{ t('Go to supplier') }}</QTooltip>
</QBtn>
</QCardActions> </QCardActions>
</template> </template>
</CardDescriptor> </CardDescriptor>
@ -204,6 +216,7 @@ es:
Customer ticket list: Listado de tickets del cliente Customer ticket list: Listado de tickets del cliente
Customer invoice out list: Listado de facturas del cliente Customer invoice out list: Listado de facturas del cliente
Go to user: Ir al usuario Go to user: Ir al usuario
Go to supplier: Ir al proveedor
Customer unpaid: Cliente impago Customer unpaid: Cliente impago
Unpaid: Impagado Unpaid: Impagado
unpaidDated: 'Fecha {dated}' unpaidDated: 'Fecha {dated}'

View File

@ -134,15 +134,17 @@ function handleLocation(data, location) {
</QTooltip> </QTooltip>
</QIcon> </QIcon>
</div> </div>
<QCheckbox :label="t('Verified data')" v-model="data.isTaxDataChecked" /> <QCheckbox :label="t('Daily invoice')" v-model="data.hasDailyInvoice" />
</VnRow> </VnRow>
<VnRow> <VnRow>
<QCheckbox <QCheckbox
:label="t('Electronic invoice')" :label="t('Electronic invoice')"
v-model="data.hasElectronicInvoice" v-model="data.hasElectronicInvoice"
/><QCheckbox
:label="t('Verified data')"
v-model="data.isTaxDataChecked"
/> />
<QCheckbox :label="t('Daily invoice')" v-model="data.hasDailyInvoice" />
</VnRow> </VnRow>
</template> </template>
</FormModel> </FormModel>

View File

@ -1,35 +1,20 @@
<script setup> <script setup>
import { ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import FetchData from 'components/FetchData.vue';
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue'; import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
import VnSelect from 'components/common/VnSelect.vue'; import VnSelect from 'components/common/VnSelect.vue';
import VnInput from 'src/components/common/VnInput.vue'; import VnInput from 'src/components/common/VnInput.vue';
const { t } = useI18n(); const { t } = useI18n();
const props = defineProps({ defineProps({
dataKey: { dataKey: {
type: String, type: String,
required: true, required: true,
}, },
}); });
const provinces = ref();
const workers = ref();
const zones = ref();
</script> </script>
<template> <template>
<FetchData url="Provinces" @on-fetch="(data) => (provinces = data)" auto-load /> <VnFilterPanel :data-key="dataKey" :search-button="true" search-url="table">
<FetchData url="Zones" @on-fetch="(data) => (zones = data)" auto-load />
<FetchData
url="Workers/activeWithInheritedRole"
:filter="{ where: { role: 'salesPerson' } }"
@on-fetch="(data) => (workers = data)"
auto-load
/>
<VnFilterPanel :data-key="props.dataKey" :search-button="true" search-url="table">
<template #tags="{ tag, formatFn }"> <template #tags="{ tag, formatFn }">
<div class="q-gutter-x-xs"> <div class="q-gutter-x-xs">
<strong>{{ t(`params.${tag.label}`) }}: </strong> <strong>{{ t(`params.${tag.label}`) }}: </strong>
@ -65,15 +50,14 @@ const zones = ref();
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem class="q-mb-sm"> <QItem class="q-mb-sm">
<QItemSection v-if="!workers"> <QItemSection>
<QSkeleton type="QInput" class="full-width" />
</QItemSection>
<QItemSection v-if="workers">
<VnSelect <VnSelect
url="Workers/activeWithInheritedRole"
:filter="{ where: { role: 'salesPerson' } }"
auto-load
:label="t('Salesperson')" :label="t('Salesperson')"
v-model="params.salesPersonFk" v-model="params.salesPersonFk"
@update:model-value="searchFn()" @update:model-value="searchFn()"
:options="workers"
option-value="id" option-value="id"
option-label="name" option-label="name"
emit-value emit-value
@ -88,15 +72,12 @@ const zones = ref();
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem class="q-mb-sm"> <QItem class="q-mb-sm">
<QItemSection v-if="!provinces"> <QItemSection
<QSkeleton type="QInput" class="full-width" /> ><VnSelect
</QItemSection> url="Provinces"
<QItemSection v-if="provinces">
<VnSelect
:label="t('Province')" :label="t('Province')"
v-model="params.provinceFk" v-model="params.provinceFk"
@update:model-value="searchFn()" @update:model-value="searchFn()"
:options="provinces"
option-value="id" option-value="id"
option-label="name" option-label="name"
emit-value emit-value
@ -105,6 +86,7 @@ const zones = ref();
dense dense
outlined outlined
rounded rounded
auto-load
:input-debounce="0" :input-debounce="0"
/> />
</QItemSection> </QItemSection>
@ -135,15 +117,11 @@ const zones = ref();
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem> <QItem>
<QItemSection v-if="!zones">
<QSkeleton type="QInput" class="full-width" />
</QItemSection>
<QItemSection v-if="zones">
<VnSelect <VnSelect
url="Zones"
:label="t('Zone')" :label="t('Zone')"
v-model="params.zoneFk" v-model="params.zoneFk"
@update:model-value="searchFn()" @update:model-value="searchFn()"
:options="zones"
option-value="id" option-value="id"
option-label="name" option-label="name"
emit-value emit-value
@ -152,8 +130,8 @@ const zones = ref();
dense dense
outlined outlined
rounded rounded
auto-load
/> />
</QItemSection>
</QItem> </QItem>
<QItem> <QItem>
<QItemSection> <QItemSection>

View File

@ -8,10 +8,10 @@ import VnLocation from 'src/components/common/VnLocation.vue';
import VnSearchbar from 'components/ui/VnSearchbar.vue'; import VnSearchbar from 'components/ui/VnSearchbar.vue';
import CustomerSummary from './Card/CustomerSummary.vue'; import CustomerSummary from './Card/CustomerSummary.vue';
import { useSummaryDialog } from 'src/composables/useSummaryDialog'; import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import RightMenu from 'src/components/common/RightMenu.vue';
import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue'; import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue';
import { toDate } from 'src/filters'; import { toDate } from 'src/filters';
import CustomerFilter from './CustomerFilter.vue';
const { t } = useI18n(); const { t } = useI18n();
const router = useRouter(); const router = useRouter();
@ -397,6 +397,11 @@ function handleLocation(data, location) {
:label="t('Search customer')" :label="t('Search customer')"
data-key="Customer" data-key="Customer"
/> />
<RightMenu>
<template #right-panel>
<CustomerFilter data-key="Customer" />
</template>
</RightMenu>
<VnTable <VnTable
ref="tableRef" ref="tableRef"
data-key="Customer" data-key="Customer"
@ -413,6 +418,7 @@ function handleLocation(data, location) {
order="id DESC" order="id DESC"
:columns="columns" :columns="columns"
redirect="customer" redirect="customer"
:right-search="false"
auto-load auto-load
> >
<template #more-create-dialog="{ data }"> <template #more-create-dialog="{ data }">
@ -425,7 +431,6 @@ function handleLocation(data, location) {
}" }"
:fields="['id', 'nickname']" :fields="['id', 'nickname']"
sort-by="nickname ASC" sort-by="nickname ASC"
:use-like="false"
emit-value emit-value
auto-load auto-load
> >

View File

@ -134,6 +134,7 @@ function handleLocation(data, location) {
option-label="fiscalName" option-label="fiscalName"
option-value="id" option-value="id"
v-model="data.customsAgentFk" v-model="data.customsAgentFk"
:tooltip="t('Create a new expense')"
> >
<template #form> <template #form>
<CustomerNewCustomsAgent @on-data-saved="refreshData()" /> <CustomerNewCustomsAgent @on-data-saved="refreshData()" />

View File

@ -11,7 +11,7 @@ import VnRow from 'components/ui/VnRow.vue';
import VnInput from 'src/components/common/VnInput.vue'; import VnInput from 'src/components/common/VnInput.vue';
import VnSelect from 'src/components/common/VnSelect.vue'; import VnSelect from 'src/components/common/VnSelect.vue';
import VnSelectDialog from 'src/components/common/VnSelectDialog.vue'; import VnSelectDialog from 'src/components/common/VnSelectDialog.vue';
import CustomsNewCustomsAgent from 'src/pages/Customer/components/CustomerNewCustomsAgent.vue'; import CustomerNewCustomsAgent from 'src/pages/Customer/components/CustomerNewCustomsAgent.vue';
const { t } = useI18n(); const { t } = useI18n();
const route = useRoute(); const route = useRoute();
@ -226,9 +226,10 @@ function handleLocation(data, location) {
option-label="fiscalName" option-label="fiscalName"
option-value="id" option-value="id"
v-model="data.customsAgentFk" v-model="data.customsAgentFk"
:tooltip="t('New customs agent')"
> >
<template #form> <template #form>
<CustomsNewCustomsAgent /> <CustomerNewCustomsAgent />
</template> </template>
</VnSelectDialog> </VnSelectDialog>
</div> </div>
@ -309,6 +310,7 @@ es:
Mobile: Movíl Mobile: Movíl
Incoterms: Incoterms Incoterms: Incoterms
Customs agent: Agente de aduanas Customs agent: Agente de aduanas
New customs agent: Nuevo agente de aduanas
Notes: Notas Notes: Notas
Observation type: Tipo de observación Observation type: Tipo de observación
Description: Descripción Description: Descripción

View File

@ -46,7 +46,6 @@ const onSubmit = async () => {
}; };
try { try {
await axios.patch(`Clients/${$props.id}/setPassword`, payload); await axios.patch(`Clients/${$props.id}/setPassword`, payload);
await $props.promise();
} catch (error) { } catch (error) {
notify('errors.create', 'negative'); notify('errors.create', 'negative');
} finally { } finally {

View File

@ -58,7 +58,7 @@ customer:
vies: VIES vies: VIES
payMethod: Método de pago payMethod: Método de pago
bankAccount: Cuenta bancaria bankAccount: Cuenta bancaria
dueDay: Día de pago dueDay: Vencimiento
hasLcr: Recibido LCR hasLcr: Recibido LCR
hasCoreVnl: Recibido core VNL hasCoreVnl: Recibido core VNL
hasB2BVnl: Recibido B2B VNL hasB2BVnl: Recibido B2B VNL

View File

@ -39,6 +39,7 @@ ticketSale:
agency: Agency agency: Agency
address: Address address: Address
advanceTickets: advanceTickets:
preparation: Preparation
origin: Origin origin: Origin
destination: Destination destination: Destination
originAgency: 'Origin agency: {agency}' originAgency: 'Origin agency: {agency}'

View File

@ -86,6 +86,7 @@ weeklyTickets:
search: Buscar por tickets programados search: Buscar por tickets programados
searchInfo: Buscar tickets programados por el identificador o el identificador del cliente searchInfo: Buscar tickets programados por el identificador o el identificador del cliente
advanceTickets: advanceTickets:
preparation: Preparación
origin: Origen origin: Origen
destination: Destinatario destination: Destinatario
originAgency: 'Agencia origen: {agency}' originAgency: 'Agencia origen: {agency}'

View File

@ -37,7 +37,7 @@ describe('ClaimDevelopment', () => {
cy.wait(['@workers', '@workers']); cy.wait(['@workers', '@workers']);
cy.addCard(); cy.addCard();
cy.get(thirdRow).should('exist'); cy.waitForElement(thirdRow);
const rowData = [ const rowData = [
false, false,

View File

@ -34,22 +34,25 @@ describe('VnLocation', () => {
cy.visit('/#/supplier/567/fiscal-data', { timeout: 7000 }); cy.visit('/#/supplier/567/fiscal-data', { timeout: 7000 });
cy.waitForElement('.q-form'); cy.waitForElement('.q-form');
}); });
it('Fin by postalCode', () => { it('Find by postalCode', () => {
const postCode = '46600'; const postCode = '46600';
const postCodeLabel = '46600, Valencia(Province one), España';
const firstOption = '[role="listbox"] .q-item:nth-child(1)'; const firstOption = '[role="listbox"] .q-item:nth-child(1)';
cy.get(inputLocation).click(); cy.get(inputLocation).click();
cy.get(inputLocation).clear(); cy.get(inputLocation).clear();
cy.get(inputLocation).type(postCode); cy.get(inputLocation).type(postCode);
cy.get(locationOptions).should('have.length.at.least', 2); cy.get(locationOptions)
.get(':nth-child(1)')
.should('have.length.at.least', 2);
cy.get(
firstOption.concat(' > .q-item__section > .q-item__label--caption')
).should('have.text', postCodeLabel);
cy.get(firstOption).click(); cy.get(firstOption).click();
cy.get('.q-btn-group > .q-btn--standard > .q-btn__content > .q-icon').click(); cy.get('.q-btn-group > .q-btn--standard > .q-btn__content > .q-icon').click();
cy.reload(); cy.reload();
cy.waitForElement('.q-form'); cy.waitForElement('.q-form');
cy.get(inputLocation).should( cy.get(inputLocation).should('have.value', postCodeLabel);
'have.value',
'46600 - Valencia(Province one), España'
);
}); });
it('Create postCode', () => { it('Create postCode', () => {

View File

@ -140,6 +140,7 @@ Cypress.Commands.add('removeCard', () => {
}); });
Cypress.Commands.add('addCard', () => { Cypress.Commands.add('addCard', () => {
cy.waitForElement('tbody'); cy.waitForElement('tbody');
cy.waitForElement('.q-page-sticky > div > .q-btn');
cy.get('.q-page-sticky > div > .q-btn').click(); cy.get('.q-page-sticky > div > .q-btn').click();
}); });
Cypress.Commands.add('clickConfirm', () => { Cypress.Commands.add('clickConfirm', () => {