Order checkout

This commit is contained in:
Juan Ferrer 2019-08-30 12:59:49 +02:00
parent 29acd913ee
commit 703d6932ff
16 changed files with 729 additions and 84 deletions

View File

@ -1,6 +1,50 @@
const warehouseIds = [1, 44]; const warehouseIds = [1, 44];
module.exports = Self => { module.exports = Self => {
Self.remoteMethod('calcCatalog', {
description: 'Get the available and prices list for an item',
accessType: 'READ',
accepts: [
{
arg: 'id',
type: 'Number',
description: 'The item id'
}, {
arg: 'dated',
type: 'Date',
description: 'The date'
}, {
arg: 'addressFk',
type: 'Number',
description: 'The address id'
}, {
arg: 'agencyModeFk',
type: 'Number',
description: 'The agency id'
}
],
returns: {
type: ['Object'],
description: 'The item available and prices list',
root: true,
},
http: {
path: `/:id/calcCatalog`,
verb: 'GET'
}
});
Self.calcCatalog = (id, dated, addressFk, agencyModeFk, cb) => {
Self.dataSource.connector.query(
`CALL hedera.item_calcCatalog(?, ?, ?, ?)`,
[id, dated, addressFk, agencyModeFk],
(err, res) => {
if (err) return cb(err)
return cb(null, res[0])
}
);
};
Self.remoteMethod('catalog', { Self.remoteMethod('catalog', {
description: 'Get the catalog', description: 'Get the catalog',
accessType: 'READ', accessType: 'READ',

View File

@ -3,7 +3,7 @@
"base": "PersistedModel", "base": "PersistedModel",
"options": { "options": {
"mysql": { "mysql": {
"table": "hedera.orderRow" "table": "hedera.orderRow"
} }
}, },
"properties": { "properties": {

View File

@ -3,7 +3,7 @@
"base": "PersistedModel", "base": "PersistedModel",
"options": { "options": {
"mysql": { "mysql": {
"table": "hedera.order" "table": "hedera.order"
} }
}, },
"properties": { "properties": {
@ -79,9 +79,23 @@
"mysql": { "mysql": {
"columnName": "confirm_date" "columnName": "confirm_date"
} }
},
"taxableBase": {
"type": "Number"
},
"tax": {
"type": "Number"
},
"total": {
"type": "Number"
} }
}, },
"relations": { "relations": {
"rows": {
"type": "hasMany",
"model": "OrderRow",
"foreignKey": "orderFk"
},
"agencyMode": { "agencyMode": {
"type": "belongsTo", "type": "belongsTo",
"model": "AgencyMode", "model": "AgencyMode",
@ -101,11 +115,6 @@
"type": "belongsTo", "type": "belongsTo",
"model": "DeliveryMethod", "model": "DeliveryMethod",
"foreignKey": "delivery_method_id" "foreignKey": "delivery_method_id"
},
"rows": {
"type": "hasMany",
"model": "OrderRow",
"foreignKey": "orderFk"
} }
} }
} }

View File

@ -52,6 +52,7 @@ module.exports = function (ctx) {
'QItemLabel', 'QItemLabel',
'QList', 'QList',
'QLayout', 'QLayout',
'QMarkupTable',
'QPageContainer', 'QPageContainer',
'QPage', 'QPage',
'QPageSticky', 'QPageSticky',
@ -79,8 +80,8 @@ module.exports = function (ctx) {
'ClosePopup' 'ClosePopup'
], ],
// Quasar plugins
plugins: [ plugins: [
'Dialog',
'Notify' 'Notify'
] ]

View File

@ -6,7 +6,7 @@ export default async ({ app, Vue }) => {
let i18n = app.i18n let i18n = app.i18n
function currency (val) { function currency (val) {
return val ? val.toFixed(2) + '€' : val return typeof val === 'number' ? val.toFixed(2) + '€' : val
} }
function date (val, format) { function date (val, format) {

View File

@ -9,7 +9,11 @@ export default async ({ app, Vue }) => {
title: null, title: null,
subtitle: null, subtitle: null,
useRightDrawer: false, useRightDrawer: false,
rightDrawerOpen: true rightDrawerOpen: true,
catalogConfig: {
agencyModeFk: 2,
addressFk: 1823
}
}) })
Vue.prototype.$state = state Vue.prototype.$state = state
} }

View File

@ -115,7 +115,7 @@ export default {
params.filter = filter params.filter = filter
limit = filter.limit limit = filter.limit
if (!limit) { if (limit === undefined) {
limit = this.index * 30 limit = this.index * 30
filter.limit = limit filter.limit = limit
} }
@ -149,7 +149,7 @@ export default {
this.doRequest() this.doRequest()
.then(res => { .then(res => {
if (!res) return done(true) if (!res) return done(true)
done(!res.limit || res.data.length < res.limit) done(!res.limit || !Array.isArray(res.data) || res.data.length < res.limit)
return res return res
}) })
.catch(err => { .catch(err => {

View File

@ -1,9 +1,5 @@
export default { export default {
// Login // global
enter: 'Enter',
email: 'E-Mail',
password: 'Password',
remember: 'Don not close session',
search: 'Search', search: 'Search',
accept: 'Accept', accept: 'Accept',
cancel: 'Cancel', cancel: 'Cancel',
@ -22,6 +18,7 @@ export default {
createdSuccess: 'Item created successfully', createdSuccess: 'Item created successfully',
fieldIsRequired: 'Field is required', fieldIsRequired: 'Field is required',
setSearchFilter: 'Please, set a search filter', setSearchFilter: 'Please, set a search filter',
id: 'Id',
today: 'Today', today: 'Today',
yesterday: 'Yesterday', yesterday: 'Yesterday',
tomorrow: 'Tomorrow', tomorrow: 'Tomorrow',
@ -81,7 +78,13 @@ export default {
logout: 'Logout', logout: 'Logout',
visitor: 'Visitor', visitor: 'Visitor',
// Menu // login
enter: 'Enter',
email: 'E-Mail',
password: 'Password',
remember: 'Don not close session',
// menu
home: 'Home', home: 'Home',
catalog: 'Catalog', catalog: 'Catalog',
orders: 'Orders', orders: 'Orders',
@ -104,7 +107,7 @@ export default {
addressEdit: 'Edit address', addressEdit: 'Edit address',
register: 'Register', register: 'Register',
// Home // home
recentNews: 'Recent news', recentNews: 'Recent news',
startOrder: 'Start order', startOrder: 'Start order',
@ -123,7 +126,7 @@ export default {
n1InPrice: 'Nº1 in price', n1InPrice: 'Nº1 in price',
ourBigVolumeAllows: 'our big volume allows us to offer the best prices', ourBigVolumeAllows: 'our big volume allows us to offer the best prices',
// Catalog // catalog
more: 'More', more: 'More',
noItemsFound: 'No items found', noItemsFound: 'No items found',
pleaseSetFilter: 'Please, set a filter using the right menu', pleaseSetFilter: 'Please, set a filter using the right menu',
@ -146,21 +149,60 @@ export default {
siceAsc: 'Ascending size', siceAsc: 'Ascending size',
sizeDesc: 'Descencing size', sizeDesc: 'Descencing size',
// Orders // orders
ordersMadeAt: 'Orders made at',
pendingConfirmtion: 'Pending confirmation',
noOrdersFound: 'No orders found',
pending: 'Pending', pending: 'Pending',
confirmed: 'Confirmed', confirmed: 'Confirmed',
// orders
pendingConfirmtion: 'Pending confirmation',
noOrdersFound: 'No orders found',
// orders
ordersMadeAt: 'Orders made at',
packages: '{n} packages', packages: '{n} packages',
// Conditions // order
total: 'Total',
confirm: 'Confirm',
delivery: 'Delivery date',
address: 'Address',
agency: 'Agency',
warehouse: 'Warehouse',
configure: 'Configure',
// order/checkout
checkout: 'Checkout',
orderSummary: 'Order summary',
accountsSummary: 'Accounts summary',
previousBalance: 'Previous balance',
orderTotal: 'Order total',
vat: 'VAT',
totalDebt: 'Total debt',
credit: 'Credit',
exceededCredit: 'Exceeded credit',
payAmount: 'Amount to pay',
payMethod: 'Pay method',
useMyBalance: 'Use my balance',
youHaveFaborableBalance: 'You do not need to perform any payment, you have a favorable balance.',
useMyCredit: 'Use my credit',
youHaveFaborableCredit: 'You do not need to pay now, you have a favorable credit.',
creditCard: 'Credit card',
youWillRedirectToPayment: 'By confirming the order you will be redirected to the payment platform.',
bankTransfer: 'Bank Transfer',
makeTransfer: 'Make a transfer to the following account and send the receipt to your salesperson.',
payLater: 'Pay later',
doYouWantToConfirm: 'Do you want to confirm the order?',
orderConfirmedSuccessfully: 'Your order has been confirmed successfully',
youExceededCredit: 'You have exceeded your credit, in order to prepare your order please pay your debt.',
notes: 'Notes',
// conditions
conditionsDesc: 'The order will arrive to your home in 24/48 hours depending on which area you are.', conditionsDesc: 'The order will arrive to your home in 24/48 hours depending on which area you are.',
// About // about
aboutDesc: 'Verdnatura offers all services for your florist.', aboutDesc: 'Verdnatura offers all services for your florist.',
// Connections // connections
nConnections: '{0} connections', nConnections: '{0} connections',
refreshRate: 'Refresh rate', refreshRate: 'Refresh rate',
lastAction: 'Last actions', lastAction: 'Last actions',
@ -168,27 +210,27 @@ export default {
nSeconds: '{0} seconds', nSeconds: '{0} seconds',
dontRefresh: 'Do not refresh', dontRefresh: 'Do not refresh',
// Visits // accessLog
accessLog: 'Access log',
// visits
visitsCount: '{0} visits, {1} new', visitsCount: '{0} visits, {1} new',
// New // new
title: 'Title', title: 'Title',
image: 'Image', image: 'Image',
tag: 'Tag', tag: 'Tag',
priority: 'Priority', priority: 'Priority',
text: 'Text', text: 'Text',
// Images // images
collection: 'Collection', collection: 'Collection',
updateMatchingId: 'Update items with matching id', updateMatchingId: 'Update items with matching id',
uploadAutomatically: 'Upload automatically', uploadAutomatically: 'Upload automatically',
imagesUploadSuccess: 'Images uploaded successfully', imagesUploadSuccess: 'Images uploaded successfully',
imagesUploadFailed: 'Some images could not be uploaded', imagesUploadFailed: 'Some images could not be uploaded',
// User // user
accessLog: 'Access log',
// Config
userName: 'Username', userName: 'Username',
nickname: 'Nickname', nickname: 'Nickname',
language: 'Language', language: 'Language',
@ -207,14 +249,14 @@ export default {
passwordsDontMatch: 'Passwords do not match', passwordsDontMatch: 'Passwords do not match',
passwordChanged: 'Password changed successfully!', passwordChanged: 'Password changed successfully!',
// Addresses // addresses
setAsDefault: 'Set as default', setAsDefault: 'Set as default',
addressSetAsDefault: 'Address set as default', addressSetAsDefault: 'Address set as default',
addressRemoved: 'Address removed', addressRemoved: 'Address removed',
areYouSureDeleteAddress: 'Are you sure you want to delete the address?', areYouSureDeleteAddress: 'Are you sure you want to delete the address?',
addressCreated: 'Address created successfully!', addressCreated: 'Address created successfully!',
// Address // address
consignatary: 'Consignatary', consignatary: 'Consignatary',
street: 'Street', street: 'Street',
city: 'City', city: 'City',
@ -224,7 +266,7 @@ export default {
phone: 'Phone', phone: 'Phone',
mobile: 'Mobile', mobile: 'Mobile',
// Register // register
registerAsNew: 'Registrarse como nuevo usuario', registerAsNew: 'Registrarse como nuevo usuario',
notYetUser: 'You are not yet a user, register now and start enjoying everything that Verdnatura offers you.', notYetUser: 'You are not yet a user, register now and start enjoying everything that Verdnatura offers you.',
receiveOffers: 'Receive offers and promotions by e-mail', receiveOffers: 'Receive offers and promotions by e-mail',

View File

@ -1,9 +1,5 @@
export default { export default {
// Login // global
enter: 'Entrar',
email: 'Correo electrónico',
password: 'Contraseña',
remember: 'No cerrar sesión',
search: 'Buscar', search: 'Buscar',
accept: 'Aceptar', accept: 'Aceptar',
cancel: 'Cancelar', cancel: 'Cancelar',
@ -22,6 +18,7 @@ export default {
createdSuccess: 'Elemento creado correctamente', createdSuccess: 'Elemento creado correctamente',
fieldIsRequired: 'Campo requerido', fieldIsRequired: 'Campo requerido',
setSearchFilter: 'Por favor, establece un filtro de búsqueda', setSearchFilter: 'Por favor, establece un filtro de búsqueda',
id: 'Id',
today: 'Hoy', today: 'Hoy',
yesterday: 'Ayer', yesterday: 'Ayer',
tomorrow: 'Mañana', tomorrow: 'Mañana',
@ -76,12 +73,18 @@ export default {
] ]
}, },
// Layout // layout
login: 'Iniciar sesión', login: 'Iniciar sesión',
logout: 'Cerrar sesión', logout: 'Cerrar sesión',
visitor: 'Visitante', visitor: 'Visitante',
// Menu // login
enter: 'Entrar',
email: 'Correo electrónico',
password: 'Contraseña',
remember: 'No cerrar sesión',
// menu
home: 'Inicio', home: 'Inicio',
catalog: 'Catálogo', catalog: 'Catálogo',
orders: 'Pedidos', orders: 'Pedidos',
@ -104,7 +107,7 @@ export default {
addressEdit: 'Editar dirección', addressEdit: 'Editar dirección',
register: 'Registrarse', register: 'Registrarse',
// Home // home
recentNews: 'Noticias recientes', recentNews: 'Noticias recientes',
startOrder: 'Empezar pedido', startOrder: 'Empezar pedido',
@ -123,7 +126,7 @@ export default {
n1InPrice: 'Nº1 en precio', n1InPrice: 'Nº1 en precio',
ourBigVolumeAllows: 'Nuestro gran volumen nos permite ofrecerte los mejores precios', ourBigVolumeAllows: 'Nuestro gran volumen nos permite ofrecerte los mejores precios',
// Catalog // catalog
more: 'Más', more: 'Más',
noItemsFound: 'No se han encontrado artículos', noItemsFound: 'No se han encontrado artículos',
pleaseSetFilter: 'Por favor, establece un filtro usando el menú de la derecha', pleaseSetFilter: 'Por favor, establece un filtro usando el menú de la derecha',
@ -146,21 +149,60 @@ export default {
siceAsc: 'Medida ascendente', siceAsc: 'Medida ascendente',
sizeDesc: 'Medida descendente', sizeDesc: 'Medida descendente',
// Orders // orders
ordersMadeAt: 'Pedidos realizados en',
pendingConfirmtion: 'Pendientes de confirmar',
noOrdersFound: 'No se han encontrado pedidos',
pending: 'Pendientes', pending: 'Pendientes',
confirmed: 'Confirmados', confirmed: 'Confirmados',
// orders/pending
pendingConfirmtion: 'Pendientes de confirmar',
noOrdersFound: 'No se han encontrado pedidos',
// orders/confirmed
ordersMadeAt: 'Pedidos realizados en',
packages: '{n} bultos', packages: '{n} bultos',
// Conditions // order
total: 'Total',
confirm: 'Confirmar',
delivery: 'Fecha de entrega',
address: 'Dirección',
agency: 'Agencia',
warehouse: 'Almacén',
configure: 'Configurar',
// order/checkout
checkout: 'Finalizar pedido',
orderSummary: 'Resumen del pedido',
accountsSummary: 'Resumen de cuentas',
previousBalance: 'Saldo anterior',
orderTotal: 'Total pedido',
vat: 'IVA',
totalDebt: 'Total deuda',
credit: 'Crédito',
exceededCredit: 'Crédito excedido',
payAmount: 'Cantidad a pagar',
payMethod: 'Método de pago',
useMyBalance: 'Usar mi saldo',
youHaveFaborableBalance: 'No necesitas pagar nada, tienes un saldo favorable.',
useMyCredit: 'Usar mi crédito',
youHaveFaborableCredit: 'No necesitas pagar nada, tienes crédito favorable.',
creditCard: 'Tarjeta de crédito',
youWillRedirectToPayment: 'Al confirmar el pedido serás redirigido a la plataforma de pago.',
bankTransfer: 'Transferencia bancaria',
makeTransfer: 'Haz una transferecia a la siguiente cuenta y enví­a el justificante a tu comercial.',
payLater: 'Pagar más tarde',
doYouWantToConfirm: '¿Deseas confirmar el pedido?',
orderConfirmedSuccessfully: 'Tu pedido ha sido realizado con éxito',
youExceededCredit: 'Has excedido tu crédito, por favor realiza el pago para que podamos preparar tu pedido.',
notes: 'Notas',
// conditions
conditionsDesc: 'Te aseguramos que el pedido llegara a tu casa/tienda en menos de 24/48 horas (Dependiendo de en que zona te encuentres).', conditionsDesc: 'Te aseguramos que el pedido llegara a tu casa/tienda en menos de 24/48 horas (Dependiendo de en que zona te encuentres).',
// About // about
aboutDesc: 'Verdnatura te ofrece todos los servicios que necesita tu floristería.', aboutDesc: 'Verdnatura te ofrece todos los servicios que necesita tu floristería.',
// Connections // connections
nConnections: '{0} connexiones', nConnections: '{0} connexiones',
refreshRate: 'Frecuencia de actualización', refreshRate: 'Frecuencia de actualización',
lastAction: 'Última acción', lastAction: 'Última acción',
@ -168,27 +210,27 @@ export default {
nSeconds: '{0} segundos', nSeconds: '{0} segundos',
dontRefresh: 'No refrescar', dontRefresh: 'No refrescar',
// Visits // accessLog
accessLog: 'Registro de accesos',
// visits
visitsCount: '{0} visitas, {1} nuevas', visitsCount: '{0} visitas, {1} nuevas',
// New // new
title: 'Título', title: 'Título',
image: 'Imagen', image: 'Imagen',
tag: 'Etiqueta', tag: 'Etiqueta',
priority: 'Prioridad', priority: 'Prioridad',
text: 'Texto', text: 'Texto',
// Images // images
collection: 'Colección', collection: 'Colección',
updateMatchingId: 'Actualizar ítems con id coincidente', updateMatchingId: 'Actualizar ítems con id coincidente',
uploadAutomatically: 'Subir automáticamente', uploadAutomatically: 'Subir automáticamente',
imagesUploadSuccess: 'Imágenes subidas correctamente', imagesUploadSuccess: 'Imágenes subidas correctamente',
imagesUploadFailed: 'Algunas imágenes no se ha podido subir', imagesUploadFailed: 'Algunas imágenes no se ha podido subir',
// User // user
accessLog: 'Registro de accesos',
// Config
userName: 'Nombre de usuario', userName: 'Nombre de usuario',
nickname: 'Nombre a mostrar', nickname: 'Nombre a mostrar',
language: 'Idioma', language: 'Idioma',
@ -207,14 +249,14 @@ export default {
passwordsDontMatch: 'Las contraseñas no coinciden', passwordsDontMatch: 'Las contraseñas no coinciden',
passwordChanged: '¡Contraseña modificada correctamente!', passwordChanged: '¡Contraseña modificada correctamente!',
// Addresses // addresses
setAsDefault: 'Establecer como predeterminada', setAsDefault: 'Establecer como predeterminada',
addressSetAsDefault: 'Dirección establecida como predeterminada', addressSetAsDefault: 'Dirección establecida como predeterminada',
addressRemoved: 'Dirección eliminada', addressRemoved: 'Dirección eliminada',
areYouSureDeleteAddress: '¿Seguro que quieres eliminar la dirección?', areYouSureDeleteAddress: '¿Seguro que quieres eliminar la dirección?',
addressCreated: '¡Dirección creada correctamente!', addressCreated: '¡Dirección creada correctamente!',
// Address // address
consignatary: 'Consignatario', consignatary: 'Consignatario',
street: 'Dirección', street: 'Dirección',
city: 'City', city: 'City',
@ -224,7 +266,7 @@ export default {
phone: 'Teléfono', phone: 'Teléfono',
mobile: 'Móvil', mobile: 'Móvil',
// Register // register
registerAsNew: 'Registrarse como nuevo usuario', registerAsNew: 'Registrarse como nuevo usuario',
notYetUser: '¿Todavía no eres usuari@?, registrate y empieza a disfrutar de todo lo que Verdnatura puede ofrecerte.', notYetUser: '¿Todavía no eres usuari@?, registrate y empieza a disfrutar de todo lo que Verdnatura puede ofrecerte.',
receiveOffers: 'Recibir ofertas y promociones por correo electrónico', receiveOffers: 'Recibir ofertas y promociones por correo electrónico',

View File

@ -8,9 +8,6 @@
</div> </div>
</template> </template>
<style lang="stylus" scoped>
</style>
<script> <script>
export default { export default {
name: 'About' name: 'About'

View File

@ -199,6 +199,7 @@
<q-btn <q-btn
icon="add_shopping_cart" icon="add_shopping_cart"
:title="$t('buy')" :title="$t('buy')"
@click="showItem(item)"
flat> flat>
</q-btn> </q-btn>
</q-card-actions> </q-card-actions>
@ -210,14 +211,51 @@
</div> </div>
</template> </template>
</q-infinite-scroll> </q-infinite-scroll>
<q-dialog v-model="showItemDialog">
<q-card style="width: 25em;">
<q-img
:src="`${$imageBase}/catalog/200x200/${item.image}`"
:ratio="5/3">
<div class="absolute-bottom text-center q-pa-xs">
<div class="text-subtitle1">
{{item.longName}}
</div>
</div>
</q-img>
<q-card-section>
<div class="text-uppercase text-subtitle1 text-grey-7 ellipsize">
{{item.subName}}
</div>
<div class="text-grey-7">
#{{item.id}}
</div>
</q-card-section>
<q-card-section>
<div v-for="tag in item.tags" :key="tag.tagFk">
<span class="text-grey-7">{{tag.tag.name}}</span> {{tag.value}}
</div>
</q-card-section>
<q-card-actions align="right">
<q-btn
@click="showItemDialog = false"
flat>
{{$t('cancel')}}
</q-btn>
<q-btn
@click="showItemDialog = false"
flat>
{{$t('accept')}}
</q-btn>
</q-card-actions>
</q-card>
</q-dialog>
<q-page-sticky position="bottom-right" :offset="[18, 18]"> <q-page-sticky position="bottom-right" :offset="[18, 18]">
<q-btn <q-btn
fab fab
icon="shopping_basket" icon="shopping_basket"
color="accent" color="accent"
:to="{name: 'orders'}" :to="{name: 'orders'}"
:title="$t('orders')" :title="$t('orders')"/>
/>
</q-page-sticky> </q-page-sticky>
</div> </div>
</template> </template>
@ -279,6 +317,8 @@ export default {
typeId: null, typeId: null,
types: [], types: [],
orgTypes: [], orgTypes: [],
item: {},
showItemDialog: false,
tags: [], tags: [],
isLoading: false, isLoading: false,
items: null, items: null,
@ -537,6 +577,19 @@ export default {
type.name.toLowerCase().indexOf(needle) > -1) type.name.toLowerCase().indexOf(needle) > -1)
}) })
} }
},
showItem (item) {
this.item = item
this.showItemDialog = true
let conf = this.$state.catalogConfig
let params = {
dated: this.date,
addressFk: conf.addressFk,
agencyModeFk: conf.agencyModeFk
}
this.$axios.get(`Items/${item.id}/calcCatalog`, { params })
.then(res => (this.lots = res.data))
} }
} }
} }

View File

@ -1,14 +1,95 @@
<template> <template>
<div class="text-subtitle1 text-center text-grey-7 q-pa-lg"> <div>
Sorry this section is under construction <router-view></router-view>
<q-drawer
v-model="$state.rightDrawerOpen"
side="right"
elevated>
<div
v-if="order"
class="q-pa-md">
<q-input
:label="$t('id')"
:value="order.id"
readonly/>
<q-input
:label="$t('delivery')"
:value="order.landed | relDate"
readonly/>
<q-input
v-if="order.address"
:label="$t('address')"
:value="order.address.nickname"
readonly/>
<q-input
v-if="order.agencyMode"
:label="$t('agency')"
:value="order.agencyMode.name"
readonly/>
<q-input
v-model="notes"
:label="$t('notes')"
type="textarea"/>
<q-btn
:label="$t('configure')"
color="primary"
class="q-mt-md"
style="width: 100%;"
flat/>
</div>
</q-drawer>
</div> </div>
</template> </template>
<style lang="stylus" scoped>
</style>
<script> <script>
import Page from 'components/Page'
export default { export default {
name: 'Order' name: 'Order',
mixins: [Page],
data () {
return {
order: {},
notes: null
}
},
created () {
this.$state.useRightDrawer = true
},
beforeRouteUpdate (to, from, next) {
next()
this.reload()
},
mounted () {
this.reload()
},
methods: {
reload () {
let filter = {
fields: [
'id',
'landed',
'addressFk',
'agencyModeFk'
],
include: [
{
relation: 'address',
scope: {
fields: ['nickname']
}
}, {
relation: 'agencyMode',
scope: {
fields: ['name']
}
}
]
}
this.$axios.get(`Orders/${this.$route.params.id}`, { params: { filter } })
.then(res => (this.order = res.data))
}
}
} }
</script> </script>

216
src/pages/OrderCheckout.vue Normal file
View File

@ -0,0 +1,216 @@
<template>
<div class="vn-pp row justify-center">
<q-card class="vn-w-md">
<q-card-section>
<div class="text-h6">{{$t('accountsSummary')}}</div>
<q-markup-table
class="q-ma-sm"
separator="vertical"
bordered
flat>
<tbody>
<tr>
<td>{{$t('previousBalance')}}</td>
<td class="text-right">{{data.debt | currency}}</td>
</tr>
</tbody>
<tbody
class="border">
<tr>
<td>{{$t('orderTotal')}}</td>
<td class="text-right">{{data.total | currency}}</td>
</tr>
<tr>
<td>{{$t('vat')}}</td>
<td class="text-right">{{data.vat | currency}}</td>
</tr>
</tbody>
<tbody
class="border">
<tr class="text-bold">
<td class="text-left">{{$t('totalDebt')}}</td>
<td class="text-right">{{totalDebt | currency}}</td>
</tr>
<tr v-if="hasCredit">
<td class="text-left">{{$t('credit')}}</td>
<td class="text-right">{{data.credit | currency}}</td>
</tr>
</tbody>
<tbody
class="border"
v-if="isCreditExceeded">
<tr class="text-red text-bold">
<td class="text-left">{{$t('exceededCredit')}}</td>
<td class="text-right">{{execeededCredit | currency}}</td>
</tr>
</tbody>
</q-markup-table>
</q-card-section>
<q-card-section>
<div class="text-h6">{{$t('payMethod')}}</div>
<div v-if="!hasDebt">
<q-radio
v-model="payMethod"
val="balance"
:label="$t('useMyBalance')"/>
<div
v-if="payMethod == 'balance'"
class="method-desc">
{{$t('youHaveFaborableBalance')}}
</div>
</div>
<div v-if="canUseCredit">
<q-radio
v-model="payMethod"
val="credit"
:label="$t('useMyCredit')"/>
<div
v-if="payMethod == 'credit'"
class="method-desc">
{{$t('youHaveFaborableCredit')}}
</div>
</div>
<div>
<q-radio
v-model="payMethod"
val="card"
:label="$t('creditCard')"/>
<div
v-if="payMethod == 'card'"
class="method-desc">
{{$t('youWillRedirectToPayment')}}
</div>
</div>
<div>
<q-radio
v-model="payMethod"
val="transfer"
:label="$t('bankTransfer')"/>
<div
v-if="payMethod == 'transfer'"
class="method-desc">
<div>
{{$t('makeTransfer')}}
</div>
<div class="q-mt-sm">
{{bankName}}
</div>
<div>
{{bankAccount}}
</div>
</div>
</div>
<div>
<q-radio
v-model="payMethod"
val="later"
:label="$t('payLater')"/>
</div>
</q-card-section>
<q-card-section v-if="payMethod == 'card' && isCreditExceeded">
<div class="text-h6">{{$t('payAmount')}}</div>
<div>
<q-radio
v-model="payAmount"
val="exceeded"
:label="$t('exceededCredit') + ', '">
{{execeededCredit | currency}}
</q-radio>
</div>
<div>
<q-radio
v-model="payAmount"
val="total"
:label="$t('totalDebt') + ', '">
{{totalDebt | currency}}
</q-radio>
</div>
</q-card-section>
</q-card>
<q-page-sticky position="bottom-right" :offset="[18, 18]">
<q-btn
fab
icon="send"
color="accent"
@click="onConfirm"
:title="$t('confirm')"/>
</q-page-sticky>
</div>
</template>
<style lang="stylus" scoped>
.border
border-top $layout-border
.method-desc
margin-left 3.2em
color: $grey-8
</style>
<script>
import Page from 'components/Page'
export default {
name: 'OrderCheckout',
mixins: [Page],
data () {
return {
data: {
debt: -27.52,
total: 163.13,
vat: 16.31,
credit: 50
},
payAmount: null,
payMethod: null,
bankName: 'BANKINTER SA',
bankAccount: 'ES81 0128 7635 0205 0000 2291'
}
},
computed: {
totalDebt () {
let data = this.data
return data.debt + data.total + data.vat
},
execeededCredit () {
return this.totalDebt - this.data.credit
},
hasCredit () {
return this.data.credit > 0
},
isCreditExceeded () {
return this.hasCredit && this.execeededCredit > 0
},
canUseCredit () {
return this.hasCredit && !this.isCreditExceeded
},
hasDebt () {
return this.totalDebt > 0
}
},
mounted () {
this.payAmount = this.isCreditExceeded ? 'exceeded' : 'total'
if (!this.hasDebt) {
this.payMethod = 'balance'
} else if (this.canUseCredit) {
this.payMethod = 'credit'
} else {
this.payMethod = 'card'
}
},
methods: {
onConfirm () {
this.$q.dialog({
message: this.$t('doYouWantToConfirm'),
cancel: true
}).onOk(() => {
this.$q.dialog({
message: this.$t('orderConfirmedSuccessfully')
})
// this.$axios.delete(`Orders/${this.$route.params.id}/confirm`)
// .then(() => {})
})
}
}
}
</script>

146
src/pages/OrderView.vue Normal file
View File

@ -0,0 +1,146 @@
<template>
<div class="vn-pp row justify-center">
<toolbar>
<div class="row">
<q-badge
v-if="total != null"
class="text-subtitle1 q-mr-sm"
color="secondary">
{{$t('total')}} {{total | currency}}
</q-badge>
</div>
</toolbar>
<lb-scroll
ref="scroll"
:request="request"
@data="data = arguments[0]">
<q-card class="vn-w-md">
<q-list bordered separator>
<q-item
v-for="row in data"
:key="row.id">
<q-item-section avatar>
<q-avatar
style="cursor: pointer;"
@click.native="onImgClick(row.item.image)">
<img :src="`${$imageBase}/catalog/200x200/${row.item.image}`">
</q-avatar>
</q-item-section>
<q-item-section>
<q-item-label class="ellipsis">
{{row.item.longName}}
</q-item-label>
<q-item-label class="ellipsis" caption>
<span
v-for="tag in row.item.tags.slice(1, 3)"
:key="tag.tagFk">
{{tag.value}}
</span>
</q-item-label>
<q-item-label class="ellipsis">
{{row.quantity}} x {{row.price | currency}}
<span style="float: right;">
{{row.quantity * row.price | currency}}
</span>
</q-item-label>
</q-item-section>
<q-item-section side top>
<q-btn
icon="delete"
@click="onRemove(row)"
:title="$t('delete')"
size="12px"
flat
dense
round/>
</q-item-section>
</q-item>
</q-list>
</q-card>
</lb-scroll>
<full-image
ref="fullImage"
v-model="image"
collection="catalog"/>
<q-page-sticky position="bottom-right" :offset="[18, 18]">
<q-btn
fab
icon="check"
color="accent"
to="checkout"
:title="$t('confirm')"/>
</q-page-sticky>
</div>
</template>
<script>
import Page from 'components/Page'
export default {
name: 'OrderView',
mixins: [Page],
data () {
return {
image: null
}
},
computed: {
total () {
let rows = this.data
if (!rows) return null
return rows.reduce((a, i) => a + i.quantity * i.price, 0)
}
},
beforeRouteUpdate (to, from, next) {
next()
this.$refs.scroll.reload()
},
methods: {
request () {
return {
url: `Orders/${this.$route.params.id}/rows`,
filter: {
fields: [
'id',
'quantity',
'price',
'itemFk'
],
order: 'created DESC',
include: {
relation: 'item',
scope: {
fields: ['longName', 'image'],
include: {
relation: 'tags',
scope: {
fields: ['tagFk', 'value'],
order: 'priority'
}
}
}
}
}
}
},
onRemove (row) {
this.$q.dialog({
message: this.$t('areYouSureDelete'),
cancel: true
}).onOk(() => {
this.$axios.delete(`Orders/${this.$route.params.id}/rows/${row.id}`)
.then(res => {
let rows = this.data
let index = rows.indexOf(row)
if (index !== -1) rows.splice(index, 1)
this.$q.notify(this.$t('removedSuccess'))
})
})
},
onImgClick (image) {
this.image = image
this.$refs.fullImage.show()
}
}
}
</script>

View File

@ -12,7 +12,7 @@
<q-item <q-item
v-for="order in orders" v-for="order in orders"
:key="order.id" :key="order.id"
:to="`/order/${order.id}`" :to="`/order/${order.id}/view`"
clickable clickable
v-ripple> v-ripple>
<q-item-section> <q-item-section>
@ -22,7 +22,7 @@
<q-item-label caption>{{order.address.city}}</q-item-label> <q-item-label caption>{{order.address.city}}</q-item-label>
</q-item-section> </q-item-section>
<q-item-section side top> <q-item-section side top>
485.50 {{order.taxableBase | currency}}
</q-item-section> </q-item-section>
</q-item> </q-item>
</q-list> </q-list>
@ -33,8 +33,7 @@
icon="add_shopping_cart" icon="add_shopping_cart"
color="accent" color="accent"
:to="{name: 'catalog'}" :to="{name: 'catalog'}"
:title="$t('startOrder')" :title="$t('startOrder')"/>
/>
</q-page-sticky> </q-page-sticky>
</div> </div>
</template> </template>
@ -48,7 +47,7 @@ export default {
} }
}, },
mounted () { mounted () {
let params = { filter: { let filter = {
where: { where: {
clientFk: this.$state.userId, clientFk: this.$state.userId,
isConfirmed: false isConfirmed: false
@ -56,8 +55,8 @@ export default {
include: 'address', include: 'address',
order: 'created DESC', order: 'created DESC',
limit: 20 limit: 20
} } }
this.$axios.get('Orders', { params }) this.$axios.get('Orders', { params: { filter } })
.then(res => (this.orders = res.data)) .then(res => (this.orders = res.data))
} }
} }

View File

@ -33,11 +33,22 @@ const routes = [
] ]
}, { }, {
name: 'order', name: 'order',
path: '/order/:order', path: '/order/:id',
component: () => import('pages/Order.vue') component: () => import('pages/Order.vue'),
children: [
{
name: 'view',
path: 'view',
component: () => import('pages/OrderView.vue')
}, {
name: 'checkout',
path: 'checkout',
component: () => import('pages/OrderCheckout.vue')
}
]
}, { }, {
name: 'ticket', name: 'ticket',
path: '/ticket/:ticket', path: '/ticket/:id',
component: () => import('pages/Ticket.vue') component: () => import('pages/Ticket.vue')
}, { }, {
name: 'conditions', name: 'conditions',