diff --git a/src/components/common/VnModule.vue b/src/components/common/VnModule.vue
index 038ee1d60..747a7c951 100644
--- a/src/components/common/VnModule.vue
+++ b/src/components/common/VnModule.vue
@@ -12,7 +12,7 @@ const $props = defineProps({
},
});
onMounted(
- () => (stateStore.leftDrawer = useQuasar().screen.gt.xs ? $props.leftDrawer : false)
+ () => (stateStore.leftDrawer = useQuasar().screen.gt.xs ? $props.leftDrawer : false),
);
const teleportRef = ref({});
@@ -35,8 +35,14 @@ onMounted(() => {
-
-
+
+
+
+
+
+
+
+
diff --git a/src/pages/Customer/Card/CustomerSummary.vue b/src/pages/Customer/Card/CustomerSummary.vue
index 324da0771..c98bf1ffb 100644
--- a/src/pages/Customer/Card/CustomerSummary.vue
+++ b/src/pages/Customer/Card/CustomerSummary.vue
@@ -325,7 +325,7 @@ const sumRisk = ({ clientRisks }) => {
-
+
diff --git a/src/pages/Customer/components/CustomerSummaryTable.vue b/src/pages/Customer/components/CustomerSummaryTable.vue
index bb6f4442b..09c7e714c 100644
--- a/src/pages/Customer/components/CustomerSummaryTable.vue
+++ b/src/pages/Customer/components/CustomerSummaryTable.vue
@@ -20,7 +20,12 @@ const { t } = useI18n();
const route = useRoute();
const router = useRouter();
const { viewSummary } = useSummaryDialog();
-
+const $props = defineProps({
+ id: {
+ type: Number,
+ default: null,
+ },
+});
const filter = {
include: [
{
@@ -43,7 +48,7 @@ const filter = {
},
},
],
- where: { clientFk: route.params.id },
+ where: { clientFk: $props.id ?? route.params.id },
order: ['shipped DESC', 'id'],
limit: 30,
};
diff --git a/src/pages/Entry/Card/EntryBuys.vue b/src/pages/Entry/Card/EntryBuys.vue
index 15f8cc20c..6e67c31ed 100644
--- a/src/pages/Entry/Card/EntryBuys.vue
+++ b/src/pages/Entry/Card/EntryBuys.vue
@@ -62,9 +62,10 @@ const columns = [
name: 'workerFk',
component: 'select',
attrs: {
- url: 'Workers/search',
+ url: 'TicketRequests/getItemTypeWorker',
fields: ['id', 'nickname'],
optionLabel: 'nickname',
+ sortBy: 'nickname ASC',
optionValue: 'id',
},
visible: false,
diff --git a/src/pages/Entry/EntryFilter.vue b/src/pages/Entry/EntryFilter.vue
index 8c60918a8..6bce6aa04 100644
--- a/src/pages/Entry/EntryFilter.vue
+++ b/src/pages/Entry/EntryFilter.vue
@@ -248,7 +248,7 @@ const entryFilterPanel = ref();
en:
params:
- isExcludedFromAvailable: Inventory
+ isExcludedFromAvailable: Is excluded
isOrdered: Ordered
isReceived: Received
isConfirmed: Confirmed
diff --git a/src/pages/Entry/EntryStockBought.vue b/src/pages/Entry/EntryStockBought.vue
index 888dd205c..41f78617c 100644
--- a/src/pages/Entry/EntryStockBought.vue
+++ b/src/pages/Entry/EntryStockBought.vue
@@ -19,6 +19,7 @@ const { t } = useI18n();
const quasar = useQuasar();
const state = useState();
const user = state.getUser();
+const footer = ref({ bought: 0, reserve: 0 });
const columns = computed(() => [
{
align: 'left',
@@ -38,16 +39,14 @@ const columns = computed(() => [
cardVisible: true,
create: true,
attrs: {
- url: 'Workers/activeWithInheritedRole',
- fields: ['id', 'name', 'nickname'],
- where: { role: 'buyer' },
- optionFilter: 'firstName',
+ url: 'TicketRequests/getItemTypeWorker',
+ fields: ['id', 'nickname'],
optionLabel: 'nickname',
+ sortBy: 'nickname ASC',
optionValue: 'id',
- useLike: false,
},
columnFilter: false,
- width: '70px',
+ width: '50px',
},
{
align: 'center',
@@ -58,6 +57,7 @@ const columns = computed(() => [
component: 'number',
summation: true,
width: '50px',
+ format: ({ reserve }, dashIfEmpty) => dashIfEmpty(round(reserve)),
},
{
align: 'center',
@@ -65,6 +65,7 @@ const columns = computed(() => [
name: 'bought',
summation: true,
cardVisible: true,
+ style: ({ reserve, bought }) => boughtStyle(bought, reserve),
columnFilter: false,
},
{
@@ -95,7 +96,6 @@ const columns = computed(() => [
},
},
],
- dataCy: 'table-actions',
},
]);
@@ -137,20 +137,20 @@ function openDialog() {
}
function setFooter(data) {
- const footer = {
- bought: 0,
- reserve: 0,
- };
+ footer.value = { bought: 0, reserve: 0 };
data.forEach((row) => {
- footer.bought += row?.bought;
- footer.reserve += row?.reserve;
+ footer.value.bought += row?.bought;
+ footer.value.reserve += row?.reserve;
});
- tableRef.value.footer = footer;
}
function round(value) {
return Math.round(value * 100) / 100;
}
+
+function boughtStyle(bought, reserve) {
+ return reserve < bought ? { color: 'var(--q-negative)' } : '';
+}
@@ -253,24 +253,14 @@ function round(value) {
-
-
- {{ row?.bought }}
-
-
- {{ round(tableRef.footer.reserve) }}
+ {{ round(footer.reserve) }}
-
- {{ round(tableRef.footer.bought) }}
+
+ {{ round(footer.bought) }}
@@ -286,7 +276,7 @@ function round(value) {
justify-content: center;
}
.column {
- min-width: 40%;
+ min-width: 35%;
margin-top: 5%;
display: flex;
flex-direction: column;
diff --git a/src/pages/Entry/EntryStockBoughtDetail.vue b/src/pages/Entry/EntryStockBoughtDetail.vue
index 1a37994d9..4f002ecb9 100644
--- a/src/pages/Entry/EntryStockBoughtDetail.vue
+++ b/src/pages/Entry/EntryStockBoughtDetail.vue
@@ -14,7 +14,7 @@ const $props = defineProps({
required: true,
},
dated: {
- type: Date,
+ type: [Date, String],
required: true,
},
});
diff --git a/src/pages/Item/Card/ItemDiary.vue b/src/pages/Item/Card/ItemDiary.vue
index 31b3c328e..f839c1f71 100644
--- a/src/pages/Item/Card/ItemDiary.vue
+++ b/src/pages/Item/Card/ItemDiary.vue
@@ -12,7 +12,7 @@ import FetchData from 'components/FetchData.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import VnInputDate from 'src/components/common/VnInputDate.vue';
-import { toDateFormat } from 'src/filters/date.js';
+import { toDateTimeFormat } from 'src/filters/date.js';
import { dashIfEmpty } from 'src/filters';
import { date } from 'quasar';
import { useState } from 'src/composables/useState';
@@ -143,7 +143,12 @@ onMounted(async () => {
const fetchItemBalances = async () => await arrayDataItemBalances.fetch({});
const getBadgeAttrs = (_date) => {
- const isSameDate = date.isSameDate(today, _date);
+ let today = Date.vnNew();
+ today.setHours(0, 0, 0, 0);
+ let timeTicket = new Date(_date);
+ timeTicket.setHours(0, 0, 0, 0);
+
+ const isSameDate = date.isSameDate(today, timeTicket);
const attrs = {
'text-color': isSameDate ? 'black' : 'white',
color: isSameDate ? 'warning' : 'transparent',
@@ -153,15 +158,10 @@ const getBadgeAttrs = (_date) => {
const scrollToToday = async () => {
await nextTick();
- const todayCell = document.querySelector(`td[data-date="${today.toISOString()}"]`);
- if (todayCell) {
- todayCell.scrollIntoView({ behavior: 'smooth', block: 'center' });
- }
-};
-
-const formatDateForAttribute = (dateValue) => {
- if (dateValue instanceof Date) return date.formatDate(dateValue, 'YYYY-MM-DD');
- return dateValue;
+ const todayCell = document.querySelector(
+ `td[data-date="${date.formatDate(today, 'YYYY-MM-DD')}"]`,
+ );
+ if (todayCell) todayCell.scrollIntoView({ behavior: 'smooth', block: 'center' });
};
async function updateWarehouse(warehouseFk) {
@@ -237,14 +237,14 @@ async function updateWarehouse(warehouseFk) {
-
+
- {{ toDateFormat(row.shipped) }}
+ {{ toDateTimeFormat(row.shipped) }}
diff --git a/src/pages/Item/Card/ItemLastEntries.vue b/src/pages/Item/Card/ItemLastEntries.vue
index 7d8890c2b..1fb8bc287 100644
--- a/src/pages/Item/Card/ItemLastEntries.vue
+++ b/src/pages/Item/Card/ItemLastEntries.vue
@@ -11,7 +11,6 @@ import { toCurrency } from 'filters/index';
import { useArrayData } from 'composables/useArrayData';
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
import SupplierDescriptorProxy from 'src/pages/Supplier/Card/SupplierDescriptorProxy.vue';
-
const { t } = useI18n();
const route = useRoute();
const from = ref();
@@ -41,7 +40,7 @@ const itemLastEntries = ref([]);
const columns = computed(() => [
{
- label: 'Nv',
+ label: 'NV',
name: 'ig',
align: 'center',
},
@@ -70,6 +69,7 @@ const columns = computed(() => [
field: 'reference',
align: 'center',
format: (_, row) => toCurrency(row.price2) + ' / ' + toCurrency(row.price3),
+ style: (row) => highlightedRow(row),
},
{
label: t('lastEntries.printedStickers'),
@@ -84,6 +84,7 @@ const columns = computed(() => [
field: 'stickers',
align: 'center',
format: (val) => dashIfEmpty(val),
+ style: (row) => highlightedRow(row),
},
{
label: 'Packing',
@@ -102,12 +103,14 @@ const columns = computed(() => [
name: 'stems',
field: 'stems',
align: 'center',
+ style: (row) => highlightedRow(row),
},
{
label: t('lastEntries.quantity'),
name: 'quantity',
field: 'quantity',
align: 'center',
+ style: (row) => highlightedRow(row),
},
{
label: t('lastEntries.cost'),
@@ -120,12 +123,14 @@ const columns = computed(() => [
name: 'weight',
field: 'weight',
align: 'center',
+ style: (row) => highlightedRow(row),
},
{
label: t('lastEntries.cube'),
name: 'cube',
field: 'packagingFk',
align: 'center',
+ style: (row) => highlightedRow(row),
},
{
label: t('lastEntries.supplier'),
@@ -208,6 +213,14 @@ onMounted(async () => {
function getBadgeClass(groupingMode, expectedGrouping) {
return groupingMode === expectedGrouping ? 'accent-badge' : 'simple-badge';
}
+
+function highlightedRow(row) {
+ return row?.isInventorySupplier
+ ? {
+ 'background-color': 'var(--vn-section-hover-color)',
+ }
+ : '';
+}
@@ -236,7 +249,7 @@ function getBadgeClass(groupingMode, expectedGrouping) {
:no-data-label="t('globals.noResults')"
>
-
+
-
+
{{ row.warehouse }}
-
+
-
+
{{ row.entryFk }}
-
-
+
+
{{ value }}
- {{ t('lastEntries.grouping') }}/Packing
+ {{ t('lastEntries.grouping') }}/Packing
+
-
+
{{ row.printedStickers }}
-
+
-
+
-
+
{{ toCurrency(row.cost, 'EUR', 3) }}
@@ -319,7 +332,7 @@ function getBadgeClass(groupingMode, expectedGrouping) {
-
+
diff --git a/src/pages/Order/Card/OrderCatalogFilter.vue b/src/pages/Order/Card/OrderCatalogFilter.vue
index 76e608983..d16a92017 100644
--- a/src/pages/Order/Card/OrderCatalogFilter.vue
+++ b/src/pages/Order/Card/OrderCatalogFilter.vue
@@ -24,6 +24,10 @@ const props = defineProps({
type: Array,
required: true,
},
+ arrayData: {
+ type: Object,
+ required: true,
+ },
});
const { t } = useI18n();
@@ -74,17 +78,6 @@ const loadTypes = async (id) => {
typeList.value = data;
};
-function exprBuilder(param, value) {
- switch (param) {
- case 'categoryFk':
- case 'typeFk':
- return { [param]: value };
- case 'search':
- if (/^\d+$/.test(value)) return { 'i.id': value };
- else return { 'i.name': { like: `%${value}%` } };
- }
-}
-
const applyTags = (tagInfo, params, search) => {
if (!tagInfo || !tagInfo.values.length) {
params.tagGroups = null;
@@ -152,9 +145,8 @@ function addOrder(value, field, params) {
:data-key="props.dataKey"
:hidden-tags="['filter', 'orderFk', 'orderBy']"
:unremovable-params="['orderFk', 'orderBy']"
- :expr-builder="exprBuilder"
:custom-tags="['tagGroups', 'categoryFk']"
- :redirect="false"
+ :arrayData
>
diff --git a/src/pages/Ticket/Card/TicketService.vue b/src/pages/Ticket/Card/TicketService.vue
index 6ce69a6aa..1bd1548a4 100644
--- a/src/pages/Ticket/Card/TicketService.vue
+++ b/src/pages/Ticket/Card/TicketService.vue
@@ -121,6 +121,50 @@ async function handleSave() {
isSaving.value = false;
}
}
+function validateFields(item) {
+ // Only validate fields that are being updated
+ const shouldExist = (field) => !isUpdate || field in item;
+
+ if (!shouldExist('ticketServiceTypeFk') && !item.ticketServiceTypeFk) {
+ notify('Description is required', 'negative');
+ return false;
+ }
+
+ if (!shouldExist('quantity') && (!item.quantity || item.quantity <= 0)) {
+ notify('Quantity must be greater than 0', 'negative');
+ return false;
+ }
+
+ if (!shouldExist('price') && (!item.price || item.price < 0)) {
+ notify('Price must be valid', 'negative');
+ return false;
+ }
+
+ return true;
+}
+
+function beforeSave(data) {
+ const { creates = [], updates = [] } = data;
+ const validData = { creates: [], updates: [] };
+
+ // Validate creates
+ if (creates.length) {
+ for (const create of creates) {
+ create.ticketFk = route.params.id;
+ if (validateFields(create)) {
+ validData.creates.push(create);
+ }
+ }
+ }
+
+ // Validate updates
+ if (updates.length) {
+ for (const update of updates) {
+ validData.updates.push(update);
+ }
+ }
+ return validData;
+}
@@ -141,6 +185,7 @@ async function handleSave() {
v-model:selected="selected"
:order="['description ASC']"
:default-remove="false"
+ :beforeSaveFn="beforeSave"
>
@@ -196,6 +243,7 @@ async function handleSave() {
:label="col.label"
v-model.number="row.price"
type="number"
+ :required="true"
min="0"
@keyup.enter="handleSave"
/>
diff --git a/src/pages/Ticket/TicketAdvance.vue b/src/pages/Ticket/TicketAdvance.vue
index 05bd14075..94b4623aa 100644
--- a/src/pages/Ticket/TicketAdvance.vue
+++ b/src/pages/Ticket/TicketAdvance.vue
@@ -456,6 +456,7 @@ watch(
:pagination="{ rowsPerPage: 0 }"
:no-data-label="t('globals.noResults')"
:right-search="false"
+ :order="['futureTotalWithVat ASC']"
auto-load
:disable-option="{ card: true }"
>
diff --git a/src/pages/Worker/Card/WorkerCalendarItem.vue b/src/pages/Worker/Card/WorkerCalendarItem.vue
index 893a81c6d..86d227ad3 100644
--- a/src/pages/Worker/Card/WorkerCalendarItem.vue
+++ b/src/pages/Worker/Card/WorkerCalendarItem.vue
@@ -79,7 +79,7 @@ const editEvent = async (event) => {
};
const { data } = await axios.patch(
`Workers/${route.params.id}/updateAbsence`,
- params
+ params,
);
if (data) emit('refresh');
@@ -108,14 +108,14 @@ const handleDateSelected = (date) => {
if (!event) createEvent(_date);
};
-const handleEventSelected = (event, { year, month, day }) => {
+const handleEventSelected = async (event, { year, month, day }) => {
if (!props.absenceType) {
notify(t('Choose an absence type from the right menu'), 'warning');
return;
}
const date = new Date(year, month - 1, day);
- if (!event?.absenceId) createEvent(date);
+ if (!event?.absenceId) await createEvent(date);
else if (event.type == props.absenceType.code) deleteEvent(event, date);
else editEvent(event);
};
diff --git a/src/pages/Worker/WorkerDepartment.vue b/src/pages/Worker/WorkerDepartment.vue
index baf6db154..e1411250b 100644
--- a/src/pages/Worker/WorkerDepartment.vue
+++ b/src/pages/Worker/WorkerDepartment.vue
@@ -1,16 +1,9 @@
-
-
-
-
-
-
-
+
diff --git a/src/stores/useStateStore.js b/src/stores/useStateStore.js
index e48b67279..ca447bc11 100644
--- a/src/stores/useStateStore.js
+++ b/src/stores/useStateStore.js
@@ -7,7 +7,11 @@ export const useStateStore = defineStore('stateStore', () => {
const rightDrawer = ref(false);
const rightAdvancedDrawer = ref(false);
const subToolbar = ref(false);
+ const cardDescriptor = ref(null);
+ function cardDescriptorChangeValue(descriptor) {
+ cardDescriptor.value = descriptor;
+ }
function toggleLeftDrawer() {
leftDrawer.value = !leftDrawer.value;
}
@@ -49,6 +53,8 @@ export const useStateStore = defineStore('stateStore', () => {
}
return {
+ cardDescriptor,
+ cardDescriptorChangeValue,
leftDrawer,
rightDrawer,
rightAdvancedDrawer,