#6899 end invoiceOut migration with VnTable #513
|
@ -46,22 +46,6 @@ const onDataSaved = async (formData, requestResponse) => {
|
|||
@on-fetch="(data) => (taxAreasOptions = data)"
|
||||
auto-load
|
||||
/>
|
||||
<FetchData
|
||||
url="Tickets"
|
||||
:filter="{
|
||||
fields: ['id', 'nickname'],
|
||||
where: { refFk: null },
|
||||
order: 'shipped DESC',
|
||||
}"
|
||||
@on-fetch="(data) => (ticketsOptions = data)"
|
||||
auto-load
|
||||
/>
|
||||
<FetchData
|
||||
url="Clients"
|
||||
:filter="{ fields: ['id', 'name'], order: 'name ASC', limit: 30 }"
|
||||
@on-fetch="(data) => (clientsOptions = data)"
|
||||
auto-load
|
||||
/>
|
||||
<FormModelPopup
|
||||
ref="formModelPopupRef"
|
||||
:title="t('Create manual invoice')"
|
||||
|
@ -84,6 +68,10 @@ const onDataSaved = async (formData, requestResponse) => {
|
|||
option-value="id"
|
||||
v-model="data.ticketFk"
|
||||
@update:model-value="data.clientFk = null"
|
||||
url="Tickets"
|
||||
:where="{ refFk: null }"
|
||||
:fields="['id', 'nickname']"
|
||||
:filter-options="{ order: 'shipped DESC' }"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
|
@ -105,6 +93,9 @@ const onDataSaved = async (formData, requestResponse) => {
|
|||
option-value="id"
|
||||
v-model="data.clientFk"
|
||||
@update:model-value="data.ticketFk = null"
|
||||
url="Clients"
|
||||
:fields="['id', 'name']"
|
||||
:filter-options="{ order: 'name ASC' }"
|
||||
/>
|
||||
<VnInputDate :label="t('Max date')" v-model="data.maxShipped" />
|
||||
</VnRow>
|
||||
|
@ -116,7 +107,6 @@ const onDataSaved = async (formData, requestResponse) => {
|
|||
option-label="description"
|
||||
option-value="code"
|
||||
v-model="data.serial"
|
||||
:required="true"
|
||||
/>
|
||||
<VnSelect
|
||||
:label="t('Area')"
|
||||
|
@ -125,7 +115,6 @@ const onDataSaved = async (formData, requestResponse) => {
|
|||
option-label="code"
|
||||
option-value="code"
|
||||
v-model="data.taxArea"
|
||||
:required="true"
|
||||
/>
|
||||
</VnRow>
|
||||
<VnRow class="row q-gutter-md q-mb-md">
|
||||
|
|
|
@ -8,7 +8,7 @@ import VnRow from 'components/ui/VnRow.vue';
|
|||
import FetchData from 'components/FetchData.vue';
|
||||
import VnSelect from 'components/common/VnSelect.vue';
|
||||
import FormPopup from './FormPopup.vue';
|
||||
|
||||
import { useDialogPluginComponent } from 'quasar';
|
||||
import axios from 'axios';
|
||||
import useNotify from 'src/composables/useNotify.js';
|
||||
|
||||
|
@ -18,7 +18,7 @@ const $props = defineProps({
|
|||
default: () => {},
|
||||
},
|
||||
});
|
||||
|
||||
const { dialogRef } = useDialogPluginComponent();
|
||||
const quasar = useQuasar();
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
|
@ -116,6 +116,7 @@ const makeInvoice = async () => {
|
|||
@on-fetch="(data) => (invoiceCorrectionTypesOptions = data)"
|
||||
auto-load
|
||||
/>
|
||||
<QDialog ref="dialogRef">
|
||||
<FormPopup
|
||||
jsegarra marked this conversation as resolved
|
||||
@on-submit="makeInvoice()"
|
||||
:title="t('Transfer invoice')"
|
||||
|
@ -200,6 +201,7 @@ const makeInvoice = async () => {
|
|||
</VnRow>
|
||||
</template>
|
||||
</FormPopup>
|
||||
</QDialog>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
|
|
|
@ -67,6 +67,10 @@ const $props = defineProps({
|
|||
type: Object,
|
||||
default: () => ({ card: false, table: false }),
|
||||
},
|
||||
table: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
const { t } = useI18n();
|
||||
const stateStore = useStateStore();
|
||||
|
@ -249,7 +253,7 @@ defineExpose({
|
|||
</template>
|
||||
<template #body="{ rows }">
|
||||
<QTable
|
||||
v-bind="$attrs['q-table']"
|
||||
v-bind="table"
|
||||
class="vnTable"
|
||||
:columns="splittedColumns.columns"
|
||||
:rows="rows"
|
||||
|
|
|
@ -165,9 +165,9 @@ const toModule = computed(() =>
|
|||
<QTooltip>
|
||||
{{ t('components.cardDescriptor.moreOptions') }}
|
||||
</QTooltip>
|
||||
<QMenu>
|
||||
<QMenu ref="menuRef">
|
||||
<QList>
|
||||
<slot name="menu" :entity="entity" />
|
||||
<slot name="menu" :entity="entity" :menu-ref="menuRef" />
|
||||
</QList>
|
||||
</QMenu>
|
||||
</QBtn>
|
||||
|
|
|
@ -63,8 +63,8 @@ const setData = (entity) => (data.value = useCardDescription(entity.ref, entity.
|
|||
@on-fetch="setData"
|
||||
data-key="invoiceOutData"
|
||||
>
|
||||
<template #menu="{ entity }">
|
||||
<InvoiceOutDescriptorMenu :invoice-out-data="entity" />
|
||||
<template #menu="{ entity, menuRef }">
|
||||
<InvoiceOutDescriptorMenu :invoice-out-data="entity" :menu-ref="menuRef" />
|
||||
</template>
|
||||
<template #body="{ entity }">
|
||||
<VnLv :label="t('invoiceOut.card.issued')" :value="toDate(entity.issued)" />
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { ref, onBeforeMount } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useQuasar } from 'quasar';
|
||||
|
@ -11,13 +11,20 @@ import useNotify from 'src/composables/useNotify';
|
|||
import { useSession } from 'src/composables/useSession';
|
||||
import { usePrintService } from 'composables/usePrintService';
|
||||
import { useVnConfirm } from 'composables/useVnConfirm';
|
||||
import { getUrl } from 'src/composables/getUrl';
|
||||
import axios from 'axios';
|
||||
|
||||
onBeforeMount(async () => (salixUrl.value = await getUrl('')));
|
||||
|
||||
const $props = defineProps({
|
||||
invoiceOutData: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
menuRef: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
});
|
||||
|
||||
const { notify } = useNotify();
|
||||
|
@ -28,8 +35,7 @@ const { t } = useI18n();
|
|||
const { openReport, sendEmail } = usePrintService();
|
||||
const { openConfirmationModal } = useVnConfirm();
|
||||
const quasar = useQuasar();
|
||||
|
||||
const transferInvoiceDialogRef = ref();
|
||||
const salixUrl = ref();
|
||||
const invoiceFormType = ref('pdf');
|
||||
const defaultEmailAddress = ref($props.invoiceOutData.client?.email);
|
||||
|
||||
|
@ -115,6 +121,7 @@ const refundInvoice = async (withWarehouse) => {
|
|||
try {
|
||||
const params = { ref: $props.invoiceOutData.ref, withWarehouse: withWarehouse };
|
||||
const { data } = await axios.post('InvoiceOuts/refund', params);
|
||||
location.href = window.origin + `/#/ticket/${data[0].id}/sale`;
|
||||
notify(
|
||||
t('refundInvoiceSuccessMessage', {
|
||||
refundTicket: data[0].id,
|
||||
|
@ -125,11 +132,22 @@ const refundInvoice = async (withWarehouse) => {
|
|||
console.error('Error generating invoice out pdf', err);
|
||||
}
|
||||
};
|
||||
|
||||
const showTransferInvoiceForm = async () => {
|
||||
quasar.dialog({
|
||||
jsegarra marked this conversation as resolved
jsegarra
commented
Ufff... me suena que esto ya pasó una vez y lo corregimos Ufff... me suena que esto ya pasó una vez y lo corregimos
|
||||
component: TransferInvoiceForm,
|
||||
componentProps: {
|
||||
invoiceOutData: $props.invoiceOutData,
|
||||
},
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<QItem v-ripple clickable @click="transferInvoiceDialogRef.show()">
|
||||
<QItemSection>{{ t('Transfer invoice to...') }}</QItemSection>
|
||||
<QItem v-ripple clickable>
|
||||
<QItemSection @click="showTransferInvoiceForm()">{{
|
||||
t('Transfer invoice to...')
|
||||
}}</QItemSection>
|
||||
</QItem>
|
||||
<QItem v-ripple clickable>
|
||||
<QItemSection>{{ t('Show invoice...') }}</QItemSection>
|
||||
|
@ -222,10 +240,6 @@ const refundInvoice = async (withWarehouse) => {
|
|||
{{ t('Create a single ticket with all the content of the current invoice') }}
|
||||
</QTooltip>
|
||||
</QItem>
|
||||
|
||||
<QDialog ref="transferInvoiceDialogRef">
|
||||
<TransferInvoiceForm :invoice-out-data="invoiceOutData" />
|
||||
</QDialog>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
|
|
|
@ -3,7 +3,7 @@ import { onMounted, ref, computed } from 'vue';
|
|||
import { useRoute } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import axios from 'axios';
|
||||
import { toCurrency, toDate } from 'src/filters';
|
||||
import { toCurrency, toDate, toPercentage } from 'src/filters';
|
||||
jon marked this conversation as resolved
jsegarra
commented
Hay una traducción que no va bien Hay una traducción que no va bien
|
||||
import CardSummary from 'components/ui/CardSummary.vue';
|
||||
import VnLv from 'src/components/ui/VnLv.vue';
|
||||
import { getUrl } from 'src/composables/getUrl';
|
||||
|
@ -57,12 +57,14 @@ const taxColumns = ref([
|
|||
name: 'quantity',
|
||||
label: 'invoiceOut.summary.rate',
|
||||
field: (row) => row.rate,
|
||||
format: (value) => toPercentage(value / 100),
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'invoiceOuted',
|
||||
label: 'invoiceOut.summary.fee',
|
||||
field: (row) => row.vat,
|
||||
format: (value) => toCurrency(value),
|
||||
sortable: true,
|
||||
},
|
||||
]);
|
||||
|
@ -113,7 +115,7 @@ const ticketsColumns = ref([
|
|||
</template>
|
||||
<template #body="{ entity: { invoiceOut } }">
|
||||
<QCard class="vn-one">
|
||||
<VnTitle :text="t('invoiceOut.pageTitles.basicData')" />
|
||||
<VnTitle :text="t('globals.pageTitles.basicData')" />
|
||||
<VnLv
|
||||
:label="t('invoiceOut.summary.issued')"
|
||||
:value="toDate(invoiceOut.issued)"
|
||||
|
@ -164,7 +166,7 @@ const ticketsColumns = ref([
|
|||
</template>
|
||||
<template #body-cell-item="{ value }">
|
||||
<QTd>
|
||||
<QBtn flat color="primary">
|
||||
<QBtn flat class="link">
|
||||
{{ value }}
|
||||
<TicketDescriptorProxy :id="value" />
|
||||
</QBtn>
|
||||
|
@ -172,7 +174,7 @@ const ticketsColumns = ref([
|
|||
</template>
|
||||
<template #body-cell-quantity="{ value, row }">
|
||||
<QTd>
|
||||
<QBtn class="no-uppercase" flat color="primary" dense>
|
||||
<QBtn class="no-uppercase link" flat dense>
|
||||
{{ value }}
|
||||
<CustomerDescriptorProxy :id="row.id" />
|
||||
</QBtn>
|
||||
|
|
|
@ -41,7 +41,7 @@ function setWorkers(data) {
|
|||
<span>{{ formatFn(tag.value) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #body="{ params, searchFn }">
|
||||
<template #body="{ params }">
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<VnInput
|
||||
|
@ -93,7 +93,6 @@ function setWorkers(data) {
|
|||
<QItemSection>
|
||||
<QCheckbox
|
||||
:label="t('Has PDF')"
|
||||
@update:model-value="searchFn()"
|
||||
toggle-indeterminate
|
||||
v-model="params.hasPdf"
|
||||
/>
|
||||
|
|
|
@ -30,7 +30,7 @@ const selectedCustomerId = ref(null);
|
|||
const tableColumnComponents = {
|
||||
clientId: {
|
||||
component: QBtn,
|
||||
props: { flat: true, color: 'blue' },
|
||||
props: { flat: true, class: 'link' },
|
||||
event: (prop) => selectCustomerId(prop.value),
|
||||
},
|
||||
clientName: {
|
||||
|
@ -52,7 +52,12 @@ const tableColumnComponents = {
|
|||
};
|
||||
|
||||
const columns = computed(() => [
|
||||
{ label: 'Id', field: 'clientId', name: 'clientId', align: 'left' },
|
||||
{
|
||||
align: 'left',
|
||||
name: 'clientId',
|
||||
label: 'Id',
|
||||
field: 'clientId',
|
||||
},
|
||||
{
|
||||
label: t('invoiceOut.globalInvoices.table.client'),
|
||||
field: 'clientName',
|
||||
|
|
|
@ -48,7 +48,7 @@ const getStatus = computed({
|
|||
|
||||
onMounted(async () => {
|
||||
await invoiceOutGlobalStore.init();
|
||||
formData.value = { ...formInitialData.value };
|
||||
formData.value = formInitialData.value.invoiceDate;
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,96 +1,177 @@
|
|||
<script setup>
|
||||
import { onMounted, onUnmounted, ref } from 'vue';
|
||||
import { onMounted, onUnmounted, ref, computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import VnPaginate from 'src/components/ui/VnPaginate.vue';
|
||||
import InvoiceOutSummary from './Card/InvoiceOutSummary.vue';
|
||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
||||
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
|
||||
import VnLv from 'src/components/ui/VnLv.vue';
|
||||
import CardList from 'src/components/ui/CardList.vue';
|
||||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
||||
import CustomerDescriptorProxy from '../Customer/Card/CustomerDescriptorProxy.vue';
|
||||
import CreateManualInvoiceForm from 'src/components/CreateManualInvoiceForm.vue';
|
||||
|
||||
import InvoiceOutFilter from './InvoiceOutFilter.vue';
|
||||
import { toDate, toCurrency } from 'src/filters/index';
|
||||
import { useStateStore } from 'stores/useStateStore';
|
||||
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
|
||||
import { useSession } from 'src/composables/useSession';
|
||||
import RightMenu from 'src/components/common/RightMenu.vue';
|
||||
import { usePrintService } from 'composables/usePrintService';
|
||||
import VnTable from 'components/VnTable/VnTable.vue';
|
||||
import InvoiceOutSummary from './Card/InvoiceOutSummary.vue';
|
||||
import { toCurrency, toDate } from 'src/filters/index';
|
||||
import { useStateStore } from 'stores/useStateStore';
|
||||
import { QBtn } from 'quasar';
|
||||
import { watchEffect } from 'vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
const stateStore = useStateStore();
|
||||
const session = useSession();
|
||||
const tokenMultimedia = session.getTokenMultimedia();
|
||||
const { viewSummary } = useSummaryDialog();
|
||||
const tableRef = ref();
|
||||
const invoiceOutSerialsOptions = ref([]);
|
||||
const ticketsOptions = ref([]);
|
||||
const customerOptions = ref([]);
|
||||
const selectedRows = ref([]);
|
||||
const hasSelectedCards = computed(() => selectedRows.value.length > 0);
|
||||
const MODEL = 'InvoiceOuts';
|
||||
const { openReport } = usePrintService();
|
||||
|
||||
const manualInvoiceDialogRef = ref(null);
|
||||
const selectedCards = ref(new Map());
|
||||
|
||||
const columns = computed(() => [
|
||||
{
|
||||
align: 'left',
|
||||
name: 'id',
|
||||
label: t('invoiceOutList.tableVisibleColumns.id'),
|
||||
chip: {
|
||||
condition: () => true,
|
||||
},
|
||||
isId: true,
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: 'ref',
|
||||
label: t('invoiceOutList.tableVisibleColumns.ref'),
|
||||
isTitle: true,
|
||||
component: 'select',
|
||||
attrs: {
|
||||
url: MODEL,
|
||||
optionLabel: 'ref',
|
||||
optionValue: 'id',
|
||||
},
|
||||
columnField: {
|
||||
component: null,
|
||||
},
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: 'Issued',
|
||||
label: t('invoiceOutList.tableVisibleColumns.issued'),
|
||||
component: 'date',
|
||||
format: (row) => toDate(row.issued),
|
||||
columnField: {
|
||||
component: null,
|
||||
},
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: 'clientSocialName',
|
||||
label: t('invoiceOutModule.customer'),
|
||||
cardVisible: true,
|
||||
component: 'select',
|
||||
attrs: {
|
||||
url: 'Clients',
|
||||
fields: ['id', 'name'],
|
||||
},
|
||||
columnField: {
|
||||
component: null,
|
||||
},
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: 'companyCode',
|
||||
label: t('invoiceOutModule.company'),
|
||||
cardVisible: true,
|
||||
component: 'select',
|
||||
attrs: {
|
||||
url: 'Companies',
|
||||
optionLabel: 'code',
|
||||
optionValue: 'id',
|
||||
},
|
||||
columnField: {
|
||||
component: null,
|
||||
},
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: 'amount',
|
||||
label: t('invoiceOutModule.amount'),
|
||||
cardVisible: true,
|
||||
format: (row) => toCurrency(row.amount),
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: 'created',
|
||||
label: t('invoiceOutList.tableVisibleColumns.created'),
|
||||
component: 'date',
|
||||
columnField: {
|
||||
component: null,
|
||||
},
|
||||
format: (row) => toDate(row.created),
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: 'dued',
|
||||
label: t('invoiceOutList.tableVisibleColumns.dueDate'),
|
||||
component: 'date',
|
||||
columnField: {
|
||||
component: null,
|
||||
},
|
||||
format: (row) => toDate(row.dued),
|
||||
},
|
||||
{
|
||||
align: 'right',
|
||||
name: 'tableActions',
|
||||
actions: [
|
||||
{
|
||||
title: t('InvoiceOutSummary'),
|
||||
jsegarra marked this conversation as resolved
jsegarra
commented
Si no pones label, no se rompe nada. Si no pones label, no se rompe nada.
Yo también he pecado de lo mismo
|
||||
icon: 'preview',
|
||||
action: (row) => viewSummary(row.id, InvoiceOutSummary),
|
||||
},
|
||||
{
|
||||
title: t('DownloadPdf'),
|
||||
icon: 'vn:ticket',
|
||||
isPrimary: true,
|
||||
action: (row) => openPdf(row.id),
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
onMounted(() => (stateStore.rightDrawer = true));
|
||||
onUnmounted(() => (stateStore.rightDrawer = false));
|
||||
|
||||
function navigate(id) {
|
||||
router.push({ path: `/invoice-out/${id}` });
|
||||
function openPdf(id) {
|
||||
try {
|
||||
openReport(`${MODEL}/${id}/download`);
|
||||
} catch (err) {
|
||||
console.error('Error opening PDF', err);
|
||||
}
|
||||
}
|
||||
|
||||
const toggleIndividualCard = (cardData) => {
|
||||
if (selectedCards.value.has(cardData.id)) {
|
||||
selectedCards.value.delete(cardData.id);
|
||||
return;
|
||||
}
|
||||
selectedCards.value.set(cardData.id, cardData);
|
||||
};
|
||||
|
||||
const toggleAllCards = (cardsData) => {
|
||||
const allSelected = selectedCards.value.size === cardsData.length;
|
||||
|
||||
if (!allSelected) {
|
||||
// Si no todas las tarjetas están seleccionadas, selecciónalas todas
|
||||
cardsData.forEach((data) => {
|
||||
if (!selectedCards.value.has(data.id)) {
|
||||
selectedCards.value.set(data.id, data);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Si todas las tarjetas están seleccionadas, deselecciónalas todas
|
||||
selectedCards.value.clear();
|
||||
}
|
||||
};
|
||||
|
||||
const openPdf = () => {
|
||||
function downloadPdf() {
|
||||
try {
|
||||
if (selectedCards.value.size === 0) return;
|
||||
const selectedCardsArray = Array.from(selectedCards.value.values());
|
||||
if (selectedRows.value.size === 0) return;
|
||||
const selectedCardsArray = Array.from(selectedRows.value.values());
|
||||
|
||||
if (selectedCards.value.size === 1) {
|
||||
if (selectedRows.value.size === 1) {
|
||||
const [invoiceOut] = selectedCardsArray;
|
||||
const url = `api/InvoiceOuts/${invoiceOut.id}/download?access_token=${tokenMultimedia}`;
|
||||
window.open(url, '_blank');
|
||||
openPdf(invoiceOut.id);
|
||||
} else {
|
||||
const invoiceOutIdsArray = selectedCardsArray.map(
|
||||
(invoiceOut) => invoiceOut.id
|
||||
);
|
||||
const invoiceOutIds = invoiceOutIdsArray.join(',');
|
||||
|
||||
const params = new URLSearchParams({
|
||||
access_token: tokenMultimedia,
|
||||
const params = {
|
||||
ids: invoiceOutIds,
|
||||
});
|
||||
};
|
||||
|
||||
const url = `api/InvoiceOuts/downloadZip?${params}`;
|
||||
window.open(url, '_blank');
|
||||
openReport(`${MODEL}/downloadZip`, params);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error opening PDF');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const openCreateInvoiceModal = () => {
|
||||
manualInvoiceDialogRef.value.show();
|
||||
};
|
||||
watchEffect(selectedRows);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -99,115 +180,84 @@ const openCreateInvoiceModal = () => {
|
|||
:label="t('searchInvoice')"
|
||||
data-key="InvoiceOutList"
|
||||
/>
|
||||
<RightMenu>
|
||||
<template #right-panel>
|
||||
<InvoiceOutFilter data-key="InvoiceOutList" />
|
||||
</template>
|
||||
</RightMenu>
|
||||
<QPage>
|
||||
<VnPaginate
|
||||
auto-load
|
||||
data-key="InvoiceOutList"
|
||||
:order="['issued DESC', 'id DESC']"
|
||||
url="InvoiceOuts/filter"
|
||||
>
|
||||
<template #body="{ rows }">
|
||||
<VnSubToolbar class="justify-end">
|
||||
<VnSubToolbar>
|
||||
<template #st-actions>
|
||||
<QBtn
|
||||
@click="openPdf()"
|
||||
class="q-mr-md"
|
||||
color="primary"
|
||||
icon="cloud_download"
|
||||
:disable="selectedCards.size === 0"
|
||||
icon-right="cloud_download"
|
||||
@click="downloadPdf()"
|
||||
:disable="!hasSelectedCards"
|
||||
>
|
||||
<QTooltip>{{ t('globals.downloadPdf') }}</QTooltip>
|
||||
</QBtn>
|
||||
<QCheckbox
|
||||
left-label
|
||||
:label="t('globals.markAll')"
|
||||
@click="toggleAllCards(rows)"
|
||||
:model-value="selectedCards.size === rows.length"
|
||||
class="q-mr-md"
|
||||
/>
|
||||
</template>
|
||||
</VnSubToolbar>
|
||||
<div class="flex flex-center q-pa-md">
|
||||
<div class="vn-card-list">
|
||||
<CardList
|
||||
:element="row"
|
||||
:id="row.id"
|
||||
:show-checkbox="true"
|
||||
:is-selected="selectedCards.has(row.id)"
|
||||
:key="row.id"
|
||||
:title="row.ref"
|
||||
@click="navigate(row.id)"
|
||||
@toggle-card-check="toggleIndividualCard(row)"
|
||||
v-for="row of rows"
|
||||
<VnTable
|
||||
ref="tableRef"
|
||||
data-key="invoiceOut"
|
||||
:url="`${MODEL}/filter`"
|
||||
:create="{
|
||||
urlCreate: 'InvoiceOuts/createManualInvoice',
|
||||
title: t('Create Manual Invoice'),
|
||||
onDataSaved: ({ id }) => tableRef.redirect(id),
|
||||
formInitialData: {
|
||||
active: true,
|
||||
},
|
||||
}"
|
||||
v-model:selected="selectedRows"
|
||||
order="id DESC"
|
||||
:columns="columns"
|
||||
default-mode="table"
|
||||
redirect="invoice-out"
|
||||
auto-load
|
||||
:table="{
|
||||
'row-key': 'id',
|
||||
selection: 'multiple',
|
||||
}"
|
||||
>
|
||||
<template #list-items>
|
||||
<VnLv
|
||||
:label="t('invoiceOut.list.issued')"
|
||||
:value="toDate(row.issued)"
|
||||
<template #more-create-dialog="{ data }">
|
||||
<VnSelect
|
||||
url="Tickets"
|
||||
v-model="data.ticketFk"
|
||||
:label="t('invoiceOutList.tableVisibleColumns.ticket')"
|
||||
:options="ticketsOptions"
|
||||
option-label="nickname"
|
||||
option-value="id"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('invoiceOut.list.amount')"
|
||||
:value="toCurrency(row.amount)"
|
||||
<VnSelect
|
||||
url="Clients"
|
||||
v-model="data.clientFk"
|
||||
:label="t('invoiceOutModule.customer')"
|
||||
:options="customerOptions"
|
||||
option-label="name"
|
||||
option-value="id"
|
||||
/>
|
||||
<VnLv :label="t('invoiceOut.list.client')">
|
||||
<template #value>
|
||||
<span class="link" @click.stop>
|
||||
{{ row?.clientSocialName }}
|
||||
<CustomerDescriptorProxy
|
||||
:id="row?.clientFk"
|
||||
<VnInputDate
|
||||
:label="t('invoiceOutList.tableVisibleColumns.dueDate')"
|
||||
v-model="data.maxShipped"
|
||||
/>
|
||||
</span>
|
||||
</template>
|
||||
</VnLv>
|
||||
<VnLv
|
||||
:label="t('invoiceOut.list.shortCreated')"
|
||||
:title-label="t('invoiceOut.list.created')"
|
||||
:value="toDate(row.created)"
|
||||
<VnSelect
|
||||
url="InvoiceOutSerials"
|
||||
v-model="data.invoiceOutSerial"
|
||||
:label="t('invoiceOutList.tableVisibleColumns.invoiceOutSerial')"
|
||||
:options="invoiceOutSerialsOptions"
|
||||
option-label="description"
|
||||
option-value="code"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('invoiceOut.list.company')"
|
||||
:value="row.companyCode"
|
||||
<VnSelect
|
||||
url="TaxAreas"
|
||||
v-model="data.area"
|
||||
:label="t('invoiceOutList.tableVisibleColumns.taxArea')"
|
||||
:options="taxAreasOptions"
|
||||
option-label="code"
|
||||
option-value="code"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('invoiceOut.list.shortDued')"
|
||||
:title-label="t('invoiceOut.list.dued')"
|
||||
:value="toDate(row.dued)"
|
||||
<QInput
|
||||
v-model="data.reference"
|
||||
:label="t('invoiceOutList.tableVisibleColumns.ref')"
|
||||
/>
|
||||
</template>
|
||||
<template #actions>
|
||||
<QBtn
|
||||
:label="t('components.smartCard.openSummary')"
|
||||
@click.stop="viewSummary(row.id, InvoiceOutSummary)"
|
||||
color="primary"
|
||||
style="margin-top: 15px"
|
||||
type="submit"
|
||||
/>
|
||||
</template>
|
||||
</CardList>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</VnPaginate>
|
||||
<QPageSticky :offset="[20, 20]">
|
||||
<QBtn fab icon="add" color="primary" @click="openCreateInvoiceModal()" />
|
||||
<QTooltip>
|
||||
{{ t('createInvoice') }}
|
||||
</QTooltip>
|
||||
</QPageSticky>
|
||||
|
||||
<QDialog
|
||||
ref="manualInvoiceDialogRef"
|
||||
transition-show="scale"
|
||||
transition-hide="scale"
|
||||
>
|
||||
<CreateManualInvoiceForm />
|
||||
</QDialog>
|
||||
</QPage>
|
||||
</VnTable>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
|
|
|
@ -1,29 +1,158 @@
|
|||
<script setup>
|
||||
import { computed, onBeforeMount } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
|
||||
import InvoiceOutNegativeFilter from './InvoiceOutNegativeBasesFilter.vue';
|
||||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
||||
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
||||
import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue';
|
||||
import { toCurrency } from 'src/filters';
|
||||
import VnTable from 'src/components/VnTable/VnTable.vue';
|
||||
import { useInvoiceOutGlobalStore } from 'src/stores/invoiceOutGlobal.js';
|
||||
import { useStateStore } from 'stores/useStateStore';
|
||||
import { useArrayData } from 'composables/useArrayData';
|
||||
import RightMenu from 'src/components/common/RightMenu.vue';
|
||||
import { useArrayData } from 'src/composables/useArrayData';
|
||||
|
||||
const invoiceOutGlobalStore = useInvoiceOutGlobalStore();
|
||||
const stateStore = useStateStore();
|
||||
const { t } = useI18n();
|
||||
|
||||
const arrayData = useArrayData('InvoiceOutNegative', {
|
||||
url: 'InvoiceOuts/negativeBases',
|
||||
limit: 0,
|
||||
userParams: {
|
||||
const tableRef = ref();
|
||||
const invoiceOutGlobalStore = useInvoiceOutGlobalStore();
|
||||
const userParams = {
|
||||
from: Date.vnFirstDayOfMonth().toISOString(),
|
||||
to: Date.vnLastDayOfMonth().toISOString(),
|
||||
};
|
||||
jsegarra marked this conversation as resolved
jon
commented
Se ha decidido dejar así para no hacer dos llamadas iguales(la del Vntable y la del arrayData) Se ha decidido dejar así para no hacer dos llamadas iguales(la del Vntable y la del arrayData)
|
||||
useArrayData('InvoiceOutNegative', { userParams });
|
||||
|
||||
const columns = computed(() => [
|
||||
{
|
||||
align: 'left',
|
||||
name: 'company',
|
||||
label: t('invoiceOutModule.company'),
|
||||
component: 'select',
|
||||
cardVisible: true,
|
||||
attrs: {
|
||||
url: 'Companies',
|
||||
optionLabel: 'code',
|
||||
optionValue: 'id',
|
||||
},
|
||||
exprBuilder: (param, value) => {
|
||||
columnField: {
|
||||
component: null,
|
||||
},
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: 'country',
|
||||
label: t('negativeBases.country'),
|
||||
component: 'select',
|
||||
attrs: {
|
||||
url: 'Countries',
|
||||
optionLabel: 'name',
|
||||
optionValue: 'id',
|
||||
},
|
||||
columnField: {
|
||||
component: null,
|
||||
},
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: 'clientId',
|
||||
label: t('negativeBases.clientId'),
|
||||
cardVisible: true,
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: 'clientSocialName',
|
||||
label: t('invoiceOutModule.customer'),
|
||||
component: 'select',
|
||||
isTitle: true,
|
||||
cardVisible: true,
|
||||
attrs: {
|
||||
url: 'Clients',
|
||||
fields: ['id', 'name'],
|
||||
},
|
||||
columnField: {
|
||||
component: null,
|
||||
},
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: 'amount',
|
||||
label: t('invoiceOutModule.amount'),
|
||||
format: (row) => toCurrency(row.amount),
|
||||
cardVisible: true,
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: 'taxableBase',
|
||||
label: t('negativeBases.base'),
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: 'ticketFk',
|
||||
label: t('negativeBases.ticketId'),
|
||||
cardVisible: true,
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: 'isActive',
|
||||
label: t('negativeBases.active'),
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: 'hasToInvoice',
|
||||
label: t('negativeBases.hasToInvoice'),
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: 'hasVerifiedData',
|
||||
label: t('negativeBases.verifiedData'),
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
label: t('customer.extendedList.tableVisibleColumns.salesPersonFk'),
|
||||
name: 'workerName',
|
||||
component: 'select',
|
||||
attrs: {
|
||||
url: 'Workers/activeWithInheritedRole',
|
||||
fields: ['id', 'name'],
|
||||
where: { role: 'salesPerson' },
|
||||
},
|
||||
columnField: {
|
||||
component: null,
|
||||
},
|
||||
format: (row, dashIfEmpty) => dashIfEmpty(row.workerName),
|
||||
},
|
||||
]);
|
||||
|
||||
const downloadCSV = async () => {
|
||||
const filterParams = {
|
||||
limit: 20,
|
||||
where: {
|
||||
and: [],
|
||||
},
|
||||
};
|
||||
|
||||
for (const [key, value] of Object.entries(userParams)) {
|
||||
if (value) {
|
||||
filterParams.where.and.push({ [key]: value });
|
||||
}
|
||||
}
|
||||
|
||||
await invoiceOutGlobalStore.getNegativeBasesCsv(
|
||||
userParams.from,
|
||||
userParams.to,
|
||||
filterParams
|
||||
);
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<VnSubToolbar>
|
||||
<template #st-actions>
|
||||
<QBtn color="primary" icon-right="download" @click="downloadCSV()">
|
||||
<QTooltip>{{ t('Download as CSV') }}</QTooltip>
|
||||
</QBtn>
|
||||
</template>
|
||||
</VnSubToolbar>
|
||||
<VnTable
|
||||
ref="tableRef"
|
||||
data-key="negativeFilter"
|
||||
url="InvoiceOuts/negativeBases"
|
||||
:user-params="userParams"
|
||||
:expr-builder="
|
||||
(param, value) => {
|
||||
switch (param) {
|
||||
case 'from':
|
||||
case 'to':
|
||||
|
@ -31,170 +160,18 @@ const arrayData = useArrayData('InvoiceOutNegative', {
|
|||
default:
|
||||
return { [param]: value };
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
onBeforeMount(async () => {
|
||||
await arrayData.fetch({ append: false });
|
||||
stateStore.rightDrawer = true;
|
||||
});
|
||||
|
||||
const columns = computed(() => [
|
||||
{
|
||||
label: t('invoiceOut.negativeBases.company'),
|
||||
field: 'company',
|
||||
name: 'company',
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
label: t('invoiceOut.negativeBases.country'),
|
||||
field: 'country',
|
||||
name: 'country',
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
label: t('invoiceOut.negativeBases.clientId'),
|
||||
field: 'clientId',
|
||||
name: 'clientId',
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
label: t('invoiceOut.negativeBases.client'),
|
||||
field: 'clientSocialName',
|
||||
name: 'client',
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
label: t('invoiceOut.negativeBases.amount'),
|
||||
field: 'amount',
|
||||
name: 'amount',
|
||||
align: 'left',
|
||||
format: (value) => toCurrency(value),
|
||||
},
|
||||
{
|
||||
label: t('invoiceOut.negativeBases.base'),
|
||||
field: 'taxableBase',
|
||||
name: 'base',
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
label: t('invoiceOut.negativeBases.ticketId'),
|
||||
field: 'ticketFk',
|
||||
name: 'ticketId',
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
label: t('invoiceOut.negativeBases.active'),
|
||||
field: 'isActive',
|
||||
name: 'active',
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
label: t('invoiceOut.negativeBases.hasToInvoice'),
|
||||
field: 'hasToInvoice',
|
||||
name: 'hasToInvoice',
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
label: t('invoiceOut.negativeBases.verifiedData'),
|
||||
field: 'isTaxDataChecked',
|
||||
name: 'verifiedData',
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
label: t('invoiceOut.negativeBases.comercial'),
|
||||
field: 'workerName',
|
||||
name: 'worker',
|
||||
align: 'left',
|
||||
},
|
||||
]);
|
||||
|
||||
const downloadCSV = async () => {
|
||||
const params = {}; // filter.value;
|
||||
const filterParams = {
|
||||
limit: 20,
|
||||
where: {
|
||||
and: [],
|
||||
},
|
||||
};
|
||||
for (const param in params) {
|
||||
if (params[param]) filterParams.where.and.push({ [param]: params[param] });
|
||||
}
|
||||
|
||||
await invoiceOutGlobalStore.getNegativeBasesCsv(
|
||||
arrayData.value.store.userParams.from,
|
||||
arrayData.value.store.userParams.to,
|
||||
params
|
||||
);
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<VnSubToolbar>
|
||||
<template #st-actions>
|
||||
<QBtn color="primary" icon-right="download" no-caps @click="downloadCSV()">
|
||||
<QTooltip>{{ t('Download as CSV') }}</QTooltip>
|
||||
</QBtn>
|
||||
</template>
|
||||
</VnSubToolbar>
|
||||
<RightMenu>
|
||||
<template #right-panel>
|
||||
<InvoiceOutNegativeFilter data-key="InvoiceOutNegative" />
|
||||
</template>
|
||||
</RightMenu>
|
||||
<QPage class="column items-center q-pa-md">
|
||||
<QTable
|
||||
"
|
||||
:limit="0"
|
||||
:columns="columns"
|
||||
:rows="arrayData.store.data"
|
||||
row-key="clientId"
|
||||
class="full-width q-mt-md"
|
||||
default-mode="table"
|
||||
auto-load
|
||||
:is-editable="false"
|
||||
:use-model="true"
|
||||
>
|
||||
<template #body-cell-clientId="{ row }">
|
||||
<QTd>
|
||||
<QBtn flat dense class="link"> {{ row.clientId }}</QBtn>
|
||||
<CustomerDescriptorProxy :id="row.clientId" />
|
||||
</QTd>
|
||||
</template>
|
||||
<template #body-cell-ticketId="{ row }">
|
||||
<QTd>
|
||||
<QBtn flat dense class="link"> {{ row.ticketFk }}</QBtn>
|
||||
<TicketDescriptorProxy :id="row.ticketFk" />
|
||||
</QTd>
|
||||
</template>
|
||||
<template #body-cell-worker="{ row }">
|
||||
<QTd>
|
||||
<QBtn class="no-uppercase link" flat dense>{{ row.workerName }}</QBtn>
|
||||
<WorkerDescriptorProxy :id="row.comercialId" />
|
||||
</QTd>
|
||||
</template>
|
||||
<template #body-cell-active="{ row }">
|
||||
<QTd>
|
||||
<QCheckbox :model-value="!!row.isActive" disable />
|
||||
</QTd>
|
||||
</template>
|
||||
<template #body-cell-hasToInvoice="{ row }">
|
||||
<QTd>
|
||||
<QCheckbox :model-value="!!row.hasToInvoice" disable />
|
||||
</QTd>
|
||||
</template>
|
||||
<template #body-cell-verifiedData="{ row }">
|
||||
<QTd>
|
||||
<QCheckbox :model-value="!!row.isTaxDataChecked" disable />
|
||||
</QTd>
|
||||
</template>
|
||||
</QTable>
|
||||
</QPage>
|
||||
</VnTable>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.col-content {
|
||||
border-radius: 4px;
|
||||
padding: 6px;
|
||||
}
|
||||
.no-uppercase {
|
||||
text-transform: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<i18n>
|
||||
es:
|
||||
Download as CSV: Descargar como CSV
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
invoiceOutModule:
|
||||
customer: Client
|
||||
amount: Amount
|
||||
company: Company
|
||||
invoiceOutList:
|
||||
tableVisibleColumns:
|
||||
id: ID
|
||||
ref: Reference
|
||||
issued: Issued
|
||||
created: Created
|
||||
dueDate: Max date
|
||||
invoiceOutSerial: Serial
|
||||
ticket: Ticket
|
||||
taxArea: Tax area
|
||||
DownloadPdf: Download PDF
|
||||
InvoiceOutSummary: Summary
|
||||
negativeBases:
|
||||
country: Country
|
||||
clientId: Client ID
|
||||
base: Base
|
||||
ticketId: Ticket
|
||||
active: Active
|
||||
hasToInvoice: Has to invoice
|
||||
verifiedData: Verified data
|
||||
commercial: Commercial
|
|
@ -1,2 +1,31 @@
|
|||
Search invoice: Buscar factura emitida
|
||||
You can search by invoice reference: Puedes buscar por referencia de la factura
|
||||
invoiceOutModule:
|
||||
customer: Cliente
|
||||
amount: Importe
|
||||
company: Empresa
|
||||
invoiceOutList:
|
||||
tableVisibleColumns:
|
||||
id: ID
|
||||
ref: Referencia
|
||||
issued: Fecha emisión
|
||||
customer: Cliente
|
||||
company: Empresa
|
||||
amount: Importe
|
||||
created: F. creación
|
||||
dueDate: F. máxima
|
||||
invoiceOutSerial: Serial
|
||||
ticket: Ticket
|
||||
taxArea: Area
|
||||
DownloadPdf: Descargar PDF
|
||||
InvoiceOutSummary: Resumen
|
||||
negativeBases:
|
||||
country: País
|
||||
clientId: ID del cliente
|
||||
client: Cliente
|
||||
base: Base
|
||||
ticketId: Ticket
|
||||
active: Activo
|
||||
hasToInvoice: Debe facturar
|
||||
verifiedData: Datos verificados
|
||||
commercial: Comercial
|
|
@ -35,7 +35,7 @@ export default {
|
|||
name: 'InvoiceOutGlobal',
|
||||
meta: {
|
||||
title: 'globalInvoicing',
|
||||
icon: 'contact_support',
|
||||
icon: 'Date_Range',
|
||||
},
|
||||
component: () => import('src/pages/InvoiceOut/InvoiceOutGlobal.vue'),
|
||||
},
|
||||
|
|
|
@ -237,7 +237,7 @@ export const useInvoiceOutGlobalStore = defineStore({
|
|||
async getNegativeBasesCsv() {
|
||||
try {
|
||||
const arrayData = useArrayData('InvoiceOutNegative');
|
||||
const params = arrayData.store.currentFilter;
|
||||
const params = arrayData.store.userParams;
|
||||
jon
commented
Debido al cambio en el uso de arrayData en negativeBases la store deja de tener currentFitler, y le pasa los userParams declarados Debido al cambio en el uso de arrayData en negativeBases la store deja de tener currentFitler, y le pasa los userParams declarados
|
||||
|
||||
const { data } = await axios.get('InvoiceOuts/negativeBasesCsv', {
|
||||
params,
|
||||
|
|
Loading…
Reference in New Issue
Has probado a usar FormPopupDialog?