Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 2319_show_delivery_note

This commit is contained in:
Carlos Jimenez Ruiz 2020-06-17 09:22:09 +02:00
commit fb37e156d4
14 changed files with 171 additions and 106 deletions

View File

@ -39,7 +39,8 @@ module.exports = class Docker {
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;
try {
@ -53,7 +54,7 @@ module.exports = class Docker {
this.dbConf.port = netSettings.Ports['3306/tcp'][0]['HostPort'];
}
if (runChown) await this.wait();
await this.waitForHealthy();
} catch (err) {
if (this.isRandom)
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() {
return new Promise((resolve, reject) => {
const mysql = require('mysql2');

View File

@ -83,6 +83,8 @@ async function backTestOnce(done) {
port: container.dbConf.port
});
log('[Debug] dataSources', dataSources.vn);
let bootOptions = {dataSources};
let app = require(`./loopback/server/server`);
@ -90,6 +92,8 @@ async function backTestOnce(done) {
try {
app.boot(bootOptions);
log('[Debug] back started');
await new Promise((resolve, reject) => {
const jasmine = require('gulp-jasmine');

View File

@ -84,6 +84,7 @@
"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",
"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",
"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",

View File

@ -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;
};
};

View File

@ -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);
});
});

View File

@ -1,7 +1,30 @@
const UserError = require('vn-loopback/util/user-error');
const LoopBackContext = require('loopback-context');
module.exports = Self => {
require('../methods/claim-beginning/importToNewRefundTicket')(Self);
Self.validatesUniquenessOf('saleFk', {
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`);
}
};

View File

@ -6,4 +6,5 @@ module.exports = Self => {
require('../methods/claim/regularizeClaim')(Self);
require('../methods/claim/uploadFile')(Self);
require('../methods/claim/updateClaimAction')(Self);
require('../methods/claim/isEditable')(Self);
};

View File

@ -40,6 +40,7 @@
<vn-input-number
min="0"
step="1"
disabled="!$ctrl.isRewritable"
ng-model="saleClaimed.quantity"
on-change="$ctrl.setClaimedQuantity(saleClaimed.id, saleClaimed.quantity)"
class="dense">
@ -66,6 +67,7 @@
<vn-td shrink>
<vn-icon-button
vn-tooltip="Remove sale"
ng-if ="$ctrl.isRewritable"
icon="delete"
ng-click="$ctrl.deleteClaimedSale($index)"
tabindex="-1">
@ -76,9 +78,13 @@
</vn-table>
</vn-card>
</vn-data-viewer>
<a ng-click="$ctrl.openAddSalesDialog()" vn-tooltip="Add sale item" vn-bind="+" fixed-bottom-right>
<vn-float-button icon="add"></vn-float-button>
</a>
<vn-float-button
icon="add"
ng-if="$ctrl.isRewritable"
ng-click="$ctrl.openAddSalesDialog()"
vn-tooltip="Add sale item" vn-bind="+"
fixed-bottom-right>
</vn-float-button>
<!-- Add Lines Dialog -->
<vn-dialog vn-id="add-sales" class="modal-form">
<tpl-title>

View File

@ -28,6 +28,7 @@ class Controller extends Section {
if (value) {
this.calculateTotals();
this.isClaimEditable();
this.isTicketEditable();
}
}
@ -134,7 +135,7 @@ class Controller extends Section {
});
}
isClaimEditable() {
isTicketEditable() {
if (!this.claim) return;
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() {
const claimedSale = this.saleClaimed.sale;
if (this.newDiscount != claimedSale.discount) {

View File

@ -17,9 +17,13 @@ describe('claim', () => {
$httpBackend = _$httpBackend_;
$httpBackend.whenGET('Claims/ClaimBeginnings').respond({});
$httpBackend.whenGET(`Tickets/1/isEditable`).respond(true);
$httpBackend.whenGET(`Claims/2/isEditable`).respond(true);
const $element = angular.element('<vn-claim-detail></vn-claim-detail>');
controller = $componentController('vnClaimDetail', {$element, $scope});
controller.claim = {ticketFk: 1};
controller.claim = {
ticketFk: 1,
id: 2}
;
controller.salesToClaim = [{saleFk: 1}, {saleFk: 2}];
controller.salesClaimed = [{id: 1, sale: {}}];
controller.$.model = crudModel;
@ -125,9 +129,9 @@ describe('claim', () => {
});
});
describe('isClaimEditable()', () => {
it('should check if the claim is editable', () => {
controller.isClaimEditable();
describe('isTicketEditable()', () => {
it('should check if the ticket assigned to the claim is editable', () => {
controller.isTicketEditable();
$httpBackend.flush();
expect(controller.isEditable).toBeTruthy();

View File

@ -15,5 +15,4 @@ Show Pickup order: Ver orden de recogida
Search claim by id or client name: Buscar reclamaciones por identificador o nombre de cliente
Claim deleted!: Reclamación eliminada!
claim: reclamación
Photos: Fotos
Photos: Fotos

View File

@ -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);
});
});

View File

@ -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');
});
});

View File

@ -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);
});
});