Merge branch 'dev' of http://git.verdnatura.es/salix into dev

This commit is contained in:
Carlos Jimenez 2018-08-31 11:25:30 +02:00
commit bc2554e6f9
24 changed files with 227 additions and 375 deletions

View File

@ -1,9 +0,0 @@
import FilterList from 'core/src/lib/filter-list';
export default class FilterClientList extends FilterList {
constructor($scope, $timeout, $state) {
super($scope, $timeout, $state);
this.modelName = 'clientFk';
}
}
FilterClientList.$inject = ['$scope', '$timeout', '$state'];

View File

@ -1,45 +0,0 @@
/**
* Generic class to list models.
*/
export default class FilterList {
constructor($scope, $timeout, $state) {
this.$ = $scope;
this.$timeout = $timeout;
this.$state = $state;
this.waitingMgCrud = 0;
this.modelId = $state.params.id;
this.instances = [];
}
onOrder(field, order) {
this.filter(`${field} ${order}`);
}
filter(order) {
if (this.$.index && this.modelId && this.modelName) {
this.waitingMgCrud = 0;
this.$.index.filter = {
page: 1,
size: 10
};
this.$.index.filter[this.modelName] = this.modelId;
if (order) {
this.$.index.filter.order = order;
}
this.$.index.accept().then(res => {
this.instances = res.instances;
});
} else if (!this.modelId || !this.modelName) {
throw new Error('Error: model not found');
} else if (this.waitingMgCrud > 3) {
throw new Error('Error: Magic Crud is not loaded');
} else {
this.waitingMgCrud++;
this.$timeout(() => {
this.filter(order);
}, 250);
}
}
}

View File

@ -4,7 +4,6 @@ import './app';
import './interceptor';
import './acl-service';
import './storage-services';
import './filter-list';
import './template';
import './spliting-register';
import './interpolate';

View File

@ -1,9 +0,0 @@
import FilterList from 'core/src/lib/filter-list';
export default class FilterItemList extends FilterList {
constructor($scope, $timeout, $state) {
super($scope, $timeout, $state);
this.modelName = 'itemFk';
}
}
FilterItemList.$inject = ['$scope', '$timeout', '$state'];

View File

@ -1,7 +1,6 @@
export * from './module';
import './index';
import './filter-item-list';
import './search-panel';
import './diary';
import './create';

View File

@ -1,4 +1,10 @@
<mg-ajax path="/ticket/api/Sales/saleComponentFilter" options="vnIndexNonAuto" actions="$ctrl.sales = index.model.instances"></mg-ajax>
<vn-crud-model
vn-id="model"
url="/ticket/api/Sales"
link="{ticketFk: $ctrl.$stateParams.id}"
filter="::$ctrl.filter"
data="components">
</vn-crud-model>
<vn-vertical>
<vn-card pad-large>
<vn-vertical>
@ -32,7 +38,7 @@
</td>
</tr>
</tfoot>
<tbody ng-repeat="sale in $ctrl.sales track by sale.id">
<tbody ng-repeat="sale in components track by sale.id">
<tr>
<td rowspan="{{
::sale.components.length + 1
@ -61,13 +67,13 @@
first: $index == 0,last: $index == sale.components.length - 1
}" number>{{::sale.quantity * component.value | currency:'€':3}}</td>
</tr>
<tr ng-if="index.model.count === 0" class="list list-element">
<tr ng-if="model.data.length === 0" class="list list-element">
<td colspan="7" style="text-align: center" translate>No results</td>
</tr>
</tbody>
</table>
</vn-vertical>
<vn-paging vn-one margin-large-top index="index" total="index.model.count"></vn-paging>
<!-- <vn-paging vn-one margin-large-top index="index" total="index.model.count"></vn-paging> -->
</vn-card>
</vn-vertical>
<vn-item-descriptor-popover vn-id="descriptor"></vn-item-descriptor-popover>

View File

@ -1,46 +1,89 @@
import ngModule from '../module';
import './style.scss';
import FilterTicketList from '../filter-ticket-list';
class Controller extends FilterTicketList {
constructor($scope, $timeout, $stateParams) {
super($scope, $timeout, $stateParams);
class Controller {
constructor($scope, $stateParams) {
this.$stateParams = $stateParams;
this.$scope = $scope;
this.onOrder('itemFk', 'ASC');
this.filter = {
order: 'concept ASC',
include: [{
relation: 'item',
scope: {
include: {
relation: 'tags',
scope: {
fields: ['tagFk', 'value'],
include: {
relation: 'tag',
scope: {
fields: ['name']
}
},
limit: 6
}
},
fields: ['itemFk', 'name']
}
},
{
relation: 'components',
scope: {
fields: ['componentFk', 'value'],
include: {
relation: 'componentRate',
scope: {
fields: ['componentTypeRate', 'name'],
include: {
relation: 'componentType',
scope: {
fields: ['type']
}
}
}
}
}
}]
};
}
total() {
let sum;
if (this.sales) {
sum = 0;
for (let sale of this.sales)
for (let component of sale.components)
sum += sale.quantity * component.value;
}
let sales = this.$scope.model.data;
let sum = 0;
if (!sales) return;
for (let sale of sales)
for (let component of sale.components)
sum += sale.quantity * component.value;
return sum;
}
base() {
let sum;
if (this.sales) {
sum = 0;
for (let sale of this.sales)
for (let component of sale.components)
if (component.componentRate.name == 'valor de compra')
sum += sale.quantity * component.value;
}
let sales = this.$scope.model.data;
let sum = 0;
if (!sales) return;
for (let sale of sales)
for (let component of sale.components)
if (component.componentRate.name == 'valor de compra')
sum += sale.quantity * component.value;
return sum;
}
profitMargin() {
let sum;
if (this.sales) {
sum = 0;
for (let sale of this.sales)
for (let component of sale.components)
if (component.componentRate.name != 'valor de compra')
sum += sale.quantity * component.value;
}
let sales = this.$scope.model.data;
let sum = 0;
if (!sales) return;
for (let sale of sales)
for (let component of sale.components)
if (component.componentRate.name != 'valor de compra')
sum += sale.quantity * component.value;
return sum;
}
@ -55,7 +98,7 @@ class Controller extends FilterTicketList {
}
}
Controller.$inject = ['$scope', '$timeout', '$state'];
Controller.$inject = ['$scope', '$stateParams'];
ngModule.component('vnTicketComponents', {
template: require('./index.html'),

View File

@ -1,41 +1,44 @@
import './index.js';
import {crudModel} from '../../../helpers/crudModelHelper';
describe('ticket', () => {
describe('Component vnTicketComponents', () => {
let $componentController;
let $state;
let $scope;
let controller;
beforeEach(() => {
angular.mock.module('ticket');
});
beforeEach(angular.mock.inject((_$componentController_, _$state_) => {
beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$state_) => {
$componentController = _$componentController_;
$state = _$state_;
$state.params.id = '1';
controller = $componentController('vnTicketComponents');
$scope = $rootScope.$new();
$scope.model = crudModel;
$scope.model.data = [{
components: [
{componentRate: {name: 'valor de compra'}, value: 5},
{componentRate: {name: 'reparto'}, value: 5},
{componentRate: {name: 'recobro'}, value: 5}
],
quantity: 1
},
{
components: [
{componentRate: {name: 'valor de compra'}, value: 1},
{componentRate: {name: 'reparto'}, value: 1},
{componentRate: {name: 'recobro'}, value: 1}
],
quantity: 5
}];
controller = $componentController('vnTicketComponents', {$scope});
}));
describe('total()', () => {
it('should return the sum from all componenets in each sale', () => {
controller.sales = [{
components: [
{componentRate: {name: 'valor de compra'}, value: 5},
{componentRate: {name: 'reparto'}, value: 5},
{componentRate: {name: 'recobro'}, value: 5}
],
quantity: 1
},
{
components: [
{componentRate: {name: 'valor de compra'}, value: 1},
{componentRate: {name: 'reparto'}, value: 1},
{componentRate: {name: 'recobro'}, value: 1}
],
quantity: 5
}
];
let result = controller.total();
expect(result).toEqual(30);

View File

@ -1,9 +0,0 @@
import FilterList from 'core/src/lib/filter-list';
export default class FilterTicketList extends FilterList {
constructor($scope, $timeout, $state) {
super($scope, $timeout, $state);
this.modelName = 'ticketFk';
}
}
FilterTicketList.$inject = ['$scope', '$timeout', '$state'];

View File

@ -2,7 +2,8 @@
import Nightmare from 'nightmare';
export default function createNightmare(width = 1280, height = 720) {
const nightmare = new Nightmare({show: false, typeInterval: 10, x: 0, y: 0}).viewport(width, height);
const nightmare = new Nightmare({show: process.env.E2E_SHOW, typeInterval: 10, x: 0, y: 0})
.viewport(width, height);
nightmare.on('page', (type, message, error) => {
fail(error);

View File

@ -50,8 +50,10 @@ describe('Client', () => {
return nightmare
.waitToClick(selectors.clientPayMethod.payMethodInput)
.waitToClick(selectors.clientPayMethod.payMethodIBANOption)
.waitForTextInInput(selectors.clientPayMethod.payMethodInput, 'PayMethod with IBAN')
.clearInput(selectors.clientPayMethod.dueDayInput)
.type(selectors.clientPayMethod.dueDayInput, '60')
.waitForTextInInput(selectors.clientPayMethod.dueDayInput, '60')
.waitToClick(selectors.clientPayMethod.receivedCoreLCRCheckbox)
.waitToClick(selectors.clientPayMethod.receivedCoreVNLCheckbox)
.waitToClick(selectors.clientPayMethod.receivedB2BVNLCheckbox)
@ -66,6 +68,7 @@ describe('Client', () => {
return nightmare
.clearInput(selectors.clientPayMethod.IBANInput)
.type(selectors.clientPayMethod.IBANInput, 'ES91 2100 0418 4502 0005 1332')
.waitForTextInInput(selectors.clientPayMethod.IBANInput, 'ES91 2100 0418 4502 0005 1332')
.waitToClick(selectors.clientPayMethod.saveButton)
.waitForSnackbar()
.then(result => {

View File

@ -71,6 +71,9 @@ gulp.task('services-only', async () => {
* Runs the e2e tests, restoring the fixtures first.
*/
gulp.task('e2e', ['docker'], async () => {
if (argv.show || argv.s)
process.env.E2E_SHOW = true;
await runSequenceP('e2e-only');
});

View File

@ -1,20 +0,0 @@
module.exports = Self => {
Self.installMethod('filter', filterParams);
function filterParams(params) {
return {
where: {
clientFk: params.clientFk
},
skip: (params.page - 1) * params.size,
limit: params.size,
order: params.order || 'created DESC',
include: {
relation: "worker",
scope: {
fields: ["id", "firstName", "name"]
}
}
};
}
};

View File

@ -0,0 +1,115 @@
USE `vn`;
DROP procedure IF EXISTS `itemDiary`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `itemDiary`(IN vItemId INT, IN vWarehouse INT)
BEGIN
DECLARE vDateInventory DATETIME;
DECLARE vCurdate DATE DEFAULT CURDATE();
DECLARE vDayEnd DATETIME DEFAULT util.dayEnd(vCurdate);
-- traduccion: date, alertLevel, origin, reference, name, In, Out, Balance
SELECT Fechainventario INTO vDateInventory FROM vn2008.tblContadores;
SET @a = 0;
SELECT sql_no_cache DATE(date) AS date,
alertLevel,
stateName,
origin,
reference,
name,
`in`,
`out`,
@a := @a + IFNULL(`in`,0) - IFNULL(`out`,0) as balance,
isPicked,
isTicket
FROM
( SELECT tr.landed as date,
b.quantity as `in`,
NULL as `out`,
IF(tr.isReceived != FALSE,3, IF(tr.isDelivered,1,0)) as alertLevel,
st.name AS stateName,
s.name as name,
e.ref as reference,
e.id as origin,
TRUE isPicked,
FALSE AS isTicket
FROM vn.buy b
JOIN vn.entry e ON e.id = b.entryFk
JOIN vn.travel tr ON tr.id = e.travelFk
JOIN vn.supplier s ON s.id = e.supplierFk
JOIN vn.alertLevel al ON al.alertLevel =
CASE
WHEN tr.isReceived != FALSE THEN 3
WHEN tr.isDelivered THEN 1
ELSE 0
END
JOIN vn.state st ON st.code = al.code
WHERE tr.landed >= vDateInventory
AND vWarehouse = tr.warehouseInFk
AND b.itemFk = vItemId
AND e.isInventory = 0
UNION ALL
SELECT tr.shipped as date,
NULL as `in`,
b.quantity as `out`,
IF(tr.isReceived != FALSE,3, IF(tr.isDelivered,1,0)) as alertLevel,
st.name AS stateName,
s.name as name,
e.ref as reference,
e.id as origin,
TRUE isPicked,
FALSE AS isTicket
FROM vn.buy b
JOIN vn.entry e ON e.id = b.entryFk
JOIN vn.travel tr ON tr.id = e.travelFk
JOIN vn.warehouse w ON w.id = tr.warehouseOutFk
JOIN vn.supplier s ON s.id = e.supplierFk
JOIN vn.alertLevel al ON al.alertLevel =
CASE
WHEN tr.isReceived != FALSE THEN 3
WHEN tr.isDelivered THEN 1
ELSE 0
END
JOIN vn.state st ON st.code = al.code
WHERE tr.shipped >= vDateInventory
AND vWarehouse =tr.warehouseOutFk
AND s.id <> 4
AND b.itemFk = vItemId
AND e.isInventory = 0
AND w.isFeedStock = 0
UNION ALL
SELECT t.shipped as date,
NULL as `in`,
s.quantity as `out`,
al.alertLevel as alertLevel,
st.name AS stateName,
t.nickname as name,
t.refFk as reference,
t.id as origin,
TRUE as isPicked, -- stk.id as isPicked
TRUE as isTicket
FROM vn.sale s
JOIN vn.ticket t ON t.id = s.ticketFk
LEFT JOIN vn.ticketState ts ON ts.ticket = t.id
JOIN vn.client c ON c.id = t.clientFk
JOIN vn.alertLevel al ON al.alertLevel =
CASE
WHEN t.shipped < vCurdate THEN 3
WHEN t.shipped > vDayEnd THEN 0
ELSE IFNULL(ts.alertLevel, 0)
END
JOIN vn.state st ON st.code = al.code
-- LEFT JOIN vn.saleTracking stk ON stk.saleFk = s.id AND stk.stateFk = 14
WHERE t.shipped >= vDateInventory
AND s.itemFk = vItemId
AND vWarehouse =t.warehouseFk
) AS itemDiary
ORDER BY date, alertLevel DESC, isPicked DESC, `in` DESC, `out` DESC;
END$$
DELIMITER ;

View File

@ -1,3 +0,0 @@
module.exports = Self => {
Self.installCrudModel('crudItemBarcodes');
};

View File

@ -1,72 +0,0 @@
// const crudItemBarcodes = require('../crudItemBarcodes');
// const catchErrors = require('../../../../../../services/utils/jasmineHelpers').catchErrors;
// let mysql = require('mysql2');
// describe('Item crudItemBarcodes()', () => {
// let connection;
// beforeAll(() => {
// connection = mysql.createConnection({
// multipleStatements: true,
// host: 'localhost',
// user: 'root',
// password: '',
// database: 'salix'
// });
// });
// it('should call the destroyAll methodif there are ids in delete Array', done => {
// let self = jasmine.createSpyObj('self', ['remoteMethod', 'crudItemBarcodes', 'destroyAll', 'create', 'upsert']);
// crudItemBarcodes(self);
// self.crudItemBarcodes({
// delete: [1],
// create: [],
// update: []
// }).then(result => {
// expect(self.destroyAll).toHaveBeenCalledWith({id: {inq: [1]}});
// done();
// })
// .catch(catchErrors(done));
// });
// it('should call the create method if there are ids in create Array', done => {
// let self = jasmine.createSpyObj('self', ['remoteMethod', 'crudItemBarcodes', 'destroyAll', 'create', 'upsert']);
// crudItemBarcodes(self);
// self.crudItemBarcodes({
// delete: [],
// create: [1],
// update: []
// }).then(result => {
// expect(self.create).toHaveBeenCalledWith([1]);
// done();
// })
// .catch(catchErrors(done));
// });
// it('should call the upsert method as many times as ids in update Array', done => {
// let self = jasmine.createSpyObj('self', ['remoteMethod', 'crudItemBarcodes', 'destroyAll', 'create', 'upsert']);
// crudItemBarcodes(self);
// self.crudItemBarcodes({
// delete: [],
// create: [],
// update: [1, 2]
// }).then(result => {
// expect(self.upsert).toHaveBeenCalledWith(1);
// expect(self.upsert).toHaveBeenCalledWith(2);
// expect(self.upsert.calls.count()).toEqual(2);
// done();
// })
// .catch(catchErrors(done));
// });
// it('should return an error when attempting to save a duplicated barcode', done => {
// let callback = (err, res) => {
// expect(err.toString()).toBe("Error: Duplicate entry '4' for key 'PRIMARY'");
// done();
// };
// connection.query('INSERT INTO `vn`.`itemBarcode` VALUES (4, 2 ,4 );', callback);
// });
// });

View File

@ -1,3 +0,0 @@
module.exports = Self => {
Self.installCrudModel('crudItemNiches');
};

View File

@ -1,51 +0,0 @@
// const crudItemNiches = require('../crudItemNiches');
// const catchErrors = require('../../../../../../services/utils/jasmineHelpers').catchErrors;
// describe('Item crudItemNiches()', () => {
// it('should call the destroyAll method if there are ids in delete Array', done => {
// let self = jasmine.createSpyObj('self', ['remoteMethod', 'crudItemNiches', 'destroyAll', 'create', 'upsert']);
// crudItemNiches(self);
// self.crudItemNiches({
// delete: [1],
// create: [],
// update: []
// }).then(result => {
// expect(self.destroyAll).toHaveBeenCalledWith({id: {inq: [1]}});
// done();
// })
// .catch(catchErrors(done));
// });
// it('should call the create method if there are ids in create Array', done => {
// let self = jasmine.createSpyObj('self', ['remoteMethod', 'crudItemNiches', 'destroyAll', 'create', 'upsert']);
// crudItemNiches(self);
// self.crudItemNiches({
// delete: [],
// create: [1],
// update: []
// }).then(result => {
// expect(self.create).toHaveBeenCalledWith([1]);
// done();
// })
// .catch(catchErrors(done));
// });
// it('should call the upsert method as many times as ids in update Array', done => {
// let self = jasmine.createSpyObj('self', ['remoteMethod', 'crudItemNiches', 'destroyAll', 'create', 'upsert']);
// crudItemNiches(self);
// self.crudItemNiches({
// delete: [],
// create: [],
// update: [1, 2]
// }).then(result => {
// expect(self.upsert).toHaveBeenCalledWith(1);
// expect(self.upsert).toHaveBeenCalledWith(2);
// expect(self.upsert.calls.count()).toEqual(2);
// done();
// })
// .catch(catchErrors(done));
// });
// });

View File

@ -1,6 +1,4 @@
module.exports = Self => {
require('../methods/item-barcode/crudItemBarcodes')(Self);
Self.validatesUniquenessOf('code', {
message: `Barcode must be unique`
});

View File

@ -1,39 +0,0 @@
module.exports = Self => {
Self.installMethod('filter', filterParams);
function filterParams(params) {
return {
where: {
ticketFk: params.ticketFk
},
skip: (params.page - 1) * params.size,
limit: params.size,
order: params.order || 'concept ASC',
include: [{
relation: 'item',
scope: {
include: {
relation: 'tags',
scope: {
fields: ['tagFk', 'value'],
include: {
relation: 'tag',
scope: {
fields: ['name']
}
},
limit: 6
}
},
fields: ['itemFk', 'name']
}
},
{
relation: 'isChecked',
scope: {
fields: ['isChecked']
}
}]
};
}
};

View File

@ -1,51 +0,0 @@
module.exports = Self => {
Self.installMethod('saleComponentFilter', filterParams);
function filterParams(params) {
return {
where: {
ticketFk: params.ticketFk
},
skip: (params.page - 1) * params.size,
limit: params.size,
order: params.order || 'concept ASC',
include: [{
relation: 'item',
scope: {
include: {
relation: 'tags',
scope: {
fields: ['tagFk', 'value'],
include: {
relation: 'tag',
scope: {
fields: ['name']
}
},
limit: 6
}
},
fields: ['itemFk', 'name']
}
},
{
relation: 'components',
scope: {
fields: ['componentFk', 'value'],
include: {
relation: 'componentRate',
scope: {
fields: ['componentTypeRate', 'name'],
include: {
relation: 'componentType',
scope: {
fields: ['type']
}
}
}
}
}
}]
};
}
};

View File

@ -1,7 +1,5 @@
module.exports = Self => {
require('../methods/sale/filter')(Self);
require('../methods/sale/getClaimableFromTicket')(Self);
require('../methods/sale/saleComponentFilter')(Self);
require('../methods/sale/priceDifference')(Self);
require('../methods/sale/moveToTicket')(Self);
require('../methods/sale/reserve')(Self);

View File

@ -1,3 +0,0 @@
module.exports = Self => {
Self.installCrudModel('crudTicketObservation');
};

View File

@ -1,6 +1,4 @@
module.exports = function(Self) {
require('../methods/notes/crudTicketObservation.js')(Self);
/* Self.validateAsync('observationTypeFk', validateObservationUniqueness, {
message: `The observation type can't be repeated`
});