-
+ |
{{ item.warehouse }}
|
-
+ |
{
diff --git a/src/pages/Order/Card/OrderCreateDialog.vue b/src/pages/Order/Card/OrderCreateDialog.vue
new file mode 100644
index 000000000..9d5c9281e
--- /dev/null
+++ b/src/pages/Order/Card/OrderCreateDialog.vue
@@ -0,0 +1,220 @@
+
+
+
+ (clientOptions = data)"
+ :filter="{ fields: ['id', 'name', 'defaultAddressFk'], order: 'id' }"
+ auto-load
+ />
+
+
+
+
+
+
+
+
+ {{ `${scope.opt.id}: ${scope.opt.name}` }}
+
+
+
+
+
+
+
+
+
+
+ {{
+ `${scope.opt.nickname}: ${scope.opt.street},${scope.opt.city}`
+ }}
+
+
+
+
+
+
+
+ fetchAgencyList(data.landed, data.addressId)
+ "
+ />
+
+
+
+
+
+
+
+
+
+
+ es:
+ No default address found for the client: No hay ninguna dirección asociada a este cliente.
+
diff --git a/src/pages/Order/Card/OrderDescriptor.vue b/src/pages/Order/Card/OrderDescriptor.vue
index 4d84a32fc..a035971b0 100644
--- a/src/pages/Order/Card/OrderDescriptor.vue
+++ b/src/pages/Order/Card/OrderDescriptor.vue
@@ -4,13 +4,13 @@ import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { toCurrency, toDate } from 'src/filters';
import { useState } from 'src/composables/useState';
-
import useCardDescription from 'src/composables/useCardDescription';
-import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
+
import CardDescriptor from 'components/ui/CardDescriptor.vue';
import VnLv from 'src/components/ui/VnLv.vue';
-import OrderDescriptorMenu from 'pages/Order/Card/OrderDescriptorMenu.vue';
import FetchData from 'components/FetchData.vue';
+import OrderDescriptorMenu from 'pages/Order/Card/OrderDescriptorMenu.vue';
+import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
const DEFAULT_ITEMS = 0;
@@ -25,6 +25,8 @@ const $props = defineProps({
const route = useRoute();
const state = useState();
const { t } = useI18n();
+const data = ref(useCardDescription());
+const getTotalRef = ref();
const entityId = computed(() => {
return $props.id || route.params.id;
@@ -57,11 +59,11 @@ const filter = {
],
};
-const data = ref(useCardDescription());
const setData = (entity) => {
if (!entity) return;
+ getTotalRef.value && getTotalRef.value.fetch();
data.value = useCardDescription(entity?.client?.name, entity?.id);
- state.set('OrderDescriptor', entity);
+ state.set('orderData', entity);
};
const getConfirmationValue = (isConfirmed) => {
@@ -69,13 +71,17 @@ const getConfirmationValue = (isConfirmed) => {
};
const total = ref(null);
+
+function ticketFilter(order) {
+ return JSON.stringify({ id: order.id });
+}
(total = response)"
- auto-load
/>
{{ t('order.summary.orderTicketList') }}
diff --git a/src/pages/Order/Card/OrderDescriptorMenu.vue b/src/pages/Order/Card/OrderDescriptorMenu.vue
index 2e36aa3c5..2695da4e5 100644
--- a/src/pages/Order/Card/OrderDescriptorMenu.vue
+++ b/src/pages/Order/Card/OrderDescriptorMenu.vue
@@ -23,7 +23,7 @@ function confirmRemove() {
.dialog({
component: VnConfirm,
componentProps: {
- title: t('confirmDeletion'),
+ title: t('globals.confirmDeletion'),
message: t('confirmDeletionMessage'),
promise: remove,
},
@@ -52,12 +52,10 @@ async function remove() {
en:
deleteOrder: Delete order
- confirmDeletion: Confirm deletion
confirmDeletionMessage: Are you sure you want to delete this order?
es:
deleteOrder: Eliminar pedido
- confirmDeletion: Confirmar eliminación
confirmDeletionMessage: Seguro que quieres eliminar este pedido?
diff --git a/src/pages/Order/Card/OrderFilter.vue b/src/pages/Order/Card/OrderFilter.vue
index 347affb04..be47eed54 100644
--- a/src/pages/Order/Card/OrderFilter.vue
+++ b/src/pages/Order/Card/OrderFilter.vue
@@ -21,15 +21,13 @@ const salesPersonFilter = {
fields: ['id', 'nickname'],
};
const salesPersonList = ref(null);
-const sourceFilter = { fields: ['value'] };
-const sourceList = ref(null);
+const sourceList = ref([]);
(agencyList = data)"
@@ -37,7 +35,6 @@ const sourceList = ref(null);
(salesPersonList = data)"
:params="{ departmentCodes: ['VT'] }"
@@ -45,8 +42,7 @@ const sourceList = ref(null);
/>
(sourceList = data)"
auto-load
@@ -59,148 +55,88 @@ const sourceList = ref(null);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ opt.name }}
-
- {{ opt.nickname }},{{ opt.code }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+ {{ opt.name }}
+
+ {{ opt.nickname }},{{ opt.code }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/Order/OrderLines.vue b/src/pages/Order/Card/OrderLines.vue
similarity index 69%
rename from src/pages/Order/OrderLines.vue
rename to src/pages/Order/Card/OrderLines.vue
index 9814eaf34..17a157797 100644
--- a/src/pages/Order/OrderLines.vue
+++ b/src/pages/Order/Card/OrderLines.vue
@@ -1,23 +1,27 @@
@@ -204,78 +236,85 @@ async function confirmOrder() {
auto-load
/>
(orderSummary.total = data)"
auto-load
/>
(orderSummary.vat = data)"
auto-load
/>
-
+
-
-
+
+
-
-
-
- {{ t('globals.noResults') }}
-
-
-
-
-
-
-
-
-
- {{ row?.item?.name }}
-
- {{ row?.item?.subName.toUpperCase() }}
-
-
-
-
-
-
-
-
-
- {{ t('confirm') }}
-
-
-
+
+
+
+
+
+
+
+
+ {{ row?.item?.id }}
+
+
+
+
+
+ {{ row?.item?.name }}
+
+ {{ row?.item?.subName.toUpperCase() }}
+
+
+
+
+
+ {{ toCurrency(row.quantity * row.price) }}
+
+
+
+
+
+
+
+
+ {{ t('confirm') }}
+
+
+
+en:
+ summary: Summary
+ total: Total
+ boxes: Boxes
+ item: Item
+ quantity: Quantity
+ volume: m³ per quantity
+es:
+ summary: Resumen
+ total: Total
+ boxes: Cajas
+ item: Artículo
+ quantity: Cantidad
+ volume: m³ por cantidad
+
diff --git a/src/pages/Order/OrderList.vue b/src/pages/Order/OrderList.vue
index 945f61f3b..d96a33ef5 100644
--- a/src/pages/Order/OrderList.vue
+++ b/src/pages/Order/OrderList.vue
@@ -3,19 +3,24 @@ import axios from 'axios';
import { useI18n } from 'vue-i18n';
import { computed, ref } from 'vue';
import { dashIfEmpty, toCurrency, toDate } from 'src/filters';
-import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
import OrderSummary from 'pages/Order/Card/OrderSummary.vue';
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import VnTable from 'src/components/VnTable/VnTable.vue';
import VnInputDate from 'src/components/common/VnInputDate.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
+import OrderSearchbar from './Card/OrderSearchbar.vue';
+import RightMenu from 'src/components/common/RightMenu.vue';
+import OrderFilter from './Card/OrderFilter.vue';
+import CustomerDescriptorProxy from '../Customer/Card/CustomerDescriptorProxy.vue';
+import WorkerDescriptorProxy from '../Worker/Card/WorkerDescriptorProxy.vue';
+import { toDateTimeFormat } from 'src/filters/date';
const { t } = useI18n();
const { viewSummary } = useSummaryDialog();
const tableRef = ref();
-const clientList = ref([]);
const agencyList = ref([]);
-const selectedAddress = ref();
+const addressesList = ref([]);
+const clientId = ref();
const columns = computed(() => [
{
@@ -29,7 +34,7 @@ const columns = computed(() => [
},
{
align: 'left',
- name: 'clientName',
+ name: 'clientFk',
label: t('module.customer'),
isTitle: true,
cardVisible: true,
@@ -41,20 +46,26 @@ const columns = computed(() => [
columnField: {
component: null,
},
+ format: (row) => row?.clientName,
},
{
align: 'left',
- name: 'name',
+ name: 'salesPersonFk',
label: t('module.salesPerson'),
- component: 'select',
- attrs: {
- url: 'Workers/activeWithInheritedRole',
- fields: ['id', 'name'],
- where: { role: 'salesPerson' },
- },
- columnField: {
- component: null,
+ columnFilter: {
+ component: 'select',
+ inWhere: true,
+ attrs: {
+ url: 'Workers/activeWithInheritedRole',
+ fields: ['id', 'name'],
+ where: { role: 'salesPerson' },
+ useLike: false,
+ optionValue: 'id',
+ optionLabel: 'name',
+ optionFilter: 'firstName',
+ },
},
+ format: (row) => row?.name,
},
{
align: 'left',
@@ -67,7 +78,7 @@ const columns = computed(() => [
label: t('module.created'),
component: 'date',
cardVisible: true,
- format: (row) => toDate(row?.landed),
+ format: (row) => toDateTimeFormat(row?.landed),
columnField: {
component: null,
},
@@ -92,17 +103,22 @@ const columns = computed(() => [
},
{
align: 'left',
- name: 'agencyName',
+ name: 'agencyModeFk',
label: t('module.agency'),
- component: 'select',
+ format: (row) => row?.agencyName,
+ columnFilter: {
+ component: 'select',
+ attrs: {
+ url: 'agencyModes',
+ fields: ['id', 'name'],
+ find: {
+ value: 'agencyModeFk',
+ label: 'agencyName',
+ },
+ },
+ },
cardVisible: true,
- attrs: {
- url: 'Agencies',
- fields: ['id', 'name'],
- },
- columnField: {
- component: null,
- },
+ columnClass: 'expand',
},
{
align: 'left',
@@ -120,27 +136,52 @@ const columns = computed(() => [
title: t('InvoiceOutSummary'),
icon: 'preview',
action: (row) => viewSummary(row.id, OrderSummary),
+ isPrimary: true,
},
],
},
]);
-async function fetchClientAddress(id, data) {
- const clientData = await axios.get(`Clients/${id}`);
- selectedAddress.value = clientData.data.defaultAddressFk;
- data.addressId = selectedAddress.value;
+async function fetchClientAddress(id, formData) {
+ const { data } = await axios.get(`Clients/${id}`, {
+ params: { filter: { include: { relation: 'addresses' } } },
+ });
+ addressesList.value = data.addresses;
+ formData.addressId = data.defaultAddressFk;
+ fetchAgencies(formData);
}
+
+async function fetchAgencies({ landed, addressId }) {
+ if (!landed || !addressId) return (agencyList.value = []);
+
+ const { data } = await axios.get('Agencies/landsThatDay', {
+ params: { addressFk: addressId, landed },
+ });
+ agencyList.value = data;
+}
+
+const getDateColor = (date) => {
+ const today = Date.vnNew();
+ today.setHours(0, 0, 0, 0);
+ const timeTicket = new Date(date);
+ timeTicket.setHours(0, 0, 0, 0);
+ const comparation = today - timeTicket;
+ if (comparation == 0) return 'bg-warning';
+ if (comparation < 0) return 'bg-success';
+};
-
+
+
+
+
+
+
+
+
+ {{ row?.clientName }}
+
+
+
+
+
+ {{ row?.name }}
+
+
+
+
+
+
+ {{ toDate(row?.landed) }}
+
+
+
fetchClientAddress(id, data)"
/>
fetchAgencies(data)"
+ >
+
+
+
+
+ {{ scope.opt?.nickname }}: {{ scope.opt?.street }},
+ {{ scope.opt?.city }}
+
+
+
+
+ fetchAgencies(data)"
/>
-
diff --git a/src/pages/Order/OrderVolume.vue b/src/pages/Order/OrderVolume.vue
deleted file mode 100644
index 35d68de16..000000000
--- a/src/pages/Order/OrderVolume.vue
+++ /dev/null
@@ -1,156 +0,0 @@
-
-
-
- (volumeSummary = data)"
- auto-load
- />
-
-
-
- {{ t('globals.noResults') }}
-
-
-
-
-
-
- loadVolumes(data)"
- >
-
-
-
-
-
-
-
-
-
-
-
- {{ row.item.subName }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-en:
- summary: Summary
- total: Total
- boxes: Boxes
- item: Item
- subName: Subname
- quantity: Quantity
- volume: m³ per quantity
-es:
- summary: Resumen
- total: Total
- boxes: Cajas
- item: Artículo
- subName: Subname
- quantity: Cantidad
- volume: m³ por cantidad
-
diff --git a/src/pages/Route/Agency/Card/AgencyWorkcenter.vue b/src/pages/Route/Agency/Card/AgencyWorkcenter.vue
index 3531ad288..1f3cab5d0 100644
--- a/src/pages/Route/Agency/Card/AgencyWorkcenter.vue
+++ b/src/pages/Route/Agency/Card/AgencyWorkcenter.vue
@@ -88,7 +88,7 @@ async function deleteWorCenter(id) {
-
+
-
{{ value }}
@@ -226,7 +226,7 @@ const ticketColumns = ref([
-
+
{{ value }}
@@ -234,7 +234,7 @@ const ticketColumns = ref([
-
+
{{ value }}
diff --git a/src/pages/Route/Roadmap/RoadmapBasicData.vue b/src/pages/Route/Roadmap/RoadmapBasicData.vue
index e1611ed61..eeefaca2c 100644
--- a/src/pages/Route/Roadmap/RoadmapBasicData.vue
+++ b/src/pages/Route/Roadmap/RoadmapBasicData.vue
@@ -103,8 +103,8 @@ es:
Roadmap: Troncal
ETD date: Fecha ETD
ETD hour: Hora ETD
- Tractor plate: Matrícula tractor
- Trailer plate: Matrícula trailer
+ Tractor plate: Matrícula tractora
+ Trailer plate: Matrícula remolque
Carrier: Transportista
Price: Precio
Driver name: Nombre del conductor
diff --git a/src/pages/Route/Roadmap/RoadmapFilter.vue b/src/pages/Route/Roadmap/RoadmapFilter.vue
index 04c5c9696..ecf8d39fc 100644
--- a/src/pages/Route/Roadmap/RoadmapFilter.vue
+++ b/src/pages/Route/Roadmap/RoadmapFilter.vue
@@ -164,8 +164,8 @@ en:
to: To
es:
params:
- tractorPlate: Matrícula del tractor
- trailerPlate: Matrícula del trailer
+ tractorPlate: Matrícula tractora
+ trailerPlate: Matrícula remolque
supplierFk: Transportista
price: Precio
driverName: Nombre del conductor
@@ -174,8 +174,8 @@ es:
to: Hasta
From: Desde
To: Hasta
- Tractor Plate: Matrícula del tractor
- Trailer Plate: Matrícula del trailer
+ Tractor Plate: Matrícula tractora
+ Trailer Plate: Matrícula remolque
Carrier: Transportista
Price: Precio
Driver name: Nombre del conductor
diff --git a/src/pages/Route/Roadmap/RoadmapStops.vue b/src/pages/Route/Roadmap/RoadmapStops.vue
index 8ff044d2d..d8215ea49 100644
--- a/src/pages/Route/Roadmap/RoadmapStops.vue
+++ b/src/pages/Route/Roadmap/RoadmapStops.vue
@@ -65,9 +65,10 @@ const updateDefaultStop = (data) => {
- {
{{ t('Add stop') }}
-
+
diff --git a/src/pages/Route/Roadmap/RoadmapSummary.vue b/src/pages/Route/Roadmap/RoadmapSummary.vue
index 7f8b7107b..3fb36b4f7 100644
--- a/src/pages/Route/Roadmap/RoadmapSummary.vue
+++ b/src/pages/Route/Roadmap/RoadmapSummary.vue
@@ -149,8 +149,8 @@ const filter = {
es:
Carrier: Transportista
- Tractor Plate: Matrícula tractor
- Trailer Plate: Matrícula trailer
+ Tractor Plate: Matrícula tractora
+ Trailer Plate: Matrícula remolque
Phone: Teléfono
Worker: Trabajador
Observations: Observaciones
diff --git a/src/pages/Route/RouteList.vue b/src/pages/Route/RouteList.vue
index e24ed33ed..1e20df99c 100644
--- a/src/pages/Route/RouteList.vue
+++ b/src/pages/Route/RouteList.vue
@@ -17,7 +17,9 @@ import RouteFilter from 'pages/Route/Card/RouteFilter.vue';
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
import VnInputDate from 'components/common/VnInputDate.vue';
import VnTable from 'components/VnTable/VnTable.vue';
+import { usePrintService } from 'src/composables/usePrintService';
+const { openReport } = usePrintService();
const { t } = useI18n();
const { viewSummary } = useSummaryDialog();
const quasar = useQuasar();
@@ -87,6 +89,7 @@ const columns = computed(() => [
label: 'agencyName',
},
},
+ columnClass: 'expand',
},
{
align: 'left',
@@ -142,17 +145,9 @@ const columns = computed(() => [
{
align: 'center',
name: 'm3',
- label: 'volume',
+ label: t('Volume'),
cardVisible: true,
- },
- {
- align: 'left',
- name: 'description',
- label: t('Description'),
- isTitle: true,
- create: true,
- component: 'input',
- field: 'description',
+ columnClass: 'shrink',
},
{
align: 'left',
@@ -168,12 +163,38 @@ const columns = computed(() => [
component: 'time',
columnFilter: false,
},
+ {
+ align: 'center',
+ name: 'kmStart',
+ label: t('KmStart'),
+ columnClass: 'shrink',
+ create: true,
+ visible: false,
+ },
+ {
+ align: 'center',
+ name: 'kmEnd',
+ label: t('KmEnd'),
+ columnClass: 'shrink',
+ create: true,
+ visible: false,
+ },
+ {
+ align: 'left',
+ name: 'description',
+ label: t('Description'),
+ isTitle: true,
+ create: true,
+ component: 'input',
+ field: 'description',
+ },
{
align: 'left',
name: 'isOk',
label: t('Served'),
component: 'checkbox',
columnFilter: false,
+ columnClass: 'shrink',
},
{
align: 'right',
@@ -185,7 +206,7 @@ const columns = computed(() => [
action: (row) => openTicketsDialog(row?.id),
},
{
- title: t('Preview'),
+ title: t('components.smartCard.viewSummary'),
icon: 'preview',
action: (row) => viewSummary(row?.id, RouteSummary),
},
@@ -216,18 +237,15 @@ const cloneRoutes = () => {
const showRouteReport = () => {
const ids = selectedRows.value.map((row) => row?.id);
const idString = ids.join(',');
- let url;
-
- if (selectedRows.value.length <= 1) {
- url = `api/Routes/${idString}/driver-route-pdf?access_token=${session.getTokenMultimedia()}`;
- } else {
- const params = new URLSearchParams({
- access_token: session.getTokenMultimedia(),
+ let url = `Routes/${idString}/driver-route-pdf`;
+ let params = {};
+ if (selectedRows.value.length >= 1) {
+ params = {
id: idString,
- });
- url = `api/Routes/downloadZip?${params.toString()}`;
+ };
+ url = `Routes/downloadZip`;
}
- window.open(url, '_blank');
+ openReport(url, params, '_blank');
};
function markAsServed() {
@@ -368,10 +386,13 @@ es:
Worker: Trabajador
Agency: Agencia
Vehicle: Vehículo
+ Volume: Volumen
Date: Fecha
Description: Descripción
Hour started: Hora inicio
Hour finished: Hora fin
+ KmStart: Km inicio
+ KmEnd: Km fin
Served: Servida
newRoute: Nueva Ruta
Clone Selected Routes: Clonar rutas seleccionadas
diff --git a/src/pages/Route/RouteRoadmap.vue b/src/pages/Route/RouteRoadmap.vue
index 306387cbe..d921dab1f 100644
--- a/src/pages/Route/RouteRoadmap.vue
+++ b/src/pages/Route/RouteRoadmap.vue
@@ -237,4 +237,5 @@ es:
Price: Precio
Observations: Observaciones
Preview: Vista previa
+ Select the estimated date of departure (ETD): Selecciona la fecha estimada de salida
diff --git a/src/pages/Route/RouteTickets.vue b/src/pages/Route/RouteTickets.vue
index 9356f7590..5960636b0 100644
--- a/src/pages/Route/RouteTickets.vue
+++ b/src/pages/Route/RouteTickets.vue
@@ -396,7 +396,7 @@ const openSmsDialog = async () => {
-
+
{{ t('Add ticket') }}
diff --git a/src/pages/Shelving/Card/ShelvingFilter.vue b/src/pages/Shelving/Card/ShelvingFilter.vue
index abc91373b..0056ffaec 100644
--- a/src/pages/Shelving/Card/ShelvingFilter.vue
+++ b/src/pages/Shelving/Card/ShelvingFilter.vue
@@ -3,6 +3,7 @@ import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import FetchData from 'components/FetchData.vue';
import VnFilterPanel from 'components/ui/VnFilterPanel.vue';
+import VnSelect from 'src/components/common/VnSelect.vue';
const { t } = useI18n();
const props = defineProps({
@@ -15,25 +16,13 @@ const props = defineProps({
const emit = defineEmits(['search']);
const workers = ref();
-const parkings = ref();
function setWorkers(data) {
workers.value = data;
}
-
-function setParkings(data) {
- parkings.value = data;
-}
-
-
-
-
-
-
+
-
-
-
-
-
+
diff --git a/src/pages/Shelving/Card/ShelvingForm.vue b/src/pages/Shelving/Card/ShelvingForm.vue
index dd1c4e4a2..dc0234c22 100644
--- a/src/pages/Shelving/Card/ShelvingForm.vue
+++ b/src/pages/Shelving/Card/ShelvingForm.vue
@@ -1,18 +1,18 @@
-
-
+
-
+
- filter(value, update, parkingSelectFilter)
- "
:rules="validate('Shelving.parkingFk')"
- :input-debounce="0"
/>
diff --git a/src/pages/Shelving/ShelvingList.vue b/src/pages/Shelving/ShelvingList.vue
index 3f16f8ef7..d29f6ff15 100644
--- a/src/pages/Shelving/ShelvingList.vue
+++ b/src/pages/Shelving/ShelvingList.vue
@@ -87,7 +87,7 @@ function exprBuilder(param, value) {
-
+
{{ t('shelving.list.newShelving') }}
diff --git a/src/pages/Supplier/Card/SupplierAccounts.vue b/src/pages/Supplier/Card/SupplierAccounts.vue
index b0e8b06e8..f8fbba0e4 100644
--- a/src/pages/Supplier/Card/SupplierAccounts.vue
+++ b/src/pages/Supplier/Card/SupplierAccounts.vue
@@ -102,9 +102,7 @@ const setWireTransfer = async () => {
- {{
- t('components.iban_tooltip')
- }}
+ {{ t('components.iban_tooltip') }}
@@ -165,9 +163,10 @@ const setWireTransfer = async () => {
- {
{{ t('Add account') }}
-
+
diff --git a/src/pages/Supplier/Card/SupplierAddresses.vue b/src/pages/Supplier/Card/SupplierAddresses.vue
index 735b50625..f46a3be19 100644
--- a/src/pages/Supplier/Card/SupplierAddresses.vue
+++ b/src/pages/Supplier/Card/SupplierAddresses.vue
@@ -26,7 +26,13 @@ const addressesFilter = {
{
relation: 'province',
scope: {
- fields: ['id', 'name'],
+ fields: ['id', 'name', 'countryFk'],
+ include: [
+ {
+ relation: 'country',
+ scope: { fields: ['id', 'name'] },
+ },
+ ],
},
},
],
@@ -81,7 +87,13 @@ const redirectToUpdateView = (addressData) => {
-
+
{{ t('New address') }}
@@ -93,3 +105,4 @@ const redirectToUpdateView = (addressData) => {
es:
New address: Nueva dirección
+s
diff --git a/src/pages/Supplier/Card/SupplierAddressesCreate.vue b/src/pages/Supplier/Card/SupplierAddressesCreate.vue
index da6549a24..290373039 100644
--- a/src/pages/Supplier/Card/SupplierAddressesCreate.vue
+++ b/src/pages/Supplier/Card/SupplierAddressesCreate.vue
@@ -21,6 +21,7 @@ const newAddressForm = reactive({
provinceFk: null,
phone: null,
mobile: null,
+ province: null,
});
const onDataSaved = () => {
@@ -83,8 +84,17 @@ function handleLocation(data, location) {
handleLocation(data, location)"
>
diff --git a/src/pages/Supplier/Card/SupplierAgencyTerm.vue b/src/pages/Supplier/Card/SupplierAgencyTerm.vue
index 26a410e8c..99b672cc4 100644
--- a/src/pages/Supplier/Card/SupplierAgencyTerm.vue
+++ b/src/pages/Supplier/Card/SupplierAgencyTerm.vue
@@ -109,7 +109,13 @@ const redirectToCreateView = () => {
-
+
{{ t('supplier.agencyTerms.addRow') }}
diff --git a/src/pages/Supplier/Card/SupplierConsumption.vue b/src/pages/Supplier/Card/SupplierConsumption.vue
index 100a38b2a..8fa6a1e5c 100644
--- a/src/pages/Supplier/Card/SupplierConsumption.vue
+++ b/src/pages/Supplier/Card/SupplierConsumption.vue
@@ -208,7 +208,7 @@ onMounted(async () => {
{{ buy.subName }}
-
+
{{ dashIfEmpty(buy.quantity) }}
{{ dashIfEmpty(buy.price) }}
diff --git a/src/pages/Supplier/Card/SupplierConsumptionFilter.vue b/src/pages/Supplier/Card/SupplierConsumptionFilter.vue
index 3fc61b15e..401bde8fa 100644
--- a/src/pages/Supplier/Card/SupplierConsumptionFilter.vue
+++ b/src/pages/Supplier/Card/SupplierConsumptionFilter.vue
@@ -1,56 +1,21 @@
- (buyersOptions = data)"
- auto-load
- />
- (itemTypesOptions = data)"
- auto-load
- />
- (itemCategoriesOptions = data)"
- auto-load
- />
-
+
{{ t(`params.${tag.label}`) }}:
@@ -82,7 +47,9 @@ const itemCategoriesOptions = ref([]);
:label="t('params.buyerId')"
v-model="params.buyerId"
@update:model-value="searchFn()"
- :options="buyersOptions"
+ url="TicketRequests/getItemTypeWorker"
+ :fields="['id', 'nickname']"
+ sort-by="nickname ASC"
option-value="id"
option-label="nickname"
hide-selected
@@ -98,7 +65,10 @@ const itemCategoriesOptions = ref([]);
:label="t('params.typeId')"
v-model="params.typeId"
@update:model-value="searchFn()"
- :options="itemTypesOptions"
+ url="ItemTypes"
+ :include="['category']"
+ :fields="['id', 'name', 'categoryFk']"
+ sort-by="name ASC"
option-value="id"
option-label="name"
hide-selected
@@ -125,7 +95,9 @@ const itemCategoriesOptions = ref([]);
:label="t('params.categoryId')"
v-model="params.categoryId"
@update:model-value="searchFn()"
- :options="itemCategoriesOptions"
+ url="ItemCategories"
+ :fields="['id', 'name']"
+ sort-by="name ASC"
option-value="id"
option-label="name"
hide-selected
diff --git a/src/pages/Supplier/Card/SupplierContacts.vue b/src/pages/Supplier/Card/SupplierContacts.vue
index 35e8b98fc..3f2063784 100644
--- a/src/pages/Supplier/Card/SupplierContacts.vue
+++ b/src/pages/Supplier/Card/SupplierContacts.vue
@@ -84,9 +84,10 @@ const insertRow = () => {
- {
{{ t('Add contact') }}
-
+
diff --git a/src/pages/Supplier/Card/SupplierDescriptor.vue b/src/pages/Supplier/Card/SupplierDescriptor.vue
index 6e60a336c..5754031b3 100644
--- a/src/pages/Supplier/Card/SupplierDescriptor.vue
+++ b/src/pages/Supplier/Card/SupplierDescriptor.vue
@@ -109,7 +109,7 @@ const getEntryQueryParams = (supplier) => {
:subtitle="data.subtitle"
:filter="filter"
@on-fetch="setData"
- data-key="supplier"
+ data-key="supplierDescriptor"
:summary="$props.summary"
>
diff --git a/src/pages/Supplier/Card/SupplierFiscalData.vue b/src/pages/Supplier/Card/SupplierFiscalData.vue
index fd9667112..553fc0f94 100644
--- a/src/pages/Supplier/Card/SupplierFiscalData.vue
+++ b/src/pages/Supplier/Card/SupplierFiscalData.vue
@@ -51,6 +51,23 @@ function handleLocation(data, location) {
:url="`Suppliers/${route.params.id}`"
:url-update="`Suppliers/${route.params.id}/updateFiscalData`"
model="supplier"
+ :filter="{
+ fields: ['id', 'name', 'city', 'postCode', 'countryFk', 'provinceFk'],
+ include: [
+ {
+ relation: 'province',
+ scope: {
+ fields: ['id', 'name'],
+ },
+ },
+ {
+ relation: 'country',
+ scope: {
+ fields: ['id', 'name'],
+ },
+ },
+ ],
+ }"
auto-load
:clear-store-on-unmount="false"
>
@@ -129,8 +146,13 @@ function handleLocation(data, location) {
handleLocation(data, location)"
>
diff --git a/src/pages/Supplier/Card/SupplierSummary.vue b/src/pages/Supplier/Card/SupplierSummary.vue
index 822586b47..5791db1eb 100644
--- a/src/pages/Supplier/Card/SupplierSummary.vue
+++ b/src/pages/Supplier/Card/SupplierSummary.vue
@@ -4,13 +4,11 @@ import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import CardSummary from 'components/ui/CardSummary.vue';
import VnLv from 'src/components/ui/VnLv.vue';
-import { useRole } from 'src/composables/useRole';
import { dashIfEmpty } from 'src/filters';
import VnUserLink from 'src/components/ui/VnUserLink.vue';
import VnTitle from 'src/components/common/VnTitle.vue';
const route = useRoute();
-const roleState = useRole();
const { t } = useI18n();
const $props = defineProps({
@@ -32,13 +30,7 @@ async function setData(data) {
}
}
-const isAdministrative = computed(() => {
- return roleState.hasAny(['administrative']);
-});
-
-function getUrl(section) {
- return isAdministrative.value && `#/supplier/${entityId.value}/${section}`;
-}
+const getUrl = (section) => `#/supplier/${entityId.value}/${section}`;
diff --git a/src/pages/Ticket/Card/BasicData/BasicDataTable.vue b/src/pages/Ticket/Card/BasicData/BasicDataTable.vue
index 48b8c882f..7f2f100ad 100644
--- a/src/pages/Ticket/Card/BasicData/BasicDataTable.vue
+++ b/src/pages/Ticket/Card/BasicData/BasicDataTable.vue
@@ -245,7 +245,7 @@ onUnmounted(() => (stateStore.rightDrawer = false));
{{ row.item.name }}
{{ row.item.subName }}
-
+
diff --git a/src/pages/Ticket/Card/BasicData/TicketBasicDataForm.vue b/src/pages/Ticket/Card/BasicData/TicketBasicDataForm.vue
index 2d937346a..28c6fcf15 100644
--- a/src/pages/Ticket/Card/BasicData/TicketBasicDataForm.vue
+++ b/src/pages/Ticket/Card/BasicData/TicketBasicDataForm.vue
@@ -30,7 +30,6 @@ const { t } = useI18n();
const agencyFetchRef = ref(null);
const zonesFetchRef = ref(null);
-const clientsOptions = ref([]);
const warehousesOptions = ref([]);
const companiesOptions = ref([]);
const agenciesOptions = ref([]);
@@ -273,15 +272,6 @@ const redirectToCustomerAddress = () => {
onMounted(() => onFormModelInit());
- (clientsOptions = data)"
- auto-load
- />
(warehousesOptions = data)"
@@ -317,7 +307,9 @@ onMounted(() => onFormModelInit());
v-model="clientId"
option-value="id"
option-label="name"
- :options="clientsOptions"
+ url="Clients"
+ :fields="['id', 'name']"
+ sort-by="id"
hide-selected
map-options
:required="true"
diff --git a/src/pages/Ticket/Card/TicketCard.vue b/src/pages/Ticket/Card/TicketCard.vue
index cf15cb7fa..73b6f5543 100644
--- a/src/pages/Ticket/Card/TicketCard.vue
+++ b/src/pages/Ticket/Card/TicketCard.vue
@@ -1,17 +1,11 @@
routeName.value);
:descriptor="TicketDescriptor"
search-data-key="TicketList"
:searchbar-props="{
- customRouteRedirectName,
+ url: 'Tickets/filter',
label: t('card.search'),
info: t('card.searchInfo'),
}"
diff --git a/src/pages/Ticket/Card/TicketComponents.vue b/src/pages/Ticket/Card/TicketComponents.vue
index 3954b5a62..6131c92db 100644
--- a/src/pages/Ticket/Card/TicketComponents.vue
+++ b/src/pages/Ticket/Card/TicketComponents.vue
@@ -310,7 +310,7 @@ onUnmounted(() => (stateStore.rightDrawer = false));
{{ row.item.name }}
{{ row.item.subName }}
-
+
diff --git a/src/pages/Ticket/Card/TicketCreateTracking.vue b/src/pages/Ticket/Card/TicketCreateTracking.vue
index 87ca8dd3f..d692f550d 100644
--- a/src/pages/Ticket/Card/TicketCreateTracking.vue
+++ b/src/pages/Ticket/Card/TicketCreateTracking.vue
@@ -17,9 +17,7 @@ const { t } = useI18n();
const state = useState();
const user = state.getUser();
const stateFetchDataRef = ref(null);
-
const statesOptions = ref([]);
-const workersOptions = ref([]);
const onStateFkChange = (formData) => (formData.userFk = user.value.id);
@@ -30,12 +28,6 @@ const onStateFkChange = (formData) => (formData.userFk = user.value.id);
auto-load
@on-fetch="(data) => (statesOptions = data)"
/>
- (workersOptions = data)"
- />
(formData.userFk = user.value.id);
{
const opts = { message: t('Ticket cloned'), type: 'positive' };
let clonedTicketId;
try {
- const { data } = await axios.post(`Tickets/${ticketId}/clone`, {
- shipped: ticket.value.shipped,
+ const { data } = await axios.post(`Tickets/cloneAll`, {
+ ticketsIds: [ticket.value.id],
+ withWarehouse: true,
+ negative: false,
});
- clonedTicketId = data;
+ clonedTicketId = data[0].id;
} catch (e) {
opts.message = t('It was not able to clone the ticket');
opts.type = 'negative';
@@ -44,6 +49,25 @@ const actions = {
push({ name: 'TicketSummary', params: { id: clonedTicketId } });
}
},
+ setWeight: async () => {
+ try {
+ const invoiceIds = (
+ await axios.post(`Tickets/${ticketId}/setWeight`, {
+ weight: weight.value,
+ })
+ ).data;
+
+ notify({ message: t('Weight set'), type: 'positive' });
+ if (invoiceIds.length)
+ notify({
+ message: t('invoiceIds', { invoiceIds: invoiceIds.join() }),
+ type: 'positive',
+ });
+ await ticketSummary.fetch({ updateRouter: false });
+ } catch (e) {
+ notify({ message: e.message, type: 'negative' });
+ }
+ },
remove: async () => {
try {
await axios.post(`Tickets/${ticketId}/setDeleted`);
@@ -253,6 +277,12 @@ function openConfirmDialog(callback) {
{{ t('To clone ticket') }}
+
+
+
+
+ {{ t('Set weight') }}
+
@@ -262,9 +292,25 @@ function openConfirmDialog(callback) {
{{ t('Delete ticket') }}
+
+
+
+
+
-
+en:
+ invoiceIds: "Invoices have been generated with the following ids: {invoiceIds}"
+
es:
Open Delivery Note...: Abrir albarán...
Send Delivery Note...: Enviar albarán...
@@ -282,4 +328,8 @@ es:
To clone ticket: Clonar ticket
Ticket cloned: Ticked clonado
It was not able to clone the ticket: No se pudo clonar el ticket
+ Set weight: Establecer peso
+ Weight set: Peso establecido
+ This ticket may be invoiced, do you want to continue?: Es posible que se facture este ticket, desea continuar?
+ invoiceIds: "Se han generado las facturas con los siguientes ids: {invoiceIds}"
diff --git a/src/pages/Ticket/Card/TicketExpedition.vue b/src/pages/Ticket/Card/TicketExpedition.vue
index a7eb9e27e..c4ab63b39 100644
--- a/src/pages/Ticket/Card/TicketExpedition.vue
+++ b/src/pages/Ticket/Card/TicketExpedition.vue
@@ -3,7 +3,6 @@ import { onMounted, ref, computed, onUnmounted, reactive, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
-import FetchData from 'components/FetchData.vue';
import VnInput from 'src/components/common/VnInput.vue';
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
import TicketEditManaProxy from './TicketEditMana.vue';
@@ -35,7 +34,6 @@ const selectedExpeditions = ref([]);
const allColumnNames = ref([]);
const visibleColumns = ref([]);
const newTicketWithRoute = ref(false);
-const itemsOptions = ref([]);
const exprBuilder = (param, value) => {
switch (param) {
@@ -139,7 +137,9 @@ const columns = computed(() => [
filterValue: null,
event: getInputEvents,
attrs: {
- options: itemsOptions.value,
+ url: 'Items',
+ fields: ['id', 'name'],
+ 'sort-by': 'name ASC',
'option-value': 'id',
'option-label': 'name',
dense: true,
@@ -268,19 +268,12 @@ onMounted(async () => {
stateStore.rightDrawer = true;
const filteredColumns = columns.value.filter((col) => col.name !== 'history');
allColumnNames.value = filteredColumns.map((col) => col.name);
- // await expeditionsArrayData.fetch({ append: false });
});
onUnmounted(() => (stateStore.rightDrawer = false));
- (itemsOptions = data)"
- />
-
{{ t('ticketNotes.addNote') }}
-
+
diff --git a/src/pages/Ticket/Card/TicketPackage.vue b/src/pages/Ticket/Card/TicketPackage.vue
index a76fce2b6..c071d4f7f 100644
--- a/src/pages/Ticket/Card/TicketPackage.vue
+++ b/src/pages/Ticket/Card/TicketPackage.vue
@@ -114,17 +114,20 @@ watch(
-
-
- {{ t('package.addPackage') }}
-
-
+
+
+
+ {{ t('package.addPackage') }}
+
+
+
diff --git a/src/pages/Ticket/Card/TicketPurchaseRequest.vue b/src/pages/Ticket/Card/TicketPurchaseRequest.vue
index 281dc46a1..8d84e2b46 100644
--- a/src/pages/Ticket/Card/TicketPurchaseRequest.vue
+++ b/src/pages/Ticket/Card/TicketPurchaseRequest.vue
@@ -252,7 +252,13 @@ const openCreateModal = () => createTicketRequestDialogRef.value.show();
-
+
{{ t('purchaseRequest.newRequest') }}
diff --git a/src/pages/Ticket/Card/TicketSale.vue b/src/pages/Ticket/Card/TicketSale.vue
index cbc94b388..f86863f05 100644
--- a/src/pages/Ticket/Card/TicketSale.vue
+++ b/src/pages/Ticket/Card/TicketSale.vue
@@ -11,7 +11,6 @@ import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
import TicketEditManaProxy from './TicketEditMana.vue';
import VnImg from 'src/components/ui/VnImg.vue';
-import RightMenu from 'src/components/common/RightMenu.vue';
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
import TicketSaleMoreActions from './TicketSaleMoreActions.vue';
import TicketTransfer from './TicketTransfer.vue';
@@ -39,7 +38,6 @@ const ticketConfig = ref(null);
const isLocked = ref(false);
const isTicketEditable = ref(false);
const sales = ref([]);
-const itemsWithNameOptions = ref([]);
const editableStatesOptions = ref([]);
const selectedSales = ref([]);
const mana = ref(null);
@@ -436,12 +434,6 @@ onUnmounted(() => (stateStore.rightDrawer = false));
auto-load
@on-fetch="(data) => (isLocked = data)"
/>
- (itemsWithNameOptions = data)"
- />
(stateStore.rightDrawer = false));
@@ -662,7 +656,7 @@ onUnmounted(() => (stateStore.rightDrawer = false));
{{ row.concept }}
{{ row.item?.subName }}
-
+
@@ -741,6 +735,7 @@ onUnmounted(() => (stateStore.rightDrawer = false));
size="md"
round
flat
+ shortcut="+"
:disable="!isTicketEditable"
@click="insertRow()"
>
@@ -752,7 +747,7 @@ onUnmounted(() => (stateStore.rightDrawer = false));
-
+
{{ t('Add item to basket') }}
diff --git a/src/pages/Ticket/Card/TicketSaleMoreActions.vue b/src/pages/Ticket/Card/TicketSaleMoreActions.vue
index 9ec6b303a..94db67be2 100644
--- a/src/pages/Ticket/Card/TicketSaleMoreActions.vue
+++ b/src/pages/Ticket/Card/TicketSaleMoreActions.vue
@@ -131,7 +131,11 @@ const createClaim = () => {
onCreateClaimAccepted
);
else
- openConfirmationModal(t('Do you want to create a claim?'), onCreateClaimAccepted);
+ openConfirmationModal(
+ t('Do you want to create a claim?'),
+ false,
+ onCreateClaimAccepted
+ );
};
const onCreateClaimAccepted = async () => {
@@ -153,14 +157,22 @@ const setReserved = async (reserved) => {
};
const createRefund = async (withWarehouse) => {
- if (!props.sales) return;
+ if (!props.ticket) return;
- const salesIds = props.sales.map((sale) => sale.id);
- const params = { salesIds: salesIds, withWarehouse: withWarehouse, negative: true };
- const { data } = await axios.post('Sales/clone', params);
- const [refundTicket] = data;
- notify(t('refundTicketCreated', { ticketId: refundTicket.id }), 'positive');
- router.push({ name: 'TicketSale', params: { id: refundTicket.id } });
+ const params = {
+ ticketsIds: [props.ticket.id],
+ withWarehouse: withWarehouse,
+ negative: true,
+ };
+
+ try {
+ const { data } = await axios.post('Tickets/cloneAll', params);
+ const [refundTicket] = data;
+ notify(t('refundTicketCreated', { ticketId: refundTicket.id }), 'positive');
+ router.push({ name: 'TicketSale', params: { id: refundTicket.id } });
+ } catch (error) {
+ console.error(error);
+ }
};
@@ -244,7 +256,7 @@ const createRefund = async (withWarehouse) => {
- {{ t('Refund...') }}
+ {{ t('Refund') }}
@@ -279,7 +291,7 @@ es:
Add claim: Crear reclamación
Mark as reserved: Marcar como reservado
Unmark as reserved: Desmarcar como reservado
- Refund...: Abono...
+ Refund: Abono
with warehouse: con almacén
without warehouse: sin almacén
Claim out of time: Reclamación fuera de plazo
diff --git a/src/pages/Ticket/Card/TicketSaleTracking.vue b/src/pages/Ticket/Card/TicketSaleTracking.vue
index d519bc2c6..6978d92c8 100644
--- a/src/pages/Ticket/Card/TicketSaleTracking.vue
+++ b/src/pages/Ticket/Card/TicketSaleTracking.vue
@@ -26,8 +26,6 @@ const saleTrackingFetchDataRef = ref(null);
const sales = ref([]);
const saleTrackings = ref([]);
const itemShelvignsSales = ref([]);
-const shelvingsOptions = ref([]);
-const parkingsOptions = ref([]);
const saleTrackingUrl = computed(() => `SaleTrackings/${route.params.id}/filter`);
const oldQuantity = ref(null);
@@ -330,12 +328,6 @@ const qCheckBoxController = (sale, action) => {
auto-load
@on-fetch="(data) => (sales = data)"
/>
- (shelvingsOptions = data)"
- />
- (parkingsOptions = data)" />
{
{{ row.subName }}
-
+
@@ -500,7 +492,7 @@ const qCheckBoxController = (sale, action) => {
{
[
-
+
diff --git a/src/pages/Ticket/Card/TicketSummary.vue b/src/pages/Ticket/Card/TicketSummary.vue
index 177384663..6af782173 100644
--- a/src/pages/Ticket/Card/TicketSummary.vue
+++ b/src/pages/Ticket/Card/TicketSummary.vue
@@ -31,8 +31,7 @@ const $props = defineProps({
const entityId = computed(() => $props.id || route.params.id);
const summaryRef = ref();
-const ticket = ref();
-const salesLines = ref(null);
+const ticket = computed(() => summaryRef.value?.entity);
const editableStates = ref([]);
const ticketUrl = ref();
const grafanaUrl = 'https://grafana.verdnatura.es';
@@ -40,12 +39,6 @@ const grafanaUrl = 'https://grafana.verdnatura.es';
onMounted(async () => {
ticketUrl.value = (await getUrl('ticket/')) + entityId.value + '/';
});
-async function setData(data) {
- if (data) {
- ticket.value = data;
- salesLines.value = data.sales;
- }
-}
function formattedAddress() {
if (!ticket.value) return '';
@@ -89,7 +82,6 @@ async function changeState(value) {
setData(data)"
data-key="TicketSummary"
>
@@ -131,7 +123,7 @@ async function changeState(value) {
-
+
-
- {{ ticket.ticketState?.state?.name }}
+
+ {{ entity.ticketState?.state?.name }}
-
+
- {{ ticket.ticketCollections[0]?.collectionFk }}
+ {{ entity.ticketCollections[0]?.collectionFk }}
-
+
-
- {{ dashIfEmpty(ticket.refFk) }}
+
+ {{ dashIfEmpty(entity.refFk) }}
@@ -199,35 +192,35 @@ async function changeState(value) {
/>
-
-
+
+
{{ t('ticket.summary.consigneePhone') }}
-
+
-
+
{{ t('ticket.summary.consigneeMobile') }}
-
+
-
+
{{ t('ticket.summary.clientPhone') }}
-
+
-
+
{{ t('ticket.summary.clientMobile') }}
-
+
-
+
@@ -279,7 +272,7 @@ async function changeState(value) {
:url="ticketUrl + 'sale'"
:text="t('ticket.summary.saleLines')"
/>
-
+
{{ value }}
@@ -383,7 +376,11 @@ async function changeState(value) {
{{ props.row.itemFk }}
-
+
{{ props.row.visible }}
@@ -399,7 +396,6 @@ async function changeState(value) {
{{ props.row.price }} €
@@ -420,10 +416,10 @@ async function changeState(value) {
-
+
{{ t('ticket.summary.created') }}
@@ -443,7 +439,7 @@ async function changeState(value) {
:url="ticketUrl + 'service'"
:text="t('ticket.summary.service')"
/>
-
+
{{ t('ticket.summary.quantity') }}
diff --git a/src/pages/Ticket/Card/TicketTracking.vue b/src/pages/Ticket/Card/TicketTracking.vue
index 2ddb278fa..f7cbb14e9 100644
--- a/src/pages/Ticket/Card/TicketTracking.vue
+++ b/src/pages/Ticket/Card/TicketTracking.vue
@@ -83,6 +83,8 @@ const openCreateModal = () => createTrackingDialogRef.value.show();
:filter="paginateFilter"
url="TicketTrackings"
auto-load
+ order="created DESC"
+ :limit="0"
>
createTrackingDialogRef.value.show();
-
+
{{ t('tracking.addState') }}
diff --git a/src/pages/Ticket/Card/TicketTransfer.vue b/src/pages/Ticket/Card/TicketTransfer.vue
index 9a22c764c..1944b80f4 100644
--- a/src/pages/Ticket/Card/TicketTransfer.vue
+++ b/src/pages/Ticket/Card/TicketTransfer.vue
@@ -4,6 +4,7 @@ import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router';
import VnInput from 'src/components/common/VnInput.vue';
+import TicketTransferForm from './TicketTransferForm.vue';
import { toDateFormat } from 'src/filters/date.js';
import axios from 'axios';
@@ -135,9 +136,7 @@ onMounted(() => (_transfer.value = $props.transfer));
:columns="destinationTicketColumns"
:title="t('Destination ticket')"
row-key="id"
- :pagination="{ rowsPerPage: 0 }"
class="full-width q-mt-md"
- :no-data-label="t('globals.noResults')"
>
@@ -158,29 +157,11 @@ onMounted(() => (_transfer.value = $props.transfer));
+
+
+
-
-
-
-
-
-
-
-
+
diff --git a/src/pages/Ticket/Card/TicketTransferForm.vue b/src/pages/Ticket/Card/TicketTransferForm.vue
new file mode 100644
index 000000000..9507429e6
--- /dev/null
+++ b/src/pages/Ticket/Card/TicketTransferForm.vue
@@ -0,0 +1,86 @@
+
+
+
+ {{ _transfer }}
+
+
+
+
+
+
+
+
+
+
+
+es:
+ Sales to transfer: Líneas a transferir
+ Destination ticket: Ticket destinatario
+ Transfer to ticket: Transferir a ticket
+ New ticket: Nuevo ticket
+
diff --git a/src/pages/Ticket/Card/TicketVolume.vue b/src/pages/Ticket/Card/TicketVolume.vue
index 93da31e53..68d2a1f73 100644
--- a/src/pages/Ticket/Card/TicketVolume.vue
+++ b/src/pages/Ticket/Card/TicketVolume.vue
@@ -145,7 +145,7 @@ onUnmounted(() => (stateStore.rightDrawer = false));
{{ row.item.name }}
{{ row.item.subName }}
-
+
diff --git a/src/pages/Ticket/TicketAdvance.vue b/src/pages/Ticket/TicketAdvance.vue
index bf4000fdf..177b3a29b 100644
--- a/src/pages/Ticket/TicketAdvance.vue
+++ b/src/pages/Ticket/TicketAdvance.vue
@@ -133,6 +133,14 @@ const ticketColumns = computed(() => [
sortable: true,
columnFilter: null,
},
+ {
+ label: t('advanceTickets.preparation'),
+ name: 'preparation',
+ field: 'preparation',
+ align: 'left',
+ sortable: true,
+ columnFilter: null,
+ },
{
label: t('advanceTickets.liters'),
name: 'liters',
@@ -448,7 +456,7 @@ const handleCloseProgressDialog = () => {
const handleCancelProgress = () => (cancelProgress.value = true);
onMounted(async () => {
- let today = Date.vnNew();
+ let today = Date.vnNew().toISOString();
const tomorrow = new Date(today);
tomorrow.setDate(tomorrow.getDate() + 1);
userParams.dateFuture = tomorrow;
@@ -624,6 +632,7 @@ onMounted(async () => {
+
@@ -635,6 +644,7 @@ onMounted(async () => {
{
>
{{ row.state }}
+ {{ dashIfEmpty(row.state) }}
diff --git a/src/pages/Ticket/TicketAdvanceFilter.vue b/src/pages/Ticket/TicketAdvanceFilter.vue
index c4548763a..209a1a307 100644
--- a/src/pages/Ticket/TicketAdvanceFilter.vue
+++ b/src/pages/Ticket/TicketAdvanceFilter.vue
@@ -70,7 +70,6 @@ onMounted(async () => await getItemPackingTypes());
v-model="params.dateFuture"
:label="t('params.dateFuture')"
is-outlined
- @update:model-value="searchFn()"
/>
@@ -80,7 +79,6 @@ onMounted(async () => await getItemPackingTypes());
v-model="params.dateToAdvance"
:label="t('params.dateToAdvance')"
is-outlined
- @update:model-value="searchFn()"
/>
@@ -121,10 +119,9 @@ onMounted(async () => await getItemPackingTypes());
@@ -157,7 +154,7 @@ en:
dateToAdvance: Destination date
futureIpt: Origin IPT
ipt: Destination IPT
- itemPackingTypes: 100% movable
+ isFullMovable: 100% movable
warehouseFk: Warehouse
es:
Horizontal: Horizontal
@@ -168,6 +165,6 @@ es:
dateToAdvance: Fecha destino
futureIpt: IPT Origen
ipt: IPT destino
- itemPackingTypes: 100% movible
+ isFullMovable: 100% movible
warehouseFk: Almacén
diff --git a/src/pages/Ticket/TicketCreateDialog.vue b/src/pages/Ticket/TicketCreateDialog.vue
new file mode 100644
index 000000000..1493adc53
--- /dev/null
+++ b/src/pages/Ticket/TicketCreateDialog.vue
@@ -0,0 +1,226 @@
+
+
+
+ (clientOptions = data)"
+ :filter="{ fields: ['id', 'name', 'defaultAddressFk'], order: 'id' }"
+ auto-load
+ />
+ (warehousesOptions = data)"
+ order="name"
+ auto-load
+ />
+
+
+
+
+
+ onClientSelected(data)"
+ >
+
+
+
+
+ {{ scope.opt.name }}
+
+
+ {{ `#${scope.opt.id}` }}
+
+
+
+
+
+
+
+
+
+ fetchAvailableAgencies(data)"
+ >
+
+
+
+
+ {{ scope.opt.nickname }}
+
+
+ {{ `${scope.opt.street}, ${scope.opt.city}` }}
+
+
+
+
+
+
+
+
+
+ fetchAvailableAgencies(data)"
+ />
+
+
+
+
+ fetchAvailableAgencies(data)"
+ />
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/Ticket/TicketFuture.vue b/src/pages/Ticket/TicketFuture.vue
index 2fec6dc18..2078d0595 100644
--- a/src/pages/Ticket/TicketFuture.vue
+++ b/src/pages/Ticket/TicketFuture.vue
@@ -8,6 +8,8 @@ import VnSelect from 'src/components/common/VnSelect.vue';
import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue';
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
+import RightMenu from 'src/components/common/RightMenu.vue';
+import TicketFutureFilter from './TicketFutureFilter.vue';
import { dashIfEmpty, toCurrency } from 'src/filters';
import { useVnConfirm } from 'composables/useVnConfirm';
@@ -37,9 +39,9 @@ const exprBuilder = (param, value) => {
return { liters: value };
case 'lines':
return { lines: value };
- case 'ipt':
+ case 'iptColFilter':
return { ipt: { like: `%${value}%` } };
- case 'futureIpt':
+ case 'futureIptColFilter':
return { futureIpt: { like: `%${value}%` } };
case 'totalWithVat':
return { totalWithVat: value };
@@ -47,8 +49,8 @@ const exprBuilder = (param, value) => {
};
const userParams = reactive({
- futureDated: Date.vnNew(),
- originDated: Date.vnNew(),
+ futureScopeDays: Date.vnNew().toISOString(),
+ originScopeDays: Date.vnNew().toISOString(),
warehouseFk: user.value.warehouseFk,
});
@@ -60,8 +62,8 @@ const arrayData = useArrayData('FutureTickets', {
const { store } = arrayData;
const params = reactive({
- futureDated: Date.vnNew(),
- originDated: Date.vnNew(),
+ futureScopeDays: Date.vnNew(),
+ originScopeDays: Date.vnNew(),
warehouseFk: user.value.warehouseFk,
});
@@ -83,6 +85,8 @@ const getInputEvents = (col) => {
};
};
+const tickets = computed(() => store.data);
+
const ticketColumns = computed(() => [
{
label: t('futureTickets.problems'),
@@ -121,7 +125,7 @@ const ticketColumns = computed(() => [
sortable: true,
columnFilter: {
component: VnSelect,
- filterParamKey: 'ipt',
+ filterParamKey: 'iptColFilter',
type: 'select',
filterValue: null,
event: getInputEvents,
@@ -168,7 +172,7 @@ const ticketColumns = computed(() => [
label: t('futureTickets.availableLines'),
name: 'lines',
field: 'lines',
- align: 'left',
+ align: 'center',
sortable: true,
columnFilter: {
component: VnInput,
@@ -214,7 +218,7 @@ const ticketColumns = computed(() => [
sortable: true,
columnFilter: {
component: VnSelect,
- filterParamKey: 'futureIpt',
+ filterParamKey: 'futureIptColFilter',
type: 'select',
filterValue: null,
event: getInputEvents,
@@ -230,7 +234,7 @@ const ticketColumns = computed(() => [
{
label: t('futureTickets.futureState'),
name: 'futureState',
- align: 'left',
+ align: 'right',
sortable: true,
columnFilter: null,
format: (val) => dashIfEmpty(val),
@@ -305,9 +309,14 @@ onMounted(async () => {
+
+
+
+
+
{
-
+
{
-
+
{
diff --git a/src/pages/Wagon/Type/WagonCreateTray.vue b/src/pages/Wagon/Type/WagonCreateTray.vue
new file mode 100644
index 000000000..304fa83ac
--- /dev/null
+++ b/src/pages/Wagon/Type/WagonCreateTray.vue
@@ -0,0 +1,116 @@
+
+
+
+ (wagonColors = data)"
+ auto-load
+ />
+
+
+
+
+
+
+
+ {{ scope.opt.name }}
+
+
+
+
+
+
+
+
+
+
+
+ en:
+ Select a tray: Select a tray
+ colors:
+ white: White
+ red: Red
+ green: Green
+ blue: Blue
+ es:
+ Select a tray color: Seleccione un color
+ Add new tray: Añadir nueva bandeja
+ Height: Altura
+ The minimum height between trays is 50cm: La altura mínima entre bandejas es de 50cm
+ The maximum height of the wagon is 200cm: La altura máxima del vagón es de 200cm
+ A tray with the same height already exists, try with a different height: Ya existe una bandeja con la misma altura, prueba con una diferente
+ colors:
+ white: Blanco
+ red: Rojo
+ green: Verde
+ blue: Azul
+
diff --git a/src/pages/Wagon/Type/WagonTypeCreate.vue b/src/pages/Wagon/Type/WagonTypeCreate.vue
deleted file mode 100644
index bc9c1a40c..000000000
--- a/src/pages/Wagon/Type/WagonTypeCreate.vue
+++ /dev/null
@@ -1,433 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
- {{
- t('wagon.warnings.minHeightBetweenTrays') +
- wagonConfig.minHeightBetweenTrays +
- ' cm'
- }}
-
- {{
- t('wagon.warnings.maxWagonHeight') +
- wagonConfig.maxWagonHeight +
- ' cm'
- }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ t('wagon.type.trayColor') }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/pages/Wagon/Type/WagonTypeEdit.vue b/src/pages/Wagon/Type/WagonTypeEdit.vue
new file mode 100644
index 000000000..eb8205d72
--- /dev/null
+++ b/src/pages/Wagon/Type/WagonTypeEdit.vue
@@ -0,0 +1,293 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ en:
+ tray: Tray
+ wagonColor: Wagon color
+ Select a tray: Select a tray
+ es:
+ tray: Bandeja
+ wagonColor: Color de la bandeja
+ Select a tray: Seleccione una bandeja
+ Create new Wagon type: Crear nuevo tipo de vagón
+ Add new tray: Añadir nueva bandeja
+ Height: Altura
+ Tray added successfully: Bandeja añadida correctamente
+ Tray deleted successfully: Bandeja eliminada correctamente
+
diff --git a/src/pages/Wagon/Type/WagonTypeList.vue b/src/pages/Wagon/Type/WagonTypeList.vue
index 3ecca1ea3..c0943c58e 100644
--- a/src/pages/Wagon/Type/WagonTypeList.vue
+++ b/src/pages/Wagon/Type/WagonTypeList.vue
@@ -1,80 +1,136 @@
-
-
-
-
+
+
+
+
+
-
-
-
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+ {{ t('globals.new') }}
+
+
+
+en:
+ nameNotEmpty: The name cannot be empty
+es:
+ Create new Wagon type: Crear nuevo tipo de vagón
+ Name: Nombre
+ nameNotEmpty: El nombre no puede estar vacío
+
diff --git a/src/pages/Wagon/WagonList.vue b/src/pages/Wagon/WagonList.vue
index a8b6728c3..02e3b6d16 100644
--- a/src/pages/Wagon/WagonList.vue
+++ b/src/pages/Wagon/WagonList.vue
@@ -1,19 +1,20 @@
(workersOptions = data)"
- auto-load
- url="Workers/search"
- />
- (countriesOptions = data)"
- auto-load
- url="Countries"
- />
- (educationLevelsOptions = data)"
+ :filter="{ fields: ['id', 'name'], order: 'name ASC' }"
+ @on-fetch="(data) => (educationLevels = data)"
auto-load
url="EducationLevels"
/>
-
+ (countries = data)"
+ auto-load
+ />
{
if (isFestive) {
attrs.class = '--festive';
- attrs.label = event.absenceId ?? timestamp.day;
+ attrs.label = timestamp.day;
} else attrs.class = `--${type}`;
return attrs;
diff --git a/src/pages/Worker/Card/WorkerCard.vue b/src/pages/Worker/Card/WorkerCard.vue
index 0abcdcafd..5f9fa0f8e 100644
--- a/src/pages/Worker/Card/WorkerCard.vue
+++ b/src/pages/Worker/Card/WorkerCard.vue
@@ -15,5 +15,6 @@ import WorkerFilter from '../WorkerFilter.vue';
label: 'Search worker',
info: 'You can search by worker id or name',
}"
+ :redirect-on-error="true"
/>
diff --git a/src/pages/Worker/Card/WorkerDescriptor.vue b/src/pages/Worker/Card/WorkerDescriptor.vue
index 8fbb23ef8..3675d40f8 100644
--- a/src/pages/Worker/Card/WorkerDescriptor.vue
+++ b/src/pages/Worker/Card/WorkerDescriptor.vue
@@ -1,15 +1,15 @@
@@ -107,14 +71,12 @@ const refetch = async () => await cardDescriptorRef.value.getData();
ref="cardDescriptorRef"
module="Worker"
data-key="workerData"
- :url="`Workers/${entityId}`"
- :filter="filter"
- :title="data.title"
- :subtitle="data.subtitle"
+ url="Workers/descriptor"
+ :filter="{ where: { id: entityId } }"
+ title="user.nickname"
@on-fetch="
(data) => {
worker = data;
- setData(data);
getIsExcluded();
}
"
@@ -133,7 +95,7 @@ const refetch = async () => await cardDescriptorRef.value.getData();
v-if="!worker.user.emailVerified && user.id != worker.id"
v-ripple
clickable
- @click="openChangePasswordForm()"
+ @click="$refs.changePasswordFormDialog.show()"
>
{{ t('Change password') }}
@@ -144,31 +106,57 @@ const refetch = async () => await cardDescriptorRef.value.getData();
-
-
-
-
-
-
-
-
- {{ t('worker.imageNotFound') }}
+
+
+
+
+
+
+
+
+
+ {{ t('worker.imageNotFound') }}
+
-
-
-
+
+
+
+
+
+
+
-
-
+
+
await cardDescriptorRef.value.getData();
-
+
{{ t('worker.summary.sipExtension') }}
-
+
diff --git a/src/pages/Worker/Card/WorkerDms.vue b/src/pages/Worker/Card/WorkerDms.vue
index a4f7ef5a9..e2b62bc4f 100644
--- a/src/pages/Worker/Card/WorkerDms.vue
+++ b/src/pages/Worker/Card/WorkerDms.vue
@@ -10,6 +10,6 @@ const route = useRoute();
delete-model="WorkerDms"
download-model="WorkerDms"
default-dms-code="hhrrData"
- filter="worker"
+ filter="wd.workerFk"
/>
diff --git a/src/pages/Worker/Card/WorkerFormation.vue b/src/pages/Worker/Card/WorkerFormation.vue
index 829326898..71c5cba5d 100644
--- a/src/pages/Worker/Card/WorkerFormation.vue
+++ b/src/pages/Worker/Card/WorkerFormation.vue
@@ -108,7 +108,7 @@ const columns = computed(() => [
:filter="courseFilter"
:create="{
urlCreate: 'trainingCourses',
- title: 'Create trainingCourse',
+ title: t('Create training course'),
onDataSaved: () => tableRef.reload(),
formInitialData: {
workerFk: entityId,
@@ -122,3 +122,7 @@ const columns = computed(() => [
:use-model="true"
/>
+
+es:
+ Create training course: Crear curso de formación
+
diff --git a/src/pages/Worker/Card/WorkerLocker.vue b/src/pages/Worker/Card/WorkerLocker.vue
index f19fc8ae6..4a19e472c 100644
--- a/src/pages/Worker/Card/WorkerLocker.vue
+++ b/src/pages/Worker/Card/WorkerLocker.vue
@@ -3,13 +3,13 @@ import { ref, computed } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import axios from 'axios';
-import { useRole } from 'src/composables/useRole';
+import { useAcl } from 'src/composables/useAcl';
import FormModel from 'components/FormModel.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import { useArrayData } from 'src/composables/useArrayData';
import FetchData from 'components/FetchData.vue';
-const { hasAny } = useRole();
+const { hasAny } = useAcl();
const { t } = useI18n();
const fetchData = ref();
const originaLockerId = ref();
@@ -57,7 +57,11 @@ const init = async (data) => {
option-label="code"
option-value="id"
hide-selected
- :readonly="!hasAny(['productionBoss', 'hr'])"
+ :readonly="
+ !hasAny([
+ { model: 'Worker', props: '__get__locker', accessType: 'READ' },
+ ])
+ "
/>
diff --git a/src/pages/Worker/Card/WorkerMedical.vue b/src/pages/Worker/Card/WorkerMedical.vue
new file mode 100644
index 000000000..6bca4ae85
--- /dev/null
+++ b/src/pages/Worker/Card/WorkerMedical.vue
@@ -0,0 +1,91 @@
+
+
+
+
diff --git a/src/pages/Worker/Card/WorkerPda.vue b/src/pages/Worker/Card/WorkerPda.vue
index 4e0abc20c..a53aac270 100644
--- a/src/pages/Worker/Card/WorkerPda.vue
+++ b/src/pages/Worker/Card/WorkerPda.vue
@@ -116,7 +116,7 @@ function reloadData() {
-
+
-import { ref, onMounted, computed } from 'vue';
+import { ref, onBeforeMount, computed } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
+import axios from 'axios';
import { dashIfEmpty, toDate } from 'src/filters';
-import { getUrl } from 'src/composables/getUrl';
import VnLv from 'src/components/ui/VnLv.vue';
import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue';
import CardSummary from 'components/ui/CardSummary.vue';
import VnUserLink from 'src/components/ui/VnUserLink.vue';
import VnTitle from 'src/components/common/VnTitle.vue';
import RoleDescriptorProxy from 'src/pages/Account/Role/Card/RoleDescriptorProxy.vue';
-import VnRow from 'src/components/ui/VnRow.vue';
import DepartmentDescriptorProxy from 'src/pages/Department/Card/DepartmentDescriptorProxy.vue';
+import { useRole } from 'src/composables/useRole';
const route = useRoute();
const { t } = useI18n();
@@ -24,55 +24,27 @@ const $props = defineProps({
});
const entityId = computed(() => $props.id || route.params.id);
-const workerUrl = ref();
+const basicDataUrl = ref(null);
+const isHr = computed(() => useRole().hasAny(['hr']));
+const advancedSummary = ref();
-onMounted(async () => {
- workerUrl.value = (await getUrl('')) + `worker/${entityId.value}/`;
+onBeforeMount(async () => {
+ if (isHr.value) {
+ advancedSummary.value = (
+ await axios.get('Workers/advancedSummary', {
+ params: { filter: { where: { id: entityId.value } } },
+ })
+ ).data[0];
+ basicDataUrl.value = `#/worker/${entityId.value}/basic-data`;
+ }
});
-
-const filter = {
- include: [
- {
- relation: 'user',
- scope: {
- fields: ['email', 'name', 'nickname', 'roleFk'],
- include: {
- relation: 'role',
- scope: {
- fields: ['name'],
- },
- },
- },
- },
- {
- relation: 'department',
- scope: {
- include: {
- relation: 'department',
- scope: {
- fields: ['name'],
- },
- },
- },
- },
- {
- relation: 'boss',
- },
- {
- relation: 'client',
- },
- {
- relation: 'sip',
- },
- ],
-};
@@ -80,10 +52,7 @@ const filter = {
-
+
@@ -93,7 +62,6 @@ const filter = {
/>
-
-
-
-
+
+
-
-
-
-
-
-
+
+
+
+
-
-
+
+
- {{ worker.user.role.name }}
-
+ {{ worker?.user?.role?.name }}
+
diff --git a/src/pages/Worker/Card/WorkerTimeControl.vue b/src/pages/Worker/Card/WorkerTimeControl.vue
index 87ff44e63..fbfd4b28d 100644
--- a/src/pages/Worker/Card/WorkerTimeControl.vue
+++ b/src/pages/Worker/Card/WorkerTimeControl.vue
@@ -2,6 +2,7 @@
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
import { onMounted, ref, computed, onBeforeMount, nextTick, reactive } from 'vue';
+import { axiosNoError } from 'src/boot/axios';
import FetchData from 'components/FetchData.vue';
import WorkerTimeHourChip from 'pages/Worker/Card/WorkerTimeHourChip.vue';
@@ -12,7 +13,7 @@ import WorkerTimeControlCalendar from 'pages/Worker/Card/WorkerTimeControlCalend
import useNotify from 'src/composables/useNotify.js';
import axios from 'axios';
-import { useRole } from 'src/composables/useRole';
+import { useAcl } from 'src/composables/useAcl';
import { useWeekdayStore } from 'src/stores/useWeekdayStore';
import { useStateStore } from 'stores/useStateStore';
import { useState } from 'src/composables/useState';
@@ -26,7 +27,6 @@ import { date } from 'quasar';
const route = useRoute();
const { t, locale } = useI18n();
const { notify } = useNotify();
-const { hasAny } = useRole();
const _state = useState();
const user = _state.getUser();
const stateStore = useStateStore();
@@ -34,6 +34,10 @@ const weekdayStore = useWeekdayStore();
const weekDays = ref([]);
const { openConfirmationModal } = useVnConfirm();
const { getWeekOfYear } = date;
+const defaultDate = computed(() => {
+ const timestamp = route.query.timestamp;
+ return timestamp ? new Date(timestamp * 1000) : Date.vnNew();
+});
const workerTimeFormDialogRef = ref(null);
const workerTimeReasonFormDialogRef = ref(null);
@@ -56,15 +60,20 @@ const workerTimeFormProps = reactive({
// Array utilizado por QCalendar para seleccionar un rango de fechas
const selectedCalendarDates = ref([]);
// Date formateada para bindear al componente QDate
-const selectedDateFormatted = ref(toDateString(Date.vnNew()));
+const selectedDateFormatted = ref(toDateString(defaultDate.value));
const arrayData = useArrayData('workerData');
-
+const acl = useAcl();
const worker = computed(() => arrayData.store?.data);
-
-const isHr = computed(() => hasAny(['hr']));
-
-const isHimSelf = computed(() => user.value.id === Number(route.params.id));
+const canSend = computed(() =>
+ acl.hasAny([{ model: 'WorkerTimeControl', props: 'sendMail', accessType: 'WRITE' }])
+);
+const canUpdate = computed(() =>
+ acl.hasAny([
+ { model: 'WorkerTimeControl', props: 'updateMailState', accessType: 'WRITE' },
+ ])
+);
+const isHimself = computed(() => user.value.id === Number(route.params.id));
const columns = computed(() => {
return weekdayStore.getLocales?.map((day, index) => {
@@ -251,58 +260,32 @@ const fetchHours = async () => {
}
};
-const fetchWorkerTimeControlMails = async (filter) => {
- try {
- const { data } = await axios.get('WorkerTimeControlMails', {
- params: { filter: JSON.stringify(filter) },
- });
-
- return data;
- } catch (err) {
- console.error('Error fetching worker time control mails');
- }
-};
-
const fetchWeekData = async () => {
+ const where = {
+ year: selectedDate.value.getFullYear(),
+ week: selectedWeekNumber.value,
+ };
try {
- const filter = {
- where: {
- workerFk: route.params.id,
- year: selectedDate.value ? selectedDate.value?.getFullYear() : null,
- week: selectedWeekNumber.value,
- },
- };
+ const mail = (
+ await axiosNoError.get(`Workers/${route.params.id}/mail`, {
+ params: { filter: { where } },
+ })
+ ).data[0];
- const data = await fetchWorkerTimeControlMails(filter);
- if (!data.length) {
- state.value = null;
- } else {
- const [mail] = data;
+ if (!mail) state.value = null;
+ else {
state.value = mail.state;
reason.value = mail.reason;
}
- await canBeResend();
+ canResend.value = !!(
+ await axiosNoError.get('WorkerTimeControlMails/count', { params: { where } })
+ ).data.count;
} catch (err) {
console.error('Error fetching week data');
}
};
-const canBeResend = async () => {
- canResend.value = false;
-
- const filter = {
- where: {
- year: selectedDate.value.getFullYear(),
- week: selectedWeekNumber.value,
- },
- limit: 1,
- };
-
- const data = await fetchWorkerTimeControlMails(filter);
- if (data.length) canResend.value = true;
-};
-
const setHours = (data) => {
for (const weekDay of weekDays.value) {
if (data) {
@@ -423,7 +406,7 @@ onBeforeMount(() => {
});
onMounted(async () => {
- await setDate(Date.vnNew());
+ await setDate(defaultDate.value);
await getMailStates(selectedDate.value);
stateStore.rightDrawer = true;
});
@@ -443,7 +426,7 @@ onMounted(async () => {
{
@click="isSatisfied()"
/>
{
{
-
+
{
{{ secondsToHoursMinutes(day.dayData?.workedHours) }}
-
{{ t('Add time') }}
-
+
@@ -596,7 +583,7 @@ onMounted(async () => {
@@ -622,6 +609,9 @@ onMounted(async () => {
margin-bottom: 0px;
}
}
+:deep(.q-td) {
+ min-width: 170px;
+}
diff --git a/src/pages/Worker/Card/WorkerTimeReasonForm.vue b/src/pages/Worker/Card/WorkerTimeReasonForm.vue
index 5c1ab9118..23bdba15e 100644
--- a/src/pages/Worker/Card/WorkerTimeReasonForm.vue
+++ b/src/pages/Worker/Card/WorkerTimeReasonForm.vue
@@ -9,7 +9,7 @@ const $props = defineProps({
type: String,
default: '',
},
- isHimSelf: {
+ isHimself: {
type: Boolean,
default: false,
},
@@ -40,7 +40,7 @@ const closeForm = () => {
v-model="reasonFormData"
type="textarea"
autogrow
- :disable="!isHimSelf"
+ :disable="!isHimself"
/>
diff --git a/src/pages/Worker/WorkerCreate.vue b/src/pages/Worker/WorkerCreate.vue
index a1ded2bfd..b51209879 100644
--- a/src/pages/Worker/WorkerCreate.vue
+++ b/src/pages/Worker/WorkerCreate.vue
@@ -2,7 +2,6 @@
import { onBeforeMount, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import axios from 'axios';
-import { useUserConfig } from 'src/composables/useUserConfig';
import VnRow from 'components/ui/VnRow.vue';
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
import VnInputDate from 'components/common/VnInputDate.vue';
@@ -14,15 +13,25 @@ import FetchData from 'components/FetchData.vue';
import FormModel from 'components/FormModel.vue';
import CreateBankEntityForm from 'src/components/CreateBankEntityForm.vue';
import VnRadio from 'src/components/common/VnRadio.vue';
+import { useState } from 'src/composables/useState';
const { t } = useI18n();
+const user = useState().getUser();
const companiesOptions = ref([]);
-const workersOptions = ref([]);
const payMethodsOptions = ref([]);
const bankEntitiesOptions = ref([]);
-const formData = ref({ isFreelance: false });
-const defaultPayMethod = ref(0);
+const formData = ref({ companyFk: user.value.companyFk, isFreelance: false });
+const defaultPayMethod = ref();
+
+onBeforeMount(async () => {
+ defaultPayMethod.value = (
+ await axios.get('WorkerConfigs/findOne', {
+ params: { field: ['payMethodFk'] },
+ })
+ ).data.payMethodFk;
+ formData.value.payMethodFk = defaultPayMethod.value;
+});
function handleLocation(data, location) {
const { town, code, provinceFk, countryFk } = location ?? {};
@@ -32,16 +41,32 @@ function handleLocation(data, location) {
data.countryFk = countryFk;
}
-onBeforeMount(async () => {
- const userInfo = await useUserConfig().fetch();
- formData.value.companyFk = userInfo.companyFk;
+function generateCodeUser(worker) {
+ if (!worker.firstName || !worker.lastNames) return;
- const { data } = await axios.get('WorkerConfigs/findOne', {
- params: { field: ['payMethodFk'] },
- });
- defaultPayMethod.value = data.payMethodFk;
- formData.value.payMethodFk = defaultPayMethod.value;
-});
+ const totalName = worker.firstName.concat(' ' + worker.lastNames).toLowerCase();
+ const totalNameArray = totalName.split(' ');
+ let newCode = '';
+
+ for (let part of totalNameArray) newCode += part.charAt(0);
+
+ worker.code = newCode.toUpperCase().slice(0, 3);
+ worker.name = totalNameArray[0] + newCode.slice(1);
+
+ if (!worker.companyFk) worker.companyFk = user.companyFk;
+}
+
+async function autofillBic(worker) {
+ if (!worker || !worker.iban) return;
+
+ let bankEntityId = parseInt(worker.iban.substr(4, 4));
+ let filter = { where: { id: bankEntityId } };
+
+ const { data } = await axios.get(`BankEntities`, { params: { filter } });
+ const hasData = data && data[0];
+ if (hasData) worker.bankEntityFk = data[0].id;
+ else if (!hasData) worker.bankEntityFk = undefined;
+}
{
@on-fetch="(data) => (companiesOptions = data)"
auto-load
/>
- (workersOptions = data)"
- auto-load
- />
(payMethodsOptions = data)"
@@ -93,11 +113,13 @@ onBeforeMount(async () => {
v-model="data.firstName"
:label="t('worker.create.name')"
:rules="validate('Worker.firstName')"
+ @update:model-value="generateCodeUser(data)"
/>
{
{
handleLocation(data, location)"
:disable="formData.isFreelance"
>
@@ -204,6 +225,7 @@ onBeforeMount(async () => {
:label="t('worker.create.iban')"
:rules="validate('Worker.iban')"
:disable="formData.isFreelance"
+ @update:model-value="autofillBic(data)"
>
@@ -221,6 +243,8 @@ onBeforeMount(async () => {
:roles-allowed-to-create="['salesAssistant', 'hr']"
:rules="validate('Worker.bankEntity')"
:disable="formData.isFreelance"
+ @update:model-value="autofillBic(data)"
+ :filter-options="['bic', 'name']"
>
-
{{ t('Create') }}
-
+
diff --git a/src/pages/Worker/WorkerFilter.vue b/src/pages/Worker/WorkerFilter.vue
index 0853791ef..765241341 100644
--- a/src/pages/Worker/WorkerFilter.vue
+++ b/src/pages/Worker/WorkerFilter.vue
@@ -5,6 +5,7 @@ import { useI18n } from 'vue-i18n';
import FetchData from 'components/FetchData.vue';
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
import VnInput from 'src/components/common/VnInput.vue';
+import VnSelect from 'src/components/common/VnSelect.vue';
const { t } = useI18n();
const props = defineProps({
@@ -26,7 +27,7 @@ const departments = ref();
{{ formatFn(tag.value) }}
-
+
-
@@ -107,6 +105,7 @@ en:
userName: User
extension: Extension
departmentFk: Department
+ id: ID
es:
params:
search: Contiene
@@ -116,6 +115,7 @@ es:
userName: Usuario
extension: Extensión
departmentFk: Departamento
+ id: ID
FI: NIF
First Name: Nombre
Last Name: Apellidos
diff --git a/src/pages/Worker/WorkerList.vue b/src/pages/Worker/WorkerList.vue
index 0c2656597..4c9964c0b 100644
--- a/src/pages/Worker/WorkerList.vue
+++ b/src/pages/Worker/WorkerList.vue
@@ -1,5 +1,5 @@
(companiesOptions = data)"
auto-load
/>
- (workersOptions = data)"
- auto-load
- />
(payMethodsOptions = data)"
@@ -130,7 +156,13 @@ function uppercaseStreetModel(data) {
@on-fetch="(data) => (bankEntitiesOptions = data)"
auto-load
/>
+
+
+
+
+
tableRef.redirect(id),
formInitialData: {
+ payMethodFk: defaultPayMethod,
+ companyFk: user.companyFk,
isFreelance: false,
},
}"
:columns="columns"
default-mode="table"
redirect="worker"
+ :right-search="false"
auto-load
>
-
+
-
+
@@ -188,7 +229,7 @@ function uppercaseStreetModel(data) {
handleLocation(data, location)"
:disable="data.isFreelance"
>
@@ -253,6 +293,7 @@ function uppercaseStreetModel(data) {
v-model="data.iban"
:label="t('worker.create.iban')"
:disable="data.isFreelance"
+ @update:model-value="autofillBic(data)"
>
@@ -269,8 +310,10 @@ function uppercaseStreetModel(data) {
option-label="name"
option-value="id"
hide-selected
- :roles-allowed-to-create="['salesAssistant', 'hr']"
+ :acls="[{ model: 'BankEntity', props: '*', accessType: 'WRITE' }]"
:disable="data.isFreelance"
+ @update:model-value="autofillBic(data)"
+ :filter-options="['bic', 'name']"
>
-
+
route.name);
-const customRouteRedirectName = computed(() => {
- if (routeName.value === 'ZoneLocations') return null;
- return routeName.value;
-});
-const searchbarMakeFetch = computed(() => routeName.value !== 'ZoneEvents');
-const searchBarDataKeys = {
- ZoneWarehouses: 'ZoneWarehouses',
- ZoneSummary: 'ZoneSummary',
- ZoneLocations: 'ZoneLocations',
- ZoneEvents: 'ZoneEvents',
-};
+
+function notIsLocations(ifIsFalse, ifIsTrue) {
+ if (routeName.value != 'ZoneLocations') return ifIsFalse;
+ return ifIsTrue;
+}
-
-
-
-
+ />
diff --git a/src/pages/Zone/Card/ZoneDescriptorMenuItems.vue b/src/pages/Zone/Card/ZoneDescriptorMenuItems.vue
index 8f1168ce9..22d5bcd5e 100644
--- a/src/pages/Zone/Card/ZoneDescriptorMenuItems.vue
+++ b/src/pages/Zone/Card/ZoneDescriptorMenuItems.vue
@@ -8,13 +8,6 @@ import VnConfirm from 'components/ui/VnConfirm.vue';
import axios from 'axios';
-const $props = defineProps({
- zone: {
- type: Object,
- default: () => {},
- },
-});
-
const { t } = useI18n();
const { push, currentRoute } = useRouter();
const zoneId = currentRoute.value.params.id;
@@ -22,32 +15,21 @@ const zoneId = currentRoute.value.params.id;
const actions = {
clone: async () => {
const opts = { message: t('Zone cloned'), type: 'positive' };
- let clonedZoneId;
try {
- const { data } = await axios.post(`Zones/${zoneId}/clone`, {
- shipped: $props.zone.value.shipped,
- });
- clonedZoneId = data;
+ const { data } = await axios.post(`Zones/${zoneId}/clone`, {});
+ notify(opts);
+ push(`/zone/${data.id}/basic-data`);
} catch (e) {
opts.message = t('It was not able to clone the zone');
opts.type = 'negative';
- } finally {
- notify(opts);
-
- if (clonedZoneId) push({ name: 'ZoneSummary', params: { id: clonedZoneId } });
}
},
remove: async () => {
try {
- await axios.post(`Zones/${zoneId}/setDeleted`);
+ await axios.post(`Zones/${zoneId}/deleteZone`);
notify({ message: t('Zone deleted'), type: 'positive' });
- notify({
- message: t('You can undo this action within the first hour'),
- icon: 'info',
- });
-
push({ name: 'ZoneList' });
} catch (e) {
notify({ message: e.message, type: 'negative' });
@@ -64,30 +46,31 @@ function openConfirmDialog(callback) {
}
-
-
-
-
- {{ t('To clone zone') }}
-
{{ t('deleteZone') }}
+
+
+
+
+ {{ t('cloneZone') }}
+
en:
- deleteZone: Delete zone
+ deleteZone: Delete
+ cloneZone: Clone
confirmDeletion: Confirm deletion
confirmDeletionMessage: Are you sure you want to delete this zone?
es:
- To clone zone: Clonar zone
- deleteZone: Eliminar zona
+ cloneZone: Clonar
+ deleteZone: Eliminar
confirmDeletion: Confirmar eliminación
confirmDeletionMessage: Seguro que quieres eliminar este zona?
-
+ Zone deleted: Zona eliminada
diff --git a/src/pages/Zone/Card/ZoneEventExclusionForm.vue b/src/pages/Zone/Card/ZoneEventExclusionForm.vue
index 721f4bbc3..0ba2e640a 100644
--- a/src/pages/Zone/Card/ZoneEventExclusionForm.vue
+++ b/src/pages/Zone/Card/ZoneEventExclusionForm.vue
@@ -58,20 +58,12 @@ const arrayData = useArrayData('ZoneEvents');
const exclusionGeoCreate = async () => {
try {
- if (isNew.value) {
- const params = {
- zoneFk: parseInt(route.params.id),
- date: dated.value,
- geoIds: tickedNodes.value,
- };
- await axios.post('Zones/exclusionGeo', params);
- } else {
- const params = {
- zoneExclusionFk: props.event?.zoneExclusionFk,
- geoIds: tickedNodes.value,
- };
- await axios.post('Zones/updateExclusionGeo', params);
- }
+ const params = {
+ zoneFk: parseInt(route.params.id),
+ date: dated.value,
+ geoIds: tickedNodes.value,
+ };
+ await axios.post('Zones/exclusionGeo', params);
await refetchEvents();
} catch (err) {
console.error('Error creating exclusion geo: ', err);
@@ -85,7 +77,7 @@ const exclusionCreate = async () => {
{ dated: dated.value },
]);
else
- await axios.put(`Zones/${route.params.id}/exclusions/${props.event?.id}`, {
+ await axios.post(`Zones/${route.params.id}/exclusions`, {
dated: dated.value,
});
@@ -103,8 +95,7 @@ const onSubmit = async () => {
const deleteEvent = async () => {
try {
if (!props.event) return;
- const exclusionId = props.event?.zoneExclusionFk || props.event?.id;
- await axios.delete(`Zones/${route.params.id}/exclusions/${exclusionId}`);
+ await axios.delete(`Zones/${route.params.id}/exclusions`);
await refetchEvents();
} catch (err) {
console.error('Error deleting event: ', err);
@@ -141,7 +132,11 @@ onMounted(() => {
>
-
+
(stateStore.rightDrawer = false));
@click="stateStore.toggleRightDrawer()"
round
dense
- icon="menu"
+ icon="dock_to_left"
>
{{ t('globals.collapseMenu') }}
@@ -102,6 +102,7 @@ onUnmounted(() => (stateStore.rightDrawer = false));
color="primary"
fab
icon="add"
+ shortcut="+"
/>
{{ t('eventsInclusionForm.addEvent') }}
diff --git a/src/pages/Zone/Card/ZoneLocationsTree.vue b/src/pages/Zone/Card/ZoneLocationsTree.vue
index 70384a1bb..cb1508ed6 100644
--- a/src/pages/Zone/Card/ZoneLocationsTree.vue
+++ b/src/pages/Zone/Card/ZoneLocationsTree.vue
@@ -1,10 +1,7 @@
-
-
-
-
-
{
agencyModeFk: value,
};
case 'search':
- if (value) {
- if (!isNaN(value)) {
- return { id: value };
- } else {
- return {
- name: {
- like: `%${value}%`,
- },
- };
- }
- }
+ return /^\d+$/.test(value) ? { id: value } : { name: { like: `%${value}%` } };
}
};
-
+
{{ t('warehouses.add') }}
diff --git a/src/pages/Zone/Delivery/ZoneDeliveryList.vue b/src/pages/Zone/Delivery/ZoneDeliveryList.vue
index ca87dbd84..975cbdb67 100644
--- a/src/pages/Zone/Delivery/ZoneDeliveryList.vue
+++ b/src/pages/Zone/Delivery/ZoneDeliveryList.vue
@@ -74,7 +74,7 @@ async function remove(row) {
-
+
diff --git a/src/pages/Zone/Upcoming/ZoneUpcomingList.vue b/src/pages/Zone/Upcoming/ZoneUpcomingList.vue
index 89e53132e..5a7f0bb4c 100644
--- a/src/pages/Zone/Upcoming/ZoneUpcomingList.vue
+++ b/src/pages/Zone/Upcoming/ZoneUpcomingList.vue
@@ -74,7 +74,7 @@ async function remove(row) {
-
+
diff --git a/src/pages/Zone/ZoneDeliveryPanel.vue b/src/pages/Zone/ZoneDeliveryPanel.vue
index 03f534701..d6c96b935 100644
--- a/src/pages/Zone/ZoneDeliveryPanel.vue
+++ b/src/pages/Zone/ZoneDeliveryPanel.vue
@@ -1,47 +1,25 @@
+ {
+ Object.entries(deliveryMethodsConfig).forEach(([key, value]) => {
+ deliveryMethods[key] = data
+ .filter((code) => value.includes(code.code))
+ .map((method) => method.id);
+ });
+ inq = {
+ deliveryMethodFk: { inq: deliveryMethods[deliveryMethodFk] },
+ };
+ }
+ "
+ auto-load
+ />
{
:label="t('deliveryPanel.postcode')"
v-model="formData.geoFk"
url="Postcodes/location"
- :fields="['geoFk', 'code', 'townFk']"
+ :fields="['geoFk', 'code', 'townFk', 'countryFk']"
sort-by="code, townFk"
option-value="geoFk"
option-label="code"
@@ -106,26 +108,35 @@ onMounted(async () => {
{{ opt.code }}
{{ opt.town?.province?.name }},
- {{ opt.town?.province?.country?.country }}
+
diff --git a/src/pages/Zone/ZoneList.vue b/src/pages/Zone/ZoneList.vue
index 0272292f6..d160ea6b5 100644
--- a/src/pages/Zone/ZoneList.vue
+++ b/src/pages/Zone/ZoneList.vue
@@ -1,74 +1,120 @@
@@ -91,82 +138,72 @@ onMounted(() => (stateStore.rightDrawer = true));
-
+
-
-
-
-
-
-
-
-
-
- {{ t(col.label) }}
- {{
- col.tooltip
- }}
-
-
-
-
-
-
-
- {{ props.value }}
-
-
-
-
-
-
- {{ t('globals.clone') }}
-
-
- {{ t('Preview') }}
-
-
-
-
-
-
-
-
-
-
- {{ t('list.create') }}
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+es:
+ Search zone: Buscar zona
+ You can search zones by id or name: Puedes buscar zonas por id o nombre
+
diff --git a/src/pages/Zone/locale/en.yml b/src/pages/Zone/locale/en.yml
index 31eeb2b7f..2608c071c 100644
--- a/src/pages/Zone/locale/en.yml
+++ b/src/pages/Zone/locale/en.yml
@@ -18,9 +18,16 @@ list:
create: Create zone
openSummary: Details
searchZone: Search zones
+ searchLocation: Search locations
searchInfo: Search zone by id or name
confirmCloneTitle: All it's properties will be copied
confirmCloneSubtitle: Do you want to clone this zone?
+ travelingDays: Traveling days
+ warehouse: Warehouse
+ bonus: Bonus
+ isVolumetric: Volumetric
+ createZone: Create zone
+ zoneSummary: Summary
create:
name: Name
warehouse: Warehouse
@@ -30,6 +37,8 @@ create:
price: Price
bonus: Bonus
volumetric: Volumetric
+ itemMaxSize: Max m³
+ inflation: Inflation
summary:
agency: Agency
price: Price
diff --git a/src/pages/Zone/locale/es.yml b/src/pages/Zone/locale/es.yml
index c670c2c08..dd919a0c5 100644
--- a/src/pages/Zone/locale/es.yml
+++ b/src/pages/Zone/locale/es.yml
@@ -18,9 +18,16 @@ list:
create: Crear zona
openSummary: Detalles
searchZone: Buscar zonas
+ searchLocation: Buscar localizaciones
searchInfo: Buscar zonas por identificador o nombre
confirmCloneTitle: Todas sus propiedades serán copiadas
confirmCloneSubtitle: ¿Seguro que quieres clonar esta zona?
+ travelingDays: Días de viaje
+ warehouse: Almacén
+ bonus: Bonus
+ isVolumetric: Volumétrico
+ createZone: Crear zona
+ zoneSummary: Resumen
create:
name: Nombre
warehouse: Almacén
@@ -30,6 +37,8 @@ create:
price: Precio
bonus: Bonificación
volumetric: Volumétrico
+ itemMaxSize: Medida máxima
+ inflation: Inflación
summary:
agency: Agencia
price: Precio
diff --git a/src/router/index.js b/src/router/index.js
index 686da2dde..18541c0b2 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -60,15 +60,12 @@ export default route(function (/* { store, ssrContext } */) {
await useTokenConfig().fetch();
}
const matches = to.matched;
- const hasRequiredRoles = matches.every((route) => {
+ const hasRequiredAcls = matches.every((route) => {
const meta = route.meta;
- if (meta && meta.roles) return useRole().hasAny(meta.roles);
- return true;
+ if (!meta?.acls) return true;
+ return useAcl().hasAny(meta.acls);
});
-
- if (!hasRequiredRoles) {
- return next({ path: '/' });
- }
+ if (!hasRequiredAcls) return next({ path: '/' });
}
next();
diff --git a/src/router/modules/Supplier.js b/src/router/modules/Supplier.js
index b711066b2..143d7c824 100644
--- a/src/router/modules/Supplier.js
+++ b/src/router/modules/Supplier.js
@@ -7,6 +7,7 @@ export default {
title: 'suppliers',
icon: 'vn:supplier',
moduleName: 'Supplier',
+ keyBinding: 'p',
},
component: RouterView,
redirect: { name: 'SupplierMain' },
diff --git a/src/router/modules/account.js b/src/router/modules/account.js
index cfec2b95d..7200131da 100644
--- a/src/router/modules/account.js
+++ b/src/router/modules/account.js
@@ -7,6 +7,7 @@ export default {
title: 'users',
icon: 'face',
moduleName: 'Account',
+ keyBinding: 'u',
},
component: RouterView,
redirect: { name: 'AccountMain' },
@@ -79,7 +80,7 @@ export default {
meta: {
title: 'accounts',
icon: 'accessibility',
- roles: ['itManagement'],
+ acls: [{ model: 'Account', props: '*', accessType: '*' }],
},
component: () => import('src/pages/Account/AccountAccounts.vue'),
},
@@ -89,7 +90,7 @@ export default {
meta: {
title: 'ldap',
icon: 'account_tree',
- roles: ['itManagement'],
+ acls: [{ model: 'LdapConfig', props: '*', accessType: '*' }],
},
component: () => import('src/pages/Account/AccountLdap.vue'),
},
@@ -99,7 +100,7 @@ export default {
meta: {
title: 'samba',
icon: 'preview',
- roles: ['itManagement'],
+ acls: [{ model: 'SambaConfig', props: '*', accessType: '*' }],
},
component: () => import('src/pages/Account/AccountSamba.vue'),
},
diff --git a/src/router/modules/claim.js b/src/router/modules/claim.js
index cced9e24d..b58a58e8d 100644
--- a/src/router/modules/claim.js
+++ b/src/router/modules/claim.js
@@ -7,6 +7,7 @@ export default {
title: 'claims',
icon: 'vn:claims',
moduleName: 'Claim',
+ keyBinding: 'r',
},
component: RouterView,
redirect: { name: 'ClaimMain' },
@@ -61,7 +62,7 @@ export default {
meta: {
title: 'basicData',
icon: 'vn:settings',
- roles: ['salesPerson'],
+ acls: [{ model: 'Claim', props: 'findById', accessType: 'READ' }],
},
component: () => import('src/pages/Claim/Card/ClaimBasicData.vue'),
},
@@ -98,7 +99,13 @@ export default {
meta: {
title: 'development',
icon: 'vn:traceability',
- roles: ['claimManager'],
+ acls: [
+ {
+ model: 'ClaimDevelopment',
+ props: '*',
+ accessType: 'WRITE',
+ },
+ ],
},
component: () => import('src/pages/Claim/Card/ClaimDevelopment.vue'),
},
diff --git a/src/router/modules/customer.js b/src/router/modules/customer.js
index 684b83b0f..1b707f1a2 100644
--- a/src/router/modules/customer.js
+++ b/src/router/modules/customer.js
@@ -7,6 +7,7 @@ export default {
title: 'customers',
icon: 'vn:client',
moduleName: 'Customer',
+ keyBinding: 'c',
},
component: RouterView,
redirect: { name: 'CustomerMain' },
@@ -174,7 +175,7 @@ export default {
path: 'edit',
name: 'CustomerAddressEdit',
meta: {
- title: 'address-edit',
+ title: 'addressEdit',
},
component: () =>
import(
diff --git a/src/router/modules/entry.js b/src/router/modules/entry.js
index 0d38ed626..4750a4301 100644
--- a/src/router/modules/entry.js
+++ b/src/router/modules/entry.js
@@ -7,11 +7,12 @@ export default {
title: 'entries',
icon: 'vn:entry',
moduleName: 'Entry',
+ keyBinding: 'e',
},
component: RouterView,
redirect: { name: 'EntryMain' },
menus: {
- main: ['EntryList', 'MyEntries', 'EntryLatestBuys'],
+ main: ['EntryList', 'MyEntries', 'EntryLatestBuys', 'EntryStockBought'],
card: ['EntryBasicData', 'EntryBuys', 'EntryNotes', 'EntryDms', 'EntryLog'],
},
children: [
@@ -57,6 +58,15 @@ export default {
},
component: () => import('src/pages/Entry/EntryLatestBuys.vue'),
},
+ {
+ path: 'stock-Bought',
+ name: 'EntryStockBought',
+ meta: {
+ title: 'reserves',
+ icon: 'deployed_code_history',
+ },
+ component: () => import('src/pages/Entry/EntryStockBought.vue'),
+ },
],
},
{
diff --git a/src/router/modules/invoiceIn.js b/src/router/modules/invoiceIn.js
index cd8f7de9c..168d64f37 100644
--- a/src/router/modules/invoiceIn.js
+++ b/src/router/modules/invoiceIn.js
@@ -1,5 +1,5 @@
import { RouterView } from 'vue-router';
-
+import { setRectificative } from 'src/pages/InvoiceIn/composables/setRectificative';
export default {
path: '/invoice-in',
name: 'InvoiceIn',
@@ -11,7 +11,7 @@ export default {
component: RouterView,
redirect: { name: 'InvoiceInMain' },
menus: {
- main: ['InvoiceInList'],
+ main: ['InvoiceInList', 'InvoiceInSerial'],
card: [
'InvoiceInBasicData',
'InvoiceInVat',
@@ -37,6 +37,16 @@ export default {
},
component: () => import('src/pages/InvoiceIn/InvoiceInList.vue'),
},
+ {
+ path: 'serial',
+ name: 'InvoiceInSerial',
+ meta: {
+ title: 'serial',
+ icon: 'view_list',
+ },
+ component: () =>
+ import('src/pages/InvoiceIn/Serial/InvoiceInSerial.vue'),
+ },
{
path: 'create',
name: 'InvoiceInCreare',
@@ -53,6 +63,10 @@ export default {
path: ':id',
component: () => import('src/pages/InvoiceIn/Card/InvoiceInCard.vue'),
redirect: { name: 'InvoiceInSummary' },
+ beforeEnter: async (to, from, next) => {
+ await setRectificative(to);
+ next();
+ },
children: [
{
name: 'InvoiceInSummary',
@@ -70,7 +84,6 @@ export default {
meta: {
title: 'basicData',
icon: 'vn:settings',
- roles: ['salesPerson'],
},
component: () =>
import('src/pages/InvoiceIn/Card/InvoiceInBasicData.vue'),
diff --git a/src/router/modules/item.js b/src/router/modules/item.js
index 4bd5df4e2..48e19dd54 100644
--- a/src/router/modules/item.js
+++ b/src/router/modules/item.js
@@ -7,6 +7,7 @@ export default {
title: 'items',
icon: 'vn:item',
moduleName: 'Item',
+ keyBinding: 'a',
},
component: RouterView,
redirect: { name: 'ItemMain' },
diff --git a/src/router/modules/monitor.js b/src/router/modules/monitor.js
index f0db8d3f3..7342a5904 100644
--- a/src/router/modules/monitor.js
+++ b/src/router/modules/monitor.js
@@ -7,11 +7,12 @@ export default {
title: 'monitors',
icon: 'grid_view',
moduleName: 'Monitor',
+ keyBinding: 'm',
},
component: RouterView,
redirect: { name: 'MonitorMain' },
menus: {
- main: ['MonitorList'],
+ main: ['MonitorTickets', 'MonitorClientsActions'],
card: [],
},
children: [
@@ -19,16 +20,27 @@ export default {
path: '',
name: 'MonitorMain',
component: () => import('src/components/common/VnSectionMain.vue'),
- redirect: { name: 'MonitorList' },
+ redirect: { name: 'MonitorTickets' },
children: [
{
- path: 'list',
- name: 'MonitorList',
+ path: 'tickets',
+ name: 'MonitorTickets',
meta: {
- title: 'list',
- icon: 'grid_view',
+ title: 'ticketsMonitor',
+ icon: 'vn:ticket',
},
- component: () => import('src/pages/Monitor/MonitorList.vue'),
+ component: () =>
+ import('src/pages/Monitor/Ticket/MonitorTickets.vue'),
+ },
+ {
+ path: 'clients-actions',
+ name: 'MonitorClientsActions',
+ meta: {
+ title: 'clientsActionsMonitor',
+ icon: 'vn:client',
+ },
+ component: () =>
+ import('src/pages/Monitor/MonitorClientsActions.vue'),
},
],
},
diff --git a/src/router/modules/order.js b/src/router/modules/order.js
index a2b874cc6..bfa37fce5 100644
--- a/src/router/modules/order.js
+++ b/src/router/modules/order.js
@@ -7,6 +7,7 @@ export default {
title: 'order',
icon: 'vn:basket',
moduleName: 'Order',
+ keyBinding: 'o',
},
component: RouterView,
redirect: { name: 'OrderMain' },
@@ -63,7 +64,7 @@ export default {
title: 'basicData',
icon: 'vn:settings',
},
- component: () => import('src/pages/Order/Card/OrderForm.vue'),
+ component: () => import('src/pages/Order/Card/OrderBasicData.vue'),
},
{
name: 'OrderCatalog',
@@ -72,7 +73,7 @@ export default {
title: 'catalog',
icon: 'vn:basket',
},
- component: () => import('src/pages/Order/OrderCatalog.vue'),
+ component: () => import('src/pages/Order/Card/OrderCatalog.vue'),
},
{
name: 'OrderVolume',
@@ -81,7 +82,7 @@ export default {
title: 'volume',
icon: 'vn:volume',
},
- component: () => import('src/pages/Order/OrderVolume.vue'),
+ component: () => import('src/pages/Order/Card/OrderVolume.vue'),
},
{
name: 'OrderLines',
@@ -90,7 +91,7 @@ export default {
title: 'lines',
icon: 'vn:lines',
},
- component: () => import('src/pages/Order/OrderLines.vue'),
+ component: () => import('src/pages/Order/Card/OrderLines.vue'),
},
],
},
diff --git a/src/router/modules/shelving.js b/src/router/modules/shelving.js
index 70145dfb4..b7f50a3b6 100644
--- a/src/router/modules/shelving.js
+++ b/src/router/modules/shelving.js
@@ -76,7 +76,6 @@ export default {
meta: {
title: 'basicData',
icon: 'vn:settings',
- roles: ['salesPerson'],
},
component: () => import('pages/Shelving/Card/ShelvingForm.vue'),
},
diff --git a/src/router/modules/ticket.js b/src/router/modules/ticket.js
index 4074f089f..dcc238f95 100644
--- a/src/router/modules/ticket.js
+++ b/src/router/modules/ticket.js
@@ -7,6 +7,7 @@ export default {
title: 'tickets',
icon: 'vn:ticket',
moduleName: 'Ticket',
+ keyBinding: 't',
},
component: RouterView,
redirect: { name: 'TicketMain' },
@@ -53,7 +54,6 @@ export default {
meta: {
title: 'createTicket',
icon: 'vn:ticketAdd',
- roles: ['developer'],
},
component: () => import('src/pages/Ticket/TicketCreate.vue'),
},
diff --git a/src/router/modules/wagon.js b/src/router/modules/wagon.js
index d3d14a888..e25e585eb 100644
--- a/src/router/modules/wagon.js
+++ b/src/router/modules/wagon.js
@@ -11,7 +11,7 @@ export default {
component: RouterView,
redirect: { name: 'WagonMain' },
menus: {
- main: ['WagonList', 'WagonTypeList', 'WagonCounter'],
+ main: ['WagonList', 'WagonTypeList', 'WagonCounter', 'WagonTray'],
card: [],
},
children: [
@@ -81,7 +81,7 @@ export default {
title: 'typeCreate',
icon: 'create',
},
- component: () => import('src/pages/Wagon/Type/WagonTypeCreate.vue'),
+ component: () => import('src/pages/Wagon/Type/WagonTypeList.vue'),
},
{
path: ':id/edit',
@@ -90,7 +90,7 @@ export default {
title: 'typeEdit',
icon: 'edit',
},
- component: () => import('src/pages/Wagon/Type/WagonTypeCreate.vue'),
+ component: () => import('src/pages/Wagon/Type/WagonTypeEdit.vue'),
},
],
},
diff --git a/src/router/modules/worker.js b/src/router/modules/worker.js
index f80df5e06..b2716474b 100644
--- a/src/router/modules/worker.js
+++ b/src/router/modules/worker.js
@@ -7,6 +7,7 @@ export default {
title: 'workers',
icon: 'vn:worker',
moduleName: 'Worker',
+ keyBinding: 'w',
},
component: RouterView,
redirect: { name: 'WorkerMain' },
@@ -25,6 +26,7 @@ export default {
'WorkerLocker',
'WorkerBalance',
'WorkerFormation',
+ 'WorkerMedical',
],
},
children: [
@@ -196,6 +198,15 @@ export default {
},
component: () => import('src/pages/Worker/Card/WorkerFormation.vue'),
},
+ {
+ name: 'WorkerMedical',
+ path: 'medical',
+ meta: {
+ title: 'medical',
+ icon: 'medical_information',
+ },
+ component: () => import('src/pages/Worker/Card/WorkerMedical.vue'),
+ },
],
},
],
diff --git a/src/router/modules/zone.js b/src/router/modules/zone.js
index 889b47464..1f27cc76f 100644
--- a/src/router/modules/zone.js
+++ b/src/router/modules/zone.js
@@ -7,6 +7,7 @@ export default {
title: 'zones',
icon: 'vn:zone',
moduleName: 'Zone',
+ keyBinding: 'z',
},
component: RouterView,
redirect: { name: 'ZoneMain' },
@@ -50,33 +51,6 @@ export default {
},
component: () => import('src/pages/Zone/ZoneDeliveryDays.vue'),
},
- {
- path: 'create',
- name: 'ZoneCreate',
- meta: {
- title: 'zoneCreate',
- icon: 'create',
- },
- component: () => import('src/pages/Zone/ZoneCreate.vue'),
- },
- {
- path: ':id/edit',
- name: 'ZoneEdit',
- meta: {
- title: 'zoneEdit',
- icon: 'edit',
- },
- component: () => import('src/pages/Zone/ZoneCreate.vue'),
- },
- // {
- // path: 'counter',
- // name: 'ZoneCounter',
- // meta: {
- // title: 'zoneCounter',
- // icon: 'add_circle',
- // },
- // component: () => import('src/pages/Zone/ZoneCounter.vue'),
- // },
{
name: 'ZoneUpcomingDeliveries',
path: 'upcoming-deliveries',
diff --git a/src/stores/invoiceOutGlobal.js b/src/stores/invoiceOutGlobal.js
index bb9a3d376..42acac013 100644
--- a/src/stores/invoiceOutGlobal.js
+++ b/src/stores/invoiceOutGlobal.js
@@ -19,6 +19,7 @@ export const useInvoiceOutGlobalStore = defineStore({
maxShipped: null,
clientId: null,
printer: null,
+ serialType: null,
},
addresses: [],
minInvoicingDate: null,
@@ -100,6 +101,7 @@ export const useInvoiceOutGlobalStore = defineStore({
maxShipped: new Date(formData.maxShipped),
clientId: formData.clientId ? formData.clientId : null,
companyFk: formData.companyFk,
+ serialType: formData.serialType,
};
this.validateMakeInvoceParams(params, clientsToInvoice);
@@ -152,7 +154,13 @@ export const useInvoiceOutGlobalStore = defineStore({
);
throw new Error('Invoice date in the future');
}
-
+ if (!params.serialType) {
+ notify(
+ 'invoiceOut.globalInvoices.errors.chooseValidSerialType',
+ 'negative'
+ );
+ throw new Error('Invalid Serial Type');
+ }
if (!params.companyFk) {
notify('invoiceOut.globalInvoices.errors.chooseValidCompany', 'negative');
throw new Error('Invalid company');
@@ -180,6 +188,7 @@ export const useInvoiceOutGlobalStore = defineStore({
invoiceDate: new Date(formData.invoiceDate),
maxShipped: new Date(formData.maxShipped),
companyFk: formData.companyFk,
+ serialType: formData.serialType,
};
this.status = 'invoicing';
@@ -191,12 +200,7 @@ export const useInvoiceOutGlobalStore = defineStore({
this.addressIndex++;
this.isInvoicing = false;
} catch (err) {
- if (
- err &&
- err.response &&
- err.response.status >= 400 &&
- err.response.status < 500
- ) {
+ if (err?.response?.status >= 400 && err?.response?.status < 500) {
this.invoiceClientError(address, err.response?.data?.error?.message);
return;
} else {
@@ -243,7 +247,7 @@ export const useInvoiceOutGlobalStore = defineStore({
params,
});
- if (data.data && data.data.error) throw new Error();
+ if (data?.data?.error) throw new Error();
const status = exportFile('negativeBases.csv', data, {
encoding: 'windows-1252',
diff --git a/src/stores/useNavigationStore.js b/src/stores/useNavigationStore.js
index 961e80377..4a819bf19 100644
--- a/src/stores/useNavigationStore.js
+++ b/src/stores/useNavigationStore.js
@@ -2,7 +2,7 @@ import axios from 'axios';
import { ref } from 'vue';
import { defineStore } from 'pinia';
import { toLowerCamel } from 'src/filters';
-import { useRole } from 'src/composables/useRole';
+import { useAcl } from 'src/composables/useAcl';
import routes from 'src/router/modules';
export const useNavigationStore = defineStore('navigationStore', () => {
@@ -26,7 +26,7 @@ export const useNavigationStore = defineStore('navigationStore', () => {
'zone',
];
const pinnedModules = ref([]);
- const role = useRole();
+ const acl = useAcl();
function getModules() {
const modulesRoutes = ref([]);
@@ -56,6 +56,7 @@ export const useNavigationStore = defineStore('navigationStore', () => {
function addMenuItem(module, route, parent) {
const { meta } = route;
let { menuChildren = null } = meta;
+ if (meta.hidden) return;
if (menuChildren)
menuChildren = menuChildren.map(({ name, title, icon }) => ({
name,
@@ -63,7 +64,7 @@ export const useNavigationStore = defineStore('navigationStore', () => {
title: `globals.pageTitles.${title}`,
}));
- if (meta && meta.roles && role.hasAny(meta.roles) === false) return;
+ if (meta && meta.acls && acl.hasAny(meta.acls) === false) return;
const item = {
name: route.name,
@@ -72,6 +73,7 @@ export const useNavigationStore = defineStore('navigationStore', () => {
if (meta) {
item.title = `globals.pageTitles.${meta.title}`;
item.icon = meta.icon;
+ item.keyBinding = meta.keyBinding;
}
parent.push(item);
diff --git a/test/cypress/integration/claim/claimDevelopment.spec.js b/test/cypress/integration/claim/claimDevelopment.spec.js
index 903f58d4b..3b73a24d9 100755
--- a/test/cypress/integration/claim/claimDevelopment.spec.js
+++ b/test/cypress/integration/claim/claimDevelopment.spec.js
@@ -8,6 +8,8 @@ describe('ClaimDevelopment', () => {
cy.viewport(1920, 1080);
cy.login('developer');
cy.visit(`/#/claim/${claimId}/development`);
+ cy.intercept('GET', /\/api\/Workers\/search/).as('workers');
+ cy.intercept('GET', /\/api\/Workers\/search/).as('workers');
cy.waitForElement('tbody');
});
@@ -32,10 +34,19 @@ describe('ClaimDevelopment', () => {
});
it('should add and remove new line', () => {
+ cy.wait(['@workers', '@workers']);
cy.addCard();
+
cy.get(thirdRow).should('exist');
- const rowData = [false, 'Novato', 'Roces', 'Compradores', 'employeeNick', 'Tour'];
+ const rowData = [
+ false,
+ 'Novato',
+ 'Roces',
+ 'Compradores',
+ 'administrativeNick',
+ 'Tour',
+ ];
cy.fillRow(thirdRow, rowData);
cy.saveCard();
diff --git a/test/cypress/integration/entry/entryDms.spec.js b/test/cypress/integration/entry/entryDms.spec.js
index ed4a3d79c..47dcdba9e 100644
--- a/test/cypress/integration/entry/entryDms.spec.js
+++ b/test/cypress/integration/entry/entryDms.spec.js
@@ -23,7 +23,7 @@ describe('EntryDms', () => {
expect(value).to.have.length(newFileTd++);
const newRowSelector = `tbody > :nth-child(${newFileTd})`;
cy.waitForElement(newRowSelector);
- cy.validateRow(newRowSelector, [u, u, u, u, 'ENTRADA ID 1']);
+ cy.validateRow(newRowSelector, [u, u, u, u, u, 'ENTRADA ID 1']);
//Edit new dms
const newDescription = 'entry id 1 modified';
@@ -38,7 +38,7 @@ describe('EntryDms', () => {
cy.saveCard();
cy.reload();
- cy.validateRow(newRowSelector, [u, u, u, u, newDescription]);
+ cy.validateRow(newRowSelector, [u, u, u, u, u, newDescription]);
});
});
});
diff --git a/test/cypress/integration/entry/stockBought.spec.js b/test/cypress/integration/entry/stockBought.spec.js
new file mode 100644
index 000000000..b93afa520
--- /dev/null
+++ b/test/cypress/integration/entry/stockBought.spec.js
@@ -0,0 +1,41 @@
+describe('EntryStockBought', () => {
+ beforeEach(() => {
+ cy.viewport(1920, 1080);
+ cy.login('buyer');
+ cy.visit(`/#/entry/stock-Bought`);
+ });
+ it('Should edit the reserved space', () => {
+ cy.get('.q-field__native.q-placeholder').should('have.value', '01/01/2001');
+ cy.get('tBody > tr').its('length').should('eq', 2);
+ cy.get('input[name="reserve"]').type('10{enter}');
+ cy.get('button[title="Save"]').click();
+ cy.get('.q-notification__message').should('have.text', 'Data saved');
+ });
+ it('Should add a new reserved space for buyerBoss', () => {
+ cy.get('.q-page-sticky > div > .q-btn > .q-btn__content > .q-icon').click();
+ cy.get('input[aria-label="Reserve"]').type('1');
+ cy.get('input[aria-label="Date"]').eq(1).clear();
+ cy.get('input[aria-label="Date"]').eq(1).type('01-01');
+ cy.get('input[aria-label="Buyer"]').type('buyerboss{downarrow}{enter}');
+ cy.get('.q-notification__message').should('have.text', 'Data created');
+ cy.get('tBody > tr').its('length').should('eq', 3);
+ });
+ it('Should check detail for the buyer', () => {
+ cy.get(':nth-child(1) > .sticky > .q-btn > .q-btn__content > .q-icon').click();
+ cy.get('tBody > tr').eq(1).its('length').should('eq', 1);
+ });
+ it('Should check detail for the buyerBoss and had no content', () => {
+ cy.get(':nth-child(2) > .sticky > .q-btn > .q-btn__content > .q-icon').click();
+ cy.get('.q-table__bottom.row.items-center.q-table__bottom--nodata').should(
+ 'have.text',
+ 'warningNo data available'
+ );
+ });
+ it('Should edit travel m3 and refresh', () => {
+ cy.get('.vn-row > div > .q-btn > .q-btn__content > .q-icon').click();
+ cy.get('input[aria-label="m3"]').clear();
+ cy.get('input[aria-label="m3"]').type('60');
+ cy.get('.q-mt-lg > .q-btn--standard > .q-btn__content > .block').click();
+ cy.get('.vn-row > div > :nth-child(2)').should('have.text', '60');
+ });
+});
diff --git a/test/cypress/integration/invoiceIn/invoiceInBasicData.spec.js b/test/cypress/integration/invoiceIn/invoiceInBasicData.spec.js
index 77a11969b..e1939fe5a 100644
--- a/test/cypress/integration/invoiceIn/invoiceInBasicData.spec.js
+++ b/test/cypress/integration/invoiceIn/invoiceInBasicData.spec.js
@@ -36,8 +36,7 @@ describe('InvoiceInBasicData', () => {
});
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(5).type('{selectall}{backspace}');
+ cy.get(formInputs).eq(7).type('{selectall}{backspace}');
cy.get(documentBtns).eq(0).click();
cy.get(dialogActionBtns).eq(1).click();
cy.get('.q-notification__message').should(
diff --git a/test/cypress/integration/invoiceIn/invoiceInVat.spec.js b/test/cypress/integration/invoiceIn/invoiceInVat.spec.js
index 018ae7a53..b84d743d1 100644
--- a/test/cypress/integration/invoiceIn/invoiceInVat.spec.js
+++ b/test/cypress/integration/invoiceIn/invoiceInVat.spec.js
@@ -3,13 +3,14 @@ describe('InvoiceInVat', () => {
const thirdRow = 'tbody > :nth-child(3)';
const firstLineVat = 'tbody > :nth-child(1) > :nth-child(4)';
const dialogInputs = '.q-dialog label input';
- const dialogBtns = '.q-dialog button';
- const acrossInput = 'tbody tr:nth-child(1) td:nth-child(2) .default-icon';
+ const addBtn = 'tbody tr:nth-child(1) td:nth-child(2) .--add-icon';
const randomInt = Math.floor(Math.random() * 100);
beforeEach(() => {
cy.login('developer');
cy.visit(`/#/invoice-in/1/vat`);
+ cy.intercept('GET', '/api/InvoiceIns/1/getTotals').as('lastCall');
+ cy.wait('@lastCall');
});
it('should edit the sage iva', () => {
@@ -26,22 +27,15 @@ describe('InvoiceInVat', () => {
});
it('should remove the first line', () => {
- cy.removeRow(2);
- });
-
- 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");
+ cy.removeRow(1);
});
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(1).click();
cy.get(dialogInputs).eq(1).type('This is a dummy expense');
- cy.get(dialogBtns).eq(2).click();
- cy.get('.q-notification__message').should('have.text', 'Data saved');
+ cy.get('button[type="submit"]').click();
+ cy.get('.q-notification__message').should('have.text', 'Data created');
});
});
diff --git a/test/cypress/integration/outLogin/login.spec.js b/test/cypress/integration/outLogin/login.spec.js
index f8a9f5c64..3db223cdb 100755
--- a/test/cypress/integration/outLogin/login.spec.js
+++ b/test/cypress/integration/outLogin/login.spec.js
@@ -52,9 +52,9 @@ describe('Login', () => {
cy.url().should('contain', '/login');
});
- it(`should get redirected to dashboard since employee can't create tickets`, () => {
- cy.visit('/#/ticket/create', { failOnStatusCode: false });
- cy.url().should('contain', '/#/login?redirect=/ticket/create');
+ it(`should be redirected to dashboard since the employee is not enabled to see ldap`, () => {
+ cy.visit('/#/account/ldap', { failOnStatusCode: false });
+ cy.url().should('contain', '/#/login?redirect=/account/ldap');
cy.get('input[aria-label="Username"]').type('employee');
cy.get('input[aria-label="Password"]').type('nightmare');
cy.get('button[type="submit"]').click();
diff --git a/test/cypress/integration/route/routeList.spec.js b/test/cypress/integration/route/routeList.spec.js
index afc0fc395..c9d7147c2 100644
--- a/test/cypress/integration/route/routeList.spec.js
+++ b/test/cypress/integration/route/routeList.spec.js
@@ -10,12 +10,13 @@ describe('Route', () => {
it('Route list create route', () => {
cy.get('.q-page-sticky > div > .q-btn > .q-btn__content > .q-icon').click();
- cy.get('input[name="description"]').eq(1).type('routeTestOne{enter}');
+ cy.get('input[name="description"]').type('routeTestOne{enter}');
cy.get('.q-notification__message').should('have.text', 'Data created');
cy.url().should('include', '/summary');
});
it('Route list search and edit', () => {
+ cy.get('#searchbar input').type('{enter}');
cy.get('input[name="description"]').type('routeTestOne{enter}');
cy.get('.q-table tr')
.its('length')
diff --git a/test/cypress/integration/ticket/ticketDescriptor.spec.js b/test/cypress/integration/ticket/ticketDescriptor.spec.js
index fc920f346..8192b7c7c 100644
--- a/test/cypress/integration/ticket/ticketDescriptor.spec.js
+++ b/test/cypress/integration/ticket/ticketDescriptor.spec.js
@@ -1,22 +1,22 @@
///
describe('Ticket descriptor', () => {
const toCloneOpt = '[role="menu"] .q-list > :nth-child(5)';
+ const setWeightOpt = '[role="menu"] .q-list > :nth-child(6)';
const warehouseValue = ':nth-child(1) > :nth-child(6) > .value > span';
const summaryHeader = '.summaryHeader > div';
-
+ const weight = 25;
+ const weightValue = '.summaryBody.row :nth-child(1) > :nth-child(9) > .value > span';
beforeEach(() => {
- const ticketId = 1;
-
cy.login('developer');
- cy.visit(`/#/ticket/${ticketId}/summary`);
+ cy.viewport(1920, 1080);
});
it('should clone the ticket without warehouse', () => {
- cy.openLeftMenu();
+ cy.visit('/#/ticket/1/summary');
cy.openActionsDescriptor();
cy.get(toCloneOpt).click();
cy.clickConfirm();
- cy.get(warehouseValue).contains('-');
+ cy.get(warehouseValue).contains('Warehouse One');
cy.get(summaryHeader)
.invoke('text')
.then((text) => {
@@ -24,4 +24,15 @@ describe('Ticket descriptor', () => {
cy.wrap(owner.trim()).should('eq', 'Bruce Wayne (1101)');
});
});
+
+ it('should set the weight of the ticket', () => {
+ cy.visit('/#/ticket/10/summary');
+ cy.openActionsDescriptor();
+ cy.get(setWeightOpt).click();
+ cy.intercept('POST', /\/api\/Tickets\/\d+\/setWeight/).as('weight');
+ cy.get('.q-dialog input').type(weight);
+ cy.clickConfirm();
+ cy.wait('@weight');
+ cy.get(weightValue).contains(weight);
+ });
});
diff --git a/test/cypress/integration/vnComponent/VnShortcut.spec.js b/test/cypress/integration/vnComponent/VnShortcut.spec.js
new file mode 100644
index 000000000..b49b4e964
--- /dev/null
+++ b/test/cypress/integration/vnComponent/VnShortcut.spec.js
@@ -0,0 +1,33 @@
+///
+
+describe('VnShortcuts', () => {
+ const modules = {
+ item: 'a',
+ customer: 'c',
+ ticket: 't',
+ claim: 'r',
+ worker: 'w',
+ monitor: 'm',
+ order: 'o',
+ supplier: 'p',
+ entry: 'e',
+ zone: 'z',
+ account: 'u',
+ };
+ beforeEach(() => {
+ cy.login('developer');
+ cy.visit('/');
+ });
+
+ for (const [module, shortcut] of Object.entries(modules)) {
+ it(`should visit ${module} module`, () => {
+ cy.get('body').trigger('keydown', {
+ ctrlKey: true,
+ altKey: true,
+ code: `Key${shortcut.toUpperCase()}`,
+ });
+
+ cy.url().should('include', module);
+ });
+ }
+});
diff --git a/test/cypress/integration/vnComponent/vnLocation.spec.js b/test/cypress/integration/vnComponent/vnLocation.spec.js
index 30c1d6df2..3533a3c1f 100644
--- a/test/cypress/integration/vnComponent/vnLocation.spec.js
+++ b/test/cypress/integration/vnComponent/vnLocation.spec.js
@@ -18,7 +18,7 @@ describe('VnLocation', () => {
cy.get(inputLocation).click();
cy.get(inputLocation).clear();
cy.get(inputLocation).type('al');
- cy.get(locationOptions).should('have.length.at.least', 3);
+ cy.get(locationOptions).should('have.length.at.least', 4);
});
it('input filter location as "ecuador"', function () {
cy.get(inputLocation).click();
@@ -33,11 +33,29 @@ describe('VnLocation', () => {
cy.login('developer');
cy.visit('/#/supplier/567/fiscal-data', { timeout: 7000 });
cy.waitForElement('.q-form');
- cy.get(createLocationButton).click();
});
+ it('Fin by postalCode', () => {
+ const postCode = '46600';
+ const firstOption = '[role="listbox"] .q-item:nth-child(1)';
+
+ cy.get(inputLocation).click();
+ cy.get(inputLocation).clear();
+ cy.get(inputLocation).type(postCode);
+ cy.get(locationOptions).should('have.length.at.least', 2);
+ cy.get(firstOption).click();
+ cy.get('.q-btn-group > .q-btn--standard > .q-btn__content > .q-icon').click();
+ cy.reload();
+ cy.waitForElement('.q-form');
+ cy.get(inputLocation).should(
+ 'have.value',
+ '46600 - Valencia(Province one), España'
+ );
+ });
+
it('Create postCode', () => {
const postCode = '1234475';
const province = 'Valencia';
+ cy.get(createLocationButton).click();
cy.get('.q-card > h1').should('have.text', 'New postcode');
cy.get(dialogInputs).eq(0).clear();
cy.get(dialogInputs).eq(0).type(postCode);
@@ -54,6 +72,7 @@ describe('VnLocation', () => {
it('Create city', () => {
const postCode = '9011';
const province = 'Saskatchew';
+ cy.get(createLocationButton).click();
cy.get(dialogInputs).eq(0).type(postCode);
// city create button
cy.get(
diff --git a/test/cypress/integration/wagonType/wagonTypeCreate.spec.js b/test/cypress/integration/wagonType/wagonTypeCreate.spec.js
index bcf7fe841..cd7ffa58f 100644
--- a/test/cypress/integration/wagonType/wagonTypeCreate.spec.js
+++ b/test/cypress/integration/wagonType/wagonTypeCreate.spec.js
@@ -3,52 +3,15 @@ describe('WagonTypeCreate', () => {
cy.viewport(1920, 1080);
cy.login('developer');
cy.visit('/#/wagon/type/create');
+ cy.waitForElement('.q-page', 6000);
});
- function chooseColor(color) {
- cy.get('div.shelving-down').eq(1).click();
- cy.get('div.q-color-picker__cube').eq(color).click();
- cy.get('div.q-card__section').find('button').click();
- }
-
- function addTray(position) {
- cy.get('div.action-button').last().find('button').click();
- cy.focused().type(position);
- cy.focused().blur();
- }
-
- it('should create and delete a new wagon type', () => {
+ it('should create a new wagon type', () => {
+ cy.get('.q-page-sticky > div > .q-btn').click();
cy.get('input').first().type('Example for testing');
- cy.get('div.q-checkbox__bg').click();
- chooseColor(1);
-
- // Insert invalid position (not minimal height)
- addTray(20);
- cy.get('div[role="alert"]').should('exist');
- chooseColor(2);
- addTray(150);
- chooseColor(3);
- addTray(100);
-
- // Insert invalid position (max height reached)
- addTray(210);
- cy.get('div[role="alert"]').should('exist');
-
- // Save
cy.get('button[type="submit"]').click();
-
- // Check data has been saved successfully
- cy.get(':nth-child(1) > :nth-child(1) > .justify-between > .flex > .title')
- .contains('Example for testing')
- .click();
- cy.get('input').first().should('have.value', 'Example for testing');
- cy.get('div.wagon-tray').should('have.length', 4);
- cy.get('div.position').eq(0).find('input').should('have.value', '150');
- cy.get('div.position').eq(1).find('input').should('have.value', '100');
- cy.get('div.position').eq(2).find('input').should('have.value', '50');
-
- // Delete wagon type created
- cy.go('back');
+ });
+ it('delete a wagon type', () => {
cy.get(
':nth-child(2) > :nth-child(1) > .card-list-body > .actions > .q-btn--standard'
).click();
diff --git a/test/cypress/integration/wagonType/wagonTypeEdit.spec.js b/test/cypress/integration/wagonType/wagonTypeEdit.spec.js
new file mode 100644
index 000000000..6e5816e51
--- /dev/null
+++ b/test/cypress/integration/wagonType/wagonTypeEdit.spec.js
@@ -0,0 +1,27 @@
+describe('WagonTypeEdit', () => {
+ const trayColorRow =
+ '.q-select > .q-field__inner > .q-field__control > .q-field__control-container';
+ beforeEach(() => {
+ cy.viewport(1920, 1080);
+ cy.login('developer');
+ cy.visit('/#/wagon/type/2/edit');
+ });
+
+ it('should edit the name and the divisible field of the wagon type', () => {
+ cy.get('.q-card');
+ cy.get('input').first().type(' changed');
+ cy.get('div.q-checkbox__bg').first().click();
+ cy.get('.q-btn--standard').click();
+ });
+
+ it('should create a tray', () => {
+ cy.get('.action-button > .q-btn > .q-btn__content > .q-icon').click();
+ cy.get('input').last().type('150');
+ cy.get(trayColorRow).type('{downArrow}{downArrow}{enter}');
+ });
+
+ it('should delete a tray', () => {
+ cy.get('.action-button > .q-btn > .q-btn__content > .q-icon').first().click();
+ cy.reload();
+ });
+});
diff --git a/test/cypress/integration/worker/workerCreate.spec.js b/test/cypress/integration/worker/workerCreate.spec.js
index c1832ad67..50afe1892 100644
--- a/test/cypress/integration/worker/workerCreate.spec.js
+++ b/test/cypress/integration/worker/workerCreate.spec.js
@@ -2,6 +2,9 @@ describe('WorkerCreate', () => {
const externalRadio = '.q-radio:nth-child(2)';
const notification = '.q-notification__message';
const developerBossId = 120;
+ const payMethodCross =
+ '.grid-create .full-width > :nth-child(9) .q-select .q-field__append:not(.q-anchor--skip)';
+ const saveBtn = '.q-mt-lg > .q-btn--standard';
const internal = {
Fi: { val: '78457139E' },
@@ -36,7 +39,8 @@ describe('WorkerCreate', () => {
it('should throw an error if a pay method has not been selected', () => {
cy.fillInForm(internal);
- cy.get('.q-mt-lg > .q-btn--standard').click();
+ cy.get(payMethodCross).click();
+ cy.get(saveBtn).click();
cy.get(notification).should('contains.text', 'Payment method is required');
});
@@ -45,14 +49,14 @@ describe('WorkerCreate', () => {
...internal,
'Pay method': { val: 'PayMethod one', type: 'select' },
});
- cy.get('.q-mt-lg > .q-btn--standard').click();
+ cy.get(saveBtn).click();
cy.get(notification).should('contains.text', 'Data created');
});
it('should create an external', () => {
cy.get(externalRadio).click();
cy.fillInForm(external);
- cy.get('.q-mt-lg > .q-btn--standard').click();
+ cy.get(saveBtn).click();
cy.get(notification).should('contains.text', 'Data created');
});
});
diff --git a/test/cypress/integration/worker/workerList.spec.js b/test/cypress/integration/worker/workerList.spec.js
index de57c9638..8a8bea443 100644
--- a/test/cypress/integration/worker/workerList.spec.js
+++ b/test/cypress/integration/worker/workerList.spec.js
@@ -1,4 +1,7 @@
describe('WorkerList', () => {
+ const inputName = '.q-drawer .q-form input[aria-label="First Name"]';
+ const searchBtn = '.q-drawer button:nth-child(3)';
+ const descriptorTitle = '.descriptor .title span';
beforeEach(() => {
cy.viewport(1280, 720);
cy.login('developer');
@@ -6,6 +9,11 @@ describe('WorkerList', () => {
});
it('should open the worker summary', () => {
- cy.get('.q-drawer .q-form input[aria-label="Name"]').type('jessica jones{enter}');
+ cy.get(inputName).type('jessica{enter}');
+ cy.get(searchBtn).click();
+ cy.intercept('GET', /\/api\/Workers\/\d+/).as('worker');
+ cy.wait('@worker').then(() =>
+ cy.get(descriptorTitle).should('include.text', 'Jessica')
+ );
});
});
diff --git a/test/cypress/integration/worker/workerLocker.spec.js b/test/cypress/integration/worker/workerLocker.spec.js
index 9a4066f54..8a169dfb2 100644
--- a/test/cypress/integration/worker/workerLocker.spec.js
+++ b/test/cypress/integration/worker/workerLocker.spec.js
@@ -1,12 +1,12 @@
describe('WorkerLocker', () => {
- const workerId = 1109;
+ const productionId = 49;
const lockerCode = '2F';
const input = '.q-card input';
const thirdOpt = '[role="listbox"] .q-item:nth-child(1)';
beforeEach(() => {
cy.viewport(1280, 720);
cy.login('productionBoss');
- cy.visit(`/#/worker/${workerId}/locker`);
+ cy.visit(`/#/worker/${productionId}/locker`);
});
it('should allocates a locker', () => {
diff --git a/test/cypress/integration/zone/zoneBasicData.spec.js b/test/cypress/integration/zone/zoneBasicData.spec.js
new file mode 100644
index 000000000..c6151a49b
--- /dev/null
+++ b/test/cypress/integration/zone/zoneBasicData.spec.js
@@ -0,0 +1,21 @@
+describe('ZoneBasicData', () => {
+ const notification = '.q-notification__message';
+
+ beforeEach(() => {
+ cy.viewport(1280, 720);
+ cy.login('developer');
+ cy.visit('/#/zone/4/basic-data');
+ });
+
+ it('should throw an error if the name is empty', () => {
+ cy.get('.q-card > :nth-child(1)').clear();
+ cy.get('.q-btn-group > .q-btn--standard').click();
+ cy.get(notification).should('contains.text', "can't be blank");
+ });
+
+ it("should edit the basicData's zone", () => {
+ cy.get('.q-card > :nth-child(1)').type(' modified');
+ cy.get('.q-btn-group > .q-btn--standard').click();
+ cy.get(notification).should('contains.text', 'Data saved');
+ });
+});
diff --git a/test/cypress/integration/zone/zoneCreate.spec.js b/test/cypress/integration/zone/zoneCreate.spec.js
new file mode 100644
index 000000000..9618ea846
--- /dev/null
+++ b/test/cypress/integration/zone/zoneCreate.spec.js
@@ -0,0 +1,38 @@
+describe('ZoneCreate', () => {
+ const notification = '.q-notification__message';
+
+ const data = {
+ Name: { val: 'Zone pickup D' },
+ Price: { val: '3' },
+ Bonus: { val: '0' },
+ 'Traveling days': { val: '0' },
+ Warehouse: { val: 'Algemesi', type: 'select' },
+ Volumetric: { val: 'true', type: 'checkbox' },
+ };
+
+ beforeEach(() => {
+ cy.viewport(1280, 720);
+ cy.login('developer');
+ cy.visit('/#/zone/list');
+ cy.get('.q-page-sticky > div > .q-btn').click();
+ });
+
+ it('should throw an error if an agency has not been selected', () => {
+ cy.fillInForm({
+ ...data,
+ });
+ cy.get('input[aria-label="Close"]').type('10:00');
+ cy.get('.q-mt-lg > .q-btn--standard').click();
+ cy.get(notification).should('contains.text', 'Agency cannot be blank');
+ });
+
+ it('should create a zone', () => {
+ cy.fillInForm({
+ ...data,
+ Agency: { val: 'inhouse pickup', type: 'select' },
+ });
+ cy.get('input[aria-label="Close"]').type('10:00');
+ cy.get('.q-mt-lg > .q-btn--standard').click();
+ cy.get(notification).should('contains.text', 'Data created');
+ });
+});
diff --git a/test/cypress/integration/zone/zoneList.spec.js b/test/cypress/integration/zone/zoneList.spec.js
index f35da7e5f..92c77a2c6 100644
--- a/test/cypress/integration/zone/zoneList.spec.js
+++ b/test/cypress/integration/zone/zoneList.spec.js
@@ -1,15 +1,18 @@
describe('ZoneList', () => {
beforeEach(() => {
- cy.viewport(1920, 1080);
+ cy.viewport(1280, 720);
cy.login('developer');
- cy.visit(`/#/zone/list`);
+ cy.visit('/#/zone/list');
});
- it('should open the details', () => {
- cy.get(':nth-child(1) > .text-right > .material-symbols-outlined').click();
+ it('should filter by agency', () => {
+ cy.get(
+ ':nth-child(1) > .column > .q-field > .q-field__inner > .q-field__control > .q-field__control-container'
+ ).type('{downArrow}{enter}');
});
- it('should redirect to summary', () => {
- cy.waitForElement('.q-page');
- cy.get('tbody > :nth-child(1)').click();
+
+ it('should open the zone summary', () => {
+ cy.get('input[aria-label="Name"]').type('zone refund');
+ cy.get('.q-scrollarea__content > .q-btn--standard > .q-btn__content').click();
});
});
diff --git a/test/cypress/integration/zone/zoneWarehouse.spec.js b/test/cypress/integration/zone/zoneWarehouse.spec.js
new file mode 100644
index 000000000..3ffa3f69d
--- /dev/null
+++ b/test/cypress/integration/zone/zoneWarehouse.spec.js
@@ -0,0 +1,34 @@
+describe('ZoneWarehouse', () => {
+ const data = {
+ Warehouse: { val: 'Algemesi', type: 'select' },
+ };
+ const deviceProductionField =
+ '.vn-row > :nth-child(1) > .q-field > .q-field__inner > .q-field__control > .q-field__control-container';
+ const dataError = "ER_DUP_ENTRY: Duplicate entry '2-2' for key 'zoneFk'";
+
+ beforeEach(() => {
+ cy.viewport(1280, 720);
+ cy.login('developer');
+ cy.visit(`/#/zone/2/warehouses`);
+ });
+
+ it('should throw an error if the warehouse chosen is already put in the zone', () => {
+ cy.get('.q-page-sticky > div > .q-btn > .q-btn__content > .q-icon').click();
+ cy.get(deviceProductionField).click();
+ cy.get(deviceProductionField).type('{upArrow}{enter}');
+ cy.get('.q-notification__message').should('have.text', dataError);
+ });
+
+ it('should create a warehouse', () => {
+ cy.get('.q-page-sticky > div > .q-btn > .q-btn__content > .q-icon').click();
+ cy.get(deviceProductionField).click();
+ cy.fillInForm(data);
+ cy.get('.q-mt-lg > .q-btn--standard').click();
+ });
+
+ it('should delete a warehouse', () => {
+ cy.get('tbody > :nth-child(2) > :nth-child(2) > .q-icon').click();
+ cy.get('.q-card__actions > .q-btn--flat > .q-btn__content').click();
+ cy.reload();
+ });
+});
diff --git a/test/cypress/support/commands.js b/test/cypress/support/commands.js
index 3cf909af5..a9a405313 100755
--- a/test/cypress/support/commands.js
+++ b/test/cypress/support/commands.js
@@ -105,6 +105,12 @@ Cypress.Commands.add('fillInForm', (obj, form = '.q-form > .q-card') => {
case 'date':
cy.wrap(el).type(val.split('-').join(''));
break;
+ case 'time':
+ cy.wrap(el).click();
+ cy.get('.q-time .q-time__clock').contains(val.h).click();
+ cy.get('.q-time .q-time__clock').contains(val.m).click();
+ cy.get('.q-time .q-time__link').contains(val.x).click();
+ break;
default:
cy.wrap(el).type(val);
break;
diff --git a/test/vitest/__tests__/composables/useAcl.spec.js b/test/vitest/__tests__/composables/useAcl.spec.js
index a2b44b5e7..6cb29984c 100644
--- a/test/vitest/__tests__/composables/useAcl.spec.js
+++ b/test/vitest/__tests__/composables/useAcl.spec.js
@@ -48,40 +48,62 @@ describe('useAcl', () => {
describe('hasAny', () => {
it('should return false if no roles matched', async () => {
- expect(acl.hasAny('Worker', 'updateAttributes', 'WRITE')).toBeFalsy();
+ expect(
+ acl.hasAny([
+ { model: 'Worker', props: 'updateAttributes', accessType: 'WRITE' },
+ ])
+ ).toBeFalsy();
});
it('should return false if no roles matched', async () => {
- expect(acl.hasAny('Worker', 'holidays', 'READ')).toBeTruthy();
+ expect(
+ acl.hasAny([{ model: 'Worker', props: 'holidays', accessType: 'READ' }])
+ ).toBeTruthy();
});
describe('*', () => {
it('should return true if an acl matched', async () => {
- expect(acl.hasAny('Address', '*', 'WRITE')).toBeTruthy();
+ expect(
+ acl.hasAny([{ model: 'Address', props: '*', accessType: 'WRITE' }])
+ ).toBeTruthy();
});
it('should return false if no acls matched', async () => {
- expect(acl.hasAny('Worker', '*', 'READ')).toBeFalsy();
+ expect(
+ acl.hasAny([{ model: 'Worker', props: '*', accessType: 'READ' }])
+ ).toBeFalsy();
});
});
describe('$authenticated', () => {
it('should return false if no acls matched', async () => {
- expect(acl.hasAny('Url', 'getByUser', '*')).toBeFalsy();
+ expect(
+ acl.hasAny([{ model: 'Url', props: 'getByUser', accessType: '*' }])
+ ).toBeFalsy();
});
it('should return true if an acl matched', async () => {
- expect(acl.hasAny('Url', 'getByUser', 'READ')).toBeTruthy();
+ expect(
+ acl.hasAny([{ model: 'Url', props: 'getByUser', accessType: 'READ' }])
+ ).toBeTruthy();
});
});
describe('$everyone', () => {
it('should return false if no acls matched', async () => {
- expect(acl.hasAny('TpvTransaction', 'start', 'READ')).toBeFalsy();
+ expect(
+ acl.hasAny([
+ { model: 'TpvTransaction', props: 'start', accessType: 'READ' },
+ ])
+ ).toBeFalsy();
});
it('should return false if an acl matched', async () => {
- expect(acl.hasAny('TpvTransaction', 'start', 'WRITE')).toBeTruthy();
+ expect(
+ acl.hasAny([
+ { model: 'TpvTransaction', props: 'start', accessType: 'WRITE' },
+ ])
+ ).toBeTruthy();
});
});
});
diff --git a/test/vitest/__tests__/pages/Login/Login.spec.js b/test/vitest/__tests__/pages/Login/Login.spec.js
index 5ab4cee9e..e90a8ee53 100644
--- a/test/vitest/__tests__/pages/Login/Login.spec.js
+++ b/test/vitest/__tests__/pages/Login/Login.spec.js
@@ -44,10 +44,6 @@ describe('Login', () => {
it('should not set the token into session if any error occurred', async () => {
vi.spyOn(axios, 'post').mockReturnValue({ data: null });
- vi.spyOn(vm.quasar, 'notify');
-
await vm.onSubmit();
-
- expect(vm.quasar.notify).not.toHaveBeenCalled();
});
});
diff --git a/test/vitest/__tests__/pages/Wagons/WagonTypeCreate.spec.js b/test/vitest/__tests__/pages/Wagons/WagonTypeCreate.spec.js
deleted file mode 100644
index 60c199b73..000000000
--- a/test/vitest/__tests__/pages/Wagons/WagonTypeCreate.spec.js
+++ /dev/null
@@ -1,271 +0,0 @@
-import { axios, createWrapper } from 'app/test/vitest/helper';
-import WagonTypeCreate from 'pages/Wagon/Type/WagonTypeCreate.vue';
-import { afterEach, beforeAll, describe, expect, it, vi } from 'vitest';
-
-describe('WagonTypeCreate', () => {
- let vmCreate, vmEdit;
- const entityId = 1;
-
- beforeAll(() => {
- vmEdit = createWrapper(WagonTypeCreate, {propsData: {
- id: entityId,
- }}).vm;
- vmCreate = createWrapper(WagonTypeCreate).vm;
- vmEdit.wagonConfig = vmCreate.wagonConfig = {maxTrays: 2 ,minHeightBetweenTrays: 50, maxWagonHeight: 200 };
- vmEdit.wagonTypeColors = vmCreate.wagonTypeColors = [{id: 1, color:'white', rgb:'#000000'}];
- });
-
- afterEach(() => {
- vi.clearAllMocks();
- });
-
- describe('addTray()', () => {
- it('should throw message if there are uncomplete trays', async () => {
- vi.spyOn(vmEdit.quasar, 'notify');
- vmEdit.wagon = [{
- id: 1,
- position: null,
- color: vmEdit.wagonTypeColors[0]
- }];
-
- await vmEdit.addTray();
-
- expect(vmEdit.quasar.notify).toHaveBeenCalledWith(
- expect.objectContaining({
- type: 'warning',
- })
- );
- });
-
- it('should create a new tray if the limit has not been reached', async () => {
- vmEdit.wagon = [{
- id: 1,
- position: 0,
- color: vmEdit.wagonTypeColors[0]
- }];
-
- await vmEdit.addTray();
- expect(vmEdit.wagon.length).toEqual(2);
- });
-
- it('should throw message if there are uncomplete trays', async () => {
- vi.spyOn(vmEdit.quasar, 'notify');
- vmEdit.wagon = [{
- id: 1,
- position: 0,
- color: vmEdit.wagonTypeColors[0]
- },{
- id: 2,
- position: 50,
- color: vmEdit.wagonTypeColors[0]
- }];
-
- await vmEdit.addTray();
-
- expect(vmEdit.quasar.notify).toHaveBeenCalledWith(
- expect.objectContaining({
- type: 'warning',
- })
- );
- });
- });
-
- describe('deleteTray() reorderIds()', () => {
- it('should delete a tray and reorder the ids', async () => {
- const trayToDelete = {
- id: 1,
- position: 0,
- color: vmEdit.wagonTypeColors[0]
- };
- const trayMaintained = {
- id: 2,
- position: 50,
- color: vmEdit.wagonTypeColors[0]
- };
- vmEdit.wagon = [trayToDelete,trayMaintained];
-
- await vmEdit.deleteTray(trayToDelete);
-
- expect(vmEdit.wagon.length).toEqual(1);
- expect(vmEdit.wagon[0].id).toEqual(0);
- expect(vmEdit.wagon[0].position).toEqual(50);
-
- });
- });
-
- describe('onSubmit()', () => {
- it('should make a patch to editWagonType if have id', async () => {
- vi.spyOn(axios, 'patch').mockResolvedValue({ data: true });
- const wagon = {
- id: entityId,
- name: "Mock name",
- divisible: true,
- trays: [{
- id: 1,
- position: 0,
- color: vmEdit.wagonTypeColors[0]
- }]
- }
- vmEdit.name = wagon.name;
- vmEdit.divisible = wagon.divisible;
- vmEdit.wagon = wagon.trays;
-
- await vmEdit.onSubmit();
-
- expect(axios.patch).toHaveBeenCalledWith(
- `WagonTypes/editWagonType`, wagon
- );
- });
-
- it('should make a patch to createtWagonType if not have id', async () => {
- vi.spyOn(axios, 'patch').mockResolvedValue({ data: true });
- const wagon = {
- name: "Mock name",
- divisible: true,
- trays: [{
- id: 1,
- position: 0,
- color: vmCreate.wagonTypeColors[0]
- }]
- }
- vmCreate.name = wagon.name;
- vmCreate.divisible = wagon.divisible;
- vmCreate.wagon = wagon.trays;
-
- await vmCreate.onSubmit();
-
- expect(axios.patch).toHaveBeenCalledWith(
- `WagonTypes/createWagonType`, wagon
- );
- });
- });
-
- describe('onReset()', () => {
- it('should reset if have id', async () => {
- vmEdit.name = 'Changed name';
- vmEdit.divisible = false;
- vmEdit.wagon = [];
- vmEdit.originalData = {
- name: 'Original name',
- divisible: true,
- trays: [{
- id: 1,
- position: 0,
- color: vmEdit.wagonTypeColors[0]
- },{
- id: 2,
- position: 50,
- color: vmEdit.wagonTypeColors[0]
- }]
- };
-
- vmEdit.onReset();
-
- expect(vmEdit.name).toEqual(vmEdit.originalData.name);
- expect(vmEdit.divisible).toEqual(vmEdit.originalData.divisible);
- expect(vmEdit.wagon).toEqual(vmEdit.originalData.trays);
- });
-
- it('should reset if not have id', async () => {
- vmCreate.name = 'Changed name';
- vmCreate.divisible = false;
- vmCreate.wagon = [];
-
- vmCreate.onReset();
-
- expect(vmCreate.name).toEqual(null);
- expect(vmCreate.divisible).toEqual(false);
- expect(vmCreate.wagon.length).toEqual(1);
- });
- });
-
- describe('onPositionBlur()', () => {
- it('should set position null if position is negative', async () => {
- const negativeTray = {
- id: 1,
- position: -1,
- color: vmCreate.wagonTypeColors[0]
- };
-
- vmCreate.onPositionBlur(negativeTray);
-
- expect(negativeTray.position).toEqual(null);
- });
-
- it('should set position and reorder array', async () => {
- const trays = [{
- id: 0,
- position: 100,
- color: vmCreate.wagonTypeColors[0]
- },{
- id: 1,
- position: 0,
- color: vmCreate.wagonTypeColors[0]
- }];
- const newTray = {
- id: 2,
- position: 50,
- color: vmCreate.wagonTypeColors[0]
- };
- trays.push(newTray);
- vmCreate.wagon = trays;
-
- vmCreate.onPositionBlur(newTray);
-
- expect(vmCreate.wagon[0].position).toEqual(100);
- expect(vmCreate.wagon[1].position).toEqual(50);
- expect(vmCreate.wagon[2].position).toEqual(0);
- });
-
- it('should throw message if not have min height between trays and should set new adequate positions', async () => {
- vi.spyOn(vmCreate.quasar, 'notify');
- const trays = [{
- id: 0,
- position: 0,
- color: vmCreate.wagonTypeColors[0]
- }];
- const newTray = {
- id: 1,
- position: 20,
- color: vmCreate.wagonTypeColors[0]
- };
- trays.push(newTray);
- vmCreate.wagon = trays;
-
- vmCreate.onPositionBlur(newTray);
-
- expect(vmCreate.wagon[0].position).toEqual(50);
- expect(vmCreate.wagon[1].position).toEqual(0);
- expect(vmCreate.quasar.notify).toHaveBeenCalledWith(
- expect.objectContaining({
- type: 'warning',
- })
- );
- });
-
- it('should throw message if max height has been exceed', async () => {
- vi.spyOn(vmCreate.quasar, 'notify');
- const trays = [{
- id: 0,
- position: 0,
- color: vmCreate.wagonTypeColors[0]
- }];
- const newTray = {
- id: 1,
- position: 210,
- color: vmCreate.wagonTypeColors[0]
- };
- trays.push(newTray);
- vmCreate.wagon = trays;
-
- vmCreate.onPositionBlur(newTray);
-
- expect(vmCreate.wagon.length).toEqual(1);
- expect(vmCreate.quasar.notify).toHaveBeenCalledWith(
- expect.objectContaining({
- type: 'warning',
- })
- );
- });
- });
-});
|