Merge branch 'dev' into 8612-shelvinge2e
gitea/salix-front/pipeline/pr-dev This commit is unstable Details

This commit is contained in:
PAU ROVIRA ROSALENY 2025-03-03 13:13:12 +00:00
commit 8ed3441007
5 changed files with 93 additions and 41 deletions

View File

@ -184,8 +184,11 @@ async function saveChanges(data) {
if ($props.beforeSaveFn) { if ($props.beforeSaveFn) {
changes = await $props.beforeSaveFn(changes, getChanges); changes = await $props.beforeSaveFn(changes, getChanges);
} }
try { try {
if (changes?.creates?.length === 0 && changes?.updates?.length === 0) {
return;
}
await axios.post($props.saveUrl || $props.url + '/crud', changes); await axios.post($props.saveUrl || $props.url + '/crud', changes);
} finally { } finally {
isLoading.value = false; isLoading.value = false;

View File

@ -30,8 +30,8 @@ describe('CrudModel', () => {
saveFn: '', saveFn: '',
}, },
}); });
wrapper=wrapper.wrapper; wrapper = wrapper.wrapper;
vm=wrapper.vm; vm = wrapper.vm;
}); });
beforeEach(() => { beforeEach(() => {
@ -143,14 +143,14 @@ describe('CrudModel', () => {
}); });
it('should return true if object is empty', async () => { it('should return true if object is empty', async () => {
dummyObj ={}; dummyObj = {};
result = vm.isEmpty(dummyObj); result = vm.isEmpty(dummyObj);
expect(result).toBe(true); expect(result).toBe(true);
}); });
it('should return false if object is not empty', async () => { it('should return false if object is not empty', async () => {
dummyObj = {a:1, b:2, c:3}; dummyObj = { a: 1, b: 2, c: 3 };
result = vm.isEmpty(dummyObj); result = vm.isEmpty(dummyObj);
expect(result).toBe(false); expect(result).toBe(false);
@ -164,20 +164,22 @@ describe('CrudModel', () => {
}); });
it('should return false if array is not empty', async () => { it('should return false if array is not empty', async () => {
dummyArray = [1,2,3]; dummyArray = [1, 2, 3];
result = vm.isEmpty(dummyArray); result = vm.isEmpty(dummyArray);
expect(result).toBe(false); expect(result).toBe(false);
}) });
}); });
describe('resetData()', () => { describe('resetData()', () => {
it('should add $index to elements in data[] and sets originalData and formData with data', async () => { it('should add $index to elements in data[] and sets originalData and formData with data', async () => {
data = [{ data = [
name: 'Tony', {
lastName: 'Stark', name: 'Tony',
age: 42, lastName: 'Stark',
}]; age: 42,
},
];
vm.resetData(data); vm.resetData(data);
@ -210,11 +212,13 @@ describe('CrudModel', () => {
}); });
describe('saveChanges()', () => { describe('saveChanges()', () => {
data = [{ data = [
name: 'Tony', {
lastName: 'Stark', name: 'Tony',
age: 42, lastName: 'Stark',
}]; age: 42,
},
];
it('should call saveFn if exists', async () => { it('should call saveFn if exists', async () => {
await wrapper.setProps({ saveFn: vi.fn() }); await wrapper.setProps({ saveFn: vi.fn() });
@ -229,13 +233,15 @@ describe('CrudModel', () => {
}); });
it("should use default url if there's not saveFn", async () => { it("should use default url if there's not saveFn", async () => {
const postMock =vi.spyOn(axios, 'post'); const postMock = vi.spyOn(axios, 'post');
vm.formData = [{ vm.formData = [
name: 'Bruce', {
lastName: 'Wayne', name: 'Bruce',
age: 45, lastName: 'Wayne',
}] age: 45,
},
];
await vm.saveChanges(data); await vm.saveChanges(data);

View File

@ -158,15 +158,10 @@ const getBadgeAttrs = (_date) => {
const scrollToToday = async () => { const scrollToToday = async () => {
await nextTick(); await nextTick();
const todayCell = document.querySelector(`td[data-date="${today.toISOString()}"]`); const todayCell = document.querySelector(
if (todayCell) { `td[data-date="${date.formatDate(today, 'YYYY-MM-DD')}"]`,
todayCell.scrollIntoView({ behavior: 'smooth', block: 'center' }); );
} if (todayCell) todayCell.scrollIntoView({ behavior: 'smooth', block: 'center' });
};
const formatDateForAttribute = (dateValue) => {
if (dateValue instanceof Date) return date.formatDate(dateValue, 'YYYY-MM-DD');
return dateValue;
}; };
async function updateWarehouse(warehouseFk) { async function updateWarehouse(warehouseFk) {
@ -242,7 +237,7 @@ async function updateWarehouse(warehouseFk) {
</QTd> </QTd>
</template> </template>
<template #body-cell-date="{ row }"> <template #body-cell-date="{ row }">
<QTd @click.stop :data-date="formatDateForAttribute(row.shipped)"> <QTd @click.stop :data-date="row?.shipped.substring(0, 10)">
<QBadge <QBadge
v-bind="getBadgeAttrs(row.shipped)" v-bind="getBadgeAttrs(row.shipped)"
class="q-ma-none" class="q-ma-none"

View File

@ -121,6 +121,50 @@ async function handleSave() {
isSaving.value = false; 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;
}
</script> </script>
<template> <template>
@ -141,6 +185,7 @@ async function handleSave() {
v-model:selected="selected" v-model:selected="selected"
:order="['description ASC']" :order="['description ASC']"
:default-remove="false" :default-remove="false"
:beforeSaveFn="beforeSave"
> >
<template #moreBeforeActions> <template #moreBeforeActions>
<QBtn <QBtn
@ -170,6 +215,7 @@ async function handleSave() {
option-value="id" option-value="id"
hide-selected hide-selected
sort-by="name ASC" sort-by="name ASC"
:required="true"
> >
<template #form> <template #form>
<TicketCreateServiceType <TicketCreateServiceType
@ -185,6 +231,7 @@ async function handleSave() {
:label="col.label" :label="col.label"
v-model.number="row.quantity" v-model.number="row.quantity"
type="number" type="number"
:required="true"
min="0" min="0"
:info="t('service.quantityInfo')" :info="t('service.quantityInfo')"
/> />
@ -196,6 +243,7 @@ async function handleSave() {
:label="col.label" :label="col.label"
v-model.number="row.price" v-model.number="row.price"
type="number" type="number"
:required="true"
min="0" min="0"
@keyup.enter="handleSave" @keyup.enter="handleSave"
/> />

View File

@ -1,5 +1,5 @@
<script setup> <script setup>
import { ref } from 'vue'; import { ref, nextTick } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import VnInputDate from 'src/components/common/VnInputDate.vue'; import VnInputDate from 'src/components/common/VnInputDate.vue';
import FetchData from 'components/FetchData.vue'; import FetchData from 'components/FetchData.vue';