diff --git a/client/client/routes.json b/client/client/routes.json index e26ae5356..153c1449b 100644 --- a/client/client/routes.json +++ b/client/client/routes.json @@ -332,6 +332,15 @@ "params": { "client": "$ctrl.client" } + }, + { + "url": "/web-payment", + "state": "client.card.webPayment", + "component": "vn-client-web-payment", + "description": "Web Payment", + "menu": { + "icon": "web" + } } ] } diff --git a/client/client/src/client.js b/client/client/src/client.js index 4c67413dc..f6e2eff9f 100644 --- a/client/client/src/client.js +++ b/client/client/src/client.js @@ -31,3 +31,4 @@ import './credit-insurance/insurance/create'; import './contact'; import './sample/index'; import './sample/create'; +import './web-payment'; diff --git a/client/client/src/web-payment/index.html b/client/client/src/web-payment/index.html new file mode 100644 index 000000000..1511a02f5 --- /dev/null +++ b/client/client/src/web-payment/index.html @@ -0,0 +1,56 @@ + + + + + + + Web Payment + + + + + Id + Amount + Payed + + + + + + + + + + {{::transaction.id}} + {{::transaction.amount | currency: '€ '}} + {{::transaction.created | date:'dd/MM/yyyy'}} + + + + + + + + No results + + + + + + + \ No newline at end of file diff --git a/client/client/src/web-payment/index.js b/client/client/src/web-payment/index.js new file mode 100644 index 000000000..54ba6534b --- /dev/null +++ b/client/client/src/web-payment/index.js @@ -0,0 +1,33 @@ +import ngModule from '../module'; + +class Controller { + constructor($scope, $http, $stateParams) { + this.$scope = $scope; + this.$http = $http; + this.$stateParams = $stateParams; + } + + confirm(transaction) { + const path = '/client/api/Clients/confirmTransaction'; + let data = {id: transaction.id}; + this.$http.post(path, data).then(res => { + this.$scope.model.refresh(); + }); + } + + getFormattedMessage(transaction) { + const errorMessage = transaction.errorMessage ? transaction.errorMessage : ''; + const separator = transaction.errorMessage && transaction.responseMessage ? '
' : ''; + const responseMessage = transaction.responseMessage ? transaction.responseMessage : ''; + return `${errorMessage}` + + separator + + `${responseMessage}`; + } +} + +Controller.$inject = ['$scope', '$http', '$stateParams']; + +ngModule.component('vnClientWebPayment', { + template: require('./index.html'), + controller: Controller +}); diff --git a/client/client/src/web-payment/index.spec.js b/client/client/src/web-payment/index.spec.js new file mode 100644 index 000000000..452dd4963 --- /dev/null +++ b/client/client/src/web-payment/index.spec.js @@ -0,0 +1,50 @@ +import './index'; +import {crudModel} from '../../../helpers/crudModelHelper'; + +describe('Component vnClientWebPayment', () => { + let $componentController; + let $httpBackend; + let $scope; + let vnApp; + let controller; + + beforeEach(() => { + angular.mock.module('client'); + }); + + beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$httpBackend_, _vnApp_) => { + $componentController = _$componentController_; + $scope = $rootScope.$new(); + $scope.model = crudModel; + $httpBackend = _$httpBackend_; + $httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({}); + vnApp = _vnApp_; + spyOn(vnApp, 'showError'); + controller = $componentController('vnClientWebPayment', {$scope: $scope}); + })); + + describe('confirm()', () => { + it(`should confirm a transaction`, () => { + let transaction = {id: 1}; + let query = '/client/api/Clients/confirmTransaction'; + + controller.confirm(transaction); + $httpBackend.when('POST', query, transaction).respond('ok'); + $httpBackend.expect('POST', query, transaction); + $httpBackend.flush(); + }); + }); + + describe('getFormattedMessage()', () => { + it(`should return error message and response Message`, () => { + let transaction = { + errorMessage: 'My error message', + responseMessage: 'My response message' + }; + let result = controller.getFormattedMessage(transaction); + + expect(result).toContain('My error message'); + expect(result).toContain('My response message'); + }); + }); +}); diff --git a/client/client/src/web-payment/locale/es.yml b/client/client/src/web-payment/locale/es.yml new file mode 100644 index 000000000..656bfd32d --- /dev/null +++ b/client/client/src/web-payment/locale/es.yml @@ -0,0 +1,4 @@ +Web Payment: Pago Web +Confirmed: Confirmado +Payed: Pagado +Confirm transaction: Confirmar transacción \ No newline at end of file diff --git a/client/ticket/src/sale-tracking/index.html b/client/ticket/src/sale-tracking/index.html index 13ecc543c..6f3ce16e6 100644 --- a/client/ticket/src/sale-tracking/index.html +++ b/client/ticket/src/sale-tracking/index.html @@ -4,8 +4,7 @@ filter="{}" link="{ticketFk: $ctrl.$stateParams.id}" limit="20" - data="sales" - on-data-change="$ctrl.getTags()"> + data="sales"> diff --git a/services/loopback/common/locale/es.json b/services/loopback/common/locale/es.json index 3e3cca4cc..21e049ff2 100644 --- a/services/loopback/common/locale/es.json +++ b/services/loopback/common/locale/es.json @@ -50,5 +50,6 @@ "A claim with that sale already exists": "Ya existe una reclamación para esta línea", "You don't have enough privileges to change that field": "No tienes permisos para cambiar ese campo", "Warehouse cannot be blank": "El almacén no puede quedar en blanco", - "Agency cannot be blank": "La agencia no puede quedar en blanco" + "Agency cannot be blank": "La agencia no puede quedar en blanco", + "You don't have enough privileges to do that": "No tienes permisos para para hacer esto" } \ No newline at end of file diff --git a/services/loopback/common/methods/client/confirmTransaction.js b/services/loopback/common/methods/client/confirmTransaction.js new file mode 100644 index 000000000..2c6e6c624 --- /dev/null +++ b/services/loopback/common/methods/client/confirmTransaction.js @@ -0,0 +1,32 @@ +const UserError = require('../../../common/helpers').UserError; + +module.exports = Self => { + Self.remoteMethodCtx('confirmTransaction', { + description: 'Returns last entries', + accessType: 'READ', + accepts: [{ + arg: 'id', + type: 'number', + required: true, + description: 'Transaction id' + }], + returns: { + type: 'Object', + root: true + }, + http: { + path: `/confirmTransaction`, + verb: 'POST' + } + }); + + Self.confirmTransaction = async(ctx, id) => { + let userId = ctx.req.accessToken.userId; + let isAdministrative = await Self.app.models.Account.hasRole(userId, 'administrative'); + + if (!isAdministrative) + throw new UserError(`You don't have enough privileges to do that`); + + return await Self.rawSql('CALL hedera.tpvTransactionConfirmById(?)', [id]); + }; +}; diff --git a/services/loopback/common/methods/client/getTransactions.js b/services/loopback/common/methods/client/getTransactions.js new file mode 100644 index 000000000..764e0df7d --- /dev/null +++ b/services/loopback/common/methods/client/getTransactions.js @@ -0,0 +1,43 @@ + +const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; + +module.exports = Self => { + Self.remoteMethod('getTransactions', { + description: 'Returns last entries', + accessType: 'READ', + accepts: [{ + arg: 'filter', + type: 'Object', + description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string', + http: {source: 'query'} + }], + returns: { + type: ['Object'], + root: true + }, + http: { + path: `/getTransactions`, + verb: 'GET' + } + }); + + Self.getTransactions = async filter => { + let stmt = new ParameterizedSQL(` + SELECT + t.id, + t.clientFk, + t.created, + t.amount / 100 amount, + t.receiptFk IS NOT NULL AS isConfirmed, + tt.message responseMessage, + te.message errorMessage + FROM hedera.tpvTransaction t + JOIN hedera.tpvMerchant m ON m.id = t.merchantFk + LEFT JOIN hedera.tpvResponse tt ON tt.id = t.response + LEFT JOIN hedera.tpvError te ON te.code = errorCode`); + + stmt.merge(Self.buildSuffix(filter, 't')); + + return await Self.rawStmt(stmt); + }; +}; diff --git a/services/loopback/common/methods/client/specs/confirmTransaction.spec.js b/services/loopback/common/methods/client/specs/confirmTransaction.spec.js new file mode 100644 index 000000000..7cd5bd292 --- /dev/null +++ b/services/loopback/common/methods/client/specs/confirmTransaction.spec.js @@ -0,0 +1,32 @@ +const app = require(`${servicesDir}/client/server/server`); + +describe('Client confirmTransaction', () => { + const transactionId = 2; + + afterAll(async() => { + await app.models.Client.rawSql(` + CALL hedera.tpvTransactionUndo(?)`, [transactionId]); + }); + + it('should call confirmTransaction() method and throw error for a non administrative person', async() => { + let ctx = {req: {accessToken: {userId: 1}}}; + let error; + await app.models.Client.confirmTransaction(ctx, transactionId).catch(e => { + error = e; + }).finally(() => { + expect(error.message).toEqual(`You don't have enough privileges to do that`); + }); + }); + + it('should call confirmTransaction() method to mark transaction as confirmed', async() => { + let ctx = {req: {accessToken: {userId: 5}}}; + await app.models.Client.confirmTransaction(ctx, transactionId); + + let [receipt] = await app.models.Client.rawSql( + `SELECT receiptFk + FROM hedera.tpvTransaction + WHERE id = ?`, [transactionId]); + + expect(receipt.receiptFk).toBeGreaterThan(0); + }); +}); diff --git a/services/loopback/common/methods/client/specs/getTransactions.spec.js b/services/loopback/common/methods/client/specs/getTransactions.spec.js new file mode 100644 index 000000000..d7e553115 --- /dev/null +++ b/services/loopback/common/methods/client/specs/getTransactions.spec.js @@ -0,0 +1,10 @@ +const app = require(`${servicesDir}/client/server/server`); + +describe('Client getTransations', () => { + it('should call getTransations() method to receive a list of Web Payments from Bruce Wayne', async() => { + let filter = {where: {clientFk: 101}}; + let result = await app.models.Client.getTransactions(filter); + + expect(result[1].id).toBeTruthy(); + }); +}); diff --git a/services/loopback/common/models/client.js b/services/loopback/common/models/client.js index 41149b30a..c7fa10e81 100644 --- a/services/loopback/common/models/client.js +++ b/services/loopback/common/models/client.js @@ -19,6 +19,8 @@ module.exports = Self => { require('../methods/client/updateFiscalData')(Self); require('../methods/client/updateBillingData')(Self); require('../methods/client/updateBasicData')(Self); + require('../methods/client/getTransactions')(Self); + require('../methods/client/confirmTransaction')(Self); // Validations diff --git a/services/ticket/common/methods/sale-tracking/listSaleTracking.js b/services/ticket/common/methods/sale-tracking/listSaleTracking.js index e45249ec6..ff198f3ad 100644 --- a/services/ticket/common/methods/sale-tracking/listSaleTracking.js +++ b/services/ticket/common/methods/sale-tracking/listSaleTracking.js @@ -1,3 +1,6 @@ + +const ParameterizedSQL = require('vn-loopback/node_modules/loopback-connector').ParameterizedSQL; + module.exports = Self => { Self.remoteMethod('listSaleTracking', { description: 'Returns all ticket sale trackings', @@ -20,40 +23,27 @@ module.exports = Self => { }); Self.listSaleTracking = async filter => { - let where = ''; - let limit = ''; - let order = ''; - let params; + let stmt = new ParameterizedSQL(` + SELECT + st.id, + s.ticketFk, + s.quantity, + s.concept, + s.itemFk, + st.originalQuantity, + st.created, + st.workerFk, + w.firstName, + w.name, + ste.name AS state + FROM saleTracking st + JOIN sale s ON s.id = st.saleFk + JOIN worker w ON w.id = st.workerFk + JOIN state ste ON ste.id = st.stateFk`); - if (filter) { - let connector = Self.dataSource.connector; - if (filter.where) { - where = 'WHERE s.ticketFk = ?'; - params = [filter.where.ticketFk]; - } + stmt.merge(Self.buildSuffix(filter)); - limit = connector._buildLimit(null, filter.limit, filter.skip); - order = connector.buildOrderBy('Item', filter.order); - } - - let query = `SELECT - st.id, - s.quantity, - s.concept, - s.itemFk, - st.originalQuantity, - st.created, - st.workerFk, - w.firstName, - w.name, - ste.name AS state - FROM saleTracking st - JOIN sale s ON s.id = st.saleFK - JOIN worker w ON w.id = st.workerFk - JOIN ticketState ts ON ts.ticketFk = s.ticketFk - JOIN state ste ON ste.id = ts.stateFK ${where} ${order} ${limit}`; - - let trackings = await Self.rawSql(query, params); + let trackings = await Self.rawStmt(stmt); let salesFilter = { include: [