#7356 - TicketServices and CrudModel updates #1479

Merged
jsegarra merged 6 commits from 7356_ticketService into test 2025-03-03 12:06:24 +00:00
3 changed files with 87 additions and 30 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', name: 'Tony',
lastName: 'Stark', lastName: 'Stark',
age: 42, age: 42,
}]; },
];
vm.resetData(data); vm.resetData(data);
@ -210,11 +212,13 @@ describe('CrudModel', () => {
}); });
describe('saveChanges()', () => { describe('saveChanges()', () => {
data = [{ data = [
{
name: 'Tony', name: 'Tony',
lastName: 'Stark', lastName: 'Stark',
age: 42, 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', name: 'Bruce',
lastName: 'Wayne', lastName: 'Wayne',
age: 45, age: 45,
}] },
];
await vm.saveChanges(data); await vm.saveChanges(data);

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"
/> />