Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into dev
gitea/salix/dev This commit looks good Details

This commit is contained in:
Carlos Jimenez Ruiz 2019-03-29 10:51:13 +01:00
commit d2331ccd68
47 changed files with 273 additions and 77 deletions

View File

@ -1 +0,0 @@
INSERT INTO `vn`.`smsConfig` (`id`, `uri`, `user`, `password`, `title`) VALUES ('1', 'https://websms.xtratelecom.es/api_php/server.wsdl', 'FERRERTORIBIO', 'HERMANOS', 'Verdnatura');

View File

@ -71,6 +71,6 @@ describe('Item log path', () => {
const fifthLineCreatedProperty = await nightmare
.waitToGetProperty(selectors.itemLog.fifthLineCreatedProperty, 'innerText');
expect(fifthLineCreatedProperty).toEqual('5080000');
expect(fifthLineCreatedProperty).toEqual('Coral y materiales similares');
});
});

View File

@ -14,10 +14,6 @@ export default class Textfield extends Input {
this.hasFocus = false;
this.hasMouseIn = false;
this.input.addEventListener('keydown', () => {
if (!this.oldValue)
this.saveOldValue();
});
this.input.addEventListener('keyup', e => {
if (e.defaultPrevented || e.key != 'Escape')
return;

View File

@ -92,6 +92,8 @@ module.exports = function(Self) {
newInstance: {}
};
delete instance.originFk;
let logModel = definition.settings.log.model;
await ctx.Model.app.models[logModel].create(logRecord, options);
});
@ -111,10 +113,28 @@ module.exports = function(Self) {
let val1 = ctx.Model.relations[key1];
if (val1.keyFrom == key && key != 'id') {
let recordSet = await ctx.Model.app.models[val1.modelTo.modelName].findById(val, options);
let definition = val1.modelTo.definition;
let changedModelValue = definition.settings.log && definition.settings.log.changedModelValue;
val = (changedModelValue && recordSet && recordSet[changedModelValue]) || (recordSet && recordSet.id) || val; // FIXME preparar todos los modelos con campo name
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) {
const showFieldNames = [
'name',
'description',
'code'
];
for (field of showFieldNames) {
if (val1.modelTo.definition.properties && val1.modelTo.definition.properties[field] && recordSet && recordSet[field]) {
showField = field;
break;
}
}
}
if (showField) {
val = recordSet[showField];
break;
}
val = recordSet && recordSet.id; // FIXME preparar todos los modelos con campo name
break;
}
}
@ -161,18 +181,18 @@ module.exports = function(Self) {
}
// Sets the changedModelValue to save and the instances changed in case its an updateAll
let changedModelValue = definition.settings.log.changedModelValue;
let showField = definition.settings.log.showField;
let where;
if (changedModelValue && (!ctx.instance || !ctx.instance[changedModelValue]) && ctx.where) {
if (showField && (!ctx.instance || !ctx.instance[showField]) && ctx.where) {
changedModelId = [];
where = [];
let changedInstances = await ctx.Model.app.models[definition.name].find({where: ctx.where, fields: ['id', changedModelValue]}, options);
let changedInstances = await ctx.Model.app.models[definition.name].find({where: ctx.where, fields: ['id', showField]}, options);
changedInstances.forEach(element => {
where.push(element[changedModelValue]);
where.push(element[showField]);
changedModelId.push(element.id);
});
} else if (ctx.hookState.oldInstance)
where = ctx.instance[changedModelValue];
where = ctx.instance[showField];
// Set oldInstance, newInstance, userFk and action

View File

@ -5,7 +5,7 @@
"log": {
"model": "ClientLog",
"relation": "client",
"changedModelValue": "nickname"
"showField": "nickname"
},
"options": {
"mysql": {

View File

@ -5,7 +5,7 @@
"log": {
"model": "ClientLog",
"relation": "client",
"changedModelValue": "name"
"showField": "name"
},
"options": {
"mysql": {

View File

@ -4,7 +4,7 @@
"log": {
"model": "ClientLog",
"relation": "client",
"changedModelValue": "type"
"showField": "type"
},
"options": {
"mysql": {

View File

@ -2,7 +2,8 @@
"name": "Client",
"base": "Loggable",
"log": {
"model":"ClientLog"
"model":"ClientLog",
"showField": "id"
},
"options": {
"mysql": {

View File

@ -4,7 +4,7 @@
"log": {
"model": "ClientLog",
"relation": "client",
"changedModelValue": "description"
"showField": "description"
},
"options": {
"mysql": {

View File

@ -34,3 +34,5 @@ import './sample/index';
import './sample/create';
import './web-payment';
import './log';
import './sms';

View File

@ -0,0 +1,23 @@
<vn-dialog
vn-id="SMSDialog"
on-response="$ctrl.onResponse(response)">
<tpl-body>
<h5 pad-small-v translate>Send SMS</h5>
<vn-horizontal>
<vn-textfield vn-one
label="Recipient"
model="$ctrl.sms.recipient">
</vn-textfield>
</vn-horizontal>
<vn-horizontal >
<vn-textarea vn-one
label="Message"
field="$ctrl.sms.message">
</vn-textarea>
</vn-horizontal>
</tpl-body>
<tpl-buttons>
<input type="button" response="CANCEL" translate-attr="{value: 'Cancel'}"/>
<button response="ACCEPT" translate>Send</button>
</tpl-buttons>
</vn-dialog>

View File

@ -0,0 +1,42 @@
import ngModule from '../module';
import Component from 'core/lib/component';
import './style.scss';
class Controller extends Component {
constructor($element, $scope, $http, $translate, vnApp) {
super($element, $scope);
this.$scope = $scope;
this.$http = $http;
this.$translate = $translate;
this.vnApp = vnApp;
}
open() {
this.$scope.SMSDialog.show();
}
onResponse(response) {
if (response === 'ACCEPT') {
let params = {
recipient: this.sms.recipient,
message: this.sms.message
};
this.$http.post(`/client/api/Sms/send`, params).then(res => {
this.vnApp.showMessage(this.$translate.instant('SMS sent!'));
if (res.data) this.emit('send', {response: res.data});
});
}
}
}
Controller.$inject = ['$element', '$scope', '$http', '$translate', 'vnApp'];
ngModule.component('vnClientSms', {
template: require('./index.html'),
controller: Controller,
bindings: {
sms: '<',
}
});

View File

@ -0,0 +1,34 @@
import './index';
describe('Client', () => {
describe('Component vnClientSms', () => {
let controller;
let $httpBackend;
let $element;
beforeEach(ngModule('client'));
beforeEach(angular.mock.inject(($componentController, _$httpBackend_) => {
$httpBackend = _$httpBackend_;
$element = angular.element('<vn-dialog></vn-dialog>');
controller = $componentController('vnClientSms', {$element});
controller.client = {id: 101};
}));
describe('onResponse()', () => {
it('should perform a POST query and show a success snackbar', () => {
let params = {recipient: 111111111, message: 'My SMS'};
controller.sms = {recipient: 111111111, message: 'My SMS'};
spyOn(controller.vnApp, 'showMessage');
$httpBackend.when('POST', `/client/api/Sms/send`, params).respond(200, params);
$httpBackend.expect('POST', `/client/api/Sms/send`, params).respond(params);
controller.onResponse('ACCEPT');
$httpBackend.flush();
expect(controller.vnApp.showMessage).toHaveBeenCalledWith('SMS sent!');
});
});
});
});

View File

@ -0,0 +1,4 @@
Send SMS: Enviar SMS
Recipient: Destinatario
Message: Mensaje
SMS sent!: ¡SMS enviado!

View File

@ -0,0 +1,7 @@
@import "variables";
vn-client-sms {
textarea {
height: 8em
}
}

View File

@ -4,7 +4,7 @@
"log": {
"model": "ItemLog",
"relation": "item",
"changedModelValue": "code"
"showField": "code"
},
"options": {
"mysql": {

View File

@ -4,7 +4,7 @@
"log": {
"model": "ItemLog",
"relation": "item",
"changedModelValue": "botanical"
"showField": "botanical"
},
"options": {
"mysql": {

View File

@ -4,7 +4,7 @@
"log": {
"model": "ItemLog",
"relation": "item",
"changedModelValue": "code"
"showField": "code"
},
"options": {
"mysql": {

View File

@ -4,7 +4,7 @@
"log": {
"model": "ItemLog",
"relation": "item",
"changedModelValue": "value"
"showField": "value"
},
"options": {
"mysql": {

View File

@ -1,7 +1,7 @@
<vn-horizontal>
<vn-one>{{::$ctrl.title}}</vn-one>
<vn-one title="{{::$ctrl.item.name}}">{{::$ctrl.item.name}}</vn-one>
<vn-one ng-if="$ctrl.subName">
<h3>{{::$ctrl.subName}}</h3>
<h3 title="{{::$ctrl.subName}}">{{::$ctrl.subName}}</h3>
</vn-one>
<vn-auto>
<section

View File

@ -20,20 +20,20 @@
<vn-table model="model" auto-load="false" show-fields="$ctrl.showFields" vn-uvc="itemIndex">
<vn-thead>
<vn-tr>
<vn-th th-id="picture"></vn-th>
<vn-th field="id" number>Id</vn-th>
<vn-th th-id="grouping" number>Grouping</vn-th>
<vn-th th-id="packing" number>Packing</vn-th>
<vn-th th-id="picture" shrink></vn-th>
<vn-th field="id" shrink>Id</vn-th>
<vn-th th-id="grouping" shrink>Grouping</vn-th>
<vn-th th-id="packing" shrink>Packing</vn-th>
<vn-th th-id="description" style="text-align: center">Description</vn-th>
<vn-th th-id="stems" number>Stems</vn-th>
<vn-th th-id="size"number>Size</vn-th>
<vn-th th-id="niche"number>Niche</vn-th>
<vn-th th-id="type">Type</vn-th>
<vn-th th-id="category">Category</vn-th>
<vn-th th-id="intrastat">Intrastat</vn-th>
<vn-th th-id="origin">Origin</vn-th>
<vn-th th-id="salesperson">Buyer</vn-th>
<vn-th th-id="density" number>Density</vn-th>
<vn-th th-id="stems" shrink>Stems</vn-th>
<vn-th th-id="size" shrink>Size</vn-th>
<vn-th th-id="niche" shrink>Niche</vn-th>
<vn-th th-id="type" shrink>Type</vn-th>
<vn-th th-id="category" shrink>Category</vn-th>
<vn-th th-id="intrastat" shrink>Intrastat</vn-th>
<vn-th th-id="origin" shrink>Origin</vn-th>
<vn-th th-id="salesperson" shrink>Buyer</vn-th>
<vn-th th-id="density" shrink>Density</vn-th>
<vn-th th-id="active" shrink>Active</vn-th>
<vn-th></vn-th>
</vn-tr>
@ -49,38 +49,43 @@
ng-click="$ctrl.stopEvent($event)"
on-error-src/>
</vn-td>
<vn-td number>
<vn-td shrink>
<span
class="link"
ng-click="$ctrl.showItemDescriptor($event, item.id)">
{{::item.id | zeroFill:6}}
</span>
</vn-td>
<vn-td number>{{::item.grouping | dashIfEmpty}}</vn-td>
<vn-td number>{{::item.packing | dashIfEmpty}}</vn-td>
<vn-td shrink>{{::item.grouping | dashIfEmpty}}</vn-td>
<vn-td shrink>{{::item.packing | dashIfEmpty}}</vn-td>
<vn-td expand>
<vn-fetched-tags
max-length="6"
item="::item"
title="::item.name"
sub-name="::item.subName">
</vn-fetched-tags>
</vn-td>
<vn-td number>{{::item.stems}}</vn-td>
<vn-td number>{{::item.size}}</vn-td>
<vn-td number>{{::item.niche}}</vn-td>
<vn-td>{{::item.type}}</vn-td>
<vn-td>{{::item.category}}</vn-td>
<vn-td>{{::item.intrastat}}</vn-td>
<vn-td>{{::item.origin}}</vn-td>
<vn-td expand>
<vn-td shrink>{{::item.stems}}</vn-td>
<vn-td shrink>{{::item.size}}</vn-td>
<vn-td shrink>{{::item.niche}}</vn-td>
<vn-td shrink title="{{::item.type}}">
{{::item.type}}
</vn-td>
<vn-td shrink title="{{::item.category}}">
{{::item.category}}
</vn-td>
<vn-td shrink title="{{::item.intrastat}}">
{{::item.intrastat}}
</vn-td>
<vn-td shrink>{{::item.origin}}</vn-td>
<vn-td shrink title="{{::item.userNickname}}">
<span
class="link"
ng-click="$ctrl.showWorkerDescriptor($event, item.userId)">
{{::item.userNickname}}
</span>
</vn-td>
<vn-td number>{{::item.density}}</vn-td>
<vn-td shrink>{{::item.density}}</vn-td>
<vn-td shrink>
<vn-check
disabled="true"

View File

@ -43,7 +43,6 @@
<vn-fetched-tags
max-length="6"
item="::row.item"
title="::row.item.name"
sub-name="::row.item.subName">
</vn-fetched-tags>
</vn-td>

View File

@ -72,7 +72,6 @@
<vn-fetched-tags
max-length="6"
item="::row.item"
title="::row.item.name"
sub-name="::row.item.subName">
</vn-fetched-tags>
</vn-td>

View File

@ -42,7 +42,6 @@
<vn-fetched-tags
max-length="6"
item="::row.item"
title="::row.item.name"
sub-name="::row.item.subName">
</vn-fetched-tags>
</vn-td>

View File

@ -1,7 +1,7 @@
const app = require('vn-loopback/server/server');
describe('route summary()', () => {
it('should return a summary object containing data freom his tickets', async() => {
it('should return a summary object containing data from his tickets', async() => {
let result = await app.models.Route.getTickets(1);
expect(result[2].id).toEqual(11);

View File

@ -8,7 +8,7 @@ describe('route summary()', () => {
expect(result.route.workerFk).toEqual(56);
});
it('should return a summary object containing data freom his tickets', async() => {
it('should return a summary object containing data from his tickets', async() => {
let result = await app.models.Route.summary(1);
expect(result.tickets[2].id).toEqual(11);

View File

@ -1,6 +1,10 @@
{
"name": "TicketObservation",
"base": "VnModel",
"base": "Loggable",
"log": {
"model": "TicketLog",
"relation": "ticket"
},
"options": {
"mysql": {
"table": "ticketObservation"

View File

@ -3,8 +3,7 @@
"base": "Loggable",
"log": {
"model": "TicketLog",
"relation": "ticket",
"changedModelValue": "description"
"relation": "ticket"
},
"options": {
"mysql": {

View File

@ -4,7 +4,7 @@
"log": {
"model": "TicketLog",
"relation": "ticket",
"changedModelValue": "description"
"showField": "description"
},
"options": {
"mysql": {

View File

@ -4,7 +4,7 @@
"log": {
"model": "TicketLog",
"relation": "ticket",
"changedModelValue": "stateFk"
"showField": "stateFk"
},
"options": {
"mysql": {

View File

@ -4,7 +4,7 @@
"log": {
"model": "TicketLog",
"relation": "ticket",
"changedModelValue": "ticketFk"
"showField": "ticketFk"
},
"options": {
"mysql": {

View File

@ -7,6 +7,7 @@ class Controller {
this.filter = {
include: [
{relation: 'warehouse', scope: {fields: ['name']}},
{relation: 'address'},
{relation: 'ship'},
{relation: 'agencyMode', scope: {fields: ['name']}},
{relation: 'stowaway'},

View File

@ -51,7 +51,6 @@
<vn-fetched-tags
max-length="6"
item="::sale.item"
title="::sale.concept"
sub-name="::sale.item.subName">
</vn-fetched-tags>
</td>

View File

@ -18,8 +18,7 @@
<td expand>
<vn-fetched-tags
max-length="6"
item="::sale.item"
title="::sale.concept">
item="::sale.item">
</vn-fetched-tags>
</td>
<td number>{{::sale.quantity}}</td>

View File

@ -177,4 +177,8 @@
<input type="button" response="CANCEL" translate-attr="{value: 'Cancel'}"/>
<button response="ACCEPT" translate>Save</button>
</tpl-buttons>
</vn-dialog>
</vn-dialog>
<!-- SMS Dialog -->
<vn-client-sms vn-id="sms" sms="$ctrl.newSMS"></vn-client-sms>
<!-- SMS Dialog -->

View File

@ -13,7 +13,8 @@ class Controller {
{callback: this.showRemoveStowaway, name: 'Remove stowaway', show: () => this.shouldShowRemoveStowaway()},
{callback: this.showDeliveryNote, name: 'Show Delivery Note', show: true},
{callback: this.showDeleteTicketDialog, name: 'Delete ticket', show: true},
{callback: this.showChangeShipped, name: 'Change shipped hour', show: true}
{callback: this.showChangeShipped, name: 'Change shipped hour', show: true},
{callback: this.showSMSDialog, name: 'Send SMS', show: true}
];
}
@ -163,6 +164,15 @@ class Controller {
let url = `/api/report/rpt-delivery-note?ticketFk=${this.ticket.id}`;
window.open(url);
}
showSMSDialog() {
const address = this.ticket.address;
this.newSMS = {
recipient: address.mobile || null,
message: this.$translate.instant('SMSPayment')
};
this.$scope.sms.open();
}
}
Controller.$inject = ['$state', '$scope', '$http', 'vnApp', '$translate'];

View File

@ -0,0 +1,3 @@
SMSPayment: >-
Verdnatura communicates: Your order is pending of payment.
Please, enter the web page and make the payment with card. Thank you.

View File

@ -9,4 +9,7 @@ Remove stowaway: Borrar polizón
Are you sure you want to delete this stowaway?: ¿Estas seguro de que quieres borrar este polizón?
Show Delivery Note: Ver albarán
Change shipped hour: Cambiar hora de envío
Shipped hour: Hora de envío
Shipped hour: Hora de envío
SMSPayment: >-
Verdnatura le comunica: Su pedido está pendiente de pago.
Por favor, entre en la página web y efectue el pago con tarjeta. Muchas gracias.

View File

@ -37,7 +37,6 @@
<vn-fetched-tags
max-length="6"
item="::sale.item"
title="::sale.concept"
sub-name="::sale.item.subName">
</vn-fetched-tags>
</vn-td>

View File

@ -41,7 +41,6 @@
<vn-fetched-tags
max-length="6"
item="::sale.item"
title="::sale.concept"
sub-name="::sale.item.subName">
</vn-fetched-tags>
</vn-td>

View File

@ -121,7 +121,6 @@
<vn-fetched-tags
max-length="6"
item="::sale.tags"
title="::sale.concept"
sub-name="::sale.subName">
</vn-fetched-tags>
</vn-td>
@ -285,6 +284,10 @@
</vn-horizontal>
</div>
</vn-popover>
<!-- SMS Dialog -->
<vn-client-sms vn-id="sms" sms="$ctrl.newSMS"></vn-client-sms>
<!-- SMS Dialog -->
</vn-vertical>
<vn-confirm
vn-id="delete-lines"

View File

@ -15,7 +15,8 @@ class Controller {
{callback: this.markAsReserved, name: 'Mark as reserved'},
{callback: this.unmarkAsReserved, name: 'Unmark as reserved'},
{callback: this.showEditDialog, name: 'Update discount'},
{callback: this.createClaim, name: 'Add claim'}
{callback: this.createClaim, name: 'Add claim'},
{callback: this.showSMSDialog, name: 'Send SMS'}
];
this.imagesPath = '//verdnatura.es/vn-image-data/catalog';
@ -315,6 +316,26 @@ class Controller {
this.vnApp.showSuccess(this.$translate.instant('Order created'));
});
}
showSMSDialog() {
const address = this.ticket.address;
const lines = this.getCheckedLines();
const items = lines.map(line => {
const instance = this.sales[line.instance];
return `${instance.quantity} ${instance.concept}`;
});
const notAvailables = items.join(', ');
const params = {
ticketFk: this.ticket.id,
created: this.ticket.created,
notAvailables
};
this.newSMS = {
recipient: address.mobile || null,
message: this.$translate.instant('SMSAvailability', params)
};
this.$scope.sms.open();
}
}
Controller.$inject = ['$scope', '$state', '$http', 'vnApp', '$translate'];

View File

@ -11,16 +11,20 @@ describe('Ticket', () => {
id: 1,
clientFk: 1,
shipped: 1,
client: {salesPersonFk: 1}
created: new Date(),
client: {salesPersonFk: 1},
address: {mobile: 111111111}
};
let sales = [
{
id: 1,
concept: 'Item 1',
quantity: 5,
price: 23.5,
discount: 0
}, {
id: 4,
concept: 'Item 2',
quantity: 20,
price: 5.5,
discount: 0
@ -30,6 +34,7 @@ describe('Ticket', () => {
beforeEach(() => {
ngModule('item');
ngModule('ticket');
ngModule('client');
});
beforeEach(angular.mock.inject(($compile, $rootScope, $state, _$httpBackend_) => {
@ -166,5 +171,18 @@ describe('Ticket', () => {
$httpBackend.flush();
});
});
describe('showSMSDialog()', () => {
it('should open an SMS dialog with specified data', () => {
spyOn(controller.$scope.sms, 'open');
controller.sales[1].checked = true;
controller.showSMSDialog();
expect(controller.$scope.sms.open).toHaveBeenCalledWith();
expect(controller.newSMS.recipient).toEqual(111111111);
expect(controller.newSMS.message).not.toEqual('');
});
});
});
});

View File

@ -0,0 +1,3 @@
SMSAvailability: >-
Verdnatura communicates: Your order {{ticketFk}} created on {{created | date: "dd/MM/yyyy"}}.
{{notAvailables}} not available. Sorry for the inconvenience.

View File

@ -28,3 +28,6 @@ Claim: Reclamación
Transfer lines: Transferir líneas
Change ticket state to 'Ok': Cambiar estado del ticket a 'Ok'
Reserved: Reservado
SMSAvailability: >-
Verdnatura le comunica: Pedido {{ticketFk}} día {{created | date: "dd/MM/yyyy"}}.
{{notAvailables}} no disponible/s. Disculpe las molestias.

View File

@ -100,8 +100,7 @@
<vn-td expand>
<vn-fetched-tags
max-length="6"
item="::sale.item"
title="::sale.concept"
item="::sale.item"
sub-name="::sale.item.subName"/>
</vn-td>
<vn-td number>{{::sale.price | currency: 'EUR':2}}</vn-td>

View File

@ -45,8 +45,7 @@
<vn-td expand>
<vn-fetched-tags
max-length="6"
item="::sale.item"
title="::sale.concept"
item="::sale.item"
sub-name="::sale.item.subName"/>
</vn-td>
<vn-td number>{{::sale.quantity}}</vn-td>