Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 2783-itemPriceFixed_advanced_search
This commit is contained in:
commit
f146c6a279
|
@ -35,3 +35,4 @@ rules:
|
||||||
space-in-parens: ["error", "never"]
|
space-in-parens: ["error", "never"]
|
||||||
jasmine/no-focused-tests: 0
|
jasmine/no-focused-tests: 0
|
||||||
jasmine/prefer-toHaveBeenCalledWith: 0
|
jasmine/prefer-toHaveBeenCalledWith: 0
|
||||||
|
arrow-spacing: ["error", { "before": true, "after": true }]
|
|
@ -49,7 +49,7 @@ pipeline {
|
||||||
NODE_ENV = ""
|
NODE_ENV = ""
|
||||||
}
|
}
|
||||||
steps {
|
steps {
|
||||||
nodejs('node-lts') {
|
nodejs('node-v12') {
|
||||||
sh 'npm install --no-audit --prefer-offline'
|
sh 'npm install --no-audit --prefer-offline'
|
||||||
sh 'gulp install --ci'
|
sh 'gulp install --ci'
|
||||||
}
|
}
|
||||||
|
@ -66,14 +66,14 @@ pipeline {
|
||||||
parallel {
|
parallel {
|
||||||
stage('Frontend') {
|
stage('Frontend') {
|
||||||
steps {
|
steps {
|
||||||
nodejs('node-lts') {
|
nodejs('node-v12') {
|
||||||
sh 'jest --ci --reporters=default --reporters=jest-junit --maxWorkers=2'
|
sh 'jest --ci --reporters=default --reporters=jest-junit --maxWorkers=2'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// stage('Backend') {
|
// stage('Backend') {
|
||||||
// steps {
|
// steps {
|
||||||
// nodejs('node-lts') {
|
// nodejs('node-v12') {
|
||||||
// sh 'gulp launchBackTest --ci'
|
// sh 'gulp launchBackTest --ci'
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
@ -89,7 +89,7 @@ pipeline {
|
||||||
CREDS = credentials('docker-registry')
|
CREDS = credentials('docker-registry')
|
||||||
}
|
}
|
||||||
steps {
|
steps {
|
||||||
nodejs('node-lts') {
|
nodejs('node-v12') {
|
||||||
sh 'gulp build'
|
sh 'gulp build'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethodCtx('notifyIssues', {
|
||||||
|
description: 'Notifies new urgent issues',
|
||||||
|
accessType: 'READ',
|
||||||
|
returns: {
|
||||||
|
type: 'Object',
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/notifyIssues`,
|
||||||
|
verb: 'GET'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.notifyIssues = async ctx => {
|
||||||
|
const models = Self.app.models;
|
||||||
|
const $t = ctx.req.__; // $translate
|
||||||
|
const [urgentIssue] = await Self.rawSql(`
|
||||||
|
SELECT * FROM managedesktop.vn_workOrderInmediata LIMIT 1
|
||||||
|
`);
|
||||||
|
|
||||||
|
if (!urgentIssue) return;
|
||||||
|
|
||||||
|
const message = $t(`There's a new urgent ticket`, {
|
||||||
|
title: urgentIssue.title,
|
||||||
|
issueId: urgentIssue.workOrderId
|
||||||
|
});
|
||||||
|
|
||||||
|
const department = await models.Department.findOne({
|
||||||
|
where: {code: 'IT'}
|
||||||
|
});
|
||||||
|
const channelName = department && department.chatName;
|
||||||
|
|
||||||
|
if (channelName)
|
||||||
|
return Self.send(ctx, `#${channelName}`, `@all ➔ ${message}`);
|
||||||
|
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,38 @@
|
||||||
|
const app = require('vn-loopback/server/server');
|
||||||
|
|
||||||
|
describe('Chat notifyIssue()', () => {
|
||||||
|
const ctx = {req: {accessToken: {userId: 1}}};
|
||||||
|
ctx.req.__ = value => {
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
const chatModel = app.models.Chat;
|
||||||
|
const departmentId = 31;
|
||||||
|
|
||||||
|
it(`should not call to the send() method and neither return a response`, async() => {
|
||||||
|
spyOn(chatModel, 'send').and.callThrough();
|
||||||
|
spyOn(chatModel, 'rawSql').and.returnValue([]);
|
||||||
|
|
||||||
|
const response = await chatModel.notifyIssues(ctx);
|
||||||
|
|
||||||
|
expect(chatModel.send).not.toHaveBeenCalled();
|
||||||
|
expect(response).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should return a response calling the send() method`, async() => {
|
||||||
|
spyOn(chatModel, 'send').and.callThrough();
|
||||||
|
spyOn(chatModel, 'rawSql').and.returnValue([{title: 'Issue title'}]);
|
||||||
|
|
||||||
|
const department = await app.models.Department.findById(departmentId);
|
||||||
|
let orgChatName = department.chatName;
|
||||||
|
await department.updateAttribute('chatName', 'IT');
|
||||||
|
|
||||||
|
const response = await chatModel.notifyIssues(ctx);
|
||||||
|
|
||||||
|
expect(response.statusCode).toEqual(200);
|
||||||
|
expect(response.message).toEqual('Fake notification sent');
|
||||||
|
expect(chatModel.send).toHaveBeenCalledWith(ctx, '#IT', `@all ➔ There's a new urgent ticket`);
|
||||||
|
|
||||||
|
// restores
|
||||||
|
await department.updateAttribute('chatName', orgChatName);
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,6 +1,6 @@
|
||||||
const app = require('vn-loopback/server/server');
|
const app = require('vn-loopback/server/server');
|
||||||
|
|
||||||
describe('chat send()', () => {
|
describe('Chat send()', () => {
|
||||||
it('should return a "Fake notification sent" as response', async() => {
|
it('should return a "Fake notification sent" as response', async() => {
|
||||||
let ctx = {req: {accessToken: {userId: 1}}};
|
let ctx = {req: {accessToken: {userId: 1}}};
|
||||||
let response = await app.models.Chat.send(ctx, '@salesPerson', 'I changed something');
|
let response = await app.models.Chat.send(ctx, '@salesPerson', 'I changed something');
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
const app = require('vn-loopback/server/server');
|
const app = require('vn-loopback/server/server');
|
||||||
|
|
||||||
describe('chat sendCheckingPresence()', () => {
|
describe('Chat sendCheckingPresence()', () => {
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
today.setHours(6, 0);
|
today.setHours(6, 0);
|
||||||
const ctx = {req: {accessToken: {userId: 1}}};
|
const ctx = {req: {accessToken: {userId: 1}}};
|
||||||
|
|
|
@ -11,25 +11,36 @@ module.exports = Self => {
|
||||||
type: 'Number',
|
type: 'Number',
|
||||||
description: 'The document id',
|
description: 'The document id',
|
||||||
http: {source: 'path'}
|
http: {source: 'path'}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
arg: 'warehouseId',
|
arg: 'warehouseId',
|
||||||
type: 'Number',
|
type: 'Number',
|
||||||
description: 'The warehouse id'
|
description: 'The warehouse id'
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
arg: 'companyId',
|
arg: 'companyId',
|
||||||
type: 'Number',
|
type: 'Number',
|
||||||
description: 'The company id'
|
description: 'The company id'
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
arg: 'dmsTypeId',
|
arg: 'dmsTypeId',
|
||||||
type: 'Number',
|
type: 'Number',
|
||||||
description: 'The dms type id'
|
description: 'The dms type id'
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
arg: 'reference',
|
arg: 'reference',
|
||||||
type: 'String'
|
type: 'String'
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
arg: 'description',
|
arg: 'description',
|
||||||
type: 'String'
|
type: 'String'
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
|
arg: 'hasFile',
|
||||||
|
type: 'Boolean',
|
||||||
|
description: 'True if has an attached file'
|
||||||
|
},
|
||||||
|
{
|
||||||
arg: 'hasFileAttached',
|
arg: 'hasFileAttached',
|
||||||
type: 'Boolean',
|
type: 'Boolean',
|
||||||
description: 'True if has an attached file'
|
description: 'True if has an attached file'
|
||||||
|
@ -70,7 +81,8 @@ module.exports = Self => {
|
||||||
companyFk: args.companyId,
|
companyFk: args.companyId,
|
||||||
warehouseFk: args.warehouseId,
|
warehouseFk: args.warehouseId,
|
||||||
reference: args.reference,
|
reference: args.reference,
|
||||||
description: args.description
|
description: args.description,
|
||||||
|
hasFile: args.hasFile
|
||||||
}, myOptions);
|
}, myOptions);
|
||||||
|
|
||||||
if (args.hasFileAttached)
|
if (args.hasFileAttached)
|
||||||
|
|
|
@ -57,6 +57,9 @@ module.exports = Self => {
|
||||||
const entity = await models[imageCollection.model].findById(id, {
|
const entity = await models[imageCollection.model].findById(id, {
|
||||||
fields: ['id', imageCollection.property]
|
fields: ['id', imageCollection.property]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!entity) return false;
|
||||||
|
|
||||||
const image = await models.Image.findOne({where: {
|
const image = await models.Image.findOne({where: {
|
||||||
collectionFk: collection,
|
collectionFk: collection,
|
||||||
name: entity[imageCollection.property]}
|
name: entity[imageCollection.property]}
|
||||||
|
|
|
@ -35,6 +35,15 @@
|
||||||
"DmsContainer": {
|
"DmsContainer": {
|
||||||
"dataSource": "dmsStorage"
|
"dataSource": "dmsStorage"
|
||||||
},
|
},
|
||||||
|
"Dms": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
|
"DmsType": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
|
"EmailUser": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
"Image": {
|
"Image": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
@ -53,38 +62,32 @@
|
||||||
"Province": {
|
"Province": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
"TempContainer": {
|
"Payment": {
|
||||||
"dataSource": "tempStorage"
|
|
||||||
},
|
|
||||||
"UserConfig": {
|
|
||||||
"dataSource": "vn"
|
|
||||||
},
|
|
||||||
"Warehouse": {
|
|
||||||
"dataSource": "vn"
|
|
||||||
},
|
|
||||||
"SageWithholding": {
|
|
||||||
"dataSource": "vn"
|
|
||||||
},
|
|
||||||
"UserConfigView": {
|
|
||||||
"dataSource": "vn"
|
|
||||||
},
|
|
||||||
"EmailUser": {
|
|
||||||
"dataSource": "vn"
|
|
||||||
},
|
|
||||||
"Dms": {
|
|
||||||
"dataSource": "vn"
|
|
||||||
},
|
|
||||||
"DmsType": {
|
|
||||||
"dataSource": "vn"
|
|
||||||
},
|
|
||||||
"Town": {
|
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
"Postcode": {
|
"Postcode": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
"SageWithholding": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
|
"TempContainer": {
|
||||||
|
"dataSource": "tempStorage"
|
||||||
|
},
|
||||||
|
"Town": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
|
"UserConfig": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
|
"UserConfigView": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
"UserLog": {
|
"UserLog": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
|
"Warehouse": {
|
||||||
|
"dataSource": "vn"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,17 +8,20 @@
|
||||||
},
|
},
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"id": {
|
||||||
"type": "Number",
|
"type": "number",
|
||||||
"id": true,
|
"id": true,
|
||||||
"description": "Identifier"
|
"description": "Identifier"
|
||||||
},
|
},
|
||||||
"description": {
|
"description": {
|
||||||
"type": "String",
|
"type": "string",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
"receiptDescription": {
|
"receiptDescription": {
|
||||||
"type": "String",
|
"type": "string",
|
||||||
"required": true
|
"required": true
|
||||||
|
},
|
||||||
|
"code": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"acls": [{
|
"acls": [{
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
require('../methods/chat/send')(Self);
|
require('../methods/chat/send')(Self);
|
||||||
require('../methods/chat/sendCheckingPresence')(Self);
|
require('../methods/chat/sendCheckingPresence')(Self);
|
||||||
|
require('../methods/chat/notifyIssues')(Self);
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
},
|
},
|
||||||
"expired": {
|
"expired": {
|
||||||
"type": "date"
|
"type": "date"
|
||||||
|
},
|
||||||
|
"isOfficial": {
|
||||||
|
"type": "boolean"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"hardCopyNumber": {
|
"hardCopyNumber": {
|
||||||
"type": "Number"
|
"type": "number"
|
||||||
},
|
},
|
||||||
"hasFile": {
|
"hasFile": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
"nRefs": {
|
"nRefs": {
|
||||||
"type": "Number",
|
"type": "Number",
|
||||||
"required": true,
|
"required": true,
|
||||||
"default": 0
|
"default": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"relations": {
|
"relations": {
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
{
|
||||||
|
"name": "Payment",
|
||||||
|
"base": "VnModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "payment"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "number",
|
||||||
|
"id": true,
|
||||||
|
"description": "Identifier"
|
||||||
|
},
|
||||||
|
"received": {
|
||||||
|
"type": "date"
|
||||||
|
},
|
||||||
|
"amount": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"divisa": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"concept": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"created": {
|
||||||
|
"type": "date"
|
||||||
|
},
|
||||||
|
"isConciliated": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"dueDated": {
|
||||||
|
"type": "date"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"relations": {
|
||||||
|
"supplier": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Supplier",
|
||||||
|
"foreignKey": "supplierFk"
|
||||||
|
},
|
||||||
|
"currency": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Currency",
|
||||||
|
"foreignKey": "currencyFk"
|
||||||
|
},
|
||||||
|
"bank": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Bank",
|
||||||
|
"foreignKey": "bankFk"
|
||||||
|
},
|
||||||
|
"payMethod": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "PayMethodFk",
|
||||||
|
"foreignKey": "payMethodFk"
|
||||||
|
},
|
||||||
|
"company": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Company",
|
||||||
|
"foreignKey": "companyFk"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,2 +1 @@
|
||||||
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');
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('FixedPrice', '*', '*', 'ALLOW', 'ROLE', 'buyer');
|
||||||
|
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('PayDem', '*', 'READ', 'ALLOW', 'ROLE', 'employee');
|
||||||
|
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('Client', 'createReceipt', '*', 'ALLOW', 'ROLE', 'administrative');
|
||||||
INSERT INTO salix.ACL (model, property, accessType, permission, principalType, principalId)
|
INSERT INTO salix.ACL (model, property, accessType, permission, principalType, principalId)
|
||||||
VALUES ('PrintServerQueue', '*', 'WRITE', 'ALLOW', 'ROLE', 'employee');
|
VALUES ('PrintServerQueue', '*', 'WRITE', 'ALLOW', 'ROLE', 'employee');
|
||||||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('FixedPrice', '*', '*', 'ALLOW', 'ROLE', 'buyer');
|
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
DROP PROCEDURE IF EXISTS vn.ledger_doCompensation;
|
||||||
|
|
||||||
|
|
||||||
|
DELIMITER $$
|
||||||
|
$$
|
||||||
|
CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`ledger_doCompensation`(vDated DATE, vCompensationAccount VARCHAR(10) , vBankFk VARCHAR(10), vConcept VARCHAR(255), vAmount DECIMAL(10,2), vCompanyFk INT, vOriginalAccount VARCHAR(10))
|
||||||
|
BEGIN
|
||||||
|
/**
|
||||||
|
* Compensa un pago o un recibo insertando en contabilidad
|
||||||
|
*
|
||||||
|
* @param vDated fecha en la cual se anota
|
||||||
|
* @param vCompensationAccount cuenta contable contra la que se compensa
|
||||||
|
* @param vBankFk banco de la compensacion
|
||||||
|
* @param vConcept descripcion
|
||||||
|
* @param vAmount cantidad que se compensa
|
||||||
|
* @param vCompany empresa
|
||||||
|
* @param vOriginalAccount cuenta contable desde la cual se compensa
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
DECLARE vNewBookEntry INT;
|
||||||
|
DECLARE vIsClientCompensation INT;
|
||||||
|
DECLARE vClientFk INT;
|
||||||
|
DECLARE vSupplierFk INT;
|
||||||
|
DECLARE vIsOriginalAClient BOOL;
|
||||||
|
DECLARE vPayMethodCompensation INT;
|
||||||
|
|
||||||
|
CALL ledger_next(vNewBookEntry);
|
||||||
|
|
||||||
|
SELECT COUNT(id) INTO vIsOriginalAClient FROM client WHERE accountingAccount LIKE vOriginalAccount COLLATE utf8_general_ci;
|
||||||
|
|
||||||
|
SELECT id, COUNT(id) INTO vClientFk, vIsClientCompensation
|
||||||
|
FROM client
|
||||||
|
WHERE accountingAccount LIKE vCompensationAccount COLLATE utf8_general_ci;
|
||||||
|
|
||||||
|
SET @vAmount1:= 0.0;
|
||||||
|
SET @vAmount2:= 0.0;
|
||||||
|
|
||||||
|
INSERT INTO XDiario (ASIEN, FECHA, SUBCTA, CONTRA, CONCEPTO, EURODEBE, EUROHABER, empresa_id)
|
||||||
|
VALUES ( vNewBookEntry,
|
||||||
|
vDated,
|
||||||
|
vOriginalAccount,
|
||||||
|
vCompensationAccount,
|
||||||
|
vConcept,
|
||||||
|
@vAmount1:= IF(
|
||||||
|
(vIsOriginalAClient OR NOT vIsOriginalAClient)
|
||||||
|
AND vAmount > 0,
|
||||||
|
0,
|
||||||
|
ABS(vAmount)
|
||||||
|
),
|
||||||
|
@vAmount2:= IF(@vAmount1,
|
||||||
|
0,
|
||||||
|
ABS(vAmount)
|
||||||
|
),
|
||||||
|
vCompanyFk
|
||||||
|
),
|
||||||
|
( vNewBookEntry,
|
||||||
|
vDated,
|
||||||
|
vCompensationAccount,
|
||||||
|
vOriginalAccount,
|
||||||
|
vConcept,
|
||||||
|
@vAmount2,
|
||||||
|
@vAmount1,
|
||||||
|
vCompanyFk);
|
||||||
|
|
||||||
|
IF vIsClientCompensation THEN
|
||||||
|
IF vIsOriginalAClient THEN
|
||||||
|
SET vAmount = -vAmount;
|
||||||
|
END IF;
|
||||||
|
INSERT INTO receipt(invoiceFk, amountPaid, payed, bankFk, companyFk, clientFk, isConciliate)
|
||||||
|
VALUES (vConcept, vAmount, vDated, vBankFk, vCompanyFk, vClientFk, TRUE);
|
||||||
|
ELSE
|
||||||
|
IF NOT vIsOriginalAClient THEN
|
||||||
|
SET vAmount = -vAmount;
|
||||||
|
END IF;
|
||||||
|
SELECT id INTO vSupplierFk FROM supplier WHERE `account` LIKE vCompensationAccount COLLATE utf8_general_ci;
|
||||||
|
SELECT id INTO vPayMethodCompensation FROM payMethod WHERE `code` = 'compensation';
|
||||||
|
|
||||||
|
INSERT INTO payment (received, dueDated, supplierFk, amount, bankFk, payMethodFk, concept, companyFk, isConciliated)
|
||||||
|
VALUES(vDated, vDated, vSupplierFk, vAmount, vBankFk, vPayMethodCompensation, vConcept, vCompanyFk, TRUE);
|
||||||
|
END IF;
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
|
@ -0,0 +1,17 @@
|
||||||
|
DROP TRIGGER IF EXISTS vn.receipt_beforInsert;
|
||||||
|
|
||||||
|
DELIMITER $$
|
||||||
|
$$
|
||||||
|
CREATE TRIGGER receipt_beforInsert
|
||||||
|
BEFORE INSERT
|
||||||
|
ON receipt FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
SELECT isAutoConciliated INTO @isAutoConciliated
|
||||||
|
FROM accounting a
|
||||||
|
JOIN accountingType at2 ON at2.id = a.accountingTypeFk
|
||||||
|
WHERE a.id =NEW.bankFk;
|
||||||
|
|
||||||
|
SET NEW.isConciliate = @isAutoConciliated;
|
||||||
|
END
|
||||||
|
$$
|
||||||
|
DELIMITER ;
|
|
@ -0,0 +1,4 @@
|
||||||
|
ALTER TABLE `vn`.`department`
|
||||||
|
ADD code VARCHAR(45) NULL AFTER id;
|
||||||
|
|
||||||
|
UPDATE `vn`.`department` t SET t.code = 'IT', t.chatName = 'informatica-cau' WHERE t.id = 31;
|
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE `vn`.`itemImageQueue`
|
||||||
|
ADD attempts INT default 0 NULL AFTER error;
|
|
@ -0,0 +1,137 @@
|
||||||
|
DROP PROCEDURE `vn`.`item_getBalance`;
|
||||||
|
|
||||||
|
DELIMITER $$
|
||||||
|
$$
|
||||||
|
CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`item_getBalance`(IN vItemId INT, IN vWarehouse INT)
|
||||||
|
BEGIN
|
||||||
|
DECLARE vDateInventory DATETIME;
|
||||||
|
DECLARE vCurdate DATE DEFAULT CURDATE();
|
||||||
|
DECLARE vDayEnd DATETIME DEFAULT util.dayEnd(vCurdate);
|
||||||
|
|
||||||
|
SELECT inventoried INTO vDateInventory FROM config;
|
||||||
|
SET @a = 0;
|
||||||
|
SET @currentLineFk = 0;
|
||||||
|
SET @shipped = '';
|
||||||
|
|
||||||
|
SELECT DATE(@shipped:= shipped) shipped,
|
||||||
|
alertLevel,
|
||||||
|
stateName,
|
||||||
|
origin,
|
||||||
|
reference,
|
||||||
|
clientFk,
|
||||||
|
name,
|
||||||
|
`in`,
|
||||||
|
`out`,
|
||||||
|
@a := @a + IFNULL(`in`,0) - IFNULL(`out`,0) as balance,
|
||||||
|
@currentLineFk := IF (@shipped < CURDATE()
|
||||||
|
OR (@shipped = CURDATE() AND (isPicked OR alertLevel >= 2)),
|
||||||
|
lineFk,@currentLineFk) lastPreparedLineFk,
|
||||||
|
isTicket,
|
||||||
|
lineFk,
|
||||||
|
isPicked,
|
||||||
|
clientType
|
||||||
|
FROM
|
||||||
|
( SELECT tr.landed AS shipped,
|
||||||
|
b.quantity AS `in`,
|
||||||
|
NULL AS `out`,
|
||||||
|
al.alertLevel AS alertLevel,
|
||||||
|
st.name AS stateName,
|
||||||
|
s.name AS name,
|
||||||
|
e.ref AS reference,
|
||||||
|
e.id AS origin,
|
||||||
|
s.id AS clientFk,
|
||||||
|
IF(al.alertLevel = 3, TRUE, FALSE) isPicked,
|
||||||
|
FALSE AS isTicket,
|
||||||
|
b.id lineFk,
|
||||||
|
NULL `order`,
|
||||||
|
NULL AS clientType
|
||||||
|
FROM buy b
|
||||||
|
JOIN entry e ON e.id = b.entryFk
|
||||||
|
JOIN travel tr ON tr.id = e.travelFk
|
||||||
|
JOIN supplier s ON s.id = e.supplierFk
|
||||||
|
JOIN alertLevel al ON al.alertLevel =
|
||||||
|
CASE
|
||||||
|
WHEN tr.shipped < CURDATE() THEN 3
|
||||||
|
WHEN tr.shipped = CURDATE() AND tr.isReceived = TRUE THEN 3
|
||||||
|
ELSE 0
|
||||||
|
END
|
||||||
|
JOIN state st ON st.code = al.code
|
||||||
|
WHERE tr.landed >= vDateInventory
|
||||||
|
AND vWarehouse = tr.warehouseInFk
|
||||||
|
AND b.itemFk = vItemId
|
||||||
|
AND e.isInventory = FALSE
|
||||||
|
AND e.isRaid = FALSE
|
||||||
|
UNION ALL
|
||||||
|
|
||||||
|
SELECT tr.shipped,
|
||||||
|
NULL as `in`,
|
||||||
|
b.quantity AS `out`,
|
||||||
|
al.alertLevel AS alertLevel,
|
||||||
|
st.name AS stateName,
|
||||||
|
s.name AS name,
|
||||||
|
e.ref AS reference,
|
||||||
|
e.id AS origin,
|
||||||
|
s.id AS clientFk,
|
||||||
|
IF(al.alertLevel = 3, TRUE, FALSE) isPicked,
|
||||||
|
FALSE AS isTicket,
|
||||||
|
b.id,
|
||||||
|
NULL `order`,
|
||||||
|
NULL AS clientType
|
||||||
|
FROM buy b
|
||||||
|
JOIN entry e ON e.id = b.entryFk
|
||||||
|
JOIN travel tr ON tr.id = e.travelFk
|
||||||
|
JOIN warehouse w ON w.id = tr.warehouseOutFk
|
||||||
|
JOIN supplier s ON s.id = e.supplierFk
|
||||||
|
JOIN alertLevel al ON al.alertLevel =
|
||||||
|
CASE
|
||||||
|
WHEN tr.shipped < CURDATE() THEN 3
|
||||||
|
WHEN tr.shipped = CURDATE() AND tr.isReceived = TRUE THEN 3
|
||||||
|
ELSE 0
|
||||||
|
END
|
||||||
|
JOIN 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 = FALSE
|
||||||
|
AND w.isFeedStock = FALSE
|
||||||
|
AND e.isRaid = FALSE
|
||||||
|
UNION ALL
|
||||||
|
|
||||||
|
SELECT DATE(t.shipped),
|
||||||
|
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,
|
||||||
|
t.clientFk,
|
||||||
|
stk.id AS isPicked,
|
||||||
|
TRUE AS isTicket,
|
||||||
|
s.id,
|
||||||
|
st.`order`,
|
||||||
|
ct.code AS clientType
|
||||||
|
FROM sale s
|
||||||
|
JOIN ticket t ON t.id = s.ticketFk
|
||||||
|
LEFT JOIN ticketState ts ON ts.ticket = t.id
|
||||||
|
LEFT JOIN state st ON st.code = ts.code
|
||||||
|
JOIN client c ON c.id = t.clientFk
|
||||||
|
JOIN clientType ct ON ct.id = c.clientTypeFk
|
||||||
|
JOIN alertLevel al ON al.alertLevel =
|
||||||
|
CASE
|
||||||
|
WHEN t.shipped < curdate() THEN 3
|
||||||
|
WHEN t.shipped > util.dayEnd(curdate()) THEN 0
|
||||||
|
ELSE IFNULL(ts.alertLevel, 0)
|
||||||
|
END
|
||||||
|
LEFT JOIN state stPrep ON stPrep.`code` = 'PREPARED'
|
||||||
|
LEFT JOIN saleTracking stk ON stk.saleFk = s.id AND stk.stateFk = stPrep.id
|
||||||
|
WHERE t.shipped >= vDateInventory
|
||||||
|
AND s.itemFk = vItemId
|
||||||
|
AND vWarehouse =t.warehouseFk
|
||||||
|
ORDER BY shipped, alertLevel DESC, isTicket, `order` DESC, isPicked DESC, `in` DESC, `out` DESC
|
||||||
|
) AS itemDiary;
|
||||||
|
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE `vn`.`supplier` ADD COLUMN `workerFk` INT(11) NULL DEFAULT NULL COMMENT 'Responsible for approving invoices' AFTER `isTrucker`;
|
||||||
|
ALTER TABLE `vn`.`supplier` ADD CONSTRAINT `supplier_workerFk` FOREIGN KEY (`workerFk`) REFERENCES `vn`.`worker` (`id`) ON UPDATE CASCADE;
|
File diff suppressed because one or more lines are too long
|
@ -151,20 +151,19 @@ INSERT INTO `vn`.`shelving` (`code`, `parkingFk`, `isPrinted`, `priority`, `park
|
||||||
INSERT INTO `vn`.`accountingType`(`id`, `description`, `receiptDescription`,`code`)
|
INSERT INTO `vn`.`accountingType`(`id`, `description`, `receiptDescription`,`code`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 'CC y Polizas de crédito', NULL, NULL),
|
(1, 'CC y Polizas de crédito', NULL, NULL),
|
||||||
(2, 'Caja registradora', NULL, NULL),
|
(2, 'Cash', 'Cash', 'cash'),
|
||||||
(3, 'Tarjeta de credito', NULL, NULL),
|
(3, 'Credit card', 'Credit Card', 'creditCard'),
|
||||||
(4, 'Lineas de financiacion', NULL, NULL),
|
(4, 'Finalcial lines', NULL, NULL),
|
||||||
(5, 'Otros productos', NULL, NULL),
|
(5, 'Other products', NULL, NULL),
|
||||||
(6, 'Prestamos', NULL, NULL),
|
(6, 'Loans', NULL, NULL),
|
||||||
(7, 'Leasing', NULL, NULL),
|
(7, 'Leasing', NULL, NULL),
|
||||||
(8, 'Compensaciones', NULL, NULL),
|
(8, 'Compensations', 'Compensations', 'compensation');
|
||||||
(9, 'Cash', 'Cash', NULL),
|
|
||||||
(10, 'Card', 'Pay on receipt', NULL);
|
|
||||||
|
|
||||||
INSERT INTO `vn`.`bank`(`id`, `bank`, `account`, `cash`, `entityFk`, `isActive`, `currencyFk`)
|
INSERT INTO `vn`.`bank`(`id`, `bank`, `account`, `cash`, `entityFk`, `isActive`, `currencyFk`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 'Pay on receipt', '0000000000', 10, 0, 1, 1),
|
(1, 'Pay on receipt', '5720000001', 3, 0, 1, 1),
|
||||||
(2, 'Cash', '1111111111', 9, 0, 1, 1);
|
(2, 'Cash', '5700000001', 2, 0, 1, 1),
|
||||||
|
(3, 'Compensation', '4000000000', 8, 0, 1, 1);
|
||||||
|
|
||||||
INSERT INTO `vn`.`deliveryMethod`(`id`, `code`, `description`)
|
INSERT INTO `vn`.`deliveryMethod`(`id`, `code`, `description`)
|
||||||
VALUES
|
VALUES
|
||||||
|
@ -212,13 +211,13 @@ UPDATE `vn`.`agencyMode` SET `web` = 1;
|
||||||
|
|
||||||
UPDATE `vn`.`agencyMode` SET `code` = 'refund' WHERE `id` = 23;
|
UPDATE `vn`.`agencyMode` SET `code` = 'refund' WHERE `id` = 23;
|
||||||
|
|
||||||
INSERT INTO `vn`.`payMethod`(`id`, `name`, `graceDays`, `outstandingDebt`, `ibanRequired`)
|
INSERT INTO `vn`.`payMethod`(`id`,`code`, `name`, `graceDays`, `outstandingDebt`, `ibanRequired`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 'PayMethod one', 0, 001, 0),
|
(1, NULL, 'PayMethod one', 0, 001, 0),
|
||||||
(2, 'PayMethod two', 10, 001, 0),
|
(2, NULL, 'PayMethod two', 10, 001, 0),
|
||||||
(3, 'PayMethod three', 0, 001, 0),
|
(3, 'compensation', 'PayMethod three', 0, 001, 0),
|
||||||
(4, 'PayMethod with IBAN', 0, 001, 1),
|
(4, NULL, 'PayMethod with IBAN', 0, 001, 1),
|
||||||
(5, 'PayMethod five', 10, 001, 0);
|
(5, NULL, 'PayMethod five', 10, 001, 0);
|
||||||
|
|
||||||
INSERT INTO `vn`.`payDem`(`id`, `payDem`)
|
INSERT INTO `vn`.`payDem`(`id`, `payDem`)
|
||||||
VALUES
|
VALUES
|
||||||
|
@ -271,17 +270,17 @@ INSERT INTO `vn`.`contactChannel`(`id`, `name`)
|
||||||
INSERT INTO `vn`.`client`(`id`,`name`,`fi`,`socialName`,`contact`,`street`,`city`,`postcode`,`phone`,`mobile`,`fax`,`isRelevant`,`email`,`iban`,`dueDay`,`accountingAccount`,`isEqualizated`,`provinceFk`,`hasToInvoice`,`credit`,`countryFk`,`isActive`,`gestdocFk`,`quality`,`payMethodFk`,`created`,`isToBeMailed`,`contactChannelFk`,`hasSepaVnl`,`hasCoreVnl`,`hasCoreVnh`,`riskCalculated`,`clientTypeFk`,`mailAddress`,`cplusTerIdNifFk`,`hasToInvoiceByAddress`,`isTaxDataChecked`,`isFreezed`,`creditInsurance`,`isCreatedAsServed`,`hasInvoiceSimplified`,`salesPersonFk`,`isVies`,`eypbc`)
|
INSERT INTO `vn`.`client`(`id`,`name`,`fi`,`socialName`,`contact`,`street`,`city`,`postcode`,`phone`,`mobile`,`fax`,`isRelevant`,`email`,`iban`,`dueDay`,`accountingAccount`,`isEqualizated`,`provinceFk`,`hasToInvoice`,`credit`,`countryFk`,`isActive`,`gestdocFk`,`quality`,`payMethodFk`,`created`,`isToBeMailed`,`contactChannelFk`,`hasSepaVnl`,`hasCoreVnl`,`hasCoreVnh`,`riskCalculated`,`clientTypeFk`,`mailAddress`,`cplusTerIdNifFk`,`hasToInvoiceByAddress`,`isTaxDataChecked`,`isFreezed`,`creditInsurance`,`isCreatedAsServed`,`hasInvoiceSimplified`,`salesPersonFk`,`isVies`,`eypbc`)
|
||||||
VALUES
|
VALUES
|
||||||
(101, 'Bruce Wayne', '84612325V', 'Batman', 'Alfred', '1007 Mountain Drive, Gotham', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'BruceWayne@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1),
|
(101, 'Bruce Wayne', '84612325V', 'Batman', 'Alfred', '1007 Mountain Drive, Gotham', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'BruceWayne@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1),
|
||||||
(102, 'Petter Parker', '87945234L', 'Spider man', 'Aunt May', '20 Ingram Street', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'PetterParker@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1),
|
(102, 'Petter Parker', '87945234L', 'Spider man', 'Aunt May', '20 Ingram Street, Queens, USA', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'PetterParker@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1),
|
||||||
(103, 'Clark Kent', '06815934E', 'Super man', 'lois lane', '344 Clinton Street', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'ClarkKent@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 0, 19, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1),
|
(103, 'Clark Kent', '06815934E', 'Super man', 'lois lane', '344 Clinton Street, Apartament 3-D', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'ClarkKent@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 0, 19, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1),
|
||||||
(104, 'Tony Stark', '06089160W', 'Iron man', 'Pepper Potts', '10880 Malibu Point', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'TonyStark@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1),
|
(104, 'Tony Stark', '06089160W', 'Iron man', 'Pepper Potts', '10880 Malibu Point, 90265', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'TonyStark@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1),
|
||||||
(105, 'Max Eisenhardt', '251628698', 'Magneto', 'Rogue', 'Unknown Whereabouts', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'MaxEisenhardt@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 8, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 18, 0, 1),
|
(105, 'Max Eisenhardt', '251628698', 'Magneto', 'Rogue', 'Unknown Whereabouts', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'MaxEisenhardt@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 8, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 18, 0, 1),
|
||||||
(106, 'DavidCharlesHaller', '53136686Q', 'Legion', 'Charles Xavier', 'Evil hideout', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'DavidCharlesHaller@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 0, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 19, 0, 1),
|
(106, 'DavidCharlesHaller', '53136686Q', 'Legion', 'Charles Xavier', 'City of New York, New York, USA', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'DavidCharlesHaller@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 0, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 19, 0, 1),
|
||||||
(107, 'Hank Pym', '09854837G', 'Ant man', 'Hawk', 'Anthill', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'HankPym@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 0, 0, NULL, 0, 0, 19, 0, 1),
|
(107, 'Hank Pym', '09854837G', 'Ant man', 'Hawk', 'Anthill, San Francisco, California', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'HankPym@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 0, 0, NULL, 0, 0, 19, 0, 1),
|
||||||
(108, 'Charles Xavier', '22641921P', 'Professor X', 'Beast', '3800 Victory Pkwy, Cincinnati, OH 45207, USA', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'CharlesXavier@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 19, 0, 1),
|
(108, 'Charles Xavier', '22641921P', 'Professor X', 'Beast', '3800 Victory Pkwy, Cincinnati, OH 45207, USA', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'CharlesXavier@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 19, 0, 1),
|
||||||
(109, 'Bruce Banner', '16104829E', 'Hulk', 'Black widow', 'Somewhere in New York', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'BruceBanner@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 0, 0, NULL, 0, 0, 19, 0, 1),
|
(109, 'Bruce Banner', '16104829E', 'Hulk', 'Black widow', 'Somewhere in New York', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'BruceBanner@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 0, 0, NULL, 0, 0, 19, 0, 1),
|
||||||
(110, 'Jessica Jones', '58282869H', 'Jessica Jones', 'Luke Cage', 'NYCC 2015 Poster', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'JessicaJones@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 0, 0, NULL, 0, 0, NULL, 0, 1),
|
(110, 'Jessica Jones', '58282869H', 'Jessica Jones', 'Luke Cage', 'NYCC 2015 Poster', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'JessicaJones@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 0, 0, NULL, 0, 0, NULL, 0, 1),
|
||||||
(111, 'Missing', NULL, 'Missing man', 'Anton', 'The space', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, NULL, NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 4, NULL, 1, 0, 1, 0, NULL, 1, 0, NULL, 0, 1),
|
(111, 'Missing', NULL, 'Missing man', 'Anton', 'The space, Universe far away', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, NULL, NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 4, NULL, 1, 0, 1, 0, NULL, 1, 0, NULL, 0, 1),
|
||||||
(112, 'Trash', NULL, 'Garbage man', 'Unknown name', 'New York city', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, NULL, NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 4, NULL, 1, 0, 1, 0, NULL, 1, 0, NULL, 0, 1);
|
(112, 'Trash', NULL, 'Garbage man', 'Unknown name', 'New York city, Underground', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, NULL, NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 4, NULL, 1, 0, 1, 0, NULL, 1, 0, NULL, 0, 1);
|
||||||
|
|
||||||
INSERT INTO `vn`.`client`(`id`, `name`, `fi`, `socialName`, `contact`, `street`, `city`, `postcode`, `isRelevant`, `email`, `iban`,`dueDay`,`accountingAccount`, `isEqualizated`, `provinceFk`, `hasToInvoice`, `credit`, `countryFk`, `isActive`, `gestdocFk`, `quality`, `payMethodFk`,`created`, `isTaxDataChecked`)
|
INSERT INTO `vn`.`client`(`id`, `name`, `fi`, `socialName`, `contact`, `street`, `city`, `postcode`, `isRelevant`, `email`, `iban`,`dueDay`,`accountingAccount`, `isEqualizated`, `provinceFk`, `hasToInvoice`, `credit`, `countryFk`, `isActive`, `gestdocFk`, `quality`, `payMethodFk`,`created`, `isTaxDataChecked`)
|
||||||
SELECT id, name, CONCAT(RPAD(CONCAT(id,9),8,id),'A'), CONCAT(name, 'Social'), CONCAT(name, 'Contact'), CONCAT(name, 'Street'), 'SILLA', 46460, 1, CONCAT(name,'@mydomain.com'), NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5, CURDATE(), 1
|
SELECT id, name, CONCAT(RPAD(CONCAT(id,9),8,id),'A'), CONCAT(name, 'Social'), CONCAT(name, 'Contact'), CONCAT(name, 'Street'), 'SILLA', 46460, 1, CONCAT(name,'@mydomain.com'), NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5, CURDATE(), 1
|
||||||
|
@ -1234,11 +1233,11 @@ INSERT INTO `vn`.`annualAverageInvoiced`(`clientFk`, `invoiced`)
|
||||||
(104, 500),
|
(104, 500),
|
||||||
(105, 5000);
|
(105, 5000);
|
||||||
|
|
||||||
INSERT INTO `vn`.`supplier`(`id`, `name`, `nickname`,`account`,`countryFk`,`nif`,`isFarmer`,`commission`, `created`, `isActive`, `street`, `city`, `provinceFk`, `postCode`, `payMethodFk`, `payDemFk`, `payDay`, `taxTypeSageFk`, `withholdingSageFk`, `transactionTypeSageFk`)
|
INSERT INTO `vn`.`supplier`(`id`, `name`, `nickname`,`account`,`countryFk`,`nif`,`isFarmer`,`commission`, `created`, `isActive`, `street`, `city`, `provinceFk`, `postCode`, `payMethodFk`, `payDemFk`, `payDay`, `taxTypeSageFk`, `withholdingSageFk`, `transactionTypeSageFk`, `workerFk`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 'Plants SL', 'Plants nick', 4100000001, 1, '06089160W', 0, 0, CURDATE(), 1, 'supplier address 1', 'PONTEVEDRA', 1, 15214, 1, 1, 15, 4, 1, 1),
|
(1, 'Plants SL', 'Plants nick', 4100000001, 1, '06089160W', 0, 0, CURDATE(), 1, 'supplier address 1', 'PONTEVEDRA', 1, 15214, 1, 1, 15, 4, 1, 1, 18),
|
||||||
(2, 'Farmer King', 'The farmer', 4000020002, 1, '87945234L', 1, 0, CURDATE(), 1, 'supplier address 2', 'SILLA', 2, 43022, 1, 2, 10, 93, 2, 8),
|
(2, 'Farmer King', 'The farmer', 4000020002, 1, '87945234L', 1, 0, CURDATE(), 1, 'supplier address 2', 'SILLA', 2, 43022, 1, 2, 10, 93, 2, 8, 18),
|
||||||
(442, 'Verdnatura Levante SL', 'Verdnatura', 5115000442, 1, '06815934E', 0, 0, CURDATE(), 1, 'supplier address 3', 'SILLA', 1, 43022, 1, 2, 15, 6, 9, 3);
|
(442, 'Verdnatura Levante SL', 'Verdnatura', 5115000442, 1, '06815934E', 0, 0, CURDATE(), 1, 'supplier address 3', 'SILLA', 1, 43022, 1, 2, 15, 6, 9, 3, 18);
|
||||||
|
|
||||||
INSERT INTO `vn`.`supplierContact`(`id`, `supplierFk`, `phone`, `mobile`, `email`, `observation`, `name`)
|
INSERT INTO `vn`.`supplierContact`(`id`, `supplierFk`, `phone`, `mobile`, `email`, `observation`, `name`)
|
||||||
VALUES
|
VALUES
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -186,8 +186,11 @@ export default {
|
||||||
clientBalance: {
|
clientBalance: {
|
||||||
company: 'vn-client-balance-index vn-autocomplete[ng-model="$ctrl.companyId"]',
|
company: 'vn-client-balance-index vn-autocomplete[ng-model="$ctrl.companyId"]',
|
||||||
newPaymentButton: `vn-float-button`,
|
newPaymentButton: `vn-float-button`,
|
||||||
newPaymentBank: '.vn-dialog.shown vn-autocomplete[ng-model="$ctrl.receipt.bankFk"]',
|
newPaymentBank: '.vn-dialog.shown vn-autocomplete[ng-model="$ctrl.bankFk"]',
|
||||||
newPaymentAmount: '.vn-dialog.shown vn-input-number[ng-model="$ctrl.receipt.amountPaid"]',
|
newPaymentAmount: '.vn-dialog.shown vn-input-number[ng-model="$ctrl.amountPaid"]',
|
||||||
|
newDescription: 'vn-textfield[ng-model="$ctrl.receipt.description"]',
|
||||||
|
deliveredAmount: '.vn-dialog vn-input-number[ng-model="$ctrl.deliveredAmount"]',
|
||||||
|
refundAmount: '.vn-dialog vn-input-number[ng-model="$ctrl.amountToReturn"]',
|
||||||
saveButton: '.vn-dialog.shown [response="accept"]',
|
saveButton: '.vn-dialog.shown [response="accept"]',
|
||||||
firstLineBalance: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(8)',
|
firstLineBalance: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(8)',
|
||||||
firstLineReference: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td-editable',
|
firstLineReference: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td-editable',
|
||||||
|
@ -313,7 +316,7 @@ export default {
|
||||||
fourthRelevancy: 'vn-item-tags vn-horizontal:nth-child(4) [ng-model="itemTag.priority"]',
|
fourthRelevancy: 'vn-item-tags vn-horizontal:nth-child(4) [ng-model="itemTag.priority"]',
|
||||||
fourthRemoveTagButton: 'vn-item-tags vn-horizontal:nth-child(4) vn-icon-button[icon="delete"]',
|
fourthRemoveTagButton: 'vn-item-tags vn-horizontal:nth-child(4) vn-icon-button[icon="delete"]',
|
||||||
fifthTag: 'vn-item-tags vn-horizontal:nth-child(5) > vn-autocomplete[ng-model="itemTag.tagFk"]',
|
fifthTag: 'vn-item-tags vn-horizontal:nth-child(5) > vn-autocomplete[ng-model="itemTag.tagFk"]',
|
||||||
fifthValue: 'vn-item-tags vn-horizontal:nth-child(5) vn-textfield[ng-model="itemTag.value"]',
|
fifthValue: 'vn-item-tags vn-horizontal:nth-child(5) vn-autocomplete[ng-model="itemTag.value"]',
|
||||||
fifthRelevancy: 'vn-item-tags vn-horizontal:nth-child(5) vn-input-number[ng-model="itemTag.priority"]',
|
fifthRelevancy: 'vn-item-tags vn-horizontal:nth-child(5) vn-input-number[ng-model="itemTag.priority"]',
|
||||||
sixthTag: 'vn-item-tags vn-horizontal:nth-child(6) > vn-autocomplete[ng-model="itemTag.tagFk"]',
|
sixthTag: 'vn-item-tags vn-horizontal:nth-child(6) > vn-autocomplete[ng-model="itemTag.tagFk"]',
|
||||||
sixthValue: 'vn-item-tags vn-horizontal:nth-child(6) vn-textfield[ng-model="itemTag.value"]',
|
sixthValue: 'vn-item-tags vn-horizontal:nth-child(6) vn-textfield[ng-model="itemTag.value"]',
|
||||||
|
@ -389,18 +392,22 @@ export default {
|
||||||
descriptorTicketId: 'vn-ticket-descriptor > vn-descriptor-content > div > div.body > div.top > div'
|
descriptorTicketId: 'vn-ticket-descriptor > vn-descriptor-content > div > div.body > div.top > div'
|
||||||
},
|
},
|
||||||
ticketsIndex: {
|
ticketsIndex: {
|
||||||
|
anySearchResult: 'vn-ticket-index vn-tbody > a',
|
||||||
openAdvancedSearchButton: 'vn-searchbar .append vn-icon[icon="arrow_drop_down"]',
|
openAdvancedSearchButton: 'vn-searchbar .append vn-icon[icon="arrow_drop_down"]',
|
||||||
advancedSearchInvoiceOut: 'vn-ticket-search-panel vn-textfield[ng-model="filter.refFk"]',
|
advancedSearchInvoiceOut: 'vn-ticket-search-panel vn-textfield[ng-model="filter.refFk"]',
|
||||||
advancedSearchDaysOnward: 'vn-ticket-search-panel vn-input-number[ng-model="filter.scopeDays"]',
|
advancedSearchDaysOnward: 'vn-ticket-search-panel vn-input-number[ng-model="filter.scopeDays"]',
|
||||||
|
advancedSearchClient: 'vn-ticket-search-panel vn-textfield[ng-model="filter.clientFk"]',
|
||||||
advancedSearchButton: 'vn-ticket-search-panel button[type=submit]',
|
advancedSearchButton: 'vn-ticket-search-panel button[type=submit]',
|
||||||
newTicketButton: 'vn-ticket-index a[ui-sref="ticket.create"]',
|
newTicketButton: 'vn-ticket-index a[ui-sref="ticket.create"]',
|
||||||
searchResult: 'vn-ticket-index vn-card > vn-table > div > vn-tbody > a.vn-tr',
|
searchResult: 'vn-ticket-index vn-card > vn-table > div > vn-tbody > a.vn-tr',
|
||||||
|
firstTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(1) > vn-td:nth-child(1) > vn-check',
|
||||||
secondTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(2) > vn-td:nth-child(1) > vn-check',
|
secondTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(2) > vn-td:nth-child(1) > vn-check',
|
||||||
thirdTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(3) > vn-td:nth-child(1) > vn-check',
|
thirdTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(3) > vn-td:nth-child(1) > vn-check',
|
||||||
sixthTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(6) > vn-td:nth-child(1) > vn-check',
|
sixthTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(6) > vn-td:nth-child(1) > vn-check',
|
||||||
payoutButton: 'vn-ticket-index vn-button[icon="icon-recovery"]',
|
payoutButton: 'vn-ticket-index vn-button[icon="icon-recovery"]',
|
||||||
payoutCompany: '.vn-dialog vn-autocomplete[ng-model="$ctrl.receipt.companyFk"]',
|
payoutCompany: '.vn-dialog vn-autocomplete[ng-model="$ctrl.receipt.companyFk"]',
|
||||||
payoutBank: '.vn-dialog vn-autocomplete[ng-model="$ctrl.receipt.bankFk"]',
|
payoutBank: '.vn-dialog vn-autocomplete[ng-model="$ctrl.bankFk"]',
|
||||||
|
payoutDescription: 'vn-textfield[ng-model="$ctrl.receipt.description"]',
|
||||||
submitPayout: '.vn-dialog button[response="accept"]',
|
submitPayout: '.vn-dialog button[response="accept"]',
|
||||||
searchWeeklyResult: 'vn-ticket-weekly-index vn-table vn-tbody > vn-tr',
|
searchWeeklyResult: 'vn-ticket-weekly-index vn-table vn-tbody > vn-tr',
|
||||||
searchResultDate: 'vn-ticket-summary [label=Landed] span',
|
searchResultDate: 'vn-ticket-summary [label=Landed] span',
|
||||||
|
|
|
@ -38,7 +38,7 @@ describe('Client balance path', () => {
|
||||||
expect(message.text).toContain('Data saved!');
|
expect(message.text).toContain('Data saved!');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should click the new payment button', async() => {
|
it('should reload the section', async() => {
|
||||||
await page.closePopup();
|
await page.closePopup();
|
||||||
await page.reloadSection('client.card.balance.index');
|
await page.reloadSection('client.card.balance.index');
|
||||||
});
|
});
|
||||||
|
@ -46,7 +46,8 @@ describe('Client balance path', () => {
|
||||||
it('should create a new payment that clears the debt', async() => {
|
it('should create a new payment that clears the debt', async() => {
|
||||||
await page.closePopup();
|
await page.closePopup();
|
||||||
await page.waitToClick(selectors.clientBalance.newPaymentButton);
|
await page.waitToClick(selectors.clientBalance.newPaymentButton);
|
||||||
await page.autocompleteSearch(selectors.clientBalance.newPaymentBank, 'Pay on receipt');
|
await page.autocompleteSearch(selectors.clientBalance.newPaymentBank, 'Cash');
|
||||||
|
await page.write(selectors.clientBalance.newDescription, 'Description');
|
||||||
await page.waitToClick(selectors.clientBalance.saveButton);
|
await page.waitToClick(selectors.clientBalance.saveButton);
|
||||||
const message = await page.waitForSnackbar();
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
|
@ -78,16 +79,24 @@ describe('Client balance path', () => {
|
||||||
expect(firstBalanceLine).toContain('0.00');
|
expect(firstBalanceLine).toContain('0.00');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create a new payment that sets the balance to positive value', async() => {
|
it('should create a new payment and check the cash comparison works correctly', async() => {
|
||||||
|
const amountPaid = '100';
|
||||||
|
const cashHanded = '500';
|
||||||
|
const expectedRefund = '400';
|
||||||
|
|
||||||
await page.waitToClick(selectors.clientBalance.newPaymentButton);
|
await page.waitToClick(selectors.clientBalance.newPaymentButton);
|
||||||
await page.overwrite(selectors.clientBalance.newPaymentAmount, '100');
|
await page.write(selectors.clientBalance.newPaymentAmount, amountPaid);
|
||||||
|
await page.write(selectors.clientBalance.newDescription, 'Payment');
|
||||||
|
await page.write(selectors.clientBalance.deliveredAmount, cashHanded);
|
||||||
|
const refund = await page.waitToGetProperty(selectors.clientBalance.refundAmount, 'value');
|
||||||
await page.waitToClick(selectors.clientBalance.saveButton);
|
await page.waitToClick(selectors.clientBalance.saveButton);
|
||||||
const message = await page.waitForSnackbar();
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
|
expect(refund).toEqual(expectedRefund);
|
||||||
expect(message.text).toContain('Data saved!');
|
expect(message.text).toContain('Data saved!');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should check balance is now -100', async() => {
|
it('should check the balance value is now -100', async() => {
|
||||||
let result = await page
|
let result = await page
|
||||||
.waitToGetProperty(selectors.clientBalance.firstLineBalance, 'innerText');
|
.waitToGetProperty(selectors.clientBalance.firstLineBalance, 'innerText');
|
||||||
|
|
||||||
|
@ -96,7 +105,9 @@ describe('Client balance path', () => {
|
||||||
|
|
||||||
it('should create a new payment that sets the balance back to the original negative value', async() => {
|
it('should create a new payment that sets the balance back to the original negative value', async() => {
|
||||||
await page.waitToClick(selectors.clientBalance.newPaymentButton);
|
await page.waitToClick(selectors.clientBalance.newPaymentButton);
|
||||||
|
await page.autocompleteSearch(selectors.clientBalance.newPaymentBank, 'Pay on receipt');
|
||||||
await page.overwrite(selectors.clientBalance.newPaymentAmount, '-150');
|
await page.overwrite(selectors.clientBalance.newPaymentAmount, '-150');
|
||||||
|
await page.write(selectors.clientBalance.newDescription, 'Description');
|
||||||
await page.waitToClick(selectors.clientBalance.saveButton);
|
await page.waitToClick(selectors.clientBalance.saveButton);
|
||||||
const message = await page.waitForSnackbar();
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ describe('Item create tags path', () => {
|
||||||
await browser.close();
|
await browser.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should create a new tag and delete a former one`, async() => {
|
it('should create a new tag and delete a former one', async() => {
|
||||||
await page.waitToClick(selectors.itemTags.fourthRemoveTagButton);
|
await page.waitToClick(selectors.itemTags.fourthRemoveTagButton);
|
||||||
await page.waitToClick(selectors.itemTags.addItemTagButton);
|
await page.waitToClick(selectors.itemTags.addItemTagButton);
|
||||||
await page.autocompleteSearch(selectors.itemTags.seventhTag, 'Ancho de la base');
|
await page.autocompleteSearch(selectors.itemTags.seventhTag, 'Ancho de la base');
|
||||||
|
@ -29,7 +29,7 @@ describe('Item create tags path', () => {
|
||||||
expect(message.text).toContain('Data saved!');
|
expect(message.text).toContain('Data saved!');
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should confirm the fourth row data is the expected one`, async() => {
|
it('should confirm the fourth row data is the expected one', async() => {
|
||||||
await page.reloadSection('item.card.tags');
|
await page.reloadSection('item.card.tags');
|
||||||
await page.waitForSelector('vn-item-tags');
|
await page.waitForSelector('vn-item-tags');
|
||||||
let result = await page.waitToGetProperty(selectors.itemTags.fourthTag, 'value');
|
let result = await page.waitToGetProperty(selectors.itemTags.fourthTag, 'value');
|
||||||
|
@ -47,7 +47,7 @@ describe('Item create tags path', () => {
|
||||||
expect(result).toEqual('4');
|
expect(result).toEqual('4');
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should confirm the fifth row data is the expected one`, async() => {
|
it('should confirm the fifth row data is the expected one', async() => {
|
||||||
let tag = await page
|
let tag = await page
|
||||||
.waitToGetProperty(selectors.itemTags.fifthTag, 'value');
|
.waitToGetProperty(selectors.itemTags.fifthTag, 'value');
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ describe('Item create tags path', () => {
|
||||||
expect(relevancy).toEqual('5');
|
expect(relevancy).toEqual('5');
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should confirm the sixth row data is the expected one`, async() => {
|
it('should confirm the sixth row data is the expected one', async() => {
|
||||||
let tag = await page
|
let tag = await page
|
||||||
.waitToGetProperty(selectors.itemTags.sixthTag, 'value');
|
.waitToGetProperty(selectors.itemTags.sixthTag, 'value');
|
||||||
|
|
||||||
|
|
|
@ -22,23 +22,31 @@ describe('Ticket index payout path', () => {
|
||||||
it('should check the second ticket from a client and 1 of another', async() => {
|
it('should check the second ticket from a client and 1 of another', async() => {
|
||||||
await page.waitToClick(selectors.globalItems.searchButton);
|
await page.waitToClick(selectors.globalItems.searchButton);
|
||||||
await page.waitToClick(selectors.ticketsIndex.secondTicketCheckbox);
|
await page.waitToClick(selectors.ticketsIndex.secondTicketCheckbox);
|
||||||
await page.waitToClick(selectors.ticketsIndex.sixthTicketCheckbox);
|
await page.waitToClick(selectors.ticketsIndex.thirdTicketCheckbox);
|
||||||
await page.waitToClick(selectors.ticketsIndex.payoutButton);
|
await page.waitToClick(selectors.ticketsIndex.payoutButton);
|
||||||
const message = await page.waitForSnackbar();
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
expect(message.text).toContain('You cannot make a payment on account from multiple clients');
|
expect(message.text).toContain('You cannot make a payment on account from multiple clients');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should uncheck the sixth ticket result and check the third which is from the same client then open the payout form', async() => {
|
it('should search for tickets of the same client then open the payout form', async() => {
|
||||||
await page.waitToClick(selectors.ticketsIndex.sixthTicketCheckbox);
|
await page.waitToClick(selectors.ticketsIndex.openAdvancedSearchButton);
|
||||||
await page.waitToClick(selectors.ticketsIndex.thirdTicketCheckbox);
|
await page.write(selectors.ticketsIndex.advancedSearchClient, '101');
|
||||||
|
await page.keyboard.press('Enter');
|
||||||
|
await page.waitForNumberOfElements(selectors.ticketsIndex.anySearchResult, 6);
|
||||||
|
await page.waitToClick(selectors.ticketsIndex.firstTicketCheckbox);
|
||||||
|
await page.waitToClick(selectors.ticketsIndex.secondTicketCheckbox);
|
||||||
|
|
||||||
await page.waitToClick(selectors.ticketsIndex.payoutButton);
|
await page.waitToClick(selectors.ticketsIndex.payoutButton);
|
||||||
|
|
||||||
await page.waitForSelector(selectors.ticketsIndex.payoutCompany);
|
await page.waitForSelector(selectors.ticketsIndex.payoutCompany);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fill the company and bank to perform a payout', async() => {
|
it('should fill the company and bank to perform a payout', async() => {
|
||||||
|
await page.autocompleteSearch(selectors.ticketsIndex.payoutCompany, 'VNL');
|
||||||
await page.autocompleteSearch(selectors.ticketsIndex.payoutBank, 'cash');
|
await page.autocompleteSearch(selectors.ticketsIndex.payoutBank, 'cash');
|
||||||
|
await page.write(selectors.clientBalance.newPaymentAmount, '100');
|
||||||
|
await page.write(selectors.ticketsIndex.payoutDescription, 'Payment');
|
||||||
await page.waitToClick(selectors.ticketsIndex.submitPayout);
|
await page.waitToClick(selectors.ticketsIndex.submitPayout);
|
||||||
const message = await page.waitForSnackbar();
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ export default class Autocomplete extends Field {
|
||||||
constructor($element, $, $compile, $transclude) {
|
constructor($element, $, $compile, $transclude) {
|
||||||
super($element, $, $compile);
|
super($element, $, $compile);
|
||||||
this.$transclude = $transclude;
|
this.$transclude = $transclude;
|
||||||
|
this.$compile = $compile;
|
||||||
this._selection = null;
|
this._selection = null;
|
||||||
this.input = this.element.querySelector('input');
|
this.input = this.element.querySelector('input');
|
||||||
}
|
}
|
||||||
|
@ -149,6 +149,9 @@ export default class Autocomplete extends Field {
|
||||||
where: where
|
where: where
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (this.include)
|
||||||
|
filter.include = this.include;
|
||||||
|
|
||||||
let json = encodeURIComponent(JSON.stringify(filter));
|
let json = encodeURIComponent(JSON.stringify(filter));
|
||||||
this.$http.get(`${this.url}?filter=${json}`).then(
|
this.$http.get(`${this.url}?filter=${json}`).then(
|
||||||
json => this.onSelectionRequest(json.data),
|
json => this.onSelectionRequest(json.data),
|
||||||
|
@ -182,8 +185,14 @@ export default class Autocomplete extends Field {
|
||||||
} else {
|
} else {
|
||||||
display = this._selection[this.showField];
|
display = this._selection[this.showField];
|
||||||
if (hasTemplate) {
|
if (hasTemplate) {
|
||||||
let template = this.$transclude(() => {}, null, 'tplItem').text();
|
let template = this.$transclude(() => {}, null, 'tplItem');
|
||||||
display = this.$interpolate(template)(this._selection);
|
const element = template[0];
|
||||||
|
const description = element.querySelector('.text-secondary');
|
||||||
|
if (description) description.remove();
|
||||||
|
|
||||||
|
const displayElement = angular.element(element);
|
||||||
|
const displayText = displayElement.text();
|
||||||
|
display = this.$interpolate(displayText)(this._selection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,6 +85,25 @@ vn-table {
|
||||||
max-width: 400px;
|
max-width: 400px;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
&[vn-fetched-tags] {
|
||||||
|
width: 235px;
|
||||||
|
min-width: 155px;
|
||||||
|
& > vn-one {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > vn-one:nth-child(2) h3 {
|
||||||
|
color: $color-font-secondary;
|
||||||
|
text-transform: uppercase;
|
||||||
|
line-height: initial;
|
||||||
|
font-size: 0.75rem
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&[vn-fetched-tags][wide] {
|
||||||
|
width: 430px;
|
||||||
|
}
|
||||||
vn-icon.bright, i.bright {
|
vn-icon.bright, i.bright {
|
||||||
color: #f7931e;
|
color: #f7931e;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,13 @@ import ngModule from '../../module';
|
||||||
import Section from '../section';
|
import Section from '../section';
|
||||||
import './style.scss';
|
import './style.scss';
|
||||||
|
|
||||||
export default class Summary extends Section {}
|
export default class Summary extends Section {
|
||||||
|
listEmails(email) {
|
||||||
|
if (!email) return;
|
||||||
|
const emailList = email.split(',');
|
||||||
|
return emailList.join(', ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ngModule.vnComponent('vnSummary', {
|
ngModule.vnComponent('vnSummary', {
|
||||||
controller: Summary
|
controller: Summary
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
import './index.js';
|
||||||
|
|
||||||
|
describe('Salix', () => {
|
||||||
|
describe('Component vnSummary', () => {
|
||||||
|
let controller;
|
||||||
|
|
||||||
|
beforeEach(ngModule('salix'));
|
||||||
|
|
||||||
|
beforeEach(inject($componentController => {
|
||||||
|
const $element = angular.element('<vn-summary></vn-summary>');
|
||||||
|
controller = $componentController('vnSummary', {$element});
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('listEmails()', () => {
|
||||||
|
it('should do nothing when receives no arguments', () => {
|
||||||
|
const emailList = controller.listEmails();
|
||||||
|
|
||||||
|
expect(emailList).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should format the receives emails to be separated with comma', () => {
|
||||||
|
const expectedResult = 'captainmarvel@marvel.com, ironman@marvel.com';
|
||||||
|
|
||||||
|
const emailList = controller.listEmails('captainmarvel@marvel.com,ironman@marvel.com');
|
||||||
|
|
||||||
|
expect(emailList).toEqual(expectedResult);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -85,8 +85,11 @@
|
||||||
"You need to fill sage information before you check verified data": "You need to fill sage information before you check verified data",
|
"You need to fill sage information before you check verified data": "You need to fill sage information before you check verified data",
|
||||||
"The social name cannot be empty": "The social name cannot be empty",
|
"The social name cannot be empty": "The social name cannot be empty",
|
||||||
"The nif cannot be empty": "The nif cannot be empty",
|
"The nif cannot be empty": "The nif cannot be empty",
|
||||||
|
"Amount cannot be zero": "Amount cannot be zero",
|
||||||
|
"Company has to be official": "Company has to be official",
|
||||||
"A travel with this data already exists": "A travel with this data already exists",
|
"A travel with this data already exists": "A travel with this data already exists",
|
||||||
"The observation type can't be repeated": "The observation type can't be repeated",
|
"The observation type can't be repeated": "The observation type can't be repeated",
|
||||||
"New ticket request has been created with price": "New ticket request has been created '{{description}}' for day <strong>{{shipped}}</strong>, with a quantity of <strong>{{quantity}}</strong> and a price of <strong>{{price}} €</strong>",
|
"New ticket request has been created with price": "New ticket request has been created *'{{description}}'* for day *{{shipped}}*, with a quantity of *{{quantity}}* and a price of *{{price}} €*",
|
||||||
"New ticket request has been created": "New ticket request has been created '{{description}}' for day <strong>{{shipped}}</strong>, with a quantity of <strong>{{quantity}}</strong>"
|
"New ticket request has been created": "New ticket request has been created *'{{description}}'* for day *{{shipped}}*, with a quantity of *{{quantity}}*",
|
||||||
|
"There's a new urgent ticket": "There's a new urgent ticket: [{{title}}](https://cau.verdnatura.es/WorkOrder.do?woMode=viewWO&woID={{issueId}})"
|
||||||
}
|
}
|
|
@ -161,11 +161,16 @@
|
||||||
"The nif cannot be empty": "El NIF no puede quedar en blanco",
|
"The nif cannot be empty": "El NIF no puede quedar en blanco",
|
||||||
"You need to fill sage information before you check verified data": "Debes rellenar la información de sage antes de marcar datos comprobados",
|
"You need to fill sage information before you check verified data": "Debes rellenar la información de sage antes de marcar datos comprobados",
|
||||||
"ASSIGN_ZONE_FIRST": "Asigna una zona primero",
|
"ASSIGN_ZONE_FIRST": "Asigna una zona primero",
|
||||||
|
"Amount cannot be zero": "El importe no puede ser cero",
|
||||||
|
"Company has to be official": "Empresa inválida",
|
||||||
"You can not select this payment method without a registered bankery account": "No se puede utilizar este método de pago si no has registrado una cuenta bancaria",
|
"You can not select this payment method without a registered bankery account": "No se puede utilizar este método de pago si no has registrado una cuenta bancaria",
|
||||||
"You can't upload images on the test environment": "No puedes subir imágenes en el entorno de pruebas",
|
"You can't upload images on the test environment": "No puedes subir imágenes en el entorno de pruebas",
|
||||||
"The selected ticket is not suitable for this route": "El ticket seleccionado no es apto para esta ruta",
|
"The selected ticket is not suitable for this route": "El ticket seleccionado no es apto para esta ruta",
|
||||||
"Sorts whole route": "Reordena ruta entera",
|
"Sorts whole route": "Reordena ruta entera",
|
||||||
"New ticket request has been created with price": "Se ha creado una nueva petición de compra '{{description}}' para el día <strong>{{shipped}}</strong>, con una cantidad de <strong>{{quantity}}</strong> y un precio de <strong>{{price}} €</strong>",
|
"Invalid account": "Cuenta inválida",
|
||||||
"New ticket request has been created": "Se ha creado una nueva petición de compra '{{description}}' para el día <strong>{{shipped}}</strong>, con una cantidad de <strong>{{quantity}}</strong>",
|
"New ticket request has been created with price": "Se ha creado una nueva petición de compra *'{{description}}'* para el día *{{shipped}}*, con una cantidad de *{{quantity}}* y un precio de *{{price}} €*",
|
||||||
"That item doesn't exists": "Ese artículo no existe"
|
"New ticket request has been created": "Se ha creado una nueva petición de compra *'{{description}}'* para el día *{{shipped}}*, con una cantidad de *{{quantity}}*",
|
||||||
|
"That item doesn't exists": "Ese artículo no existe",
|
||||||
|
"There's a new urgent ticket": "Hay un nuevo ticket urgente: [{{title}}](https://cau.verdnatura.es/WorkOrder.do?woMode=viewWO&woID={{issueId}})",
|
||||||
|
"Compensation account is empty": "La cuenta para compensar está vacia"
|
||||||
}
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/**
|
||||||
|
* Transforms a UTC date to string without datetime.
|
||||||
|
*
|
||||||
|
* @param {date} date Date to format
|
||||||
|
* @return {String} Formatted date string
|
||||||
|
*/
|
||||||
|
function toString(date) {
|
||||||
|
date = new Date(date);
|
||||||
|
|
||||||
|
let day = date.getDate();
|
||||||
|
let month = date.getMonth() + 1;
|
||||||
|
let year = date.getFullYear();
|
||||||
|
|
||||||
|
if (day < 10)
|
||||||
|
day = `0${day}`;
|
||||||
|
|
||||||
|
if (month < 10)
|
||||||
|
month = `0${month}`;
|
||||||
|
|
||||||
|
return `${day}-${month}-${year}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
toString: toString
|
||||||
|
};
|
|
@ -31,6 +31,9 @@
|
||||||
{"state": "account.alias.card.users", "icon": "groups"}
|
{"state": "account.alias.card.users", "icon": "groups"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"keybindings": [
|
||||||
|
{"key": "u", "state": "account.index"}
|
||||||
|
],
|
||||||
"routes": [
|
"routes": [
|
||||||
{
|
{
|
||||||
"url": "/account",
|
"url": "/account",
|
||||||
|
|
|
@ -86,16 +86,15 @@ class Controller extends Section {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
showDeleteConfirm(index) {
|
showDeleteConfirm($index) {
|
||||||
this.sale = this.salesClaimed[index];
|
this.claimedIndex = $index;
|
||||||
this.$.confirm.show();
|
this.$.confirm.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteClaimedSale() {
|
deleteClaimedSale() {
|
||||||
let query = `ClaimBeginnings/${this.sale.id}`;
|
this.$.model.remove(this.claimedIndex);
|
||||||
this.$http.delete(query).then(() => {
|
this.$.model.save().then(() => {
|
||||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
this.vnApp.showSuccess(this.$t('Data saved!'));
|
||||||
this.$.model.remove(this.sale);
|
|
||||||
this.calculateTotals();
|
this.calculateTotals();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,13 +73,16 @@ describe('claim', () => {
|
||||||
|
|
||||||
describe('deleteClaimedSale()', () => {
|
describe('deleteClaimedSale()', () => {
|
||||||
it('should make a delete and call refresh and showSuccess', () => {
|
it('should make a delete and call refresh and showSuccess', () => {
|
||||||
controller.sale = {id: 1};
|
const claimedIndex = 1;
|
||||||
|
controller.claimedIndex = claimedIndex;
|
||||||
jest.spyOn(controller.$.model, 'remove');
|
jest.spyOn(controller.$.model, 'remove');
|
||||||
|
jest.spyOn(controller.$.model, 'save');
|
||||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
jest.spyOn(controller.vnApp, 'showSuccess');
|
||||||
$httpBackend.expectDELETE(`ClaimBeginnings/1`).respond('ok');
|
|
||||||
controller.deleteClaimedSale();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
|
controller.deleteClaimedSale();
|
||||||
|
|
||||||
|
expect(controller.$.model.remove).toHaveBeenCalledWith(claimedIndex);
|
||||||
|
expect(controller.$.model.save).toHaveBeenCalledWith();
|
||||||
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,145 @@
|
||||||
|
const UserError = require('vn-loopback/util/user-error');
|
||||||
|
|
||||||
|
module.exports = function(Self) {
|
||||||
|
Self.remoteMethodCtx('createReceipt', {
|
||||||
|
description: 'Creates receipt and its compensation if necessary',
|
||||||
|
accepts: [{
|
||||||
|
arg: 'clientFk',
|
||||||
|
type: 'number',
|
||||||
|
description: 'The client id',
|
||||||
|
http: {source: 'path'}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'payed',
|
||||||
|
type: 'Date',
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'companyFk',
|
||||||
|
type: 'number',
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'bankFk',
|
||||||
|
type: 'number',
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'amountPaid',
|
||||||
|
type: 'number',
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'description',
|
||||||
|
type: 'string',
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'compensationAccount',
|
||||||
|
type: 'any'
|
||||||
|
}],
|
||||||
|
returns: {
|
||||||
|
root: true,
|
||||||
|
type: 'Object'
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
verb: 'post',
|
||||||
|
path: '/:clientFk/createReceipt'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.createReceipt = async ctx => {
|
||||||
|
const models = Self.app.models;
|
||||||
|
const args = ctx.args;
|
||||||
|
const tx = await models.Address.beginTransaction({});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
delete args.ctx; // Remove unwanted properties
|
||||||
|
const newReceipt = await models.Receipt.create(args, options);
|
||||||
|
const clientOriginal = await models.Client.findById(args.clientFk);
|
||||||
|
const bank = await models.Bank.findById(args.bankFk);
|
||||||
|
const accountingType = await models.AccountingType.findById(bank.accountingTypeFk);
|
||||||
|
|
||||||
|
if (accountingType.code == 'compensation') {
|
||||||
|
if (!args.compensationAccount)
|
||||||
|
throw new UserError('Compensation account is empty');
|
||||||
|
|
||||||
|
const supplierCompensation = await models.Supplier.findOne({
|
||||||
|
where: {
|
||||||
|
account: args.compensationAccount
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let clientCompensation = {};
|
||||||
|
if (!supplierCompensation) {
|
||||||
|
clientCompensation = await models.Client.findOne({
|
||||||
|
where: {
|
||||||
|
accountingAccount: args.compensationAccount
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!supplierCompensation && !clientCompensation)
|
||||||
|
throw new UserError('Invalid account');
|
||||||
|
|
||||||
|
await Self.rawSql(
|
||||||
|
`CALL vn.ledger_doCompensation(?, ?, ?, ?, ?, ?, ?)`,
|
||||||
|
[
|
||||||
|
Date(),
|
||||||
|
args.compensationAccount,
|
||||||
|
args.bankFk,
|
||||||
|
accountingType.receiptDescription + args.compensationAccount,
|
||||||
|
args.amountPaid,
|
||||||
|
args.companyFk,
|
||||||
|
clientOriginal.accountingAccount
|
||||||
|
],
|
||||||
|
options);
|
||||||
|
} else {
|
||||||
|
const description = `${clientOriginal.id} : ${clientOriginal.socialName} - ${accountingType.receiptDescription}`;
|
||||||
|
const [xdiarioNew] = await Self.rawSql(
|
||||||
|
`SELECT xdiario_new(?, CURDATE(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ledger;`,
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
bank.account,
|
||||||
|
clientOriginal.accountingAccount,
|
||||||
|
description,
|
||||||
|
args.amountPaid,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
args.companyFk
|
||||||
|
],
|
||||||
|
options);
|
||||||
|
|
||||||
|
await Self.rawSql(
|
||||||
|
`SELECT xdiario_new(?, CURDATE(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);`,
|
||||||
|
[
|
||||||
|
xdiarioNew.ledger,
|
||||||
|
clientOriginal.accountingAccount,
|
||||||
|
bank.account,
|
||||||
|
description,
|
||||||
|
0,
|
||||||
|
args.amountPaid,
|
||||||
|
0,
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
args.companyFk
|
||||||
|
],
|
||||||
|
options);
|
||||||
|
}
|
||||||
|
|
||||||
|
await tx.commit();
|
||||||
|
return newReceipt;
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,171 @@
|
||||||
|
const app = require('vn-loopback/server/server');
|
||||||
|
|
||||||
|
describe('Client createReceipt', () => {
|
||||||
|
const clientFk = 108;
|
||||||
|
const payed = Date();
|
||||||
|
const companyFk = 442;
|
||||||
|
const amountPaid = 12.50;
|
||||||
|
const description = 'Receipt description';
|
||||||
|
|
||||||
|
it('should create a new receipt', async() => {
|
||||||
|
const bankFk = 1;
|
||||||
|
let ctx = {
|
||||||
|
args: {
|
||||||
|
clientFk: clientFk,
|
||||||
|
payed: payed,
|
||||||
|
companyFk: companyFk,
|
||||||
|
bankFk: bankFk,
|
||||||
|
amountPaid: amountPaid,
|
||||||
|
description: description
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const receipt = await app.models.Client.createReceipt(ctx);
|
||||||
|
delete ctx.args.payed;
|
||||||
|
|
||||||
|
const till = await app.models.Till.findOne({
|
||||||
|
where: {
|
||||||
|
bankFk: bankFk,
|
||||||
|
in: amountPaid,
|
||||||
|
number: clientFk
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(receipt).toEqual(jasmine.objectContaining(ctx.args));
|
||||||
|
|
||||||
|
// restores
|
||||||
|
await receipt.destroy();
|
||||||
|
await till.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw Compensation account is empty', async() => {
|
||||||
|
const bankFk = 3;
|
||||||
|
let ctx = {
|
||||||
|
args: {
|
||||||
|
clientFk: clientFk,
|
||||||
|
payed: payed,
|
||||||
|
companyFk: companyFk,
|
||||||
|
bankFk: bankFk,
|
||||||
|
amountPaid: amountPaid,
|
||||||
|
description: description
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
await app.models.Client.createReceipt(ctx);
|
||||||
|
} catch (e) {
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error).toBeDefined();
|
||||||
|
expect(error.message).toEqual('Compensation account is empty');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw Invalid account if compensationAccount does not belongs to a client nor a supplier', async() => {
|
||||||
|
let error;
|
||||||
|
const bankFk = 3;
|
||||||
|
const ctx = {
|
||||||
|
args: {
|
||||||
|
clientFk: clientFk,
|
||||||
|
payed: payed,
|
||||||
|
companyFk: companyFk,
|
||||||
|
bankFk: bankFk,
|
||||||
|
amountPaid: amountPaid,
|
||||||
|
description: description,
|
||||||
|
compensationAccount: 'non existing account'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
await app.models.Client.createReceipt(ctx);
|
||||||
|
} catch (e) {
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error).toBeDefined();
|
||||||
|
expect(error.message).toEqual('Invalid account');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create a new receipt with a compensation for a client', async() => {
|
||||||
|
const bankFk = 3;
|
||||||
|
const ctx = {
|
||||||
|
args: {
|
||||||
|
clientFk: clientFk,
|
||||||
|
payed: payed,
|
||||||
|
companyFk: companyFk,
|
||||||
|
bankFk: bankFk,
|
||||||
|
amountPaid: amountPaid,
|
||||||
|
description: description,
|
||||||
|
compensationAccount: '4300000001'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const receipt = await app.models.Client.createReceipt(ctx);
|
||||||
|
const receiptCompensated = await app.models.Receipt.findOne({
|
||||||
|
where: {
|
||||||
|
clientFk: 1,
|
||||||
|
bankFk: ctx.args.bankFk
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const till = await app.models.Till.findOne({
|
||||||
|
where: {
|
||||||
|
bankFk: bankFk,
|
||||||
|
in: amountPaid,
|
||||||
|
number: clientFk
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
delete ctx.args.payed;
|
||||||
|
|
||||||
|
expect(receipt).toEqual(jasmine.objectContaining(ctx.args));
|
||||||
|
expect(receipt.amountPaid).toEqual(-receiptCompensated.amountPaid);
|
||||||
|
|
||||||
|
// restores
|
||||||
|
await receipt.destroy();
|
||||||
|
await receiptCompensated.destroy();
|
||||||
|
await till.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create a new receipt with a compensation for a supplier', async() => {
|
||||||
|
const ctx = {
|
||||||
|
args: {
|
||||||
|
clientFk: clientFk,
|
||||||
|
payed: payed,
|
||||||
|
companyFk: companyFk,
|
||||||
|
bankFk: 3,
|
||||||
|
amountPaid: amountPaid,
|
||||||
|
description: description,
|
||||||
|
compensationAccount: '4100000001'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const receipt = await app.models.Client.createReceipt(ctx);
|
||||||
|
|
||||||
|
const paymentCompensated = await app.models.Payment.findOne({
|
||||||
|
where: {
|
||||||
|
clientFk: ctx.args.sale,
|
||||||
|
payed: ctx.args.payed,
|
||||||
|
amountPaid: ctx.args.amountPaid,
|
||||||
|
bankFk: ctx.args.bankFk
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const till = await app.models.Till.findOne({
|
||||||
|
where: {
|
||||||
|
bankFk: ctx.args.bankFk,
|
||||||
|
in: amountPaid,
|
||||||
|
number: clientFk
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
delete ctx.args.payed;
|
||||||
|
|
||||||
|
expect(receipt).toEqual(jasmine.objectContaining(ctx.args));
|
||||||
|
|
||||||
|
expect(paymentCompensated.amountPaid).toEqual(paymentCompensated.amountPaid);
|
||||||
|
|
||||||
|
// restores
|
||||||
|
await receipt.destroy();
|
||||||
|
await paymentCompensated.destroy();
|
||||||
|
await till.destroy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -8,6 +8,7 @@ describe('Address updateAddress', () => {
|
||||||
const customAgentOneId = 1;
|
const customAgentOneId = 1;
|
||||||
|
|
||||||
it('should throw the non uee member error if no incoterms is defined', async() => {
|
it('should throw the non uee member error if no incoterms is defined', async() => {
|
||||||
|
let err;
|
||||||
const ctx = {
|
const ctx = {
|
||||||
args: {
|
args: {
|
||||||
provinceFk: provinceId,
|
provinceFk: provinceId,
|
||||||
|
@ -26,6 +27,7 @@ describe('Address updateAddress', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw a non uee member error if no customsAgent is defined', async() => {
|
it('should throw a non uee member error if no customsAgent is defined', async() => {
|
||||||
|
let err;
|
||||||
const ctx = {
|
const ctx = {
|
||||||
args: {
|
args: {
|
||||||
provinceFk: provinceId,
|
provinceFk: provinceId,
|
||||||
|
|
|
@ -104,6 +104,9 @@
|
||||||
"ClientDms": {
|
"ClientDms": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
"Till": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
"CustomsAgent": {
|
"CustomsAgent": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
{
|
||||||
|
"name": "XDiario",
|
||||||
|
"base": "VnModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "XDiario"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"ASIEN": {
|
||||||
|
"type": "number",
|
||||||
|
"id": true,
|
||||||
|
"description": "Identifier"
|
||||||
|
},
|
||||||
|
"FECHA": {
|
||||||
|
"type": "date"
|
||||||
|
},
|
||||||
|
"SUBCTA": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"CONTRA": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"CONCEPTO": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"EURODEBE": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"EUROHABER": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"BASEEURO": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"SERIE": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"CAMBIO": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"DEBEME": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"HABERME": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"FACTURA": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"IVA": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"RECEQUIV": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"METAL": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"METALIMP": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"CLIENTE": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"METALEJE": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"AUXILIAR": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"MONEDAUSO": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"relations": {
|
||||||
|
"company": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Company",
|
||||||
|
"foreignKey": "empresa_id"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ module.exports = Self => {
|
||||||
require('../methods/client/createAddress')(Self);
|
require('../methods/client/createAddress')(Self);
|
||||||
require('../methods/client/updateAddress')(Self);
|
require('../methods/client/updateAddress')(Self);
|
||||||
require('../methods/client/consumption')(Self);
|
require('../methods/client/consumption')(Self);
|
||||||
|
require('../methods/client/createReceipt')(Self);
|
||||||
|
|
||||||
// Validations
|
// Validations
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,44 @@
|
||||||
module.exports = function(Self) {
|
module.exports = function(Self) {
|
||||||
require('../methods/receipt/filter')(Self);
|
require('../methods/receipt/filter')(Self);
|
||||||
|
|
||||||
|
Self.validateBinded('amountPaid', isNotZero, {
|
||||||
|
message: 'Amount cannot be zero',
|
||||||
|
allowNull: false,
|
||||||
|
allowBlank: false
|
||||||
|
});
|
||||||
|
|
||||||
|
function isNotZero(value) {
|
||||||
|
return !isNaN(value) && value != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Self.validateAsync('companyFk', isOfficialCompany, {
|
||||||
|
message: 'Company has to be official'
|
||||||
|
});
|
||||||
|
|
||||||
|
async function isOfficialCompany(err, done) {
|
||||||
|
const hasCompany = await Self.app.models.Company.exists(this.companyFk);
|
||||||
|
if (!hasCompany) err();
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
|
||||||
Self.observe('before save', async function(ctx) {
|
Self.observe('before save', async function(ctx) {
|
||||||
if (ctx.isNewInstance) {
|
if (ctx.isNewInstance) {
|
||||||
let token = ctx.options.accessToken;
|
let token = ctx.options.accessToken;
|
||||||
let userId = token && token.userId;
|
let userId = token && token.userId;
|
||||||
let worker = await Self.app.models.Worker.findOne({where: {userFk: userId}});
|
|
||||||
|
|
||||||
ctx.instance.workerFk = worker.id;
|
ctx.instance.workerFk = userId;
|
||||||
|
|
||||||
|
await Self.app.models.Till.create({
|
||||||
|
workerFk: userId,
|
||||||
|
bankFk: ctx.instance.bankFk,
|
||||||
|
in: ctx.instance.amountPaid,
|
||||||
|
concept: ctx.instance.description,
|
||||||
|
dated: ctx.instance.payed,
|
||||||
|
serie: 'A',
|
||||||
|
isAccountable: true,
|
||||||
|
number: ctx.instance.clientFk,
|
||||||
|
companyFk: ctx.instance.companyFk
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,17 +9,19 @@
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"id": {
|
||||||
"id": true,
|
"id": true,
|
||||||
"type": "Number",
|
"type": "number",
|
||||||
"description": "Identifier"
|
"description": "Identifier"
|
||||||
},
|
},
|
||||||
"amountPaid": {
|
"amountPaid": {
|
||||||
"type": "Number"
|
"type": "number",
|
||||||
|
"required": true
|
||||||
},
|
},
|
||||||
"amountUnpaid": {
|
"amountUnpaid": {
|
||||||
"type": "Number"
|
"type": "number"
|
||||||
},
|
},
|
||||||
"payed": {
|
"payed": {
|
||||||
"type": "date"
|
"type": "date",
|
||||||
|
"required": true
|
||||||
},
|
},
|
||||||
"created": {
|
"created": {
|
||||||
"type": "date"
|
"type": "date"
|
||||||
|
@ -31,7 +33,16 @@
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"mysql": {
|
"mysql": {
|
||||||
"columnName": "invoiceFk"
|
"columnName": "invoiceFk"
|
||||||
}
|
},
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"bankFk": {
|
||||||
|
"type": "number",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"companyFk": {
|
||||||
|
"type": "number",
|
||||||
|
"required": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"relations": {
|
"relations": {
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
{
|
||||||
|
"name": "Till",
|
||||||
|
"base": "VnModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "till"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "number",
|
||||||
|
"id": true,
|
||||||
|
"description": "Identifier"
|
||||||
|
},
|
||||||
|
"dated": {
|
||||||
|
"type": "date",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"isAccountable": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"serie": {
|
||||||
|
"type": "string",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"number": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"concept": {
|
||||||
|
"type": "string",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"in": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"out": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"created": {
|
||||||
|
"type": "date"
|
||||||
|
},
|
||||||
|
"isConciliate": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"relations": {
|
||||||
|
"bank": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Bank",
|
||||||
|
"foreignKey": "bankFk"
|
||||||
|
},
|
||||||
|
"worker": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Account",
|
||||||
|
"foreignKey": "workerFk"
|
||||||
|
},
|
||||||
|
"company": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Company",
|
||||||
|
"foreignKey": "companyFk"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,19 +6,23 @@
|
||||||
auto-load="true"
|
auto-load="true"
|
||||||
url="Companies"
|
url="Companies"
|
||||||
data="companies"
|
data="companies"
|
||||||
order="code">
|
order="code"
|
||||||
|
required="true">
|
||||||
</vn-crud-model>
|
</vn-crud-model>
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
<vn-date-picker
|
<vn-date-picker
|
||||||
label="Date"
|
label="Date"
|
||||||
ng-model="$ctrl.receipt.payed">
|
ng-model="$ctrl.receipt.payed"
|
||||||
|
required="true">
|
||||||
</vn-date-picker>
|
</vn-date-picker>
|
||||||
<vn-autocomplete
|
<vn-autocomplete
|
||||||
data="companies"
|
data="companies"
|
||||||
label="Company"
|
label="Company"
|
||||||
show-field="code"
|
show-field="code"
|
||||||
value-field="id"
|
value-field="id"
|
||||||
ng-model="$ctrl.receipt.companyFk">
|
ng-model="$ctrl.receipt.companyFk"
|
||||||
|
required="true"
|
||||||
|
rule>
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
|
@ -29,27 +33,51 @@
|
||||||
value-field="id"
|
value-field="id"
|
||||||
fields="['accountingTypeFk']"
|
fields="['accountingTypeFk']"
|
||||||
include="{relation: 'accountingType'}"
|
include="{relation: 'accountingType'}"
|
||||||
ng-model="$ctrl.receipt.bankFk"
|
ng-model="$ctrl.bankFk"
|
||||||
search-function="{or: [{id: $search}, {bank: {like: '%'+ $search +'%'}}]}"
|
search-function="{or: [{id: $search}, {bank: {like: '%'+ $search +'%'}}]}"
|
||||||
selection="$ctrl.bankSelection"
|
selection="$ctrl.bankSelection"
|
||||||
order="id">
|
order="id"
|
||||||
|
required="true">
|
||||||
<tpl-item>{{id}}: {{bank}}</tpl-item>
|
<tpl-item>{{id}}: {{bank}}</tpl-item>
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
<vn-input-number
|
<vn-input-number
|
||||||
vn-focus
|
vn-focus
|
||||||
label="Amount"
|
label="Amount"
|
||||||
ng-model="$ctrl.receipt.amountPaid"
|
ng-model="$ctrl.amountPaid"
|
||||||
step="0.01"
|
step="0.01"
|
||||||
rule>
|
required="true">
|
||||||
</vn-input-number>
|
</vn-input-number>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
<vn-textfield
|
<vn-textfield
|
||||||
label="Reference"
|
label="Reference"
|
||||||
ng-model="$ctrl.receipt.description"
|
ng-model="$ctrl.receipt.description"
|
||||||
rule>
|
rule
|
||||||
|
required="true">
|
||||||
</vn-textfield>
|
</vn-textfield>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
|
<vn-vertical ng-show="$ctrl.bankSelection.accountingType.code == 'cash'">
|
||||||
|
<h6 translate>Cash</h6>
|
||||||
|
<vn-horizontal>
|
||||||
|
<vn-input-number
|
||||||
|
ng-model="$ctrl.deliveredAmount"
|
||||||
|
label="Delivered amount">
|
||||||
|
</vn-input-number>
|
||||||
|
<vn-input-number
|
||||||
|
disabled="true"
|
||||||
|
ng-model="$ctrl.amountToReturn"
|
||||||
|
label="Amount to return">
|
||||||
|
</vn-input-number>
|
||||||
|
</vn-horizontal>
|
||||||
|
</vn-vertical>
|
||||||
|
<vn-vertical ng-show="$ctrl.bankSelection.accountingType.code == 'compensation'">
|
||||||
|
<h6 translate>Compensation</h6>
|
||||||
|
<vn-textfield
|
||||||
|
ng-model="$ctrl.receipt.compensationAccount"
|
||||||
|
label="Compensation Account"
|
||||||
|
on-change="$ctrl.accountShortToStandard(value)">
|
||||||
|
</vn-textfield>
|
||||||
|
</vn-vertical>
|
||||||
</tpl-body>
|
</tpl-body>
|
||||||
<tpl-buttons>
|
<tpl-buttons>
|
||||||
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
|
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
|
||||||
|
|
|
@ -6,10 +6,7 @@ class Controller extends Dialog {
|
||||||
super($element, $, $transclude);
|
super($element, $, $transclude);
|
||||||
|
|
||||||
this.receipt = {
|
this.receipt = {
|
||||||
payed: new Date(),
|
payed: new Date()
|
||||||
clientFk: this.$params.id,
|
|
||||||
companyFk: this.vnConfig.companyFk,
|
|
||||||
bankFk: this.vnConfig.bankFk
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,12 +14,9 @@ class Controller extends Dialog {
|
||||||
this.receipt.payed = value;
|
this.receipt.payed = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
set bankFk(value) {
|
|
||||||
this.receipt.bankFk = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
set amountPaid(value) {
|
set amountPaid(value) {
|
||||||
this.receipt.amountPaid = value;
|
this.receipt.amountPaid = value;
|
||||||
|
this.amountToReturn = this.deliveredAmount - value;
|
||||||
}
|
}
|
||||||
|
|
||||||
get amountPaid() {
|
get amountPaid() {
|
||||||
|
@ -63,6 +57,30 @@ class Controller extends Dialog {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set deliveredAmount(value) {
|
||||||
|
this._deliveredAmount = value;
|
||||||
|
this.amountToReturn = value - this.receipt.amountPaid;
|
||||||
|
}
|
||||||
|
|
||||||
|
get deliveredAmount() {
|
||||||
|
return this._deliveredAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
get bankFk() {
|
||||||
|
if (!this.receipt.bankFk)
|
||||||
|
this.receipt.bankFk = this.vnConfig.bankFk;
|
||||||
|
|
||||||
|
return this.receipt.bankFk;
|
||||||
|
}
|
||||||
|
|
||||||
|
set bankFk(value) {
|
||||||
|
this.receipt.bankFk = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
accountShortToStandard(value) {
|
||||||
|
this.receipt.compensationAccount = value.replace('.', '0'.repeat(11 - value.length));
|
||||||
|
}
|
||||||
|
|
||||||
getAmountPaid() {
|
getAmountPaid() {
|
||||||
const filter = {
|
const filter = {
|
||||||
where: {
|
where: {
|
||||||
|
@ -80,7 +98,7 @@ class Controller extends Dialog {
|
||||||
if (response !== 'accept')
|
if (response !== 'accept')
|
||||||
return super.responseHandler(response);
|
return super.responseHandler(response);
|
||||||
|
|
||||||
return this.$http.post(`Receipts`, this.receipt)
|
return this.$http.post(`Clients/${this.clientFk}/createReceipt`, this.receipt)
|
||||||
.then(() => super.responseHandler(response))
|
.then(() => super.responseHandler(response))
|
||||||
.then(() => this.vnApp.showSuccess(this.$t('Data saved!')));
|
.then(() => this.vnApp.showSuccess(this.$t('Data saved!')));
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,12 +65,30 @@ describe('Client', () => {
|
||||||
|
|
||||||
controller.$params = {id: 101};
|
controller.$params = {id: 101};
|
||||||
|
|
||||||
$httpBackend.expect('POST', `Receipts`).respond({id: 1});
|
$httpBackend.expect('POST', `Clients/101/createReceipt`).respond({id: 1});
|
||||||
controller.responseHandler('accept');
|
controller.responseHandler('accept');
|
||||||
$httpBackend.flush();
|
$httpBackend.flush();
|
||||||
|
|
||||||
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('deliveredAmount() setter', () => {
|
||||||
|
it('should set the deliveredAmount property', () => {
|
||||||
|
controller.amountPaid = 999;
|
||||||
|
controller.deliveredAmount = 1000;
|
||||||
|
|
||||||
|
expect(controller.amountToReturn).toEqual(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('accountShortToStandard()', () => {
|
||||||
|
it('should get de account in stardard format', () => {
|
||||||
|
const shortAccount = '4.3';
|
||||||
|
controller.accountShortToStandard(shortAccount);
|
||||||
|
|
||||||
|
expect(controller.receipt.compensationAccount).toEqual('4000000003');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -139,7 +139,8 @@
|
||||||
<vn-client-balance-create
|
<vn-client-balance-create
|
||||||
vn-id="balance-create"
|
vn-id="balance-create"
|
||||||
on-accept="$ctrl.getData()"
|
on-accept="$ctrl.getData()"
|
||||||
company-fk="$ctrl.companyId">
|
company-fk="$ctrl.companyId"
|
||||||
|
client-fk="$ctrl.$params.id">
|
||||||
</vn-client-balance-create>
|
</vn-client-balance-create>
|
||||||
<vn-worker-descriptor-popover
|
<vn-worker-descriptor-popover
|
||||||
vn-id="workerDescriptor">
|
vn-id="workerDescriptor">
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Compensation: Compensación
|
||||||
|
Cash: Efectivo
|
|
@ -64,12 +64,15 @@
|
||||||
</span>
|
</span>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td expand>{{::sale.shipped | date: 'dd/MM/yyyy'}}</vn-td>
|
<vn-td expand>{{::sale.shipped | date: 'dd/MM/yyyy'}}</vn-td>
|
||||||
<vn-td expand>
|
<vn-td vn-fetched-tags wide>
|
||||||
|
<vn-one title="{{::sale.concept}}">{{::sale.concept}}</vn-one>
|
||||||
|
<vn-one ng-if="::sale.subName">
|
||||||
|
<h3 title="{{::sale.subName}}">{{::sale.subName}}</h3>
|
||||||
|
</vn-one>
|
||||||
<vn-fetched-tags
|
<vn-fetched-tags
|
||||||
max-length="6"
|
max-length="6"
|
||||||
item="::sale"
|
item="::sale"
|
||||||
name="::sale.concept"
|
tabindex="-1">
|
||||||
sub-name="::sale.subName">
|
|
||||||
</vn-fetched-tags>
|
</vn-fetched-tags>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td number>{{::sale.quantity | dashIfEmpty}}</vn-td>
|
<vn-td number>{{::sale.quantity | dashIfEmpty}}</vn-td>
|
||||||
|
|
|
@ -82,7 +82,6 @@
|
||||||
value-field="id"
|
value-field="id"
|
||||||
label="Previous client"
|
label="Previous client"
|
||||||
info="In case of a company succession, specify the grantor company"
|
info="In case of a company succession, specify the grantor company"
|
||||||
vn-acl="salesAssistant"
|
|
||||||
rule>
|
rule>
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
|
|
|
@ -58,3 +58,6 @@ Samples: Plantillas
|
||||||
Send sample: Enviar plantilla
|
Send sample: Enviar plantilla
|
||||||
Log: Historial
|
Log: Historial
|
||||||
Consumption: Consumo
|
Consumption: Consumo
|
||||||
|
Compensation Account: Cuenta para compensar
|
||||||
|
Amount to return: Cantidad a devolver
|
||||||
|
Delivered amount: Cantidad entregada
|
|
@ -40,7 +40,7 @@
|
||||||
value="{{$ctrl.summary.mobile}}">
|
value="{{$ctrl.summary.mobile}}">
|
||||||
</vn-label-value>
|
</vn-label-value>
|
||||||
<vn-label-value label="Email" no-ellipsize
|
<vn-label-value label="Email" no-ellipsize
|
||||||
value="{{$ctrl.summary.email}}">
|
value="{{$ctrl.listEmails($ctrl.summary.email)}}">
|
||||||
</vn-label-value>
|
</vn-label-value>
|
||||||
<vn-label-value label="Sales person">
|
<vn-label-value label="Sales person">
|
||||||
<span
|
<span
|
||||||
|
|
|
@ -97,12 +97,15 @@
|
||||||
{{::buy.description | dashIfEmpty}}
|
{{::buy.description | dashIfEmpty}}
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td number>{{::buy.size}}</vn-td>
|
<vn-td number>{{::buy.size}}</vn-td>
|
||||||
<vn-td expand>
|
<vn-td vn-fetched-tags>
|
||||||
|
<vn-one title="{{::buy.name}}">{{::buy.name}}</vn-one>
|
||||||
|
<vn-one ng-if="::buy.subName">
|
||||||
|
<h3 title="{{::buy.subName}}">{{::buy.subName}}</h3>
|
||||||
|
</vn-one>
|
||||||
<vn-fetched-tags
|
<vn-fetched-tags
|
||||||
max-length="6"
|
max-length="6"
|
||||||
item="::buy"
|
item="::buy"
|
||||||
name="::buy.name"
|
tabindex="-1">
|
||||||
sub-name="::buy.subName">
|
|
||||||
</vn-fetched-tags>
|
</vn-fetched-tags>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td shrink title="{{::buy.type}}">
|
<vn-td shrink title="{{::buy.type}}">
|
||||||
|
|
|
@ -16,6 +16,9 @@
|
||||||
{"state": "entry.card.log", "icon": "history"}
|
{"state": "entry.card.log", "icon": "history"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"keybindings": [
|
||||||
|
{"key": "e", "state": "entry.index"}
|
||||||
|
],
|
||||||
"routes": [
|
"routes": [
|
||||||
{
|
{
|
||||||
"url": "/entry",
|
"url": "/entry",
|
||||||
|
|
|
@ -142,12 +142,12 @@
|
||||||
{{::line.item.minPrice | currency: 'EUR':2}}
|
{{::line.item.minPrice | currency: 'EUR':2}}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td expand colspan="6">
|
<td vn-fetched-tags colspan="6">
|
||||||
|
<vn-one title="{{::line.item.name}}">{{::line.item.name}}</vn-one>
|
||||||
<vn-fetched-tags
|
<vn-fetched-tags
|
||||||
expand
|
max-length="6"
|
||||||
item="::line.item"
|
item="::line.item"
|
||||||
name="::line.item.name"
|
tabindex="-1">
|
||||||
sub-name="::line.item.subName">
|
|
||||||
</vn-fetched-tags>
|
</vn-fetched-tags>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -19,42 +19,56 @@ module.exports = Self => {
|
||||||
type: 'String',
|
type: 'String',
|
||||||
description: 'Searchs the invoiceOut by id',
|
description: 'Searchs the invoiceOut by id',
|
||||||
http: {source: 'query'}
|
http: {source: 'query'}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
arg: 'clientFk',
|
arg: 'clientFk',
|
||||||
type: 'Integer',
|
type: 'Integer',
|
||||||
description: 'The client id',
|
description: 'The client id',
|
||||||
http: {source: 'query'}
|
http: {source: 'query'}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
|
arg: 'fi',
|
||||||
|
type: 'String',
|
||||||
|
description: 'The client fiscal id',
|
||||||
|
http: {source: 'query'}
|
||||||
|
},
|
||||||
|
{
|
||||||
arg: 'hasPdf',
|
arg: 'hasPdf',
|
||||||
type: 'Boolean',
|
type: 'Boolean',
|
||||||
description: 'Whether the the invoiceOut has PDF or not',
|
description: 'Whether the the invoiceOut has PDF or not',
|
||||||
http: {source: 'query'}
|
http: {source: 'query'}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
arg: 'amount',
|
arg: 'amount',
|
||||||
type: 'Number',
|
type: 'Number',
|
||||||
description: 'The amount filter',
|
description: 'The amount filter',
|
||||||
http: {source: 'query'}
|
http: {source: 'query'}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
arg: 'min',
|
arg: 'min',
|
||||||
type: 'Number',
|
type: 'Number',
|
||||||
description: 'The minimun amount flter',
|
description: 'The minimun amount flter',
|
||||||
http: {source: 'query'}
|
http: {source: 'query'}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
arg: 'max',
|
arg: 'max',
|
||||||
type: 'Number',
|
type: 'Number',
|
||||||
description: 'The maximun amount flter',
|
description: 'The maximun amount flter',
|
||||||
http: {source: 'query'}
|
http: {source: 'query'}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
arg: 'issued',
|
arg: 'issued',
|
||||||
type: 'Date',
|
type: 'Date',
|
||||||
description: 'The issued date filter',
|
description: 'The issued date filter',
|
||||||
http: {source: 'query'}
|
http: {source: 'query'}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
arg: 'created',
|
arg: 'created',
|
||||||
type: 'Date',
|
type: 'Date',
|
||||||
description: 'The created date filter',
|
description: 'The created date filter',
|
||||||
http: {source: 'query'}
|
http: {source: 'query'}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
arg: 'dued',
|
arg: 'dued',
|
||||||
type: 'Date',
|
type: 'Date',
|
||||||
description: 'The due date filter',
|
description: 'The due date filter',
|
||||||
|
@ -88,6 +102,8 @@ module.exports = Self => {
|
||||||
return {'i.created': value};
|
return {'i.created': value};
|
||||||
case 'clientFk':
|
case 'clientFk':
|
||||||
return {'i.clientFk': value};
|
return {'i.clientFk': value};
|
||||||
|
case 'fi':
|
||||||
|
return {'c.fi': value};
|
||||||
case 'amount':
|
case 'amount':
|
||||||
case 'companyFk':
|
case 'companyFk':
|
||||||
case 'issued':
|
case 'issued':
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
InvoiceOut: Facturas
|
InvoiceOut: Facturas
|
||||||
Search invoices by reference: Buscar facturas por referencia
|
Search invoices by reference: Buscar facturas por referencia
|
||||||
|
Client fiscal id: CIF del cliente
|
|
@ -15,6 +15,11 @@
|
||||||
label="Client id"
|
label="Client id"
|
||||||
ng-model="filter.clientFk">
|
ng-model="filter.clientFk">
|
||||||
</vn-textfield>
|
</vn-textfield>
|
||||||
|
<vn-textfield
|
||||||
|
vn-one
|
||||||
|
label="Client fiscal id"
|
||||||
|
ng-model="filter.fi">
|
||||||
|
</vn-textfield>
|
||||||
<vn-check
|
<vn-check
|
||||||
vn-one
|
vn-one
|
||||||
triple-state="true"
|
triple-state="true"
|
||||||
|
|
|
@ -18,28 +18,44 @@ module.exports = Self => {
|
||||||
|
|
||||||
Self.downloadImages = async() => {
|
Self.downloadImages = async() => {
|
||||||
const models = Self.app.models;
|
const models = Self.app.models;
|
||||||
|
const container = await models.TempContainer.container('salix-image');
|
||||||
|
const tempPath = path.join(container.client.root, container.name);
|
||||||
|
const maxAttempts = 3;
|
||||||
|
|
||||||
try {
|
const images = await Self.find({
|
||||||
const tempPath = path.join('/tmp/salix-image');
|
where: {attempts: {eq: maxAttempts}}
|
||||||
|
|
||||||
// Create temporary path
|
|
||||||
await fs.mkdir(tempPath, {recursive: true});
|
|
||||||
|
|
||||||
const timer = setInterval(async() => {
|
|
||||||
const image = await Self.findOne({
|
|
||||||
where: {error: null, url: {neq: null}}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Exit loop
|
for (let image of images) {
|
||||||
if (!image) return clearInterval(timer);
|
const currentStamp = new Date().getTime();
|
||||||
|
const updatedStamp = image.updated.getTime();
|
||||||
|
const graceTime = Math.abs(currentStamp - updatedStamp);
|
||||||
|
const maxTTL = 3600 * 48 * 1000; // 48 hours in ms;
|
||||||
|
|
||||||
|
if (graceTime >= maxTTL)
|
||||||
|
await Self.destroyById(image.itemFk);
|
||||||
|
}
|
||||||
|
|
||||||
|
download();
|
||||||
|
|
||||||
|
async function download() {
|
||||||
|
const image = await Self.findOne({
|
||||||
|
where: {url: {neq: null}, attempts: {lt: maxAttempts}},
|
||||||
|
order: 'attempts, updated'
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!image) return;
|
||||||
|
|
||||||
const srcFile = image.url.split('/').pop();
|
const srcFile = image.url.split('/').pop();
|
||||||
const fileName = srcFile.split('.')[0];
|
const dotIndex = srcFile.lastIndexOf('.');
|
||||||
|
|
||||||
|
let fileName = srcFile.substring(0, dotIndex);
|
||||||
|
if (dotIndex == -1)
|
||||||
|
fileName = srcFile;
|
||||||
|
|
||||||
const file = `${fileName}.png`;
|
const file = `${fileName}.png`;
|
||||||
const filePath = path.join(tempPath, file);
|
const filePath = path.join(tempPath, file);
|
||||||
|
|
||||||
const writeStream = fs.createWriteStream(filePath);
|
|
||||||
writeStream.on('open', () => {
|
|
||||||
https.get(image.url, async response => {
|
https.get(image.url, async response => {
|
||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
const error = new Error(`Could not download the image. Status code ${response.statusCode}`);
|
const error = new Error(`Could not download the image. Status code ${response.statusCode}`);
|
||||||
|
@ -47,10 +63,9 @@ module.exports = Self => {
|
||||||
return await errorHandler(image.itemFk, error, filePath);
|
return await errorHandler(image.itemFk, error, filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const writeStream = fs.createWriteStream(filePath);
|
||||||
|
writeStream.on('open', () => {
|
||||||
response.pipe(writeStream);
|
response.pipe(writeStream);
|
||||||
}).on('error', async error => {
|
|
||||||
await errorHandler(image.itemFk, error, filePath);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
writeStream.on('error', async error => {
|
writeStream.on('error', async error => {
|
||||||
|
@ -58,31 +73,44 @@ module.exports = Self => {
|
||||||
});
|
});
|
||||||
|
|
||||||
writeStream.on('finish', async function() {
|
writeStream.on('finish', async function() {
|
||||||
|
writeStream.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
writeStream.on('close', async function() {
|
||||||
try {
|
try {
|
||||||
await models.Image.registerImage('catalog', filePath, fileName, image.itemFk);
|
await models.Image.registerImage('catalog', filePath, fileName, image.itemFk);
|
||||||
await image.destroy();
|
await image.destroy();
|
||||||
|
|
||||||
|
download();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
await errorHandler(image.itemFk, error, filePath);
|
await errorHandler(image.itemFk, error, filePath);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, 1000);
|
}).on('error', async error => {
|
||||||
} catch (error) {
|
await errorHandler(image.itemFk, error, filePath);
|
||||||
throw new Error('Try-catch error: ', error);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function errorHandler(rowId, error, filePath) {
|
async function errorHandler(rowId, error, filePath) {
|
||||||
try {
|
try {
|
||||||
const row = await Self.findById(rowId);
|
const row = await Self.findById(rowId);
|
||||||
|
|
||||||
if (!row)
|
if (!row) return;
|
||||||
throw new Error(`Could not update due error ${error}`);
|
|
||||||
|
|
||||||
await row.updateAttribute('error', error);
|
if (row.attempts < maxAttempts) {
|
||||||
|
await row.updateAttributes({
|
||||||
|
error: error,
|
||||||
|
attempts: row.attempts + 1,
|
||||||
|
updated: new Date()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (filePath && fs.existsSync(filePath))
|
if (filePath && fs.existsSync(filePath))
|
||||||
await fs.unlink(filePath);
|
await fs.unlink(filePath);
|
||||||
|
|
||||||
|
download();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new Error(`ErrorHandler error: ${err}`);
|
throw new Error(`Image download failed: ${err}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,8 +20,12 @@ module.exports = Self => {
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.getBalance = async filter => {
|
Self.getBalance = async filter => {
|
||||||
let where = filter.where;
|
const where = filter.where;
|
||||||
let [diary] = await Self.rawSql(`CALL vn.item_getBalance(?, ?)`, [where.itemFk, where.warehouseFk]);
|
let [diary] = await Self.rawSql(`CALL vn.item_getBalance(?, ?)`, [where.itemFk, where.warehouseFk]);
|
||||||
|
|
||||||
|
for (const entry of diary)
|
||||||
|
if (entry.clientType === 'loses') entry.highlighted = true;
|
||||||
|
|
||||||
return diary;
|
return diary;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
const app = require('vn-loopback/server/server');
|
||||||
|
const LoopBackContext = require('loopback-context');
|
||||||
|
|
||||||
|
describe('item getBalance()', () => {
|
||||||
|
it('should return the balance lines of a client type loses in which one has highlighted true', async() => {
|
||||||
|
const activeCtx = {
|
||||||
|
accessToken: {userId: 9},
|
||||||
|
};
|
||||||
|
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||||
|
active: activeCtx
|
||||||
|
});
|
||||||
|
|
||||||
|
const losesClientId = 111;
|
||||||
|
const ticket = await app.models.Ticket.findById(7);
|
||||||
|
const originalClientId = ticket.clientFk;
|
||||||
|
await ticket.updateAttribute('clientFk', losesClientId);
|
||||||
|
|
||||||
|
const filter = {
|
||||||
|
where: {
|
||||||
|
itemFk: 1,
|
||||||
|
warehouseFk: 1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const results = await app.models.Item.getBalance(filter);
|
||||||
|
|
||||||
|
const result = results.find(element => element.clientType == 'loses');
|
||||||
|
|
||||||
|
expect(result.highlighted).toBe(true);
|
||||||
|
|
||||||
|
// restores
|
||||||
|
await ticket.updateAttribute('clientFk', originalClientId);
|
||||||
|
});
|
||||||
|
});
|
|
@ -9,17 +9,25 @@
|
||||||
},
|
},
|
||||||
"properties": {
|
"properties": {
|
||||||
"itemFk": {
|
"itemFk": {
|
||||||
"type": "Number",
|
"type": "number",
|
||||||
"id": true,
|
"id": true,
|
||||||
"description": "Identifier"
|
"description": "Identifier"
|
||||||
},
|
},
|
||||||
"url": {
|
"url": {
|
||||||
"type": "String",
|
"type": "string",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"type": "String",
|
"type": "string"
|
||||||
"required": true
|
},
|
||||||
|
"attempts": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"created": {
|
||||||
|
"type": "date"
|
||||||
|
},
|
||||||
|
"updated": {
|
||||||
|
"type": "date"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"relations": {
|
"relations": {
|
||||||
|
|
|
@ -68,7 +68,8 @@
|
||||||
"stemMultiplier": {
|
"stemMultiplier": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"description": "Multiplier"
|
"description": "Multiplier"
|
||||||
},"image": {
|
},
|
||||||
|
"image": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Image"
|
"description": "Image"
|
||||||
},
|
},
|
||||||
|
|
|
@ -64,6 +64,7 @@
|
||||||
<vn-td>{{::sale.stateName | dashIfEmpty}}</vn-td>
|
<vn-td>{{::sale.stateName | dashIfEmpty}}</vn-td>
|
||||||
<vn-td>{{::sale.reference | dashIfEmpty}}</vn-td>
|
<vn-td>{{::sale.reference | dashIfEmpty}}</vn-td>
|
||||||
<vn-td class="truncate" expand>
|
<vn-td class="truncate" expand>
|
||||||
|
<span ng-class="::{'warning chip': sale.highlighted}">
|
||||||
<span ng-if="::!sale.isTicket">
|
<span ng-if="::!sale.isTicket">
|
||||||
{{::sale.name | dashIfEmpty}}
|
{{::sale.name | dashIfEmpty}}
|
||||||
</span>
|
</span>
|
||||||
|
@ -73,6 +74,7 @@
|
||||||
class="link">
|
class="link">
|
||||||
{{::sale.name | dashIfEmpty}}
|
{{::sale.name | dashIfEmpty}}
|
||||||
</span>
|
</span>
|
||||||
|
</span>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td number class="in">{{::sale.in | dashIfEmpty}}</vn-td>
|
<vn-td number class="in">{{::sale.in | dashIfEmpty}}</vn-td>
|
||||||
<vn-td number>{{::sale.out | dashIfEmpty}}</vn-td>
|
<vn-td number>{{::sale.out | dashIfEmpty}}</vn-td>
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
<vn-one title="{{$ctrl.name}}">{{$ctrl.name}}</vn-one>
|
|
||||||
<vn-one ng-if="$ctrl.subName">
|
|
||||||
<h3 title="{{$ctrl.subName}}">{{$ctrl.subName}}</h3>
|
|
||||||
</vn-one>
|
|
||||||
<vn-auto>
|
<vn-auto>
|
||||||
<section
|
<section
|
||||||
class="inline-tag ellipsize"
|
class="inline-tag ellipsize"
|
||||||
|
|
|
@ -8,7 +8,5 @@ ngModule.vnComponent('vnFetchedTags', {
|
||||||
bindings: {
|
bindings: {
|
||||||
maxLength: '<',
|
maxLength: '<',
|
||||||
item: '<',
|
item: '<',
|
||||||
name: '<?',
|
|
||||||
subName: '<?'
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,42 +1,30 @@
|
||||||
@import "variables";
|
@import "variables";
|
||||||
|
|
||||||
vn-fetched-tags {
|
vn-fetched-tags {
|
||||||
&.noTitle vn-one {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
& > vn-horizontal {
|
& > vn-horizontal {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
& > vn-one {
|
& > vn-auto {
|
||||||
overflow: hidden;
|
flex-wrap: wrap;
|
||||||
text-overflow: ellipsis;
|
|
||||||
min-width: 80px;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > vn-one:nth-child(2) h3 {
|
& > .inline-tag {
|
||||||
color: $color-font-secondary;
|
margin: 1px;
|
||||||
text-transform: uppercase;
|
}
|
||||||
line-height: initial;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 1rem
|
|
||||||
}
|
}
|
||||||
|
|
||||||
& > vn-auto {
|
& > vn-auto {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding-left: 6px;
|
|
||||||
min-width: 192px;
|
|
||||||
|
|
||||||
& > .inline-tag {
|
& > .inline-tag {
|
||||||
display: inline-block;
|
|
||||||
color: $color-font-secondary;
|
color: $color-font-secondary;
|
||||||
margin-left: 6px;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: .75rem;
|
font-size: .75rem;
|
||||||
height: 20px;
|
height: 12px;
|
||||||
padding: 1px;
|
padding: 1px;
|
||||||
border-radius: 1px;
|
|
||||||
width: 64px;
|
width: 64px;
|
||||||
min-width: 64px;
|
min-width: 64px;
|
||||||
|
max-width: 64px;
|
||||||
|
flex: 1;
|
||||||
border: 1px solid $color-spacer;
|
border: 1px solid $color-spacer;
|
||||||
|
|
||||||
&.empty {
|
&.empty {
|
||||||
|
@ -44,22 +32,5 @@ vn-fetched-tags {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@media screen and (max-width: 1600px) {
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
& > vn-one {
|
|
||||||
padding-bottom: 3px
|
|
||||||
}
|
|
||||||
& > vn-auto {
|
|
||||||
white-space: initial;
|
|
||||||
padding-left: 0;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
& > .inline-tag {
|
|
||||||
margin: 1px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -22,13 +22,13 @@
|
||||||
model="model">
|
model="model">
|
||||||
</vn-searchbar>
|
</vn-searchbar>
|
||||||
</vn-portal>
|
</vn-portal>
|
||||||
<div class="vn-w-xl">
|
<div class="vn-w-lg">
|
||||||
<vn-card>
|
<vn-card>
|
||||||
<vn-table model="model">
|
<vn-table model="model">
|
||||||
<vn-thead>
|
<vn-thead>
|
||||||
<vn-tr>
|
<vn-tr>
|
||||||
<vn-th field="itemFk">Item ID</vn-th>
|
<vn-th field="itemFk" shrink>Item ID</vn-th>
|
||||||
<vn-th field="itemFk">Item</vn-th>
|
<vn-th field="itemFk">Description</vn-th>
|
||||||
<vn-th field="warehouseFk">Warehouse</vn-th>
|
<vn-th field="warehouseFk">Warehouse</vn-th>
|
||||||
<vn-th field="rate2">P.P.U.</vn-th>
|
<vn-th field="rate2">P.P.U.</vn-th>
|
||||||
<vn-th field="rate3">P.P.P.</vn-th>
|
<vn-th field="rate3">P.P.P.</vn-th>
|
||||||
|
@ -40,7 +40,7 @@
|
||||||
</vn-thead>
|
</vn-thead>
|
||||||
<vn-tbody>
|
<vn-tbody>
|
||||||
<vn-tr ng-repeat="price in prices">
|
<vn-tr ng-repeat="price in prices">
|
||||||
<vn-td>
|
<vn-td shrink>
|
||||||
<span
|
<span
|
||||||
ng-if="price.itemFk"
|
ng-if="price.itemFk"
|
||||||
ng-click="itemDescriptor.show($event, price.itemFk)"
|
ng-click="itemDescriptor.show($event, price.itemFk)"
|
||||||
|
@ -64,16 +64,16 @@
|
||||||
</tpl-item>
|
</tpl-item>
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td expand>
|
<vn-td vn-fetched-tags>
|
||||||
<text>
|
<vn-one title="{{price.name}}">{{price.name}}</vn-one>
|
||||||
|
<vn-one ng-if="price.subName">
|
||||||
|
<h3 title="{{price.subName}}">{{price.subName}}</h3>
|
||||||
|
</vn-one>
|
||||||
<vn-fetched-tags
|
<vn-fetched-tags
|
||||||
max-length="6"
|
max-length="6"
|
||||||
item="price"
|
item="price"
|
||||||
name="price.name"
|
|
||||||
sub-name="price.subName"
|
|
||||||
tabindex="-1">
|
tabindex="-1">
|
||||||
</vn-fetched-tags>
|
</vn-fetched-tags>
|
||||||
</text>
|
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td>
|
<vn-td>
|
||||||
<vn-autocomplete
|
<vn-autocomplete
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
<vn-th field="id" shrink>Id</vn-th>
|
<vn-th field="id" shrink>Id</vn-th>
|
||||||
<vn-th field="grouping" shrink>Grouping</vn-th>
|
<vn-th field="grouping" shrink>Grouping</vn-th>
|
||||||
<vn-th field="packing" shrink>Packing</vn-th>
|
<vn-th field="packing" shrink>Packing</vn-th>
|
||||||
<vn-th field="description" style="text-align: center">Description</vn-th>
|
<vn-th field="description">Description</vn-th>
|
||||||
<vn-th field="stems" shrink>Stems</vn-th>
|
<vn-th field="stems" shrink>Stems</vn-th>
|
||||||
<vn-th field="size" shrink>Size</vn-th>
|
<vn-th field="size" shrink>Size</vn-th>
|
||||||
<vn-th field="niche" shrink>Niche</vn-th>
|
<vn-th field="niche" shrink>Niche</vn-th>
|
||||||
|
@ -50,12 +50,15 @@
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td shrink>{{::item.grouping | dashIfEmpty}}</vn-td>
|
<vn-td shrink>{{::item.grouping | dashIfEmpty}}</vn-td>
|
||||||
<vn-td shrink>{{::item.packing | dashIfEmpty}}</vn-td>
|
<vn-td shrink>{{::item.packing | dashIfEmpty}}</vn-td>
|
||||||
<vn-td expand>
|
<vn-td vn-fetched-tags>
|
||||||
|
<vn-one title="{{::item.name}}">{{::item.name}}</vn-one>
|
||||||
|
<vn-one ng-if="::item.subName">
|
||||||
|
<h3 title="{{::item.subName}}">{{::item.subName}}</h3>
|
||||||
|
</vn-one>
|
||||||
<vn-fetched-tags
|
<vn-fetched-tags
|
||||||
max-length="6"
|
max-length="6"
|
||||||
item="::item"
|
item="item"
|
||||||
name="::item.name"
|
tabindex="-1">
|
||||||
sub-name="::item.subName">
|
|
||||||
</vn-fetched-tags>
|
</vn-fetched-tags>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td shrink>{{::item.stems}}</vn-td>
|
<vn-td shrink>{{::item.stems}}</vn-td>
|
||||||
|
|
|
@ -21,9 +21,6 @@ vn-item-product {
|
||||||
vn-label-value:first-of-type section{
|
vn-label-value:first-of-type section{
|
||||||
margin-top: 9px;
|
margin-top: 9px;
|
||||||
}
|
}
|
||||||
vn-fetched-tags vn-horizontal{
|
|
||||||
margin-top: 14px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vn-table {
|
vn-table {
|
||||||
|
|
|
@ -32,14 +32,14 @@
|
||||||
rule>
|
rule>
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
<vn-textfield vn-three
|
<vn-textfield vn-three
|
||||||
ng-show="tag.selection.isFree || tag.selection.isFree == undefined"
|
ng-if="tag.selection.isFree || tag.selection.isFree == undefined"
|
||||||
vn-id="text"
|
vn-id="text"
|
||||||
label="Value"
|
label="Value"
|
||||||
ng-model="itemTag.value"
|
ng-model="itemTag.value"
|
||||||
rule>
|
rule>
|
||||||
</vn-textfield>
|
</vn-textfield>
|
||||||
<vn-autocomplete vn-three
|
<vn-autocomplete vn-three
|
||||||
ng-show="tag.selection.isFree === false"
|
ng-if="tag.selection.isFree === false"
|
||||||
url="{{'Tags/' + itemTag.tagFk + '/filterValue'}}"
|
url="{{'Tags/' + itemTag.tagFk + '/filterValue'}}"
|
||||||
search-function="{value: $search}"
|
search-function="{value: $search}"
|
||||||
label="Value"
|
label="Value"
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
<vn-th number>Id</vn-th>
|
<vn-th number>Id</vn-th>
|
||||||
<vn-th>Description</vn-th>
|
<vn-th>Description</vn-th>
|
||||||
<vn-th>Warehouse</vn-th>
|
<vn-th>Warehouse</vn-th>
|
||||||
<vn-th expand>Shipped</vn-th>
|
<vn-th>Shipped</vn-th>
|
||||||
<vn-th number>Quantity</vn-th>
|
<vn-th number>Quantity</vn-th>
|
||||||
<vn-th number>Price</vn-th>
|
<vn-th number>Price</vn-th>
|
||||||
<vn-th number>Amount</vn-th>
|
<vn-th number>Amount</vn-th>
|
||||||
|
@ -42,16 +42,19 @@
|
||||||
{{::row.itemFk | zeroFill:6}}
|
{{::row.itemFk | zeroFill:6}}
|
||||||
</span>
|
</span>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td expand>
|
<vn-td vn-fetched-tags>
|
||||||
|
<vn-one title="{{::row.item.name}}">{{::row.item.name}}</vn-one>
|
||||||
|
<vn-one ng-if="::row.item.subName">
|
||||||
|
<h3 title="{{::row.item.subName}}">{{::row.item.subName}}</h3>
|
||||||
|
</vn-one>
|
||||||
<vn-fetched-tags
|
<vn-fetched-tags
|
||||||
max-length="6"
|
max-length="6"
|
||||||
item="::row.item"
|
item="::row.item"
|
||||||
name="::row.item.name"
|
tabindex="-1">
|
||||||
sub-name="::row.item.subName">
|
|
||||||
</vn-fetched-tags>
|
</vn-fetched-tags>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td shrink>{{::row.warehouse.name}}</vn-td>
|
<vn-td>{{::row.warehouse.name}}</vn-td>
|
||||||
<vn-td expand>{{::row.shipped | date: 'dd/MM/yyyy'}}</vn-td>
|
<vn-td>{{::row.shipped | date: 'dd/MM/yyyy'}}</vn-td>
|
||||||
<vn-td number>{{::row.quantity}}</vn-td>
|
<vn-td number>{{::row.quantity}}</vn-td>
|
||||||
<vn-td number>
|
<vn-td number>
|
||||||
{{::row.price | currency: 'EUR':2}}
|
{{::row.price | currency: 'EUR':2}}
|
||||||
|
|
|
@ -98,12 +98,15 @@
|
||||||
{{::row.itemFk | zeroFill:6}}
|
{{::row.itemFk | zeroFill:6}}
|
||||||
</span>
|
</span>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td expand>
|
<vn-td expand vn-fetched-tags>
|
||||||
|
<vn-one title="{{::row.item.name}}">{{::row.item.name}}</vn-one>
|
||||||
|
<vn-one ng-if="::row.item.subName">
|
||||||
|
<h3 title="{{::row.item.subName}}">{{::row.item.subName}}</h3>
|
||||||
|
</vn-one>
|
||||||
<vn-fetched-tags
|
<vn-fetched-tags
|
||||||
max-length="6"
|
max-length="6"
|
||||||
item="::row.item"
|
item="::row.item"
|
||||||
name="::row.item.name"
|
tabindex="-1">
|
||||||
sub-name="::row.item.subName">
|
|
||||||
</vn-fetched-tags>
|
</vn-fetched-tags>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td number>{{::row.quantity}}</vn-td>
|
<vn-td number>{{::row.quantity}}</vn-td>
|
||||||
|
|
|
@ -24,31 +24,34 @@
|
||||||
<vn-table model="model">
|
<vn-table model="model">
|
||||||
<vn-thead>
|
<vn-thead>
|
||||||
<vn-tr>
|
<vn-tr>
|
||||||
<vn-th field="itemFk" default-order="ASC" number>Item</vn-th>
|
<vn-th shrink field="itemFk" default-order="ASC" number>Item</vn-th>
|
||||||
<vn-th>Description</vn-th>
|
<vn-th>Description</vn-th>
|
||||||
<vn-th field="quantity" number>Quantity</vn-th>
|
<vn-th shrink field="quantity" number>Quantity</vn-th>
|
||||||
<vn-th number>m³ per quantity</vn-th>
|
<vn-th shrink number>m³ per quantity</vn-th>
|
||||||
</vn-tr>
|
</vn-tr>
|
||||||
</vn-thead>
|
</vn-thead>
|
||||||
<vn-tbody>
|
<vn-tbody>
|
||||||
<vn-tr ng-repeat="row in rows">
|
<vn-tr ng-repeat="row in rows">
|
||||||
<vn-td number>
|
<vn-td shrink number>
|
||||||
<span
|
<span
|
||||||
ng-click="descriptor.show($event, row.itemFk)"
|
ng-click="descriptor.show($event, row.itemFk)"
|
||||||
class="link">
|
class="link">
|
||||||
{{::row.itemFk}}
|
{{::row.itemFk}}
|
||||||
</span>
|
</span>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td expand>
|
<vn-td wide vn-fetched-tags>
|
||||||
|
<vn-one title="{{::row.item.name}}">{{::row.item.name}}</vn-one>
|
||||||
|
<vn-one ng-if="::row.item.subName">
|
||||||
|
<h3 title="{{::row.item.subName}}">{{::row.item.subName}}</h3>
|
||||||
|
</vn-one>
|
||||||
<vn-fetched-tags
|
<vn-fetched-tags
|
||||||
max-length="6"
|
max-length="6"
|
||||||
item="::row.item"
|
item="::row.item"
|
||||||
name="::row.item.name"
|
tabindex="-1">
|
||||||
sub-name="::row.item.subName">
|
|
||||||
</vn-fetched-tags>
|
</vn-fetched-tags>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td number>{{::row.quantity}}</vn-td>
|
<vn-td shrink number>{{::row.quantity}}</vn-td>
|
||||||
<vn-td number>{{::row.volume | number:3}}</vn-td>
|
<vn-td shrink number>{{::row.volume | number:3}}</vn-td>
|
||||||
</vn-tr>
|
</vn-tr>
|
||||||
</vn-tbody>
|
</vn-tbody>
|
||||||
</vn-table>
|
</vn-table>
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
const app = require('vn-loopback/server/server');
|
const app = require('vn-loopback/server/server');
|
||||||
const LoopBackContext = require('loopback-context');
|
const LoopBackContext = require('loopback-context');
|
||||||
|
|
||||||
// #2735 route updateVolume() returns inconsistent values
|
describe('route updateVolume()', () => {
|
||||||
xdescribe('route updateVolume()', () => {
|
|
||||||
const routeId = 1;
|
const routeId = 1;
|
||||||
const userId = 50;
|
const userId = 50;
|
||||||
const activeCtx = {
|
const activeCtx = {
|
||||||
|
@ -19,7 +18,6 @@ xdescribe('route updateVolume()', () => {
|
||||||
expect(route.m3).toEqual(1.8);
|
expect(route.m3).toEqual(1.8);
|
||||||
|
|
||||||
const ticket = await app.models.Ticket.findById(14);
|
const ticket = await app.models.Ticket.findById(14);
|
||||||
|
|
||||||
await ticket.updateAttributes({routeFk: routeId});
|
await ticket.updateAttributes({routeFk: routeId});
|
||||||
await app.models.Route.updateVolume(ctx, routeId);
|
await app.models.Route.updateVolume(ctx, routeId);
|
||||||
|
|
||||||
|
@ -30,6 +28,7 @@ xdescribe('route updateVolume()', () => {
|
||||||
const logs = await app.models.RouteLog.find({fields: ['id', 'newInstance']});
|
const logs = await app.models.RouteLog.find({fields: ['id', 'newInstance']});
|
||||||
|
|
||||||
const m3Log = logs.filter(log => {
|
const m3Log = logs.filter(log => {
|
||||||
|
if (log.newInstance)
|
||||||
return log.newInstance.m3 === updatedRoute.m3;
|
return log.newInstance.m3 === updatedRoute.m3;
|
||||||
});
|
});
|
||||||
const logIdToDestroy = m3Log[0].id;
|
const logIdToDestroy = m3Log[0].id;
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
vn-focus
|
vn-focus
|
||||||
panel="vn-route-search-panel"
|
panel="vn-route-search-panel"
|
||||||
info="Search routes by id"
|
info="Search routes by id"
|
||||||
|
fetch-params="$ctrl.fetchParams($params)"
|
||||||
filter="$ctrl.filterParams"
|
filter="$ctrl.filterParams"
|
||||||
model="model">
|
model="model">
|
||||||
</vn-searchbar>
|
</vn-searchbar>
|
||||||
|
|
|
@ -3,16 +3,36 @@ import ModuleMain from 'salix/components/module-main';
|
||||||
|
|
||||||
export default class Route extends ModuleMain {
|
export default class Route extends ModuleMain {
|
||||||
$postLink() {
|
$postLink() {
|
||||||
let to = new Date();
|
const to = new Date();
|
||||||
to.setDate(to.getDate() + 1);
|
to.setDate(to.getDate() + 1);
|
||||||
to.setHours(0, 0, 0, 0);
|
to.setHours(0, 0, 0, 0);
|
||||||
|
|
||||||
let from = new Date();
|
const from = new Date();
|
||||||
|
from.setDate(from.getDate());
|
||||||
from.setHours(0, 0, 0, 0);
|
from.setHours(0, 0, 0, 0);
|
||||||
|
|
||||||
this.filterParams = {from, to, warehouseFk: this.vnConfig.warehouseFk};
|
this.filterParams = {from, to};
|
||||||
this.$.model.applyFilter(null, this.filterParams);
|
this.$.model.applyFilter(null, this.filterParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fetchParams($params) {
|
||||||
|
const hasEntries = Object.entries($params).length;
|
||||||
|
if (!hasEntries)
|
||||||
|
$params.scopeDays = 1;
|
||||||
|
|
||||||
|
if (typeof $params.scopeDays === 'number') {
|
||||||
|
const from = new Date();
|
||||||
|
from.setHours(0, 0, 0, 0);
|
||||||
|
|
||||||
|
const to = new Date(from.getTime());
|
||||||
|
to.setDate(to.getDate() + $params.scopeDays);
|
||||||
|
to.setHours(23, 59, 59, 999);
|
||||||
|
|
||||||
|
Object.assign($params, {from, to});
|
||||||
|
}
|
||||||
|
|
||||||
|
return $params;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngModule.vnComponent('vnRoute', {
|
ngModule.vnComponent('vnRoute', {
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
import './index.js';
|
||||||
|
|
||||||
|
describe('Route Component vnRoute', () => {
|
||||||
|
let controller;
|
||||||
|
|
||||||
|
beforeEach(ngModule('route'));
|
||||||
|
|
||||||
|
beforeEach(inject($componentController => {
|
||||||
|
let $element = angular.element(`<div></div>`);
|
||||||
|
controller = $componentController('vnRoute', {$element});
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('fetchParams()', () => {
|
||||||
|
it('should return a range of dates with passed scope days', () => {
|
||||||
|
let params = controller.fetchParams({
|
||||||
|
scopeDays: 2
|
||||||
|
});
|
||||||
|
const from = new Date();
|
||||||
|
from.setHours(0, 0, 0, 0);
|
||||||
|
const to = new Date(from.getTime());
|
||||||
|
to.setDate(to.getDate() + params.scopeDays);
|
||||||
|
to.setHours(23, 59, 59, 999);
|
||||||
|
|
||||||
|
const expectedParams = {
|
||||||
|
from,
|
||||||
|
scopeDays: params.scopeDays,
|
||||||
|
to
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(params).toEqual(expectedParams);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return default value for scope days', () => {
|
||||||
|
let params = controller.fetchParams({
|
||||||
|
scopeDays: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(params.scopeDays).toEqual(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the given scope days', () => {
|
||||||
|
let params = controller.fetchParams({
|
||||||
|
scopeDays: 2
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(params.scopeDays).toEqual(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,6 +1,6 @@
|
||||||
<div class="search-panel">
|
<div class="search-panel">
|
||||||
<form ng-submit="$ctrl.onSearch()">
|
<form id="manifold-form" ng-submit="$ctrl.onSearch()">
|
||||||
<vn-horizontal>
|
<vn-horizontal class="vn-px-lg vn-pt-lg">
|
||||||
<vn-textfield
|
<vn-textfield
|
||||||
vn-one
|
vn-one
|
||||||
label="General search"
|
label="General search"
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
vn-focus>
|
vn-focus>
|
||||||
</vn-textfield>
|
</vn-textfield>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
<vn-horizontal>
|
<vn-horizontal class="vn-px-lg">
|
||||||
<vn-autocomplete
|
<vn-autocomplete
|
||||||
vn-one
|
vn-one
|
||||||
ng-model="filter.workerFk"
|
ng-model="filter.workerFk"
|
||||||
|
@ -29,19 +29,37 @@
|
||||||
value-field="id">
|
value-field="id">
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
<vn-horizontal>
|
<section class="vn-px-md">
|
||||||
|
<vn-horizontal class="manifold-panel vn-pa-md">
|
||||||
<vn-date-picker
|
<vn-date-picker
|
||||||
vn-one
|
vn-one
|
||||||
label="From"
|
label="From"
|
||||||
ng-model="filter.from">
|
ng-model="filter.from"
|
||||||
|
on-change="$ctrl.from = value">
|
||||||
</vn-date-picker>
|
</vn-date-picker>
|
||||||
<vn-date-picker
|
<vn-date-picker
|
||||||
vn-one
|
vn-one
|
||||||
label="To"
|
label="To"
|
||||||
ng-model="filter.to">
|
ng-model="filter.to"
|
||||||
|
on-change="$ctrl.to = value">
|
||||||
</vn-date-picker>
|
</vn-date-picker>
|
||||||
|
<vn-none class="or vn-px-md" translate>Or</vn-none>
|
||||||
|
<vn-input-number
|
||||||
|
vn-one
|
||||||
|
min="0"
|
||||||
|
step="1"
|
||||||
|
label="Days onward"
|
||||||
|
ng-model="filter.scopeDays"
|
||||||
|
on-change="$ctrl.scopeDays = value"
|
||||||
|
display-controls="true">
|
||||||
|
</vn-input-number>
|
||||||
|
<vn-icon color-marginal
|
||||||
|
icon="info"
|
||||||
|
vn-tooltip="Cannot choose a range of dates and days onward at the same time">
|
||||||
|
</vn-icon>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
<vn-horizontal>
|
</section>
|
||||||
|
<vn-horizontal class="vn-px-lg">
|
||||||
<vn-autocomplete
|
<vn-autocomplete
|
||||||
vn-one
|
vn-one
|
||||||
label="Vehicle"
|
label="Vehicle"
|
||||||
|
@ -56,7 +74,7 @@
|
||||||
ng-model="filter.m3">
|
ng-model="filter.m3">
|
||||||
</vn-textfield>
|
</vn-textfield>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
<vn-horizontal>
|
<vn-horizontal class="vn-px-lg">
|
||||||
<vn-autocomplete
|
<vn-autocomplete
|
||||||
vn-one
|
vn-one
|
||||||
label="Warehouse"
|
label="Warehouse"
|
||||||
|
@ -71,7 +89,7 @@
|
||||||
ng-model="filter.description">
|
ng-model="filter.description">
|
||||||
</vn-textfield>
|
</vn-textfield>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
<vn-horizontal class="vn-mt-lg">
|
<vn-horizontal class="vn-px-lg vn-pb-lg vn-mt-lg">
|
||||||
<vn-submit label="Search"></vn-submit>
|
<vn-submit label="Search"></vn-submit>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -1,7 +1,43 @@
|
||||||
import ngModule from '../module';
|
import ngModule from '../module';
|
||||||
import SearchPanel from 'core/components/searchbar/search-panel';
|
import SearchPanel from 'core/components/searchbar/search-panel';
|
||||||
|
|
||||||
|
class Controller extends SearchPanel {
|
||||||
|
constructor($, $element) {
|
||||||
|
super($, $element);
|
||||||
|
this.filter = this.$.filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
get from() {
|
||||||
|
return this._from;
|
||||||
|
}
|
||||||
|
|
||||||
|
set from(value) {
|
||||||
|
this._from = value;
|
||||||
|
this.filter.scopeDays = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
get to() {
|
||||||
|
return this._to;
|
||||||
|
}
|
||||||
|
|
||||||
|
set to(value) {
|
||||||
|
this._to = value;
|
||||||
|
this.filter.scopeDays = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
get scopeDays() {
|
||||||
|
return this._scopeDays;
|
||||||
|
}
|
||||||
|
|
||||||
|
set scopeDays(value) {
|
||||||
|
this._scopeDays = value;
|
||||||
|
|
||||||
|
this.filter.from = null;
|
||||||
|
this.filter.to = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ngModule.vnComponent('vnRouteSearchPanel', {
|
ngModule.vnComponent('vnRouteSearchPanel', {
|
||||||
template: require('./index.html'),
|
template: require('./index.html'),
|
||||||
controller: SearchPanel
|
controller: Controller
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
import './index';
|
||||||
|
|
||||||
|
describe('Route Component vnRouteSearchPanel', () => {
|
||||||
|
let controller;
|
||||||
|
|
||||||
|
beforeEach(ngModule('route'));
|
||||||
|
|
||||||
|
beforeEach(inject($componentController => {
|
||||||
|
controller = $componentController('vnRouteSearchPanel', {$element: null});
|
||||||
|
controller.$t = () => {};
|
||||||
|
controller.filter = {};
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('from() setter', () => {
|
||||||
|
it('should clear the scope days when setting the from property', () => {
|
||||||
|
controller.filter.scopeDays = 1;
|
||||||
|
|
||||||
|
controller.from = new Date();
|
||||||
|
|
||||||
|
expect(controller.filter.scopeDays).toBeNull();
|
||||||
|
expect(controller.from).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('to() setter', () => {
|
||||||
|
it('should clear the scope days when setting the to property', () => {
|
||||||
|
controller.filter.scopeDays = 1;
|
||||||
|
|
||||||
|
controller.to = new Date();
|
||||||
|
|
||||||
|
expect(controller.filter.scopeDays).toBeNull();
|
||||||
|
expect(controller.to).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('scopeDays() setter', () => {
|
||||||
|
it('should clear the date range when setting the scopeDays property', () => {
|
||||||
|
controller.filter.from = new Date();
|
||||||
|
controller.filter.to = new Date();
|
||||||
|
|
||||||
|
controller.scopeDays = 1;
|
||||||
|
|
||||||
|
expect(controller.filter.from).toBeNull();
|
||||||
|
expect(controller.filter.to).toBeNull();
|
||||||
|
expect(controller.scopeDays).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -42,6 +42,7 @@ module.exports = Self => {
|
||||||
'sageTaxTypeFk',
|
'sageTaxTypeFk',
|
||||||
'sageTransactionTypeFk',
|
'sageTransactionTypeFk',
|
||||||
'sageWithholdingFk',
|
'sageWithholdingFk',
|
||||||
|
'workerFk'
|
||||||
],
|
],
|
||||||
include: [
|
include: [
|
||||||
{
|
{
|
||||||
|
@ -85,7 +86,19 @@ module.exports = Self => {
|
||||||
scope: {
|
scope: {
|
||||||
fields: ['id', 'withholding']
|
fields: ['id', 'withholding']
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
relation: 'worker',
|
||||||
|
scope: {
|
||||||
|
fields: ['userFk'],
|
||||||
|
include: {
|
||||||
|
relation: 'user',
|
||||||
|
scope: {
|
||||||
|
fields: ['nickname']
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
let supplier = await Self.app.models.Supplier.findOne(filter);
|
let supplier = await Self.app.models.Supplier.findOne(filter);
|
||||||
|
|
|
@ -11,75 +11,78 @@
|
||||||
},
|
},
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"id": {
|
||||||
"type": "Number",
|
"type": "number",
|
||||||
"id": true,
|
"id": true,
|
||||||
"description": "Identifier"
|
"description": "Identifier"
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"type": "String"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"account": {
|
"account": {
|
||||||
"type": "String"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"countryFk": {
|
"countryFk": {
|
||||||
"type": "Number"
|
"type": "number"
|
||||||
},
|
},
|
||||||
"nif": {
|
"nif": {
|
||||||
"type": "String"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"isFarmer": {
|
"isFarmer": {
|
||||||
"type": "Boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"phone": {
|
"phone": {
|
||||||
"type": "Number"
|
"type": "number"
|
||||||
},
|
},
|
||||||
"retAccount": {
|
"retAccount": {
|
||||||
"type": "Number"
|
"type": "number"
|
||||||
},
|
},
|
||||||
"commission": {
|
"commission": {
|
||||||
"type": "Boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"created": {
|
"created": {
|
||||||
"type": "Date"
|
"type": "date"
|
||||||
},
|
},
|
||||||
"postcodeFk": {
|
"postcodeFk": {
|
||||||
"type": "Number"
|
"type": "number"
|
||||||
},
|
},
|
||||||
"isActive": {
|
"isActive": {
|
||||||
"type": "Boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"isOfficial": {
|
"isOfficial": {
|
||||||
"type": "Boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"isSerious": {
|
"isSerious": {
|
||||||
"type": "Boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"note": {
|
"note": {
|
||||||
"type": "String"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"street": {
|
"street": {
|
||||||
"type": "String"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"city": {
|
"city": {
|
||||||
"type": "String"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"provinceFk": {
|
"provinceFk": {
|
||||||
"type": "Number"
|
"type": "number"
|
||||||
},
|
},
|
||||||
"postCode": {
|
"postCode": {
|
||||||
"type": "String"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"payMethodFk": {
|
"payMethodFk": {
|
||||||
"type": "Number"
|
"type": "number"
|
||||||
},
|
},
|
||||||
"payDemFk": {
|
"payDemFk": {
|
||||||
"type": "Number"
|
"type": "number"
|
||||||
},
|
},
|
||||||
"payDay": {
|
"payDay": {
|
||||||
"type": "Number"
|
"type": "number"
|
||||||
},
|
},
|
||||||
"nickname": {
|
"nickname": {
|
||||||
"type": "String"
|
"type": "string"
|
||||||
|
},
|
||||||
|
"workerFk": {
|
||||||
|
"type": "number"
|
||||||
},
|
},
|
||||||
"sageTaxTypeFk": {
|
"sageTaxTypeFk": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
|
@ -126,6 +129,11 @@
|
||||||
"model": "Client",
|
"model": "Client",
|
||||||
"foreignKey": "nif",
|
"foreignKey": "nif",
|
||||||
"primaryKey": "fi"
|
"primaryKey": "fi"
|
||||||
|
},
|
||||||
|
"worker": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Worker",
|
||||||
|
"foreignKey": "workerFk"
|
||||||
},
|
},
|
||||||
"sageTaxType": {
|
"sageTaxType": {
|
||||||
"type": "belongsTo",
|
"type": "belongsTo",
|
||||||
|
|
|
@ -15,6 +15,17 @@
|
||||||
rule
|
rule
|
||||||
vn-focus>
|
vn-focus>
|
||||||
</vn-textfield>
|
</vn-textfield>
|
||||||
|
<vn-autocomplete
|
||||||
|
vn-one
|
||||||
|
ng-model="$ctrl.supplier.workerFk"
|
||||||
|
url="Clients/activeWorkersWithRole"
|
||||||
|
search-function="{firstName: $search}"
|
||||||
|
show-field="nickname"
|
||||||
|
value-field="id"
|
||||||
|
where="{role: 'employee'}"
|
||||||
|
label="Responsible"
|
||||||
|
info="Responsible for approving invoices">
|
||||||
|
</vn-autocomplete>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
<vn-check
|
<vn-check
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
Notes: Notas
|
Notes: Notas
|
||||||
Active: Activo
|
Active: Activo
|
||||||
Verified: Verificado
|
Verified: Verificado
|
||||||
|
Responsible for approving invoices: Responsable de aprobar las facturas
|
|
@ -37,7 +37,7 @@
|
||||||
<vn-thead>
|
<vn-thead>
|
||||||
<vn-tr>
|
<vn-tr>
|
||||||
<vn-th field="entryFk" expand>Entry </vn-th>
|
<vn-th field="entryFk" expand>Entry </vn-th>
|
||||||
<vn-td expand>{{::entry.id}}</vn-td>
|
<vn-td>{{::entry.id}}</vn-td>
|
||||||
<vn-th field="data">Date</vn-th>
|
<vn-th field="data">Date</vn-th>
|
||||||
<vn-td>{{::entry.shipped | date: 'dd/MM/yyyy'}}</vn-td>
|
<vn-td>{{::entry.shipped | date: 'dd/MM/yyyy'}}</vn-td>
|
||||||
<vn-th field="ref">Reference</vn-th>
|
<vn-th field="ref">Reference</vn-th>
|
||||||
|
@ -51,10 +51,15 @@
|
||||||
{{::buy.itemName}}
|
{{::buy.itemName}}
|
||||||
</span>
|
</span>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td expand>
|
<vn-td vn-fetched-tags wide>
|
||||||
|
<vn-one></vn-one>
|
||||||
|
<vn-one ng-if="::buy.subName">
|
||||||
|
<h3 title="{{::buy.subName}}">{{::buy.subName}}</h3>
|
||||||
|
</vn-one>
|
||||||
<vn-fetched-tags
|
<vn-fetched-tags
|
||||||
max-length="6"
|
max-length="6"
|
||||||
item="::buy">
|
item="::buy"
|
||||||
|
tabindex="-1">
|
||||||
</vn-fetched-tags>
|
</vn-fetched-tags>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td number>{{::buy.quantity | dashIfEmpty}}</vn-td>
|
<vn-td number>{{::buy.quantity | dashIfEmpty}}</vn-td>
|
||||||
|
|
|
@ -17,6 +17,9 @@
|
||||||
{"state": "supplier.card.consumption", "icon": "show_chart"}
|
{"state": "supplier.card.consumption", "icon": "show_chart"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"keybindings": [
|
||||||
|
{"key": "p", "state": "supplier.index"}
|
||||||
|
],
|
||||||
"routes": [
|
"routes": [
|
||||||
{
|
{
|
||||||
"url": "/supplier",
|
"url": "/supplier",
|
||||||
|
|
|
@ -31,6 +31,13 @@
|
||||||
label="Alias"
|
label="Alias"
|
||||||
value="{{::$ctrl.summary.nickname}}">
|
value="{{::$ctrl.summary.nickname}}">
|
||||||
</vn-label-value>
|
</vn-label-value>
|
||||||
|
<vn-label-value label="Responsible">
|
||||||
|
<span
|
||||||
|
ng-click="workerDescriptor.show($event, $ctrl.summary.workerFk)"
|
||||||
|
class="link">
|
||||||
|
{{$ctrl.summary.worker.user.nickname}}
|
||||||
|
</span>
|
||||||
|
</vn-label-value>
|
||||||
<vn-label-value no-ellipsize
|
<vn-label-value no-ellipsize
|
||||||
label="Notes"
|
label="Notes"
|
||||||
value="{{::$ctrl.summary.note}}">
|
value="{{::$ctrl.summary.note}}">
|
||||||
|
|
|
@ -7,3 +7,4 @@ Sage tax type: Tipo de impuesto Sage
|
||||||
Sage transaction type: Tipo de transacción Sage
|
Sage transaction type: Tipo de transacción Sage
|
||||||
Sage withholding: Retencion Sage
|
Sage withholding: Retencion Sage
|
||||||
Go to the supplier: Ir al proveedor
|
Go to the supplier: Ir al proveedor
|
||||||
|
Responsible: Responsable
|
|
@ -197,6 +197,7 @@ module.exports = Self => {
|
||||||
t.id,
|
t.id,
|
||||||
t.shipped,
|
t.shipped,
|
||||||
CAST(DATE(t.shipped) AS CHAR) AS shippedDate,
|
CAST(DATE(t.shipped) AS CHAR) AS shippedDate,
|
||||||
|
HOUR(t.shipped) AS shippedHour,
|
||||||
t.nickname,
|
t.nickname,
|
||||||
t.refFk,
|
t.refFk,
|
||||||
t.routeFk,
|
t.routeFk,
|
||||||
|
|
|
@ -101,7 +101,7 @@ module.exports = Self => {
|
||||||
if (!shipped && landed) {
|
if (!shipped && landed) {
|
||||||
const shippedResult = await models.Agency.getShipped(landed,
|
const shippedResult = await models.Agency.getShipped(landed,
|
||||||
address.id, agencyModeId, warehouseId);
|
address.id, agencyModeId, warehouseId);
|
||||||
shipped = shippedResult && shippedResult.shipped;
|
shipped = (shippedResult && shippedResult.shipped) || landed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shipped && !landed) {
|
if (shipped && !landed) {
|
||||||
|
|
|
@ -28,7 +28,7 @@ describe('ticket new()', () => {
|
||||||
params.shipped,
|
params.shipped,
|
||||||
params.landed,
|
params.landed,
|
||||||
params.warehouseId,
|
params.warehouseId,
|
||||||
params.companyFk,
|
params.companyId,
|
||||||
params.addressId
|
params.addressId
|
||||||
).catch(e => {
|
).catch(e => {
|
||||||
error = e;
|
error = e;
|
||||||
|
@ -53,7 +53,7 @@ describe('ticket new()', () => {
|
||||||
params.shipped,
|
params.shipped,
|
||||||
params.landed,
|
params.landed,
|
||||||
params.warehouseId,
|
params.warehouseId,
|
||||||
params.companyFk,
|
params.companyId,
|
||||||
params.addressId
|
params.addressId
|
||||||
).catch(response => {
|
).catch(response => {
|
||||||
expect(response.message).toEqual(`This address doesn't exist`);
|
expect(response.message).toEqual(`This address doesn't exist`);
|
||||||
|
@ -79,7 +79,7 @@ describe('ticket new()', () => {
|
||||||
params.shipped,
|
params.shipped,
|
||||||
params.landed,
|
params.landed,
|
||||||
params.warehouseId,
|
params.warehouseId,
|
||||||
params.companyFk,
|
params.companyId,
|
||||||
params.addressId,
|
params.addressId,
|
||||||
params.agencyModeId);
|
params.agencyModeId);
|
||||||
|
|
||||||
|
@ -87,4 +87,27 @@ describe('ticket new()', () => {
|
||||||
|
|
||||||
expect(ticket.id).toBeGreaterThan(newestTicketIdInFixtures);
|
expect(ticket.id).toBeGreaterThan(newestTicketIdInFixtures);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should return the set a shipped when the agency is not especified', async() => {
|
||||||
|
let params = {
|
||||||
|
clientId: 104,
|
||||||
|
landed: today,
|
||||||
|
shipped: null,
|
||||||
|
warehouseId: 2,
|
||||||
|
companyId: 442,
|
||||||
|
addressId: 4,
|
||||||
|
agencyModeId: null
|
||||||
|
};
|
||||||
|
|
||||||
|
ticket = await app.models.Ticket.new(ctx,
|
||||||
|
params.clientId,
|
||||||
|
params.shipped,
|
||||||
|
params.landed,
|
||||||
|
params.warehouseId,
|
||||||
|
params.companyId,
|
||||||
|
params.addressId,
|
||||||
|
params.agencyModeId);
|
||||||
|
|
||||||
|
expect(ticket.shipped).toEqual(jasmine.any(Date));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
const LoopBackContext = require('loopback-context');
|
const LoopBackContext = require('loopback-context');
|
||||||
|
const dateUtil = require('vn-loopback/util/date');
|
||||||
|
|
||||||
module.exports = function(Self) {
|
module.exports = function(Self) {
|
||||||
require('../methods/ticket-request/filter')(Self);
|
require('../methods/ticket-request/filter')(Self);
|
||||||
|
@ -26,12 +27,7 @@ module.exports = function(Self) {
|
||||||
if (instance.price)
|
if (instance.price)
|
||||||
messageText = 'New ticket request has been created with price';
|
messageText = 'New ticket request has been created with price';
|
||||||
|
|
||||||
const shipped = new Intl.DateTimeFormat('es', {
|
const shipped = dateUtil.toString(ticket.shipped);
|
||||||
year: 'numeric',
|
|
||||||
month: 'numeric',
|
|
||||||
day: 'numeric'
|
|
||||||
}).format(ticket.shipped);
|
|
||||||
|
|
||||||
const message = $t(messageText, {
|
const message = $t(messageText, {
|
||||||
description: instance.description,
|
description: instance.description,
|
||||||
shipped: shipped,
|
shipped: shipped,
|
||||||
|
|
|
@ -18,11 +18,15 @@
|
||||||
<vn-tbody>
|
<vn-tbody>
|
||||||
<vn-tr ng-repeat="sale in $ctrl.ticket.sale.items track by sale.id">
|
<vn-tr ng-repeat="sale in $ctrl.ticket.sale.items track by sale.id">
|
||||||
<vn-td number>{{("000000"+sale.itemFk).slice(-6)}}</vn-td>
|
<vn-td number>{{("000000"+sale.itemFk).slice(-6)}}</vn-td>
|
||||||
<vn-td expand>
|
<vn-td vn-fetched-tags wide>
|
||||||
|
<vn-one title="{{::sale.item.name}}">{{::sale.item.name}}</vn-one>
|
||||||
|
<vn-one ng-if="::sale.item.subName">
|
||||||
|
<h3 title="{{::sale.item.subName}}">{{::sale.item.subName}}</h3>
|
||||||
|
</vn-one>
|
||||||
<vn-fetched-tags
|
<vn-fetched-tags
|
||||||
max-length="6"
|
max-length="6"
|
||||||
item="::sale.item"
|
item="::sale.item"
|
||||||
name="::sale.concept">
|
tabindex="-1">
|
||||||
</vn-fetched-tags>
|
</vn-fetched-tags>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td number>{{::sale.quantity}}</vn-td>
|
<vn-td number>{{::sale.quantity}}</vn-td>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue