Item Fixed prices #307
|
@ -5,6 +5,8 @@ All notable changes to this project will be documented in this file.
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [2420.01]
|
||||||
|
|
||||||
## [2418.01]
|
## [2418.01]
|
||||||
|
|
||||||
## [2416.01] - 2024-04-18
|
## [2416.01] - 2024-04-18
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "salix-front",
|
"name": "salix-front",
|
||||||
"version": "24.18.0",
|
"version": "24.20.0",
|
||||||
"description": "Salix frontend",
|
"description": "Salix frontend",
|
||||||
"productName": "Salix",
|
"productName": "Salix",
|
||||||
"author": "Verdnatura",
|
"author": "Verdnatura",
|
||||||
|
|
14490
pnpm-lock.yaml
14490
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
@ -81,6 +81,7 @@ const emit = defineEmits(['onFetch', 'onDataSaved']);
|
||||||
const componentIsRendered = ref(false);
|
const componentIsRendered = ref(false);
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
originalData.value = $props.formInitialData;
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
componentIsRendered.value = true;
|
componentIsRendered.value = true;
|
||||||
});
|
});
|
||||||
|
@ -101,7 +102,7 @@ onMounted(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
onBeforeRouteLeave((to, from, next) => {
|
onBeforeRouteLeave((to, from, next) => {
|
||||||
if (hasChanges.value)
|
if (hasChanges.value && $props.observeFormChanges)
|
||||||
quasar.dialog({
|
quasar.dialog({
|
||||||
component: VnConfirm,
|
component: VnConfirm,
|
||||||
componentProps: {
|
componentProps: {
|
||||||
|
@ -126,7 +127,7 @@ const isLoading = ref(false);
|
||||||
// Si elegimos observar los cambios del form significa que inicialmente las actions estaran deshabilitadas
|
// Si elegimos observar los cambios del form significa que inicialmente las actions estaran deshabilitadas
|
||||||
const isResetting = ref(false);
|
const isResetting = ref(false);
|
||||||
const hasChanges = ref(!$props.observeFormChanges);
|
const hasChanges = ref(!$props.observeFormChanges);
|
||||||
const originalData = ref({ ...$props.formInitialData });
|
const originalData = ref({});
|
||||||
const formData = computed(() => state.get($props.model));
|
const formData = computed(() => state.get($props.model));
|
||||||
const formUrl = computed(() => $props.url);
|
const formUrl = computed(() => $props.url);
|
||||||
const defaultButtons = computed(() => ({
|
const defaultButtons = computed(() => ({
|
||||||
|
@ -154,14 +155,18 @@ const startFormWatcher = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
async function fetch() {
|
async function fetch() {
|
||||||
const { data } = await axios.get($props.url, {
|
try {
|
||||||
params: { filter: JSON.stringify($props.filter) },
|
const { data } = await axios.get($props.url, {
|
||||||
});
|
params: { filter: JSON.stringify($props.filter) },
|
||||||
|
});
|
||||||
|
state.set($props.model, data);
|
||||||
|
originalData.value = data && JSON.parse(JSON.stringify(data));
|
||||||
|
|
||||||
state.set($props.model, data);
|
emit('onFetch', state.get($props.model));
|
||||||
originalData.value = data && JSON.parse(JSON.stringify(data));
|
} catch (error) {
|
||||||
|
state.set($props.model, {});
|
||||||
emit('onFetch', state.get($props.model));
|
originalData.value = {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function save() {
|
async function save() {
|
||||||
|
|
|
@ -76,6 +76,16 @@ defineExpose({
|
||||||
<p>{{ subtitle }}</p>
|
<p>{{ subtitle }}</p>
|
||||||
<slot name="form-inputs" :data="data" :validate="validate" />
|
<slot name="form-inputs" :data="data" :validate="validate" />
|
||||||
<div class="q-mt-lg row justify-end">
|
<div class="q-mt-lg row justify-end">
|
||||||
|
<QBtn
|
||||||
|
:label="t('globals.cancel')"
|
||||||
|
:title="t('globals.cancel')"
|
||||||
|
type="reset"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
:disabled="isLoading"
|
||||||
|
:loading="isLoading"
|
||||||
|
v-close-popup
|
||||||
|
/>
|
||||||
<QBtn
|
<QBtn
|
||||||
:label="t('globals.save')"
|
:label="t('globals.save')"
|
||||||
:title="t('globals.save')"
|
:title="t('globals.save')"
|
||||||
|
@ -84,17 +94,6 @@ defineExpose({
|
||||||
:disabled="isLoading"
|
:disabled="isLoading"
|
||||||
:loading="isLoading"
|
:loading="isLoading"
|
||||||
/>
|
/>
|
||||||
<QBtn
|
|
||||||
:label="t('globals.cancel')"
|
|
||||||
:title="t('globals.cancel')"
|
|
||||||
type="reset"
|
|
||||||
color="primary"
|
|
||||||
flat
|
|
||||||
class="q-ml-sm"
|
|
||||||
:disabled="isLoading"
|
|
||||||
:loading="isLoading"
|
|
||||||
v-close-popup
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</FormModel>
|
</FormModel>
|
||||||
|
|
|
@ -56,14 +56,6 @@ const closeForm = () => {
|
||||||
<p>{{ subtitle }}</p>
|
<p>{{ subtitle }}</p>
|
||||||
<slot name="form-inputs" />
|
<slot name="form-inputs" />
|
||||||
<div class="q-mt-lg row justify-end">
|
<div class="q-mt-lg row justify-end">
|
||||||
<QBtn
|
|
||||||
v-if="defaultSubmitButton"
|
|
||||||
:label="customSubmitButtonLabel || t('globals.save')"
|
|
||||||
type="submit"
|
|
||||||
color="primary"
|
|
||||||
:disabled="isLoading"
|
|
||||||
:loading="isLoading"
|
|
||||||
/>
|
|
||||||
<QBtn
|
<QBtn
|
||||||
v-if="defaultCancelButton"
|
v-if="defaultCancelButton"
|
||||||
:label="t('globals.cancel')"
|
:label="t('globals.cancel')"
|
||||||
|
@ -74,6 +66,14 @@ const closeForm = () => {
|
||||||
:loading="isLoading"
|
:loading="isLoading"
|
||||||
v-close-popup
|
v-close-popup
|
||||||
/>
|
/>
|
||||||
|
<QBtn
|
||||||
|
v-if="defaultSubmitButton"
|
||||||
|
:label="customSubmitButtonLabel || t('globals.save')"
|
||||||
|
type="submit"
|
||||||
|
color="primary"
|
||||||
|
:disabled="isLoading"
|
||||||
|
:loading="isLoading"
|
||||||
|
/>
|
||||||
<slot name="customButtons" />
|
<slot name="customButtons" />
|
||||||
</div>
|
</div>
|
||||||
</QCard>
|
</QCard>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref, reactive } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { QSeparator, useQuasar } from 'quasar';
|
import { QSeparator, useQuasar } from 'quasar';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
@ -22,6 +22,8 @@ const props = defineProps({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const expansionItemElements = reactive({});
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await navigation.fetchPinned();
|
await navigation.fetchPinned();
|
||||||
getRoutes();
|
getRoutes();
|
||||||
|
@ -108,6 +110,10 @@ async function togglePinned(item, event) {
|
||||||
type: 'positive',
|
type: 'positive',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleItemExpansion = (itemName) => {
|
||||||
|
expansionItemElements[itemName].scrollToLastElement();
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -213,8 +219,12 @@ async function togglePinned(item, event) {
|
||||||
:icon="item.icon"
|
:icon="item.icon"
|
||||||
:label="t(item.title)"
|
:label="t(item.title)"
|
||||||
:content-inset-level="0.5"
|
:content-inset-level="0.5"
|
||||||
|
@after-show="handleItemExpansion(item.name)"
|
||||||
>
|
>
|
||||||
<LeftMenuItemGroup :item="item" />
|
<LeftMenuItemGroup
|
||||||
|
:ref="(el) => (expansionItemElements[item.name] = el)"
|
||||||
|
:item="item"
|
||||||
|
/>
|
||||||
</QExpansionItem>
|
</QExpansionItem>
|
||||||
</QList>
|
</QList>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import LeftMenuItem from './LeftMenuItem.vue';
|
import LeftMenuItem from './LeftMenuItem.vue';
|
||||||
|
import { elementIsVisibleInViewport } from 'src/composables/elementIsVisibleInViewport';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
item: {
|
item: {
|
||||||
|
@ -13,10 +14,27 @@ const props = defineProps({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const groupEnd = ref(null);
|
||||||
|
|
||||||
|
const scrollToLastElement = () => {
|
||||||
|
if (groupEnd.value && !elementIsVisibleInViewport(groupEnd.value)) {
|
||||||
|
groupEnd.value.scrollIntoView({
|
||||||
|
behavior: 'smooth',
|
||||||
|
block: 'end',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const item = computed(() => props.item); // eslint-disable-line vue/no-dupe-keys
|
const item = computed(() => props.item); // eslint-disable-line vue/no-dupe-keys
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
scrollToLastElement,
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<template v-for="section in item.children" :key="section.name">
|
<template v-for="section in item.children" :key="section.name">
|
||||||
<LeftMenuItem :item="section" />
|
<LeftMenuItem :item="section" />
|
||||||
</template>
|
</template>
|
||||||
|
<div ref="groupEnd" />
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
<script setup>
|
||||||
|
import { onBeforeMount, computed } from 'vue';
|
||||||
|
import { useRoute, onBeforeRouteUpdate } from 'vue-router';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useArrayData } from 'src/composables/useArrayData';
|
||||||
|
import { useStateStore } from 'stores/useStateStore';
|
||||||
|
import useCardSize from 'src/composables/useCardSize';
|
||||||
|
import VnSubToolbar from '../ui/VnSubToolbar.vue';
|
||||||
|
import VnSearchbar from 'components/ui/VnSearchbar.vue';
|
||||||
|
import LeftMenu from 'components/LeftMenu.vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
dataKey: { type: String, required: true },
|
||||||
|
baseUrl: { type: String, default: undefined },
|
||||||
|
customUrl: { type: String, default: undefined },
|
||||||
|
filter: { type: Object, default: () => {} },
|
||||||
|
descriptor: { type: Object, required: true },
|
||||||
|
searchbarDataKey: { type: String, default: undefined },
|
||||||
|
searchbarUrl: { type: String, default: undefined },
|
||||||
|
searchbarLabel: { type: String, default: '' },
|
||||||
|
searchbarInfo: { type: String, default: '' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const stateStore = useStateStore();
|
||||||
|
const route = useRoute();
|
||||||
|
const url = computed(() => {
|
||||||
|
if (props.baseUrl) return `${props.baseUrl}/${route.params.id}`;
|
||||||
|
return props.customUrl;
|
||||||
|
});
|
||||||
|
|
||||||
|
const arrayData = useArrayData(props.dataKey, {
|
||||||
|
url: url.value,
|
||||||
|
filter: props.filter,
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeMount(async () => {
|
||||||
|
if (!props.baseUrl) arrayData.store.filter.where = { id: route.params.id };
|
||||||
|
await arrayData.fetch({ append: false });
|
||||||
|
});
|
||||||
|
|
||||||
|
if (props.baseUrl) {
|
||||||
|
onBeforeRouteUpdate(async (to, from) => {
|
||||||
|
if (to.params.id !== from.params.id) {
|
||||||
|
arrayData.store.url = `${props.baseUrl}/${route.params.id}`;
|
||||||
|
await arrayData.fetch({ append: false });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<Teleport
|
||||||
|
to="#searchbar"
|
||||||
|
v-if="stateStore.isHeaderMounted() && props.searchbarDataKey"
|
||||||
|
>
|
||||||
|
<VnSearchbar
|
||||||
|
:data-key="props.searchbarDataKey"
|
||||||
|
:url="props.searchbarUrl"
|
||||||
|
:label="t(props.searchbarLabel)"
|
||||||
|
:info="t(props.searchbarInfo)"
|
||||||
|
/>
|
||||||
|
</Teleport>
|
||||||
|
<QDrawer v-model="stateStore.leftDrawer" show-if-above :width="256">
|
||||||
|
<QScrollArea class="fit">
|
||||||
|
<component :is="descriptor" />
|
||||||
|
<QSeparator />
|
||||||
|
<LeftMenu source="card" />
|
||||||
|
</QScrollArea>
|
||||||
|
</QDrawer>
|
||||||
|
<QPageContainer>
|
||||||
|
<QPage>
|
||||||
|
<VnSubToolbar />
|
||||||
|
<div :class="[useCardSize(), $attrs.class]">
|
||||||
|
<RouterView />
|
||||||
|
</div>
|
||||||
|
</QPage>
|
||||||
|
</QPageContainer>
|
||||||
|
</template>
|
|
@ -187,7 +187,7 @@ const columns = computed(() => [
|
||||||
downloadFile(
|
downloadFile(
|
||||||
prop.row.id,
|
prop.row.id,
|
||||||
$props.downloadModel,
|
$props.downloadModel,
|
||||||
null,
|
undefined,
|
||||||
prop.row.download
|
prop.row.download
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
|
@ -21,7 +21,8 @@ const props = defineProps({
|
||||||
},
|
},
|
||||||
template: {
|
template: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: false,
|
||||||
|
default: '',
|
||||||
},
|
},
|
||||||
locale: {
|
locale: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -49,7 +50,7 @@ updateMessage();
|
||||||
|
|
||||||
function updateMessage() {
|
function updateMessage() {
|
||||||
const params = props.data;
|
const params = props.data;
|
||||||
const key = `templates['${props.template}']`;
|
const key = props.template ? `templates['${props.template}']` : '';
|
||||||
|
|
||||||
message.value = t(key, params, { locale: locale.value });
|
message.value = t(key, params, { locale: locale.value });
|
||||||
}
|
}
|
||||||
|
@ -104,15 +105,14 @@ async function send() {
|
||||||
map-options
|
map-options
|
||||||
:input-debounce="0"
|
:input-debounce="0"
|
||||||
rounded
|
rounded
|
||||||
outlined
|
|
||||||
dense
|
dense
|
||||||
/>
|
/>
|
||||||
</QCardSection>
|
</QCardSection>
|
||||||
<QCardSection class="q-pb-xs">
|
<QCardSection class="q-pb-xs">
|
||||||
<VnInput :label="t('Phone')" v-model="phone" is-outlined />
|
<VnInput :label="t('Phone')" v-model="phone" />
|
||||||
</QCardSection>
|
</QCardSection>
|
||||||
<QCardSection class="q-pb-xs">
|
<QCardSection class="q-pb-xs">
|
||||||
<VnInput v-model="subject" :label="t('Subject')" is-outlined />
|
<VnInput v-model="subject" :label="t('Subject')" />
|
||||||
</QCardSection>
|
</QCardSection>
|
||||||
<QCardSection class="q-mb-md" q-input>
|
<QCardSection class="q-mb-md" q-input>
|
||||||
<QInput
|
<QInput
|
||||||
|
@ -125,7 +125,6 @@ async function send() {
|
||||||
:bottom-slots="true"
|
:bottom-slots="true"
|
||||||
:rules="[(value) => value.length < maxLength || 'Error!']"
|
:rules="[(value) => value.length < maxLength || 'Error!']"
|
||||||
stack-label
|
stack-label
|
||||||
outlined
|
|
||||||
autofocus
|
autofocus
|
||||||
>
|
>
|
||||||
<template #append>
|
<template #append>
|
||||||
|
@ -135,6 +134,11 @@ async function send() {
|
||||||
@click="message = ''"
|
@click="message = ''"
|
||||||
class="cursor-pointer"
|
class="cursor-pointer"
|
||||||
/>
|
/>
|
||||||
|
<QIcon name="info" class="cursor-pointer">
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('messageTooltip') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QIcon>
|
||||||
</template>
|
</template>
|
||||||
<template #counter>
|
<template #counter>
|
||||||
<QChip :color="color" dense>
|
<QChip :color="color" dense>
|
||||||
|
@ -184,18 +188,20 @@ en:
|
||||||
es: Spanish
|
es: Spanish
|
||||||
fr: French
|
fr: French
|
||||||
pt: Portuguese
|
pt: Portuguese
|
||||||
|
messageTooltip: Special characters like accents counts as multiple
|
||||||
es:
|
es:
|
||||||
Send SMS: Enviar SMS
|
Send SMS: Enviar SMS
|
||||||
Language: Idioma
|
Language: Idioma
|
||||||
Phone: Móvil
|
Phone: Móvil
|
||||||
Subject: Asunto
|
Subject: Asunto
|
||||||
Message: Mensaje
|
Message: Mensaje
|
||||||
|
messageTooltip: Carácteres especiales como acentos cuentan como varios
|
||||||
templates:
|
templates:
|
||||||
pendingPayment: 'Su pedido está pendiente de pago.
|
pendingPayment: 'Su pedido está pendiente de pago.
|
||||||
Por favor, entre en la página web y efectue el pago con tarjeta. Muchas gracias.'
|
Por favor, entre en la página web y efectue el pago con tarjeta. Muchas gracias.'
|
||||||
minAmount: 'Es necesario un importe mínimo de 50€ (Sin IVA) en su pedido
|
minAmount: 'Es necesario un importe mínimo de 50€ (Sin IVA) en su pedido
|
||||||
{ orderId } del día { shipped } para recibirlo sin portes adicionales.'
|
{ orderId } con llegada { landing } para recibirlo sin portes adicionales.'
|
||||||
orderChanges: 'Pedido {orderId} día { shipped }: { changes }'
|
orderChanges: 'Pedido {orderId} con llegada estimada día { landing }: { changes }'
|
||||||
en: Inglés
|
en: Inglés
|
||||||
es: Español
|
es: Español
|
||||||
fr: Francés
|
fr: Francés
|
||||||
|
@ -207,12 +213,14 @@ fr:
|
||||||
Phone: Mobile
|
Phone: Mobile
|
||||||
Subject: Affaire
|
Subject: Affaire
|
||||||
Message: Message
|
Message: Message
|
||||||
|
messageTooltip: Les caractères spéciaux comme les accents comptent comme plusieurs
|
||||||
templates:
|
templates:
|
||||||
pendingPayment: 'Votre commande est en attente de paiement.
|
pendingPayment: 'Verdnatura : Commande en attente de règlement. Veuillez régler votre commande avant 9h.
|
||||||
Veuillez vous connecter sur le site web et effectuer le paiement par carte. Merci beaucoup.'
|
Sinon elle sera décalée en fonction de vos jours de livraison . Merci'
|
||||||
minAmount: 'Un montant minimum de 50€ (TVA non incluse) est requis pour votre commande
|
minAmount: 'Verdnatura vous rappelle :
|
||||||
{ orderId } du { shipped } afin de la recevoir sans frais de port supplémentaires.'
|
Montant minimum nécessaire de 50 euros pour recevoir la commande { orderId } livraison { landing }.
|
||||||
orderChanges: 'Commande { orderId } du { shipped }: { changes }'
|
Merci.'
|
||||||
|
orderChanges: 'Commande {orderId} livraison {landing} indisponible/s. Désolés pour le dérangement.'
|
||||||
en: Anglais
|
en: Anglais
|
||||||
es: Espagnol
|
es: Espagnol
|
||||||
fr: Français
|
fr: Français
|
||||||
|
@ -224,12 +232,13 @@ pt:
|
||||||
Phone: Móvel
|
Phone: Móvel
|
||||||
Subject: Assunto
|
Subject: Assunto
|
||||||
Message: Mensagem
|
Message: Mensagem
|
||||||
|
messageTooltip: Caracteres especiais como acentos contam como vários
|
||||||
templates:
|
templates:
|
||||||
pendingPayment: 'Seu pedido está pendente de pagamento.
|
pendingPayment: 'Seu pedido está pendente de pagamento.
|
||||||
Por favor, acesse o site e faça o pagamento com cartão. Muito obrigado.'
|
Por favor, acesse o site e faça o pagamento com cartão. Muito obrigado.'
|
||||||
minAmount: 'É necessário um valor mínimo de 50€ (sem IVA) em seu pedido
|
minAmount: 'É necessário um valor mínimo de 50€ (sem IVA) em seu pedido
|
||||||
{ orderId } do dia { shipped } para recebê-lo sem custos de envio adicionais.'
|
{ orderId } do dia { landing } para recebê-lo sem custos de envio adicionais.'
|
||||||
orderChanges: 'Pedido { orderId } dia { shipped }: { changes }'
|
orderChanges: 'Pedido { orderId } com chegada dia { landing }: { changes }'
|
||||||
en: Inglês
|
en: Inglês
|
||||||
es: Espanhol
|
es: Espanhol
|
||||||
fr: Francês
|
fr: Francês
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onBeforeMount, useSlots, watch, computed, ref } from 'vue';
|
import { onBeforeMount, watch, computed, ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import SkeletonDescriptor from 'components/ui/SkeletonDescriptor.vue';
|
import SkeletonDescriptor from 'components/ui/SkeletonDescriptor.vue';
|
||||||
import { useArrayData } from 'composables/useArrayData';
|
import { useArrayData } from 'composables/useArrayData';
|
||||||
|
@ -38,7 +38,6 @@ const $props = defineProps({
|
||||||
});
|
});
|
||||||
|
|
||||||
const state = useState();
|
const state = useState();
|
||||||
const slots = useSlots();
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { viewSummary } = useSummaryDialog();
|
const { viewSummary } = useSummaryDialog();
|
||||||
const arrayData = useArrayData($props.dataKey || $props.module, {
|
const arrayData = useArrayData($props.dataKey || $props.module, {
|
||||||
|
@ -47,7 +46,7 @@ const arrayData = useArrayData($props.dataKey || $props.module, {
|
||||||
skip: 0,
|
skip: 0,
|
||||||
});
|
});
|
||||||
const { store } = arrayData;
|
const { store } = arrayData;
|
||||||
const entity = computed(() =>Array.isArray( store.data) ? store.data[0] : store.data);
|
const entity = computed(() => (Array.isArray(store.data) ? store.data[0] : store.data));
|
||||||
const isLoading = ref(false);
|
const isLoading = ref(false);
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
|
@ -55,14 +54,12 @@ defineExpose({
|
||||||
});
|
});
|
||||||
onBeforeMount(async () => {
|
onBeforeMount(async () => {
|
||||||
await getData();
|
await getData();
|
||||||
watch(
|
watch($props, async () => await getData());
|
||||||
() => $props.url,
|
|
||||||
async () => await getData()
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
async function getData() {
|
async function getData() {
|
||||||
store.url = $props.url;
|
store.url = $props.url;
|
||||||
|
store.filter = $props.filter ?? {};
|
||||||
isLoading.value = true;
|
isLoading.value = true;
|
||||||
try {
|
try {
|
||||||
const { data } = await arrayData.fetch({ append: false, updateRouter: false });
|
const { data } = await arrayData.fetch({ append: false, updateRouter: false });
|
||||||
|
@ -117,7 +114,7 @@ const emit = defineEmits(['onFetch']);
|
||||||
icon="more_vert"
|
icon="more_vert"
|
||||||
round
|
round
|
||||||
size="md"
|
size="md"
|
||||||
:class="{ invisible: !slots.menu }"
|
:class="{ invisible: !$slots.menu }"
|
||||||
>
|
>
|
||||||
<QTooltip>
|
<QTooltip>
|
||||||
{{ t('components.cardDescriptor.moreOptions') }}
|
{{ t('components.cardDescriptor.moreOptions') }}
|
||||||
|
|
|
@ -15,7 +15,7 @@ const props = defineProps({
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
entityId: {
|
entityId: {
|
||||||
type: Number,
|
type: [Number, String],
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
dataKey: {
|
dataKey: {
|
||||||
|
@ -32,7 +32,7 @@ const arrayData = useArrayData(props.dataKey || route.meta.moduleName, {
|
||||||
skip: 0,
|
skip: 0,
|
||||||
});
|
});
|
||||||
const { store } = arrayData;
|
const { store } = arrayData;
|
||||||
const entity = computed(() => Array.isArray(store.data) ? store.data[0] : store.data);
|
const entity = computed(() => (Array.isArray(store.data) ? store.data[0] : store.data));
|
||||||
const isLoading = ref(false);
|
const isLoading = ref(false);
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
|
@ -48,9 +48,10 @@ onBeforeMount(async () => {
|
||||||
|
|
||||||
async function fetch() {
|
async function fetch() {
|
||||||
store.url = props.url;
|
store.url = props.url;
|
||||||
|
store.filter = props.filter ?? {};
|
||||||
isLoading.value = true;
|
isLoading.value = true;
|
||||||
const { data } = await arrayData.fetch({ append: false, updateRouter: false });
|
const { data } = await arrayData.fetch({ append: false, updateRouter: false });
|
||||||
emit('onFetch', data);
|
emit('onFetch', Array.isArray(data) ? data[0] : data);
|
||||||
isLoading.value = false;
|
isLoading.value = false;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -12,12 +12,23 @@ const $props = defineProps({
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
viewCustomization: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const $q = useQuasar();
|
const $q = useQuasar();
|
||||||
|
|
||||||
|
// El objetivo de asignar las clases de personalización desde el wrapper es no tener conflictos entre vistas que usen el mismo componente
|
||||||
|
const viewCustomizationClasses = {
|
||||||
|
workerCalendar: 'worker-calendar-customizations',
|
||||||
|
};
|
||||||
|
|
||||||
const containerClasses = computed(() => {
|
const containerClasses = computed(() => {
|
||||||
const classes = ['main-container-background'];
|
const classes = ['main-container-background'];
|
||||||
|
if (viewCustomizationClasses[$props.viewCustomization])
|
||||||
|
classes.push(viewCustomizationClasses[$props.viewCustomization]);
|
||||||
if ($props.bordered) classes.push('--bordered');
|
if ($props.bordered) classes.push('--bordered');
|
||||||
if ($props.transparentBackground) classes.push('transparent-background');
|
if ($props.transparentBackground) classes.push('transparent-background');
|
||||||
else classes.push($q.dark.isActive ? '--dark' : '--light');
|
else classes.push($q.dark.isActive ? '--dark' : '--light');
|
||||||
|
@ -33,6 +44,47 @@ const containerClasses = computed(() => {
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
@import '../../css/quasar.variables.scss';
|
||||||
|
|
||||||
|
:root {
|
||||||
|
// Cambia los colores del día actual del calendario por los de salix
|
||||||
|
--calendar-border-current-dark: #84d0e2 2px solid;
|
||||||
|
--calendar-border-current: #84d0e2 2px solid;
|
||||||
|
--calendar-current-color-dark: #84d0e2;
|
||||||
|
// Colores de fondo del calendario en dark mode
|
||||||
|
--calendar-outside-background-dark: #222;
|
||||||
|
--calendar-background-dark: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clases para modificar el color de fecha seleccionada en componente QCalendarMonth
|
||||||
|
.q-dark div .q-calendar-mini .q-calendar-month__day.q-selected .q-calendar__button {
|
||||||
|
background-color: $primary !important;
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.q-calendar-mini .q-calendar-month__day.q-selected .q-calendar__button {
|
||||||
|
background-color: $primary !important;
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.q-calendar-month__head--weekday {
|
||||||
|
// Transforma los nombres de los días de la semana a mayúsculas
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.transparent-background {
|
||||||
|
--calendar-background-dark: transparent;
|
||||||
|
--calendar-background: transparent;
|
||||||
|
--calendar-outside-background-dark: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.q-calendar__button {
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--vn-accent-color);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.main-container-background {
|
.main-container-background {
|
||||||
--calendar-current-background-dark: transparent;
|
--calendar-current-background-dark: transparent;
|
||||||
|
|
||||||
|
@ -45,14 +97,64 @@ const containerClasses = computed(() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
&.--bordered {
|
&.--bordered {
|
||||||
border: 1px solid black;
|
border: 1px solid #222;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.transparent-background {
|
.worker-calendar-customizations {
|
||||||
--calendar-background-dark: transparent;
|
.q-calendar__button {
|
||||||
--calendar-background: transparent;
|
width: 32px;
|
||||||
--calendar-outside-background-dark: transparent;
|
height: 32px;
|
||||||
|
font-size: 13px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--vn-accent-color);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.q-calendar-month__week--days > div:nth-child(6),
|
||||||
|
.q-calendar-month__week--days > div:nth-child(7) {
|
||||||
|
// Cambia el color de los días sábado y domingo
|
||||||
|
color: #777777;
|
||||||
|
}
|
||||||
|
|
||||||
|
.q-calendar-month__week--wrapper {
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.q-calendar-month__workweek {
|
||||||
|
height: 32px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.q-calendar__button--bordered {
|
||||||
|
color: $info !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.q-calendar-month__day--content {
|
||||||
|
position: absolute;
|
||||||
|
top: 1;
|
||||||
|
left: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.q-outside .calendar-event {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.q-calendar-month__workweek,
|
||||||
|
.q-calendar-month__head--workweek,
|
||||||
|
.q-calendar-month__head--weekday.q-calendar__center.q-calendar__ellipsis {
|
||||||
|
text-transform: capitalize;
|
||||||
|
color: #777;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-container {
|
.nav-container {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import VnAvatar from 'src/components/ui/VnAvatar.vue';
|
import VnAvatar from 'src/components/ui/VnAvatar.vue';
|
||||||
import { toDateHour } from 'src/filters';
|
import { toDateHourMin } from 'src/filters';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
@ -32,7 +32,7 @@ async function insert() {
|
||||||
<template>
|
<template>
|
||||||
<QCard class="q-pa-xs q-mb-xl full-width" v-if="$props.addNote">
|
<QCard class="q-pa-xs q-mb-xl full-width" v-if="$props.addNote">
|
||||||
<QCardSection horizontal>
|
<QCardSection horizontal>
|
||||||
<VnAvatar :descriptor="false" :worker-id="1" size="md" />
|
<VnAvatar :worker-id="currentUser.id" size="md" />
|
||||||
<div class="full-width row justify-between q-pa-xs">
|
<div class="full-width row justify-between q-pa-xs">
|
||||||
<VnUserLink :name="t('New note')" :worker-id="currentUser.id" />
|
<VnUserLink :name="t('New note')" :worker-id="currentUser.id" />
|
||||||
{{ t('globals.now') }}
|
{{ t('globals.now') }}
|
||||||
|
@ -78,8 +78,8 @@ async function insert() {
|
||||||
<TransitionGroup name="list" tag="div" class="column items-center full-width">
|
<TransitionGroup name="list" tag="div" class="column items-center full-width">
|
||||||
<QCard
|
<QCard
|
||||||
class="q-pa-xs q-mb-sm full-width"
|
class="q-pa-xs q-mb-sm full-width"
|
||||||
v-for="note in rows"
|
v-for="(note, index) in rows"
|
||||||
:key="note.id"
|
:key="note.id ?? index"
|
||||||
>
|
>
|
||||||
<QCardSection horizontal>
|
<QCardSection horizontal>
|
||||||
<VnAvatar
|
<VnAvatar
|
||||||
|
@ -92,7 +92,7 @@ async function insert() {
|
||||||
:name="`${note.worker.user.nickname}`"
|
:name="`${note.worker.user.nickname}`"
|
||||||
:worker-id="note.worker.id"
|
:worker-id="note.worker.id"
|
||||||
/>
|
/>
|
||||||
{{ toDateHour(note.created) }}
|
{{ toDateHourMin(note.created) }}
|
||||||
</div>
|
</div>
|
||||||
</QCardSection>
|
</QCardSection>
|
||||||
<QCardSection class="q-pa-xs q-my-none q-py-none">
|
<QCardSection class="q-pa-xs q-my-none q-py-none">
|
||||||
|
|
|
@ -77,7 +77,6 @@ const arrayData = useArrayData(props.dataKey, {
|
||||||
userParams: props.userParams,
|
userParams: props.userParams,
|
||||||
exprBuilder: props.exprBuilder,
|
exprBuilder: props.exprBuilder,
|
||||||
});
|
});
|
||||||
const hasMoreData = ref();
|
|
||||||
const store = arrayData.store;
|
const store = arrayData.store;
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
@ -97,7 +96,7 @@ const addFilter = async (filter, params) => {
|
||||||
|
|
||||||
async function fetch() {
|
async function fetch() {
|
||||||
await arrayData.fetch({ append: false });
|
await arrayData.fetch({ append: false });
|
||||||
if (!arrayData.hasMoreData.value) {
|
if (!store.hasMoreData) {
|
||||||
isLoading.value = false;
|
isLoading.value = false;
|
||||||
}
|
}
|
||||||
emit('onFetch', store.data);
|
emit('onFetch', store.data);
|
||||||
|
@ -110,8 +109,8 @@ async function paginate() {
|
||||||
|
|
||||||
isLoading.value = true;
|
isLoading.value = true;
|
||||||
await arrayData.loadMore();
|
await arrayData.loadMore();
|
||||||
if (!arrayData.hasMoreData.value) {
|
if (!store.hasMoreData) {
|
||||||
if (store.userParamsChanged) arrayData.hasMoreData.value = true;
|
if (store.userParamsChanged) store.hasMoreData = true;
|
||||||
store.userParamsChanged = false;
|
store.userParamsChanged = false;
|
||||||
endPagination();
|
endPagination();
|
||||||
return;
|
return;
|
||||||
|
@ -132,9 +131,7 @@ function endPagination() {
|
||||||
emit('onPaginate');
|
emit('onPaginate');
|
||||||
}
|
}
|
||||||
async function onLoad(index, done) {
|
async function onLoad(index, done) {
|
||||||
if (!store.data) {
|
if (!store.data) return done();
|
||||||
return done();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (store.data.length === 0 || !props.url) return done(false);
|
if (store.data.length === 0 || !props.url) return done(false);
|
||||||
|
|
||||||
|
@ -142,7 +139,7 @@ async function onLoad(index, done) {
|
||||||
|
|
||||||
await paginate();
|
await paginate();
|
||||||
let isDone = false;
|
let isDone = false;
|
||||||
if (store.userParamsChanged) isDone = !arrayData.hasMoreData.value;
|
if (store.userParamsChanged) isDone = !store.hasMoreData;
|
||||||
done(isDone);
|
done(isDone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,13 +179,12 @@ defineExpose({ fetch, addFilter });
|
||||||
</QCard>
|
</QCard>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<QInfiniteScroll
|
<QInfiniteScroll
|
||||||
v-if="store.data"
|
v-if="store.data"
|
||||||
@load="onLoad"
|
@load="onLoad"
|
||||||
:offset="offset"
|
:offset="offset"
|
||||||
:disable="disableInfiniteScroll || !arrayData.hasMoreData"
|
|
||||||
class="full-width"
|
class="full-width"
|
||||||
|
:disable="disableInfiniteScroll || !store.hasMoreData"
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
>
|
>
|
||||||
<slot name="body" :rows="store.data"></slot>
|
<slot name="body" :rows="store.data"></slot>
|
||||||
|
@ -196,7 +192,10 @@ defineExpose({ fetch, addFilter });
|
||||||
<QSpinner color="orange" size="md" />
|
<QSpinner color="orange" size="md" />
|
||||||
</div>
|
</div>
|
||||||
</QInfiniteScroll>
|
</QInfiniteScroll>
|
||||||
<div v-if="!isLoading && hasMoreData" class="w-full flex justify-center q-mt-md">
|
<div
|
||||||
|
v-if="!isLoading && store.hasMoreData"
|
||||||
|
class="w-full flex justify-center q-mt-md"
|
||||||
|
>
|
||||||
<QBtn color="primary" :label="t('Load more data')" @click="paginate()" />
|
<QBtn color="primary" :label="t('Load more data')" @click="paginate()" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -131,13 +131,6 @@ async function search() {
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #append>
|
<template #append>
|
||||||
<QIcon
|
|
||||||
v-if="searchText !== ''"
|
|
||||||
name="close"
|
|
||||||
@click="searchText = ''"
|
|
||||||
class="cursor-pointer"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<QIcon
|
<QIcon
|
||||||
v-if="props.info && $q.screen.gt.xs"
|
v-if="props.info && $q.screen.gt.xs"
|
||||||
name="info"
|
name="info"
|
||||||
|
|
|
@ -1,11 +1,27 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, onUnmounted } from 'vue';
|
import { onMounted, onUnmounted, ref } from 'vue';
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
import { useStateStore } from 'stores/useStateStore';
|
||||||
|
|
||||||
const stateStore = useStateStore();
|
const stateStore = useStateStore();
|
||||||
|
const actions = ref(null);
|
||||||
|
const data = ref(null);
|
||||||
|
const opts = { subtree: true, childList: true, attributes: true };
|
||||||
|
const hasContent = ref(false);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
stateStore.toggleSubToolbar();
|
stateStore.toggleSubToolbar();
|
||||||
|
actions.value = document.querySelector('#st-actions');
|
||||||
|
data.value = document.querySelector('#st-data');
|
||||||
|
|
||||||
|
if (!actions.value && !data.value) return;
|
||||||
|
|
||||||
|
// Check if there's content to display
|
||||||
|
const observer = new MutationObserver(
|
||||||
|
() =>
|
||||||
|
(hasContent.value =
|
||||||
|
actions.value.childNodes.length + data.value.childNodes.length)
|
||||||
|
);
|
||||||
|
if (actions.value) observer.observe(actions.value, opts);
|
||||||
|
if (data.value) observer.observe(data.value, opts);
|
||||||
});
|
});
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
|
@ -14,7 +30,10 @@ onUnmounted(() => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<QToolbar class="bg-vn-section-color justify-end sticky">
|
<QToolbar
|
||||||
|
class="justify-end sticky"
|
||||||
|
v-show="hasContent || $slots['st-actions'] || $slots['st-data']"
|
||||||
|
>
|
||||||
<slot name="st-data">
|
<slot name="st-data">
|
||||||
<div id="st-data"></div>
|
<div id="st-data"></div>
|
||||||
</slot>
|
</slot>
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
export const elementIsVisibleInViewport = (el) => {
|
||||||
|
const { top, left, bottom, right } = el.getBoundingClientRect();
|
||||||
|
const { innerHeight, innerWidth } = window;
|
||||||
|
|
||||||
|
return top >= 0 && left >= 0 && bottom <= innerHeight && right <= innerWidth;
|
||||||
|
};
|
|
@ -9,12 +9,9 @@ const arrayDataStore = useArrayDataStore();
|
||||||
export function useArrayData(key, userOptions) {
|
export function useArrayData(key, userOptions) {
|
||||||
if (!key) throw new Error('ArrayData: A key is required to use this composable');
|
if (!key) throw new Error('ArrayData: A key is required to use this composable');
|
||||||
|
|
||||||
if (!arrayDataStore.get(key)) {
|
if (!arrayDataStore.get(key)) arrayDataStore.set(key);
|
||||||
arrayDataStore.set(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
const store = arrayDataStore.get(key);
|
const store = arrayDataStore.get(key);
|
||||||
const hasMoreData = ref(false);
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
let canceller = null;
|
let canceller = null;
|
||||||
|
|
||||||
|
@ -22,6 +19,7 @@ export function useArrayData(key, userOptions) {
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
setOptions();
|
setOptions();
|
||||||
|
store.skip = 0;
|
||||||
|
|
||||||
const query = route.query;
|
const query = route.query;
|
||||||
if (query.params) {
|
if (query.params) {
|
||||||
|
@ -29,9 +27,7 @@ export function useArrayData(key, userOptions) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (key && userOptions) {
|
if (key && userOptions) setOptions();
|
||||||
setOptions();
|
|
||||||
}
|
|
||||||
|
|
||||||
function setOptions() {
|
function setOptions() {
|
||||||
const allowedOptions = [
|
const allowedOptions = [
|
||||||
|
@ -96,8 +92,7 @@ export function useArrayData(key, userOptions) {
|
||||||
});
|
});
|
||||||
|
|
||||||
const { limit } = filter;
|
const { limit } = filter;
|
||||||
hasMoreData.value = limit && response.data.length >= limit;
|
store.hasMoreData = limit && response.data.length >= limit;
|
||||||
store.hasMoreData = hasMoreData.value;
|
|
||||||
|
|
||||||
if (append) {
|
if (append) {
|
||||||
if (!store.data) store.data = [];
|
if (!store.data) store.data = [];
|
||||||
|
@ -170,7 +165,7 @@ export function useArrayData(key, userOptions) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadMore() {
|
async function loadMore() {
|
||||||
if (!hasMoreData.value && !store.hasMoreData) return;
|
if (!store.hasMoreData) return;
|
||||||
|
|
||||||
store.skip = store.limit * page.value;
|
store.skip = store.limit * page.value;
|
||||||
page.value += 1;
|
page.value += 1;
|
||||||
|
@ -212,7 +207,6 @@ export function useArrayData(key, userOptions) {
|
||||||
destroy,
|
destroy,
|
||||||
loadMore,
|
loadMore,
|
||||||
store,
|
store,
|
||||||
hasMoreData,
|
|
||||||
totalRows,
|
totalRows,
|
||||||
updateStateParams,
|
updateStateParams,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
|
|
@ -75,6 +75,10 @@ select:-webkit-autofill {
|
||||||
background-color: #666666;
|
background-color: #666666;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.color-vn-label {
|
||||||
|
color: var(--vn-label);
|
||||||
|
}
|
||||||
|
|
||||||
.color-vn-text {
|
.color-vn-text {
|
||||||
color: var(--vn-text-color);
|
color: var(--vn-text-color);
|
||||||
}
|
}
|
||||||
|
@ -94,6 +98,10 @@ select:-webkit-autofill {
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card-width {
|
||||||
|
width: 770px;
|
||||||
|
}
|
||||||
|
|
||||||
.vn-card-list {
|
.vn-card-list {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 60em;
|
max-width: 60em;
|
||||||
|
@ -166,3 +174,7 @@ input::-webkit-inner-spin-button {
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
-moz-appearance: none;
|
-moz-appearance: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.q-scrollarea__content {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
|
@ -80,7 +80,7 @@
|
||||||
<glyph unicode="" glyph-name="consignatarios" d="M409.6-64v349.867h204.8v-349.867h256v563.2h153.6l-512 460.8-512-460.8h153.6v-563.2h256z" />
|
<glyph unicode="" glyph-name="consignatarios" d="M409.6-64v349.867h204.8v-349.867h256v563.2h153.6l-512 460.8-512-460.8h153.6v-563.2h256z" />
|
||||||
<glyph unicode="" glyph-name="control" d="M418.133 315.733l-128-123.733 256-256 469.333 469.333-128 128-341.333-341.333zM546.133 311.467l34.133 34.133h-68.267zM230.4 128l-59.733 64 153.6 153.6h-68.267v102.4h426.667l204.8 204.8 85.333-85.333v187.733c0 55.467-46.933 102.4-102.4 102.4h-213.333c-21.333 59.733-76.8 102.4-145.067 102.4s-123.733-42.667-145.067-102.4h-213.333c-55.467 0-102.4-46.933-102.4-102.4v-716.8c0-55.467 46.933-102.4 102.4-102.4h273.067l-196.267 192zM512 857.6c29.867 0 51.2-21.333 51.2-51.2s-21.333-51.2-51.2-51.2-51.2 21.333-51.2 51.2c0 29.867 21.333 51.2 51.2 51.2zM256 652.8h512v-102.4h-512v102.4zM665.6-64h204.8c55.467 0 102.4 46.933 102.4 102.4v204.8l-307.2-307.2z" />
|
<glyph unicode="" glyph-name="control" d="M418.133 315.733l-128-123.733 256-256 469.333 469.333-128 128-341.333-341.333zM546.133 311.467l34.133 34.133h-68.267zM230.4 128l-59.733 64 153.6 153.6h-68.267v102.4h426.667l204.8 204.8 85.333-85.333v187.733c0 55.467-46.933 102.4-102.4 102.4h-213.333c-21.333 59.733-76.8 102.4-145.067 102.4s-123.733-42.667-145.067-102.4h-213.333c-55.467 0-102.4-46.933-102.4-102.4v-716.8c0-55.467 46.933-102.4 102.4-102.4h273.067l-196.267 192zM512 857.6c29.867 0 51.2-21.333 51.2-51.2s-21.333-51.2-51.2-51.2-51.2 21.333-51.2 51.2c0 29.867 21.333 51.2 51.2 51.2zM256 652.8h512v-102.4h-512v102.4zM665.6-64h204.8c55.467 0 102.4 46.933 102.4 102.4v204.8l-307.2-307.2z" />
|
||||||
<glyph unicode="" glyph-name="credit" d="M921.6 849.067h-819.2c-55.467 0-102.4-42.667-102.4-98.133v-601.6c0-55.467 46.933-102.4 102.4-102.4h819.2c55.467 0 102.4 42.667 102.4 102.4v601.6c0 55.467-46.933 98.133-102.4 98.133zM921.6 145.067h-819.2v302.933h819.2v-302.933zM921.6 648.533h-819.2v102.4h819.2v-102.4z" />
|
<glyph unicode="" glyph-name="credit" d="M921.6 849.067h-819.2c-55.467 0-102.4-42.667-102.4-98.133v-601.6c0-55.467 46.933-102.4 102.4-102.4h819.2c55.467 0 102.4 42.667 102.4 102.4v601.6c0 55.467-46.933 98.133-102.4 98.133zM921.6 145.067h-819.2v302.933h819.2v-302.933zM921.6 648.533h-819.2v102.4h819.2v-102.4z" />
|
||||||
<glyph unicode="" glyph-name="deaulter" d="M677.973-64c-30.72 35.84-61.867 70.827-91.307 107.52-40.96 51.2-80.64 103.253-121.173 154.88-16.64 21.333-21.76 20.48-30.72-4.693-13.227-36.693-25.6-73.387-40.107-109.653-5.12-12.8-13.227-26.88-24.32-34.56-51.627-34.987-104.107-69.12-157.867-100.693-10.667-6.4-30.72-5.547-41.813 0.853-8.107 4.693-12.373 23.893-11.093 35.84 0.853 8.96 11.093 19.627 19.627 25.6 39.253 26.453 78.933 51.627 119.040 76.8 18.347 11.52 30.293 26.027 35.84 47.787 12.373 48.213 27.307 95.573 39.253 143.36 8.533 33.707 26.88 58.88 56.32 77.227 40.533 25.173 80.64 52.053 120.747 78.507 6.4 4.267 10.24 11.52 15.36 17.493-7.253 2.56-14.933 7.253-22.187 6.827-75.52-6.4-151.467-13.227-226.987-20.48-2.133 0-4.693-0.853-6.827-0.853-22.613-1.707-39.253 10.24-40.96 29.867s12.373 33.707 35.413 35.84c45.227 4.267 90.88 8.96 136.107 12.8 65.707 5.547 131.84 10.667 197.547 15.36 26.027 1.707 53.76-21.76 67.413-55.467 9.813-23.893 5.12-46.080-18.347-65.28-49.92-40.107-100.693-78.933-151.040-118.187-23.040-17.92-23.893-23.467-6.4-46.507 58.453-78.080 116.48-156.587 174.933-234.667 27.307-36.693 25.173-50.773-12.373-75.52-5.12 0-9.813 0-14.080 0zM791.893 649.813c-43.093 1.28-76.373-31.573-77.227-75.52-0.853-44.373 29.44-76.8 72.107-77.653 45.227-1.28 77.653 29.44 78.080 73.813 0.427 45.227-29.44 78.080-72.96 79.36zM671.147 737.707c0-72.107-34.133-136.107-87.467-176.64l-235.52-21.76c-72.107 36.693-122.027 111.787-122.027 198.4 0 122.88 99.84 222.293 222.72 222.293 122.453 0 222.293-99.413 222.293-222.293zM592.213 680.533l-50.347 18.347c-2.133-8.533-5.12-16.213-9.813-22.613-5.12-6.4-10.24-11.947-16.213-17.067-5.973-4.267-12.373-8.107-19.2-11.093s-13.653-4.693-20.053-5.547c-17.92-2.987-33.707-0.427-48.64 6.827s-26.88 18.347-36.693 32.853l76.373 12.373 7.253 32.427-97.28-15.787c-1.28 5.547-2.987 11.093-3.84 16.64l-0.853 4.267 99.413 16.213 7.253 32.427-106.667-17.493c0.853 9.387 2.987 17.493 6.4 26.027 3.84 8.533 8.107 16.213 14.080 23.040 5.547 6.827 12.8 12.373 21.333 17.067s17.92 8.107 28.587 9.813c6.827 1.28 13.227 1.707 20.907 1.28s14.507-1.707 21.333-3.84c6.827-2.133 13.653-5.973 20.053-10.24 5.973-4.693 11.947-11.093 17.493-18.773l38.827 37.973c-13.227 17.92-30.293 31.147-52.053 39.253-21.76 8.533-46.080 10.667-73.387 6.4-19.627-2.987-36.267-9.387-51.2-17.92-14.507-8.533-26.88-19.2-37.547-32-10.667-12.373-18.773-26.027-23.893-40.96-5.547-14.507-8.96-29.867-9.813-45.653l-21.76-3.84-7.253-32.427 29.013 4.693 0.427-2.987c1.28-6.827 2.56-12.8 4.267-18.347l-23.467-3.84-8.107-32.427 43.52 7.253c6.827-13.653 15.787-26.027 26.027-36.693 10.24-11.52 22.187-20.48 35.413-27.733 13.227-7.68 27.307-12.8 42.667-15.787s31.573-3.413 47.36-0.853c12.373 2.133 24.32 5.12 35.84 10.667s22.613 11.52 32.853 19.2c10.24 8.107 18.347 16.64 26.027 26.453 6.827 9.387 12.373 20.48 15.36 32.427z" />
|
<glyph unicode="" glyph-name="defaulter" d="M677.973-64c-30.72 35.84-61.867 70.827-91.307 107.52-40.96 51.2-80.64 103.253-121.173 154.88-16.64 21.333-21.76 20.48-30.72-4.693-13.227-36.693-25.6-73.387-40.107-109.653-5.12-12.8-13.227-26.88-24.32-34.56-51.627-34.987-104.107-69.12-157.867-100.693-10.667-6.4-30.72-5.547-41.813 0.853-8.107 4.693-12.373 23.893-11.093 35.84 0.853 8.96 11.093 19.627 19.627 25.6 39.253 26.453 78.933 51.627 119.040 76.8 18.347 11.52 30.293 26.027 35.84 47.787 12.373 48.213 27.307 95.573 39.253 143.36 8.533 33.707 26.88 58.88 56.32 77.227 40.533 25.173 80.64 52.053 120.747 78.507 6.4 4.267 10.24 11.52 15.36 17.493-7.253 2.56-14.933 7.253-22.187 6.827-75.52-6.4-151.467-13.227-226.987-20.48-2.133 0-4.693-0.853-6.827-0.853-22.613-1.707-39.253 10.24-40.96 29.867s12.373 33.707 35.413 35.84c45.227 4.267 90.88 8.96 136.107 12.8 65.707 5.547 131.84 10.667 197.547 15.36 26.027 1.707 53.76-21.76 67.413-55.467 9.813-23.893 5.12-46.080-18.347-65.28-49.92-40.107-100.693-78.933-151.040-118.187-23.040-17.92-23.893-23.467-6.4-46.507 58.453-78.080 116.48-156.587 174.933-234.667 27.307-36.693 25.173-50.773-12.373-75.52-5.12 0-9.813 0-14.080 0zM791.893 649.813c-43.093 1.28-76.373-31.573-77.227-75.52-0.853-44.373 29.44-76.8 72.107-77.653 45.227-1.28 77.653 29.44 78.080 73.813 0.427 45.227-29.44 78.080-72.96 79.36zM671.147 737.707c0-72.107-34.133-136.107-87.467-176.64l-235.52-21.76c-72.107 36.693-122.027 111.787-122.027 198.4 0 122.88 99.84 222.293 222.72 222.293 122.453 0 222.293-99.413 222.293-222.293zM592.213 680.533l-50.347 18.347c-2.133-8.533-5.12-16.213-9.813-22.613-5.12-6.4-10.24-11.947-16.213-17.067-5.973-4.267-12.373-8.107-19.2-11.093s-13.653-4.693-20.053-5.547c-17.92-2.987-33.707-0.427-48.64 6.827s-26.88 18.347-36.693 32.853l76.373 12.373 7.253 32.427-97.28-15.787c-1.28 5.547-2.987 11.093-3.84 16.64l-0.853 4.267 99.413 16.213 7.253 32.427-106.667-17.493c0.853 9.387 2.987 17.493 6.4 26.027 3.84 8.533 8.107 16.213 14.080 23.040 5.547 6.827 12.8 12.373 21.333 17.067s17.92 8.107 28.587 9.813c6.827 1.28 13.227 1.707 20.907 1.28s14.507-1.707 21.333-3.84c6.827-2.133 13.653-5.973 20.053-10.24 5.973-4.693 11.947-11.093 17.493-18.773l38.827 37.973c-13.227 17.92-30.293 31.147-52.053 39.253-21.76 8.533-46.080 10.667-73.387 6.4-19.627-2.987-36.267-9.387-51.2-17.92-14.507-8.533-26.88-19.2-37.547-32-10.667-12.373-18.773-26.027-23.893-40.96-5.547-14.507-8.96-29.867-9.813-45.653l-21.76-3.84-7.253-32.427 29.013 4.693 0.427-2.987c1.28-6.827 2.56-12.8 4.267-18.347l-23.467-3.84-8.107-32.427 43.52 7.253c6.827-13.653 15.787-26.027 26.027-36.693 10.24-11.52 22.187-20.48 35.413-27.733 13.227-7.68 27.307-12.8 42.667-15.787s31.573-3.413 47.36-0.853c12.373 2.133 24.32 5.12 35.84 10.667s22.613 11.52 32.853 19.2c10.24 8.107 18.347 16.64 26.027 26.453 6.827 9.387 12.373 20.48 15.36 32.427z" />
|
||||||
<glyph unicode="" glyph-name="deletedTicket" d="M160.672 85.696h693.248v639.776c0 0-2.016 234.528-349.696 234.528s-343.552-234.528-343.552-234.528v-639.776zM291.328 652.704h170.976v152.256h102.336v-152.256h171.008v-102.336h-171.008v-356.96h-102.336v356.96h-170.976v102.336zM64 61.056v-123.456h899.008v123.456h-899.008z" />
|
<glyph unicode="" glyph-name="deletedTicket" d="M160.672 85.696h693.248v639.776c0 0-2.016 234.528-349.696 234.528s-343.552-234.528-343.552-234.528v-639.776zM291.328 652.704h170.976v152.256h102.336v-152.256h171.008v-102.336h-171.008v-356.96h-102.336v356.96h-170.976v102.336zM64 61.056v-123.456h899.008v123.456h-899.008z" />
|
||||||
<glyph unicode="" glyph-name="deleteline" d="M354.133 192l-98.133 98.133 157.867 153.6-157.867 157.867 98.133 102.4 157.867-157.867 157.867 153.6 98.133-98.133-157.867-157.867 157.867-153.6-98.133-98.133-157.867 157.867-157.867-157.867zM780.8 507.733l-64-64 59.733-55.467h247.467v119.467h-243.2zM307.2 443.733l-64 64h-243.2v-119.467h251.733l55.467 55.467z" />
|
<glyph unicode="" glyph-name="deleteline" d="M354.133 192l-98.133 98.133 157.867 153.6-157.867 157.867 98.133 102.4 157.867-157.867 157.867 153.6 98.133-98.133-157.867-157.867 157.867-153.6-98.133-98.133-157.867 157.867-157.867-157.867zM780.8 507.733l-64-64 59.733-55.467h247.467v119.467h-243.2zM307.2 443.733l-64 64h-243.2v-119.467h251.733l55.467 55.467z" />
|
||||||
<glyph unicode="" glyph-name="delivery" d="M789.333 264.533c-55.467 0-102.4-46.933-102.4-102.4s46.933-102.4 102.4-102.4 102.4 46.933 102.4 102.4c0 59.733-46.933 102.4-102.4 102.4zM789.333 110.933c-29.867 0-51.2 21.333-51.2 51.2s21.333 51.2 51.2 51.2 51.2-21.333 51.2-51.2c0-25.6-25.6-51.2-51.2-51.2zM251.733 264.533c-55.467 0-102.4-46.933-102.4-102.4s46.933-102.4 102.4-102.4c55.467 0 102.4 46.933 102.4 102.4 0 59.733-46.933 102.4-102.4 102.4zM251.733 110.933c-29.867 0-51.2 21.333-51.2 51.2s21.333 51.2 51.2 51.2c29.867 0 51.2-21.333 51.2-51.2 0-25.6-25.6-51.2-51.2-51.2zM1006.933 537.6l-196.267 192c-12.8 12.8-29.867 17.067-46.933 17.067h-98.133v38.4c0 25.6-21.333 51.2-51.2 51.2h-563.2c-29.867 0-51.2-21.333-51.2-51.2v-554.667c0-29.867 25.6-51.2 51.2-51.2h68.267c8.533 64 64 115.2 132.267 115.2 64 0 123.733-51.2 132.267-115.2h268.8c8.533 64 64 115.2 132.267 115.2s128-51.2 136.533-115.2h51.2c29.867 0 51.2 25.6 51.2 51.2v260.267c0 17.067-8.533 34.133-17.067 46.933zM725.333 682.667c0 4.267 4.267 8.533 8.533 8.533h34.133c0 0 4.267 0 4.267-4.267l153.6-145.067c4.267 0 0-12.8-4.267-12.8h-187.733c-8.533 0-8.533 4.267-8.533 8.533v145.067zM311.467 597.333c0 46.933 29.867 85.333 59.733 93.867 4.267 0 4.267 0 8.533 0l98.133 12.8v-51.2c0-46.933-29.867-85.333-59.733-93.867-4.267 0-4.267 0-8.533 0l-98.133-17.067v55.467zM311.467 516.267l46.933 8.533c17.067 4.267 29.867-17.067 29.867-38.4l4.267-29.867-51.2-4.267c-17.067-4.267-29.867 12.8-29.867 38.4v25.6zM149.333 597.333v51.2l85.333 12.8c34.133 4.267 55.467-25.6 55.467-72.533v-51.2l-85.333-12.8c-34.133 0-59.733 29.867-55.467 72.533zM285.867 512v-38.4c0-34.133-21.333-64-42.667-68.267h-4.267l-72.533-8.533v38.4c0 34.133 21.333 64 42.667 68.267h4.267l72.533 8.533z" />
|
<glyph unicode="" glyph-name="delivery" d="M789.333 264.533c-55.467 0-102.4-46.933-102.4-102.4s46.933-102.4 102.4-102.4 102.4 46.933 102.4 102.4c0 59.733-46.933 102.4-102.4 102.4zM789.333 110.933c-29.867 0-51.2 21.333-51.2 51.2s21.333 51.2 51.2 51.2 51.2-21.333 51.2-51.2c0-25.6-25.6-51.2-51.2-51.2zM251.733 264.533c-55.467 0-102.4-46.933-102.4-102.4s46.933-102.4 102.4-102.4c55.467 0 102.4 46.933 102.4 102.4 0 59.733-46.933 102.4-102.4 102.4zM251.733 110.933c-29.867 0-51.2 21.333-51.2 51.2s21.333 51.2 51.2 51.2c29.867 0 51.2-21.333 51.2-51.2 0-25.6-25.6-51.2-51.2-51.2zM1006.933 537.6l-196.267 192c-12.8 12.8-29.867 17.067-46.933 17.067h-98.133v38.4c0 25.6-21.333 51.2-51.2 51.2h-563.2c-29.867 0-51.2-21.333-51.2-51.2v-554.667c0-29.867 25.6-51.2 51.2-51.2h68.267c8.533 64 64 115.2 132.267 115.2 64 0 123.733-51.2 132.267-115.2h268.8c8.533 64 64 115.2 132.267 115.2s128-51.2 136.533-115.2h51.2c29.867 0 51.2 25.6 51.2 51.2v260.267c0 17.067-8.533 34.133-17.067 46.933zM725.333 682.667c0 4.267 4.267 8.533 8.533 8.533h34.133c0 0 4.267 0 4.267-4.267l153.6-145.067c4.267 0 0-12.8-4.267-12.8h-187.733c-8.533 0-8.533 4.267-8.533 8.533v145.067zM311.467 597.333c0 46.933 29.867 85.333 59.733 93.867 4.267 0 4.267 0 8.533 0l98.133 12.8v-51.2c0-46.933-29.867-85.333-59.733-93.867-4.267 0-4.267 0-8.533 0l-98.133-17.067v55.467zM311.467 516.267l46.933 8.533c17.067 4.267 29.867-17.067 29.867-38.4l4.267-29.867-51.2-4.267c-17.067-4.267-29.867 12.8-29.867 38.4v25.6zM149.333 597.333v51.2l85.333 12.8c34.133 4.267 55.467-25.6 55.467-72.533v-51.2l-85.333-12.8c-34.133 0-59.733 29.867-55.467 72.533zM285.867 512v-38.4c0-34.133-21.333-64-42.667-68.267h-4.267l-72.533-8.533v38.4c0 34.133 21.333 64 42.667 68.267h4.267l72.533 8.533z" />
|
||||||
|
@ -132,4 +132,4 @@
|
||||||
<glyph unicode="" glyph-name="polizon" d="M1011.2 456.533l-264.533 106.667 29.867 29.867c4.267 4.267 4.267 12.8 4.267 17.067-4.267 4.267-8.533 8.533-12.8 8.533h-157.867c0 93.867 76.8 157.867 174.933 157.867 4.267 0 8.533 4.267 12.8 8.533s4.267 8.533 0 17.067l-81.067 153.6c-4.267 0-12.8 4.267-17.067 4.267-46.933 0-93.867-17.067-132.267-42.667-25.6-17.067-42.667-38.4-55.467-59.733-12.8 25.6-29.867 42.667-55.467 59.733-38.4 25.6-85.333 42.667-132.267 42.667-4.267 0-12.8-4.267-12.8-8.533l-81.067-153.6c-4.267-4.267-4.267-8.533 0-17.067 4.267-4.267 8.533-8.533 12.8-8.533 98.133 0 174.933-59.733 174.933-153.6v0h-140.8c-4.267 0-12.8-4.267-12.8-8.533-4.267-4.267 0-12.8 4.267-17.067l21.333-21.333-277.333-110.933c-8.533-8.533-12.8-12.8-8.533-21.333 0-8.533 8.533-12.8 17.067-12.8 0 0 0 0 0 0l98.133 4.267-76.8-98.133c0-4.267-4.267-8.533 0-12.8 0-4.267 4.267-8.533 8.533-8.533l85.333-34.133v-179.2c0-8.533 4.267-12.8 8.533-12.8l362.667-145.067c0 0 4.267 0 4.267 0s4.267 0 4.267 0l362.667 145.067c4.267 4.267 8.533 8.533 8.533 12.8v179.2l85.333 34.133c4.267 0 8.533 4.267 8.533 8.533s0 8.533-4.267 12.8l-72.533 98.133 102.4-4.267c8.533 0 12.8 4.267 17.067 12.8 0 8.533-4.267 12.8-12.8 17.067zM110.933 460.8l200.533 81.067 8.533-8.533-170.667-68.267-38.4-4.267zM153.6 294.4v4.267l-72.533 29.867 72.533 98.133 328.533-132.267-72.533-98.133-256 102.4v-4.267zM494.933-25.6l-328.533 132.267v153.6l243.2-98.133c0 0 4.267 0 4.267 0h4.267c0 0 4.267 0 4.267 0v0c0 0 0 0 4.267 0v0c0 0 4.267 0 4.267 4.267l64 85.333v-277.333zM494.933 328.533l-302.933 119.467 149.333 59.733 153.6-162.133v-17.067zM529.067 345.6l162.133 157.867 140.8-55.467-302.933-119.467v17.067zM857.6 106.667l-328.533-132.267v281.6l64-85.333c0 0 0-4.267 4.267-4.267v0c0 0 4.267 0 4.267 0v0c0 0 4.267 0 4.267 0v0 0c0 0 4.267 0 4.267 0l243.2 98.133v-157.867zM942.933 328.533l-328.533-132.267-72.533 98.133 328.533 132.267 72.533-98.133zM874.667 465.067l-162.133 64 12.8 8.533 187.733-76.8-38.4 4.267z" />
|
<glyph unicode="" glyph-name="polizon" d="M1011.2 456.533l-264.533 106.667 29.867 29.867c4.267 4.267 4.267 12.8 4.267 17.067-4.267 4.267-8.533 8.533-12.8 8.533h-157.867c0 93.867 76.8 157.867 174.933 157.867 4.267 0 8.533 4.267 12.8 8.533s4.267 8.533 0 17.067l-81.067 153.6c-4.267 0-12.8 4.267-17.067 4.267-46.933 0-93.867-17.067-132.267-42.667-25.6-17.067-42.667-38.4-55.467-59.733-12.8 25.6-29.867 42.667-55.467 59.733-38.4 25.6-85.333 42.667-132.267 42.667-4.267 0-12.8-4.267-12.8-8.533l-81.067-153.6c-4.267-4.267-4.267-8.533 0-17.067 4.267-4.267 8.533-8.533 12.8-8.533 98.133 0 174.933-59.733 174.933-153.6v0h-140.8c-4.267 0-12.8-4.267-12.8-8.533-4.267-4.267 0-12.8 4.267-17.067l21.333-21.333-277.333-110.933c-8.533-8.533-12.8-12.8-8.533-21.333 0-8.533 8.533-12.8 17.067-12.8 0 0 0 0 0 0l98.133 4.267-76.8-98.133c0-4.267-4.267-8.533 0-12.8 0-4.267 4.267-8.533 8.533-8.533l85.333-34.133v-179.2c0-8.533 4.267-12.8 8.533-12.8l362.667-145.067c0 0 4.267 0 4.267 0s4.267 0 4.267 0l362.667 145.067c4.267 4.267 8.533 8.533 8.533 12.8v179.2l85.333 34.133c4.267 0 8.533 4.267 8.533 8.533s0 8.533-4.267 12.8l-72.533 98.133 102.4-4.267c8.533 0 12.8 4.267 17.067 12.8 0 8.533-4.267 12.8-12.8 17.067zM110.933 460.8l200.533 81.067 8.533-8.533-170.667-68.267-38.4-4.267zM153.6 294.4v4.267l-72.533 29.867 72.533 98.133 328.533-132.267-72.533-98.133-256 102.4v-4.267zM494.933-25.6l-328.533 132.267v153.6l243.2-98.133c0 0 4.267 0 4.267 0h4.267c0 0 4.267 0 4.267 0v0c0 0 0 0 4.267 0v0c0 0 4.267 0 4.267 4.267l64 85.333v-277.333zM494.933 328.533l-302.933 119.467 149.333 59.733 153.6-162.133v-17.067zM529.067 345.6l162.133 157.867 140.8-55.467-302.933-119.467v17.067zM857.6 106.667l-328.533-132.267v281.6l64-85.333c0 0 0-4.267 4.267-4.267v0c0 0 4.267 0 4.267 0v0c0 0 4.267 0 4.267 0v0 0c0 0 4.267 0 4.267 0l243.2 98.133v-157.867zM942.933 328.533l-328.533-132.267-72.533 98.133 328.533 132.267 72.533-98.133zM874.667 465.067l-162.133 64 12.8 8.533 187.733-76.8-38.4 4.267z" />
|
||||||
<glyph unicode="" glyph-name="preserved" d="M512-64c16.213 0 28.587 13.227 28.587 28.587v215.040h2.987c73.387 2.133 130.987 25.173 170.667 67.84 68.267 72.107 62.72 177.493 60.16 197.973v0c-1.28 15.36-14.080 28.16-29.44 29.44-7.253 0.853-33.707 2.987-67.84-2.133l-12.373-2.133 11.093 6.827c14.080 8.96 26.453 19.2 37.547 30.72 68.267 72.107 62.72 177.493 60.16 197.973-1.28 15.36-14.080 28.16-29.44 29.44-14.080 1.28-64 4.267-117.76-14.507l-4.267-1.28 0.853 5.12c2.987 15.36 4.267 31.573 4.267 46.933-2.56 98.56-78.933 168.107-93.867 180.48-12.373 10.24-29.44 10.24-41.813 0-15.36-11.947-92.16-81.067-94.72-180.48-0.853-16.213 0.853-31.573 4.267-47.787l0.853-5.12-4.267 1.28c-53.76 19.2-104.533 16.213-118.613 14.507-15.36-1.28-28.16-14.080-29.44-29.44-2.133-20.48-8.107-125.867 60.16-197.973 11.093-11.093 22.613-21.333 36.693-30.293l10.24-6.827-12.373 2.133c-16.213 2.133-30.293 2.987-41.387 2.987s-19.2-0.853-23.467-0.853c-15.36-1.28-28.16-14.080-29.44-29.44-2.133-20.48-8.107-125.013 60.16-197.973 39.68-41.813 97.28-64.853 169.813-67.84h2.987v-215.040c0.427-14.933 12.8-28.16 29.013-28.16zM715.093 418.133h2.987v-2.987c-0.853-30.72-7.253-87.467-45.653-128-28.587-30.72-71.253-46.933-127.147-49.92h-2.987v2.987c2.133 58.88 20.053 103.68 51.627 133.12 38.827 37.973 92.587 44.8 121.173 44.8zM713.813 679.253h2.987v-2.987c-0.853-30.72-7.253-87.467-45.653-128-28.587-30.293-71.253-46.933-127.147-49.493h-2.987v2.987c2.133 58.88 20.053 103.68 51.627 133.12 39.253 37.12 93.013 43.52 121.173 44.373zM454.4 770.56c1.28 55.040 35.413 99.413 55.893 120.747l2.133 2.133 2.133-2.133c20.053-21.333 53.76-65.707 55.893-120.747 1.28-43.52-17.493-87.040-55.040-128.853l-2.133-2.133-2.133 2.133c-39.68 41.813-58.027 85.333-56.747 128.853zM351.573 548.267c-37.547 39.68-44.8 97.28-45.653 128v2.987h2.987c34.56-0.853 84.053-8.96 121.6-43.947v0c31.573-29.44 48.64-74.24 51.627-133.12v-2.987h-2.987c-56.32 2.133-98.987 18.773-127.573 49.067zM479.573 237.653c-55.893 2.133-98.56 19.2-127.147 49.493-37.547 39.68-44.8 97.28-45.653 128v2.987h2.987c28.587-0.853 82.347-7.253 121.6-43.947 31.573-29.44 48.64-74.24 51.627-133.12v-2.987h-3.413zM471.467 416.427c-8.96 8.107-18.347 15.36-29.44 22.613l-11.093 6.827 12.373-1.28c21.333-2.987 41.813-3.84 64-2.987 0.853 0 1.28 0 2.133 0h2.56c0.853 0 1.28 0 2.133 0 5.12 0 9.387 0 14.507 0 17.493 0 35.413 1.28 52.053 3.84l13.227 2.133-11.093-7.253c-11.093-6.827-20.48-14.507-29.44-22.613-14.507-14.080-28.16-31.573-38.827-51.627l-2.133-4.267-2.133 4.267c-10.667 18.773-23.893 36.267-38.827 50.347z" />
|
<glyph unicode="" glyph-name="preserved" d="M512-64c16.213 0 28.587 13.227 28.587 28.587v215.040h2.987c73.387 2.133 130.987 25.173 170.667 67.84 68.267 72.107 62.72 177.493 60.16 197.973v0c-1.28 15.36-14.080 28.16-29.44 29.44-7.253 0.853-33.707 2.987-67.84-2.133l-12.373-2.133 11.093 6.827c14.080 8.96 26.453 19.2 37.547 30.72 68.267 72.107 62.72 177.493 60.16 197.973-1.28 15.36-14.080 28.16-29.44 29.44-14.080 1.28-64 4.267-117.76-14.507l-4.267-1.28 0.853 5.12c2.987 15.36 4.267 31.573 4.267 46.933-2.56 98.56-78.933 168.107-93.867 180.48-12.373 10.24-29.44 10.24-41.813 0-15.36-11.947-92.16-81.067-94.72-180.48-0.853-16.213 0.853-31.573 4.267-47.787l0.853-5.12-4.267 1.28c-53.76 19.2-104.533 16.213-118.613 14.507-15.36-1.28-28.16-14.080-29.44-29.44-2.133-20.48-8.107-125.867 60.16-197.973 11.093-11.093 22.613-21.333 36.693-30.293l10.24-6.827-12.373 2.133c-16.213 2.133-30.293 2.987-41.387 2.987s-19.2-0.853-23.467-0.853c-15.36-1.28-28.16-14.080-29.44-29.44-2.133-20.48-8.107-125.013 60.16-197.973 39.68-41.813 97.28-64.853 169.813-67.84h2.987v-215.040c0.427-14.933 12.8-28.16 29.013-28.16zM715.093 418.133h2.987v-2.987c-0.853-30.72-7.253-87.467-45.653-128-28.587-30.72-71.253-46.933-127.147-49.92h-2.987v2.987c2.133 58.88 20.053 103.68 51.627 133.12 38.827 37.973 92.587 44.8 121.173 44.8zM713.813 679.253h2.987v-2.987c-0.853-30.72-7.253-87.467-45.653-128-28.587-30.293-71.253-46.933-127.147-49.493h-2.987v2.987c2.133 58.88 20.053 103.68 51.627 133.12 39.253 37.12 93.013 43.52 121.173 44.373zM454.4 770.56c1.28 55.040 35.413 99.413 55.893 120.747l2.133 2.133 2.133-2.133c20.053-21.333 53.76-65.707 55.893-120.747 1.28-43.52-17.493-87.040-55.040-128.853l-2.133-2.133-2.133 2.133c-39.68 41.813-58.027 85.333-56.747 128.853zM351.573 548.267c-37.547 39.68-44.8 97.28-45.653 128v2.987h2.987c34.56-0.853 84.053-8.96 121.6-43.947v0c31.573-29.44 48.64-74.24 51.627-133.12v-2.987h-2.987c-56.32 2.133-98.987 18.773-127.573 49.067zM479.573 237.653c-55.893 2.133-98.56 19.2-127.147 49.493-37.547 39.68-44.8 97.28-45.653 128v2.987h2.987c28.587-0.853 82.347-7.253 121.6-43.947 31.573-29.44 48.64-74.24 51.627-133.12v-2.987h-3.413zM471.467 416.427c-8.96 8.107-18.347 15.36-29.44 22.613l-11.093 6.827 12.373-1.28c21.333-2.987 41.813-3.84 64-2.987 0.853 0 1.28 0 2.133 0h2.56c0.853 0 1.28 0 2.133 0 5.12 0 9.387 0 14.507 0 17.493 0 35.413 1.28 52.053 3.84l13.227 2.133-11.093-7.253c-11.093-6.827-20.48-14.507-29.44-22.613-14.507-14.080-28.16-31.573-38.827-51.627l-2.133-4.267-2.133 4.267c-10.667 18.773-23.893 36.267-38.827 50.347z" />
|
||||||
<glyph unicode="" glyph-name="recovery" d="M746.667 477.867c68.267 0 140.8-21.333 196.267-72.533 110.933-102.4 115.2-277.333 8.533-384s-277.333-115.2-384-8.533c-93.867 85.333-110.933 221.867-51.2 328.533l51.2-46.933c-34.133-76.8-17.067-170.667 46.933-230.4 81.067-76.8 209.067-72.533 290.133 8.533 76.8 81.067 72.533 209.067-8.533 290.133-42.667 38.4-93.867 55.467-145.067 55.467l4.267-153.6-170.667 162.133 162.133 170.667v-119.467zM337.067 209.067c0 0 0 0 0 0-17.067 8.533-38.4 17.067-55.467 25.6-21.333 8.533-29.867 25.6-29.867 51.2s0 51.2 0 81.067c29.867-17.067 64-29.867 102.4-38.4 4.267 17.067 12.8 34.133 21.333 51.2-17.067 4.267-34.133 8.533-51.2 17.067-21.333 8.533-38.4 21.333-55.467 29.867-12.8 8.533-17.067 17.067-12.8 34.133 0 29.867 0 55.467 0 85.333 68.267-29.867 132.267-46.933 200.533-51.2 17.067 21.333 38.4 38.4 64 55.467 0 0-4.267 0-4.267 0-51.2 0-106.667 4.267-157.867 21.333-34.133 0-59.733 12.8-81.067 29.867-29.867 21.333-29.867 42.667 4.267 64 38.4 25.6 81.067 34.133 128 42.667 55.467 8.533 110.933 8.533 166.4 4.267 51.2-4.267 102.4-17.067 149.333-38.4 12.8-4.267 42.667-29.867 38.4-55.467 55.467 0 106.667-12.8 153.6-34.133 17.067 4.267 29.867 8.533 46.933 12.8 0-12.8 0-25.6 0-38.4 21.333-12.8 38.4-25.6 55.467-42.667 0 98.133 0 200.533 0 298.667 0 42.667-17.067 72.533-51.2 93.867-46.933 29.867-98.133 38.4-149.333 42.667-34.133 8.533-72.533 8.533-110.933 8.533-72.533-4.267-140.8-21.333-200.533-64-4.267 0-8.533 4.267-8.533 4.267-51.2 34.133-110.933 46.933-170.667 51.2-51.2 0-102.4 0-153.6-8.533-46.933-8.533-93.867-17.067-136.533-46.933-25.6-21.333-38.4-42.667-38.4-76.8 0-145.067 0-294.4 0-439.467 0-38.4 17.067-64 46.933-81.067 21.333-12.8 46.933-25.6 72.533-29.867 25.6-8.533 51.2-12.8 81.067-17.067 17.067-46.933 55.467-68.267 102.4-85.333 12.8-4.267 29.867-8.533 42.667-12.8-4.267 17.067-8.533 34.133-8.533 55.467zM964.267 686.933c0-8.533-8.533-21.333-17.067-25.6-34.133-21.333-76.8-34.133-119.467-38.4-4.267 38.4-17.067 68.267-55.467 89.6 68.267 0 128 12.8 192 42.667 4.267-25.6 4.267-46.933 0-68.267zM610.133 883.2c68.267 17.067 136.533 25.6 204.8 17.067 42.667-4.267 85.333-12.8 128-34.133 12.8-8.533 21.333-12.8 25.6-34.133-8.533-8.533-17.067-17.067-25.6-21.333-29.867-17.067-64-29.867-98.133-34.133-38.4-4.267-76.8-8.533-115.2-8.533-46.933 0-89.6 8.533-132.267 25.6-21.333 8.533-42.667 17.067-55.467 42.667 12.8 29.867 38.4 42.667 68.267 46.933zM68.267 844.8c25.6 25.6 64 34.133 98.133 38.4 29.867 4.267 59.733 12.8 85.333 12.8 68.267 0 132.267-4.267 196.267-34.133 8.533-4.267 17.067-8.533 25.6-17.067 12.8-8.533 12.8-21.333 0-34.133-8.533-8.533-17.067-12.8-29.867-21.333-42.667-21.333-85.333-29.867-132.267-34.133-17.067 0-29.867 0-42.667 0-55.467 4.267-110.933 12.8-162.133 29.867-12.8 4.267-29.867 12.8-42.667 21.333-12.8 17.067-8.533 25.6 4.267 38.4zM196.267 307.2c-25.6 8.533-51.2 12.8-72.533 21.333-8.533 4.267-21.333 8.533-29.867 12.8-25.6 12.8-38.4 29.867-34.133 59.733 0 17.067 0 29.867 0 51.2 46.933-25.6 89.6-34.133 136.533-38.4 0-42.667 0-72.533 0-106.667zM55.467 529.067c0 21.333 0 42.667 0 59.733 46.933-12.8 93.867-21.333 140.8-34.133 0-29.867 0-59.733 0-93.867-34.133 4.267-64 12.8-93.867 21.333-8.533 4.267-21.333 12.8-29.867 17.067-12.8 8.533-17.067 17.067-17.067 29.867zM196.267 618.667c-4.267 0-12.8-4.267-17.067 0-34.133 0-68.267 12.8-102.4 29.867-12.8 8.533-21.333 21.333-21.333 38.4s0 38.4 0 59.733c59.733-25.6 115.2-38.4 179.2-42.667-21.333-25.6-42.667-51.2-38.4-85.333z" />
|
<glyph unicode="" glyph-name="recovery" d="M746.667 477.867c68.267 0 140.8-21.333 196.267-72.533 110.933-102.4 115.2-277.333 8.533-384s-277.333-115.2-384-8.533c-93.867 85.333-110.933 221.867-51.2 328.533l51.2-46.933c-34.133-76.8-17.067-170.667 46.933-230.4 81.067-76.8 209.067-72.533 290.133 8.533 76.8 81.067 72.533 209.067-8.533 290.133-42.667 38.4-93.867 55.467-145.067 55.467l4.267-153.6-170.667 162.133 162.133 170.667v-119.467zM337.067 209.067c0 0 0 0 0 0-17.067 8.533-38.4 17.067-55.467 25.6-21.333 8.533-29.867 25.6-29.867 51.2s0 51.2 0 81.067c29.867-17.067 64-29.867 102.4-38.4 4.267 17.067 12.8 34.133 21.333 51.2-17.067 4.267-34.133 8.533-51.2 17.067-21.333 8.533-38.4 21.333-55.467 29.867-12.8 8.533-17.067 17.067-12.8 34.133 0 29.867 0 55.467 0 85.333 68.267-29.867 132.267-46.933 200.533-51.2 17.067 21.333 38.4 38.4 64 55.467 0 0-4.267 0-4.267 0-51.2 0-106.667 4.267-157.867 21.333-34.133 0-59.733 12.8-81.067 29.867-29.867 21.333-29.867 42.667 4.267 64 38.4 25.6 81.067 34.133 128 42.667 55.467 8.533 110.933 8.533 166.4 4.267 51.2-4.267 102.4-17.067 149.333-38.4 12.8-4.267 42.667-29.867 38.4-55.467 55.467 0 106.667-12.8 153.6-34.133 17.067 4.267 29.867 8.533 46.933 12.8 0-12.8 0-25.6 0-38.4 21.333-12.8 38.4-25.6 55.467-42.667 0 98.133 0 200.533 0 298.667 0 42.667-17.067 72.533-51.2 93.867-46.933 29.867-98.133 38.4-149.333 42.667-34.133 8.533-72.533 8.533-110.933 8.533-72.533-4.267-140.8-21.333-200.533-64-4.267 0-8.533 4.267-8.533 4.267-51.2 34.133-110.933 46.933-170.667 51.2-51.2 0-102.4 0-153.6-8.533-46.933-8.533-93.867-17.067-136.533-46.933-25.6-21.333-38.4-42.667-38.4-76.8 0-145.067 0-294.4 0-439.467 0-38.4 17.067-64 46.933-81.067 21.333-12.8 46.933-25.6 72.533-29.867 25.6-8.533 51.2-12.8 81.067-17.067 17.067-46.933 55.467-68.267 102.4-85.333 12.8-4.267 29.867-8.533 42.667-12.8-4.267 17.067-8.533 34.133-8.533 55.467zM964.267 686.933c0-8.533-8.533-21.333-17.067-25.6-34.133-21.333-76.8-34.133-119.467-38.4-4.267 38.4-17.067 68.267-55.467 89.6 68.267 0 128 12.8 192 42.667 4.267-25.6 4.267-46.933 0-68.267zM610.133 883.2c68.267 17.067 136.533 25.6 204.8 17.067 42.667-4.267 85.333-12.8 128-34.133 12.8-8.533 21.333-12.8 25.6-34.133-8.533-8.533-17.067-17.067-25.6-21.333-29.867-17.067-64-29.867-98.133-34.133-38.4-4.267-76.8-8.533-115.2-8.533-46.933 0-89.6 8.533-132.267 25.6-21.333 8.533-42.667 17.067-55.467 42.667 12.8 29.867 38.4 42.667 68.267 46.933zM68.267 844.8c25.6 25.6 64 34.133 98.133 38.4 29.867 4.267 59.733 12.8 85.333 12.8 68.267 0 132.267-4.267 196.267-34.133 8.533-4.267 17.067-8.533 25.6-17.067 12.8-8.533 12.8-21.333 0-34.133-8.533-8.533-17.067-12.8-29.867-21.333-42.667-21.333-85.333-29.867-132.267-34.133-17.067 0-29.867 0-42.667 0-55.467 4.267-110.933 12.8-162.133 29.867-12.8 4.267-29.867 12.8-42.667 21.333-12.8 17.067-8.533 25.6 4.267 38.4zM196.267 307.2c-25.6 8.533-51.2 12.8-72.533 21.333-8.533 4.267-21.333 8.533-29.867 12.8-25.6 12.8-38.4 29.867-34.133 59.733 0 17.067 0 29.867 0 51.2 46.933-25.6 89.6-34.133 136.533-38.4 0-42.667 0-72.533 0-106.667zM55.467 529.067c0 21.333 0 42.667 0 59.733 46.933-12.8 93.867-21.333 140.8-34.133 0-29.867 0-59.733 0-93.867-34.133 4.267-64 12.8-93.867 21.333-8.533 4.267-21.333 12.8-29.867 17.067-12.8 8.533-17.067 17.067-17.067 29.867zM196.267 618.667c-4.267 0-12.8-4.267-17.067 0-34.133 0-68.267 12.8-102.4 29.867-12.8 8.533-21.333 21.333-21.333 38.4s0 38.4 0 59.733c59.733-25.6 115.2-38.4 179.2-42.667-21.333-25.6-42.667-51.2-38.4-85.333z" />
|
||||||
</font></defs></svg>
|
</font></defs></svg>
|
||||||
|
|
Before Width: | Height: | Size: 173 KiB After Width: | Height: | Size: 173 KiB |
File diff suppressed because one or more lines are too long
|
@ -1,402 +1,418 @@
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'icon';
|
font-family: 'icon';
|
||||||
src: url('fonts/icon.eot?2omjsr');
|
src: url('fonts/icon.eot?2omjsr');
|
||||||
src: url('fonts/icon.eot?2omjsr#iefix') format('embedded-opentype'),
|
src: url('fonts/icon.eot?2omjsr#iefix') format('embedded-opentype'),
|
||||||
url('fonts/icon.ttf?2omjsr') format('truetype'),
|
url('fonts/icon.ttf?2omjsr') format('truetype'),
|
||||||
url('fonts/icon.woff?2omjsr') format('woff'),
|
url('fonts/icon.woff?2omjsr') format('woff'),
|
||||||
url('fonts/icon.svg?2omjsr#icon') format('svg');
|
url('fonts/icon.svg?2omjsr#icon') format('svg');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-display: block;
|
font-display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
[class^="icon-"], [class*=" icon-"] {
|
[class^='icon-'],
|
||||||
/* use !important to prevent issues with browser extensions that change fonts */
|
[class*=' icon-'] {
|
||||||
font-family: 'icon' !important;
|
/* use !important to prevent issues with browser extensions that change fonts */
|
||||||
speak: never;
|
font-family: 'icon' !important;
|
||||||
font-style: normal;
|
speak: never;
|
||||||
font-weight: normal;
|
font-style: normal;
|
||||||
font-variant: normal;
|
font-weight: normal;
|
||||||
text-transform: none;
|
font-variant: normal;
|
||||||
line-height: 1;
|
text-transform: none;
|
||||||
|
line-height: 1;
|
||||||
|
|
||||||
/* Better Font Rendering =========== */
|
/* Better Font Rendering =========== */
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-100:before {
|
.icon-100:before {
|
||||||
content: "\e926";
|
content: '\e926';
|
||||||
}
|
}
|
||||||
.icon-Client_unpaid:before {
|
.icon-Client_unpaid:before {
|
||||||
content: "\e925";
|
content: '\e925';
|
||||||
|
}
|
||||||
|
.icon-Client_unpaid:before {
|
||||||
|
content: '\e925';
|
||||||
}
|
}
|
||||||
.icon-History:before {
|
.icon-History:before {
|
||||||
content: "\e964";
|
content: '\e964';
|
||||||
}
|
}
|
||||||
.icon-Person:before {
|
.icon-Person:before {
|
||||||
content: "\e984";
|
content: '\e984';
|
||||||
}
|
}
|
||||||
.icon-accessory:before {
|
.icon-accessory:before {
|
||||||
content: "\e948";
|
content: '\e948';
|
||||||
}
|
}
|
||||||
.icon-account:before {
|
.icon-account:before {
|
||||||
content: "\e927";
|
content: '\e927';
|
||||||
}
|
}
|
||||||
.icon-actions:before {
|
.icon-actions:before {
|
||||||
content: "\e928";
|
content: '\e928';
|
||||||
}
|
}
|
||||||
.icon-addperson:before {
|
.icon-addperson:before {
|
||||||
content: "\e929";
|
content: '\e929';
|
||||||
}
|
}
|
||||||
.icon-agency:before {
|
.icon-agency:before {
|
||||||
content: "\e92a";
|
content: '\e92a';
|
||||||
|
}
|
||||||
|
.icon-agency:before {
|
||||||
|
content: '\e92a';
|
||||||
}
|
}
|
||||||
.icon-agency-term:before {
|
.icon-agency-term:before {
|
||||||
content: "\e92b";
|
content: '\e92b';
|
||||||
}
|
}
|
||||||
.icon-albaran:before {
|
.icon-albaran:before {
|
||||||
content: "\e92c";
|
content: '\e92c';
|
||||||
|
}
|
||||||
|
.icon-albaran:before {
|
||||||
|
content: '\e92c';
|
||||||
}
|
}
|
||||||
.icon-anonymous:before {
|
.icon-anonymous:before {
|
||||||
content: "\e92d";
|
content: '\e92d';
|
||||||
}
|
}
|
||||||
.icon-apps:before {
|
.icon-apps:before {
|
||||||
content: "\e92e";
|
content: '\e92e';
|
||||||
}
|
}
|
||||||
.icon-artificial:before {
|
.icon-artificial:before {
|
||||||
content: "\e92f";
|
content: '\e92f';
|
||||||
}
|
}
|
||||||
.icon-attach:before {
|
.icon-attach:before {
|
||||||
content: "\e930";
|
content: '\e930';
|
||||||
}
|
}
|
||||||
.icon-barcode:before {
|
.icon-barcode:before {
|
||||||
content: "\e932";
|
content: '\e932';
|
||||||
}
|
}
|
||||||
.icon-basket:before {
|
.icon-basket:before {
|
||||||
content: "\e933";
|
content: '\e933';
|
||||||
}
|
}
|
||||||
.icon-basketadd:before {
|
.icon-basketadd:before {
|
||||||
content: "\e934";
|
content: '\e934';
|
||||||
}
|
}
|
||||||
.icon-bin:before {
|
.icon-bin:before {
|
||||||
content: "\e935";
|
content: '\e935';
|
||||||
}
|
}
|
||||||
.icon-botanical:before {
|
.icon-botanical:before {
|
||||||
content: "\e936";
|
content: '\e936';
|
||||||
}
|
}
|
||||||
.icon-bucket:before {
|
.icon-bucket:before {
|
||||||
content: "\e937";
|
content: '\e937';
|
||||||
}
|
}
|
||||||
.icon-buscaman:before {
|
.icon-buscaman:before {
|
||||||
content: "\e938";
|
content: '\e938';
|
||||||
}
|
}
|
||||||
.icon-buyrequest:before {
|
.icon-buyrequest:before {
|
||||||
content: "\e939";
|
content: '\e939';
|
||||||
}
|
}
|
||||||
.icon-calc_volum:before {
|
.icon-calc_volum:before {
|
||||||
content: "\e93a";
|
content: '\e93a';
|
||||||
}
|
}
|
||||||
.icon-calendar:before {
|
.icon-calendar:before {
|
||||||
content: "\e940";
|
content: '\e940';
|
||||||
}
|
}
|
||||||
.icon-catalog:before {
|
.icon-catalog:before {
|
||||||
content: "\e941";
|
content: '\e941';
|
||||||
}
|
}
|
||||||
.icon-claims:before {
|
.icon-claims:before {
|
||||||
content: "\e942";
|
content: '\e942';
|
||||||
}
|
}
|
||||||
.icon-client:before {
|
.icon-client:before {
|
||||||
content: "\e943";
|
content: '\e943';
|
||||||
}
|
}
|
||||||
.icon-clone:before {
|
.icon-clone:before {
|
||||||
content: "\e945";
|
content: '\e945';
|
||||||
}
|
}
|
||||||
.icon-columnadd:before {
|
.icon-columnadd:before {
|
||||||
content: "\e946";
|
content: '\e946';
|
||||||
}
|
}
|
||||||
.icon-columndelete:before {
|
.icon-columndelete:before {
|
||||||
content: "\e947";
|
content: '\e947';
|
||||||
}
|
}
|
||||||
.icon-components:before {
|
.icon-components:before {
|
||||||
content: "\e949";
|
content: '\e949';
|
||||||
}
|
}
|
||||||
.icon-consignatarios:before {
|
.icon-consignatarios:before {
|
||||||
content: "\e94b";
|
content: '\e94b';
|
||||||
}
|
}
|
||||||
.icon-control:before {
|
.icon-control:before {
|
||||||
content: "\e94c";
|
content: '\e94c';
|
||||||
}
|
}
|
||||||
.icon-credit:before {
|
.icon-credit:before {
|
||||||
content: "\e94d";
|
content: '\e94d';
|
||||||
}
|
}
|
||||||
.icon-deaulter:before {
|
.icon-defaulter:before {
|
||||||
content: "\e94e";
|
content: '\e94e';
|
||||||
}
|
}
|
||||||
.icon-deletedTicket:before {
|
.icon-deletedTicket:before {
|
||||||
content: "\e94f";
|
content: '\e94f';
|
||||||
}
|
}
|
||||||
.icon-deleteline:before {
|
.icon-deleteline:before {
|
||||||
content: "\e950";
|
content: '\e950';
|
||||||
}
|
}
|
||||||
.icon-delivery:before {
|
.icon-delivery:before {
|
||||||
content: "\e951";
|
content: '\e951';
|
||||||
}
|
}
|
||||||
.icon-deliveryprices:before {
|
.icon-deliveryprices:before {
|
||||||
content: "\e952";
|
content: '\e952';
|
||||||
}
|
}
|
||||||
.icon-details:before {
|
.icon-details:before {
|
||||||
content: "\e954";
|
content: '\e954';
|
||||||
}
|
}
|
||||||
.icon-dfiscales:before {
|
.icon-dfiscales:before {
|
||||||
content: "\e955";
|
content: '\e955';
|
||||||
}
|
}
|
||||||
.icon-disabled:before {
|
.icon-disabled:before {
|
||||||
content: "\e965";
|
content: '\e965';
|
||||||
}
|
}
|
||||||
.icon-doc:before {
|
.icon-doc:before {
|
||||||
content: "\e956";
|
content: '\e956';
|
||||||
}
|
}
|
||||||
.icon-entry:before {
|
.icon-entry:before {
|
||||||
content: "\e958";
|
content: '\e958';
|
||||||
}
|
}
|
||||||
.icon-exit:before {
|
.icon-exit:before {
|
||||||
content: "\e959";
|
content: '\e959';
|
||||||
}
|
}
|
||||||
.icon-eye:before {
|
.icon-eye:before {
|
||||||
content: "\e95a";
|
content: '\e95a';
|
||||||
}
|
}
|
||||||
.icon-fixedPrice:before {
|
.icon-fixedPrice:before {
|
||||||
content: "\e95b";
|
content: '\e95b';
|
||||||
}
|
}
|
||||||
.icon-flower:before {
|
.icon-flower:before {
|
||||||
content: "\e95c";
|
content: '\e95c';
|
||||||
}
|
}
|
||||||
.icon-frozen:before {
|
.icon-frozen:before {
|
||||||
content: "\e95d";
|
content: '\e95d';
|
||||||
}
|
}
|
||||||
.icon-fruit:before {
|
.icon-fruit:before {
|
||||||
content: "\e95e";
|
content: '\e95e';
|
||||||
}
|
}
|
||||||
.icon-funeral:before {
|
.icon-funeral:before {
|
||||||
content: "\e95f";
|
content: '\e95f';
|
||||||
}
|
}
|
||||||
.icon-grafana:before {
|
.icon-grafana:before {
|
||||||
content: "\e931";
|
content: '\e931';
|
||||||
|
}
|
||||||
|
.icon-grafana:before {
|
||||||
|
content: '\e931';
|
||||||
}
|
}
|
||||||
.icon-greenery:before {
|
.icon-greenery:before {
|
||||||
content: "\e91e";
|
content: '\e91e';
|
||||||
}
|
}
|
||||||
.icon-greuge:before {
|
.icon-greuge:before {
|
||||||
content: "\e960";
|
content: '\e960';
|
||||||
}
|
}
|
||||||
.icon-grid:before {
|
.icon-grid:before {
|
||||||
content: "\e961";
|
content: '\e961';
|
||||||
}
|
}
|
||||||
.icon-handmade:before {
|
.icon-handmade:before {
|
||||||
content: "\e94a";
|
content: '\e94a';
|
||||||
}
|
}
|
||||||
.icon-handmadeArtificial:before {
|
.icon-handmadeArtificial:before {
|
||||||
content: "\e962";
|
content: '\e962';
|
||||||
}
|
}
|
||||||
.icon-headercol:before {
|
.icon-headercol:before {
|
||||||
content: "\e963";
|
content: '\e963';
|
||||||
}
|
}
|
||||||
.icon-info:before {
|
.icon-info:before {
|
||||||
content: "\e966";
|
content: '\e966';
|
||||||
}
|
}
|
||||||
.icon-inventory:before {
|
.icon-inventory:before {
|
||||||
content: "\e967";
|
content: '\e967';
|
||||||
}
|
}
|
||||||
.icon-invoice:before {
|
.icon-invoice:before {
|
||||||
content: "\e969";
|
content: '\e969';
|
||||||
}
|
}
|
||||||
.icon-invoice-in:before {
|
.icon-invoice-in:before {
|
||||||
content: "\e96a";
|
content: '\e96a';
|
||||||
}
|
}
|
||||||
.icon-invoice-in-create:before {
|
.icon-invoice-in-create:before {
|
||||||
content: "\e96b";
|
content: '\e96b';
|
||||||
}
|
}
|
||||||
.icon-invoice-out:before {
|
.icon-invoice-out:before {
|
||||||
content: "\e96c";
|
content: '\e96c';
|
||||||
}
|
}
|
||||||
.icon-isTooLittle:before {
|
.icon-isTooLittle:before {
|
||||||
content: "\e96e";
|
content: '\e96e';
|
||||||
}
|
}
|
||||||
.icon-item:before {
|
.icon-item:before {
|
||||||
content: "\e96f";
|
content: '\e96f';
|
||||||
}
|
}
|
||||||
.icon-languaje:before {
|
.icon-languaje:before {
|
||||||
content: "\e912";
|
content: '\e912';
|
||||||
}
|
}
|
||||||
.icon-lines:before {
|
.icon-lines:before {
|
||||||
content: "\e971";
|
content: '\e971';
|
||||||
}
|
}
|
||||||
.icon-linesprepaired:before {
|
.icon-linesprepaired:before {
|
||||||
content: "\e972";
|
content: '\e972';
|
||||||
}
|
}
|
||||||
.icon-link-to-corrected:before {
|
.icon-link-to-corrected:before {
|
||||||
content: "\e900";
|
content: '\e900';
|
||||||
}
|
}
|
||||||
.icon-link-to-correcting:before {
|
.icon-link-to-correcting:before {
|
||||||
content: "\e906";
|
content: '\e906';
|
||||||
}
|
}
|
||||||
.icon-logout:before {
|
.icon-logout:before {
|
||||||
content: "\e90a";
|
content: '\e90a';
|
||||||
}
|
}
|
||||||
.icon-mana:before {
|
.icon-mana:before {
|
||||||
content: "\e974";
|
content: '\e974';
|
||||||
}
|
}
|
||||||
.icon-mandatory:before {
|
.icon-mandatory:before {
|
||||||
content: "\e975";
|
content: '\e975';
|
||||||
}
|
}
|
||||||
.icon-net:before {
|
.icon-net:before {
|
||||||
content: "\e976";
|
content: '\e976';
|
||||||
}
|
}
|
||||||
.icon-newalbaran:before {
|
.icon-newalbaran:before {
|
||||||
content: "\e977";
|
content: '\e977';
|
||||||
}
|
}
|
||||||
.icon-niche:before {
|
.icon-niche:before {
|
||||||
content: "\e979";
|
content: '\e979';
|
||||||
}
|
}
|
||||||
.icon-no036:before {
|
.icon-no036:before {
|
||||||
content: "\e97a";
|
content: '\e97a';
|
||||||
}
|
}
|
||||||
.icon-noPayMethod:before {
|
.icon-noPayMethod:before {
|
||||||
content: "\e97b";
|
content: '\e97b';
|
||||||
}
|
}
|
||||||
.icon-notes:before {
|
.icon-notes:before {
|
||||||
content: "\e97c";
|
content: '\e97c';
|
||||||
}
|
}
|
||||||
.icon-noweb:before {
|
.icon-noweb:before {
|
||||||
content: "\e97e";
|
content: '\e97e';
|
||||||
}
|
}
|
||||||
.icon-onlinepayment:before {
|
.icon-onlinepayment:before {
|
||||||
content: "\e97f";
|
content: '\e97f';
|
||||||
}
|
}
|
||||||
.icon-package:before {
|
.icon-package:before {
|
||||||
content: "\e980";
|
content: '\e980';
|
||||||
}
|
}
|
||||||
.icon-payment:before {
|
.icon-payment:before {
|
||||||
content: "\e982";
|
content: '\e982';
|
||||||
}
|
}
|
||||||
.icon-pbx:before {
|
.icon-pbx:before {
|
||||||
content: "\e983";
|
content: '\e983';
|
||||||
}
|
}
|
||||||
.icon-pets:before {
|
.icon-pets:before {
|
||||||
content: "\e985";
|
content: '\e985';
|
||||||
}
|
}
|
||||||
.icon-photo:before {
|
.icon-photo:before {
|
||||||
content: "\e986";
|
content: '\e986';
|
||||||
}
|
}
|
||||||
.icon-plant:before {
|
.icon-plant:before {
|
||||||
content: "\e987";
|
content: '\e987';
|
||||||
}
|
}
|
||||||
.icon-polizon:before {
|
.icon-polizon:before {
|
||||||
content: "\e989";
|
content: '\e989';
|
||||||
}
|
}
|
||||||
.icon-preserved:before {
|
.icon-preserved:before {
|
||||||
content: "\e98a";
|
content: '\e98a';
|
||||||
}
|
}
|
||||||
.icon-recovery:before {
|
.icon-recovery:before {
|
||||||
content: "\e98b";
|
content: '\e98b';
|
||||||
}
|
}
|
||||||
.icon-regentry:before {
|
.icon-regentry:before {
|
||||||
content: "\e901";
|
content: '\e901';
|
||||||
}
|
}
|
||||||
.icon-reserva:before {
|
.icon-reserva:before {
|
||||||
content: "\e902";
|
content: '\e902';
|
||||||
}
|
}
|
||||||
.icon-revision:before {
|
.icon-revision:before {
|
||||||
content: "\e903";
|
content: '\e903';
|
||||||
}
|
}
|
||||||
.icon-risk:before {
|
.icon-risk:before {
|
||||||
content: "\e904";
|
content: '\e904';
|
||||||
}
|
}
|
||||||
.icon-services:before {
|
.icon-services:before {
|
||||||
content: "\e905";
|
content: '\e905';
|
||||||
}
|
}
|
||||||
.icon-settings:before {
|
.icon-settings:before {
|
||||||
content: "\e907";
|
content: '\e907';
|
||||||
}
|
}
|
||||||
.icon-shipment:before {
|
.icon-shipment:before {
|
||||||
content: "\e908";
|
content: '\e908';
|
||||||
}
|
}
|
||||||
.icon-sign:before {
|
.icon-sign:before {
|
||||||
content: "\e909";
|
content: '\e909';
|
||||||
}
|
}
|
||||||
.icon-sms:before {
|
.icon-sms:before {
|
||||||
content: "\e90b";
|
content: '\e90b';
|
||||||
}
|
}
|
||||||
.icon-solclaim:before {
|
.icon-solclaim:before {
|
||||||
content: "\e90c";
|
content: '\e90c';
|
||||||
}
|
}
|
||||||
.icon-solunion:before {
|
.icon-solunion:before {
|
||||||
content: "\e90d";
|
content: '\e90d';
|
||||||
}
|
}
|
||||||
.icon-splitline:before {
|
.icon-splitline:before {
|
||||||
content: "\e90e";
|
content: '\e90e';
|
||||||
}
|
}
|
||||||
.icon-splur:before {
|
.icon-splur:before {
|
||||||
content: "\e90f";
|
content: '\e90f';
|
||||||
}
|
}
|
||||||
.icon-stowaway:before {
|
.icon-stowaway:before {
|
||||||
content: "\e910";
|
content: '\e910';
|
||||||
}
|
}
|
||||||
.icon-supplier:before {
|
.icon-supplier:before {
|
||||||
content: "\e911";
|
content: '\e911';
|
||||||
}
|
}
|
||||||
.icon-supplierfalse:before {
|
.icon-supplierfalse:before {
|
||||||
content: "\e913";
|
content: '\e913';
|
||||||
}
|
}
|
||||||
.icon-tags:before {
|
.icon-tags:before {
|
||||||
content: "\e914";
|
content: '\e914';
|
||||||
}
|
}
|
||||||
.icon-tax:before {
|
.icon-tax:before {
|
||||||
content: "\e915";
|
content: '\e915';
|
||||||
}
|
}
|
||||||
.icon-thermometer:before {
|
.icon-thermometer:before {
|
||||||
content: "\e916";
|
content: '\e916';
|
||||||
}
|
}
|
||||||
.icon-ticket:before {
|
.icon-ticket:before {
|
||||||
content: "\e917";
|
content: '\e917';
|
||||||
}
|
}
|
||||||
.icon-ticketAdd:before {
|
.icon-ticketAdd:before {
|
||||||
content: "\e918";
|
content: '\e918';
|
||||||
}
|
}
|
||||||
.icon-traceability:before {
|
.icon-traceability:before {
|
||||||
content: "\e919";
|
content: '\e919';
|
||||||
}
|
}
|
||||||
.icon-transaction:before {
|
.icon-transaction:before {
|
||||||
content: "\e93b";
|
content: '\e93b';
|
||||||
|
}
|
||||||
|
.icon-transaction:before {
|
||||||
|
content: '\e93b';
|
||||||
}
|
}
|
||||||
.icon-treatments:before {
|
.icon-treatments:before {
|
||||||
content: "\e91c";
|
content: '\e91c';
|
||||||
}
|
}
|
||||||
.icon-trolley:before {
|
.icon-trolley:before {
|
||||||
content: "\e91a";
|
content: '\e91a';
|
||||||
}
|
}
|
||||||
.icon-troncales:before {
|
.icon-troncales:before {
|
||||||
content: "\e91b";
|
content: '\e91b';
|
||||||
}
|
}
|
||||||
.icon-unavailable:before {
|
.icon-unavailable:before {
|
||||||
content: "\e91d";
|
content: '\e91d';
|
||||||
}
|
}
|
||||||
.icon-volume:before {
|
.icon-volume:before {
|
||||||
content: "\e91f";
|
content: '\e91f';
|
||||||
}
|
}
|
||||||
.icon-wand:before {
|
.icon-wand:before {
|
||||||
content: "\e920";
|
content: '\e920';
|
||||||
}
|
}
|
||||||
.icon-web:before {
|
.icon-web:before {
|
||||||
content: "\e921";
|
content: '\e921';
|
||||||
}
|
}
|
||||||
.icon-wiki:before {
|
.icon-wiki:before {
|
||||||
content: "\e922";
|
content: '\e922';
|
||||||
}
|
}
|
||||||
.icon-worker:before {
|
.icon-worker:before {
|
||||||
content: "\e923";
|
content: '\e923';
|
||||||
}
|
}
|
||||||
.icon-zone:before {
|
.icon-zone:before {
|
||||||
content: "\e924";
|
content: '\e924';
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,11 +26,11 @@ export function isValidDate(date) {
|
||||||
* // returns "02/12/2022"
|
* // returns "02/12/2022"
|
||||||
* toDateFormat(new Date(2022, 11, 2));
|
* toDateFormat(new Date(2022, 11, 2));
|
||||||
*/
|
*/
|
||||||
export function toDateFormat(date) {
|
export function toDateFormat(date, locale = 'es-ES') {
|
||||||
if (!isValidDate(date)) {
|
if (!isValidDate(date)) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
return new Date(date).toLocaleDateString('es-ES', {
|
return new Date(date).toLocaleDateString(locale, {
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
month: '2-digit',
|
month: '2-digit',
|
||||||
day: '2-digit',
|
day: '2-digit',
|
||||||
|
@ -56,7 +56,7 @@ export function toTimeFormat(date, showSeconds = false) {
|
||||||
if (!isValidDate(date)) {
|
if (!isValidDate(date)) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
return new Date(date).toLocaleDateString('es-ES', {
|
return new Date(date).toLocaleTimeString('es-ES', {
|
||||||
hour: '2-digit',
|
hour: '2-digit',
|
||||||
minute: '2-digit',
|
minute: '2-digit',
|
||||||
second: showSeconds ? '2-digit' : undefined,
|
second: showSeconds ? '2-digit' : undefined,
|
||||||
|
@ -92,6 +92,27 @@ export function toDateTimeFormat(date, showSeconds = false) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts seconds to a formatted string representing hours and minutes (hh:mm).
|
||||||
|
* @param {number} seconds - The number of seconds to convert.
|
||||||
|
* @param {boolean} includeHSuffix - Optional parameter indicating whether to include "h." after the hour.
|
||||||
|
* @returns {string} A string representing the time in the format "hh:mm" with optional "h." suffix.
|
||||||
|
*/
|
||||||
|
export function secondsToHoursMinutes(seconds, includeHSuffix = true) {
|
||||||
|
if (!seconds) return includeHSuffix ? '00:00 h.' : '00:00';
|
||||||
|
|
||||||
|
const hours = Math.floor(seconds / 3600);
|
||||||
|
const remainingMinutes = seconds % 3600;
|
||||||
|
const minutes = Math.floor(remainingMinutes / 60);
|
||||||
|
const formattedHours = hours < 10 ? '0' + hours : hours;
|
||||||
|
const formattedMinutes = minutes < 10 ? '0' + minutes : minutes;
|
||||||
|
|
||||||
|
// Append "h." if includeHSuffix is true
|
||||||
|
const suffix = includeHSuffix ? ' h.' : '';
|
||||||
|
// Return formatted string
|
||||||
|
return formattedHours + ':' + formattedMinutes + suffix;
|
||||||
|
}
|
||||||
|
|
||||||
export function getTimeDifferenceWithToday(date) {
|
export function getTimeDifferenceWithToday(date) {
|
||||||
let today = Date.vnNew();
|
let today = Date.vnNew();
|
||||||
today.setHours(0, 0, 0, 0);
|
today.setHours(0, 0, 0, 0);
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import toLowerCase from './toLowerCase';
|
import toLowerCase from './toLowerCase';
|
||||||
import toDate from './toDate';
|
import toDate from './toDate';
|
||||||
import toDateString from './toDateString';
|
import toDateString from './toDateString';
|
||||||
import toDateHour from './toDateHour';
|
import toDateHourMin from './toDateHourMin';
|
||||||
|
import toDateHourMinSec from './toDateHourMinSec';
|
||||||
import toRelativeDate from './toRelativeDate';
|
import toRelativeDate from './toRelativeDate';
|
||||||
import toCurrency from './toCurrency';
|
import toCurrency from './toCurrency';
|
||||||
import toPercentage from './toPercentage';
|
import toPercentage from './toPercentage';
|
||||||
|
@ -16,7 +17,8 @@ export {
|
||||||
toDate,
|
toDate,
|
||||||
toHour,
|
toHour,
|
||||||
toDateString,
|
toDateString,
|
||||||
toDateHour,
|
toDateHourMin,
|
||||||
|
toDateHourMinSec,
|
||||||
toRelativeDate,
|
toRelativeDate,
|
||||||
toCurrency,
|
toCurrency,
|
||||||
toPercentage,
|
toPercentage,
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
export default function toDateHourMin(date) {
|
||||||
|
const dateHour = new Date(date).toLocaleDateString('es-ES', {
|
||||||
|
timeZone: 'Europe/Madrid',
|
||||||
|
year: 'numeric',
|
||||||
|
month: '2-digit',
|
||||||
|
day: '2-digit',
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit',
|
||||||
|
});
|
||||||
|
return dateHour;
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
export default function toDateHour(date) {
|
export default function toDateHourMinSec(date) {
|
||||||
const dateHour = new Date(date).toLocaleDateString('es-ES', {
|
const dateHour = new Date(date).toLocaleDateString('es-ES', {
|
||||||
timeZone: 'Europe/Madrid',
|
timeZone: 'Europe/Madrid',
|
||||||
year: 'numeric',
|
year: 'numeric',
|
|
@ -67,6 +67,7 @@ globals:
|
||||||
reason: reason
|
reason: reason
|
||||||
noResults: No results
|
noResults: No results
|
||||||
system: System
|
system: System
|
||||||
|
notificationSent: Notification sent
|
||||||
warehouse: Warehouse
|
warehouse: Warehouse
|
||||||
company: Company
|
company: Company
|
||||||
fieldRequired: Field required
|
fieldRequired: Field required
|
||||||
|
@ -82,6 +83,7 @@ globals:
|
||||||
selectFile: Select a file
|
selectFile: Select a file
|
||||||
copyClipboard: Copy on clipboard
|
copyClipboard: Copy on clipboard
|
||||||
salesPerson: SalesPerson
|
salesPerson: SalesPerson
|
||||||
|
send: Send
|
||||||
code: Code
|
code: Code
|
||||||
pageTitles:
|
pageTitles:
|
||||||
summary: Summary
|
summary: Summary
|
||||||
|
@ -151,6 +153,13 @@ customer:
|
||||||
creditContracts: Credit contracts
|
creditContracts: Credit contracts
|
||||||
creditOpinion: Credit opinion
|
creditOpinion: Credit opinion
|
||||||
others: Others
|
others: Others
|
||||||
|
samples: Samples
|
||||||
|
consumption: Consumption
|
||||||
|
mandates: Mandates
|
||||||
|
contacts: Contacts
|
||||||
|
webPayment: Web payment
|
||||||
|
fileManagement: File management
|
||||||
|
unpaid: Unpaid
|
||||||
list:
|
list:
|
||||||
phone: Phone
|
phone: Phone
|
||||||
email: Email
|
email: Email
|
||||||
|
@ -161,14 +170,18 @@ customer:
|
||||||
customerId: Claim ID
|
customerId: Claim ID
|
||||||
salesPerson: Sales person
|
salesPerson: Sales person
|
||||||
credit: Credit
|
credit: Credit
|
||||||
|
risk: Risk
|
||||||
securedCredit: Secured credit
|
securedCredit: Secured credit
|
||||||
payMethod: Pay method
|
payMethod: Pay method
|
||||||
debt: Debt
|
debt: Debt
|
||||||
isDisabled: Customer is disabled
|
isFrozen: Customer frozen
|
||||||
isFrozen: Customer is frozen
|
|
||||||
hasDebt: Customer has debt
|
hasDebt: Customer has debt
|
||||||
notChecked: Customer not checked
|
isDisabled: Customer inactive
|
||||||
|
notChecked: Customer no checked
|
||||||
|
webAccountInactive: Web account inactive
|
||||||
noWebAccess: Web access is disabled
|
noWebAccess: Web access is disabled
|
||||||
|
businessType: Business type
|
||||||
|
passwordRequirements: 'The password must have at least { length } length characters, {nAlpha} alphabetic characters, {nUpper} capital letters, {nDigits} digits and {nPunct} symbols (Ex: $%&.)\n'
|
||||||
businessTypeFk: Business type
|
businessTypeFk: Business type
|
||||||
summary:
|
summary:
|
||||||
basicData: Basic data
|
basicData: Basic data
|
||||||
|
@ -228,17 +241,20 @@ customer:
|
||||||
recoverySince: Recovery since
|
recoverySince: Recovery since
|
||||||
businessType: Business Type
|
businessType: Business Type
|
||||||
city: City
|
city: City
|
||||||
|
descriptorInfo: Invoices minus payments plus orders not yet
|
||||||
rating: Rating
|
rating: Rating
|
||||||
recommendCredit: Recommended credit
|
recommendCredit: Recommended credit
|
||||||
basicData:
|
basicData:
|
||||||
socialName: Fiscal name
|
socialName: Fiscal name
|
||||||
businessType: Business type
|
businessType: Business type
|
||||||
contact: Contact
|
contact: Contact
|
||||||
|
youCanSaveMultipleEmails: You can save multiple emails
|
||||||
email: Email
|
email: Email
|
||||||
phone: Phone
|
phone: Phone
|
||||||
mobile: Mobile
|
mobile: Mobile
|
||||||
salesPerson: Sales person
|
salesPerson: Sales person
|
||||||
contactChannel: Contact channel
|
contactChannel: Contact channel
|
||||||
|
previousClient: Previous client
|
||||||
extendedList:
|
extendedList:
|
||||||
tableVisibleColumns:
|
tableVisibleColumns:
|
||||||
id: Identifier
|
id: Identifier
|
||||||
|
@ -468,6 +484,12 @@ ticket:
|
||||||
weight: Weight
|
weight: Weight
|
||||||
goTo: Go to
|
goTo: Go to
|
||||||
summaryAmount: Summary
|
summaryAmount: Summary
|
||||||
|
create:
|
||||||
|
client: Client
|
||||||
|
address: Address
|
||||||
|
landed: Landed
|
||||||
|
warehouse: Warehouse
|
||||||
|
agency: Agency
|
||||||
claim:
|
claim:
|
||||||
pageTitles:
|
pageTitles:
|
||||||
claims: Claims
|
claims: Claims
|
||||||
|
@ -790,6 +812,7 @@ worker:
|
||||||
pbx: Private Branch Exchange
|
pbx: Private Branch Exchange
|
||||||
log: Log
|
log: Log
|
||||||
calendar: Calendar
|
calendar: Calendar
|
||||||
|
timeControl: Time control
|
||||||
list:
|
list:
|
||||||
name: Name
|
name: Name
|
||||||
email: Email
|
email: Email
|
||||||
|
|
|
@ -67,6 +67,7 @@ globals:
|
||||||
reason: motivo
|
reason: motivo
|
||||||
noResults: Sin resultados
|
noResults: Sin resultados
|
||||||
system: Sistema
|
system: Sistema
|
||||||
|
notificationSent: Notificación enviada
|
||||||
warehouse: Almacén
|
warehouse: Almacén
|
||||||
company: Empresa
|
company: Empresa
|
||||||
fieldRequired: Campo requerido
|
fieldRequired: Campo requerido
|
||||||
|
@ -82,6 +83,7 @@ globals:
|
||||||
selectFile: Seleccione un fichero
|
selectFile: Seleccione un fichero
|
||||||
copyClipboard: Copiar en portapapeles
|
copyClipboard: Copiar en portapapeles
|
||||||
salesPerson: Comercial
|
salesPerson: Comercial
|
||||||
|
send: Enviar
|
||||||
code: Código
|
code: Código
|
||||||
pageTitles:
|
pageTitles:
|
||||||
summary: Resumen
|
summary: Resumen
|
||||||
|
@ -150,6 +152,13 @@ customer:
|
||||||
creditContracts: Contratos de crédito
|
creditContracts: Contratos de crédito
|
||||||
creditOpinion: Opinión de crédito
|
creditOpinion: Opinión de crédito
|
||||||
others: Otros
|
others: Otros
|
||||||
|
samples: Plantillas
|
||||||
|
consumption: Consumo
|
||||||
|
mandates: Mandatos
|
||||||
|
contacts: Contactos
|
||||||
|
webPayment: Pago web
|
||||||
|
fileManagement: Gestión documental
|
||||||
|
unpaid: Impago
|
||||||
list:
|
list:
|
||||||
phone: Teléfono
|
phone: Teléfono
|
||||||
email: Email
|
email: Email
|
||||||
|
@ -159,14 +168,18 @@ customer:
|
||||||
customerId: ID cliente
|
customerId: ID cliente
|
||||||
salesPerson: Comercial
|
salesPerson: Comercial
|
||||||
credit: Crédito
|
credit: Crédito
|
||||||
|
risk: Riesgo
|
||||||
securedCredit: Crédito asegurado
|
securedCredit: Crédito asegurado
|
||||||
payMethod: Método de pago
|
payMethod: Método de pago
|
||||||
debt: Riesgo
|
debt: Riesgo
|
||||||
isDisabled: El cliente está desactivado
|
isFrozen: Cliente congelado
|
||||||
isFrozen: El cliente está congelado
|
hasDebt: Cliente con riesgo
|
||||||
hasDebt: El cliente tiene riesgo
|
isDisabled: Cliente inactivo
|
||||||
notChecked: El cliente no está comprobado
|
notChecked: Cliente no comprobado
|
||||||
|
webAccountInactive: Sin acceso web
|
||||||
noWebAccess: El acceso web está desactivado
|
noWebAccess: El acceso web está desactivado
|
||||||
|
businessType: Tipo de negocio
|
||||||
|
passwordRequirements: 'La contraseña debe tener al menos { length } caracteres de longitud, {nAlpha} caracteres alfabéticos, {nUpper} letras mayúsculas, {nDigits} dígitos y {nPunct} símbolos (Ej: $%&.)'
|
||||||
businessTypeFk: Tipo de negocio
|
businessTypeFk: Tipo de negocio
|
||||||
summary:
|
summary:
|
||||||
basicData: Datos básicos
|
basicData: Datos básicos
|
||||||
|
@ -226,17 +239,20 @@ customer:
|
||||||
recoverySince: Recobro desde
|
recoverySince: Recobro desde
|
||||||
businessType: Tipo de negocio
|
businessType: Tipo de negocio
|
||||||
city: Población
|
city: Población
|
||||||
|
descriptorInfo: Facturas menos recibos mas pedidos sin facturar
|
||||||
rating: Clasificación
|
rating: Clasificación
|
||||||
recommendCredit: Crédito recomendado
|
recommendCredit: Crédito recomendado
|
||||||
basicData:
|
basicData:
|
||||||
socialName: Nombre fiscal
|
socialName: Nombre fiscal
|
||||||
businessType: Tipo de negocio
|
businessType: Tipo de negocio
|
||||||
contact: Contacto
|
contact: Contacto
|
||||||
|
youCanSaveMultipleEmails: Puede guardar varios correos electrónicos encadenándolos mediante comas sin espacios{','} ejemplo{':'} user{'@'}dominio{'.'}com, user2{'@'}dominio{'.'}com siendo el primer correo electrónico el principal
|
||||||
email: Email
|
email: Email
|
||||||
phone: Teléfono
|
phone: Teléfono
|
||||||
mobile: Móvil
|
mobile: Móvil
|
||||||
salesPerson: Comercial
|
salesPerson: Comercial
|
||||||
contactChannel: Canal de contacto
|
contactChannel: Canal de contacto
|
||||||
|
previousClient: Cliente anterior
|
||||||
extendedList:
|
extendedList:
|
||||||
tableVisibleColumns:
|
tableVisibleColumns:
|
||||||
id: Identificador
|
id: Identificador
|
||||||
|
@ -466,6 +482,12 @@ ticket:
|
||||||
weight: Peso
|
weight: Peso
|
||||||
goTo: Ir a
|
goTo: Ir a
|
||||||
summaryAmount: Resumen
|
summaryAmount: Resumen
|
||||||
|
create:
|
||||||
|
client: Cliente
|
||||||
|
address: Dirección
|
||||||
|
landed: F. entrega
|
||||||
|
warehouse: Almacén
|
||||||
|
agency: Agencia
|
||||||
claim:
|
claim:
|
||||||
pageTitles:
|
pageTitles:
|
||||||
claims: Reclamaciones
|
claims: Reclamaciones
|
||||||
|
@ -788,6 +810,7 @@ worker:
|
||||||
pbx: Centralita
|
pbx: Centralita
|
||||||
log: Historial
|
log: Historial
|
||||||
calendar: Calendario
|
calendar: Calendario
|
||||||
|
timeControl: Control de horario
|
||||||
list:
|
list:
|
||||||
name: Nombre
|
name: Nombre
|
||||||
email: Email
|
email: Email
|
||||||
|
|
|
@ -1,46 +1,15 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import LeftMenu from 'components/LeftMenu.vue';
|
import VnCard from 'components/common/VnCard.vue';
|
||||||
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
|
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
|
||||||
import ClaimDescriptor from './ClaimDescriptor.vue';
|
import ClaimDescriptor from './ClaimDescriptor.vue';
|
||||||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
|
||||||
import useCardSize from 'src/composables/useCardSize';
|
|
||||||
|
|
||||||
const stateStore = useStateStore();
|
|
||||||
const { t } = useI18n();
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<Teleport to="#searchbar" v-if="stateStore.isHeaderMounted()">
|
<VnCard
|
||||||
<VnSearchbar
|
data-key="Claim"
|
||||||
data-key="ClaimList"
|
base-url="Claims"
|
||||||
url="Claims/filter"
|
:descriptor="ClaimDescriptor"
|
||||||
:label="t('Search claim')"
|
searchbar-data-key="ClaimList"
|
||||||
:info="t('You can search by claim id or customer name')"
|
searchbar-url="Claims/filter"
|
||||||
/>
|
searchbar-label="Search claim"
|
||||||
</Teleport>
|
searchbar-info="You can search by claim id or customer name"
|
||||||
<QDrawer v-model="stateStore.leftDrawer" show-if-above :width="256">
|
/>
|
||||||
<QScrollArea class="fit">
|
|
||||||
<ClaimDescriptor />
|
|
||||||
<QSeparator />
|
|
||||||
<LeftMenu source="card" />
|
|
||||||
</QScrollArea>
|
|
||||||
</QDrawer>
|
|
||||||
<QPageContainer>
|
|
||||||
<QPage>
|
|
||||||
<VnSubToolbar />
|
|
||||||
<div :class="useCardSize()">
|
|
||||||
<RouterView></RouterView>
|
|
||||||
</div>
|
|
||||||
</QPage>
|
|
||||||
</QPageContainer>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<i18n>
|
|
||||||
es:
|
|
||||||
Search claim: Buscar reclamación
|
|
||||||
You can search by claim id or customer name: Puedes buscar por id de la reclamación o nombre del cliente
|
|
||||||
Details: Detalles
|
|
||||||
Notes: Notas
|
|
||||||
Action: Acción
|
|
||||||
</i18n>
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ const claimId = computed(() => $props.id || route.params.id);
|
||||||
|
|
||||||
const claimFilter = {
|
const claimFilter = {
|
||||||
where: { claimFk: claimId.value },
|
where: { claimFk: claimId.value },
|
||||||
fields: ['created', 'workerFk', 'text'],
|
fields: ['id', 'created', 'workerFk', 'text'],
|
||||||
include: {
|
include: {
|
||||||
relation: 'worker',
|
relation: 'worker',
|
||||||
scope: {
|
scope: {
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Search claim: Buscar reclamación
|
||||||
|
You can search by claim id or customer name: Puedes buscar por id de la reclamación o nombre del cliente
|
|
@ -1,18 +1,21 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue';
|
import { onBeforeMount, ref, watch } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
import FetchData from 'components/FetchData.vue';
|
import FetchData from 'components/FetchData.vue';
|
||||||
import VnPaginate from 'src/components/ui/VnPaginate.vue';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
const addresses = ref([]);
|
||||||
|
const client = ref(null);
|
||||||
const provincesLocation = ref([]);
|
const provincesLocation = ref([]);
|
||||||
|
|
||||||
const consigneeFilter = {
|
const addressFilter = {
|
||||||
fields: [
|
fields: [
|
||||||
'id',
|
'id',
|
||||||
'isDefaultAddress',
|
'isDefaultAddress',
|
||||||
|
@ -44,6 +47,42 @@ const consigneeFilter = {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onBeforeMount(() => {
|
||||||
|
const { id } = route.params;
|
||||||
|
getAddressesData(id);
|
||||||
|
getClientData(id);
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.params.id,
|
||||||
|
(newValue) => {
|
||||||
|
if (!newValue) return;
|
||||||
|
getAddressesData(newValue);
|
||||||
|
getClientData(newValue);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const getAddressesData = async (id) => {
|
||||||
|
try {
|
||||||
|
const { data } = await axios.get(`Clients/${id}/addresses`, {
|
||||||
|
params: { filter: JSON.stringify(addressFilter) },
|
||||||
|
});
|
||||||
|
addresses.value = data;
|
||||||
|
sortAddresses();
|
||||||
|
} catch (error) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getClientData = async (id) => {
|
||||||
|
try {
|
||||||
|
const { data } = await axios.get(`Clients/${id}`);
|
||||||
|
client.value = data;
|
||||||
|
} catch (error) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const setProvince = (provinceFk) => {
|
const setProvince = (provinceFk) => {
|
||||||
const result = provincesLocation.value.filter(
|
const result = provincesLocation.value.filter(
|
||||||
(province) => province.id === provinceFk
|
(province) => province.id === provinceFk
|
||||||
|
@ -51,16 +90,38 @@ const setProvince = (provinceFk) => {
|
||||||
return result[0]?.name || '';
|
return result[0]?.name || '';
|
||||||
};
|
};
|
||||||
|
|
||||||
const toCustomerConsigneeCreate = () => {
|
const isDefaultAddress = (address) => {
|
||||||
router.push({ name: 'CustomerConsigneeCreate' });
|
return client?.value?.defaultAddressFk === address.id ? 1 : 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
const toCustomerConsigneeEdit = (consigneeId) => {
|
const setDefault = (address) => {
|
||||||
|
const url = `Clients/${route.params.id}`;
|
||||||
|
const payload = { defaultAddressFk: address.id };
|
||||||
|
axios.patch(url, payload).then((res) => {
|
||||||
|
if (res.data) {
|
||||||
|
client.value.defaultAddressFk = res.data.defaultAddressFk;
|
||||||
|
sortAddresses();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const sortAddresses = () => {
|
||||||
|
if (!client.value || !addresses.value) return;
|
||||||
|
addresses.value = addresses.value.sort((a, b) => {
|
||||||
|
return isDefaultAddress(b) - isDefaultAddress(a);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const toCustomerAddressCreate = () => {
|
||||||
|
router.push({ name: 'CustomerAddressCreate' });
|
||||||
|
};
|
||||||
|
|
||||||
|
const toCustomerAddressEdit = (addressId) => {
|
||||||
router.push({
|
router.push({
|
||||||
name: 'CustomerConsigneeEdit',
|
name: 'CustomerAddressEdit',
|
||||||
params: {
|
params: {
|
||||||
id: route.params.id,
|
id: route.params.id,
|
||||||
consigneeId,
|
addressId,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -73,26 +134,41 @@ const toCustomerConsigneeEdit = (consigneeId) => {
|
||||||
url="Provinces/location"
|
url="Provinces/location"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<QCard class="q-pa-lg">
|
<div class="full-width flex justify-center">
|
||||||
<VnPaginate
|
<QCard class="card-width q-pa-lg" v-if="addresses.length">
|
||||||
data-key="CustomerConsignees"
|
<QCardSection>
|
||||||
:url="`Clients/${route.params.id}/addresses`"
|
<div
|
||||||
order="id"
|
v-for="(item, index) in addresses"
|
||||||
auto-load
|
|
||||||
:filter="consigneeFilter"
|
|
||||||
>
|
|
||||||
<template #body="{ rows }">
|
|
||||||
<QCard
|
|
||||||
v-for="(item, index) in rows"
|
|
||||||
:key="index"
|
:key="index"
|
||||||
|
class="address-card"
|
||||||
:class="{
|
:class="{
|
||||||
'consignees-card': true,
|
'q-mb-md': index < addresses.length - 1,
|
||||||
'q-mb-md': index < rows.length - 1,
|
'item-disabled': !item.isActive,
|
||||||
}"
|
}"
|
||||||
@click="toCustomerConsigneeEdit(item.id)"
|
@click="toCustomerAddressEdit(item.id)"
|
||||||
>
|
>
|
||||||
<div class="q-ml-xs q-mr-md flex items-center">
|
<div class="q-ml-xs q-mr-md flex items-center">
|
||||||
<QIcon name="star" size="md" color="primary" />
|
<QIcon
|
||||||
|
:style="{
|
||||||
|
'font-variation-settings': `'FILL' ${isDefaultAddress(
|
||||||
|
item
|
||||||
|
)}`,
|
||||||
|
}"
|
||||||
|
color="primary"
|
||||||
|
name="star"
|
||||||
|
size="md"
|
||||||
|
@click.stop="!isDefaultAddress(item) && setDefault(item)"
|
||||||
|
>
|
||||||
|
<QTooltip>
|
||||||
|
{{
|
||||||
|
t(
|
||||||
|
isDefaultAddress(item)
|
||||||
|
? 'Default address'
|
||||||
|
: 'Set as default'
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</QTooltip>
|
||||||
|
</QIcon>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="text-weight-bold q-mb-sm">
|
<div class="text-weight-bold q-mb-sm">
|
||||||
|
@ -136,12 +212,13 @@ const toCustomerConsigneeEdit = (consigneeId) => {
|
||||||
<div>{{ observation.description }}</div>
|
<div>{{ observation.description }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</QCard>
|
</div>
|
||||||
</template>
|
</QCardSection>
|
||||||
</VnPaginate>
|
</QCard>
|
||||||
</QCard>
|
</div>
|
||||||
|
|
||||||
<QPageSticky :offset="[18, 18]">
|
<QPageSticky :offset="[18, 18]">
|
||||||
<QBtn @click.stop="toCustomerConsigneeCreate()" color="primary" fab icon="add" />
|
<QBtn @click.stop="toCustomerAddressCreate()" color="primary" fab icon="add" />
|
||||||
<QTooltip>
|
<QTooltip>
|
||||||
{{ t('New consignee') }}
|
{{ t('New consignee') }}
|
||||||
</QTooltip>
|
</QTooltip>
|
||||||
|
@ -149,8 +226,8 @@ const toCustomerConsigneeEdit = (consigneeId) => {
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.consignees-card {
|
.address-card {
|
||||||
border: 2px solid var(--vn-accent-color);
|
border: 2px solid var(--vn-light-gray);
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -160,6 +237,10 @@ const toCustomerConsigneeEdit = (consigneeId) => {
|
||||||
background-color: var(--vn-accent-color);
|
background-color: var(--vn-accent-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item-disabled {
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<i18n>
|
<i18n>
|
||||||
|
@ -167,4 +248,6 @@ es:
|
||||||
Is equalizated: Recargo de equivalencia
|
Is equalizated: Recargo de equivalencia
|
||||||
Is logiflora allowed: Compra directa en Holanda
|
Is logiflora allowed: Compra directa en Holanda
|
||||||
New consignee: Nuevo consignatario
|
New consignee: Nuevo consignatario
|
||||||
|
Default address: Consignatario predeterminado
|
||||||
|
Set as default: Establecer como predeterminado
|
||||||
</i18n>
|
</i18n>
|
|
@ -1,145 +1,102 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, ref } from 'vue';
|
import { computed, onBeforeMount, ref, watch } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
import { date, QCheckbox, QBtn, useQuasar } from 'quasar';
|
import axios from 'axios';
|
||||||
|
import { QCheckbox, QBtn, useQuasar } from 'quasar';
|
||||||
|
|
||||||
import { toCurrency } from 'src/filters';
|
import { toCurrency, toDate, toDateHourMin } from 'src/filters';
|
||||||
|
import { useState } from 'src/composables/useState';
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
import { useStateStore } from 'stores/useStateStore';
|
||||||
|
import { useValidator } from 'src/composables/useValidator';
|
||||||
|
import { usePrintService } from 'src/composables/usePrintService';
|
||||||
|
|
||||||
|
import VnPaginate from 'src/components/ui/VnPaginate.vue';
|
||||||
import FetchData from 'components/FetchData.vue';
|
import FetchData from 'components/FetchData.vue';
|
||||||
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
|
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
|
||||||
import CustomerNewPayment from 'src/pages/Customer/components/CustomerNewPayment.vue';
|
import CustomerNewPayment from 'src/pages/Customer/components/CustomerNewPayment.vue';
|
||||||
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
||||||
|
import InvoiceOutDescriptorProxy from 'src/pages/InvoiceOut/Card/InvoiceOutDescriptorProxy.vue';
|
||||||
|
|
||||||
|
const { sendEmail } = usePrintService();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
const { validate } = useValidator();
|
||||||
const quasar = useQuasar();
|
const quasar = useQuasar();
|
||||||
|
const route = useRoute();
|
||||||
|
const state = useState();
|
||||||
const stateStore = useStateStore();
|
const stateStore = useStateStore();
|
||||||
|
const user = state.getUser();
|
||||||
|
|
||||||
const clientRisks = ref(null);
|
const clientRisks = ref(null);
|
||||||
const companiesOptions = ref([]);
|
|
||||||
const companyId = ref(442);
|
|
||||||
const rows = ref(null);
|
|
||||||
const workerId = ref(0);
|
|
||||||
const receiptsRef = ref(null);
|
|
||||||
const clientRisksRef = ref(null);
|
const clientRisksRef = ref(null);
|
||||||
|
const companiesOptions = ref([]);
|
||||||
|
const companyId = ref(null);
|
||||||
|
const receiptsRef = ref(null);
|
||||||
|
const receiptsData = ref([]);
|
||||||
|
|
||||||
const filterCompanies = { order: ['code'] };
|
const filterCompanies = { order: ['code'] };
|
||||||
const params = {
|
const userParams = {
|
||||||
clientId: `${route.params.id}`,
|
clientId: route.params.id,
|
||||||
companyId: companyId.value,
|
companyId: user.value.companyFk,
|
||||||
filter: { limit: 20 },
|
|
||||||
};
|
};
|
||||||
const filter = {
|
const filter = {
|
||||||
include: { relation: 'company', scope: { fields: ['code'] } },
|
include: { relation: 'company', scope: { fields: ['code'] } },
|
||||||
where: { clientFk: `${route.params.id}`, companyFk: companyId.value },
|
where: { clientFk: route.params.id, companyFk: user.value.companyFk },
|
||||||
};
|
|
||||||
|
|
||||||
const tableColumnComponents = {
|
|
||||||
payed: {
|
|
||||||
component: 'span',
|
|
||||||
props: () => {},
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
created: {
|
|
||||||
component: 'span',
|
|
||||||
props: () => {},
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
userName: {
|
|
||||||
component: QBtn,
|
|
||||||
props: () => ({ flat: true, color: 'blue' }),
|
|
||||||
event: (prop) => {
|
|
||||||
workerId.value = prop.row.clientFk;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
description: {
|
|
||||||
component: 'span',
|
|
||||||
props: () => {},
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
bankFk: {
|
|
||||||
component: 'span',
|
|
||||||
props: () => {},
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
debit: {
|
|
||||||
component: 'span',
|
|
||||||
props: () => {},
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
credit: {
|
|
||||||
component: 'span',
|
|
||||||
props: () => {},
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
balance: {
|
|
||||||
component: 'span',
|
|
||||||
props: () => {},
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
isConciliate: {
|
|
||||||
component: QCheckbox,
|
|
||||||
props: (prop) => ({
|
|
||||||
disable: true,
|
|
||||||
'model-value': Boolean(prop.value),
|
|
||||||
}),
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const columns = computed(() => [
|
const columns = computed(() => [
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: 'payed',
|
field: 'payed',
|
||||||
format: (value) => date.formatDate(value, 'DD/MM/YYYY'),
|
format: (value) => toDate(value),
|
||||||
label: t('Date'),
|
label: t('Date'),
|
||||||
name: 'payed',
|
name: 'date',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: 'created',
|
field: 'created',
|
||||||
format: (value) => date.formatDate(value, 'DD/MM/YYYY hh:mm'),
|
format: (value) => toDateHourMin(value),
|
||||||
label: t('Creation date'),
|
label: t('Creation date'),
|
||||||
name: 'created',
|
name: 'creationDate',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: 'userName',
|
field: 'userName',
|
||||||
label: t('Employee'),
|
label: t('Employee'),
|
||||||
name: 'userName',
|
name: 'employee',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: 'description',
|
field: 'description',
|
||||||
label: t('Reference'),
|
label: t('Reference'),
|
||||||
name: 'description',
|
name: 'reference',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: 'bankFk',
|
field: 'bankFk',
|
||||||
label: t('Bank'),
|
label: t('Bank'),
|
||||||
name: 'bankFk',
|
name: 'bank',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'right',
|
||||||
field: 'debit',
|
field: 'debit',
|
||||||
|
format: (value) => value && toCurrency(value),
|
||||||
label: t('Debit'),
|
label: t('Debit'),
|
||||||
name: 'debit',
|
name: 'debit',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'right',
|
||||||
field: 'credit',
|
field: 'credit',
|
||||||
format: (value) => toCurrency(value),
|
format: (value) => value && toCurrency(value),
|
||||||
label: t('Havings'),
|
label: t('Havings'),
|
||||||
name: 'credit',
|
name: 'havings',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'right',
|
||||||
field: (value) => value.debit - value.credit,
|
field: 'balance',
|
||||||
format: (value) => toCurrency(value),
|
format: (value) => value && toCurrency(value),
|
||||||
label: t('Balance'),
|
label: t('Balance'),
|
||||||
name: 'balance',
|
name: 'balance',
|
||||||
},
|
},
|
||||||
|
@ -147,16 +104,58 @@ const columns = computed(() => [
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: 'isConciliate',
|
field: 'isConciliate',
|
||||||
label: t('Conciliated'),
|
label: t('Conciliated'),
|
||||||
name: 'isConciliate',
|
name: 'conciliated',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: 'totalWithVat',
|
||||||
|
label: '',
|
||||||
|
name: 'actions',
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const getData = () => {
|
onBeforeMount(() => {
|
||||||
stateStore.rightDrawer = true;
|
stateStore.rightDrawer = true;
|
||||||
|
companyId.value = user.value.companyFk;
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.params.id,
|
||||||
|
(newValue) => {
|
||||||
|
if (!newValue) return;
|
||||||
|
userParams.clientId = newValue;
|
||||||
|
filter.where.clientFk = newValue;
|
||||||
|
getData();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const getData = () => {
|
||||||
receiptsRef.value?.fetch();
|
receiptsRef.value?.fetch();
|
||||||
clientRisksRef.value?.fetch();
|
clientRisksRef.value?.fetch();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getCurrentBalance = () => {
|
||||||
|
const currentBalance = clientRisks.value.find((balance) => {
|
||||||
|
return balance.companyFk === companyId.value;
|
||||||
|
});
|
||||||
|
return currentBalance && currentBalance.amount;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onFetch = (balances) => {
|
||||||
|
balances.forEach((balance, index) => {
|
||||||
|
if (index === 0) {
|
||||||
|
balance.balance = getCurrentBalance();
|
||||||
|
} else {
|
||||||
|
let previousBalance = balances[index - 1];
|
||||||
|
balance.balance =
|
||||||
|
previousBalance.balance -
|
||||||
|
(previousBalance.debit - previousBalance.credit);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
receiptsData.value = balances;
|
||||||
|
};
|
||||||
|
|
||||||
const showNewPaymentDialog = () => {
|
const showNewPaymentDialog = () => {
|
||||||
quasar.dialog({
|
quasar.dialog({
|
||||||
component: CustomerNewPayment,
|
component: CustomerNewPayment,
|
||||||
|
@ -169,25 +168,29 @@ const showNewPaymentDialog = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateCompanyId = (id) => {
|
const updateCompanyId = (id) => {
|
||||||
if (id) companyId.value = id;
|
if (id) {
|
||||||
|
companyId.value = id;
|
||||||
|
userParams.companyId = id;
|
||||||
|
filter.where.companyFk = id;
|
||||||
|
}
|
||||||
getData();
|
getData();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const saveFieldValue = async (row) => {
|
||||||
|
try {
|
||||||
|
const payload = { description: row.description };
|
||||||
|
await axios.patch(`Receipts/${row.id}`, payload);
|
||||||
|
} catch (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const sendEmailAction = () => {
|
||||||
|
sendEmail(`Suppliers/${route.params.id}/campaign-metrics-email`);
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<FetchData
|
|
||||||
:filter="filterCompanies"
|
|
||||||
@on-fetch="(data) => (companiesOptions = data)"
|
|
||||||
auto-load
|
|
||||||
url="Companies"
|
|
||||||
/>
|
|
||||||
<FetchData
|
|
||||||
:params="params"
|
|
||||||
@on-fetch="(data) => (rows = data)"
|
|
||||||
auto-load
|
|
||||||
ref="receiptsRef"
|
|
||||||
url="Receipts/filter"
|
|
||||||
/>
|
|
||||||
<FetchData
|
<FetchData
|
||||||
:filter="filter"
|
:filter="filter"
|
||||||
@on-fetch="(data) => (clientRisks = data)"
|
@on-fetch="(data) => (clientRisks = data)"
|
||||||
|
@ -195,36 +198,121 @@ const updateCompanyId = (id) => {
|
||||||
ref="clientRisksRef"
|
ref="clientRisksRef"
|
||||||
url="ClientRisks"
|
url="ClientRisks"
|
||||||
/>
|
/>
|
||||||
|
<FetchData
|
||||||
|
:filter="filterCompanies"
|
||||||
|
@on-fetch="(data) => (companiesOptions = data)"
|
||||||
|
auto-load
|
||||||
|
url="Companies"
|
||||||
|
/>
|
||||||
|
|
||||||
<QTable
|
<VnPaginate
|
||||||
:columns="columns"
|
auto-load
|
||||||
:rows="rows"
|
data-key="CustomerBalance"
|
||||||
class="full-width q-mt-md"
|
url="Receipts/filter"
|
||||||
row-key="id"
|
:user-params="userParams"
|
||||||
v-if="rows?.length"
|
ref="receiptsRef"
|
||||||
|
@on-fetch="onFetch"
|
||||||
>
|
>
|
||||||
<template #body-cell="props">
|
<template #body="{ rows }">
|
||||||
<QTd :props="props">
|
<QTable
|
||||||
<QTr :props="props" class="cursor-pointer">
|
:columns="columns"
|
||||||
<component
|
:no-data-label="t('globals.noResults')"
|
||||||
:is="tableColumnComponents[props.col.name].component"
|
:rows-per-page-options="[0]"
|
||||||
class="col-content"
|
:rows="rows"
|
||||||
v-bind="tableColumnComponents[props.col.name].props(props)"
|
class="full-width q-mt-md"
|
||||||
@click="tableColumnComponents[props.col.name].event(props)"
|
row-key="id"
|
||||||
>
|
>
|
||||||
<template v-if="props.col.name !== 'isConciliate'">
|
<template #body-cell-employee="{ row }">
|
||||||
{{ props.value }}
|
<QTd auto-width @click.stop>
|
||||||
</template>
|
<QBtn color="blue" flat no-caps>{{ row.userName }}</QBtn>
|
||||||
<WorkerDescriptorProxy :id="workerId" />
|
<WorkerDescriptorProxy :id="row.clientFk" />
|
||||||
</component>
|
</QTd>
|
||||||
</QTr>
|
</template>
|
||||||
</QTd>
|
|
||||||
</template>
|
|
||||||
</QTable>
|
|
||||||
|
|
||||||
<h5 class="flex justify-center label-color" v-else>
|
<template #body-cell-reference="{ row }">
|
||||||
{{ t('globals.noResults') }}
|
<QTd auto-width @click.stop v-if="row.isInvoice">
|
||||||
</h5>
|
<QBtn color="blue" dense flat>
|
||||||
|
{{ t('bill', { ref: row.description }) }}
|
||||||
|
</QBtn>
|
||||||
|
<InvoiceOutDescriptorProxy :id="row.id" />
|
||||||
|
</QTd>
|
||||||
|
<QTd v-else>
|
||||||
|
<VnInput
|
||||||
|
@keyup.enter="saveFieldValue(row)"
|
||||||
|
autofocus
|
||||||
|
clearable
|
||||||
|
dense
|
||||||
|
v-model="row.description"
|
||||||
|
/>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #body-cell-conciliated="{ row }">
|
||||||
|
<QTd align="center">
|
||||||
|
<QCheckbox :model-value="row.isConciliate === 1" disable />
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #body-cell-actions="{ row }">
|
||||||
|
<QTd align="center">
|
||||||
|
<QIcon
|
||||||
|
@click.stop="showDialog = true"
|
||||||
|
class="q-ml-md"
|
||||||
|
color="primary"
|
||||||
|
name="outgoing_mail"
|
||||||
|
size="sm"
|
||||||
|
style="font-variation-settings: 'FILL' 1"
|
||||||
|
v-if="row.isCompensation"
|
||||||
|
>
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('Send compensation') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
|
||||||
|
<QDialog v-model="showDialog">
|
||||||
|
<QCard class="q-pa-sm">
|
||||||
|
<QCardSection>
|
||||||
|
<span
|
||||||
|
ref="closeButton"
|
||||||
|
class="flex justify-end color-vn-label"
|
||||||
|
v-close-popup
|
||||||
|
>
|
||||||
|
<QIcon name="close" size="sm" />
|
||||||
|
</span>
|
||||||
|
<div class="text-h6">
|
||||||
|
{{ t('Send compensation') }}
|
||||||
|
</div>
|
||||||
|
</QCardSection>
|
||||||
|
<QCardSection>
|
||||||
|
<div>
|
||||||
|
{{
|
||||||
|
t(
|
||||||
|
'Do you want to report compensation to the client by mail?'
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
</QCardSection>
|
||||||
|
<QCardActions class="flex justify-end q-mb-sm">
|
||||||
|
<QBtn
|
||||||
|
:label="t('globals.cancel')"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
v-close-popup
|
||||||
|
/>
|
||||||
|
<QBtn
|
||||||
|
:label="t('globals.save')"
|
||||||
|
@click="sendEmailAction"
|
||||||
|
class="q-ml-sm"
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
|
</QCardActions>
|
||||||
|
</QCard>
|
||||||
|
</QDialog>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
</QTable>
|
||||||
|
</template>
|
||||||
|
</VnPaginate>
|
||||||
|
|
||||||
<QDrawer :width="256" show-if-above side="right" v-model="stateStore.rightDrawer">
|
<QDrawer :width="256" show-if-above side="right" v-model="stateStore.rightDrawer">
|
||||||
<div class="q-mt-xl q-px-md">
|
<div class="q-mt-xl q-px-md">
|
||||||
|
@ -236,10 +324,11 @@ const updateCompanyId = (id) => {
|
||||||
option-label="code"
|
option-label="code"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
v-model="companyId"
|
v-model="companyId"
|
||||||
|
:rules="validate('entry.companyFk')"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<QCard class="q-ma-md q-pa-md q-mt-lg" v-if="rows?.length">
|
<QCard class="q-ma-md q-pa-md q-mt-lg" v-if="receiptsData?.length">
|
||||||
<QCardSection>
|
<QCardSection>
|
||||||
<div class="flex justify-center text-subtitle1 text-bold">
|
<div class="flex justify-center text-subtitle1 text-bold">
|
||||||
{{ t('Total by company') }}
|
{{ t('Total by company') }}
|
||||||
|
@ -265,6 +354,8 @@ const updateCompanyId = (id) => {
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<i18n>
|
<i18n>
|
||||||
|
en:
|
||||||
|
bill: 'N/INV {ref}'
|
||||||
es:
|
es:
|
||||||
Company: Empresa
|
Company: Empresa
|
||||||
Total by company: Total por empresa
|
Total by company: Total por empresa
|
||||||
|
@ -273,9 +364,12 @@ es:
|
||||||
Creation date: Fecha de creación
|
Creation date: Fecha de creación
|
||||||
Employee: Empleado
|
Employee: Empleado
|
||||||
Reference: Referencia
|
Reference: Referencia
|
||||||
|
bill: 'N/FRA {ref}'
|
||||||
Bank: Caja
|
Bank: Caja
|
||||||
Debit: Debe
|
Debit: Debe
|
||||||
Havings: Haber
|
Havings: Haber
|
||||||
Balance: Balance
|
Balance: Balance
|
||||||
Conciliated: Conciliado
|
Conciliated: Conciliado
|
||||||
|
Send compensation: Enviar compensación
|
||||||
|
Do you want to report compensation to the client by mail?: ¿Desea informar de la compensación al cliente por correo?
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|
|
@ -60,90 +60,105 @@ const filterOptions = {
|
||||||
@on-fetch="(data) => (businessTypes = data)"
|
@on-fetch="(data) => (businessTypes = data)"
|
||||||
auto-load
|
auto-load
|
||||||
/>
|
/>
|
||||||
|
<fetch-data
|
||||||
|
:filter="filter"
|
||||||
|
@on-fetch="(data) => (clients = data)"
|
||||||
|
auto-load
|
||||||
|
url="Clients"
|
||||||
|
/>
|
||||||
|
|
||||||
<FormModel :url="`Clients/${route.params.id}`" model="customer" auto-load>
|
<FormModel :url="`Clients/${route.params.id}`" auto-load model="customer">
|
||||||
<template #form="{ data, validate, filter }">
|
<template #form="{ data, validate, filter }">
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<VnInput
|
<VnInput
|
||||||
v-model="data.socialName"
|
:label="t('Comercial name')"
|
||||||
:label="t('customer.basicData.socialName')"
|
|
||||||
:rules="validate('client.socialName')"
|
:rules="validate('client.socialName')"
|
||||||
autofocus
|
autofocus
|
||||||
|
clearable
|
||||||
|
v-model="data.name"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<QSelect
|
<QSelect
|
||||||
v-model="data.businessTypeFk"
|
|
||||||
:options="businessTypes"
|
|
||||||
option-value="code"
|
|
||||||
option-label="description"
|
|
||||||
emit-value
|
|
||||||
:label="t('customer.basicData.businessType')"
|
|
||||||
map-options
|
|
||||||
:rules="validate('client.businessTypeFk')"
|
|
||||||
:input-debounce="0"
|
:input-debounce="0"
|
||||||
|
:label="t('customer.basicData.businessType')"
|
||||||
|
:options="businessTypes"
|
||||||
|
:rules="validate('client.businessTypeFk')"
|
||||||
|
emit-value
|
||||||
|
map-options
|
||||||
|
option-label="description"
|
||||||
|
option-value="code"
|
||||||
|
v-model="data.businessTypeFk"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<VnInput
|
<VnInput
|
||||||
v-model="data.contact"
|
|
||||||
:label="t('customer.basicData.contact')"
|
:label="t('customer.basicData.contact')"
|
||||||
:rules="validate('client.contact')"
|
:rules="validate('client.contact')"
|
||||||
clearable
|
clearable
|
||||||
|
v-model="data.contact"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<VnInput
|
<VnInput
|
||||||
v-model="data.email"
|
|
||||||
type="email"
|
|
||||||
:label="t('customer.basicData.email')"
|
:label="t('customer.basicData.email')"
|
||||||
:rules="validate('client.email')"
|
:rules="validate('client.email')"
|
||||||
clearable
|
clearable
|
||||||
/>
|
type="email"
|
||||||
|
v-model="data.email"
|
||||||
|
>
|
||||||
|
<template #append>
|
||||||
|
<QIcon name="info" class="cursor-info">
|
||||||
|
<QTooltip>{{
|
||||||
|
t('customer.basicData.youCanSaveMultipleEmails')
|
||||||
|
}}</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
</template>
|
||||||
|
</VnInput>
|
||||||
</div>
|
</div>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<VnInput
|
<VnInput
|
||||||
v-model="data.phone"
|
|
||||||
:label="t('customer.basicData.phone')"
|
:label="t('customer.basicData.phone')"
|
||||||
:rules="validate('client.phone')"
|
:rules="validate('client.phone')"
|
||||||
clearable
|
clearable
|
||||||
|
v-model="data.phone"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<VnInput
|
<VnInput
|
||||||
v-model="data.mobile"
|
|
||||||
:label="t('customer.basicData.mobile')"
|
:label="t('customer.basicData.mobile')"
|
||||||
:rules="validate('client.mobile')"
|
:rules="validate('client.mobile')"
|
||||||
clearable
|
clearable
|
||||||
|
v-model="data.mobile"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<QSelect
|
<QSelect
|
||||||
v-model="data.salesPersonFk"
|
|
||||||
:options="workers"
|
|
||||||
option-value="id"
|
|
||||||
option-label="name"
|
|
||||||
emit-value
|
|
||||||
:label="t('customer.basicData.salesPerson')"
|
|
||||||
map-options
|
|
||||||
use-input
|
|
||||||
@filter="(value, update) => filter(value, update, filterOptions)"
|
|
||||||
:rules="validate('client.salesPersonFk')"
|
|
||||||
:input-debounce="0"
|
:input-debounce="0"
|
||||||
|
:label="t('customer.basicData.salesPerson')"
|
||||||
|
:options="workers"
|
||||||
|
:rules="validate('client.salesPersonFk')"
|
||||||
|
@filter="(value, update) => filter(value, update, filterOptions)"
|
||||||
|
emit-value
|
||||||
|
map-options
|
||||||
|
option-label="name"
|
||||||
|
option-value="id"
|
||||||
|
use-input
|
||||||
|
v-model="data.salesPersonFk"
|
||||||
>
|
>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<QAvatar color="orange">
|
<QAvatar color="orange">
|
||||||
<QImg
|
<QImg
|
||||||
v-if="data.salesPersonFk"
|
|
||||||
:src="`/api/Images/user/160x160/${data.salesPersonFk}/download?access_token=${token}`"
|
:src="`/api/Images/user/160x160/${data.salesPersonFk}/download?access_token=${token}`"
|
||||||
spinner-color="white"
|
spinner-color="white"
|
||||||
|
v-if="data.salesPersonFk"
|
||||||
/>
|
/>
|
||||||
</QAvatar>
|
</QAvatar>
|
||||||
</template>
|
</template>
|
||||||
|
@ -151,18 +166,49 @@ const filterOptions = {
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<QSelect
|
<QSelect
|
||||||
v-model="data.contactChannelFk"
|
|
||||||
:options="contactChannels"
|
|
||||||
option-value="id"
|
|
||||||
option-label="name"
|
|
||||||
emit-value
|
|
||||||
:label="t('customer.basicData.contactChannel')"
|
|
||||||
map-options
|
|
||||||
:rules="validate('client.contactChannelFk')"
|
|
||||||
:input-debounce="0"
|
:input-debounce="0"
|
||||||
|
:label="t('customer.basicData.contactChannel')"
|
||||||
|
:options="contactChannels"
|
||||||
|
:rules="validate('client.contactChannelFk')"
|
||||||
|
emit-value
|
||||||
|
map-options
|
||||||
|
option-label="name"
|
||||||
|
option-value="id"
|
||||||
|
v-model="data.contactChannelFk"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
|
<div class="col">
|
||||||
|
<QSelect
|
||||||
|
:input-debounce="0"
|
||||||
|
:label="t('customer.basicData.previousClient')"
|
||||||
|
:options="clients"
|
||||||
|
:rules="validate('client.transferorFk')"
|
||||||
|
emit-value
|
||||||
|
map-options
|
||||||
|
option-label="name"
|
||||||
|
option-value="id"
|
||||||
|
v-model="data.transferorFk"
|
||||||
|
>
|
||||||
|
<template #append>
|
||||||
|
<QIcon name="info" class="cursor-pointer">
|
||||||
|
<QTooltip>{{
|
||||||
|
t(
|
||||||
|
'In case of a company succession, specify the grantor company'
|
||||||
|
)
|
||||||
|
}}</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
</template>
|
||||||
|
</QSelect>
|
||||||
|
</div>
|
||||||
|
</VnRow>
|
||||||
</template>
|
</template>
|
||||||
</FormModel>
|
</FormModel>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
In case of a company succession, specify the grantor company: En el caso de que haya habido una sucesión de empresa, indicar la empresa cedente
|
||||||
|
Comercial name: Nombre comercial
|
||||||
|
</i18n>
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
import axios from 'axios';
|
|
||||||
|
|
||||||
import FetchData from 'components/FetchData.vue';
|
import FetchData from 'components/FetchData.vue';
|
||||||
import FormModel from 'components/FormModel.vue';
|
import FormModel from 'components/FormModel.vue';
|
||||||
import VnRow from 'components/ui/VnRow.vue';
|
import VnRow from 'components/ui/VnRow.vue';
|
||||||
|
@ -26,8 +24,9 @@ const filter = {
|
||||||
limit: 30,
|
limit: 30,
|
||||||
};
|
};
|
||||||
|
|
||||||
const getBankEntities = () => {
|
const getBankEntities = (data, formData) => {
|
||||||
bankEntitiesRef.value.fetch();
|
bankEntitiesRef.value.fetch();
|
||||||
|
formData.bankEntityFk = Number(data.id);
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -60,17 +59,13 @@ const getBankEntities = () => {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<VnInput
|
<VnInput :label="t('Due day')" clearable v-model="data.dueDay" />
|
||||||
:label="t('Due day')"
|
|
||||||
:rules="validate('client.socialName')"
|
|
||||||
v-model="data.dueDay"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
|
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<VnInput :label="t('IBAN')" v-model="data.iban">
|
<VnInput :label="t('IBAN')" clearable v-model="data.iban">
|
||||||
<template #append>
|
<template #append>
|
||||||
<QIcon name="info" class="cursor-info">
|
<QIcon name="info" class="cursor-info">
|
||||||
<QTooltip>{{ t('components.iban_tooltip') }}</QTooltip>
|
<QTooltip>{{ t('components.iban_tooltip') }}</QTooltip>
|
||||||
|
@ -90,7 +85,9 @@ const getBankEntities = () => {
|
||||||
v-model="data.bankEntityFk"
|
v-model="data.bankEntityFk"
|
||||||
>
|
>
|
||||||
<template #form>
|
<template #form>
|
||||||
<CreateBankEntityForm @on-data-saved="getBankEntities()" />
|
<CreateBankEntityForm
|
||||||
|
@on-data-saved="getBankEntities($event, data)"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #option="scope">
|
<template #option="scope">
|
||||||
<QItem v-bind="scope.itemProps">
|
<QItem v-bind="scope.itemProps">
|
||||||
|
|
|
@ -1,45 +1,15 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useI18n } from 'vue-i18n';
|
import VnCard from 'components/common/VnCard.vue';
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
|
||||||
import { useRoute } from 'vue-router';
|
|
||||||
import CustomerDescriptor from './CustomerDescriptor.vue';
|
import CustomerDescriptor from './CustomerDescriptor.vue';
|
||||||
import LeftMenu from 'components/LeftMenu.vue';
|
|
||||||
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
|
|
||||||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
|
||||||
import useCardSize from 'src/composables/useCardSize';
|
|
||||||
|
|
||||||
const stateStore = useStateStore();
|
|
||||||
const route = useRoute();
|
|
||||||
const { t } = useI18n();
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<Teleport to="#searchbar" v-if="stateStore.isHeaderMounted()">
|
<VnCard
|
||||||
<VnSearchbar
|
data-key="Client"
|
||||||
data-key="CustomerList"
|
base-url="Clients"
|
||||||
url="Clients/filter"
|
:descriptor="CustomerDescriptor"
|
||||||
:label="t('Search customer')"
|
searchbar-data-key="CustomerList"
|
||||||
:info="t('You can search by customer id or name')"
|
searchbar-url="Clients/filter"
|
||||||
/>
|
searchbar-label="Search customer"
|
||||||
</Teleport>
|
searchbar-info="You can search by customer id or name"
|
||||||
<QDrawer v-model="stateStore.leftDrawer" show-if-above :width="256">
|
/>
|
||||||
<QScrollArea class="fit">
|
|
||||||
<CustomerDescriptor />
|
|
||||||
<QSeparator />
|
|
||||||
<LeftMenu source="card" />
|
|
||||||
</QScrollArea>
|
|
||||||
</QDrawer>
|
|
||||||
<QPageContainer>
|
|
||||||
<QPage>
|
|
||||||
<VnSubToolbar />
|
|
||||||
<div :class="useCardSize()">
|
|
||||||
<RouterView></RouterView>
|
|
||||||
</div>
|
|
||||||
</QPage>
|
|
||||||
</QPageContainer>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<i18n>
|
|
||||||
es:
|
|
||||||
Search customer: Buscar cliente
|
|
||||||
You can search by customer id or name: Puedes buscar por id o nombre del cliente
|
|
||||||
</i18n>
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
<script setup>
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<h5 class="flex justify-center color-vn-label">
|
||||||
|
{{ t('Enter a new search') }}
|
||||||
|
</h5>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
Enter a new search: Introduce una nueva búsqueda
|
||||||
|
</i18n>
|
|
@ -0,0 +1,87 @@
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from 'vue';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import CrudModel from 'components/CrudModel.vue';
|
||||||
|
import VnRow from 'components/ui/VnRow.vue';
|
||||||
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const customerContactsRef = ref(null);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (customerContactsRef.value) customerContactsRef.value.reload();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="full-width flex justify-center">
|
||||||
|
<QPage class="card-width q-pa-lg">
|
||||||
|
<CrudModel
|
||||||
|
:data-required="{ clientFk: route.params.id }"
|
||||||
|
:default-remove="false"
|
||||||
|
:filter="{
|
||||||
|
fields: ['id', 'name', 'phone', 'clientFk'],
|
||||||
|
where: { clientFk: route.params.id },
|
||||||
|
}"
|
||||||
|
data-key="CustomerContacts"
|
||||||
|
model="CustomerContacts"
|
||||||
|
ref="customerContactsRef"
|
||||||
|
url="ClientContacts"
|
||||||
|
>
|
||||||
|
<template #body="{ rows }">
|
||||||
|
<QCard class="q-pl-lg q-py-md">
|
||||||
|
<VnRow
|
||||||
|
v-for="(row, index) in rows"
|
||||||
|
:key="index"
|
||||||
|
class="row q-gutter-md q-mb-md"
|
||||||
|
>
|
||||||
|
<div class="col">
|
||||||
|
<VnInput :label="t('Name')" v-model="row.name" />
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<VnInput :label="t('Phone')" v-model="row.phone" />
|
||||||
|
</div>
|
||||||
|
<div class="col-1 row justify-center items-center">
|
||||||
|
<QIcon
|
||||||
|
@click="customerContactsRef.remove([row])"
|
||||||
|
class="cursor-pointer"
|
||||||
|
color="primary"
|
||||||
|
name="delete"
|
||||||
|
size="sm"
|
||||||
|
>
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('Remove contact') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
</div>
|
||||||
|
</VnRow>
|
||||||
|
<VnRow>
|
||||||
|
<QIcon
|
||||||
|
@click="customerContactsRef.insert()"
|
||||||
|
class="cursor-pointer"
|
||||||
|
color="primary"
|
||||||
|
name="add"
|
||||||
|
size="sm"
|
||||||
|
>
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('Add contact') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
</VnRow>
|
||||||
|
</QCard>
|
||||||
|
</template>
|
||||||
|
</CrudModel>
|
||||||
|
</QPage>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
Name: Nombre
|
||||||
|
Phone: Teléfono
|
||||||
|
Remove contact: Quitar contacto
|
||||||
|
Add contact: Añadir contacto
|
||||||
|
</i18n>
|
|
@ -1,3 +1,233 @@
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
import { useQuasar } from 'quasar';
|
||||||
|
|
||||||
|
import VnPaginate from 'src/components/ui/VnPaginate.vue';
|
||||||
|
import ModalCloseContract from 'src/pages/Customer/components/ModalCloseContract.vue';
|
||||||
|
import { toDate } from 'src/filters';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
const quasar = useQuasar();
|
||||||
|
|
||||||
|
const vnPaginateRef = ref(null);
|
||||||
|
const showQPageSticky = ref(true);
|
||||||
|
|
||||||
|
const filter = {
|
||||||
|
order: 'finished ASC, started DESC',
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
relation: 'insurances',
|
||||||
|
scope: {
|
||||||
|
fields: ['id', 'credit', 'created', 'grade'],
|
||||||
|
order: 'created DESC',
|
||||||
|
limit: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
where: { client: `${route.params.id}` },
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetch = (data) => {
|
||||||
|
data.forEach((element) => {
|
||||||
|
if (!element.finished) {
|
||||||
|
showQPageSticky.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const toCustomerCreditContractsCreate = () => {
|
||||||
|
router.push({ name: 'CustomerCreditContractsCreate' });
|
||||||
|
};
|
||||||
|
|
||||||
|
const openDialog = (item) => {
|
||||||
|
quasar.dialog({
|
||||||
|
component: ModalCloseContract,
|
||||||
|
componentProps: {
|
||||||
|
id: item.id,
|
||||||
|
promise: updateData,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const openViewCredit = (credit) => {
|
||||||
|
router.push({
|
||||||
|
name: 'CustomerCreditContractsInsurance',
|
||||||
|
params: {
|
||||||
|
creditId: credit.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateData = () => {
|
||||||
|
vnPaginateRef.value?.fetch();
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex justify-center">Customer credit contracts</div>
|
<div class="full-width flex justify-center">
|
||||||
|
<QCard class="card-width q-pa-lg">
|
||||||
|
<VnPaginate
|
||||||
|
:filter="filter"
|
||||||
|
@on-fetch="fetch"
|
||||||
|
auto-load
|
||||||
|
data-key="CustomerCreditContracts"
|
||||||
|
order="id DESC"
|
||||||
|
ref="vnPaginateRef"
|
||||||
|
url="CreditClassifications"
|
||||||
|
>
|
||||||
|
<template #body="{ rows }">
|
||||||
|
<div v-if="rows.length">
|
||||||
|
<QCard
|
||||||
|
v-for="(item, index) in rows"
|
||||||
|
:key="index"
|
||||||
|
:class="{
|
||||||
|
'customer-card': true,
|
||||||
|
'q-mb-md': index < rows.length - 1,
|
||||||
|
'is-active': !item.finished,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<QCardSection
|
||||||
|
class="full-width flex justify-between q-py-none"
|
||||||
|
>
|
||||||
|
<div class="width-state flex">
|
||||||
|
<div
|
||||||
|
class="flex items-center cursor-pointer q-mr-md"
|
||||||
|
v-if="!item.finished"
|
||||||
|
>
|
||||||
|
<QIcon
|
||||||
|
@click.stop="openDialog(item)"
|
||||||
|
color="primary"
|
||||||
|
name="lock"
|
||||||
|
size="md"
|
||||||
|
style="font-variation-settings: 'FILL' 1"
|
||||||
|
>
|
||||||
|
<QTooltip>{{ t('Close contract') }}</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="flex q-mb-xs">
|
||||||
|
<div class="q-mr-sm color-vn-label">
|
||||||
|
{{ t('Since') }}:
|
||||||
|
</div>
|
||||||
|
<div class="text-weight-bold">
|
||||||
|
{{ toDate(item.started) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex">
|
||||||
|
<div class="q-mr-sm color-vn-label">
|
||||||
|
{{ t('To') }}:
|
||||||
|
</div>
|
||||||
|
<div class="text-weight-bold">
|
||||||
|
{{ toDate(item.finished) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<QSeparator vertical />
|
||||||
|
|
||||||
|
<div class="width-data flex">
|
||||||
|
<div
|
||||||
|
class="full-width flex justify-between items-center"
|
||||||
|
v-if="item?.insurances.length"
|
||||||
|
>
|
||||||
|
<div class="flex">
|
||||||
|
<div class="color-vn-label q-mr-xs">
|
||||||
|
{{ t('Credit') }}:
|
||||||
|
</div>
|
||||||
|
<div class="text-weight-bold">
|
||||||
|
{{ item.insurances[0].credit }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex">
|
||||||
|
<div class="color-vn-label q-mr-xs">
|
||||||
|
{{ t('Grade') }}:
|
||||||
|
</div>
|
||||||
|
<div class="text-weight-bold">
|
||||||
|
{{ item.insurances[0].grade || '-' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex">
|
||||||
|
<div class="color-vn-label q-mr-xs">
|
||||||
|
{{ t('Date') }}:
|
||||||
|
</div>
|
||||||
|
<div class="text-weight-bold">
|
||||||
|
{{ toDate(item.insurances[0].created) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center cursor-pointer">
|
||||||
|
<QIcon
|
||||||
|
@click.stop="openViewCredit(item)"
|
||||||
|
color="primary"
|
||||||
|
name="preview"
|
||||||
|
size="md"
|
||||||
|
>
|
||||||
|
<QTooltip>{{
|
||||||
|
t('View credits')
|
||||||
|
}}</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</QCardSection>
|
||||||
|
</QCard>
|
||||||
|
</div>
|
||||||
|
<h5 class="flex justify-center color-vn-label" v-else>
|
||||||
|
{{ t('globals.noResults') }}
|
||||||
|
</h5>
|
||||||
|
</template>
|
||||||
|
</VnPaginate>
|
||||||
|
</QCard>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<QPageSticky :offset="[18, 18]" v-if="showQPageSticky">
|
||||||
|
<QBtn
|
||||||
|
@click.stop="toCustomerCreditContractsCreate()"
|
||||||
|
color="primary"
|
||||||
|
fab
|
||||||
|
icon="add"
|
||||||
|
/>
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('New contract') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QPageSticky>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.customer-card {
|
||||||
|
border: 2px solid var(--vn-light-gray);
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.is-active {
|
||||||
|
background-color: var(--vn-light-gray);
|
||||||
|
}
|
||||||
|
.width-state {
|
||||||
|
width: 30%;
|
||||||
|
}
|
||||||
|
.width-data {
|
||||||
|
width: 65%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
Close contract: Cerrar contrato
|
||||||
|
Since: Desde
|
||||||
|
To: Hasta
|
||||||
|
Credit: Crédito
|
||||||
|
Grade: Grade
|
||||||
|
Date: Fecha
|
||||||
|
View credits: Ver créditos
|
||||||
|
Created: Fecha creación
|
||||||
|
New contract: Nuevo contrato
|
||||||
|
</i18n>
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="flex justify-center">Credit management</div>
|
|
||||||
</template>
|
|
|
@ -1,3 +1,142 @@
|
||||||
|
<script setup>
|
||||||
|
import { computed, ref, watch } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
|
import { QBtn } from 'quasar';
|
||||||
|
|
||||||
|
import { toCurrency, toDateHourMin } from 'src/filters';
|
||||||
|
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
|
import FormModel from 'components/FormModel.vue';
|
||||||
|
import VnRow from 'components/ui/VnRow.vue';
|
||||||
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
|
const clientInformasRef = ref(null);
|
||||||
|
const rows = ref([]);
|
||||||
|
|
||||||
|
const filter = {
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
relation: 'worker',
|
||||||
|
scope: {
|
||||||
|
fields: ['id'],
|
||||||
|
include: { relation: 'user', scope: { fields: ['nickname'] } },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
where: { clientFk: route.params.id },
|
||||||
|
order: ['created DESC'],
|
||||||
|
limit: 20,
|
||||||
|
};
|
||||||
|
|
||||||
|
const columns = computed(() => [
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: 'created',
|
||||||
|
format: (value) => toDateHourMin(value),
|
||||||
|
label: t('Since'),
|
||||||
|
name: 'since',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: (row) => row.worker.user.nickname,
|
||||||
|
label: t('Employee'),
|
||||||
|
name: 'employee',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'right',
|
||||||
|
field: 'rating',
|
||||||
|
label: t('Rating'),
|
||||||
|
name: 'rating',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'right',
|
||||||
|
field: 'recommendedCredit',
|
||||||
|
format: (value) => toCurrency(value),
|
||||||
|
label: t('Recommended credit'),
|
||||||
|
name: 'recommendedCredit',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.params.id,
|
||||||
|
(newValue) => {
|
||||||
|
if (!newValue) return;
|
||||||
|
filter.where.clientFk = newValue;
|
||||||
|
clientInformasRef.value?.fetch();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex justify-center">Customer credit opinion</div>
|
<FetchData
|
||||||
|
:filter="filter"
|
||||||
|
@on-fetch="(data) => (rows = data)"
|
||||||
|
auto-load
|
||||||
|
ref="clientInformasRef"
|
||||||
|
url="ClientInformas"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormModel
|
||||||
|
:form-initial-data="{}"
|
||||||
|
:observe-form-changes="false"
|
||||||
|
:url-create="`Clients/${route.params.id}/setRating`"
|
||||||
|
>
|
||||||
|
<template #form="{ data }">
|
||||||
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
|
<div class="col">
|
||||||
|
<VnInput
|
||||||
|
:label="t('Rating')"
|
||||||
|
clearable
|
||||||
|
type="number"
|
||||||
|
v-model.number="data.rating"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<VnInput
|
||||||
|
:label="t('Recommended credit')"
|
||||||
|
clearable
|
||||||
|
type="number"
|
||||||
|
v-model.number="data.recommendedCredit"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</VnRow>
|
||||||
|
</template>
|
||||||
|
</FormModel>
|
||||||
|
|
||||||
|
<div class="full-width flex justify-center" v-if="rows.length">
|
||||||
|
<QTable
|
||||||
|
:columns="columns"
|
||||||
|
:pagination="{ rowsPerPage: 0 }"
|
||||||
|
:rows="rows"
|
||||||
|
hide-bottom
|
||||||
|
row-key="id"
|
||||||
|
v-model:selected="selected"
|
||||||
|
class="card-width q-px-lg"
|
||||||
|
>
|
||||||
|
<template #body-cell-employee="{ row }">
|
||||||
|
<QTd auto-width @click.stop>
|
||||||
|
<QBtn color="blue" flat no-caps>{{ row.worker.user.nickname }}</QBtn>
|
||||||
|
<WorkerDescriptorProxy :id="row.clientFk" />
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
</QTable>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h5 class="flex justify-center color-vn-label" v-else>
|
||||||
|
{{ t('globals.noResults') }}
|
||||||
|
</h5>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
Rating: Clasificación
|
||||||
|
Recommended credit: Crédito recomendado
|
||||||
|
Since: Desde
|
||||||
|
Employee: Empleado
|
||||||
|
</i18n>
|
||||||
|
|
|
@ -1,47 +1,35 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onBeforeMount } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
import { date, QBtn } from 'quasar';
|
import { QBtn } from 'quasar';
|
||||||
|
|
||||||
import { toCurrency } from 'src/filters';
|
import { toCurrency, toDateHourMin } from 'src/filters';
|
||||||
import { useArrayData } from 'composables/useArrayData';
|
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
|
||||||
|
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const stateStore = useStateStore();
|
|
||||||
|
|
||||||
const arrayData = ref(null);
|
const rows = ref([]);
|
||||||
const workerId = ref(0);
|
|
||||||
const rows = computed(() => arrayData.value.store.data);
|
|
||||||
|
|
||||||
onBeforeMount(async () => {
|
const filter = {
|
||||||
const filter = {
|
include: [
|
||||||
include: [
|
{
|
||||||
{
|
relation: 'worker',
|
||||||
relation: 'worker',
|
scope: {
|
||||||
scope: {
|
fields: ['id'],
|
||||||
fields: ['id'],
|
include: { relation: 'user', scope: { fields: ['name'] } },
|
||||||
include: { relation: 'user', scope: { fields: ['name'] } },
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
],
|
},
|
||||||
where: { clientFk: `${route.params.id}` },
|
],
|
||||||
order: ['created DESC'],
|
where: { clientFk: route.params.id },
|
||||||
limit: 20,
|
order: ['created DESC'],
|
||||||
};
|
limit: 20,
|
||||||
arrayData.value = useArrayData('CustomerCreditsCard', {
|
};
|
||||||
url: 'ClientCredits',
|
|
||||||
filter,
|
|
||||||
});
|
|
||||||
await arrayData.value.fetch({ append: false });
|
|
||||||
stateStore.rightDrawer = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
const tableColumnComponents = {
|
const tableColumnComponents = {
|
||||||
created: {
|
created: {
|
||||||
|
@ -51,10 +39,8 @@ const tableColumnComponents = {
|
||||||
},
|
},
|
||||||
employee: {
|
employee: {
|
||||||
component: QBtn,
|
component: QBtn,
|
||||||
props: () => ({ flat: true, color: 'blue' }),
|
props: () => ({ flat: true, color: 'blue', noCaps: true }),
|
||||||
event: (prop) => {
|
event: () => {},
|
||||||
selectWorkerId(prop.row.clientFk);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
amount: {
|
amount: {
|
||||||
component: 'span',
|
component: 'span',
|
||||||
|
@ -69,7 +55,7 @@ const columns = computed(() => [
|
||||||
field: 'created',
|
field: 'created',
|
||||||
label: t('Since'),
|
label: t('Since'),
|
||||||
name: 'created',
|
name: 'created',
|
||||||
format: (value) => date.formatDate(value, 'DD/MM/YYYY hh:mm:ss'),
|
format: (value) => toDateHourMin(value),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
@ -86,35 +72,58 @@ const columns = computed(() => [
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const selectWorkerId = (id) => {
|
|
||||||
workerId.value = id;
|
|
||||||
};
|
|
||||||
|
|
||||||
const toCustomerCreditCreate = () => {
|
const toCustomerCreditCreate = () => {
|
||||||
router.push({ name: 'CustomerCreditCreate' });
|
router.push({ name: 'CustomerCreditCreate' });
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<QPage class="column items-center q-pa-md">
|
<FetchData
|
||||||
<QTable :columns="columns" :rows="rows" class="full-width q-mt-md" row-key="id">
|
:filter="filter"
|
||||||
<template #body-cell="props">
|
@on-fetch="(data) => (rows = data)"
|
||||||
<QTd :props="props">
|
auto-load
|
||||||
<QTr :props="props" class="cursor-pointer">
|
url="ClientCredits"
|
||||||
<component
|
/>
|
||||||
:is="tableColumnComponents[props.col.name].component"
|
|
||||||
@click="tableColumnComponents[props.col.name].event(props)"
|
<div class="full-width flex justify-center">
|
||||||
class="rounded-borders q-pa-sm"
|
<QCard class="card-width q-pa-lg">
|
||||||
v-bind="tableColumnComponents[props.col.name].props(props)"
|
<QTable
|
||||||
>
|
:columns="columns"
|
||||||
{{ props.value }}
|
:pagination="{ rowsPerPage: 12 }"
|
||||||
<WorkerDescriptorProxy :id="workerId" />
|
:rows="rows"
|
||||||
</component>
|
class="full-width q-mt-md"
|
||||||
</QTr>
|
row-key="id"
|
||||||
</QTd>
|
v-if="rows?.length"
|
||||||
</template>
|
>
|
||||||
</QTable>
|
<template #body-cell="props">
|
||||||
</QPage>
|
<QTd :props="props">
|
||||||
|
<QTr :props="props" class="cursor-pointer">
|
||||||
|
<component
|
||||||
|
:is="tableColumnComponents[props.col.name].component"
|
||||||
|
@click="
|
||||||
|
tableColumnComponents[props.col.name].event(props)
|
||||||
|
"
|
||||||
|
class="rounded-borders q-pa-sm"
|
||||||
|
v-bind="
|
||||||
|
tableColumnComponents[props.col.name].props(props)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ props.value }}
|
||||||
|
<WorkerDescriptorProxy
|
||||||
|
:id="props.row.workerFk"
|
||||||
|
v-if="props.col.name === 'employee'"
|
||||||
|
/>
|
||||||
|
</component>
|
||||||
|
</QTr>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
</QTable>
|
||||||
|
|
||||||
|
<h5 class="flex justify-center color-vn-label" v-else>
|
||||||
|
{{ t('globals.noResults') }}
|
||||||
|
</h5>
|
||||||
|
</QCard>
|
||||||
|
</div>
|
||||||
|
|
||||||
<QPageSticky :offset="[18, 18]">
|
<QPageSticky :offset="[18, 18]">
|
||||||
<QBtn @click.stop="toCustomerCreditCreate()" color="primary" fab icon="add" />
|
<QBtn @click.stop="toCustomerCreditCreate()" color="primary" fab icon="add" />
|
||||||
|
|
|
@ -2,11 +2,15 @@
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { toCurrency } from 'src/filters';
|
|
||||||
|
import { toCurrency, toDate } from 'src/filters';
|
||||||
|
|
||||||
|
import useCardDescription from 'src/composables/useCardDescription';
|
||||||
|
|
||||||
import CardDescriptor from 'components/ui/CardDescriptor.vue';
|
import CardDescriptor from 'components/ui/CardDescriptor.vue';
|
||||||
import VnLv from 'src/components/ui/VnLv.vue';
|
import VnLv from 'src/components/ui/VnLv.vue';
|
||||||
import useCardDescription from 'src/composables/useCardDescription';
|
|
||||||
import VnUserLink from 'src/components/ui/VnUserLink.vue';
|
import VnUserLink from 'src/components/ui/VnUserLink.vue';
|
||||||
|
import CustomerDescriptorMenu from './CustomerDescriptorMenu.vue';
|
||||||
|
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
id: {
|
id: {
|
||||||
|
@ -19,8 +23,10 @@ const $props = defineProps({
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const entityId = computed(() => {
|
const entityId = computed(() => {
|
||||||
return $props.id || route.params.id;
|
return $props.id || route.params.id;
|
||||||
});
|
});
|
||||||
|
@ -39,6 +45,23 @@ const setData = (entity) => (data.value = useCardDescription(entity.name, entity
|
||||||
:summary="$props.summary"
|
:summary="$props.summary"
|
||||||
data-key="customerData"
|
data-key="customerData"
|
||||||
>
|
>
|
||||||
|
<template #header-extra-action>
|
||||||
|
<QBtn
|
||||||
|
round
|
||||||
|
flat
|
||||||
|
size="sm"
|
||||||
|
icon="vn:Person"
|
||||||
|
color="white"
|
||||||
|
:to="{ name: 'CustomerList' }"
|
||||||
|
>
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('Go to module index') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QBtn>
|
||||||
|
</template>
|
||||||
|
<template #menu="{ entity }">
|
||||||
|
<CustomerDescriptorMenu :customer="entity" />
|
||||||
|
</template>
|
||||||
<template #body="{ entity }">
|
<template #body="{ entity }">
|
||||||
<VnLv :label="t('customer.card.payMethod')" :value="entity.payMethod.name" />
|
<VnLv :label="t('customer.card.payMethod')" :value="entity.payMethod.name" />
|
||||||
|
|
||||||
|
@ -63,23 +86,26 @@ const setData = (entity) => (data.value = useCardDescription(entity.name, entity
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #icons="{ entity }">
|
<template #icons="{ entity }">
|
||||||
<QCardActions>
|
<QCardActions class="q-gutter-x-md">
|
||||||
<QIcon
|
<QIcon
|
||||||
v-if="entity.isActive == false"
|
v-if="!entity.isActive"
|
||||||
name="vn:disabled"
|
name="vn:disabled"
|
||||||
size="xs"
|
size="xs"
|
||||||
color="primary"
|
color="primary"
|
||||||
>
|
>
|
||||||
<QTooltip>{{ t('customer.card.isDisabled') }}</QTooltip>
|
<QTooltip>{{ t('customer.card.isDisabled') }}</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
<QIcon
|
<QIcon v-if="entity.isFreezed" name="vn:frozen" size="xs" color="primary">
|
||||||
v-if="entity.isFreezed == true"
|
|
||||||
name="vn:frozen"
|
|
||||||
size="xs"
|
|
||||||
color="primary"
|
|
||||||
>
|
|
||||||
<QTooltip>{{ t('customer.card.isFrozen') }}</QTooltip>
|
<QTooltip>{{ t('customer.card.isFrozen') }}</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
|
<QIcon
|
||||||
|
v-if="!entity.account.active"
|
||||||
|
color="primary"
|
||||||
|
name="vn:noweb"
|
||||||
|
size="xs"
|
||||||
|
>
|
||||||
|
<QTooltip>{{ t('customer.card.webAccountInactive') }}</QTooltip>
|
||||||
|
</QIcon>
|
||||||
<QIcon
|
<QIcon
|
||||||
v-if="entity.debt > entity.credit"
|
v-if="entity.debt > entity.credit"
|
||||||
name="vn:risk"
|
name="vn:risk"
|
||||||
|
@ -89,17 +115,41 @@ const setData = (entity) => (data.value = useCardDescription(entity.name, entity
|
||||||
<QTooltip>{{ t('customer.card.hasDebt') }}</QTooltip>
|
<QTooltip>{{ t('customer.card.hasDebt') }}</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
<QIcon
|
<QIcon
|
||||||
v-if="entity.isTaxDataChecked == false"
|
v-if="!entity.isTaxDataChecked"
|
||||||
name="vn:no036"
|
name="vn:no036"
|
||||||
size="xs"
|
size="xs"
|
||||||
color="primary"
|
color="primary"
|
||||||
>
|
>
|
||||||
<QTooltip>{{ t('customer.card.notChecked') }}</QTooltip>
|
<QTooltip>{{ t('customer.card.notChecked') }}</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
|
<QBtn
|
||||||
|
v-if="entity.unpaid"
|
||||||
|
flat
|
||||||
|
size="sm"
|
||||||
|
icon="vn:Client_unpaid"
|
||||||
|
color="primary"
|
||||||
|
:to="{ name: 'CustomerUnpaid' }"
|
||||||
|
>
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('Unpaid') }}
|
||||||
|
<br />
|
||||||
|
{{
|
||||||
|
t('unpaidDated', {
|
||||||
|
dated: toDate(entity.unpaid.dated),
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
<br />
|
||||||
|
{{
|
||||||
|
t('unpaidAmount', {
|
||||||
|
amount: toCurrency(entity.unpaid.amount),
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
</QTooltip>
|
||||||
|
</QBtn>
|
||||||
</QCardActions>
|
</QCardActions>
|
||||||
</template>
|
</template>
|
||||||
<template #actions="{ entity }">
|
<template #actions="{ entity }">
|
||||||
<QCardActions>
|
<QCardActions class="flex justify-center">
|
||||||
<QBtn
|
<QBtn
|
||||||
:to="{
|
:to="{
|
||||||
name: 'TicketList',
|
name: 'TicketList',
|
||||||
|
@ -109,7 +159,7 @@ const setData = (entity) => (data.value = useCardDescription(entity.name, entity
|
||||||
icon="vn:ticket"
|
icon="vn:ticket"
|
||||||
color="primary"
|
color="primary"
|
||||||
>
|
>
|
||||||
<QTooltip>{{ t('ticketList') }}</QTooltip>
|
<QTooltip>{{ t('Customer ticket list') }}</QTooltip>
|
||||||
</QBtn>
|
</QBtn>
|
||||||
<QBtn
|
<QBtn
|
||||||
:to="{
|
:to="{
|
||||||
|
@ -120,21 +170,40 @@ const setData = (entity) => (data.value = useCardDescription(entity.name, entity
|
||||||
icon="vn:invoice-out"
|
icon="vn:invoice-out"
|
||||||
color="primary"
|
color="primary"
|
||||||
>
|
>
|
||||||
<QTooltip>{{ t('invoiceOutList') }}</QTooltip>
|
<QTooltip>{{ t('Customer invoice out list') }}</QTooltip>
|
||||||
|
</QBtn>
|
||||||
|
<QBtn
|
||||||
|
:to="{
|
||||||
|
name: 'OrderCreate',
|
||||||
|
query: { clientFk: entity.id },
|
||||||
|
}"
|
||||||
|
size="md"
|
||||||
|
icon="vn:basketadd"
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
<QTooltip>{{ t('New order') }}</QTooltip>
|
||||||
|
</QBtn>
|
||||||
|
<QBtn size="md" icon="face" color="primary">
|
||||||
|
<!-- TODO:: Redirigir a la vista de usuario cuando exista -->
|
||||||
|
<QTooltip>{{ t('Go to user') }}</QTooltip>
|
||||||
</QBtn>
|
</QBtn>
|
||||||
</QCardActions>
|
</QCardActions>
|
||||||
</template>
|
</template>
|
||||||
</CardDescriptor>
|
</CardDescriptor>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<i18n>
|
<i18n>
|
||||||
{
|
en:
|
||||||
"en": {
|
unpaidDated: 'Date {dated}'
|
||||||
"ticketList": "Customer ticket list",
|
unpaidAmount: 'Amount {amount}'
|
||||||
"invoiceOutList": "Customer invoice out list"
|
es:
|
||||||
},
|
Go to module index: Ir al índice del módulo
|
||||||
"es": {
|
Customer ticket list: Listado de tickets del cliente
|
||||||
"ticketList": "Listado de tickets del cliente",
|
Customer invoice out list: Listado de facturas del cliente
|
||||||
"invoiceOutList": "Listado de facturas del cliente"
|
New order: Nuevo pedido
|
||||||
}
|
Go to user: Ir al usuario
|
||||||
}
|
Customer unpaid: Cliente impago
|
||||||
|
Unpaid: Impagado
|
||||||
|
unpaidDated: 'Fecha {dated}'
|
||||||
|
unpaidAmount: 'Importe {amount}'
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
<script setup>
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
|
import axios from 'axios';
|
||||||
|
import { useQuasar } from 'quasar';
|
||||||
|
|
||||||
|
import useNotify from 'src/composables/useNotify';
|
||||||
|
|
||||||
|
import VnSmsDialog from 'src/components/common/VnSmsDialog.vue';
|
||||||
|
|
||||||
|
const $props = defineProps({
|
||||||
|
customer: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { notify } = useNotify();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const quasar = useQuasar();
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
|
const showSmsDialog = () => {
|
||||||
|
quasar.dialog({
|
||||||
|
component: VnSmsDialog,
|
||||||
|
componentProps: {
|
||||||
|
phone: $props.customer.phone || $props.customer.mobile,
|
||||||
|
promise: sendSms,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const sendSms = async (payload) => {
|
||||||
|
payload.destinationFk = route.params.id;
|
||||||
|
try {
|
||||||
|
await axios.post(`Clients/${route.params.id}/sendSms`, payload);
|
||||||
|
notify('globals.notificationSent', 'positive');
|
||||||
|
} catch (error) {
|
||||||
|
notify(error.message, 'positive');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<QItem v-ripple clickable>
|
||||||
|
<QItemSection>
|
||||||
|
<RouterLink
|
||||||
|
:to="{
|
||||||
|
name: 'TicketCreate',
|
||||||
|
query: { clientFk: customer.id },
|
||||||
|
}"
|
||||||
|
class="color-vn-text"
|
||||||
|
>
|
||||||
|
{{ t('Simple ticket') }}
|
||||||
|
</RouterLink>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem v-ripple clickable>
|
||||||
|
<QItemSection @click="showSmsDialog()">{{ t('Send SMS') }}</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
Simple ticket: Ticket simple
|
||||||
|
Send SMS: Enviar SMS
|
||||||
|
</i18n>
|
|
@ -0,0 +1,259 @@
|
||||||
|
<script setup>
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
import { QBadge, QBtn, QCheckbox } from 'quasar';
|
||||||
|
|
||||||
|
import { downloadFile } from 'src/composables/downloadFile';
|
||||||
|
import { toDateTimeFormat } from 'src/filters/date';
|
||||||
|
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
|
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
||||||
|
import CustomerFileManagementActions from 'src/pages/Customer/components/CustomerFileManagementActions.vue';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const ClientDmsRef = ref(null);
|
||||||
|
const rows = ref([]);
|
||||||
|
|
||||||
|
const filter = {
|
||||||
|
include: {
|
||||||
|
relation: 'dms',
|
||||||
|
scope: {
|
||||||
|
fields: [
|
||||||
|
'dmsTypeFk',
|
||||||
|
'reference',
|
||||||
|
'hardCopyNumber',
|
||||||
|
'workerFk',
|
||||||
|
'description',
|
||||||
|
'hasFile',
|
||||||
|
'file',
|
||||||
|
'created',
|
||||||
|
],
|
||||||
|
include: [
|
||||||
|
{ relation: 'dmsType', scope: { fields: ['name'] } },
|
||||||
|
{
|
||||||
|
relation: 'worker',
|
||||||
|
scope: {
|
||||||
|
fields: ['id'],
|
||||||
|
include: { relation: 'user', scope: { fields: ['name'] } },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
where: { clientFk: route.params.id },
|
||||||
|
order: ['dmsFk DESC'],
|
||||||
|
limit: 20,
|
||||||
|
};
|
||||||
|
|
||||||
|
const tableColumnComponents = {
|
||||||
|
id: {
|
||||||
|
component: 'span',
|
||||||
|
props: () => {},
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
component: 'span',
|
||||||
|
props: () => {},
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
order: {
|
||||||
|
component: QBadge,
|
||||||
|
props: () => {},
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
reference: {
|
||||||
|
component: 'span',
|
||||||
|
props: () => {},
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
component: 'span',
|
||||||
|
props: () => {},
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
original: {
|
||||||
|
component: QCheckbox,
|
||||||
|
props: (prop) => ({
|
||||||
|
disable: true,
|
||||||
|
'model-value': Boolean(prop.value),
|
||||||
|
}),
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
file: {
|
||||||
|
component: QBtn,
|
||||||
|
props: () => ({ flat: true, color: 'blue' }),
|
||||||
|
event: ({ row }) => downloadFile(row.dmsFk),
|
||||||
|
},
|
||||||
|
employee: {
|
||||||
|
component: QBtn,
|
||||||
|
props: () => ({ flat: true, color: 'blue' }),
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
created: {
|
||||||
|
component: 'span',
|
||||||
|
props: () => {},
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
component: CustomerFileManagementActions,
|
||||||
|
props: (prop) => ({
|
||||||
|
id: prop.row.dmsFk,
|
||||||
|
promise: setData,
|
||||||
|
}),
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const columns = computed(() => [
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: ({ dms }) => dms.id,
|
||||||
|
label: t('Id'),
|
||||||
|
name: 'id',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: ({ dms }) => dms.dmsType.name,
|
||||||
|
label: t('Type'),
|
||||||
|
name: 'type',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: ({ dms }) => dms.hardCopyNumber,
|
||||||
|
label: t('Order'),
|
||||||
|
name: 'order',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: ({ dms }) => dms.reference,
|
||||||
|
label: t('Reference'),
|
||||||
|
name: 'reference',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: ({ dms }) => dms.description,
|
||||||
|
label: t('Description'),
|
||||||
|
name: 'description',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: ({ dms }) => dms.hasFile,
|
||||||
|
label: t('Original'),
|
||||||
|
name: 'original',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: ({ dms }) => dms.file,
|
||||||
|
label: t('File'),
|
||||||
|
name: 'file',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: ({ dms }) => dms.worker.user.name,
|
||||||
|
label: t('Employee'),
|
||||||
|
name: 'employee',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: (value) => value.dms.created,
|
||||||
|
label: t('Created'),
|
||||||
|
name: 'created',
|
||||||
|
format: (value) => toDateTimeFormat(value),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'right',
|
||||||
|
field: 'actions',
|
||||||
|
label: '',
|
||||||
|
name: 'actions',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const setData = () => {
|
||||||
|
ClientDmsRef.value.fetch();
|
||||||
|
};
|
||||||
|
|
||||||
|
const toCustomerFileManagementCreate = () => {
|
||||||
|
router.push({ name: 'CustomerFileManagementCreate' });
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<FetchData
|
||||||
|
ref="ClientDmsRef"
|
||||||
|
:filter="filter"
|
||||||
|
@on-fetch="(data) => (rows = data)"
|
||||||
|
auto-load
|
||||||
|
url="ClientDms"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<QPage class="column items-center q-pa-md">
|
||||||
|
<QTable
|
||||||
|
:columns="columns"
|
||||||
|
:pagination="{ rowsPerPage: 12 }"
|
||||||
|
:rows="rows"
|
||||||
|
class="full-width q-mt-md"
|
||||||
|
row-key="id"
|
||||||
|
v-if="rows?.length"
|
||||||
|
>
|
||||||
|
<template #body-cell="props">
|
||||||
|
<QTd :props="props">
|
||||||
|
<QTr :props="props" class="cursor-pointer">
|
||||||
|
<component
|
||||||
|
:is="
|
||||||
|
props.col.name === 'order' && !props.value
|
||||||
|
? 'span'
|
||||||
|
: tableColumnComponents[props.col.name].component
|
||||||
|
"
|
||||||
|
@click="tableColumnComponents[props.col.name].event(props)"
|
||||||
|
class="col-content"
|
||||||
|
v-bind="tableColumnComponents[props.col.name].props(props)"
|
||||||
|
>
|
||||||
|
<template v-if="props.col.name !== 'original'">
|
||||||
|
{{ props.value }}
|
||||||
|
</template>
|
||||||
|
<WorkerDescriptorProxy
|
||||||
|
:id="props.row.dms.workerFk"
|
||||||
|
v-if="props.col.name === 'employee'"
|
||||||
|
/>
|
||||||
|
</component>
|
||||||
|
</QTr>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
</QTable>
|
||||||
|
|
||||||
|
<h5 class="flex justify-center color-vn-label" v-else>
|
||||||
|
{{ t('globals.noResults') }}
|
||||||
|
</h5>
|
||||||
|
</QPage>
|
||||||
|
|
||||||
|
<QPageSticky :offset="[18, 18]">
|
||||||
|
<QBtn
|
||||||
|
@click.stop="toCustomerFileManagementCreate()"
|
||||||
|
color="primary"
|
||||||
|
fab
|
||||||
|
icon="add"
|
||||||
|
/>
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('Upload file') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QPageSticky>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
Id: Id
|
||||||
|
Type: Tipo
|
||||||
|
Order: Orden
|
||||||
|
Reference: Referencia
|
||||||
|
Description: Descripción
|
||||||
|
Original: Original
|
||||||
|
File: Fichero
|
||||||
|
Employee: Empleado
|
||||||
|
Created: Fecha creación
|
||||||
|
Upload file: Subir fichero
|
||||||
|
</i18n>
|
|
@ -46,17 +46,24 @@ function handleLocation(data, location) {
|
||||||
:label="t('Social name')"
|
:label="t('Social name')"
|
||||||
:required="true"
|
:required="true"
|
||||||
:rules="validate('client.socialName')"
|
:rules="validate('client.socialName')"
|
||||||
|
clearable
|
||||||
v-model="data.socialName"
|
v-model="data.socialName"
|
||||||
/>
|
>
|
||||||
|
<template #append>
|
||||||
|
<QIcon name="info" class="cursor-info">
|
||||||
|
<QTooltip>{{ t('onlyLetters') }}</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
</template>
|
||||||
|
</VnInput>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<VnInput :label="t('Tax number')" v-model="data.fi" />
|
<VnInput :label="t('Tax number')" clearable v-model="data.fi" />
|
||||||
</div>
|
</div>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
|
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<VnInput :label="t('Street')" v-model="data.street" />
|
<VnInput :label="t('Street')" clearable v-model="data.street" />
|
||||||
</div>
|
</div>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
|
|
||||||
|
@ -76,10 +83,21 @@ function handleLocation(data, location) {
|
||||||
:label="t('Sage transaction type')"
|
:label="t('Sage transaction type')"
|
||||||
:options="typesTransactions"
|
:options="typesTransactions"
|
||||||
hide-selected
|
hide-selected
|
||||||
option-label="vat"
|
option-label="transaction"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
v-model="data.sageTransactionTypeFk"
|
v-model="data.sageTransactionTypeFk"
|
||||||
/>
|
>
|
||||||
|
<template #option="scope">
|
||||||
|
<QItem v-bind="scope.itemProps">
|
||||||
|
<QItemSection>
|
||||||
|
<QItemLabel>{{ scope.opt.name }}</QItemLabel>
|
||||||
|
<QItemLabel caption>
|
||||||
|
{{ `${scope.opt.id}: ${scope.opt.transaction}` }}
|
||||||
|
</QItemLabel>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
</template>
|
||||||
|
</VnSelectFilter>
|
||||||
</div>
|
</div>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
|
|
||||||
|
@ -111,6 +129,11 @@ function handleLocation(data, location) {
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<QCheckbox :label="t('Vies')" v-model="data.isVies" />
|
<QCheckbox :label="t('Vies')" v-model="data.isVies" />
|
||||||
|
<QIcon name="info" class="cursor-info q-ml-sm" size="sm">
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('whenActivatingIt') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QIcon>
|
||||||
</div>
|
</div>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
|
|
||||||
|
@ -135,6 +158,11 @@ function handleLocation(data, location) {
|
||||||
:label="t('Is equalizated')"
|
:label="t('Is equalizated')"
|
||||||
v-model="data.isEqualizated"
|
v-model="data.isEqualizated"
|
||||||
/>
|
/>
|
||||||
|
<QIcon class="cursor-info q-ml-sm" name="info" size="sm">
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('inOrderToInvoice') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QIcon>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<QCheckbox
|
<QCheckbox
|
||||||
|
@ -183,4 +211,11 @@ es:
|
||||||
Verified data: Datos comprobados
|
Verified data: Datos comprobados
|
||||||
Incoterms authorization: Autorización incoterms
|
Incoterms authorization: Autorización incoterms
|
||||||
Electronic invoice: Factura electrónica
|
Electronic invoice: Factura electrónica
|
||||||
|
onlyLetters: Sólo se pueden usar letras, números y espacios
|
||||||
|
whenActivatingIt: Al activarlo, no informar el código del país en el campo nif
|
||||||
|
inOrderToInvoice: Para facturar no se consulta este campo, sino el RE de consignatario. Al modificar este campo si no esta marcada la casilla Facturar por consignatario, se propagará automaticamente el cambio a todos lo consignatarios, en caso contrario preguntará al usuario si quiere o no propagar
|
||||||
|
en:
|
||||||
|
onlyLetters: Only letters, numbers and spaces can be used
|
||||||
|
whenActivatingIt: When activating it, do not enter the country code in the ID field
|
||||||
|
inOrderToInvoice: In order to invoice, this field is not contulted, but the consignee's ET. When modifiying this field if the invoice by address option is not checked, the change will be automatically propagated to all addresses, otherwise the user will be asked if he wants to propagate it or not
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|
|
@ -1,59 +1,44 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onBeforeMount } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
import { date, QBtn } from 'quasar';
|
import { QBtn } from 'quasar';
|
||||||
|
|
||||||
import { useArrayData } from 'composables/useArrayData';
|
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
|
||||||
import { toCurrency } from 'src/filters';
|
import { toCurrency } from 'src/filters';
|
||||||
|
import { toDateTimeFormat } from 'src/filters/date';
|
||||||
|
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const stateStore = useStateStore();
|
|
||||||
|
|
||||||
const arrayData = ref(null);
|
const rows = ref([]);
|
||||||
const totalAmount = ref(0);
|
const totalAmount = ref(0);
|
||||||
const workerId = ref(0);
|
|
||||||
const rows = computed(() => arrayData.value.store.data);
|
|
||||||
|
|
||||||
onBeforeMount(async () => {
|
const filter = {
|
||||||
const filter = {
|
include: [
|
||||||
include: [
|
{
|
||||||
{
|
relation: 'greugeType',
|
||||||
relation: 'greugeType',
|
scope: {
|
||||||
scope: {
|
fields: ['id', 'name'],
|
||||||
fields: ['id', 'name'],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
|
||||||
relation: 'user',
|
|
||||||
scope: {
|
|
||||||
fields: ['id', 'name'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
order: 'shipped DESC, amount',
|
|
||||||
where: {
|
|
||||||
clientFk: `${route.params.id}`,
|
|
||||||
},
|
},
|
||||||
limit: 20,
|
{
|
||||||
};
|
relation: 'user',
|
||||||
|
scope: {
|
||||||
arrayData.value = useArrayData('CustomerGreugesCard', {
|
fields: ['id', 'name'],
|
||||||
url: 'greuges',
|
},
|
||||||
filter,
|
},
|
||||||
});
|
],
|
||||||
await arrayData.value.fetch({ append: false });
|
order: 'shipped DESC, amount',
|
||||||
totalAmount.value = arrayData.value.store.data.reduce((accumulator, currentValue) => {
|
where: {
|
||||||
return accumulator + currentValue.amount;
|
clientFk: `${route.params.id}`,
|
||||||
}, 0);
|
},
|
||||||
stateStore.rightDrawer = true;
|
limit: 20,
|
||||||
});
|
};
|
||||||
|
|
||||||
const tableColumnComponents = {
|
const tableColumnComponents = {
|
||||||
date: {
|
date: {
|
||||||
|
@ -63,10 +48,8 @@ const tableColumnComponents = {
|
||||||
},
|
},
|
||||||
createdBy: {
|
createdBy: {
|
||||||
component: QBtn,
|
component: QBtn,
|
||||||
props: () => ({ flat: true, color: 'blue' }),
|
props: () => ({ flat: true, color: 'blue', noCaps: true }),
|
||||||
event: (prop) => {
|
event: () => {},
|
||||||
selectWorkerId(prop.row.clientFk);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
comment: {
|
comment: {
|
||||||
component: 'span',
|
component: 'span',
|
||||||
|
@ -91,7 +74,7 @@ const columns = computed(() => [
|
||||||
field: 'shipped',
|
field: 'shipped',
|
||||||
label: t('Date'),
|
label: t('Date'),
|
||||||
name: 'date',
|
name: 'date',
|
||||||
format: (value) => date.formatDate(value, 'DD/MM/YYYY hh:mm:ss'),
|
format: (value) => toDateTimeFormat(value),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
@ -120,8 +103,11 @@ const columns = computed(() => [
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const selectWorkerId = (id) => {
|
const setRows = (data) => {
|
||||||
workerId.value = id;
|
rows.value = data;
|
||||||
|
totalAmount.value = data.reduce((accumulator, currentValue) => {
|
||||||
|
return accumulator + currentValue.amount;
|
||||||
|
}, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
const toCustomerGreugeCreate = () => {
|
const toCustomerGreugeCreate = () => {
|
||||||
|
@ -130,44 +116,52 @@ const toCustomerGreugeCreate = () => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<QPage class="column items-center q-pa-md">
|
<FetchData :filter="filter" @on-fetch="setRows" auto-load url="greuges" />
|
||||||
<QCard class="full-width" v-if="totalAmount">
|
|
||||||
<h6 class="flex justify-end q-my-lg q-pr-lg">
|
|
||||||
<span class="label-color q-mr-md">{{ t('Total') }}:</span>
|
|
||||||
{{ toCurrency(totalAmount) }}
|
|
||||||
</h6>
|
|
||||||
</QCard>
|
|
||||||
|
|
||||||
<QTable
|
<div class="full-width flex justify-center">
|
||||||
:columns="columns"
|
<QPage class="card-width q-pa-lg">
|
||||||
:rows="rows"
|
<QCard class="full-width q-pa-sm" v-if="totalAmount">
|
||||||
class="full-width q-mt-md"
|
<h6 class="flex justify-end q-my-lg q-pr-lg">
|
||||||
row-key="id"
|
<span class="color-vn-label q-mr-md">{{ t('Total') }}:</span>
|
||||||
v-if="rows?.length"
|
{{ toCurrency(totalAmount) }}
|
||||||
>
|
</h6>
|
||||||
<template #body-cell="props">
|
</QCard>
|
||||||
<QTd :props="props">
|
|
||||||
<QTr :props="props" class="cursor-pointer">
|
|
||||||
<component
|
|
||||||
:is="tableColumnComponents[props.col.name].component"
|
|
||||||
class="col-content"
|
|
||||||
v-bind="tableColumnComponents[props.col.name].props(props)"
|
|
||||||
@click="tableColumnComponents[props.col.name].event(props)"
|
|
||||||
>
|
|
||||||
{{ props.value }}
|
|
||||||
<WorkerDescriptorProxy :id="workerId" />
|
|
||||||
</component>
|
|
||||||
</QTr>
|
|
||||||
</QTd>
|
|
||||||
</template>
|
|
||||||
</QTable>
|
|
||||||
|
|
||||||
<QCard class="full-width" v-else>
|
<QCard class="q-pa-sm q-mt-md">
|
||||||
<h5 class="flex justify-center label-color">
|
<QTable
|
||||||
{{ t('globals.noResults') }}
|
:columns="columns"
|
||||||
</h5>
|
:no-data-label="t('globals.noResults')"
|
||||||
</QCard>
|
:pagination="{ rowsPerPage: 12 }"
|
||||||
</QPage>
|
:rows="rows"
|
||||||
|
class="full-width q-mt-md"
|
||||||
|
row-key="id"
|
||||||
|
>
|
||||||
|
<template #body-cell="props">
|
||||||
|
<QTd :props="props">
|
||||||
|
<QTr :props="props" class="cursor-pointer">
|
||||||
|
<component
|
||||||
|
:is="tableColumnComponents[props.col.name].component"
|
||||||
|
class="col-content"
|
||||||
|
v-bind="
|
||||||
|
tableColumnComponents[props.col.name].props(props)
|
||||||
|
"
|
||||||
|
@click="
|
||||||
|
tableColumnComponents[props.col.name].event(props)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ props.value }}
|
||||||
|
<WorkerDescriptorProxy
|
||||||
|
:id="props.row.userFk"
|
||||||
|
v-if="props.col.name === 'createdBy'"
|
||||||
|
/>
|
||||||
|
</component>
|
||||||
|
</QTr>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
</QTable>
|
||||||
|
</QCard>
|
||||||
|
</QPage>
|
||||||
|
</div>
|
||||||
|
|
||||||
<QPageSticky :offset="[18, 18]">
|
<QPageSticky :offset="[18, 18]">
|
||||||
<QBtn @click.stop="toCustomerGreugeCreate()" color="primary" fab icon="add" />
|
<QBtn @click.stop="toCustomerGreugeCreate()" color="primary" fab icon="add" />
|
||||||
|
|
|
@ -124,13 +124,13 @@ const setInq = (value, status) => {
|
||||||
:url="urlClientLogsModels"
|
:url="urlClientLogsModels"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<h5 class="flex justify-center label-color">
|
<h5 class="flex justify-center color-vn-label">
|
||||||
{{ t('globals.noResults') }}
|
{{ t('globals.noResults') }}
|
||||||
</h5>
|
</h5>
|
||||||
|
|
||||||
<QDrawer :width="256" show-if-above side="right" v-model="stateStore.rightDrawer">
|
<QDrawer :width="256" show-if-above side="right" v-model="stateStore.rightDrawer">
|
||||||
<div class="q-mt-sm q-px-md">
|
<div class="q-mt-sm q-px-md">
|
||||||
<VnInput :label="t('Search')">
|
<VnInput :label="t('Search')" clearable>
|
||||||
<template #append>
|
<template #append>
|
||||||
<QIcon name="info" class="cursor-pointer">
|
<QIcon name="info" class="cursor-pointer">
|
||||||
<QTooltip>
|
<QTooltip>
|
||||||
|
@ -187,7 +187,7 @@ const setInq = (value, status) => {
|
||||||
option-label="name"
|
option-label="name"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
/>
|
/>
|
||||||
<VnInput :label="t('Changes')" class="q-mt-sm">
|
<VnInput :label="t('Changes')" clearable class="q-mt-sm">
|
||||||
<template #append>
|
<template #append>
|
||||||
<QIcon name="info" class="cursor-pointer">
|
<QIcon name="info" class="cursor-pointer">
|
||||||
<QTooltip>
|
<QTooltip>
|
||||||
|
@ -227,7 +227,7 @@ const setInq = (value, status) => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<VnInputDate :label="t('Date')" class="q-mt-sm" />
|
<VnInputDate :label="t('Date')" class="q-mt-sm" />
|
||||||
<VnInput :label="t('To')" class="q-mt-md" />
|
<VnInput :label="t('To')" clearable class="q-mt-md" />
|
||||||
</div>
|
</div>
|
||||||
</QDrawer>
|
</QDrawer>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,135 @@
|
||||||
|
<script setup>
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
|
import { toDateTimeFormat } from 'src/filters/date';
|
||||||
|
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
|
const rows = ref([]);
|
||||||
|
|
||||||
|
const filter = {
|
||||||
|
include: [
|
||||||
|
{ relation: 'mandateType', scope: { fields: ['id', 'name'] } },
|
||||||
|
{ relation: 'company', scope: { fields: ['id', 'code'] } },
|
||||||
|
],
|
||||||
|
where: { clientFk: route.params.id },
|
||||||
|
order: ['created DESC'],
|
||||||
|
limit: 20,
|
||||||
|
};
|
||||||
|
|
||||||
|
const tableColumnComponents = {
|
||||||
|
id: {
|
||||||
|
component: 'span',
|
||||||
|
props: () => {},
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
company: {
|
||||||
|
component: 'span',
|
||||||
|
props: () => {},
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
component: 'span',
|
||||||
|
props: () => {},
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
registerDate: {
|
||||||
|
component: 'span',
|
||||||
|
props: () => {},
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
endDate: {
|
||||||
|
component: 'span',
|
||||||
|
props: () => {},
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const columns = computed(() => [
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: 'id',
|
||||||
|
label: t('Id'),
|
||||||
|
name: 'id',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: (row) => row.company.code,
|
||||||
|
label: t('Company'),
|
||||||
|
name: 'company',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: (row) => row.mandateType.name,
|
||||||
|
label: t('Type'),
|
||||||
|
name: 'type',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: 'created',
|
||||||
|
label: t('Register date'),
|
||||||
|
name: 'registerDate',
|
||||||
|
format: (value) => toDateTimeFormat(value),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: 'finished',
|
||||||
|
label: t('End date'),
|
||||||
|
name: 'endDate',
|
||||||
|
format: (value) => (value ? toDateTimeFormat(value) : '-'),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<FetchData
|
||||||
|
:filter="filter"
|
||||||
|
@on-fetch="(data) => (rows = data)"
|
||||||
|
auto-load
|
||||||
|
url="Mandates"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<QPage class="column items-center q-pa-md">
|
||||||
|
<QTable
|
||||||
|
:columns="columns"
|
||||||
|
:pagination="{ rowsPerPage: 12 }"
|
||||||
|
:rows="rows"
|
||||||
|
class="full-width q-mt-md"
|
||||||
|
row-key="id"
|
||||||
|
v-if="rows?.length"
|
||||||
|
>
|
||||||
|
<template #body-cell="props">
|
||||||
|
<QTd :props="props">
|
||||||
|
<QTr :props="props" class="cursor-pointer">
|
||||||
|
<component
|
||||||
|
:is="tableColumnComponents[props.col.name].component"
|
||||||
|
@click="tableColumnComponents[props.col.name].event(props)"
|
||||||
|
class="rounded-borders q-pa-sm"
|
||||||
|
v-bind="tableColumnComponents[props.col.name].props(props)"
|
||||||
|
>
|
||||||
|
{{ props.value }}
|
||||||
|
</component>
|
||||||
|
</QTr>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
</QTable>
|
||||||
|
|
||||||
|
<h5 class="flex justify-center color-vn-label" v-else>
|
||||||
|
{{ t('globals.noResults') }}
|
||||||
|
</h5>
|
||||||
|
</QPage>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
Id: Id
|
||||||
|
Company: Empresa
|
||||||
|
Type: Tipo
|
||||||
|
Register date: Fecha alta
|
||||||
|
End date: Fecha baja
|
||||||
|
</i18n>
|
|
@ -2,7 +2,7 @@
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
import { date } from 'quasar';
|
import { toDateTimeFormat } from 'src/filters/date';
|
||||||
|
|
||||||
import VnPaginate from 'src/components/ui/VnPaginate.vue';
|
import VnPaginate from 'src/components/ui/VnPaginate.vue';
|
||||||
|
|
||||||
|
@ -23,62 +23,48 @@ const toCustomerNoteCreate = () => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<QCard class="q-pa-lg">
|
<div class="full-width flex justify-center">
|
||||||
<VnPaginate
|
<QCard class="card-width q-pa-lg">
|
||||||
data-key="CustomerNotes"
|
<VnPaginate
|
||||||
:url="'clientObservations'"
|
data-key="CustomerNotes"
|
||||||
auto-load
|
url="clientObservations"
|
||||||
:filter="noteFilter"
|
auto-load
|
||||||
>
|
:filter="noteFilter"
|
||||||
<template #body="{ rows }">
|
>
|
||||||
<div v-if="rows.length">
|
<template #body="{ rows }">
|
||||||
<QCard
|
<div v-if="rows.length">
|
||||||
v-for="(item, index) in rows"
|
<QCard
|
||||||
:key="index"
|
v-for="(item, index) in rows"
|
||||||
:class="{
|
:key="index"
|
||||||
'q-pa-md': true,
|
class="q-pa-md q-rounded custom-border"
|
||||||
'q-rounded': true,
|
:class="{ 'q-mb-md': index < rows.length - 1 }"
|
||||||
'custom-border': true,
|
>
|
||||||
'q-mb-md': index < rows.length - 1,
|
<div class="flex justify-between">
|
||||||
}"
|
<p class="color-vn-label">
|
||||||
>
|
{{ item.worker.user.nickname }}
|
||||||
<div class="flex justify-between">
|
</p>
|
||||||
<p class="label-color">{{ item.worker.user.nickname }}</p>
|
<p class="color-vn-label">
|
||||||
<p class="label-color">
|
{{ toDateTimeFormat(item?.created) }}
|
||||||
{{
|
</p>
|
||||||
date.formatDate(item?.created, 'DD-MM-YYYY HH:mm:ss')
|
</div>
|
||||||
}}
|
<h6 class="q-mt-xs q-mb-none">{{ item.text }}</h6>
|
||||||
</p>
|
</QCard>
|
||||||
</div>
|
</div>
|
||||||
<h6 class="q-mt-xs q-mb-none">{{ item.text }}</h6>
|
|
||||||
</QCard>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<h5 class="flex justify-center label-color">
|
<h5 class="flex justify-center color-vn-label">
|
||||||
{{ t('globals.noResults') }}
|
{{ t('globals.noResults') }}
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
|
</template>
|
||||||
<QPageSticky :offset="[18, 18]">
|
</VnPaginate>
|
||||||
<QBtn
|
</QCard>
|
||||||
@click.stop="toCustomerNoteCreate()"
|
</div>
|
||||||
color="primary"
|
|
||||||
fab
|
|
||||||
icon="add"
|
|
||||||
/>
|
|
||||||
<QTooltip>
|
|
||||||
{{ t('New consignee') }}
|
|
||||||
</QTooltip>
|
|
||||||
</QPageSticky>
|
|
||||||
</template>
|
|
||||||
</VnPaginate>
|
|
||||||
</QCard>
|
|
||||||
|
|
||||||
<QPageSticky :offset="[18, 18]">
|
<QPageSticky :offset="[18, 18]">
|
||||||
<QBtn @click.stop="toCustomerNoteCreate()" color="primary" fab icon="add" />
|
<QBtn @click.stop="toCustomerNoteCreate()" color="primary" fab icon="add" />
|
||||||
<QTooltip>
|
<QTooltip>
|
||||||
{{ t('New consignee') }}
|
{{ t('New note') }}
|
||||||
</QTooltip>
|
</QTooltip>
|
||||||
</QPageSticky>
|
</QPageSticky>
|
||||||
</template>
|
</template>
|
||||||
|
@ -89,8 +75,9 @@ const toCustomerNoteCreate = () => {
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label-color {
|
|
||||||
color: var(--vn-label-color);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
New note: Nueva nota
|
||||||
|
</i18n>
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="flex justify-center">Others</div>
|
|
||||||
</template>
|
|
|
@ -1,39 +1,22 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onBeforeMount } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
import { date, QBtn } from 'quasar';
|
import { toCurrency, toDate } from 'src/filters';
|
||||||
|
|
||||||
import { useArrayData } from 'composables/useArrayData';
|
import FetchData from 'components/FetchData.vue';
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
|
||||||
import { toCurrency } from 'src/filters';
|
|
||||||
|
|
||||||
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const stateStore = useStateStore();
|
const rows = ref([]);
|
||||||
|
|
||||||
const arrayData = ref(null);
|
const filter = {
|
||||||
const workerId = ref(0);
|
where: { clientFk: route.params.id },
|
||||||
const rows = computed(() => arrayData.value.store.data);
|
order: ['started DESC'],
|
||||||
|
limit: 20,
|
||||||
onBeforeMount(async () => {
|
};
|
||||||
const filter = {
|
|
||||||
where: { clientFk: `${route.params.id}` },
|
|
||||||
order: ['started DESC'],
|
|
||||||
limit: 20,
|
|
||||||
};
|
|
||||||
|
|
||||||
arrayData.value = useArrayData('CustomerRecoveriesCard', {
|
|
||||||
url: 'Recoveries',
|
|
||||||
filter,
|
|
||||||
});
|
|
||||||
await arrayData.value.fetch({ append: false });
|
|
||||||
stateStore.rightDrawer = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
const tableColumnComponents = {
|
const tableColumnComponents = {
|
||||||
since: {
|
since: {
|
||||||
|
@ -64,14 +47,14 @@ const columns = computed(() => [
|
||||||
field: 'started',
|
field: 'started',
|
||||||
label: t('Since'),
|
label: t('Since'),
|
||||||
name: 'since',
|
name: 'since',
|
||||||
format: (value) => date.formatDate(value, 'DD/MM/YYYY'),
|
format: (value) => toDate(value),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: 'finished',
|
field: 'finished',
|
||||||
label: t('To'),
|
label: t('To'),
|
||||||
name: 'to',
|
name: 'to',
|
||||||
format: (value) => date.formatDate(value, 'DD/MM/YYYY'),
|
format: (value) => toDate(value),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
@ -94,37 +77,44 @@ const toCustomerRecoverieCreate = () => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<QPage class="column items-center q-pa-md">
|
<FetchData
|
||||||
<QTable
|
:filter="filter"
|
||||||
:columns="columns"
|
@on-fetch="(data) => (rows = data)"
|
||||||
:rows="rows"
|
auto-load
|
||||||
class="full-width q-mt-md"
|
url="Recoveries"
|
||||||
row-key="id"
|
/>
|
||||||
v-if="rows?.length"
|
|
||||||
>
|
|
||||||
<template #body-cell="props">
|
|
||||||
<QTd :props="props">
|
|
||||||
<QTr :props="props" class="cursor-pointer">
|
|
||||||
<component
|
|
||||||
:is="tableColumnComponents[props.col.name].component"
|
|
||||||
class="col-content"
|
|
||||||
v-bind="tableColumnComponents[props.col.name].props(props)"
|
|
||||||
@click="tableColumnComponents[props.col.name].event(props)"
|
|
||||||
>
|
|
||||||
{{ props.value }}
|
|
||||||
<WorkerDescriptorProxy :id="workerId" />
|
|
||||||
</component>
|
|
||||||
</QTr>
|
|
||||||
</QTd>
|
|
||||||
</template>
|
|
||||||
</QTable>
|
|
||||||
|
|
||||||
<QCard class="full-width" v-else>
|
<div class="full-width flex justify-center">
|
||||||
<h5 class="flex justify-center label-color">
|
<QPage class="card-width q-pa-lg">
|
||||||
{{ t('globals.noResults') }}
|
<QTable
|
||||||
</h5>
|
:columns="columns"
|
||||||
</QCard>
|
:no-data-label="t('globals.noResults')"
|
||||||
</QPage>
|
:pagination="{ rowsPerPage: 12 }"
|
||||||
|
:rows="rows"
|
||||||
|
class="full-width q-mt-md"
|
||||||
|
row-key="id"
|
||||||
|
>
|
||||||
|
<template #body-cell="props">
|
||||||
|
<QTd :props="props">
|
||||||
|
<QTr :props="props" class="cursor-pointer">
|
||||||
|
<component
|
||||||
|
:is="tableColumnComponents[props.col.name].component"
|
||||||
|
class="col-content"
|
||||||
|
v-bind="
|
||||||
|
tableColumnComponents[props.col.name].props(props)
|
||||||
|
"
|
||||||
|
@click="
|
||||||
|
tableColumnComponents[props.col.name].event(props)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ props.value }}
|
||||||
|
</component>
|
||||||
|
</QTr>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
</QTable>
|
||||||
|
</QPage>
|
||||||
|
</div>
|
||||||
|
|
||||||
<QPageSticky :offset="[18, 18]">
|
<QPageSticky :offset="[18, 18]">
|
||||||
<QBtn @click.stop="toCustomerRecoverieCreate()" color="primary" fab icon="add" />
|
<QBtn @click.stop="toCustomerRecoverieCreate()" color="primary" fab icon="add" />
|
||||||
|
|
|
@ -0,0 +1,144 @@
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
import { QBtn } from 'quasar';
|
||||||
|
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
|
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
||||||
|
import { toDateTimeFormat } from 'src/filters/date';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const rows = ref([]);
|
||||||
|
|
||||||
|
const filter = {
|
||||||
|
include: [
|
||||||
|
{ relation: 'type', scope: { fields: ['code', 'description'] } },
|
||||||
|
{ relation: 'user', scope: { fields: ['id', 'name'] } },
|
||||||
|
{ relation: 'company', scope: { fields: ['code'] } },
|
||||||
|
],
|
||||||
|
where: { clientFk: route.params.id },
|
||||||
|
order: ['created DESC'],
|
||||||
|
limit: 20,
|
||||||
|
};
|
||||||
|
|
||||||
|
const tableColumnComponents = {
|
||||||
|
sent: {
|
||||||
|
component: 'span',
|
||||||
|
props: () => {},
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
component: 'span',
|
||||||
|
props: () => {},
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
worker: {
|
||||||
|
component: QBtn,
|
||||||
|
props: () => ({ flat: true, color: 'blue', noCaps: true }),
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
company: {
|
||||||
|
component: 'span',
|
||||||
|
props: () => {},
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const columns = computed(() => [
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: 'created',
|
||||||
|
label: t('Sent'),
|
||||||
|
name: 'sent',
|
||||||
|
format: (value) => toDateTimeFormat(value),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: (value) => value.type.description,
|
||||||
|
label: t('Description'),
|
||||||
|
name: 'description',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: (value) => value.user.name,
|
||||||
|
label: t('Worker'),
|
||||||
|
name: 'worker',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: (value) => value.company?.code,
|
||||||
|
label: t('Company'),
|
||||||
|
name: 'company',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const toCustomerSamplesCreate = () => {
|
||||||
|
router.push({ name: 'CustomerSamplesCreate' });
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<FetchData
|
||||||
|
:filter="filter"
|
||||||
|
@on-fetch="(data) => (rows = data)"
|
||||||
|
auto-load
|
||||||
|
url="ClientSamples"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div class="full-width flex justify-center">
|
||||||
|
<QPage class="card-width q-pa-lg">
|
||||||
|
<QTable
|
||||||
|
:columns="columns"
|
||||||
|
:pagination="{ rowsPerPage: 12 }"
|
||||||
|
:rows="rows"
|
||||||
|
class="full-width q-mt-md"
|
||||||
|
row-key="id"
|
||||||
|
:no-data-label="t('globals.noResults')"
|
||||||
|
>
|
||||||
|
<template #body-cell="props">
|
||||||
|
<QTd :props="props">
|
||||||
|
<QTr :props="props" class="cursor-pointer">
|
||||||
|
<component
|
||||||
|
:is="tableColumnComponents[props.col.name].component"
|
||||||
|
class="col-content"
|
||||||
|
v-bind="
|
||||||
|
tableColumnComponents[props.col.name].props(props)
|
||||||
|
"
|
||||||
|
@click="
|
||||||
|
tableColumnComponents[props.col.name].event(props)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ props.value }}
|
||||||
|
<WorkerDescriptorProxy
|
||||||
|
:id="props.row.userFk"
|
||||||
|
v-if="props.col.name === 'worker'"
|
||||||
|
/>
|
||||||
|
</component>
|
||||||
|
</QTr>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
</QTable>
|
||||||
|
</QPage>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<QPageSticky :offset="[18, 18]">
|
||||||
|
<QBtn @click.stop="toCustomerSamplesCreate()" color="primary" fab icon="add" />
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('Send sample') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QPageSticky>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
Sent: Enviado
|
||||||
|
Description: Descripción
|
||||||
|
Worker: Trabajador
|
||||||
|
Company: Empresa
|
||||||
|
Send sample: Enviar plantilla
|
||||||
|
</i18n>
|
|
@ -7,6 +7,7 @@ import CardSummary from 'components/ui/CardSummary.vue';
|
||||||
import { getUrl } from 'src/composables/getUrl';
|
import { getUrl } from 'src/composables/getUrl';
|
||||||
import VnLv from 'src/components/ui/VnLv.vue';
|
import VnLv from 'src/components/ui/VnLv.vue';
|
||||||
import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue';
|
import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue';
|
||||||
|
import CustomerSummaryTable from 'src/pages/Customer/components/CustomerSummaryTable.vue';
|
||||||
import VnTitle from 'src/components/common/VnTitle.vue';
|
import VnTitle from 'src/components/common/VnTitle.vue';
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
@ -305,9 +306,16 @@ const creditWarning = computed(() => {
|
||||||
:value="entity.recommendedCredit"
|
:value="entity.recommendedCredit"
|
||||||
/>
|
/>
|
||||||
</QCard>
|
</QCard>
|
||||||
|
<QCard>
|
||||||
|
<div class="header">
|
||||||
|
{{ t('Latest tickets') }}
|
||||||
|
</div>
|
||||||
|
<CustomerSummaryTable />
|
||||||
|
</QCard>
|
||||||
</template>
|
</template>
|
||||||
</CardSummary>
|
</CardSummary>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@media (min-width: $breakpoint-md) {
|
@media (min-width: $breakpoint-md) {
|
||||||
.summary .vn-one {
|
.summary .vn-one {
|
||||||
|
@ -315,9 +323,11 @@ const creditWarning = computed(() => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<i18n>
|
<i18n>
|
||||||
en:
|
en:
|
||||||
valueInfo: Value from {min} to {max}. The higher the better value
|
valueInfo: Value from {min} to {max}. The higher the better value
|
||||||
es:
|
es:
|
||||||
valueInfo: Valor de {min} a {max}. Cuanto más alto, mejor valor
|
valueInfo: Valor de {min} a {max}. Cuanto más alto, mejor valor
|
||||||
|
Latest tickets: Últimos tickets
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|
|
@ -0,0 +1,167 @@
|
||||||
|
<script setup>
|
||||||
|
import { computed, onBeforeMount, ref, watch, nextTick } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
|
import VnInputDate from 'components/common/VnInputDate.vue';
|
||||||
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
|
||||||
|
import axios from 'axios';
|
||||||
|
import useNotify from 'src/composables/useNotify';
|
||||||
|
import { useStateStore } from 'stores/useStateStore';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const route = useRoute();
|
||||||
|
const { notify } = useNotify();
|
||||||
|
const stateStore = useStateStore();
|
||||||
|
|
||||||
|
const amountInputRef = ref(null);
|
||||||
|
const initialDated = Date.vnNew();
|
||||||
|
const unpaidClient = ref(false);
|
||||||
|
const isLoading = ref(false);
|
||||||
|
const amount = ref(null);
|
||||||
|
const dated = ref(initialDated);
|
||||||
|
|
||||||
|
const initialData = ref({
|
||||||
|
dated: initialDated,
|
||||||
|
});
|
||||||
|
|
||||||
|
const hasChanged = computed(() => {
|
||||||
|
return (
|
||||||
|
initialData.value.dated !== dated.value ||
|
||||||
|
initialData.value.amount !== amount.value
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeMount(() => {
|
||||||
|
getData(route.params.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.params.id,
|
||||||
|
(newValue) => {
|
||||||
|
if (!newValue) return;
|
||||||
|
getData(newValue);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const getData = async (id) => {
|
||||||
|
const filter = { where: { clientFk: id } };
|
||||||
|
try {
|
||||||
|
const { data } = await axios.get('ClientUnpaids', {
|
||||||
|
params: { filter: JSON.stringify(filter) },
|
||||||
|
});
|
||||||
|
if (data.length) {
|
||||||
|
setValues(data[0]);
|
||||||
|
} else {
|
||||||
|
defaultValues();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
defaultValues();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const setValues = (data) => {
|
||||||
|
unpaidClient.value = true;
|
||||||
|
amount.value = data.amount;
|
||||||
|
dated.value = data.dated;
|
||||||
|
initialData.value = data;
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultValues = () => {
|
||||||
|
unpaidClient.value = false;
|
||||||
|
initialData.value.amount = null;
|
||||||
|
setInitialData();
|
||||||
|
};
|
||||||
|
|
||||||
|
const setInitialData = () => {
|
||||||
|
amount.value = initialData.value.amount;
|
||||||
|
dated.value = initialData.value.dated;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSubmit = async () => {
|
||||||
|
isLoading.value = true;
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
amount: amount.value,
|
||||||
|
clientFk: route.params.id,
|
||||||
|
dated: dated.value,
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
await axios.patch('ClientUnpaids', payload);
|
||||||
|
notify('globals.dataSaved', 'positive');
|
||||||
|
unpaidClient.value = true;
|
||||||
|
} catch (error) {
|
||||||
|
notify('errors.create', 'negative');
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => unpaidClient.value,
|
||||||
|
async (val) => {
|
||||||
|
await nextTick();
|
||||||
|
if (val) amountInputRef.value.focus();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Teleport v-if="stateStore?.isSubToolbarShown()" to="#st-actions">
|
||||||
|
<QBtnGroup push class="q-gutter-x-sm">
|
||||||
|
<QBtn
|
||||||
|
:disabled="!hasChanged"
|
||||||
|
:label="t('globals.reset')"
|
||||||
|
:loading="isLoading"
|
||||||
|
@click="setInitialData"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
icon="restart_alt"
|
||||||
|
type="reset"
|
||||||
|
/>
|
||||||
|
<QBtn
|
||||||
|
:disabled="!hasChanged"
|
||||||
|
:label="t('globals.save')"
|
||||||
|
:loading="isLoading"
|
||||||
|
@click="onSubmit"
|
||||||
|
color="primary"
|
||||||
|
icon="save"
|
||||||
|
/>
|
||||||
|
</QBtnGroup>
|
||||||
|
</Teleport>
|
||||||
|
|
||||||
|
<div class="full-width flex justify-center">
|
||||||
|
<QCard class="card-width q-pa-lg">
|
||||||
|
<QForm>
|
||||||
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
|
<div class="col">
|
||||||
|
<QCheckbox :label="t('Unpaid client')" v-model="unpaidClient" />
|
||||||
|
</div>
|
||||||
|
</VnRow>
|
||||||
|
|
||||||
|
<VnRow class="row q-gutter-md q-mb-md" v-show="unpaidClient">
|
||||||
|
<div class="col">
|
||||||
|
<VnInputDate :label="t('Date')" v-model="dated" />
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<VnInput
|
||||||
|
ref="amountInputRef"
|
||||||
|
:label="t('Amount')"
|
||||||
|
clearable
|
||||||
|
type="number"
|
||||||
|
v-model="amount"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</VnRow>
|
||||||
|
</QForm>
|
||||||
|
</QCard>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
Unpaid client: Cliente impagado
|
||||||
|
Date: Fecha
|
||||||
|
Amount: Importe
|
||||||
|
</i18n>
|
|
@ -1,48 +1,158 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
import FormModel from 'components/FormModel.vue';
|
import axios from 'axios';
|
||||||
|
import { useQuasar } from 'quasar';
|
||||||
|
|
||||||
|
import { useValidator } from 'src/composables/useValidator';
|
||||||
|
import useNotify from 'src/composables/useNotify';
|
||||||
|
import { useStateStore } from 'stores/useStateStore';
|
||||||
|
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
import VnRow from 'components/ui/VnRow.vue';
|
import VnRow from 'components/ui/VnRow.vue';
|
||||||
import VnInput from 'src/components/common/VnInput.vue';
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
import CustomerChangePassword from 'src/pages/Customer/components/CustomerChangePassword.vue';
|
||||||
|
|
||||||
|
const { notify } = useNotify();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
const { validate } = useValidator();
|
||||||
|
const quasar = useQuasar();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
const stateStore = useStateStore();
|
||||||
|
|
||||||
|
const active = ref(false);
|
||||||
|
const canChangePassword = ref(0);
|
||||||
|
const email = ref(null);
|
||||||
|
const isLoading = ref(false);
|
||||||
|
const name = ref(null);
|
||||||
|
const usersPreviewRef = ref(null);
|
||||||
|
const user = ref([]);
|
||||||
|
const userPasswords = ref(0);
|
||||||
|
|
||||||
|
const dataChanges = computed(() => {
|
||||||
|
return (
|
||||||
|
user.value.active !== active.value ||
|
||||||
|
user.value.email !== email.value ||
|
||||||
|
user.value.name !== name.value
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
const filter = { where: { id: `${route.params.id}` } };
|
const filter = { where: { id: `${route.params.id}` } };
|
||||||
|
|
||||||
|
const showChangePasswordDialog = () => {
|
||||||
|
quasar.dialog({
|
||||||
|
component: CustomerChangePassword,
|
||||||
|
componentProps: {
|
||||||
|
id: route.params.id,
|
||||||
|
userPasswords: userPasswords.value,
|
||||||
|
promise: usersPreviewRef.value.fetch(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const setInitialData = () => {
|
||||||
|
if (user.value.length) {
|
||||||
|
active.value = user.value[0].active;
|
||||||
|
email.value = user.value[0].email;
|
||||||
|
name.value = user.value[0].name;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSubmit = async () => {
|
||||||
|
isLoading.value = true;
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
active: active.value,
|
||||||
|
email: email.value,
|
||||||
|
name: name.value,
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
await axios.patch(`Clients/${route.params.id}/updateUser`, payload);
|
||||||
|
notify('globals.dataSaved', 'positive');
|
||||||
|
if (usersPreviewRef.value) usersPreviewRef.value.fetch();
|
||||||
|
} catch (error) {
|
||||||
|
notify('errors.create', 'negative');
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<FormModel
|
<FetchData
|
||||||
:filter="filter"
|
:filter="filter"
|
||||||
:observe-form-changes="false"
|
@on-fetch="
|
||||||
:url-update="`Clients/${route.params.id}/updateUser`"
|
(data) => {
|
||||||
:url="'VnUsers/preview'"
|
user = data;
|
||||||
model="client"
|
setInitialData();
|
||||||
>
|
}
|
||||||
<template #form="{ data }">
|
"
|
||||||
<div
|
auto-load
|
||||||
v-for="(item, index) in data"
|
ref="usersPreviewRef"
|
||||||
:key="index"
|
url="VnUsers/preview"
|
||||||
:class="{
|
/>
|
||||||
'q-mb-md': index < data.length - 1,
|
<FetchData
|
||||||
}"
|
:url="`Clients/${route.params.id}/hasCustomerRole`"
|
||||||
>
|
@on-fetch="(data) => (canChangePassword = data)"
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
auto-load
|
||||||
<div class="col">
|
/>
|
||||||
<QCheckbox
|
<FetchData
|
||||||
:label="t('Enable web access')"
|
@on-fetch="(data) => (userPasswords = data[0])"
|
||||||
v-model="item.active"
|
auto-load
|
||||||
/>
|
url="UserPasswords"
|
||||||
</div>
|
/>
|
||||||
</VnRow>
|
|
||||||
|
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<Teleport to="#st-actions" v-if="stateStore?.isSubToolbarShown()">
|
||||||
<div class="col">
|
<QBtnGroup push class="q-gutter-x-sm">
|
||||||
<VnInput :label="t('User')" v-model="item.name" />
|
<QBtn
|
||||||
</div>
|
:disabled="isLoading"
|
||||||
<div class="col">
|
:label="t('globals.reset')"
|
||||||
<VnInput :label="t('Recovery email')" v-model="item.email">
|
:loading="isLoading"
|
||||||
|
@click="setInitialData"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
icon="restart_alt"
|
||||||
|
type="reset"
|
||||||
|
/>
|
||||||
|
<QBtn
|
||||||
|
:disabled="isLoading"
|
||||||
|
:label="t('Change password')"
|
||||||
|
:loading="isLoading"
|
||||||
|
@click.stop="showChangePasswordDialog()"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
icon="edit"
|
||||||
|
v-if="canChangePassword"
|
||||||
|
/>
|
||||||
|
<QBtn
|
||||||
|
:disabled="isLoading || !dataChanges"
|
||||||
|
:label="t('globals.save')"
|
||||||
|
:loading="isLoading"
|
||||||
|
@click="onSubmit"
|
||||||
|
color="primary"
|
||||||
|
icon="save"
|
||||||
|
/>
|
||||||
|
</QBtnGroup>
|
||||||
|
</Teleport>
|
||||||
|
|
||||||
|
<div class="full-width flex justify-center">
|
||||||
|
<QCard class="card-width q-pa-lg">
|
||||||
|
<QCardSection>
|
||||||
|
<QForm>
|
||||||
|
<QCheckbox :label="t('Enable web access')" v-model="active" />
|
||||||
|
|
||||||
|
<div class="q-px-sm">
|
||||||
|
<VnInput :label="t('User')" clearable v-model="name" />
|
||||||
|
<VnInput
|
||||||
|
:label="t('Recovery email')"
|
||||||
|
:rules="validate('client.email')"
|
||||||
|
clearable
|
||||||
|
type="email"
|
||||||
|
v-model="email"
|
||||||
|
class="q-mt-sm"
|
||||||
|
>
|
||||||
<template #append>
|
<template #append>
|
||||||
<QIcon name="info" class="cursor-pointer">
|
<QIcon name="info" class="cursor-pointer">
|
||||||
<QTooltip>{{
|
<QTooltip>{{
|
||||||
|
@ -54,10 +164,10 @@ const filter = { where: { id: `${route.params.id}` } };
|
||||||
</template>
|
</template>
|
||||||
</VnInput>
|
</VnInput>
|
||||||
</div>
|
</div>
|
||||||
</VnRow>
|
</QForm>
|
||||||
</div>
|
</QCardSection>
|
||||||
</template>
|
</QCard>
|
||||||
</FormModel>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<i18n>
|
<i18n>
|
||||||
|
@ -66,4 +176,5 @@ es:
|
||||||
User: Usuario
|
User: Usuario
|
||||||
Recovery email: Correo de recuperacion
|
Recovery email: Correo de recuperacion
|
||||||
This email is used for user to regain access their account: Este correo electrónico se usa para que el usuario recupere el acceso a su cuenta
|
This email is used for user to regain access their account: Este correo electrónico se usa para que el usuario recupere el acceso a su cuenta
|
||||||
|
Change password: Cambiar contraseña
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|
|
@ -0,0 +1,167 @@
|
||||||
|
<script setup>
|
||||||
|
import { computed, onBeforeMount, ref, watch } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
import { toCurrency, toDateHourMinSec } from 'src/filters';
|
||||||
|
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
|
import CustomerCloseIconTooltip from '../components/CustomerCloseIconTooltip.vue';
|
||||||
|
import CustomerCheckIconTooltip from '../components/CustomerCheckIconTooltip.vue';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
|
const rows = ref([]);
|
||||||
|
|
||||||
|
const filter = {
|
||||||
|
include: [
|
||||||
|
{ relation: 'mandateType', scope: { fields: ['id', 'name'] } },
|
||||||
|
{ relation: 'company', scope: { fields: ['id', 'code'] } },
|
||||||
|
],
|
||||||
|
where: { clientFk: null },
|
||||||
|
order: ['created DESC'],
|
||||||
|
limit: 20,
|
||||||
|
};
|
||||||
|
|
||||||
|
const tableColumnComponents = {
|
||||||
|
state: {
|
||||||
|
component: CustomerCloseIconTooltip,
|
||||||
|
props: ({ row }) => ({ transaction: row }),
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
id: {
|
||||||
|
component: 'span',
|
||||||
|
props: () => {},
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
date: {
|
||||||
|
component: 'span',
|
||||||
|
props: () => {},
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
amount: {
|
||||||
|
component: 'span',
|
||||||
|
props: () => {},
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
validate: {
|
||||||
|
component: CustomerCheckIconTooltip,
|
||||||
|
props: ({ row }) => ({
|
||||||
|
transaction: row,
|
||||||
|
promise: refreshData,
|
||||||
|
}),
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const columns = computed(() => [
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: '',
|
||||||
|
label: t('State'),
|
||||||
|
name: 'state',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: 'id',
|
||||||
|
label: t('Id'),
|
||||||
|
name: 'id',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: 'created',
|
||||||
|
label: t('Date'),
|
||||||
|
name: 'date',
|
||||||
|
format: (value) => toDateHourMinSec(value),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: 'amount',
|
||||||
|
label: t('Amount'),
|
||||||
|
name: 'amount',
|
||||||
|
format: (value) => toCurrency(value),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: '',
|
||||||
|
name: 'validate',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
onBeforeMount(() => {
|
||||||
|
getData(route.params.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.params.id,
|
||||||
|
(newValue) => {
|
||||||
|
if (!newValue) return;
|
||||||
|
getData(newValue);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const getData = async (id) => {
|
||||||
|
filter.where.clientFk = id;
|
||||||
|
try {
|
||||||
|
const { data } = await axios.get('clients/transactions', {
|
||||||
|
params: { filter: JSON.stringify(filter) },
|
||||||
|
});
|
||||||
|
rows.value = data;
|
||||||
|
} catch (error) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const refreshData = () => {
|
||||||
|
getData(route.params.id);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="full-width flex justify-center">
|
||||||
|
<QPage class="card-width q-pa-lg">
|
||||||
|
<QTable
|
||||||
|
:columns="columns"
|
||||||
|
:pagination="{ rowsPerPage: 12 }"
|
||||||
|
:rows="rows"
|
||||||
|
class="full-width q-mt-md"
|
||||||
|
row-key="id"
|
||||||
|
v-if="rows?.length"
|
||||||
|
>
|
||||||
|
<template #body-cell="props">
|
||||||
|
<QTd :props="props">
|
||||||
|
<QTr :props="props">
|
||||||
|
<component
|
||||||
|
:is="tableColumnComponents[props.col.name].component"
|
||||||
|
@click="
|
||||||
|
tableColumnComponents[props.col.name].event(props)
|
||||||
|
"
|
||||||
|
class="rounded-borders q-pa-sm"
|
||||||
|
v-bind="
|
||||||
|
tableColumnComponents[props.col.name].props(props)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ props.value }}
|
||||||
|
</component>
|
||||||
|
</QTr>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
</QTable>
|
||||||
|
|
||||||
|
<h5 class="flex justify-center color-vn-label" v-else>
|
||||||
|
{{ t('globals.noResults') }}
|
||||||
|
</h5>
|
||||||
|
</QPage>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
State: Estado
|
||||||
|
Id: Id
|
||||||
|
Date: Fecha
|
||||||
|
Amount: Importe
|
||||||
|
</i18n>
|
|
@ -11,20 +11,8 @@ import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const newClientForm = reactive({
|
const initialData = reactive({
|
||||||
active: true,
|
active: true,
|
||||||
name: null,
|
|
||||||
salesPersonFk: null,
|
|
||||||
businessTypeFk: null,
|
|
||||||
fi: null,
|
|
||||||
socialName: null,
|
|
||||||
street: null,
|
|
||||||
postcode: null,
|
|
||||||
city: null,
|
|
||||||
provinceFk: null,
|
|
||||||
countryFk: null,
|
|
||||||
userName: null,
|
|
||||||
email: null,
|
|
||||||
isEqualizated: false,
|
isEqualizated: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -55,7 +43,7 @@ function handleLocation(data, location) {
|
||||||
<QPage>
|
<QPage>
|
||||||
<VnSubToolbar />
|
<VnSubToolbar />
|
||||||
<FormModel
|
<FormModel
|
||||||
:form-initial-data="newClientForm"
|
:form-initial-data="initialData"
|
||||||
model="client"
|
model="client"
|
||||||
url-create="Clients/createWithUser"
|
url-create="Clients/createWithUser"
|
||||||
>
|
>
|
||||||
|
@ -94,7 +82,7 @@ function handleLocation(data, location) {
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<QInput
|
<QInput
|
||||||
:label="t('Business name')"
|
:label="t('Business name')"
|
||||||
:rules="validate('Client.socialName')"
|
:rules="validate('client.socialName')"
|
||||||
v-model="data.socialName"
|
v-model="data.socialName"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -103,7 +91,7 @@ function handleLocation(data, location) {
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<QInput
|
<QInput
|
||||||
:label="t('Street')"
|
:label="t('Street')"
|
||||||
:rules="validate('Client.street')"
|
:rules="validate('client.street')"
|
||||||
v-model="data.street"
|
v-model="data.street"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -128,12 +116,26 @@ function handleLocation(data, location) {
|
||||||
<QInput v-model="data.userName" :label="t('Web user')" />
|
<QInput v-model="data.userName" :label="t('Web user')" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<QInput v-model="data.email" :label="t('Email')" />
|
<QInput
|
||||||
|
:label="t('Email')"
|
||||||
|
:rules="validate('client.email')"
|
||||||
|
clearable
|
||||||
|
type="email"
|
||||||
|
v-model="data.email"
|
||||||
|
>
|
||||||
|
<template #append>
|
||||||
|
<QIcon name="info" class="cursor-info">
|
||||||
|
<QTooltip max-width="400px">{{
|
||||||
|
t('customer.basicData.youCanSaveMultipleEmails')
|
||||||
|
}}</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
</template>
|
||||||
|
</QInput>
|
||||||
</div>
|
</div>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
<QCheckbox
|
<QCheckbox
|
||||||
:label="t('Is equalizated')"
|
:label="t('Is equalizated')"
|
||||||
v-model="newClientForm.isEqualizated"
|
v-model="initialData.isEqualizated"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</FormModel>
|
</FormModel>
|
||||||
|
|
|
@ -1,56 +1,52 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onBeforeMount } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import { QBtn, QCheckbox, useQuasar } from 'quasar';
|
import { QBtn, QCheckbox, useQuasar } from 'quasar';
|
||||||
|
|
||||||
import { toCurrency, toDate } from 'filters/index';
|
import { toCurrency, toDate } from 'filters/index';
|
||||||
import { useArrayData } from 'composables/useArrayData';
|
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
|
||||||
|
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
import CustomerNotificationsFilter from './CustomerDefaulterFilter.vue';
|
import CustomerNotificationsFilter from './CustomerDefaulterFilter.vue';
|
||||||
import CustomerBalanceDueTotal from './CustomerBalanceDueTotal.vue';
|
import CustomerBalanceDueTotal from './CustomerBalanceDueTotal.vue';
|
||||||
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
|
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
|
||||||
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
||||||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
||||||
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
import CustomerDefaulterAddObservation from './CustomerDefaulterAddObservation.vue';
|
import CustomerDefaulterAddObservation from './CustomerDefaulterAddObservation.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const stateStore = useStateStore();
|
|
||||||
const quasar = useQuasar();
|
const quasar = useQuasar();
|
||||||
|
|
||||||
const arrayData = ref(null);
|
|
||||||
const balanceDueTotal = ref(0);
|
const balanceDueTotal = ref(0);
|
||||||
const customerId = ref(0);
|
|
||||||
const selected = ref([]);
|
const selected = ref([]);
|
||||||
const workerId = ref(0);
|
const rows = ref([]);
|
||||||
|
|
||||||
const rows = computed(() => arrayData.value.store.data);
|
|
||||||
|
|
||||||
const tableColumnComponents = {
|
const tableColumnComponents = {
|
||||||
client: {
|
client: {
|
||||||
component: QBtn,
|
component: QBtn,
|
||||||
props: () => ({ flat: true, color: 'blue' }),
|
props: () => ({ flat: true, color: 'blue', noCaps: true }),
|
||||||
event: ({ row }) => selectCustomerId(row.clientFk),
|
event: () => {},
|
||||||
},
|
},
|
||||||
isWorker: {
|
isWorker: {
|
||||||
component: QCheckbox,
|
component: QCheckbox,
|
||||||
props: ({ row }) => ({
|
props: (prop) => ({
|
||||||
disable: true,
|
disable: true,
|
||||||
'model-value': Boolean(row.selected),
|
'model-value': Boolean(prop.value),
|
||||||
}),
|
}),
|
||||||
|
event: () => {},
|
||||||
},
|
},
|
||||||
salesperson: {
|
salesPerson: {
|
||||||
component: QBtn,
|
component: QBtn,
|
||||||
props: () => ({ flat: true, color: 'blue' }),
|
props: () => ({ flat: true, color: 'blue', noCaps: true }),
|
||||||
event: ({ row }) => selectWorkerId(row.salesPersonFk),
|
event: () => {},
|
||||||
},
|
},
|
||||||
country: {
|
country: {
|
||||||
component: 'span',
|
component: 'span',
|
||||||
props: () => {},
|
props: () => {},
|
||||||
event: () => {},
|
event: () => {},
|
||||||
},
|
},
|
||||||
paymentMethod: {
|
payMethod: {
|
||||||
component: 'span',
|
component: 'span',
|
||||||
props: () => {},
|
props: () => {},
|
||||||
event: () => {},
|
event: () => {},
|
||||||
|
@ -62,8 +58,8 @@ const tableColumnComponents = {
|
||||||
},
|
},
|
||||||
author: {
|
author: {
|
||||||
component: QBtn,
|
component: QBtn,
|
||||||
props: () => ({ flat: true, color: 'blue' }),
|
props: () => ({ flat: true, color: 'blue', noCaps: true }),
|
||||||
event: ({ row }) => selectWorkerId(row.workerFk),
|
event: () => {},
|
||||||
},
|
},
|
||||||
lastObservation: {
|
lastObservation: {
|
||||||
component: 'span',
|
component: 'span',
|
||||||
|
@ -93,6 +89,7 @@ const columns = computed(() => [
|
||||||
field: 'clientName',
|
field: 'clientName',
|
||||||
label: t('Client'),
|
label: t('Client'),
|
||||||
name: 'client',
|
name: 'client',
|
||||||
|
sortable: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
@ -104,85 +101,77 @@ const columns = computed(() => [
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: 'salesPersonName',
|
field: 'salesPersonName',
|
||||||
label: t('Salesperson'),
|
label: t('Salesperson'),
|
||||||
name: 'salesperson',
|
name: 'salesPerson',
|
||||||
|
sortable: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: 'country',
|
field: 'country',
|
||||||
label: t('Country'),
|
label: t('Country'),
|
||||||
name: 'country',
|
name: 'country',
|
||||||
|
sortable: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: 'payMethod',
|
field: 'payMethod',
|
||||||
label: t('P. Method'),
|
label: t('P. Method'),
|
||||||
name: 'paymentMethod',
|
name: 'payMethod',
|
||||||
|
sortable: true,
|
||||||
|
tooltip: t('Pay method'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: ({ amount }) => toCurrency(amount),
|
field: ({ amount }) => toCurrency(amount),
|
||||||
label: t('Balance D.'),
|
label: t('Balance D.'),
|
||||||
name: 'balance',
|
name: 'balance',
|
||||||
|
sortable: true,
|
||||||
|
tooltip: t('Balance due'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: 'workerName',
|
field: 'workerName',
|
||||||
label: t('Author'),
|
label: t('Author'),
|
||||||
name: 'author',
|
name: 'author',
|
||||||
|
sortable: true,
|
||||||
|
tooltip: t('Worker who made the last observation'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: 'observation',
|
field: 'observation',
|
||||||
label: t('Last observation'),
|
label: t('Last observation'),
|
||||||
name: 'lastObservation',
|
name: 'lastObservation',
|
||||||
|
sortable: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: ({ created }) => toDate(created),
|
field: ({ created }) => toDate(created),
|
||||||
label: t('L. O. Date'),
|
label: t('L. O. Date'),
|
||||||
name: 'date',
|
name: 'date',
|
||||||
|
sortable: true,
|
||||||
|
tooltip: t('Last observation date'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: ({ creditInsurance }) => toCurrency(creditInsurance),
|
field: ({ creditInsurance }) => toCurrency(creditInsurance),
|
||||||
label: t('Credit I.'),
|
label: t('Credit I.'),
|
||||||
name: 'credit',
|
name: 'credit',
|
||||||
|
sortable: true,
|
||||||
|
tooltip: t('Credit insurance'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: ({ defaulterSinced }) => toDate(defaulterSinced),
|
field: ({ defaulterSinced }) => toDate(defaulterSinced),
|
||||||
label: t('From'),
|
label: t('From'),
|
||||||
name: 'from',
|
name: 'from',
|
||||||
|
sortable: true,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
onBeforeMount(() => {
|
const setRows = (data) => {
|
||||||
getArrayData();
|
rows.value = data;
|
||||||
});
|
balanceDueTotal.value = data.reduce((accumulator, currentValue) => {
|
||||||
|
return accumulator + (currentValue['amount'] || 0);
|
||||||
const getArrayData = async () => {
|
}, 0);
|
||||||
arrayData.value = useArrayData('CustomerDefaulter', {
|
|
||||||
url: 'Defaulters/filter',
|
|
||||||
limit: 0,
|
|
||||||
});
|
|
||||||
await arrayData.value.fetch({ append: false });
|
|
||||||
balanceDueTotal.value = arrayData.value.store.data.reduce(
|
|
||||||
(accumulator, currentValue) => {
|
|
||||||
return accumulator + (currentValue['amount'] || 0);
|
|
||||||
},
|
|
||||||
0
|
|
||||||
);
|
|
||||||
stateStore.rightDrawer = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const selectCustomerId = (id) => {
|
|
||||||
workerId.value = 0;
|
|
||||||
customerId.value = id;
|
|
||||||
};
|
|
||||||
|
|
||||||
const selectWorkerId = (id) => {
|
|
||||||
customerId.value = 0;
|
|
||||||
workerId.value = id;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const viewAddObservation = (rowsSelected) => {
|
const viewAddObservation = (rowsSelected) => {
|
||||||
|
@ -196,12 +185,21 @@ const viewAddObservation = (rowsSelected) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const refreshData = () => {
|
const refreshData = () => {
|
||||||
getArrayData();
|
setRows();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onFetch = (data) => {
|
||||||
|
for (const element of data) {
|
||||||
|
element.isWorker = element.businessTypeFk === 'worker';
|
||||||
|
}
|
||||||
|
rows.value = data;
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<QDrawer v-model="stateStore.rightDrawer" side="right" :width="256" show-if-above>
|
<FetchData :filter="filter" @on-fetch="onFetch" auto-load url="Defaulters/filter" />
|
||||||
|
|
||||||
|
<QDrawer side="right" :width="256" show-if-above>
|
||||||
<QScrollArea class="fit text-grey-8">
|
<QScrollArea class="fit text-grey-8">
|
||||||
<CustomerNotificationsFilter data-key="CustomerDefaulter" />
|
<CustomerNotificationsFilter data-key="CustomerDefaulter" />
|
||||||
</QScrollArea>
|
</QScrollArea>
|
||||||
|
@ -230,6 +228,18 @@ const refreshData = () => {
|
||||||
selection="multiple"
|
selection="multiple"
|
||||||
v-model:selected="selected"
|
v-model:selected="selected"
|
||||||
>
|
>
|
||||||
|
<template #header="props">
|
||||||
|
<QTr :props="props" class="bg">
|
||||||
|
<QTh>
|
||||||
|
<QCheckbox v-model="props.selected" />
|
||||||
|
</QTh>
|
||||||
|
<QTh v-for="col in props.cols" :key="col.name" :props="props">
|
||||||
|
{{ t(col.label) }}
|
||||||
|
<QTooltip v-if="col.tooltip">{{ col.tooltip }}</QTooltip>
|
||||||
|
</QTh>
|
||||||
|
</QTr>
|
||||||
|
</template>
|
||||||
|
|
||||||
<template #body-cell="props">
|
<template #body-cell="props">
|
||||||
<QTd :props="props">
|
<QTd :props="props">
|
||||||
<QTr :props="props" class="cursor-pointer">
|
<QTr :props="props" class="cursor-pointer">
|
||||||
|
@ -239,10 +249,29 @@ const refreshData = () => {
|
||||||
v-bind="tableColumnComponents[props.col.name].props(props)"
|
v-bind="tableColumnComponents[props.col.name].props(props)"
|
||||||
@click="tableColumnComponents[props.col.name].event(props)"
|
@click="tableColumnComponents[props.col.name].event(props)"
|
||||||
>
|
>
|
||||||
{{ props.value }}
|
<template v-if="props.col.name !== 'isWorker'">
|
||||||
|
<div v-if="props.col.name === 'lastObservation'">
|
||||||
|
<VnInput
|
||||||
|
type="textarea"
|
||||||
|
v-model="props.value"
|
||||||
|
autogrow
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-else>{{ props.value }}</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<WorkerDescriptorProxy v-if="workerId" :id="workerId" />
|
<WorkerDescriptorProxy
|
||||||
<CustomerDescriptorProxy v-else :id="customerId" />
|
:id="props.row.salesPersonFk"
|
||||||
|
v-if="props.col.name === 'salesPerson'"
|
||||||
|
/>
|
||||||
|
<WorkerDescriptorProxy
|
||||||
|
:id="props.row.workerFk"
|
||||||
|
v-if="props.col.name === 'author'"
|
||||||
|
/>
|
||||||
|
<CustomerDescriptorProxy
|
||||||
|
:id="props.row.clientFk"
|
||||||
|
v-if="props.col.name === 'client'"
|
||||||
|
/>
|
||||||
</component>
|
</component>
|
||||||
</QTr>
|
</QTr>
|
||||||
</QTd>
|
</QTd>
|
||||||
|
@ -265,10 +294,15 @@ es:
|
||||||
Salesperson: Comercial
|
Salesperson: Comercial
|
||||||
Country: País
|
Country: País
|
||||||
P. Method: F. Pago
|
P. Method: F. Pago
|
||||||
|
Pay method: Forma de pago
|
||||||
Balance D.: Saldo V.
|
Balance D.: Saldo V.
|
||||||
|
Balance due: Saldo vencido
|
||||||
Author: Autor
|
Author: Autor
|
||||||
|
Worker who made the last observation: Trabajador que ha realizado la última observación
|
||||||
Last observation: Última observación
|
Last observation: Última observación
|
||||||
L. O. Date: Fecha Ú. O.
|
L. O. Date: Fecha Ú. O.
|
||||||
|
Last observation date: Fecha última observación
|
||||||
Credit I.: Crédito A.
|
Credit I.: Crédito A.
|
||||||
|
Credit insurance: Crédito asegurado
|
||||||
From: Desde
|
From: Desde
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|
|
@ -3,7 +3,9 @@ import { ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { useQuasar } from 'quasar';
|
import { useDialogPluginComponent } from 'quasar';
|
||||||
|
|
||||||
|
import useNotify from 'src/composables/useNotify';
|
||||||
|
|
||||||
import VnRow from 'components/ui/VnRow.vue';
|
import VnRow from 'components/ui/VnRow.vue';
|
||||||
|
|
||||||
|
@ -18,8 +20,9 @@ const $props = defineProps({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { dialogRef } = useDialogPluginComponent();
|
||||||
|
const { notify } = useNotify();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const quasar = useQuasar();
|
|
||||||
|
|
||||||
const newObservation = ref(null);
|
const newObservation = ref(null);
|
||||||
|
|
||||||
|
@ -38,15 +41,9 @@ const onSubmit = async () => {
|
||||||
|
|
||||||
await $props.promise();
|
await $props.promise();
|
||||||
|
|
||||||
quasar.notify({
|
notify('globals.dataSaved', 'positive');
|
||||||
message: t('globals.dataSaved'),
|
|
||||||
type: 'positive',
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
quasar.notify({
|
notify(error.message, 'negative');
|
||||||
message: t(`${error.message}`),
|
|
||||||
type: 'negative',
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -119,6 +119,7 @@ const authors = ref();
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<VnInput
|
<VnInput
|
||||||
:label="t('P. Method')"
|
:label="t('P. Method')"
|
||||||
|
clearable
|
||||||
is-outlined
|
is-outlined
|
||||||
v-model="params.paymentMethod"
|
v-model="params.paymentMethod"
|
||||||
/>
|
/>
|
||||||
|
@ -129,6 +130,7 @@ const authors = ref();
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<VnInput
|
<VnInput
|
||||||
:label="t('Balance D.')"
|
:label="t('Balance D.')"
|
||||||
|
clearable
|
||||||
is-outlined
|
is-outlined
|
||||||
v-model="params.balance"
|
v-model="params.balance"
|
||||||
/>
|
/>
|
||||||
|
@ -160,7 +162,12 @@ const authors = ref();
|
||||||
|
|
||||||
<QItem class="q-mb-sm">
|
<QItem class="q-mb-sm">
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<VnInput :label="t('L. O. Date')" is-outlined v-model="params.date" />
|
<VnInput
|
||||||
|
:label="t('L. O. Date')"
|
||||||
|
clearable
|
||||||
|
is-outlined
|
||||||
|
v-model="params.date"
|
||||||
|
/>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
|
|
||||||
|
@ -168,6 +175,7 @@ const authors = ref();
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<VnInput
|
<VnInput
|
||||||
:label="t('Credit I.')"
|
:label="t('Credit I.')"
|
||||||
|
clearable
|
||||||
is-outlined
|
is-outlined
|
||||||
v-model="params.credit"
|
v-model="params.credit"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,32 +1,17 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onBeforeMount } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import { QBtn } from 'quasar';
|
import { QBtn } from 'quasar';
|
||||||
|
|
||||||
import { useArrayData } from 'composables/useArrayData';
|
import FetchData from 'components/FetchData.vue';
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
|
||||||
|
|
||||||
import CustomerNotificationsFilter from './CustomerNotificationsFilter.vue';
|
import CustomerNotificationsFilter from './CustomerNotificationsFilter.vue';
|
||||||
import CustomerDescriptorProxy from '../Card/CustomerDescriptorProxy.vue';
|
import CustomerDescriptorProxy from '../Card/CustomerDescriptorProxy.vue';
|
||||||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const stateStore = useStateStore();
|
|
||||||
|
|
||||||
const arrayData = ref(null);
|
|
||||||
|
|
||||||
onBeforeMount(async () => {
|
|
||||||
arrayData.value = useArrayData('CustomerNotifications', {
|
|
||||||
url: 'Clients',
|
|
||||||
limit: 0,
|
|
||||||
});
|
|
||||||
await arrayData.value.fetch({ append: false });
|
|
||||||
stateStore.rightDrawer = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
const rows = computed(() => arrayData.value.store.data);
|
|
||||||
|
|
||||||
|
const rows = ref([]);
|
||||||
const selected = ref([]);
|
const selected = ref([]);
|
||||||
const selectedCustomerId = ref(0);
|
const selectedCustomerId = ref(0);
|
||||||
|
|
||||||
|
@ -97,7 +82,14 @@ const selectCustomerId = (id) => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<QDrawer v-model="stateStore.rightDrawer" side="right" :width="256" show-if-above>
|
<FetchData
|
||||||
|
:filter="filter"
|
||||||
|
@on-fetch="(data) => (rows = data)"
|
||||||
|
auto-load
|
||||||
|
url="Clients"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<QDrawer side="right" :width="256" show-if-above>
|
||||||
<QScrollArea class="fit text-grey-8">
|
<QScrollArea class="fit text-grey-8">
|
||||||
<CustomerNotificationsFilter data-key="CustomerNotifications" />
|
<CustomerNotificationsFilter data-key="CustomerNotifications" />
|
||||||
</QScrollArea>
|
</QScrollArea>
|
||||||
|
|
|
@ -40,6 +40,7 @@ const clients = ref();
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<VnInput
|
<VnInput
|
||||||
:label="t('Identifier')"
|
:label="t('Identifier')"
|
||||||
|
clearable
|
||||||
is-outlined
|
is-outlined
|
||||||
v-model="params.identifier"
|
v-model="params.identifier"
|
||||||
/>
|
/>
|
||||||
|
@ -96,13 +97,24 @@ const clients = ref();
|
||||||
|
|
||||||
<QItem class="q-mb-sm">
|
<QItem class="q-mb-sm">
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<VnInput :label="t('Phone')" is-outlined v-model="params.phone" />
|
<VnInput
|
||||||
|
:label="t('Phone')"
|
||||||
|
clearable
|
||||||
|
is-outlined
|
||||||
|
v-model="params.phone"
|
||||||
|
/>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
|
|
||||||
<QItem class="q-mb-sm">
|
<QItem class="q-mb-sm">
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<VnInput :label="t('Email')" is-outlined v-model="params.email" />
|
<VnInput
|
||||||
|
:label="t('Email')"
|
||||||
|
clearable
|
||||||
|
is-outlined
|
||||||
|
type="email"
|
||||||
|
v-model="params.email"
|
||||||
|
/>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
<QSeparator />
|
<QSeparator />
|
||||||
|
|
|
@ -41,9 +41,9 @@ const refreshData = () => {
|
||||||
getCustomsAgents();
|
getCustomsAgents();
|
||||||
};
|
};
|
||||||
|
|
||||||
const toCustomerConsignees = () => {
|
const toCustomerAddress = () => {
|
||||||
router.push({
|
router.push({
|
||||||
name: 'CustomerConsignees',
|
name: 'CustomerAddress',
|
||||||
params: {
|
params: {
|
||||||
id: route.params.id,
|
id: route.params.id,
|
||||||
},
|
},
|
||||||
|
@ -70,84 +70,78 @@ function handleLocation(data, location) {
|
||||||
:form-initial-data="formInitialData"
|
:form-initial-data="formInitialData"
|
||||||
:observe-form-changes="false"
|
:observe-form-changes="false"
|
||||||
:url-create="urlCreate"
|
:url-create="urlCreate"
|
||||||
@on-data-saved="toCustomerConsignees()"
|
@on-data-saved="toCustomerAddress()"
|
||||||
model="client"
|
model="client"
|
||||||
>
|
>
|
||||||
|
<template #moreActions>
|
||||||
|
<QBtn
|
||||||
|
:label="t('globals.cancel')"
|
||||||
|
@click="toCustomerAddress"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
icon="close"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
<template #form="{ data, validate }">
|
<template #form="{ data, validate }">
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<QCheckbox :label="t('Default')" v-model="data.isDefaultAddress" />
|
||||||
<div class="col">
|
|
||||||
<QCheckbox :label="t('Default')" v-model="data.isDefaultAddress" />
|
|
||||||
</div>
|
|
||||||
</VnRow>
|
|
||||||
|
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<VnInput :label="t('Consignee')" clearable v-model="data.nickname" />
|
||||||
<VnInput :label="t('Consignee')" v-model="data.nickname" />
|
|
||||||
</div>
|
<VnInput :label="t('Street address')" clearable v-model="data.street" />
|
||||||
<div class="col">
|
|
||||||
<VnInput :label="t('Street address')" v-model="data.street" />
|
|
||||||
</div>
|
|
||||||
</VnRow>
|
</VnRow>
|
||||||
|
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<VnLocation
|
||||||
<div class="col">
|
:rules="validate('Worker.postcode')"
|
||||||
<VnLocation
|
:roles-allowed-to-create="['deliveryAssistant']"
|
||||||
:rules="validate('Worker.postcode')"
|
:options="postcodesOptions"
|
||||||
:roles-allowed-to-create="['deliveryAssistant']"
|
v-model="data.location"
|
||||||
:options="postcodesOptions"
|
@update:model-value="(location) => handleLocation(data, location)"
|
||||||
v-model="data.location"
|
/>
|
||||||
@update:model-value="(location) => handleLocation(data, location)"
|
|
||||||
></VnLocation>
|
<div class="row justify-between q-gutter-md q-mb-md">
|
||||||
</div>
|
<VnSelectFilter
|
||||||
</VnRow>
|
:label="t('Agency')"
|
||||||
|
:options="agencyModes"
|
||||||
|
:rules="validate('route.agencyFk')"
|
||||||
|
hide-selected
|
||||||
|
option-label="name"
|
||||||
|
option-value="id"
|
||||||
|
v-model="data.agencyModeFk"
|
||||||
|
class="col"
|
||||||
|
/>
|
||||||
|
<VnInput class="col" :label="t('Phone')" clearable v-model="data.phone" />
|
||||||
|
<VnInput
|
||||||
|
class="col"
|
||||||
|
:label="t('Mobile')"
|
||||||
|
clearable
|
||||||
|
v-model="data.mobile"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<VnSelectFilter
|
||||||
<VnSelectFilter
|
:label="t('Incoterms')"
|
||||||
:label="t('Agency')"
|
:options="incoterms"
|
||||||
:options="agencyModes"
|
hide-selected
|
||||||
hide-selected
|
option-label="name"
|
||||||
option-label="name"
|
option-value="code"
|
||||||
option-value="id"
|
v-model="data.incotermsFk"
|
||||||
v-model="data.agencyModeFk"
|
/>
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</VnRow>
|
|
||||||
|
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<VnSelectDialog
|
||||||
<div class="col">
|
:label="t('Customs agent')"
|
||||||
<VnInput :label="t('Phone')" v-model="data.phone" />
|
:options="customsAgents"
|
||||||
</div>
|
hide-selected
|
||||||
<div class="col">
|
option-label="fiscalName"
|
||||||
<VnInput :label="t('Mobile')" v-model="data.mobile" />
|
option-value="id"
|
||||||
</div>
|
v-model="data.customsAgentFk"
|
||||||
</VnRow>
|
>
|
||||||
|
<template #form>
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<CustomerNewCustomsAgent @on-data-saved="refreshData()" />
|
||||||
<div class="col">
|
</template>
|
||||||
<VnSelectFilter
|
</VnSelectDialog>
|
||||||
:label="t('Incoterms')"
|
|
||||||
:options="incoterms"
|
|
||||||
hide-selected
|
|
||||||
option-label="name"
|
|
||||||
option-value="code"
|
|
||||||
v-model="data.incotermsFk"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="col">
|
|
||||||
<VnSelectDialog
|
|
||||||
:label="t('Customs agent')"
|
|
||||||
:options="customsAgents"
|
|
||||||
hide-selected
|
|
||||||
option-label="fiscalName"
|
|
||||||
option-value="id"
|
|
||||||
v-model="data.customsAgentFk"
|
|
||||||
>
|
|
||||||
<template #form>
|
|
||||||
<CustomerNewCustomsAgent @on-data-saved="refreshData()" />
|
|
||||||
</template>
|
|
||||||
</VnSelectDialog>
|
|
||||||
</div>
|
|
||||||
</VnRow>
|
</VnRow>
|
||||||
</template>
|
</template>
|
||||||
</FormModel>
|
</FormModel>
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onBeforeMount, ref } from 'vue';
|
import { onBeforeMount, ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import VnLocation from 'src/components/common/VnLocation.vue';
|
import VnLocation from 'src/components/common/VnLocation.vue';
|
||||||
|
@ -16,6 +16,7 @@ import CustomsNewCustomsAgent from 'src/pages/Customer/components/CustomerNewCus
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
const urlUpdate = ref('');
|
const urlUpdate = ref('');
|
||||||
const postcodesOptions = ref([]);
|
const postcodesOptions = ref([]);
|
||||||
|
@ -24,9 +25,10 @@ const incoterms = ref([]);
|
||||||
const customsAgents = ref([]);
|
const customsAgents = ref([]);
|
||||||
const observationTypes = ref([]);
|
const observationTypes = ref([]);
|
||||||
const notes = ref([]);
|
const notes = ref([]);
|
||||||
|
const deletes = ref([]);
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
urlUpdate.value = `Clients/${route.params.id}/updateAddress/${route.params.consigneeId}`;
|
urlUpdate.value = `Clients/${route.params.id}/updateAddress/${route.params.addressId}`;
|
||||||
});
|
});
|
||||||
|
|
||||||
const getData = async (observations) => {
|
const getData = async (observations) => {
|
||||||
|
@ -35,7 +37,7 @@ const getData = async (observations) => {
|
||||||
if (observationTypes.value.length) {
|
if (observationTypes.value.length) {
|
||||||
const filter = {
|
const filter = {
|
||||||
fields: ['id', 'addressFk', 'observationTypeFk', 'description'],
|
fields: ['id', 'addressFk', 'observationTypeFk', 'description'],
|
||||||
where: { addressFk: `${route.params.consigneeId}` },
|
where: { addressFk: `${route.params.addressId}` },
|
||||||
};
|
};
|
||||||
const { data } = await axios.get('AddressObservations', {
|
const { data } = await axios.get('AddressObservations', {
|
||||||
params: { filter: JSON.stringify(filter) },
|
params: { filter: JSON.stringify(filter) },
|
||||||
|
@ -52,8 +54,9 @@ const getData = async (observations) => {
|
||||||
$isNew: false,
|
$isNew: false,
|
||||||
$oldData: null,
|
$oldData: null,
|
||||||
$orgIndex: null,
|
$orgIndex: null,
|
||||||
addressFk: `${route.params.consigneeId}`,
|
addressFk: `${route.params.addressId}`,
|
||||||
description: observation.description,
|
description: observation.description,
|
||||||
|
id: observation.id,
|
||||||
observationTypeFk: type.id,
|
observationTypeFk: type.id,
|
||||||
}
|
}
|
||||||
: null;
|
: null;
|
||||||
|
@ -68,21 +71,39 @@ const addNote = () => {
|
||||||
$isNew: true,
|
$isNew: true,
|
||||||
$oldData: null,
|
$oldData: null,
|
||||||
$orgIndex: null,
|
$orgIndex: null,
|
||||||
addressFk: `${route.params.consigneeId}`,
|
addressFk: `${route.params.addressId}`,
|
||||||
description: '',
|
description: '',
|
||||||
observationTypeFk: '',
|
observationTypeFk: '',
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteNote = (index) => {
|
const deleteNote = (id, index) => {
|
||||||
|
deletes.value.push(id);
|
||||||
notes.value.splice(index, 1);
|
notes.value.splice(index, 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onDataSaved = () => {
|
const onDataSaved = async () => {
|
||||||
const payload = {
|
let payload = {};
|
||||||
creates: notes.value,
|
const creates = notes.value.filter((note) => note.$isNew);
|
||||||
};
|
if (creates.length) {
|
||||||
axios.post('AddressObservations/crud', payload);
|
payload.creates = creates;
|
||||||
|
}
|
||||||
|
if (deletes.value.length) {
|
||||||
|
payload.deletes = deletes.value;
|
||||||
|
}
|
||||||
|
await axios.post('AddressObservations/crud', payload);
|
||||||
|
notes.value = [];
|
||||||
|
deletes.value = [];
|
||||||
|
toCustomerAddress();
|
||||||
|
};
|
||||||
|
|
||||||
|
const toCustomerAddress = () => {
|
||||||
|
router.push({
|
||||||
|
name: 'CustomerAddress',
|
||||||
|
params: {
|
||||||
|
id: route.params.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
};
|
};
|
||||||
function handleLocation(data, location) {
|
function handleLocation(data, location) {
|
||||||
const { town, code, provinceFk, countryFk } = location ?? {};
|
const { town, code, provinceFk, countryFk } = location ?? {};
|
||||||
|
@ -110,11 +131,21 @@ function handleLocation(data, location) {
|
||||||
<FormModel
|
<FormModel
|
||||||
:observe-form-changes="false"
|
:observe-form-changes="false"
|
||||||
:url-update="urlUpdate"
|
:url-update="urlUpdate"
|
||||||
:url="`Addresses/${route.params.consigneeId}`"
|
:url="`Addresses/${route.params.addressId}`"
|
||||||
@on-data-saved="onDataSaved()"
|
@on-data-saved="onDataSaved()"
|
||||||
auto-load
|
auto-load
|
||||||
model="client"
|
model="client"
|
||||||
>
|
>
|
||||||
|
<template #moreActions>
|
||||||
|
<QBtn
|
||||||
|
:label="t('globals.cancel')"
|
||||||
|
@click="toCustomerAddress"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
icon="close"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
<template #form="{ data, validate }">
|
<template #form="{ data, validate }">
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
|
@ -136,10 +167,10 @@ function handleLocation(data, location) {
|
||||||
|
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<VnInput :label="t('Consignee')" v-model="data.nickname" />
|
<VnInput :label="t('Consignee')" clearable v-model="data.nickname" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<VnInput :label="t('Street address')" v-model="data.street" />
|
<VnInput :label="t('Street')" clearable v-model="data.street" />
|
||||||
</div>
|
</div>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
|
|
||||||
|
@ -153,27 +184,22 @@ function handleLocation(data, location) {
|
||||||
@update:model-value="(location) => handleLocation(data, location)"
|
@update:model-value="(location) => handleLocation(data, location)"
|
||||||
></VnLocation>
|
></VnLocation>
|
||||||
</div>
|
</div>
|
||||||
</VnRow>
|
|
||||||
|
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<VnSelectFilter
|
<VnSelectFilter
|
||||||
:label="t('Agency')"
|
:label="t('Agency')"
|
||||||
:options="agencyModes"
|
:options="agencyModes"
|
||||||
|
:rules="validate('route.agencyFk')"
|
||||||
hide-selected
|
hide-selected
|
||||||
option-label="name"
|
option-label="name"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
v-model="data.agencyModeFk"
|
v-model="data.agencyModeFk"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</VnRow>
|
|
||||||
|
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<VnInput :label="t('Phone')" v-model="data.phone" />
|
<VnInput :label="t('Phone')" clearable v-model="data.phone" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<VnInput :label="t('Mobile')" v-model="data.mobile" />
|
<VnInput :label="t('Mobile')" clearable v-model="data.mobile" />
|
||||||
</div>
|
</div>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
|
|
||||||
|
@ -221,18 +247,23 @@ function handleLocation(data, location) {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<VnInput :label="t('Description')" v-model="note.description" />
|
<VnInput
|
||||||
|
:label="t('Description')"
|
||||||
|
:rules="validate('route.description')"
|
||||||
|
clearable
|
||||||
|
v-model="note.description"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<QIcon
|
<QIcon
|
||||||
@click.stop="deleteNote(index)"
|
@click.stop="deleteNote(note.id, index)"
|
||||||
class="cursor-pointer"
|
class="cursor-pointer"
|
||||||
color="primary"
|
color="primary"
|
||||||
name="delete"
|
name="delete"
|
||||||
size="sm"
|
size="sm"
|
||||||
>
|
>
|
||||||
<QTooltip>
|
<QTooltip>
|
||||||
{{ t('Remove') }}
|
{{ t('Remove note') }}
|
||||||
</QTooltip>
|
</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
</div>
|
</div>
|
||||||
|
@ -265,7 +296,7 @@ es:
|
||||||
Is equalizated: Recargo de equivalencia
|
Is equalizated: Recargo de equivalencia
|
||||||
Is Loginflora allowed: Compra directa en Holanda
|
Is Loginflora allowed: Compra directa en Holanda
|
||||||
Consignee: Consignatario
|
Consignee: Consignatario
|
||||||
Street address: Dirección postal
|
Street: Dirección fiscal
|
||||||
Postcode: Código postal
|
Postcode: Código postal
|
||||||
City: Población
|
City: Población
|
||||||
Province: Provincia
|
Province: Provincia
|
|
@ -0,0 +1,140 @@
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import axios from 'axios';
|
||||||
|
import { useDialogPluginComponent } from 'quasar';
|
||||||
|
|
||||||
|
import useNotify from 'src/composables/useNotify';
|
||||||
|
|
||||||
|
import VnRow from 'components/ui/VnRow.vue';
|
||||||
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
|
||||||
|
const { dialogRef } = useDialogPluginComponent();
|
||||||
|
const { notify } = useNotify();
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const $props = defineProps({
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
userPasswords: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
promise: {
|
||||||
|
type: Function,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const closeButton = ref(null);
|
||||||
|
const isLoading = ref(false);
|
||||||
|
const newPassword = ref('');
|
||||||
|
const requestPassword = ref('');
|
||||||
|
|
||||||
|
const onSubmit = async () => {
|
||||||
|
isLoading.value = true;
|
||||||
|
|
||||||
|
if (newPassword.value !== requestPassword.value) {
|
||||||
|
notify(t("Passwords don't match"), 'negative');
|
||||||
|
isLoading.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
newPassword: newPassword.value,
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
await axios.patch(`Clients/${$props.id}/setPassword`, payload);
|
||||||
|
await $props.promise();
|
||||||
|
} catch (error) {
|
||||||
|
notify('errors.create', 'negative');
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false;
|
||||||
|
if (closeButton.value) closeButton.value.click();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<QDialog ref="dialogRef">
|
||||||
|
<QCard class="q-pa-lg">
|
||||||
|
<QCardSection>
|
||||||
|
<QForm @submit.prevent="onSubmit">
|
||||||
|
<span
|
||||||
|
ref="closeButton"
|
||||||
|
class="row justify-end close-icon"
|
||||||
|
v-close-popup
|
||||||
|
>
|
||||||
|
<QIcon name="close" size="sm" />
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
|
<div class="col">
|
||||||
|
<VnInput
|
||||||
|
:label="t('New password')"
|
||||||
|
clearable
|
||||||
|
v-model="newPassword"
|
||||||
|
type="password"
|
||||||
|
>
|
||||||
|
<template #append>
|
||||||
|
<QIcon name="info" class="cursor-info">
|
||||||
|
<QTooltip>
|
||||||
|
{{
|
||||||
|
t('customer.card.passwordRequirements', {
|
||||||
|
length: $props.userPasswords.length,
|
||||||
|
nAlpha: $props.userPasswords.nAlpha,
|
||||||
|
nDigits: $props.userPasswords.nDigits,
|
||||||
|
nPunct: $props.userPasswords.nPunct,
|
||||||
|
nUpper: $props.userPasswords.nUpper,
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
</template>
|
||||||
|
</VnInput>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<VnInput
|
||||||
|
:label="t('Request password')"
|
||||||
|
clearable
|
||||||
|
v-model="requestPassword"
|
||||||
|
type="password"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</VnRow>
|
||||||
|
|
||||||
|
<div class="q-mt-lg row justify-end">
|
||||||
|
<QBtn
|
||||||
|
:disabled="isLoading"
|
||||||
|
:label="t('globals.cancel')"
|
||||||
|
:loading="isLoading"
|
||||||
|
class="q-ml-sm"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
type="reset"
|
||||||
|
v-close-popup
|
||||||
|
/>
|
||||||
|
<QBtn
|
||||||
|
:disabled="isLoading"
|
||||||
|
:label="t('Change password')"
|
||||||
|
:loading="isLoading"
|
||||||
|
color="primary"
|
||||||
|
type="submit"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</QForm>
|
||||||
|
</QCardSection>
|
||||||
|
</QCard>
|
||||||
|
</QDialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
New password: Nueva contraseña
|
||||||
|
Request password: Repetir contraseña
|
||||||
|
Change password: Cambiar contraseña
|
||||||
|
Passwords don't match: Las contraseñas no coinciden
|
||||||
|
</i18n>
|
|
@ -0,0 +1,47 @@
|
||||||
|
<script setup>
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const $props = defineProps({
|
||||||
|
transaction: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
promise: {
|
||||||
|
type: Function,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const setClientsConfirmTransaction = async () => {
|
||||||
|
try {
|
||||||
|
const payload = { id: $props.transaction.id };
|
||||||
|
await axios.post('Clients/confirmTransaction', payload);
|
||||||
|
$props.promise();
|
||||||
|
} catch (error) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div v-if="!$props?.transaction?.isConfirmed">
|
||||||
|
<QIcon
|
||||||
|
@click.stop="setClientsConfirmTransaction"
|
||||||
|
color="primary"
|
||||||
|
name="done_all"
|
||||||
|
size="sm"
|
||||||
|
class="cursor-pointer"
|
||||||
|
>
|
||||||
|
<QTooltip>{{ t('Confirm transaction') }}</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
Confirm transaction: Confirmar transacción
|
||||||
|
</i18n>
|
|
@ -0,0 +1,48 @@
|
||||||
|
<script setup>
|
||||||
|
import { onBeforeMount, ref } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const tooltip = ref('');
|
||||||
|
|
||||||
|
const $props = defineProps({
|
||||||
|
transaction: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeMount(() => {
|
||||||
|
const errorMessage = $props.transaction.errorMessage
|
||||||
|
? $props.transaction.errorMessage
|
||||||
|
: '';
|
||||||
|
const responseMessage = $props.transaction.responseMessage
|
||||||
|
? $props.transaction.responseMessage
|
||||||
|
: '';
|
||||||
|
tooltip.value = `${errorMessage} ${responseMessage}`;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
v-if="
|
||||||
|
($props.transaction.errorMessage || $props.transaction.responseMessage) &&
|
||||||
|
!$props.transaction.isConfirmed
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<QIcon color="negative" name="close" size="sm">
|
||||||
|
<QTooltip>{{ tooltip }}</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
</div>
|
||||||
|
<div v-if="$props.transaction.isConfirmed">
|
||||||
|
<QIcon color="positive" name="check" size="sm">
|
||||||
|
<QTooltip>{{ t('Confirmed') }}</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
Confirmed: Confirmada
|
||||||
|
</i18n>
|
|
@ -0,0 +1,72 @@
|
||||||
|
<script setup>
|
||||||
|
import { reactive } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
import FormModel from 'components/FormModel.vue';
|
||||||
|
import VnRow from 'components/ui/VnRow.vue';
|
||||||
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const initialData = reactive({
|
||||||
|
clientFK: Number(route.params.id),
|
||||||
|
});
|
||||||
|
|
||||||
|
const toCustomerCreditContracts = () => {
|
||||||
|
router.push({ name: 'CustomerCreditContracts' });
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<FormModel
|
||||||
|
:form-initial-data="initialData"
|
||||||
|
:observe-form-changes="false"
|
||||||
|
url-create="creditClassifications/createWithInsurance"
|
||||||
|
@on-data-saved="toCustomerCreditContracts()"
|
||||||
|
>
|
||||||
|
<template #moreActions>
|
||||||
|
<QBtn
|
||||||
|
:label="t('globals.cancel')"
|
||||||
|
@click="toCustomerCreditContracts"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
icon="close"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #form="{ data }">
|
||||||
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
|
<div class="col">
|
||||||
|
<VnInput
|
||||||
|
:label="t('Credit')"
|
||||||
|
clearable
|
||||||
|
type="number"
|
||||||
|
v-model.number="data.credit"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<VnInput
|
||||||
|
:label="t('Grade')"
|
||||||
|
clearable
|
||||||
|
type="number"
|
||||||
|
v-model.number="data.grade"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<VnInputDate :label="t('Since')" v-model="data.started" />
|
||||||
|
</div>
|
||||||
|
</VnRow>
|
||||||
|
</template>
|
||||||
|
</FormModel>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
Credit: Crédito
|
||||||
|
Grade: Grade
|
||||||
|
Since: Desde
|
||||||
|
</i18n>
|
|
@ -0,0 +1,107 @@
|
||||||
|
<script setup>
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
|
import { toCurrency, toDateHourMinSec } from 'src/filters';
|
||||||
|
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
|
const rows = ref([]);
|
||||||
|
|
||||||
|
const filter = {
|
||||||
|
where: {
|
||||||
|
creditClassificationFk: `${route.params.creditId}`,
|
||||||
|
},
|
||||||
|
limit: 20,
|
||||||
|
};
|
||||||
|
|
||||||
|
const tableColumnComponents = {
|
||||||
|
created: {
|
||||||
|
component: 'span',
|
||||||
|
props: () => {},
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
grade: {
|
||||||
|
component: 'span',
|
||||||
|
props: () => {},
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
credit: {
|
||||||
|
component: 'span',
|
||||||
|
props: () => {},
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const columns = computed(() => [
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: 'created',
|
||||||
|
format: (value) => toDateHourMinSec(value),
|
||||||
|
label: t('Created'),
|
||||||
|
name: 'created',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: 'grade',
|
||||||
|
label: t('Grade'),
|
||||||
|
name: 'grade',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: 'credit',
|
||||||
|
format: (value) => toCurrency(value),
|
||||||
|
label: t('Credit'),
|
||||||
|
name: 'credit',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<FetchData
|
||||||
|
:filter="filter"
|
||||||
|
@on-fetch="(data) => (rows = data)"
|
||||||
|
auto-load
|
||||||
|
url="CreditInsurances"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<QPage class="column items-center q-pa-md" v-if="rows.length">
|
||||||
|
<QTable
|
||||||
|
:columns="columns"
|
||||||
|
:pagination="{ rowsPerPage: 12 }"
|
||||||
|
:rows="rows"
|
||||||
|
class="full-width q-mt-md"
|
||||||
|
row-key="id"
|
||||||
|
>
|
||||||
|
<template #body-cell="props">
|
||||||
|
<QTd :props="props">
|
||||||
|
<QTr :props="props" class="cursor-pointer">
|
||||||
|
<component
|
||||||
|
:is="tableColumnComponents[props.col.name].component"
|
||||||
|
class="col-content"
|
||||||
|
v-bind="tableColumnComponents[props.col.name].props(props)"
|
||||||
|
@click="tableColumnComponents[props.col.name].event(props)"
|
||||||
|
>
|
||||||
|
{{ props.value }}
|
||||||
|
</component>
|
||||||
|
</QTr>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
</QTable>
|
||||||
|
</QPage>
|
||||||
|
|
||||||
|
<h5 class="flex justify-center color-vn-label" v-else>
|
||||||
|
{{ t('globals.noResults') }}
|
||||||
|
</h5>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
Created: Fecha creación
|
||||||
|
Grade: Grade
|
||||||
|
Credit: Crédito
|
||||||
|
</i18n>
|
|
@ -1,18 +1,21 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { reactive } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
import FormModel from 'components/FormModel.vue';
|
import FormModel from 'components/FormModel.vue';
|
||||||
import VnRow from 'components/ui/VnRow.vue';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const initialData = reactive({
|
const initialData = ref({});
|
||||||
credit: null,
|
|
||||||
});
|
const setClient = (data) => {
|
||||||
|
console.log(data.credit);
|
||||||
|
initialData.value.credit = data.credit;
|
||||||
|
};
|
||||||
|
|
||||||
const toCustomerCredits = () => {
|
const toCustomerCredits = () => {
|
||||||
router.push({
|
router.push({
|
||||||
|
@ -25,22 +28,36 @@ const toCustomerCredits = () => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<FetchData
|
||||||
|
:filter="filter"
|
||||||
|
@on-fetch="setClient"
|
||||||
|
auto-load
|
||||||
|
:url="`Clients/${route.params.id}/getCard`"
|
||||||
|
/>
|
||||||
|
|
||||||
<FormModel
|
<FormModel
|
||||||
:form-initial-data="initialData"
|
:form-initial-data="initialData"
|
||||||
:observe-form-changes="false"
|
:observe-form-changes="false"
|
||||||
:url-update="`/Clients/${route.params.id}`"
|
:url-update="`/Clients/${route.params.id}`"
|
||||||
@on-data-saved="toCustomerCredits()"
|
@on-data-saved="toCustomerCredits()"
|
||||||
>
|
>
|
||||||
|
<template #moreActions>
|
||||||
|
<QBtn
|
||||||
|
:label="t('globals.cancel')"
|
||||||
|
@click="toCustomerCredits"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
icon="close"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
<template #form="{ data }">
|
<template #form="{ data }">
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<QInput
|
||||||
<div class="col">
|
:label="t('Credit')"
|
||||||
<QInput
|
clearable
|
||||||
:label="t('Credit')"
|
type="number"
|
||||||
type="number"
|
v-model.number="data.credit"
|
||||||
v-model.number="data.credit"
|
/>
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</VnRow>
|
|
||||||
</template>
|
</template>
|
||||||
</FormModel>
|
</FormModel>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
<script setup>
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
import { useQuasar } from 'quasar';
|
||||||
|
|
||||||
|
import { downloadFile } from 'src/composables/downloadFile';
|
||||||
|
|
||||||
|
import CustomerFileManagementDelete from 'src/pages/Customer/components/CustomerFileManagementDelete.vue';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const quasar = useQuasar();
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const $props = defineProps({
|
||||||
|
id: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
promise: {
|
||||||
|
type: Function,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const setDownloadFile = () => downloadFile($props.id);
|
||||||
|
|
||||||
|
const toCustomerFileManagementEdit = () => {
|
||||||
|
router.push({
|
||||||
|
name: 'CustomerFileManagementEdit',
|
||||||
|
params: {
|
||||||
|
id: route.params.id,
|
||||||
|
dmsId: $props.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const showCustomerFileManagementDeleteDialog = () => {
|
||||||
|
quasar.dialog({
|
||||||
|
component: CustomerFileManagementDelete,
|
||||||
|
componentProps: {
|
||||||
|
id: $props.id,
|
||||||
|
promise: setData,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const setData = () => {
|
||||||
|
$props.promise();
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<QIcon
|
||||||
|
@click.stop="setDownloadFile"
|
||||||
|
color="primary"
|
||||||
|
name="cloud_download"
|
||||||
|
size="sm"
|
||||||
|
>
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('actionFile', { action: t('globals.download') }) }}
|
||||||
|
</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
<QIcon
|
||||||
|
@click.stop="toCustomerFileManagementEdit"
|
||||||
|
class="q-ml-md"
|
||||||
|
color="primary"
|
||||||
|
name="edit"
|
||||||
|
size="sm"
|
||||||
|
>
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('actionFile', { action: t('globals.edit') }) }}
|
||||||
|
</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
<QIcon
|
||||||
|
@click.stop="showCustomerFileManagementDeleteDialog"
|
||||||
|
class="q-ml-md"
|
||||||
|
color="primary"
|
||||||
|
name="delete"
|
||||||
|
size="sm"
|
||||||
|
>
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('actionFile', { action: t('globals.remove') }) }}
|
||||||
|
</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
en:
|
||||||
|
actionFile: '{action} file'
|
||||||
|
es:
|
||||||
|
actionFile: '{action} fichero'
|
||||||
|
</i18n>
|
|
@ -0,0 +1,260 @@
|
||||||
|
<script setup>
|
||||||
|
import { onBeforeMount, ref, watch } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
import { useState } from 'src/composables/useState';
|
||||||
|
import { useValidator } from 'src/composables/useValidator';
|
||||||
|
import useNotify from 'src/composables/useNotify';
|
||||||
|
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
|
import VnRow from 'components/ui/VnRow.vue';
|
||||||
|
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
|
||||||
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
|
||||||
|
const { notify } = useNotify();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const { validate } = useValidator();
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
const state = useState();
|
||||||
|
const user = state.getUser();
|
||||||
|
|
||||||
|
const filterFindOne = { where: { code: 'paymentsLaw' } };
|
||||||
|
const filterCompanies = { order: ['code'] };
|
||||||
|
const filterWarehouses = { order: ['name'] };
|
||||||
|
|
||||||
|
const inputFileRef = ref();
|
||||||
|
const client = ref({});
|
||||||
|
const findOne = ref([]);
|
||||||
|
const allowedContentTypes = ref([]);
|
||||||
|
const optionsCompanies = ref([]);
|
||||||
|
const optionsWarehouses = ref([]);
|
||||||
|
const optionsDmsTypes = ref([]);
|
||||||
|
const isLoading = ref(false);
|
||||||
|
const dms = ref({
|
||||||
|
hasFile: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeMount(() => {
|
||||||
|
const { companyFk, warehouseFk } = user.value;
|
||||||
|
dms.value.reference = route.params.id;
|
||||||
|
dms.value.companyId = companyFk;
|
||||||
|
dms.value.warehouseId = warehouseFk;
|
||||||
|
});
|
||||||
|
|
||||||
|
watch([client, findOne], ([newClient, newFindOne]) => {
|
||||||
|
dms.value.description = t('clientFileDescription', {
|
||||||
|
dmsTypeName: newFindOne.name?.toUpperCase(),
|
||||||
|
clientName: newClient.name?.toUpperCase(),
|
||||||
|
clientId: newClient.id,
|
||||||
|
});
|
||||||
|
dms.value.dmsTypeId = newFindOne.id;
|
||||||
|
});
|
||||||
|
|
||||||
|
const saveData = async () => {
|
||||||
|
try {
|
||||||
|
const formData = new FormData();
|
||||||
|
const files = dms.value.files;
|
||||||
|
|
||||||
|
if (files && files.length > 0) {
|
||||||
|
for (let file of files) {
|
||||||
|
formData.append(file.name, file);
|
||||||
|
}
|
||||||
|
dms.value.hasFileAttached = true;
|
||||||
|
|
||||||
|
const url = `clients/${route.params.id}/uploadFile`;
|
||||||
|
await axios.post(url, formData, {
|
||||||
|
params: dms.value,
|
||||||
|
});
|
||||||
|
notify('globals.dataSaved', 'positive');
|
||||||
|
toCustomerFileManagement();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
notify(error.message, 'negative');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const toCustomerFileManagement = () => {
|
||||||
|
router.push({ name: 'CustomerFileManagement' });
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<fetch-data
|
||||||
|
@on-fetch="(data) => (client = data)"
|
||||||
|
auto-load
|
||||||
|
:url="`Clients/${route.params.id}/getCard`"
|
||||||
|
/>
|
||||||
|
<fetch-data
|
||||||
|
:filter="filterFindOne"
|
||||||
|
@on-fetch="(data) => (findOne = data)"
|
||||||
|
auto-load
|
||||||
|
url="DmsTypes/findOne"
|
||||||
|
/>
|
||||||
|
<fetch-data
|
||||||
|
@on-fetch="(data) => (allowedContentTypes = data)"
|
||||||
|
auto-load
|
||||||
|
url="DmsContainers/allowedContentTypes"
|
||||||
|
/>
|
||||||
|
<fetch-data
|
||||||
|
:filter="filterCompanies"
|
||||||
|
@on-fetch="(data) => (optionsCompanies = data)"
|
||||||
|
auto-load
|
||||||
|
url="Companies"
|
||||||
|
/>
|
||||||
|
<fetch-data
|
||||||
|
:filter="filterWarehouses"
|
||||||
|
@on-fetch="(data) => (optionsWarehouses = data)"
|
||||||
|
auto-load
|
||||||
|
url="Warehouses"
|
||||||
|
/>
|
||||||
|
<fetch-data
|
||||||
|
:filter="filterWarehouses"
|
||||||
|
@on-fetch="(data) => (optionsDmsTypes = data)"
|
||||||
|
auto-load
|
||||||
|
url="DmsTypes"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Teleport to="#st-actions">
|
||||||
|
<QBtnGroup push class="q-gutter-x-sm">
|
||||||
|
<QBtn
|
||||||
|
:disabled="isLoading"
|
||||||
|
:label="t('globals.cancel')"
|
||||||
|
:loading="isLoading"
|
||||||
|
@click="toCustomerFileManagement"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
icon="close"
|
||||||
|
/>
|
||||||
|
<QBtn
|
||||||
|
:disabled="isLoading"
|
||||||
|
:label="t('globals.save')"
|
||||||
|
:loading="isLoading"
|
||||||
|
@click.stop="saveData"
|
||||||
|
color="primary"
|
||||||
|
icon="save"
|
||||||
|
/>
|
||||||
|
</QBtnGroup>
|
||||||
|
</Teleport>
|
||||||
|
|
||||||
|
<QCard class="q-pa-lg">
|
||||||
|
<QCardSection>
|
||||||
|
<QForm>
|
||||||
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
|
<div class="col">
|
||||||
|
<VnInput
|
||||||
|
:label="t('Reference')"
|
||||||
|
clearable
|
||||||
|
v-model="dms.reference"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<VnSelectFilter
|
||||||
|
:label="t('Company')"
|
||||||
|
:options="optionsCompanies"
|
||||||
|
:rules="validate('entry.companyFk')"
|
||||||
|
option-label="code"
|
||||||
|
option-value="id"
|
||||||
|
v-model="dms.companyId"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</VnRow>
|
||||||
|
|
||||||
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
|
<div class="col">
|
||||||
|
<VnSelectFilter
|
||||||
|
:label="t('Warehouse')"
|
||||||
|
:options="optionsWarehouses"
|
||||||
|
option-label="name"
|
||||||
|
option-value="id"
|
||||||
|
v-model="dms.warehouseId"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<VnSelectFilter
|
||||||
|
:label="t('Type')"
|
||||||
|
:options="optionsDmsTypes"
|
||||||
|
option-label="name"
|
||||||
|
option-value="id"
|
||||||
|
v-model="dms.dmsTypeId"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</VnRow>
|
||||||
|
|
||||||
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
|
<div class="col">
|
||||||
|
<VnInput
|
||||||
|
:label="t('Description')"
|
||||||
|
:rules="validate('route.description')"
|
||||||
|
clearable
|
||||||
|
type="textarea"
|
||||||
|
v-model="dms.description"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</VnRow>
|
||||||
|
|
||||||
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
|
<div class="col">
|
||||||
|
<QFile
|
||||||
|
ref="inputFileRef"
|
||||||
|
class="required"
|
||||||
|
:label="t('File')"
|
||||||
|
v-model="dms.files"
|
||||||
|
multiple
|
||||||
|
:accept="allowedContentTypes.join(',')"
|
||||||
|
clearable
|
||||||
|
clear-icon="close"
|
||||||
|
>
|
||||||
|
<template #append>
|
||||||
|
<QBtn
|
||||||
|
icon="vn:attach"
|
||||||
|
flat
|
||||||
|
round
|
||||||
|
padding="xs"
|
||||||
|
@click="inputFileRef.pickFiles()"
|
||||||
|
>
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('Select a file') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QBtn>
|
||||||
|
<QBtn icon="info" flat round padding="xs">
|
||||||
|
<QTooltip max-width="30rem">
|
||||||
|
{{
|
||||||
|
`${t(
|
||||||
|
'Allowed content types'
|
||||||
|
)}: ${allowedContentTypes.join(', ')}`
|
||||||
|
}}
|
||||||
|
</QTooltip>
|
||||||
|
</QBtn>
|
||||||
|
</template>
|
||||||
|
</QFile>
|
||||||
|
</div>
|
||||||
|
</VnRow>
|
||||||
|
|
||||||
|
<QCheckbox
|
||||||
|
:label="t('Generate identifier for original file')"
|
||||||
|
v-model="dms.hasFile"
|
||||||
|
/>
|
||||||
|
</QForm>
|
||||||
|
</QCardSection>
|
||||||
|
</QCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
en:
|
||||||
|
clientFileDescription: '{dmsTypeName} FROM CLIENT {clientName} ID {clientId}'
|
||||||
|
es:
|
||||||
|
Reference: Referencia
|
||||||
|
Company: Empresa
|
||||||
|
Warehouse: Almacén
|
||||||
|
Type: Tipo
|
||||||
|
Description: Descripción
|
||||||
|
clientFileDescription: '{dmsTypeName} DEL CLIENTE {clientName} ID {clientId}'
|
||||||
|
File: Fichero
|
||||||
|
Select a file: Selecciona un fichero
|
||||||
|
Allowed content types: Tipos de archivo permitidos
|
||||||
|
Generate identifier for original file: Generar identificador para archivo original
|
||||||
|
</i18n>
|
|
@ -0,0 +1,82 @@
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import { useDialogPluginComponent } from 'quasar';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
import useNotify from 'src/composables/useNotify';
|
||||||
|
|
||||||
|
const $props = defineProps({
|
||||||
|
id: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
promise: {
|
||||||
|
type: Function,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { dialogRef } = useDialogPluginComponent();
|
||||||
|
const { notify } = useNotify();
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const closeButton = ref(null);
|
||||||
|
|
||||||
|
const isLoading = ref(false);
|
||||||
|
|
||||||
|
const deleteDms = async () => {
|
||||||
|
isLoading.value = true;
|
||||||
|
try {
|
||||||
|
await axios.post(`ClientDms/${$props.id}/removeFile`);
|
||||||
|
if ($props.promise) await $props.promise();
|
||||||
|
notify('globals.dataDeleted', 'positive');
|
||||||
|
} catch (error) {
|
||||||
|
notify(error.message, 'negative');
|
||||||
|
} finally {
|
||||||
|
closeButton.value.click();
|
||||||
|
isLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<QDialog ref="dialogRef">
|
||||||
|
<QCard class="q-pa-md q-mb-md">
|
||||||
|
<span ref="closeButton" class="row justify-end close-icon" v-close-popup>
|
||||||
|
<QIcon name="close" size="sm" />
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<QCardSection>
|
||||||
|
<div class="mt-1 text-h6">{{ t('This file will be deleted') }}</div>
|
||||||
|
<div>{{ t('Are you sure you want to continue?') }}</div>
|
||||||
|
</QCardSection>
|
||||||
|
|
||||||
|
<QCardActions class="flex justify-end">
|
||||||
|
<QBtn
|
||||||
|
:disabled="isLoading"
|
||||||
|
:label="t('globals.cancel')"
|
||||||
|
:loading="isLoading"
|
||||||
|
class="q-mr-xl"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
v-close-popup
|
||||||
|
/>
|
||||||
|
<QBtn
|
||||||
|
:disabled="isLoading"
|
||||||
|
:label="t('globals.save')"
|
||||||
|
:loading="isLoading"
|
||||||
|
@click.stop="deleteDms"
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
|
</QCardActions>
|
||||||
|
</QCard>
|
||||||
|
</QDialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
This file will be deleted: Este fichero va a ser borrado
|
||||||
|
Are you sure you want to continue?: ¿Seguro que quieres continuar?
|
||||||
|
</i18n>
|
|
@ -0,0 +1,237 @@
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
import { useValidator } from 'src/composables/useValidator';
|
||||||
|
import useNotify from 'src/composables/useNotify';
|
||||||
|
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
|
import VnRow from 'components/ui/VnRow.vue';
|
||||||
|
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
|
||||||
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
|
||||||
|
const { notify } = useNotify();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const { validate } = useValidator();
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const filterCompanies = { order: ['code'] };
|
||||||
|
const filterWarehouses = { order: ['name'] };
|
||||||
|
|
||||||
|
const inputFileRef = ref();
|
||||||
|
const allowedContentTypes = ref([]);
|
||||||
|
const optionsCompanies = ref([]);
|
||||||
|
const optionsWarehouses = ref([]);
|
||||||
|
const optionsDmsTypes = ref([]);
|
||||||
|
const isLoading = ref(false);
|
||||||
|
const dms = ref({
|
||||||
|
hasFile: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const setCurrentDms = (data) => {
|
||||||
|
dms.value.reference = data.reference;
|
||||||
|
dms.value.companyId = data.companyFk;
|
||||||
|
dms.value.warehouseId = data.warehouseFk;
|
||||||
|
dms.value.dmsTypeId = data.dmsTypeFk;
|
||||||
|
dms.value.description = data.description;
|
||||||
|
};
|
||||||
|
|
||||||
|
const saveData = async () => {
|
||||||
|
try {
|
||||||
|
const formData = new FormData();
|
||||||
|
const files = dms.value.files;
|
||||||
|
|
||||||
|
if (files && files.length > 0) {
|
||||||
|
for (let file of files) {
|
||||||
|
formData.append(file.name, file);
|
||||||
|
}
|
||||||
|
dms.value.hasFileAttached = true;
|
||||||
|
|
||||||
|
const url = `dms/${route.params.dmsId}/updateFile`;
|
||||||
|
await axios.post(url, formData, {
|
||||||
|
params: dms.value,
|
||||||
|
});
|
||||||
|
notify('globals.dataSaved', 'positive');
|
||||||
|
toCustomerFileManagement();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
notify(error.message, 'negative');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const toCustomerFileManagement = () => {
|
||||||
|
router.push({ name: 'CustomerFileManagement' });
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<fetch-data :url="`Dms/${route.params.dmsId}`" @on-fetch="setCurrentDms" auto-load />
|
||||||
|
<fetch-data
|
||||||
|
@on-fetch="(data) => (allowedContentTypes = data)"
|
||||||
|
auto-load
|
||||||
|
url="DmsContainers/allowedContentTypes"
|
||||||
|
/>
|
||||||
|
<fetch-data
|
||||||
|
:filter="filterCompanies"
|
||||||
|
@on-fetch="(data) => (optionsCompanies = data)"
|
||||||
|
auto-load
|
||||||
|
url="Companies"
|
||||||
|
/>
|
||||||
|
<fetch-data
|
||||||
|
:filter="filterWarehouses"
|
||||||
|
@on-fetch="(data) => (optionsWarehouses = data)"
|
||||||
|
auto-load
|
||||||
|
url="Warehouses"
|
||||||
|
/>
|
||||||
|
<fetch-data
|
||||||
|
:filter="filterWarehouses"
|
||||||
|
@on-fetch="(data) => (optionsDmsTypes = data)"
|
||||||
|
auto-load
|
||||||
|
url="DmsTypes"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Teleport to="#st-actions">
|
||||||
|
<QBtnGroup push class="q-gutter-x-sm">
|
||||||
|
<QBtn
|
||||||
|
:disabled="isLoading"
|
||||||
|
:label="t('globals.cancel')"
|
||||||
|
:loading="isLoading"
|
||||||
|
@click="toCustomerFileManagement"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
icon="close"
|
||||||
|
/>
|
||||||
|
<QBtn
|
||||||
|
:disabled="isLoading"
|
||||||
|
:label="t('globals.save')"
|
||||||
|
:loading="isLoading"
|
||||||
|
@click.stop="saveData"
|
||||||
|
color="primary"
|
||||||
|
icon="save"
|
||||||
|
/>
|
||||||
|
</QBtnGroup>
|
||||||
|
</Teleport>
|
||||||
|
|
||||||
|
<QCard class="q-pa-lg">
|
||||||
|
<QCardSection>
|
||||||
|
<QForm>
|
||||||
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
|
<div class="col">
|
||||||
|
<VnInput
|
||||||
|
:label="t('Reference')"
|
||||||
|
clearable
|
||||||
|
v-model="dms.reference"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<VnSelectFilter
|
||||||
|
:label="t('Company')"
|
||||||
|
:options="optionsCompanies"
|
||||||
|
:rules="validate('entry.companyFk')"
|
||||||
|
option-label="code"
|
||||||
|
option-value="id"
|
||||||
|
v-model="dms.companyId"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</VnRow>
|
||||||
|
|
||||||
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
|
<div class="col">
|
||||||
|
<VnSelectFilter
|
||||||
|
:label="t('Warehouse')"
|
||||||
|
:options="optionsWarehouses"
|
||||||
|
option-label="name"
|
||||||
|
option-value="id"
|
||||||
|
v-model="dms.warehouseId"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<VnSelectFilter
|
||||||
|
:label="t('Type')"
|
||||||
|
:options="optionsDmsTypes"
|
||||||
|
option-label="name"
|
||||||
|
option-value="id"
|
||||||
|
v-model="dms.dmsTypeId"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</VnRow>
|
||||||
|
|
||||||
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
|
<div class="col">
|
||||||
|
<VnInput
|
||||||
|
:label="t('Description')"
|
||||||
|
:rules="validate('route.description')"
|
||||||
|
clearable
|
||||||
|
type="textarea"
|
||||||
|
v-model="dms.description"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</VnRow>
|
||||||
|
|
||||||
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
|
<div class="col">
|
||||||
|
<QFile
|
||||||
|
ref="inputFileRef"
|
||||||
|
class="required"
|
||||||
|
:label="t('File')"
|
||||||
|
v-model="dms.files"
|
||||||
|
multiple
|
||||||
|
:accept="allowedContentTypes.join(',')"
|
||||||
|
clearable
|
||||||
|
clear-icon="close"
|
||||||
|
>
|
||||||
|
<template #append>
|
||||||
|
<QBtn
|
||||||
|
icon="vn:attach"
|
||||||
|
flat
|
||||||
|
round
|
||||||
|
padding="xs"
|
||||||
|
@click="inputFileRef.pickFiles()"
|
||||||
|
>
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('Select a file') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QBtn>
|
||||||
|
<QBtn icon="info" flat round padding="xs">
|
||||||
|
<QTooltip max-width="30rem">
|
||||||
|
{{
|
||||||
|
`${t(
|
||||||
|
'Allowed content types'
|
||||||
|
)}: ${allowedContentTypes.join(', ')}`
|
||||||
|
}}
|
||||||
|
</QTooltip>
|
||||||
|
</QBtn>
|
||||||
|
</template>
|
||||||
|
</QFile>
|
||||||
|
</div>
|
||||||
|
</VnRow>
|
||||||
|
|
||||||
|
<QCheckbox
|
||||||
|
:label="t('Generate identifier for original file')"
|
||||||
|
v-model="dms.hasFile"
|
||||||
|
disable
|
||||||
|
/>
|
||||||
|
</QForm>
|
||||||
|
</QCardSection>
|
||||||
|
</QCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
en:
|
||||||
|
clientFileDescription: '{dmsTypeName} FROM CLIENT {clientName} ID {clientId}'
|
||||||
|
es:
|
||||||
|
Reference: Referencia
|
||||||
|
Company: Empresa
|
||||||
|
Warehouse: Almacén
|
||||||
|
Type: Tipo
|
||||||
|
Description: Descripción
|
||||||
|
clientFileDescription: '{dmsTypeName} DEL CLIENTE {clientName} ID {clientId}'
|
||||||
|
File: Fichero
|
||||||
|
Select a file: Selecciona un fichero
|
||||||
|
Allowed content types: Tipos de archivo permitidos
|
||||||
|
Generate identifier for original file: Generar identificador para archivo original
|
||||||
|
</i18n>
|
|
@ -15,9 +15,6 @@ const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const initialData = reactive({
|
const initialData = reactive({
|
||||||
amount: null,
|
|
||||||
description: null,
|
|
||||||
greugeTypeFk: null,
|
|
||||||
shipped: '2001-01-01T11:00:00.000Z',
|
shipped: '2001-01-01T11:00:00.000Z',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -47,10 +44,25 @@ const toCustomerGreuges = () => {
|
||||||
model="client"
|
model="client"
|
||||||
url-create="Greuges"
|
url-create="Greuges"
|
||||||
>
|
>
|
||||||
|
<template #moreActions>
|
||||||
|
<QBtn
|
||||||
|
:label="t('globals.cancel')"
|
||||||
|
@click="toCustomerGreuges"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
icon="close"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
<template #form="{ data }">
|
<template #form="{ data }">
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<VnInput :label="t('Amount')" type="number" v-model="data.amount" />
|
<VnInput
|
||||||
|
:label="t('Amount')"
|
||||||
|
clearable
|
||||||
|
type="number"
|
||||||
|
v-model="data.amount"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<VnInputDate :label="t('Date')" v-model="data.shipped" />
|
<VnInputDate :label="t('Date')" v-model="data.shipped" />
|
||||||
|
@ -59,7 +71,7 @@ const toCustomerGreuges = () => {
|
||||||
|
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<VnInput :label="t('Comment')" v-model="data.description" />
|
<VnInput :label="t('Comment')" clearable v-model="data.description" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<VnSelectFilter
|
<VnSelectFilter
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { reactive, ref } from 'vue';
|
import { reactive } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import VnRow from 'components/ui/VnRow.vue';
|
import VnRow from 'components/ui/VnRow.vue';
|
||||||
|
@ -10,13 +10,6 @@ const emit = defineEmits(['onDataSaved']);
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const initialData = reactive({
|
|
||||||
nif: null,
|
|
||||||
fiscalName: null,
|
|
||||||
street: null,
|
|
||||||
phone: null,
|
|
||||||
});
|
|
||||||
|
|
||||||
const onDataSaved = (dataSaved) => {
|
const onDataSaved = (dataSaved) => {
|
||||||
emit('onDataSaved', dataSaved);
|
emit('onDataSaved', dataSaved);
|
||||||
};
|
};
|
||||||
|
@ -25,30 +18,35 @@ const onDataSaved = (dataSaved) => {
|
||||||
<template>
|
<template>
|
||||||
<FormModelPopup
|
<FormModelPopup
|
||||||
:title="t('New customs agent')"
|
:title="t('New customs agent')"
|
||||||
url-create="CustomsAgents"
|
|
||||||
model="customer"
|
|
||||||
:form-initial-data="initialData"
|
|
||||||
@on-data-saved="onDataSaved($event)"
|
@on-data-saved="onDataSaved($event)"
|
||||||
|
model="customer"
|
||||||
|
url-create="CustomsAgents"
|
||||||
>
|
>
|
||||||
<template #form-inputs="{ data }">
|
<template #form-inputs="{ data }">
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<VnInput :label="t('NIF')" :required="true" v-model="data.nif" />
|
<VnInput
|
||||||
|
:label="t('NIF')"
|
||||||
|
:required="true"
|
||||||
|
clearable
|
||||||
|
v-model="data.nif"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<VnInput
|
<VnInput
|
||||||
:label="t('Fiscal name')"
|
:label="t('Fiscal name')"
|
||||||
:required="true"
|
:required="true"
|
||||||
|
clearable
|
||||||
v-model="data.fiscalName"
|
v-model="data.fiscalName"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<VnInput :label="t('Street')" v-model="data.street" />
|
<VnInput :label="t('Street')" clearable v-model="data.street" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<VnInput :label="t('Phone')" v-model="data.phone" />
|
<VnInput :label="t('Phone')" clearable v-model="data.phone" />
|
||||||
</div>
|
</div>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -3,6 +3,8 @@ import { onBeforeMount, reactive, ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
|
import { useDialogPluginComponent } from 'quasar';
|
||||||
|
|
||||||
import FetchData from 'components/FetchData.vue';
|
import FetchData from 'components/FetchData.vue';
|
||||||
import FormModel from 'components/FormModel.vue';
|
import FormModel from 'components/FormModel.vue';
|
||||||
import VnRow from 'components/ui/VnRow.vue';
|
import VnRow from 'components/ui/VnRow.vue';
|
||||||
|
@ -12,6 +14,7 @@ import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
const { dialogRef } = useDialogPluginComponent();
|
||||||
|
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
companyId: {
|
companyId: {
|
||||||
|
@ -49,19 +52,15 @@ const filterBanks = {
|
||||||
const filterClientFindOne = {
|
const filterClientFindOne = {
|
||||||
fields: ['email'],
|
fields: ['email'],
|
||||||
where: {
|
where: {
|
||||||
id: `${route.params.id}`,
|
id: route.params.id,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const initialData = reactive({
|
const initialData = reactive({
|
||||||
amountPaid: $props.totalCredit,
|
amountPaid: $props.totalCredit,
|
||||||
bankFk: null,
|
clientFk: route.params.id,
|
||||||
clientFk: `${route.params.id}`,
|
|
||||||
companyFk: $props.companyId,
|
companyFk: $props.companyId,
|
||||||
compensationAccount: null,
|
|
||||||
description: null,
|
|
||||||
email: clientFindOne.value.email,
|
email: clientFindOne.value.email,
|
||||||
payed: null,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
|
@ -128,14 +127,12 @@ const onDataSaved = async () => {
|
||||||
:url-create="urlCreate"
|
:url-create="urlCreate"
|
||||||
@on-data-saved="onDataSaved()"
|
@on-data-saved="onDataSaved()"
|
||||||
>
|
>
|
||||||
<template #form="{ data }">
|
<template #form="{ data, validate }">
|
||||||
<span ref="closeButton" class="row justify-end close-icon" v-close-popup>
|
<span ref="closeButton" class="row justify-end close-icon" v-close-popup>
|
||||||
<QIcon name="close" size="sm" />
|
<QIcon name="close" size="sm" />
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<h5 class="flex justify-center q-mt-xs">
|
<h5 class="q-mt-none">{{ t('New payment') }}</h5>
|
||||||
{{ t('New payment') }}
|
|
||||||
</h5>
|
|
||||||
|
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
|
@ -150,6 +147,7 @@ const onDataSaved = async () => {
|
||||||
:label="t('Company')"
|
:label="t('Company')"
|
||||||
:options="companyOptions"
|
:options="companyOptions"
|
||||||
:required="true"
|
:required="true"
|
||||||
|
:rules="validate('entry.companyFk')"
|
||||||
hide-selected
|
hide-selected
|
||||||
option-label="code"
|
option-label="code"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
|
@ -186,6 +184,7 @@ const onDataSaved = async () => {
|
||||||
:label="t('Amount')"
|
:label="t('Amount')"
|
||||||
:required="true"
|
:required="true"
|
||||||
@update:model-value="calculateFromAmount($event)"
|
@update:model-value="calculateFromAmount($event)"
|
||||||
|
clearable
|
||||||
type="number"
|
type="number"
|
||||||
v-model.number="data.amountPaid"
|
v-model.number="data.amountPaid"
|
||||||
/>
|
/>
|
||||||
|
@ -200,6 +199,7 @@ const onDataSaved = async () => {
|
||||||
<div class="col" v-if="data.bankFk === 3 || data.bankFk === 3117">
|
<div class="col" v-if="data.bankFk === 3 || data.bankFk === 3117">
|
||||||
<VnInput
|
<VnInput
|
||||||
:label="t('Compensation account')"
|
:label="t('Compensation account')"
|
||||||
|
clearable
|
||||||
v-model="data.compensationAccount"
|
v-model="data.compensationAccount"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -207,6 +207,7 @@ const onDataSaved = async () => {
|
||||||
<VnInput
|
<VnInput
|
||||||
:label="t('Reference')"
|
:label="t('Reference')"
|
||||||
:required="true"
|
:required="true"
|
||||||
|
clearable
|
||||||
v-model="data.description"
|
v-model="data.description"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -220,6 +221,7 @@ const onDataSaved = async () => {
|
||||||
<VnInput
|
<VnInput
|
||||||
:label="t('Delivered amount')"
|
:label="t('Delivered amount')"
|
||||||
@update:model-value="calculateFromDeliveredAmount($event)"
|
@update:model-value="calculateFromDeliveredAmount($event)"
|
||||||
|
clearable
|
||||||
type="number"
|
type="number"
|
||||||
v-model="deliveredAmount"
|
v-model="deliveredAmount"
|
||||||
/>
|
/>
|
||||||
|
@ -227,6 +229,7 @@ const onDataSaved = async () => {
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<VnInput
|
<VnInput
|
||||||
:label="t('Amount to return')"
|
:label="t('Amount to return')"
|
||||||
|
clearable
|
||||||
disable
|
disable
|
||||||
type="number"
|
type="number"
|
||||||
v-model="amountToReturn"
|
v-model="amountToReturn"
|
||||||
|
|
|
@ -10,9 +10,7 @@ const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const initialData = reactive({
|
const initialData = reactive({});
|
||||||
text: null,
|
|
||||||
});
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
initialData.clientFk = `${route.params.id}`;
|
initialData.clientFk = `${route.params.id}`;
|
||||||
|
@ -35,6 +33,16 @@ const toCustomerNotes = () => {
|
||||||
@on-data-saved="toCustomerNotes()"
|
@on-data-saved="toCustomerNotes()"
|
||||||
url-create="ClientObservations"
|
url-create="ClientObservations"
|
||||||
>
|
>
|
||||||
|
<template #moreActions>
|
||||||
|
<QBtn
|
||||||
|
:label="t('globals.cancel')"
|
||||||
|
@click="toCustomerNotes"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
icon="close"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
<template #form="{ data }">
|
<template #form="{ data }">
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
|
|
|
@ -14,9 +14,6 @@ const router = useRouter();
|
||||||
|
|
||||||
const initialData = reactive({
|
const initialData = reactive({
|
||||||
started: '2001-01-01T11:00:00.000Z',
|
started: '2001-01-01T11:00:00.000Z',
|
||||||
finished: null,
|
|
||||||
amount: null,
|
|
||||||
period: null,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
@ -41,6 +38,16 @@ const toCustomerRecoveries = () => {
|
||||||
model="client"
|
model="client"
|
||||||
url-create="Recoveries"
|
url-create="Recoveries"
|
||||||
>
|
>
|
||||||
|
<template #moreActions>
|
||||||
|
<QBtn
|
||||||
|
:label="t('globals.cancel')"
|
||||||
|
@click="toCustomerRecoveries"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
icon="close"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
<template #form="{ data }">
|
<template #form="{ data }">
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
|
@ -53,10 +60,20 @@ const toCustomerRecoveries = () => {
|
||||||
|
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<VnInput :label="t('Amount')" type="number" v-model="data.amount" />
|
<VnInput
|
||||||
|
:label="t('Amount')"
|
||||||
|
clearable
|
||||||
|
type="number"
|
||||||
|
v-model="data.amount"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<VnInput :label="t('Period')" type="number" v-model="data.period" />
|
<VnInput
|
||||||
|
:label="t('Period')"
|
||||||
|
clearable
|
||||||
|
type="number"
|
||||||
|
v-model="data.period"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -0,0 +1,385 @@
|
||||||
|
<script setup>
|
||||||
|
import { onBeforeMount, reactive, ref } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
import axios from 'axios';
|
||||||
|
import { useQuasar } from 'quasar';
|
||||||
|
|
||||||
|
import { useState } from 'src/composables/useState';
|
||||||
|
import { useValidator } from 'src/composables/useValidator';
|
||||||
|
import useNotify from 'src/composables/useNotify';
|
||||||
|
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
|
import VnRow from 'components/ui/VnRow.vue';
|
||||||
|
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
|
||||||
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
||||||
|
import CustomerSamplesPreview from 'src/pages/Customer/components/CustomerSamplesPreview.vue';
|
||||||
|
import { useStateStore } from 'stores/useStateStore';
|
||||||
|
|
||||||
|
const { notify } = useNotify();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const { validate } = useValidator();
|
||||||
|
const quasar = useQuasar();
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
const state = useState();
|
||||||
|
const user = state.getUser();
|
||||||
|
const stateStore = useStateStore();
|
||||||
|
|
||||||
|
const client = ref({});
|
||||||
|
const hasChanged = ref(false);
|
||||||
|
const isLoading = ref(false);
|
||||||
|
const optionsClientsAddressess = ref([]);
|
||||||
|
const optionsCompanies = ref([]);
|
||||||
|
const optionsEmailUsers = ref([]);
|
||||||
|
const optionsSamplesVisible = ref([]);
|
||||||
|
const sampleType = ref({ hasPreview: false });
|
||||||
|
|
||||||
|
const filterEmailUsers = { where: { userFk: user.value.id } };
|
||||||
|
const filterClientsAddresses = {
|
||||||
|
include: [
|
||||||
|
{ relation: 'province', scope: { fields: ['name'] } },
|
||||||
|
{ relation: 'agencyMode', scope: { fields: ['name'] } },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const filterCompanies = { order: ['code'] };
|
||||||
|
const filterSamplesVisible = {
|
||||||
|
fields: [
|
||||||
|
'id',
|
||||||
|
'code',
|
||||||
|
'description',
|
||||||
|
'model',
|
||||||
|
'hasCompany',
|
||||||
|
'hasAddress',
|
||||||
|
'hasPreview',
|
||||||
|
'datepickerEnabled',
|
||||||
|
],
|
||||||
|
order: ['description'],
|
||||||
|
};
|
||||||
|
const initialData = reactive({});
|
||||||
|
|
||||||
|
onBeforeMount(async () => {
|
||||||
|
const { data } = await axios.get(`Clients/1/getCard`);
|
||||||
|
client.value = data;
|
||||||
|
initialData.clientFk = route.params?.id;
|
||||||
|
initialData.recipient = data.email;
|
||||||
|
initialData.recipientId = data.id;
|
||||||
|
});
|
||||||
|
|
||||||
|
const setEmailUser = (data) => {
|
||||||
|
optionsEmailUsers.value = data;
|
||||||
|
initialData.replyTo = data[0]?.email;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setClientsAddresses = (data) => {
|
||||||
|
initialData.addressId = data[0].id;
|
||||||
|
optionsClientsAddressess.value = data;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setSampleType = (sampleId) => {
|
||||||
|
hasChanged.value = true;
|
||||||
|
const { companyFk } = user.value;
|
||||||
|
sampleType.value = optionsSamplesVisible.value.find((option) => {
|
||||||
|
return option.id === sampleId;
|
||||||
|
});
|
||||||
|
initialData.companyFk = companyFk;
|
||||||
|
initialData.companyId = companyFk;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setInitialData = () => {
|
||||||
|
hasChanged.value = false;
|
||||||
|
|
||||||
|
initialData.addressId = optionsClientsAddressess.value[0].id;
|
||||||
|
initialData.companyFk = null;
|
||||||
|
initialData.from = null;
|
||||||
|
initialData.recipient = client.value.email;
|
||||||
|
initialData.recipientId = client.value.id;
|
||||||
|
initialData.replyTo = optionsEmailUsers.value[0]?.email;
|
||||||
|
initialData.typeFk = '';
|
||||||
|
|
||||||
|
sampleType.value = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
const validateMessage = () => {
|
||||||
|
if (!initialData.recipient) return 'Email cannot be blank';
|
||||||
|
if (!sampleType.value) return 'Choose a sample';
|
||||||
|
if (sampleType.value.hasCompany && !initialData.companyFk) return 'Choose a company';
|
||||||
|
if (sampleType.value.datepickerEnabled && !initialData.from) return 'Choose a date';
|
||||||
|
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
|
||||||
|
const setParams = (params) => {
|
||||||
|
if (sampleType.value.hasCompany) params.companyId = initialData.companyFk;
|
||||||
|
if (sampleType.value.datepickerEnabled) params.from = initialData.from;
|
||||||
|
if (initialData.addressId) params.addressId = initialData.addressId;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getPreview = async () => {
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
recipientId: route.params.id,
|
||||||
|
};
|
||||||
|
const validationMessage = validateMessage();
|
||||||
|
if (validationMessage) return notify(t(validationMessage), 'negative');
|
||||||
|
|
||||||
|
setParams(params);
|
||||||
|
|
||||||
|
const path = `${sampleType.value.model}/${route.params.id}/${sampleType.value.code}-html`;
|
||||||
|
const { data } = await axios.get(path, { params });
|
||||||
|
|
||||||
|
if (!data) return;
|
||||||
|
quasar.dialog({
|
||||||
|
component: CustomerSamplesPreview,
|
||||||
|
componentProps: {
|
||||||
|
htmlContent: data,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
notify('Errors getting preview', 'negative');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSubmit = async () => {
|
||||||
|
isLoading.value = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { data } = await axios.patch('ClientSamples', initialData);
|
||||||
|
notify('globals.dataSaved', 'positive');
|
||||||
|
onDataSaved(data);
|
||||||
|
} catch (error) {
|
||||||
|
notify('errors.create', 'negative');
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDataSaved = async ({
|
||||||
|
addressId,
|
||||||
|
companyFk,
|
||||||
|
companyId,
|
||||||
|
from,
|
||||||
|
recipient,
|
||||||
|
replyTo,
|
||||||
|
}) => {
|
||||||
|
await axios.post(`Clients/${route.params.id}/incoterms-authorization-email`, {
|
||||||
|
addressId,
|
||||||
|
companyFk,
|
||||||
|
companyId,
|
||||||
|
from,
|
||||||
|
recipient,
|
||||||
|
replyTo,
|
||||||
|
});
|
||||||
|
toCustomerSamples();
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateModelValue = () => {
|
||||||
|
hasChanged.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const toCustomerSamples = () => {
|
||||||
|
router.push({ name: 'CustomerSamples' });
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<fetch-data
|
||||||
|
:filter="filterEmailUsers"
|
||||||
|
@on-fetch="setEmailUser"
|
||||||
|
auto-load
|
||||||
|
url="EmailUsers"
|
||||||
|
/>
|
||||||
|
<fetch-data
|
||||||
|
:filter="filterClientsAddresses"
|
||||||
|
:url="`Clients/${route.params.id}/addresses`"
|
||||||
|
@on-fetch="setClientsAddresses"
|
||||||
|
auto-load
|
||||||
|
/>
|
||||||
|
<fetch-data
|
||||||
|
:filter="filterCompanies"
|
||||||
|
@on-fetch="(data) => (optionsCompanies = data)"
|
||||||
|
auto-load
|
||||||
|
url="Companies"
|
||||||
|
/>
|
||||||
|
<fetch-data
|
||||||
|
:filter="filterSamplesVisible"
|
||||||
|
@on-fetch="(data) => (optionsSamplesVisible = data)"
|
||||||
|
auto-load
|
||||||
|
url="Samples/visible"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Teleport v-if="stateStore?.isSubToolbarShown()" to="#st-actions">
|
||||||
|
<QBtnGroup push class="q-gutter-x-sm">
|
||||||
|
<QBtn
|
||||||
|
:label="t('globals.cancel')"
|
||||||
|
@click="toCustomerSamples"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
icon="close"
|
||||||
|
/>
|
||||||
|
<QBtn
|
||||||
|
:disabled="isLoading || !sampleType?.hasPreview"
|
||||||
|
:label="t('Preview')"
|
||||||
|
:loading="isLoading"
|
||||||
|
@click.stop="getPreview()"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
icon="preview"
|
||||||
|
/>
|
||||||
|
<QBtn
|
||||||
|
:disabled="!hasChanged"
|
||||||
|
:label="t('globals.reset')"
|
||||||
|
:loading="isLoading"
|
||||||
|
@click="setInitialData"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
icon="restart_alt"
|
||||||
|
type="reset"
|
||||||
|
/>
|
||||||
|
<QBtn
|
||||||
|
:disabled="!hasChanged"
|
||||||
|
:label="t('globals.save')"
|
||||||
|
:loading="isLoading"
|
||||||
|
@click="onSubmit"
|
||||||
|
color="primary"
|
||||||
|
icon="save"
|
||||||
|
/>
|
||||||
|
</QBtnGroup>
|
||||||
|
</Teleport>
|
||||||
|
|
||||||
|
<div class="full-width flex justify-center">
|
||||||
|
<QCard class="card-width q-pa-lg">
|
||||||
|
<QForm>
|
||||||
|
<div class="col">
|
||||||
|
<VnSelectFilter
|
||||||
|
:label="t('Sample')"
|
||||||
|
:options="optionsSamplesVisible"
|
||||||
|
@update:model-value="setSampleType"
|
||||||
|
hide-selected
|
||||||
|
option-label="description"
|
||||||
|
option-value="id"
|
||||||
|
v-model="initialData.typeFk"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
|
<div class="col">
|
||||||
|
<VnInput
|
||||||
|
:label="t('Recipient')"
|
||||||
|
@update:model-value="updateModelValue"
|
||||||
|
clearable
|
||||||
|
required="true"
|
||||||
|
v-model="initialData.recipient"
|
||||||
|
>
|
||||||
|
<template #append>
|
||||||
|
<QIcon name="info" class="cursor-pointer">
|
||||||
|
<QTooltip>{{
|
||||||
|
t('Its only used when sample is sent')
|
||||||
|
}}</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
</template>
|
||||||
|
</VnInput>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<VnInput
|
||||||
|
:label="t('Reply to')"
|
||||||
|
@update:model-value="updateModelValue"
|
||||||
|
clearable
|
||||||
|
required="true"
|
||||||
|
v-model="initialData.replyTo"
|
||||||
|
>
|
||||||
|
<template #append>
|
||||||
|
<QIcon name="info" class="cursor-pointer">
|
||||||
|
<QTooltip>{{
|
||||||
|
t('To who should the recipient replay?')
|
||||||
|
}}</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
</template>
|
||||||
|
</VnInput>
|
||||||
|
</div>
|
||||||
|
</VnRow>
|
||||||
|
|
||||||
|
<VnRow
|
||||||
|
class="row q-gutter-md q-mb-md"
|
||||||
|
v-if="sampleType?.hasCompany || sampleType?.datepickerEnabled"
|
||||||
|
>
|
||||||
|
<div class="col">
|
||||||
|
<VnSelectFilter
|
||||||
|
:label="t('Company')"
|
||||||
|
:options="optionsCompanies"
|
||||||
|
:rules="validate('entry.companyFk')"
|
||||||
|
hide-selected
|
||||||
|
option-label="code"
|
||||||
|
option-value="id"
|
||||||
|
required="true"
|
||||||
|
v-model="initialData.companyFk"
|
||||||
|
v-if="sampleType.hasCompany"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<VnSelectFilter
|
||||||
|
:label="t('Address')"
|
||||||
|
:options="optionsClientsAddressess"
|
||||||
|
hide-selected
|
||||||
|
option-label="nickname"
|
||||||
|
option-value="id"
|
||||||
|
required="true"
|
||||||
|
v-model="initialData.addressId"
|
||||||
|
v-if="sampleType.id === 20"
|
||||||
|
>
|
||||||
|
<template #option="scope">
|
||||||
|
<QItem v-bind="scope.itemProps">
|
||||||
|
<QItemSection>
|
||||||
|
<QItemLabel>
|
||||||
|
{{
|
||||||
|
`${scope.opt.nickname}, ${scope.opt.street}, ${scope.opt.city}, ${scope.opt.province.name} - ${scope.opt.agencyMode.name}`
|
||||||
|
}}
|
||||||
|
</QItemLabel>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
</template>
|
||||||
|
<template #append>
|
||||||
|
<QIcon name="edit" class="cursor-pointer">
|
||||||
|
<QTooltip>{{ t('Edit address') }}</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
</template>
|
||||||
|
</VnSelectFilter>
|
||||||
|
</div>
|
||||||
|
</VnRow>
|
||||||
|
|
||||||
|
<VnRow
|
||||||
|
class="row q-gutter-md q-mb-md"
|
||||||
|
v-if="sampleType?.datepickerEnabled"
|
||||||
|
>
|
||||||
|
<div class="col">
|
||||||
|
<VnInputDate
|
||||||
|
:label="t('Since')"
|
||||||
|
required="true"
|
||||||
|
v-model="initialData.from"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</VnRow>
|
||||||
|
</QForm>
|
||||||
|
</QCard>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
Sample: Plantilla
|
||||||
|
Recipient: Destinatario
|
||||||
|
Reply to: Responder a
|
||||||
|
Company: Empresa
|
||||||
|
Address: Dirección
|
||||||
|
Since: Desde
|
||||||
|
Its only used when sample is sent: Se utiliza únicamente cuando se envía la plantilla
|
||||||
|
To who should the recipient replay?: ¿A quien debería responder el destinatario?
|
||||||
|
Edit address: Editar dirección
|
||||||
|
Preview: Vista previa
|
||||||
|
Email cannot be blank: Debes introducir un email
|
||||||
|
Choose a sample: Selecciona una plantilla
|
||||||
|
Choose a company: Selecciona una empresa
|
||||||
|
Choose a date: Selecciona una fecha
|
||||||
|
</i18n>
|
|
@ -0,0 +1,34 @@
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { useDialogPluginComponent } from 'quasar';
|
||||||
|
|
||||||
|
const { dialogRef } = useDialogPluginComponent();
|
||||||
|
|
||||||
|
const closeButton = ref(null);
|
||||||
|
|
||||||
|
const $props = defineProps({
|
||||||
|
htmlContent: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<QDialog ref="dialogRef" full-width>
|
||||||
|
<QCard class="dialog-width q-pa-lg">
|
||||||
|
<QCardSection>
|
||||||
|
<span ref="closeButton" class="row justify-end close-icon" v-close-popup>
|
||||||
|
<QIcon name="close" size="sm" />
|
||||||
|
</span>
|
||||||
|
<div v-html="$props.htmlContent" />
|
||||||
|
</QCardSection>
|
||||||
|
</QCard>
|
||||||
|
</QDialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.dialog-width {
|
||||||
|
max-width: 900px !important;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,247 @@
|
||||||
|
<script setup>
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
import { QBtn, date } from 'quasar';
|
||||||
|
|
||||||
|
import { toCurrency } from 'src/filters';
|
||||||
|
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
|
import CustomerSummaryTableActions from './CustomerSummaryTableActions.vue';
|
||||||
|
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
|
||||||
|
import RouteDescriptorProxy from 'src/pages/Route/Card/RouteDescriptorProxy.vue';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const rows = ref([]);
|
||||||
|
|
||||||
|
const filter = {
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
relation: 'ticketState',
|
||||||
|
scope: {
|
||||||
|
fields: ['stateFk', 'code', 'alertLevel'],
|
||||||
|
include: { relation: 'state' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ relation: 'invoiceOut', scope: { fields: ['id'] } },
|
||||||
|
{ relation: 'agencyMode', scope: { fields: ['name'] } },
|
||||||
|
],
|
||||||
|
where: { clientFk: route.params.id },
|
||||||
|
order: ['shipped DESC', 'id'],
|
||||||
|
limit: 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
const tableColumnComponents = {
|
||||||
|
id: {
|
||||||
|
component: 'span',
|
||||||
|
props: () => {},
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
nickname: {
|
||||||
|
component: QBtn,
|
||||||
|
props: () => ({ flat: true, color: 'blue', noCaps: true }),
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
agency: {
|
||||||
|
component: 'span',
|
||||||
|
props: () => {},
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
route: {
|
||||||
|
component: QBtn,
|
||||||
|
props: () => ({ flat: true, color: 'blue' }),
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
packages: {
|
||||||
|
component: 'span',
|
||||||
|
props: () => {},
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
date: {
|
||||||
|
component: 'span',
|
||||||
|
props: () => {},
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
state: {
|
||||||
|
component: 'span',
|
||||||
|
props: () => {},
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
total: {
|
||||||
|
component: 'span',
|
||||||
|
props: () => {},
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
component: CustomerSummaryTableActions,
|
||||||
|
props: (prop) => ({
|
||||||
|
id: prop.row.id,
|
||||||
|
}),
|
||||||
|
event: () => {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const columns = computed(() => [
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: 'id',
|
||||||
|
label: t('Id'),
|
||||||
|
name: 'id',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: 'nickname',
|
||||||
|
label: t('Nickname'),
|
||||||
|
name: 'nickname',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: (row) => row?.agencyMode?.name,
|
||||||
|
label: t('Agency'),
|
||||||
|
name: 'agency',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: 'routeFk',
|
||||||
|
label: t('Route'),
|
||||||
|
name: 'route',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: 'packages',
|
||||||
|
label: t('Packages'),
|
||||||
|
name: 'packages',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: (row) => date.formatDate(row?.shipped, 'DD/MM/YYYY'),
|
||||||
|
label: t('Date'),
|
||||||
|
name: 'date',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: (row) => row?.ticketState?.state?.name,
|
||||||
|
label: t('State'),
|
||||||
|
name: 'state',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: 'totalWithVat',
|
||||||
|
label: t('Total'),
|
||||||
|
name: 'total',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
field: 'totalWithVat',
|
||||||
|
label: '',
|
||||||
|
name: 'actions',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const setStateColor = (ticket) => {
|
||||||
|
const { ticketState } = ticket;
|
||||||
|
if (!ticketState) return;
|
||||||
|
const codeColorMap = { OK: 'success', FREE: 'notice' };
|
||||||
|
const alertLevelColorMap = { 0: 'alert', 1: 'warning' };
|
||||||
|
if (codeColorMap[ticketState.code]) return codeColorMap[ticketState.code];
|
||||||
|
return alertLevelColorMap[ticketState.alertLevel];
|
||||||
|
};
|
||||||
|
|
||||||
|
const setTotalPriceColor = (ticket) => {
|
||||||
|
const total = parseInt(ticket.totalWithVat);
|
||||||
|
if (total > 0 && total < 50) return 'warning';
|
||||||
|
};
|
||||||
|
|
||||||
|
const navigateToticketSummary = (id) => {
|
||||||
|
router.push({
|
||||||
|
name: 'TicketSummary',
|
||||||
|
params: { id },
|
||||||
|
});
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<FetchData
|
||||||
|
:filter="filter"
|
||||||
|
@on-fetch="(data) => (rows = data)"
|
||||||
|
auto-load
|
||||||
|
url="Tickets"
|
||||||
|
/>
|
||||||
|
<QTable
|
||||||
|
:columns="columns"
|
||||||
|
:pagination="{ rowsPerPage: 12 }"
|
||||||
|
:rows="rows"
|
||||||
|
class="full-width q-mt-md"
|
||||||
|
row-key="id"
|
||||||
|
v-if="rows?.length"
|
||||||
|
>
|
||||||
|
<template #body-cell="props">
|
||||||
|
<QTd :props="props" @click="navigateToticketSummary(props.row.id)">
|
||||||
|
<QTr :props="props" class="cursor-pointer">
|
||||||
|
<component
|
||||||
|
:is="tableColumnComponents[props.col.name].component"
|
||||||
|
@click="tableColumnComponents[props.col.name].event(props)"
|
||||||
|
class="rounded-borders q-pa-sm"
|
||||||
|
v-bind="tableColumnComponents[props.col.name].props(props)"
|
||||||
|
>
|
||||||
|
<template
|
||||||
|
v-if="
|
||||||
|
props.col.name === 'id' ||
|
||||||
|
props.col.name === 'nickname' ||
|
||||||
|
props.col.name === 'agency' ||
|
||||||
|
props.col.name === 'route' ||
|
||||||
|
props.col.name === 'packages'
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ props.value }}
|
||||||
|
</template>
|
||||||
|
<template v-if="props.col.name === 'date'">
|
||||||
|
<QBadge class="q-pa-sm" color="warning">
|
||||||
|
{{ props.value }}
|
||||||
|
</QBadge>
|
||||||
|
</template>
|
||||||
|
<template v-if="props.col.name === 'state'">
|
||||||
|
<QBadge :color="setStateColor(props.row)" class="q-pa-sm">
|
||||||
|
{{ props.value }}
|
||||||
|
</QBadge>
|
||||||
|
</template>
|
||||||
|
<template v-if="props.col.name === 'total'">
|
||||||
|
<QBadge
|
||||||
|
:color="setTotalPriceColor(props.row)"
|
||||||
|
class="q-pa-sm"
|
||||||
|
v-if="setTotalPriceColor(props.row)"
|
||||||
|
>
|
||||||
|
{{ toCurrency(props.value) }}
|
||||||
|
</QBadge>
|
||||||
|
<div v-else>{{ toCurrency(props.value) }}</div>
|
||||||
|
</template>
|
||||||
|
<CustomerDescriptorProxy
|
||||||
|
:id="props.row.clientFk"
|
||||||
|
v-if="props.col.name === 'nickname'"
|
||||||
|
/>
|
||||||
|
<RouteDescriptorProxy
|
||||||
|
:id="props.row.routeFk"
|
||||||
|
v-if="props.col.name === 'route'"
|
||||||
|
/>
|
||||||
|
</component>
|
||||||
|
</QTr>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
</QTable>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
Id: Id
|
||||||
|
Nickname: Alias
|
||||||
|
Agency: Agencia
|
||||||
|
Route: Ruta
|
||||||
|
Packages: Bultos
|
||||||
|
Date: Fecha
|
||||||
|
State: Estado
|
||||||
|
Total: Total
|
||||||
|
</i18n>
|
|
@ -0,0 +1,44 @@
|
||||||
|
<script setup>
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
|
||||||
|
import TicketSummary from 'src/pages/Ticket/Card/TicketSummary.vue';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
id: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { viewSummary } = useSummaryDialog();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<QIcon color="primary" name="vn:lines" size="sm">
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('Go to lines') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
<QIcon
|
||||||
|
@click.stop="viewSummary(id, TicketSummary)"
|
||||||
|
class="q-ml-md"
|
||||||
|
color="primary"
|
||||||
|
name="preview"
|
||||||
|
size="sm"
|
||||||
|
>
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('Preview') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
Go to lines: Ir a lineas
|
||||||
|
Preview: Vista previa
|
||||||
|
</i18n>
|
|
@ -0,0 +1,73 @@
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import axios from 'axios';
|
||||||
|
import { useDialogPluginComponent } from 'quasar';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const { dialogRef } = useDialogPluginComponent();
|
||||||
|
|
||||||
|
const closeButton = ref(null);
|
||||||
|
|
||||||
|
const $props = defineProps({
|
||||||
|
id: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
promise: {
|
||||||
|
type: Function,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const isLoading = ref(false);
|
||||||
|
|
||||||
|
const saveData = async () => {
|
||||||
|
const timestamp = new Date().getTime();
|
||||||
|
const payload = {
|
||||||
|
finished: timestamp,
|
||||||
|
};
|
||||||
|
await axios.patch(`CreditClassifications/${$props.id}`, payload);
|
||||||
|
$props.promise();
|
||||||
|
closeButton.value.click();
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<QDialog ref="dialogRef">
|
||||||
|
<QCard class="q-pa-sm">
|
||||||
|
<span
|
||||||
|
ref="closeButton"
|
||||||
|
class="flex justify-end cursor-pointer q-mb-sm"
|
||||||
|
v-close-popup
|
||||||
|
>
|
||||||
|
<QIcon name="close" size="sm" />
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<QCardSection>
|
||||||
|
<div class="text-h6 q-mb-sm">
|
||||||
|
{{ t('Are you sure you want to close this contract?') }}
|
||||||
|
</div>
|
||||||
|
<div class="q-mb-sm">{{ t('Close contract') }}</div>
|
||||||
|
</QCardSection>
|
||||||
|
|
||||||
|
<QCardActions align="right">
|
||||||
|
<QBtn :label="t('globals.cancel')" color="primary" flat v-close-popup />
|
||||||
|
<QBtn
|
||||||
|
:label="t('globals.confirm')"
|
||||||
|
color="primary"
|
||||||
|
:loading="isLoading"
|
||||||
|
@click="saveData"
|
||||||
|
unelevated
|
||||||
|
/>
|
||||||
|
</QCardActions>
|
||||||
|
</QCard>
|
||||||
|
</QDialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
Are you sure you want to close this contract?: ¿Seguro que quieres cerrar este contrato?
|
||||||
|
Close contract: Cerrar contrato
|
||||||
|
</i18n>
|
|
@ -1,3 +1,5 @@
|
||||||
|
Search customer: Buscar cliente
|
||||||
|
You can search by customer id or name: Puedes buscar por id o nombre del cliente
|
||||||
customerFilter:
|
customerFilter:
|
||||||
filter:
|
filter:
|
||||||
name: Nombre
|
name: Nombre
|
||||||
|
|
|
@ -1,26 +1,13 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
import VnCard from 'components/common/VnCard.vue';
|
||||||
import DepartmentDescriptor from 'pages/Department/Card/DepartmentDescriptor.vue';
|
import DepartmentDescriptor from 'pages/Department/Card/DepartmentDescriptor.vue';
|
||||||
import LeftMenu from 'components/LeftMenu.vue';
|
|
||||||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
|
||||||
|
|
||||||
const stateStore = useStateStore();
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<QDrawer v-model="stateStore.leftDrawer" show-if-above :width="256">
|
<VnCard
|
||||||
<QScrollArea class="fit">
|
class="q-pa-md column items-center"
|
||||||
<DepartmentDescriptor />
|
v-bind="{ ...$attrs }"
|
||||||
<QSeparator />
|
data-key="Department"
|
||||||
<LeftMenu source="card" />
|
base-url="Departments"
|
||||||
</QScrollArea>
|
:descriptor="DepartmentDescriptor"
|
||||||
</QDrawer>
|
/>
|
||||||
<QPageContainer>
|
|
||||||
<QPage>
|
|
||||||
<VnSubToolbar />
|
|
||||||
|
|
||||||
<div class="q-pa-md column items-center">
|
|
||||||
<RouterView></RouterView>
|
|
||||||
</div>
|
|
||||||
</QPage>
|
|
||||||
</QPageContainer>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -27,6 +27,7 @@ onMounted(async () => {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<CardSummary
|
<CardSummary
|
||||||
|
data-key="DepartmentSummary"
|
||||||
ref="summary"
|
ref="summary"
|
||||||
:url="`Departments/${entityId}`"
|
:url="`Departments/${entityId}`"
|
||||||
class="full-width"
|
class="full-width"
|
||||||
|
|
|
@ -1,48 +1,15 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useI18n } from 'vue-i18n';
|
import VnCard from 'components/common/VnCard.vue';
|
||||||
|
|
||||||
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
|
|
||||||
import LeftMenu from 'components/LeftMenu.vue';
|
|
||||||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
|
||||||
import EntryDescriptor from './EntryDescriptor.vue';
|
import EntryDescriptor from './EntryDescriptor.vue';
|
||||||
|
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
|
||||||
import useCardSize from 'src/composables/useCardSize';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
const stateStore = useStateStore();
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<template v-if="stateStore.isHeaderMounted()">
|
<VnCard
|
||||||
<Teleport to="#searchbar">
|
data-key="Entry"
|
||||||
<VnSearchbar
|
base-url="Entries"
|
||||||
data-key="EntryList"
|
:descriptor="EntryDescriptor"
|
||||||
url="Entries/filter"
|
searchbar-data-key="EntryList"
|
||||||
:label="t('Search entries')"
|
searchbar-url="Entries/filter"
|
||||||
:info="t('You can search by entry reference')"
|
searchbar-label="Search entries"
|
||||||
/>
|
searchbar-info="You can search by entry reference"
|
||||||
</Teleport>
|
/>
|
||||||
</template>
|
|
||||||
<QDrawer v-model="stateStore.leftDrawer" show-if-above :width="256">
|
|
||||||
<QScrollArea class="fit">
|
|
||||||
<EntryDescriptor />
|
|
||||||
<QSeparator />
|
|
||||||
<LeftMenu source="card" />
|
|
||||||
</QScrollArea>
|
|
||||||
</QDrawer>
|
|
||||||
<QPageContainer>
|
|
||||||
<QPage>
|
|
||||||
<VnSubToolbar />
|
|
||||||
|
|
||||||
<div :class="useCardSize()">
|
|
||||||
<RouterView></RouterView>
|
|
||||||
</div>
|
|
||||||
</QPage>
|
|
||||||
</QPageContainer>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<i18n>
|
|
||||||
es:
|
|
||||||
Search entries: Buscar entradas
|
|
||||||
You can search by entry reference: Puedes buscar por referencia de la entrada
|
|
||||||
</i18n>
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
Search entries: Buscar entradas
|
||||||
|
You can search by entry reference: Puedes buscar por referencia de la entrada
|
||||||
entryList:
|
entryList:
|
||||||
list:
|
list:
|
||||||
inventoryEntry: Es inventario
|
inventoryEntry: Es inventario
|
||||||
|
|
|
@ -1,18 +1,6 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useI18n } from 'vue-i18n';
|
import VnCard from 'components/common/VnCard.vue';
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
|
||||||
import InvoiceInDescriptor from './InvoiceInDescriptor.vue';
|
import InvoiceInDescriptor from './InvoiceInDescriptor.vue';
|
||||||
import LeftMenu from 'components/LeftMenu.vue';
|
|
||||||
import VnSearchbar from 'components/ui/VnSearchbar.vue';
|
|
||||||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
|
||||||
import { useArrayData } from 'src/composables/useArrayData';
|
|
||||||
import { onMounted, watch } from 'vue';
|
|
||||||
import { useRoute } from 'vue-router';
|
|
||||||
import useCardSize from 'src/composables/useCardSize';
|
|
||||||
|
|
||||||
const stateStore = useStateStore();
|
|
||||||
const { t } = useI18n();
|
|
||||||
const route = useRoute();
|
|
||||||
|
|
||||||
const filter = {
|
const filter = {
|
||||||
include: [
|
include: [
|
||||||
|
@ -21,69 +9,25 @@ const filter = {
|
||||||
scope: {
|
scope: {
|
||||||
include: {
|
include: {
|
||||||
relation: 'contacts',
|
relation: 'contacts',
|
||||||
scope: {
|
scope: { where: { email: { neq: null } } },
|
||||||
where: {
|
|
||||||
email: { neq: null },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{ relation: 'invoiceInDueDay' },
|
||||||
relation: 'invoiceInDueDay',
|
{ relation: 'company' },
|
||||||
},
|
{ relation: 'currency' },
|
||||||
{
|
|
||||||
relation: 'company',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
relation: 'currency',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
const arrayData = useArrayData('InvoiceIn', {
|
|
||||||
url: `InvoiceIns/${route.params.id}`,
|
|
||||||
filter,
|
|
||||||
});
|
|
||||||
|
|
||||||
onMounted(async () => await arrayData.fetch({ append: false }));
|
|
||||||
watch(
|
|
||||||
() => route.params.id,
|
|
||||||
async (newId, oldId) => {
|
|
||||||
if (newId) {
|
|
||||||
arrayData.store.url = `InvoiceIns/${newId}`;
|
|
||||||
await arrayData.fetch({ append: false });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<Teleport to="#searchbar" v-if="stateStore.isHeaderMounted()">
|
<VnCard
|
||||||
<VnSearchbar
|
data-key="InvoiceIn"
|
||||||
data-key="InvoiceInList"
|
base-url="InvoiceIns"
|
||||||
url="InvoiceIns/filter"
|
:filter="filter"
|
||||||
:label="t('Search invoice')"
|
:descriptor="InvoiceInDescriptor"
|
||||||
:info="t('You can search by invoice reference')"
|
searchbar-data-key="InvoiceInList"
|
||||||
/>
|
searchbar-url="InvoiceIns/filter"
|
||||||
</Teleport>
|
searchbar-label="Search invoice"
|
||||||
<QDrawer v-model="stateStore.leftDrawer" show-if-above :width="256">
|
searchbar-info="You can search by invoice reference"
|
||||||
<QScrollArea class="fit">
|
/>
|
||||||
<InvoiceInDescriptor />
|
|
||||||
<QSeparator />
|
|
||||||
<LeftMenu source="card" />
|
|
||||||
</QScrollArea>
|
|
||||||
</QDrawer>
|
|
||||||
<QPageContainer>
|
|
||||||
<QPage>
|
|
||||||
<VnSubToolbar />
|
|
||||||
<div :class="useCardSize()">
|
|
||||||
<RouterView></RouterView>
|
|
||||||
</div>
|
|
||||||
</QPage>
|
|
||||||
</QPageContainer>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<i18n>
|
|
||||||
es:
|
|
||||||
Search invoice: Buscar factura recibida
|
|
||||||
You can search by invoice reference: Puedes buscar por referencia de la factura
|
|
||||||
</i18n>
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
|
||||||
import FetchData from 'components/FetchData.vue';
|
import FetchData from 'components/FetchData.vue';
|
||||||
import VnInput from 'src/components/common/VnInput.vue';
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
import VnInputDate from 'components/common/VnInputDate.vue';
|
import VnInputDate from 'components/common/VnInputDate.vue';
|
||||||
import { useCapitalize } from 'src/composables/useCapitalize';
|
|
||||||
import VnCurrency from 'src/components/common/VnCurrency.vue';
|
import VnCurrency from 'src/components/common/VnCurrency.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -70,19 +69,15 @@ const suppliersRef = ref();
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
<QItem>
|
<QItem>
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<VnInputDate
|
<VnInputDate :label="t('From')" v-model="params.from" is-outlined />
|
||||||
:label="t('From')"
|
</QItemSection>
|
||||||
v-model="params.from"
|
</QItem>
|
||||||
is-outlined
|
<QItem>
|
||||||
/>
|
<QItemSection>
|
||||||
</QItemSection>
|
<VnInputDate :label="t('To')" v-model="params.to" is-outlined />
|
||||||
</QItem>
|
</QItemSection>
|
||||||
<QItem>
|
</QItem>
|
||||||
<QItemSection>
|
|
||||||
<VnInputDate :label="t('To')" v-model="params.to" is-outlined />
|
|
||||||
</QItemSection>
|
|
||||||
</QItem>
|
|
||||||
<QItem>
|
<QItem>
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<VnInput
|
<VnInput
|
||||||
|
@ -114,33 +109,33 @@ const suppliersRef = ref();
|
||||||
</QItem>
|
</QItem>
|
||||||
<QExpansionItem :label="t('More options')" expand-separator>
|
<QExpansionItem :label="t('More options')" expand-separator>
|
||||||
<QItem>
|
<QItem>
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<VnInput
|
<VnInput
|
||||||
:label="t('params.fi')"
|
:label="t('params.fi')"
|
||||||
v-model="params.fi"
|
v-model="params.fi"
|
||||||
is-outlined
|
is-outlined
|
||||||
lazy-rules
|
lazy-rules
|
||||||
>
|
>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<QIcon name="badge" size="sm"></QIcon>
|
<QIcon name="badge" size="sm"></QIcon>
|
||||||
</template>
|
</template>
|
||||||
</VnInput>
|
</VnInput>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
<QItem>
|
<QItem>
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<VnInput
|
<VnInput
|
||||||
:label="t('params.serialNumber')"
|
:label="t('params.serialNumber')"
|
||||||
v-model="params.serialNumber"
|
v-model="params.serialNumber"
|
||||||
is-outlined
|
is-outlined
|
||||||
lazy-rules
|
lazy-rules
|
||||||
>
|
>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<QIcon name="badge" size="sm"></QIcon>
|
<QIcon name="badge" size="sm"></QIcon>
|
||||||
</template>
|
</template>
|
||||||
</VnInput>
|
</VnInput>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
<QItem>
|
<QItem>
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<VnInput
|
<VnInput
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Search invoice: Buscar factura recibida
|
||||||
|
You can search by invoice reference: Puedes buscar por referencia de la factura
|
|
@ -1,43 +1,15 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useI18n } from 'vue-i18n';
|
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
|
||||||
import InvoiceOutDescriptor from './InvoiceOutDescriptor.vue';
|
import InvoiceOutDescriptor from './InvoiceOutDescriptor.vue';
|
||||||
import LeftMenu from 'components/LeftMenu.vue';
|
import VnCard from 'components/common/VnCard.vue';
|
||||||
import VnSearchbar from 'components/ui/VnSearchbar.vue';
|
|
||||||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
|
||||||
import useCardSize from 'src/composables/useCardSize';
|
|
||||||
|
|
||||||
const stateStore = useStateStore();
|
|
||||||
const { t } = useI18n();
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<Teleport to="#searchbar" v-if="stateStore.isHeaderMounted()">
|
<VnCard
|
||||||
<VnSearchbar
|
data-key="InvoiceOut"
|
||||||
data-key="InvoiceOutList"
|
base-url="InvoiceOuts"
|
||||||
url="InvoiceOuts/filter"
|
:descriptor="InvoiceOutDescriptor"
|
||||||
:label="t('Search invoice')"
|
searchbar-data-key="InvoiceOutList"
|
||||||
:info="t('You can search by invoice reference')"
|
searchbar-url="InvoiceOuts/filter"
|
||||||
/>
|
searchbar-label="Search invoice"
|
||||||
</Teleport>
|
searchbar-info="You can search by invoice reference"
|
||||||
<QDrawer v-model="stateStore.leftDrawer" show-if-above :width="256">
|
/>
|
||||||
<QScrollArea class="fit">
|
|
||||||
<InvoiceOutDescriptor />
|
|
||||||
<QSeparator />
|
|
||||||
<LeftMenu source="card" />
|
|
||||||
</QScrollArea>
|
|
||||||
</QDrawer>
|
|
||||||
<QPageContainer>
|
|
||||||
<QPage>
|
|
||||||
<VnSubToolbar />
|
|
||||||
<div :class="useCardSize()">
|
|
||||||
<RouterView></RouterView>
|
|
||||||
</div>
|
|
||||||
</QPage>
|
|
||||||
</QPageContainer>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<i18n>
|
|
||||||
es:
|
|
||||||
Search invoice: Buscar factura emitida
|
|
||||||
You can search by invoice reference: Puedes buscar por referencia de la factura
|
|
||||||
</i18n>
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Search invoice: Buscar factura emitida
|
||||||
|
You can search by invoice reference: Puedes buscar por referencia de la factura
|
|
@ -1,28 +1,7 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import LeftMenu from 'components/LeftMenu.vue';
|
import VnCard from 'components/common/VnCard.vue';
|
||||||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
|
||||||
import ItemDescriptor from './ItemDescriptor.vue';
|
import ItemDescriptor from './ItemDescriptor.vue';
|
||||||
|
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
|
||||||
import useCardSize from 'src/composables/useCardSize';
|
|
||||||
|
|
||||||
const stateStore = useStateStore();
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<QDrawer v-model="stateStore.leftDrawer" show-if-above :width="256">
|
<VnCard data-key="Item" base-url="Items" :descriptor="ItemDescriptor" />
|
||||||
<QScrollArea class="fit">
|
|
||||||
<ItemDescriptor />
|
|
||||||
<QSeparator />
|
|
||||||
<LeftMenu source="card" />
|
|
||||||
</QScrollArea>
|
|
||||||
</QDrawer>
|
|
||||||
<QPageContainer>
|
|
||||||
<QPage>
|
|
||||||
<VnSubToolbar />
|
|
||||||
|
|
||||||
<div :class="useCardSize()">
|
|
||||||
<RouterView></RouterView>
|
|
||||||
</div>
|
|
||||||
</QPage>
|
|
||||||
</QPageContainer>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,23 +1,7 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import LeftMenu from 'components/LeftMenu.vue';
|
import VnCard from 'components/common/VnCard.vue';
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
|
||||||
import OrderDescriptor from 'pages/Order/Card/OrderDescriptor.vue';
|
import OrderDescriptor from 'pages/Order/Card/OrderDescriptor.vue';
|
||||||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
|
||||||
|
|
||||||
const stateStore = useStateStore();
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<QDrawer v-model="stateStore.leftDrawer" show-if-above :width="256">
|
<VnCard data-key="Order" base-url="Orders" :descriptor="OrderDescriptor" />
|
||||||
<QScrollArea class="fit">
|
|
||||||
<OrderDescriptor />
|
|
||||||
<QSeparator />
|
|
||||||
<LeftMenu source="card" />
|
|
||||||
</QScrollArea>
|
|
||||||
</QDrawer>
|
|
||||||
<QPageContainer>
|
|
||||||
<QPage>
|
|
||||||
<VnSubToolbar />
|
|
||||||
<RouterView></RouterView>
|
|
||||||
</QPage>
|
|
||||||
</QPageContainer>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { reactive, ref } from 'vue';
|
import { reactive, ref, onMounted } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { useState } from 'composables/useState';
|
import { useState } from 'composables/useState';
|
||||||
|
@ -27,6 +27,23 @@ const clientList = ref([]);
|
||||||
const agencyList = ref([]);
|
const agencyList = ref([]);
|
||||||
const addressList = ref([]);
|
const addressList = ref([]);
|
||||||
|
|
||||||
|
const onClientsFetched = async (data) => {
|
||||||
|
try {
|
||||||
|
clientList.value = data;
|
||||||
|
initialFormState.clientFk = Number(route.query?.clientFk) || null;
|
||||||
|
|
||||||
|
if (initialFormState.clientFk) {
|
||||||
|
const { defaultAddressFk } = clientList.value.find(
|
||||||
|
(client) => client.id === initialFormState.clientFk
|
||||||
|
);
|
||||||
|
|
||||||
|
if (defaultAddressFk) await fetchAddressList(defaultAddressFk);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error fetching clients', err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const fetchAddressList = async (addressId) => {
|
const fetchAddressList = async (addressId) => {
|
||||||
try {
|
try {
|
||||||
const { data } = await axios.get('addresses', {
|
const { data } = await axios.get('addresses', {
|
||||||
|
@ -47,6 +64,7 @@ const fetchAddressList = async (addressId) => {
|
||||||
return err.response;
|
return err.response;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchAgencyList = async (landed, addressFk) => {
|
const fetchAgencyList = async (landed, addressFk) => {
|
||||||
if (!landed || !addressFk) {
|
if (!landed || !addressFk) {
|
||||||
return;
|
return;
|
||||||
|
@ -108,7 +126,7 @@ const orderFilter = {
|
||||||
<template>
|
<template>
|
||||||
<FetchData
|
<FetchData
|
||||||
url="Clients"
|
url="Clients"
|
||||||
@on-fetch="(data) => (clientList = data)"
|
@on-fetch="(data) => onClientsFetched(data)"
|
||||||
:filter="{ fields: ['id', 'name', 'defaultAddressFk'] }"
|
:filter="{ fields: ['id', 'name', 'defaultAddressFk'] }"
|
||||||
auto-load
|
auto-load
|
||||||
/>
|
/>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue