diff --git a/src/components/UserPanel.vue b/src/components/UserPanel.vue index 5f3266eb2..3937c803e 100644 --- a/src/components/UserPanel.vue +++ b/src/components/UserPanel.vue @@ -47,6 +47,8 @@ const darkMode = computed({ }, }); +const foreignCurrency = ref(); + const user = state.getUser(); const warehousesData = ref(); const companiesData = ref(); @@ -58,6 +60,8 @@ onMounted(async () => { }); function updatePreferences() { + foreignCurrency.value = user.value.foreignCurrency; + if (user.value.darkMode !== null) { darkMode.value = user.value.darkMode; } @@ -116,6 +120,11 @@ async function saveUserData(param, value) { } } +async function saveCurrency(value) { + user.value.foreignCurrency = value; + useState().setUser(user.value); +} + const onDataSaved = () => { notify('globals.dataSaved', 'positive'); }; @@ -169,6 +178,14 @@ const onDataError = () => { color="primary" unchecked-icon="light_mode" /> + diff --git a/src/components/VnTable/VnColumn.vue b/src/components/VnTable/VnColumn.vue index 3ce62c5de..0276f1bdb 100644 --- a/src/components/VnTable/VnColumn.vue +++ b/src/components/VnTable/VnColumn.vue @@ -11,6 +11,7 @@ import VnInputDate from 'components/common/VnInputDate.vue'; import VnInputTime from 'components/common/VnInputTime.vue'; import VnComponent from 'components/common/VnComponent.vue'; import VnUserLink from 'components/ui/VnUserLink.vue'; +import VnCurrency from '../ui/VnCurrency.vue'; import VnSelectEnum from '../common/VnSelectEnum.vue'; import VnCheckbox from '../common/VnCheckbox.vue'; @@ -152,6 +153,9 @@ const defaultComponents = { userLink: { component: markRaw(VnUserLink), }, + currency: { + component: markRaw(VnCurrency), + }, toggle: { component: markRaw(QToggle), }, diff --git a/src/components/common/VnSelectCompany.vue b/src/components/common/VnSelectCompany.vue new file mode 100644 index 000000000..15dea27cf --- /dev/null +++ b/src/components/common/VnSelectCompany.vue @@ -0,0 +1,43 @@ + + + diff --git a/src/components/common/VnSelectCurrency.vue b/src/components/common/VnSelectCurrency.vue new file mode 100644 index 000000000..4968fe677 --- /dev/null +++ b/src/components/common/VnSelectCurrency.vue @@ -0,0 +1,57 @@ + + + diff --git a/src/components/ui/CatalogItem.vue b/src/components/ui/CatalogItem.vue index 0ae890e37..f25bac744 100644 --- a/src/components/ui/CatalogItem.vue +++ b/src/components/ui/CatalogItem.vue @@ -6,8 +6,7 @@ import VnLv from 'components/ui/VnLv.vue'; import VnImg from 'src/components/ui/VnImg.vue'; import OrderCatalogItemDialog from 'pages/Order/Card/OrderCatalogItemDialog.vue'; import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue'; - -import { toCurrency } from 'filters/index'; +import VnCurrency from './VnCurrency.vue'; const DEFAULT_PRICE_KG = 0; @@ -61,7 +60,7 @@ const card = toRef(props, 'item');

{{ card.available }} {{ t('to') }} - {{ toCurrency(card.price) }} +

@@ -81,7 +80,12 @@ const card = toRef(props, 'item');

{{ t('price-kg') }} - {{ toCurrency(card.priceKg) || DEFAULT_PRICE_KG }} +

diff --git a/src/components/ui/VnCurrency.vue b/src/components/ui/VnCurrency.vue new file mode 100644 index 000000000..999028805 --- /dev/null +++ b/src/components/ui/VnCurrency.vue @@ -0,0 +1,82 @@ + + + diff --git a/src/composables/useSession.js b/src/composables/useSession.js index e69819a68..1f7862651 100644 --- a/src/composables/useSession.js +++ b/src/composables/useSession.js @@ -60,7 +60,7 @@ export function useSession() { const { data: isValidToken } = await axios.get('VnUsers/validateToken'); if (isValidToken) destroyTokenPromises = Object.entries(tokens).map(([key, url]) => - destroyToken(url, storage, key) + destroyToken(url, storage, key), ); } } finally { @@ -75,6 +75,8 @@ export function useSession() { nickname: '', lang: '', darkMode: null, + foreignCurrency: true, + currencyCode: 'EUR', //FIXME: use config }); stopRenewer(); diff --git a/src/composables/useState.js b/src/composables/useState.js index c2ac1740c..04e5463fe 100644 --- a/src/composables/useState.js +++ b/src/composables/useState.js @@ -10,6 +10,7 @@ const user = ref({ darkMode: null, companyFk: null, warehouseFk: null, + foreignCurrency: true, }); if (sessionStorage.getItem('user')) user.value = JSON.parse(sessionStorage.getItem('user')); diff --git a/src/composables/useVnConfirm.js b/src/composables/useVnConfirm.js index 4438ad11d..f334b4eec 100644 --- a/src/composables/useVnConfirm.js +++ b/src/composables/useVnConfirm.js @@ -22,7 +22,7 @@ export function useVnConfirm() { { customHTML: () => h(component, props) } ), }).onOk(async () => { - if (successFn) successFn(); + if (successFn) await successFn(); }); }; diff --git a/src/filters/toCurrency.js b/src/filters/toCurrency.js index f820c0127..153e52345 100644 --- a/src/filters/toCurrency.js +++ b/src/filters/toCurrency.js @@ -1,9 +1,9 @@ -import { useI18n } from 'vue-i18n'; +// import { useI18n } from 'vue-i18n'; export default function (value, symbol = 'EUR', fractionSize = 2) { if (value == null || value === '') value = 0; - const { locale } = useI18n(); + // const { locale } = useI18n(); // sacar en el boot, cuando se añade al user. Y aqui usarlo const options = { style: 'currency', @@ -12,7 +12,7 @@ export default function (value, symbol = 'EUR', fractionSize = 2) { maximumFractionDigits: fractionSize, }; - const lang = locale.value == 'es' ? 'de' : locale.value; + const lang = 'de'; return new Intl.NumberFormat(lang, options).format(value); } diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml index 7bcf90793..02da120cb 100644 --- a/src/i18n/locale/en.yml +++ b/src/i18n/locale/en.yml @@ -2,8 +2,9 @@ globals: lang: es: Spanish en: English - language: Language + foreignCurrency: Foreign currency quantity: Quantity + language: Language entity: Entity preview: Preview user: User @@ -136,6 +137,7 @@ globals: medium: Medium big: Big email: Email + currency: Currency supplier: Supplier ticketList: Ticket List created: Created diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml index b2512193d..4fcb5d087 100644 --- a/src/i18n/locale/es.yml +++ b/src/i18n/locale/es.yml @@ -2,6 +2,7 @@ globals: lang: es: Español en: Inglés + foreignCurrency: Moneda extranjera language: Idioma quantity: Cantidad entity: Entidad @@ -140,6 +141,7 @@ globals: medium: Mediano/a big: Grande email: Correo + currency: Moneda supplier: Proveedor ticketList: Listado de tickets created: Fecha creación diff --git a/src/pages/Customer/Card/CustomerBasicData.vue b/src/pages/Customer/Card/CustomerBasicData.vue index 9c9d1b50b..a1b124551 100644 --- a/src/pages/Customer/Card/CustomerBasicData.vue +++ b/src/pages/Customer/Card/CustomerBasicData.vue @@ -9,6 +9,8 @@ import VnRow from 'components/ui/VnRow.vue'; import VnInput from 'src/components/common/VnInput.vue'; import VnSelect from 'src/components/common/VnSelect.vue'; import { getDifferences, getUpdatedValues } from 'src/filters'; +import VnSelectCompany from 'src/components/common/VnSelectCompany.vue'; +import VnSelectCurrency from 'src/components/common/VnSelectCurrency.vue'; const route = useRoute(); const { t } = useI18n(); @@ -136,6 +138,10 @@ function onBeforeSave(formData, originalData) { :input-debounce="0" /> + + + + { :color="setTotalPriceColor(row)" text-color="black" > - {{ toCurrency(row.totalWithVat) }} + - {{ toCurrency(row.totalWithVat) }} + + + - diff --git a/src/pages/Ticket/Card/BasicData/TicketBasicData.vue b/src/pages/Ticket/Card/BasicData/TicketBasicData.vue index 055c9a0ff..09f851e57 100644 --- a/src/pages/Ticket/Card/BasicData/TicketBasicData.vue +++ b/src/pages/Ticket/Card/BasicData/TicketBasicData.vue @@ -9,6 +9,7 @@ import FetchData from 'components/FetchData.vue'; import { useStateStore } from 'stores/useStateStore'; import { toCurrency } from 'filters/index'; import { useRole } from 'src/composables/useRole'; +import VnCurrency from 'src/components/ui/VnCurrency.vue'; import VnCheckbox from 'src/components/common/VnCheckbox.vue'; const haveNegatives = defineModel('have-negatives', { type: Boolean, required: true }); @@ -19,7 +20,7 @@ const { t } = useI18n(); const { hasAny } = useRole(); const ticketUpdateActions = ref(null); -const rows = computed(() => formData.value?.sale?.items || []); +const rows = computed(() => formData.value?.sale?.sales || []); const columns = computed(() => [ { @@ -84,27 +85,13 @@ const loadDefaultTicketAction = () => { formData.value.option = isSalesAssistant ? 'mana' : 'renewPrices'; }; -const totalPrice = computed(() => { - return rows.value.reduce((acc, item) => acc + item.price * item.quantity, 0); -}); - -const totalNewPrice = computed(() => { - return rows.value.reduce( - (acc, item) => acc + item.component.newPrice * item.quantity, - 0 - ); -}); - -const totalDifference = computed(() => { - return rows.value.reduce((acc, item) => acc + item.component?.difference || 0, 0); -}); const showMovableColumn = computed(() => (haveDifferences.value > 0 ? ['movable'] : [])); const haveDifferences = computed(() => formData.value.sale?.haveDifferences); async function ticketHaveNegatives() { let _haveNegatives = false; let haveNotNegatives = false; formData.value.withoutNegatives = false; - formData.value?.sale?.items.forEach((item) => { + formData.value?.sale?.sales.forEach((item) => { if (item.quantity > item.movable) _haveNegatives = true; else haveNotNegatives = true; }); @@ -142,17 +129,34 @@ onMounted(async () => { {{ t('basicData.price') }}: - {{ toCurrency(totalPrice) }} + - {{ t('basicData.newPrice') }}: {{ toCurrency(totalNewPrice) }} + {{ t('basicData.newPrice') }}: + - {{ t('basicData.difference') }}: {{ toCurrency(totalDifference) }} + {{ t('basicData.difference') }}: + @@ -242,5 +246,33 @@ onMounted(async () => { /> + + + diff --git a/src/pages/Ticket/Card/BasicData/TicketBasicDataForm.vue b/src/pages/Ticket/Card/BasicData/TicketBasicDataForm.vue index 61932468c..e49e49cc2 100644 --- a/src/pages/Ticket/Card/BasicData/TicketBasicDataForm.vue +++ b/src/pages/Ticket/Card/BasicData/TicketBasicDataForm.vue @@ -15,6 +15,7 @@ import useNotify from 'src/composables/useNotify.js'; import { useAcl } from 'src/composables/useAcl'; import { useValidator } from 'src/composables/useValidator'; import { toTimeFormat } from 'filters/date.js'; +import VnSelectCurrency from 'src/components/common/VnSelectCurrency.vue'; const formData = defineModel({ type: Object, @@ -355,7 +356,7 @@ async function getZone(options) { :rules="validate('basicData.alias')" /> - + + + + { zoneId: ticket.value.zoneFk, warehouseId: ticket.value.warehouseFk, shipped: ticket.value.shipped, + currencyId: ticket.value.currencyFk, }; const { data } = await axios.post( `tickets/${ticket.value.id}/priceDifference`, @@ -67,6 +68,7 @@ const submit = async () => { option: ticket.value.option, isWithoutNegatives: ticket.value.withoutNegatives, withWarningAccept: ticket.value.withWarningAccept, + currencyFk: ticket.value.currencyFk, keepPrice: false, }; @@ -78,6 +80,8 @@ const submit = async () => { 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 } }); }; @@ -101,7 +105,7 @@ const onNextStep = async () => { t('basicData.negativesConfirmMessage'), submitWithNegatives, ); - else submit(); + else await submit(); } }; diff --git a/src/pages/Ticket/Card/TicketDescriptor.vue b/src/pages/Ticket/Card/TicketDescriptor.vue index 96920231c..d71b1c51c 100644 --- a/src/pages/Ticket/Card/TicketDescriptor.vue +++ b/src/pages/Ticket/Card/TicketDescriptor.vue @@ -9,9 +9,9 @@ import TicketDescriptorMenu from './TicketDescriptorMenu.vue'; import VnLv from 'src/components/ui/VnLv.vue'; import { toDateTimeFormat } from 'src/filters/date'; import filter from './TicketFilter.js'; -import FetchData from 'src/components/FetchData.vue'; import TicketProblems from 'src/components/TicketProblems.vue'; import axios from 'axios'; +import useCardDescription from 'src/composables/useCardDescription'; const $props = defineProps({ id: { @@ -31,6 +31,8 @@ const { t } = useI18n(); const entityId = computed(() => { return $props.id || route.params.id; }); + +const data = ref(useCardDescription()); const problems = ref({}); const originalTicket = ref(); diff --git a/src/pages/Ticket/Card/TicketEditMana.vue b/src/pages/Ticket/Card/TicketEditMana.vue index 266c82ccd..b36709052 100644 --- a/src/pages/Ticket/Card/TicketEditMana.vue +++ b/src/pages/Ticket/Card/TicketEditMana.vue @@ -5,6 +5,7 @@ import { computed, ref } from 'vue'; import { useRoute } from 'vue-router'; import { toCurrency } from 'src/filters'; import VnUsesMana from 'components/ui/VnUsesMana.vue'; +import VnCurrency from 'src/components/ui/VnCurrency.vue'; const $props = defineProps({ newPrice: { @@ -58,7 +59,15 @@ defineExpose({ save }); data-cy="ticketEditManaProxy" >
-
Mana: {{ toCurrency(mana) }}
+
+ Mana: + +
diff --git a/src/pages/Ticket/Card/TicketFilter.js b/src/pages/Ticket/Card/TicketFilter.js index daa204a7a..1b59c9d9c 100644 --- a/src/pages/Ticket/Card/TicketFilter.js +++ b/src/pages/Ticket/Card/TicketFilter.js @@ -68,5 +68,6 @@ export default { ], }, }, + { relation: 'currency' }, ], }; diff --git a/src/pages/Ticket/Card/TicketPicture.vue b/src/pages/Ticket/Card/TicketPicture.vue index d6cc19bd1..438a63db6 100644 --- a/src/pages/Ticket/Card/TicketPicture.vue +++ b/src/pages/Ticket/Card/TicketPicture.vue @@ -5,11 +5,13 @@ import { useI18n } from 'vue-i18n'; import FetchData from 'components/FetchData.vue'; import CatalogItem from 'components/ui/CatalogItem.vue'; - -import { toCurrency } from 'filters/index'; +import VnCurrency from 'src/components/ui/VnCurrency.vue'; +import { useArrayData } from 'composables/useArrayData'; const { t } = useI18n(); const route = useRoute(); +const arrayData = useArrayData('ticketData'); +const { store } = arrayData; const salesFilter = { include: { @@ -37,7 +39,12 @@ const sales = ref([]);
{{ sale.quantity }} {{ t('by') }} - {{ toCurrency(sale?.price) }} + + +
diff --git a/src/pages/Ticket/Card/TicketRightTotals.vue b/src/pages/Ticket/Card/TicketRightTotals.vue new file mode 100644 index 000000000..c98104d61 --- /dev/null +++ b/src/pages/Ticket/Card/TicketRightTotals.vue @@ -0,0 +1,59 @@ + + diff --git a/src/pages/Ticket/Card/TicketSale.vue b/src/pages/Ticket/Card/TicketSale.vue index a613f905a..31631ed7c 100644 --- a/src/pages/Ticket/Card/TicketSale.vue +++ b/src/pages/Ticket/Card/TicketSale.vue @@ -3,6 +3,7 @@ import { onMounted, ref, computed, watch, inject } 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'; @@ -23,12 +24,16 @@ import useNotify from 'src/composables/useNotify.js'; import axios from 'axios'; import VnTable from 'src/components/VnTable/VnTable.vue'; import VnConfirm from 'src/components/ui/VnConfirm.vue'; +import VnCurrency from 'src/components/ui/VnCurrency.vue'; +import TicketRightTotals from './TicketRightTotals.vue'; import TicketProblems from 'src/components/TicketProblems.vue'; -import RightMenu from 'src/components/common/RightMenu.vue'; const app = inject('app'); 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); @@ -130,7 +135,7 @@ const columns = computed(() => [ { align: 'left', label: t('globals.amount'), - name: 'amount', + name: 'total', }, { align: 'left', @@ -160,11 +165,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; @@ -284,7 +284,9 @@ const selectedValidSales = computed(() => { const onOpenEditPricePopover = async (sale) => { edit.value = { sale: JSON.parse(JSON.stringify(sale)), - price: sale.price, + price: user.value.foreignCurrency + ? (sale.foreignPrice ?? sale.price) + : sale.price, }; }; @@ -312,7 +314,10 @@ const changePrice = async (sale) => { }; const updatePrice = async (sale, newPrice) => { try { - await axios.post(`Sales/${sale.id}/updatePrice`, { newPrice }); + await axios.post(`Sales/${sale.id}/updatePrice`, { + newPrice, + isForeign: user.value.foreignCurrency, + }); sale.price = newPrice; edit.value = { ...DEFAULT_EDIT }; notify('globals.dataSaved', 'positive'); @@ -362,7 +367,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; @@ -476,7 +484,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); }; @@ -497,7 +505,7 @@ const addRow = (original = null) => { quantity: original.quantity, price: original.price, discount: original.discount, - amount: original.amount, + total: original.total, isNew: true, }; } @@ -659,38 +667,7 @@ watch( - - - + - {{ toCurrency(row.price) }} + + + - diff --git a/src/router/modules/ticket.js b/src/router/modules/ticket.js index bfcb78787..b9c96a6e6 100644 --- a/src/router/modules/ticket.js +++ b/src/router/modules/ticket.js @@ -9,6 +9,7 @@ const ticketCard = { menu: [ 'TicketBasicData', 'TicketSale', + 'TicketService', 'TicketLog', 'TicketExpedition', 'TicketDms', @@ -19,7 +20,6 @@ const ticketCard = { 'TicketVolume', 'TicketComponents', 'TicketPackage', - 'TicketService', 'TicketSaleTracking', 'TicketBoxing', 'TicketSms',