Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 2665-route_index_multi_clone
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
This commit is contained in:
commit
e6106b1aa9
|
@ -1 +1,2 @@
|
|||
INSERT INTO salix.ACL (model, property, accessType, permission, principalType, principalId) VALUES ('Image', '*', 'WRITE', 'ALLOW', 'ROLE', 'employee')
|
||||
INSERT INTO salix.ACL (model, property, accessType, permission, principalType, principalId) VALUES ('Image', '*', 'WRITE', 'ALLOW', 'ROLE', 'employee');
|
||||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('PayDem', '*', 'READ', 'ALLOW', 'ROLE', 'employee');
|
|
@ -0,0 +1,14 @@
|
|||
CREATE TABLE `vn`.`entryObservation` (
|
||||
id int NOT NULL AUTO_INCREMENT,
|
||||
entryFk int NOT NULL,
|
||||
observationTypeFk TINYINT(3) UNSIGNED,
|
||||
description TEXT,
|
||||
PRIMARY KEY (id),
|
||||
CONSTRAINT entry_id_entryFk
|
||||
FOREIGN KEY (entryFk) REFERENCES entry(id),
|
||||
CONSTRAINT observationType_id_observationTypeFk
|
||||
FOREIGN KEY (observationTypeFk) REFERENCES observationType(id)
|
||||
);
|
||||
|
||||
ALTER TABLE `vn`.`entryObservation`
|
||||
ADD UNIQUE INDEX `entryFk_observationTypeFk_UNIQUE` (`entryFk` ASC,`observationTypeFk` ASC);
|
|
@ -1,2 +0,0 @@
|
|||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||
VALUES ('PayDem', '*', 'READ', 'ALLOW', 'ROLE', 'employee');
|
|
@ -1638,7 +1638,7 @@ INSERT INTO `vn`.`orderTicket`(`orderFk`, `ticketFk`)
|
|||
|
||||
INSERT INTO `vn`.`userConfig` (`userFk`, `warehouseFk`, `companyFk`)
|
||||
VALUES
|
||||
(1, 2, 69),
|
||||
(1, 1, 69),
|
||||
(5, 1, 442),
|
||||
(9, 1, 442),
|
||||
(18, 3, 567);
|
||||
|
|
|
@ -71,7 +71,7 @@ describe('User config', () => {
|
|||
expect(expectedLocalWarehouse).toBeTruthy();
|
||||
expect(expectedLocalBank).toBeTruthy();
|
||||
expect(expectedLocalCompany).toBeTruthy();
|
||||
expect(userWarehouse).toEqual('Warehouse Two');
|
||||
expect(userWarehouse).toEqual('Warehouse One');
|
||||
expect(userCompany).toEqual('CCs');
|
||||
});
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ import './style.scss';
|
|||
|
||||
export default class DescriptorPopover extends Popover {
|
||||
show(parent, id) {
|
||||
if (!id) return;
|
||||
|
||||
super.show(parent);
|
||||
|
||||
this.id = id;
|
||||
|
|
|
@ -7,5 +7,8 @@
|
|||
},
|
||||
"EntryLog": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"EntryObservation": {
|
||||
"dataSource": "vn"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
const UserError = require('vn-loopback/util/user-error');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.rewriteDbError(function(err) {
|
||||
if (err.code === 'ER_DUP_ENTRY')
|
||||
return new UserError(`The observation type can't be repeated`);
|
||||
return err;
|
||||
});
|
||||
};
|
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"name": "EntryObservation",
|
||||
"base": "Loggable",
|
||||
"log": {
|
||||
"model": "EntryLog",
|
||||
"relation": "entry"
|
||||
},
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "entryObservation"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "Number",
|
||||
"description": "Identifier"
|
||||
},
|
||||
"description": {
|
||||
"type": "String",
|
||||
"required": true
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"entry": {
|
||||
"type": "belongsTo",
|
||||
"model": "Entry",
|
||||
"foreignKey": "entryFk"
|
||||
},
|
||||
"observationType": {
|
||||
"type": "belongsTo",
|
||||
"model": "ObservationType",
|
||||
"foreignKey": "observationTypeFk",
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ import './latest-buys-search-panel';
|
|||
import './descriptor';
|
||||
import './descriptor-popover';
|
||||
import './card';
|
||||
import './note';
|
||||
import './summary';
|
||||
import './log';
|
||||
import './buy';
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="EntryObservations"
|
||||
fields="['id', 'entryFk', 'observationTypeFk', 'description']"
|
||||
link="{entryFk: $ctrl.$params.id}"
|
||||
data="observations"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<vn-crud-model
|
||||
url="ObservationTypes"
|
||||
data="observationTypes"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
data="observations"
|
||||
form="form">
|
||||
</vn-watcher>
|
||||
<form name="form" ng-submit="$ctrl.onSubmit()" class="vn-w-md">
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-one class="vn-mt-md">
|
||||
<vn-horizontal ng-repeat="observation in observations track by $index">
|
||||
<vn-autocomplete
|
||||
ng-attr-disabled="observation.id ? true : false"
|
||||
ng-model="observation.observationTypeFk"
|
||||
data="observationTypes"
|
||||
show-field="description"
|
||||
label="Observation type"
|
||||
vn-one
|
||||
vn-focus>
|
||||
</vn-autocomplete>
|
||||
<vn-textfield
|
||||
vn-two
|
||||
class="vn-mr-lg"
|
||||
label="Description"
|
||||
ng-model="observation.description"
|
||||
rule="EntryObservation">
|
||||
</vn-textfield>
|
||||
<vn-auto class="vn-pt-md">
|
||||
<vn-icon-button
|
||||
pointer
|
||||
vn-tooltip="Remove note"
|
||||
icon="delete"
|
||||
ng-click="model.remove($index)">
|
||||
</vn-icon-button>
|
||||
</vn-auto>
|
||||
</vn-horizontal>
|
||||
</vn-one>
|
||||
<vn-one>
|
||||
<vn-icon-button
|
||||
vn-tooltip="Add note"
|
||||
icon="add_circle"
|
||||
vn-bind="+"
|
||||
ng-if="observationTypes.length > observations.length"
|
||||
ng-click="model.insert()">
|
||||
</vn-icon-button>
|
||||
</vn-one>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
<vn-submit
|
||||
disabled="!watcher.dataChanged()"
|
||||
label="Save">
|
||||
</vn-submit>
|
||||
<!-- # #2680 Undo changes button bugs -->
|
||||
<!-- <vn-button
|
||||
class="cancel"
|
||||
label="Undo changes"
|
||||
disabled="!watcher.dataChanged()"
|
||||
ng-click="watcher.loadOriginalData()">
|
||||
</vn-button> -->
|
||||
</vn-button-bar>
|
||||
</form>
|
|
@ -0,0 +1,20 @@
|
|||
import ngModule from '../module';
|
||||
import Section from 'salix/components/section';
|
||||
|
||||
class Controller extends Section {
|
||||
onSubmit() {
|
||||
this.$.watcher.check();
|
||||
this.$.model.save().then(() => {
|
||||
this.$.watcher.notifySaved();
|
||||
this.$.watcher.updateOriginalData();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnEntryObservation', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller,
|
||||
bindings: {
|
||||
entry: '<'
|
||||
}
|
||||
});
|
|
@ -12,6 +12,7 @@
|
|||
"card": [
|
||||
{"state": "entry.card.basicData", "icon": "settings"},
|
||||
{"state": "entry.card.buy", "icon": "icon-lines"},
|
||||
{"state": "entry.card.observation", "icon": "insert_drive_file"},
|
||||
{"state": "entry.card.log", "icon": "history"}
|
||||
]
|
||||
},
|
||||
|
@ -61,7 +62,15 @@
|
|||
"params": {
|
||||
"entry": "$ctrl.entry"
|
||||
}
|
||||
}, {
|
||||
},{
|
||||
"url": "/observation",
|
||||
"state": "entry.card.observation",
|
||||
"component": "vn-entry-observation",
|
||||
"description": "Notes",
|
||||
"params": {
|
||||
"entry": "$ctrl.entry"
|
||||
}
|
||||
},{
|
||||
"url" : "/log",
|
||||
"state": "entry.card.log",
|
||||
"component": "vn-entry-log",
|
||||
|
|
|
@ -2,15 +2,14 @@
|
|||
vn-id="model"
|
||||
url="Routes/filter"
|
||||
limit="20"
|
||||
order="created DESC"
|
||||
auto-load="true">
|
||||
order="created DESC">
|
||||
</vn-crud-model>
|
||||
<vn-portal slot="topbar">
|
||||
<vn-searchbar
|
||||
vn-focus
|
||||
panel="vn-route-search-panel"
|
||||
info="Search routes by id"
|
||||
filter="$ctrl.filter"
|
||||
filter="$ctrl.filterParams"
|
||||
model="model">
|
||||
</vn-searchbar>
|
||||
</vn-portal>
|
||||
|
|
|
@ -10,7 +10,8 @@ export default class Route extends ModuleMain {
|
|||
let from = new Date();
|
||||
from.setHours(0, 0, 0, 0);
|
||||
|
||||
this.filter = {from, to, warehouseFk: this.vnConfig.warehouseFk};
|
||||
this.filterParams = {from, to, warehouseFk: this.vnConfig.warehouseFk};
|
||||
this.$.model.applyFilter(null, this.filterParams);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,8 +25,7 @@
|
|||
"ticket": {
|
||||
"type": "belongsTo",
|
||||
"model": "Ticket",
|
||||
"foreignKey": "ticketFk",
|
||||
"required": true
|
||||
"foreignKey": "ticketFk"
|
||||
},
|
||||
"observationType": {
|
||||
"type": "belongsTo",
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
info="Search ticket by id or alias"
|
||||
model="model"
|
||||
fetch-params="$ctrl.fetchParams($params)"
|
||||
suggested-filter="$ctrl.defaultFilter">
|
||||
suggested-filter="$ctrl.filterParams">
|
||||
</vn-searchbar>
|
||||
</vn-portal>
|
||||
<vn-portal slot="menu">
|
||||
|
|
|
@ -5,7 +5,7 @@ export default class Ticket extends ModuleMain {
|
|||
constructor() {
|
||||
super();
|
||||
|
||||
this.defaultFilter = {
|
||||
this.filterParams = {
|
||||
scopeDays: 1
|
||||
};
|
||||
}
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
<vn-td>{{::tracking.state.name}}</vn-td>
|
||||
<vn-td expand>
|
||||
<span
|
||||
class="link"
|
||||
ng-class="{'link': tracking.worker.id}"
|
||||
ng-click="workerDescriptor.show($event, tracking.worker.user.id)">
|
||||
{{::tracking.worker.user.name | dashIfEmpty}}
|
||||
{{::tracking.worker.user.name || 'System' | translate}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td>{{::tracking.created | date:'dd/MM/yyyy HH:mm'}}</vn-td>
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
panel="vn-travel-search-panel"
|
||||
info="Search travels by id"
|
||||
model="model"
|
||||
fetch-params="$ctrl.fetchParams($params)">
|
||||
fetch-params="$ctrl.fetchParams($params)"
|
||||
suggested-filter="$ctrl.filterParams">
|
||||
</vn-searchbar>
|
||||
</vn-portal>
|
||||
<vn-portal slot="menu">
|
||||
|
|
|
@ -2,6 +2,14 @@ import ngModule from '../module';
|
|||
import ModuleMain from 'salix/components/module-main';
|
||||
|
||||
export default class Travel extends ModuleMain {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.filterParams = {
|
||||
scopeDays: 1
|
||||
};
|
||||
}
|
||||
|
||||
fetchParams($params) {
|
||||
if (!Object.entries($params).length)
|
||||
$params.scopeDays = 1;
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
<span
|
||||
ng-class="{'link': log.user.worker.id, 'value': !log.user.worker.id}"
|
||||
ng-click="$ctrl.showWorkerDescriptor($event, log.user.worker.id)"
|
||||
translate>{{::log.user.name | dashIfEmpty}}
|
||||
translate>{{::log.user.name || 'System' | translate}}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
|
@ -54,7 +54,7 @@
|
|||
<span
|
||||
ng-class="{'link': log.user.worker.id, 'value': !log.user.worker.id}"
|
||||
ng-click="$ctrl.showWorkerDescriptor($event, log.user.worker.id)"
|
||||
translate>{{::log.user.name | dashIfEmpty}}
|
||||
translate>{{::log.user.name || 'System' | translate}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td class="expendable">
|
||||
|
@ -70,7 +70,7 @@
|
|||
<vn-one ng-repeat="old in log.oldProperties">
|
||||
<div>
|
||||
<span translate class="label">{{::old.key}}</span><span class="label">: </span>
|
||||
<span translate class="value">{{::old.value}}</span>
|
||||
<span translate class="value">{{::old.value | dashIfEmpty}}</span>
|
||||
</div>
|
||||
</vn-one>
|
||||
</vn-td>
|
||||
|
@ -81,7 +81,7 @@
|
|||
id="newInstance">
|
||||
<div>
|
||||
<span translate class="label">{{::new.key}}</span><span class="label">: </span>
|
||||
<span translate class="value">{{::new.value}}</span>
|
||||
<span translate class="value">{{::new.value | dashIfEmpty}}</span>
|
||||
</div>
|
||||
</vn-one>
|
||||
<vn-one
|
||||
|
|
|
@ -9,4 +9,5 @@ Name: Nombre
|
|||
Creates: Crea
|
||||
Updates: Actualiza
|
||||
Deletes: Elimina
|
||||
Views: Visualiza
|
||||
Views: Visualiza
|
||||
System: Sistema
|
|
@ -151,6 +151,7 @@ module.exports = app => {
|
|||
SELECT
|
||||
t.id,
|
||||
t.clientFk,
|
||||
c.name clientName,
|
||||
c.email recipient,
|
||||
c.salesPersonFk,
|
||||
c.isToBeMailed,
|
||||
|
@ -196,6 +197,10 @@ module.exports = app => {
|
|||
const email = new Email('delivery-note-link', args);
|
||||
await email.send();
|
||||
} catch (error) {
|
||||
// Domain not found
|
||||
if (error.responseCode == 450)
|
||||
return invalidEmail(ticket);
|
||||
|
||||
// Save tickets on a list of failed ids
|
||||
failedtickets.push({
|
||||
id: ticket.id,
|
||||
|
@ -220,4 +225,33 @@ module.exports = app => {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function invalidEmail(ticket) {
|
||||
await db.rawSql(`UPDATE client SET email = NULL WHERE id = :clientId`, {
|
||||
clientId: ticket.clientFk
|
||||
});
|
||||
|
||||
const oldInstance = `{"email": "${ticket.recipient}"}`;
|
||||
const newInstance = `{"email": ""}`;
|
||||
await db.rawSql(`
|
||||
INSERT INTO clientLog (originFk, userFk, action, changedModel, oldInstance, newInstance)
|
||||
VALUES (:clientId, :userId, 'UPDATE', 'Client', :oldInstance, :newInstance)`, {
|
||||
clientId: ticket.clientFk,
|
||||
userId: null,
|
||||
oldInstance: oldInstance,
|
||||
newInstance: newInstance
|
||||
});
|
||||
|
||||
const body = `No se ha podido enviar el albarán <strong>${ticket.id}</strong>
|
||||
al cliente <strong>${ticket.clientFk} - ${ticket.clientName}</strong>
|
||||
porque la dirección de email <strong>"${ticket.recipient}"</strong> no es correcta o no está disponible.<br/><br/>
|
||||
Para evitar que se repita este error, se ha eliminado la dirección de email de la ficha del cliente.
|
||||
Actualiza la dirección de email con una correcta.`;
|
||||
|
||||
smtp.send({
|
||||
to: ticket.salesPersonEmail,
|
||||
subject: 'No se ha podido enviar el albarán',
|
||||
html: body
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue