refactor: refs #6900 create new expense form
This commit is contained in:
parent
0faa42867d
commit
b42385d7d6
|
@ -0,0 +1,52 @@
|
||||||
|
<script setup>
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import VnRow from 'components/ui/VnRow.vue';
|
||||||
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
import FormModelPopup from './FormModelPopup.vue';
|
||||||
|
|
||||||
|
const emit = defineEmits(['onDataSaved']);
|
||||||
|
const { t } = useI18n();
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<FormModelPopup
|
||||||
|
url-create="Expenses"
|
||||||
|
model="Expense"
|
||||||
|
:title="t('New expense')"
|
||||||
|
:form-initial-data="{ id: null, isWithheld: false, name: null }"
|
||||||
|
@on-data-saved="emit('onDataSaved', $event)"
|
||||||
|
>
|
||||||
|
<template #form-inputs="{ data, validate }">
|
||||||
|
<VnRow>
|
||||||
|
<VnInput
|
||||||
|
:label="`${t('Code')}`"
|
||||||
|
v-model="data.id"
|
||||||
|
:required="true"
|
||||||
|
:rules="validate('expense.code')"
|
||||||
|
/>
|
||||||
|
<QCheckbox
|
||||||
|
dense
|
||||||
|
size="sm"
|
||||||
|
:label="`${t('It\'s a withholding')}`"
|
||||||
|
v-model="data.isWithheld"
|
||||||
|
:rules="validate('expense.isWithheld')"
|
||||||
|
/>
|
||||||
|
</VnRow>
|
||||||
|
<VnRow>
|
||||||
|
<VnInput
|
||||||
|
:label="`${t('Description')}`"
|
||||||
|
v-model="data.name"
|
||||||
|
:required="true"
|
||||||
|
:rules="validate('expense.description')"
|
||||||
|
/>
|
||||||
|
</VnRow>
|
||||||
|
</template>
|
||||||
|
</FormModelPopup>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
New expense: Nuevo gasto
|
||||||
|
Code: Código
|
||||||
|
It's a withholding: Es una retención
|
||||||
|
Description: Descripción
|
||||||
|
</i18n>
|
|
@ -2,19 +2,17 @@
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useQuasar } from 'quasar';
|
|
||||||
import axios from 'axios';
|
|
||||||
import { useArrayData } from 'src/composables/useArrayData';
|
import { useArrayData } from 'src/composables/useArrayData';
|
||||||
import { getTotal } from 'src/composables/getTotal';
|
import { getTotal } from 'src/composables/getTotal';
|
||||||
import { toCurrency } from 'src/filters';
|
import { toCurrency } from 'src/filters';
|
||||||
import FetchData from 'src/components/FetchData.vue';
|
import FetchData from 'src/components/FetchData.vue';
|
||||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
import CrudModel from 'src/components/CrudModel.vue';
|
import CrudModel from 'src/components/CrudModel.vue';
|
||||||
import VnInput from 'src/components/common/VnInput.vue';
|
|
||||||
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
|
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
|
||||||
|
import VnSelectDialog from 'src/components/common/VnSelectDialog.vue';
|
||||||
|
import CreateNewExpenseForm from 'src/components/CreateNewExpenseForm.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const quasar = useQuasar();
|
|
||||||
|
|
||||||
const arrayData = useArrayData();
|
const arrayData = useArrayData();
|
||||||
const invoiceIn = computed(() => arrayData.store.data);
|
const invoiceIn = computed(() => arrayData.store.data);
|
||||||
|
@ -24,15 +22,7 @@ const expenses = ref([]);
|
||||||
const sageTaxTypes = ref([]);
|
const sageTaxTypes = ref([]);
|
||||||
const sageTransactionTypes = ref([]);
|
const sageTransactionTypes = ref([]);
|
||||||
const rowsSelected = ref([]);
|
const rowsSelected = ref([]);
|
||||||
const newExpense = ref({
|
|
||||||
code: undefined,
|
|
||||||
isWithheld: false,
|
|
||||||
description: undefined,
|
|
||||||
});
|
|
||||||
|
|
||||||
const invoiceInFormRef = ref();
|
const invoiceInFormRef = ref();
|
||||||
const expensesRef = ref();
|
|
||||||
const newExpenseRef = ref();
|
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
actionIcon: {
|
actionIcon: {
|
||||||
|
@ -133,37 +123,6 @@ function taxRate(invoiceInTax) {
|
||||||
return (taxTypeSage / 100) * taxableBase;
|
return (taxTypeSage / 100) * taxableBase;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addExpense() {
|
|
||||||
try {
|
|
||||||
if (!newExpense.value.code) throw new Error(t(`The code can't be empty`));
|
|
||||||
if (isNaN(newExpense.value.code))
|
|
||||||
throw new Error(t(`The code have to be a number`));
|
|
||||||
if (!newExpense.value.description)
|
|
||||||
throw new Error(t(`The description can't be empty`));
|
|
||||||
|
|
||||||
const data = [
|
|
||||||
{
|
|
||||||
id: newExpense.value.code,
|
|
||||||
isWithheld: newExpense.value.isWithheld,
|
|
||||||
name: newExpense.value.description,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
await axios.post(`Expenses`, data);
|
|
||||||
await expensesRef.value.fetch();
|
|
||||||
quasar.notify({
|
|
||||||
type: 'positive',
|
|
||||||
message: t('globals.dataSaved'),
|
|
||||||
});
|
|
||||||
newExpenseRef.value.hide();
|
|
||||||
} catch (error) {
|
|
||||||
quasar.notify({
|
|
||||||
type: 'negative',
|
|
||||||
message: t(`${error.message}`),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const formatOpt = (row, { model, options }, prop) => {
|
const formatOpt = (row, { model, options }, prop) => {
|
||||||
const obj = row[model];
|
const obj = row[model];
|
||||||
const option = options.find(({ id }) => id == obj);
|
const option = options.find(({ id }) => id == obj);
|
||||||
|
@ -205,7 +164,7 @@ const formatOpt = (row, { model, options }, prop) => {
|
||||||
>
|
>
|
||||||
<template #body-cell-expense="{ row, col }">
|
<template #body-cell-expense="{ row, col }">
|
||||||
<QTd>
|
<QTd>
|
||||||
<VnSelect
|
<VnSelectDialog
|
||||||
v-model="row[col.model]"
|
v-model="row[col.model]"
|
||||||
:options="col.options"
|
:options="col.options"
|
||||||
:option-value="col.optionValue"
|
:option-value="col.optionValue"
|
||||||
|
@ -217,25 +176,12 @@ const formatOpt = (row, { model, options }, prop) => {
|
||||||
{{ `${scope.opt.id}: ${scope.opt.name}` }}
|
{{ `${scope.opt.id}: ${scope.opt.name}` }}
|
||||||
</QItem>
|
</QItem>
|
||||||
</template>
|
</template>
|
||||||
<template #append>
|
<template #form>
|
||||||
<QIcon
|
<CreateNewExpenseForm
|
||||||
name="close"
|
@on-data-saved="$refs.expensesRef.fetch()"
|
||||||
@click.stop="value = null"
|
|
||||||
class="cursor-pointer"
|
|
||||||
size="xs"
|
|
||||||
/>
|
/>
|
||||||
<QIcon
|
|
||||||
@click.stop.prevent="newExpenseRef.show()"
|
|
||||||
:name="actionIcon"
|
|
||||||
size="xs"
|
|
||||||
class="default-icon"
|
|
||||||
>
|
|
||||||
<QTooltip>
|
|
||||||
{{ t('Create expense') }}
|
|
||||||
</QTooltip>
|
|
||||||
</QIcon>
|
|
||||||
</template>
|
</template>
|
||||||
</VnSelect>
|
</VnSelectDialog>
|
||||||
</QTd>
|
</QTd>
|
||||||
</template>
|
</template>
|
||||||
<template #body-cell-taxablebase="{ row }">
|
<template #body-cell-taxablebase="{ row }">
|
||||||
|
@ -351,7 +297,7 @@ const formatOpt = (row, { model, options }, prop) => {
|
||||||
<QSeparator />
|
<QSeparator />
|
||||||
<QList>
|
<QList>
|
||||||
<QItem>
|
<QItem>
|
||||||
<VnSelect
|
<VnSelectDialog
|
||||||
:label="t('Expense')"
|
:label="t('Expense')"
|
||||||
class="full-width"
|
class="full-width"
|
||||||
v-model="props.row['expenseFk']"
|
v-model="props.row['expenseFk']"
|
||||||
|
@ -365,7 +311,10 @@ const formatOpt = (row, { model, options }, prop) => {
|
||||||
{{ `${scope.opt.id}: ${scope.opt.name}` }}
|
{{ `${scope.opt.id}: ${scope.opt.name}` }}
|
||||||
</QItem>
|
</QItem>
|
||||||
</template>
|
</template>
|
||||||
</VnSelect>
|
<template #form>
|
||||||
|
<CreateNewExpenseForm />
|
||||||
|
</template>
|
||||||
|
</VnSelectDialog>
|
||||||
</QItem>
|
</QItem>
|
||||||
<QItem>
|
<QItem>
|
||||||
<VnInputNumber
|
<VnInputNumber
|
||||||
|
@ -452,44 +401,6 @@ const formatOpt = (row, { model, options }, prop) => {
|
||||||
</QTable>
|
</QTable>
|
||||||
</template>
|
</template>
|
||||||
</CrudModel>
|
</CrudModel>
|
||||||
<QDialog ref="newExpenseRef">
|
|
||||||
<QCard>
|
|
||||||
<QCardSection class="q-pb-none">
|
|
||||||
<QItem class="q-pa-none">
|
|
||||||
<span class="text-primary text-h6 full-width">
|
|
||||||
<QIcon name="edit" class="q-mr-xs" />
|
|
||||||
{{ t('New expense') }}
|
|
||||||
</span>
|
|
||||||
<QBtn icon="close" flat round dense v-close-popup />
|
|
||||||
</QItem>
|
|
||||||
</QCardSection>
|
|
||||||
<QCardSection class="q-pt-none">
|
|
||||||
<QItem>
|
|
||||||
<VnInput
|
|
||||||
:label="`${t('Code')}*`"
|
|
||||||
v-model="newExpense.code"
|
|
||||||
:required="true"
|
|
||||||
/>
|
|
||||||
<QCheckbox
|
|
||||||
dense
|
|
||||||
size="sm"
|
|
||||||
:label="`${t('It\'s a withholding')}`"
|
|
||||||
v-model="newExpense.isWithheld"
|
|
||||||
/>
|
|
||||||
</QItem>
|
|
||||||
<QItem>
|
|
||||||
<VnInput
|
|
||||||
:label="`${t('Descripction')}*`"
|
|
||||||
v-model="newExpense.description"
|
|
||||||
/>
|
|
||||||
</QItem>
|
|
||||||
</QCardSection>
|
|
||||||
<QCardActions class="justify-end">
|
|
||||||
<QBtn flat :label="t('globals.close')" color="primary" v-close-popup />
|
|
||||||
<QBtn :label="t('globals.save')" color="primary" @click="addExpense" />
|
|
||||||
</QCardActions>
|
|
||||||
</QCard>
|
|
||||||
</QDialog>
|
|
||||||
<QPageSticky position="bottom-right" :offset="[25, 25]">
|
<QPageSticky position="bottom-right" :offset="[25, 25]">
|
||||||
<QBtn
|
<QBtn
|
||||||
color="primary"
|
color="primary"
|
||||||
|
@ -544,10 +455,7 @@ es:
|
||||||
Sage transaction: Sage transacción
|
Sage transaction: Sage transacción
|
||||||
Rate: Tasa
|
Rate: Tasa
|
||||||
Foreign value: Divisa
|
Foreign value: Divisa
|
||||||
New expense: Nuevo gasto
|
|
||||||
Code: Código
|
|
||||||
It's a withholding: Es una retención
|
|
||||||
Descripction: Descripción
|
|
||||||
The code can't be empty: El código no puede estar vacío
|
The code can't be empty: El código no puede estar vacío
|
||||||
The description can't be empty: La descripción no puede estar vacía
|
The description can't be empty: La descripción no puede estar vacía
|
||||||
The code have to be a number: El código debe ser un número.
|
The code have to be a number: El código debe ser un número.
|
||||||
|
|
|
@ -36,8 +36,7 @@ describe('InvoiceInBasicData', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw an error creating a new dms if a file is not attached', () => {
|
it('should throw an error creating a new dms if a file is not attached', () => {
|
||||||
cy.get(formInputs).eq(5).click();
|
cy.get(formInputs).eq(7).type('{selectall}{backspace}');
|
||||||
cy.get(formInputs).eq(5).type('{selectall}{backspace}');
|
|
||||||
cy.get(documentBtns).eq(0).click();
|
cy.get(documentBtns).eq(0).click();
|
||||||
cy.get(dialogActionBtns).eq(1).click();
|
cy.get(dialogActionBtns).eq(1).click();
|
||||||
cy.get('.q-notification__message').should(
|
cy.get('.q-notification__message').should(
|
||||||
|
|
|
@ -3,13 +3,14 @@ describe('InvoiceInVat', () => {
|
||||||
const thirdRow = 'tbody > :nth-child(3)';
|
const thirdRow = 'tbody > :nth-child(3)';
|
||||||
const firstLineVat = 'tbody > :nth-child(1) > :nth-child(4)';
|
const firstLineVat = 'tbody > :nth-child(1) > :nth-child(4)';
|
||||||
const dialogInputs = '.q-dialog label input';
|
const dialogInputs = '.q-dialog label input';
|
||||||
const dialogBtns = '.q-dialog button';
|
const addBtn = 'tbody tr:nth-child(1) td:nth-child(2) .--add-icon';
|
||||||
const acrossInput = 'tbody tr:nth-child(1) td:nth-child(2) .default-icon';
|
|
||||||
const randomInt = Math.floor(Math.random() * 100);
|
const randomInt = Math.floor(Math.random() * 100);
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.login('developer');
|
cy.login('developer');
|
||||||
cy.visit(`/#/invoice-in/1/vat`);
|
cy.visit(`/#/invoice-in/1/vat`);
|
||||||
|
cy.intercept('GET', '/api/InvoiceIns/1/getTotals').as('lastCall');
|
||||||
|
cy.wait('@lastCall');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should edit the sage iva', () => {
|
it('should edit the sage iva', () => {
|
||||||
|
@ -26,22 +27,15 @@ describe('InvoiceInVat', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should remove the first line', () => {
|
it('should remove the first line', () => {
|
||||||
cy.removeRow(2);
|
cy.removeRow(1);
|
||||||
});
|
|
||||||
|
|
||||||
it('should throw an error if there are fields undefined', () => {
|
|
||||||
cy.get(acrossInput).click();
|
|
||||||
cy.get(dialogBtns).eq(2).click();
|
|
||||||
cy.get('.q-notification__message').should('have.text', "The code can't be empty");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly handle expense addition', () => {
|
it('should correctly handle expense addition', () => {
|
||||||
cy.get(acrossInput).click();
|
cy.get(addBtn).click();
|
||||||
cy.get(dialogInputs).eq(0).type(randomInt);
|
cy.get(dialogInputs).eq(0).type(randomInt);
|
||||||
cy.get(dialogInputs).eq(1).click();
|
|
||||||
cy.get(dialogInputs).eq(1).type('This is a dummy expense');
|
cy.get(dialogInputs).eq(1).type('This is a dummy expense');
|
||||||
|
|
||||||
cy.get(dialogBtns).eq(2).click();
|
cy.get('button[type="submit"]').click();
|
||||||
cy.get('.q-notification__message').should('have.text', 'Data saved');
|
cy.get('.q-notification__message').should('have.text', 'Data created');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue