forked from verdnatura/salix-front
Merge pull request 'Ticket service' (!494) from hyervoni/salix-front-mindshore:feature/TicketService into dev
Reviewed-on: verdnatura/salix-front#494 Reviewed-by: Alex Moreno <alexm@verdnatura.es> Reviewed-by: Javier Segarra <jsegarra@verdnatura.es>
This commit is contained in:
commit
62d58b479f
|
@ -450,6 +450,7 @@ ticket:
|
|||
futureTickets: Future tickets
|
||||
purchaseRequest: Purchase request
|
||||
weeklyTickets: Weekly tickets
|
||||
services: Service
|
||||
tracking: Tracking
|
||||
list:
|
||||
nickname: Nickname
|
||||
|
|
|
@ -449,6 +449,7 @@ ticket:
|
|||
futureTickets: Tickets a futuro
|
||||
purchaseRequest: Petición de compra
|
||||
weeklyTickets: Tickets programados
|
||||
services: Servicios
|
||||
tracking: Estados
|
||||
list:
|
||||
nickname: Alias
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
<script setup>
|
||||
import { reactive, ref, onMounted, nextTick } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
|
||||
import VnRow from 'components/ui/VnRow.vue';
|
||||
import FormModelPopup from 'components/FormModelPopup.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const emit = defineEmits(['onDataSaved']);
|
||||
|
||||
const nameInputRef = ref(null);
|
||||
const serviceFormData = reactive({});
|
||||
|
||||
const onDataSaved = (formData, requestResponse) => {
|
||||
emit('onDataSaved', formData, requestResponse);
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
await nextTick();
|
||||
nameInputRef.value.focus();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FormModelPopup
|
||||
url-create="TicketServiceTypes"
|
||||
model="TicketServiceType"
|
||||
:title="t('New service type')"
|
||||
:form-initial-data="serviceFormData"
|
||||
@on-data-saved="onDataSaved"
|
||||
>
|
||||
<template #form-inputs="{ data }">
|
||||
<VnRow class="row q-gutter-md q-mb-md">
|
||||
<VnInput
|
||||
ref="nameInputRef"
|
||||
:label="t('service.description')"
|
||||
v-model="data.name"
|
||||
:required="true"
|
||||
/>
|
||||
</VnRow>
|
||||
</template>
|
||||
</FormModelPopup>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
es:
|
||||
New service type: Nuevo tipo de servicio
|
||||
</i18n>
|
|
@ -0,0 +1,190 @@
|
|||
<script setup>
|
||||
import { ref, watch, computed, onMounted } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import CrudModel from 'components/CrudModel.vue';
|
||||
import VnSelectDialog from 'src/components/common/VnSelectDialog.vue';
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import TicketCreateServiceType from './TicketCreateServiceType.vue';
|
||||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
|
||||
import { useArrayData } from 'src/composables/useArrayData';
|
||||
import useNotify from 'src/composables/useNotify.js';
|
||||
import axios from 'axios';
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const { t } = useI18n();
|
||||
const ticketServiceTypeFetchRef = ref(null);
|
||||
const ticketServiceCrudRef = ref(null);
|
||||
const ticketServiceOptions = ref([]);
|
||||
const arrayData = useArrayData('TicketNotes');
|
||||
const { store } = arrayData;
|
||||
const { notify } = useNotify();
|
||||
|
||||
const selected = ref([]);
|
||||
const defaultTaxClass = ref(null);
|
||||
|
||||
const crudModelFilter = computed(() => ({
|
||||
where: { ticketFk: route.params.id },
|
||||
}));
|
||||
|
||||
const crudModelRequiredData = computed(() => ({
|
||||
ticketFk: route.params.id,
|
||||
taxClassFk: defaultTaxClass.value?.id,
|
||||
}));
|
||||
|
||||
watch(
|
||||
() => route.params.id,
|
||||
async () => {
|
||||
store.filter = crudModelFilter.value;
|
||||
await ticketServiceCrudRef.value.reload();
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(async () => await getDefaultTaxClass());
|
||||
|
||||
const createRefund = async () => {
|
||||
try {
|
||||
if (!selected.value.length) return;
|
||||
|
||||
const params = {
|
||||
servicesIds: selected.value.map((s) => +s.ticketFk),
|
||||
withWarehouse: false,
|
||||
negative: true,
|
||||
};
|
||||
const { data } = await axios.post('Sales/clone', params);
|
||||
const [refundTicket] = data;
|
||||
notify(
|
||||
t('service.createRefundSuccess', {
|
||||
ticketId: refundTicket.id,
|
||||
}),
|
||||
'positive'
|
||||
);
|
||||
router.push({ name: 'TicketSale', params: { id: refundTicket.id } });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
const getDefaultTaxClass = async () => {
|
||||
try {
|
||||
let filter = {
|
||||
where: { code: 'G' },
|
||||
};
|
||||
const { data } = await axios.get('TaxClasses/findOne', {
|
||||
params: { filter: JSON.stringify(filter) },
|
||||
});
|
||||
defaultTaxClass.value = data;
|
||||
console.log('defaultTaxClass', defaultTaxClass.value);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
const columns = computed(() => [
|
||||
{
|
||||
name: 'description',
|
||||
label: t('service.description'),
|
||||
field: (row) => row.ticketServiceTypeFk,
|
||||
sortable: true,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'quantity',
|
||||
label: t('service.quantity'),
|
||||
field: (row) => row.quantity,
|
||||
sortable: true,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'price',
|
||||
label: t('service.price'),
|
||||
field: (row) => row.price,
|
||||
sortable: true,
|
||||
align: 'left',
|
||||
},
|
||||
]);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData
|
||||
ref="ticketServiceTypeFetchRef"
|
||||
@on-fetch="(data) => (ticketServiceOptions = data)"
|
||||
auto-load
|
||||
url="TicketServiceTypes"
|
||||
/>
|
||||
<CrudModel
|
||||
ref="ticketServiceCrudRef"
|
||||
data-key="TicketService"
|
||||
url="TicketServices"
|
||||
model="TicketService"
|
||||
:filter="crudModelFilter"
|
||||
:data-required="crudModelRequiredData"
|
||||
auto-load
|
||||
v-model:selected="selected"
|
||||
>
|
||||
<template #moreBeforeActions>
|
||||
<QBtn
|
||||
color="primary"
|
||||
:label="t('service.pay')"
|
||||
:disabled="!selected.length"
|
||||
@click.stop="createRefund()"
|
||||
/>
|
||||
</template>
|
||||
<template #body="{ rows }">
|
||||
<QTable
|
||||
:columns="columns"
|
||||
:rows="rows"
|
||||
row-key="$index"
|
||||
selection="multiple"
|
||||
v-model:selected="selected"
|
||||
table-header-class="text-left"
|
||||
>
|
||||
<template #body-cell-description="{ row, col }">
|
||||
<QTd auto-width>
|
||||
<VnSelectDialog
|
||||
:label="col.label"
|
||||
v-model="row.ticketServiceTypeFk"
|
||||
:options="ticketServiceOptions"
|
||||
option-label="name"
|
||||
option-value="id"
|
||||
hide-selected
|
||||
>
|
||||
<template #form>
|
||||
<TicketCreateServiceType
|
||||
@on-data-saved="ticketServiceTypeFetchRef.fetch()"
|
||||
/>
|
||||
</template>
|
||||
</VnSelectDialog>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #body-cell-quantity="{ row, col }">
|
||||
<QTd auto-width>
|
||||
<VnInput
|
||||
:label="col.label"
|
||||
v-model.number="row.quantity"
|
||||
type="number"
|
||||
min="0"
|
||||
:info="t('service.quantityInfo')"
|
||||
/>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #body-cell-price="{ row, col }">
|
||||
<QTd auto-width>
|
||||
<VnInput
|
||||
:label="col.label"
|
||||
v-model.number="row.price"
|
||||
type="number"
|
||||
min="0"
|
||||
/>
|
||||
</QTd>
|
||||
</template>
|
||||
</QTable>
|
||||
</template>
|
||||
</CrudModel>
|
||||
<QPageSticky position="bottom-right" :offset="[25, 25]">
|
||||
<QBtn fab color="primary" icon="add" @click="ticketServiceCrudRef.insert()" />
|
||||
</QPageSticky>
|
||||
</template>
|
|
@ -149,6 +149,16 @@ weeklyTickets:
|
|||
salesperson: Salesperson
|
||||
search: Search weekly tickets
|
||||
searchInfo: Search weekly tickets by id or client id
|
||||
service:
|
||||
pay: Pay
|
||||
description: Description
|
||||
quantity: Quantity
|
||||
price: Price
|
||||
removeService: Remove service
|
||||
newService: New service type
|
||||
addService: Add service
|
||||
quantityInfo: To create services with negative amounts mark the service on the source ticket and press the pay button.
|
||||
createRefundSuccess: 'The following refund ticket have been created: { ticketId }'
|
||||
tracking:
|
||||
state: State
|
||||
worker: Worker
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
service:
|
||||
pay: Abonar
|
||||
description: Descripción
|
||||
quantity: Cantidad
|
||||
price: Precio
|
||||
removeService: Quitar servicio
|
||||
newService: Nuevo tipo de servicio
|
||||
addService: Añadir servicio
|
||||
quantityInfo: Para crear sevicios con cantidades negativas marcar servicio en el ticket origen y apretar el boton abonar.
|
||||
createRefundSuccess: 'Se ha creado siguiente ticket de abono: { ticketId }'
|
||||
tracking:
|
||||
state: Estado
|
||||
worker: Trabajador
|
||||
|
|
|
@ -19,6 +19,7 @@ export default {
|
|||
'TicketSale',
|
||||
'TicketLog',
|
||||
'TicketPurchaseRequest',
|
||||
'TicketService',
|
||||
'TicketTracking',
|
||||
'TicketVolume',
|
||||
'TicketNotes',
|
||||
|
@ -159,6 +160,16 @@ export default {
|
|||
},
|
||||
component: () => import('src/pages/Ticket/Card/TicketSms.vue'),
|
||||
},
|
||||
|
||||
{
|
||||
path: 'service',
|
||||
name: 'TicketService',
|
||||
meta: {
|
||||
title: 'services',
|
||||
icon: 'vn:services',
|
||||
},
|
||||
component: () => import('src/pages/Ticket/Card/TicketService.vue'),
|
||||
},
|
||||
{
|
||||
path: 'volume',
|
||||
name: 'TicketVolume',
|
||||
|
|
Loading…
Reference in New Issue