merge
gitea/salix/dev This commit looks good
Details
gitea/salix/dev This commit looks good
Details
This commit is contained in:
commit
9c596b06c8
|
@ -0,0 +1 @@
|
|||
INSERT INTO `salix`.`ACL` (`id`, `model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('160', 'TicketServiceType', '*', 'READ', 'ALLOW', 'ROLE', 'employee');
|
|
@ -0,0 +1,9 @@
|
|||
ALTER TABLE `vn2008`.`Facturas`
|
||||
DROP FOREIGN KEY `invoice_bank_id`;
|
||||
ALTER TABLE `vn2008`.`Facturas`
|
||||
CHANGE COLUMN `Id_Banco` `Id_Banco` INT(11) NULL DEFAULT NULL ;
|
||||
ALTER TABLE `vn2008`.`Facturas`
|
||||
ADD CONSTRAINT `invoice_bank_id`
|
||||
FOREIGN KEY (`Id_Banco`)
|
||||
REFERENCES `vn2008`.`Bancos` (`Id_Banco`)
|
||||
ON UPDATE CASCADE;
|
|
@ -0,0 +1,17 @@
|
|||
ALTER TABLE `vn2008`.`Colas`
|
||||
DROP FOREIGN KEY `Colas_ibfk_1`,
|
||||
DROP FOREIGN KEY `Colas_ibfk_2`,
|
||||
DROP FOREIGN KEY `Colas_ibfk_3`,
|
||||
DROP FOREIGN KEY `Colas_ibfk_5`;
|
||||
ALTER TABLE `vn2008`.`Colas`
|
||||
CHANGE COLUMN `Id_Impresora` `Id_Impresora` TINYINT(3) UNSIGNED NULL DEFAULT NULL ,
|
||||
CHANGE COLUMN `Id_Prioridad` `Id_Prioridad` TINYINT(3) UNSIGNED NULL DEFAULT NULL ;
|
||||
ALTER TABLE `vn2008`.`Colas`
|
||||
ADD CONSTRAINT `Colas_ibfk_4`
|
||||
FOREIGN KEY (`Id_Impresora`)
|
||||
REFERENCES `vn2008`.`Impresoras` (`Id_Impresora`)
|
||||
ON UPDATE CASCADE,
|
||||
ADD CONSTRAINT `Colas_ibfk_3`
|
||||
FOREIGN KEY (`Id_Prioridad`)
|
||||
REFERENCES `vn2008`.`Prioridades` (`Id_Prioridad`)
|
||||
ON UPDATE CASCADE;
|
|
@ -976,6 +976,14 @@ INSERT INTO `vn2008`.`tblContadores`(`id`,`FechaInventario`)
|
|||
VALUES
|
||||
(1,DATE_ADD(CURDATE(),INTERVAL -1 MONTH));
|
||||
|
||||
INSERT INTO `vn2008`.`Estados` (`Id_Estado`, `Estado`)
|
||||
VALUES
|
||||
('1', 'En Espera');
|
||||
|
||||
INSERT INTO `vn2008`.`Informes` (`Id_Informe`, `Informe`)
|
||||
VALUES
|
||||
('30', 'Generar factura PDF');
|
||||
|
||||
INSERT INTO `vn`.`deliveryMethod`(`id`, `code`, `description`)
|
||||
VALUES
|
||||
( 1, 'AGENCY', 'Agencia'),
|
||||
|
|
|
@ -455,7 +455,7 @@ export default {
|
|||
},
|
||||
ticketService: {
|
||||
addServiceButton: 'vn-ticket-service > form > vn-card > div > vn-one:nth-child(3) > vn-icon-button > button > vn-icon',
|
||||
firstDescriptionInput: 'vn-ticket-service vn-autocomplete[label="Documentos"]',
|
||||
firstDescriptionAutocomplete: 'vn-ticket-service vn-autocomplete[field="service.description"]',
|
||||
firstQuantityInput: 'vn-ticket-service vn-input-number[label="Quantity"] input',
|
||||
firstPriceInput: 'vn-ticket-service vn-input-number[label="Price"] input',
|
||||
firstVatTypeAutocomplete: 'vn-ticket-service vn-autocomplete[label="Tax class"]',
|
||||
|
|
|
@ -13,8 +13,7 @@ describe('Ticket services path', () => {
|
|||
|
||||
it('should edit the first service', async() => {
|
||||
const result = await nightmare
|
||||
.clearInput(selectors.ticketService.firstDescriptionInput)
|
||||
.write(selectors.ticketService.firstDescriptionInput, 'my service')
|
||||
.autocompleteSearch(selectors.ticketService.firstDescriptionAutocomplete, 'Documentos')
|
||||
.clearInput(selectors.ticketService.firstQuantityInput)
|
||||
.write(selectors.ticketService.firstQuantityInput, 99)
|
||||
.clearInput(selectors.ticketService.firstPriceInput)
|
||||
|
@ -29,9 +28,9 @@ describe('Ticket services path', () => {
|
|||
it('should confirm the service description was edited correctly', async() => {
|
||||
const result = await nightmare
|
||||
.reloadSection('ticket.card.service')
|
||||
.waitToGetProperty(selectors.ticketService.firstDescriptionInput, 'value');
|
||||
.waitToGetProperty(`${selectors.ticketService.firstDescriptionAutocomplete} input`, 'value');
|
||||
|
||||
expect(result).toEqual('my service');
|
||||
expect(result).toEqual('Documentos');
|
||||
});
|
||||
|
||||
it('should confirm the service quantity was edited correctly', async() => {
|
||||
|
|
|
@ -48,7 +48,7 @@ vn-drop-down {
|
|||
}
|
||||
}
|
||||
& > .list {
|
||||
max-height: 12.8em;
|
||||
max-height: 20em;
|
||||
overflow: auto;
|
||||
|
||||
ul {
|
||||
|
|
|
@ -120,7 +120,6 @@ export default class Popover extends Component {
|
|||
if (!(this.parent && this._shown)) return;
|
||||
|
||||
let margin = 10;
|
||||
let scrollbarSize = 10;
|
||||
|
||||
let style = this.popover.style;
|
||||
style.width = '';
|
||||
|
@ -135,11 +134,12 @@ export default class Popover extends Component {
|
|||
let arrowRect = this.arrow.getBoundingClientRect();
|
||||
let clamp = (value, min, max) => Math.min(Math.max(value, min), max);
|
||||
|
||||
let arrowHeight = Math.sqrt(Math.pow(arrowRect.height, 2) * 2) / 2;
|
||||
let arrowHeight = Math.floor(arrowRect.height / 2);
|
||||
let arrowOffset = arrowHeight + margin / 2;
|
||||
|
||||
let endMargin = margin + scrollbarSize;
|
||||
let maxRight = window.innerWidth - endMargin;
|
||||
let maxBottom = window.innerHeight - endMargin;
|
||||
let docEl = document.documentElement;
|
||||
let maxRight = Math.min(window.innerWidth, docEl.clientWidth) - margin;
|
||||
let maxBottom = Math.min(window.innerHeight, docEl.clientHeight) - margin;
|
||||
let maxWith = maxRight - margin;
|
||||
let maxHeight = maxBottom - margin - arrowHeight;
|
||||
|
||||
|
@ -149,9 +149,9 @@ export default class Popover extends Component {
|
|||
let left = parentRect.left + parentRect.width / 2 - width / 2;
|
||||
left = clamp(left, margin, maxRight - width);
|
||||
|
||||
let top = parentRect.top + parentRect.height + arrowHeight;
|
||||
let top = parentRect.top + parentRect.height + arrowOffset;
|
||||
let showTop = top + height > maxBottom;
|
||||
if (showTop) top = parentRect.top - height - arrowHeight;
|
||||
if (showTop) top = parentRect.top - height - arrowOffset;
|
||||
top = Math.max(top, margin);
|
||||
|
||||
if (showTop)
|
||||
|
|
|
@ -8,8 +8,14 @@
|
|||
pointer>
|
||||
</vn-icon>
|
||||
</t-left-icons>
|
||||
<t-right-icons>
|
||||
<vn-icon
|
||||
<t-right-icons vn-horizontal>
|
||||
<vn-icon vn-one
|
||||
ng-if="$ctrl.info"
|
||||
icon="info_outline"
|
||||
vn-tooltip = "{{$ctrl.info}}"
|
||||
pointer>
|
||||
</vn-icon>
|
||||
<vn-icon vn-one
|
||||
ng-if="$ctrl.panel"
|
||||
ng-click="$ctrl.openPanel($event)"
|
||||
icon="keyboard_arrow_down"
|
||||
|
|
|
@ -19,9 +19,10 @@ import {buildFilter} from 'vn-loopback/util/filter';
|
|||
export default class Controller extends Component {
|
||||
constructor($element, $scope, $compile, $state, $transitions) {
|
||||
super($element, $scope);
|
||||
this.$element = $element;
|
||||
this.$compile = $compile;
|
||||
this.$state = $state;
|
||||
|
||||
this.$scope = $scope;
|
||||
let criteria = {to: this.$state.current.name};
|
||||
this.deregisterCallback = $transitions.onSuccess(criteria,
|
||||
() => this.onStateChange());
|
||||
|
@ -218,7 +219,8 @@ ngModule.component('vnSearchbar', {
|
|||
model: '<?',
|
||||
exprBuilder: '&?',
|
||||
paramBuilder: '&?',
|
||||
autoLoad: '<?'
|
||||
autoLoad: '<?',
|
||||
info: '@?'
|
||||
},
|
||||
controller: Controller
|
||||
});
|
||||
|
|
|
@ -10,7 +10,6 @@ export default class Textfield extends Input {
|
|||
this.type = $attrs.type;
|
||||
this.showActions = false;
|
||||
this.hasInfo = Boolean($attrs.info);
|
||||
this.info = $attrs.info || null;
|
||||
this.hasFocus = false;
|
||||
this.hasMouseIn = false;
|
||||
|
||||
|
@ -90,6 +89,7 @@ ngModule.component('vnTextfield', {
|
|||
type: '@?',
|
||||
vnTabIndex: '@?',
|
||||
onChange: '&',
|
||||
onClear: '&'
|
||||
onClear: '&',
|
||||
info: '@?'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
panel="vn-zone-search-panel"
|
||||
model="model"
|
||||
expr-builder="$ctrl.exprBuilder(param, value)"
|
||||
info="Search zone by id or name"
|
||||
vn-focus>
|
||||
</vn-searchbar>
|
||||
</vn-card>
|
||||
|
|
|
@ -10,3 +10,4 @@ Zones: Zonas
|
|||
New zone: Nueva zona
|
||||
Volumetric: Volumétrico
|
||||
Clone: Clonar
|
||||
Search zone by id or name: Buscar zonas por identificador o nombre
|
|
@ -5,6 +5,7 @@
|
|||
vn-one
|
||||
label="General search"
|
||||
model="filter.search"
|
||||
info="Search zone by id or name"
|
||||
vn-focus>
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
|
||||
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
|
||||
const buildFilter = require('vn-loopback/util/filter').buildFilter;
|
||||
const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('filter', {
|
||||
description: 'Find all instances of the model matched by filter from the data source.',
|
||||
accessType: 'READ',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'filter',
|
||||
type: 'Object',
|
||||
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
arg: 'tags',
|
||||
type: ['Object'],
|
||||
description: 'List of tags to filter with',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
arg: 'search',
|
||||
type: 'String',
|
||||
description: `If it's and integer searchs by id, otherwise it searchs by client name`,
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
arg: 'client',
|
||||
type: 'String',
|
||||
description: 'The worker name',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
arg: 'id',
|
||||
type: 'Integer',
|
||||
description: 'The claim id',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
arg: 'clientFk',
|
||||
type: 'Integer',
|
||||
description: 'The client id',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
arg: 'claimStateFk',
|
||||
type: 'Integer',
|
||||
description: 'The claim state id',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
arg: 'workerFk',
|
||||
type: 'Integer',
|
||||
description: 'The worker id',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
arg: 'created',
|
||||
type: 'Date',
|
||||
description: 'The to date filter',
|
||||
http: {source: 'query'}
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
type: ['Object'],
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/filter`,
|
||||
verb: 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
Self.filter = async(ctx, filter) => {
|
||||
let conn = Self.dataSource.connector;
|
||||
|
||||
let where = buildFilter(ctx.args, (param, value) => {
|
||||
switch (param) {
|
||||
case 'search':
|
||||
return /^\d+$/.test(value)
|
||||
? {'cl.id': value}
|
||||
: {
|
||||
or: [
|
||||
{'c.name': {like: `%${value}%`}}
|
||||
]
|
||||
};
|
||||
case 'client':
|
||||
return {'c.name': {like: `%${value}%`}};
|
||||
case 'id':
|
||||
return {'cl.id': value};
|
||||
case 'clientFk':
|
||||
return {'c.id': value};
|
||||
case 'claimStateFk':
|
||||
return {'cl.claimStateFk': value};
|
||||
case 'workerFk':
|
||||
return {'cl.workerFk': value};
|
||||
case 'created':
|
||||
return {'cl.created': value};
|
||||
}
|
||||
});
|
||||
|
||||
filter = mergeFilters(ctx.args.filter, {where});
|
||||
|
||||
let stmts = [];
|
||||
let stmt;
|
||||
|
||||
stmt = new ParameterizedSQL(
|
||||
`SELECT cl.id, c.name, u.nickName, cs.description, cl.created
|
||||
FROM claim cl
|
||||
LEFT JOIN client c ON c.id = cl.clientFk
|
||||
LEFT JOIN worker w ON w.id = cl.workerFk
|
||||
LEFT JOIN account.user u ON u.id = w.userFk
|
||||
LEFT JOIN claimState cs ON cs.id = cl.claimStateFk`
|
||||
);
|
||||
|
||||
|
||||
stmt.merge(conn.makeSuffix(filter));
|
||||
let itemsIndex = stmts.push(stmt) - 1;
|
||||
|
||||
let sql = ParameterizedSQL.join(stmts, ';');
|
||||
let result = await conn.executeStmt(sql);
|
||||
return itemsIndex === 0 ? result : result[itemsIndex];
|
||||
};
|
||||
};
|
|
@ -0,0 +1,27 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
|
||||
describe('claim filter()', () => {
|
||||
it('should return 1 result filtering by id', async() => {
|
||||
let result = await app.models.Claim.filter({args: {filter: {}, search: 1}});
|
||||
|
||||
expect(result.length).toEqual(1);
|
||||
expect(result[0].id).toEqual(1);
|
||||
});
|
||||
|
||||
it('should return 1 result filtering by string', async() => {
|
||||
let result = await app.models.Claim.filter({args: {filter: {}, search: 'Tony Stark'}});
|
||||
|
||||
expect(result.length).toEqual(1);
|
||||
expect(result[0].id).toEqual(4);
|
||||
});
|
||||
|
||||
it('should return 4 results filtering by worker id', async() => {
|
||||
let result = await app.models.Claim.filter({args: {filter: {}, workerFk: 18}});
|
||||
|
||||
expect(result.length).toEqual(4);
|
||||
expect(result[0].id).toEqual(1);
|
||||
expect(result[1].id).toEqual(2);
|
||||
expect(result[2].id).toEqual(3);
|
||||
expect(result[3].id).toEqual(4);
|
||||
});
|
||||
});
|
|
@ -41,7 +41,7 @@ module.exports = Self => {
|
|||
let notModifiable = ['id', 'responsibility', 'isChargedToMana'];
|
||||
let changedFields = diff(oldClaim, params);
|
||||
let changedFieldsPicked = pick(changedFields, notModifiable);
|
||||
let statesViables = ['Gestionado', 'Pendiente', 'Anulado'];
|
||||
let statesViables = ['Gestionado', 'Pendiente', 'Anulado', 'Mana'];
|
||||
let oldState = await models.ClaimState.findOne({where: {id: oldClaim.claimStateFk}});
|
||||
let newState = await models.ClaimState.findOne({where: {id: params.claimStateFk}});
|
||||
let canChangeState = statesViables.includes(oldState.description)
|
||||
|
|
|
@ -3,4 +3,5 @@ module.exports = Self => {
|
|||
require('../methods/claim/createFromSales')(Self);
|
||||
require('../methods/claim/updateClaim')(Self);
|
||||
require('../methods/claim/regularizeClaim')(Self);
|
||||
require('../methods/claim/filter')(Self);
|
||||
};
|
||||
|
|
|
@ -34,9 +34,6 @@
|
|||
"claimStateFk": {
|
||||
"type": "Number"
|
||||
},
|
||||
"clientFk": {
|
||||
"type": "Number"
|
||||
},
|
||||
"workerFk": {
|
||||
"type": "Number"
|
||||
}
|
||||
|
|
|
@ -1,19 +1,17 @@
|
|||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="/claim/api/Claims"
|
||||
filter="::$ctrl.filter"
|
||||
url="/claim/api/Claims/filter"
|
||||
limit="20"
|
||||
data="claims"
|
||||
auto-load="false">
|
||||
order="claimStateFk ASC, created DESC">
|
||||
</vn-crud-model>
|
||||
<div class="content-block">
|
||||
<div class="vn-list">
|
||||
<vn-card pad-medium-h>
|
||||
<vn-searchbar
|
||||
panel="vn-claim-search-panel"
|
||||
model="model"
|
||||
expr-builder="$ctrl.exprBuilder(param, value)"
|
||||
auto-load="true"
|
||||
on-search="$ctrl.onSearch($params)"
|
||||
info="Search claim by id or client name"
|
||||
vn-focus>
|
||||
</vn-searchbar>
|
||||
</vn-card>
|
||||
|
@ -38,7 +36,7 @@
|
|||
<vn-td number>{{::claim.id}}</vn-td>
|
||||
<vn-td expand>
|
||||
<span class="link" ng-click="$ctrl.showClientDescriptor($event, claim.client.id)">
|
||||
{{::claim.client.name}}
|
||||
{{::claim.name}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td center>{{::claim.created | dateTime:'dd/MM/yyyy'}}</vn-td>
|
||||
|
@ -46,12 +44,12 @@
|
|||
<span
|
||||
class="link"
|
||||
ng-click="$ctrl.showWorkerDescriptor($event, claim.worker.user.id)">
|
||||
{{::claim.worker.user.nickname}}
|
||||
{{::claim.nickName}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td>
|
||||
<span class="chip {{::$ctrl.stateColor(claim)}}">
|
||||
{{::claim.claimState.description}}
|
||||
{{::claim.description}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td shrink>
|
||||
|
|
|
@ -4,58 +4,10 @@ export default class Controller {
|
|||
constructor($scope) {
|
||||
this.$ = $scope;
|
||||
this.ticketSelected = null;
|
||||
|
||||
this.filter = {
|
||||
include: [
|
||||
{
|
||||
relation: 'client',
|
||||
scope: {
|
||||
fields: ['name']
|
||||
}
|
||||
},
|
||||
{
|
||||
relation: 'worker',
|
||||
scope: {
|
||||
fields: ['userFk'],
|
||||
include: {
|
||||
relation: 'user',
|
||||
scope: {
|
||||
fields: ['nickname']
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
relation: 'claimState',
|
||||
scope: {
|
||||
fields: ['description']
|
||||
}
|
||||
}
|
||||
],
|
||||
order: 'claimStateFk ASC, created DESC'
|
||||
};
|
||||
}
|
||||
|
||||
exprBuilder(param, value) {
|
||||
switch (param) {
|
||||
case 'search':
|
||||
return /^\d+$/.test(value)
|
||||
? {id: value}
|
||||
: {client: {like: `%${value}%`}};
|
||||
case 'client':
|
||||
return {[param]: {like: `%${value}%`}};
|
||||
case 'created':
|
||||
return {created: {between: [value, value]}};
|
||||
case 'id':
|
||||
case 'clientFk':
|
||||
case 'workerFk':
|
||||
case 'claimStateFk':
|
||||
return {[param]: value};
|
||||
}
|
||||
}
|
||||
|
||||
stateColor(claim) {
|
||||
switch (claim.claimState.description) {
|
||||
switch (claim.description) {
|
||||
case 'Pendiente':
|
||||
return 'warning';
|
||||
case 'Gestionado':
|
||||
|
@ -91,6 +43,13 @@ export default class Controller {
|
|||
onDescriptorLoad() {
|
||||
this.$.popover.relocate();
|
||||
}
|
||||
|
||||
onSearch(params) {
|
||||
if (params)
|
||||
this.$.model.applyFilter(null, params);
|
||||
else
|
||||
this.$.model.clear();
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$scope'];
|
||||
|
|
|
@ -10,4 +10,5 @@ Claim Id: Id reclamación
|
|||
Created: Creado
|
||||
Send Pickup order: Enviar orden de recogida
|
||||
Show Pickup order: Ver orden de recogida
|
||||
Search claim by id or client name: Buscar reclamaciones por identificador o nombre de cliente
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
vn-one
|
||||
label="General search"
|
||||
model="filter.search"
|
||||
info="Search claim by id or client name"
|
||||
vn-focus>
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
|
|
|
@ -197,10 +197,11 @@ module.exports = Self => {
|
|||
if (payMethodChanged || ibanChanged || dueDayChanged) {
|
||||
const message = `La forma de pago del cliente con id ${instance.id} ha cambiado`;
|
||||
const salesPersonFk = instance.salesPersonFk;
|
||||
const salesPerson = await Self.app.models.Worker.findById(salesPersonFk);
|
||||
|
||||
if (salesPersonFk) {
|
||||
if (salesPerson) {
|
||||
await Self.app.models.Message.send(ctx, {
|
||||
recipientFk: salesPersonFk,
|
||||
recipientFk: salesPerson.userFk,
|
||||
message: message
|
||||
});
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
panel="vn-client-search-panel"
|
||||
model="model"
|
||||
expr-builder="$ctrl.exprBuilder(param, value)"
|
||||
info="Search client by id or name"
|
||||
vn-focus>
|
||||
</vn-searchbar>
|
||||
</vn-card>
|
||||
|
|
|
@ -27,6 +27,7 @@ Client inactive: Cliente inactivo
|
|||
Client not checked: Cliente no comprobado
|
||||
Credit insurance: Crédito asegurado
|
||||
Web Account inactive: Sin acceso Web
|
||||
Search client by id or name: Buscar clientes por identificador o nombre
|
||||
|
||||
# Sections
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
vn-one
|
||||
label="General search"
|
||||
model="filter.search"
|
||||
info="Search client by id or name"
|
||||
vn-focus>
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
model="model"
|
||||
expr-builder="$ctrl.exprBuilder(param, value)"
|
||||
auto-load="true"
|
||||
info="Search invoices by reference"
|
||||
vn-focus>
|
||||
</vn-searchbar>
|
||||
</vn-card>
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
Invoice out: Facturas
|
||||
Search invoices by reference: Buscar facturas por referencia
|
|
@ -5,6 +5,7 @@
|
|||
vn-one
|
||||
label="General search"
|
||||
model="filter.search"
|
||||
info="Search invoices by reference"
|
||||
vn-focus>
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
vn-three
|
||||
panel="vn-item-search-panel"
|
||||
on-search="$ctrl.onSearch($params)"
|
||||
info="Search items by id, name or barcode"
|
||||
vn-focus>
|
||||
</vn-searchbar>
|
||||
<vn-icon-menu
|
||||
|
|
|
@ -44,6 +44,7 @@ Shipped: F. envío
|
|||
stems: Tallos
|
||||
Compression: Compresión
|
||||
Density: Densidad
|
||||
Search items by id, name or barcode: Buscar articulos por identificador, nombre o codigo de barras
|
||||
|
||||
# Sections
|
||||
Items: Artículos
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
vn-one
|
||||
label="General search"
|
||||
model="filter.search"
|
||||
info="Search items by id, name or barcode"
|
||||
vn-focus>
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
<vn-searchbar
|
||||
panel="vn-order-search-panel"
|
||||
on-search="$ctrl.onSearch($params)"
|
||||
info="Search orders by id"
|
||||
vn-focus>
|
||||
</vn-searchbar>
|
||||
</vn-card>
|
||||
|
|
|
@ -20,3 +20,4 @@ Price: Precio
|
|||
Ascendant: Ascendente
|
||||
Descendant: Descendente
|
||||
Created from: Creado desde
|
||||
Search orders by id: Buscar en la cesta por identificador
|
|
@ -5,6 +5,7 @@
|
|||
vn-one
|
||||
label="General search"
|
||||
model="filter.search"
|
||||
info="Search orders by id"
|
||||
vn-focus>
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
model="model"
|
||||
expr-builder="$ctrl.exprBuilder(param, value)"
|
||||
auto-load="true"
|
||||
info="Search routes by id"
|
||||
vn-focus>
|
||||
</vn-searchbar>
|
||||
</vn-card>
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
Routes: Rutas
|
||||
Search routes by id: Buscar rutas por identificador
|
|
@ -5,6 +5,7 @@
|
|||
vn-one
|
||||
label="General search"
|
||||
model="filter.search"
|
||||
info="Search routes by id"
|
||||
vn-focus>
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
|
|
|
@ -2,14 +2,14 @@ const UserError = require('vn-loopback/util/user-error');
|
|||
|
||||
module.exports = function(Self) {
|
||||
Self.remoteMethodCtx('makeInvoice', {
|
||||
description: 'Change property isEqualizated in all client addresses',
|
||||
description: 'Make out an invoice from a ticket id',
|
||||
accessType: 'WRITE',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'id',
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'Client id',
|
||||
description: 'Ticket id',
|
||||
http: {source: 'path'}
|
||||
}
|
||||
],
|
||||
|
@ -53,7 +53,7 @@ module.exports = function(Self) {
|
|||
query = `CALL vn.invoiceOutMake(?, ?, @invoiceId);
|
||||
SELECT @invoiceId AS invoiceId;`;
|
||||
result = await Self.rawSql(query, [serial, null], options);
|
||||
let invoice = result[1].invoiceId;
|
||||
let invoice = result[1][0].invoiceId;
|
||||
|
||||
if (serial != 'R' && invoice) {
|
||||
query = `CALL vn.invoiceOutBooking(?)`;
|
||||
|
@ -62,9 +62,11 @@ module.exports = function(Self) {
|
|||
|
||||
let user = await Self.app.models.Worker.findOne({where: {userFk: userId}});
|
||||
|
||||
query = `INSERT INTO vn2008.Colas(Id_Informe,Cola,Id_Trabajador) VALUES (?, ?, ?)`;
|
||||
query = `INSERT INTO printServerQueue(reportFk, param1, workerFk) VALUES (?, ?, ?)`;
|
||||
await Self.rawSql(query, [3, invoice, user.id], options);
|
||||
await options.transaction.commit();
|
||||
|
||||
return {invoiceFk: invoice, serial};
|
||||
} catch (e) {
|
||||
options.transaction.rollback();
|
||||
throw e;
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
|
||||
describe('ticket makeInvoice()', () => {
|
||||
let invoice;
|
||||
|
||||
afterAll(async done => {
|
||||
let ticket = await app.models.Ticket.findById(11);
|
||||
ticket.updateAttributes({refFk: null});
|
||||
|
||||
let ticketTracking = await app.models.TicketTracking.findOne({order: 'id DESC', limit: 1});
|
||||
ticketTracking.destroy();
|
||||
|
||||
let invoiceOut = await app.models.InvoiceOut.findById(invoice.invoiceFk);
|
||||
invoiceOut.destroy();
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it('should invoice a ticket', async() => {
|
||||
let ctx = {req: {accessToken: {userId: 9}}};
|
||||
let ticketFk = 11;
|
||||
invoice = await app.models.Ticket.makeInvoice(ctx, ticketFk);
|
||||
|
||||
expect(invoice.invoiceFk).not.toBeNaN();
|
||||
expect(invoice.serial).toEqual('T');
|
||||
});
|
||||
|
||||
it('should not invoice an already invoiced ticket', async() => {
|
||||
let ctx = {req: {accessToken: {userId: 9}}};
|
||||
let ticketFk = 11;
|
||||
let error;
|
||||
|
||||
await app.models.Ticket.makeInvoice(ctx, ticketFk).catch(e => {
|
||||
error = e;
|
||||
}).finally(() => {
|
||||
expect(error.message).toEqual(`This ticket can't be invoiced`);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -179,6 +179,15 @@
|
|||
</tpl-buttons>
|
||||
</vn-dialog>
|
||||
|
||||
<!-- Make invoice dialog -->
|
||||
<vn-confirm
|
||||
vn-id="invoiceMakeConfirmation"
|
||||
on-response="$ctrl.invoiceMakeOut(response)"
|
||||
question="You are going to invoice this ticket"
|
||||
message="Are you sure you want to invoice this ticket?">
|
||||
</vn-confirm>
|
||||
<!-- Make invoice dialog -->
|
||||
|
||||
<!-- SMS Dialog -->
|
||||
<vn-client-sms vn-id="sms" sms="$ctrl.newSMS"></vn-client-sms>
|
||||
<!-- SMS Dialog -->
|
|
@ -1,21 +1,23 @@
|
|||
import ngModule from '../module';
|
||||
|
||||
class Controller {
|
||||
constructor($state, $scope, $http, vnApp, $translate) {
|
||||
constructor($state, $scope, $http, vnApp, $translate, aclService) {
|
||||
this.$scope = $scope;
|
||||
this.$state = $state;
|
||||
this.$http = $http;
|
||||
this.vnApp = vnApp;
|
||||
this.$translate = $translate;
|
||||
this.aclService = aclService;
|
||||
this.moreOptions = [
|
||||
{callback: this.showAddTurnDialog, name: 'Add turn', show: true},
|
||||
{callback: this.showAddTurnDialog, name: 'Add turn'},
|
||||
{callback: this.showAddStowaway, name: 'Add stowaway', show: () => this.isTicketModule()},
|
||||
{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.showSMSDialog, name: 'Send SMS', show: true},
|
||||
{callback: this.openRptRoute, name: 'Show pallet report', show: true}
|
||||
{callback: this.showInvoiceOutMakeDialog, name: 'Make invoice', acl: 'invoicing'},
|
||||
{callback: this.showDeliveryNote, name: 'Show Delivery Note'},
|
||||
{callback: this.showDeleteTicketDialog, name: 'Delete ticket'},
|
||||
{callback: this.showChangeShipped, name: 'Change shipped hour'},
|
||||
{callback: this.showSMSDialog, name: 'Send SMS'},
|
||||
{callback: this.openRptRoute, name: 'Show pallet report'}
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -64,7 +66,12 @@ class Controller {
|
|||
|
||||
onMoreOpen() {
|
||||
let options = this.moreOptions.filter(option => {
|
||||
return option.show === true || typeof option.show === 'function' && option.show();
|
||||
const hasShowProperty = Object.hasOwnProperty.call(option, 'show');
|
||||
const hasAclProperty = Object.hasOwnProperty.call(option, 'acl');
|
||||
const hasAcl = !hasAclProperty || (hasAclProperty && this.aclService.hasAny([option.acl]));
|
||||
|
||||
return (!hasShowProperty || option.show === true ||
|
||||
typeof option.show === 'function' && option.show()) && hasAcl;
|
||||
});
|
||||
this.$scope.moreButton.data = options;
|
||||
}
|
||||
|
@ -180,9 +187,32 @@ class Controller {
|
|||
};
|
||||
this.$scope.sms.open();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows an invoice confirmation
|
||||
*/
|
||||
showInvoiceOutMakeDialog() {
|
||||
this.$scope.invoiceMakeConfirmation.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes an invoice
|
||||
* from current ticket
|
||||
*
|
||||
* @param {String} response - Response result
|
||||
*/
|
||||
invoiceMakeOut(response) {
|
||||
if (response === 'ACCEPT') {
|
||||
const query = `/ticket/api/Tickets/${this.ticket.id}/makeInvoice`;
|
||||
this.$http.post(query).then(() => {
|
||||
this.vnApp.showSuccess(this.$translate.instant('Ticket invoiced'));
|
||||
this.$state.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$state', '$scope', '$http', 'vnApp', '$translate'];
|
||||
Controller.$inject = ['$state', '$scope', '$http', 'vnApp', '$translate', 'aclService'];
|
||||
|
||||
ngModule.component('vnTicketDescriptor', {
|
||||
template: require('./index.html'),
|
||||
|
|
|
@ -77,5 +77,20 @@ describe('Ticket Component vnTicketDescriptor', () => {
|
|||
expect(window.open).toHaveBeenCalledWith(expectedPath);
|
||||
});
|
||||
});
|
||||
|
||||
describe('invoiceMakeOut(response)', () => {
|
||||
it('should make a query and call $state.reload() method if the response is ACCEPT', () => {
|
||||
spyOn(controller.$state, 'reload');
|
||||
spyOn(controller.vnApp, 'showSuccess');
|
||||
|
||||
$httpBackend.when('POST', `/ticket/api/Tickets/2/makeInvoice`).respond();
|
||||
$httpBackend.expect('POST', `/ticket/api/Tickets/2/makeInvoice`).respond();
|
||||
controller.invoiceMakeOut('ACCEPT');
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Ticket invoiced');
|
||||
expect(controller.$state.reload).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ Stowaways to add: Polizones a añadir
|
|||
Stowaways of the ticket: Polizones del ticket
|
||||
Add stowaway: Añadir polizón
|
||||
Remove stowaway: Borrar polizón
|
||||
Are you sure you want to delete this stowaway?: ¿Estas seguro de que quieres borrar este polizón?
|
||||
Are you sure you want to delete this stowaway?: ¿Seguro que quieres borrar este polizón?
|
||||
Show Delivery Note: Ver albarán
|
||||
Show pallet report: Mostrar hoja de pallet
|
||||
Change shipped hour: Cambiar hora de envío
|
||||
|
@ -14,3 +14,7 @@ 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.
|
||||
Ticket invoiced: Ticket facturado
|
||||
Make invoice: Facturar
|
||||
You are going to invoice this ticket: Vas a facturar este ticket
|
||||
Are you sure you want to invoice this ticket?: ¿Seguro que quieres facturar este ticket?
|
|
@ -15,6 +15,7 @@
|
|||
style="width: 100%"
|
||||
panel="vn-ticket-search-panel"
|
||||
on-search="$ctrl.onSearch($params)"
|
||||
info="Search ticket by id or alias"
|
||||
vn-focus>
|
||||
</vn-searchbar>
|
||||
<vn-icon-menu
|
||||
|
|
|
@ -60,6 +60,7 @@ Risk: Riesgo
|
|||
Invoice: Factura
|
||||
You are going to delete this ticket: Vas a eliminar este ticket
|
||||
Ticket deleted: Ticket borrado
|
||||
Search ticket by id or alias: Buscar tickets por identificador o alias
|
||||
|
||||
#sections
|
||||
List: Listado
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
<vn-td number>
|
||||
<vn-check vn-one
|
||||
field="::request.isOk"
|
||||
triple-state="true"
|
||||
disabled="true">
|
||||
</vn-check>
|
||||
</vn-td>
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
vn-one
|
||||
label="General search"
|
||||
model="filter.search"
|
||||
info="Search ticket by id or alias"
|
||||
vn-focus>
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
panel="vn-travel-search-panel"
|
||||
model="model"
|
||||
expr-builder="$ctrl.exprBuilder(param, value)"
|
||||
info="Search travels by id"
|
||||
vn-focus>
|
||||
</vn-searchbar>
|
||||
</vn-card>
|
||||
|
|
|
@ -7,6 +7,7 @@ Landed: F. llegada
|
|||
Delivered: Enviado
|
||||
Received: Recibido
|
||||
Travel id: Id envío
|
||||
Search travels by id: Buscar envios por identificador
|
||||
|
||||
# Sections
|
||||
Travels: Envíos
|
|
@ -5,6 +5,7 @@
|
|||
vn-one
|
||||
label="General search"
|
||||
model="filter.search"
|
||||
info="Search travels by id"
|
||||
vn-focus>
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="/agency/api/Workers/filter"
|
||||
url="/worker/api/Workers/filter"
|
||||
limit="20"
|
||||
order="id"
|
||||
data="workers">
|
||||
|
@ -13,6 +13,7 @@
|
|||
style="width: 100%"
|
||||
panel="vn-worker-search-panel"
|
||||
on-search="$ctrl.onSearch($params)"
|
||||
info="Search workers by id, firstName, lastName or user name"
|
||||
vn-focus>
|
||||
</vn-searchbar>
|
||||
<vn-icon-menu
|
||||
|
|
|
@ -15,3 +15,4 @@ Fiscal Identifier: NIF
|
|||
User name: Usuario
|
||||
Departments: Departamentos
|
||||
Calendar: Calendario
|
||||
Search workers by id, firstName, lastName or user name: Buscar trabajadores por el identificador, nombre, apellidos o nombre de usuario
|
|
@ -5,6 +5,7 @@
|
|||
vn-one
|
||||
label="General search"
|
||||
model="filter.search"
|
||||
info="Search workers by id, firstName, lastName or user name"
|
||||
vn-focus>
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
|
|
Loading…
Reference in New Issue