This commit is contained in:
Juan Ferrer 2019-01-29 16:38:11 +01:00
commit d46575a072
28 changed files with 112 additions and 94 deletions

View File

@ -1,4 +1,9 @@
<section class="ellipsize"> <section class="ellipsize">
<vn-label></vn-label> <vn-label></vn-label>
<span></span> <span></span>
<vn-icon
ng-if="$ctrl.hasInfo"
vn-tooltip="{{$ctrl.info}}"
icon="info_outline">
</vn-icon>
</section> </section>

View File

@ -2,9 +2,11 @@ import ngModule from '../../module';
import './style.scss'; import './style.scss';
export default class Controller { export default class Controller {
constructor($element, $translate) { constructor($element, $translate, $attrs) {
this.element = $element[0]; this.element = $element[0];
this._ = $translate; this._ = $translate;
this.hasInfo = Boolean($attrs.info);
this.info = $attrs.info || null;
} }
set label(value) { set label(value) {
let label = this.element.querySelector('vn-label'); let label = this.element.querySelector('vn-label');
@ -24,7 +26,7 @@ export default class Controller {
return this._value; return this._value;
} }
} }
Controller.$inject = ['$element', '$translate']; Controller.$inject = ['$element', '$translate', '$attrs'];
ngModule.component('vnLabelValue', { ngModule.component('vnLabelValue', {
controller: Controller, controller: Controller,

View File

@ -11,4 +11,10 @@ vn-label-value > section {
& > span { & > span {
color: $main-font-color; color: $main-font-color;
} }
& > vn-icon {
vertical-align: middle;
color: $secondary-font-color;
font-size: 1.2em
}
} }

View File

@ -145,8 +145,9 @@ export default class ModelProxy extends DataModel {
}); });
return new Proxy(obj, { return new Proxy(obj, {
set: (obj, prop, value) => { set: (obj, prop, value) => {
let changed = prop.charAt(0) !== '$' && value !== obj[prop] && !obj.$isNew; let changed = prop.charAt(0) !== '$' && value !== obj[prop];
if (changed) {
if (changed && !obj.$isNew) {
if (!obj.$oldData) if (!obj.$oldData)
obj.$oldData = {}; obj.$oldData = {};
if (!obj.$oldData[prop]) if (!obj.$oldData[prop])
@ -159,7 +160,8 @@ export default class ModelProxy extends DataModel {
if (changed) { if (changed) {
this.emit('rowChange', {obj, prop, value}); this.emit('rowChange', {obj, prop, value});
this.emit('dataUpdate'); this.emit('dataUpdate');
if (this.autoSave)
if (!obj.$isNew && this.autoSave)
this.save(); this.save();
} }
@ -173,9 +175,10 @@ export default class ModelProxy extends DataModel {
this.isChanged = false; this.isChanged = false;
let data = this.proxiedData; let data = this.proxiedData;
if (data) if (data) {
for (let row of data) for (let row of data)
row.$oldData = null; row.$oldData = null;
}
} }
/** /**
@ -186,18 +189,21 @@ export default class ModelProxy extends DataModel {
let orgData = this.orgData; let orgData = this.orgData;
if (!data) return; if (!data) return;
for (let row of data) for (let row of data) {
if (row.$isNew) { if (row.$isNew) {
let orgRow = {}; let orgRow = {};
for (let prop in row) for (let prop in row) {
if (prop.charAt(0) !== '$') if (prop.charAt(0) !== '$')
orgRow[prop] = row[prop]; orgRow[prop] = row[prop];
}
row.$orgIndex = orgData.push(orgRow) - 1; row.$orgIndex = orgData.push(orgRow) - 1;
row.$orgRow = orgRow; row.$orgRow = orgRow;
row.$isNew = false; row.$isNew = false;
} else if (row.$oldData) } else if (row.$oldData) {
for (let prop in row.$oldData) for (let prop in row.$oldData)
row.$orgRow[prop] = row[prop]; row.$orgRow[prop] = row[prop];
}
}
let removed = this.removed; let removed = this.removed;

View File

@ -100,7 +100,7 @@ function backTest(done) {
nodemon({ nodemon({
exec: gulpBin, exec: gulpBin,
args: ['dockerAndBackTest'], args: ['backendUnitTest'],
watch: backSources, watch: backSources,
done: done done: done
}); });

View File

@ -29,5 +29,6 @@
"You can't make changes on the basic data of an confirmed order or with rows": "You can't make changes on the basic data of an confirmed order or with rows", "You can't make changes on the basic data of an confirmed order or with rows": "You can't make changes on the basic data of an confirmed order or with rows",
"You can't create a ticket for a inactive client": "You can't create a ticket for a inactive client", "You can't create a ticket for a inactive client": "You can't create a ticket for a inactive client",
"Worker cannot be blank": "Worker cannot be blank", "Worker cannot be blank": "Worker cannot be blank",
"You don't have enough privileges to change the state of this ticket": "You don't have enough privileges to change the state of this ticket" "You don't have enough privileges to change the state of this ticket": "You don't have enough privileges to change the state of this ticket",
"You must delete the claim id %d first": "You must delete the claim id %d first"
} }

View File

@ -38,7 +38,7 @@ module.exports = Self => {
stmts.push(new ParameterizedSQL( stmts.push(new ParameterizedSQL(
`SELECT lft, rgt, depth + 1 INTO @lft, @rgt, @depth `SELECT lft, rgt, depth + 1 INTO @lft, @rgt, @depth
FROM zoneTreeview WHERE id = ?`, [parentFk])); FROM zoneGeo WHERE id = ?`, [parentFk]));
stmts.push(`DROP TEMPORARY TABLE IF EXISTS tChilds`); stmts.push(`DROP TEMPORARY TABLE IF EXISTS tChilds`);
@ -46,7 +46,7 @@ module.exports = Self => {
`CREATE TEMPORARY TABLE tChilds `CREATE TEMPORARY TABLE tChilds
ENGINE = MEMORY ENGINE = MEMORY
SELECT id, lft, rgt SELECT id, lft, rgt
FROM zoneTreeview pt`); FROM zoneGeo pt`);
stmt.merge(conn.makeSuffix(filter)); stmt.merge(conn.makeSuffix(filter));
if (!filter.where) { if (!filter.where) {
@ -63,7 +63,7 @@ module.exports = Self => {
ENGINE = MEMORY ENGINE = MEMORY
SELECT t.id SELECT t.id
FROM tChilds t FROM tChilds t
JOIN zoneTreeview zt JOIN zoneGeo zt
ON zt.lft > t.lft AND zt.rgt < t.rgt ON zt.lft > t.lft AND zt.rgt < t.rgt
JOIN zoneIncluded zi JOIN zoneIncluded zi
ON zi.geoFk = zt.id AND zi.zoneFk = ? ON zi.geoFk = zt.id AND zi.zoneFk = ?
@ -80,7 +80,7 @@ module.exports = Self => {
ti.id IS NOT NULL hasCheckedChilds, ti.id IS NOT NULL hasCheckedChilds,
zi.geoFk IS NOT NULL AS selected, zi.geoFk IS NOT NULL AS selected,
zi.isIncluded AS excluded zi.isIncluded AS excluded
FROM zoneTreeview pt FROM zoneGeo pt
LEFT JOIN vn.zoneIncluded zi LEFT JOIN vn.zoneIncluded zi
ON zi.geoFk = pt.id AND zi.zoneFk = ? ON zi.geoFk = pt.id AND zi.zoneFk = ?
JOIN tChilds c ON c.id = pt.id JOIN tChilds c ON c.id = pt.id

View File

@ -24,20 +24,20 @@ module.exports = Self => {
Self.toggleIsIncluded = async(zoneFk, geoFk) => { Self.toggleIsIncluded = async(zoneFk, geoFk) => {
const models = Self.app.models; const models = Self.app.models;
const geo = await models.ZoneTreeview.findById(geoFk); const geo = await models.ZoneGeo.findById(geoFk);
const isIncluded = await Self.findOne({ const isIncluded = await Self.findOne({
where: {zoneFk, geoFk} where: {zoneFk, geoFk}
}); });
const hasCheckedParents = await Self.rawSql( const hasCheckedParents = await Self.rawSql(
`SELECT id `SELECT id
FROM vn.zoneTreeview zt FROM vn.zoneGeo zt
JOIN vn.zoneIncluded zi ON zi.geoFk = zt.id JOIN vn.zoneIncluded zi ON zi.geoFk = zt.id
WHERE zt.lft < ? AND zt.rgt > ?`, [geo.lft, geo.rgt] WHERE zt.lft < ? AND zt.rgt > ?`, [geo.lft, geo.rgt]
); );
const hasCheckedChilds = await Self.rawSql( const hasCheckedChilds = await Self.rawSql(
`SELECT id `SELECT id
FROM vn.zoneTreeview zt FROM vn.zoneGeo zt
JOIN vn.zoneIncluded zi ON zi.geoFk = zt.id JOIN vn.zoneIncluded zi ON zi.geoFk = zt.id
WHERE zt.lft > ? AND zt.rgt < ?`, [geo.lft, geo.rgt] WHERE zt.lft > ? AND zt.rgt < ?`, [geo.lft, geo.rgt]
); );

View File

@ -20,9 +20,6 @@
"ZoneIncluded": { "ZoneIncluded": {
"dataSource": "vn" "dataSource": "vn"
}, },
"ZoneTreeview": {
"dataSource": "vn"
},
"LabourHoliday": { "LabourHoliday": {
"dataSource": "vn" "dataSource": "vn"
}, },

View File

@ -0,0 +1,3 @@
module.exports = Self => {
require('../methods/zone-geo/getLeaves')(Self);
};

View File

@ -19,6 +19,12 @@
}, },
"rgt": { "rgt": {
"type": "Number" "type": "Number"
},
"depth": {
"type": "Number"
},
"sons": {
"type": "Number"
} }
} }
} }

View File

@ -1,3 +0,0 @@
module.exports = Self => {
require('../methods/zone-treeview/getLeaves')(Self);
};

View File

@ -1,30 +0,0 @@
{
"name": "ZoneTreeview",
"base": "VnModel",
"options": {
"mysql": {
"table": "zoneTreeview"
}
},
"properties": {
"id": {
"id": true,
"type": "Number"
},
"name": {
"type": "String"
},
"lft": {
"type": "Number"
},
"rgt": {
"type": "Number"
},
"depth": {
"type": "Number"
},
"sons": {
"type": "Number"
}
}
}

View File

@ -1,6 +1,6 @@
<vn-crud-model <vn-crud-model
vn-id="model" vn-id="model"
url="/agency/api/ZoneTreeviews/getLeaves" url="/agency/api/ZoneGeos/getLeaves"
filter="::$ctrl.filter" filter="::$ctrl.filter"
params="{zoneFk: $ctrl.$stateParams.id, parentFk: 1}"> params="{zoneFk: $ctrl.$stateParams.id, parentFk: 1}">
</vn-crud-model> </vn-crud-model>

View File

@ -24,7 +24,6 @@ describe('Update Claim', () => {
it('should throw error if isSaleAssistant is false and try to modify a forbidden field', async() => { it('should throw error if isSaleAssistant is false and try to modify a forbidden field', async() => {
let params = { let params = {
id: newInstance.id,
ticketFk: 3, ticketFk: 3,
clientFk: 101, clientFk: 101,
ticketCreated: newDate, ticketCreated: newDate,
@ -40,7 +39,7 @@ describe('Update Claim', () => {
} }
} }
}; };
await app.models.Claim.updateClaim(ctx, params) await app.models.Claim.updateClaim(ctx, newInstance.id, params)
.catch(e => { .catch(e => {
error = e; error = e;
}); });
@ -50,7 +49,6 @@ describe('Update Claim', () => {
it('should throw error if isSaleAssistant is false and try to modify a valid field but a forbidden stated', async() => { it('should throw error if isSaleAssistant is false and try to modify a valid field but a forbidden stated', async() => {
let params = { let params = {
id: newInstance.id,
ticketFk: 3, ticketFk: 3,
clientFk: 101, clientFk: 101,
ticketCreated: newDate, ticketCreated: newDate,
@ -65,7 +63,7 @@ describe('Update Claim', () => {
} }
} }
}; };
await app.models.Claim.updateClaim(ctx, params) await app.models.Claim.updateClaim(ctx, newInstance.id, params)
.catch(e => { .catch(e => {
error = e; error = e;
}); });
@ -75,7 +73,6 @@ describe('Update Claim', () => {
it('should change field observation', async() => { it('should change field observation', async() => {
let params = { let params = {
id: newInstance.id,
ticketCreated: newDate, ticketCreated: newDate,
observation: 'another3' observation: 'another3'
}; };
@ -86,7 +83,7 @@ describe('Update Claim', () => {
} }
} }
}; };
await app.models.Claim.updateClaim(ctx, params); await app.models.Claim.updateClaim(ctx, newInstance.id, params);
let claimUpdated = await app.models.Claim.findById(newInstance.id); let claimUpdated = await app.models.Claim.findById(newInstance.id);
@ -95,7 +92,6 @@ describe('Update Claim', () => {
it('should change sensible fields as salesAssistant', async() => { it('should change sensible fields as salesAssistant', async() => {
let params = { let params = {
id: newInstance.id,
ticketFk: 3, ticketFk: 3,
clientFk: 101, clientFk: 101,
ticketCreated: newDate, ticketCreated: newDate,
@ -112,7 +108,7 @@ describe('Update Claim', () => {
} }
} }
}; };
await app.models.Claim.updateClaim(ctx, params); await app.models.Claim.updateClaim(ctx, newInstance.id, params);
let claimUpdated = await app.models.Claim.findById(newInstance.id); let claimUpdated = await app.models.Claim.findById(newInstance.id);

View File

@ -7,6 +7,12 @@ module.exports = Self => {
description: 'Update a claim with privileges', description: 'Update a claim with privileges',
accessType: 'WRITE', accessType: 'WRITE',
accepts: [{ accepts: [{
arg: 'id',
type: 'string',
required: true,
description: 'Client id',
http: {source: 'path'}
}, {
arg: 'params', arg: 'params',
type: 'object', type: 'object',
required: true, required: true,
@ -18,22 +24,21 @@ module.exports = Self => {
root: true root: true
}, },
http: { http: {
path: `/updateClaim`, path: `/:id/updateClaim`,
verb: 'post' verb: 'post'
} }
}); });
Self.updateClaim = async(ctx, params) => { Self.updateClaim = async(ctx, id, params) => {
let models = Self.app.models; let models = Self.app.models;
let isSalesAssistant; let isSalesAssistant;
let token = ctx.req.accessToken; let currentUserId = ctx.req.accessToken.userId;
let currentUserId = token && token.userId;
isSalesAssistant = await models.Account.hasRole(currentUserId, 'salesAssistant'); isSalesAssistant = await models.Account.hasRole(currentUserId, 'salesAssistant');
if (!isSalesAssistant) { if (!isSalesAssistant) {
let oldClaim = await models.Claim.findById(params.id); let oldClaim = await models.Claim.findById(id);
let notModifiable = ['responsibility', 'isChargedToMana']; let notModifiable = ['id', 'responsibility', 'isChargedToMana'];
let changedFields = diff(oldClaim, params); let changedFields = diff(oldClaim, params);
let changedFieldsPicked = pick(changedFields, notModifiable); let changedFieldsPicked = pick(changedFields, notModifiable);
let statesViables = ['Gestionado', 'Pendiente', 'Anulado']; let statesViables = ['Gestionado', 'Pendiente', 'Anulado'];
@ -45,6 +50,7 @@ module.exports = Self => {
throw new UserError(`You don't have enough privileges to change that field`); throw new UserError(`You don't have enough privileges to change that field`);
} }
return await Self.updateAll({id: params.id}, params); let claim = await Self.findById(id);
return await claim.updateAttributes(params);
}; };
}; };

View File

@ -147,7 +147,7 @@ class Controller {
} }
saveResponsibility(value) { saveResponsibility(value) {
let query = `/claim/api/Claims/updateClaim`; let query = `/api/Claims/${this.$stateParams.id}/updateClaim`;
this.$http.post(query, {responsibility: value}).then(() => { this.$http.post(query, {responsibility: value}).then(() => {
this.vnApp.showSuccess(this.$translate.instant('Data saved!')); this.vnApp.showSuccess(this.$translate.instant('Data saved!'));

View File

@ -2,7 +2,7 @@
vn-id="watcher" vn-id="watcher"
data="$ctrl.claim" data="$ctrl.claim"
form="form" form="form"
url="/claim/api/Claims/updateClaim" url="/api/Claims/{{$ctrl.$stateParams.id}}/updateClaim"
save="post"> save="post">
</vn-watcher> </vn-watcher>
<form name="form" ng-submit="watcher.submit()" compact> <form name="form" ng-submit="watcher.submit()" compact>

View File

@ -1,8 +1,17 @@
import ngModule from '../module'; import ngModule from '../module';
import './style.scss'; import './style.scss';
class Controller {
constructor($stateParams) {
this.$stateParams = $stateParams;
}
}
Controller.$inject = ['$stateParams'];
ngModule.component('vnClaimBasicData', { ngModule.component('vnClaimBasicData', {
template: require('./index.html'), template: require('./index.html'),
controller: Controller,
bindings: { bindings: {
claim: '<' claim: '<'
} }

View File

@ -29,12 +29,14 @@ module.exports = function(Self) {
} }
}); });
Self.addressesPropagateRe = async (id, data) => { Self.addressesPropagateRe = async(id, data) => {
if (data.hasOwnProperty('isEqualizated')) { if (data.hasOwnProperty('isEqualizated')) {
await Self.app.models.Address.updateAll({clientFk: id}, data); let client = await Self.app.models.Client.findById(id);
let client = await Self.app.models.Client.findById(id) if (client) {
await client.updateAttributes({hasToInvoiceByAddress: false}); await Self.app.models.Address.updateAll({clientFk: id}, data);
return true; await client.updateAttributes({hasToInvoiceByAddress: false});
return true;
}
} }
return false; return false;
}; };

View File

@ -35,7 +35,7 @@ export default class Controller {
} }
notifyChanges() { notifyChanges() {
this.$http.post(`/email/payment-update`, {clientFk: this.client.id}).then( this.$http.post(`/api/email/payment-update`, {clientFk: this.client.id}).then(
() => this.vnApp.showMessage(this.$translate.instant('Notification sent!')) () => this.vnApp.showMessage(this.$translate.instant('Notification sent!'))
); );
} }

View File

@ -6,21 +6,21 @@ class Controller {
this.filter = { this.filter = {
include: [ include: [
{ {
relation: "type", relation: 'type',
scope: { scope: {
fields: ["code", "description"] fields: ['code', 'description']
} }
}, },
{ {
relation: "worker", relation: 'worker',
scope: { scope: {
fields: ["firstName", "name"] fields: ['firstName', 'name']
} }
}, },
{ {
relation: "company", relation: 'company',
scope: { scope: {
fields: ["code"] fields: ['code']
} }
} }
] ]

View File

@ -168,22 +168,27 @@
<h4 translate>Financial information</h4> <h4 translate>Financial information</h4>
<vn-label-value label="Risk" <vn-label-value label="Risk"
value="{{$ctrl.summary.debt.debt | currency:'€':2}}" value="{{$ctrl.summary.debt.debt | currency:'€':2}}"
ng-class="{alert: $ctrl.summary.debt.debt > $ctrl.summary.credit}"> ng-class="{alert: $ctrl.summary.debt.debt > $ctrl.summary.credit}"
info="Invoices minus payments plus orders not yet invoiced">
</vn-label-value> </vn-label-value>
<vn-label-value label="Credit" <vn-label-value label="Credit"
value="{{$ctrl.summary.credit | currency:'€':2 }} " value="{{$ctrl.summary.credit | currency:'€':2 }} "
ng-class="{alert: $ctrl.summary.credit > $ctrl.summary.creditInsurance || ng-class="{alert: $ctrl.summary.credit > $ctrl.summary.creditInsurance ||
($ctrl.summary.credit && $ctrl.summary.creditInsurance == null)}"> ($ctrl.summary.credit && $ctrl.summary.creditInsurance == null)}"
info="Verdnatura's maximum risk">
</vn-label-value> </vn-label-value>
<vn-label-value label="Secured credit" <vn-label-value label="Secured credit"
value="{{$ctrl.summary.creditInsurance | currency:'€':2}} ({{$ctrl.summary.classifications[0].insurances[0].grade}})"> value="{{$ctrl.summary.creditInsurance | currency:'€':2}} ({{$ctrl.summary.classifications[0].insurances[0].grade}})"
info="Solunion's maximum risk">
</vn-label-value> </vn-label-value>
<vn-label-value label="Balance" <vn-label-value label="Balance"
value="{{$ctrl.summary.sumRisk | currency:'€':2}}"> value="{{$ctrl.summary.sumRisk | currency:'€':2}}"
info="Invoices minus payments">
</vn-label-value> </vn-label-value>
<vn-label-value label="Balance due" <vn-label-value label="Balance due"
value="{{$ctrl.summary.defaulters[0].amount | currency:'€':2}}" value="{{$ctrl.summary.defaulters[0].amount | currency:'€':2}}"
ng-class="{alert: $ctrl.summary.defaulters[0].amount}"> ng-class="{alert: $ctrl.summary.defaulters[0].amount}"
info="Deviated invoices minus payments">
</vn-label-value> </vn-label-value>
<vn-vertical ng-if="$ctrl.summary.recovery.started"> <vn-vertical ng-if="$ctrl.summary.recovery.started">
<vn-label-value label="Recovery since" <vn-label-value label="Recovery since"

View File

@ -12,3 +12,8 @@ Rate: Tarifa
Business data: Datos comerciales Business data: Datos comerciales
Recovery since: Recobro desde Recovery since: Recobro desde
Fiscal address: Dirección fiscal Fiscal address: Dirección fiscal
Invoices minus payments plus orders not yet invoiced: Facturas menos recibos mas pedidos sin facturar
Verdnatura's maximum risk: Riesgo máximo asumido por Verdnatura
Solunion's maximum risk: Riesgo máximo asumido por Solunion
Invoices minus payments: Facturas menos recibos
Deviated invoices minus payments: Facturas fuera de plazo menos recibos

View File

@ -5,7 +5,6 @@
link="{itemFk: $ctrl.$stateParams.id}" link="{itemFk: $ctrl.$stateParams.id}"
include="$ctrl.include" include="$ctrl.include"
order="priority ASC" order="priority ASC"
on-row-change="$ctrl.getSourceTable(obj)"
data="$ctrl.itemTags" data="$ctrl.itemTags"
auto-load="true"> auto-load="true">
</vn-crud-model> </vn-crud-model>
@ -30,6 +29,7 @@
initial-data="itemTag.tag" initial-data="itemTag.tag"
field="itemTag.tagFk" field="itemTag.tagFk"
data="tags" data="tags"
on-change="$ctrl.getSourceTable(tag)"
show-field="name" show-field="name"
vn-acl="buyer" vn-acl="buyer"
vn-focus> vn-focus>

View File

@ -30,7 +30,7 @@ class Controller {
getSourceTable(obj) { getSourceTable(obj) {
let sourceTable; let sourceTable;
this.sourceTables[obj.id] = {}; this.sourceTables[obj.id] = {};
let tag = obj.tag; let tag = obj.tag || obj.selection;
if (!tag || !tag.sourceTable && (tag.isFree === true || tag.isFree === undefined)) if (!tag || !tag.sourceTable && (tag.isFree === true || tag.isFree === undefined))
sourceTable = null; sourceTable = null;

View File

@ -58,6 +58,8 @@ Delay: Retraso
Code 100: Código 100 Code 100: Código 100
Invoice: Factura Invoice: Factura
Client card: Ficha del cliente Client card: Ficha del cliente
You are going to delete this ticket: Vas a borrar este ticket
Ticket deleted: Ticket borrado
#sections #sections
List: Listado List: Listado

View File

@ -16,8 +16,8 @@ module.exports = {
data() { data() {
return { return {
files: [ files: [
'/assets/images/action.png', /* '/assets/images/action.png',
'/assets/images/info.png', '/assets/images/info.png', */
'/assets/images/facebook.png', '/assets/images/facebook.png',
'/assets/images/twitter.png', '/assets/images/twitter.png',
'/assets/images/youtube.png', '/assets/images/youtube.png',