@@ -66,23 +60,19 @@ const warehouses = ref([]);
-
-
-
-
-
+
diff --git a/src/pages/Ticket/TicketList.vue b/src/pages/Ticket/TicketList.vue
index ad97e75c1..fe9667bea 100644
--- a/src/pages/Ticket/TicketList.vue
+++ b/src/pages/Ticket/TicketList.vue
@@ -95,6 +95,7 @@ const columns = computed(() => [
columnField: {
component: null,
},
+ columnClass: 'expand',
format: (row, dashIfEmpty) => dashIfEmpty(row.salesPerson),
},
{
@@ -153,11 +154,6 @@ const columns = computed(() => [
},
columnClass: 'expand',
},
- {
- align: 'left',
- name: 'refFk',
- label: t('ticketList.ref'),
- },
{
align: 'left',
name: 'zoneFk',
@@ -191,6 +187,12 @@ const columns = computed(() => [
},
format: (row) => toCurrency(row.totalWithVat),
},
+ {
+ align: 'left',
+ name: 'packing',
+ label: t('ticketSale.packaging'),
+ format: (row, dashIfEmpty) => dashIfEmpty(row.packing),
+ },
{
align: 'right',
name: 'tableActions',
@@ -548,7 +550,7 @@ function setReference(data) {
- {{ row.salesPerson }}
+ {{ dashIfEmpty(row.salesPerson) }}
@@ -577,16 +579,16 @@ function setReference(data) {
{{ row.state }}
+
+
+ {{ row.refFk }}
+
+
+
{{ row.state }}
-
-
- {{ dashIfEmpty(row.refFk) }}
-
-
-
{{ dashIfEmpty(row.zoneName) }}
diff --git a/src/pages/Ticket/locale/en.yml b/src/pages/Ticket/locale/en.yml
index 58367e3a2..829ea7a91 100644
--- a/src/pages/Ticket/locale/en.yml
+++ b/src/pages/Ticket/locale/en.yml
@@ -14,6 +14,16 @@ ticketNotes:
description: Description
removeNote: Remove note
addNote: Add note
+ observationTypes:
+ ItemPicker: Item picker
+ Packager: Packager
+ Delivery: Delivery
+ SalesPerson: Sales person
+ Administrative: Administrative
+ Weight: Weight
+ InvoiceOut: Invoice Out
+ DropOff: Drop Off
+ Sustitución: Sustitution
ticketSale:
id: Id
visible: Visible
diff --git a/src/pages/Ticket/locale/es.yml b/src/pages/Ticket/locale/es.yml
index 1acaf154b..b372e48ef 100644
--- a/src/pages/Ticket/locale/es.yml
+++ b/src/pages/Ticket/locale/es.yml
@@ -29,6 +29,18 @@ ticketNotes:
description: Descripción
removeNote: Quitar nota
addNote: Añadir nota
+ observationTypes:
+ ItemPicker: Sacador
+ Packager: Encajador
+ Delivery: Envío
+ SalesPerson: Comercial
+ Administrative: Administrativa
+ Weight: Peso
+ InvoiceOut: Facturas
+ DropOff: Despacho
+ Sustitución: Sustitución
+ Accepted: Aceptado
+ Denied: Denegado
purchaseRequest:
Id: Id
description: Descripción
@@ -86,7 +98,7 @@ weeklyTickets:
search: Buscar por tickets programados
searchInfo: Buscar tickets programados por el identificador o el identificador del cliente
advanceTickets:
- preparation: Preparación
+ preparation: Preparación
origin: Origen
destination: Destinatario
originAgency: 'Agencia origen: {agency}'
diff --git a/src/pages/Travel/Card/TravelSummary.vue b/src/pages/Travel/Card/TravelSummary.vue
index d7dce911b..4be198493 100644
--- a/src/pages/Travel/Card/TravelSummary.vue
+++ b/src/pages/Travel/Card/TravelSummary.vue
@@ -121,6 +121,20 @@ const thermographsTableColumns = computed(() => {
name: 'temperatureFk',
align: 'left',
},
+ {
+ label: t('globals.maxTemperature'),
+ field: 'maxTemperature',
+ name: 'maxTemperature',
+ align: 'left',
+ format: (val) => (val ? `${val}°` : ''),
+ },
+ {
+ label: t('globals.minTemperature'),
+ field: 'minTemperature',
+ name: 'minTemperature',
+ align: 'left',
+ format: (val) => (val ? `${val}°` : ''),
+ },
{
label: t('travel.thermographs.state'),
field: 'result',
@@ -133,7 +147,7 @@ const thermographsTableColumns = computed(() => {
name: 'destination',
align: 'left',
format: (val) =>
- warehouses.value.find((warehouse) => warehouse.id === val).name,
+ warehouses.value.find((warehouse) => warehouse.id === val)?.name,
},
{
label: t('travel.thermographs.created'),
@@ -319,7 +333,7 @@ const getLink = (param) => `#/travel/${entityId.value}/${param}`;
-
+
{{ value }}
diff --git a/src/pages/Travel/Card/TravelThermographs.vue b/src/pages/Travel/Card/TravelThermographs.vue
index 6d83581ee..e308243e3 100644
--- a/src/pages/Travel/Card/TravelThermographs.vue
+++ b/src/pages/Travel/Card/TravelThermographs.vue
@@ -47,6 +47,20 @@ const TableColumns = computed(() => {
name: 'temperatureFk',
align: 'left',
},
+ {
+ label: t('globals.maxTemperature'),
+ field: 'maxTemperature',
+ name: 'maxTemperature',
+ align: 'left',
+ format: (val) => (val ? `${val}°` : ''),
+ },
+ {
+ label: t('globals.minTemperature'),
+ field: 'minTemperature',
+ name: 'minTemperature',
+ align: 'left',
+ format: (val) => (val ? `${val}°` : ''),
+ },
{
label: t('travel.thermographs.state'),
field: 'result',
@@ -92,11 +106,7 @@ const openRemoveDialog = async (id) => {
},
})
.onOk(async () => {
- try {
- await removeThermograph(id);
- } catch (err) {
- console.error('Error removing thermograph');
- }
+ await removeThermograph(id);
});
};
@@ -106,9 +116,7 @@ const redirectToThermographForm = (action, id) => {
};
if (action === 'edit' && id) {
- const params = {};
- params.thermographId = id;
- routeDetails.params = params;
+ routeDetails.query = { travelThermographFk: id };
}
router.push(routeDetails);
};
diff --git a/src/pages/Travel/Card/TravelThermographsForm.vue b/src/pages/Travel/Card/TravelThermographsForm.vue
index 4f16b0a49..5e3ecdc3e 100644
--- a/src/pages/Travel/Card/TravelThermographsForm.vue
+++ b/src/pages/Travel/Card/TravelThermographsForm.vue
@@ -1,6 +1,6 @@
@@ -185,6 +158,11 @@ const onThermographCreated = async (data) => {
:filter="{ order: 'name' }"
auto-load
/>
+ (temperaturesOptions = data)"
+ auto-load
+ url="Temperatures"
+ />
{
(thermographForm.thermographId = data.id)
- "
+ @on-data-saved="onThermographCreated"
/>
@@ -271,6 +248,26 @@ const onThermographCreated = async (data) => {
option-label="name"
/>
+
+
+
+
+
+
{
-es:
- Select files: Selecciona ficheros
- Thermograph created: Termógrafo creado
- New thermograph: Nuevo termógrafo
+ es:
+ Select files: Selecciona ficheros
+ Thermograph created: Termógrafo creado
+ New thermograph: Nuevo termógrafo
diff --git a/src/pages/Travel/TravelFilter.vue b/src/pages/Travel/TravelFilter.vue
new file mode 100644
index 000000000..c91146257
--- /dev/null
+++ b/src/pages/Travel/TravelFilter.vue
@@ -0,0 +1,163 @@
+
+
+
+ (states = data)" auto-load />
+
+
+
+ {{ t(`params.${tag.label}`) }}:
+ {{ formatFn(tag.value) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+en:
+ travel:
+ Id: Contains
+ ref: Reference
+ agency: Agency
+ warehouseInFk: W. In
+ shipped: Shipped
+ shipmentHour: Shipment Hour
+ warehouseOut: W. Out
+ landed: Landed
+ landingHour: Landing Hour
+ totalEntries: Σ
+es:
+ travel:
+ Id: Id
+ ref: Referencia
+ agency: Agencia
+ warehouseInFk: Alm.Salida
+ shipped: F.Envío
+ shipmentHour: Hora de envío
+ warehouseOut: Alm.Entrada
+ landed: F.Entrega
+ landingHour: Hora de entrega
+ totalEntries: Σ
+
diff --git a/src/pages/Travel/TravelList.vue b/src/pages/Travel/TravelList.vue
index e56f5d2ff..a8c0e69cb 100644
--- a/src/pages/Travel/TravelList.vue
+++ b/src/pages/Travel/TravelList.vue
@@ -9,6 +9,8 @@ import TravelSummary from './Card/TravelSummary.vue';
import VnSearchbar from 'components/ui/VnSearchbar.vue';
import { toDate } from 'src/filters';
import { getDateQBadgeColor } from 'src/composables/getDateQBadgeColor.js';
+import RightMenu from 'src/components/common/RightMenu.vue';
+import TravelFilter from './TravelFilter.vue';
const { viewSummary } = useSummaryDialog();
const router = useRouter();
@@ -24,6 +26,7 @@ const $props = defineProps({
});
const entityId = computed(() => $props.id || route.params.id);
+const travelFilterRef = ref();
onMounted(async () => {
stateStore.rightDrawer = true;
});
@@ -158,15 +161,6 @@ const columns = computed(() => [
cardVisible: true,
create: true,
},
- {
- align: 'left',
- name: 'daysOnward',
- label: t('travel.travelList.tableVisibleColumns.daysOnward'),
- visible: false,
- columnFilter: {
- inWhere: false,
- },
- },
{
align: 'right',
label: '',
@@ -201,6 +195,11 @@ const columns = computed(() => [
:label="t('Search travel')"
data-key="TravelList"
/>
+
+
+
+
+
[
editorFk: entityId,
},
}"
+ :right-search="false"
:user-params="{ daysOnward: 7 }"
order="landed DESC"
:columns="columns"
@@ -220,7 +220,6 @@ const columns = computed(() => [
redirect="travel"
:is-editable="false"
:use-model="true"
- chip-locale="travel.travelList.tableVisibleColumns"
>
[
field: 'concept',
cardVisible: true,
},
+ {
+ align: 'right',
+ name: 'tableActions',
+ style: 'max-width: 20px; text-align: initial;',
+ actions: [
+ {
+ title: t('delete'),
+ icon: 'delete',
+ action: async (row) => await tableRef.value.CrudModelRef.remove([row]),
+ isPrimary: true,
+ },
+ ],
+ },
]);
-
[
save-url="WorkerIncomes/crud"
:create="{
urlCreate: 'workerIncomes',
- title: t('Create workerBalance'),
+ title: t('Create balance'),
onDataSaved: () => tableRef.reload(),
formInitialData: {
workerFk: entityId,
@@ -81,10 +93,10 @@ const columns = computed(() => [
:right-search="false"
:is-editable="true"
:use-model="true"
+ :default-remove="false"
/>
-
es:
- Create workerBalance: Crear balance
+ Create balance: Crear balance
diff --git a/src/pages/Worker/Card/WorkerCalendarFilter.vue b/src/pages/Worker/Card/WorkerCalendarFilter.vue
index 2b81b6eaf..67b7df907 100644
--- a/src/pages/Worker/Card/WorkerCalendarFilter.vue
+++ b/src/pages/Worker/Card/WorkerCalendarFilter.vue
@@ -3,9 +3,11 @@ import WorkerEventLabel from 'pages/Worker/Card/WorkerEventLabel.vue';
import FetchData from 'components/FetchData.vue';
import { useI18n } from 'vue-i18n';
import VnSelect from 'components/common/VnSelect.vue';
+import useNotify from 'src/composables/useNotify';
import { useRoute } from 'vue-router';
-import { computed, ref } from 'vue';
+import { computed, ref, watch } from 'vue';
import { toDateFormat } from '../../../filters/date';
+const { notify } = useNotify();
const { t } = useI18n();
const route = useRoute();
@@ -33,6 +35,13 @@ const props = defineProps({
},
});
+watch(
+ () => props.contractHolidays,
+ (newValue) => {
+ checkHolidays(newValue);
+ },
+ { deep: true, immediate: true }
+);
const emit = defineEmits(['update:businessFk', 'update:year', 'update:absenceType']);
const selectedBusinessFk = computed({
@@ -53,12 +62,22 @@ const selectedAbsenceType = computed({
},
});
-const generateYears = () => {
+function generateYears() {
const now = Date.vnNew();
const maxYear = now.getFullYear() + 1;
return Array.from({ length: 5 }, (_, i) => String(maxYear - i)) || [];
-};
+}
+
+function checkHolidays(contractHolidays) {
+ if (!contractHolidays) return;
+ if (
+ contractHolidays.holidaysEnjoyed > contractHolidays.totalHolidays ||
+ contractHolidays.hoursEnjoyed > contractHolidays.totalHours
+ ) {
+ notify(t('Vacation days have been exceeded'), 'negative');
+ }
+}
const absenceTypeList = ref([]);
const contractList = ref([]);
diff --git a/src/pages/Worker/Card/WorkerChangePasswordForm.vue b/src/pages/Worker/Card/WorkerChangePasswordForm.vue
deleted file mode 100644
index 20132f21e..000000000
--- a/src/pages/Worker/Card/WorkerChangePasswordForm.vue
+++ /dev/null
@@ -1,99 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-es:
- Reset password: Restablecer contraseña
- New password: Nueva contraseña
- Repeat password: Repetir contraseña
- You must enter a new password: Debes introducir la nueva contraseña
- Passwords don't match: Las contraseñas no coinciden
-
diff --git a/src/pages/Worker/Card/WorkerDescriptor.vue b/src/pages/Worker/Card/WorkerDescriptor.vue
index 3675d40f8..1cb42bbfb 100644
--- a/src/pages/Worker/Card/WorkerDescriptor.vue
+++ b/src/pages/Worker/Card/WorkerDescriptor.vue
@@ -5,7 +5,7 @@ import { useI18n } from 'vue-i18n';
import CardDescriptor from 'src/components/ui/CardDescriptor.vue';
import VnLv from 'src/components/ui/VnLv.vue';
import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue';
-import WorkerChangePasswordForm from 'src/pages/Worker/Card/WorkerChangePasswordForm.vue';
+import VnChangePassword from 'src/components/common/VnChangePassword.vue';
import { useState } from 'src/composables/useState';
import axios from 'axios';
import VnImg from 'src/components/ui/VnImg.vue';
@@ -24,18 +24,13 @@ const route = useRoute();
const { t } = useI18n();
const state = useState();
const user = state.getUser();
-const changePasswordFormDialog = ref(null);
-const cardDescriptorRef = ref(null);
const showEditPhotoForm = ref(false);
const toggleEditPictureForm = () => {
showEditPhotoForm.value = !showEditPhotoForm.value;
};
-
const entityId = computed(() => {
return $props.id || route.params.id;
});
-
-const worker = ref();
const workerExcluded = ref(false);
const getIsExcluded = async () => {
@@ -61,10 +56,10 @@ const handleExcluded = async () => {
workerExcluded.value = !workerExcluded.value;
};
+
const handlePhotoUpdated = (evt = false) => {
image.value.reload(evt);
};
-const refetch = async () => await cardDescriptorRef.value.getData();
await cardDescriptorRef.value.getData();
url="Workers/descriptor"
:filter="{ where: { id: entityId } }"
title="user.nickname"
- @on-fetch="
- (data) => {
- worker = data;
- getIsExcluded();
- }
- "
+ @on-fetch="getIsExcluded"
>
-
-
+
+
{{
workerExcluded
@@ -92,16 +82,13 @@ const refetch = async () => await cardDescriptorRef.value.getData();
- {{ t('Change password') }}
-
-
-
+ {{ t('globals.changePass') }}
@@ -167,10 +154,10 @@ const refetch = async () => await cardDescriptorRef.value.getData();
-
+
{{ t('worker.summary.sipExtension') }}
-
+
@@ -201,6 +188,15 @@ const refetch = async () => await cardDescriptorRef.value.getData();
+
es:
Create training course: Crear curso de formación
diff --git a/src/pages/Worker/Card/WorkerMedical.vue b/src/pages/Worker/Card/WorkerMedical.vue
index 6bca4ae85..fab1416c9 100644
--- a/src/pages/Worker/Card/WorkerMedical.vue
+++ b/src/pages/Worker/Card/WorkerMedical.vue
@@ -65,6 +65,18 @@ const columns = [
create: true,
component: 'input',
},
+ {
+ align: 'right',
+ name: 'tableActions',
+ actions: [
+ {
+ title: t('delete'),
+ icon: 'delete',
+ action: async (row) => await tableRef.value.CrudModelRef.remove([row]),
+ isPrimary: true,
+ },
+ ],
+ },
];
@@ -87,5 +99,6 @@ const columns = [
:right-search="false"
:is-editable="true"
:use-model="true"
+ :default-remove="false"
/>
diff --git a/src/pages/Worker/Card/WorkerOperator.vue b/src/pages/Worker/Card/WorkerOperator.vue
new file mode 100644
index 000000000..cdacc72c0
--- /dev/null
+++ b/src/pages/Worker/Card/WorkerOperator.vue
@@ -0,0 +1,204 @@
+
+
+
+
+ (trainsData = data)" auto-load />
+ (itemPackingTypesData = data)"
+ auto-load
+ />
+ (warehousesData = data)"
+ auto-load
+ />
+ (PrintersData = data)" auto-load />
+ (sectorsData = data)" auto-load />
+ (machinesData = data)" auto-load />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ID: {{ scope.opt?.id }}
+
+ {{ scope.opt?.id }},
+ {{ scope.opt?.name }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+es:
+ Model: Modelo
+ Serial number: Número de serie
+ Current SIM: SIM actual
+ Add new device: Añadir nuevo dispositivo
+ PDA deallocated: PDA desasignada
+ Remove PDA: Eliminar PDA
+ Do you want to remove this PDA?: ¿Desea eliminar este PDA?
+ You can only have one PDA: Solo puedes tener un PDA si no eres autonomo
+ This PDA is already assigned to another user: Este PDA ya está asignado a otro usuario
+
diff --git a/src/pages/Worker/Card/WorkerSummary.vue b/src/pages/Worker/Card/WorkerSummary.vue
index 8fee52dd3..ed34e771d 100644
--- a/src/pages/Worker/Card/WorkerSummary.vue
+++ b/src/pages/Worker/Card/WorkerSummary.vue
@@ -139,6 +139,7 @@ onBeforeMount(async () => {
+
diff --git a/src/pages/Worker/Card/WorkerTimeControl.vue b/src/pages/Worker/Card/WorkerTimeControl.vue
index fbfd4b28d..39fb536b6 100644
--- a/src/pages/Worker/Card/WorkerTimeControl.vue
+++ b/src/pages/Worker/Card/WorkerTimeControl.vue
@@ -326,16 +326,20 @@ const updateData = async () => {
};
const getMailStates = async (date) => {
+ const url = `WorkerTimeControls/${route.params.id}/getMailStates`;
+ const month = date.getMonth() + 1;
+ const prevMonth = month == 1 ? 12 : month - 1;
const params = {
- month: date.getMonth() + 1,
+ month,
year: date.getFullYear(),
};
- const { data } = await axios.get(
- `WorkerTimeControls/${route.params.id}/getMailStates`,
- { params }
- );
- workerTimeControlMails.value = data;
+ const curMonthStates = (await axios.get(url, { params })).data;
+ const prevMonthStates = (
+ await axios.get(url, { params: { ...params, month: prevMonth } })
+ ).data;
+
+ workerTimeControlMails.value = curMonthStates.concat(prevMonthStates);
};
const showWorkerTimeForm = (propValue, formType) => {
diff --git a/src/pages/Worker/WorkerFilter.vue b/src/pages/Worker/WorkerFilter.vue
index 765241341..dfb5659fe 100644
--- a/src/pages/Worker/WorkerFilter.vue
+++ b/src/pages/Worker/WorkerFilter.vue
@@ -7,7 +7,7 @@ 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 { t, te } = useI18n();
const props = defineProps({
dataKey: {
type: String,
@@ -16,6 +16,11 @@ const props = defineProps({
});
const departments = ref();
+
+const getLocale = (label) => {
+ const globalLocale = `globals.params.${label}`;
+ return te(globalLocale) ? t(globalLocale) : t(`params.${label}`);
+};
@@ -23,7 +28,7 @@ const departments = ref();
- {{ t(`params.${tag.label}`) }}:
+ {{ getLocale(tag.label) }}:
{{ formatFn(tag.value) }}
@@ -64,10 +69,7 @@ const departments = ref();
-
-
-
-
+
+
+
+
+
+
[
{
align: 'left',
@@ -39,13 +40,31 @@ const columns = computed(() => [
},
{
align: 'left',
- name: 'nickname',
- label: t('tableColumns.name'),
+ name: 'firstName',
+ label: t('tableColumns.firstName'),
isTitle: true,
columnFilter: {
name: 'firstName',
},
},
+ {
+ align: 'left',
+ name: 'lastName',
+ label: t('tableColumns.lastName'),
+ isTitle: true,
+ columnFilter: {
+ name: 'lastName',
+ },
+ },
+ {
+ align: 'left',
+ name: 'nickname',
+ label: t('tableColumns.userName'),
+ isTitle: true,
+ columnFilter: {
+ name: 'userName',
+ },
+ },
{
align: 'left',
name: 'departmentFk',
@@ -66,10 +85,17 @@ const columns = computed(() => [
label: t('tableColumns.email'),
cardVisible: true,
columnFilter: {
- alias: 'mu',
- inWhere: true,
+ name: 'email',
+ },
+ },
+ {
+ align: 'left',
+ name: 'extension',
+ label: t('tableColumns.extension'),
+ cardVisible: true,
+ columnFilter: {
+ name: 'extension',
},
- hidden: true,
},
{
align: 'right',
@@ -93,6 +119,12 @@ onBeforeMount(async () => {
).data?.payMethodFk;
});
+async function handleNewBankEntity(data, resp) {
+ await bankEntitiesRef.value.fetch();
+ data.bankEntityFk = resp.id;
+ bankEntitiesOptions.value.push(resp);
+}
+
function handleLocation(data, location) {
const { town, code, provinceFk, countryFk } = location ?? {};
data.postcode = code;
@@ -152,6 +184,7 @@ async function autofillBic(worker) {
auto-load
/>
(bankEntitiesOptions = data)"
auto-load
@@ -180,7 +213,7 @@ async function autofillBic(worker) {
default-mode="table"
redirect="worker"
:right-search="false"
- auto-load
+ :order="['id DESC']"
>
@@ -214,6 +247,7 @@ async function autofillBic(worker) {
@@ -262,6 +296,7 @@ async function autofillBic(worker) {
handleLocation(data, location)"
@@ -317,7 +352,9 @@ async function autofillBic(worker) {
>
bankEntitiesOptions.push(data)"
+ @on-data-saved="
+ (_, resp) => handleNewBankEntity(data, resp)
+ "
/>
diff --git a/src/pages/Worker/locale/en.yml b/src/pages/Worker/locale/en.yml
index 96df37919..8276977fd 100644
--- a/src/pages/Worker/locale/en.yml
+++ b/src/pages/Worker/locale/en.yml
@@ -1,6 +1,12 @@
passwordRequirements: 'The password must have at least { length } length characters, {nAlpha} alphabetic characters, {nUpper} capital letters, {nDigits} digits and {nPunct} symbols (Ex: $%&.)\n'
tableColumns:
id: ID
- name: Name
+ firstName: First name
+ lastName: Last Name
+ userName: User Name
department: Department
email: Email
+ fi: FI
+ SSN: SSN
+ extension: Extension
+queue: Queue
diff --git a/src/pages/Worker/locale/es.yml b/src/pages/Worker/locale/es.yml
index 41812345f..9c7618bc3 100644
--- a/src/pages/Worker/locale/es.yml
+++ b/src/pages/Worker/locale/es.yml
@@ -6,6 +6,12 @@ External: Externo
passwordRequirements: 'La contraseña debe tener al menos { length } caracteres de longitud, {nAlpha} caracteres alfabéticos, {nUpper} letras mayúsculas, {nDigits} dígitos y {nPunct} símbolos (Ej: $%&.)'
tableColumns:
id: ID
- name: Nombre
+ firstName: Nombre
+ lastName: Apellidos
+ userName: Nombre de usuario
department: Departamento
email: Email
+ fi: NIF
+ SSN: NSS
+ extension: Extensión
+queue: Cola
diff --git a/src/pages/Zone/Card/ZoneEventExclusionForm.vue b/src/pages/Zone/Card/ZoneEventExclusionForm.vue
index 0ba2e640a..215c12f46 100644
--- a/src/pages/Zone/Card/ZoneEventExclusionForm.vue
+++ b/src/pages/Zone/Card/ZoneEventExclusionForm.vue
@@ -154,7 +154,7 @@ onMounted(() => {
(stateStore.rightDrawer = false));
-
-
-
-
-
- {{ t('globals.collapseMenu') }}
-
-
-
-
-
import { onMounted, ref, computed, watch, onUnmounted } from 'vue';
import { useRoute } from 'vue-router';
-
+import VnInput from 'src/components/common/VnInput.vue';
import { useState } from 'src/composables/useState';
import axios from 'axios';
import { useArrayData } from 'composables/useArrayData';
@@ -144,7 +144,8 @@ watch(storeData, async (val) => {
});
const reFetch = async () => {
- await arrayData.fetch({ append: false });
+ const { data } = await arrayData.fetch({ append: false });
+ nodes.value = data;
};
onMounted(async () => {
@@ -182,6 +183,16 @@ onUnmounted(() => {
+
+
+
+
+
import('src/pages/Entry/EntryStockBought.vue'),
},
+ {
+ path: 'waste-recalc',
+ name: 'EntryWasteRecalc',
+ meta: {
+ title: 'wasteRecalc',
+ icon: 'compost',
+ },
+ component: () => import('src/pages/Entry/EntryWasteRecalc.vue'),
+ },
],
},
{
diff --git a/src/router/modules/route.js b/src/router/modules/route.js
index 3c5c860cf..9a7b16df3 100644
--- a/src/router/modules/route.js
+++ b/src/router/modules/route.js
@@ -11,7 +11,14 @@ export default {
component: RouterView,
redirect: { name: 'RouteMain' },
menus: {
- main: ['RouteList', 'RouteAutonomous', 'RouteRoadmap', 'CmrList', 'AgencyList'],
+ main: [
+ 'RouteList',
+ 'RouteExtendedList',
+ 'RouteAutonomous',
+ 'RouteRoadmap',
+ 'CmrList',
+ 'AgencyList',
+ ],
card: ['RouteBasicData', 'RouteTickets', 'RouteLog'],
},
children: [
@@ -19,9 +26,6 @@ export default {
path: '/route',
name: 'RouteMain',
component: () => import('src/components/common/VnSectionMain.vue'),
- props: {
- leftDrawer: false,
- },
redirect: { name: 'RouteList' },
children: [
{
@@ -33,6 +37,15 @@ export default {
},
component: () => import('src/pages/Route/RouteList.vue'),
},
+ {
+ path: 'extended-list',
+ name: 'RouteExtendedList',
+ meta: {
+ title: 'RouteExtendedList',
+ icon: 'format_list_bulleted',
+ },
+ component: () => import('src/pages/Route/RouteExtendedList.vue'),
+ },
{
path: 'create',
name: 'RouteCreate',
@@ -78,7 +91,7 @@ export default {
name: 'AgencyList',
meta: {
title: 'agencyList',
- icon: 'view_list',
+ icon: 'list',
},
component: () =>
import('src/pages/Route/Agency/AgencyList.vue'),
diff --git a/src/router/modules/worker.js b/src/router/modules/worker.js
index b2716474b..c2a9e668f 100644
--- a/src/router/modules/worker.js
+++ b/src/router/modules/worker.js
@@ -27,6 +27,7 @@ export default {
'WorkerBalance',
'WorkerFormation',
'WorkerMedical',
+ 'WorkerOperator',
],
},
children: [
@@ -168,6 +169,7 @@ export default {
meta: {
title: 'log',
icon: 'vn:History',
+ acls: [{ model: 'WorkerLog', props: 'find', accessType: 'READ' }],
},
component: () => import('src/pages/Worker/Card/WorkerLog.vue'),
},
@@ -207,6 +209,15 @@ export default {
},
component: () => import('src/pages/Worker/Card/WorkerMedical.vue'),
},
+ {
+ name: 'WorkerOperator',
+ path: 'operator',
+ meta: {
+ title: 'operator',
+ icon: 'person',
+ },
+ component: () => import('src/pages/Worker/Card/WorkerOperator.vue'),
+ },
],
},
],
diff --git a/test/cypress/integration/claim/claimDevelopment.spec.js b/test/cypress/integration/claim/claimDevelopment.spec.js
index 81fc33ecd..eb39f340a 100755
--- a/test/cypress/integration/claim/claimDevelopment.spec.js
+++ b/test/cypress/integration/claim/claimDevelopment.spec.js
@@ -33,7 +33,8 @@ describe('ClaimDevelopment', () => {
cy.saveCard();
});
- it('should add and remove new line', () => {
+ // TODO: #8112
+ xit('should add and remove new line', () => {
cy.wait(['@workers', '@workers']);
cy.addCard();
diff --git a/test/cypress/integration/claim/claimNotes.spec.js b/test/cypress/integration/claim/claimNotes.spec.js
index a4a493cda..d7a918db1 100644
--- a/test/cypress/integration/claim/claimNotes.spec.js
+++ b/test/cypress/integration/claim/claimNotes.spec.js
@@ -1,4 +1,6 @@
describe('ClaimNotes', () => {
+ const saveBtn = '.q-field__append > .q-btn > .q-btn__content > .q-icon';
+ const firstNote = '.q-infinite-scroll :nth-child(1) > .q-card__section--vert';
beforeEach(() => {
cy.login('developer');
cy.visit(`/#/claim/${2}/notes`);
@@ -7,7 +9,7 @@ describe('ClaimNotes', () => {
it('should add a new note', () => {
const message = 'This is a new message.';
cy.get('.q-textarea').type(message);
- cy.get('.q-field__append > .q-btn > .q-btn__content > .q-icon').click(); //save
- cy.get(':nth-child(1) > .q-card__section--vert').should('have.text', message);
+ cy.get(saveBtn).click();
+ cy.get(firstNote).should('have.text', message);
});
});
diff --git a/test/cypress/integration/entry/myEntry.spec.js b/test/cypress/integration/entry/myEntry.spec.js
index dca74dec2..4addec1c4 100644
--- a/test/cypress/integration/entry/myEntry.spec.js
+++ b/test/cypress/integration/entry/myEntry.spec.js
@@ -11,7 +11,7 @@ describe('EntryMy when is supplier', () => {
it('should open buyLabel when is supplier', () => {
cy.get(
- '[to="/null/2"] > .q-card > .column > .q-btn > .q-btn__content > .q-icon'
+ '[to="/null/3"] > .q-card > .column > .q-btn > .q-btn__content > .q-icon'
).click();
cy.get('.q-card__actions > .q-btn').click();
cy.window().its('open').should('be.called');
diff --git a/test/cypress/integration/route/agency/agencyWorkCenter.spec.js b/test/cypress/integration/route/agency/agencyWorkCenter.spec.js
index 6d33dbc39..353c5805b 100644
--- a/test/cypress/integration/route/agency/agencyWorkCenter.spec.js
+++ b/test/cypress/integration/route/agency/agencyWorkCenter.spec.js
@@ -4,12 +4,12 @@ describe('AgencyWorkCenter', () => {
cy.login('developer');
cy.visit(`/#/agency/11/workCenter`);
});
+ const createButton = '.q-page-sticky > div > .q-btn > .q-btn__content > .q-icon';
+ const workCenterCombobox = 'input[role="combobox"]';
it('assign workCenter', () => {
- cy.get('.q-page-sticky > div > .q-btn > .q-btn__content > .q-icon').click();
- cy.get(
- '.vn-row > .q-field > .q-field__inner > .q-field__control > .q-field__control-container'
- ).type('workCenterOne{enter}');
+ cy.get(createButton).click();
+ cy.get(workCenterCombobox).type('workCenterOne{enter}');
cy.get('.q-notification__message').should('have.text', 'Data created');
});
@@ -22,12 +22,10 @@ describe('AgencyWorkCenter', () => {
});
it('error on duplicate workCenter', () => {
- cy.get('.q-page-sticky > div > .q-btn > .q-btn__content > .q-icon').click();
- cy.get(
- '.vn-row > .q-field > .q-field__inner > .q-field__control > .q-field__control-container'
- ).type('workCenterOne{enter}');
+ cy.get(createButton).click();
+ cy.get(workCenterCombobox).type('workCenterOne{enter}');
cy.get('.q-notification__message').should('have.text', 'Data created');
- cy.get('.q-page-sticky > div > .q-btn > .q-btn__content > .q-icon').click();
+ cy.get(createButton).click();
cy.get(
'.vn-row > .q-field > .q-field__inner > .q-field__control > .q-field__control-container'
).type('workCenterOne{enter}');
diff --git a/test/cypress/integration/route/routeList.spec.js b/test/cypress/integration/route/routeList.spec.js
index c9d7147c2..8020d3ea9 100644
--- a/test/cypress/integration/route/routeList.spec.js
+++ b/test/cypress/integration/route/routeList.spec.js
@@ -2,7 +2,7 @@ describe('Route', () => {
beforeEach(() => {
cy.viewport(1920, 1080);
cy.login('developer');
- cy.visit(`/#/route/list`);
+ cy.visit(`/#/route/extended-list`);
});
const getVnSelect =
'> :nth-child(1) > .column > .q-field > .q-field__inner > .q-field__control > .q-field__control-container';
diff --git a/test/cypress/integration/ticket/ticketDescriptor.spec.js b/test/cypress/integration/ticket/ticketDescriptor.spec.js
index 8192b7c7c..0ba2723a2 100644
--- a/test/cypress/integration/ticket/ticketDescriptor.spec.js
+++ b/test/cypress/integration/ticket/ticketDescriptor.spec.js
@@ -1,7 +1,8 @@
///
describe('Ticket descriptor', () => {
- const toCloneOpt = '[role="menu"] .q-list > :nth-child(5)';
- const setWeightOpt = '[role="menu"] .q-list > :nth-child(6)';
+ const listItem = '[role="menu"] .q-list .q-item';
+ const toCloneOpt = 'To clone ticket';
+ const setWeightOpt = 'Set weight';
const warehouseValue = ':nth-child(1) > :nth-child(6) > .value > span';
const summaryHeader = '.summaryHeader > div';
const weight = 25;
@@ -14,7 +15,7 @@ describe('Ticket descriptor', () => {
it('should clone the ticket without warehouse', () => {
cy.visit('/#/ticket/1/summary');
cy.openActionsDescriptor();
- cy.get(toCloneOpt).click();
+ cy.contains(listItem, toCloneOpt).click();
cy.clickConfirm();
cy.get(warehouseValue).contains('Warehouse One');
cy.get(summaryHeader)
@@ -28,7 +29,7 @@ describe('Ticket descriptor', () => {
it('should set the weight of the ticket', () => {
cy.visit('/#/ticket/10/summary');
cy.openActionsDescriptor();
- cy.get(setWeightOpt).click();
+ cy.contains(listItem, setWeightOpt).click();
cy.intercept('POST', /\/api\/Tickets\/\d+\/setWeight/).as('weight');
cy.get('.q-dialog input').type(weight);
cy.clickConfirm();
diff --git a/test/cypress/integration/vnComponent/UserPanel.spec.js b/test/cypress/integration/vnComponent/UserPanel.spec.js
new file mode 100644
index 000000000..e83d07954
--- /dev/null
+++ b/test/cypress/integration/vnComponent/UserPanel.spec.js
@@ -0,0 +1,58 @@
+///
+describe('UserPanel', () => {
+ beforeEach(() => {
+ cy.viewport(1280, 720);
+ cy.login('developer');
+ cy.visit(`/#dashboard`);
+ cy.waitForElement('.q-page', 6000);
+ });
+
+ it('should notify when update user warehouse', () => {
+ const userWarehouse =
+ '.q-menu .q-gutter-xs > :nth-child(3) > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native> .q-field__input';
+
+ // Abro el panel
+ cy.openUserPanel();
+
+ // Compruebo la opcion inicial
+ cy.get(userWarehouse).should('have.value', 'VNL').click();
+
+ // Actualizo la opción
+ getOption(3);
+
+ //Compruebo la notificación
+ cy.get('.q-notification').should('be.visible');
+ cy.get(userWarehouse).should('have.value', 'VNH');
+
+ //Restauro el valor
+ cy.get(userWarehouse).click();
+ getOption(2);
+ });
+ it('should notify when update user company', () => {
+ const userCompany =
+ '.q-menu .q-gutter-xs > :nth-child(2) > .q-field--float > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native> .q-field__input';
+
+ // Abro el panel
+ cy.openUserPanel();
+
+ // Compruebo la opcion inicial
+ cy.get(userCompany).should('have.value', 'Warehouse One').click();
+
+ //Actualizo la opción
+ getOption(2);
+
+ //Compruebo la notificación
+ cy.get('.q-notification').should('be.visible');
+ cy.get(userCompany).should('have.value', 'Warehouse Two');
+
+ //Restauro el valor
+ cy.get(userCompany).click();
+ getOption(1);
+ });
+});
+
+function getOption(index) {
+ cy.waitForElement('[role="listbox"]');
+ const option = `[role="listbox"] .q-item:nth-child(${index})`;
+ cy.get(option).click();
+}
diff --git a/test/cypress/integration/vnComponent/vnLocation.spec.js b/test/cypress/integration/vnComponent/vnLocation.spec.js
index 1872d3591..c1b0cf929 100644
--- a/test/cypress/integration/vnComponent/vnLocation.spec.js
+++ b/test/cypress/integration/vnComponent/vnLocation.spec.js
@@ -3,25 +3,90 @@ describe('VnLocation', () => {
const dialogInputs = '.q-dialog label input';
const createLocationButton = '.q-form > .q-card > .vn-row:nth-child(6) .--add-icon';
const inputLocation = '.q-form input[aria-label="Location"]';
+ const createForm = {
+ prefix: '.q-dialog__inner > .column > #formModel > .q-card',
+ sufix: ' .q-field__inner > .q-field__control',
+ };
+ describe('CreateFormDialog ', () => {
+ beforeEach(() => {
+ cy.viewport(1280, 720);
+ cy.login('developer');
+ cy.visit('/#/supplier/567/fiscal-data', { timeout: 7000 });
+ cy.waitForElement('.q-card');
+ cy.get(createLocationButton).click();
+ });
+ it('should filter provinces based on selected country', () => {
+ // Select a country
+ cy.selectOption(
+ `${createForm.prefix} > :nth-child(5) > .q-field:nth-child(5)> ${createForm.sufix}`,
+ 'Ecuador'
+ );
+ // Verify that provinces are filtered
+ cy.get(
+ `${createForm.prefix} > :nth-child(5) > .q-field:nth-child(3)> ${createForm.sufix}`
+ ).should('have.length', 1);
+
+ // Verify that towns are filtered
+ cy.get(
+ `${createForm.prefix} > :nth-child(4) > .q-field:nth-child(3)> ${createForm.sufix}`
+ ).should('have.length', 1);
+ });
+
+ it('should filter towns based on selected province', () => {
+ // Select a country
+ cy.selectOption(
+ `${createForm.prefix} > :nth-child(5) > .q-field:nth-child(3)> ${createForm.sufix}`,
+ 'Ecuador'
+ );
+ // Verify that provinces are filtered
+ cy.get(
+ `${createForm.prefix} > :nth-child(5) > .q-field:nth-child(3)> ${createForm.sufix}`
+ ).should('have.length', 1);
+
+ // Verify that towns are filtered
+ cy.get(
+ `${createForm.prefix} > :nth-child(4) > .q-field:nth-child(3)> ${createForm.sufix}`
+ ).should('have.length', 1);
+ });
+ it('should pass selected country', () => {
+ // Select a country
+ const country = 'Ecuador';
+ const province = 'Province five';
+ cy.selectOption(
+ `${createForm.prefix} > :nth-child(5) > .q-field:nth-child(5)> ${createForm.sufix}`,
+ country
+ );
+ cy.selectOption(
+ `${createForm.prefix} > :nth-child(4) > .q-select > ${createForm.sufix}`,
+ province
+ );
+ cy.get(
+ `${createForm.prefix} > :nth-child(4) > .q-select > ${createForm.sufix} > :nth-child(3) > .q-icon`
+ ).click();
+ cy.get(
+ `#q-portal--dialog--5 > .q-dialog > ${createForm.prefix} > .vn-row > .q-select > ${createForm.sufix} > :nth-child(1) input`
+ ).should('have.value', province);
+ });
+ });
describe('Worker Create', () => {
beforeEach(() => {
cy.viewport(1280, 720);
cy.login('developer');
cy.visit('/#/worker/create', { timeout: 5000 });
cy.waitForElement('.q-card');
+ cy.get(inputLocation).click();
});
it('Show all options', function () {
- cy.get(inputLocation).click();
cy.get(locationOptions).should('have.length.at.least', 5);
});
it('input filter location as "al"', function () {
- cy.get(inputLocation).click();
+ // cy.get(inputLocation).click();
cy.get(inputLocation).clear();
cy.get(inputLocation).type('al');
cy.get(locationOptions).should('have.length.at.least', 4);
});
it('input filter location as "ecuador"', function () {
- cy.get(inputLocation).click();
+ // cy.get(inputLocation).click();
cy.get(inputLocation).clear();
cy.get(inputLocation).type('ecuador');
cy.get(locationOptions).should('have.length.at.least', 1);
@@ -63,13 +128,13 @@ describe('VnLocation', () => {
cy.get(dialogInputs).eq(0).clear();
cy.get(dialogInputs).eq(0).type(postCode);
cy.selectOption(
- '.q-dialog__inner > .column > #formModel > .q-card > :nth-child(4) > .q-select > .q-field__inner > .q-field__control ',
+ `${createForm.prefix} > :nth-child(4) > .q-select > ${createForm.sufix}`,
province
);
cy.get('.q-mt-lg > .q-btn--standard').click();
- cy.get('.q-dialog__inner > .column > #formModel > .q-card').should(
- 'not.exist'
- );
+ cy.get(`${createForm.prefix}`).should('not.exist');
+ cy.waitForElement('.q-form');
+
checkVnLocation(postCode, province);
});
it('Create city', () => {
@@ -79,19 +144,19 @@ describe('VnLocation', () => {
cy.get(dialogInputs).eq(0).type(postCode);
// city create button
cy.get(
- '.q-dialog__inner > .column > #formModel > .q-card > :nth-child(4) > .q-select > .q-field__inner > .q-field__control > :nth-child(2) > .q-icon'
+ `${createForm.prefix} > :nth-child(4) > .q-select > ${createForm.sufix} > :nth-child(2) > .q-icon`
).click();
- cy.selectOption('#q-portal--dialog--2 .q-select', 'one');
- cy.get('#q-portal--dialog--2 .q-input').type(province);
- cy.get('#q-portal--dialog--2 .q-btn--standard').click();
+ cy.selectOption('#q-portal--dialog--3 .q-select', 'one');
+ cy.get('#q-portal--dialog--3 .q-input').type(province);
+ cy.get('#q-portal--dialog--3 .q-btn--standard').click();
cy.get('#q-portal--dialog--1 .q-btn--standard').click();
+ cy.waitForElement('.q-form');
+
checkVnLocation(postCode, province);
});
function checkVnLocation(postCode, province) {
- cy.get('.q-dialog__inner > .column > #formModel > .q-card').should(
- 'not.exist'
- );
+ cy.get(`${createForm.prefix}`).should('not.exist');
cy.get('.q-form > .q-card > .vn-row:nth-child(6)')
.find('input')
.invoke('val')
diff --git a/test/cypress/support/commands.js b/test/cypress/support/commands.js
index 43788f59f..83f45b721 100755
--- a/test/cypress/support/commands.js
+++ b/test/cypress/support/commands.js
@@ -248,3 +248,9 @@ Cypress.Commands.add('validateContent', (selector, expectedValue) => {
Cypress.Commands.add('openActionsDescriptor', () => {
cy.get('.header > :nth-child(3) > .q-btn__content > .q-icon').click();
});
+
+Cypress.Commands.add('openUserPanel', () => {
+ cy.get(
+ '.column > .q-avatar > .q-avatar__content > .q-img > .q-img__container > .q-img__image'
+ ).click();
+});
diff --git a/test/vitest/__tests__/components/common/VnChangePassword.spec.js b/test/vitest/__tests__/components/common/VnChangePassword.spec.js
new file mode 100644
index 000000000..f5a967bb5
--- /dev/null
+++ b/test/vitest/__tests__/components/common/VnChangePassword.spec.js
@@ -0,0 +1,70 @@
+import { createWrapper, axios } from 'app/test/vitest/helper';
+import VnChangePassword from 'src/components/common/VnChangePassword.vue';
+import { vi, beforeEach, afterEach, beforeAll, describe, expect, it } from 'vitest';
+import { Notify } from 'quasar';
+
+describe('VnSmsDialog', () => {
+ let vm;
+
+ beforeAll(() => {
+ vi.spyOn(axios, 'get').mockResolvedValue({
+ data: [],
+ });
+ vm = createWrapper(VnChangePassword, {
+ propsData: {
+ submitFn: vi.fn(),
+ },
+ }).vm;
+ });
+
+ beforeEach(() => {
+ Notify.create = vi.fn();
+ });
+
+ afterEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it('should notify when new password is empty', async () => {
+ vm.passwords.newPassword = '';
+ vm.passwords.repeatPassword = 'password';
+
+ await vm.validate();
+ expect(Notify.create).toHaveBeenCalledWith(
+ expect.objectContaining({
+ message: 'You must enter a new password',
+ type: 'negative',
+ })
+ );
+ });
+
+ it("should notify when passwords don't match", async () => {
+ vm.passwords.newPassword = 'password1';
+ vm.passwords.repeatPassword = 'password2';
+ await vm.validate();
+ expect(Notify.create).toHaveBeenCalledWith(
+ expect.objectContaining({
+ message: `Passwords don't match`,
+ type: 'negative',
+ })
+ );
+ });
+
+ describe('if passwords match', () => {
+ it('should call submitFn and emit password', async () => {
+ vm.passwords.newPassword = 'password';
+ vm.passwords.repeatPassword = 'password';
+ await vm.validate();
+ expect(vm.props.submitFn).toHaveBeenCalledWith('password', undefined);
+ });
+
+ it('should call submitFn and emit password and old password', async () => {
+ vm.passwords.newPassword = 'password';
+ vm.passwords.repeatPassword = 'password';
+ vm.passwords.oldPassword = 'oldPassword';
+
+ await vm.validate();
+ expect(vm.props.submitFn).toHaveBeenCalledWith('password', 'oldPassword');
+ });
+ });
+});