From 703d6932ffb005f85e649fa3087f5815722b88d0 Mon Sep 17 00:00:00 2001 From: Juan Ferrer Toribio Date: Fri, 30 Aug 2019 12:59:49 +0200 Subject: [PATCH] Order checkout --- back/common/models/item.js | 44 ++++++ back/common/models/order-row.json | 2 +- back/common/models/order.json | 21 ++- quasar.conf.js | 3 +- src/boot/filters.js | 2 +- src/boot/state.js | 6 +- src/components/LbScroll.vue | 4 +- src/i18n/en-us/index.js | 92 +++++++++---- src/i18n/es-es/index.js | 94 +++++++++---- src/pages/About.vue | 3 - src/pages/Catalog.vue | 57 +++++++- src/pages/Order.vue | 93 ++++++++++++- src/pages/OrderCheckout.vue | 216 ++++++++++++++++++++++++++++++ src/pages/OrderView.vue | 146 ++++++++++++++++++++ src/pages/Pending.vue | 13 +- src/router/routes.js | 17 ++- 16 files changed, 729 insertions(+), 84 deletions(-) create mode 100644 src/pages/OrderCheckout.vue create mode 100644 src/pages/OrderView.vue diff --git a/back/common/models/item.js b/back/common/models/item.js index 10f690b..81bcddf 100644 --- a/back/common/models/item.js +++ b/back/common/models/item.js @@ -1,6 +1,50 @@ const warehouseIds = [1, 44]; 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', { description: 'Get the catalog', accessType: 'READ', diff --git a/back/common/models/order-row.json b/back/common/models/order-row.json index 677f0ec..681f015 100644 --- a/back/common/models/order-row.json +++ b/back/common/models/order-row.json @@ -3,7 +3,7 @@ "base": "PersistedModel", "options": { "mysql": { - "table": "hedera.orderRow" + "table": "hedera.orderRow" } }, "properties": { diff --git a/back/common/models/order.json b/back/common/models/order.json index 8c9dcb1..2e87dc3 100644 --- a/back/common/models/order.json +++ b/back/common/models/order.json @@ -3,7 +3,7 @@ "base": "PersistedModel", "options": { "mysql": { - "table": "hedera.order" + "table": "hedera.order" } }, "properties": { @@ -79,9 +79,23 @@ "mysql": { "columnName": "confirm_date" } + }, + "taxableBase": { + "type": "Number" + }, + "tax": { + "type": "Number" + }, + "total": { + "type": "Number" } }, "relations": { + "rows": { + "type": "hasMany", + "model": "OrderRow", + "foreignKey": "orderFk" + }, "agencyMode": { "type": "belongsTo", "model": "AgencyMode", @@ -101,11 +115,6 @@ "type": "belongsTo", "model": "DeliveryMethod", "foreignKey": "delivery_method_id" - }, - "rows": { - "type": "hasMany", - "model": "OrderRow", - "foreignKey": "orderFk" } } } diff --git a/quasar.conf.js b/quasar.conf.js index 0a9722c..ecfdf1b 100644 --- a/quasar.conf.js +++ b/quasar.conf.js @@ -52,6 +52,7 @@ module.exports = function (ctx) { 'QItemLabel', 'QList', 'QLayout', + 'QMarkupTable', 'QPageContainer', 'QPage', 'QPageSticky', @@ -79,8 +80,8 @@ module.exports = function (ctx) { 'ClosePopup' ], - // Quasar plugins plugins: [ + 'Dialog', 'Notify' ] diff --git a/src/boot/filters.js b/src/boot/filters.js index 2c5c14e..e9fdf79 100644 --- a/src/boot/filters.js +++ b/src/boot/filters.js @@ -6,7 +6,7 @@ export default async ({ app, Vue }) => { let i18n = app.i18n function currency (val) { - return val ? val.toFixed(2) + '€' : val + return typeof val === 'number' ? val.toFixed(2) + '€' : val } function date (val, format) { diff --git a/src/boot/state.js b/src/boot/state.js index 8e15feb..5edc730 100644 --- a/src/boot/state.js +++ b/src/boot/state.js @@ -9,7 +9,11 @@ export default async ({ app, Vue }) => { title: null, subtitle: null, useRightDrawer: false, - rightDrawerOpen: true + rightDrawerOpen: true, + catalogConfig: { + agencyModeFk: 2, + addressFk: 1823 + } }) Vue.prototype.$state = state } diff --git a/src/components/LbScroll.vue b/src/components/LbScroll.vue index 0e891e1..e47b4e5 100644 --- a/src/components/LbScroll.vue +++ b/src/components/LbScroll.vue @@ -115,7 +115,7 @@ export default { params.filter = filter limit = filter.limit - if (!limit) { + if (limit === undefined) { limit = this.index * 30 filter.limit = limit } @@ -149,7 +149,7 @@ export default { this.doRequest() .then(res => { 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 }) .catch(err => { diff --git a/src/i18n/en-us/index.js b/src/i18n/en-us/index.js index eef3806..a6ba309 100644 --- a/src/i18n/en-us/index.js +++ b/src/i18n/en-us/index.js @@ -1,9 +1,5 @@ export default { - // Login - enter: 'Enter', - email: 'E-Mail', - password: 'Password', - remember: 'Don not close session', + // global search: 'Search', accept: 'Accept', cancel: 'Cancel', @@ -22,6 +18,7 @@ export default { createdSuccess: 'Item created successfully', fieldIsRequired: 'Field is required', setSearchFilter: 'Please, set a search filter', + id: 'Id', today: 'Today', yesterday: 'Yesterday', tomorrow: 'Tomorrow', @@ -81,7 +78,13 @@ export default { logout: 'Logout', visitor: 'Visitor', - // Menu + // login + enter: 'Enter', + email: 'E-Mail', + password: 'Password', + remember: 'Don not close session', + + // menu home: 'Home', catalog: 'Catalog', orders: 'Orders', @@ -104,7 +107,7 @@ export default { addressEdit: 'Edit address', register: 'Register', - // Home + // home recentNews: 'Recent news', startOrder: 'Start order', @@ -123,7 +126,7 @@ export default { n1InPrice: 'Nº1 in price', ourBigVolumeAllows: 'our big volume allows us to offer the best prices', - // Catalog + // catalog more: 'More', noItemsFound: 'No items found', pleaseSetFilter: 'Please, set a filter using the right menu', @@ -146,21 +149,60 @@ export default { siceAsc: 'Ascending size', sizeDesc: 'Descencing size', - // Orders - ordersMadeAt: 'Orders made at', - pendingConfirmtion: 'Pending confirmation', - noOrdersFound: 'No orders found', + // orders pending: 'Pending', confirmed: 'Confirmed', + + // orders + pendingConfirmtion: 'Pending confirmation', + noOrdersFound: 'No orders found', + + // orders + ordersMadeAt: 'Orders made at', 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.', - // About + // about aboutDesc: 'Verdnatura offers all services for your florist.', - // Connections + // connections nConnections: '{0} connections', refreshRate: 'Refresh rate', lastAction: 'Last actions', @@ -168,27 +210,27 @@ export default { nSeconds: '{0} seconds', dontRefresh: 'Do not refresh', - // Visits + // accessLog + accessLog: 'Access log', + + // visits visitsCount: '{0} visits, {1} new', - // New + // new title: 'Title', image: 'Image', tag: 'Tag', priority: 'Priority', text: 'Text', - // Images + // images collection: 'Collection', updateMatchingId: 'Update items with matching id', uploadAutomatically: 'Upload automatically', imagesUploadSuccess: 'Images uploaded successfully', imagesUploadFailed: 'Some images could not be uploaded', - // User - accessLog: 'Access log', - - // Config + // user userName: 'Username', nickname: 'Nickname', language: 'Language', @@ -207,14 +249,14 @@ export default { passwordsDontMatch: 'Passwords do not match', passwordChanged: 'Password changed successfully!', - // Addresses + // addresses setAsDefault: 'Set as default', addressSetAsDefault: 'Address set as default', addressRemoved: 'Address removed', areYouSureDeleteAddress: 'Are you sure you want to delete the address?', addressCreated: 'Address created successfully!', - // Address + // address consignatary: 'Consignatary', street: 'Street', city: 'City', @@ -224,7 +266,7 @@ export default { phone: 'Phone', mobile: 'Mobile', - // Register + // register registerAsNew: 'Registrarse como nuevo usuario', 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', diff --git a/src/i18n/es-es/index.js b/src/i18n/es-es/index.js index c094a0a..86d2a28 100644 --- a/src/i18n/es-es/index.js +++ b/src/i18n/es-es/index.js @@ -1,9 +1,5 @@ export default { - // Login - enter: 'Entrar', - email: 'Correo electrónico', - password: 'Contraseña', - remember: 'No cerrar sesión', + // global search: 'Buscar', accept: 'Aceptar', cancel: 'Cancelar', @@ -22,6 +18,7 @@ export default { createdSuccess: 'Elemento creado correctamente', fieldIsRequired: 'Campo requerido', setSearchFilter: 'Por favor, establece un filtro de búsqueda', + id: 'Id', today: 'Hoy', yesterday: 'Ayer', tomorrow: 'Mañana', @@ -76,12 +73,18 @@ export default { ] }, - // Layout + // layout login: 'Iniciar sesión', logout: 'Cerrar sesión', visitor: 'Visitante', - // Menu + // login + enter: 'Entrar', + email: 'Correo electrónico', + password: 'Contraseña', + remember: 'No cerrar sesión', + + // menu home: 'Inicio', catalog: 'Catálogo', orders: 'Pedidos', @@ -104,7 +107,7 @@ export default { addressEdit: 'Editar dirección', register: 'Registrarse', - // Home + // home recentNews: 'Noticias recientes', startOrder: 'Empezar pedido', @@ -123,7 +126,7 @@ export default { n1InPrice: 'Nº1 en precio', ourBigVolumeAllows: 'Nuestro gran volumen nos permite ofrecerte los mejores precios', - // Catalog + // catalog more: 'Más', noItemsFound: 'No se han encontrado artículos', pleaseSetFilter: 'Por favor, establece un filtro usando el menú de la derecha', @@ -146,21 +149,60 @@ export default { siceAsc: 'Medida ascendente', sizeDesc: 'Medida descendente', - // Orders - ordersMadeAt: 'Pedidos realizados en', - pendingConfirmtion: 'Pendientes de confirmar', - noOrdersFound: 'No se han encontrado pedidos', + // orders pending: 'Pendientes', confirmed: 'Confirmados', + + // orders/pending + pendingConfirmtion: 'Pendientes de confirmar', + noOrdersFound: 'No se han encontrado pedidos', + + // orders/confirmed + ordersMadeAt: 'Pedidos realizados en', 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).', - // About + // about aboutDesc: 'Verdnatura te ofrece todos los servicios que necesita tu floristería.', - // Connections + // connections nConnections: '{0} connexiones', refreshRate: 'Frecuencia de actualización', lastAction: 'Última acción', @@ -168,27 +210,27 @@ export default { nSeconds: '{0} segundos', dontRefresh: 'No refrescar', - // Visits + // accessLog + accessLog: 'Registro de accesos', + + // visits visitsCount: '{0} visitas, {1} nuevas', - // New + // new title: 'Título', image: 'Imagen', tag: 'Etiqueta', priority: 'Prioridad', text: 'Texto', - // Images + // images collection: 'Colección', updateMatchingId: 'Actualizar ítems con id coincidente', uploadAutomatically: 'Subir automáticamente', imagesUploadSuccess: 'Imágenes subidas correctamente', imagesUploadFailed: 'Algunas imágenes no se ha podido subir', - // User - accessLog: 'Registro de accesos', - - // Config + // user userName: 'Nombre de usuario', nickname: 'Nombre a mostrar', language: 'Idioma', @@ -207,14 +249,14 @@ export default { passwordsDontMatch: 'Las contraseñas no coinciden', passwordChanged: '¡Contraseña modificada correctamente!', - // Addresses + // addresses setAsDefault: 'Establecer como predeterminada', addressSetAsDefault: 'Dirección establecida como predeterminada', addressRemoved: 'Dirección eliminada', areYouSureDeleteAddress: '¿Seguro que quieres eliminar la dirección?', addressCreated: '¡Dirección creada correctamente!', - // Address + // address consignatary: 'Consignatario', street: 'Dirección', city: 'City', @@ -224,7 +266,7 @@ export default { phone: 'Teléfono', mobile: 'Móvil', - // Register + // register registerAsNew: 'Registrarse como nuevo usuario', 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', diff --git a/src/pages/About.vue b/src/pages/About.vue index 7003f79..077fd10 100644 --- a/src/pages/About.vue +++ b/src/pages/About.vue @@ -8,9 +8,6 @@ - - diff --git a/src/pages/OrderCheckout.vue b/src/pages/OrderCheckout.vue new file mode 100644 index 0000000..089a9f1 --- /dev/null +++ b/src/pages/OrderCheckout.vue @@ -0,0 +1,216 @@ + + + + + diff --git a/src/pages/OrderView.vue b/src/pages/OrderView.vue new file mode 100644 index 0000000..f71639c --- /dev/null +++ b/src/pages/OrderView.vue @@ -0,0 +1,146 @@ + + + diff --git a/src/pages/Pending.vue b/src/pages/Pending.vue index 27f0448..50435e2 100644 --- a/src/pages/Pending.vue +++ b/src/pages/Pending.vue @@ -12,7 +12,7 @@ @@ -22,7 +22,7 @@ {{order.address.city}} - 485.50€ + {{order.taxableBase | currency}} @@ -33,8 +33,7 @@ icon="add_shopping_cart" color="accent" :to="{name: 'catalog'}" - :title="$t('startOrder')" - /> + :title="$t('startOrder')"/> @@ -48,7 +47,7 @@ export default { } }, mounted () { - let params = { filter: { + let filter = { where: { clientFk: this.$state.userId, isConfirmed: false @@ -56,8 +55,8 @@ export default { include: 'address', order: 'created DESC', limit: 20 - } } - this.$axios.get('Orders', { params }) + } + this.$axios.get('Orders', { params: { filter } }) .then(res => (this.orders = res.data)) } } diff --git a/src/router/routes.js b/src/router/routes.js index 5228a6f..e44730d 100644 --- a/src/router/routes.js +++ b/src/router/routes.js @@ -33,11 +33,22 @@ const routes = [ ] }, { name: 'order', - path: '/order/:order', - component: () => import('pages/Order.vue') + path: '/order/:id', + 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', - path: '/ticket/:ticket', + path: '/ticket/:id', component: () => import('pages/Ticket.vue') }, { name: 'conditions',