forked from verdnatura/hedera-web
Several changes
This commit is contained in:
parent
745e9a569c
commit
67c6f84de3
10
src/App.vue
10
src/App.vue
|
@ -2,10 +2,10 @@
|
|||
<router-view />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent } from 'vue';
|
||||
<script setup>
|
||||
import { useAppStore } from 'stores/app';
|
||||
import { onBeforeMount } from 'vue';
|
||||
const appStore = useAppStore();
|
||||
|
||||
export default defineComponent({
|
||||
name: 'App'
|
||||
});
|
||||
onBeforeMount(() => appStore.init());
|
||||
</script>
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { boot } from 'quasar/wrappers'
|
||||
import { appStore } from 'stores/app'
|
||||
import { userStore } from 'stores/user'
|
||||
import { boot } from 'quasar/wrappers';
|
||||
import { useAppStore } from 'stores/app';
|
||||
import { userStore } from 'stores/user';
|
||||
|
||||
export default boot(({ app }) => {
|
||||
const props = app.config.globalProperties
|
||||
props.$app = appStore()
|
||||
props.$user = userStore()
|
||||
props.$actions = document.createElement('div')
|
||||
})
|
||||
const props = app.config.globalProperties;
|
||||
props.$app = useAppStore();
|
||||
props.$user = userStore();
|
||||
props.$actions = document.createElement('div');
|
||||
});
|
||||
|
|
|
@ -9,7 +9,7 @@ const emit = defineEmits([
|
|||
'remove'
|
||||
]);
|
||||
|
||||
const $props = defineProps({
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: [String, Number],
|
||||
default: null
|
||||
|
@ -33,7 +33,7 @@ const requiredFieldRule = val => !!val || t('globals.fieldRequired');
|
|||
const vnInputRef = ref(null);
|
||||
const value = computed({
|
||||
get() {
|
||||
return $props.modelValue;
|
||||
return props.modelValue;
|
||||
},
|
||||
set(value) {
|
||||
emit('update:modelValue', value);
|
||||
|
@ -41,7 +41,7 @@ const value = computed({
|
|||
});
|
||||
const hover = ref(false);
|
||||
const styleAttrs = computed(() => {
|
||||
return $props.isOutlined
|
||||
return props.isOutlined
|
||||
? { dense: true, outlined: true, rounded: true }
|
||||
: {};
|
||||
});
|
||||
|
@ -88,9 +88,7 @@ const inputRules = [
|
|||
<template #append>
|
||||
<slot v-if="$slots.append && !$attrs.disabled" name="append" />
|
||||
<QIcon
|
||||
v-if="
|
||||
hover && value && !$attrs.disabled && $props.clearable
|
||||
"
|
||||
v-if="hover && value && !$attrs.disabled && props.clearable"
|
||||
name="close"
|
||||
size="xs"
|
||||
@click="
|
||||
|
|
|
@ -23,9 +23,9 @@ const handleClick = () => {
|
|||
@click="handleClick()"
|
||||
>
|
||||
<QItemSection class="no-padding">
|
||||
<div class="row">
|
||||
<div class="row no-wrap">
|
||||
<slot name="prepend" />
|
||||
<div class="column">
|
||||
<div class="column full-width">
|
||||
<slot name="content" />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
<script setup>
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { currency, formatDateTitle } from 'src/lib/filters.js';
|
||||
import VnImg from 'src/components/ui/VnImg.vue';
|
||||
|
||||
defineProps({
|
||||
ticket: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
rows: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
});
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const lineDiscountSubtotal = line => {
|
||||
return line.quantity * line.price;
|
||||
};
|
||||
|
||||
const lineSubtotal = line => {
|
||||
const discount = line.discount;
|
||||
return lineDiscountSubtotal(line) * ((100 - discount) / 100);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<QCard class="vn-w-sm" style="padding: 32px">
|
||||
<QCardSection class="no-padding q-mb-md">
|
||||
<div class="text-h6">#{{ ticket.id }}</div>
|
||||
</QCardSection>
|
||||
<QCardSection class="no-padding q-mb-md">
|
||||
<div class="text-subtitle1 text-bold">
|
||||
{{ t('shippingInformation') }}
|
||||
</div>
|
||||
<div>
|
||||
{{ t('preparation') }}
|
||||
{{ formatDateTitle(ticket.shipped) }}
|
||||
</div>
|
||||
<div>
|
||||
{{ t('delivery') }}
|
||||
{{ formatDateTitle(ticket.shipped) }}
|
||||
</div>
|
||||
<div>
|
||||
{{ t(ticket.method != 'PICKUP' ? 'agency' : 'warehouse') }}
|
||||
{{ ticket.agency }}
|
||||
</div>
|
||||
</QCardSection>
|
||||
<QCardSection class="no-padding q-mb-md">
|
||||
<div class="text-subtitle1 text-bold">
|
||||
{{ t('deliveryAddress') }}
|
||||
</div>
|
||||
<div>{{ ticket.nickname }}</div>
|
||||
<div>{{ ticket.street }}</div>
|
||||
<div>
|
||||
{{ ticket.postalCode }} {{ ticket.city }} ({{
|
||||
ticket.province
|
||||
}})
|
||||
</div>
|
||||
</QCardSection>
|
||||
<QCardSection
|
||||
class="no-padding q-mb-md text-subtitle1 text-bold column"
|
||||
>
|
||||
<span class="text-right">
|
||||
{{ t('total') }} {{ currency(ticket.taxBase) }}
|
||||
</span>
|
||||
<span class="text-right">
|
||||
{{ t('totalTax') }} {{ currency(ticket.total) }}
|
||||
</span>
|
||||
</QCardSection>
|
||||
<QSeparator inset />
|
||||
<QList v-for="row in rows" :key="row.itemFk">
|
||||
<QItem>
|
||||
<QItemSection avatar>
|
||||
<VnImg
|
||||
storage="catalog"
|
||||
size="200x200"
|
||||
:id="row.image"
|
||||
rounded
|
||||
/>
|
||||
</QItemSection>
|
||||
<QItemSection>
|
||||
<QItemLabel lines="1">
|
||||
{{ row.concept }}
|
||||
</QItemLabel>
|
||||
<QItemLabel lines="1" caption>
|
||||
{{ row.value5 }} {{ row.value6 }} {{ row.value7 }}
|
||||
</QItemLabel>
|
||||
<QItemLabel lines="1">
|
||||
{{ row.quantity }} x {{ currency(row.price) }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
<QItemSection side class="total">
|
||||
<QItemLabel>
|
||||
<span class="discount" v-if="row.discount">
|
||||
{{ currency(lineDiscountSubtotal(row)) }} -
|
||||
{{ currency(row.discount) }} =
|
||||
</span>
|
||||
{{ currency(lineSubtotal(row)) }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</QList>
|
||||
</QCard>
|
||||
</template>
|
||||
|
||||
<i18n lang="yaml">
|
||||
en-US:
|
||||
shippingInformation: Shipping Information
|
||||
preparation: Preparation
|
||||
delivery: Delivery
|
||||
agency: Agency
|
||||
warehouse: Store
|
||||
deliveryAddress: Delivery address
|
||||
total: Total
|
||||
totalTax: Total + IVA
|
||||
es-ES:
|
||||
shippingInformation: Datos de envío
|
||||
preparation: Preparación
|
||||
delivery: Entrega
|
||||
agency: Agencia
|
||||
warehouse: Almacén
|
||||
deliveryAddress: Dirección de entrega
|
||||
total: Total
|
||||
totalTax: Total + IVA
|
||||
ca-ES:
|
||||
shippingInformation: Dades d'enviament
|
||||
preparation: Preparació
|
||||
delivery: Lliurament
|
||||
agency: Agència
|
||||
warehouse: Magatzem
|
||||
deliveryAddress: Adreça de lliurament
|
||||
total: Total
|
||||
totalTax: Total + IVA
|
||||
fr-FR:
|
||||
shippingInformation: Informations sur la livraison
|
||||
preparation: Préparation
|
||||
delivery: Livraison
|
||||
warehouse: Entrepôt
|
||||
deliveryAddress: Adresse de livraison
|
||||
total: Total
|
||||
totalTax: Total + IVA
|
||||
pt-PT:
|
||||
shippingInformation: Dados de envio
|
||||
preparation: Preparação
|
||||
delivery: Entrega
|
||||
agency: Agência
|
||||
warehouse: Armazém
|
||||
deliveryAddress: Endereço de entrega
|
||||
total: Total
|
||||
totalTax: Total + IVA
|
||||
</i18n>
|
|
@ -1,8 +1,8 @@
|
|||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import { appStore } from 'stores/app';
|
||||
import { useAppStore } from 'stores/app';
|
||||
|
||||
const $props = defineProps({
|
||||
const props = defineProps({
|
||||
baseURL: {
|
||||
type: String,
|
||||
default: null
|
||||
|
@ -23,23 +23,27 @@ const $props = defineProps({
|
|||
id: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
rounded: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
const app = appStore();
|
||||
const app = useAppStore();
|
||||
const show = ref(false);
|
||||
const url = computed(() => {
|
||||
return `${$props.baseURL ?? app.imageUrl}/${$props.storage}/${$props.size}/${$props.id}`;
|
||||
return `${props.baseURL ?? app.imageUrl}/${props.storage}/${props.size}/${props.id}`;
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<QImg
|
||||
:class="{ zoomIn: $props.zoomSize }"
|
||||
:class="{ zoomIn: props.zoomSize, rounded: props.rounded }"
|
||||
:src="url"
|
||||
v-bind="$attrs"
|
||||
@click="show = !show"
|
||||
spinner-color="primary"
|
||||
/>
|
||||
<QDialog v-model="show" v-if="$props.zoomSize">
|
||||
<QDialog v-model="show" v-if="props.zoomSize">
|
||||
<QImg
|
||||
:src="url"
|
||||
size="full"
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
import toCurrency from './toCurrency';
|
||||
|
||||
export { toCurrency };
|
|
@ -1,18 +0,0 @@
|
|||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
export default function (value, symbol = 'EUR', fractionSize = 2) {
|
||||
if (value == null || value === '') value = 0;
|
||||
|
||||
const { locale } = useI18n();
|
||||
|
||||
const options = {
|
||||
style: 'currency',
|
||||
currency: symbol,
|
||||
minimumFractionDigits: fractionSize,
|
||||
maximumFractionDigits: fractionSize
|
||||
};
|
||||
|
||||
const lang = locale.value === 'es' ? 'de' : locale.value;
|
||||
|
||||
return new Intl.NumberFormat(lang, options).format(value);
|
||||
}
|
|
@ -49,5 +49,8 @@ export default {
|
|||
agencyPackages: 'Paquets per agència',
|
||||
accountConfig: 'Configuració',
|
||||
addressesList: 'Adreces',
|
||||
addressDetails: 'Configuració'
|
||||
addressDetails: 'Configuració',
|
||||
checkout: 'Configurar encàrrec',
|
||||
//
|
||||
orderLoadedIntoBasket: 'Comanda carregada a la cistella!'
|
||||
};
|
||||
|
|
|
@ -63,6 +63,9 @@ export default {
|
|||
accountConfig: 'Configuration',
|
||||
addressesList: 'Addresses',
|
||||
addressDetails: 'Configuration',
|
||||
checkout: 'Configure order',
|
||||
//
|
||||
orderLoadedIntoBasket: 'Order loaded into basket!',
|
||||
|
||||
orders: 'Orders',
|
||||
order: 'Pending order',
|
||||
|
|
|
@ -72,6 +72,9 @@ export default {
|
|||
accountConfig: 'Configuración',
|
||||
addressesList: 'Direcciones',
|
||||
addressDetails: 'Configuración',
|
||||
checkout: 'Configurar pedido',
|
||||
//
|
||||
orderLoadedIntoBasket: '¡Pedido cargado en la cesta!',
|
||||
|
||||
orders: 'Pedidos',
|
||||
order: 'Pedido pendiente',
|
||||
|
|
|
@ -49,5 +49,8 @@ export default {
|
|||
agencyPackages: 'Liste par agence',
|
||||
accountConfig: 'Configuration',
|
||||
addressesList: 'Adresses',
|
||||
addressDetails: 'Configuration'
|
||||
addressDetails: 'Configuration',
|
||||
checkout: "Définissez l'ordre",
|
||||
//
|
||||
orderLoadedIntoBasket: 'Commande chargée dans le panier!'
|
||||
};
|
||||
|
|
|
@ -50,5 +50,8 @@ export default {
|
|||
agencyPackages: 'Bultos por agencia',
|
||||
accountConfig: 'Configuração',
|
||||
addressesList: 'Moradas',
|
||||
addressDetails: 'Configuração'
|
||||
addressDetails: 'Configuração',
|
||||
checkout: 'Configurar encomenda',
|
||||
//
|
||||
orderLoadedIntoBasket: 'Pedido carregado na cesta!'
|
||||
};
|
||||
|
|
|
@ -1,73 +1,87 @@
|
|||
import { date as qdate, format } from 'quasar'
|
||||
const { pad } = format
|
||||
import { i18n } from 'src/boot/i18n';
|
||||
import { date as qdate, format } from 'quasar';
|
||||
const { pad } = format;
|
||||
|
||||
export function currency (val) {
|
||||
return typeof val === 'number' ? val.toFixed(2) + '€' : val
|
||||
export function currency(val) {
|
||||
return typeof val === 'number' ? val.toFixed(2) + '€' : val;
|
||||
}
|
||||
|
||||
export function date (val, format) {
|
||||
if (val == null) return val
|
||||
export function date(val, format) {
|
||||
if (val == null) return val;
|
||||
if (!(val instanceof Date)) {
|
||||
val = new Date(val)
|
||||
val = new Date(val);
|
||||
}
|
||||
return qdate.formatDate(val, format, window.i18n.tm('date'))
|
||||
return qdate.formatDate(val, format, i18n.global.tm('date'));
|
||||
}
|
||||
|
||||
export function relDate (val) {
|
||||
if (val == null) return val
|
||||
export const formatDateTitle = timeStamp => {
|
||||
const { t, messages, locale } = i18n.global;
|
||||
const formattedString = qdate.formatDate(
|
||||
timeStamp,
|
||||
`dddd, D [${t('of')}] MMMM [${t('of')}] YYYY`,
|
||||
{
|
||||
days: messages.value[locale.value].date.days,
|
||||
months: messages.value[locale.value].date.months
|
||||
}
|
||||
);
|
||||
return formattedString;
|
||||
};
|
||||
|
||||
export function relDate(val) {
|
||||
if (val == null) return val;
|
||||
if (!(val instanceof Date)) {
|
||||
val = new Date(val)
|
||||
val = new Date(val);
|
||||
}
|
||||
|
||||
const dif = qdate.getDateDiff(new Date(), val, 'days')
|
||||
let day
|
||||
const dif = qdate.getDateDiff(new Date(), val, 'days');
|
||||
let day;
|
||||
|
||||
switch (dif) {
|
||||
case 0:
|
||||
day = 'today'
|
||||
break
|
||||
day = 'today';
|
||||
break;
|
||||
case 1:
|
||||
day = 'yesterday'
|
||||
break
|
||||
day = 'yesterday';
|
||||
break;
|
||||
case -1:
|
||||
day = 'tomorrow'
|
||||
break
|
||||
day = 'tomorrow';
|
||||
break;
|
||||
}
|
||||
|
||||
if (day) {
|
||||
day = window.i18n.t(day)
|
||||
day = i18n.global.t(day);
|
||||
} else {
|
||||
if (dif > 0 && dif <= 7) {
|
||||
day = qdate.formatDate(val, 'ddd', window.i18n.tm('date'))
|
||||
day = qdate.formatDate(val, 'ddd', i18n.global.tm('date'));
|
||||
} else {
|
||||
day = qdate.formatDate(val, 'ddd, MMMM Do', window.i18n.tm('date'))
|
||||
day = qdate.formatDate(val, 'ddd, MMMM Do', i18n.global.tm('date'));
|
||||
}
|
||||
}
|
||||
|
||||
return day
|
||||
return day;
|
||||
}
|
||||
|
||||
export function relTime (val) {
|
||||
if (val == null) return val
|
||||
export function relTime(val) {
|
||||
if (val == null) return val;
|
||||
if (!(val instanceof Date)) {
|
||||
val = new Date(val)
|
||||
val = new Date(val);
|
||||
}
|
||||
return relDate(val) + ' ' + qdate.formatDate(val, 'H:mm:ss')
|
||||
return relDate(val) + ' ' + qdate.formatDate(val, 'H:mm:ss');
|
||||
}
|
||||
|
||||
export function elapsedTime (val) {
|
||||
if (val == null) return val
|
||||
export function elapsedTime(val) {
|
||||
if (val == null) return val;
|
||||
if (!(val instanceof Date)) {
|
||||
val = new Date(val)
|
||||
val = new Date(val);
|
||||
}
|
||||
const now = new Date().getTime()
|
||||
val = Math.floor((now - val.getTime()) / 1000)
|
||||
const now = new Date().getTime();
|
||||
val = Math.floor((now - val.getTime()) / 1000);
|
||||
|
||||
const hours = Math.floor(val / 3600)
|
||||
val -= hours * 3600
|
||||
const minutes = Math.floor(val / 60)
|
||||
val -= minutes * 60
|
||||
const seconds = val
|
||||
const hours = Math.floor(val / 3600);
|
||||
val -= hours * 3600;
|
||||
const minutes = Math.floor(val / 60);
|
||||
val -= minutes * 60;
|
||||
const seconds = val;
|
||||
|
||||
return `${pad(hours, 2)}:${pad(minutes, 2)}:${pad(seconds, 2)}`
|
||||
return `${pad(hours, 2)}:${pad(minutes, 2)}:${pad(seconds, 2)}`;
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<template>Basket view</template>
|
|
@ -346,11 +346,16 @@
|
|||
import { date, currency } from 'src/lib/filters.js';
|
||||
import { date as qdate } from 'quasar';
|
||||
import axios from 'axios';
|
||||
import { useAppStore } from 'stores/app';
|
||||
|
||||
const CancelToken = axios.CancelToken;
|
||||
|
||||
export default {
|
||||
name: 'HederaCatalog',
|
||||
setup() {
|
||||
const appStore = useAppStore();
|
||||
return { appStore };
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
uid: 0,
|
||||
|
@ -446,7 +451,7 @@ export default {
|
|||
if (!value) return;
|
||||
|
||||
const res = await this.$jApi.execQuery(
|
||||
`CALL myBasket_getAvailable;
|
||||
`CALL myOrder_getAvailable(${this.appStore.basketOrderId});
|
||||
SELECT DISTINCT t.id, l.name
|
||||
FROM vn.item i
|
||||
JOIN vn.itemType t ON t.id = i.typeFk
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<template>Checkout</template>
|
|
@ -1,183 +0,0 @@
|
|||
<template>
|
||||
<Teleport :to="$actions">
|
||||
<QSelect
|
||||
v-model="year"
|
||||
:options="years"
|
||||
color="white"
|
||||
dark
|
||||
standout
|
||||
dense
|
||||
rounded
|
||||
/>
|
||||
</Teleport>
|
||||
<div class="vn-w-sm">
|
||||
<div
|
||||
v-if="!invoices?.length"
|
||||
class="text-subtitle1 text-center text-grey-7 q-pa-md"
|
||||
>
|
||||
{{ $t('noInvoicesFound') }}
|
||||
</div>
|
||||
<QCard v-if="invoices?.length">
|
||||
<QTable
|
||||
:columns="columns"
|
||||
:pagination="pagination"
|
||||
:rows="invoices"
|
||||
row-key="id"
|
||||
hide-header
|
||||
hide-bottom
|
||||
>
|
||||
<template v-slot:body="props">
|
||||
<QTr :props="props">
|
||||
<QTd key="ref" :props="props">
|
||||
{{ props.row.ref }}
|
||||
</QTd>
|
||||
<QTd key="issued" :props="props">
|
||||
{{ date(props.row.issued, 'ddd, MMMM Do') }}
|
||||
</QTd>
|
||||
<QTd key="amount" :props="props">
|
||||
{{ currency(props.row.amount) }}
|
||||
</QTd>
|
||||
<QTd key="hasPdf" :props="props">
|
||||
<QBtn
|
||||
v-if="props.row.hasPdf"
|
||||
icon="download"
|
||||
:title="$t('downloadInvoicePdf')"
|
||||
:href="invoiceUrl(props.row.id)"
|
||||
target="_blank"
|
||||
flat
|
||||
round
|
||||
/>
|
||||
<QIcon
|
||||
v-else
|
||||
name="warning"
|
||||
:title="$t('notDownloadable')"
|
||||
color="warning"
|
||||
size="24px"
|
||||
/>
|
||||
</QTd>
|
||||
</QTr>
|
||||
</template>
|
||||
</QTable>
|
||||
</QCard>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { date, currency } from 'src/lib/filters.js';
|
||||
|
||||
export default {
|
||||
name: 'OrdersPendingIndex',
|
||||
data() {
|
||||
const curYear = new Date().getFullYear();
|
||||
const years = [];
|
||||
|
||||
for (let year = curYear - 5; year <= curYear; year++) {
|
||||
years.push(year);
|
||||
}
|
||||
|
||||
return {
|
||||
columns: [
|
||||
{ name: 'ref', label: 'serial', field: 'ref', align: 'left' },
|
||||
{
|
||||
name: 'issued',
|
||||
label: 'issued',
|
||||
field: 'issued',
|
||||
align: 'left'
|
||||
},
|
||||
{ name: 'amount', label: 'amount', field: 'amount' },
|
||||
{
|
||||
name: 'hasPdf',
|
||||
label: 'download',
|
||||
field: 'hasPdf',
|
||||
align: 'center'
|
||||
}
|
||||
],
|
||||
pagination: {
|
||||
rowsPerPage: 0
|
||||
},
|
||||
year: curYear,
|
||||
years,
|
||||
invoices: null
|
||||
};
|
||||
},
|
||||
|
||||
async mounted() {
|
||||
await this.loadData();
|
||||
},
|
||||
|
||||
watch: {
|
||||
async year() {
|
||||
await this.loadData();
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
date,
|
||||
currency,
|
||||
|
||||
async loadData() {
|
||||
const params = {
|
||||
from: new Date(this.year, 0),
|
||||
to: new Date(this.year, 11, 31, 23, 59, 59)
|
||||
};
|
||||
this._invoices = await this.$jApi.query(
|
||||
`SELECT id, ref, issued, amount, hasPdf
|
||||
FROM myInvoice
|
||||
WHERE issued BETWEEN #from AND #to
|
||||
ORDER BY issued DESC
|
||||
LIMIT 500`,
|
||||
params
|
||||
);
|
||||
},
|
||||
|
||||
invoiceUrl(id) {
|
||||
return (
|
||||
'?' +
|
||||
new URLSearchParams({
|
||||
srv: 'rest:dms/invoice',
|
||||
invoice: id,
|
||||
access_token: this.$user.token
|
||||
}).toString()
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<i18n lang="yaml">
|
||||
en-US:
|
||||
noInvoicesFound: No invoices found
|
||||
serial: Serial
|
||||
issued: Date
|
||||
amount: Import
|
||||
downloadInvoicePdf: Download invoice PDF
|
||||
notDownloadable: Not available for download, request the invoice to your salesperson
|
||||
es-ES:
|
||||
noInvoicesFound: No se han encontrado facturas
|
||||
serial: Serie
|
||||
issued: Fecha
|
||||
amount: Importe
|
||||
downloadInvoicePdf: Descargar factura en PDF
|
||||
notDownloadable: No disponible para descarga, solicita la factura a tu comercial
|
||||
ca-ES:
|
||||
noInvoicesFound: No s'han trobat factures
|
||||
serial: Sèrie
|
||||
issued: Data
|
||||
amount: Import
|
||||
downloadInvoicePdf: Descarregar PDF
|
||||
notDownloadable: No disponible per cescarrega, sol·licita la factura al teu comercial
|
||||
fr-FR:
|
||||
noInvoicesFound: Aucune facture trouvée
|
||||
serial: Série
|
||||
issued: Date
|
||||
amount: Montant
|
||||
downloadInvoicePdf: Télécharger le PDF
|
||||
notDownloadable: Non disponible en téléchargement, demander la facture à votre commercial
|
||||
pt-PT:
|
||||
noInvoicesFound: Nenhuma fatura encontrada
|
||||
serial: Serie
|
||||
issued: Data
|
||||
amount: Importe
|
||||
downloadInvoicePdf: Baixar PDF
|
||||
notDownloadable: Não disponível para download, solicite a fatura ao seu comercial
|
||||
</i18n>
|
|
@ -0,0 +1,170 @@
|
|||
<script setup>
|
||||
import { ref, onMounted, inject, computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import { currency } from 'src/lib/filters.js';
|
||||
import { date as qdate } from 'quasar';
|
||||
import { userStore as useUserStore } from 'stores/user';
|
||||
|
||||
const { t } = useI18n();
|
||||
const jApi = inject('jApi');
|
||||
const userStore = useUserStore();
|
||||
|
||||
const currentYear = ref(new Date('2001-01-01').getFullYear());
|
||||
const years = ref([]);
|
||||
const invoices = ref([]);
|
||||
|
||||
const columns = computed(() => [
|
||||
{ name: 'ref', label: t('serial'), field: 'ref', align: 'left' },
|
||||
{
|
||||
name: 'issued',
|
||||
label: t('issued'),
|
||||
field: 'issued',
|
||||
align: 'left',
|
||||
format: val => qdate.formatDate(val, 'D MMM YYYY')
|
||||
},
|
||||
{
|
||||
name: 'amount',
|
||||
label: t('amount'),
|
||||
field: 'amount',
|
||||
format: val => currency(val)
|
||||
},
|
||||
{
|
||||
name: 'hasPdf',
|
||||
field: 'hasPdf',
|
||||
align: 'center'
|
||||
}
|
||||
]);
|
||||
|
||||
const getInvoiceUrl = id => {
|
||||
const params = new URLSearchParams({
|
||||
access_token: userStore.token
|
||||
});
|
||||
return `/api/InvoiceOuts/${id}/download?${params}`;
|
||||
};
|
||||
|
||||
const fetchInvoices = async () => {
|
||||
const params = {
|
||||
from: new Date(currentYear.value, 0),
|
||||
to: new Date(currentYear.value, 11, 31, 23, 59, 59)
|
||||
};
|
||||
invoices.value = await jApi.query(
|
||||
`SELECT id, ref, issued, amount, hasPdf
|
||||
FROM myInvoice
|
||||
WHERE issued BETWEEN #from AND #to
|
||||
ORDER BY issued DESC
|
||||
LIMIT 100`,
|
||||
params
|
||||
);
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
await fetchInvoices();
|
||||
for (let year = currentYear.value - 5; year <= currentYear.value; year++) {
|
||||
years.value.push(year);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Teleport :to="$actions">
|
||||
<QSelect
|
||||
v-model="currentYear"
|
||||
:options="years"
|
||||
color="white"
|
||||
dark
|
||||
standout
|
||||
dense
|
||||
rounded
|
||||
@update:model-value="fetchInvoices()"
|
||||
/>
|
||||
</Teleport>
|
||||
<div class="vn-w-sm">
|
||||
<QCard>
|
||||
<!-- -->
|
||||
<QTable
|
||||
:columns="columns"
|
||||
:rows="invoices"
|
||||
:no-data-label="t('noInvoicesFound')"
|
||||
row-key="id"
|
||||
:hide-header="!invoices.length"
|
||||
:rows-per-page-options="[0]"
|
||||
>
|
||||
<template #body-cell-hasPdf="{ row }">
|
||||
<QTd
|
||||
auto-width
|
||||
@click.stop
|
||||
class="flex full-width justify-center items-center"
|
||||
>
|
||||
<QBtn
|
||||
v-if="row.hasPdf"
|
||||
icon="download"
|
||||
:href="getInvoiceUrl(row.id)"
|
||||
target="_blank"
|
||||
flat
|
||||
round
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('downloadInvoicePdf') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
<QIcon
|
||||
v-else
|
||||
name="warning"
|
||||
:title="t('notDownloadable')"
|
||||
color="warning"
|
||||
size="sm"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('requestTheInvoiceToComercial') }}
|
||||
</QTooltip>
|
||||
</QIcon>
|
||||
</QTd>
|
||||
</template>
|
||||
</QTable>
|
||||
</QCard>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<i18n lang="yaml">
|
||||
en-US:
|
||||
noInvoicesFound: No invoices found
|
||||
serial: Serial
|
||||
issued: Date
|
||||
amount: Import
|
||||
downloadInvoicePdf: Download invoice PDF
|
||||
notDownloadable: Not available for download, request the invoice to your salesperson
|
||||
requestTheInvoiceToComercial: Request the invoice to your salesperson
|
||||
es-ES:
|
||||
noInvoicesFound: No se han encontrado facturas
|
||||
serial: Serie
|
||||
issued: Fecha
|
||||
amount: Importe
|
||||
downloadInvoicePdf: Descargar factura en PDF
|
||||
notDownloadable: No disponible para descarga, solicita la factura a tu comercial
|
||||
requestTheInvoiceToComercial: Solicita la factura a tu comercial
|
||||
ca-ES:
|
||||
noInvoicesFound: No s'han trobat factures
|
||||
serial: Sèrie
|
||||
issued: Data
|
||||
amount: Import
|
||||
downloadInvoicePdf: Descarregar PDF
|
||||
notDownloadable: No disponible per cescarrega, sol·licita la factura al teu comercial
|
||||
requestTheInvoiceToComercial: Sol·licita la factura al teu comercial
|
||||
fr-FR:
|
||||
noInvoicesFound: Aucune facture trouvée
|
||||
serial: Série
|
||||
issued: Date
|
||||
amount: Montant
|
||||
downloadInvoicePdf: Télécharger le PDF
|
||||
notDownloadable: Non disponible en téléchargement, demander la facture à votre commercial
|
||||
requestTheInvoiceToComercial: Demander la facture à votre commercial
|
||||
pt-PT:
|
||||
noInvoicesFound: Nenhuma fatura encontrada
|
||||
serial: Serie
|
||||
issued: Data
|
||||
amount: Importe
|
||||
downloadInvoicePdf: Baixar PDF
|
||||
notDownloadable: Não disponível para download, solicite a fatura ao seu comercial
|
||||
requestTheInvoiceToComercial: Solicite a fatura ao seu comercial
|
||||
</i18n>
|
|
@ -1,70 +1,112 @@
|
|||
<script setup>
|
||||
import { ref, onMounted, inject } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import CardList from 'src/components/ui/CardList.vue';
|
||||
|
||||
import { currency, formatDateTitle } from 'src/lib/filters.js';
|
||||
import { tpvStore } from 'stores/tpv';
|
||||
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const jApi = inject('jApi');
|
||||
|
||||
const orders = ref(null);
|
||||
const debt = ref(0);
|
||||
const tpv = tpvStore();
|
||||
|
||||
onMounted(async () => {
|
||||
await tpv.check(route);
|
||||
|
||||
orders.value = await jApi.query('CALL myTicket_list(NULL, NULL)');
|
||||
debt.value = await jApi.getValue('SELECT -myClient_getDebt(NULL)');
|
||||
});
|
||||
|
||||
const onPayClick = async () => {
|
||||
let amount = -debt.value;
|
||||
amount = amount <= 0 ? null : amount;
|
||||
|
||||
let defaultAmountStr = '';
|
||||
if (amount !== null) {
|
||||
defaultAmountStr = amount;
|
||||
}
|
||||
|
||||
amount = prompt(t('amountToPay'), defaultAmountStr);
|
||||
|
||||
if (amount != null) {
|
||||
amount = parseFloat(amount.replace(',', '.'));
|
||||
await tpv.pay(amount);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Teleport :to="$actions">
|
||||
<div class="balance">
|
||||
<span class="label">{{ $t('balance') }}</span>
|
||||
<span class="label">{{ t('balance') }}</span>
|
||||
<span class="amount" :class="{ negative: debt < 0 }">
|
||||
{{ currency(debt || 0) }}
|
||||
</span>
|
||||
<QIcon
|
||||
name="info"
|
||||
:title="$t('paymentInfo')"
|
||||
:title="t('paymentInfo')"
|
||||
class="info"
|
||||
size="24px"
|
||||
size="sm"
|
||||
/>
|
||||
</div>
|
||||
<QBtn
|
||||
icon="payments"
|
||||
:label="$t('makePayment')"
|
||||
:label="t('makePayment')"
|
||||
@click="onPayClick()"
|
||||
rounded
|
||||
no-caps
|
||||
/>
|
||||
<QBtn
|
||||
to="/ecomerce/basket"
|
||||
:to="{ name: 'basket' }"
|
||||
icon="shopping_cart"
|
||||
:label="$t('shoppingCart')"
|
||||
:label="t('shoppingCart')"
|
||||
rounded
|
||||
no-caps
|
||||
/>
|
||||
</Teleport>
|
||||
<div class="vn-w-sm">
|
||||
<QPage class="vn-w-sm">
|
||||
<div
|
||||
v-if="!orders?.length"
|
||||
class="text-subtitle1 text-center text-grey-7 q-pa-md"
|
||||
>
|
||||
{{ $t('noOrdersFound') }}
|
||||
{{ t('noOrdersFound') }}
|
||||
</div>
|
||||
<QCard v-if="orders?.length">
|
||||
<QList bordered separator padding>
|
||||
<QItem
|
||||
<QList v-if="orders?.length">
|
||||
<CardList
|
||||
v-for="order in orders"
|
||||
:key="order.id"
|
||||
:to="`ticket/${order.id}`"
|
||||
clickable
|
||||
v-ripple
|
||||
tag="label"
|
||||
>
|
||||
<QItemSection>
|
||||
<QItemLabel>
|
||||
{{ date(order.landed, 'ddd, MMMM Do') }}
|
||||
<template #content>
|
||||
<QItemLabel
|
||||
class="full-width text-bold q-mb-sm flex row justify-between"
|
||||
>
|
||||
<span>{{ formatDateTitle(order.landed) }}</span>
|
||||
<span>{{ currency(order.total) }}</span>
|
||||
</QItemLabel>
|
||||
<QItemLabel caption>#{{ order.id }}</QItemLabel>
|
||||
<QItemLabel caption>{{ order.nickname }}</QItemLabel>
|
||||
<QItemLabel caption>{{ order.agency }}</QItemLabel>
|
||||
</QItemSection>
|
||||
<QItemSection side top> {{ order.total }}€ </QItemSection>
|
||||
</QItem>
|
||||
<QItemLabel>#{{ order.id }}</QItemLabel>
|
||||
<QItemLabel>{{ order.nickname }}</QItemLabel>
|
||||
<QItemLabel>{{ order.agency }}</QItemLabel>
|
||||
</template>
|
||||
</CardList>
|
||||
</QList>
|
||||
</QCard>
|
||||
<QPageSticky>
|
||||
<QBtn
|
||||
fab
|
||||
icon="add_shopping_cart"
|
||||
color="accent"
|
||||
to="/ecomerce/catalog"
|
||||
:title="$t('startOrder')"
|
||||
:to="{ name: 'catalog' }"
|
||||
:title="t('startOrder')"
|
||||
/>
|
||||
</QPageSticky>
|
||||
</div>
|
||||
</QPage>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -92,50 +134,6 @@
|
|||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { date, currency } from 'src/lib/filters.js';
|
||||
import { tpvStore } from 'stores/tpv';
|
||||
|
||||
export default {
|
||||
name: 'OrdersPendingIndex',
|
||||
data() {
|
||||
return {
|
||||
orders: null,
|
||||
debt: 0,
|
||||
tpv: tpvStore()
|
||||
};
|
||||
},
|
||||
|
||||
async mounted() {
|
||||
await this.tpv.check(this.$route);
|
||||
|
||||
this.orders = await this.$jApi.query('CALL myTicket_list(NULL, NULL)');
|
||||
this.debt = await this.$jApi.getValue('SELECT -myClient_getDebt(NULL)');
|
||||
},
|
||||
|
||||
methods: {
|
||||
date,
|
||||
currency,
|
||||
|
||||
async onPayClick() {
|
||||
let amount = -this.debt;
|
||||
amount = amount <= 0 ? null : amount;
|
||||
|
||||
let defaultAmountStr = '';
|
||||
if (amount !== null) {
|
||||
defaultAmountStr = amount;
|
||||
}
|
||||
amount = prompt(this.$t('amountToPay'), defaultAmountStr);
|
||||
|
||||
if (amount != null) {
|
||||
amount = parseFloat(amount.replace(',', '.'));
|
||||
await this.tpv.pay(amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<i18n lang="yaml">
|
||||
en-US:
|
||||
startOrder: Start order
|
||||
|
@ -148,6 +146,7 @@ en-US:
|
|||
disregards future orders. For get your order shipped, this amount must be
|
||||
equal to or greater than 0. If you want to make a down payment, click the
|
||||
payment button, delete the suggested amount and enter the amount you want.
|
||||
amountToPay: 'Amount to pay (€):'
|
||||
es-ES:
|
||||
startOrder: Empezar pedido
|
||||
noOrdersFound: No se encontrado pedidos
|
||||
|
@ -160,6 +159,7 @@ es-ES:
|
|||
esta cantidad debe ser igual o mayor que 0. Si quieres realizar una entrega a
|
||||
cuenta, pulsa el botón de pago, borra la cantidad sugerida e introduce la
|
||||
cantidad que desees.
|
||||
amountToPay: 'Cantidad a pagar (€):'
|
||||
ca-ES:
|
||||
startOrder: Començar encàrrec
|
||||
noOrdersFound: No s'han trobat comandes
|
||||
|
@ -172,6 +172,7 @@ ca-ES:
|
|||
enviat, aquesta quantitat ha de ser igual o més gran que 0. Si vols fer un
|
||||
lliurament a compte, prem el botó de pagament, esborra la quantitat suggerida
|
||||
e introdueix la quantitat que vulguis.
|
||||
amountToPay: 'Quantitat a pagar (€):'
|
||||
fr-FR:
|
||||
startOrder: Acheter
|
||||
noOrdersFound: Aucune commande trouvée
|
||||
|
@ -184,6 +185,7 @@ fr-FR:
|
|||
commande est expédiée, ce montant doit être égal ou supérieur à 0. Si vous
|
||||
voulez faire un versement, le montant suggéré effacé et entrez le montant que
|
||||
vous souhaitez.
|
||||
amountToPay: 'Montant à payer (€):'
|
||||
pt-PT:
|
||||
startOrder: Iniciar encomenda
|
||||
noOrdersFound: Nenhum pedido encontrado
|
||||
|
@ -196,4 +198,5 @@ pt-PT:
|
|||
quantidade deve ser igual ou superior a 0. Se queres realizar um depósito à
|
||||
conta, clique no botão de pagamento, apague a quantidade sugerida e introduza
|
||||
a quantidade que deseje.
|
||||
amountToPay: 'Valor a pagar (€):'
|
||||
</i18n>
|
|
@ -1,18 +1,20 @@
|
|||
<script setup>
|
||||
import { ref, inject, onMounted } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { date } from 'quasar';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import CardList from 'src/components/ui/CardList.vue';
|
||||
import { toCurrency } from 'src/filters/index';
|
||||
import { currency, formatDateTitle } from 'src/lib/filters.js';
|
||||
import { useVnConfirm } from 'src/composables/useVnConfirm.js';
|
||||
import useNotify from 'src/composables/useNotify.js';
|
||||
import { useAppStore } from 'src/stores/app.js';
|
||||
|
||||
const jApi = inject('jApi');
|
||||
const { t, locale } = useI18n();
|
||||
const globalI18n = useI18n({ useScope: 'global' });
|
||||
const { t } = useI18n();
|
||||
const { openConfirmationModal } = useVnConfirm();
|
||||
const { notify } = useNotify();
|
||||
const store = useAppStore();
|
||||
const router = useRouter();
|
||||
|
||||
const orders = ref([]);
|
||||
|
||||
|
@ -32,18 +34,6 @@ const getOrders = async () => {
|
|||
}
|
||||
};
|
||||
|
||||
const formatDateTitle = timeStamp => {
|
||||
const formattedString = date.formatDate(
|
||||
timeStamp,
|
||||
`dddd, D [${t('of')}] MMMM [${t('of')}] YYYY`,
|
||||
{
|
||||
days: globalI18n.messages.value[locale.value].date.days,
|
||||
months: globalI18n.messages.value[locale.value].date.months
|
||||
}
|
||||
);
|
||||
return formattedString;
|
||||
};
|
||||
|
||||
const removeOrder = async (id, index) => {
|
||||
try {
|
||||
await jApi.execQuery(
|
||||
|
@ -61,6 +51,11 @@ const removeOrder = async (id, index) => {
|
|||
}
|
||||
};
|
||||
|
||||
const loadOrder = orderId => {
|
||||
store.loadIntoBasket(orderId);
|
||||
router.push({ name: 'catalog' });
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
getOrders();
|
||||
});
|
||||
|
@ -69,30 +64,34 @@ onMounted(async () => {
|
|||
<template>
|
||||
<Teleport :to="$actions">
|
||||
<QBtn
|
||||
to="/ecomerce/basket"
|
||||
icon="shopping_cart"
|
||||
:label="$t('shoppingCart')"
|
||||
:to="{ name: 'checkout' }"
|
||||
icon="add_shopping_cart"
|
||||
:label="t('newOrder')"
|
||||
rounded
|
||||
no-caps
|
||||
/>
|
||||
</Teleport>
|
||||
<QPage class="vn-w-sm">
|
||||
<CardList v-for="(order, index) in orders" :key="index">
|
||||
<CardList
|
||||
v-for="(order, index) in orders"
|
||||
:key="index"
|
||||
:to="{ name: 'basket', params: { id: order.id } }"
|
||||
>
|
||||
<template #content>
|
||||
<span class="text-bold q-mb-sm">{{
|
||||
<QItemLabel class="text-bold q-mb-sm">{{
|
||||
formatDateTitle(order.sent)
|
||||
}}</span>
|
||||
<span> #{{ order.id }} </span>
|
||||
<span>{{ order.nickname }}</span>
|
||||
<span>{{ order.agency }}</span>
|
||||
<span>{{ toCurrency(order.taxableBase) }}</span>
|
||||
}}</QItemLabel>
|
||||
<QItemLabel> #{{ order.id }} </QItemLabel>
|
||||
<QItemLabel>{{ order.nickname }}</QItemLabel>
|
||||
<QItemLabel>{{ order.agency }}</QItemLabel>
|
||||
<QItemLabel>{{ currency(order.taxableBase) }}</QItemLabel>
|
||||
</template>
|
||||
<template #actions>
|
||||
<QBtn
|
||||
icon="delete"
|
||||
flat
|
||||
rounded
|
||||
@click.stop="
|
||||
@click.stop.prevent="
|
||||
openConfirmationModal(
|
||||
null,
|
||||
t('areYouSureDeleteOrder'),
|
||||
|
@ -104,8 +103,7 @@ onMounted(async () => {
|
|||
icon="shopping_bag"
|
||||
flat
|
||||
rounded
|
||||
:to="{ name: 'basket', params: { id: order.id } }"
|
||||
@click.stop="goToAddressDetails(address.id)"
|
||||
@click.stop.prevent="loadOrder(order.id)"
|
||||
/>
|
||||
</template>
|
||||
</CardList>
|
||||
|
|
|
@ -1,145 +0,0 @@
|
|||
<template>
|
||||
<Teleport :to="$actions">
|
||||
<QBtn
|
||||
icon="print"
|
||||
:label="$t('printDeliveryNote')"
|
||||
@click="onPrintClick()"
|
||||
rounded
|
||||
no-caps
|
||||
/>
|
||||
</Teleport>
|
||||
<div>
|
||||
<QCard class="vn-w-sm">
|
||||
<QCardSection>
|
||||
<div class="text-h6">#{{ ticket.id }}</div>
|
||||
</QCardSection>
|
||||
<QCardSection>
|
||||
<div class="text-h6">{{ $t('shippingInformation') }}</div>
|
||||
<div>
|
||||
{{ $t('preparation') }}
|
||||
{{ date(ticket.shipped, 'ddd, MMMM Do') }}
|
||||
</div>
|
||||
<div>
|
||||
{{ $t('delivery') }}
|
||||
{{ date(ticket.shipped, 'ddd, MMMM Do') }}
|
||||
</div>
|
||||
<div>
|
||||
{{ $t(ticket.method != 'PICKUP' ? 'agency' : 'warehouse') }}
|
||||
{{ ticket.agency }}
|
||||
</div>
|
||||
</QCardSection>
|
||||
<QCardSection>
|
||||
<div class="text-h6">{{ $t('deliveryAddress') }}</div>
|
||||
<div>{{ ticket.nickname }}</div>
|
||||
<div>{{ ticket.street }}</div>
|
||||
<div>
|
||||
{{ ticket.postalCode }} {{ ticket.city }} ({{
|
||||
ticket.province
|
||||
}})
|
||||
</div>
|
||||
</QCardSection>
|
||||
<QSeparator inset />
|
||||
<QList v-for="row in rows" :key="row.itemFk">
|
||||
<QItem>
|
||||
<QItemSection avatar>
|
||||
<QAvatar size="68px">
|
||||
<img
|
||||
:src="`${$app.imageUrl}/catalog/200x200/${row.image}`"
|
||||
/>
|
||||
</QAvatar>
|
||||
</QItemSection>
|
||||
<QItemSection>
|
||||
<QItemLabel lines="1">
|
||||
{{ row.concept }}
|
||||
</QItemLabel>
|
||||
<QItemLabel lines="1" caption>
|
||||
{{ row.value5 }} {{ row.value6 }} {{ row.value7 }}
|
||||
</QItemLabel>
|
||||
<QItemLabel lines="1">
|
||||
{{ row.quantity }} x {{ currency(row.price) }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
<QItemSection side class="total">
|
||||
<QItemLabel>
|
||||
<span class="discount" v-if="row.discount">
|
||||
{{ currency(discountSubtotal(row)) }} -
|
||||
{{ currency(row.discount) }} =
|
||||
</span>
|
||||
{{ currency(subtotal(row)) }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</QList>
|
||||
</QCard>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.total {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { date, currency } from 'src/lib/filters.js';
|
||||
|
||||
export default {
|
||||
name: 'OrdersConfirmedView',
|
||||
|
||||
data() {
|
||||
return {
|
||||
ticket: {},
|
||||
rows: null,
|
||||
services: null,
|
||||
packages: null
|
||||
};
|
||||
},
|
||||
|
||||
async mounted() {
|
||||
const params = {
|
||||
ticket: parseInt(this.$route.params.id)
|
||||
};
|
||||
this.ticket = await this.$jApi.getObject(
|
||||
'CALL myTicket_get(#ticket)',
|
||||
params
|
||||
);
|
||||
this.rows = await this.$jApi.query(
|
||||
'CALL myTicket_getRows(#ticket)',
|
||||
params
|
||||
);
|
||||
this.services = await this.$jApi.query(
|
||||
'CALL myTicket_getServices(#ticket)',
|
||||
params
|
||||
);
|
||||
this.packages = await this.$jApi.query(
|
||||
'CALL myTicket_getPackages(#ticket)',
|
||||
params
|
||||
);
|
||||
},
|
||||
|
||||
methods: {
|
||||
date,
|
||||
currency,
|
||||
|
||||
discountSubtotal(line) {
|
||||
return line.quantity * line.price;
|
||||
},
|
||||
|
||||
subtotal(line) {
|
||||
const discount = line.discount;
|
||||
return this.discountSubtotal(line) * ((100 - discount) / 100);
|
||||
},
|
||||
|
||||
onPrintClick() {
|
||||
const params = new URLSearchParams({
|
||||
access_token: this.$user.token,
|
||||
recipientId: this.$user.id,
|
||||
type: 'deliveryNote'
|
||||
});
|
||||
window.open(
|
||||
`/api/Tickets/${this.ticket.id}/delivery-note-pdf?${params.toString()}`
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,74 @@
|
|||
<script setup>
|
||||
import { onMounted, inject, ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import TicketDetails from 'src/components/ui/TicketDetails.vue';
|
||||
|
||||
import { userStore as useUserStore } from 'stores/user';
|
||||
|
||||
const { t } = useI18n();
|
||||
const jApi = inject('jApi');
|
||||
const route = useRoute();
|
||||
const userStore = useUserStore();
|
||||
|
||||
const ticket = ref({});
|
||||
const rows = ref([]);
|
||||
const services = ref(null);
|
||||
const packages = ref(null);
|
||||
|
||||
onMounted(async () => {
|
||||
const params = {
|
||||
ticket: parseInt(route.params.id)
|
||||
};
|
||||
ticket.value = await jApi.getObject('CALL myTicket_get(#ticket)', params);
|
||||
rows.value = await jApi.query('CALL myTicket_getRows(#ticket)', params);
|
||||
services.value = await jApi.query(
|
||||
'CALL myTicket_getServices(#ticket)',
|
||||
params
|
||||
);
|
||||
packages.value = await jApi.query(
|
||||
'CALL myTicket_getPackages(#ticket)',
|
||||
params
|
||||
);
|
||||
});
|
||||
|
||||
const onPrintClick = () => {
|
||||
const params = new URLSearchParams({
|
||||
access_token: userStore.token,
|
||||
recipientId: userStore.id,
|
||||
type: 'deliveryNote'
|
||||
});
|
||||
window.open(
|
||||
`/api/Tickets/${ticket.value.id}/delivery-note-pdf?${params.toString()}`
|
||||
);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Teleport :to="$actions">
|
||||
<QBtn
|
||||
icon="print"
|
||||
:label="t('printDeliveryNote')"
|
||||
@click="onPrintClick()"
|
||||
rounded
|
||||
no-caps
|
||||
/>
|
||||
</Teleport>
|
||||
<QPage>
|
||||
<TicketDetails :rows="rows" :ticket="ticket" />
|
||||
</QPage>
|
||||
</template>
|
||||
|
||||
<i18n lang="yaml">
|
||||
en-US:
|
||||
printDeliveryNote: Print delivery note
|
||||
es-ES:
|
||||
printDeliveryNote: Imprimir albarán
|
||||
ca-ES:
|
||||
printDeliveryNote: Imprimir albarà
|
||||
fr-FR:
|
||||
printDeliveryNote: Imprimer bulletin de livraison
|
||||
pt-PT:
|
||||
printDeliveryNote: Imprimir nota de entrega
|
||||
</i18n>
|
|
@ -1,5 +1,5 @@
|
|||
import { route } from 'quasar/wrappers';
|
||||
import { appStore } from 'stores/app';
|
||||
import { useAppStore } from 'stores/app';
|
||||
import {
|
||||
createRouter,
|
||||
createMemoryHistory,
|
||||
|
@ -39,7 +39,7 @@ export default route(function (/* { store, ssrContext } */) {
|
|||
|
||||
Router.afterEach((to, from) => {
|
||||
if (from.name === to.name) return;
|
||||
const app = appStore();
|
||||
const app = useAppStore();
|
||||
app.$patch({
|
||||
title: i18n.global.t(to.name || 'home'),
|
||||
subtitle: null,
|
||||
|
|
|
@ -37,17 +37,17 @@ const routes = [
|
|||
{
|
||||
name: 'confirmedOrders',
|
||||
path: '/ecomerce/orders',
|
||||
component: () => import('pages/Ecomerce/Orders.vue')
|
||||
component: () => import('pages/Ecomerce/OrdersView.vue')
|
||||
},
|
||||
{
|
||||
name: 'ticket',
|
||||
path: '/ecomerce/ticket/:id',
|
||||
component: () => import('pages/Ecomerce/Ticket.vue')
|
||||
component: () => import('pages/Ecomerce/TicketView.vue')
|
||||
},
|
||||
{
|
||||
name: 'invoices',
|
||||
path: '/ecomerce/invoices',
|
||||
component: () => import('pages/Ecomerce/Invoices.vue')
|
||||
component: () => import('pages/Ecomerce/InvoicesView.vue')
|
||||
},
|
||||
{
|
||||
name: 'pendingOrders',
|
||||
|
@ -59,6 +59,16 @@ const routes = [
|
|||
path: '/ecomerce/catalog/:category?/:type?',
|
||||
component: () => import('pages/Ecomerce/Catalog.vue')
|
||||
},
|
||||
{
|
||||
name: 'basket',
|
||||
path: '/ecomerce/basket/:id?',
|
||||
component: () => import('pages/Ecomerce/BasketView.vue')
|
||||
},
|
||||
{
|
||||
name: 'checkout',
|
||||
path: '/ecomerce/checkout',
|
||||
component: () => import('pages/Ecomerce/CheckoutView.vue')
|
||||
},
|
||||
{
|
||||
name: 'agencyPackages',
|
||||
path: '/agencies/packages',
|
||||
|
|
|
@ -1,19 +1,51 @@
|
|||
import { defineStore } from 'pinia'
|
||||
import { jApi } from 'boot/axios'
|
||||
import { defineStore } from 'pinia';
|
||||
import { jApi } from 'boot/axios';
|
||||
import useNotify from 'src/composables/useNotify.js';
|
||||
|
||||
export const appStore = defineStore('hedera', {
|
||||
const { notify } = useNotify();
|
||||
|
||||
export const useAppStore = defineStore('hedera', {
|
||||
state: () => ({
|
||||
title: null,
|
||||
subtitle: null,
|
||||
imageUrl: '',
|
||||
useRightDrawer: false,
|
||||
rightDrawerOpen: false
|
||||
rightDrawerOpen: false,
|
||||
basketOrderId: null
|
||||
}),
|
||||
|
||||
actions: {
|
||||
async loadConfig () {
|
||||
const imageUrl = await jApi.getValue('SELECT url FROM imageConfig')
|
||||
this.$patch({ imageUrl })
|
||||
async init() {
|
||||
this.getBasketOrderId();
|
||||
},
|
||||
|
||||
getBasketOrderId() {
|
||||
this.basketOrderId = localStorage.getItem('hederaBasket');
|
||||
},
|
||||
|
||||
async loadConfig() {
|
||||
const imageUrl = await jApi.getValue('SELECT url FROM imageConfig');
|
||||
this.$patch({ imageUrl });
|
||||
},
|
||||
|
||||
async checkOrder(orderId) {
|
||||
try {
|
||||
const resultSet = await jApi.execQuery(
|
||||
'CALL myOrder_checkConfig(#id)',
|
||||
{ id: orderId }
|
||||
);
|
||||
resultSet.fetchValue();
|
||||
} catch (err) {
|
||||
console.error('Error checking order', err);
|
||||
}
|
||||
},
|
||||
|
||||
loadIntoBasket(orderId) {
|
||||
if (this.basketOrderId !== orderId) {
|
||||
localStorage.setItem('hederaBasket', orderId);
|
||||
this.basketOrderId = orderId;
|
||||
notify('orderLoadedIntoBasket', 'positive');
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { store } from 'quasar/wrappers'
|
||||
import { createPinia } from 'pinia'
|
||||
import { store } from 'quasar/wrappers';
|
||||
import { createPinia } from 'pinia';
|
||||
|
||||
/*
|
||||
* If not building with SSR mode, you can
|
||||
|
@ -11,10 +11,10 @@ import { createPinia } from 'pinia'
|
|||
*/
|
||||
|
||||
export default store((/* { ssrContext } */) => {
|
||||
const pinia = createPinia()
|
||||
const pinia = createPinia();
|
||||
|
||||
// You can add Pinia plugins here
|
||||
// pinia.use(SomePiniaPlugin)
|
||||
|
||||
return pinia
|
||||
})
|
||||
return pinia;
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue