Merge branch 'dev' into 6695-fix_CHANGE_TARGET
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details

This commit is contained in:
Alex Moreno 2025-02-24 13:52:40 +00:00
commit 10dedc97ae
16 changed files with 146 additions and 85 deletions

View File

@ -1,12 +1,13 @@
<script setup>
import { ref, computed } from 'vue';
import { ref, computed, useAttrs, nextTick } from 'vue';
import { useI18n } from 'vue-i18n';
import { useState } from 'src/composables/useState';
import FormModel from 'components/FormModel.vue';
const emit = defineEmits(['onDataSaved', 'onDataCanceled']);
defineProps({
const props = defineProps({
title: {
type: String,
default: '',
@ -22,12 +23,21 @@ defineProps({
});
const { t } = useI18n();
const attrs = useAttrs();
const state = useState();
const formModelRef = ref(null);
const closeButton = ref(null);
const isSaveAndContinue = ref(false);
const onDataSaved = (formData, requestResponse) => {
if (closeButton.value && !isSaveAndContinue.value) closeButton.value.click();
const isSaveAndContinue = ref(props.showSaveAndContinueBtn);
const isLoading = computed(() => formModelRef.value?.isLoading);
const reset = computed(() => formModelRef.value?.reset);
const onDataSaved = async (formData, requestResponse) => {
if (!isSaveAndContinue.value) closeButton.value?.click();
if (isSaveAndContinue.value) {
await nextTick();
state.set(attrs.model, attrs.formInitialData);
}
isSaveAndContinue.value = props.showSaveAndContinueBtn;
emit('onDataSaved', formData, requestResponse);
};
@ -36,9 +46,6 @@ const onClick = async (saveAndContinue) => {
await formModelRef.value.save();
};
const isLoading = computed(() => formModelRef.value?.isLoading);
const reset = computed(() => formModelRef.value?.reset);
defineExpose({
isLoading,
onDataSaved,
@ -74,10 +81,7 @@ defineExpose({
data-cy="FormModelPopup_cancel"
v-close-popup
z-max
@click="
isSaveAndContinue = false;
emit('onDataCanceled');
"
@click="emit('onDataCanceled')"
/>
<QBtn
:flat="showSaveAndContinueBtn"

View File

@ -953,14 +953,6 @@ function cardClick(_, row) {
transition-show="scale"
transition-hide="scale"
:full-width="createComplement?.isFullWidth ?? false"
@before-hide="
() => {
if (createRef.isSaveAndContinue) {
showForm = true;
createForm.formInitialData = { ...create.formInitialData };
}
}
"
data-cy="vn-table-create-dialog"
>
<FormModelPopup

View File

@ -27,6 +27,7 @@ const claimActionsForm = ref();
const rows = ref([]);
const selectedRows = ref([]);
const destinationTypes = ref([]);
const shelvings = ref([]);
const totalClaimed = ref(null);
const DEFAULT_MAX_RESPONSABILITY = 5;
const DEFAULT_MIN_RESPONSABILITY = 1;
@ -56,6 +57,12 @@ const columns = computed(() => [
field: (row) => row.claimDestinationFk,
align: 'left',
},
{
name: 'shelving',
label: t('shelvings.shelving'),
field: (row) => row.shelvingFk,
align: 'left',
},
{
name: 'Landed',
label: t('Landed'),
@ -125,6 +132,10 @@ async function updateDestination(claimDestinationFk, row, options = {}) {
options.reload && claimActionsForm.value.reload();
}
}
async function updateShelving(shelvingFk, row) {
await axios.patch(`ClaimEnds/${row.id}`, { shelvingFk });
claimActionsForm.value.reload();
}
async function regularizeClaim() {
await post(`Claims/${claimId}/regularizeClaim`);
@ -200,6 +211,7 @@ async function post(query, params) {
auto-load
@on-fetch="(data) => (destinationTypes = data)"
/>
<FetchData url="Shelvings" auto-load @on-fetch="(data) => (shelvings = data)" />
<RightMenu v-if="claim">
<template #right-panel>
<QCard class="totalClaim q-my-md q-pa-sm no-box-shadow">
@ -312,6 +324,20 @@ async function post(query, params) {
/>
</QTd>
</template>
<template #body-cell-shelving="{ row }">
<QTd>
<VnSelect
v-model="row.shelvingFk"
:options="shelvings"
option-label="code"
option-value="id"
style="width: 100px"
hide-selected
@update:model-value="(value) => updateShelving(value, row)"
/>
</QTd>
</template>
<template #body-cell-price="{ value }">
<QTd align="center">
{{ toCurrency(value) }}
@ -354,7 +380,7 @@ async function post(query, params) {
(value) =>
updateDestination(
value,
props.row
props.row,
)
"
/>
@ -371,6 +397,17 @@ async function post(query, params) {
</QTable>
</template>
<template #moreBeforeActions>
<QBtn
color="primary"
text-color="white"
:unelevated="true"
:label="tMobile('Import claim')"
:title="t('Import claim')"
icon="Download"
@click="importToNewRefundTicket"
:disable="claim.claimStateFk == resolvedStateId"
:loading="loading"
/>
<QBtn
color="primary"
text-color="white"
@ -394,17 +431,6 @@ async function post(query, params) {
@click="dialogDestination = !dialogDestination"
:loading="loading"
/>
<QBtn
color="primary"
text-color="white"
:unelevated="true"
:label="tMobile('Import claim')"
:title="t('Import claim')"
icon="Upload"
@click="importToNewRefundTicket"
:disable="claim.claimStateFk == resolvedStateId"
:loading="loading"
/>
</template>
</CrudModel>
<QDialog v-model="dialogDestination">

View File

@ -19,30 +19,36 @@ const columns = [
name: 'itemFk',
label: t('Id item'),
columnFilter: false,
align: 'left',
align: 'right',
},
{
name: 'ticketFk',
label: t('Ticket'),
columnFilter: false,
align: 'left',
align: 'right',
},
{
name: 'claimDestinationFk',
label: t('Destination'),
columnFilter: false,
align: 'left',
align: 'right',
},
{
name: 'shelvingCode',
label: t('Shelving'),
columnFilter: false,
align: 'right',
},
{
name: 'landed',
label: t('Landed'),
format: (row) => toDate(row.landed),
align: 'left',
align: 'center',
},
{
name: 'quantity',
label: t('Quantity'),
align: 'left',
align: 'right',
},
{
name: 'concept',
@ -52,18 +58,18 @@ const columns = [
{
name: 'price',
label: t('Price'),
align: 'left',
align: 'right',
},
{
name: 'discount',
label: t('Discount'),
format: ({ discount }) => toPercentage(discount / 100),
align: 'left',
align: 'right',
},
{
name: 'total',
label: t('Total'),
align: 'left',
align: 'right',
},
];
</script>

View File

@ -143,6 +143,7 @@ const exprBuilder = (param, value) => {
outlined
rounded
auto-load
sortBy="name ASC"
/></QItemSection>
</QItem>
<QItem class="q-mb-sm">

View File

@ -78,10 +78,20 @@ const columns = computed(() => [
component: 'select',
attrs: {
url: 'Workers/activeWithInheritedRole',
fields: ['id', 'name'],
fields: ['id', 'name', 'firstName'],
where: { role: 'salesPerson' },
optionFilter: 'firstName',
},
columnFilter: {
component: 'select',
attrs: {
url: 'Workers/activeWithInheritedRole',
fields: ['id', 'name', 'firstName'],
where: { role: 'salesPerson' },
optionLabel: 'firstName',
optionValue: 'id',
},
},
create: false,
columnField: {
component: null,

View File

@ -18,6 +18,7 @@ import VnInput from 'src/components/common/VnInput.vue';
import VnInputDate from 'src/components/common/VnInputDate.vue';
import CustomerSamplesPreview from 'src/pages/Customer/components/CustomerSamplesPreview.vue';
import FormPopup from 'src/components/FormPopup.vue';
import { useArrayData } from 'src/composables/useArrayData';
const { dialogRef, onDialogOK } = useDialogPluginComponent();
@ -39,7 +40,7 @@ const optionsSamplesVisible = ref([]);
const sampleType = ref({ hasPreview: false });
const initialData = reactive({});
const entityId = computed(() => route.params.id);
const customer = computed(() => state.get('Customer'));
const customer = computed(() => useArrayData('Customer').store?.data);
const filterEmailUsers = { where: { userFk: user.value.id } };
const filterClientsAddresses = {
include: [
@ -65,9 +66,9 @@ const filterSamplesVisible = {
defineEmits(['confirm', ...useDialogPluginComponent.emits]);
onBeforeMount(async () => {
initialData.clientFk = customer.value.id;
initialData.recipient = customer.value.email;
initialData.recipientId = customer.value.id;
initialData.clientFk = customer.value?.id;
initialData.recipient = customer.value?.email;
initialData.recipientId = customer.value?.id;
});
const setEmailUser = (data) => {

View File

@ -27,7 +27,7 @@ const user = state.getUser();
const today = Date.vnNew();
today.setHours(0, 0, 0, 0);
const warehousesOptions = ref([]);
const itemBalances = computed(() => arrayDataItemBalances.store.data);
const itemBalances = computed(() => arrayDataItemBalances.store.data || []);
const where = computed(() => arrayDataItemBalances.store.filter.where || {});
const showWhatsBeforeInventory = ref(false);
const inventoriedDate = ref(null);
@ -313,8 +313,8 @@ async function updateWarehouse(warehouseFk) {
row.lineFk == row.lastPreparedLineFk
? 'black'
: row.balance < 0
? 'negative'
: ''
? 'negative'
: ''
"
dense
style="font-size: 14px"

View File

@ -87,7 +87,7 @@ const insertTag = (rows) => {
tagFk: undefined,
}"
:default-remove="false"
:filter="{
:user-filter="{
fields: ['id', 'itemFk', 'tagFk', 'value', 'priority'],
where: { itemFk: route.params.id },
include: {
@ -119,6 +119,7 @@ const insertTag = (rows) => {
"
:required="true"
:rules="validate('itemTag.tagFk')"
:data-cy="`tag${row?.tag?.name}`"
/>
<VnSelect
v-if="row.tag?.isFree === false"
@ -145,6 +146,7 @@ const insertTag = (rows) => {
:label="t('itemTags.value')"
:is-clearable="false"
@keyup.enter.stop="(data) => itemTagsRef.onSubmit(data)"
:data-cy="`tag${row?.tag?.name}Value`"
/>
<VnInput
:label="t('itemBasicData.relevancy')"
@ -162,6 +164,7 @@ const insertTag = (rows) => {
name="delete"
size="sm"
dense
:data-cy="`deleteTag${row?.tag?.name}`"
>
<QTooltip>
{{ t('itemTags.removeTag') }}
@ -177,6 +180,7 @@ const insertTag = (rows) => {
icon="add"
v-shortcut="'+'"
fab
data-cy="createNewTag"
>
<QTooltip>
{{ t('itemTags.addTag') }}

View File

@ -175,17 +175,21 @@ const getSaleTotal = (sale) => {
return price - discount;
};
const getRowUpdateInputEvents = (sale) => ({
'keyup.enter': () => {
changeQuantity(sale);
},
blur: () => {
changeQuantity(sale);
},
});
const resetChanges = async () => {
arrayData.fetch({ append: false });
tableRef.value.reload();
};
const rowToUpdate = ref(null);
const changeQuantity = async (sale) => {
if (
!sale.itemFk ||
sale.quantity == null ||
edit.value?.oldQuantity === sale.quantity
)
if (!sale.itemFk || sale.quantity == null || sale?.originalQuantity === sale.quantity)
return;
if (!sale.id) return addSale(sale);
@ -197,11 +201,8 @@ const changeQuantity = async (sale) => {
const updateQuantity = async (sale) => {
try {
let { quantity, id } = sale;
if (!rowToUpdate.value) return;
rowToUpdate.value = null;
sale.isNew = false;
const params = { quantity: quantity };
await axios.post(`Sales/${id}/updateQuantity`, params);
await axios.post(`Sales/${id}/updateQuantity`, { quantity });
notify('globals.dataSaved', 'positive');
tableRef.value.reload();
} catch (e) {
@ -772,9 +773,7 @@ watch(
v-if="row.isNew || isTicketEditable"
type="number"
v-model.number="row.quantity"
@blur="changeQuantity(row)"
@keyup.enter.stop="changeQuantity(row)"
@update:model-value="() => (rowToUpdate = row)"
v-on="getRowUpdateInputEvents(row)"
@focus="edit.oldQuantity = row.quantity"
/>
<span v-else>{{ row.quantity }}</span>

View File

@ -50,6 +50,7 @@ const { dialog } = useQuasar();
const { notify } = useNotify();
const acl = useAcl();
const btnDropdownRef = ref(null);
const editManaProxyRef = ref(null);
const { openConfirmationModal } = useVnConfirm();
const newDiscount = ref(null);
@ -131,13 +132,13 @@ const createClaim = () => {
openConfirmationModal(
t('Claim out of time'),
t('Do you want to continue?'),
onCreateClaimAccepted
onCreateClaimAccepted,
);
else
openConfirmationModal(
t('Do you want to create a claim?'),
false,
onCreateClaimAccepted
onCreateClaimAccepted,
);
};
@ -216,8 +217,15 @@ const createRefund = async (withWarehouse) => {
<QItemSection>
<QItemLabel>{{ t('Update discount') }}</QItemLabel>
</QItemSection>
<TicketEditManaProxy :mana="props.mana" @save="changeMultipleDiscount()">
<TicketEditManaProxy
ref="editManaProxyRef"
:sale="row"
:mana="props.mana"
@save="changeMultipleDiscount"
>
<VnInput
autofocus
@keyup.enter.stop="() => editManaProxyRef.save(row)"
v-model.number="newDiscount"
:label="t('ticketSale.discount')"
type="number"

View File

@ -46,6 +46,15 @@ const descriptorData = useArrayData('Ticket');
onMounted(async () => {
ticketUrl.value = (await getUrl('ticket/')) + entityId.value + '/';
});
const formattedAddress = computed(() => {
if (!ticket.value) return '';
const address = ticket.value.address;
const postcode = address.postalCode;
const province = address.province ? `(${address.province.name})` : '';
return `${address.street} - ${postcode} - ${address.city} ${province}`;
});
function isEditable() {
try {
@ -238,7 +247,7 @@ onMounted(async () => {
/>
<VnLv
:label="t('ticket.summary.consigneeStreet')"
:value="entity.address?.street"
:value="formattedAddress"
/>
</QCard>
<QCard class="vn-one" v-if="entity.notes.length">

View File

@ -293,6 +293,7 @@ en:
clientFk: Customer
orderFk: Order
from: From
shipped: Shipped
to: To
salesPersonFk: Salesperson
stateFk: State
@ -320,6 +321,7 @@ es:
clientFk: Cliente
orderFk: Pedido
from: Desde
shipped: F. envío
to: Hasta
salesPersonFk: Comercial
stateFk: Estado

View File

@ -108,13 +108,11 @@ const columns = computed(() => [
},
{
align: 'left',
name: 'shippedDate',
name: 'shipped',
cardVisible: true,
label: t('ticketList.shipped'),
columnFilter: {
component: 'date',
alias: 't',
inWhere: true,
},
format: ({ shippedDate }) => toDate(shippedDate),
},

View File

@ -1,6 +1,6 @@
/// <reference types="cypress" />
describe('ClaimAction', () => {
const claimId = 2;
const claimId = 1;
const firstRow = 'tbody > :nth-child(1)';
const destinationRow = '.q-item__section > .q-field';

View File

@ -1,4 +1,3 @@
/// <reference types="cypress" />
describe('Item tag', () => {
beforeEach(() => {
cy.viewport(1920, 1080);
@ -8,25 +7,27 @@ describe('Item tag', () => {
cy.waitForElement('[data-cy="itemTags"]');
});
const createNewTag = 'createNewTag';
const saveBtn = 'crudModelDefaultSaveBtn';
const newTag = 'tagundefined';
it('should throw an error adding an existent tag', () => {
cy.get('.q-page-sticky > div').click();
cy.selectOption(':nth-child(8) > .q-select', 'Tallos');
cy.get(':nth-child(8) > [label="Value"]').type('1');
cy.dataCy('crudModelDefaultSaveBtn').click();
cy.dataCy(createNewTag).click();
cy.dataCy(newTag).should('be.visible').click().type('Genero{enter}');
cy.dataCy('tagGeneroValue').eq(1).should('be.visible');
cy.dataCy(saveBtn).click();
cy.checkNotification("The tag or priority can't be repeated for an item");
});
it('should add a new tag', () => {
cy.get('.q-page-sticky > div').click();
cy.selectOption(':nth-child(8) > .q-select', 'Ancho de la base');
cy.get(':nth-child(8) > [label="Value"]').type('50');
cy.dataCy('crudModelDefaultSaveBtn').click();
cy.dataCy(createNewTag).click();
cy.dataCy(newTag).should('be.visible').click().type('Forma{enter}');
cy.dataCy('tagFormaValue').should('be.visible').type('50');
cy.dataCy(saveBtn).click();
cy.checkNotification('Data saved');
cy.dataCy('itemTags')
.children(':nth-child(8)')
.find('.justify-center > .q-icon')
.click();
cy.dataCy('VnConfirm_confirm').click();
cy.dataCy('deleteTagForma').should('be.visible').click();
cy.dataCy('VnConfirm_confirm').should('be.visible').click();
cy.checkNotification('Data saved');
});
});