#7936 improve InvoiceIn #1004

Merged
jorgep merged 55 commits from 7936-improveInvoiceIn into dev 2024-12-18 09:22:09 +00:00
60 changed files with 493 additions and 593 deletions
Showing only changes of commit 74e2eb3df1 - Show all commits

View File

@ -0,0 +1,36 @@
import routes from 'src/router/modules';
import { useRouter } from 'vue-router';
let isNotified = false;
export default {
created: function () {
const router = useRouter();
const keyBindingMap = routes
.filter((route) => route.meta.keyBinding)
.reduce((map, route) => {
map['Key' + route.meta.keyBinding.toUpperCase()] = route.path;
return map;
}, {});
const handleKeyDown = (event) => {
const { ctrlKey, altKey, code } = event;
if (ctrlKey && altKey && keyBindingMap[code] && !isNotified) {
event.preventDefault();
router.push(keyBindingMap[code]);
isNotified = true;
}
};
const handleKeyUp = (event) => {
const { ctrlKey, altKey } = event;
if (!ctrlKey || !altKey) {
isNotified = false;
}
};
window.addEventListener('keydown', handleKeyDown);
window.addEventListener('keyup', handleKeyUp);
},
};

View File

@ -1,30 +1,52 @@
import { getCurrentInstance } from 'vue';
function focusFirstInput(input) {
input.focus();
return;
}
export default {
mounted: function () {
const vm = getCurrentInstance();
if (vm.type.name === 'QForm') {
if (!['searchbarForm', 'filterPanelForm'].includes(this.$el?.id)) {
// TODO: AUTOFOCUS IS NOT FOCUSING
const that = this;
this.$el.addEventListener('keyup', function (evt) {
if (evt.key === 'Enter') {
const input = evt.target;
if (input.type == 'textarea' && evt.shiftKey) {
evt.preventDefault();
let { selectionStart, selectionEnd } = input;
input.value =
input.value.substring(0, selectionStart) +
'\n' +
input.value.substring(selectionEnd);
selectionStart = selectionEnd = selectionStart + 1;
return;
}
evt.preventDefault();
that.onSubmit();
}
});
const that = this;
const form = document.querySelector('.q-form#formModel');
if (!form) return;
try {
const inputsFormCard = form.querySelectorAll(
`input:not([disabled]):not([type="checkbox"])`
);
if (inputsFormCard.length) {
focusFirstInput(inputsFormCard[0]);
}
const textareas = document.querySelectorAll(
'textarea:not([disabled]), [contenteditable]:not([disabled])'
);
if (textareas.length) {
focusFirstInput(textareas[textareas.length - 1]);
}
const inputs = document.querySelectorAll(
'form#formModel input:not([disabled]):not([type="checkbox"])'
);
const input = inputs[0];
if (!input) return;
focusFirstInput(input);
} catch (error) {
console.error(error);
}
form.addEventListener('keyup', function (evt) {
if (evt.key === 'Enter') {
const input = evt.target;
if (input.type == 'textarea' && evt.shiftKey) {
evt.preventDefault();
let { selectionStart, selectionEnd } = input;
input.value =
input.value.substring(0, selectionStart) +
'\n' +
input.value.substring(selectionEnd);
selectionStart = selectionEnd = selectionStart + 1;
return;
}
evt.preventDefault();
that.onSubmit();
}
});
},
};

View File

@ -3,11 +3,16 @@ import qFormMixin from './qformMixin';
import keyShortcut from './keyShortcut';
import useNotify from 'src/composables/useNotify.js';
import { CanceledError } from 'axios';
import { QForm } from 'quasar';
import { QLayout } from 'quasar';
import mainShortcutMixin from './mainShortcutMixin';
const { notify } = useNotify();
export default boot(({ app }) => {
app.mixin(qFormMixin);
QForm.mixins = [qFormMixin];
QLayout.mixins = [mainShortcutMixin];
app.directive('shortcut', keyShortcut);
app.config.errorHandler = (error) => {
let message;

View File

@ -610,6 +610,7 @@ function handleSelection({ evt, added, rows: selectedRows }, rows) {
$props.rowClick && $props.rowClick(row);
}
"
style="height: 100%"
>
<QCardSection
vertical

View File

@ -238,6 +238,7 @@ async function openPointRecord(id, modelLog) {
pointRecord.value = parseProps(propNames, locale, data);
}
async function setLogTree(data) {
if (!data) return;
logTree.value = getLogTree(data);
}

View File

@ -0,0 +1,85 @@
<script setup>
import { computed, useAttrs } from 'vue';
import VnSelect from 'components/common/VnSelect.vue';
import VnAvatar from 'src/components/ui/VnAvatar.vue';
const emit = defineEmits(['update:modelValue']);
const $props = defineProps({
hasAvatar: {
type: Boolean,
default: false,
},
hasInfo: {
type: Boolean,
default: false,
},
modelValue: {
type: [String, Number, Object],
default: null,
},
});
const $attrs = useAttrs();
const value = computed({
get() {
return $props.modelValue;
},
set(val) {
emit('update:modelValue', val);
},
});
const url = computed(() => {
let url = 'Workers/search';
const { departmentCodes } = $attrs.params ?? {};
if (!departmentCodes) return url;
const params = new URLSearchParams({
departmentCodes: JSON.stringify(departmentCodes),
});
return url.concat(`?${params.toString()}`);
});
</script>
<template>
<VnSelect
:label="$t('globals.worker')"
v-bind="$attrs"
v-model="value"
:url="url"
option-value="id"
option-label="nickname"
:fields="['id', 'name', 'nickname', 'code']"
sort-by="nickname ASC"
>
<template #prepend v-if="$props.hasAvatar">
<VnAvatar :worker-id="value" color="primary" :title="title" />
</template>
<template #append v-if="$props.hasInfo">
<QIcon name="info" class="cursor-pointer">
<QTooltip>{{ $t($props.hasInfo) }}</QTooltip>
</QIcon>
</template>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>
{{ scope.opt.name }}
</QItemLabel>
<QItemLabel v-if="!scope.opt.id">
{{ scope.opt.nickname }}
</QItemLabel>
<QItemLabel caption v-else>
{{ scope.opt.nickname }}, {{ scope.opt.code }}
</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelect>
</template>
<i18n>
es:
Responsible for approving invoices: Responsable de aprobar las facturas
</i18n>

View File

@ -61,6 +61,7 @@ const emit = defineEmits([
'update:modelValue',
'refresh',
'clear',
'search',
'init',
'remove',
'setUserParams',

View File

@ -409,8 +409,8 @@ entry:
buys: Buys
stickers: Stickers
package: Package
packing: Packing
grouping: Grouping
packing: Pack.
grouping: Group.
buyingValue: Buying value
import: Import
pvp: PVP

View File

@ -410,8 +410,8 @@ entry:
buys: Compras
stickers: Etiquetas
package: Embalaje
packing: Packing
grouping: Grouping
packing: Pack.
grouping: Group.
buyingValue: Coste
import: Importe
pvp: PVP

View File

@ -1,50 +1,10 @@
<script setup>
import { useQuasar } from 'quasar';
import Navbar from 'src/components/NavBar.vue';
import { useRouter } from 'vue-router';
import routes from 'src/router/modules';
import { onMounted } from 'vue';
const quasar = useQuasar();
onMounted(() => {
let isNotified = false;
const router = useRouter();
const keyBindingMap = routes
.filter((route) => route.meta.keyBinding)
.reduce((map, route) => {
map['Key' + route.meta.keyBinding.toUpperCase()] = route.path;
return map;
}, {});
const handleKeyDown = (event) => {
const { ctrlKey, altKey, code } = event;
if (ctrlKey && altKey && keyBindingMap[code] && !isNotified) {
event.preventDefault();
router.push(keyBindingMap[code]);
isNotified = true;
}
};
const handleKeyUp = (event) => {
const { ctrlKey, altKey } = event;
if (!ctrlKey || !altKey) {
isNotified = false;
}
};
window.addEventListener('keydown', handleKeyDown);
window.addEventListener('keyup', handleKeyUp);
});
</script>
<template>
<QLayout view="hHh LpR fFf" v-shortcut>
<Navbar />
<RouterView></RouterView>
<QFooter v-if="quasar.platform.is.mobile"></QFooter>
<QFooter v-if="$q.platform.is.mobile"></QFooter>
</QLayout>
</template>

View File

@ -31,7 +31,6 @@ const rolesOptions = ref([]);
<VnFilterPanel
:data-key="props.dataKey"
:search-button="true"
:hidden-tags="['search']"
:redirect="false"
search-url="table"
>

View File

@ -37,11 +37,7 @@ onBeforeMount(() => {
@on-fetch="(data) => (rolesOptions = data)"
auto-load
/>
<VnFilterPanel
:data-key="props.dataKey"
:search-button="true"
:hidden-tags="['search']"
>
<VnFilterPanel :data-key="props.dataKey" :search-button="true">
<template #tags="{ tag, formatFn }">
<div class="q-gutter-x-xs">
<strong>{{ t(`acls.aclFilter.${tag.label}`) }}: </strong>

View File

@ -13,12 +13,7 @@ const props = defineProps({
</script>
<template>
<VnFilterPanel
:data-key="props.dataKey"
:search-button="true"
:hidden-tags="['search']"
:redirect="false"
>
<VnFilterPanel :data-key="props.dataKey" :search-button="true" :redirect="false">
<template #tags="{ tag, formatFn }">
<div class="q-gutter-x-xs">
<strong>{{ t(`role.${tag.label}`) }}: </strong>

View File

@ -8,7 +8,7 @@ import FormModel from 'components/FormModel.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnInput from 'src/components/common/VnInput.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import VnAvatar from 'src/components/ui/VnAvatar.vue';
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
import { getDifferences, getUpdatedValues } from 'src/filters';
const route = useRoute();
@ -16,7 +16,6 @@ const { t } = useI18n();
const businessTypes = ref([]);
const contactChannels = ref([]);
const title = ref();
const handleSalesModelValue = (val) => ({
or: [
{ id: val },
@ -117,41 +116,17 @@ function onBeforeSave(formData, originalData) {
/>
</VnRow>
<VnRow>
<VnSelect
url="Workers/search"
v-model="data.salesPersonFk"
<VnSelectWorker
:label="t('customer.summary.salesPerson')"
v-model="data.salesPersonFk"
:params="{
departmentCodes: ['VT', 'shopping'],
}"
:fields="['id', 'nickname']"
sort-by="nickname ASC"
option-label="nickname"
option-value="id"
:has-avatar="true"
:rules="validate('client.salesPersonFk')"
:expr-builder="exprBuilder"
emit-value
auto-load
>
<template #prepend>
<VnAvatar
:worker-id="data.salesPersonFk"
color="primary"
:title="title"
/>
</template>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>{{ scope.opt?.name }}</QItemLabel>
<QItemLabel caption
>{{ scope.opt?.nickname }},
{{ scope.opt?.code }}</QItemLabel
>
</QItemSection>
</QItem>
</template>
</VnSelect>
/>
<VnSelect
v-model="data.contactChannelFk"
:options="contactChannels"

View File

@ -3,6 +3,7 @@ import { useI18n } from 'vue-i18n';
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
import VnSelect from 'components/common/VnSelect.vue';
import VnInput from 'src/components/common/VnInput.vue';
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
const { t } = useI18n();
defineProps({
@ -65,19 +66,14 @@ const exprBuilder = (param, value) => {
</QItem>
<QItem class="q-mb-sm">
<QItemSection>
<VnSelect
url="Workers/search"
<VnSelectWorker
:label="t('Salesperson')"
v-model="params.salesPersonFk"
:params="{
departmentCodes: ['VT'],
}"
auto-load
:label="t('Salesperson')"
:expr-builder="exprBuilder"
v-model="params.salesPersonFk"
@update:model-value="searchFn()"
option-value="id"
option-label="name"
sort-by="nickname ASC"
emit-value
map-options
use-input
@ -86,18 +82,7 @@ const exprBuilder = (param, value) => {
outlined
rounded
:input-debounce="0"
>
<template #option="{ itemProps, opt }">
<QItem v-bind="itemProps">
<QItemSection>
<QItemLabel>{{ opt.name }}</QItemLabel>
<QItemLabel caption>
{{ opt.nickname }},{{ opt.code }}
</QItemLabel>
</QItemSection>
</QItem>
</template></VnSelect
>
/>
</QItemSection>
</QItem>
<QItem class="q-mb-sm">

View File

@ -2,7 +2,6 @@
import { ref, computed, markRaw } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router';
import VnSelect from 'src/components/common/VnSelect.vue';
import VnTable from 'components/VnTable/VnTable.vue';
import VnLocation from 'src/components/common/VnLocation.vue';
import VnSearchbar from 'components/ui/VnSearchbar.vue';
@ -12,7 +11,7 @@ import RightMenu from 'src/components/common/RightMenu.vue';
import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue';
import { toDate } from 'src/filters';
import CustomerFilter from './CustomerFilter.vue';
import VnAvatar from 'src/components/ui/VnAvatar.vue';
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
const { t } = useI18n();
const router = useRouter();
@ -422,40 +421,17 @@ function handleLocation(data, location) {
auto-load
>
<template #more-create-dialog="{ data }">
<VnSelect
url="Workers/search"
v-model="data.salesPersonFk"
<VnSelectWorker
:label="t('customer.summary.salesPerson')"
v-model="data.salesPersonFk"
:params="{
departmentCodes: ['VT', 'shopping'],
}"
:fields="['id', 'nickname', 'code']"
sort-by="nickname ASC"
option-label="nickname"
option-value="id"
:has-avatar="true"
:id-value="data.salesPersonFk"
emit-value
auto-load
>
<template #prepend>
<VnAvatar
:worker-id="data.salesPersonFk"
color="primary"
:title="title"
/>
</template>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>{{ scope.opt?.name }}</QItemLabel>
<QItemLabel caption
>{{ scope.opt?.nickname }},
{{ scope.opt?.code }}</QItemLabel
>
</QItemSection>
</QItem>
</template>
</VnSelect>
/>
<VnLocation
:acls="[{ model: 'Province', props: '*', accessType: 'WRITE' }]"
v-model="data.location"

View File

@ -6,6 +6,7 @@ import FormModel from 'components/FormModel.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnInput from 'src/components/common/VnInput.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
const route = useRoute();
const { t } = useI18n();
@ -48,14 +49,9 @@ const { t } = useI18n();
/>
</VnRow>
<VnRow>
<VnSelect
<VnSelectWorker
:label="t('department.bossDepartment')"
v-model="data.workerFk"
url="Workers/search"
option-value="id"
option-label="name"
hide-selected
map-options
:rules="validate('department.workerFk')"
/>
<VnSelect

View File

@ -2,12 +2,15 @@
import { ref, nextTick } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import axios from 'axios';
import CrudModel from 'src/components/CrudModel.vue';
import VnInput from 'src/components/common/VnInput.vue';
import useNotify from 'src/composables/useNotify.js';
const route = useRoute();
const { t } = useI18n();
const { notify } = useNotify();
const itemBarcodeRef = ref(null);
@ -23,6 +26,24 @@ const focusLastInput = () => {
if (lastInput) lastInput.focus();
});
};
const removeRow = (row) => {
itemBarcodeRef.value.remove([row]);
};
const submit = async (rows) => {
const params = rows[rows.length - 1];
let { data } = await axios.get('ItemBarcodes');
const code = params.code;
if (data.some((codes) => codes.code === code)) {
notify(t('Codes can not be repeated'), 'negative');
itemBarcodeRef.value.reset();
return;
}
await axios.patch(`ItemBarcodes`, params);
notify(t('globals.dataSaved'), 'positive');
};
</script>
<template>
<div class="full-width flex justify-center">
@ -39,6 +60,7 @@ const focusLastInput = () => {
ref="itemBarcodeRef"
url="ItemBarcodes"
auto-load
:save-fn="submit"
>
<template #body="{ rows }">
<QCard class="q-px-lg q-py-md">
@ -54,7 +76,7 @@ const focusLastInput = () => {
focusable-input
/>
<QIcon
@click="itemBarcodeRef.remove([row])"
@click="removeRow(row)"
class="cursor-pointer q-ml-md"
color="primary"
name="delete"
@ -89,4 +111,5 @@ es:
Code: Código
Remove barcode: Quitar código de barras
Add barcode: Añadir código de barras
Codes can not be repeated: Los códigos no puden ser repetidos
</i18n>

View File

@ -70,6 +70,7 @@ const onIntrastatCreated = (response, formData) => {
option-label="name"
hide-selected
map-options
required
>
<template #option="scope">
<QItem v-bind="scope.itemProps">

View File

@ -1,5 +1,5 @@
<script setup>
import { ref, onMounted, reactive, computed } from 'vue';
import { ref, reactive, computed } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';

View File

@ -67,7 +67,7 @@ const handlePhotoUpdated = (evt = false) => {
<template>
<div class="relative-position">
<VnImg ref="image" :id="$props.entityId" zoom-resolution="1600x900">
<VnImg ref="image" :id="parseInt($props.entityId)" zoom-resolution="1600x900">
<template #error>
<div class="absolute-full picture text-center q-pa-md flex flex-center">
<div>

View File

@ -1,5 +1,5 @@
<script setup>
import { onMounted, computed, onUnmounted, reactive, ref, nextTick, watch } from 'vue';
import { onMounted, computed, reactive, ref, nextTick, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
@ -145,8 +145,6 @@ onMounted(async () => {
await updateWarehouse(warehouseFk.value);
});
onUnmounted(() => (stateStore.rightDrawer = false));
watch(
() => router.currentRoute.value.params.id,
(newId) => {

View File

@ -1,12 +1,10 @@
<script setup>
import { onMounted, computed, onUnmounted, ref, watch } from 'vue';
import { onMounted, computed, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
import { dateRange } from 'src/filters';
import EntryDescriptorProxy from 'src/pages/Entry/Card/EntryDescriptorProxy.vue';
import VnInputDate from 'src/components/common/VnInputDate.vue';
import { useStateStore } from 'stores/useStateStore';
import { toDateTimeFormat } from 'src/filters/date.js';
import { dashIfEmpty } from 'src/filters';
import { toCurrency } from 'filters/index';
@ -15,7 +13,6 @@ import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
const { t } = useI18n();
const route = useRoute();
const stateStore = useStateStore();
const exprBuilder = (param, value) => {
switch (param) {
@ -180,8 +177,6 @@ onMounted(async () => {
updateFilter();
});
});
onUnmounted(() => (stateStore.rightDrawer = false));
</script>
<template>

View File

@ -1,19 +1,15 @@
<script setup>
import { onMounted, ref, computed, reactive } from 'vue';
import { onMounted, ref, computed, reactive, watchEffect } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
import VnInput from 'src/components/common/VnInput.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
import { toDateFormat } from 'src/filters/date.js';
import { dashIfEmpty } from 'src/filters';
import { useArrayData } from 'src/composables/useArrayData';
import useNotify from 'src/composables/useNotify.js';
import { useVnConfirm } from 'composables/useVnConfirm';
import axios from 'axios';
import { useStateStore } from 'stores/useStateStore';
import VnTable from 'src/components/VnTable/VnTable.vue';
const stateStore = useStateStore();
@ -21,8 +17,9 @@ const route = useRoute();
const { t } = useI18n();
const { notify } = useNotify();
const { openConfirmationModal } = useVnConfirm();
const rowsSelected = ref([]);
const tableRef = ref();
const selectedRows = ref([]);
const hasSelectedCards = computed(() => selectedRows.value.length > 0);
const exprBuilder = (param, value) => {
switch (param) {
@ -36,6 +33,11 @@ const exprBuilder = (param, value) => {
};
const params = reactive({ itemFk: route.params.id });
const filter = reactive({
where: {
itemFk: route.params.id,
},
});
const arrayData = useArrayData('ItemShelvings', {
url: 'ItemShelvingPlacementSupplyStocks',
@ -44,123 +46,69 @@ const arrayData = useArrayData('ItemShelvings', {
});
const rows = computed(() => arrayData.store.data || []);
const applyColumnFilter = async (col) => {
const paramKey = col.columnFilter?.filterParamKey || col.field;
params[paramKey] = col.columnFilter.filterValue;
await arrayData.addFilter({ filter: null, params });
};
const getInputEvents = (col) => {
return col.columnFilter.type === 'select'
? { 'update:modelValue': () => applyColumnFilter(col) }
: {
'keyup.enter': () => applyColumnFilter(col),
};
};
const columns = computed(() => [
{
label: t('shelvings.created'),
name: 'created',
field: 'created',
align: 'left',
sortable: true,
columnFilter: null,
format: (val) => toDateFormat(val),
columnFilter: false,
format: (row) => toDateFormat(row.created),
},
{
label: t('shelvings.item'),
name: 'item',
field: 'itemFk',
name: 'itemFk',
align: 'left',
sortable: true,
columnFilter: null,
columnFilter: false,
},
{
label: t('shelvings.concept'),
name: 'concept',
name: 'longName',
align: 'left',
sortable: true,
columnFilter: null,
columnFilter: false,
},
{
label: t('shelvings.parking'),
name: 'parking',
field: 'parking',
align: 'left',
sortable: true,
format: (val) => dashIfEmpty(val),
columnFilter: {
component: VnSelect,
type: 'select',
filterValue: null,
event: getInputEvents,
attrs: {
url: 'parkings',
fields: ['code'],
'sort-by': 'code ASC',
'option-value': 'code',
'option-label': 'code',
dense: true,
},
component: 'select',
attrs: {
url: 'parkings',
fields: ['code'],
'sort-by': 'code ASC',
'option-value': 'code',
'option-label': 'code',
dense: true,
},
columnField: { component: null },
},
{
label: t('shelvings.shelving'),
name: 'shelving',
field: 'shelving',
align: 'left',
sortable: true,
format: (val) => dashIfEmpty(val),
columnFilter: {
component: VnSelect,
type: 'select',
filterValue: null,
event: getInputEvents,
attrs: {
url: 'shelvings',
fields: ['code'],
'sort-by': 'code ASC',
'option-value': 'code',
'option-label': 'code',
dense: true,
},
component: 'select',
attrs: {
url: 'shelvings',
fields: ['code'],
'sort-by': 'code ASC',
'option-value': 'code',
'option-label': 'code',
dense: true,
},
columnField: { component: null },
},
{
label: t('shelvings.label'),
name: 'label',
align: 'left',
sortable: true,
format: (_, row) => (row.stock / row.packing).toFixed(2),
columnFilter: {
component: VnInput,
type: 'text',
filterParamKey: 'label',
filterValue: null,
event: getInputEvents,
attrs: {
dense: true,
},
},
columnFilter: { inWhere: true },
format: (row) => (row.stock / row.packing).toFixed(2),
},
{
label: t('shelvings.packing'),
field: 'packing',
name: 'packing',
attrs: { inWhere: true },
align: 'left',
sortable: true,
columnFilter: {
component: VnInput,
type: 'text',
filterValue: null,
event: getInputEvents,
attrs: {
dense: true,
},
},
format: (val) => dashIfEmpty(val),
},
]);
@ -169,15 +117,16 @@ const totalLabels = computed(() =>
);
const removeLines = async () => {
const itemShelvingIds = rowsSelected.value.map((row) => row.itemShelvingFk);
const itemShelvingIds = selectedRows.value.map((row) => row.itemShelvingFk);
await axios.post('ItemShelvings/deleteItemShelvings', { itemShelvingIds });
rowsSelected.value = [];
selectedRows.value = [];
notify('shelvings.shelvingsRemoved', 'positive');
await arrayData.fetch({ append: false });
await tableRef.value.reload();
};
onMounted(async () => {
await arrayData.fetch({ append: false });
});
watchEffect(selectedRows);
</script>
<template>
@ -203,7 +152,7 @@ onMounted(async () => {
<QBtn
color="primary"
icon="delete"
:disabled="!rowsSelected.length"
:disabled="!hasSelectedCards"
@click="
openConfirmationModal(
t('shelvings.removeConfirmTitle'),
@ -219,41 +168,27 @@ onMounted(async () => {
</Teleport>
</template>
<QPage class="column items-center q-pa-md">
<QTable
:rows="rows"
<VnTable
ref="tableRef"
data-key="ItemShelving"
:columns="columns"
row-key="id"
:pagination="{ rowsPerPage: 0 }"
class="full-width q-mt-md"
selection="multiple"
v-model:selected="rowsSelected"
:no-data-label="t('globals.noResults')"
:url="`ItemShelvingPlacementSupplyStocks`"
:filter="filter"
:expr-builder="exprBuilder"
:right-search="false"
v-model:selected="selectedRows"
:table="{
'row-key': 'itemShelvingFk',
selection: 'multiple',
}"
auto-load
>
<template #top-row="{ cols }">
<QTr>
<QTd />
<QTd
v-for="(col, index) in cols"
:key="index"
style="max-width: 100px"
>
<component
:is="col.columnFilter.component"
v-if="col.columnFilter"
v-model="col.columnFilter.filterValue"
v-bind="col.columnFilter.attrs"
v-on="col.columnFilter.event(col)"
dense
/>
</QTd>
</QTr>
</template>
<template #body-cell-concept="{ row }">
<QTd @click.stop>
<span class="link">{{ row.longName }}</span>
<template #column-longName="{ row }">
<span class="link" @click.stop>
{{ row.longName }}
<ItemDescriptorProxy :id="row.itemFk" />
</QTd>
</span>
</template>
</QTable>
</VnTable>
</QPage>
</template>

View File

@ -89,7 +89,7 @@ const getUrl = (id, param) => `#/Item/${id}/${param}`;
<QCard class="vn-one">
<VnTitle
:url="getUrl(entityId, 'basic-data')"
:text="t('item.summary.otherData')"
:text="t('item.summary.basicData')"
/>
<VnLv
:label="t('item.summary.intrastatCode')"

View File

@ -8,7 +8,6 @@ import VnRow from 'components/ui/VnRow.vue';
import VnInput from 'src/components/common/VnInput.vue';
import FetchData from 'components/FetchData.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import axios from 'axios';
const route = useRoute();
@ -60,6 +59,10 @@ const insertTag = (rows) => {
itemTagsRef.value.formData[itemTagsRef.value.formData.length - 1].priority =
getHighestPriority(rows);
};
const submitTags = async (data) => {
itemTagsRef.value.onSubmit(data);
};
</script>
<template>
@ -77,7 +80,6 @@ const insertTag = (rows) => {
data-key="ItemTags"
model="ItemTags"
url="ItemTags"
update-url="Tags/onSubmit"
:data-required="{
$index: undefined,
itemFk: route.params.id,
@ -147,6 +149,7 @@ const insertTag = (rows) => {
v-model="row.value"
:label="t('itemTags.value')"
:is-clearable="false"
@keyup.enter.stop="submitTags(row)"
/>
<VnInput
:label="t('itemBasicData.relevancy')"
@ -154,6 +157,7 @@ const insertTag = (rows) => {
v-model="row.priority"
:required="true"
:rules="validate('itemTag.priority')"
@keyup.enter.stop="submitTags(row)"
/>
<div class="row justify-center" style="flex: 0">
<QIcon
@ -189,3 +193,8 @@ const insertTag = (rows) => {
</QPage>
</div>
</template>
<i18n>
es:
Tags can not be repeated: Las etiquetas no pueden repetirse
</i18n>

View File

@ -28,7 +28,7 @@ const taxesFilter = {
],
};
const ItemTaxRef = ref(null);
const ItemTaxRef = ref();
const taxesOptions = ref([]);
const submitTaxes = async (data) => {
@ -36,7 +36,10 @@ const submitTaxes = async (data) => {
id: tax.id,
taxClassFk: tax.taxClassFk,
}));
if (payload.some((item) => item.taxClassFk === null)) {
notify(t('Tax class cannot be blank'), 'negative');
return;
}
await axios.post(`Items/updateTaxes`, payload);
notify(t('globals.dataSaved'), 'positive');
};

View File

@ -413,7 +413,6 @@ function handleOnDataSave({ CrudModelRef }) {
save-url="FixedPrices/crud"
:user-params="{ warehouseFk: user.warehouseFk }"
ref="tableRef"
dense
:columns="columns"
default-mode="table"
auto-load

View File

@ -55,17 +55,6 @@ const columns = computed(() => [
label: '',
name: 'image',
align: 'left',
columnField: {
component: VnImg,
attrs: ({ row }) => {
return {
id: row?.id,
zoomResolution: '1600x900',
zoom: true,
class: 'rounded',
};
},
},
columnFilter: false,
cardVisible: true,
},
@ -184,7 +173,7 @@ const columns = computed(() => [
cardVisible: true,
},
{
label: t('globals.origin'),
label: t('item.list.origin'),
name: 'origin',
align: 'left',
component: 'select',
@ -228,7 +217,8 @@ const columns = computed(() => [
},
},
{
label: t('item.list.weightByPiece'),
label: t('item.list.weight'),
toolTip: t('item.list.weightByPiece'),
name: 'weightByPiece',
align: 'left',
component: 'input',
@ -322,7 +312,6 @@ const columns = computed(() => [
ref="tableRef"
data-key="ItemList"
url="Items/filter"
url-create="Items"
:create="{
urlCreate: 'Items',
title: t('Create Item'),
@ -333,12 +322,19 @@ const columns = computed(() => [
}"
:order="['isActive DESC', 'name', 'id']"
:columns="columns"
auto-load
redirect="Item"
:is-editable="false"
:right-search="false"
:filer="itemFilter"
:filter="itemFilter"
>
<template #column-image="{ row }">
<VnImg
:id="row?.id"
zoom-resolution="1600x900"
:zoom="true"
class="rounded"
/>
</template>
<template #column-id="{ row }">
<span class="link" @click.stop>
{{ row.id }}
@ -348,7 +344,7 @@ const columns = computed(() => [
<template #column-userName="{ row }">
<span class="link" @click.stop>
{{ row.userName }}
<WorkerDescriptorProxy :id="row.workerFk" />
<WorkerDescriptorProxy :id="row.buyerFk" />
</span>
</template>
<template #column-description="{ row }">

View File

@ -199,7 +199,17 @@ onMounted(async () => {
dense
outlined
rounded
/>
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>{{
t(`params.${scope.opt?.name}`)
}}</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelect>
</QItemSection>
</QItem>
<QItem>
@ -434,6 +444,13 @@ en:
description: Description
name: Name
id: Id
Accessories: Accessories
Artificial: Artificial
Flower: Flower
Fruit: Fruit
Green: Green
Handmade: Handmade
Plant: Plant
es:
More fields: Más campos
params:
@ -450,4 +467,11 @@ es:
description: Descripción
name: Nombre
id: Id
Accessories: Accesorios
Artificial: Artificial
Flower: Flor
Fruit: Fruta
Green: Verde
Handmade: Hecho a mano
Plant: Planta
</i18n>

View File

@ -5,13 +5,16 @@ import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.v
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
import { useStateStore } from 'stores/useStateStore';
import { useArrayData } from 'composables/useArrayData';
import { dashIfEmpty, toCurrency } from 'filters/index';
import { toCurrency } from 'filters/index';
import useNotify from 'src/composables/useNotify.js';
import axios from 'axios';
import ItemRequestDenyForm from './ItemRequestDenyForm.vue';
import { toDate } from 'src/filters';
import VnTable from 'components/VnTable/VnTable.vue';
import VnInput from 'src/components/common/VnInput.vue';
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
import ItemRequestFilter from './ItemRequestFilter.vue';
import RightMenu from 'src/components/common/RightMenu.vue';
const { t } = useI18n();
const { notify } = useNotify();
const stateStore = useStateStore();
@ -228,6 +231,11 @@ onMounted(async () => {
</script>
<template>
<RightMenu>
<template #right-panel>
<ItemRequestFilter data-key="itemRequest" />
</template>
</RightMenu>
<VnTable
ref="tableRef"
data-key="itemRequest"
@ -239,6 +247,7 @@ onMounted(async () => {
auto-load
:disable-option="{ card: true }"
chip-locale="item.params"
:right-search="false"
>
<template #column-ticketFk="{ row }">
<span class="link">
@ -306,30 +315,28 @@ onMounted(async () => {
/>
</template>
<template #column-denyOptions="{ row, rowIndex }">
<QTd class="sticky no-padding">
<QIcon
v-if="row.response?.length"
name="insert_drive_file"
color="primary"
size="sm"
>
<QTooltip>
{{ row.response }}
</QTooltip>
</QIcon>
<QIcon
v-if="row.isOk == null"
name="thumb_down"
color="primary"
size="sm"
class="fill-icon"
@click="showDenyRequestForm(row.id, rowIndex)"
>
<QTooltip>
{{ t('Discard') }}
</QTooltip>
</QIcon>
</QTd>
<QIcon
v-if="row.response?.length"
name="insert_drive_file"
color="primary"
size="sm"
>
<QTooltip>
{{ row.response }}
</QTooltip>
</QIcon>
<QIcon
v-if="row.isOk == null"
name="thumb_down"
color="primary"
size="sm"
class="fill-icon"
@click="showDenyRequestForm(row.id, rowIndex)"
>
<QTooltip>
{{ t('Discard') }}
</QTooltip>
</QIcon>
</template>
</VnTable>
<QDialog ref="denyFormRef" transition-show="scale" transition-hide="scale">

View File

@ -1,5 +1,5 @@
<script setup>
import { ref } from 'vue';
import { onMounted, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { dateRange } from 'src/filters';
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
@ -7,6 +7,8 @@ import VnSelect from 'src/components/common/VnSelect.vue';
import VnInput from 'src/components/common/VnInput.vue';
import FetchData from 'components/FetchData.vue';
import VnInputDate from 'src/components/common/VnInputDate.vue';
import { useArrayData } from 'src/composables/useArrayData';
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
const { t } = useI18n();
const props = defineProps({
@ -21,7 +23,8 @@ const stateOptions = [
{ code: 'accepted', name: t('accepted') },
{ code: 'denied', name: t('denied') },
];
const arrayData = useArrayData(props.dataKey);
const fieldFiltersValues = ref([]);
const itemTypesOptions = ref([]);
const warehousesOptions = ref([]);
@ -56,6 +59,19 @@ const decrement = (paramsObj, key) => {
paramsObj[key]--;
};
onMounted(async () => {
if (arrayData.store?.userParams) {
fieldFiltersValues.value = Object.entries(arrayData.store.userParams).map(
([key, value]) => ({
name: key,
value,
selectedField: { name: key, label: t(`params.${key}`) },
})
);
}
exprBuilder('state', arrayData.store?.userParams?.state);
});
</script>
<template>
@ -145,33 +161,17 @@ const decrement = (paramsObj, key) => {
</QItem>
<QItem>
<QItemSection>
<VnSelect
<VnSelectWorker
:label="t('params.requesterFk')"
v-model="params.requesterFk"
@update:model-value="searchFn()"
url="Workers/search"
:fields="['id', 'name']"
order="name ASC"
:params="{ departmentCodes: ['VT'] }"
option-value="id"
option-label="name"
hide-selected
dense
outlined
rounded
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>{{ scope.opt?.name }}</QItemLabel>
<QItemLabel caption
>{{ scope.opt?.nickname }},
{{ scope.opt?.code }}</QItemLabel
>
</QItemSection>
</QItem>
</template>
</VnSelect>
/>
</QItemSection>
</QItem>
<QItem>

View File

@ -10,7 +10,6 @@ const { t } = useI18n();
url="ItemTypes"
:label="t('Search item type')"
:info="t('Search itemType by id, name or code')"
search-url="table"
/>
</template>
<i18n>

View File

@ -6,6 +6,7 @@ import VnTable from 'components/VnTable/VnTable.vue';
import FetchData from 'components/FetchData.vue';
import RightMenu from 'src/components/common/RightMenu.vue';
import ItemTypeFilter from './ItemType/ItemTypeFilter.vue';
import WorkerDescriptorProxy from '../Worker/Card/WorkerDescriptorProxy.vue';
const { t } = useI18n();
const tableRef = ref();
@ -31,13 +32,14 @@ const columns = computed(() => [
{
align: 'left',
name: 'name',
label: t('name'),
label: t('globals.name'),
cardVisible: true,
create: true,
},
{
align: 'left',
label: t('worker'),
name: 'workerFk',
create: true,
component: 'select',
attrs: {
@ -45,20 +47,20 @@ const columns = computed(() => [
optionLabel: 'nickname',
optionValue: 'id',
},
format: (row) => row.worker?.user?.name,
cardVisible: true,
visible: true,
columnField: {
component: 'userLink',
attrs: ({ row }) => {
return {
workerId: row?.worker?.id,
name: row.worker?.user?.name,
defaultName: true,
};
},
},
columnField: { component: null },
columnFilter: {
name: 'workerFk',
attrs: {
url: 'Workers/activeWithInheritedRole',
fields: ['id', 'name'],
where: { role: 'buyer' },
optionFilter: 'firstName',
optionLabel: 'name',
optionValue: 'id',
useLike: false,
},
inWhere: true,
},
},
{
@ -135,24 +137,27 @@ const columns = computed(() => [
:columns="columns"
auto-load
:right-search="false"
:is-editable="false"
:use-model="true"
redirect="item/item-type"
/>
>
<template #column-workerFk="{ row }">
<span class="link" @click.stop>
{{ row.worker?.user?.name }}
<WorkerDescriptorProxy :id="row.workerFk" />
</span>
</template>
</VnTable>
</template>
<i18n>
es:
id: Id
code: Código
name: Nombre
worker: Trabajador
ItemCategory: Reino
Temperature: Temperatura
Create ItemTypes: Crear familia
en:
code: Code
name: Name
worker: Worker
ItemCategory: ItemCategory
Temperature: Temperature

View File

@ -95,6 +95,15 @@ item:
mine: For me
state: State
myTeam: My team
shipped: Shipped
description: Description
quantity: Quantity
price: Price
item: Item
achieved: Achieved
concept: Concept
denyOptions: Deny
scopeDays: Scope days
searchbar:
label: Search item
descriptor:
@ -112,7 +121,7 @@ item:
title: All its properties will be copied
subTitle: Do you want to clone this item?
list:
id: Identifier
id: Id
grouping: Grouping
packing: Packing
description: Description
@ -122,8 +131,9 @@ item:
intrastat: Intrastat
isActive: Active
size: Size
origin: Origin
origin: Orig.
userName: Buyer
weight: Weight
weightByPiece: Weight/Piece
stemMultiplier: Multiplier
producer: Producer

View File

@ -97,6 +97,15 @@ item:
mine: Para mi
state: Estado
myTeam: Mi equipo
shipped: Enviado
description: Descripción
quantity: Cantidad
price: Precio
item: Artículo
achieved: Conseguido
concept: Concepto
denyOptions: Denegado
scopeDays: Días en adelante
searchbar:
label: Buscar artículo
descriptor:
@ -114,7 +123,7 @@ item:
title: Todas sus propiedades serán copiadas
subTitle: ¿Desea clonar este artículo?
list:
id: Identificador
id: Id
grouping: Grouping
packing: Packing
description: Descripción
@ -124,7 +133,8 @@ item:
intrastat: Intrastat
isActive: Activo
size: Medida
origin: Origen
origin: Orig.
weight: Peso
weightByPiece: Peso (gramos)/tallo
userName: Comprador
stemMultiplier: Multiplicador

View File

@ -9,6 +9,7 @@ import VnInput from 'src/components/common/VnInput.vue';
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
import FetchData from 'src/components/FetchData.vue';
import { dateRange } from 'src/filters';
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
defineProps({ dataKey: { type: String, required: true } });
const { t, te } = useI18n();
@ -112,33 +113,16 @@ const getLocale = (label) => {
</QItem>
<QItem>
<QItemSection>
<VnSelect
<VnSelectWorker
outlined
dense
rounded
:label="t('globals.params.salesPersonFk')"
v-model="params.salesPersonFk"
url="Workers/search"
:params="{ departmentCodes: ['VT'] }"
is-outlined
option-value="id"
option-label="name"
:no-one="true"
>
<template #option="{ opt, itemProps }">
<QItem v-bind="itemProps">
<QItemSection>
<QItemLabel>{{ opt.name }}</QItemLabel>
<QItemLabel
v-if="opt.code"
class="text-grey text-caption"
>
{{ `${opt.nickname}, ${opt.code}` }}
</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelect>
</VnSelectWorker>
</QItemSection>
</QItem>
<QItem>

View File

@ -1,7 +1,7 @@
<script setup>
import { useStateStore } from 'stores/useStateStore';
import { useRoute, useRouter } from 'vue-router';
import { onMounted, onUnmounted, ref, computed, watch } from 'vue';
import { onMounted, ref, computed, watch } from 'vue';
import axios from 'axios';
import { useI18n } from 'vue-i18n';
import VnPaginate from 'src/components/ui/VnPaginate.vue';
@ -29,8 +29,6 @@ onMounted(() => {
checkOrderConfirmation();
});
onUnmounted(() => (stateStore.rightDrawer = false));
async function checkOrderConfirmation() {
const response = await axios.get(`Orders/${route.params.id}`);
if (response.data.isConfirmed === 1) {

View File

@ -6,6 +6,7 @@ import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
import VnSelect from 'components/common/VnSelect.vue';
import VnInputDate from 'components/common/VnInputDate.vue';
import VnInput from 'components/common/VnInput.vue';
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
const { t } = useI18n();
const props = defineProps({
@ -61,28 +62,16 @@ const sourceList = ref([]);
outlined
rounded
/>
<VnSelect
:label="t('salesPerson')"
<VnSelectWorker
:label="t('globals.salesPerson')"
v-model="params.workerFk"
url="Workers/search"
:filter="{ departmentCodes: ['VT'] }"
sort-by="nickname ASC"
option-label="nickname"
:params="{
departmentCodes: ['VT'],
}"
dense
outlined
rounded
>
<template #option="{ itemProps, opt }">
<QItem v-bind="itemProps">
<QItemSection>
<QItemLabel>{{ opt.name }}</QItemLabel>
<QItemLabel caption>
{{ opt.nickname }},{{ opt.code }}
</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelect>
/>
<VnInputDate
v-model="params.from"
:label="t('fromLanded')"

View File

@ -4,6 +4,7 @@ import VnFilterPanel from 'components/ui/VnFilterPanel.vue';
import VnSelect from 'components/common/VnSelect.vue';
import VnInputDate from 'components/common/VnInputDate.vue';
import VnInput from 'components/common/VnInput.vue';
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
const { t } = useI18n();
const props = defineProps({
@ -31,29 +32,13 @@ const emit = defineEmits(['search']);
<template #body="{ params }">
<QItem class="q-my-sm">
<QItemSection>
<VnSelect
:label="t('Worker')"
<VnSelectWorker
v-model="params.workerFk"
url="Workers/search"
sort-by="nickname ASC"
option-value="id"
option-label="nickname"
dense
outlined
rounded
:input-debounce="0"
>
<template #option="{ itemProps, opt }">
<QItem v-bind="itemProps">
<QItemSection>
<QItemLabel>{{ opt.name }}</QItemLabel>
<QItemLabel caption>
{{ opt.nickname }},{{ opt.code }}
</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelect>
/>
</QItemSection>
</QItem>
<QItem class="q-my-sm">

View File

@ -11,6 +11,7 @@ import VnInputDate from 'components/common/VnInputDate.vue';
import VnInput from 'components/common/VnInput.vue';
import axios from 'axios';
import VnInputTime from 'components/common/VnInputTime.vue';
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
const { t } = useI18n();
const route = useRoute();
@ -94,26 +95,7 @@ const onSave = (data, response) => {
>
<template #form="{ data }">
<VnRow>
<VnSelect
:label="t('Worker')"
v-model="data.workerFk"
url="Workers/search"
sort-by="nickname ASC"
option-value="id"
option-label="nickname"
:input-debounce="0"
>
<template #option="{ itemProps, opt }">
<QItem v-bind="itemProps">
<QItemSection>
<QItemLabel>{{ opt.name }}</QItemLabel>
<QItemLabel caption>
{{ opt.nickname }}, {{ opt.code }}
</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelect>
<VnSelectWorker v-model="data.workerFk" />
<VnSelect
:label="t('Vehicle')"
v-model="data.vehicleFk"

View File

@ -2,7 +2,7 @@
import VnPaginate from 'components/ui/VnPaginate.vue';
import { useStateStore } from 'stores/useStateStore';
import { useI18n } from 'vue-i18n';
import { onMounted, onUnmounted } from 'vue';
import { onMounted } from 'vue';
import CardList from 'components/ui/CardList.vue';
import VnLv from 'components/ui/VnLv.vue';
import { useRouter } from 'vue-router';
@ -21,7 +21,6 @@ const filter = {
};
onMounted(() => (stateStore.rightDrawer = true));
onUnmounted(() => (stateStore.rightDrawer = false));
function navigate(id) {
router.push({ path: `/shelving/${id}` });

View File

@ -5,6 +5,7 @@ import FormModel from 'components/FormModel.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnInput from 'src/components/common/VnInput.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
const route = useRoute();
const { t } = useI18n();
@ -30,31 +31,11 @@ const companySizes = [
:rules="validate('supplier.nickname')"
clearable
/>
<VnSelect
:label="t('supplier.basicData.workerFk')"
<VnSelectWorker
v-model="data.workerFk"
url="Workers/search"
sort-by="nickname ASC"
has-info="Responsible for approving invoices"
:rules="validate('supplier.workerFk')"
>
<template #append>
<QIcon name="info" class="cursor-pointer">
<QTooltip>{{
t('Responsible for approving invoices')
}}</QTooltip>
</QIcon>
</template>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>{{ scope.opt?.name }}</QItemLabel>
<QItemLabel caption>
{{ scope.opt?.nickname }}, {{ scope.opt?.id }}
</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelect>
/>
<VnSelect
:label="t('supplier.basicData.size')"
v-model="data.companySize"
@ -102,6 +83,5 @@ const companySizes = [
<i18n>
es:
Responsible for approving invoices: Responsable de aprobar las facturas
Small(1-5), Medium(6-50), Big(> 50): Pequeño(1-5), Mediano(6-50), Grande(> 50)
</i18n>

View File

@ -1,5 +1,5 @@
<script setup>
import { ref, computed, onMounted, onUnmounted, watch } from 'vue';
import { ref, computed, onMounted, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
@ -134,8 +134,6 @@ onMounted(() => {
loadDefaultTicketAction();
ticketHaveNegatives();
});
onUnmounted(() => (stateStore.rightDrawer = false));
</script>
<template>

View File

@ -1,5 +1,5 @@
<script setup>
import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue';
import { ref, computed, onMounted, watch, nextTick } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
@ -168,8 +168,6 @@ const getTicketVolume = async () => {
onMounted(() => {
stateStore.rightDrawer = true;
});
onUnmounted(() => (stateStore.rightDrawer = false));
</script>
<template>

View File

@ -9,6 +9,7 @@ import VnSelect from 'src/components/common/VnSelect.vue';
import FetchData from 'components/FetchData.vue';
import { useState } from 'src/composables/useState';
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
const emit = defineEmits(['onRequestCreated']);
@ -46,29 +47,7 @@ const onStateFkChange = (formData) => (formData.userFk = user.value.id);
option-label="name"
option-value="id"
/>
<VnSelect
:label="t('expedition.worker')"
v-model="data.userFk"
url="Workers/search"
fields=" ['id', 'name']"
sort-by="name ASC"
hide-selected
option-label="name"
option-value="id"
>
<template #option="{ opt, itemProps }">
<QItem v-bind="itemProps">
<QItemSection>
<QItemLabel>
{{ opt.name }}
</QItemLabel>
<QItemLabel caption>
{{ opt.nickname }}, {{ opt.code }}
</QItemLabel>
</QItemSection>
</QItem>
</template></VnSelect
>
<VnSelectWorker v-model="data.userFk" :fields="['id', 'name']" />
</VnRow>
</template>
</FormModelPopup>

View File

@ -1,5 +1,5 @@
<script setup>
import { onMounted, ref, computed, onUnmounted } from 'vue';
import { onMounted, ref, computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
@ -197,8 +197,6 @@ onMounted(async () => {
const filteredColumns = columns.value.filter((col) => col.name !== 'history');
allColumnNames.value = filteredColumns.map((col) => col.name);
});
onUnmounted(() => (stateStore.rightDrawer = false));
</script>
<template>

View File

@ -1,5 +1,5 @@
<script setup>
import { onMounted, ref, computed, onUnmounted, watch } from 'vue';
import { onMounted, ref, computed, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRouter, useRoute } from 'vue-router';
import { useQuasar } from 'quasar';
@ -421,8 +421,6 @@ onMounted(async () => {
getConfig();
});
onUnmounted(() => (stateStore.rightDrawer = false));
const items = ref([]);
const newRow = ref({});

View File

@ -1,5 +1,5 @@
<script setup>
import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue';
import { ref, computed, onMounted, watch, nextTick } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
@ -90,8 +90,6 @@ const applyVolumes = async (salesData) => {
};
onMounted(() => (stateStore.rightDrawer = true));
onUnmounted(() => (stateStore.rightDrawer = false));
</script>
<template>

View File

@ -57,7 +57,6 @@ onMounted(async () => await getItemPackingTypes());
search-url="advanceTickets"
:data-key="props.dataKey"
:search-button="true"
:hidden-tags="['search']"
:unremovable-params="['warehouseFk', 'dateFuture', 'dateToAdvance']"
>
<template #tags="{ tag, formatFn }">

View File

@ -59,7 +59,6 @@ onMounted(async () => {
/>
<VnFilterPanel
:data-key="props.dataKey"
:hidden-tags="['search']"
:un-removable-params="['warehouseFk', 'originScopeDays ', 'futureScopeDays']"
>
<template #tags="{ tag, formatFn }">

View File

@ -1,5 +1,5 @@
<script setup>
import { onMounted, ref, computed, onUnmounted } from 'vue';
import { onMounted, ref, computed } from 'vue';
import { useI18n } from 'vue-i18n';
import VnSelect from 'src/components/common/VnSelect.vue';
import VnSelectCache from 'src/components/common/VnSelectCache.vue';
@ -170,8 +170,6 @@ onMounted(async () => {
const filteredColumns = columns.value.filter((col) => col.name !== 'actions');
allColumnNames.value = filteredColumns.map((col) => col.name);
});
onUnmounted(() => (stateStore.rightDrawer = false));
</script>
<template>

View File

@ -133,6 +133,7 @@ function reloadData() {
option-value="id"
id="deviceProductionFk"
hide-selected
data-cy="pda-dialog-select"
>
<template #option="scope">
<QItem v-bind="scope.itemProps">

View File

@ -14,6 +14,7 @@ import FormModel from 'components/FormModel.vue';
import CreateBankEntityForm from 'src/components/CreateBankEntityForm.vue';
import VnRadio from 'src/components/common/VnRadio.vue';
import { useState } from 'src/composables/useState';
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
const { t } = useI18n();
const user = useState().getUser();
@ -149,27 +150,11 @@ async function autofillBic(worker) {
hide-selected
:rules="validate('Worker.company')"
/>
<VnSelect
<VnSelectWorker
:label="t('worker.summary.boss')"
v-model="data.bossFk"
url="Workers/search"
option-value="id"
option-label="name"
hide-selected
:rules="validate('Worker.boss')"
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>{{ scope.opt.name }}</QItemLabel>
<QItemLabel caption
>{{ scope.opt.nickname }},
{{ scope.opt.code }}
</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelect>
/>
</VnRow>
<VnRow>
<VnInput

View File

@ -18,6 +18,7 @@ import RightMenu from 'src/components/common/RightMenu.vue';
import WorkerFilter from './WorkerFilter.vue';
import { useState } from 'src/composables/useState';
import axios from 'axios';
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
const { t } = useI18n();
const tableRef = ref();
@ -260,26 +261,10 @@ async function autofillBic(worker) {
option-label="code"
hide-selected
/>
<VnSelect
<VnSelectWorker
:label="t('worker.summary.boss')"
v-model="data.bossFk"
url="Workers/search"
option-value="id"
option-label="name"
hide-selected
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>{{ scope.opt.name }}</QItemLabel>
<QItemLabel caption
>{{ scope.opt.nickname }},
{{ scope.opt.code }}
</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelect>
/>
</VnRow>
<VnRow>
<VnInput v-model="data.fi" :label="t('worker.create.fi')" />
@ -376,6 +361,7 @@ async function autofillBic(worker) {
<i18n>
es:
Create worker: Crear trabajador
Search worker: Buscar trabajador
You can search by worker id or name: Puedes buscar por id o nombre del trabajador
</i18n>

View File

@ -32,7 +32,12 @@ const agencyOptions = ref([]);
<FormModel :url="`Zones/${route.params.id}`" auto-load model="zone">
<template #form="{ data, validate }">
<VnRow>
<VnInput :label="t('Name')" clearable v-model="data.name" />
<VnInput
data-cy="zone-basic-data-name"
:label="t('Name')"
clearable
v-model="data.name"
/>
</VnRow>
<VnRow>

View File

@ -1,5 +1,5 @@
<script setup>
import { ref, onUnmounted } from 'vue';
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import ZoneEventsPanel from './ZoneEventsPanel.vue';
@ -40,8 +40,6 @@ const onZoneEventFormClose = () => {
showZoneEventForm.value = false;
zoneEventsFormProps.value = {};
};
onUnmounted(() => (stateStore.rightDrawer = false));
</script>
<template>

View File

@ -28,11 +28,7 @@ const agencies = ref([]);
@on-fetch="(data) => (agencies = data)"
auto-load
/>
<VnFilterPanel
:data-key="props.dataKey"
:search-button="true"
:hidden-tags="['search']"
>
<VnFilterPanel :data-key="props.dataKey" :search-button="true">
<template #tags="{ tag }">
<div class="q-gutter-x-xs">
<strong>{{ t(`filterPanel.${tag.label}`) }}: </strong>

View File

@ -1,6 +1,5 @@
describe('WorkerPda', () => {
const deviceProductionField =
'.vn-row > .q-field > .q-field__inner > .q-field__control > .q-field__control-container';
const select = '[data-cy="pda-dialog-select"]';
beforeEach(() => {
cy.viewport(1920, 1080);
cy.login('developer');
@ -9,7 +8,8 @@ describe('WorkerPda', () => {
it('assign pda', () => {
cy.get('.q-page-sticky > div > .q-btn > .q-btn__content > .q-icon').click();
cy.get(deviceProductionField).type('{downArrow}{enter}');
cy.get(select).click();
cy.get(select).type('{downArrow}{enter}');
cy.get('.q-notification__message').should('have.text', 'Data created');
});

View File

@ -8,7 +8,7 @@ describe('ZoneBasicData', () => {
});
it('should throw an error if the name is empty', () => {
cy.get('.q-card > :nth-child(1)').clear();
cy.get('[data-cy="zone-basic-data-name"] input').type('{selectall}{backspace}');
cy.get('.q-btn-group > .q-btn--standard').click();
cy.get(notification).should('contains.text', "can't be blank");
});