0
0
Fork 0

Merge branch 'dev' into Fix_OrderModuleProblems

This commit is contained in:
Jon Elias 2024-10-23 11:05:14 +00:00
commit 76ed5150a5
16 changed files with 204 additions and 91 deletions

View File

@ -1,5 +1,5 @@
<script setup>
import { ref, watch } from 'vue';
import { ref } from 'vue';
import { useValidator } from 'src/composables/useValidator';
import { useI18n } from 'vue-i18n';

View File

@ -316,6 +316,7 @@ defineExpose({
selected,
CrudModelRef,
params,
tableRef,
});
function handleOnDataSaved(_) {
@ -815,6 +816,7 @@ es:
top: 0;
}
}
.vnTable {
thead tr th {
position: sticky;

View File

@ -0,0 +1,19 @@
<script setup>
import VnSelect from './VnSelect.vue';
defineProps({
selectProps: { type: Object, required: true },
promise: { type: Function, default: () => {} },
});
</script>
<template>
<QBtnDropdown v-bind="$attrs" color="primary">
<VnSelect
v-bind="selectProps"
hide-selected
hide-dropdown-icon
focus-on-mount
@update:model-value="promise"
/>
</QBtnDropdown>
</template>

View File

@ -304,12 +304,14 @@ globals:
from: From
To: To
stateFk: State
departmentFk: Department
email: Email
SSN: SSN
fi: FI
myTeam: My team
departmentFk: Department
changePass: Change password
deleteConfirmTitle: Delete selected elements
changeState: Change state
errors:
statusUnauthorized: Access denied
statusInternalServerError: An internal server error has ocurred
@ -556,7 +558,6 @@ ticket:
package: Package
taxClass: Tax class
services: Services
changeState: Change state
requester: Requester
atender: Atender
request: Request

View File

@ -312,8 +312,10 @@ globals:
email: Correo
SSN: NSS
fi: NIF
myTeam: Mi equipo
changePass: Cambiar contraseña
deleteConfirmTitle: Eliminar los elementos seleccionados
changeState: Cambiar estado
errors:
statusUnauthorized: Acceso denegado
statusInternalServerError: Ha ocurrido un error interno del servidor
@ -565,7 +567,6 @@ ticket:
package: Embalaje
taxClass: Tipo IVA
services: Servicios
changeState: Cambiar estado
requester: Solicitante
atender: Comprador
request: Petición de compra

View File

@ -204,7 +204,7 @@ function claimUrl(section) {
top
color="black"
text-color="white"
:label="t('ticket.summary.changeState')"
:label="t('globals.changeState')"
>
<QList>
<QVirtualScroll

View File

@ -258,15 +258,28 @@ onBeforeMount(() => {
<template #body-cell-attender="{ row }">
<QTd>
<VnSelect
url="Workers/search"
v-model="row.attenderFk"
:where="{ role: 'buyer' }"
sort-by="id"
url="Workers"
:params="{ departmentCodes: ['shopping'] }"
:fields="['id', 'nickname']"
sort-by="nickname ASC"
hide-selected
option-label="firstName"
option-label="nickname"
option-value="id"
dense
/>
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>{{ scope.opt?.name }}</QItemLabel>
<QItemLabel caption
>{{ scope.opt?.nickname }},
{{ scope.opt?.code }}</QItemLabel
>
</QItemSection>
</QItem>
</template>
</VnSelect>
</QTd>
</template>
<template #body-cell-item="{ row }">

View File

@ -52,15 +52,27 @@ const redirectToItemTypeBasicData = (_, { id }) => {
</VnRow>
<VnRow>
<VnSelect
url="Workers/search"
v-model="data.workerFk"
:label="t('itemType.shared.worker')"
url="Workers"
sort-by="firstName ASC"
:fields="['id', 'firstName']"
:label="t('shared.worker')"
sort-by="nickname ASC"
:fields="['id', 'nickname']"
:params="{ departmentCodes: ['shopping'] }"
option-label="nickname"
option-value="id"
option-label="firstName"
hide-selected
/>
><template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>{{ scope.opt?.name }}</QItemLabel>
<QItemLabel caption
>{{ scope.opt?.nickname }},
{{ scope.opt?.code }}</QItemLabel
>
</QItemSection>
</QItem>
</template>
</VnSelect>
<VnSelect
v-model="data.categoryFk"
:label="t('itemType.shared.category')"

View File

@ -41,15 +41,27 @@ const temperaturesOptions = ref([]);
</VnRow>
<VnRow>
<VnSelect
url="Workers/search"
v-model="data.workerFk"
:label="t('shared.worker')"
url="Workers"
sort-by="firstName ASC"
:fields="['id', 'firstName']"
sort-by="nickname ASC"
:fields="['id', 'nickname']"
:params="{ departmentCodes: ['shopping'] }"
option-label="nickname"
option-value="id"
option-label="firstName"
hide-selected
/>
><template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>{{ scope.opt?.name }}</QItemLabel>
<QItemLabel caption
>{{ scope.opt?.nickname }},
{{ scope.opt?.code }}</QItemLabel
>
</QItemSection>
</QItem>
</template></VnSelect
>
<VnSelect
v-model="data.categoryFk"
:label="t('shared.category')"

View File

@ -1,5 +1,5 @@
<script setup>
import { onMounted, ref, computed, onUnmounted, watch } from 'vue';
import { onMounted, ref, computed, onUnmounted } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
@ -15,6 +15,8 @@ import useNotify from 'src/composables/useNotify.js';
import { toDateTimeFormat } from 'src/filters/date';
import axios from 'axios';
import VnTable from 'src/components/VnTable/VnTable.vue';
import VnBtnSelect from 'src/components/common/VnBtnSelect.vue';
import FetchData from 'src/components/FetchData.vue';
const route = useRoute();
const stateStore = useStateStore();
@ -23,50 +25,24 @@ const { notify } = useNotify();
const { openConfirmationModal } = useVnConfirm();
const newTicketDialogRef = ref(null);
const logsTableDialogRef = ref(null);
const tableRef = ref();
const vnTableRef = ref();
const expeditionsLogsData = ref([]);
const selectedExpeditions = ref([]);
const allColumnNames = ref([]);
const newTicketWithRoute = ref(false);
const selectedRows = ref([]);
const hasSelectedRows = computed(() => selectedRows.value.length > 0);
const exprBuilder = (param, value) => {
switch (param) {
case 'expeditionFk':
return { id: value };
case 'packageItemName':
return { packagingItemFk: value };
}
};
const expeditionStateTypes = ref([]);
const expeditionsFilter = computed(() => ({
where: { ticketFk: route.params.id },
order: ['created DESC'],
}));
const expeditionsArrayData = useArrayData('ticketExpeditions', {
url: 'Expeditions/filter',
filter: expeditionsFilter.value,
exprBuilder: exprBuilder,
});
const ticketArrayData = useArrayData('ticketData');
const ticketStore = ticketArrayData.store;
const ticketData = computed(() => ticketStore.data);
const refetchExpeditions = async () => {
await expeditionsArrayData.applyFilter({
filter: expeditionsFilter.value,
});
};
watch(
() => route.params.id,
async () => await refetchExpeditions(),
{ immediate: true }
);
const columns = computed(() => [
{
align: 'left',
@ -188,12 +164,10 @@ const showNewTicketDialog = (withRoute = false) => {
const deleteExpedition = async () => {
try {
const expeditionIds = selectedExpeditions.value.map(
(expedition) => expedition.id
);
const expeditionIds = selectedRows.value.map((expedition) => expedition.id);
const params = { expeditionIds };
await axios.post('Expeditions/deleteExpeditions', params);
await refetchExpeditions();
vnTableRef.value.reload();
selectedExpeditions.value = [];
notify(t('expedition.expeditionRemoved'), 'positive');
} catch (error) {
@ -242,9 +216,34 @@ onUnmounted(() => (stateStore.rightDrawer = false));
</script>
<template>
<FetchData
url="expeditionStateTypes"
@on-fetch="(data) => (expeditionStateTypes = data)"
auto-load
/>
<VnSubToolbar>
<template #st-actions>
<QBtnGroup push class="q-gutter-x-sm" flat>
<VnBtnSelect
:disable="!hasSelectedRows"
color="primary"
:label="t('globals.changeState')"
:select-props="{
options: expeditionStateTypes,
optionLabel: 'description',
}"
:promise="
async (stateTypeFk) => {
await vnTableRef.CrudModelRef.saveChanges({
updates: selectedRows.map(({ id }) => ({
data: { stateTypeFk },
where: { id },
})),
});
vnTableRef.tableRef.clearSelection();
}
"
/>
<QBtnDropdown
ref="btnDropdownRef"
color="primary"
@ -298,11 +297,11 @@ onUnmounted(() => (stateStore.rightDrawer = false));
</QBtnGroup>
</template>
</VnSubToolbar>
<VnTable
ref="tableRef"
ref="vnTableRef"
data-key="TicketExpedition"
url="Expeditions/filter"
search-url="expeditions"
:columns="columns"
:filter="expeditionsFilter"
v-model:selected="selectedRows"
@ -310,7 +309,18 @@ onUnmounted(() => (stateStore.rightDrawer = false));
'row-key': 'id',
selection: 'multiple',
}"
save-url="Expeditions/crud"
auto-load
:expr-builder="
(param, value) => {
switch (param) {
case 'expeditionFk':
return { id: value };
case 'packageItemName':
return { packagingItemFk: value };
}
}
"
order="created DESC"
>
<template #column-packagingItemFk="{ row }">
@ -324,7 +334,7 @@ onUnmounted(() => (stateStore.rightDrawer = false));
<ExpeditionNewTicket
:ticket="ticketData"
:with-route="newTicketWithRoute"
:selected-expeditions="selectedExpeditions"
:selected-expeditions="selectedRows"
/>
</QDialog>
<QDialog ref="logsTableDialogRef" transition-show="scale" transition-hide="scale">

View File

@ -122,37 +122,23 @@ function isOnTicketCard() {
</div>
</template>
<template #header-right>
<div class="flex items-end">
<QBtnDropdown
ref="stateBtnDropdownRef"
color="black"
text-color="white"
:label="t('ticket.summary.changeState')"
:disable="!isEditable()"
>
<VnSelect
:options="editableStates"
hide-selected
option-label="name"
option-value="code"
hide-dropdown-icon
focus-on-mount
@update:model-value="changeState"
/>
</QBtnDropdown>
<QBtn
v-if="!isOnTicketCard()"
icon="more_vert"
round
size="md"
flat
color="white"
>
<QMenu>
<TicketDescriptorMenu :ticket="entityId" />
</QMenu>
</QBtn>
</div>
<QBtnDropdown
ref="stateBtnDropdownRef"
color="black"
text-color="white"
:label="t('globals.changeState')"
:disable="!isEditable()"
>
<VnSelect
:options="editableStates"
hide-selected
option-label="name"
option-value="code"
hide-dropdown-icon
focus-on-mount
@update:model-value="changeState"
/>
</QBtnDropdown>
</template>
<template #body="{ entity }">
<QCard class="vn-one">

View File

@ -463,6 +463,9 @@ onMounted(async () => {
userParams.dateToAdvance = today;
userParams.scopeDays = 1;
userParams.warehouseFk = user.value.warehouseFk;
userParams.ipt = 'H';
userParams.futureIpt = 'H';
userParams.isFullMovable = true;
const filter = { limit: 0 };
await arrayData.addFilter({ filter, userParams });
});

View File

@ -11,7 +11,7 @@ import axios from 'axios';
import { onMounted } from 'vue';
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
const { t } = useI18n();
const { t, te } = useI18n();
const props = defineProps({
dataKey: {
type: String,
@ -43,6 +43,11 @@ const getItemPackingTypes = async () => {
}
};
const getLocale = (val) => {
const param = `params.${val}`;
return te(param) ? t(param) : t(`globals.${param}`);
};
onMounted(async () => await getItemPackingTypes());
</script>
@ -60,7 +65,7 @@ onMounted(async () => await getItemPackingTypes());
>
<template #tags="{ tag, formatFn }">
<div class="q-gutter-x-xs">
<strong>{{ t(`params.${tag.label}`) }}: </strong>
<strong>{{ getLocale(tag.label) }}: </strong>
<span>{{ formatFn(tag.value) }}</span>
</div>
</template>
@ -136,6 +141,19 @@ onMounted(async () => await getItemPackingTypes());
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnSelect
:label="t('globals.params.departmentFk')"
v-model="params.departmentFk"
url="Departments"
:fields="['id', 'name']"
dense
outlined
rounded
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnSelect

View File

@ -100,7 +100,7 @@ weeklyTickets:
advanceTickets:
preparation: Preparación
origin: Origen
destination: Destinatario
destination: Destino
originAgency: 'Agencia origen: {agency}'
destinationAgency: 'Agencia destino: {agency}'
ticketId: ID

View File

@ -0,0 +1,28 @@
/// <reference types="cypress" />
describe('Ticket expedtion', () => {
const tableContent = '.q-table .q-virtual-scroll__content';
const stateTd = 'td:nth-child(9)';
beforeEach(() => {
cy.login('developer');
cy.viewport(1920, 1080);
});
it('should change the state', () => {
cy.visit('#/ticket/1/expedition');
cy.intercept('GET', /\/api\/Expeditions\/filter/).as('expeditions');
cy.intercept('POST', /\/api\/Expeditions\/crud/).as('crud');
cy.wait('@expeditions');
cy.selectRows([1, 2]);
cy.get('#subToolbar [aria-controls]:nth-child(1)').click();
cy.get('.q-menu .q-item').contains('Perdida').click();
cy.wait('@crud');
cy.get(`${tableContent} tr:nth-child(-n+2) ${stateTd}`).each(($el) => {
cy.wrap($el).contains('Perdida');
});
});
});

View File

@ -152,6 +152,14 @@ Cypress.Commands.add('notificationHas', (selector, text) => {
cy.get(selector).should('have.text', text);
});
Cypress.Commands.add('selectRows', (rows) => {
rows.forEach((row) => {
cy.get('.q-table .q-virtual-scroll__content tr .q-checkbox__inner')
.eq(row - 1)
.click();
});
});
Cypress.Commands.add('fillRow', (rowSelector, data) => {
// Usar el selector proporcionado para obtener la fila deseada
cy.waitForElement('tbody');