diff --git a/.eslintrc.yml b/.eslintrc.yml
index f20cefcb8f..e7121aa4ae 100644
--- a/.eslintrc.yml
+++ b/.eslintrc.yml
@@ -26,5 +26,7 @@ rules:
bracketSpacing: 0
space-infix-ops: 1
prefer-const: 0
- curly: ["error", "multi-or-nest"]
- indent: [error, 4]
\ No newline at end of file
+ curly: [error, multi]
+ indent: [error, 4]
+ arrow-parens: [error, as-needed]
+ no-focused-tests: 0
\ No newline at end of file
diff --git a/client/core/src/components/crud-model/crud-model.js b/client/core/src/components/crud-model/crud-model.js
index 5ddf546533..251dbcfc4d 100644
--- a/client/core/src/components/crud-model/crud-model.js
+++ b/client/core/src/components/crud-model/crud-model.js
@@ -203,7 +203,7 @@ export default class CrudModel extends ModelProxy {
this.canceler = this.$q.defer();
let params = Object.assign(
- {filter: filter},
+ {filter},
this.buildParams()
);
let options = {
diff --git a/client/core/src/components/searchbar/searchbar.js b/client/core/src/components/searchbar/searchbar.js
index 6bb019b91f..40a023d5ae 100644
--- a/client/core/src/components/searchbar/searchbar.js
+++ b/client/core/src/components/searchbar/searchbar.js
@@ -1,6 +1,7 @@
import ngModule from '../../module';
import Component from '../../lib/component';
import './style.scss';
+import {buildFilter} from 'vn-loopback/common/filter.js';
/**
* An input specialized to perform searches, it allows to use a panel
@@ -84,41 +85,28 @@ export default class Controller extends Component {
this.pushFilterToState(this.filter);
if (this.onSearch)
- this.onSearch({filter: this.filter});
+ this.onSearch({$params: this.filter});
if (this.model) {
- let and = [];
+ let where = buildFilter(this.filter,
+ (param, value) => this.exprBuilder({param, value}));
+
let userParams = {};
let hasParams = false;
- for (let param in this.filter) {
- let value = this.filter[param];
- if (value == null) continue;
-
- let expr = this.exprBuilder({param, value});
- if (expr)
- and.push(expr);
-
- if (this.paramBuilder) {
+ if (this.paramBuilder)
+ for (let param in this.filter) {
+ let value = this.filter[param];
+ if (value == null) continue;
let expr = this.paramBuilder({param, value});
if (expr) {
Object.assign(userParams, expr);
hasParams = true;
}
}
- }
-
- let where;
-
- if (and.length == 1)
- where = and[0];
- else if (and.length > 1)
- where = {and};
- else
- where = null;
this.model.applyFilter(
- and.length > 0 ? {where: where} : null,
+ where ? {where} : null,
hasParams ? userParams : null
);
}
@@ -235,7 +223,7 @@ ngModule.component('vnSearchbar', {
template: require('./searchbar.html'),
bindings: {
filter: '',
- onSearch: '&',
+ onSearch: '&?',
panel: '@',
model: '',
exprBuilder: '&?',
diff --git a/client/ticket/src/index/index.html b/client/ticket/src/index/index.html
index 9b9430bc6f..971dab93e5 100644
--- a/client/ticket/src/index/index.html
+++ b/client/ticket/src/index/index.html
@@ -1,9 +1,9 @@
@@ -11,8 +11,7 @@
@@ -85,10 +84,12 @@
scroll-selector="ui-view">
-
+
-
+
-
\ No newline at end of file
+
+
\ No newline at end of file
diff --git a/client/ticket/src/index/index.js b/client/ticket/src/index/index.js
index 1fa53b5ce0..04c54638e0 100644
--- a/client/ticket/src/index/index.js
+++ b/client/ticket/src/index/index.js
@@ -2,32 +2,8 @@ import ngModule from '../module';
export default class Controller {
constructor($scope) {
- this.$scope = $scope;
- this.ticketSelected = null;
-
- this.filter = {
- order: 'shipped DESC'
- };
- }
-
- exprBuilder(param, value) {
- switch (param) {
- case 'search':
- return /^\d+$/.test(value)
- ? {id: value}
- : {nickname: {like: value}};
- case 'from':
- return {shipped: {gte: value}};
- case 'to':
- return {shipped: {lte: value}};
- case 'nickname':
- return {[param]: {like: value}};
- case 'id':
- case 'clientFk':
- case 'agencyModeFk':
- case 'warehouseFk':
- return {[param]: value};
- }
+ this.$ = $scope;
+ this.selectedTicket = null;
}
compareDate(date) {
@@ -40,28 +16,23 @@ export default class Controller {
if (comparation == 0)
return 'warning';
-
if (comparation < 0)
return 'success';
}
showDescriptor(event, clientFk) {
- this.$scope.descriptor.clientFk = clientFk;
- this.$scope.descriptor.parent = event.target;
- this.$scope.descriptor.show();
event.preventDefault();
event.stopImmediatePropagation();
- }
-
- onDescriptorLoad() {
- this.$scope.popover.relocate();
+ this.$.descriptor.clientFk = clientFk;
+ this.$.descriptor.parent = event.target;
+ this.$.descriptor.show();
}
preview(event, ticket) {
event.preventDefault();
event.stopImmediatePropagation();
- this.$scope.dialogSummaryTicket.show();
- this.ticketSelected = ticket;
+ this.selectedTicket = ticket;
+ this.$.summary.show();
}
}
diff --git a/client/ticket/src/index/index.spec.js b/client/ticket/src/index/index.spec.js
index 6d60996a6d..d334cb7c95 100644
--- a/client/ticket/src/index/index.spec.js
+++ b/client/ticket/src/index/index.spec.js
@@ -1,98 +1,89 @@
import './index.js';
-describe('ticket', () => {
- describe('Component vnTicketIndex', () => {
- let $componentController;
- let controller;
+describe('Component vnTicketIndex', () => {
+ let $element;
+ let $ctrl;
+ let $window;
+ let tickets = [{
+ id: 1,
+ clientFk: 1,
+ salesPersonFk: 9,
+ shipped: new Date(),
+ nickname: 'Test',
+ total: 10.5
+ }];
- beforeEach(() => {
- angular.mock.module('ticket');
+ beforeEach(() => {
+ ngModule('client');
+ ngModule('item');
+ ngModule('ticket');
+ });
+
+ beforeEach(inject(($compile, $rootScope, $httpBackend, _$window_) => {
+ $window = _$window_;
+ $element = $compile('')($rootScope);
+ $ctrl = $element.controller('vnTicketIndex');
+
+ $httpBackend.whenGET(/\/ticket\/api\/Tickets\/filter.*/).respond(tickets);
+ $httpBackend.flush();
+ }));
+
+ afterEach(() => {
+ $element.remove();
+ });
+
+ describe('compareDate()', () => {
+ it('should return warning when the date is the present', () => {
+ let curDate = new Date();
+ let result = $ctrl.compareDate(curDate);
+
+ expect(result).toEqual('warning');
});
- beforeEach(angular.mock.inject(_$componentController_ => {
- $componentController = _$componentController_;
- controller = $componentController('vnTicketIndex');
- }));
+ it('should return sucess when the date is in the future', () => {
+ let futureDate = new Date();
+ futureDate = futureDate.setDate(futureDate.getDate() + 10);
+ let result = $ctrl.compareDate(futureDate);
- describe('exprBuilder()', () => {
- it('should return a formated object with the id in case of search', () => {
- let param = 'search';
- let value = 1;
- let result = controller.exprBuilder(param, value);
-
- expect(result).toEqual({id: 1});
- });
-
- it('should return a formated object with the nickname in case of search', () => {
- let param = 'search';
- let value = 'Bruce';
- let result = controller.exprBuilder(param, value);
-
- expect(result).toEqual({nickname: {like: 'Bruce'}});
- });
-
- it('should return a formated object with the date in case of from', () => {
- let param = 'from';
- let value = 'Fri Aug 10 2018 11:39:21 GMT+0200';
- let result = controller.exprBuilder(param, value);
-
- expect(result).toEqual({shipped: {gte: 'Fri Aug 10 2018 11:39:21 GMT+0200'}});
- });
-
- it('should return a formated object with the date in case of to', () => {
- let param = 'to';
- let value = 'Fri Aug 10 2018 11:39:21 GMT+0200';
- let result = controller.exprBuilder(param, value);
-
- expect(result).toEqual({shipped: {lte: 'Fri Aug 10 2018 11:39:21 GMT+0200'}});
- });
-
- it('should return a formated object with the nickname in case of nickname', () => {
- let param = 'nickname';
- let value = 'Bruce';
- let result = controller.exprBuilder(param, value);
-
- expect(result).toEqual({nickname: {like: 'Bruce'}});
- });
-
- it('should return a formated object with the warehouseFk in case of warehouseFk', () => {
- let param = 'warehouseFk';
- let value = 'Silla';
- let result = controller.exprBuilder(param, value);
-
- expect(result).toEqual({warehouseFk: 'Silla'});
- });
+ expect(result).toEqual('success');
});
- describe('compareDate()', () => {
- it('should return warning when the date is the present', () => {
- let date = new Date();
- let result = controller.compareDate(date);
+ it('should return undefined when the date is in the past', () => {
+ let pastDate = new Date();
+ pastDate = pastDate.setDate(pastDate.getDate() - 10);
+ let result = $ctrl.compareDate(pastDate);
- expect(result).toEqual('warning');
- });
-
- it('should return sucess when the date is in the future', () => {
- let futureDate = '2518-05-19T00:00:00.000Z';
- let result = controller.compareDate(futureDate);
-
- expect(result).toEqual('success');
- });
+ expect(result).toEqual(undefined);
});
+ });
- describe('preview()', () => {
- it('should call preventDefault and stopImmediatePropagation from event and show', () => {
- let event = jasmine.createSpyObj('event', ['preventDefault', 'stopImmediatePropagation']);
+ describe('showDescriptor()', () => {
+ it('should show the descriptor popover', () => {
+ spyOn($ctrl.$.descriptor, 'show');
- controller.$scope = {dialogSummaryTicket: {show: () => {}}};
- spyOn(controller.$scope.dialogSummaryTicket, 'show');
- let ticket = {};
- controller.preview(event, ticket);
-
- expect(event.preventDefault).toHaveBeenCalledWith();
- expect(event.stopImmediatePropagation).toHaveBeenCalledWith();
- expect(controller.$scope.dialogSummaryTicket.show).toHaveBeenCalledWith();
+ let event = new MouseEvent('click', {
+ view: $window,
+ bubbles: true,
+ cancelable: true
});
+ $ctrl.showDescriptor(event, tickets[0].clientFk);
+
+ expect($ctrl.$.descriptor.show).toHaveBeenCalledWith();
+ });
+ });
+
+ describe('preview()', () => {
+ it('should show the dialog summary', () => {
+ spyOn($ctrl.$.summary, 'show');
+
+ let event = new MouseEvent('click', {
+ view: $window,
+ bubbles: true,
+ cancelable: true
+ });
+ $ctrl.preview(event, tickets[0]);
+
+ expect($ctrl.$.summary.show).toHaveBeenCalledWith();
});
});
});
diff --git a/client/ticket/src/search-panel/index.html b/client/ticket/src/search-panel/index.html
index e8ddd290e9..b53e3e739d 100644
--- a/client/ticket/src/search-panel/index.html
+++ b/client/ticket/src/search-panel/index.html
@@ -37,20 +37,42 @@
vn-one
label="Agency"
field="filter.agencyModeFk"
- url="/api/AgencyModes"
- show-field="name"
- value-field="id">
- {{name}}
+ url="/api/AgencyModes">
+ url="/api/Warehouses">
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/client/ticket/src/search-panel/locale/es.yml b/client/ticket/src/search-panel/locale/es.yml
index 1f892a7429..20ef1ee232 100644
--- a/client/ticket/src/search-panel/locale/es.yml
+++ b/client/ticket/src/search-panel/locale/es.yml
@@ -4,4 +4,8 @@ Nickname: Alias
From: Desde
To: Hasta
Agency: Agencia
-Warehouse: Almacén
\ No newline at end of file
+Warehouse: Almacén
+Sales person: Comercial
+Province: Provincia
+My team: Mi equipo
+My tickets: Mis tickets
\ No newline at end of file
diff --git a/e2e/paths/ticket-module/04_create_ticket_packages.spec.js b/e2e/paths/ticket-module/04_create_ticket_packages.spec.js
index ad9a52830a..a5a266489a 100644
--- a/e2e/paths/ticket-module/04_create_ticket_packages.spec.js
+++ b/e2e/paths/ticket-module/04_create_ticket_packages.spec.js
@@ -9,128 +9,108 @@ describe('Ticket Create packages path', () => {
.waitForLogin('employee');
});
- it('should click on the Tickets button of the top bar menu', (done) => {
- return nightmare
+ it('should click on the Tickets button of the top bar menu', async () => {
+ let url = await nightmare
.waitToClick(selectors.globalItems.applicationsMenuButton)
.wait(selectors.globalItems.applicationsMenuVisible)
.waitToClick(selectors.globalItems.ticketsButton)
.wait(selectors.ticketsIndex.searchResult)
- .parsedUrl()
- .then((url) => {
- expect(url.hash).toEqual('#!/ticket/index');
- done();
- }).catch(done.fail);
+ .parsedUrl();
+
+ expect(url.hash).toEqual('#!/ticket/index');
});
- it('should search for the ticket 1', (done) => {
- return nightmare
+ it('should search for the ticket 1', async () => {
+ let result = await nightmare
.wait(selectors.ticketsIndex.searchResult)
.type(selectors.ticketsIndex.searchTicketInput, 'id:1')
.click(selectors.ticketsIndex.searchButton)
.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1)
- .countElement(selectors.ticketsIndex.searchResult)
- .then((result) => {
- expect(result).toEqual(1);
- done();
- }).catch(done.fail);
+ .countElement(selectors.ticketsIndex.searchResult);
+
+ expect(result).toEqual(1);
});
- it(`should click on the search result to access to the ticket packages`, (done) => {
- return nightmare
+ it(`should click on the search result to access to the ticket packages`, async () => {
+ let url = await nightmare
.waitForTextInElement(selectors.ticketsIndex.searchResultAddress, 'address 21')
.waitToClick(selectors.ticketsIndex.searchResult)
.waitToClick(selectors.ticketPackages.packagesButton)
.waitForURL('package/index')
- .url()
- .then((url) => {
- expect(url).toContain('package/index');
- done();
- }).catch(done.fail);
+ .url();
+
+ expect(url).toContain('package/index');
});
- it(`should delete the first package and receive and error to save a new one with blank quantity`, (done) => {
- return nightmare
+ it(`should delete the first package and receive and error to save a new one with blank quantity`, async () => {
+ let result = await nightmare
.waitToClick(selectors.ticketPackages.firstRemovePackageButton)
.waitToClick(selectors.ticketPackages.addPackageButton)
.waitToClick(selectors.ticketPackages.firstPackageSelect)
.waitToClick(selectors.ticketPackages.firstPackageSelectOptionTwo)
.click(selectors.ticketPackages.savePackagesButton)
- .waitForLastSnackbar()
- .then((result) => {
- expect(result).toEqual('Some fields are invalid');
- done();
- }).catch(done.fail);
+ .waitForLastSnackbar();
+
+ expect(result).toEqual('Some fields are invalid');
});
- it(`should attempt create a new package but receive an error if quantity is a string`, (done) => {
- return nightmare
+ it(`should attempt create a new package but receive an error if quantity is a string`, async () => {
+ let result = await nightmare
.type(selectors.ticketPackages.firstQuantityInput, 'ninety 9')
.click(selectors.ticketPackages.savePackagesButton)
- .waitForLastSnackbar()
- .then((result) => {
- expect(result).toEqual('Some fields are invalid');
- done();
- }).catch(done.fail);
+ .waitForLastSnackbar();
+
+ expect(result).toEqual('Some fields are invalid');
});
- it(`should attempt create a new package but receive an error if quantity is 0`, (done) => {
- return nightmare
+ it(`should attempt create a new package but receive an error if quantity is 0`, async () => {
+ let result = await nightmare
.clearInput(selectors.ticketPackages.firstQuantityInput)
.type(selectors.ticketPackages.firstQuantityInput, 0)
.click(selectors.ticketPackages.savePackagesButton)
- .waitForLastSnackbar()
- .then((result) => {
- expect(result).toEqual('Some fields are invalid');
- done();
- }).catch(done.fail);
+ .waitForLastSnackbar();
+
+ expect(result).toEqual('Some fields are invalid');
});
- it(`should attempt create a new package but receive an error if package is blank`, (done) => {
- return nightmare
+ it(`should attempt create a new package but receive an error if package is blank`, async () => {
+ let result = await nightmare
.clearInput(selectors.ticketPackages.firstQuantityInput)
.type(selectors.ticketPackages.firstQuantityInput, 99)
.click(selectors.ticketPackages.clearPackageSelectButton)
.click(selectors.ticketPackages.savePackagesButton)
- .waitForLastSnackbar()
- .then((result) => {
- expect(result).toEqual('Package cannot be blank');
- done();
- }).catch(done.fail);
+ .waitForLastSnackbar();
+
+ expect(result).toEqual('Package cannot be blank');
});
- it(`should create a new package with correct data`, (done) => {
- return nightmare
+ it(`should create a new package with correct data`, async () => {
+ let result = await nightmare
.waitToClick(selectors.ticketPackages.firstPackageSelect)
.waitToClick(selectors.ticketPackages.firstPackageSelectOptionTwo)
.waitForTextInInput(selectors.ticketPackages.firstPackageSelect, 'Legendary Box')
.click(selectors.ticketPackages.savePackagesButton)
- .waitForLastSnackbar()
- .then((result) => {
- expect(result).toEqual('Data saved!');
- done();
- }).catch(done.fail);
+ .waitForLastSnackbar();
+
+ expect(result).toEqual('Data saved!');
});
- it(`should confirm the first select is the expected one`, (done) => {
- return nightmare
+ it(`should confirm the first select is the expected one`, async () => {
+ let result = await nightmare
.click(selectors.ticketSales.saleButton)
.wait(selectors.ticketSales.firstPackageSelect)
.click(selectors.ticketPackages.packagesButton)
.waitForTextInInput(selectors.ticketPackages.firstPackageSelect, 'Legendary Box')
- .getInputValue(selectors.ticketPackages.firstPackageSelect)
- .then((result) => {
- expect(result).toEqual('Legendary Box');
- done();
- }).catch(done.fail);
+ .getInputValue(selectors.ticketPackages.firstPackageSelect);
+
+ expect(result).toEqual('Legendary Box');
});
- it(`should confirm the first quantity is the expected one`, (done) => {
- return nightmare
+ it(`should confirm the first quantity is the expected one`, async () => {
+ let result = await nightmare
.waitForTextInInput(selectors.ticketPackages.firstQuantityInput, '99')
- .getInputValue(selectors.ticketPackages.firstQuantityInput)
- .then((result) => {
- expect(result).toEqual('99');
- done();
- }).catch(done.fail);
+ .getInputValue(selectors.ticketPackages.firstQuantityInput);
+
+ expect(result).toEqual('99');
});
});
diff --git a/package-lock.json b/package-lock.json
index 48fe0ed94a..5ea74cf5c0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -250,7 +250,7 @@
"string-width": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
- "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+ "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=",
"dev": true,
"requires": {
"is-fullwidth-code-point": "^2.0.0",
@@ -1482,7 +1482,7 @@
"bluebird": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
- "integrity": "sha1-2VUfnemPH82h5oPRfukaBgLuLrk=",
+ "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==",
"dev": true
},
"bn.js": {
@@ -1677,7 +1677,7 @@
"string-width": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
- "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+ "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=",
"dev": true,
"requires": {
"is-fullwidth-code-point": "^2.0.0",
@@ -4340,7 +4340,7 @@
"dot-prop": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz",
- "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==",
+ "integrity": "sha1-HxngwuGqDjJ5fEl5nyg3rGr2nFc=",
"dev": true,
"requires": {
"is-obj": "^1.0.0"
@@ -4447,7 +4447,7 @@
},
"jsonfile": {
"version": "2.4.0",
- "resolved": "http://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
"integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=",
"dev": true,
"requires": {
@@ -5545,7 +5545,7 @@
},
"readable-stream": {
"version": "2.3.6",
- "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@@ -10019,7 +10019,7 @@
"jasmine-spec-reporter": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-4.2.1.tgz",
- "integrity": "sha1-HWMq7ANBZwrTJPkrqEtLMrNeniI=",
+ "integrity": "sha512-FZBoZu7VE5nR7Nilzy+Np8KuVIOxF4oXDPDknehCYBDE080EnlPu0afdZNmpGDBRCUBv3mj5qgqCRmk6W/K8vg==",
"dev": true,
"requires": {
"colors": "1.1.2"
@@ -10141,7 +10141,7 @@
"karma": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/karma/-/karma-1.7.1.tgz",
- "integrity": "sha1-hcwI6eCiLXzpzKN8ShvoJPaisa4=",
+ "integrity": "sha512-k5pBjHDhmkdaUccnC7gE3mBzZjcxyxYsYVaqiL2G5AqlfLyBO5nw2VdNK+O16cveEPd/gIOWULH7gkiYYwVNHg==",
"dev": true,
"requires": {
"bluebird": "^3.3.0",
@@ -11724,12 +11724,14 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -11749,7 +11751,8 @@
"concat-map": {
"version": "0.0.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"console-control-strings": {
"version": "1.1.0",
@@ -11897,6 +11900,7 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@@ -19187,7 +19191,7 @@
"split2": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz",
- "integrity": "sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw==",
+ "integrity": "sha1-GGsldbz4PoW30YRldWI47k7kJJM=",
"dev": true,
"requires": {
"through2": "^2.0.2"
@@ -19789,7 +19793,7 @@
"touch": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
- "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==",
+ "integrity": "sha1-/jZfX3XsntTlaCXgu3bSSrdK+Ds=",
"dev": true,
"requires": {
"nopt": "~1.0.10"
@@ -20286,7 +20290,7 @@
"useragent": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/useragent/-/useragent-2.3.0.tgz",
- "integrity": "sha1-IX+UOtVAyyEoZYqyP8lg9qiMmXI=",
+ "integrity": "sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw==",
"dev": true,
"requires": {
"lru-cache": "4.1.x",
@@ -20754,12 +20758,14 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -20774,17 +20780,20 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"core-util-is": {
"version": "1.0.2",
@@ -20901,7 +20910,8 @@
"inherits": {
"version": "2.0.3",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"ini": {
"version": "1.3.5",
@@ -20913,6 +20923,7 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -20927,6 +20938,7 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@@ -20934,12 +20946,14 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"minipass": {
"version": "2.2.4",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"safe-buffer": "^5.1.1",
"yallist": "^3.0.0"
@@ -20958,6 +20972,7 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"minimist": "0.0.8"
}
@@ -21038,7 +21053,8 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"object-assign": {
"version": "4.1.1",
@@ -21050,6 +21066,7 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"wrappy": "1"
}
@@ -21171,6 +21188,7 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@@ -22930,7 +22948,7 @@
"write-file-atomic": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz",
- "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==",
+ "integrity": "sha1-H/YVdcLipOjlENb6TiQ8zhg5mas=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.11",
diff --git a/services/client/common/methods/receipt/filter.js b/services/client/common/methods/receipt/filter.js
index 12474240a2..f63bac66d6 100644
--- a/services/client/common/methods/receipt/filter.js
+++ b/services/client/common/methods/receipt/filter.js
@@ -29,46 +29,49 @@ module.exports = Self => {
Self.filter = async (filter, params) => {
let stmt = new ParameterizedSQL(
- `SELECT
- r.id,
- r.isConciliate,
- r.payed,
- c.code AS company,
- r.created,
- '' description,
- 0 AS debit,
- r.amountPaid AS credit,
- r.bankFk,
- firstName,
- name,
- r.clientFk
- FROM vn.receipt r
- LEFT JOIN vn.worker w ON w.id = r.workerFk
- JOIN vn.company c ON c.id = r.companyFk
- WHERE clientFk = ?
- UNION ALL
- SELECT
- i.id,
- TRUE,
- i.dued,
- c.code AS company,
- i.created,
- CONCAT(' N/FRA ', i.ref) description,
- i.amount AS debit,
- 0 credit,
- NULL bank,
- NULL firstName,
- NULL name,
- i.clientFk
- FROM vn.invoiceOut i
- JOIN vn.company c ON c.id = i.companyFk
- WHERE clientFk = ?
+ `SELECT * FROM (
+ SELECT
+ r.id,
+ r.isConciliate,
+ r.payed,
+ c.code AS company,
+ r.created,
+ '' description,
+ 0 AS debit,
+ r.amountPaid AS credit,
+ r.bankFk,
+ firstName,
+ name,
+ r.clientFk
+ FROM vn.receipt r
+ LEFT JOIN vn.worker w ON w.id = r.workerFk
+ JOIN vn.company c ON c.id = r.companyFk
+ WHERE clientFk = ?
+ UNION ALL
+ SELECT
+ i.id,
+ TRUE,
+ i.dued,
+ c.code,
+ i.created,
+ CONCAT(' N/FRA ', i.ref),
+ i.amount,
+ 0 credit,
+ NULL,
+ NULL,
+ NULL,
+ i.clientFk
+ FROM vn.invoiceOut i
+ JOIN vn.company c ON c.id = i.companyFk
+ WHERE clientFk = ?
+ ) t
ORDER BY payed DESC, created DESC`, [
- params.clientFk,
- params.clientFk
- ]);
+ params.clientFk,
+ params.clientFk
+ ]
+ );
- stmt.merge(Self.buildPagination(filter));
+ stmt.merge(Self.makeLimit(filter));
return await Self.rawStmt(stmt);
};
};
diff --git a/services/db/install/changes/1.2-CHECK/10-ACL.sql b/services/db/install/changes/1.2-CHECK/10-ACL.sql
index 04548b327a..2750d43a53 100644
--- a/services/db/install/changes/1.2-CHECK/10-ACL.sql
+++ b/services/db/install/changes/1.2-CHECK/10-ACL.sql
@@ -1 +1,2 @@
INSERT INTO `salix`.`ACL` (`id`, `model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES (118, 'WorkerTeam', '*', '*', 'ALLOW', 'role', 'salesPerson');
+INSERT INTO `salix`.`ACL` (`id`, `model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES (119, 'TicketRequest', '*', '*', 'ALLOW', 'role', 'salesPerson');
diff --git a/services/db/install/changes/1.2-CHECK/11.ticketRequest.sql b/services/db/install/changes/1.2-CHECK/11.ticketRequest.sql
new file mode 100644
index 0000000000..5fd0276f19
--- /dev/null
+++ b/services/db/install/changes/1.2-CHECK/11.ticketRequest.sql
@@ -0,0 +1,18 @@
+USE `vn`;
+CREATE
+ OR REPLACE ALGORITHM = UNDEFINED
+ DEFINER = `root`@`%`
+ SQL SECURITY DEFINER
+VIEW `ticketRequest` AS
+ SELECT
+ `t`.`Id_ORDEN` AS `id`,
+ `t`.`ORDEN` AS `description`,
+ `t`.`CodVENDEDOR` AS `requestFk`,
+ `t`.`CodCOMPRADOR` AS `atenderFk`,
+ `t`.`CANTIDAD` AS `quantity`,
+ `t`.`PRECIOMAX` AS `price`,
+ `t`.`KO` AS `isOk`,
+ `t`.`Id_Movimiento` AS `saleFk`,
+ `t`.`odbc_date` AS `created`
+ FROM
+ `vn2008`.`Ordenes` `t`;
diff --git a/services/db/install/dump/fixtures.sql b/services/db/install/dump/fixtures.sql
index e33fae53f6..75be58e182 100644
--- a/services/db/install/dump/fixtures.sql
+++ b/services/db/install/dump/fixtures.sql
@@ -1017,4 +1017,11 @@ INSERT INTO `vn2008`.`workerTeam`(`id`, `team`, `user`)
(3, 2, 101),
(4, 2, 102),
(5, 3, 103),
- (6, 3, 104);
\ No newline at end of file
+ (6, 3, 104);
+
+INSERT INTO `vn`.`ticketRequest`(`id`, `description`, `requestFk`, `atenderFk`, `quantity`, `price`, `isOk`, `saleFk`, `created`)
+ VALUES
+ (1, 'Gem of Time', '018', '035', 5, 9.10, 0, 1, DATE_ADD(CURDATE(), INTERVAL -15 DAY)),
+ (2, 'Gem of Mind', '018', '035', 10, 1.07, 0, 2, DATE_ADD(CURDATE(), INTERVAL -15 DAY)),
+ (3, 'Mark I', '018', '035', 20, 3.06, 0, 4, DATE_ADD(CURDATE(), INTERVAL -15 DAY)),
+ (4, 'Gem of Mind', '018', '035', 15, 1.30, 0, 7, CURDATE());
\ No newline at end of file
diff --git a/services/loopback/common/filter.js b/services/loopback/common/filter.js
index 9f23b5330e..73833116f9 100644
--- a/services/loopback/common/filter.js
+++ b/services/loopback/common/filter.js
@@ -46,15 +46,7 @@ function mergeWhere(src, dst) {
let and = [];
if (src) and.push(src);
if (dst) and.push(dst);
-
- switch (and.length) {
- case 0:
- return undefined;
- case 1:
- return and[0];
- default:
- return {and};
- }
+ return simplifyOperation(and, 'and');
}
/**
@@ -80,13 +72,40 @@ function mergeFilters(src, dst) {
res.order = src.order;
if (src.limit)
res.limit = src.limit;
+ if (src.offset)
+ res.offset = src.offset;
+ if (src.skip)
+ res.skip = src.skip;
return res;
}
+function simplifyOperation(operation, operator) {
+ switch(operation.length) {
+ case 0:
+ return undefined;
+ case 1:
+ return operation[0];
+ default:
+ return {[operator]: operation};
+ }
+}
+
+function buildFilter(params, builderFunc) {
+ let and = [];
+ for (let param in params) {
+ let value = params[param];
+ if (value == null) continue;
+ let expr = builderFunc(param, value);
+ if (expr) and.push(expr);
+ }
+ return simplifyOperation(and, 'and');
+}
+
module.exports = {
fieldsToObject: fieldsToObject,
mergeFields: mergeFields,
mergeWhere: mergeWhere,
- mergeFilters: mergeFilters
+ mergeFilters: mergeFilters,
+ buildFilter: buildFilter
};
diff --git a/services/loopback/common/locale/en.json b/services/loopback/common/locale/en.json
index d870087d10..b188713ed9 100644
--- a/services/loopback/common/locale/en.json
+++ b/services/loopback/common/locale/en.json
@@ -37,5 +37,6 @@
"You don't have enough privileges to do that": "You don't have enough privileges to do that",
"You don't have enough privileges to change that field": "You don't have enough privileges to change that field",
"You don't have enough privileges": "You don't have enough privileges",
- "You can't make changes on a client with verified data": "You can't make changes on a client with verified data"
+ "You can't make changes on a client with verified data": "You can't make changes on a client with verified data",
+ "That payment method requires a BIC": "That payment method requires a BIC"
}
\ No newline at end of file
diff --git a/services/loopback/common/methods/ticket/filter.js b/services/loopback/common/methods/ticket/filter.js
index 0a7edf1f41..ec2da58958 100644
--- a/services/loopback/common/methods/ticket/filter.js
+++ b/services/loopback/common/methods/ticket/filter.js
@@ -1,16 +1,68 @@
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
+const buildFilter = require('../../filter.js').buildFilter;
+const mergeFilters = require('../../filter.js').mergeFilters;
module.exports = Self => {
Self.remoteMethod('filter', {
description: 'Find all instances of the model matched by filter from the data source.',
- accessType: 'READ',
accepts: [
{
+ arg: 'ctx',
+ type: 'Object',
+ http: {source: 'context'}
+ }, {
arg: 'filter',
type: 'Object',
- description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
- http: {source: 'query'}
+ description: `Filter defining where, order, offset, and limit - must be a JSON-encoded string`
+ }, {
+ arg: 'search',
+ type: 'String',
+ description: `If it's and integer searchs by id, otherwise it searchs by nickname`
+ }, {
+ arg: 'from',
+ type: 'Date',
+ description: `The from date filter`
+ }, {
+ arg: 'to',
+ type: 'Date',
+ description: `The to date filter`
+ }, {
+ arg: 'nickname',
+ type: 'String',
+ description: `The nickname filter`
+ }, {
+ arg: 'id',
+ type: 'Integer',
+ description: `The ticket id filter`
+ }, {
+ arg: 'clientFk',
+ type: 'Integer',
+ description: `The client id filter`
+ }, {
+ arg: 'agencyModeFk',
+ type: 'Integer',
+ description: `The agency mode id filter`
+ }, {
+ arg: 'warehouseFk',
+ type: 'Integer',
+ description: `The warehouse id filter`
+ }, {
+ arg: 'salesPersonFk',
+ type: 'Integer',
+ description: `The salesperson id filter`
+ }, {
+ arg: 'provinceFk',
+ type: 'Integer',
+ description: `The province id filter`
+ }, {
+ arg: 'stateFk',
+ type: 'Number',
+ description: `The state id filter`
+ }, {
+ arg: 'myTeam',
+ type: 'Boolean',
+ description: `Whether to show only tickets for the current logged user team (Ignored until implemented)`
}
],
returns: {
@@ -18,12 +70,52 @@ module.exports = Self => {
root: true
},
http: {
- path: `/filter`,
+ path: '/filter',
verb: 'GET'
}
});
- Self.filter = async filter => {
+ Self.filter = async (ctx, filter) => {
+ let conn = Self.dataSource.connector;
+
+ // TODO: Using the current worker id until WorkerTeam model is created
+ let worker = await Self.app.models.Worker.findOne({
+ fields: ['id'],
+ where: {userFk: ctx.req.accessToken.userId}
+ });
+ let teamIds = [worker && worker.id];
+
+ let where = buildFilter(ctx.args, (param, value) => {
+ switch (param) {
+ case 'search':
+ return /^\d+$/.test(value)
+ ? {'t.id': value}
+ : {'t.nickname': {like: `%${value}%`}};
+ case 'from':
+ return {'t.shipped': {gte: value}};
+ case 'to':
+ return {'t.shipped': {lte: value}};
+ case 'nickname':
+ return {'t.nickname': {like: `%${value}%`}};
+ case 'salesPersonFk':
+ return {'c.salesPersonFk': value};
+ case 'provinceFk':
+ return {'a.provinceFk': value};
+ case 'stateFk':
+ return {'ts.stateFk': value};
+ case 'myTeam':
+ return {'c.salesPersonFk': {inq: teamIds}};
+ case 'id':
+ case 'clientFk':
+ case 'agencyModeFk':
+ case 'warehouseFk':
+ param = `t.${param}`;
+ return {[param]: value};
+ }
+ });
+
+ filter = mergeFilters(filter, {where});
+
let stmts = [];
let stmt;
@@ -31,12 +123,13 @@ module.exports = Self => {
stmt = new ParameterizedSQL(
`CREATE TEMPORARY TABLE tmp.filter
- (INDEX (id)) ENGINE = MEMORY
+ (INDEX (id))
+ ENGINE = MEMORY
SELECT
t.id,
- t.shipped,
- t.nickname,
- t.refFk,
+ t.shipped,
+ t.nickname,
+ t.refFk,
t.routeFk,
t.agencyModeFk,
t.warehouseFk,
@@ -44,34 +137,36 @@ module.exports = Self => {
c.salesPersonFk,
a.provinceFk,
ts.stateFk,
- p.name AS province,
- w.name AS warehouse,
- am.name AS agencyMode,
- st.name AS state,
+ p.name AS province,
+ w.name AS warehouse,
+ am.name AS agencyMode,
+ st.name AS state,
wk.name AS salesPerson
- FROM ticket t
- LEFT JOIN address a ON a.id = t.addressFk
- LEFT JOIN province p ON p.id = a.provinceFk
- LEFT JOIN warehouse w ON w.id = t.warehouseFk
- LEFT JOIN agencyMode am ON am.id = t.agencyModeFk
- LEFT JOIN ticketState ts ON ts.ticketFk = t.id
- LEFT JOIN state st ON st.id = ts.stateFk
- LEFT JOIN client c ON c.id = t.clientFk
- LEFT JOIN worker wk ON wk.id = c.salesPersonFk`);
- stmt.merge(Self.buildSuffix(filter, 't'));
+ FROM ticket t
+ LEFT JOIN address a ON a.id = t.addressFk
+ LEFT JOIN province p ON p.id = a.provinceFk
+ LEFT JOIN warehouse w ON w.id = t.warehouseFk
+ LEFT JOIN agencyMode am ON am.id = t.agencyModeFk
+ LEFT JOIN ticketState ts ON ts.ticketFk = t.id
+ LEFT JOIN state st ON st.id = ts.stateFk
+ LEFT JOIN client c ON c.id = t.clientFk
+ LEFT JOIN worker wk ON wk.id = c.salesPersonFk`);
+ stmt.merge(conn.makeSuffix(filter));
stmts.push(stmt);
stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.ticket');
stmts.push(`
CREATE TEMPORARY TABLE tmp.ticket
- (INDEX (ticketFk)) ENGINE = MEMORY
+ (INDEX (ticketFk))
+ ENGINE = MEMORY
SELECT id ticketFk FROM tmp.filter`);
stmts.push('CALL ticketGetTotal()');
stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.ticketGetProblems');
stmts.push(`
CREATE TEMPORARY TABLE tmp.ticketGetProblems
- (INDEX (ticketFk)) ENGINE = MEMORY
+ (INDEX (ticketFk))
+ ENGINE = MEMORY
SELECT id ticketFk, clientFk, warehouseFk, shipped
FROM tmp.filter`);
stmts.push('CALL ticketGetProblems()');
@@ -84,7 +179,7 @@ module.exports = Self => {
FROM tmp.filter f
LEFT JOIN tmp.ticketProblems tp ON tp.ticketFk = f.id
LEFT JOIN tmp.ticketTotal tt ON tt.ticketFk = f.id`);
- stmt.merge(Self.buildOrderBy(filter));
+ stmt.merge(conn.makeOrderBy(filter.order));
let ticketsIndex = stmts.push(stmt) - 1;
stmts.push(
@@ -95,7 +190,7 @@ module.exports = Self => {
tmp.ticketGetProblems`);
let sql = ParameterizedSQL.join(stmts, ';');
- let result = await Self.rawStmt(sql);
+ let result = await conn.executeStmt(sql);
return result[ticketsIndex];
};
diff --git a/services/loopback/common/methods/ticket/specs/filter.spec.js b/services/loopback/common/methods/ticket/specs/filter.spec.js
index 38de4fabe2..e1d790b2eb 100644
--- a/services/loopback/common/methods/ticket/specs/filter.spec.js
+++ b/services/loopback/common/methods/ticket/specs/filter.spec.js
@@ -1,9 +1,11 @@
const app = require(`${servicesDir}/ticket/server/server`);
describe('ticket filter()', () => {
- it('should call the filter method', async() => {
+ it('should call the filter method', async () => {
+ let ctx = {req: {accessToken: {userId: 9}}};
+
let filter = {order: 'shipped DESC'};
- let result = await app.models.Ticket.filter(filter);
+ let result = await app.models.Ticket.filter(ctx, filter);
let ticketId = result[0].id;
expect(ticketId).toEqual(15);
diff --git a/services/loopback/common/models/ticket-request.json b/services/loopback/common/models/ticket-request.json
new file mode 100644
index 0000000000..504b67d81a
--- /dev/null
+++ b/services/loopback/common/models/ticket-request.json
@@ -0,0 +1,46 @@
+{
+ "name": "TicketRequest",
+ "base": "VnModel",
+ "options": {
+ "mysql": {
+ "table": "ticketRequest"
+ }
+ },
+ "properties": {
+ "id": {
+ "type": "Number",
+ "id": true,
+ "description": "Identifier"
+ },
+ "description": {
+ "type": "String"
+ },
+ "created": {
+ "type": "Date"
+ },
+ "quantity": {
+ "type": "Number"
+ },
+ "price": {
+ "type": "Number"
+ },
+ "isOk": {
+ "type": "Boolean"
+ },
+ "atender": {
+ "type": "String",
+ "columnName": "atenderFk"
+ },
+ "requester": {
+ "type": "String",
+ "columnName": "requesterFk"
+ }
+ },
+ "relations": {
+ "sale": {
+ "type": "belongsTo",
+ "model": "Sale",
+ "foreignKey": "saleFk"
+ }
+ }
+}
\ No newline at end of file
diff --git a/services/loopback/common/models/vn-model.js b/services/loopback/common/models/vn-model.js
index 65b6a139c8..e5c15be8a7 100644
--- a/services/loopback/common/models/vn-model.js
+++ b/services/loopback/common/models/vn-model.js
@@ -5,6 +5,10 @@ const UserError = require('../helpers').UserError;
module.exports = function(Self) {
Self.ParameterizedSQL = ParameterizedSQL;
+ require('../methods/vn-model/validateBinded')(Self);
+ require('../methods/vn-model/rewriteDbError')(Self);
+ require('../methods/vn-model/getSetValues')(Self);
+
Self.setup = function() {
Self.super_.setup.call(this);
@@ -93,7 +97,7 @@ module.exports = function(Self) {
};
Self.remoteMethodCtx = function(methodName, args) {
- var ctx = {
+ let ctx = {
arg: 'context',
type: 'object',
http: function(ctx) {
@@ -131,9 +135,9 @@ module.exports = function(Self) {
let options = {transaction: transaction};
try {
- if (actions.delete && actions.delete.length) {
+ if (actions.delete && actions.delete.length)
await this.destroyAll({id: {inq: actions.delete}}, options);
- }
+
if (actions.update) {
try {
let promises = [];
@@ -159,131 +163,6 @@ module.exports = function(Self) {
}
};
- /**
- * Executes an SQL query
- * @param {String} query - SQL query
- * @param {Object} params - Query data params
- * @param {Object} options - Query options (Ex: {transaction})
- * @param {Object} cb - Callback
- * @return {Object} Connector promise
- */
- Self.rawSql = function(query, params, options = {}, cb) {
- var connector = this.dataSource.connector;
- return new Promise(function(resolve, reject) {
- connector.execute(query, params, options, function(error, response) {
- if (cb)
- cb(error, response);
- if (error)
- reject(error);
- else
- resolve(response);
- });
- });
- };
-
- /**
- * Executes an SQL query from an Stmt
- * @param {ParameterizedSql} stmt - Stmt object
- * @param {Object} options - Query options (Ex: {transaction})
- * @return {Object} Connector promise
- */
- Self.rawStmt = function(stmt, options = {}) {
- return this.rawSql(stmt.sql, stmt.params, options);
- };
-
- Self.escapeName = function(name) {
- return this.dataSource.connector.escapeName(name);
- };
-
- /**
- * Constructs SQL where clause from Loopback filter
- * @param {Object} filter - filter
- * @param {String} tableAlias - Query main table alias
- * @return {String} Builded SQL where
- */
- Self.buildWhere = function(filter, tableAlias) {
- let connector = this.dataSource.connector;
- let wrappedConnector = Object.create(connector);
- wrappedConnector.columnEscaped = function(model, property) {
- let sql = tableAlias
- ? connector.escapeName(tableAlias) + '.'
- : '';
- return sql + connector.columnEscaped(model, property);
- };
-
- return wrappedConnector.makeWhere(this.modelName, filter.where);
- };
-
- /**
- * Constructs SQL limit clause from Loopback filter
- * @param {Object} filter - filter
- * @return {String} Builded SQL limit
- */
- Self.buildLimit = function(filter) {
- let sql = new ParameterizedSQL('');
- this.dataSource.connector.applyPagination(this.modelName, sql, filter);
- return sql;
- };
-
- /**
- * Constructs SQL order clause from Loopback filter
- * @param {Object} filter - filter
- * @return {String} Builded SQL order
- */
- Self.buildOrderBy = function(filter) {
- let order = filter.order;
-
- if (!order)
- return '';
- if (typeof order === 'string')
- order = [order];
-
- let clauses = [];
-
- for (let clause of order) {
- let sqlOrder = '';
- let t = clause.split(/[\s,]+/);
- let names = t[0].split('.');
-
- if (names.length > 1)
- sqlOrder += this.escapeName(names[0]) + '.';
- sqlOrder += this.escapeName(names[names.length - 1]);
-
- if (t.length > 1)
- sqlOrder += ' ' + (t[1].toUpperCase() == 'ASC' ? 'ASC' : 'DESC');
-
- clauses.push(sqlOrder);
- }
-
- return `ORDER BY ${clauses.join(', ')}`;
- };
-
- /**
- * Constructs SQL pagination from Loopback filter
- * @param {Object} filter - filter
- * @return {String} Builded SQL pagination
- */
- Self.buildPagination = function(filter) {
- return ParameterizedSQL.join([
- this.buildOrderBy(filter),
- this.buildLimit(filter)
- ]);
- };
-
- /**
- * Constructs SQL filter including where, order and limit
- * clauses from Loopback filter
- * @param {Object} filter - filter
- * @param {String} tableAlias - Query main table alias
- * @return {String} Builded SQL limit
- */
- Self.buildSuffix = function(filter, tableAlias) {
- return ParameterizedSQL.join([
- this.buildWhere(filter, tableAlias),
- this.buildPagination(filter)
- ]);
- };
-
Self.checkAcls = async function(ctx, actionType) {
let userId = ctx.req.accessToken.userId;
let models = this.app.models;
@@ -294,9 +173,8 @@ module.exports = function(Self) {
function modifiedProperties(data) {
let properties = [];
- for (property in data) {
+ for (property in data)
properties.push(property);
- }
return properties;
}
@@ -350,10 +228,38 @@ module.exports = function(Self) {
return this.checkAcls(ctx, 'insert');
};
- // Action bindings
- require('../methods/vn-model/validateBinded')(Self);
- // Handle MySql errors
- require('../methods/vn-model/rewriteDbError')(Self);
- // Get table set of values
- require('../methods/vn-model/getSetValues')(Self);
+ /*
+ * Shortcut to VnMySQL.executeP()
+ */
+ Self.rawSql = function(query, params, options, cb) {
+ return this.dataSource.connector.executeP(query, params, options, cb);
+ };
+
+ /*
+ * Shortcut to VnMySQL.executeStmt()
+ */
+ Self.rawStmt = function(stmt, options) {
+ return this.dataSource.connector.executeStmt(stmt, options);
+ };
+
+ /*
+ * Shortcut to VnMySQL.makeLimit()
+ */
+ Self.makeLimit = function(filter) {
+ return this.dataSource.connector.makeLimit(filter);
+ };
+
+ /*
+ * Shortcut to VnMySQL.makeSuffix()
+ */
+ Self.makeSuffix = function(filter) {
+ return this.dataSource.connector.makeSuffix(filter);
+ };
+
+ /*
+ * Shortcut to VnMySQL.buildModelSuffix()
+ */
+ Self.buildSuffix = function(filter, tableAlias) {
+ return this.dataSource.connector.buildModelSuffix(this.modelName, filter, tableAlias);
+ };
};
diff --git a/services/loopback/server/connectors/vn-mysql.js b/services/loopback/server/connectors/vn-mysql.js
index ead44653c1..046866edea 100644
--- a/services/loopback/server/connectors/vn-mysql.js
+++ b/services/loopback/server/connectors/vn-mysql.js
@@ -1,19 +1,235 @@
-var mysql = require('mysql');
+const mysql = require('mysql');
const loopbackConnector = require('loopback-connector');
const SqlConnector = loopbackConnector.SqlConnector;
const ParameterizedSQL = loopbackConnector.ParameterizedSQL;
-var MySQL = require('loopback-connector-mysql').MySQL;
-var EnumFactory = require('loopback-connector-mysql').EnumFactory;
-var debug = require('debug')('loopback-connector-sql');
+const MySQL = require('loopback-connector-mysql').MySQL;
+const EnumFactory = require('loopback-connector-mysql').EnumFactory;
+const fs = require('fs');
-exports.initialize = function(dataSource, callback) {
+class VnMySQL extends MySQL {
+ constructor(settings) {
+ super();
+ SqlConnector.call(this, 'mysql', settings);
+ }
+
+ toColumnValue(prop, val) {
+ if (val == null || !prop || prop.type !== Date)
+ return MySQL.prototype.toColumnValue.call(this, prop, val);
+
+ val = new Date(val);
+
+ return val.getFullYear() + '-' +
+ fillZeros(val.getMonth() + 1) + '-' +
+ fillZeros(val.getDate()) + ' ' +
+ fillZeros(val.getHours()) + ':' +
+ fillZeros(val.getMinutes()) + ':' +
+ fillZeros(val.getSeconds());
+
+ function fillZeros(v) {
+ return v < 10 ? '0' + v : v;
+ }
+ }
+
+ /**
+ * Promisified version of execute().
+ *
+ * @param {String} query The SQL query string
+ * @param {Array} params The query parameters
+ * @param {Object} options The loopback options
+ * @param {Function} cb The callback
+ * @return {Promise} The operation promise
+ */
+ executeP(query, params, options = {}, cb) {
+ return new Promise((resolve, reject) => {
+ this.execute(query, params, options, (error, response) => {
+ if (cb)
+ cb(error, response);
+ if (error)
+ reject(error);
+ else
+ resolve(response);
+ });
+ });
+ }
+
+ /**
+ * Executes an SQL query from an Stmt.
+ *
+ * @param {ParameterizedSql} stmt - Stmt object
+ * @param {Object} options Query options (Ex: {transaction})
+ * @return {Object} Connector promise
+ */
+ executeStmt(stmt, options) {
+ return this.executeP(stmt.sql, stmt.params, options);
+ }
+
+ /**
+ * Executes a query from an SQL script.
+ *
+ * @param {String} sqlScript The sql script file
+ * @param {Array} params The query parameters
+ * @param {Object} options Query options (Ex: {transaction})
+ * @return {Object} Connector promise
+ */
+ executeScript(sqlScript, params, options) {
+ return new Promise((resolve, reject) => {
+ fs.readFile(sqlScript, 'utf8', (err, contents) => {
+ if (err) return reject(err);
+ this.execute(contents, params, options)
+ .then(resolve, reject);
+ });
+ });
+ }
+
+ /**
+ * Build the SQL WHERE clause for the where object without checking that
+ * properties exists in the model.
+ *
+ * @param {object} where An object for the where conditions
+ * @return {ParameterizedSQL} The SQL WHERE clause
+ */
+ makeWhere(where) {
+ let wrappedConnector = Object.create(this);
+ Object.assign(wrappedConnector, {
+ getModelDefinition() {
+ return {
+ properties: new Proxy({}, {
+ get: () => true
+ })
+ };
+ },
+ toColumnValue(_, val) {
+ return val;
+ },
+ columnEscaped(_, property) {
+ return this.escapeName(property);
+ }
+ });
+
+ return wrappedConnector.buildWhere(null, where);
+ }
+
+ /**
+ * Constructs SQL order clause from Loopback filter.
+ *
+ * @param {Object} order The order definition
+ * @return {String} Built SQL order
+ */
+ makeOrderBy(order) {
+ if (!order)
+ return '';
+ if (typeof order === 'string')
+ order = [order];
+
+ let clauses = [];
+
+ for (let clause of order) {
+ let sqlOrder = '';
+ let t = clause.split(/[\s,]+/);
+
+ sqlOrder += this.escapeName(t[0]);
+
+ if (t.length > 1)
+ sqlOrder += ' ' + (t[1].toUpperCase() == 'ASC' ? 'ASC' : 'DESC');
+
+ clauses.push(sqlOrder);
+ }
+
+ return `ORDER BY ${clauses.join(', ')}`;
+ }
+
+ /**
+ * Constructs SQL limit clause from Loopback filter.
+ *
+ * @param {Object} filter The loopback filter
+ * @return {String} Built SQL limit
+ */
+ makeLimit(filter) {
+ let limit = parseInt(filter.limit);
+ let offset = parseInt(filter.offset || filter.skip);
+ return this._buildLimit(null, limit, offset);
+ }
+
+ /**
+ * Constructs SQL pagination from Loopback filter.
+ *
+ * @param {Object} filter The loopback filter
+ * @return {String} Built SQL pagination
+ */
+ makePagination(filter) {
+ return ParameterizedSQL.join([
+ this.makeOrderBy(filter.order),
+ this.makeLimit(filter)
+ ]);
+ }
+
+ /**
+ * Constructs SQL filter including where, order and limit
+ * clauses from Loopback filter.
+ *
+ * @param {Object} filter The loopback filter
+ * @return {String} Built SQL filter
+ */
+ makeSuffix(filter) {
+ return ParameterizedSQL.join([
+ this.makeWhere(filter.where),
+ this.makePagination(filter)
+ ]);
+ }
+
+ /**
+ * Constructs SQL where clause from Loopback filter discarding
+ * properties that not pertain to the model. If defined, appends
+ * the table alias to each field.
+ *
+ * @param {String} model The model name
+ * @param {Object} where The loopback where filter
+ * @param {String} tableAlias Query main table alias
+ * @return {String} Built SQL where
+ */
+ buildModelWhere(model, where, tableAlias) {
+ let parent = this;
+ let wrappedConnector = Object.create(this);
+ Object.assign(wrappedConnector, {
+ columnEscaped(model, property) {
+ let sql = tableAlias
+ ? this.escapeName(tableAlias) + '.'
+ : '';
+ return sql + parent.columnEscaped(model, property);
+ }
+ });
+
+ return wrappedConnector.buildWhere(model, where);
+ }
+
+ /**
+ * Constructs SQL where clause from Loopback filter discarding
+ * properties that not pertain to the model. If defined, appends
+ * the table alias to each field.
+ *
+ * @param {String} model The model name
+ * @param {Object} filter The loopback filter
+ * @param {String} tableAlias Query main table alias
+ * @return {String} Built SQL suffix
+ */
+ buildModelSuffix(model, filter, tableAlias) {
+ return ParameterizedSQL.join([
+ this.buildModelWhere(model, filter.where, tableAlias),
+ this.makePagination(filter)
+ ]);
+ }
+}
+
+exports.VnMySQL = VnMySQL;
+
+exports.initialize = function initialize(dataSource, callback) {
dataSource.driver = mysql;
dataSource.connector = new VnMySQL(dataSource.settings);
dataSource.connector.dataSource = dataSource;
- var modelBuilder = dataSource.modelBuilder;
- var defineType = modelBuilder.defineValueType ?
+ const modelBuilder = dataSource.modelBuilder;
+ const defineType = modelBuilder.defineValueType ?
modelBuilder.defineValueType.bind(modelBuilder) :
modelBuilder.constructor.registerType.bind(modelBuilder.constructor);
@@ -26,170 +242,7 @@ exports.initialize = function(dataSource, callback) {
process.nextTick(function() {
callback();
});
- } else {
+ } else
dataSource.connector.connect(callback);
- }
}
};
-
-exports.VnMySQL = VnMySQL;
-
-function VnMySQL(settings) {
- SqlConnector.call(this, 'mysql', settings);
-}
-
-VnMySQL.prototype = Object.create(MySQL.prototype);
-VnMySQL.constructor = VnMySQL;
-
-VnMySQL.prototype.toColumnValue = function(prop, val) {
- if (val == null || !prop || prop.type !== Date)
- return MySQL.prototype.toColumnValue.call(this, prop, val);
-
- val = new Date(val);
-
- return val.getFullYear() + '-' +
- fillZeros(val.getMonth() + 1) + '-' +
- fillZeros(val.getDate()) + ' ' +
- fillZeros(val.getHours()) + ':' +
- fillZeros(val.getMinutes()) + ':' +
- fillZeros(val.getSeconds());
-
- function fillZeros(v) {
- return v < 10 ? '0' + v : v;
- }
-};
-
-/**
- * Private make method
- * @param {Object} model Model instance
- * @param {Object} where Where filter
- * @return {ParameterizedSQL} Parametized object
- */
-VnMySQL.prototype._makeWhere = function(model, where) {
- let columnValue;
- let sqlExp;
-
- if (!where) {
- return new ParameterizedSQL('');
- }
- if (typeof where !== 'object' || Array.isArray(where)) {
- debug('Invalid value for where: %j', where);
- return new ParameterizedSQL('');
- }
- var self = this;
- var props = self.getModelDefinition(model).properties;
-
- var whereStmts = [];
- for (var key in where) {
- var stmt = new ParameterizedSQL('', []);
- // Handle and/or operators
- if (key === 'and' || key === 'or') {
- var branches = [];
- var branchParams = [];
- var clauses = where[key];
- if (Array.isArray(clauses)) {
- for (var i = 0, n = clauses.length; i < n; i++) {
- var stmtForClause = self._makeWhere(model, clauses[i]);
- if (stmtForClause.sql) {
- stmtForClause.sql = '(' + stmtForClause.sql + ')';
- branchParams = branchParams.concat(stmtForClause.params);
- branches.push(stmtForClause.sql);
- }
- }
- stmt.merge({
- sql: branches.join(' ' + key.toUpperCase() + ' '),
- params: branchParams
- });
- whereStmts.push(stmt);
- continue;
- }
- // The value is not an array, fall back to regular fields
- }
- var p = props[key];
-
- // eslint-disable one-var
- var expression = where[key];
- var columnName = self.columnEscaped(model, key);
- // eslint-enable one-var
- if (expression === null || expression === undefined) {
- stmt.merge(columnName + ' IS NULL');
- } else if (expression && expression.constructor === Object) {
- var operator = Object.keys(expression)[0];
- // Get the expression without the operator
- expression = expression[operator];
- if (operator === 'inq' || operator === 'nin' || operator === 'between') {
- columnValue = [];
- if (Array.isArray(expression)) {
- // Column value is a list
- for (var j = 0, m = expression.length; j < m; j++) {
- columnValue.push(this.toColumnValue(p, expression[j]));
- }
- } else {
- columnValue.push(this.toColumnValue(p, expression));
- }
- if (operator === 'between') {
- // BETWEEN v1 AND v2
- var v1 = columnValue[0] === undefined ? null : columnValue[0];
- var v2 = columnValue[1] === undefined ? null : columnValue[1];
- columnValue = [v1, v2];
- } else {
- // IN (v1,v2,v3) or NOT IN (v1,v2,v3)
- if (columnValue.length === 0) {
- if (operator === 'inq') {
- columnValue = [null];
- } else {
- // nin () is true
- continue;
- }
- }
- }
- } else if (operator === 'regexp' && expression instanceof RegExp) {
- // do not coerce RegExp based on property definitions
- columnValue = expression;
- } else {
- columnValue = this.toColumnValue(p, expression);
- }
- sqlExp = self.buildExpression(columnName, operator, columnValue, p);
- stmt.merge(sqlExp);
- } else {
- // The expression is the field value, not a condition
- columnValue = self.toColumnValue(p, expression);
- if (columnValue === null) {
- stmt.merge(columnName + ' IS NULL');
- } else if (columnValue instanceof ParameterizedSQL) {
- stmt.merge(columnName + '=').merge(columnValue);
- } else {
- stmt.merge({
- sql: columnName + '=?',
- params: [columnValue]
- });
- }
- }
- whereStmts.push(stmt);
- }
- var params = [];
- var sqls = [];
- for (var k = 0, s = whereStmts.length; k < s; k++) {
- sqls.push(whereStmts[k].sql);
- params = params.concat(whereStmts[k].params);
- }
- var whereStmt = new ParameterizedSQL({
- sql: sqls.join(' AND '),
- params: params
- });
- return whereStmt;
-};
-
-/**
- * Build the SQL WHERE clause for the where object
- * @param {string} model Model name
- * @param {object} where An object for the where conditions
- * @return {ParameterizedSQL} The SQL WHERE clause
- */
-VnMySQL.prototype.makeWhere = function(model, where) {
- var whereClause = this._makeWhere(model, where);
- if (whereClause.sql) {
- whereClause.sql = 'WHERE ' + whereClause.sql;
- }
- return whereClause;
-};
diff --git a/services/loopback/server/model-config.json b/services/loopback/server/model-config.json
index 47a46c412d..7c01414945 100644
--- a/services/loopback/server/model-config.json
+++ b/services/loopback/server/model-config.json
@@ -143,5 +143,8 @@
},
"WorkerTeam": {
"dataSource": "vn"
+ },
+ "TicketRequest": {
+ "dataSource": "vn"
}
}
\ No newline at end of file
diff --git a/services/ticket/common/methods/sale-tracking/listSaleTracking.js b/services/ticket/common/methods/sale-tracking/listSaleTracking.js
index ff198f3ad4..9a6b024e18 100644
--- a/services/ticket/common/methods/sale-tracking/listSaleTracking.js
+++ b/services/ticket/common/methods/sale-tracking/listSaleTracking.js
@@ -8,12 +8,10 @@ module.exports = Self => {
accepts: [{
arg: 'filter',
type: 'Object',
- required: false,
- description: 'Filter defining where and paginated data',
- http: {source: 'query'}
+ description: 'Filter defining where and paginated data'
}],
returns: {
- type: ["Object"],
+ type: ['Object'],
root: true
},
http: {
@@ -41,7 +39,7 @@ module.exports = Self => {
JOIN worker w ON w.id = st.workerFk
JOIN state ste ON ste.id = st.stateFk`);
- stmt.merge(Self.buildSuffix(filter));
+ stmt.merge(Self.makeSuffix(filter));
let trackings = await Self.rawStmt(stmt);
diff --git a/services/ticket/common/methods/sale-tracking/specs/listSaleTracking.spec.js b/services/ticket/common/methods/sale-tracking/specs/listSaleTracking.spec.js
index d2179d2cc4..a40f5b7b5a 100644
--- a/services/ticket/common/methods/sale-tracking/specs/listSaleTracking.spec.js
+++ b/services/ticket/common/methods/sale-tracking/specs/listSaleTracking.spec.js
@@ -1,14 +1,14 @@
const app = require(`${servicesDir}/ticket/server/server`);
describe('ticket listSaleTracking()', () => {
- it('should call the listSaleTracking method and return the response', async() => {
+ it('should call the listSaleTracking method and return the response', async () => {
let filter = {where: {ticketFk: 1}};
let result = await app.models.SaleTracking.listSaleTracking(filter);
expect(result[0].concept).toEqual('Gem of Time');
});
- it(`should call the listSaleTracking method and return zero if doesn't have lines`, async() => {
+ it(`should call the listSaleTracking method and return zero if doesn't have lines`, async () => {
let filter = {where: {ticketFk: 2}};
let result = await app.models.SaleTracking.listSaleTracking(filter);