This commit is contained in:
Carlos Jimenez Ruiz 2019-06-05 15:09:00 +02:00
commit 7bcd4b53e5
22 changed files with 212 additions and 85 deletions

View File

@ -1,11 +1,5 @@
module.exports = Self => { module.exports = Self => {
// Validations
Self.validatesUniquenessOf('extension', { Self.validatesUniquenessOf('extension', {
message: `The extension must be unique` message: `The extension must be unique`
}); });
Self.validatesPresenceOf('secret', {
message: `The secret can't be blank`
});
}; };

View File

@ -16,10 +16,8 @@
} }
}, },
"extension": { "extension": {
"type": "Number" "type": "String",
}, "required": true
"secret": {
"type": "String"
} }
}, },
"relations": { "relations": {

View File

@ -1,2 +1,3 @@
INSERT INTO `salix`.`ACL` ( `model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ( 'ClientDms', 'remove', 'WRITE', 'ALLOW', 'ROLE', 'employee'); INSERT INTO `salix`.`ACL` ( `model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ( 'ClientDms', 'remove', 'WRITE', 'ALLOW', 'ROLE', 'employee');
INSERT INTO `salix`.`ACL` ( `model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ( 'ClientDms', '*', 'READ', 'ALLOW', 'ROLE', 'employee'); INSERT INTO `salix`.`ACL` ( `model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ( 'ClientDms', '*', 'READ', 'ALLOW', 'ROLE', 'employee');
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('Route', 'updateVolume', 'WRITE', 'ALLOW', 'ROLE', 'deliveryBoss');

View File

@ -364,13 +364,13 @@ INSERT INTO `vn`.`creditInsurance`(`id`, `creditClassification`, `credit`, `crea
INSERT INTO `vn`.`route`(`id`, `time`, `workerFk`, `created`, `vehicleFk`, `agencyModeFk`, `description`, `m3`, `cost`, `started`, `finished`) INSERT INTO `vn`.`route`(`id`, `time`, `workerFk`, `created`, `vehicleFk`, `agencyModeFk`, `description`, `m3`, `cost`, `started`, `finished`)
VALUES VALUES
(1, '1899-12-30 12:15:00', 56, CURDATE(), 1, 1, 'first route', null, 10, CURDATE(), CURDATE()), (1, '1899-12-30 12:15:00', 56, CURDATE(), 1, 1, 'first route', 0.2, 10, CURDATE(), CURDATE()),
(2, '1899-12-30 13:20:00', 56, CURDATE(), 1, 1, 'second route', 4.2, 20, CURDATE(), CURDATE()), (2, '1899-12-30 13:20:00', 56, CURDATE(), 1, 1, 'second route', null, 20, CURDATE(), CURDATE()),
(3, '1899-12-30 14:30:00', 56, CURDATE(), 2, 7, 'third route', 5.3, 30, CURDATE(), CURDATE()), (3, '1899-12-30 14:30:00', 56, CURDATE(), 2, 7, 'third route', null, 30, CURDATE(), CURDATE()),
(4, '1899-12-30 15:45:00', 56, CURDATE(), 3, 7, 'fourth route', 6.4, 40, CURDATE(), CURDATE()), (4, '1899-12-30 15:45:00', 56, CURDATE(), 3, 7, 'fourth route', 0.1, 40, CURDATE(), CURDATE()),
(5, '1899-12-30 16:00:00', 56, CURDATE(), 4, 8, 'fifth route', 7.5, 50, CURDATE(), CURDATE()), (5, '1899-12-30 16:00:00', 56, CURDATE(), 4, 8, 'fifth route', null, 50, CURDATE(), CURDATE()),
(6, null, 57, CURDATE(), 5, 8, 'sixth route', 8.6, 60, CURDATE(), CURDATE()), (6, null, 57, CURDATE(), 5, 8, 'sixth route', null, 60, CURDATE(), CURDATE()),
(7, null, 57, CURDATE(), 6, null, 'seventh route', 9.7, 70, CURDATE(), CURDATE()); (7, null, 57, CURDATE(), 6, null, 'seventh route', null, 70, CURDATE(), CURDATE());
INSERT INTO `vn2008`.`empresa_grupo`(`empresa_grupo_id`, `grupo`) INSERT INTO `vn2008`.`empresa_grupo`(`empresa_grupo_id`, `grupo`)
VALUES VALUES
@ -1341,12 +1341,12 @@ INSERT INTO `vn`.`zoneIncluded` (`zoneFk`, `geoFk`, `isIncluded`)
(5, 4, 1), (5, 4, 1),
(5, 5, 1); (5, 5, 1);
INSERT INTO `pbx`.`sip`(`user_id`, `extension`, `secret`, `caller_id`) INSERT INTO `pbx`.`sip`(`user_id`, `extension`)
VALUES VALUES
(1, 1010, '123456', 'employee'), (1, 1010),
(3, 1101, '123456', 'agency'), (3, 1101),
(5, 1102, '123456', 'administrative'), (5, 1102),
(9, 1201, '123456', 'developer'); (9, 1201);
INSERT INTO `postgresql`.`person`(`person_id`, `name`, `nickname`, `nif`, `firstname`, `id_trabajador`) INSERT INTO `postgresql`.`person`(`person_id`, `name`, `nickname`, `nif`, `firstname`, `id_trabajador`)
SELECT w.id, w.lastName, u.nickname,CONCAT(RPAD(CONCAT(w.id,9),8,w.id),'A'),w.firstName,w.id SELECT w.id, w.lastName, u.nickname,CONCAT(RPAD(CONCAT(w.id,9),8,w.id),'A'),w.firstName,w.id

View File

@ -474,7 +474,6 @@ export default {
}, },
claimBasicData: { claimBasicData: {
claimStateAutocomplete: 'vn-claim-basic-data vn-autocomplete[field="$ctrl.claim.claimStateFk"]', claimStateAutocomplete: 'vn-claim-basic-data vn-autocomplete[field="$ctrl.claim.claimStateFk"]',
isPaidWithManaCheckbox: 'vn-check[field="$ctrl.claim.isChargedToMana"] md-checkbox',
responsabilityInputRange: 'vn-input-range', responsabilityInputRange: 'vn-input-range',
observationInput: 'vn-textarea[field="$ctrl.claim.observation"] textarea', observationInput: 'vn-textarea[field="$ctrl.claim.observation"] textarea',
saveButton: `${components.vnSubmit}` saveButton: `${components.vnSubmit}`
@ -510,8 +509,8 @@ export default {
thirdLineDestination: 'vn-claim-action vn-tr:nth-child(3) vn-autocomplete[field="saleClaimed.claimDestinationFk"]', thirdLineDestination: 'vn-claim-action vn-tr:nth-child(3) vn-autocomplete[field="saleClaimed.claimDestinationFk"]',
firstDeleteLine: 'vn-claim-action vn-tr:nth-child(1) vn-icon-button[icon="delete"]', firstDeleteLine: 'vn-claim-action vn-tr:nth-child(1) vn-icon-button[icon="delete"]',
secondDeleteLine: 'vn-claim-action vn-tr:nth-child(2) vn-icon-button[icon="delete"]', secondDeleteLine: 'vn-claim-action vn-tr:nth-child(2) vn-icon-button[icon="delete"]',
thirdDeleteLine: 'vn-claim-action vn-tr:nth-child(3) vn-icon-button[icon="delete"]' thirdDeleteLine: 'vn-claim-action vn-tr:nth-child(3) vn-icon-button[icon="delete"]',
isPaidWithManaCheckbox: 'vn-check[field="$ctrl.claim.isChargedToMana"] md-checkbox'
}, },
ordersIndex: { ordersIndex: {
searchResult: 'vn-order-index vn-card > div > vn-table > div > vn-tbody > a.vn-tr', searchResult: 'vn-order-index vn-card > div > vn-table > div > vn-tbody > a.vn-tr',
@ -591,8 +590,7 @@ export default {
confirmButton: 'vn-route-tickets > vn-confirm button[response="ACCEPT"]' confirmButton: 'vn-route-tickets > vn-confirm button[response="ACCEPT"]'
}, },
workerPbx: { workerPbx: {
extensionInput: 'vn-worker-pbx vn-input-number[model="$ctrl.worker.sip.extension"] input', extensionInput: 'vn-worker-pbx vn-textfield[model="$ctrl.worker.sip.extension"] input',
passwordInput: 'vn-worker-pbx vn-textfield[model="$ctrl.worker.sip.secret"] input',
saveButton: 'vn-worker-pbx vn-submit[label="Save"] input' saveButton: 'vn-worker-pbx vn-submit[label="Save"] input'
}, },
workerTimeControl: { workerTimeControl: {

View File

@ -25,8 +25,6 @@ describe('Worker pbx path', () => {
const result = await nightmare const result = await nightmare
.clearInput(selectors.workerPbx.extensionInput) .clearInput(selectors.workerPbx.extensionInput)
.write(selectors.workerPbx.extensionInput, 4444) .write(selectors.workerPbx.extensionInput, 4444)
.clearInput(selectors.workerPbx.passwordInput)
.write(selectors.workerPbx.passwordInput, 666666)
.waitToClick(selectors.workerPbx.saveButton) .waitToClick(selectors.workerPbx.saveButton)
.waitForLastSnackbar(); .waitForLastSnackbar();

View File

@ -11,10 +11,9 @@ describe('Claim edit basic data path', () => {
.accessToSection('claim.card.basicData'); .accessToSection('claim.card.basicData');
}); });
it(`should edit claim state, is paid with mana and observation fields`, async() => { it(`should edit claim state and observation fields`, async() => {
const result = await nightmare const result = await nightmare
.autocompleteSearch(selectors.claimBasicData.claimStateAutocomplete, 'Gestionado') .autocompleteSearch(selectors.claimBasicData.claimStateAutocomplete, 'Gestionado')
.waitToClick(selectors.claimBasicData.isPaidWithManaCheckbox)
.clearTextarea(selectors.claimBasicData.observationInput) .clearTextarea(selectors.claimBasicData.observationInput)
.write(selectors.claimBasicData.observationInput, 'edited observation') .write(selectors.claimBasicData.observationInput, 'edited observation')
.waitToClick(selectors.claimBasicData.saveButton) .waitToClick(selectors.claimBasicData.saveButton)
@ -40,13 +39,6 @@ describe('Claim edit basic data path', () => {
expect(result).toEqual('Gestionado'); expect(result).toEqual('Gestionado');
}); });
it('should confirm the Is paid with mana checkbox is checked', async() => {
const result = await nightmare
.checkboxState(selectors.claimBasicData.isPaidWithManaCheckbox);
expect(result).toBe('checked');
});
it('should confirm the claim observation was edited', async() => { it('should confirm the claim observation was edited', async() => {
const result = await nightmare const result = await nightmare
.waitToGetProperty(selectors.claimBasicData.observationInput, 'value'); .waitToGetProperty(selectors.claimBasicData.observationInput, 'value');
@ -57,7 +49,6 @@ describe('Claim edit basic data path', () => {
it(`should edit the claim to leave it untainted`, async() => { it(`should edit the claim to leave it untainted`, async() => {
const result = await nightmare const result = await nightmare
.autocompleteSearch(selectors.claimBasicData.claimStateAutocomplete, 'Pendiente') .autocompleteSearch(selectors.claimBasicData.claimStateAutocomplete, 'Pendiente')
.waitToClick(selectors.claimBasicData.isPaidWithManaCheckbox)
.clearTextarea(selectors.claimBasicData.observationInput) .clearTextarea(selectors.claimBasicData.observationInput)
.write(selectors.claimBasicData.observationInput, 'Observation one') .write(selectors.claimBasicData.observationInput, 'Observation one')
.waitToClick(selectors.claimBasicData.saveButton) .waitToClick(selectors.claimBasicData.saveButton)

View File

@ -1,7 +1,7 @@
import selectors from '../../helpers/selectors.js'; import selectors from '../../helpers/selectors.js';
import createNightmare from '../../helpers/nightmare'; import createNightmare from '../../helpers/nightmare';
describe('Claim edit basic data path', () => { describe('Claim action path', () => {
const nightmare = createNightmare(); const nightmare = createNightmare();
beforeAll(() => { beforeAll(() => {
@ -60,4 +60,20 @@ describe('Claim edit basic data path', () => {
expect(result).toEqual('Data saved!'); expect(result).toEqual('Data saved!');
}); });
it('should check the Is paid with mana checkbox', async() => {
const result = await nightmare
.waitToClick(selectors.claimAction.isPaidWithManaCheckbox)
.waitForSnackbar();
expect(result).toEqual(jasmine.arrayContaining(['Data saved!']));
});
it('should confirm the Is paid with mana checkbox is checked', async() => {
const result = await nightmare
.reloadSection('claim.card.action')
.checkboxState(selectors.claimAction.isPaidWithManaCheckbox);
expect(result).toBe('checked');
});
}); });

View File

@ -37,6 +37,16 @@
on-change="$ctrl.saveResponsibility(value)"> on-change="$ctrl.saveResponsibility(value)">
</vn-input-range> </vn-input-range>
</vn-tool-bar> </vn-tool-bar>
<vn-one
style = "text-align:right">
<vn-check
vn-one
label="Is paid with mana"
field="$ctrl.claim.isChargedToMana"
vn-acl="salesAssistant"
on-change="$ctrl.saveMana(value)">
</vn-check>
</vn-one>
</vn-horizontal> </vn-horizontal>
<vn-table model="model"> <vn-table model="model">
<vn-thead> <vn-thead>

View File

@ -173,6 +173,13 @@ class Controller {
this.vnApp.showSuccess(this.$translate.instant('Data saved!')); this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
}); });
} }
saveMana(value) {
let query = `/api/Claims/${this.$stateParams.id}/updateClaim`;
this.$http.post(query, {isChargedToMana: value}).then(() => {
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
});
}
} }
Controller.$inject = ['$stateParams', '$scope', '$http', '$translate', 'vnApp']; Controller.$inject = ['$stateParams', '$scope', '$http', '$translate', 'vnApp'];

View File

@ -18,6 +18,15 @@
label="Client" label="Client"
order="id"> order="id">
</vn-autocomplete> </vn-autocomplete>
<vn-date-picker
vn-one
disabled="true"
label="Created"
model="$ctrl.claim.created"
ini-options="{enableTime: true, dateFormat: 'd-m-Y', time_24hr: true}">
</vn-date-picker>
</vn-horizontal>
<vn-horizontal pad-small-v>
<vn-autocomplete <vn-autocomplete
vn-one vn-one
disabled="false" disabled="false"
@ -29,15 +38,6 @@
where="{role: 'employee'}" where="{role: 'employee'}"
label="Worker"> label="Worker">
</vn-autocomplete> </vn-autocomplete>
<vn-date-picker
vn-one
disabled="true"
label="Created"
model="$ctrl.claim.created"
ini-options="{enableTime: true, dateFormat: 'd-m-Y', time_24hr: true}">
</vn-date-picker>
</vn-horizontal>
<vn-horizontal pad-small-v>
<vn-autocomplete <vn-autocomplete
vn-one vn-one
field="$ctrl.claim.claimStateFk" field="$ctrl.claim.claimStateFk"
@ -47,12 +47,6 @@
label="Claim state" label="Claim state"
vn-focus> vn-focus>
</vn-autocomplete> </vn-autocomplete>
<vn-check
vn-one
label="Is paid with mana"
field="$ctrl.claim.isChargedToMana"
vn-acl="salesAssistant">
</vn-check>
</vn-horizontal> </vn-horizontal>
</vn-horizontal> </vn-horizontal>
<vn-horizontal pad-small-v> <vn-horizontal pad-small-v>

View File

@ -45,7 +45,7 @@ describe('Route filter()', () => {
it('should return the routes matching "m3"', async() => { it('should return the routes matching "m3"', async() => {
let ctx = { let ctx = {
args: { args: {
m3: 4.2, m3: 0.1,
} }
}; };

View File

@ -0,0 +1,44 @@
const app = require('vn-loopback/server/server');
describe('route updateVolume()', () => {
const routeId = 1;
const workerFk = 9;
const ctx = {req: {accessToken: {userId: workerFk}}};
let originalRoute;
let ticketRestore;
afterAll(async done => {
await originalRoute.updateAttributes({m3: 0.2});
await ticketRestore.updateAttributes({routeFk: 4});
done();
});
it('should confirm the original volume of the route is the expected', async() => {
originalRoute = await app.models.Route.findById(routeId);
expect(originalRoute.m3).toEqual(0.2);
});
it('should confirm the route volume is updated when a ticket is added', async() => {
ticketRestore = await app.models.Ticket.findById(8);
let updatedTicket = await app.models.Ticket.findById(8);
await updatedTicket.updateAttributes({routeFk: routeId});
await app.models.Route.updateVolume(ctx, routeId);
let updatedRoute = await app.models.Route.findById(routeId);
expect(updatedRoute.m3).not.toEqual(originalRoute.m3);
});
// 1462
xit('should confirm the change is logged ', async() => {
let instanceValue = {m3: 0.3};
let filterValue = JSON.stringify(instanceValue);
let filter = {where: {newInstance: filterValue}};
console.log(filter);
let routeLog = await app.models.RouteLog.find(filter);
console.log(routeLog);
expect(routeLog.length).toBeGreaterThan(0);
});
});

View File

@ -0,0 +1,42 @@
module.exports = Self => {
Self.remoteMethodCtx('updateVolume', {
description: 'Update the volume in a route',
accessType: 'WRITE',
accepts: {
arg: 'id',
type: 'number',
required: true,
description: 'Route id',
http: {source: 'path'}
},
returns: {
type: 'number',
root: true
},
http: {
path: `/:id/updateVolume`,
verb: 'POST'
}
});
Self.updateVolume = async(ctx, id) => {
let query = `CALL vn.routeUpdateM3(?)`;
let userId = ctx.req.accessToken.userId;
let originalRoute = await Self.app.models.Route.findById(id);
await Self.rawSql(query, [id]);
let updatedRoute = await Self.app.models.Route.findById(id);
let logRecord = {
originFk: id,
userFk: userId,
action: 'update',
changedModel: 'Route',
changedModelId: id,
oldInstance: {m3: originalRoute.m3},
newInstance: {m3: updatedRoute.m3}
};
return await Self.app.models.RouteLog.create(logRecord);
};
};

View File

@ -3,4 +3,5 @@ module.exports = Self => {
require('../methods/route/summary')(Self); require('../methods/route/summary')(Self);
require('../methods/route/getTickets')(Self); require('../methods/route/getTickets')(Self);
require('../methods/route/guessPriority')(Self); require('../methods/route/guessPriority')(Self);
require('../methods/route/updateVolume')(Self);
}; };

View File

@ -13,7 +13,8 @@
value-field="callback" value-field="callback"
translate-fields="['name']" translate-fields="['name']"
data="$ctrl.moreOptions" data="$ctrl.moreOptions"
on-change="$ctrl.onMoreChange(value)"> on-change="$ctrl.onMoreChange(value)"
on-open="$ctrl.onMoreOpen()">
</vn-icon-menu> </vn-icon-menu>
</div> </div>
<div class="body"> <div class="body">
@ -69,4 +70,9 @@
</a> </a>
</div> </div>
</div> </div>
</div> </div>
<vn-confirm
vn-id="updateVolumeConfirmation"
on-response="$ctrl.updateVolume(response)"
question="Are you sure you want to book this invoice?">
</vn-confirm>

View File

@ -1,16 +1,29 @@
import ngModule from '../module'; import ngModule from '../module';
import {createDecipher} from 'crypto';
class Controller { class Controller {
constructor($, $http, vnApp, $translate) { constructor($, $http, vnApp, $translate, aclService) {
this.$http = $http; this.$http = $http;
this.vnApp = vnApp; this.vnApp = vnApp;
this.$translate = $translate; this.$translate = $translate;
this.$ = $; this.$ = $;
this.aclService = aclService;
this.moreOptions = [ this.moreOptions = [
{callback: this.showRouteReport, name: 'Show route report'}, {callback: this.showRouteReport, name: 'Show route report'},
{callback: this.sendRouteReport, name: 'Send route report'} {callback: this.sendRouteReport, name: 'Send route report'},
{callback: this.showUpdateVolumeDialog, name: 'Update volume', acl: 'deliveryBoss'}
]; ];
} }
onMoreOpen() {
let options = this.moreOptions.filter(option => {
const hasAclProperty = Object.hasOwnProperty.call(option, 'acl');
return !hasAclProperty || (hasAclProperty && this.aclService.hasAny([option.acl]));
});
this.$.moreButton.data = options;
}
set quicklinks(value = {}) { set quicklinks(value = {}) {
this._quicklinks = Object.assign(value, this._quicklinks); this._quicklinks = Object.assign(value, this._quicklinks);
} }
@ -34,9 +47,23 @@ class Controller {
this.vnApp.showSuccess(this.$translate.instant('Report sent')); this.vnApp.showSuccess(this.$translate.instant('Report sent'));
}); });
} }
showUpdateVolumeDialog() {
this.$.updateVolumeConfirmation.show();
}
updateVolume(response) {
if (response === 'ACCEPT') {
let url = `/route/api/Routes/${this.route.id}/updateVolume`;
this.$http.post(url).then(() => {
this.vnApp.showSuccess(this.$translate.instant('Volume updated'));
this.card.reload();
});
}
}
} }
Controller.$inject = ['$scope', '$http', 'vnApp', '$translate']; Controller.$inject = ['$scope', '$http', 'vnApp', '$translate', 'aclService'];
ngModule.component('vnRouteDescriptor', { ngModule.component('vnRouteDescriptor', {
template: require('./index.html'), template: require('./index.html'),
@ -44,5 +71,8 @@ ngModule.component('vnRouteDescriptor', {
route: '<', route: '<',
quicklinks: '<' quicklinks: '<'
}, },
require: {
card: '^vnRouteCard'
},
controller: Controller controller: Controller
}); });

View File

@ -1,4 +1,6 @@
Volume exceded: Volumen excedido Volume exceded: Volumen excedido
Volume: Volumen Volume: Volumen
Send route report: Enviar informe de ruta Send route report: Enviar informe de ruta
Show route report: Ver informe de ruta Show route report: Ver informe de ruta
Update volume: Actualizar volumen
Volume updated: Volumen actualizado

View File

@ -7,9 +7,9 @@ describe('sale updatePrice()', () => {
let saleId = 13; let saleId = 13;
afterAll(async done => { afterAll(async done => {
originalSale.save(); await originalSale.save();
createdSaleComponent.destroy(); await app.models.SaleComponent.updateAll({componentFk: 37, saleFk: saleId}, {value: 0});
originalSalesPersonMana.save(); await originalSalesPersonMana.save();
done(); done();
}); });

View File

@ -26,23 +26,23 @@
"changedModel": { "changedModel": {
"type": "String" "type": "String"
}, },
"oldInstance": { "oldInstance": {
"type": "Object" "type": "Object"
}, },
"newInstance": { "newInstance": {
"type": "Object" "type": "Object"
}, },
"creationDate": { "creationDate": {
"type": "Date" "type": "Date"
}, },
"changedModelId": { "changedModelId": {
"type": "Number" "type": "Number"
}, },
"changedModelValue": { "changedModelValue": {
"type": "String" "type": "String"
}, },
"description": { "description": {
"type": "String" "type": "String"
} }
}, },
"relations": { "relations": {

View File

@ -6,15 +6,11 @@
<vn-card pad-large> <vn-card pad-large>
<vn-vertical> <vn-vertical>
<vn-horizontal> <vn-horizontal>
<vn-input-number vn-one min="1" step="1" <vn-textfield
label="Extension" label="Extension"
model="$ctrl.worker.sip.extension"> model="$ctrl.worker.sip.extension">
</vn-input-number>
<vn-textfield
vn-one
label="Password"
model="$ctrl.worker.sip.secret">
</vn-textfield> </vn-textfield>
</vn-horizontal> </vn-horizontal>
</vn-vertical> </vn-vertical>
</vn-card> </vn-card>

View File

@ -10,8 +10,7 @@ class Controller {
const sip = this.worker.sip; const sip = this.worker.sip;
const params = { const params = {
userFk: this.worker.userFk, userFk: this.worker.userFk,
extension: sip.extension, extension: sip.extension
secret: sip.secret
}; };
this.$scope.watcher.check(); this.$scope.watcher.check();
this.$http.patch('/api/Sips', params).then(() => { this.$http.patch('/api/Sips', params).then(() => {