refactor: refs #6897 update component props and improve UI handling in Entry pages #1520

Merged
pablone merged 3 commits from 6897-fixSomeCaus into test 2025-02-28 12:29:18 +00:00
24 changed files with 260 additions and 99 deletions
Showing only changes of commit 1aa2cb7316 - Show all commits

View File

@ -95,6 +95,10 @@ const $props = defineProps({
type: [String, Boolean], type: [String, Boolean],
default: '800px', default: '800px',
}, },
onDataSaved: {
type: Function,
default: () => {},
},
}); });
const emit = defineEmits(['onFetch', 'onDataSaved']); const emit = defineEmits(['onFetch', 'onDataSaved']);
const modelValue = computed( const modelValue = computed(

View File

@ -32,7 +32,6 @@ import VnTableOrder from 'src/components/VnTable/VnOrder.vue';
import VnTableFilter from './VnTableFilter.vue'; import VnTableFilter from './VnTableFilter.vue';
import { getColAlign } from 'src/composables/getColAlign'; import { getColAlign } from 'src/composables/getColAlign';
import RightMenu from '../common/RightMenu.vue'; import RightMenu from '../common/RightMenu.vue';
import { QItemSection } from 'quasar';
const arrayData = useArrayData(useAttrs()['data-key']); const arrayData = useArrayData(useAttrs()['data-key']);
const $props = defineProps({ const $props = defineProps({
@ -139,6 +138,10 @@ const $props = defineProps({
createComplement: { createComplement: {
type: Object, type: Object,
}, },
dataCy: {
type: String,
default: 'vn-table',
},
}); });
const { t } = useI18n(); const { t } = useI18n();
@ -167,7 +170,6 @@ const app = inject('app');
const editingRow = ref(null); const editingRow = ref(null);
const editingField = ref(null); const editingField = ref(null);
const isTableMode = computed(() => mode.value == TABLE_MODE); const isTableMode = computed(() => mode.value == TABLE_MODE);
const showRightIcon = computed(() => $props.rightSearch || $props.rightSearchIcon);
const selectRegex = /select/; const selectRegex = /select/;
const emit = defineEmits(['onFetch', 'update:selected', 'saveChanges']); const emit = defineEmits(['onFetch', 'update:selected', 'saveChanges']);
const tableModes = [ const tableModes = [
@ -255,7 +257,9 @@ function splitColumns(columns) {
col.columnFilter = { inWhere: true, ...col.columnFilter }; col.columnFilter = { inWhere: true, ...col.columnFilter };
splittedColumns.value.columns.push(col); splittedColumns.value.columns.push(col);
} }
// Status column
splittedColumns.value.create = createOrderSort(splittedColumns.value.create);
if (splittedColumns.value.chips.length) { if (splittedColumns.value.chips.length) {
splittedColumns.value.columnChips = splittedColumns.value.chips.filter( splittedColumns.value.columnChips = splittedColumns.value.chips.filter(
(c) => !c.isId, (c) => !c.isId,
@ -271,6 +275,24 @@ function splitColumns(columns) {
} }
} }
function createOrderSort(columns) {
const orderedColumn = columns
.map((column, index) =>
column.createOrder !== undefined ? { ...column, originalIndex: index } : null,
)
.filter((item) => item !== null);
orderedColumn.sort((a, b) => a.createOrder - b.createOrder);
const filteredColumns = columns.filter((col) => col.createOrder === undefined);
orderedColumn.forEach((col) => {
filteredColumns.splice(col.createOrder, 0, col);
});
return filteredColumns;
}
const rowClickFunction = computed(() => { const rowClickFunction = computed(() => {
if ($props.rowClick != undefined) return $props.rowClick; if ($props.rowClick != undefined) return $props.rowClick;
if ($props.redirect) return ({ id }) => redirectFn(id); if ($props.redirect) return ({ id }) => redirectFn(id);
@ -316,8 +338,14 @@ function handleSelection({ evt, added, rows: selectedRows }, rows) {
if (evt?.shiftKey && added) { if (evt?.shiftKey && added) {
const rowIndex = selectedRows[0].$index; const rowIndex = selectedRows[0].$index;
const selectedIndexes = new Set(selected.value.map((row) => row.$index)); const selectedIndexes = new Set(selected.value.map((row) => row.$index));
for (const row of rows) { const minIndex = selectedIndexes.size
if (row.$index == rowIndex) break; ? Math.min(...selectedIndexes, rowIndex)
: 0;
const maxIndex = Math.max(...selectedIndexes, rowIndex);
for (let i = minIndex; i <= maxIndex; i++) {
const row = rows[i];
if (row.$index == rowIndex) continue;
if (!selectedIndexes.has(row.$index)) { if (!selectedIndexes.has(row.$index)) {
selected.value.push(row); selected.value.push(row);
selectedIndexes.add(row.$index); selectedIndexes.add(row.$index);
@ -340,12 +368,11 @@ function hasEditableFormat(column) {
const clickHandler = async (event) => { const clickHandler = async (event) => {
const clickedElement = event.target.closest('td'); const clickedElement = event.target.closest('td');
const isDateElement = event.target.closest('.q-date'); const isDateElement = event.target.closest('.q-date');
const isTimeElement = event.target.closest('.q-time'); const isTimeElement = event.target.closest('.q-time');
const isQselectDropDown = event.target.closest('.q-select__dropdown-icon'); const isQSelectDropDown = event.target.closest('.q-select__dropdown-icon');
if (isDateElement || isTimeElement || isQselectDropDown) return; if (isDateElement || isTimeElement || isQSelectDropDown) return;
if (clickedElement === null) { if (clickedElement === null) {
await destroyInput(editingRow.value, editingField.value); await destroyInput(editingRow.value, editingField.value);
@ -584,9 +611,24 @@ function removeTextValue(data, getChanges) {
return data; return data;
} }
function handleRowClick(event, row) {
if (event.ctrlKey) return rowCtrlClickFunction.value(event, row);
if (rowClickFunction.value) rowClickFunction.value(row);
}
const rowCtrlClickFunction = computed(() => {
if ($props.rowCtrlClick != undefined) return $props.rowCtrlClick;
if ($props.redirect)
return (evt, { id }) => {
stopEventPropagation(evt);
window.open(`/#/${$props.redirect}/${id}`, '_blank');
};
return () => {};
});
</script> </script>
<template> <template>
<RightMenu v-if="$props.rightSearch"> <RightMenu v-if="$props.rightSearch" :overlay="overlay">
<template #right-panel> <template #right-panel>
<VnTableFilter <VnTableFilter
:data-key="$attrs['data-key']" :data-key="$attrs['data-key']"
@ -639,7 +681,7 @@ function removeTextValue(data, getChanges) {
:style="isTableMode && `max-height: ${tableHeight}`" :style="isTableMode && `max-height: ${tableHeight}`"
:virtual-scroll="isTableMode" :virtual-scroll="isTableMode"
@virtual-scroll="handleScroll" @virtual-scroll="handleScroll"
@row-click="(_, row) => rowClickFunction && rowClickFunction(row)" @row-click="(event, row) => handleRowClick(event, row)"
@update:selected="emit('update:selected', $event)" @update:selected="emit('update:selected', $event)"
@selection="(details) => handleSelection(details, rows)" @selection="(details) => handleSelection(details, rows)"
:hide-selected-banner="true" :hide-selected-banner="true"
@ -985,7 +1027,10 @@ function removeTextValue(data, getChanges) {
> >
<template #form-inputs="{ data }"> <template #form-inputs="{ data }">
<div :style="createComplement?.containerStyle"> <div :style="createComplement?.containerStyle">
<div> <div
:style="createComplement?.previousStyle"
v-if="!quasar.screen.xs"
>
<slot name="previous-create-dialog" :data="data" /> <slot name="previous-create-dialog" :data="data" />
</div> </div>
<div class="grid-create" :style="createComplement?.columnGridStyle"> <div class="grid-create" :style="createComplement?.columnGridStyle">
@ -998,7 +1043,10 @@ function removeTextValue(data, getChanges) {
:label="column.label" :label="column.label"
> >
<VnColumn <VnColumn
:column="column" :column="{
...column,
...{ disable: column?.createDisable ?? false },
}"
:row="{}" :row="{}"
default="input" default="input"
v-model="data[column.name]" v-model="data[column.name]"

View File

@ -27,30 +27,58 @@ describe('VnTable', () => {
beforeEach(() => (vm.selected = [])); beforeEach(() => (vm.selected = []));
describe('handleSelection()', () => { describe('handleSelection()', () => {
const rows = [{ $index: 0 }, { $index: 1 }, { $index: 2 }]; const rows = [
{ $index: 0 },
{ $index: 1 },
{ $index: 2 },
{ $index: 3 },
{ $index: 4 },
];
it('should add rows to selected when shift key is pressed and rows are added in ascending order', () => {
const selectedRows = [{ $index: 1 }]; const selectedRows = [{ $index: 1 }];
it('should add rows to selected when shift key is pressed and rows are added except last one', () => {
vm.handleSelection( vm.handleSelection(
{ evt: { shiftKey: true }, added: true, rows: selectedRows }, { evt: { shiftKey: true }, added: true, rows: selectedRows },
rows rows,
); );
expect(vm.selected).toEqual([{ $index: 0 }]); expect(vm.selected).toEqual([{ $index: 0 }]);
}); });
it('should add rows to selected when shift key is pressed and rows are added in descending order', () => {
const selectedRows = [{ $index: 3 }];
vm.handleSelection(
{ evt: { shiftKey: true }, added: true, rows: selectedRows },
rows,
);
expect(vm.selected).toEqual([{ $index: 0 }, { $index: 1 }, { $index: 2 }]);
});
it('should not add rows to selected when shift key is not pressed', () => { it('should not add rows to selected when shift key is not pressed', () => {
const selectedRows = [{ $index: 1 }];
vm.handleSelection( vm.handleSelection(
{ evt: { shiftKey: false }, added: true, rows: selectedRows }, { evt: { shiftKey: false }, added: true, rows: selectedRows },
rows rows,
); );
expect(vm.selected).toEqual([]); expect(vm.selected).toEqual([]);
}); });
it('should not add rows to selected when rows are not added', () => { it('should not add rows to selected when rows are not added', () => {
const selectedRows = [{ $index: 1 }];
vm.handleSelection( vm.handleSelection(
{ evt: { shiftKey: true }, added: false, rows: selectedRows }, { evt: { shiftKey: true }, added: false, rows: selectedRows },
rows rows,
); );
expect(vm.selected).toEqual([]); expect(vm.selected).toEqual([]);
}); });
it('should add all rows between the smallest and largest selected indexes', () => {
vm.selected = [{ $index: 1 }, { $index: 3 }];
const selectedRows = [{ $index: 4 }];
vm.handleSelection(
{ evt: { shiftKey: true }, added: true, rows: selectedRows },
rows,
);
expect(vm.selected).toEqual([{ $index: 1 }, { $index: 3 }, { $index: 2 }]);
});
}); });
}); });

View File

@ -11,6 +11,13 @@ const stateStore = useStateStore();
const slots = useSlots(); const slots = useSlots();
const hasContent = useHasContent('#right-panel'); const hasContent = useHasContent('#right-panel');
defineProps({
overlay: {
type: Boolean,
default: false,
},
});
onMounted(() => { onMounted(() => {
if ((!slots['right-panel'] && !hasContent.value) || quasar.platform.is.mobile) if ((!slots['right-panel'] && !hasContent.value) || quasar.platform.is.mobile)
stateStore.rightDrawer = false; stateStore.rightDrawer = false;
@ -34,7 +41,12 @@ onMounted(() => {
</QBtn> </QBtn>
</div> </div>
</Teleport> </Teleport>
<QDrawer v-model="stateStore.rightDrawer" side="right" :width="256"> <QDrawer
v-model="stateStore.rightDrawer"
side="right"
:width="256"
:overlay="overlay"
>
<QScrollArea class="fit"> <QScrollArea class="fit">
<div id="right-panel"></div> <div id="right-panel"></div>
<slot v-if="!hasContent" name="right-panel" /> <slot v-if="!hasContent" name="right-panel" />

View File

@ -27,7 +27,7 @@ const checkboxModel = computed({
</script> </script>
<template> <template>
<div> <div>
<QCheckbox v-bind="$attrs" v-on="$attrs" v-model="checkboxModel" /> <QCheckbox v-bind="$attrs" v-model="checkboxModel" />
<QIcon <QIcon
v-if="info" v-if="info"
v-bind="$attrs" v-bind="$attrs"

View File

@ -302,8 +302,6 @@ defineExpose({ opts: myOptions, vnSelectRef });
function handleKeyDown(event) { function handleKeyDown(event) {
if (event.key === 'Tab' && !event.shiftKey) { if (event.key === 'Tab' && !event.shiftKey) {
event.preventDefault();
const inputValue = vnSelectRef.value?.inputValue; const inputValue = vnSelectRef.value?.inputValue;
if (inputValue) { if (inputValue) {

View File

@ -76,6 +76,15 @@ onBeforeMount(async () => {
); );
}); });
const routeName = computed(() => {
const DESCRIPTOR_PROXY = 'DescriptorProxy';
let name = $props.dataKey;
if ($props.dataKey.includes(DESCRIPTOR_PROXY)) {
name = name.split(DESCRIPTOR_PROXY)[0];
}
return `${name}Summary`;
});
async function getData() { async function getData() {
store.url = $props.url; store.url = $props.url;
store.filter = $props.filter ?? {}; store.filter = $props.filter ?? {};
@ -154,9 +163,7 @@ const toModule = computed(() =>
{{ t('components.smartCard.openSummary') }} {{ t('components.smartCard.openSummary') }}
</QTooltip> </QTooltip>
</QBtn> </QBtn>
<RouterLink <RouterLink :to="{ name: routeName, params: { id: entity.id } }">
:to="{ name: `${dataKey}Summary`, params: { id: entity.id } }"
>
<QBtn <QBtn
class="link" class="link"
color="white" color="white"

View File

@ -204,8 +204,9 @@ async function search() {
} }
:deep(.q-field--focused) { :deep(.q-field--focused) {
.q-icon { .q-icon,
color: black; .q-placeholder {
color: var(--vn-black-text-color);
} }
} }

View File

@ -29,7 +29,6 @@ export async function checkEntryLock(entryFk, userFk) {
.dialog({ .dialog({
component: VnConfirm, component: VnConfirm,
componentProps: { componentProps: {
'data-cy': 'entry-lock-confirm',
title: t('entry.lock.title'), title: t('entry.lock.title'),
message: t('entry.lock.message', { message: t('entry.lock.message', {
userName: data?.user?.nickname, userName: data?.user?.nickname,

View File

@ -694,8 +694,10 @@ worker:
machine: Machine machine: Machine
business: business:
tableVisibleColumns: tableVisibleColumns:
id: ID
started: Start Date started: Start Date
ended: End Date ended: End Date
hourlyLabor: Time sheet
company: Company company: Company
reasonEnd: Reason for Termination reasonEnd: Reason for Termination
department: Department department: Department
@ -703,6 +705,7 @@ worker:
calendarType: Work Calendar calendarType: Work Calendar
workCenter: Work Center workCenter: Work Center
payrollCategories: Contract Category payrollCategories: Contract Category
workerBusinessAgreementName: Agreement
occupationCode: Contribution Code occupationCode: Contribution Code
rate: Rate rate: Rate
businessType: Contract Type businessType: Contract Type

View File

@ -770,8 +770,10 @@ worker:
concept: Concepto concept: Concepto
business: business:
tableVisibleColumns: tableVisibleColumns:
id: Id
started: Fecha inicio started: Fecha inicio
ended: Fecha fin ended: Fecha fin
hourlyLabor: Ficha
company: Empresa company: Empresa
reasonEnd: Motivo finalización reasonEnd: Motivo finalización
department: Departamento department: Departamento
@ -782,6 +784,7 @@ worker:
occupationCode: Cotización occupationCode: Cotización
rate: Tarifa rate: Tarifa
businessType: Contrato businessType: Contrato
workerBusinessAgreementName: Convenio
amount: Salario amount: Salario
basicSalary: Salario transportistas basicSalary: Salario transportistas
notes: Notas notes: Notas

View File

@ -54,6 +54,7 @@ const columns = [
toggleIndeterminate: false, toggleIndeterminate: false,
}, },
create: true, create: true,
createOrder: 12,
width: '25px', width: '25px',
}, },
{ {
@ -88,15 +89,6 @@ const columns = [
isEditable: false, isEditable: false,
columnFilter: false, columnFilter: false,
}, },
{
name: 'entryFk',
isId: true,
visible: false,
isEditable: false,
disable: true,
create: true,
columnFilter: false,
},
{ {
align: 'center', align: 'center',
label: 'Id', label: 'Id',
@ -138,6 +130,7 @@ const columns = [
name: 'itemFk', name: 'itemFk',
visible: false, visible: false,
create: true, create: true,
createOrder: 0,
columnFilter: false, columnFilter: false,
}, },
{ {
@ -161,6 +154,8 @@ const columns = [
name: 'stickers', name: 'stickers',
component: 'input', component: 'input',
create: true, create: true,
createOrder: 1,
attrs: { attrs: {
positive: false, positive: false,
}, },
@ -272,6 +267,7 @@ const columns = [
}, },
width: '45px', width: '45px',
create: true, create: true,
createOrder: 3,
style: getQuantityStyle, style: getQuantityStyle,
}, },
{ {
@ -281,6 +277,7 @@ const columns = [
toolTip: t('Buying value'), toolTip: t('Buying value'),
name: 'buyingValue', name: 'buyingValue',
create: true, create: true,
createOrder: 2,
component: 'number', component: 'number',
attrs: { attrs: {
positive: false, positive: false,
@ -313,6 +310,7 @@ const columns = [
toolTip: t('Package'), toolTip: t('Package'),
name: 'price2', name: 'price2',
component: 'number', component: 'number',
createDisable: true,
width: '35px', width: '35px',
create: true, create: true,
format: (row) => parseFloat(row['price2']).toFixed(2), format: (row) => parseFloat(row['price2']).toFixed(2),
@ -322,6 +320,7 @@ const columns = [
label: t('Box'), label: t('Box'),
name: 'price3', name: 'price3',
component: 'number', component: 'number',
createDisable: true,
cellEvent: { cellEvent: {
'update:modelValue': async (value, oldValue, row) => { 'update:modelValue': async (value, oldValue, row) => {
row['price2'] = row['price2'] * (value / oldValue); row['price2'] = row['price2'] * (value / oldValue);
@ -509,13 +508,14 @@ async function setBuyUltimate(itemFk, data) {
}, },
}); });
const buyUltimateData = buyUltimate.data[0]; const buyUltimateData = buyUltimate.data[0];
if (!buyUltimateData) return;
const allowedKeys = columns const allowedKeys = columns
.filter((col) => col.create === true) .filter((col) => col.create === true)
.map((col) => col.name); .map((col) => col.name);
allowedKeys.forEach((key) => { allowedKeys.forEach((key) => {
if (buyUltimateData.hasOwnProperty(key) && key !== 'entryFk') { if (buyUltimateData?.hasOwnProperty(key) && key !== 'entryFk') {
if (!['stickers', 'quantity'].includes(key)) data[key] = buyUltimateData[key]; if (!['stickers', 'quantity'].includes(key)) data[key] = buyUltimateData[key];
} }
}); });
@ -608,6 +608,7 @@ onMounted(() => {
ref="entryBuysRef" ref="entryBuysRef"
data-key="EntryBuys" data-key="EntryBuys"
:url="`Entries/${entityId}/getBuyList`" :url="`Entries/${entityId}/getBuyList`"
search-url="EntryBuys"
save-url="Buys/crud" save-url="Buys/crud"
:disable-option="{ card: true }" :disable-option="{ card: true }"
v-model:selected="selectedRows" v-model:selected="selectedRows"
@ -637,16 +638,19 @@ onMounted(() => {
isFullWidth: true, isFullWidth: true,
containerStyle: { containerStyle: {
display: 'flex', display: 'flex',
'flex-wrap': 'wrap',
gap: '16px', gap: '16px',
position: 'relative', position: 'relative',
height: '500px',
}, },
columnGridStyle: { columnGridStyle: {
'max-width': '50%', 'max-width': '50%',
flex: 1,
'margin-right': '30px', 'margin-right': '30px',
flex: 1,
}, },
previousStyle: {
'max-width': '30%',
height: '500px',
},
displayPrevious: true,
}" }"
:is-editable="editableMode" :is-editable="editableMode"
:without-header="!editableMode" :without-header="!editableMode"
@ -661,6 +665,7 @@ onMounted(() => {
auto-load auto-load
footer footer
data-cy="entry-buys" data-cy="entry-buys"
overlay
> >
<template #column-hex="{ row }"> <template #column-hex="{ row }">
<VnColor :colors="row?.hexJson" style="height: 100%; min-width: 2000px" /> <VnColor :colors="row?.hexJson" style="height: 100%; min-width: 2000px" />

View File

@ -11,6 +11,8 @@ import VnTable from 'components/VnTable/VnTable.vue';
import SupplierDescriptorProxy from 'src/pages/Supplier/Card/SupplierDescriptorProxy.vue'; import SupplierDescriptorProxy from 'src/pages/Supplier/Card/SupplierDescriptorProxy.vue';
import VnSelectTravelExtended from 'src/components/common/VnSelectTravelExtended.vue'; import VnSelectTravelExtended from 'src/components/common/VnSelectTravelExtended.vue';
import { toDate } from 'src/filters'; import { toDate } from 'src/filters';
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import EntrySummary from './Card/EntrySummary.vue';
const { t } = useI18n(); const { t } = useI18n();
const tableRef = ref(); const tableRef = ref();
@ -18,6 +20,7 @@ const defaultEntry = ref({});
const state = useState(); const state = useState();
const user = state.getUser(); const user = state.getUser();
const dataKey = 'EntryList'; const dataKey = 'EntryList';
const { viewSummary } = useSummaryDialog();
const entryQueryFilter = { const entryQueryFilter = {
include: [ include: [
@ -222,6 +225,19 @@ const columns = computed(() => [
visible: false, visible: false,
create: true, create: true,
}, },
{
align: 'right',
label: '',
name: 'tableActions',
actions: [
{
title: t('components.smartCard.viewSummary'),
icon: 'preview',
isPrimary: true,
action: (row) => viewSummary(row.id, EntrySummary, 'xlg-width'),
},
],
},
]); ]);
function getBadgeAttrs(row) { function getBadgeAttrs(row) {
const date = row.landed; const date = row.landed;
@ -267,16 +283,7 @@ onBeforeMount(async () => {
</script> </script>
<template> <template>
<VnSection <VnSection :data-key="dataKey" prefix="entry">
:data-key="dataKey"
prefix="entry"
url="Entries/filter"
:array-data-props="{
url: 'Entries/filter',
order: 'landed DESC',
userFilter: entryQueryFilter,
}"
>
<template #advanced-menu> <template #advanced-menu>
<EntryFilter :data-key="dataKey" /> <EntryFilter :data-key="dataKey" />
</template> </template>
@ -285,6 +292,7 @@ onBeforeMount(async () => {
v-if="defaultEntry.defaultSupplierFk" v-if="defaultEntry.defaultSupplierFk"
ref="tableRef" ref="tableRef"
:data-key="dataKey" :data-key="dataKey"
search-url="EntryList"
url="Entries/filter" url="Entries/filter"
:filter="entryQueryFilter" :filter="entryQueryFilter"
order="landed DESC" order="landed DESC"

View File

@ -202,7 +202,7 @@ function setCursor(ref) {
:option-label="col.optionLabel" :option-label="col.optionLabel"
:filter-options="['id', 'name']" :filter-options="['id', 'name']"
:tooltip="t('Create a new expense')" :tooltip="t('Create a new expense')"
@keydown.tab=" @keydown.tab.prevent="
autocompleteExpense( autocompleteExpense(
$event, $event,
row, row,

View File

@ -97,16 +97,19 @@ const columns = computed(() => [
align: 'left', align: 'left',
name: 'isActive', name: 'isActive',
label: t('invoiceOut.negativeBases.active'), label: t('invoiceOut.negativeBases.active'),
component: 'checkbox',
}, },
{ {
align: 'left', align: 'left',
name: 'hasToInvoice', name: 'hasToInvoice',
label: t('invoiceOut.negativeBases.hasToInvoice'), label: t('invoiceOut.negativeBases.hasToInvoice'),
component: 'checkbox',
}, },
{ {
align: 'left', align: 'left',
name: 'hasVerifiedData', name: 'isTaxDataChecked',
label: t('invoiceOut.negativeBases.verifiedData'), label: t('invoiceOut.negativeBases.verifiedData'),
component: 'checkbox',
}, },
{ {
align: 'left', align: 'left',
@ -142,7 +145,7 @@ const downloadCSV = async () => {
await invoiceOutGlobalStore.getNegativeBasesCsv( await invoiceOutGlobalStore.getNegativeBasesCsv(
userParams.from, userParams.from,
userParams.to, userParams.to,
filterParams filterParams,
); );
}; };
</script> </script>

View File

@ -120,22 +120,9 @@ const updateStock = async () => {
</template> </template>
</VnLv> </VnLv>
<VnLv :label="t('globals.producer')" :value="dashIfEmpty(entity.subName)" /> <VnLv :label="t('globals.producer')" :value="dashIfEmpty(entity.subName)" />
<VnLv <VnLv v-if="entity?.value5" :label="entity?.tag5" :value="entity.value5" />
v-if="entity.value5" <VnLv v-if="entity?.value6" :label="entity?.tag6" :value="entity.value6" />
:label="t('item.descriptor.color')" <VnLv v-if="entity?.value7" :label="entity?.tag7" :value="entity.value7" />
:value="entity.value5"
>
</VnLv>
<VnLv
v-if="entity.value6"
:label="t('item.descriptor.category')"
:value="entity.value6"
/>
<VnLv
v-if="entity.value7"
:label="t('item.list.stems')"
:value="entity.value7"
/>
</template> </template>
<template #icons="{ entity }"> <template #icons="{ entity }">
<QCardActions v-if="entity" class="q-gutter-x-md"> <QCardActions v-if="entity" class="q-gutter-x-md">

View File

@ -1,5 +1,5 @@
<script setup> <script setup>
import { computed, ref } from 'vue'; import { computed, ref, markRaw } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useSummaryDialog } from 'src/composables/useSummaryDialog'; import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import { toHour } from 'src/filters'; import { toHour } from 'src/filters';
@ -8,6 +8,7 @@ import RouteFilter from 'pages/Route/Card/RouteFilter.vue';
import VnTable from 'components/VnTable/VnTable.vue'; import VnTable from 'components/VnTable/VnTable.vue';
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue'; import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
import VnSection from 'src/components/common/VnSection.vue'; import VnSection from 'src/components/common/VnSection.vue';
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
const { t } = useI18n(); const { t } = useI18n();
const { viewSummary } = useSummaryDialog(); const { viewSummary } = useSummaryDialog();
@ -38,17 +39,7 @@ const columns = computed(() => [
align: 'left', align: 'left',
name: 'workerFk', name: 'workerFk',
label: t('route.Worker'), label: t('route.Worker'),
component: 'select', component: markRaw(VnSelectWorker),
attrs: {
url: 'Workers/activeWithInheritedRole',
fields: ['id', 'name'],
useLike: false,
optionFilter: 'firstName',
find: {
value: 'workerFk',
label: 'workerUserName',
},
},
create: true, create: true,
cardVisible: true, cardVisible: true,
format: (row, dashIfEmpty) => dashIfEmpty(row.travelRef), format: (row, dashIfEmpty) => dashIfEmpty(row.travelRef),
@ -59,6 +50,10 @@ const columns = computed(() => [
name: 'agencyName', name: 'agencyName',
label: t('route.Agency'), label: t('route.Agency'),
cardVisible: true, cardVisible: true,
},
{
label: t('route.Agency'),
name: 'agencyModeFk',
component: 'select', component: 'select',
attrs: { attrs: {
url: 'agencyModes', url: 'agencyModes',
@ -69,14 +64,19 @@ const columns = computed(() => [
}, },
}, },
create: true, create: true,
columnClass: 'expand',
columnFilter: false, columnFilter: false,
visible: false,
}, },
{ {
align: 'left', align: 'left',
name: 'vehiclePlateNumber', name: 'vehiclePlateNumber',
label: t('route.Vehicle'), label: t('route.Vehicle'),
cardVisible: true, cardVisible: true,
},
{
name: 'vehicleFk',
label: t('route.Vehicle'),
cardVisible: true,
component: 'select', component: 'select',
attrs: { attrs: {
url: 'vehicles', url: 'vehicles',
@ -90,6 +90,7 @@ const columns = computed(() => [
}, },
create: true, create: true,
columnFilter: false, columnFilter: false,
visible: false,
}, },
{ {
align: 'left', align: 'left',
@ -156,6 +157,7 @@ const columns = computed(() => [
<VnTable <VnTable
:data-key :data-key
:columns="columns" :columns="columns"
ref="tableRef"
:right-search="false" :right-search="false"
redirect="route" redirect="route"
:create="{ :create="{

View File

@ -6,7 +6,10 @@ import VnSection from 'src/components/common/VnSection.vue';
import VnInput from 'src/components/common/VnInput.vue'; import VnInput from 'src/components/common/VnInput.vue';
import VnSelect from 'src/components/common/VnSelect.vue'; import VnSelect from 'src/components/common/VnSelect.vue';
import FetchData from 'src/components/FetchData.vue'; import FetchData from 'src/components/FetchData.vue';
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import SupplierSummary from './Card/SupplierSummary.vue';
const { viewSummary } = useSummaryDialog();
const { t } = useI18n(); const { t } = useI18n();
const tableRef = ref(); const tableRef = ref();
const dataKey = 'SupplierList'; const dataKey = 'SupplierList';
@ -103,6 +106,19 @@ const columns = computed(() => [
}, },
}, },
}, },
{
align: 'right',
label: '',
name: 'tableActions',
actions: [
{
title: t('components.smartCard.viewSummary'),
icon: 'preview',
isPrimary: true,
action: (row) => viewSummary(row.id, SupplierSummary, 'md-width'),
},
],
},
]); ]);
</script> </script>
<template> <template>

View File

@ -203,7 +203,7 @@ const updateQuantity = async (sale) => {
sale.isNew = false; sale.isNew = false;
await axios.post(`Sales/${id}/updateQuantity`, { quantity }); await axios.post(`Sales/${id}/updateQuantity`, { quantity });
notify('globals.dataSaved', 'positive'); notify('globals.dataSaved', 'positive');
tableRef.value.reload(); resetChanges();
} catch (e) { } catch (e) {
const { quantity } = tableRef.value.CrudModelRef.originalData.find( const { quantity } = tableRef.value.CrudModelRef.originalData.find(
(s) => s.id === sale.id, (s) => s.id === sale.id,
@ -247,7 +247,7 @@ const updateConcept = async (sale) => {
const data = { newConcept: sale.concept }; const data = { newConcept: sale.concept };
await axios.post(`Sales/${sale.id}/updateConcept`, data); await axios.post(`Sales/${sale.id}/updateConcept`, data);
notify('globals.dataSaved', 'positive'); notify('globals.dataSaved', 'positive');
tableRef.value.reload(); resetChanges();
}; };
const DEFAULT_EDIT = { const DEFAULT_EDIT = {
@ -298,7 +298,7 @@ const updatePrice = async (sale, newPrice) => {
sale.price = newPrice; sale.price = newPrice;
edit.value = { ...DEFAULT_EDIT }; edit.value = { ...DEFAULT_EDIT };
notify('globals.dataSaved', 'positive'); notify('globals.dataSaved', 'positive');
tableRef.value.reload(); resetChanges();
}; };
const changeDiscount = async (sale) => { const changeDiscount = async (sale) => {
@ -330,7 +330,7 @@ const updateDiscount = async (sales, newDiscount = null) => {
}; };
await axios.post(`Tickets/${route.params.id}/updateDiscount`, params); await axios.post(`Tickets/${route.params.id}/updateDiscount`, params);
notify('globals.dataSaved', 'positive'); notify('globals.dataSaved', 'positive');
tableRef.value.reload(); resetChanges();
}; };
const getNewPrice = computed(() => { const getNewPrice = computed(() => {
@ -398,7 +398,7 @@ const removeSales = async () => {
await axios.post('Sales/deleteSales', params); await axios.post('Sales/deleteSales', params);
removeSelectedSales(); removeSelectedSales();
notify('globals.dataSaved', 'positive'); notify('globals.dataSaved', 'positive');
window.location.reload(); resetChanges();
}; };
const setTransferParams = async () => { const setTransferParams = async () => {

View File

@ -214,6 +214,7 @@ const columns = computed(() => [
{ {
title: t('components.smartCard.viewSummary'), title: t('components.smartCard.viewSummary'),
icon: 'preview', icon: 'preview',
isPrimary: true,
action: (row, evt) => { action: (row, evt) => {
if (evt && evt.ctrlKey) { if (evt && evt.ctrlKey) {
const url = router.resolve({ const url = router.resolve({
@ -251,7 +252,7 @@ const fetchAvailableAgencies = async (formData) => {
const { options, agency } = response; const { options, agency } = response;
if (options) agenciesOptions.value = options; if (options) agenciesOptions.value = options;
if (agency) formData.agencyModeId = agency; if (agency) formData.agencyModeId = agency.agencyModeFk;
}; };
const fetchClient = async (formData) => { const fetchClient = async (formData) => {

View File

@ -17,6 +17,12 @@ const maritalStatus = [
{ code: 'M', name: t('Married') }, { code: 'M', name: t('Married') },
{ code: 'S', name: t('Single') }, { code: 'S', name: t('Single') },
]; ];
async function setAdvancedSummary(data) {
const advanced = (await useAdvancedSummary('Workers', data.id)) ?? {};
Object.assign(form.value.formData, advanced);
await nextTick();
if (form.value) form.value.hasChanges = false;
}
</script> </script>
<template> <template>
<FetchData <FetchData
@ -36,13 +42,7 @@ const maritalStatus = [
:url-update="`Workers/${$route.params.id}`" :url-update="`Workers/${$route.params.id}`"
auto-load auto-load
model="Worker" model="Worker"
@on-fetch=" @on-fetch="setAdvancedSummary"
async (data) => {
Object.assign(data, (await useAdvancedSummary('Workers', data.id)) ?? {});
await $nextTick();
if (form) form.hasChanges = false;
}
"
> >
<template #form="{ data }"> <template #form="{ data }">
<VnRow> <VnRow>

View File

@ -35,6 +35,22 @@ async function reactivateWorker() {
} }
} }
const columns = computed(() => [ const columns = computed(() => [
{
name: 'id',
label: t('Id'),
align: 'left',
isId: true,
cardVisible: true,
width: '40px',
},
{
name: 'isHourlyLabor',
label: t('worker.business.tableVisibleColumns.hourlyLabor'),
align: 'left',
component: 'checkbox',
cardVisible: true,
width: '60px',
},
{ {
name: 'started', name: 'started',
label: t('worker.business.tableVisibleColumns.started'), label: t('worker.business.tableVisibleColumns.started'),
@ -194,6 +210,20 @@ const columns = computed(() => [
format: ({ workerBusinessTypeName }, dashIfEmpty) => format: ({ workerBusinessTypeName }, dashIfEmpty) =>
dashIfEmpty(workerBusinessTypeName), dashIfEmpty(workerBusinessTypeName),
}, },
{
align: 'left',
name: 'workerBusinessAgreementFk',
label: t('worker.business.tableVisibleColumns.workerBusinessAgreementName'),
component: 'select',
attrs: {
url: 'WorkerBusinessAgreements',
fields: ['id', 'name'],
},
cardVisible: true,
create: true,
format: ({ workerBusinessAgreementName }, dashIfEmpty) =>
dashIfEmpty(workerBusinessAgreementName),
},
{ {
align: 'left', align: 'left',
label: t('worker.business.tableVisibleColumns.amount'), label: t('worker.business.tableVisibleColumns.amount'),
@ -230,7 +260,7 @@ const columns = computed(() => [
save-url="/Businesses/crud" save-url="/Businesses/crud"
:create="{ :create="{
urlCreate: `Workers/${entityId}/Business`, urlCreate: `Workers/${entityId}/Business`,
title: 'Create business', title: t('Create business'),
onDataSaved: () => tableRef.reload(), onDataSaved: () => tableRef.reload(),
formInitialData: {}, formInitialData: {},
}" }"
@ -248,4 +278,5 @@ const columns = computed(() => [
<i18n> <i18n>
es: es:
Do you want to reactivate the user?: desea reactivar el usuario? Do you want to reactivate the user?: desea reactivar el usuario?
Create business: Crear contrato
</i18n> </i18n>

View File

@ -12,6 +12,11 @@ const $props = defineProps({
<template> <template>
<QPopupProxy> <QPopupProxy>
<WorkerDescriptor v-if="$props.id" :id="$props.id" :summary="WorkerSummary" /> <WorkerDescriptor
v-if="$props.id"
:id="$props.id"
:summary="WorkerSummary"
data-key="WorkerDescriptorProxy"
/>
</QPopupProxy> </QPopupProxy>
</template> </template>

View File

@ -67,7 +67,7 @@ describe('Entry', () => {
it('Should notify when entry is lock by another user', () => { it('Should notify when entry is lock by another user', () => {
const checkLockMessage = () => { const checkLockMessage = () => {
cy.get('[data-cy="entry-lock-confirm"]').should('be.visible'); cy.get('[role="dialog"]').should('be.visible');
cy.get('[data-cy="VnConfirm_message"] > span').should( cy.get('[data-cy="VnConfirm_message"] > span').should(
'contain.text', 'contain.text',
'This entry has been locked by buyerNick', 'This entry has been locked by buyerNick',