Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 2319_show_delivery_note
This commit is contained in:
commit
fb37e156d4
42
db/docker.js
42
db/docker.js
|
@ -39,7 +39,8 @@ module.exports = class Docker {
|
||||||
|
|
||||||
let runChown = process.platform != 'linux';
|
let runChown = process.platform != 'linux';
|
||||||
|
|
||||||
let container = await this.execP(`docker run --env RUN_CHOWN=${runChown} -d ${dockerArgs} salix-db`);
|
const healthCheck = `--health-cmd='mysqladmin ping --silent'`;
|
||||||
|
const container = await this.execP(`docker run ${healthCheck} --env RUN_CHOWN=${runChown} -d ${dockerArgs} salix-db`);
|
||||||
this.id = container.stdout;
|
this.id = container.stdout;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -53,7 +54,7 @@ module.exports = class Docker {
|
||||||
this.dbConf.port = netSettings.Ports['3306/tcp'][0]['HostPort'];
|
this.dbConf.port = netSettings.Ports['3306/tcp'][0]['HostPort'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (runChown) await this.wait();
|
await this.waitForHealthy();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (this.isRandom)
|
if (this.isRandom)
|
||||||
await this.rm();
|
await this.rm();
|
||||||
|
@ -88,6 +89,43 @@ module.exports = class Docker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
waitForHealthy() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let interval = 100;
|
||||||
|
let elapsedTime = 0;
|
||||||
|
let maxInterval = 4 * 60 * 1000;
|
||||||
|
|
||||||
|
log('Waiting for MySQL init process...');
|
||||||
|
|
||||||
|
async function checker() {
|
||||||
|
elapsedTime += interval;
|
||||||
|
let status;
|
||||||
|
|
||||||
|
try {
|
||||||
|
let result = await this.execP(`docker inspect -f "{{.State.Health.Status}}" ${this.id}`);
|
||||||
|
status = result.stdout.trimEnd();
|
||||||
|
} catch (err) {
|
||||||
|
return reject(new Error(err.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status == 'unhealthy')
|
||||||
|
return reject(new Error('Docker exited, please see the docker logs for more info'));
|
||||||
|
|
||||||
|
if (status == 'healthy') {
|
||||||
|
log('MySQL process ready.');
|
||||||
|
return resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elapsedTime >= maxInterval)
|
||||||
|
reject(new Error(`MySQL not initialized whithin ${elapsedTime / 1000} secs`));
|
||||||
|
else
|
||||||
|
setTimeout(bindedChecker, interval);
|
||||||
|
}
|
||||||
|
let bindedChecker = checker.bind(this);
|
||||||
|
bindedChecker();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
wait() {
|
wait() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const mysql = require('mysql2');
|
const mysql = require('mysql2');
|
||||||
|
|
|
@ -83,6 +83,8 @@ async function backTestOnce(done) {
|
||||||
port: container.dbConf.port
|
port: container.dbConf.port
|
||||||
});
|
});
|
||||||
|
|
||||||
|
log('[Debug] dataSources', dataSources.vn);
|
||||||
|
|
||||||
let bootOptions = {dataSources};
|
let bootOptions = {dataSources};
|
||||||
|
|
||||||
let app = require(`./loopback/server/server`);
|
let app = require(`./loopback/server/server`);
|
||||||
|
@ -90,6 +92,8 @@ async function backTestOnce(done) {
|
||||||
try {
|
try {
|
||||||
app.boot(bootOptions);
|
app.boot(bootOptions);
|
||||||
|
|
||||||
|
log('[Debug] back started');
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
const jasmine = require('gulp-jasmine');
|
const jasmine = require('gulp-jasmine');
|
||||||
|
|
||||||
|
|
|
@ -84,6 +84,7 @@
|
||||||
"NO_AGENCY_AVAILABLE": "No hay una zona de reparto disponible con estos parámetros",
|
"NO_AGENCY_AVAILABLE": "No hay una zona de reparto disponible con estos parámetros",
|
||||||
"ERROR_PAST_SHIPMENT": "No puedes seleccionar una fecha de envío en pasado",
|
"ERROR_PAST_SHIPMENT": "No puedes seleccionar una fecha de envío en pasado",
|
||||||
"The current ticket can't be modified": "El ticket actual no puede ser modificado",
|
"The current ticket can't be modified": "El ticket actual no puede ser modificado",
|
||||||
|
"The current claim can't be modified": "La reclamación actual no puede ser modificada",
|
||||||
"The sales of this ticket can't be modified": "Las lineas de este ticket no pueden ser modificadas",
|
"The sales of this ticket can't be modified": "Las lineas de este ticket no pueden ser modificadas",
|
||||||
"Please select at least one sale": "Por favor selecciona al menos una linea",
|
"Please select at least one sale": "Por favor selecciona al menos una linea",
|
||||||
"All sales must belong to the same ticket": "Todas las lineas deben pertenecer al mismo ticket",
|
"All sales must belong to the same ticket": "Todas las lineas deben pertenecer al mismo ticket",
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethodCtx('isEditable', {
|
||||||
|
description: 'Check if a claim is editable',
|
||||||
|
accessType: 'READ',
|
||||||
|
accepts: [{
|
||||||
|
arg: 'id',
|
||||||
|
type: 'number',
|
||||||
|
required: true,
|
||||||
|
description: 'the claim id',
|
||||||
|
http: {source: 'path'}
|
||||||
|
}],
|
||||||
|
returns: {
|
||||||
|
type: 'boolean',
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/:id/isEditable`,
|
||||||
|
verb: 'get'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.isEditable = async(ctx, id) => {
|
||||||
|
const userId = ctx.req.accessToken.userId;
|
||||||
|
|
||||||
|
const isSalesAssistant = await Self.app.models.Account.hasRole(userId, 'salesAssistant');
|
||||||
|
|
||||||
|
let claim = await Self.app.models.Claim.findById(id, {
|
||||||
|
fields: ['claimStateFk'],
|
||||||
|
include: [{
|
||||||
|
relation: 'claimState'
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
|
||||||
|
const isClaimResolved = claim && claim.claimState().code == 'resolved';
|
||||||
|
|
||||||
|
if (!claim || (isClaimResolved && !isSalesAssistant))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,33 @@
|
||||||
|
const app = require('vn-loopback/server/server');
|
||||||
|
|
||||||
|
describe('claim isEditable()', () => {
|
||||||
|
const salesPerdonId = 18;
|
||||||
|
const salesAssistantId = 21;
|
||||||
|
it('should return false if the given claim does not exist', async() => {
|
||||||
|
let ctx = {req: {accessToken: {userId: salesAssistantId}}};
|
||||||
|
let result = await app.models.Claim.isEditable(ctx, 99999);
|
||||||
|
|
||||||
|
expect(result).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not be able to edit a resolved claim for a salesPerson', async() => {
|
||||||
|
let ctx = {req: {accessToken: {userId: salesPerdonId}}};
|
||||||
|
let result = await app.models.Claim.isEditable(ctx, 4);
|
||||||
|
|
||||||
|
expect(result).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to edit a resolved claim for a salesAssistant', async() => {
|
||||||
|
let ctx = {req: {accessToken: {userId: salesAssistantId}}};
|
||||||
|
let result = await app.models.Claim.isEditable(ctx, 4);
|
||||||
|
|
||||||
|
expect(result).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to edit a claim for a salesAssistant', async() => {
|
||||||
|
let ctx = {req: {accessToken: {userId: salesPerdonId}}};
|
||||||
|
let result = await app.models.Claim.isEditable(ctx, 1);
|
||||||
|
|
||||||
|
expect(result).toEqual(true);
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,7 +1,30 @@
|
||||||
|
|
||||||
|
const UserError = require('vn-loopback/util/user-error');
|
||||||
|
const LoopBackContext = require('loopback-context');
|
||||||
|
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
require('../methods/claim-beginning/importToNewRefundTicket')(Self);
|
require('../methods/claim-beginning/importToNewRefundTicket')(Self);
|
||||||
|
|
||||||
Self.validatesUniquenessOf('saleFk', {
|
Self.validatesUniquenessOf('saleFk', {
|
||||||
message: `A claim with that sale already exists`
|
message: `A claim with that sale already exists`
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Self.observe('before save', async ctx => {
|
||||||
|
if (ctx.isNewInstance) return;
|
||||||
|
await claimIsEditable(ctx);
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.observe('before delete', async ctx => {
|
||||||
|
if (ctx.isNewInstance) return;
|
||||||
|
await claimIsEditable(ctx);
|
||||||
|
});
|
||||||
|
|
||||||
|
async function claimIsEditable(ctx) {
|
||||||
|
const loopBackContext = LoopBackContext.getCurrentContext();
|
||||||
|
const httpCtx = {req: loopBackContext.active};
|
||||||
|
const isEditable = await Self.app.models.Claim.isEditable(httpCtx, ctx.where.id);
|
||||||
|
|
||||||
|
if (!isEditable)
|
||||||
|
throw new UserError(`The current claim can't be modified`);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,4 +6,5 @@ module.exports = Self => {
|
||||||
require('../methods/claim/regularizeClaim')(Self);
|
require('../methods/claim/regularizeClaim')(Self);
|
||||||
require('../methods/claim/uploadFile')(Self);
|
require('../methods/claim/uploadFile')(Self);
|
||||||
require('../methods/claim/updateClaimAction')(Self);
|
require('../methods/claim/updateClaimAction')(Self);
|
||||||
|
require('../methods/claim/isEditable')(Self);
|
||||||
};
|
};
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
<vn-input-number
|
<vn-input-number
|
||||||
min="0"
|
min="0"
|
||||||
step="1"
|
step="1"
|
||||||
|
disabled="!$ctrl.isRewritable"
|
||||||
ng-model="saleClaimed.quantity"
|
ng-model="saleClaimed.quantity"
|
||||||
on-change="$ctrl.setClaimedQuantity(saleClaimed.id, saleClaimed.quantity)"
|
on-change="$ctrl.setClaimedQuantity(saleClaimed.id, saleClaimed.quantity)"
|
||||||
class="dense">
|
class="dense">
|
||||||
|
@ -66,6 +67,7 @@
|
||||||
<vn-td shrink>
|
<vn-td shrink>
|
||||||
<vn-icon-button
|
<vn-icon-button
|
||||||
vn-tooltip="Remove sale"
|
vn-tooltip="Remove sale"
|
||||||
|
ng-if ="$ctrl.isRewritable"
|
||||||
icon="delete"
|
icon="delete"
|
||||||
ng-click="$ctrl.deleteClaimedSale($index)"
|
ng-click="$ctrl.deleteClaimedSale($index)"
|
||||||
tabindex="-1">
|
tabindex="-1">
|
||||||
|
@ -76,9 +78,13 @@
|
||||||
</vn-table>
|
</vn-table>
|
||||||
</vn-card>
|
</vn-card>
|
||||||
</vn-data-viewer>
|
</vn-data-viewer>
|
||||||
<a ng-click="$ctrl.openAddSalesDialog()" vn-tooltip="Add sale item" vn-bind="+" fixed-bottom-right>
|
<vn-float-button
|
||||||
<vn-float-button icon="add"></vn-float-button>
|
icon="add"
|
||||||
</a>
|
ng-if="$ctrl.isRewritable"
|
||||||
|
ng-click="$ctrl.openAddSalesDialog()"
|
||||||
|
vn-tooltip="Add sale item" vn-bind="+"
|
||||||
|
fixed-bottom-right>
|
||||||
|
</vn-float-button>
|
||||||
<!-- Add Lines Dialog -->
|
<!-- Add Lines Dialog -->
|
||||||
<vn-dialog vn-id="add-sales" class="modal-form">
|
<vn-dialog vn-id="add-sales" class="modal-form">
|
||||||
<tpl-title>
|
<tpl-title>
|
||||||
|
|
|
@ -28,6 +28,7 @@ class Controller extends Section {
|
||||||
if (value) {
|
if (value) {
|
||||||
this.calculateTotals();
|
this.calculateTotals();
|
||||||
this.isClaimEditable();
|
this.isClaimEditable();
|
||||||
|
this.isTicketEditable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +135,7 @@ class Controller extends Section {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
isClaimEditable() {
|
isTicketEditable() {
|
||||||
if (!this.claim) return;
|
if (!this.claim) return;
|
||||||
|
|
||||||
this.$http.get(`Tickets/${this.claim.ticketFk}/isEditable`).then(res => {
|
this.$http.get(`Tickets/${this.claim.ticketFk}/isEditable`).then(res => {
|
||||||
|
@ -142,6 +143,14 @@ class Controller extends Section {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isClaimEditable() {
|
||||||
|
if (!this.claim) return;
|
||||||
|
|
||||||
|
this.$http.get(`Claims/${this.claim.id}/isEditable`).then(res => {
|
||||||
|
this.isRewritable = res.data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
updateDiscount() {
|
updateDiscount() {
|
||||||
const claimedSale = this.saleClaimed.sale;
|
const claimedSale = this.saleClaimed.sale;
|
||||||
if (this.newDiscount != claimedSale.discount) {
|
if (this.newDiscount != claimedSale.discount) {
|
||||||
|
|
|
@ -17,9 +17,13 @@ describe('claim', () => {
|
||||||
$httpBackend = _$httpBackend_;
|
$httpBackend = _$httpBackend_;
|
||||||
$httpBackend.whenGET('Claims/ClaimBeginnings').respond({});
|
$httpBackend.whenGET('Claims/ClaimBeginnings').respond({});
|
||||||
$httpBackend.whenGET(`Tickets/1/isEditable`).respond(true);
|
$httpBackend.whenGET(`Tickets/1/isEditable`).respond(true);
|
||||||
|
$httpBackend.whenGET(`Claims/2/isEditable`).respond(true);
|
||||||
const $element = angular.element('<vn-claim-detail></vn-claim-detail>');
|
const $element = angular.element('<vn-claim-detail></vn-claim-detail>');
|
||||||
controller = $componentController('vnClaimDetail', {$element, $scope});
|
controller = $componentController('vnClaimDetail', {$element, $scope});
|
||||||
controller.claim = {ticketFk: 1};
|
controller.claim = {
|
||||||
|
ticketFk: 1,
|
||||||
|
id: 2}
|
||||||
|
;
|
||||||
controller.salesToClaim = [{saleFk: 1}, {saleFk: 2}];
|
controller.salesToClaim = [{saleFk: 1}, {saleFk: 2}];
|
||||||
controller.salesClaimed = [{id: 1, sale: {}}];
|
controller.salesClaimed = [{id: 1, sale: {}}];
|
||||||
controller.$.model = crudModel;
|
controller.$.model = crudModel;
|
||||||
|
@ -125,9 +129,9 @@ describe('claim', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('isClaimEditable()', () => {
|
describe('isTicketEditable()', () => {
|
||||||
it('should check if the claim is editable', () => {
|
it('should check if the ticket assigned to the claim is editable', () => {
|
||||||
controller.isClaimEditable();
|
controller.isTicketEditable();
|
||||||
$httpBackend.flush();
|
$httpBackend.flush();
|
||||||
|
|
||||||
expect(controller.isEditable).toBeTruthy();
|
expect(controller.isEditable).toBeTruthy();
|
||||||
|
|
|
@ -16,4 +16,3 @@ Search claim by id or client name: Buscar reclamaciones por identificador o nomb
|
||||||
Claim deleted!: Reclamación eliminada!
|
Claim deleted!: Reclamación eliminada!
|
||||||
claim: reclamación
|
claim: reclamación
|
||||||
Photos: Fotos
|
Photos: Fotos
|
||||||
|
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
const app = require('vn-loopback/server/server');
|
|
||||||
|
|
||||||
// #2294 - TLS version error
|
|
||||||
xdescribe('client sendSms()', () => {
|
|
||||||
let createdLog;
|
|
||||||
|
|
||||||
afterAll(async done => {
|
|
||||||
await app.models.ClientLog.destroyById(createdLog.id);
|
|
||||||
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should send a message and log it', async() => {
|
|
||||||
let ctx = {req: {accessToken: {userId: 9}}};
|
|
||||||
let id = 101;
|
|
||||||
let destination = 222222222;
|
|
||||||
let message = 'this is the message created in a test';
|
|
||||||
|
|
||||||
let sms = await app.models.Client.sendSms(ctx, id, destination, message);
|
|
||||||
|
|
||||||
logId = sms.logId;
|
|
||||||
|
|
||||||
createdLog = await app.models.ClientLog.findById(logId);
|
|
||||||
let json = JSON.parse(JSON.stringify(createdLog.newInstance));
|
|
||||||
|
|
||||||
expect(json.message).toEqual(message);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,38 +0,0 @@
|
||||||
const app = require('vn-loopback/server/server');
|
|
||||||
const soap = require('soap');
|
|
||||||
|
|
||||||
// #2294 - TLS version error
|
|
||||||
xdescribe('sms send()', () => {
|
|
||||||
it('should return the expected message and status code', async() => {
|
|
||||||
const code = 200;
|
|
||||||
const smsConfig = await app.models.SmsConfig.findOne();
|
|
||||||
const soapClient = await soap.createClientAsync(smsConfig.uri);
|
|
||||||
spyOn(soap, 'createClientAsync').and.returnValue(soapClient);
|
|
||||||
spyOn(soapClient, 'sendSMSAsync').and.returnValue([{
|
|
||||||
result: {
|
|
||||||
$value:
|
|
||||||
`<xtratelecom-sms-response>
|
|
||||||
<sms>
|
|
||||||
<codigo>
|
|
||||||
${code}
|
|
||||||
</codigo>
|
|
||||||
<descripcion>
|
|
||||||
Envio en procesamiento
|
|
||||||
</descripcion>
|
|
||||||
<messageId>
|
|
||||||
1
|
|
||||||
</messageId>
|
|
||||||
</sms>
|
|
||||||
<procesoId>
|
|
||||||
444328681
|
|
||||||
</procesoId>
|
|
||||||
</xtratelecom-sms-response>`
|
|
||||||
}
|
|
||||||
}]);
|
|
||||||
let ctx = {req: {accessToken: {userId: 1}}};
|
|
||||||
let result = await app.models.Sms.send(ctx, 105, 'destination', 'My SMS Body');
|
|
||||||
|
|
||||||
expect(result.statusCode).toEqual(200);
|
|
||||||
expect(result.status).toContain('Fake response');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,28 +0,0 @@
|
||||||
const app = require('vn-loopback/server/server');
|
|
||||||
|
|
||||||
// #2294 - TLS version error
|
|
||||||
xdescribe('ticket sendSms()', () => {
|
|
||||||
let logId;
|
|
||||||
|
|
||||||
afterAll(async done => {
|
|
||||||
await app.models.TicketLog.destroyById(logId);
|
|
||||||
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should send a message and log it', async() => {
|
|
||||||
let ctx = {req: {accessToken: {userId: 9}}};
|
|
||||||
let id = 11;
|
|
||||||
let destination = 222222222;
|
|
||||||
let message = 'this is the message created in a test';
|
|
||||||
|
|
||||||
let sms = await app.models.Ticket.sendSms(ctx, id, destination, message);
|
|
||||||
|
|
||||||
logId = sms.logId;
|
|
||||||
|
|
||||||
let createdLog = await app.models.TicketLog.findById(logId);
|
|
||||||
let json = JSON.parse(JSON.stringify(createdLog.newInstance));
|
|
||||||
|
|
||||||
expect(json.message).toEqual(message);
|
|
||||||
});
|
|
||||||
});
|
|
Loading…
Reference in New Issue