feat(TicketSale): refs #7984 add currency
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details

This commit is contained in:
Alex Moreno 2025-01-29 15:27:08 +01:00
parent 2e085c6b15
commit 1b2573bfc6
7 changed files with 133 additions and 104 deletions

View File

@ -17,6 +17,10 @@ const $props = defineProps({
type: Object,
default: null,
},
userFilter: {
type: Object,
default: null,
},
title: {
type: String,
default: '',
@ -58,6 +62,7 @@ onBeforeMount(async () => {
arrayData = useArrayData($props.dataKey, {
url: $props.url,
filter: $props.filter,
userFilter: $props.userFilter,
skip: 0,
});
store = arrayData.store;
@ -73,7 +78,7 @@ onBeforeMount(async () => {
() => [$props.url, $props.filter],
async () => {
if (!isSameDataKey.value) await getData();
}
},
);
});
@ -108,7 +113,7 @@ const iconModule = computed(() => route.matched[1].meta.icon);
const toModule = computed(() =>
route.matched[1].path.split('/').length > 2
? route.matched[1].redirect
: route.matched[1].children[0].redirect
: route.matched[1].children[0].redirect,
);
</script>

View File

@ -6,6 +6,7 @@ import { useRoute, useRouter } from 'vue-router';
import TicketBasicData from './TicketBasicData.vue';
import TicketBasicDataForm from './TicketBasicDataForm.vue';
import { useVnConfirm } from 'composables/useVnConfirm';
import { useArrayData } from 'composables/useArrayData';
import axios from 'axios';
import useNotify from 'src/composables/useNotify.js';
@ -81,7 +82,7 @@ const getPriceDifference = async () => {
};
const { data } = await axios.post(
`tickets/${formData.value.id}/priceDifference`,
params
params,
);
formData.value.ticket = data;
};
@ -109,12 +110,14 @@ const submit = async () => {
const { data } = await axios.post(
`tickets/${formData.value.id}/componentUpdate`,
params
params,
);
if (!data) return;
const ticketToMove = data.id;
const arrayData = useArrayData('ticketData');
arrayData.fetch({});
notify(t('basicData.unroutedTicket'), 'positive');
router.push({ name: 'TicketSummary', params: { id: ticketToMove } });
};
@ -136,7 +139,7 @@ const onNextStep = async () => {
openConfirmationModal(
t('basicData.negativesConfirmTitle'),
t('basicData.negativesConfirmMessage'),
submitWithNegatives
submitWithNegatives,
);
else await submit();
}

View File

@ -117,7 +117,7 @@ const setData = (entity) => {
<CardDescriptor
module="Ticket"
:url="`Tickets/${entityId}`"
:filter="filter"
:userFilter="filter"
:title="data.title"
:subtitle="data.subtitle"
@on-fetch="setData"

View File

@ -3,6 +3,7 @@ import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { toCurrency } from 'src/filters';
import VnUsesMana from 'components/ui/VnUsesMana.vue';
import VnCurrency from 'src/components/ui/VnCurrency.vue';
const $props = defineProps({
mana: {
@ -45,13 +46,21 @@ const cancel = () => {
<div class="container">
<QSpinner v-if="!mana && mana !== 0" color="primary" size="md" />
<div v-else>
<div class="header">Mana: {{ toCurrency(mana) }}</div>
<div class="header">
Mana:
<VnCurrency
:model="{ mana }"
local-field="mana"
foreign-field="mana"
arrayDataModel="ticketData"
/>
</div>
<div class="q-pa-md">
<slot />
<div v-if="newPrice" class="column items-center q-mt-lg">
<span class="text-primary">{{ t('New price') }}</span>
<span class="text-subtitle1">
{{ toCurrency($props.newPrice) }}
{{ toCurrency($props.newPrice) }}A
</span>
</div>
</div>

View File

@ -0,0 +1,59 @@
<script setup>
import RightMenu from 'src/components/common/RightMenu.vue';
import { useArrayData } from 'composables/useArrayData';
import VnCurrency from 'src/components/ui/VnCurrency.vue';
const arrayData = useArrayData('ticketData');
const store = arrayData.store;
</script>
<template>
<RightMenu>
<template #right-panel>
<div
class="q-pa-md q-mb-md q-ma-md color-vn-text"
style="border: 2px solid black"
>
<QCardSection class="justify-end text-subtitle1" horizontal>
<span class="q-mr-xs color-vn-label"
>{{ $t('ticketSale.subtotal') }}:
</span>
<VnCurrency
:model="store.data"
:currency-code="store.data?.currency?.code"
local-field="totalWithoutVat"
foreign-field="foreignTotalWithoutVat"
/>
</QCardSection>
<QCardSection class="justify-end text-subtitle1" horizontal>
<span class="q-mr-xs color-vn-label">
{{ $t('ticketSale.tax') }}:
</span>
<VnCurrency
:model="{
vat: store.data?.totalWithVat - store.data?.totalWithoutVat,
foreignVat:
store.data?.foreignTotalWithVat -
store.data?.foreignTotalWithoutVat,
}"
:currency-code="store.data?.currency?.code"
local-field="vat"
foreign-field="foreignVat"
/>
</QCardSection>
<QCardSection
class="justify-end text-weight-bold text-subtitle1"
horizontal
>
<span class="q-mr-xs color-vn-label">
{{ $t('basicData.total') }}:
</span>
<VnCurrency
:model="store.data"
:currency-code="store.data?.currency?.code"
local-field="totalWithVat"
foreign-field="foreignTotalWithVat"
/>
</QCardSection>
</div>
</template>
</RightMenu>
</template>

View File

@ -3,6 +3,7 @@ import { onMounted, ref, computed, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRouter, useRoute } from 'vue-router';
import { useQuasar } from 'quasar';
import { useState } from 'src/composables/useState';
import FetchData from 'components/FetchData.vue';
import FetchedTags from 'components/ui/FetchedTags.vue';
@ -25,11 +26,15 @@ import VnTable from 'src/components/VnTable/VnTable.vue';
import VnUsesMana from 'src/components/ui/VnUsesMana.vue';
import VnConfirm from 'src/components/ui/VnConfirm.vue';
import VnCurrency from 'src/components/ui/VnCurrency.vue';
import RightMenu from 'src/components/common/RightMenu.vue';
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
import TicketRightTotals from './TicketRightTotals.vue';
const route = useRoute();
const router = useRouter();
const { t } = useI18n();
const state = useState();
const user = state.getUser();
const { notify } = useNotify();
const { openConfirmationModal } = useVnConfirm();
const editPriceProxyRef = ref(null);
@ -132,8 +137,7 @@ const columns = computed(() => [
{
align: 'left',
label: t('globals.amount'),
name: 'amount',
format: (row) => parseInt(row.amount * row.quantity),
name: 'total',
},
{
align: 'left',
@ -163,20 +167,6 @@ const getConfig = async () => {
ticketConfig.value = data;
};
const onSalesFetched = (salesData) => {
sales.value = salesData;
for (let sale of salesData) sale.amount = getSaleTotal(sale);
};
const getSaleTotal = (sale) => {
if (sale.quantity == null || sale.price == null) return null;
const price = sale.quantity * sale.price;
const discount = (sale.discount * price) / 100;
return price - discount;
};
const resetChanges = async () => {
arrayData.fetch({ append: false });
tableRef.value.reload();
@ -262,7 +252,9 @@ const getUsesMana = async () => {
};
const getMana = async () => {
const { data } = await axios.get(`Tickets/${route.params.id}/getSalesPersonMana`);
const { data } = await axios.get(`Tickets/${route.params.id}/getSalesPersonMana`, {
params: { isForeign: user.value.foreignCurrency },
});
mana.value = data;
await getUsesMana();
};
@ -274,9 +266,12 @@ const selectedValidSales = computed(() => {
const onOpenEditPricePopover = async (sale) => {
await getMana();
console.log('sale: ', sale, user.value.foreignCurrency);
edit.value = {
sale: JSON.parse(JSON.stringify(sale)),
price: sale.price,
price: user.value.foreignCurrency
? (sale.foreignPrice ?? sale.price)
: sale.price,
};
};
@ -301,13 +296,18 @@ const updatePrice = async (sale) => {
if (!canProceed.value) return;
const newPrice = edit.value.price;
if (newPrice != null && newPrice != sale.price) {
await axios.post(`Sales/${sale.id}/updatePrice`, { newPrice });
sale.price = newPrice;
const { data } = await axios.post(`Sales/${sale.id}/updatePrice`, {
newPrice,
isForeign: user.value.foreignCurrency,
});
sale.price = data.price;
sale.total = data.total;
sale.foreignPrice = data.foreignPrice;
sale.foreignTotal = data.foreignTotal;
arrayData.fetch({ append: false });
edit.value = { ...DEFAULT_EDIT };
notify('globals.dataSaved', 'positive');
}
await getMana();
};
const changeDiscount = async (sale) => {
@ -331,7 +331,8 @@ const updateDiscount = async (sales, newDiscount = null) => {
};
await axios.post(`Tickets/${route.params.id}/updateDiscount`, params);
notify('globals.dataSaved', 'positive');
for (let sale of sales) sale.discount = _newDiscount;
tableRef.value.reload();
arrayData.fetch({ append: false });
edit.value = { ...DEFAULT_EDIT };
};
@ -339,7 +340,10 @@ const getNewPrice = computed(() => {
if (edit.value?.sale) {
const sale = edit.value.sale;
let newDiscount = sale.discount;
let newPrice = edit.value.price || sale.price;
let newPrice = user.value.foreignCurrency
? (sale.foreignPrice ?? sale.price)
: sale.price;
// let newPrice = edit.value.price || sale.price;
if (edit.value.discount != null) newDiscount = edit.value.discount;
@ -435,7 +439,7 @@ const updateItem = async (row) => {
row.price = selectedItem.price;
row.discount = 0;
row.quantity = 0;
row.amount = row.price * row.quantity;
row.total = 0;
}
endNewRow(selectedItem);
};
@ -456,7 +460,7 @@ const addRow = (original = null) => {
quantity: original.quantity,
price: original.price,
discount: original.discount,
amount: original.amount,
total: original.total,
isNew: true,
};
}
@ -619,56 +623,7 @@ watch(
</QBtnGroup>
</template>
</VnSubToolbar>
<RightMenu>
<template #right-panel>
<div
class="q-pa-md q-mb-md q-ma-md color-vn-text"
style="border: 2px solid black"
>
<QCardSection class="justify-end text-subtitle1" horizontal>
<span class="q-mr-xs color-vn-label"
>{{ t('ticketSale.subtotal') }}:
</span>
<VnCurrency
:model="store.data"
:currency-code="store.data?.currency?.code"
local-field="totalWithoutVat"
foreign-field="foreignTotalWithoutVat"
/>
</QCardSection>
<QCardSection class="justify-end text-subtitle1" horizontal>
<span class="q-mr-xs color-vn-label">
{{ t('ticketSale.tax') }}:
</span>
<VnCurrency
:model="{
vat: store.data?.totalWithVat - store.data?.totalWithoutVat,
foreignVat:
store.data?.foreignTotalWithVat -
store.data?.foreignTotalWithoutVat,
}"
:currency-code="store.data?.currency?.code"
local-field="vat"
foreign-field="foreignVat"
/>
</QCardSection>
<QCardSection
class="justify-end text-weight-bold text-subtitle1"
horizontal
>
<span class="q-mr-xs color-vn-label">
{{ t('basicData.total') }}:
</span>
<VnCurrency
:model="store.data"
:currency-code="store.data?.currency?.code"
local-field="totalWithVat"
foreign-field="foreignTotalWithVat"
/>
</QCardSection>
</div>
</template>
</RightMenu>
<TicketRightTotals />
<VnTable
ref="tableRef"
data-key="TicketSales"
@ -684,7 +639,7 @@ watch(
:column-search="false"
:disable-option="{ card: true }"
auto-load
@on-fetch="onSalesFetched"
@on-fetch="(data) => (sales = data)"
:create="{
onDataSaved: handleOnDataSave,
}"
@ -834,11 +789,7 @@ watch(
:new-price="getNewPrice"
@save="updatePrice(row)"
>
<VnInput
v-model.number="edit.price"
:label="t('basicData.price')"
type="number"
/>
<VnInputNumber v-model="edit.price" :label="t('basicData.price')" />
</TicketEditManaProxy>
</template>
<span v-else>
@ -857,10 +808,9 @@ watch(
:mana-code="manaCode"
@save="changeDiscount(row)"
>
<VnInput
v-model.number="edit.discount"
<VnInputNumber
v-model="edit.discount"
:label="t('ticketSale.discount')"
type="number"
/>
<div v-if="usesMana" class="column q-gutter-y-sm q-mt-sm">
<VnUsesMana :mana-code="manaCode" />
@ -869,15 +819,11 @@ watch(
</template>
<span v-else>{{ toPercentage(row.discount / 100) }}</span>
</template>
<template #column-amount="{ row }">
<template #column-total="{ row }">
<VnCurrency
:model="{
amount: row.quantity * row.price,
foreignAmount: row.quantity * row.foreignPrice,
}"
:model="row"
:currency-code="store.data?.currency?.code"
local-field="amount"
foreign-field="foreignAmount"
local-field="total"
/>
</template>
</VnTable>

View File

@ -12,10 +12,14 @@ import VnInput from 'src/components/common/VnInput.vue';
import { useArrayData } from 'src/composables/useArrayData';
import useNotify from 'src/composables/useNotify.js';
import axios from 'axios';
import TicketRightTotals from './TicketRightTotals.vue';
import { useState } from 'src/composables/useState';
const route = useRoute();
const router = useRouter();
const { t } = useI18n();
const state = useState();
const user = state.getUser();
const ticketServiceTypeFetchRef = ref(null);
const ticketServiceCrudRef = ref(null);
const ticketServiceOptions = ref([]);
@ -40,7 +44,7 @@ watch(
async () => {
store.filter = crudModelFilter.value;
await ticketServiceCrudRef.value.reload();
}
},
);
onMounted(async () => await getDefaultTaxClass());
@ -59,7 +63,7 @@ const createRefund = async () => {
t('service.createRefundSuccess', {
ticketId: refundTicket.id,
}),
'positive'
'positive',
);
router.push({ name: 'TicketSale', params: { id: refundTicket.id } });
};
@ -130,6 +134,7 @@ async function handleSave() {
auto-load
url="TicketServiceTypes"
/>
<TicketRightTotals />
<CrudModel
ref="ticketServiceCrudRef"
data-key="TicketService"
@ -194,7 +199,9 @@ async function handleSave() {
<QTd auto-width>
<VnInput
:label="col.label"
v-model.number="row.price"
v-model.number="
row[user.foreignCurrency ? 'foreignPrice' : 'price']
"
type="number"
min="0"
@keyup.enter="handleSave"