This commit is contained in:
Carlos Jimenez Ruiz 2019-06-14 12:27:54 +02:00
commit fcc0ad6098
72 changed files with 2012 additions and 1571 deletions

View File

@ -5,40 +5,36 @@ module.exports = Self => {
Self.remoteMethodCtx('uploadFile', { Self.remoteMethodCtx('uploadFile', {
description: 'Uploads a file and inserts into dms model', description: 'Uploads a file and inserts into dms model',
accessType: 'WRITE', accessType: 'WRITE',
accepts: [{ accepts: [
arg: 'options', {
type: 'object' arg: 'options',
}, type: 'object'
{ }, {
arg: 'warehouseId', arg: 'warehouseId',
type: 'Number', type: 'Number',
description: '' description: ''
}, }, {
{ arg: 'companyId',
arg: 'companyId', type: 'Number',
type: 'Number', description: ''
description: '' }, {
}, arg: 'dmsTypeId',
{ type: 'Number',
arg: 'dmsTypeId', description: ''
type: 'Number', }, {
description: '' arg: 'reference',
}, type: 'String',
{ description: ''
arg: 'reference', }, {
type: 'String', arg: 'description',
description: '' type: 'String',
}, description: ''
{ }, {
arg: 'description', arg: 'hasFile',
type: 'String', type: 'Boolean',
description: '' description: ''
}, }
{ ],
arg: 'hasFile',
type: 'Boolean',
description: ''
}],
returns: { returns: {
type: 'Object', type: 'Object',
root: true root: true
@ -49,17 +45,24 @@ module.exports = Self => {
} }
}); });
Self.uploadFile = async(ctx, options = {}) => { Self.uploadFile = async(ctx, options) => {
const models = Self.app.models; const models = Self.app.models;
const storageConnector = Self.app.dataSources.storage.connector; const storageConnector = Self.app.dataSources.storage.connector;
const myUserId = ctx.req.accessToken.userId; const myUserId = ctx.req.accessToken.userId;
const myWorker = await models.Worker.findOne({where: {userFk: myUserId}}); const myWorker = await models.Worker.findOne({where: {userFk: myUserId}});
const args = ctx.args; const args = ctx.args;
const fileOptions = {}; const fileOptions = {};
const hasParentTransaction = options && options.transaction;
if (!options.transaction) let tx;
options.transaction = await Self.beginTransaction({}); let myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try { try {
const hasWriteRole = await models.DmsType.hasWriteRole(ctx, args.dmsTypeId); const hasWriteRole = await models.DmsType.hasWriteRole(ctx, args.dmsTypeId);
@ -83,11 +86,11 @@ module.exports = Self => {
reference: args.reference, reference: args.reference,
description: args.description, description: args.description,
hasFile: args.hasFile hasFile: args.hasFile
}, options).then(newDms => { }, myOptions).then(newDms => {
const extension = storageConnector.getFileExtension(file.name); const extension = storageConnector.getFileExtension(file.name);
const fileName = `${newDms.id}.${extension}`; const fileName = `${newDms.id}.${extension}`;
return newDms.updateAttribute('file', fileName, options); return newDms.updateAttribute('file', fileName, myOptions);
}).then(dms => { }).then(dms => {
return models.Container.getContainer('temp').then(container => { return models.Container.getContainer('temp').then(container => {
const originPath = `${container.client.root}/${container.name}/${file.name}`; const originPath = `${container.client.root}/${container.name}/${file.name}`;
@ -104,14 +107,10 @@ module.exports = Self => {
const resolvedPromise = await Promise.all(promises); const resolvedPromise = await Promise.all(promises);
if (!hasParentTransaction) if (tx) await tx.commit();
await options.transaction.commit();
return resolvedPromise; return resolvedPromise;
} catch (e) { } catch (e) {
if (!hasParentTransaction) if (tx) await tx.rollback();
await options.transaction.rollback();
throw e; throw e;
} }
}; };

View File

@ -11,6 +11,9 @@
"Company": { "Company": {
"dataSource": "vn" "dataSource": "vn"
}, },
"Container": {
"dataSource": "storage"
},
"Delivery": { "Delivery": {
"dataSource": "vn" "dataSource": "vn"
}, },
@ -44,8 +47,11 @@
"DmsType": { "DmsType": {
"dataSource": "vn" "dataSource": "vn"
}, },
"Container": { "Town": {
"dataSource": "storage" "dataSource": "vn"
},
"Postcode": {
"dataSource": "vn"
} }
} }

50
back/models/postcode.json Normal file
View File

@ -0,0 +1,50 @@
{
"name": "Postcode",
"base": "VnModel",
"options": {
"mysql": {
"table": "postCode"
}
},
"properties": {
"code": {
"id": true,
"type": "String"
}
},
"relations": {
"town": {
"type": "belongsTo",
"model": "Town",
"foreignKey": "townFk"
},
"geo": {
"type": "belongsTo",
"model": "ZoneGeo",
"foreignKey": "geoFk"
}
},
"acls": [{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}],
"scopes": {
"location": {
"include": {
"relation": "town",
"scope": {
"include": {
"relation": "province",
"scope": {
"include": {
"relation": "country"
}
}
}
}
}
}
}
}

56
back/models/town.json Normal file
View File

@ -0,0 +1,56 @@
{
"name": "Town",
"base": "VnModel",
"options": {
"mysql": {
"table": "town"
}
},
"properties": {
"id": {
"id": true,
"type": "Number"
},
"name": {
"type": "String"
}
},
"relations": {
"province": {
"type": "belongsTo",
"model": "Province",
"foreignKey": "provinceFk"
},
"postcodes": {
"type": "hasMany",
"model": "Postcode",
"foreignKey": "townFk"
},
"geo": {
"type": "belongsTo",
"model": "ZoneGeo",
"foreignKey": "geoFk"
}
},
"acls": [{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}],
"scopes": {
"location": {
"include": [{
"relation": "province",
"scope": {
"include": {
"relation": "country"
}
}
},
{
"relation": "postcodes"
}]
}
}
}

View File

@ -5,7 +5,7 @@ export MYSQL_PWD=root
mysql_import() { mysql_import() {
FILE=$1 FILE=$1
echo "[INFO] -> Imported $FILE" echo "[INFO] -> Imported $FILE"
mysql -u root --comments -f < "$FILE" mysql -u root --default-character-set=utf8 --comments -f < "$FILE"
} }
mysql_import dump/structure.sql mysql_import dump/structure.sql

View File

@ -147,6 +147,20 @@ INSERT INTO `vn`.`province`(`id`, `name`, `countryFk`, `warehouseFk`, `zoneFk`)
(4, 'Province four', 1, NULL, 2), (4, 'Province four', 1, NULL, 2),
(5, 'Province five', 1, NULL, 1); (5, 'Province five', 1, NULL, 1);
INSERT INTO `vn`.`town`(`id`, `name`, `provinceFk`)
VALUES
(1, 'Valencia', 1),
(2, 'Silla', 1),
(3, 'Algemesi', 1),
(4, 'Alzira', 1);
INSERT INTO `vn`.`postCode`(`code`, `townFk`)
VALUES
('46000', 1),
('46460', 2),
('46680', 3),
('46600', 4);
INSERT INTO `vn`.`clientType`(`id`, `code`, `type`) INSERT INTO `vn`.`clientType`(`id`, `code`, `type`)
VALUES VALUES
(1, 'normal', 'Normal'), (1, 'normal', 'Normal'),

View File

@ -33,7 +33,10 @@ export default {
taxNumber: `${components.vnTextfield}[name="fi"]`, taxNumber: `${components.vnTextfield}[name="fi"]`,
socialName: `${components.vnTextfield}[name="socialName"]`, socialName: `${components.vnTextfield}[name="socialName"]`,
street: `${components.vnTextfield}[name="street"]`, street: `${components.vnTextfield}[name="street"]`,
city: `${components.vnTextfield}[name="city"]`, postcode: `vn-autocomplete[field="$ctrl.client.postcode"]`,
city: `vn-autocomplete[field="$ctrl.client.city"]`,
province: `vn-autocomplete[field="$ctrl.client.provinceFk"]`,
country: `vn-autocomplete[field="$ctrl.client.countryFk"]`,
userName: `${components.vnTextfield}[name="userName"]`, userName: `${components.vnTextfield}[name="userName"]`,
email: `${components.vnTextfield}[name="email"]`, email: `${components.vnTextfield}[name="email"]`,
salesPersonAutocomplete: `vn-autocomplete[field="$ctrl.client.salesPersonFk"]`, salesPersonAutocomplete: `vn-autocomplete[field="$ctrl.client.salesPersonFk"]`,
@ -62,8 +65,8 @@ export default {
equalizationTaxCheckbox: 'vn-check[label="Is equalizated"] md-checkbox', equalizationTaxCheckbox: 'vn-check[label="Is equalizated"] md-checkbox',
acceptPropagationButton: 'vn-client-fiscal-data > vn-confirm button[response=ACCEPT]', acceptPropagationButton: 'vn-client-fiscal-data > vn-confirm button[response=ACCEPT]',
addressInput: `${components.vnTextfield}[name="street"]`, addressInput: `${components.vnTextfield}[name="street"]`,
cityInput: `${components.vnTextfield}[name="city"]`, postcodeAutocomplete: `vn-autocomplete[field="$ctrl.client.postcode"]`,
postcodeInput: `${components.vnTextfield}[name="postcode"]`, cityAutocomplete: `vn-autocomplete[field="$ctrl.client.city"]`,
provinceAutocomplete: 'vn-autocomplete[field="$ctrl.client.provinceFk"]', provinceAutocomplete: 'vn-autocomplete[field="$ctrl.client.provinceFk"]',
countryAutocomplete: 'vn-autocomplete[field="$ctrl.client.countryFk"]', countryAutocomplete: 'vn-autocomplete[field="$ctrl.client.countryFk"]',
activeCheckbox: 'vn-check[label="Active"] md-checkbox', activeCheckbox: 'vn-check[label="Active"] md-checkbox',
@ -97,8 +100,8 @@ export default {
defaultCheckboxInput: 'vn-check[label="Default"] md-checkbox', defaultCheckboxInput: 'vn-check[label="Default"] md-checkbox',
consigneeInput: `${components.vnTextfield}[name="nickname"]`, consigneeInput: `${components.vnTextfield}[name="nickname"]`,
streetAddressInput: `${components.vnTextfield}[name="street"]`, streetAddressInput: `${components.vnTextfield}[name="street"]`,
postcodeInput: `${components.vnTextfield}[name="postalCode"]`, postcodeAutocomplete: `vn-autocomplete[field="$ctrl.address.postalCode"]`,
cityInput: `${components.vnTextfield}[name="city"]`, cityAutocomplete: `vn-autocomplete[field="$ctrl.address.city"]`,
provinceAutocomplete: 'vn-autocomplete[field="$ctrl.address.provinceFk"]', provinceAutocomplete: 'vn-autocomplete[field="$ctrl.address.provinceFk"]',
agencyAutocomplete: 'vn-autocomplete[field="$ctrl.address.agencyModeFk"]', agencyAutocomplete: 'vn-autocomplete[field="$ctrl.address.agencyModeFk"]',
phoneInput: `${components.vnTextfield}[name="phone"]`, phoneInput: `${components.vnTextfield}[name="phone"]`,

View File

@ -53,7 +53,7 @@ describe('Client create path', () => {
.write(selectors.createClientView.name, 'Carol Danvers') .write(selectors.createClientView.name, 'Carol Danvers')
.write(selectors.createClientView.socialName, 'AVG tax') .write(selectors.createClientView.socialName, 'AVG tax')
.write(selectors.createClientView.street, 'Many places') .write(selectors.createClientView.street, 'Many places')
.write(selectors.createClientView.city, 'Silla') .autocompleteSearch(selectors.createClientView.postcode, '46000')
.clearInput(selectors.createClientView.email) .clearInput(selectors.createClientView.email)
.write(selectors.createClientView.email, 'incorrect email format') .write(selectors.createClientView.email, 'incorrect email format')
.waitToClick(selectors.createClientView.createButton) .waitToClick(selectors.createClientView.createButton)
@ -62,6 +62,21 @@ describe('Client create path', () => {
expect(result).toEqual('Some fields are invalid'); expect(result).toEqual('Some fields are invalid');
}); });
it(`should check for autocompleted city, province and country`, async() => {
const clientCity = await nightmare
.waitToGetProperty(`${selectors.createClientView.city} input`, 'value');
const clientProvince = await nightmare
.waitToGetProperty(`${selectors.createClientView.province} input`, 'value');
const clientCountry = await nightmare
.waitToGetProperty(`${selectors.createClientView.country} input`, 'value');
expect(clientCity).toEqual('Valencia');
expect(clientProvince).toEqual('Province one');
expect(clientCountry).toEqual('España');
});
it(`should create a new user with all correct data`, async() => { it(`should create a new user with all correct data`, async() => {
const result = await nightmare const result = await nightmare
.clearInput(selectors.createClientView.email) .clearInput(selectors.createClientView.email)

View File

@ -67,11 +67,7 @@ describe('Client Edit fiscalData path', () => {
.write(selectors.clientFiscalData.fiscalIdInput, 'INVALID!') .write(selectors.clientFiscalData.fiscalIdInput, 'INVALID!')
.clearInput(selectors.clientFiscalData.addressInput) .clearInput(selectors.clientFiscalData.addressInput)
.write(selectors.clientFiscalData.addressInput, 'Somewhere edited') .write(selectors.clientFiscalData.addressInput, 'Somewhere edited')
.clearInput(selectors.clientFiscalData.postcodeInput) .autocompleteSearch(selectors.clientFiscalData.postcodeAutocomplete, '46000')
.write(selectors.clientFiscalData.postcodeInput, '12345')
.clearInput(selectors.clientFiscalData.cityInput)
.write(selectors.clientFiscalData.cityInput, 'N/A')
.autocompleteSearch(selectors.clientFiscalData.provinceAutocomplete, 'Province two')
.waitToClick(selectors.clientFiscalData.activeCheckbox) .waitToClick(selectors.clientFiscalData.activeCheckbox)
.waitToClick(selectors.clientFiscalData.frozenCheckbox) .waitToClick(selectors.clientFiscalData.frozenCheckbox)
.waitToClick(selectors.clientFiscalData.hasToInvoiceCheckbox) .waitToClick(selectors.clientFiscalData.hasToInvoiceCheckbox)
@ -197,23 +193,31 @@ describe('Client Edit fiscalData path', () => {
it('should confirm the postcode have been edited', async() => { it('should confirm the postcode have been edited', async() => {
const result = await nightmare const result = await nightmare
.waitToGetProperty(selectors.clientFiscalData.postcodeInput, 'value'); .waitToGetProperty(`${selectors.clientFiscalData.postcodeAutocomplete} input`, 'value');
expect(result).toEqual('12345'); expect(result).toContain('46000');
}); });
it('should confirm the city have been edited', async() => { it('should confirm the city have been autocompleted', async() => {
const result = await nightmare const result = await nightmare
.waitToGetProperty(selectors.clientFiscalData.cityInput, 'value'); .waitToGetProperty(`${selectors.clientFiscalData.cityAutocomplete} input`, 'value');
expect(result).toEqual('N/A'); expect(result).toEqual('Valencia');
}); });
it(`should confirm the province have been selected`, async() => {
it(`should confirm the province have been autocompleted`, async() => {
const result = await nightmare const result = await nightmare
.waitToGetProperty(`${selectors.clientFiscalData.provinceAutocomplete} input`, 'value'); .waitToGetProperty(`${selectors.clientFiscalData.provinceAutocomplete} input`, 'value');
expect(result).toEqual('Province two'); expect(result).toEqual('Province one');
});
it('should confirm the country have been autocompleted', async() => {
const result = await nightmare
.waitToGetProperty(`${selectors.clientFiscalData.countryAutocomplete} input`, 'value');
expect(result).toEqual('España');
}); });
it('should confirm active checkbox is unchecked', async() => { it('should confirm active checkbox is unchecked', async() => {

View File

@ -24,8 +24,7 @@ describe('Client Add address path', () => {
const result = await nightmare const result = await nightmare
.waitToClick(selectors.clientAddresses.defaultCheckboxInput) .waitToClick(selectors.clientAddresses.defaultCheckboxInput)
.clearInput(selectors.clientAddresses.streetAddressInput) .clearInput(selectors.clientAddresses.streetAddressInput)
.write(selectors.clientAddresses.postcodeInput, '10022') .autocompleteSearch(selectors.clientAddresses.postcodeAutocomplete, '46000')
.autocompleteSearch(selectors.clientAddresses.provinceAutocomplete, 'Province four')
.autocompleteSearch(selectors.clientAddresses.agencyAutocomplete, 'Entanglement') .autocompleteSearch(selectors.clientAddresses.agencyAutocomplete, 'Entanglement')
.write(selectors.clientAddresses.phoneInput, '999887744') .write(selectors.clientAddresses.phoneInput, '999887744')
.write(selectors.clientAddresses.mobileInput, '999887744') .write(selectors.clientAddresses.mobileInput, '999887744')
@ -35,11 +34,32 @@ describe('Client Add address path', () => {
expect(result).toEqual('Some fields are invalid'); expect(result).toEqual('Some fields are invalid');
}); });
it('should confirm the postcode have been edited', async() => {
const result = await nightmare
.waitToGetProperty(`${selectors.clientAddresses.postcodeAutocomplete} input`, 'value');
expect(result).toContain('46000');
});
it('should confirm the city have been autocompleted', async() => {
const result = await nightmare
.waitToGetProperty(`${selectors.clientAddresses.cityAutocomplete} input`, 'value');
expect(result).toEqual('Valencia');
});
it(`should confirm the province have been autocompleted`, async() => {
const result = await nightmare
.waitToGetProperty(`${selectors.clientAddresses.provinceAutocomplete} input`, 'value');
expect(result).toEqual('Province one');
});
it(`should create a new address with all it's data`, async() => { it(`should create a new address with all it's data`, async() => {
const result = await nightmare const result = await nightmare
.write(selectors.clientAddresses.consigneeInput, 'Bruce Bunner') .write(selectors.clientAddresses.consigneeInput, 'Bruce Bunner')
.write(selectors.clientAddresses.streetAddressInput, '320 Park Avenue New York') .write(selectors.clientAddresses.streetAddressInput, '320 Park Avenue New York')
.write(selectors.clientAddresses.cityInput, 'New York')
.waitToClick(selectors.clientAddresses.saveButton) .waitToClick(selectors.clientAddresses.saveButton)
.waitForLastSnackbar(); .waitForLastSnackbar();

View File

@ -19,6 +19,6 @@
</div> </div>
<vn-drop-down <vn-drop-down
vn-id="drop-down" vn-id="drop-down"
on-select="$ctrl.onDropDownSelect(value)" on-select="$ctrl.onDropDownSelect(item)"
on-data-ready="$ctrl.onDataReady()"> on-data-ready="$ctrl.onDataReady()">
</vn-drop-down> </vn-drop-down>

View File

@ -79,10 +79,10 @@ export default class Autocomplete extends Input {
} }
set field(value) { set field(value) {
if (angular.equals(value, this._field))
return;
this._field = value; this._field = value;
if (!value) return;
this.refreshSelection(); this.refreshSelection();
this.emit('change', {value}); this.emit('change', {value});
} }
@ -125,7 +125,9 @@ export default class Autocomplete extends Input {
|| this.selectionIsValid(this._selection)) || this.selectionIsValid(this._selection))
return; return;
this.selection = this.fetchSelection(); const selection = this.fetchSelection();
if (!this.selection)
this.selection = selection;
} }
fetchSelection() { fetchSelection() {
@ -217,7 +219,9 @@ export default class Autocomplete extends Input {
if (this.form) this.form.$setDirty(); if (this.form) this.form.$setDirty();
} }
onDropDownSelect(value) { onDropDownSelect(item) {
const value = item[this.valueField];
this.selection = item;
this.setValue(value); this.setValue(value);
this.field = value; this.field = value;
} }

View File

@ -7,7 +7,7 @@
</button> </button>
<vn-drop-down <vn-drop-down
vn-id="drop-down" vn-id="drop-down"
on-select="$ctrl.onDropDownSelect(value)" on-select="$ctrl.onDropDownSelect(item)"
ng-click="$ctrl.onDropDownClick($event)"> ng-click="$ctrl.onDropDownClick($event)">
</vn-drop-down> </vn-drop-down>
</div> </div>

View File

@ -53,7 +53,8 @@ export default class ButtonMenu extends Input {
event.preventDefault(); event.preventDefault();
} }
onDropDownSelect(value) { onDropDownSelect(item) {
const value = item[this.valueField];
this.field = value; this.field = value;
this.emit('change', {value}); this.emit('change', {value});
} }

View File

@ -7,6 +7,7 @@ describe('Component vnButtonMenu', () => {
beforeEach(inject(($compile, $rootScope) => { beforeEach(inject(($compile, $rootScope) => {
$element = $compile(`<vn-icon-menu></vn-icon-menu>`)($rootScope); $element = $compile(`<vn-icon-menu></vn-icon-menu>`)($rootScope);
controller = $element.controller('vnIconMenu'); controller = $element.controller('vnIconMenu');
controller.valueField = 'name';
})); }));
afterEach(() => { afterEach(() => {
@ -31,10 +32,10 @@ describe('Component vnButtonMenu', () => {
describe('onDropDownSelect(value)', () => { describe('onDropDownSelect(value)', () => {
it(`should set field to the given value and emit the change event`, () => { it(`should set field to the given value and emit the change event`, () => {
spyOn(controller, 'emit'); spyOn(controller, 'emit');
controller.onDropDownSelect('mariano'); controller.onDropDownSelect({name: 'Item name'});
expect(controller.field).toBe('mariano'); expect(controller.field).toBe('Item name');
expect(controller.emit).toHaveBeenCalledWith('change', {value: 'mariano'}); expect(controller.emit).toHaveBeenCalledWith('change', {value: 'Item name'});
}); });
}); });
}); });

View File

@ -8,7 +8,7 @@
model="$ctrl.search" model="$ctrl.search"
class="search" class="search"
ng-blur="$ctrl.onFocusOut()" ng-blur="$ctrl.onFocusOut()"
label = "Search"> label="Search">
</vn-textfield> </vn-textfield>
</div> </div>
<div class="list" tabindex="-1"> <div class="list" tabindex="-1">

View File

@ -186,7 +186,7 @@ export default class DropDown extends Component {
this.field = value; this.field = value;
} }
this.emit('select', {value: value}); this.emit('select', {item});
} }
if (!this.multiple) if (!this.multiple)

View File

@ -5,7 +5,7 @@
</vn-icon> </vn-icon>
<vn-drop-down <vn-drop-down
vn-id="drop-down" vn-id="drop-down"
on-select="$ctrl.onDropDownSelect(value)" on-select="$ctrl.onDropDownSelect(item)"
ng-click="$ctrl.onDropDownClick($event)"> ng-click="$ctrl.onDropDownClick($event)">
</vn-drop-down> </vn-drop-down>
</div> </div>

View File

@ -2,7 +2,10 @@
<vn-empty-rows ng-if="$ctrl.isRefreshing"> <vn-empty-rows ng-if="$ctrl.isRefreshing">
<vn-spinner enable="$ctrl.isRefreshing"></vn-spinner> <vn-spinner enable="$ctrl.isRefreshing"></vn-spinner>
</vn-empty-rows> </vn-empty-rows>
<vn-empty-rows ng-if="!$ctrl.isRefreshing && !$ctrl.model.data"> <vn-empty-rows ng-if="$ctrl.model && !$ctrl.isRefreshing && !$ctrl.model.data">
<span translate>Enter a new search</span>
</vn-empty-rows>
<vn-empty-rows ng-if="$ctrl.model && !$ctrl.isRefreshing && $ctrl.model.data.length == 0">
<span translate>No results</span> <span translate>No results</span>
</vn-empty-rows> </vn-empty-rows>
</div> </div>

852
front/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -20,11 +20,11 @@
"angular-translate-loader-partial": "^2.18.1", "angular-translate-loader-partial": "^2.18.1",
"flatpickr": "^4.5.2", "flatpickr": "^4.5.2",
"fs-extra": "^5.0.0", "fs-extra": "^5.0.0",
"js-yaml": "^3.12.1", "js-yaml": "^3.13.1",
"material-design-lite": "^1.3.0", "material-design-lite": "^1.3.0",
"mg-crud": "^1.1.2", "mg-crud": "^1.1.2",
"moment-timezone": "^0.5.25", "moment-timezone": "^0.5.25",
"npm": "^6.5.0", "npm": "^6.9.0",
"oclazyload": "^0.6.3", "oclazyload": "^0.6.3",
"require-yaml": "0.0.1", "require-yaml": "0.0.1",
"validator": "^6.3.0" "validator": "^6.3.0"

View File

@ -112,7 +112,7 @@ module.exports = function(Self) {
for (let key1 in ctx.Model.relations) { for (let key1 in ctx.Model.relations) {
let val1 = ctx.Model.relations[key1]; let val1 = ctx.Model.relations[key1];
if (val1.keyFrom == key && key != 'id') { if (val1.keyFrom == key && key != 'id') {
let recordSet = await ctx.Model.app.models[val1.modelTo.modelName].findById(val, options); let recordSet = await ctx.Model.app.models[val1.modelTo.modelName].findById(val, null, options);
let showField = val1.modelTo && val1.modelTo.definition.settings.log && val1.modelTo.definition.settings.log.showField && recordSet && recordSet[val1.modelTo.definition.settings.log.showField]; let showField = val1.modelTo && val1.modelTo.definition.settings.log && val1.modelTo.definition.settings.log.showField && recordSet && recordSet[val1.modelTo.definition.settings.log.showField];
if (!showField) { if (!showField) {

View File

@ -11,6 +11,20 @@ module.exports = function(Self) {
setup() { setup() {
Self.super_.setup.call(this); Self.super_.setup.call(this);
/**
* Setting a global transaction timeout to find out if the service
* is blocked because the connection pool is empty.
*/
this.once('dataSourceAttached', () => {
let orgBeginTransaction = this.beginTransaction;
this.beginTransaction = function(options, cb) {
options = options || {};
if (!options.timeout)
options.timeout = 30000;
return orgBeginTransaction.call(this, options, cb);
};
});
// Register field ACL validation // Register field ACL validation
/* this.beforeRemote('prototype.patchAttributes', ctx => this.checkUpdateAcls(ctx)); /* this.beforeRemote('prototype.patchAttributes', ctx => this.checkUpdateAcls(ctx));
this.beforeRemote('updateAll', ctx => this.checkUpdateAcls(ctx)); this.beforeRemote('updateAll', ctx => this.checkUpdateAcls(ctx));
@ -41,10 +55,11 @@ module.exports = function(Self) {
}, },
async crud(deletes, updates, creates) { async crud(deletes, updates, creates) {
let transaction = await this.beginTransaction({}); let tx = await this.beginTransaction({});
let options = {transaction};
try { try {
let options = {transaction: tx};
if (deletes) { if (deletes) {
let promises = []; let promises = [];
for (let id of deletes) for (let id of deletes)
@ -65,9 +80,9 @@ module.exports = function(Self) {
} }
} }
await transaction.commit(); await tx.commit();
} catch (error) { } catch (error) {
await transaction.rollback(); await tx.rollback();
throw error; throw error;
} }
}, },

View File

@ -3,7 +3,7 @@
"strong-error-handler": { "strong-error-handler": {
"params": { "params": {
"debug": true, "debug": true,
"log": true "log": false
} }
} }
} }

View File

@ -49,6 +49,10 @@
}, },
"final:after": { "final:after": {
"./middleware/error-handler": {}, "./middleware/error-handler": {},
"strong-error-handler": {} "strong-error-handler": {
"params": {
"log": false
}
}
} }
} }

View File

@ -1,4 +1,5 @@
const UserError = require('../../util/user-error'); const UserError = require('../../util/user-error');
const logToConsole = require('strong-error-handler/lib/logger');
module.exports = function() { module.exports = function() {
return function(err, req, res, next) { return function(err, req, res, next) {
@ -23,6 +24,9 @@ module.exports = function() {
if (err.sqlState == '45000') if (err.sqlState == '45000')
return next(new UserError(req.__(err.sqlMessage))); return next(new UserError(req.__(err.sqlMessage)));
if (!err.statusCode || err.statusCode >= 500)
logToConsole(req, err);
next(err); next(err);
}; };
}; };

View File

@ -21,39 +21,40 @@ module.exports = Self => {
Self.clone = async id => { Self.clone = async id => {
const models = Self.app.models; const models = Self.app.models;
const transaction = await Self.beginTransaction({}); const tx = await Self.beginTransaction({});
const options = {transaction};
// Find original zone
const zone = await models.Zone.findOne({
fields: [
'name',
'hour',
'warehouseFk',
'agencyModeFk',
'travelingDays',
'price',
'bonus',
'isVolumetric'],
where: {id}
}, options);
const hour = zone.hour;
const offset = hour.getTimezoneOffset() * 60000;
hour.setTime(hour.getTime() + offset);
// Find all original included geolocations
const includedGeo = await models.ZoneIncluded.find({
fields: ['geoFk', 'isIncluded'],
where: {zoneFk: id}
}, options);
// Find all original selected days
const calendarDays = await models.ZoneCalendar.find({
where: {zoneFk: id}
}, options);
try { try {
let options = {transaction: tx};
// Find original zone
const zone = await models.Zone.findOne({
fields: [
'name',
'hour',
'warehouseFk',
'agencyModeFk',
'travelingDays',
'price',
'bonus',
'isVolumetric'],
where: {id}
}, options);
const hour = zone.hour;
const offset = hour.getTimezoneOffset() * 60000;
hour.setTime(hour.getTime() + offset);
// Find all original included geolocations
const includedGeo = await models.ZoneIncluded.find({
fields: ['geoFk', 'isIncluded'],
where: {zoneFk: id}
}, options);
// Find all original selected days
const calendarDays = await models.ZoneCalendar.find({
where: {zoneFk: id}
}, options);
const newZone = await Self.create(zone, options); const newZone = await Self.create(zone, options);
const newIncludedGeo = includedGeo.map(included => { const newIncludedGeo = includedGeo.map(included => {
included.zoneFk = newZone.id; included.zoneFk = newZone.id;
@ -66,11 +67,11 @@ module.exports = Self => {
await models.ZoneIncluded.create(newIncludedGeo, options); await models.ZoneIncluded.create(newIncludedGeo, options);
await models.ZoneCalendar.create(newCalendayDays, options); await models.ZoneCalendar.create(newCalendayDays, options);
await transaction.commit(); await tx.commit();
return newZone; return newZone;
} catch (e) { } catch (e) {
await transaction.rollback(); await tx.rollback();
throw e; throw e;
} }
}; };

View File

@ -1,3 +1,3 @@
Traveling days: Días de viaje Traveling days: Días de viaje
Estimated hour (ETD): Hora estimada (ETD) Closure hour (ETD): Hora de cierre (ETD)
Bonus: Bonificación Bonus: Bonificación

View File

@ -30,7 +30,7 @@
<vn-label-value label="Agency" <vn-label-value label="Agency"
value="{{$ctrl.zone.agencyMode.name}}"> value="{{$ctrl.zone.agencyMode.name}}">
</vn-label-value> </vn-label-value>
<vn-label-value label="Estimated hour (ETD)" <vn-label-value label="Closure hour (ETD)"
value="{{$ctrl.zone.hour | dateTime: 'HH:mm'}}"> value="{{$ctrl.zone.hour | dateTime: 'HH:mm'}}">
</vn-label-value> </vn-label-value>
<vn-label-value label="Traveling days" <vn-label-value label="Traveling days"

View File

@ -26,7 +26,7 @@
<vn-th field="name" expand>Name</vn-th> <vn-th field="name" expand>Name</vn-th>
<vn-th field="agencyModeFk">Agency</vn-th> <vn-th field="agencyModeFk">Agency</vn-th>
<vn-th field="warehouseFK">Warehouse</vn-th> <vn-th field="warehouseFK">Warehouse</vn-th>
<vn-th field="hour" shrink vn-tooltip="ETD">Hour</vn-th> <vn-th field="hour" vn-tooltip="ETD" default-order="DESC" shrink>Hour</vn-th>
<vn-th field="price" number shrink>Price</vn-th> <vn-th field="price" number shrink>Price</vn-th>
<vn-th shrink></vn-th> <vn-th shrink></vn-th>
</vn-tr> </vn-tr>

View File

@ -19,7 +19,7 @@ module.exports = Self => {
} }
}); });
async function addSalesToTicket(salesToRefund, ticketFk, transaction) { async function addSalesToTicket(salesToRefund, ticketFk, options) {
let formatedSales = []; let formatedSales = [];
salesToRefund.forEach(sale => { salesToRefund.forEach(sale => {
let formatedSale = { let formatedSale = {
@ -35,10 +35,10 @@ module.exports = Self => {
}; };
formatedSales.push(formatedSale); formatedSales.push(formatedSale);
}); });
return await Self.app.models.Sale.create(formatedSales, transaction); return await Self.app.models.Sale.create(formatedSales, options);
} }
async function insertIntoClaimEnd(createdSales, claimId, workerId, transaction) { async function insertIntoClaimEnd(createdSales, claimId, workerId, options) {
let formatedSales = []; let formatedSales = [];
createdSales.forEach(sale => { createdSales.forEach(sale => {
let formatedSale = { let formatedSale = {
@ -48,17 +48,17 @@ module.exports = Self => {
}; };
formatedSales.push(formatedSale); formatedSales.push(formatedSale);
}); });
return await Self.app.models.ClaimEnd.create(formatedSales, transaction); return await Self.app.models.ClaimEnd.create(formatedSales, options);
} }
async function saveObservation(observation, transaction) { async function saveObservation(observation, options) {
let query = `INSERT INTO vn.ticketObservation(ticketFk, observationTypeFk, description) VALUES(?, ?, ?) let query = `INSERT INTO vn.ticketObservation(ticketFk, observationTypeFk, description) VALUES(?, ?, ?)
ON DUPLICATE KEY UPDATE description = CONCAT(vn.ticketObservation.description, VALUES(description),' ')`; ON DUPLICATE KEY UPDATE description = CONCAT(vn.ticketObservation.description, VALUES(description),' ')`;
await Self.rawSql(query, [ await Self.rawSql(query, [
observation.ticketFk, observation.ticketFk,
observation.observationTypeFk, observation.observationTypeFk,
observation.description observation.description
], transaction); ], options);
} }
Self.importToNewRefundTicket = async(ctx, id) => { Self.importToNewRefundTicket = async(ctx, id) => {
@ -109,37 +109,39 @@ module.exports = Self => {
] ]
}; };
let transaction = await Self.beginTransaction({}); let tx = await Self.beginTransaction({});
try { try {
let newRefundTicket = await models.Ticket.new(ctx, params, {transaction: transaction}); let options = {transaction: tx};
let newRefundTicket = await models.Ticket.new(ctx, params, options);
let observation = { let observation = {
description: `Reclama ticket: ${claim.ticketFk}`, description: `Reclama ticket: ${claim.ticketFk}`,
ticketFk: newRefundTicket.id, ticketFk: newRefundTicket.id,
observationTypeFk: obsevationType.id observationTypeFk: obsevationType.id
}; };
await saveObservation(observation, {transaction: transaction}); await saveObservation(observation, options);
await models.TicketTracking.create({ await models.TicketTracking.create({
ticketFk: newRefundTicket.id, ticketFk: newRefundTicket.id,
stateFk: state.id, stateFk: state.id,
workerFk: worker.id workerFk: worker.id
}, {transaction: transaction}); }, options);
let salesToRefund = await models.ClaimBeginning.find(salesFilter); let salesToRefund = await models.ClaimBeginning.find(salesFilter);
let createdSales = await addSalesToTicket(salesToRefund, newRefundTicket.id, {transaction: transaction}); let createdSales = await addSalesToTicket(salesToRefund, newRefundTicket.id, options);
insertIntoClaimEnd(createdSales, id, worker.id, {transaction: transaction}); insertIntoClaimEnd(createdSales, id, worker.id, options);
await Self.rawSql('CALL vn.ticketCalculateClon(?, ?)', [ await Self.rawSql('CALL vn.ticketCalculateClon(?, ?)', [
newRefundTicket.id, claim.ticketFk newRefundTicket.id, claim.ticketFk
], {transaction: transaction}); ], options);
await transaction.commit(); await tx.commit();
return newRefundTicket; return newRefundTicket;
} catch (e) { } catch (e) {
await transaction.rollback(); await tx.rollback();
throw e; throw e;
} }
}; };

View File

@ -26,27 +26,29 @@ module.exports = Self => {
Self.createFromSales = async(ctx, params) => { Self.createFromSales = async(ctx, params) => {
let model = Self.app.models; let model = Self.app.models;
let transaction = await Self.beginTransaction({}); let tx = await Self.beginTransaction({});
try { try {
let options = {transaction: tx};
let userId = ctx.req.accessToken.userId; let userId = ctx.req.accessToken.userId;
let worker = await Self.app.models.Worker.findOne({where: {userFk: userId}}); let worker = await Self.app.models.Worker.findOne({where: {userFk: userId}});
params.claim.workerFk = worker.id; params.claim.workerFk = worker.id;
let newClaim = await Self.create(params.claim, {transaction}); let newClaim = await Self.create(params.claim, options);
let promises = []; let promises = [];
for (let i = 0; i < params.sales.length; i++) { for (let i = 0; i < params.sales.length; i++) {
promises.push(model.ClaimBeginning.create( promises.push(model.ClaimBeginning.create({
{saleFk: params.sales[i].id, saleFk: params.sales[i].id,
claimFk: newClaim.id, claimFk: newClaim.id,
quantity: params.sales[i].quantity}, quantity: params.sales[i].quantity
{transaction})); }, options));
} }
await Promise.all(promises); await Promise.all(promises);
await transaction.commit(); await tx.commit();
return newClaim; return newClaim;
} catch (e) { } catch (e) {
transaction.rollback(); await tx.rollback();
throw e; throw e;
} }
}; };

View File

@ -30,8 +30,10 @@ module.exports = Self => {
where: {claimFk: params.claimFk} where: {claimFk: params.claimFk}
}); });
let transaction = await Self.beginTransaction({}); let tx = await Self.beginTransaction({});
try { try {
let options = {transaction: tx};
for (let i = 0; i < claimEnds.length; i++) { for (let i = 0; i < claimEnds.length; i++) {
const claimEnd = claimEnds[i]; const claimEnd = claimEnds[i];
const destination = claimEnd.claimDestination(); const destination = claimEnd.claimDestination();
@ -45,7 +47,7 @@ module.exports = Self => {
addressFk: addressFk, addressFk: addressFk,
companyFk: sale.ticket().companyFk, companyFk: sale.ticket().companyFk,
warehouseFk: sale.ticket().warehouseFk warehouseFk: sale.ticket().warehouseFk
}, transaction); }, options);
let address = await models.Address.findOne({ let address = await models.Address.findOne({
where: {id: addressFk} where: {id: addressFk}
@ -58,7 +60,7 @@ module.exports = Self => {
warehouseFk: sale.ticket().warehouseFk, warehouseFk: sale.ticket().warehouseFk,
companyFk: sale.ticket().companyFk, companyFk: sale.ticket().companyFk,
userId: userId userId: userId
}, transaction); }, options);
} }
await models.Sale.create({ await models.Sale.create({
@ -68,7 +70,7 @@ module.exports = Self => {
quantity: -sale.quantity, quantity: -sale.quantity,
price: sale.price, price: sale.price,
discount: 100 discount: 100
}, {transaction: transaction}); }, options);
if (sale.ticket().client().salesPerson()) { if (sale.ticket().client().salesPerson()) {
await sendMessage(ctx, { await sendMessage(ctx, {
@ -78,20 +80,20 @@ module.exports = Self => {
quantity: sale.quantity, quantity: sale.quantity,
concept: sale.concept, concept: sale.concept,
nickname: address.nickname nickname: address.nickname
}, transaction); }, options);
} }
} }
let claim = await Self.findById(params.claimFk); let claim = await Self.findById(params.claimFk);
claim = await claim.updateAttributes({ claim = await claim.updateAttributes({
claimStateFk: resolvedState claimStateFk: resolvedState
}, {transaction: transaction}); }, options);
await transaction.commit(); await tx.commit();
return claim; return claim;
} catch (e) { } catch (e) {
await transaction.rollback(); await tx.rollback();
throw e; throw e;
} }
}; };
@ -117,7 +119,7 @@ module.exports = Self => {
}); });
} }
async function getTicketId(params, transaction) { async function getTicketId(params, options) {
const currentDate = new Date(); const currentDate = new Date();
currentDate.setHours(null, null, null); currentDate.setHours(null, null, null);
@ -129,12 +131,12 @@ module.exports = Self => {
shipped: currentDate, shipped: currentDate,
landed: currentDate landed: currentDate
} }
}, {transaction: transaction}); }, options);
return ticket && ticket.id; return ticket && ticket.id;
} }
async function createTicket(ctx, params, transaction) { async function createTicket(ctx, params, options) {
let ticket = await Self.app.models.Ticket.new(ctx, let ticket = await Self.app.models.Ticket.new(ctx,
{ {
shipped: new Date(), shipped: new Date(),
@ -144,18 +146,18 @@ module.exports = Self => {
companyFk: params.companyFk, companyFk: params.companyFk,
addressFk: params.addressFk, addressFk: params.addressFk,
userId: params.userId userId: params.userId
}, {transaction: transaction}); }, options);
return ticket.id; return ticket.id;
} }
async function sendMessage(ctx, params, transaction) { async function sendMessage(ctx, params, options) {
const message = `Envio ${params.quantity} unidades de "${params.concept}" (#${params.itemFk}) a ` const message = `Envio ${params.quantity} unidades de "${params.concept}" (#${params.itemFk}) a `
+ `"${params.nickname}" provenientes del ticket #${params.ticketFk}`; + `"${params.nickname}" provenientes del ticket #${params.ticketFk}`;
await Self.app.models.Message.send(ctx, { await Self.app.models.Message.send(ctx, {
recipientFk: params.recipientFk, recipientFk: params.recipientFk,
message: message message: message
}, {transaction: transaction}); }, options);
} }
}; };

View File

@ -74,4 +74,10 @@
on-response="$ctrl.sendPickupOrder(response)" on-response="$ctrl.sendPickupOrder(response)"
question="Send Pickup order" question="Send Pickup order"
message="Are you sure you want to send it?"> message="Are you sure you want to send it?">
</vn-confirm>
<vn-confirm
vn-id="confirm-delete-claim"
on-response="$ctrl.deleteClaim(response)"
question="Delete claim"
message="Are you sure you want to delete it?">
</vn-confirm> </vn-confirm>

View File

@ -1,15 +1,17 @@
import ngModule from '../module'; import ngModule from '../module';
class Controller { class Controller {
constructor($scope, $state, $http, $translate, vnApp) { constructor($scope, $state, $http, $translate, vnApp, aclService) {
this.$scope = $scope; this.$scope = $scope;
this.$state = $state; this.$state = $state;
this.$http = $http; this.$http = $http;
this.$translate = $translate; this.$translate = $translate;
this.vnApp = vnApp; this.vnApp = vnApp;
this.aclService = aclService;
this.moreOptions = [ this.moreOptions = [
{callback: this.showPickupOrder, name: 'Show Pickup order'}, {callback: this.showPickupOrder, name: 'Show Pickup order'},
{callback: this.confirmPickupOrder, name: 'Send Pickup order'} {callback: this.confirmPickupOrder, name: 'Send Pickup order'},
{callback: this.confirmDeleteClaim, name: 'Delete claim', acl: 'salesAssistant'}
]; ];
} }
@ -57,6 +59,9 @@ class Controller {
this.$scope.confirmPickupOrder.show(); this.$scope.confirmPickupOrder.show();
} }
confirmDeleteClaim() {
this.$scope.confirmDeleteClaim.show();
}
sendPickupOrder(response) { sendPickupOrder(response) {
if (response === 'ACCEPT') { if (response === 'ACCEPT') {
this.$http.post(`/api/email/claim-pickup-order`, {claimFk: this.claim.id}).then( this.$http.post(`/api/email/claim-pickup-order`, {claimFk: this.claim.id}).then(
@ -64,9 +69,17 @@ class Controller {
); );
} }
} }
deleteClaim(response) {
if (response === 'ACCEPT') {
this.$http.delete(`/claim/api/Claims/${this.claim.id}`).then(() => {
this.vnApp.showSuccess(this.$translate.instant('Claim deleted!'));
this.$state.go('claim.index');
});
}
}
} }
Controller.$inject = ['$scope', '$state', '$http', '$translate', 'vnApp']; Controller.$inject = ['$scope', '$state', '$http', '$translate', 'vnApp', 'aclService'];
ngModule.component('vnClaimDescriptor', { ngModule.component('vnClaimDescriptor', {
template: require('./index.html'), template: require('./index.html'),

View File

@ -48,5 +48,34 @@ describe('Item Component vnClaimDescriptor', () => {
expect(controller.vnApp.showMessage).toHaveBeenCalledWith('Notification sent!'); expect(controller.vnApp.showMessage).toHaveBeenCalledWith('Notification sent!');
}); });
}); });
describe('confirmDeleteClaim()', () => {
it('should call confirmDeleteClaim.show()', () => {
controller.$scope.confirmDeleteClaim = {
show: jasmine.createSpy('show')
};
controller.claim = {id: 2};
controller.confirmDeleteClaim();
expect(controller.$scope.confirmDeleteClaim.show).toHaveBeenCalledWith();
});
});
describe('deleteClaime(response)', () => {
it('should perform a query and call showSuccess if the response is ACCEPT', () => {
let response = 'ACCEPT';
controller.claim = {id: 2};
spyOn(controller.vnApp, 'showSuccess');
spyOn(controller.$state, 'go');
$httpBackend.when('DELETE', `/claim/api/Claims/2`).respond(200);
$httpBackend.expect('DELETE', `/claim/api/Claims/2`);
controller.deleteClaim(response);
$httpBackend.flush();
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Claim deleted!');
expect(controller.$state.go).toHaveBeenCalledWith('claim.index');
});
});
}); });

View File

@ -129,29 +129,28 @@
enable="true"> enable="true">
</vn-spinner> </vn-spinner>
<div ng-if="$ctrl.mana != null"> <div ng-if="$ctrl.mana != null">
<vn-horizontal pad-medium class="header"> <vn-horizontal pad-medium class="header">
<h5>MANÁ: {{$ctrl.mana | currency: 'EUR':0}}</h5> <h5>MANÁ: {{$ctrl.mana | currency: 'EUR':0}}</h5>
</vn-horizontal> </vn-horizontal>
<div pad-medium> <div pad-medium>
<vn-input-number <vn-input-number
vn-focus vn-focus
label="Discount" label="Discount"
model="$ctrl.newDiscount" model="$ctrl.newDiscount"
type="text" type="text"
step="0.01" step="0.01"
on-change="$ctrl.updateDiscount()"> on-change="$ctrl.updateDiscount()">
<t-right-icons> <t-right-icons>
<span class="filter"></span> <span class="filter"></span>
</t-right-icons> </t-right-icons>
</vn-input-number> </vn-input-number>
<div class="simulator"> <div class="simulator">
<p class="simulatorTitle" translate>New price</p> <p class="simulatorTitle" translate>New price</p>
<p>{{($ctrl.saleClaimed.quantity * $ctrl.saleClaimed.sale.price) - <p>{{($ctrl.saleClaimed.quantity * $ctrl.saleClaimed.sale.price) -
(($ctrl.newDiscount * ($ctrl.saleClaimed.quantity * $ctrl.saleClaimed.sale.price))/100) (($ctrl.newDiscount * ($ctrl.saleClaimed.quantity * $ctrl.saleClaimed.sale.price))/100)
| currency: 'EUR':2}} | currency: 'EUR':2}}
</p> </p>
</div>
</div> </div>
</div> </div>
</div>
</vn-popover> </vn-popover>
<p>

View File

@ -3,6 +3,7 @@ Add sale: Añadir linea
Are you sure you want to send it?: ¿Seguro que quieres enviarlo? Are you sure you want to send it?: ¿Seguro que quieres enviarlo?
Client Id: Id cliente Client Id: Id cliente
Claimed ticket: Ticket reclamado Claimed ticket: Ticket reclamado
Delete claim: Eliminar reclamación
Observation: Observación Observation: Observación
Responsible: Responsable Responsible: Responsable
Remove sale: Borrar linea Remove sale: Borrar linea
@ -11,4 +12,5 @@ Created: Creado
Send Pickup order: Enviar orden de recogida Send Pickup order: Enviar orden de recogida
Show Pickup order: Ver orden de recogida Show Pickup order: Ver orden de recogida
Search claim by id or client name: Buscar reclamaciones por identificador o nombre de cliente Search claim by id or client name: Buscar reclamaciones por identificador o nombre de cliente
Claim deleted!: Reclamación eliminada!

View File

@ -19,23 +19,25 @@ module.exports = function(Self) {
Self.createDefaultAddress = async data => { Self.createDefaultAddress = async data => {
const Address = Self.app.models.Address; const Address = Self.app.models.Address;
const Client = Self.app.models.Client; const Client = Self.app.models.Client;
const transaction = await Address.beginTransaction({}); const tx = await Address.beginTransaction({});
try { try {
let options = {transaction: tx};
let address = data.address; let address = data.address;
let newAddress = await Address.create(address, {transaction}); let newAddress = await Address.create(address, options);
let client = await Client.findById(address.clientFk, {transaction}); let client = await Client.findById(address.clientFk, options);
if (data.isDefaultAddress) { if (data.isDefaultAddress) {
await client.updateAttributes({ await client.updateAttributes({
defaultAddressFk: newAddress.id defaultAddressFk: newAddress.id
}, {transaction}); }, options);
} }
await transaction.commit(); await tx.commit();
return newAddress; return newAddress;
} catch (e) { } catch (e) {
await transaction.rollback(); await tx.rollback();
throw e; throw e;
} }
}; };

View File

@ -19,15 +19,17 @@ module.exports = Self => {
}); });
Self.confirmTransaction = async(ctx, id) => { Self.confirmTransaction = async(ctx, id) => {
let transaction = await Self.beginTransaction({});
let userId = ctx.req.accessToken.userId; let userId = ctx.req.accessToken.userId;
let tx = await Self.beginTransaction({});
try { try {
let oldTpvTransaction = await Self.app.models.TpvTransaction.findById(id, {options: transaction}); let options = {transaction: tx};
let confirm = await Self.rawSql('CALL hedera.tpvTransactionConfirmById(?)', [id], {options: transaction}); let oldTpvTransaction = await Self.app.models.TpvTransaction.findById(id, null, options);
let tpvTransaction = await Self.app.models.TpvTransaction.findById(id, {options: transaction}); let confirm = await Self.rawSql('CALL hedera.tpvTransaction_confirmById(?)', [id], options);
let tpvTransaction = await Self.app.models.TpvTransaction.findById(id, null, options);
let oldInstance = {status: oldTpvTransaction.status}; let oldInstance = {status: oldTpvTransaction.status};
let newInstance = {status: tpvTransaction.status}; let newInstance = {status: tpvTransaction.status};
@ -42,12 +44,12 @@ module.exports = Self => {
newInstance: newInstance newInstance: newInstance
}; };
await Self.app.models.ClientLog.create(logRecord, {options: transaction}); await Self.app.models.ClientLog.create(logRecord, options);
await transaction.commit(); await tx.commit();
return confirm; return confirm;
} catch (e) { } catch (e) {
await transaction.rollback(); await tx.rollback();
throw e; throw e;
} }
}; };

View File

@ -25,10 +25,12 @@ module.exports = function(Self) {
}; };
const Account = Self.app.models.Account; const Account = Self.app.models.Account;
const Address = Self.app.models.Address; const Address = Self.app.models.Address;
const transaction = await Account.beginTransaction({}); const tx = await Account.beginTransaction({});
try { try {
let account = await Account.create(user, {transaction}); let options = {transaction: tx};
let account = await Account.create(user, options);
let client = await Self.create({ let client = await Self.create({
id: account.id, id: account.id,
name: data.name, name: data.name,
@ -42,7 +44,7 @@ module.exports = function(Self) {
provinceFk: data.provinceFk, provinceFk: data.provinceFk,
countryFk: data.countryFk, countryFk: data.countryFk,
isEqualizated: data.isEqualizated isEqualizated: data.isEqualizated
}, {transaction}); }, options);
let address = await Address.create({ let address = await Address.create({
@ -54,16 +56,16 @@ module.exports = function(Self) {
provinceFk: client.provinceFk, provinceFk: client.provinceFk,
isEqualizated: client.isEqualizated, isEqualizated: client.isEqualizated,
isActive: true isActive: true
}, {transaction}); }, options);
await client.updateAttributes({ await client.updateAttributes({
defaultAddressFk: address.id defaultAddressFk: address.id
}, {transaction}); }, options);
await transaction.commit(); await tx.commit();
return client; return client;
} catch (e) { } catch (e) {
await transaction.rollback(); await tx.rollback();
throw e; throw e;
} }
}; };

View File

@ -5,7 +5,7 @@ describe('Client confirmTransaction', () => {
afterAll(async done => { afterAll(async done => {
await app.models.Client.rawSql(` await app.models.Client.rawSql(`
CALL hedera.tpvTransactionUndo(?)`, [transactionId]); CALL hedera.tpvTransaction_undo(?)`, [transactionId]);
done(); done();
}); });

View File

@ -50,11 +50,12 @@ module.exports = Self => {
Self.uploadFile = async(ctx, id) => { Self.uploadFile = async(ctx, id) => {
const models = Self.app.models; const models = Self.app.models;
const transaction = await Self.beginTransaction({});
const options = {transaction};
const promises = []; const promises = [];
const tx = await Self.beginTransaction({});
try { try {
const options = {transaction: tx};
const uploadedFiles = await models.Dms.uploadFile(ctx, options); const uploadedFiles = await models.Dms.uploadFile(ctx, options);
uploadedFiles.forEach(dms => { uploadedFiles.forEach(dms => {
const newClientDms = models.ClientDms.create({ const newClientDms = models.ClientDms.create({
@ -66,11 +67,11 @@ module.exports = Self => {
}); });
const resolvedPromises = await Promise.all(promises); const resolvedPromises = await Promise.all(promises);
await transaction.commit(); await tx.commit();
return resolvedPromises; return resolvedPromises;
} catch (err) { } catch (err) {
await transaction.rollback(); await tx.rollback();
throw err; throw err;
} }
}; };

View File

@ -23,11 +23,13 @@ module.exports = Self => {
}); });
Self.createWithInsurance = async(data, ctx) => { Self.createWithInsurance = async(data, ctx) => {
let transaction = await Self.beginTransaction({}); let tx = await Self.beginTransaction({});
try { try {
let options = {transaction: tx};
let classificationSchema = {client: data.clientFk, started: data.started}; let classificationSchema = {client: data.clientFk, started: data.started};
let newClassification = await Self.create(classificationSchema, {transaction}); let newClassification = await Self.create(classificationSchema, options);
let CreditInsurance = Self.app.models.CreditInsurance; let CreditInsurance = Self.app.models.CreditInsurance;
let insuranceSchema = { let insuranceSchema = {
creditClassification: newClassification.id, creditClassification: newClassification.id,
@ -35,13 +37,13 @@ module.exports = Self => {
grade: data.grade grade: data.grade
}; };
let newCreditInsurance = await CreditInsurance.create(insuranceSchema, {transaction}); let newCreditInsurance = await CreditInsurance.create(insuranceSchema, options);
await transaction.commit(); await tx.commit();
await CreditInsurance.messageSend(newCreditInsurance, ctx.req.accessToken); await CreditInsurance.messageSend(newCreditInsurance, ctx.req.accessToken);
return newClassification; return newClassification;
} catch (e) { } catch (e) {
transaction.rollback(); await tx.rollback();
throw e; throw e;
} }
}; };

View File

@ -6,6 +6,14 @@
save="post" save="post"
form="form"> form="form">
</vn-watcher> </vn-watcher>
<vn-crud-model
vn-id="model"
url="/client/api/AddressObservations"
fields="['id', 'addressFk', 'observationTypeFk', 'description']"
link="{addressFk: $ctrl.$stateParams.addressId}"
data="observations"
auto-load="true">
</vn-crud-model>
<form name="form" ng-submit="$ctrl.onSubmit()" compact> <form name="form" ng-submit="$ctrl.onSubmit()" compact>
<vn-card pad-large> <vn-card pad-large>
<vn-horizontal pad-small-v> <vn-horizontal pad-small-v>
@ -16,22 +24,40 @@
<vn-textfield vn-one label="Street address" field="$ctrl.address.street"></vn-textfield> <vn-textfield vn-one label="Street address" field="$ctrl.address.street"></vn-textfield>
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-textfield vn-one label="Postcode" field="$ctrl.address.postalCode"></vn-textfield> <vn-autocomplete vn-id="postcode" vn-one
<vn-textfield vn-one label="Town/City" field="$ctrl.address.city"></vn-textfield> field="$ctrl.address.postalCode"
<vn-autocomplete on-change="$ctrl.setLocation()"
vn-one search-function="{code: $search}"
url="/api/Postcodes/location"
fields="['code', 'townFk']"
show-field="code"
value-field="code"
label="Postcode">
<tpl-item>
{{code}}, {{town.name}} - {{town.province.name}}
({{town.province.country.country}})
</tpl-item>
</vn-autocomplete>
<vn-autocomplete vn-one
label="City"
url="/api/Towns"
show-field="name"
value-field="name"
field="$ctrl.address.city">
</vn-autocomplete>
<vn-autocomplete vn-one
disabled="true"
field="$ctrl.address.provinceFk" field="$ctrl.address.provinceFk"
url="/client/api/Provinces" url="/api/Provinces"
show-field="name" show-field="name"
value-field="id" value-field="id"
label="Province"> label="Province">
</vn-autocomplete> </vn-horizontal>
</vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-autocomplete <vn-autocomplete
vn-one vn-one
field="$ctrl.address.agencyModeFk" field="$ctrl.address.agencyModeFk"
url="/client/api/AgencyModes/isActive" url="/api/AgencyModes/isActive"
show-field="name" show-field="name"
value-field="id" value-field="id"
label="Agency"> label="Agency">

View File

@ -1,8 +1,8 @@
import ngModule from '../../module'; import ngModule from '../../module';
export default class Controller { export default class Controller {
constructor($scope, $state) { constructor($, $state) {
this.$scope = $scope; this.$ = $;
this.$state = $state; this.$state = $state;
this.data = { this.data = {
address: { address: {
@ -14,8 +14,20 @@ export default class Controller {
this.address = this.data.address; this.address = this.data.address;
} }
setLocation() {
const location = this.$.postcode.selection;
if (!location || !location.town) return;
const town = location.town;
const province = town.province;
const country = province.country;
this.address.city = location.town.name;
this.address.provinceFk = province.id;
this.address.countryFk = country.id;
}
onSubmit() { onSubmit() {
this.$scope.watcher.submit().then(res => { this.$.watcher.submit().then(res => {
if (res.data && this.data.isDefaultAddress) if (res.data && this.data.isDefaultAddress)
this.client.defaultAddressFk = res.data.id; this.client.defaultAddressFk = res.data.id;

View File

@ -14,8 +14,8 @@ describe('Client', () => {
$state = _$state_; $state = _$state_;
$state.params.id = '1234'; $state.params.id = '1234';
controller = $componentController('vnClientAddressCreate', {$state}); controller = $componentController('vnClientAddressCreate', {$state});
controller.$scope.watcher = watcher; controller.$.watcher = watcher;
controller.$scope.watcher.submit = () => { controller.$.watcher.submit = () => {
return { return {
then: callback => { then: callback => {
callback({data: {id: 124}}); callback({data: {id: 124}});

View File

@ -25,7 +25,7 @@
data="types" data="types"
auto-load="true"> auto-load="true">
</vn-crud-model> </vn-crud-model>
<form name="form" ng-submit="$ctrl.submit()" compact> <form name="form" ng-submit="$ctrl.onSubmit()" compact>
<vn-card pad-large> <vn-card pad-large>
<vn-horizontal pad-small-v> <vn-horizontal pad-small-v>
<vn-check vn-one label="Enabled" field="$ctrl.address.isActive"></vn-check> <vn-check vn-one label="Enabled" field="$ctrl.address.isActive"></vn-check>
@ -40,12 +40,31 @@
<vn-textfield vn-one label="Street" field="$ctrl.address.street"></vn-textfield> <vn-textfield vn-one label="Street" field="$ctrl.address.street"></vn-textfield>
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-textfield vn-one label="Postcode" field="$ctrl.address.postalCode"></vn-textfield> <vn-autocomplete vn-id="postcode" vn-one
<vn-textfield vn-one label="City" field="$ctrl.address.city"></vn-textfield> field="$ctrl.address.postalCode"
on-change="$ctrl.setLocation()"
search-function="{code: $search}"
url="/api/Postcodes/location"
fields="['code', 'townFk']"
show-field="code"
value-field="code"
label="Postcode">
<tpl-item>
{{code}}, {{town.name}} - {{town.province.name}}
({{town.province.country.country}})
</tpl-item>
</vn-autocomplete>
<vn-autocomplete vn-one <vn-autocomplete vn-one
initial-data="$ctrl.address.province" label="City"
url="/api/Towns"
show-field="name"
value-field="name"
field="$ctrl.address.city">
</vn-autocomplete>
<vn-autocomplete vn-one
disabled="true"
field="$ctrl.address.provinceFk" field="$ctrl.address.provinceFk"
url="/client/api/Provinces" url="/api/Provinces"
show-field="name" show-field="name"
value-field="id" value-field="id"
label="Province"> label="Province">

View File

@ -20,7 +20,19 @@ export default class Controller {
this.$state.go('client.card.address.index'); this.$state.go('client.card.address.index');
} }
submit() { setLocation() {
const location = this.$.postcode.selection;
if (!location || !location.town) return;
const town = location.town;
const province = town.province;
const country = province.country;
this.address.city = location.town.name;
this.address.provinceFk = province.id;
this.address.countryFk = country.id;
}
onSubmit() {
this.$.watcher.check(); this.$.watcher.check();
this.$.watcher.realSubmit() this.$.watcher.realSubmit()
.then(() => this.$.model.save(true)) .then(() => this.$.model.save(true))

View File

@ -33,34 +33,45 @@
</vn-textfield> </vn-textfield>
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-textfield <vn-autocomplete vn-id="postcode" vn-one
vn-one field="$ctrl.client.postcode"
label="Postcode" on-change="$ctrl.setLocation()"
field="$ctrl.client.postcode"> search-function="{code: $search}"
</vn-textfield> url="/api/Postcodes/location"
<vn-textfield fields="['code', 'townFk']"
vn-one show-field="code"
value-field="code"
label="Postcode">
<tpl-item>
{{code}}, {{town.name}} - {{town.province.name}}
({{town.province.country.country}})
</tpl-item>
</vn-autocomplete>
<vn-autocomplete vn-one
label="City" label="City"
url="/api/Towns"
show-field="name"
value-field="name"
field="$ctrl.client.city"> field="$ctrl.client.city">
</vn-textfield> </vn-autocomplete>
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-autocomplete <vn-autocomplete vn-one
vn-one disabled="true"
field="$ctrl.client.countryFk"
url="/client/api/Countries"
show-field="country"
value-field="id"
label="Country">
</vn-autocomplete>
<vn-autocomplete
vn-one
field="$ctrl.client.provinceFk" field="$ctrl.client.provinceFk"
url="/client/api/Provinces" url="/api/Provinces"
show-field="name" show-field="name"
value-field="id" value-field="id"
label="Province"> label="Province">
</vn-autocomplete> </vn-autocomplete>
<vn-autocomplete vn-one
disabled="true"
field="$ctrl.client.countryFk"
url="/api/Countries"
show-field="country"
value-field="id"
label="Country">
</vn-autocomplete>
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-textfield <vn-textfield

View File

@ -1,20 +1,34 @@
import ngModule from '../module'; import ngModule from '../module';
export default class Controller { export default class Controller {
constructor($scope, $state) { constructor($scope, $state, $http) {
this.$ = $scope; this.$ = $scope;
this.$state = $state; this.$state = $state;
this.$http = $http;
this.client = { this.client = {
active: true active: true
}; };
} }
setLocation() {
const location = this.$.postcode.selection;
if (!location || !location.town) return;
const town = location.town;
const province = town.province;
const country = province.country;
this.client.city = location.town.name;
this.client.provinceFk = province.id;
this.client.countryFk = country.id;
}
onSubmit() { onSubmit() {
this.$.watcher.submit().then( this.$.watcher.submit().then(
json => this.$state.go('client.card.basicData', {id: json.data.id}) json => this.$state.go('client.card.basicData', {id: json.data.id})
); );
} }
} }
Controller.$inject = ['$scope', '$state']; Controller.$inject = ['$scope', '$state', '$http'];
ngModule.component('vnClientCreate', { ngModule.component('vnClientCreate', {
template: require('./index.html'), template: require('./index.html'),

View File

@ -5,7 +5,7 @@
form="form" form="form"
save="patch"> save="patch">
</vn-watcher> </vn-watcher>
<form name="form" ng-submit="$ctrl.submit()" compact> <form name="form" ng-submit="$ctrl.onSubmit()" compact>
<vn-card pad-large> <vn-card pad-large>
<vn-horizontal> <vn-horizontal>
<vn-textfield <vn-textfield
@ -28,36 +28,45 @@
</vn-textfield> </vn-textfield>
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-textfield <vn-autocomplete vn-id="postcode" vn-one
vn-one field="$ctrl.client.postcode"
label="Postcode" on-change="$ctrl.setLocation()"
field="$ctrl.client.postcode"> search-function="{code: $search}"
</vn-textfield> url="/api/Postcodes/location"
<vn-textfield fields="['code', 'townFk']"
vn-one show-field="code"
value-field="code"
label="Postcode">
<tpl-item>
{{code}}, {{town.name}} - {{town.province.name}}
({{town.province.country.country}})
</tpl-item>
</vn-autocomplete>
<vn-autocomplete vn-one
label="City" label="City"
url="/api/Towns"
show-field="name"
value-field="name"
field="$ctrl.client.city"> field="$ctrl.client.city">
</vn-textfield> </vn-autocomplete>
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-autocomplete <vn-autocomplete vn-one
vn-one disabled="true"
initial-data="$ctrl.client.country"
field="$ctrl.client.countryFk"
url="/client/api/Countries"
show-field="country"
value-field="id"
label="Country">
</vn-autocomplete>
<vn-autocomplete
vn-one
initial-data="$ctrl.client.province"
field="$ctrl.client.provinceFk" field="$ctrl.client.provinceFk"
url="/client/api/Provinces" url="/api/Provinces"
show-field="name" show-field="name"
value-field="id" value-field="id"
label="Province"> label="Province">
</vn-autocomplete> </vn-autocomplete>
<vn-autocomplete vn-one
disabled="true"
field="$ctrl.client.countryFk"
url="/api/Countries"
show-field="country"
value-field="id"
label="Country">
</vn-autocomplete>
</vn-horizontal> </vn-horizontal>
<vn-horizontal pad-small-v> <vn-horizontal pad-small-v>
<vn-check <vn-check

View File

@ -24,7 +24,7 @@ export default class Controller {
return !this.client.isTaxDataChecked; return !this.client.isTaxDataChecked;
} }
submit() { onSubmit() {
if (this.isEqualizated != this.client.isEqualizated) { if (this.isEqualizated != this.client.isEqualizated) {
this.oldHasToInvoiceByAddress = this.client.hasToInvoiceByAddress; this.oldHasToInvoiceByAddress = this.client.hasToInvoiceByAddress;
this.client.hasToInvoiceByAddress = false; this.client.hasToInvoiceByAddress = false;
@ -56,6 +56,18 @@ export default class Controller {
); );
} }
} }
setLocation() {
const location = this.$.postcode.selection;
if (!location || !location.town) return;
const town = location.town;
const province = town.province;
const country = province.country;
this.client.city = location.town.name;
this.client.provinceFk = province.id;
this.client.countryFk = country.id;
}
} }
Controller.$inject = ['$scope', '$http', 'vnApp', '$translate']; Controller.$inject = ['$scope', '$http', 'vnApp', '$translate'];

View File

@ -21,24 +21,24 @@ module.exports = Self => {
}); });
Self.delete = async id => { Self.delete = async id => {
const transaction = await Self.beginTransaction({}); const tx = await Self.beginTransaction({});
try { try {
let options = {transaction: tx};
let invoiceOut = await Self.findById(id); let invoiceOut = await Self.findById(id);
let tickets = await Self.app.models.Ticket.find({where: {refFk: invoiceOut.ref}}); let tickets = await Self.app.models.Ticket.find({where: {refFk: invoiceOut.ref}});
const promises = []; const promises = [];
tickets.forEach(ticket => { tickets.forEach(ticket => {
promises.push(ticket.updateAttribute('refFk', null, {transaction})); promises.push(ticket.updateAttribute('refFk', null, options));
}); });
return Promise.all(promises).then(async() => { await Promise.all(promises);
await invoiceOut.destroy({transaction}); await invoiceOut.destroy(options);
await transaction.commit(); await tx.commit();
return tickets;
return tickets;
});
} catch (e) { } catch (e) {
await transaction.rollback(); await tx.rollback();
throw e; throw e;
} }
}; };

View File

@ -24,11 +24,13 @@ module.exports = Self => {
const models = Self.app.models; const models = Self.app.models;
const invoiceReportFk = 30; // FIXME - Should be deprecated const invoiceReportFk = 30; // FIXME - Should be deprecated
const worker = await models.Worker.findOne({where: {userFk: userId}}); const worker = await models.Worker.findOne({where: {userFk: userId}});
const transaction = await Self.beginTransaction({}); const tx = await Self.beginTransaction({});
try { try {
let options = {transaction: tx};
// Remove all invoice references from tickets // Remove all invoice references from tickets
const invoiceOut = await models.InvoiceOut.findById(id, {transaction}); const invoiceOut = await models.InvoiceOut.findById(id, null, options);
await invoiceOut.updateAttributes({ await invoiceOut.updateAttributes({
hasPdf: false hasPdf: false
}); });
@ -36,13 +38,13 @@ module.exports = Self => {
// Send to print queue // Send to print queue
await Self.rawSql(` await Self.rawSql(`
INSERT INTO vn.printServerQueue (reportFk, param1, workerFk) INSERT INTO vn.printServerQueue (reportFk, param1, workerFk)
VALUES (?, ?, ?)`, [invoiceReportFk, id, worker.id], {transaction}); VALUES (?, ?, ?)`, [invoiceReportFk, id, worker.id], options);
await transaction.commit(); await tx.commit();
return invoiceOut; return invoiceOut;
} catch (e) { } catch (e) {
await transaction.rollback(); await tx.rollback();
throw e; throw e;
} }
}; };

View File

@ -23,11 +23,12 @@ module.exports = Self => {
}); });
Self.clone = async itemId => { Self.clone = async itemId => {
let transaction = await Self.beginTransaction({}); let tx = await Self.beginTransaction({});
let options = {transaction};
try { try {
const origin = await Self.findById(itemId, options); let options = {transaction: tx};
const origin = await Self.findById(itemId, null, options);
if (!origin) if (!origin)
throw new UserError(`That item doesn't exists`); throw new UserError(`That item doesn't exists`);
@ -46,11 +47,10 @@ module.exports = Self => {
await cloneTags(origin.id, newItem.id, promises, options); await cloneTags(origin.id, newItem.id, promises, options);
await Promise.all(promises); await Promise.all(promises);
await transaction.commit(); await tx.commit();
return newItem; return newItem;
} catch (e) { } catch (e) {
await transaction.rollback(); await tx.rollback();
throw e; throw e;
} }
}; };

View File

@ -33,16 +33,18 @@ module.exports = Self => {
throw new UserError(`You don't have enough privileges to do that`); throw new UserError(`You don't have enough privileges to do that`);
} }
let transaction = await Self.beginTransaction({}); let tx = await Self.beginTransaction({});
try { try {
let options = {transaction: tx};
let provisionalName = params.provisionalName; let provisionalName = params.provisionalName;
delete params.provisionalName; delete params.provisionalName;
let item = await Self.app.models.Item.create(params, {transaction: transaction}); let item = await Self.app.models.Item.create(params, options);
let typeTags = await Self.app.models.ItemTypeTag.find({where: {itemTypeFk: item.typeFk}}); let typeTags = await Self.app.models.ItemTypeTag.find({where: {itemTypeFk: item.typeFk}});
let query = `SET @isTriggerDisabled = TRUE`; let query = `SET @isTriggerDisabled = TRUE`;
await Self.rawSql(query, null, {transaction: transaction}); await Self.rawSql(query, null, options);
let nameTag = await Self.app.models.Tag.findOne({where: {name: 'Nombre temporal'}}); let nameTag = await Self.app.models.Tag.findOne({where: {name: 'Nombre temporal'}});
@ -53,18 +55,18 @@ module.exports = Self => {
newTags.push({itemFk: item.id, tagFk: typeTag.tagFk, value: '', priority: typeTag.priority}); newTags.push({itemFk: item.id, tagFk: typeTag.tagFk, value: '', priority: typeTag.priority});
}); });
await Self.app.models.ItemTag.create(newTags, {transaction: transaction}); await Self.app.models.ItemTag.create(newTags, options);
query = `SET @isTriggerDisabled = FALSE`; query = `SET @isTriggerDisabled = FALSE`;
await Self.rawSql(query, null, {transaction: transaction}); await Self.rawSql(query, null, options);
query = `CALL vn.itemRefreshTags(?)`; query = `CALL vn.itemRefreshTags(?)`;
await Self.rawSql(query, [item.id], {transaction: transaction}); await Self.rawSql(query, [item.id], options);
await transaction.commit(); await tx.commit();
return item; return item;
} catch (e) { } catch (e) {
await transaction.rollback(); await tx.rollback();
throw e; throw e;
} }
}; };

View File

@ -42,15 +42,17 @@ module.exports = Self => {
where: {description: 'Corregido'} where: {description: 'Corregido'}
}); });
let transaction = await Self.beginTransaction({}); let tx = await Self.beginTransaction({});
try { try {
let options = {transaction: tx};
let item = await models.Item.findById(itemFk); let item = await models.Item.findById(itemFk);
let ticketFk = await getTicketId({ let ticketFk = await getTicketId({
clientFk: itemDestination.address.clientFk, clientFk: itemDestination.address.clientFk,
addressFk: itemDestination.addressFk, addressFk: itemDestination.addressFk,
warehouseFk: warehouseFk warehouseFk: warehouseFk
}, transaction); }, options);
if (!ticketFk) { if (!ticketFk) {
ticketFk = await createTicket(ctx, { ticketFk = await createTicket(ctx, {
@ -58,15 +60,15 @@ module.exports = Self => {
addressFk: itemDestination.addressFk, addressFk: itemDestination.addressFk,
warehouseFk: warehouseFk, warehouseFk: warehouseFk,
userId: userId userId: userId
}, transaction); }, options);
} }
let query = ` let query = `
CALL vn.getItemVisibleAvailable(?,curdate(),?,?)`; CALL vn.getItemVisibleAvailable(?,curdate(),?,?)`;
let options = [itemFk, warehouseFk, true]; let params = [itemFk, warehouseFk, true];
let [res] = await Self.rawSql(query, options, {transaction: transaction}); let [res] = await Self.rawSql(query, params, options);
let newQuantity = res[0].visible - quantity; let newQuantity = res[0].visible - quantity;
@ -76,16 +78,16 @@ module.exports = Self => {
concept: item.name, concept: item.name,
quantity: newQuantity, quantity: newQuantity,
discount: 100 discount: 100
}, {transaction: transaction}); }, options);
await transaction.commit(); await tx.commit();
return ticketFk; return ticketFk;
} catch (e) { } catch (e) {
await transaction.rollback(); await tx.rollback();
throw e; throw e;
} }
async function createTicket(ctx, params, transaction) { async function createTicket(ctx, params, options) {
let ticket = await Self.app.models.Ticket.new( let ticket = await Self.app.models.Ticket.new(
ctx, ctx,
{ {
@ -96,13 +98,13 @@ module.exports = Self => {
companyFk: params.companyFk, companyFk: params.companyFk,
addressFk: params.addressFk, addressFk: params.addressFk,
userId: params.userId userId: params.userId
}, {transaction: transaction}); }, options);
return ticket.id; return ticket.id;
} }
async function getTicketId(params, transaction) { async function getTicketId(params, options) {
const currentDate = new Date(); const currentDate = new Date();
currentDate.setHours(null, null, null); currentDate.setHours(null, null, null);
@ -113,7 +115,7 @@ module.exports = Self => {
shipped: currentDate, shipped: currentDate,
landed: currentDate landed: currentDate
} }
}, {transaction: transaction}); }, options);
return ticket && ticket.id; return ticket && ticket.id;
} }

View File

@ -140,7 +140,7 @@ module.exports = Self => {
SELECT id AS orderFk SELECT id AS orderFk
FROM tmp.filter`); FROM tmp.filter`);
stmts.push('CALL hedera.orderGetTotal()'); stmts.push('CALL hedera.order_getTotal()');
let orderIndex = stmts.push(` let orderIndex = stmts.push(`
SELECT f.*, ot.* SELECT f.*, ot.*

View File

@ -36,7 +36,7 @@ module.exports = Self => {
SELECT ? AS orderFk`, [orderFk]); SELECT ? AS orderFk`, [orderFk]);
stmts.push(stmt); stmts.push(stmt);
stmts.push('CALL hedera.orderGetTax()'); stmts.push('CALL hedera.order_getTax()');
let orderTaxIndex = stmts.push('SELECT * FROM tmp.orderAmount') - 1; let orderTaxIndex = stmts.push('SELECT * FROM tmp.orderAmount') - 1;

View File

@ -20,7 +20,7 @@ module.exports = Self => {
}); });
Self.getTotal = async orderFk => { Self.getTotal = async orderFk => {
let query = `SELECT hedera.orderGetTotal(?) total;`; let query = `SELECT hedera.order_getTotal(?) total;`;
let [total] = await Self.rawSql(query, [orderFk]); let [total] = await Self.rawSql(query, [orderFk]);
return total.total; return total.total;

View File

@ -26,8 +26,6 @@ module.exports = Self => {
let currentTicket = await models.Ticket.findById(params.currentTicket.currentTicketId); let currentTicket = await models.Ticket.findById(params.currentTicket.currentTicketId);
let newTicketData = {}; let newTicketData = {};
let receiverTicket = params.receiverTicket; let receiverTicket = params.receiverTicket;
let transaction = await Self.beginTransaction({});
let options = {transaction};
let isCurrentTicketEditable = await models.Ticket.isEditable(params.currentTicket.currentTicketId); let isCurrentTicketEditable = await models.Ticket.isEditable(params.currentTicket.currentTicketId);
if (!isCurrentTicketEditable) if (!isCurrentTicketEditable)
@ -55,7 +53,11 @@ module.exports = Self => {
}; };
} }
let tx = await Self.beginTransaction({});
try { try {
let options = {transaction: tx};
if (!params.receiverTicket.id) if (!params.receiverTicket.id)
receiverTicket = await models.Ticket.new(ctx, newTicketData, options); receiverTicket = await models.Ticket.new(ctx, newTicketData, options);
@ -74,11 +76,11 @@ module.exports = Self => {
promises.push(currentTicket.updateAttributes({isDeleted: true}, options)); promises.push(currentTicket.updateAttributes({isDeleted: true}, options));
await Promise.all(promises); await Promise.all(promises);
await transaction.commit(); await tx.commit();
return receiverTicket; return receiverTicket;
} catch (error) { } catch (error) {
await transaction.rollback(); await tx.rollback();
throw error; throw error;
} }
}; };

View File

@ -30,10 +30,11 @@ module.exports = Self => {
Self.updatePrice = async(id, newPrice) => { Self.updatePrice = async(id, newPrice) => {
let models = Self.app.models; let models = Self.app.models;
let transaction = await Self.beginTransaction({}); let tx = await Self.beginTransaction({});
let options = {transaction};
try { try {
let options = {transaction: tx};
let filter = { let filter = {
fields: ['id', 'ticketFk', 'price'], fields: ['id', 'ticketFk', 'price'],
include: { include: {
@ -86,9 +87,9 @@ module.exports = Self => {
query = `call vn.manaSpellersRequery(?)`; query = `call vn.manaSpellersRequery(?)`;
await Self.rawSql(query, [salesPerson], options); await Self.rawSql(query, [salesPerson], options);
await transaction.commit(); await tx.commit();
} catch (error) { } catch (error) {
await transaction.rollback(); await tx.rollback();
throw error; throw error;
} }
}; };

View File

@ -32,10 +32,11 @@ module.exports = Self => {
Self.confirm = async ctx => { Self.confirm = async ctx => {
const models = Self.app.models; const models = Self.app.models;
let transaction = await Self.beginTransaction({}); let tx = await Self.beginTransaction({});
let options = {transaction: transaction};
try { try {
let options = {transaction: tx};
let item = await models.Item.findById(ctx.args.itemFk); let item = await models.Item.findById(ctx.args.itemFk);
if (!item) if (!item)
throw new UserError(`That item doesn't exists`); throw new UserError(`That item doesn't exists`);
@ -88,9 +89,9 @@ module.exports = Self => {
message: message message: message
}, options); }, options);
await transaction.commit(); await tx.commit();
} catch (error) { } catch (error) {
await transaction.rollback(); await tx.rollback();
throw error; throw error;
} }
}; };

View File

@ -26,19 +26,20 @@ module.exports = function(Self) {
Self.makeInvoice = async(ctx, id) => { Self.makeInvoice = async(ctx, id) => {
let userId = ctx.req.accessToken.userId; let userId = ctx.req.accessToken.userId;
let models = Self.app.models; let $ = Self.app.models;
let tx = await Self.beginTransaction({});
let options = {};
options.transaction = await Self.beginTransaction({});
try { try {
let ticket = await models.Ticket.findById(id, {fields: ['id', 'clientFk', 'companyFk']}); let options = {transaction: tx};
let clientCanBeInvoiced = await models.Client.canBeInvoiced(ticket.clientFk); let filter = {fields: ['id', 'clientFk', 'companyFk']};
let ticket = await $.Ticket.findById(id, filter, options);
let clientCanBeInvoiced = await $.Client.canBeInvoiced(ticket.clientFk);
if (!clientCanBeInvoiced) if (!clientCanBeInvoiced)
throw new UserError(`This client can't be invoiced`); throw new UserError(`This client can't be invoiced`);
let ticketCanBeInvoiced = await models.Ticket.canBeInvoiced(ticket.id); let ticketCanBeInvoiced = await $.Ticket.canBeInvoiced(ticket.id);
if (!ticketCanBeInvoiced) if (!ticketCanBeInvoiced)
throw new UserError(`This ticket can't be invoiced`); throw new UserError(`This ticket can't be invoiced`);
@ -50,9 +51,12 @@ module.exports = function(Self) {
query = `CALL vn.invoiceFromTicket(?)`; query = `CALL vn.invoiceFromTicket(?)`;
await Self.rawSql(query, [ticket.id], options); await Self.rawSql(query, [ticket.id], options);
query = `CALL vn.invoiceOutMake(?, ?, @invoiceId); result = await Self.rawSql(
SELECT @invoiceId AS invoiceId;`; `CALL vn.invoiceOutMake(?, ?, @invoiceId);
result = await Self.rawSql(query, [serial, null], options); SELECT @invoiceId AS invoiceId;`,
[serial, null],
options
);
let invoice = result[1][0].invoiceId; let invoice = result[1][0].invoiceId;
if (serial != 'R' && invoice) { if (serial != 'R' && invoice) {
@ -60,15 +64,15 @@ module.exports = function(Self) {
await Self.rawSql(query, [invoice], options); await Self.rawSql(query, [invoice], options);
} }
let user = await Self.app.models.Worker.findOne({where: {userFk: userId}}); let user = await $.Worker.findOne({where: {userFk: userId}}, options);
query = `INSERT INTO printServerQueue(reportFk, param1, workerFk) VALUES (?, ?, ?)`; query = `INSERT INTO printServerQueue(reportFk, param1, workerFk) VALUES (?, ?, ?)`;
await Self.rawSql(query, [3, invoice, user.id], options); await Self.rawSql(query, [3, invoice, user.id], options);
await options.transaction.commit(); await tx.commit();
return {invoiceFk: invoice, serial}; return {invoiceFk: invoice, serial};
} catch (e) { } catch (e) {
options.transaction.rollback(); await tx.rollback();
throw e; throw e;
} }
}; };

View File

@ -21,8 +21,9 @@ module.exports = Self => {
} }
}); });
Self.new = async(ctx, params, transaction) => { Self.new = async(ctx, params, options) => {
let address = await Self.app.models.Address.findOne({ let $ = Self.app.models;
let address = await $.Address.findOne({
where: {id: params.addressFk}, where: {id: params.addressFk},
fields: ['id', 'clientFk'], fields: ['id', 'clientFk'],
include: [ include: [
@ -41,7 +42,7 @@ module.exports = Self => {
let agencyMode; let agencyMode;
if (params && params.agencyModeFk) if (params && params.agencyModeFk)
agencyMode = await Self.app.models.AgencyMode.findById(params.agencyModeFk); agencyMode = await $.AgencyMode.findById(params.agencyModeFk);
if (address.client().type().code === 'normal' && (!agencyMode || agencyMode.code != 'refund')) { if (address.client().type().code === 'normal' && (!agencyMode || agencyMode.code != 'refund')) {
if (address.client().isFreezed) if (address.client().isFreezed)
@ -51,12 +52,19 @@ module.exports = Self => {
throw new UserError(`You can't create a ticket for a inactive client`); throw new UserError(`You can't create a ticket for a inactive client`);
} }
if (!transaction || !transaction.commit) let tx;
transaction = await Self.beginTransaction({});
if ((typeof options) != 'object')
options = {};
if (!options.transaction) {
tx = await Self.beginTransaction({});
options.transaction = tx;
}
try { try {
if (!params.shipped && params.landed) { if (!params.shipped && params.landed) {
params.shipped = await Self.app.models.Agency.getShipped(ctx, { params.shipped = await $.Agency.getShipped(ctx, {
landed: params.landed, landed: params.landed,
addressFk: address.id, addressFk: address.id,
agencyModeFk: params.agencyModeFk, agencyModeFk: params.agencyModeFk,
@ -65,7 +73,7 @@ module.exports = Self => {
} }
if (params.shipped && !params.landed) { if (params.shipped && !params.landed) {
const landedResult = await Self.app.models.Agency.getLanded(ctx, { const landedResult = await $.Agency.getLanded(ctx, {
shipped: params.shipped, shipped: params.shipped,
addressFk: address.id, addressFk: address.id,
agencyModeFk: params.agencyModeFk, agencyModeFk: params.agencyModeFk,
@ -89,9 +97,9 @@ module.exports = Self => {
params.routeFk || null, params.routeFk || null,
params.landed, params.landed,
params.userId params.userId
], {options: transaction}); ], options);
let ticket = await Self.app.models.Ticket.findById(result[1][0].newTicketId, {options: transaction}); let ticket = await $.Ticket.findById(result[1][0].newTicketId, null, options);
let cleanInstance = JSON.parse(JSON.stringify(ticket)); let cleanInstance = JSON.parse(JSON.stringify(ticket));
let logRecord = { let logRecord = {
@ -104,12 +112,12 @@ module.exports = Self => {
newInstance: cleanInstance newInstance: cleanInstance
}; };
await Self.app.models.TicketLog.create(logRecord, {options: transaction}); await $.TicketLog.create(logRecord, options);
await transaction.commit(); if (tx) await tx.commit();
return await ticket; return await ticket;
} catch (e) { } catch (e) {
await transaction.rollback(); if (tx) await tx.rollback();
throw e; throw e;
} }
}; };

View File

@ -36,10 +36,11 @@ module.exports = Self => {
Self.updateDiscount = async(id, salesIds, newDiscount) => { Self.updateDiscount = async(id, salesIds, newDiscount) => {
const models = Self.app.models; const models = Self.app.models;
const transaction = await Self.beginTransaction({}); const tx = await Self.beginTransaction({});
const options = {transaction};
try { try {
const options = {transaction: tx};
const filter = { const filter = {
fields: ['id', 'ticketFk', 'price'], fields: ['id', 'ticketFk', 'price'],
where: { where: {
@ -112,9 +113,9 @@ module.exports = Self => {
query = `call vn.manaSpellersRequery(?)`; query = `call vn.manaSpellersRequery(?)`;
await Self.rawSql(query, [salesPersonId], options); await Self.rawSql(query, [salesPersonId], options);
await transaction.commit(); await tx.commit();
} catch (error) { } catch (error) {
await transaction.rollback(); await tx.rollback();
throw error; throw error;
} }
}; };

View File

@ -50,11 +50,12 @@ module.exports = Self => {
Self.uploadFile = async(ctx, id) => { Self.uploadFile = async(ctx, id) => {
const models = Self.app.models; const models = Self.app.models;
const transaction = await Self.beginTransaction({});
const options = {transaction};
const promises = []; const promises = [];
const tx = await Self.beginTransaction({});
try { try {
const options = {transaction: tx};
const uploadedFiles = await models.Dms.uploadFile(ctx, options); const uploadedFiles = await models.Dms.uploadFile(ctx, options);
uploadedFiles.forEach(dms => { uploadedFiles.forEach(dms => {
const newTicketDms = models.TicketDms.create({ const newTicketDms = models.TicketDms.create({
@ -66,11 +67,11 @@ module.exports = Self => {
}); });
const resolvedPromises = await Promise.all(promises); const resolvedPromises = await Promise.all(promises);
await transaction.commit(); await tx.commit();
return resolvedPromises; return resolvedPromises;
} catch (err) { } catch (err) {
await transaction.rollback(); await tx.rollback();
throw err; throw err;
} }
}; };

View File

@ -1,4 +1,5 @@
const UserError = require('vn-loopback/util/user-error'); const UserError = require('vn-loopback/util/user-error');
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
module.exports = Self => { module.exports = Self => {
Self.remoteMethodCtx('absences', { Self.remoteMethodCtx('absences', {

1571
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -16,7 +16,7 @@
"loopback": "^3.25.0", "loopback": "^3.25.0",
"loopback-boot": "^2.27.1", "loopback-boot": "^2.27.1",
"loopback-component-explorer": "^6.3.1", "loopback-component-explorer": "^6.3.1",
"loopback-component-storage": "^3.6.0", "loopback-component-storage": "^3.6.1",
"loopback-connector-mysql": "^5.3.1", "loopback-connector-mysql": "^5.3.1",
"loopback-connector-remote": "^3.4.1", "loopback-connector-remote": "^3.4.1",
"loopback-context": "^3.4.0", "loopback-context": "^3.4.0",
@ -47,7 +47,7 @@
"eslint-plugin-jasmine": "^2.10.1", "eslint-plugin-jasmine": "^2.10.1",
"fancy-log": "^1.3.2", "fancy-log": "^1.3.2",
"file-loader": "^1.1.11", "file-loader": "^1.1.11",
"gulp": "^4.0.0", "gulp": "^4.0.2",
"gulp-concat": "^2.6.1", "gulp-concat": "^2.6.1",
"gulp-env": "^0.4.0", "gulp-env": "^0.4.0",
"gulp-file": "^0.4.0", "gulp-file": "^0.4.0",

View File

@ -15,7 +15,7 @@ module.exports = {
sections: { sections: {
agency: { agency: {
description: `Para agilizar tu recogida, por favor, pónte en contacto con la oficina de integrados. <br/> description: `Para agilizar tu recogida, por favor, pónte en contacto con la oficina de integrados. <br/>
Tlf: 96 166 77 88 - Ana Gómez <em>(agomezf@integra2.es)</em>` Tlf: 96 166 77 88 - Ana Gómez (Ext. 113) <em>(agomezf@integra2.es)</em> `
} }
} }
}, },