7565-testToMaster #2567

Merged
alexm merged 250 commits from 7565-testToMaster into master 2024-06-11 06:31:18 +00:00
108 changed files with 1611 additions and 683 deletions

View File

@ -1,3 +1,82 @@
# Version 24.24 - 2024-06-11
### Added 🆕
- 6281 feat:buyFk in itemShekving by:sergiodt
- 6281 feat:buyFk in itemShelving by:sergiodt
- feat: #6408 tests by:jgallego
- feat: packaging refs #4021 (origin/4021_packaging) by:sergiodt
- feat: refs #6021 add new field by:pablone
- feat: refs #6281 change fixtures by:robert
- feat: refs # 6408 test ok (origin/6408-rocketChat) by:jgallego
- feat: refs #6477 productionConfig add column by:robert
- feat: refs #6600 add column (origin/6600-createItemPhotoComment) by:jorgep
- feat: refs #6600 Add photoMotivation column to item table and create itemPhotoComment table by:jorgep
- feat: refs #6889 add back tests by:jorgep
- feat: refs #6889 fixtures & models by:jorgep
- feat : refs #6889 wip: check if is productionReviewer or owner by:jorgep
- feat: refs #6942 set false isBooed & ledger by:jorgep
- feat: refs #6942 toUnbook by:jorgep
- feat: refs #6942 xdiario fixtures by:jorgep
- feat: refs #7398 Change by:guillermo
- feat: refs #7438 Added volume to item_valuateInventory by:guillermo
- feat: refs #7438 Requested changes and little changes by:guillermo
- refs #6281 feat:buyFk in itemShelving by:sergiodt
### Changed 📦
- refactor: refs #6600 add space by:jorgep
- refactor: refs #6889 improve file loading logic by:jorgep
- refactor: refs #6889 sale tests e2e by:jorgep
- refactor: refs #6889 script sql (origin/6889-dropAddSaleByCode) by:jorgep
- refactor: refs #6889 use addSale by:jorgep
- refactor: refs #6942 toUnbook & drop buyer acls by:jorgep
- refactor: refs #7398 Refactor and change ekt_scan (origin/7398-ektScan) by:guillermo
- refactor: refs #7486 Optimized procs by:guillermo
### Fixed 🛠️
- feat: refs #6281 change fixtures by:robert
- feat: refs #6889 fixtures & models by:jorgep
- feat: refs #6942 xdiario fixtures by:jorgep
- fix: checking process.env.NODE_ENV by:alexm
- fix: en translations by:alexm
- fix: move to boot (origin/7421-fix_checking_NODE_ENV, 7421-fix_checking_NODE_ENV) by:alexm
- fix: refs #6095 filter by refFk null by:pablone
- fix: refs #6600 rollback by:jorgep
- fix: refs #6889 allocate 'productionReviewer' role to revision dep. workers & check if is owner or reviewer by:jorgep
- fix: refs #6889 check if has collection or sectorCollection by:jorgep
- fix: refs #6889 e2e tests by:jorgep
- fix: refs #6889 fix back tests by:jorgep
- fix: refs #6889 modify fixtures by:jorgep
- fix: refs #6889 rollback by:jorgep
- fix: refs #6942 acls & back by:jorgep
- fix: refs #6942 add deleteById acl by:jorgep
- fix: refs #6942 add test & change column name by:jorgep
- fix: refs #6942 create invoiceIn acl by:jorgep
- fix: refs #6942 delete by:jorgep
- fix: refs #6942 drop quotes by:jorgep
- fix : refs #6942 remove grafana update priv by:jorgep
- fix: refs #6942 revoke update isBooked by:jorgep
- fix: refs #6942 toBook/toUnbook by:jorgep
- fix: refs #7442 Fix kubernetes deploy by:Juan Ferrer Toribio
- fix(salix): refs #7272 #7272 Add aclService in routes.js by:Javier Segarra
- fix(salix): refs #7272 #7272 Back validateToken endpoint by:Javier Segarra
- fix(salix): refs #7272 #7272 Bug when acl not loaded by:Javier Segarra
- fix(salix): refs #7272 #7272 Call validateToken by:Javier Segarra
- fix(salix): refs #7272 #7272 Errors when Token not exists by:Javier Segarra
- fix(salix): refs #7272 #7272 Front retry calls by:Javier Segarra
- fix(salix): refs #7272 #7272 i18n Error by:Javier Segarra
- fix(salix): refs #7272 #7272 Remove aclService from auth.js by:Javier Segarra
- fix: simplify by:alexm
- fix traduction & e2e by:carlossa
- refs #6820 fix back by:carlossa
- refs #6820 fix pr by:carlossa
- refs #6832 fix: ToItem (origin/6832_refactorBackToItem) by:Sergio De la torre
- refs #7292 fix tback by:carlossa
- refs #7296 fix pr errors, trad by:carlossa
- test(salix): refs #7272 #7272 fix renew-token.spec by:Javier Segarra
# Changelog # Changelog

4
Jenkinsfile vendored
View File

@ -24,6 +24,7 @@ node {
FROM_GIT = env.JOB_NAME.startsWith('gitea/') FROM_GIT = env.JOB_NAME.startsWith('gitea/')
RUN_TESTS = !PROTECTED_BRANCH && FROM_GIT RUN_TESTS = !PROTECTED_BRANCH && FROM_GIT
RUN_BUILD = PROTECTED_BRANCH && FROM_GIT RUN_BUILD = PROTECTED_BRANCH && FROM_GIT
// https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#using-environment-variables // https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#using-environment-variables
echo "NODE_NAME: ${env.NODE_NAME}" echo "NODE_NAME: ${env.NODE_NAME}"
echo "WORKSPACE: ${env.WORKSPACE}" echo "WORKSPACE: ${env.WORKSPACE}"
@ -206,9 +207,6 @@ pipeline {
when { when {
expression { FROM_GIT } expression { FROM_GIT }
} }
environment {
DOCKER_HOST = "${env.SWARM_HOST}"
}
steps { steps {
script { script {
def packageJson = readJSON file: 'package.json' def packageJson = readJSON file: 'package.json'

View File

@ -11,11 +11,16 @@ Required applications.
* Node.js * Node.js
* Docker * Docker
* Git * Git
* MYT
You will need to install globally the following items. You will need to install globally the following items.
``` ```
$ sudo npm install -g jest gulp-cli $ sudo npm install -g jest gulp-cli
``` ```
After installing MYT you will need the following item.
```
$ apt install libkrb5-dev libssl-dev
```
## Installing dependencies and launching ## Installing dependencies and launching

View File

@ -1,3 +1,5 @@
const isProduction = require('vn-loopback/server/boot/isProduction');
module.exports = Self => { module.exports = Self => {
Self.remoteMethodCtx('sendCheckingPresence', { Self.remoteMethodCtx('sendCheckingPresence', {
description: 'Creates a message in the chat model checking the user status', description: 'Creates a message in the chat model checking the user status',
@ -37,7 +39,7 @@ module.exports = Self => {
if (!recipient) if (!recipient)
throw new Error(`Could not send message "${message}" to worker id ${recipientId} from user ${userId}`); throw new Error(`Could not send message "${message}" to worker id ${recipientId} from user ${userId}`);
if (process.env.NODE_ENV == 'test') if (!isProduction())
message = `[Test:Environment to user ${userId}] ` + message; message = `[Test:Environment to user ${userId}] ` + message;
const chat = await models.Chat.create({ const chat = await models.Chat.create({

View File

@ -1,4 +1,6 @@
const axios = require('axios'); const axios = require('axios');
const isProduction = require('vn-loopback/server/boot/isProduction');
module.exports = Self => { module.exports = Self => {
Self.remoteMethodCtx('sendQueued', { Self.remoteMethodCtx('sendQueued', {
description: 'Send a RocketChat message', description: 'Send a RocketChat message',
@ -94,7 +96,7 @@ module.exports = Self => {
* @return {Promise} - The request promise * @return {Promise} - The request promise
*/ */
Self.sendMessage = async function sendMessage(senderFk, recipient, message) { Self.sendMessage = async function sendMessage(senderFk, recipient, message) {
if (process.env.NODE_ENV !== 'production') { if (!isProduction(false)) {
return new Promise(resolve => { return new Promise(resolve => {
return resolve({ return resolve({
statusCode: 200, statusCode: 200,
@ -149,7 +151,7 @@ module.exports = Self => {
* @return {Promise} - The request promise * @return {Promise} - The request promise
*/ */
Self.getUserStatus = async function getUserStatus(username) { Self.getUserStatus = async function getUserStatus(username) {
if (process.env.NODE_ENV !== 'production') { if (!isProduction(false)) {
return new Promise(resolve => { return new Promise(resolve => {
return resolve({ return resolve({
data: { data: {

View File

@ -1,6 +1,7 @@
const UserError = require('vn-loopback/util/user-error'); const UserError = require('vn-loopback/util/user-error');
const fs = require('fs-extra'); const fs = require('fs-extra');
const path = require('path'); const path = require('path');
const isProduction = require('vn-loopback/server/boot/isProduction');
module.exports = Self => { module.exports = Self => {
Self.remoteMethod('deleteTrashFiles', { Self.remoteMethod('deleteTrashFiles', {
@ -22,7 +23,7 @@ module.exports = Self => {
if (typeof options == 'object') if (typeof options == 'object')
Object.assign(myOptions, options); Object.assign(myOptions, options);
if (process.env.NODE_ENV == 'test') if (!isProduction())
throw new UserError(`Action not allowed on the test environment`); throw new UserError(`Action not allowed on the test environment`);
const models = Self.app.models; const models = Self.app.models;

View File

@ -1,5 +1,6 @@
const UserError = require('vn-loopback/util/user-error'); const UserError = require('vn-loopback/util/user-error');
const axios = require('axios'); const axios = require('axios');
const isProduction = require('vn-loopback/server/boot/isProduction');
module.exports = Self => { module.exports = Self => {
Self.remoteMethodCtx('upload', { Self.remoteMethodCtx('upload', {
@ -119,7 +120,7 @@ module.exports = Self => {
] ]
}; };
if (process.env.NODE_ENV != 'production') if (!isProduction(false))
throw new UserError('Action not allowed on the test environment'); throw new UserError('Action not allowed on the test environment');
// delete old // delete old

View File

@ -1,6 +1,7 @@
const fs = require('fs-extra'); const fs = require('fs-extra');
const path = require('path'); const path = require('path');
const UserError = require('vn-loopback/util/user-error'); const UserError = require('vn-loopback/util/user-error');
const isProduction = require('vn-loopback/server/boot/isProduction');
module.exports = Self => { module.exports = Self => {
Self.remoteMethod('scrub', { Self.remoteMethod('scrub', {
@ -43,8 +44,7 @@ module.exports = Self => {
Self.scrub = async function(collection, remove, limit, dryRun, skipLock) { Self.scrub = async function(collection, remove, limit, dryRun, skipLock) {
const $ = Self.app.models; const $ = Self.app.models;
const env = process.env.NODE_ENV; dryRun = dryRun || !isProduction(false);
dryRun = dryRun || (env && env !== 'production');
const instance = await $.ImageCollection.findOne({ const instance = await $.ImageCollection.findOne({
fields: ['id'], fields: ['id'],

View File

@ -1,6 +1,7 @@
const UserError = require('vn-loopback/util/user-error'); const UserError = require('vn-loopback/util/user-error');
const fs = require('fs/promises'); const fs = require('fs/promises');
const path = require('path'); const path = require('path');
const isProduction = require('vn-loopback/server/boot/isProduction');
module.exports = Self => { module.exports = Self => {
Self.remoteMethodCtx('upload', { Self.remoteMethodCtx('upload', {
@ -41,7 +42,7 @@ module.exports = Self => {
if (!hasWriteRole) if (!hasWriteRole)
throw new UserError(`You don't have enough privileges`); throw new UserError(`You don't have enough privileges`);
if (process.env.NODE_ENV == 'test') if (!isProduction())
throw new UserError(`Action not allowed on the test environment`); throw new UserError(`Action not allowed on the test environment`);
// Upload file to temporary path // Upload file to temporary path

View File

@ -1,4 +1,5 @@
const {Email} = require('vn-print'); const {Email} = require('vn-print');
const isProduction = require('vn-loopback/server/boot/isProduction');
module.exports = Self => { module.exports = Self => {
Self.remoteMethod('send', { Self.remoteMethod('send', {
@ -70,7 +71,7 @@ module.exports = Self => {
const newParams = Object.assign({}, queueParams, sendParams); const newParams = Object.assign({}, queueParams, sendParams);
const email = new Email(queueName, newParams); const email = new Email(queueName, newParams);
if (process.env.NODE_ENV != 'test') if (isProduction())
await email.send(); await email.send();
await queue.updateAttribute('status', statusSent); await queue.updateAttribute('status', statusSent);

View File

@ -18,15 +18,10 @@ module.exports = Self => {
Self.renewToken = async function(ctx) { Self.renewToken = async function(ctx) {
const {accessToken: token} = ctx.req; const {accessToken: token} = ctx.req;
// Check if current token is valid const {courtesyTime} = await models.AccessTokenConfig.findOne({
fields: ['courtesyTime']
const {renewPeriod, courtesyTime} = await models.AccessTokenConfig.findOne({
fields: ['renewPeriod', 'courtesyTime']
}); });
const now = Date.now(); const isNotExceeded = await Self.validateToken(ctx);
const differenceMilliseconds = now - token.created;
const differenceSeconds = Math.floor(differenceMilliseconds / 1000);
const isNotExceeded = differenceSeconds < renewPeriod - courtesyTime;
if (isNotExceeded) if (isNotExceeded)
return token; return token;

View File

@ -0,0 +1,30 @@
const {models} = require('vn-loopback/server/server');
module.exports = Self => {
Self.remoteMethodCtx('validateToken', {
description: 'Validates the current logged user token',
accepts: [],
accessType: 'READ',
returns: {
type: 'Boolean',
root: true
},
http: {
path: `/validateToken`,
verb: 'GET'
}
});
Self.validateToken = async function(ctx) {
const {accessToken: token} = ctx.req;
// Check if current token is valid
const {renewPeriod, courtesyTime} = await models.AccessTokenConfig.findOne({
fields: ['renewPeriod', 'courtesyTime']
});
const now = Date.now();
const differenceMilliseconds = now - token.created;
const differenceSeconds = Math.floor(differenceMilliseconds / 1000);
const isNotExceeded = differenceSeconds < renewPeriod - courtesyTime;
return isNotExceeded;
};
};

View File

@ -186,5 +186,8 @@
}, },
"AgencyWorkCenter": { "AgencyWorkCenter": {
"dataSource": "vn" "dataSource": "vn"
},
"RouteConfig": {
"dataSource": "vn"
} }
} }

View File

@ -1,6 +1,16 @@
{ {
"name": "Collection", "name": "Collection",
"base": "VnModel", "base": "VnModel",
"properties": {
"id": {
"id": true,
"type": "number",
"required": true
},
"workerFk": {
"type": "number"
}
},
"options": { "options": {
"mysql": { "mysql": {
"table": "collection" "table": "collection"

View File

@ -0,0 +1,18 @@
{
"name": "RouteConfig",
"base": "VnModel",
"options": {
"mysql": {
"table": "routeConfig"
}
},
"properties": {
"id": {
"type": "number",
"description": "Identifier"
},
"kmMax": {
"type": "number"
}
}
}

View File

@ -15,6 +15,7 @@ module.exports = function(Self) {
require('../methods/vn-user/renew-token')(Self); require('../methods/vn-user/renew-token')(Self);
require('../methods/vn-user/share-token')(Self); require('../methods/vn-user/share-token')(Self);
require('../methods/vn-user/update-user')(Self); require('../methods/vn-user/update-user')(Self);
require('../methods/vn-user/validate-token')(Self);
Self.definition.settings.acls = Self.definition.settings.acls.filter(acl => acl.property !== 'create'); Self.definition.settings.acls = Self.definition.settings.acls.filter(acl => acl.property !== 'create');

View File

@ -113,6 +113,13 @@
"principalId": "$everyone", "principalId": "$everyone",
"permission": "ALLOW" "permission": "ALLOW"
}, },
{
"property": "validateToken",
"accessType": "EXECUTE",
"principalType": "ROLE",
"principalId": "$authenticated",
"permission": "ALLOW"
},
{ {
"property": "privileges", "property": "privileges",
"accessType": "*", "accessType": "*",

View File

@ -762,7 +762,12 @@ INSERT INTO `vn`.`ticket`(`id`, `priority`, `agencyModeFk`,`warehouseFk`,`routeF
(30, 1, 8, 1, 1, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE(), NULL, NULL), (30, 1, 8, 1, 1, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE(), NULL, NULL),
(31, 1, 8, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL + 2 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE(), NULL, NULL), (31, 1, 8, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL + 2 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE(), NULL, NULL),
(32, 1, 8, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL + 2 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE(), NULL, NULL), (32, 1, 8, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL + 2 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE(), NULL, NULL),
(33, 1, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1102, 'NY roofs', 122, NULL, 0, 3, 5, 1, util.VN_CURDATE(), NULL, NULL); (33, 1, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1102, 'NY roofs', 122, NULL, 0, 3, 5, 1, util.VN_CURDATE(), NULL, NULL),
(34, 1, 1, 1, 3, util.VN_CURDATE(), util.VN_CURDATE(), 1103, 'BEJAR', 123, NULL, 0, 1, 16, 0, util.VN_CURDATE(), NULL, NULL),
(35, 1, 1, 1, 3, util.VN_CURDATE(), util.VN_CURDATE(), 1102, 'Somewhere in Philippines', 123, NULL, 0, 1, 16, 0, util.VN_CURDATE(), NULL, NULL),
(36, 1, 1, 1, 3, util.VN_CURDATE(), util.VN_CURDATE(), 1102, 'Ant-Man Adventure', 123, NULL, 0, 1, 16, 0, util.VN_CURDATE(), NULL, NULL),
(37, 1, 1, 1, 3, util.VN_CURDATE(), util.VN_CURDATE(), 1110, 'Deadpool swords', 123, NULL, 0, 1, 16, 0, util.VN_CURDATE(), NULL, NULL);
INSERT INTO `vn`.`ticketObservation`(`id`, `ticketFk`, `observationTypeFk`, `description`) INSERT INTO `vn`.`ticketObservation`(`id`, `ticketFk`, `observationTypeFk`, `description`)
VALUES VALUES
(1, 11, 1, 'ready'), (1, 11, 1, 'ready'),
@ -808,7 +813,10 @@ INSERT INTO `vn`.`ticketTracking`(`ticketFk`, `stateFk`, `userFk`, `created`)
(21, 1, 19, DATE_ADD(util.VN_NOW(), INTERVAL +1 MONTH)), (21, 1, 19, DATE_ADD(util.VN_NOW(), INTERVAL +1 MONTH)),
(22, 1, 19, DATE_ADD(util.VN_NOW(), INTERVAL +1 MONTH)), (22, 1, 19, DATE_ADD(util.VN_NOW(), INTERVAL +1 MONTH)),
(23, 16, 21, util.VN_NOW()), (23, 16, 21, util.VN_NOW()),
(24, 16, 21, util.VN_NOW()); (24, 16, 21, util.VN_NOW()),
(34, 14, 49, util.VN_NOW()),
(35, 14, 18, util.VN_NOW()),
(36, 14, 18, util.VN_NOW());
INSERT INTO `vn`.`deliveryPoint` (`id`, `name`, `ubication`) INSERT INTO `vn`.`deliveryPoint` (`id`, `name`, `ubication`)
VALUES VALUES
@ -1068,7 +1076,10 @@ INSERT INTO `vn`.`sale`(`id`, `itemFk`, `ticketFk`, `concept`, `quantity`, `pric
(37, 4, 31, 'Melee weapon heavy shield 100cm', 20, 1.72, 0, 0, 0, util.VN_CURDATE()), (37, 4, 31, 'Melee weapon heavy shield 100cm', 20, 1.72, 0, 0, 0, util.VN_CURDATE()),
(36, 4, 30, 'Melee weapon heavy shield 100cm', 20, 1.72, 0, 0, 0, util.VN_CURDATE()), (36, 4, 30, 'Melee weapon heavy shield 100cm', 20, 1.72, 0, 0, 0, util.VN_CURDATE()),
(38, 2, 32, 'Melee weapon combat fist 15cm', 30, 7.07, 0, 0, 0, DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH)), (38, 2, 32, 'Melee weapon combat fist 15cm', 30, 7.07, 0, 0, 0, DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH)),
(39, 1, 32, 'Ranged weapon longbow 200cm', 2, 103.49, 0, 0, 0, util.VN_CURDATE()); (39, 1, 32, 'Ranged weapon longbow 200cm', 2, 103.49, 0, 0, 0, util.VN_CURDATE()),
(40, 2, 34, 'Melee weapon combat fist 15cm', 10.00, 3.91, 0, 0, 0, util.VN_CURDATE()),
(41, 2, 35, 'Melee weapon combat fist 15cm', 8.00, 3.01, 0, 0, 0, util.VN_CURDATE()),
(42, 2, 36, 'Melee weapon combat fist 15cm', 6.00, 2.50, 0, 0, 0, util.VN_CURDATE());
INSERT INTO `vn`.`saleComponent`(`saleFk`, `componentFk`, `value`) INSERT INTO `vn`.`saleComponent`(`saleFk`, `componentFk`, `value`)
VALUES VALUES
@ -1205,11 +1216,11 @@ INSERT INTO `vn`.`saleComponent`(`saleFk`, `componentFk`, `value`)
(32, 36, -92.324), (32, 36, -92.324),
(32, 39, 0.994); (32, 39, 0.994);
INSERT INTO `vn`.`itemShelving` (`itemFk`, `shelvingFk`, `visible`, `grouping`, `packing`, `userFk`) INSERT INTO `vn`.`itemShelving` (`itemFk`, `shelvingFk`, `visible`, `grouping`, `packing`,`buyFk`, `userFk`)
VALUES VALUES
(2, 'GVC', 1, 1, 1, 1106), (2, 'GVC', 1, 1, 1, 2,1106),
(4, 'HEJ', 1, 1, 1, 1106), (4, 'HEJ', 1, 1, 1, NULL,1106),
(1, 'UXN', 2, 12, 12, 1106); (1, 'UXN', 2, 12, 12, NULL,1106);
INSERT INTO `vn`.`itemShelvingSale` (`itemShelvingFk`, `saleFk`, `quantity`, `created`, `userFk`) INSERT INTO `vn`.`itemShelvingSale` (`itemShelvingFk`, `saleFk`, `quantity`, `created`, `userFk`)
VALUES VALUES
@ -1247,14 +1258,20 @@ INSERT INTO `vn`.`operator` (`workerFk`, `numberOfWagons`, `trainFk`, `itemPacki
INSERT INTO `vn`.`collection`(`id`, `workerFk`, `stateFk`, `created`, `trainFk`) INSERT INTO `vn`.`collection`(`id`, `workerFk`, `stateFk`, `created`, `trainFk`)
VALUES VALUES
(1, 1106, 5, DATE_ADD(util.VN_CURDATE(),INTERVAL +1 DAY), 1), (1, 1106, 5, DATE_ADD(util.VN_CURDATE(),INTERVAL +1 DAY), 1),
(2, 1106, 14, util.VN_CURDATE(), 1); (2, 1106, 14, util.VN_CURDATE(), 1),
(4, 49, 5, util.VN_CURDATE(), 1),
(5, 18, 5, util.VN_CURDATE(), 1),
(6, 18, 5, util.VN_CURDATE(), 1);
INSERT INTO `vn`.`ticketCollection`(`ticketFk`, `collectionFk`, `level`) INSERT INTO `vn`.`ticketCollection`(`ticketFk`, `collectionFk`, `level`)
VALUES VALUES
(1, 1, 1), (1, 1, 1),
(2, 1, NULL), (2, 1, NULL),
(3, 2, NULL), (3, 2, NULL),
(23, 1, NULL); (23, 1, NULL),
(34, 4, 1),
(35, 5, 1),
(8, 6, 1);
INSERT INTO `vn`.`genus`(`id`, `name`) INSERT INTO `vn`.`genus`(`id`, `name`)
VALUES VALUES
@ -3705,7 +3722,8 @@ INSERT IGNORE INTO vn.saleGroup
SET id = 4, SET id = 4,
userFk = 1, userFk = 1,
parkingFk = 9, parkingFk = 9,
sectorFk = 9992; sectorFk = 9992,
ticketFk = 36;
INSERT IGNORE INTO vn.sectorCollectionSaleGroup INSERT IGNORE INTO vn.sectorCollectionSaleGroup
SET id = 9999, SET id = 9999,
@ -3807,3 +3825,27 @@ INSERT INTO `vn`.`ledgerCompany` SET
INSERT INTO `vn`.`ledgerConfig` SET INSERT INTO `vn`.`ledgerConfig` SET
maxTolerance = 0.01; maxTolerance = 0.01;
INSERT INTO vn.sectorCollection
SET id = 2,
userFk = 18,
sectorFk = 1;
INSERT INTO vn.sectorCollectionSaleGroup
SET id = 8,
sectorCollectionFk = 2,
saleGroupFk = 4;
INSERT INTO vn.saleGroup (userFk, parkingFk, sectorFk, ticketFk)
VALUES
(1, 1, 1, 37);
INSERT INTO vn.sectorCollection
SET id = 3,
userFk = 18,
sectorFk = 1;
INSERT INTO vn.sectorCollectionSaleGroup
SET id = 9,
sectorCollectionFk = 3,
saleGroupFk = 6;

View File

@ -23,22 +23,19 @@ BEGIN
DECLARE vXtraLongAgj INT; DECLARE vXtraLongAgj INT;
DECLARE vDefaultKlo INT; DECLARE vDefaultKlo INT;
SELECT SELECT usefulAuctionLeftSegmentLength,
ec.usefulAuctionLeftSegmentLength, standardBarcodeLength,
ec.standardBarcodeLength, floridayBarcodeLength,
ec.floridayBarcodeLength, floramondoBarcodeLength,
ec.floramondoBarcodeLength, defaultKlo
ec.defaultKlo INTO vUsefulAuctionLeftSegmentLength,
INTO
vUsefulAuctionLeftSegmentLength,
vStandardBarcodeLength, vStandardBarcodeLength,
vFloridayBarcodeLength, vFloridayBarcodeLength,
vFloramondoBarcodeLength, vFloramondoBarcodeLength,
vDefaultKlo vDefaultKlo
FROM edi.ektConfig ec; FROM ektConfig;
DROP TEMPORARY TABLE IF EXISTS tmp.ekt; CREATE OR REPLACE TEMPORARY TABLE tmp.ekt
CREATE TEMPORARY TABLE tmp.ekt
ENGINE = MEMORY ENGINE = MEMORY
SELECT id ektFk FROM ekt LIMIT 0; SELECT id ektFk FROM ekt LIMIT 0;
@ -46,19 +43,19 @@ BEGIN
WHEN LENGTH(vBarcode) <= vFloridayBarcodeLength THEN WHEN LENGTH(vBarcode) <= vFloridayBarcodeLength THEN
INSERT INTO tmp.ekt INSERT INTO tmp.ekt
SELECT id SELECT id
FROM edi.ektRecent e FROM ektRecent e
WHERE e.cps = vBarcode WHERE e.cps = vBarcode
OR e.batchNumber = vBarcode; OR e.batchNumber = vBarcode;
WHEN LENGTH(vBarcode) = vFloramondoBarcodeLength THEN WHEN LENGTH(vBarcode) = vFloramondoBarcodeLength THEN
INSERT INTO tmp.ekt INSERT INTO tmp.ekt
SELECT e.id SELECT e.id
FROM edi.ektRecent e FROM ektRecent e
WHERE e.pro = MID(vBarcode,2,6) WHERE e.pro = MID(vBarcode,2,6)
AND CAST(e.ptd AS SIGNED) = MID(vBarcode,8,5); AND CAST(e.ptd AS SIGNED) = MID(vBarcode, 8, 5);
ELSE ELSE
SET vBarcode = LPAD(vBarcode,vStandardBarcodeLength,'0'); SET vBarcode = LPAD(vBarcode, vStandardBarcodeLength, '0');
SET vAuction = MID(vBarcode, 1, 3); SET vAuction = MID(vBarcode, 1, 3);
SET vKlo = MID(vBarcode, 4, 2); SET vKlo = MID(vBarcode, 4, 2);
SET vFec = MAKEDATE(YEAR(util.VN_CURDATE()), MID(vBarcode, 6, 3)); SET vFec = MAKEDATE(YEAR(util.VN_CURDATE()), MID(vBarcode, 6, 3));
@ -74,13 +71,15 @@ BEGIN
SELECT id SELECT id
FROM ekt FROM ekt
WHERE fec >= vFec - INTERVAL 1 DAY WHERE fec >= vFec - INTERVAL 1 DAY
AND (( AND (
vKlo = vDefaultKlo (vKlo = vDefaultKlo
AND (klo = vKlo OR klo IS NULL OR klo = 0) AND (klo = vKlo OR klo IS NULL OR klo = 0)
AND agj IN (vShortAgj, vLongAgj, vXtraLongAgj)) AND agj IN (vShortAgj, vLongAgj, vXtraLongAgj)
OR (klo = vKlo ) OR (
klo = vKlo
AND auction = vAuction AND auction = vAuction
AND agj = vShortAgj) AND agj = vShortAgj
)
) )
ORDER BY agj DESC, fec DESC ORDER BY agj DESC, fec DESC
LIMIT 1; LIMIT 1;
@ -91,9 +90,11 @@ BEGIN
IF NOT vIsFound THEN IF NOT vIsFound THEN
INSERT INTO tmp.ekt INSERT INTO tmp.ekt
SELECT id SELECT id
FROM edi.ektRecent e FROM ektRecent e
WHERE e.batchNumber WHERE e.batchNumber = LEFT(
= LEFT(vBarcode,vUsefulAuctionLeftSegmentLength) vBarcode,
vUsefulAuctionLeftSegmentLength
)
AND e.batchNumber > 0; AND e.batchNumber > 0;
SELECT COUNT(*) FROM tmp.ekt INTO vIsFound; SELECT COUNT(*) FROM tmp.ekt INTO vIsFound;
@ -103,7 +104,7 @@ BEGIN
IF NOT vIsFound THEN IF NOT vIsFound THEN
INSERT INTO tmp.ekt INSERT INTO tmp.ekt
SELECT id SELECT id
FROM edi.ektRecent e FROM ektRecent e
WHERE e.putOrderFk = vBarcode; WHERE e.putOrderFk = vBarcode;
SELECT COUNT(*) FROM tmp.ekt INTO vIsFound; SELECT COUNT(*) FROM tmp.ekt INTO vIsFound;
@ -113,13 +114,23 @@ BEGIN
IF NOT vIsFound THEN IF NOT vIsFound THEN
INSERT INTO tmp.ekt INSERT INTO tmp.ekt
SELECT id SELECT id
FROM edi.ektRecent e FROM ektRecent e
WHERE e.deliveryNumber WHERE e.deliveryNumber = MID(vBarcode, 4, 13)
= MID(vBarcode, 4, 13)
AND e.deliveryNumber > 0; AND e.deliveryNumber > 0;
SELECT COUNT(*) FROM tmp.ekt INTO vIsFound; SELECT COUNT(*) FROM tmp.ekt INTO vIsFound;
END IF; END IF;
-- Solo campo agj
IF NOT vIsFound THEN
INSERT INTO tmp.ekt
SELECT id
FROM ektRecent
WHERE agj = vShortAgj;
SELECT COUNT(*) FROM tmp.ekt INTO vIsFound;
END IF;
END CASE; END CASE;
IF vIsFound THEN IF vIsFound THEN

View File

@ -40,19 +40,28 @@ proc:BEGIN
postalCode, postalCode,
`type`, `type`,
image, image,
description description,
addressFk
) )
SELECT i.name, SELECT CONCAT(i.name, ' by ',a.nickname),
i.`size`, r.price + apc.deliveryCost,
i.id, r.itemFk,
vLanded, vLanded,
vPostalCode, vPostalCode,
it.name, it.name,
CONCAT('https://cdn.verdnatura.es/image/catalog/1600x900/', i.image), CONCAT('https://cdn.verdnatura.es/image/catalog/1600x900/', i.image),
i.description i.description,
apc.addressFk
FROM vn.item i FROM vn.item i
JOIN (SELECT itemFk, SUM(quantity * cost) price
FROM recipe
GROUP BY itemFk) r ON r.itemFk = i.id
JOIN vn.itemType it ON it.id = i.typeFk JOIN vn.itemType it ON it.id = i.typeFk
WHERE it.code IN ('FNR','FNP'); JOIN addressPostCode apc
ON apc.dayOfWeek = dayOfWeek(vLanded)
AND NOW() < vLanded - INTERVAL apc.hoursInAdvance HOUR
AND apc.postCode = vPostalCode
JOIN vn.address a ON a.id = apc.addressFk;
SELECT * SELECT *
FROM catalogue FROM catalogue

View File

@ -13,8 +13,17 @@ BEGIN
/** /**
* Set actions for contact request * Set actions for contact request
* *
* @param vPostalCode Delivery address postal code * @param vName Name
* @param vPhone Phone number
* @param vEmail e-mail
* @param vMessage text of the message
*/ */
CALL vn.mail_insert(
'floranet@verdnatura.es',
vEmail,
'Contact request',
CONCAT('Phone: ',vPhone, ' Message: ', vMessage)
);
END$$ END$$
DELIMITER ; DELIMITER ;

View File

@ -21,7 +21,7 @@ BEGIN
apc.dayOfWeek - vCurrentDayOfWeek, apc.dayOfWeek - vCurrentDayOfWeek,
7 - apc.dayOfWeek 7 - apc.dayOfWeek
) DAY nextDay, ) DAY nextDay,
NOW() + INTERVAL apc.hoursInAdvance - 12 HOUR minDeliveryTime NOW() + INTERVAL apc.hoursInAdvance HOUR minDeliveryTime
FROM addressPostCode apc FROM addressPostCode apc
WHERE apc.postCode = vPostalCode WHERE apc.postCode = vPostalCode
HAVING nextDay > minDeliveryTime) sub; HAVING nextDay > minDeliveryTime) sub;

View File

@ -1,25 +1,167 @@
DROP PROCEDURE IF EXISTS floranet.order_confirm;
DELIMITER $$ DELIMITER $$
$$ $$
CREATE DEFINER=`root`@`localhost`PROCEDURE floranet.order_confirm(vCatalogueFk INT) CREATE OR REPLACE DEFINER=`root`@`localhost`PROCEDURE floranet.order_confirm(vCatalogueFk INT)
READS SQL DATA READS SQL DATA
BEGIN proc:BEGIN
/** Update order.isPaid field. /** Update order.isPaid field, and makes the ticket
* *
* @param vCatalogueFk floranet.catalogue.id * @param vCatalogueFk floranet.catalogue.id
* *
* @returns floranet.order.isPaid * @returns floranet.order.isPaid
*/ */
DECLARE vNewTicketFk INT;
DECLARE vCustomerEmail VARCHAR(255);
DECLARE vFloranetEmail VARCHAR(255);
DECLARE vSubjectEmail VARCHAR(100);
DECLARE vBodyEmail TEXT;
DECLARE vZoneFk INT;
DECLARE exit handler FOR SQLEXCEPTION
BEGIN
ROLLBACK;
GET DIAGNOSTICS CONDITION 2 @errno = MYSQL_ERRNO, @text = MESSAGE_TEXT;
SELECT CONCAT('ERROR ', IFNULL(@errno,0), ': ', ifnull(@text,'texto')) AS `SQLEXCEPTION`;
CALL vn.mail_insert(
'floranet@verdnatura.es,pako@verdnatura.es',
'noreply@verdnatura.es',
'Floranet.order_confirm failure',
CONCAT('CatalogueFk: ', vCatalogueFk, '\n','ERROR ', IFNULL(@errno, 0), ': ', ifnull(@text, 'texto'))
);
END;
IF (SELECT isPaid FROM `order` WHERE catalogueFk = vCatalogueFk) THEN
SELECT CONCAT('CatalogueFk: ', vCatalogueFk, ' Esta orden ya está confirmada') AS `ERROR`;
LEAVE proc;
END IF;
START TRANSACTION;
UPDATE `order` UPDATE `order`
SET isPaid = TRUE, SET isPaid = TRUE,
payed = NOW() payed = NOW()
WHERE catalogueFk = vCatalogueFk; WHERE catalogueFk = vCatalogueFk;
SELECT isPaid SELECT zoneFk
INTO vZoneFk
FROM (
SELECT zoneFk, COUNT(*) totalCount
FROM vn.ticket t
JOIN catalogue c ON c.id = vCatalogueFk
WHERE t.shipped > util.VN_CURDATE() - INTERVAL 1 YEAR
AND t.addressFk = c.addressFk
GROUP BY zoneFk
ORDER BY totalCount DESC
LIMIT 10000000000000000000
) sub
LIMIT 1;
INSERT INTO vn.ticket (
clientFk,
shipped,
addressFk,
agencyModeFk,
nickname,
warehouseFk,
routeFk,
companyFk,
landed,
zoneFk
)
SELECT a.clientFk,
c.dated - INTERVAL 1 DAY,
c.addressFk,
a.agencyModeFk,
a.nickname,
ag.warehouseFk,
NULL,
co.id,
c.dated,
vZoneFk
FROM vn.address a
JOIN vn.agencyMode am ON am.id = a.agencyModeFk
JOIN vn.agency ag ON ag.id = am.agencyFk
JOIN catalogue c ON c.addressFk = a.id
JOIN vn.company co ON co.code = 'VNL'
WHERE c.id = vCatalogueFk;
SET vNewTicketFk = LAST_INSERT_ID();
INSERT INTO vn.sale(
ticketFk,
itemFk,
concept,
price,
quantity)
SELECT
vNewTicketFk,
c.itemFk,
CONCAT('Entrega: ',c.name),
- c.price,
1
FROM catalogue c
JOIN addressPostCode apc
ON apc.addressFk = c.addressFk
AND apc.dayOfWeek = dayOfWeek(c.dated)
WHERE c.id = vCatalogueFk;
INSERT INTO vn.sale(
ticketFk,
itemFk,
concept,
price,
quantity)
SELECT
vNewTicketFk,
r.elementFk,
i.longName,
r.cost,
r.quantity
FROM catalogue c
JOIN recipe r ON r.itemFk = c.itemFk
JOIN vn.item i ON i.id = r.elementFk
WHERE c.id = vCatalogueFk;
SELECT cl.email,
cf.email,
CONCAT('Nuevo pedido FLORANET para entrega el ',c.dated),
CONCAT_WS('\n',
CONCAT('Producto: ', c.name),
CONCAT('Fecha de entrega: ',c.dated),
CONCAT('Destinatario: ', o.deliveryName),
CONCAT('Dirección: ', o.address),
CONCAT('CP: ', c.postalCode),
CONCAT('Foto: ', c.image),
CONCAT('Mensaje: ', IFNULL(o.message,"Ninguno.")),
CONCAT('Teléfono: ',IFNULL(o.deliveryPhone,"--")),
CONCAT('Observaciones: ', IFNULL(o.observations,"No hay."))
)
INTO vCustomerEmail,
vFloranetEmail,
vSubjectEmail,
vBodyEmail
FROM vn.client cl
JOIN vn.address a ON a.clientFk = cl.id
JOIN catalogue c ON c.addressFk = a.id
JOIN `order` o ON o.catalogueFk = c.id
JOIN config cf
WHERE c.id = vCatalogueFk;
CALL vn.mail_insert(
vCustomerEmail,
vFloranetEmail,
vSubjectEmail,
vBodyEmail);
SELECT isPaid, vNewTicketFk
FROM `order` FROM `order`
WHERE catalogueFk = vCatalogueFk; WHERE catalogueFk = vCatalogueFk;
COMMIT;
END$$ END$$
DELIMITER ; DELIMITER ;

View File

@ -7,7 +7,7 @@ BEGIN
* *
* @param vJsonData The order data in json format * @param vJsonData The order data in json format
*/ */
INSERT INTO `order` REPLACE `order`
SET catalogueFk = JSON_UNQUOTE(JSON_EXTRACT(vJsonData, '$.customer.customerData.products[0].id')), SET catalogueFk = JSON_UNQUOTE(JSON_EXTRACT(vJsonData, '$.customer.customerData.products[0].id')),
customerName = JSON_UNQUOTE(JSON_EXTRACT(vJsonData, '$.customer.customerData.customerName')), customerName = JSON_UNQUOTE(JSON_EXTRACT(vJsonData, '$.customer.customerData.customerName')),
email = JSON_UNQUOTE(JSON_EXTRACT(vJsonData, '$.customer.customerData.email')), email = JSON_UNQUOTE(JSON_EXTRACT(vJsonData, '$.customer.customerData.email')),
@ -15,7 +15,8 @@ BEGIN
message= JSON_UNQUOTE(JSON_EXTRACT(vJsonData, '$.customer.customerData.message')), message= JSON_UNQUOTE(JSON_EXTRACT(vJsonData, '$.customer.customerData.message')),
deliveryName = JSON_UNQUOTE(JSON_EXTRACT(vJsonData, '$.customer.customerData.deliveryName')), deliveryName = JSON_UNQUOTE(JSON_EXTRACT(vJsonData, '$.customer.customerData.deliveryName')),
address = JSON_UNQUOTE(JSON_EXTRACT(vJsonData, '$.customer.customerData.address')), address = JSON_UNQUOTE(JSON_EXTRACT(vJsonData, '$.customer.customerData.address')),
deliveryPhone = JSON_UNQUOTE(JSON_EXTRACT(vJsonData, '$.customer.customerData.deliveryPhone')); deliveryPhone = JSON_UNQUOTE(JSON_EXTRACT(vJsonData, '$.customer.customerData.deliveryPhone')),
observations = JSON_UNQUOTE(JSON_EXTRACT(vJsonData, '$.customer.customerData.observations'));
SELECT LAST_INSERT_ID() orderFk; SELECT LAST_INSERT_ID() orderFk;
END$$ END$$

View File

@ -15,6 +15,5 @@ BEGIN
JOIN vn.itemType it ON it.id = i.typeFk JOIN vn.itemType it ON it.id = i.typeFk
WHERE it.code IN ('FNR','FNP') WHERE it.code IN ('FNR','FNP')
LIMIT 3; LIMIT 3;
END$$ END$$
DELIMITER ; DELIMITER ;

View File

@ -17,13 +17,15 @@ BEGIN
SELECT SELECT
itemFk, itemFk,
packing, packing,
created created,
buyFk
FROM itemShelving FROM itemShelving
WHERE id = vItemShelvingFk WHERE id = vItemShelvingFk
) ish2 ) ish2
ON ish2.itemFk = ish.itemFk ON ish2.itemFk = ish.itemFk
AND ish2.packing = ish.packing AND ish2.packing = ish.packing
AND date(ish2.created) = date(ish.created) AND date(ish2.created) = date(ish.created)
AND ish2.buyFk = ish.buyFk
WHERE ish.shelvingFk = vShelvingFk COLLATE utf8_unicode_ci; WHERE ish.shelvingFk = vShelvingFk COLLATE utf8_unicode_ci;
IF vNewItemShelvingFk THEN IF vNewItemShelvingFk THEN

View File

@ -2,7 +2,6 @@ DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`itemShelving_add`(IN vShelvingFk VARCHAR(8), IN vBarcode VARCHAR(22), IN vQuantity INT, IN vPackagingFk VARCHAR(10), IN vGrouping INT, IN vPacking INT, IN vWarehouseFk INT) CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`itemShelving_add`(IN vShelvingFk VARCHAR(8), IN vBarcode VARCHAR(22), IN vQuantity INT, IN vPackagingFk VARCHAR(10), IN vGrouping INT, IN vPacking INT, IN vWarehouseFk INT)
BEGIN BEGIN
/** /**
* Añade registro o lo actualiza si ya existe. * Añade registro o lo actualiza si ya existe.
* *
@ -15,11 +14,23 @@ BEGIN
* @param vWarehouseFk indica el sector * @param vWarehouseFk indica el sector
* *
**/ **/
DECLARE vItemFk INT; DECLARE vItemFk INT;
DECLARE vBuyFk INT;
SELECT id INTO vBuyFk
FROM buy WHERE id = vBarcode;
SELECT barcodeToItem(vBarcode) INTO vItemFk; SELECT barcodeToItem(vBarcode) INTO vItemFk;
IF vBuyFk IS NULL THEN
CALL cache.last_buy_refresh(FALSE);
SELECT buy_id INTO vBuyFk
FROM cache.last_buy
WHERE item_id = vItemFk
AND warehouse_id = vWarehouseFk;
END IF;
IF vPacking IS NULL IF vPacking IS NULL
THEN THEN
SET vPacking = itemPacking(vBarcode, vWarehouseFk); SET vPacking = itemPacking(vBarcode, vWarehouseFk);
@ -29,31 +40,32 @@ BEGIN
IF (SELECT COUNT(*) FROM itemShelving IF (SELECT COUNT(*) FROM itemShelving
WHERE shelvingFk COLLATE utf8_unicode_ci = vShelvingFk WHERE shelvingFk COLLATE utf8_unicode_ci = vShelvingFk
AND itemFk = vItemFk AND itemFk = vItemFk
AND packing = vPacking) = 1 THEN AND packing = vPacking
AND buyFk = vBuyFk) THEN
UPDATE itemShelving UPDATE itemShelving
SET visible = visible+vQuantity SET visible = visible + vQuantity
WHERE shelvingFk COLLATE utf8_unicode_ci = vShelvingFk AND itemFk = vItemFk AND packing = vPacking; WHERE shelvingFk COLLATE utf8_unicode_ci = vShelvingFk AND itemFk = vItemFk AND packing = vPacking;
ELSE ELSE
CALL cache.last_buy_refresh(FALSE);
INSERT INTO itemShelving( itemFk, INSERT INTO itemShelving(
itemFk,
shelvingFk, shelvingFk,
visible, visible,
grouping, grouping,
packing, packing,
packagingFk) packagingFk,
buyFk)
SELECT vItemFk, SELECT vItemFk,
vShelvingFk, vShelvingFk,
vQuantity, vQuantity,
IFNULL(vGrouping, b.grouping), IFNULL(vGrouping, b.grouping),
IFNULL(vPacking, b.packing), IFNULL(vPacking, b.packing),
IFNULL(vPackagingFk, b.packagingFk) IFNULL(vPackagingFk, b.packagingFk),
FROM item i id
LEFT JOIN cache.last_buy lb ON i.id = lb.item_id AND lb.warehouse_id = vWarehouseFk FROM buy b
LEFT JOIN buy b ON b.id = lb.buy_id WHERE id = vBuyFk;
WHERE i.id = vItemFk;
END IF; END IF;
END$$ END$$
DELIMITER ; DELIMITER ;

View File

@ -23,7 +23,6 @@ proc: BEGIN
* @param tmp.comparativeFilterType(filterFk INT ,itemTypeFk INT) * @param tmp.comparativeFilterType(filterFk INT ,itemTypeFk INT)
* @return tmp.comparative * @return tmp.comparative
*/ */
DECLARE vDayRangeStart DATE; DECLARE vDayRangeStart DATE;
DECLARE vDayRangeEnd DATE; DECLARE vDayRangeEnd DATE;
DECLARE w1, w2, w3, w4, w5, w6, w7 INT; DECLARE w1, w2, w3, w4, w5, w6, w7 INT;
@ -59,14 +58,14 @@ proc: BEGIN
END IF; END IF;
SELECT MIN(dated) INTO vDayRangeStart SELECT MIN(dated) INTO vDayRangeStart
FROM vn.time FROM `time`
WHERE dated <= vDate WHERE dated <= vDate
GROUP BY period GROUP BY period
ORDER BY dated desc ORDER BY dated desc
LIMIT 1 OFFSET vWeekRange; LIMIT 1 OFFSET vWeekRange;
SELECT MAX(dated) INTO vDayRangeEnd SELECT MAX(dated) INTO vDayRangeEnd
FROM vn.time FROM `time`
WHERE dated >= vDate WHERE dated >= vDate
GROUP BY period GROUP BY period
ORDER BY dated ASC ORDER BY dated ASC
@ -83,12 +82,11 @@ proc: BEGIN
JOIN itemType t ON t.id = i.typeFk JOIN itemType t ON t.id = i.typeFk
JOIN itemCategory c ON c.id = t.categoryFk JOIN itemCategory c ON c.id = t.categoryFk
LEFT JOIN worker w ON w.id = t.workerFk LEFT JOIN worker w ON w.id = t.workerFk
WHERE (NOT vHasTypeFilter WHERE (NOT vHasTypeFilter OR t.id IN (
OR t.id IN (SELECT itemTypeFk FROM tmp.comparativeFilterType)) SELECT itemTypeFk FROM tmp.comparativeFilterType
AND (vBuyerFk IS NULL ))
OR t.workerFk = vBuyerFk) AND (vBuyerFk IS NULL OR t.workerFk = vBuyerFk)
AND (vIsFloramondo IS NULL AND (vIsFloramondo IS NULL OR i.isFloramondo = vIsFloramondo);
OR i.isFloramondo = vIsFloramondo);
IF vDate < util.VN_CURDATE() THEN IF vDate < util.VN_CURDATE() THEN
ALTER TABLE tmp.itemInventory ALTER TABLE tmp.itemInventory
@ -115,10 +113,11 @@ proc: BEGIN
SET i = i + 1; SET i = i + 1;
SELECT t.period INTO vPeriod SELECT t.period INTO vPeriod
FROM vn.`time` t FROM `time` t
WHERE t.dated = vDayRangeStart + INTERVAL (vWeekCount * (i - 1)) DAY; WHERE t.dated = vDayRangeStart + INTERVAL (vWeekCount * (i - 1)) DAY;
INSERT IGNORE INTO tTable(cy, ly, zy) VALUES(vPeriod, vPeriod - 100, vPeriod - 200); INSERT IGNORE INTO tTable(cy, ly, zy)
VALUES(vPeriod, vPeriod - 100, vPeriod - 200);
UNTIL i = vWeekCount END REPEAT; UNTIL i = vWeekCount END REPEAT;
SELECT cy, ly, zy INTO w1, y1, z1 FROM tTable LIMIT 1; SELECT cy, ly, zy INTO w1, y1, z1 FROM tTable LIMIT 1;
@ -130,7 +129,6 @@ proc: BEGIN
SELECT cy, ly, zy INTO w7, y7, z7 FROM tTable WHERE cy > w6 LIMIT 1; SELECT cy, ly, zy INTO w7, y7, z7 FROM tTable WHERE cy > w6 LIMIT 1;
-- Genera una tabla con los datos del año pasado. -- Genera una tabla con los datos del año pasado.
CREATE OR REPLACE TEMPORARY TABLE tLastYear CREATE OR REPLACE TEMPORARY TABLE tLastYear
(KEY (lItemFk)) (KEY (lItemFk))
ENGINE = MEMORY ENGINE = MEMORY
@ -151,15 +149,14 @@ proc: BEGIN
SUM(IF(c.timePeriod = y7, c.price, 0)) lprice7 SUM(IF(c.timePeriod = y7, c.price, 0)) lprice7
FROM tmp.itemInventory ai FROM tmp.itemInventory ai
JOIN comparative c ON c.itemFk = ai.id JOIN comparative c ON c.itemFk = ai.id
JOIN warehouse w on w.id = c.warehouseFk JOIN warehouse w ON w.id = c.warehouseFk
JOIN tTable wt ON c.timePeriod = wt.ly JOIN tTable wt ON c.timePeriod = wt.ly
WHERE IFNULL(vWarehouseFk, c.warehouseFk) = c.warehouseFk WHERE (vWarehouseFk IS NULL OR vWarehouseFk = c.warehouseFk)
AND w.isComparative AND w.isComparative
AND (vCountryFk IS NULL OR c.countryFk = vCountryFk) AND (vCountryFk IS NULL OR c.countryFk = vCountryFk)
GROUP BY ai.id; GROUP BY ai.id;
-- Genera una tabla con los datos de hace DOS años. -- Genera una tabla con los datos de hace 2 años
CREATE OR REPLACE TEMPORARY TABLE tTwoYearsAgo CREATE OR REPLACE TEMPORARY TABLE tTwoYearsAgo
(KEY (tItemFk)) (KEY (tItemFk))
ENGINE = MEMORY ENGINE = MEMORY
@ -180,59 +177,58 @@ proc: BEGIN
SUM(IF(c.timePeriod = z7, c.price, 0)) vlprice7 SUM(IF(c.timePeriod = z7, c.price, 0)) vlprice7
FROM tmp.itemInventory ai FROM tmp.itemInventory ai
JOIN comparative c ON c.itemFk = ai.id JOIN comparative c ON c.itemFk = ai.id
JOIN warehouse w on w.id = c.warehouseFk JOIN warehouse w ON w.id = c.warehouseFk
JOIN tTable wt ON c.timePeriod = wt.zy JOIN tTable wt ON c.timePeriod = wt.zy
WHERE IFNULL(vWarehouseFk, c.warehouseFk) = c.warehouseFk WHERE (vWarehouseFk IS NULL OR vWarehouseFk = c.warehouseFk)
AND w.isComparative AND w.isComparative
AND (vCountryFk IS NULL OR c.countryFk = vCountryFk) AND (vCountryFk IS NULL OR c.countryFk = vCountryFk)
GROUP BY ai.id; GROUP BY ai.id;
-- Genera una tabla con los datos de este año.ss -- Genera una tabla con los datos de este año
CREATE OR REPLACE TEMPORARY TABLE tCurrentYear CREATE OR REPLACE TEMPORARY TABLE tCurrentYear
(KEY (cItemFk)) (KEY (cItemFk))
ENGINE = MEMORY ENGINE = MEMORY
SELECT t.itemFk cItemFk, SELECT t.itemFk cItemFk,
SUM(IF(week = w1, total, 0)) cweek1, SUM(IF(`week` = w1, total, 0)) cweek1,
SUM(IF(week = w2, total, 0)) cweek2, SUM(IF(`week` = w2, total, 0)) cweek2,
SUM(IF(week = w3, total, 0)) cweek3, SUM(IF(`week` = w3, total, 0)) cweek3,
SUM(IF(week = w4, total, 0)) cweek4, SUM(IF(`week` = w4, total, 0)) cweek4,
SUM(IF(week = w5, total, 0)) cweek5, SUM(IF(`week` = w5, total, 0)) cweek5,
SUM(IF(week = w6, total, 0)) cweek6, SUM(IF(`week` = w6, total, 0)) cweek6,
SUM(IF(week = w7, total, 0)) cweek7, SUM(IF(`week` = w7, total, 0)) cweek7,
SUM(IF(week = w1, price, 0)) cprice1, SUM(IF(`week` = w1, price, 0)) cprice1,
SUM(IF(week = w2, price, 0)) cprice2, SUM(IF(`week` = w2, price, 0)) cprice2,
SUM(IF(week = w3, price, 0)) cprice3, SUM(IF(`week` = w3, price, 0)) cprice3,
SUM(IF(week = w4, price, 0)) cprice4, SUM(IF(`week` = w4, price, 0)) cprice4,
SUM(IF(week = w5, price, 0)) cprice5, SUM(IF(`week` = w5, price, 0)) cprice5,
SUM(IF(week = w6, price, 0)) cprice6, SUM(IF(`week` = w6, price, 0)) cprice6,
SUM(IF(week = w7, price, 0)) cprice7 SUM(IF(`week` = w7, price, 0)) cprice7
FROM ( FROM (
SELECT s.itemFk, SELECT s.itemFk,
ti.period `week`, ti.period `week`,
SUM(s.quantity) total, SUM(s.quantity) total,
TRUNCATE(SUM(s.quantity * s.priceFixed),0) price TRUNCATE(SUM(s.quantity * s.priceFixed), 0) price
FROM ticket t FROM ticket t FORCE INDEX (Fecha)
JOIN sale s ON t.id = s.ticketFk JOIN sale s ON t.id = s.ticketFk
JOIN tmp.itemInventory it ON it.id = s.itemFk JOIN tmp.itemInventory it ON it.id = s.itemFk
JOIN time ti ON ti.dated = DATE(t.shipped) JOIN `time` ti ON ti.dated = DATE(t.shipped)
JOIN item i ON i.id = s.itemFk JOIN item i ON i.id = s.itemFk
JOIN itemType tp ON tp.id = i.typeFk JOIN itemType tp ON tp.id = i.typeFk
JOIN itemCategory ic ON ic.id = tp.categoryFk JOIN itemCategory ic ON ic.id = tp.categoryFk
JOIN warehouse w ON w.id = t.warehouseFk JOIN warehouse w ON w.id = t.warehouseFk
STRAIGHT_JOIN address ad ON ad.id = t.addressFk JOIN `address` ad ON ad.id = t.addressFk
JOIN province p ON p.id = ad.provinceFk JOIN province p ON p.id = ad.provinceFk
JOIN `client` c ON c.id = ad.clientFk JOIN `client` c ON c.id = ad.clientFk
WHERE t.shipped BETWEEN vDayRangeStart AND util.dayEnd(vDayRangeEnd) WHERE t.shipped BETWEEN vDayRangeStart AND util.dayEnd(vDayRangeEnd)
AND c.typeFk IN ('Normal','handMaking') AND c.typeFk IN ('normal', 'handMaking')
AND w.id = COALESCE(vWarehouseFk, w.id) AND (vWarehouseFk IS NULL OR vWarehouseFk = w.id)
AND w.isComparative
AND (vCountryFk IS NULL OR p.countryFk = vCountryFk) AND (vCountryFk IS NULL OR p.countryFk = vCountryFk)
GROUP BY i.id, week AND w.isComparative
GROUP BY i.id, `week`
) t ) t
GROUP BY t.itemFk; GROUP BY t.itemFk;
-- Genera la tabla con la comparativa. -- Genera la tabla con la comparativa
CREATE OR REPLACE TEMPORARY TABLE tmp.comparative CREATE OR REPLACE TEMPORARY TABLE tmp.comparative
ENGINE = MEMORY ENGINE = MEMORY
SELECT it.subName productor, SELECT it.subName productor,
@ -240,13 +236,13 @@ proc: BEGIN
b.buyingValue costefijo, b.buyingValue costefijo,
b.groupingMode caja, b.groupingMode caja,
it.image ArticleImage, it.image ArticleImage,
IFNULL(it.inkFk,"?") color, IFNULL(it.inkFk, '?') color,
tp.code tipo, tp.code tipo,
it.typeFk tipo_id, it.typeFk tipo_id,
o.code origen, o.code origen,
it.category categoria, it.category categoria,
it.stems tallos, it.stems tallos,
it.size medida, it.`size` medida,
it.name article, it.name article,
w.code codigoTrabajador, w.code codigoTrabajador,
tp.categoryFk reino_id, tp.categoryFk reino_id,
@ -257,24 +253,27 @@ proc: BEGIN
it.id Id_Article, it.id Id_Article,
i.buy_id, i.buy_id,
tp.life, tp.life,
IFNULL(i.sd,0) sd, IFNULL(i.sd, 0) sd,
i.avalaible, i.avalaible,
i.visible, i.visible,
i.buy_date, i.buy_date,
e.id provider_id, e.id provider_id,
it.comment comments, it.comment comments,
it.description itemDescription, it.description itemDescription,
IF(cy.cItemFk IS NULL AND i.visible = 0 AND i.avalaible = 0 IF(cy.cItemFk IS NULL AND i.visible = 0
AND IFNULL(i.sd, 0) = 0, FALSE, TRUE) filtret, AND i.avalaible = 0 AND (i.sd IS NULL OR i.sd = 0),
FALSE,
TRUE
) filtret,
IF(it.hasMinPrice, FORMAT(it.minPrice, 2), "") pvp, IF(it.hasMinPrice, FORMAT(it.minPrice, 2), "") pvp,
s.company_name s.company_name
FROM tmp.itemInventory i FROM tmp.itemInventory i
JOIN item it ON it.id = i.id JOIN item it ON it.id = i.id
LEFT JOIN itemType tp ON tp.id = it.typeFk JOIN itemType tp ON tp.id = it.typeFk
LEFT JOIN worker w ON w.id = tp.workerFk JOIN worker w ON w.id = tp.workerFk
LEFT JOIN buy b ON b.id = i.buy_id LEFT JOIN buy b ON b.id = i.buy_id
LEFT JOIN entry e ON e.id = b.entryFk LEFT JOIN `entry` e ON e.id = b.entryFk
LEFT JOIN origin o ON o.id = it.originFk JOIN origin o ON o.id = it.originFk
LEFT JOIN tLastYear ly ON ly.lItemFk = it.id LEFT JOIN tLastYear ly ON ly.lItemFk = it.id
LEFT JOIN tCurrentYear cy ON cy.cItemFk = it.id LEFT JOIN tCurrentYear cy ON cy.cItemFk = it.id
LEFT JOIN tTwoYearsAgo zy ON zy.tItemFk = it.id LEFT JOIN tTwoYearsAgo zy ON zy.tItemFk = it.id
@ -287,8 +286,8 @@ proc: BEGIN
OR ly.lweek1 OR ly.lweek2 OR ly.lweek3 OR ly.lweek4 OR ly.lweek5 OR ly.lweek6 OR ly.lweek7 OR ly.lweek1 OR ly.lweek2 OR ly.lweek3 OR ly.lweek4 OR ly.lweek5 OR ly.lweek6 OR ly.lweek7
OR zy.vlweek1 OR zy.vlweek2 OR zy.vlweek3 OR zy.vlweek4 OR zy.vlweek5 OR zy.vlweek6 OR zy.vlweek7; OR zy.vlweek1 OR zy.vlweek2 OR zy.vlweek3 OR zy.vlweek4 OR zy.vlweek5 OR zy.vlweek6 OR zy.vlweek7;
-- Elimina las tablas temporales creadas... DROP TEMPORARY TABLE IF EXISTS
DROP TEMPORARY TABLE IF EXISTS tmp.itemInventory, tmp.itemInventory,
tTwoYearsAgo, tTwoYearsAgo,
tLastYear, tLastYear,
tCurrentYear, tCurrentYear,

View File

@ -1,5 +1,7 @@
DELIMITER $$ DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`item_ValuateInventory`(vDated DATE, vIsDetailed BOOLEAN) CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`item_valuateInventory`(
vDated DATE
)
BEGIN BEGIN
DECLARE vInventoried DATE; DECLARE vInventoried DATE;
DECLARE vHasNotInventory BOOLEAN DEFAULT FALSE; DECLARE vHasNotInventory BOOLEAN DEFAULT FALSE;
@ -15,8 +17,7 @@ BEGIN
SELECT tr.landed INTO vInventoried SELECT tr.landed INTO vInventoried
FROM travel tr FROM travel tr
JOIN `entry` e ON e.travelFk = tr.id JOIN `entry` e ON e.travelFk = tr.id
JOIN entryConfig ec WHERE tr.landed <= vDateDayEnd
WHERE landed <= vDateDayEnd
AND e.supplierFk = vInventorySupplierFk AND e.supplierFk = vInventorySupplierFk
ORDER BY tr.landed DESC ORDER BY tr.landed DESC
LIMIT 1; LIMIT 1;
@ -27,8 +28,7 @@ BEGIN
SELECT landed INTO vInventoryClone SELECT landed INTO vInventoryClone
FROM travel tr FROM travel tr
JOIN `entry` e ON e.travelFk = tr.id JOIN `entry` e ON e.travelFk = tr.id
JOIN entryConfig ec WHERE tr.landed >= vDated
WHERE landed >= vDated
AND e.supplierFk = vInventorySupplierFk AND e.supplierFk = vInventorySupplierFk
ORDER BY landed ASC ORDER BY landed ASC
LIMIT 1; LIMIT 1;
@ -41,6 +41,7 @@ BEGIN
warehouseFk SMALLINT, warehouseFk SMALLINT,
itemFk BIGINT, itemFk BIGINT,
quantity INT, quantity INT,
volume DECIMAL(10,2),
cost DOUBLE DEFAULT 0, cost DOUBLE DEFAULT 0,
total DOUBLE DEFAULT 0, total DOUBLE DEFAULT 0,
warehouseInventory VARCHAR(20), warehouseInventory VARCHAR(20),
@ -60,9 +61,8 @@ BEGIN
JOIN `entry` e ON e.id = b.entryFk JOIN `entry` e ON e.id = b.entryFk
JOIN travel tr ON tr.id = e.travelFk JOIN travel tr ON tr.id = e.travelFk
JOIN itemType t ON t.id = i.typeFk JOIN itemType t ON t.id = i.typeFk
JOIN warehouse w ON w.id = warehouseInFk JOIN warehouse w ON w.id = tr.warehouseInFk
JOIN entryConfig ec WHERE tr.landed = vDateDayEnd
WHERE landed = vDateDayEnd
AND e.supplierFk = vInventorySupplierFk AND e.supplierFk = vInventorySupplierFk
AND w.valuatedInventory AND w.valuatedInventory
AND t.isInventory AND t.isInventory
@ -78,9 +78,8 @@ BEGIN
JOIN `entry` e ON e.id = b.entryFk JOIN `entry` e ON e.id = b.entryFk
JOIN travel tr ON tr.id = e.travelFk JOIN travel tr ON tr.id = e.travelFk
JOIN itemType t ON t.id = i.typeFk JOIN itemType t ON t.id = i.typeFk
JOIN warehouse w ON w.id = warehouseInFk JOIN warehouse w ON w.id = tr.warehouseInFk
JOIN entryConfig ec WHERE tr.landed = vInventoried
WHERE landed = vInventoried
AND e.supplierFk = vInventorySupplierFk AND e.supplierFk = vInventorySupplierFk
AND w.valuatedInventory AND w.valuatedInventory
AND t.isInventory AND t.isInventory
@ -99,7 +98,6 @@ BEGIN
JOIN travel tr ON tr.id = e.travelFk JOIN travel tr ON tr.id = e.travelFk
JOIN itemType t ON t.id = i.typeFk JOIN itemType t ON t.id = i.typeFk
JOIN warehouse w ON w.id = tr.warehouseInFk JOIN warehouse w ON w.id = tr.warehouseInFk
JOIN entryConfig ec
WHERE tr.landed BETWEEN vInventoried AND vDateDayEnd WHERE tr.landed BETWEEN vInventoried AND vDateDayEnd
AND IF(tr.landed = util.VN_CURDATE(), tr.isReceived, TRUE) AND IF(tr.landed = util.VN_CURDATE(), tr.isReceived, TRUE)
AND NOT e.isRaid AND NOT e.isRaid
@ -183,52 +181,37 @@ BEGIN
AND e.isConfirmed AND e.isConfirmed
ON DUPLICATE KEY UPDATE tInventory.quantity = tInventory.quantity + (b.quantity); ON DUPLICATE KEY UPDATE tInventory.quantity = tInventory.quantity + (b.quantity);
CALL vn.buyUltimate(NULL, vDateDayEnd); CALL buyUltimate(NULL, vDateDayEnd);
DELETE FROM tInventory WHERE quantity IS NULL OR NOT quantity;
UPDATE tInventory i UPDATE tInventory i
JOIN tmp.buyUltimate bu ON i.warehouseFk = bu.warehouseFk AND i.itemFk = bu.itemFk JOIN tmp.buyUltimate bu ON i.warehouseFk = bu.warehouseFk AND i.itemFk = bu.itemFk
JOIN buy b ON b.id = bu.buyFk JOIN buy b ON b.id = bu.buyFk
SET total = i.quantity * (IFNULL(b.buyingValue, 0) + IFNULL(b.packageValue, 0) + IFNULL(b.freightValue, 0) + IFNULL(b.comissionValue, 0)), LEFT JOIN itemCost ic ON ic.itemFk = i.itemFk
cost = IFNULL(b.buyingValue, 0) + IFNULL(b.packageValue, 0) + IFNULL(b.freightValue, 0) + IFNULL(b.comissionValue, 0) AND ic.warehouseFk = i.warehouseFk
WHERE i.quantity; SET i.total = i.quantity * (IFNULL(b.buyingValue, 0) + IFNULL(b.packageValue, 0) + IFNULL(b.freightValue, 0) + IFNULL(b.comissionValue, 0)),
i.cost = IFNULL(b.buyingValue, 0) + IFNULL(b.packageValue, 0) + IFNULL(b.freightValue, 0) + IFNULL(b.comissionValue, 0),
i.volume = i.quantity * ic.cm3delivery / 1000000;
DELETE FROM tInventory
WHERE quantity IS NULL OR NOT quantity;
IF vIsDetailed THEN
SELECT ti.warehouseFk, SELECT ti.warehouseFk,
i.id itemFk, i.id,
i.longName, i.longName,
i.size, i.size,
ti.quantity, ti.quantity,
tp.name Tipo, ti.volume,
ic.name Reino, tp.name itemTypeName,
ic.name itemCategoryName,
ti.cost, ti.cost,
CAST(ti.total AS DECIMAL(10, 2)) total, ti.total,
ti.warehouseInventory almacen ti.warehouseInventory
FROM tInventory ti FROM tInventory ti
JOIN warehouse w ON w.id = warehouseFk JOIN warehouse w ON w.id = warehouseFk
JOIN item i ON i.id = ti.itemFk JOIN item i ON i.id = ti.itemFk
JOIN itemType tp ON tp.id = i.typeFk JOIN itemType tp ON tp.id = i.typeFk
JOIN itemCategory ic ON ic.id = tp.categoryFk JOIN itemCategory ic ON ic.id = tp.categoryFk
WHERE w.valuatedInventory WHERE w.valuatedInventory
AND ti.total > 0 AND ti.total > 0;
ORDER BY ti.total DESC;
ELSE
SELECT i.warehouseInventory Almacen,
ic.name Reino,
CAST(i.total AS DECIMAL(10, 2)) Euros,
w.code Comprador,
it.id
FROM tInventory i
JOIN warehouse wh ON wh.id = warehouseFk
JOIN item it ON it.id = i.itemFk
JOIN itemType itp ON itp.id = it.typeFk
LEFT JOIN worker w ON w.id = itp.workerFk
JOIN itemCategory ic ON ic.id = itp.categoryFk
WHERE wh.valuatedInventory
AND i.total > 0;
END IF;
DROP TEMPORARY TABLE DROP TEMPORARY TABLE
tmp.buyUltimate, tmp.buyUltimate,

View File

@ -147,10 +147,16 @@ proc: BEGIN
JOIN ( JOIN (
SELECT tt.ticketFk, SELECT tt.ticketFk,
COUNT(*) `lines`, COUNT(*) `lines`,
SUM(sv.volume) m3, SUM(s.quantity * ic.cm3delivery / 1000000) m3,
IFNULL(SUM(IF(sv.isPicked, sv.volume, 0)) / SUM(sv.volume), 0) rate IFNULL(SUM(IF(s.isPicked,
(s.quantity * ic.cm3delivery / 1000000),
0)) / SUM(s.quantity * ic.cm3delivery / 1000000),
0) rate
FROM tmp.productionTicket tt FROM tmp.productionTicket tt
JOIN saleVolume sv ON sv.ticketFk = tt.ticketFk JOIN sale s ON s.ticketFk = tt.ticketFk
AND s.quantity > 0
JOIN itemCost ic ON ic.itemFk = s.itemFk
AND ic.warehouseFk = vWarehouseFk
GROUP BY tt.ticketFk GROUP BY tt.ticketFk
) m ON m.ticketFk = pb.ticketFk ) m ON m.ticketFk = pb.ticketFk
SET pb.`lines` = m.`lines`, SET pb.`lines` = m.`lines`,
@ -218,6 +224,8 @@ proc: BEGIN
AND ish.visible AND ish.visible
GROUP BY ish.itemFk, p.sectorFk; GROUP BY ish.itemFk, p.sectorFk;
CREATE INDEX idxItem ON tItemShelvingStock (itemFk);
INSERT INTO tmp.ticketWithPrevia(ticketFk, salesCount) INSERT INTO tmp.ticketWithPrevia(ticketFk, salesCount)
SELECT pb.ticketFk, COUNT(DISTINCT s.id) SELECT pb.ticketFk, COUNT(DISTINCT s.id)
FROM tmp.productionBuffer pb FROM tmp.productionBuffer pb

View File

@ -64,10 +64,15 @@ BEGIN
FROM tmp.sale_getProblems tp FROM tmp.sale_getProblems tp
JOIN ticket t ON t.id = tp.ticketFk JOIN ticket t ON t.id = tp.ticketFk
JOIN ( JOIN (
SELECT t.addressFk, SUM(sv.litros) litros, t.totalWithoutVat SELECT t.addressFk,
SUM(ROUND(`ic`.`cm3delivery` * `s`.`quantity` / 1000, 0)) litros,
t.totalWithoutVat
FROM tmp.ticket_list tl FROM tmp.ticket_list tl
JOIN saleVolume sv ON sv.ticketFk = tl.ticketFk
JOIN ticket t ON t.id = tl.ticketFk JOIN ticket t ON t.id = tl.ticketFk
JOIN sale s ON s.ticketFk = t.id
AND s.quantity > 0
JOIN itemCost ic ON ic.itemFk = s.itemFk
AND ic.warehouseFk = t.warehouseFk
JOIN zoneClosure zc ON zc.zoneFk = t.zoneFk JOIN zoneClosure zc ON zc.zoneFk = t.zoneFk
AND zc.dated = util.VN_CURDATE() AND zc.dated = util.VN_CURDATE()
JOIN agencyMode am ON am.id = t.agencyModeFk JOIN agencyMode am ON am.id = t.agencyModeFk
@ -95,12 +100,12 @@ BEGIN
FROM ( FROM (
SELECT COUNT(s.id) nComp, tl.ticketFk, s.id saleFk SELECT COUNT(s.id) nComp, tl.ticketFk, s.id saleFk
FROM tmp.ticket_list tl FROM tmp.ticket_list tl
JOIN vn.sale s ON s.ticketFk = tl.ticketFk JOIN sale s ON s.ticketFk = tl.ticketFk
LEFT JOIN vn.saleComponent sc ON sc.saleFk = s.id LEFT JOIN saleComponent sc ON sc.saleFk = s.id
LEFT JOIN vn.component c ON c.id = sc.componentFk AND c.isRequired LEFT JOIN component c ON c.id = sc.componentFk AND c.isRequired
JOIN vn.ticket t ON t.id = tl.ticketFk JOIN ticket t ON t.id = tl.ticketFk
JOIN vn.agencyMode am ON am.id = t.agencyModeFk JOIN agencyMode am ON am.id = t.agencyModeFk
JOIN vn.deliveryMethod dm ON dm.id = am.deliveryMethodFk JOIN deliveryMethod dm ON dm.id = am.deliveryMethodFk
WHERE dm.code IN ('AGENCY','DELIVERY','PICKUP') WHERE dm.code IN ('AGENCY','DELIVERY','PICKUP')
AND s.quantity > 0 AND s.quantity > 0
GROUP BY s.id GROUP BY s.id

View File

@ -8,6 +8,8 @@ BEGIN
END; END;
CREATE OR REPLACE TEMPORARY TABLE tSalesToPreserve CREATE OR REPLACE TEMPORARY TABLE tSalesToPreserve
(PRIMARY KEY (id))
ENGINE = MEMORY
SELECT s.id, s.itemFk, SUM(s.quantity) newQuantity SELECT s.id, s.itemFk, SUM(s.quantity) newQuantity
FROM sale s FROM sale s
JOIN item i ON i.id = s.itemFk JOIN item i ON i.id = s.itemFk
@ -20,7 +22,7 @@ BEGIN
UPDATE sale s UPDATE sale s
JOIN tSalesToPreserve stp ON stp.id = s.id JOIN tSalesToPreserve stp ON stp.id = s.id
SET quantity = newQuantity SET s.quantity = newQuantity
WHERE s.ticketFk = vTicketFk; WHERE s.ticketFk = vTicketFk;
DELETE s.* DELETE s.*

View File

@ -27,7 +27,10 @@ BEGIN
SELECT DISTINCT clientFk SELECT DISTINCT clientFk
FROM ( FROM (
SELECT clientFk, SUM(quantity) totalQuantity SELECT clientFk, SUM(quantity) totalQuantity
FROM tmp.packagingToInvoice FROM tmp.packagingToInvoice tpi
JOIN client c ON c.id = tpi.clientFk
LEFT JOIN supplier s ON s.nif = c.fi
WHERE s.id IS NULL
GROUP BY itemFk, clientFk GROUP BY itemFk, clientFk
HAVING totalQuantity > 0)sub; HAVING totalQuantity > 0)sub;

View File

@ -0,0 +1,14 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`travel_throwAwb`(vSelf INT)
BEGIN
/**
* Throws an error if travel does not have a logical AWB
* or there are several AWBs associated with the same DUA
*
* @param vSelf The travel id
*/
IF NOT travel_hasUniqueAwb(vSelf) THEN
CALL util.throw('A different AWB is found in the entries');
END IF;
END$$
DELIMITER ;

View File

@ -7,8 +7,8 @@ BEGIN
CALL supplier_checkIsActive(NEW.supplierFk); CALL supplier_checkIsActive(NEW.supplierFk);
SET NEW.currencyFk = entry_getCurrency(NEW.currencyFk, NEW.supplierFk); SET NEW.currencyFk = entry_getCurrency(NEW.currencyFk, NEW.supplierFk);
SET NEW.commission = entry_getCommission(NEW.travelFk, NEW.currencyFk,NEW.supplierFk); SET NEW.commission = entry_getCommission(NEW.travelFk, NEW.currencyFk,NEW.supplierFk);
IF NEW.travelFk IS NOT NULL AND NOT travel_hasUniqueAwb(NEW.travelFk) THEN IF NEW.travelFk IS NOT NULL THEN
CALL util.throw('The travel is incorrect, there is a different AWB in the associated entries'); CALL travel_throwAwb(NEW.travelFk);
END IF; END IF;
END$$ END$$
DELIMITER ; DELIMITER ;

View File

@ -25,8 +25,8 @@ BEGIN
IF NOT (NEW.travelFk <=> OLD.travelFk) THEN IF NOT (NEW.travelFk <=> OLD.travelFk) THEN
IF NEW.travelFk IS NOT NULL AND NOT travel_hasUniqueAwb(NEW.travelFk) THEN IF NEW.travelFk IS NOT NULL THEN
CALL util.throw('The travel is incorrect, there is a different AWB in the associated entries'); CALL travel_throwAwb(NEW.travelFk);
END IF; END IF;
SELECT COUNT(*) > 0 INTO vIsVirtual SELECT COUNT(*) > 0 INTO vIsVirtual

View File

@ -9,8 +9,8 @@ BEGIN
CALL travel_checkWarehouseIsFeedStock(NEW.warehouseInFk); CALL travel_checkWarehouseIsFeedStock(NEW.warehouseInFk);
IF NEW.awbFk IS NOT NULL AND NOT travel_hasUniqueAwb(NEW.id) THEN IF NEW.awbFk IS NOT NULL THEN
CALL util.throw('The AWB is incorrect, there is a different AWB in the associated entries'); CALL travel_throwAwb(NEW.id);
END IF; END IF;
END$$ END$$
DELIMITER ; DELIMITER ;

View File

@ -33,8 +33,8 @@ BEGIN
END IF; END IF;
END IF; END IF;
IF (NOT(NEW.awbFk <=> OLD.awbFk)) AND NEW.awbFk IS NOT NULL AND NOT travel_hasUniqueAwb(NEW.id) THEN IF (NOT(NEW.awbFk <=> OLD.awbFk)) AND NEW.awbFk IS NOT NULL THEN
CALL util.throw('The AWB is incorrect, there is a different AWB in the associated entries'); CALL travel_throwAwb(NEW.id);
END IF; END IF;
END$$ END$$
DELIMITER ; DELIMITER ;

View File

@ -0,0 +1,4 @@
-- Place your SQL code here
INSERT INTO salix.defaultViewConfig
(tableCode, `columns`)
VALUES('routesList', '{"ID":true,"worker":true,"agency":true,"vehicle":true,"date":true,"volume":true,"description":true,"started":true,"finished":true,"actions":true}');

View File

@ -0,0 +1 @@
ALTER TABLE vn.item ADD COLUMN photoMotivation VARCHAR(255);

View File

@ -0,0 +1,4 @@
-- Place your SQL code here
ALTER TABLE floranet.catalogue ADD addressFk int(11) NOT NULL;
ALTER TABLE floranet.catalogue ADD CONSTRAINT catalogue_address_FK FOREIGN KEY (addressFk) REFERENCES vn.address(id) ON DELETE CASCADE ON UPDATE CASCADE;

View File

@ -0,0 +1,6 @@
ALTER TABLE floranet.builder DROP FOREIGN KEY builder_FK_1;
ALTER TABLE floranet.`element` DROP PRIMARY KEY;
ALTER TABLE floranet.`element` ADD id INT NOT NULL;
ALTER TABLE floranet.`element` ADD CONSTRAINT element_pk PRIMARY KEY (id);
ALTER TABLE floranet.builder ADD CONSTRAINT builder_element_FK FOREIGN KEY (elementFk) REFERENCES floranet.`element`(id) ON DELETE CASCADE ON UPDATE CASCADE;

View File

@ -0,0 +1,3 @@
-- Place your SQL code here
INSERT INTO salix.ACL (model,property,accessType,permission,principalType,principalId)
VALUES ('RouteConfig','*','READ','ALLOW','ROLE','employee');

View File

@ -0,0 +1,46 @@
use account;
INSERT INTO role
SET name = 'reviewer',
description = 'Revisor de producción',
hasLogin = TRUE,
created = util.VN_CURDATE(),
modified = util.VN_CURDATE(),
editorFk = NULL;
INSERT INTO roleInherit(
role,
inheritsFrom
)
SELECT r1.id,
r2.id
FROM role r1
JOIN role r2
WHERE r1.name = 'reviewer'
AND r2.name = 'production'
UNION
SELECT ri.role,
r2.id
FROM roleInherit ri
JOIN role r1 ON r1.id = ri.role
JOIN role r2 ON r2.name = 'reviewer'
WHERE r1.name IN ('claimManager', 'productionBoss')
GROUP BY ri.role;
DELETE ri
FROM roleInherit ri
JOIN role r1 ON ri.role = r1.id
JOIN role r2 ON ri.inheritsFrom = r2.id
WHERE r1.name = 'replenisher'
AND r2.name = 'buyer';
UPDATE salix.ACL
SET principalId = 'reviewer'
WHERE property = 'isInPreparing';
UPDATE user u
JOIN vn.workerDepartment wd ON wd.workerFk = u.id
JOIN vn.department d ON wd.departmentFk = d.id
JOIN role r ON r.name = 'reviewer'
SET u.role = r.id
WHERE d.name IN ('REVISION', 'PREVIA');

View File

@ -0,0 +1,24 @@
REVOKE UPDATE ON vn. invoiceIn FROM administrative, hrBoss, buyer, logistic;
GRANT UPDATE (id,
serialNumber,
serial,
supplierFk,
issued,
supplierRef,
currencyFk,
created,
companyFk,
docFk,
booked,
operated,
siiTypeInvoiceInFk,
cplusRectificationTypeFk,
cplusSubjectOpFk,
cplusTaxBreakFk,
siiTrascendencyInvoiceInFk,
bookEntried,
isVatDeductible,
withholdingSageFk,
expenseFkDeductible,
editorFk
) ON vn.invoiceIn TO administrative, hrBoss, buyer, logistic;

View File

@ -0,0 +1,23 @@
UPDATE salix.ACL
SET accessType = 'READ'
WHERE principalId IN ('administrative','buyer')
AND model = 'invoiceIn'
AND property = '*';
INSERT INTO salix.ACL (model, property, accessType, permission, principalType, principalId)
VALUES
('InvoiceIn', 'updateInvoiceIn', 'WRITE', 'ALLOW', 'ROLE', 'administrative'),
('InvoiceIn', 'clone', 'WRITE', 'ALLOW', 'ROLE', 'administrative'),
('InvoiceIn', 'corrective', 'WRITE', 'ALLOW', 'ROLE', 'administrative'),
('InvoiceIn', 'exchangeRateUpdate', 'WRITE', 'ALLOW', 'ROLE', 'administrative'),
('InvoiceIn', 'invoiceInEmail', 'WRITE', 'ALLOW', 'ROLE', 'administrative'),
('InvoiceIn', 'toBook', 'WRITE', 'ALLOW', 'ROLE', 'administrative'),
('InvoiceIn', 'toUnbook', 'WRITE', 'ALLOW', 'ROLE', 'administrative'),
('InvoiceIn', 'deleteById', 'WRITE', 'ALLOW', 'ROLE', 'administrative'),
('InvoiceIn', 'updateInvoiceIn', 'WRITE', 'ALLOW', 'ROLE', 'buyer'),
('InvoiceIn', 'clone', 'WRITE', 'ALLOW', 'ROLE', 'buyer'),
('InvoiceIn', 'corrective', 'WRITE', 'ALLOW', 'ROLE', 'buyer'),
('InvoiceIn', 'exchangeRateUpdate', 'WRITE', 'ALLOW', 'ROLE', 'buyer'),
('InvoiceIn', 'invoiceInEmail', 'WRITE', 'ALLOW', 'ROLE', 'buyer'),
('InvoiceIn', 'toBook', 'WRITE', 'ALLOW', 'ROLE', 'buyer'),
('InvoiceIn', 'deleteById', 'WRITE', 'ALLOW', 'ROLE', 'buyer');

View File

@ -0,0 +1,9 @@
-- Place your SQL code here
CREATE OR REPLACE TABLE floranet.config (
email varchar(255) DEFAULT 'floranet@verdnatura.es' NOT NULL
)
ENGINE=InnoDB
DEFAULT CHARSET=utf8mb3
COLLATE=utf8mb3_unicode_ci;

View File

@ -0,0 +1,35 @@
-- Place your SQL code here
DROP TABLE IF EXISTS floranet.builder;
CREATE OR REPLACE TABLE floranet.`element` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(30) NOT NULL,
`itemFk` int(11) DEFAULT NULL,
`longNameFilter` varchar(30) DEFAULT NULL,
`typeFk` smallint(5) unsigned DEFAULT NULL,
`minSize` int(10) unsigned DEFAULT NULL,
`maxSize` int(10) unsigned DEFAULT NULL,
`inkFk` char(3) CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci DEFAULT NULL,
`originFk` tinyint(2) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `element_FK` (`itemFk`),
KEY `element_FK_1` (`typeFk`),
KEY `element_FK_2` (`inkFk`),
KEY `element_FK_3` (`originFk`),
CONSTRAINT `element_FK` FOREIGN KEY (`itemFk`) REFERENCES `vn`.`item` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `element_FK_1` FOREIGN KEY (`typeFk`) REFERENCES `vn`.`itemType` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `element_FK_2` FOREIGN KEY (`inkFk`) REFERENCES `vn`.`ink` (`id`) ON UPDATE CASCADE,
CONSTRAINT `element_FK_3` FOREIGN KEY (`originFk`) REFERENCES `vn`.`origin` (`id`) ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='Filtro para localizar posibles items que coincidan con la descripción';
CREATE OR REPLACE TABLE floranet.`recipe` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`itemFk` int(11) NOT NULL,
`elementFk` int(11) NOT NULL,
`quantity` int(10) unsigned NOT NULL DEFAULT 1,
PRIMARY KEY (`id`),
KEY `recipe_FK` (`itemFk`),
KEY `recipe_FK_1` (`elementFk`),
CONSTRAINT `recipe_FK` FOREIGN KEY (`itemFk`) REFERENCES `vn`.`item` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `recipe_element_FK` FOREIGN KEY (`elementFk`) REFERENCES `element` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='Links handmade products with their elements';

View File

@ -0,0 +1,20 @@
-- Place your SQL code here
-- floranet.recipe definition
CREATE OR REPLACE TABLE floranet.`recipe`
(
`id` int(11) NOT NULL AUTO_INCREMENT,
`itemFk` int(11) NOT NULL COMMENT 'Bouquet or plant name',
`elementFk` int(11) NOT NULL COMMENT 'Item detail for bouquet''s composition',
`quantity` int(10) unsigned NOT NULL DEFAULT 1,
`cost` decimal(10,2) NOT NULL DEFAULT 1.00,
PRIMARY KEY (`id`),
KEY `recipe_FK` (`itemFk`),
KEY `recipe_FK_1` (`elementFk`),
CONSTRAINT `recipe_FK` FOREIGN KEY (`itemFk`) REFERENCES `vn`.`item` (`id`) ON UPDATE CASCADE,
CONSTRAINT `recipe_item_FK` FOREIGN KEY (`elementFk`) REFERENCES `vn`.`item` (`id`) ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='Links handmade products with their elements';
DROP TABLE IF EXISTS floranet.`element`;

View File

@ -0,0 +1,2 @@
ALTER TABLE vn.productionConfig ADD scannablePreviusCodeType enum('qr','barcode')
CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci DEFAULT 'barcode' NOT NULL;

View File

@ -0,0 +1,3 @@
INSERT INTO salix.ACL(model,property,accessType,permission,principalType,principalId)
VALUES('InvoiceIn', 'create', 'WRITE', 'ALLOW', 'ROLE', 'administrative'),
('InvoiceIn', 'create', 'WRITE', 'ALLOW', 'ROLE', 'buyer');

View File

@ -51,7 +51,7 @@ describe('Client Add address path', () => {
await page.waitToClick(selectors.clientAddresses.saveButton); await page.waitToClick(selectors.clientAddresses.saveButton);
const message = await page.waitForSnackbar(); const message = await page.waitForSnackbar();
expect(message.text).toContain('Incoterms is required for a non UEE member'); expect(message.text).toContain('Incoterms and Customs agent are required for a non UEE member');
}); });
it(`should receive an error after clicking save button as customsAgent is empty`, async() => { it(`should receive an error after clicking save button as customsAgent is empty`, async() => {
@ -59,7 +59,7 @@ describe('Client Add address path', () => {
await page.waitToClick(selectors.clientAddresses.saveButton); await page.waitToClick(selectors.clientAddresses.saveButton);
const message = await page.waitForSnackbar(); const message = await page.waitForSnackbar();
expect(message.text).toContain('Customs agent is required for a non UEE member'); expect(message.text).toContain('Incoterms and Customs agent are required for a non UEE member');
}); });
it(`should create a new custom agent and then save the address`, async() => { it(`should create a new custom agent and then save the address`, async() => {

View File

@ -225,7 +225,7 @@ describe('Ticket Edit sale path', () => {
}); });
it('should show error trying to delete a ticket with a refund', async() => { it('should show error trying to delete a ticket with a refund', async() => {
await page.loginAndModule('production', 'ticket'); await page.loginAndModule('salesPerson', 'ticket');
await page.accessToSearchResult('8'); await page.accessToSearchResult('8');
await page.waitToClick(selectors.ticketDescriptor.moreMenu); await page.waitToClick(selectors.ticketDescriptor.moreMenu);
await page.waitToClick(selectors.ticketDescriptor.moreMenuDeleteTicket); await page.waitToClick(selectors.ticketDescriptor.moreMenuDeleteTicket);

View File

@ -69,3 +69,4 @@ Send cau: Enviar cau
By sending this ticket, all the data related to the error, the section, the user, etc., are already sent.: Al enviar este cau ya se envían todos los datos relacionados con el error, la sección, el usuario, etc By sending this ticket, all the data related to the error, the section, the user, etc., are already sent.: Al enviar este cau ya se envían todos los datos relacionados con el error, la sección, el usuario, etc
ExplainReason: Explique el motivo por el que no deberia aparecer este fallo ExplainReason: Explique el motivo por el que no deberia aparecer este fallo
You already have the mailAlias: Ya tienes este alias de correo You already have the mailAlias: Ya tienes este alias de correo
Error loading ACLs: Error al cargar los ACLs

View File

@ -7,16 +7,17 @@ import UserError from 'core/lib/user-error';
* @property {Boolean} loggedIn Whether the user is currently logged * @property {Boolean} loggedIn Whether the user is currently logged
*/ */
export default class Auth { export default class Auth {
constructor($http, $q, $state, $transitions, $window, vnToken, vnModules, aclService) { constructor($http, $q, vnApp, $translate, $state, $transitions, $window, vnToken, vnModules) {
Object.assign(this, { Object.assign(this, {
$http, $http,
$q, $q,
vnApp,
$translate,
$state, $state,
$transitions, $transitions,
$window, $window,
vnToken, vnToken,
vnModules, vnModules,
aclService,
loggedIn: false loggedIn: false
}); });
} }
@ -39,9 +40,26 @@ export default class Auth {
}; };
if (this.vnToken.token) { if (this.vnToken.token) {
return this.loadAcls() const loadWithRetry = () => {
return this.validateToken()
.then(() => true) .then(() => true)
.catch(redirectToLogin); .catch(err => {
switch (err.status) {
case 400:
case 401:
return redirectToLogin();
default:
return new Promise(resolve => {
setTimeout(() => {
this.vnApp.showMessage(this.$translate.instant('Loading...'));
resolve(loadWithRetry());
}, 2000);
});
}
});
};
return loadWithRetry();
} else } else
return redirectToLogin(); return redirectToLogin();
}); });
@ -87,13 +105,11 @@ export default class Auth {
headers: {Authorization: json.data.token} headers: {Authorization: json.data.token}
}).then(({data}) => { }).then(({data}) => {
this.vnToken.set(json.data.token, data.multimediaToken.id, now, json.data.ttl, remember); this.vnToken.set(json.data.token, data.multimediaToken.id, now, json.data.ttl, remember);
this.loadAcls().then(() => {
let continueHash = this.$state.params.continue; let continueHash = this.$state.params.continue;
if (continueHash) if (continueHash)
this.$window.location = continueHash; this.$window.location = continueHash;
else else
this.$state.go('home'); this.$state.go('home');
});
}).catch(() => {}); }).catch(() => {});
} }
@ -107,24 +123,25 @@ export default class Auth {
this.vnToken.unset(); this.vnToken.unset();
this.loggedIn = false; this.loggedIn = false;
this.vnModules.reset(); this.vnModules.reset();
this.aclService.reset(); this.vnModules.aclService.reset();
this.$state.go('login'); this.$state.go('login');
return promise; return promise;
} }
loadAcls() { validateToken() {
return this.aclService.load() return this.$http.get('VnUsers/validateToken')
.then(() => { .then(() => {
this.loggedIn = true; this.loggedIn = true;
this.vnModules.reset(); this.vnModules.reset();
}) })
.catch(err => { .catch(err => {
this.vnToken.unset();
throw err; throw err;
}); });
} }
} }
Auth.$inject = ['$http', '$q', '$state', '$transitions', '$window', 'vnToken', 'vnModules', 'aclService']; Auth.$inject = [
'$http', '$q', 'vnApp', '$translate', '$state',
'$transitions', '$window', 'vnToken', 'vnModules'];
ngModule.service('vnAuth', Auth); ngModule.service('vnAuth', Auth);

View File

@ -164,6 +164,7 @@ export default class UploadPhoto extends Component {
const options = { const options = {
type: 'blob', type: 'blob',
size: 'original'
}; };
return this.editor.result(options) return this.editor.result(options)
.then(blob => this.newPhoto.blob = blob) .then(blob => this.newPhoto.blob = blob)

View File

@ -12,7 +12,8 @@ function config($stateProvider, $urlRouterProvider) {
template: '<vn-layout></vn-layout>', template: '<vn-layout></vn-layout>',
resolve: { resolve: {
config: ['vnConfig', vnConfig => vnConfig.initialize()], config: ['vnConfig', vnConfig => vnConfig.initialize()],
token: ['vnToken', vnToken => vnToken.fetchConfig()] token: ['vnToken', vnToken => vnToken.fetchConfig()],
acl: ['aclService', aclService => aclService.load()]
} }
}) })
.state('outLayout', { .state('outLayout', {

View File

@ -1,4 +1,3 @@
module.exports = function(Self) { module.exports = function(Self) {
require('../methods/application/status')(Self); require('../methods/application/status')(Self);
require('../methods/application/post')(Self); require('../methods/application/post')(Self);

View File

@ -61,7 +61,8 @@
"Changed sale discount": "I have changed the following lines discounts from the ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}", "Changed sale discount": "I have changed the following lines discounts from the ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
"Created claim": "I have created the claim [{{claimId}}]({{{claimUrl}}}) for the following lines from the ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}", "Created claim": "I have created the claim [{{claimId}}]({{{claimUrl}}}) for the following lines from the ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
"Changed sale price": "I have changed the price of [{{itemId}} {{concept}}]({{{itemUrl}}}) ({{quantity}}) from {{oldPrice}}€ ➔ *{{newPrice}}€* of the ticket [{{ticketId}}]({{{ticketUrl}}})", "Changed sale price": "I have changed the price of [{{itemId}} {{concept}}]({{{itemUrl}}}) ({{quantity}}) from {{oldPrice}}€ ➔ *{{newPrice}}€* of the ticket [{{ticketId}}]({{{ticketUrl}}})",
"Changed sale quantity": "I have changed the quantity of [{{itemId}} {{concept}}]({{{itemUrl}}}) from {{oldQuantity}} ➔ *{{newQuantity}}* of the ticket [{{ticketId}}]({{{ticketUrl}}})", "Changed sale quantity": "I have changed {{changes}} of the ticket [{{ticketId}}]({{{ticketUrl}}})",
"Changes in sales": "the quantity of [{{itemId}} {{concept}}]({{{itemUrl}}}) from {{oldQuantity}} ➔ *{{newQuantity}}*",
"Changed sale reserved state": "I have changed the following lines reserved state from the ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}", "Changed sale reserved state": "I have changed the following lines reserved state from the ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
"Bought units from buy request": "Bought {{quantity}} units of [{{itemId}} {{concept}}]({{{urlItem}}}) for the ticket id [{{ticketId}}]({{{url}}})", "Bought units from buy request": "Bought {{quantity}} units of [{{itemId}} {{concept}}]({{{urlItem}}}) for the ticket id [{{ticketId}}]({{{url}}})",
"MESSAGE_INSURANCE_CHANGE": "I have changed the insurence credit of client [{{clientName}} ({{clientId}})]({{{url}}}) to *{{credit}} €*", "MESSAGE_INSURANCE_CHANGE": "I have changed the insurence credit of client [{{clientName}} ({{clientId}})]({{{url}}}) to *{{credit}} €*",
@ -228,6 +229,7 @@
"InvoiceIn is already booked": "InvoiceIn is already booked", "InvoiceIn is already booked": "InvoiceIn is already booked",
"This workCenter is already assigned to this agency": "This workCenter is already assigned to this agency", "This workCenter is already assigned to this agency": "This workCenter is already assigned to this agency",
"You can only have one PDA": "You can only have one PDA", "You can only have one PDA": "You can only have one PDA",
"Incoterms and Customs agent are required for a non UEE member": "Incoterms and Customs agent are required for a non UEE member",
"It has been invoiced but the PDF could not be generated": "It has been invoiced but the PDF could not be generated", "It has been invoiced but the PDF could not be generated": "It has been invoiced but the PDF could not be generated",
"It has been invoiced but the PDF of refund not be generated": "It has been invoiced but the PDF of refund not be generated" "It has been invoiced but the PDF of refund not be generated": "It has been invoiced but the PDF of refund not be generated"

View File

@ -124,7 +124,8 @@
"Changed sale discount": "He cambiado el descuento de las siguientes lineas al ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}", "Changed sale discount": "He cambiado el descuento de las siguientes lineas al ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
"Created claim": "He creado la reclamación [{{claimId}}]({{{claimUrl}}}) de las siguientes lineas del ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}", "Created claim": "He creado la reclamación [{{claimId}}]({{{claimUrl}}}) de las siguientes lineas del ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
"Changed sale price": "He cambiado el precio de [{{itemId}} {{concept}}]({{{itemUrl}}}) ({{quantity}}) de {{oldPrice}}€ ➔ *{{newPrice}}€* del ticket [{{ticketId}}]({{{ticketUrl}}})", "Changed sale price": "He cambiado el precio de [{{itemId}} {{concept}}]({{{itemUrl}}}) ({{quantity}}) de {{oldPrice}}€ ➔ *{{newPrice}}€* del ticket [{{ticketId}}]({{{ticketUrl}}})",
"Changed sale quantity": "He cambiado la cantidad de [{{itemId}} {{concept}}]({{{itemUrl}}}) de {{oldQuantity}} ➔ *{{newQuantity}}* del ticket [{{ticketId}}]({{{ticketUrl}}})", "Changed sale quantity": "He cambiado {{changes}} del ticket [{{ticketId}}]({{{ticketUrl}}})",
"Changes in sales": "la cantidad de [{{itemId}} {{concept}}]({{{itemUrl}}}) de {{oldQuantity}} ➔ *{{newQuantity}}*",
"State": "Estado", "State": "Estado",
"regular": "normal", "regular": "normal",
"reserved": "reservado", "reserved": "reservado",
@ -358,6 +359,8 @@
"Select ticket or client": "Elija un ticket o un client", "Select ticket or client": "Elija un ticket o un client",
"It was not able to create the invoice": "No se pudo crear la factura", "It was not able to create the invoice": "No se pudo crear la factura",
"ticketCommercial": "El ticket {{ ticket }} para el vendedor {{ salesMan }} está en preparación. (mensaje generado automáticamente)", "ticketCommercial": "El ticket {{ ticket }} para el vendedor {{ salesMan }} está en preparación. (mensaje generado automáticamente)",
"Incoterms and Customs agent are required for a non UEE member": "Se requieren Incoterms y agente de aduanas para un no miembro de la UEE",
"You can not use the same password": "No puedes usar la misma contraseña",
"This PDA is already assigned to another user": "Este PDA ya está asignado a otro usuario", "This PDA is already assigned to another user": "Este PDA ya está asignado a otro usuario",
"You can only have one PDA": "Solo puedes tener un PDA", "You can only have one PDA": "Solo puedes tener un PDA",
"It has been invoiced but the PDF could not be generated": "Se ha facturado pero no se ha podido generar el PDF", "It has been invoiced but the PDF could not be generated": "Se ha facturado pero no se ha podido generar el PDF",

View File

@ -123,8 +123,9 @@
"Added sale to ticket": "J'ai ajouté la ligne suivante au ticket [{{ticketId}}]({{{ticketUrl}}}): {{{addition}}}", "Added sale to ticket": "J'ai ajouté la ligne suivante au ticket [{{ticketId}}]({{{ticketUrl}}}): {{{addition}}}",
"Changed sale discount": "J'ai changé le rabais des lignes suivantes du ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}", "Changed sale discount": "J'ai changé le rabais des lignes suivantes du ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
"Created claim": "J'ai créé la réclamation [{{claimId}}]({{{claimUrl}}}) des lignes suivantes du ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}", "Created claim": "J'ai créé la réclamation [{{claimId}}]({{{claimUrl}}}) des lignes suivantes du ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
"Changed sale price": "J'ai changé le prix de [{{itemId}} {{concept}}]({{{itemUrl}}}) ({{quantity}}) de {{oldPrice}}€ ➔ *{{newPrice}}€* du ticket [{{ticketId}}]({{{ticketUrl}}})", "Changed sale price": " le prix de [{{itemId}} {{concept}}]({{{itemUrl}}}) ({{quantity}}) de {{oldPrice}}€ ➔ *{{newPrice}}€* du ticket [{{ticketId}}]({{{ticketUrl}}})",,
"Changed sale quantity": "J'ai changé la quantité de {{itemId}} {{concept}} de {{oldQuantity}} ➔ {{newQuantity}} du ticket [{{ticketId}}]({{{ticketUrl}}})", "Changed sale quantity": "J'ai changé {{changes}} du ticket [{{ticketId}}]({{{ticketUrl}}})",
"Changes in sales": "la quantité de {{itemId}} {{concept}} de {{oldQuantity}} ➔ {{newQuantity}}",
"State": "État", "State": "État",
"regular": "normal", "regular": "normal",
"reserved": "réservé", "reserved": "réservé",

View File

@ -124,7 +124,8 @@
"Changed sale discount": "Desconto da venda alterado no ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}", "Changed sale discount": "Desconto da venda alterado no ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
"Created claim": "Reclamação criada [{{claimId}}]({{{claimUrl}}}) no ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}", "Created claim": "Reclamação criada [{{claimId}}]({{{claimUrl}}}) no ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
"Changed sale price": "Preço da venda alterado para [{{itemId}} {{concept}}]({{{itemUrl}}}) ({{quantity}}) de {{oldPrice}}€ ➔ *{{newPrice}}€* no ticket [{{ticketId}}]({{{ticketUrl}}})", "Changed sale price": "Preço da venda alterado para [{{itemId}} {{concept}}]({{{itemUrl}}}) ({{quantity}}) de {{oldPrice}}€ ➔ *{{newPrice}}€* no ticket [{{ticketId}}]({{{ticketUrl}}})",
"Changed sale quantity": "Quantidade da venda alterada para [{{itemId}} {{concept}}]({{{itemUrl}}}) de {{oldQuantity}} ➔ *{{newQuantity}}* no ticket [{{ticketId}}]({{{ticketUrl}}})", "Changed sale quantity": "Quantidade da venda alterada para {{changes}} no ticket [{{ticketId}}]({{{ticketUrl}}})",
"Changes in sales": " [{{itemId}} {{concept}}]({{{itemUrl}}}) de {{oldQuantity}} ➔ *{{newQuantity}}* ",
"State": "Estado", "State": "Estado",
"regular": "normal", "regular": "normal",
"reserved": "reservado", "reserved": "reservado",

View File

@ -0,0 +1,3 @@
module.exports = (localAsProduction = true) => {
return (!process.env.NODE_ENV && localAsProduction) || process.env.NODE_ENV == 'production';
};

View File

@ -3,9 +3,10 @@ const app = require('vn-loopback/server/server');
const ldap = require('../util/ldapjs-extra'); const ldap = require('../util/ldapjs-extra');
const crypto = require('crypto'); const crypto = require('crypto');
const nthash = require('smbhash').nthash; const nthash = require('smbhash').nthash;
const isProduction = require('vn-loopback/server/boot/isProduction');
module.exports = Self => { module.exports = Self => {
const shouldSync = process.env.NODE_ENV !== 'test'; const shouldSync = isProduction();
Self.getLinker = async function() { Self.getLinker = async function() {
return await Self.findOne({ return await Self.findOne({

View File

@ -1,6 +1,7 @@
const ldap = require('../util/ldapjs-extra'); const ldap = require('../util/ldapjs-extra');
const execFile = require('child_process').execFile; const execFile = require('child_process').execFile;
const isProduction = require('vn-loopback/server/boot/isProduction');
/** /**
* Summary of userAccountControl flags: * Summary of userAccountControl flags:
@ -12,7 +13,7 @@ const UserAccountControlFlags = {
}; };
module.exports = Self => { module.exports = Self => {
const shouldSync = process.env.NODE_ENV !== 'test'; const shouldSync = isProduction();
Self.getLinker = async function() { Self.getLinker = async function() {
return await Self.findOne({ return await Self.findOne({

View File

@ -6,6 +6,7 @@ describe('claimBeginning', () => {
const claimManagerId = 72; const claimManagerId = 72;
const activeCtx = { const activeCtx = {
accessToken: {userId: claimManagerId}, accessToken: {userId: claimManagerId},
__: value => value
}; };
const ctx = {req: activeCtx}; const ctx = {req: activeCtx};

View File

@ -92,11 +92,8 @@ module.exports = function(Self) {
}, myOptions); }, myOptions);
const isUeeMember = province.country().isUeeMember; const isUeeMember = province.country().isUeeMember;
if (!isUeeMember && !args.incotermsFk) if (!isUeeMember && (!args.incotermsFk || !args.customsAgentFk))
throw new UserError(`Incoterms is required for a non UEE member`); throw new UserError(`Incoterms and Customs agent are required for a non UEE member`);
if (!isUeeMember && !args.customsAgentFk)
throw new UserError(`Customs agent is required for a non UEE member`);
delete args.ctx; // Remove unwanted properties delete args.ctx; // Remove unwanted properties
const newAddress = await models.Address.create(args, myOptions); const newAddress = await models.Address.create(args, myOptions);

View File

@ -50,7 +50,7 @@ describe('Address createAddress', () => {
} }
expect(error).toBeDefined(); expect(error).toBeDefined();
expect(error.message).toEqual('Incoterms is required for a non UEE member'); expect(error.message).toEqual('Incoterms and Customs agent are required for a non UEE member');
}); });
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() => {
@ -81,7 +81,7 @@ describe('Address createAddress', () => {
} }
expect(error).toBeDefined(); expect(error).toBeDefined();
expect(error.message).toEqual('Customs agent is required for a non UEE member'); expect(error.message).toEqual('Incoterms and Customs agent are required for a non UEE member');
}); });
it('should create a new address and set as a client default address', async() => { it('should create a new address and set as a client default address', async() => {

View File

@ -1,5 +1,6 @@
const got = require('got'); const got = require('got');
const UserError = require('vn-loopback/util/user-error'); const UserError = require('vn-loopback/util/user-error');
const isProduction = require('vn-loopback/server/boot/isProduction');
module.exports = Self => { module.exports = Self => {
Self.remoteMethod('send', { Self.remoteMethod('send', {
@ -47,7 +48,7 @@ module.exports = Self => {
let response; let response;
try { try {
if (process.env.NODE_ENV !== 'production') if (!isProduction(false))
response = {result: [{status: 'ok'}]}; response = {result: [{status: 'ok'}]};
else { else {
const jsonTest = { const jsonTest = {

View File

@ -76,6 +76,15 @@
}, },
"enlazadoSage": { "enlazadoSage": {
"type": "boolean" "type": "boolean"
},
"enlazado": {
"type": "boolean"
},
"key": {
"type": "number",
"mysql": {
"columnName": "CLAVE"
}
} }
}, },
"relations": { "relations": {

View File

@ -22,5 +22,8 @@
}, },
"EntryObservation": { "EntryObservation": {
"dataSource": "vn" "dataSource": "vn"
},
"EntryType": {
"dataSource": "vn"
} }
} }

View File

@ -0,0 +1,25 @@
{
"name": "EntryType",
"base": "VnModel",
"mixins": {
"Loggable": true
},
"options": {
"mysql": {
"table": "entryType"
}
},
"properties": {
"code": {
"type": "string",
"id": true,
"description": "Identifier"
},
"description": {
"type": "string"
},
"isInformal": {
"type": "boolean"
}
}
}

View File

@ -101,6 +101,11 @@
"type": "belongsTo", "type": "belongsTo",
"model": "Account", "model": "Account",
"foreignKey": "observationEditorFk" "foreignKey": "observationEditorFk"
},
"entryType": {
"type": "belongsTo",
"model": "EntryType",
"foreignKey": "typeFk"
} }
} }
} }

View File

@ -54,6 +54,20 @@ module.exports = Self => {
value: rate value: rate
}); });
} }
const monday = 1;
if (xmlDateWithoutTime.getDay() === monday) {
const saturday = new Date(xmlDateWithoutTime);
saturday.setDate(xmlDateWithoutTime.getDate() - 2);
const sunday = new Date(xmlDateWithoutTime);
sunday.setDate(xmlDateWithoutTime.getDate() - 1);
for (const date of [saturday, sunday]) {
await models.ReferenceRate.upsertWithWhere(
{currencyFk: currency.id, dated: date},
{currencyFk: currency.id, dated: date, value: rate}
);
}
}
} }
} }
} }

View File

@ -0,0 +1,32 @@
const models = require('vn-loopback/server/server').models;
describe('invoiceIn toUnbook()', () => {
it('should check that invoiceIn is unbooked', async() => {
const userId = 1;
const ctx = {
req: {
accessToken: {userId: userId},
headers: {origin: 'http://localhost:5000'},
}
};
const invoiceInId = 1;
const tx = await models.InvoiceIn.beginTransaction({});
const options = {transaction: tx};
try {
await models.InvoiceIn.toBook(ctx, invoiceInId, options);
const bookEntry = await models.InvoiceIn.toUnbook(ctx, invoiceInId, options);
const invoiceIn = await models.InvoiceIn.findById(invoiceInId, null, options);
expect(bookEntry.accountingEntries).toEqual(4);
expect(bookEntry.isLinked).toBeFalsy();
expect(invoiceIn.isBooked).toEqual(false);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -0,0 +1,80 @@
module.exports = Self => {
Self.remoteMethodCtx('toUnbook', {
description: 'To unbook the invoiceIn',
accessType: 'WRITE',
accepts: {
arg: 'id',
type: 'number',
required: true,
description: 'The invoiceIn id',
http: {source: 'path'}
},
returns: {
type: 'object',
root: true
},
http: {
path: '/:id/toUnbook',
verb: 'POST'
}
});
Self.toUnbook = async(ctx, invoiceInId, options) => {
let tx;
const models = Self.app.models;
const myOptions = {userId: ctx.req.accessToken.userId};
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
let isLinked;
let accountingEntries;
let bookEntry = await models.Xdiario.findOne({
fields: ['ASIEN'],
where: {
and: [
{key: invoiceInId},
{enlazado: false},
{enlazadoSage: false}
]
}
}, myOptions);
let asien = bookEntry?.ASIEN;
if (asien) {
accountingEntries = await models.Xdiario.count({ASIEN: asien}, myOptions);
await models.Xdiario.destroyAll({ASIEN: asien}, myOptions);
await Self.updateAll({id: invoiceInId}, {isBooked: false}, myOptions);
} else {
const linkedBookEntry = await models.Xdiario.findOne({
fields: ['ASIEN'],
where: {
key: invoiceInId,
and: [{or: [{enlazado: true, enlazadoSage: true}]}]
}
}, myOptions);
asien = linkedBookEntry?.ASIEN;
isLinked = true;
}
if (tx) await tx.commit();
return {
isLinked,
bookEntry: asien,
accountingEntries
};
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
};
};

View File

@ -0,0 +1,104 @@
module.exports = Self => {
Self.remoteMethodCtx('updateInvoiceIn', {
description: 'To update the invoiceIn attributes',
accessType: 'WRITE',
accepts: [{
arg: 'id',
type: 'number',
required: true,
description: 'The invoiceIn id',
http: {source: 'path'}
}, {
arg: 'supplierFk',
type: 'number',
required: true
}, {
arg: 'supplierRef',
type: 'any',
}, {
arg: 'issued',
type: 'any',
}, {
arg: 'operated',
type: 'any',
}, {
arg: 'deductibleExpenseFk',
type: 'any',
}, {
arg: 'dmsFk',
type: 'any',
}, {
arg: 'bookEntried',
type: 'any',
}, {
arg: 'booked',
type: 'any',
}, {
arg: 'currencyFk',
type: 'number',
required: true
}, {
arg: 'companyFk',
type: 'any',
}, {
arg: 'withholdingSageFk',
type: 'any',
},
],
returns: {
type: 'object',
root: true
},
http: {
path: '/:id/updateInvoiceIn',
verb: 'PATCH'
}
});
Self.updateInvoiceIn = async(ctx,
id,
supplierFk,
supplierRef,
issued,
operated,
deductibleExpenseFk,
dmsFk,
bookEntried,
booked,
currencyFk,
companyFk,
withholdingSageFk,
options
) => {
let tx;
const myOptions = {userId: ctx.req.accessToken.userId};
if (typeof options == 'object') Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const invoiceIn = await Self.findById(id, null, myOptions);
invoiceIn.updateAttributes({supplierFk,
supplierRef,
issued,
operated,
deductibleExpenseFk,
dmsFk,
bookEntried,
booked,
currencyFk,
companyFk,
withholdingSageFk
}, myOptions);
if (tx) await tx.commit();
return invoiceIn;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
};
};

View File

@ -11,6 +11,8 @@ module.exports = Self => {
require('../methods/invoice-in/getSerial')(Self); require('../methods/invoice-in/getSerial')(Self);
require('../methods/invoice-in/corrective')(Self); require('../methods/invoice-in/corrective')(Self);
require('../methods/invoice-in/exchangeRateUpdate')(Self); require('../methods/invoice-in/exchangeRateUpdate')(Self);
require('../methods/invoice-in/toUnbook')(Self);
require('../methods/invoice-in/updateInvoiceIn')(Self);
Self.rewriteDbError(function(err) { Self.rewriteDbError(function(err) {
if (err.code === 'ER_ROW_IS_REFERENCED_2' && err.sqlMessage.includes('vehicleInvoiceIn')) if (err.code === 'ER_ROW_IS_REFERENCED_2' && err.sqlMessage.includes('vehicleInvoiceIn'))

View File

@ -1,4 +1,4 @@
<mg-ajax path="InvoiceIns/{{patch.params.id}}" options="vnPatch"></mg-ajax> <mg-ajax path="InvoiceIns/{{patch.params.id}}/updateInvoiceIn" options="vnPatch"></mg-ajax>
<vn-watcher <vn-watcher
vn-id="watcher" vn-id="watcher"
data="$ctrl.invoiceIn" data="$ctrl.invoiceIn"

View File

@ -1,5 +1,6 @@
const fs = require('fs-extra'); const fs = require('fs-extra');
const path = require('path'); const path = require('path');
const isProduction = require('vn-loopback/server/boot/isProduction');
module.exports = Self => { module.exports = Self => {
Self.remoteMethodCtx('download', { Self.remoteMethodCtx('download', {
@ -66,7 +67,7 @@ module.exports = Self => {
console.error(err); console.error(err);
}); });
if (process.env.NODE_ENV == 'test') { if (!isProduction()) {
try { try {
await fs.access(file.path); await fs.access(file.path);
} catch (error) { } catch (error) {

View File

@ -1,6 +1,7 @@
const print = require('vn-print'); const print = require('vn-print');
const path = require('path'); const path = require('path');
const UserError = require('vn-loopback/util/user-error'); const UserError = require('vn-loopback/util/user-error');
const isProduction = require('vn-loopback/server/boot/isProduction');
module.exports = Self => { module.exports = Self => {
require('../methods/invoiceOut/filter')(Self); require('../methods/invoiceOut/filter')(Self);
@ -59,7 +60,7 @@ module.exports = Self => {
hasPdf: true hasPdf: true
}, options); }, options);
if (process.env.NODE_ENV !== 'test') { if (isProduction()) {
await print.storage.write(buffer, { await print.storage.write(buffer, {
type: 'invoice', type: 'invoice',
path: pdfFile.path, path: pdfFile.path,

View File

@ -27,7 +27,7 @@
<vn-autocomplete <vn-autocomplete
url="Tickets" url="Tickets"
label="Ticket" label="Ticket"
search-function="{or: [{id: $search}, {nickname: {like: '%'+$search+'%'}}]}" search-function="{refFk: null, or: [{id: $search}, {nickname: {like: '%'+$search+'%'}}]}"
show-field="id" show-field="id"
value-field="id" value-field="id"
fields="['nickname']" fields="['nickname']"

View File

@ -4,7 +4,7 @@ module.exports = Self => {
accessType: 'READ', accessType: 'READ',
accepts: [{ accepts: [{
arg: 'barcode', arg: 'barcode',
type: 'number', type: 'string',
required: true, required: true,
description: 'barcode' description: 'barcode'
}], }],
@ -18,7 +18,7 @@ module.exports = Self => {
} }
}); });
Self.toItem = async(barcode, options) => { Self.toItem = async (barcode, options) => {
const myOptions = {}; const myOptions = {};
if (typeof options == 'object') if (typeof options == 'object')

View File

@ -64,7 +64,7 @@ describe('item getBalance()', () => {
const secondItemBalance = await models.Item.getBalance(ctx, secondFilter, options); const secondItemBalance = await models.Item.getBalance(ctx, secondFilter, options);
expect(firstItemBalance[9].claimFk).toEqual(null); expect(firstItemBalance[9].claimFk).toEqual(null);
expect(secondItemBalance[4].claimFk).toEqual(2); expect(secondItemBalance[7].claimFk).toEqual(2);
await tx.rollback(); await tx.rollback();
} catch (e) { } catch (e) {

View File

@ -9,7 +9,7 @@
"properties": { "properties": {
"id": { "id": {
"id": true, "id": true,
"type": "number", "type": "string",
"description": "Identifier" "description": "Identifier"
}, },
"name": { "name": {

View File

@ -155,6 +155,9 @@
"minQuantity": { "minQuantity": {
"type": "number", "type": "number",
"description": "Min quantity" "description": "Min quantity"
},
"photoMotivation": {
"type": "string"
} }
}, },
"relations": { "relations": {

View File

@ -1,6 +1,7 @@
const fs = require('fs-extra'); const fs = require('fs-extra');
const path = require('path'); const path = require('path');
const UserError = require('vn-loopback/util/user-error'); const UserError = require('vn-loopback/util/user-error');
const isProduction = require('vn-loopback/server/boot/isProduction');
module.exports = Self => { module.exports = Self => {
Self.remoteMethodCtx('upload', { Self.remoteMethodCtx('upload', {
@ -111,7 +112,7 @@ module.exports = Self => {
const destinationFile = path.join( const destinationFile = path.join(
accessContainer.client.root, accessContainer.name, appName, `${toVersion}.7z`); accessContainer.client.root, accessContainer.name, appName, `${toVersion}.7z`);
if (process.env.NODE_ENV == 'test') if (!isProduction())
await fs.unlink(srcFile); await fs.unlink(srcFile);
else { else {
await fs.move(srcFile, destinationFile, { await fs.move(srcFile, destinationFile, {

View File

@ -151,7 +151,7 @@ describe('SalesMonitor salesFilter()', () => {
const result = await models.SalesMonitor.salesFilter(ctx, filter, options); const result = await models.SalesMonitor.salesFilter(ctx, filter, options);
const firstRow = result[0]; const firstRow = result[0];
expect(result.length).toEqual(12); expect(result.length).toEqual(15);
expect(firstRow.alertLevel).not.toEqual(0); expect(firstRow.alertLevel).not.toEqual(0);
await tx.rollback(); await tx.rollback();

View File

@ -11,6 +11,12 @@
"Sector": { "Sector": {
"dataSource": "vn" "dataSource": "vn"
}, },
"SectorCollection": {
"dataSource": "vn"
},
"SectorCollectionSaleGroup": {
"dataSource": "vn"
},
"Train": { "Train": {
"dataSource": "vn" "dataSource": "vn"
} }

View File

@ -0,0 +1,24 @@
{
"name": "SectorCollection",
"base": "VnModel",
"options": {
"mysql": {
"table": "sectorCollection"
}
},
"properties": {
"id": {
"type": "number",
"id": true
},
"created": {
"type": "date"
},
"userFk": {
"type": "number"
},
"sectorFk": {
"type": "number"
}
}
}

View File

@ -0,0 +1,30 @@
{
"name": "SectorCollectionSaleGroup",
"base": "VnModel",
"options": {
"mysql": {
"table": "sectorCollectionSaleGroup"
}
},
"properties": {
"id": {
"type": "number",
"id": true
},
"created": {
"type": "date"
}
},
"relations": {
"sectorCollection": {
"type": "belongsTo",
"model": "SectorCollection",
"foreignKey": "sectorCollectionFk"
},
"saleGroup": {
"type": "belongsTo",
"model": "SaleGroup",
"foreignKey": "saleGroupFk"
}
}
}

View File

@ -33,7 +33,7 @@ module.exports = Self => {
JOIN vn.item i ON i.id = b.itemFk JOIN vn.item i ON i.id = b.itemFk
WHERE e.id = ? AND e.supplierFk = ? WHERE e.id = ? AND e.supplierFk = ?
GROUP BY i.id GROUP BY i.id
) SELECT i.id, i.name, et.quantity, SUM(b.quantity) quantityTotal, et.printedStickers ) SELECT i.id, i.name, et.quantity, SUM(b.quantity) quantityTotal, et.printedStickers, ic.url
FROM vn.buy b FROM vn.buy b
JOIN vn.item i ON i.id = b.itemFk JOIN vn.item i ON i.id = b.itemFk
JOIN vn.entry e ON e.id = b.entryFk JOIN vn.entry e ON e.id = b.entryFk
@ -41,6 +41,7 @@ module.exports = Self => {
JOIN vn.buyConfig bc ON bc.monthsAgo JOIN vn.buyConfig bc ON bc.monthsAgo
JOIN vn.travel t ON t.id = e.travelFk JOIN vn.travel t ON t.id = e.travelFk
LEFT JOIN entryTmp et ON et.id = i.id LEFT JOIN entryTmp et ON et.id = i.id
JOIN hedera.imageConfig ic
WHERE e.supplierFk = ? WHERE e.supplierFk = ?
AND i.family IN ('EMB', 'CONT') AND i.family IN ('EMB', 'CONT')
AND b.created > (util.VN_CURDATE() - INTERVAL bc.monthsAgo MONTH) AND b.created > (util.VN_CURDATE() - INTERVAL bc.monthsAgo MONTH)

View File

@ -2,10 +2,12 @@ const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context'); const LoopBackContext = require('loopback-context');
describe('ticket setDelivered()', () => { describe('ticket setDelivered()', () => {
const userId = 50; const userId = 49;
const activeCtx = { const activeCtx = {
accessToken: {userId: userId}, accessToken: {userId: userId},
__: value => value
}; };
const ctx = {req: activeCtx};
beforeAll(async() => { beforeAll(async() => {
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
@ -19,8 +21,6 @@ describe('ticket setDelivered()', () => {
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
const ctx = {req: {accessToken: {userId: 49}}};
const originalTicketOne = await models.Ticket.findById(8, null, options); const originalTicketOne = await models.Ticket.findById(8, null, options);
const originalTicketTwo = await models.Ticket.findById(10, null, options); const originalTicketTwo = await models.Ticket.findById(10, null, options);

View File

@ -10,8 +10,8 @@ module.exports = Self => {
http: {source: 'path'} http: {source: 'path'}
}, },
{ {
arg: 'itemId', arg: 'barcode',
type: 'number', type: 'any',
required: true required: true
}, },
{ {
@ -29,7 +29,7 @@ module.exports = Self => {
} }
}); });
Self.addSale = async(ctx, id, itemId, quantity, options) => { Self.addSale = async(ctx, id, barcode, quantity, options) => {
const $t = ctx.req.__; // $translate const $t = ctx.req.__; // $translate
const models = Self.app.models; const models = Self.app.models;
const myOptions = {userId: ctx.req.accessToken.userId}; const myOptions = {userId: ctx.req.accessToken.userId};
@ -46,7 +46,9 @@ module.exports = Self => {
try { try {
await models.Ticket.isEditableOrThrow(ctx, id, myOptions); await models.Ticket.isEditableOrThrow(ctx, id, myOptions);
const itemId = await models.ItemBarcode.toItem(barcode, myOptions);
const item = await models.Item.findById(itemId, null, myOptions); const item = await models.Item.findById(itemId, null, myOptions);
const ticket = await models.Ticket.findById(id, { const ticket = await models.Ticket.findById(id, {
include: { include: {
relation: 'client', relation: 'client',

View File

@ -1,56 +0,0 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethodCtx('addSaleByCode', {
description: 'Add a collection',
accessType: 'WRITE',
accepts: [
{
arg: 'barcode',
type: 'string',
required: true
}, {
arg: 'quantity',
type: 'number',
required: true
}, {
arg: 'ticketFk',
type: 'number',
required: true
}, {
arg: 'warehouseFk',
type: 'number',
required: true
},
],
http: {
path: `/addSaleByCode`,
verb: 'POST'
},
});
Self.addSaleByCode = async(ctx, barcode, quantity, ticketFk, warehouseFk, options) => {
const myOptions = {userId: ctx.req.accessToken.userId};
let tx;
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const [[item]] = await Self.rawSql('CALL vn.item_getInfo(?,?)', [barcode, warehouseFk], myOptions);
if (!item?.available) throw new UserError('We do not have availability for the selected item');
await Self.rawSql('CALL vn.collection_addItem(?, ?, ?)', [item.id, quantity, ticketFk], myOptions);
if (tx) await tx.commit();
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
};
};

View File

@ -8,18 +8,13 @@ module.exports = Self => {
if (typeof options == 'object') if (typeof options == 'object')
Object.assign(myOptions, options); Object.assign(myOptions, options);
const state = await models.TicketState.findOne({ const state = await models.TicketState.findOne({where: {ticketFk: id}}, myOptions);
where: {ticketFk: id}
}, myOptions);
const isRoleAdvanced = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'isRoleAdvanced', '*'); const isRoleAdvanced = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'isRoleAdvanced', '*');
const isProductionReviewer = await models.ACL.checkAccessAcl(ctx, 'Sale', 'isInPreparing', '*');
const canEditWeeklyTicket = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'canEditWeekly', 'WRITE'); const canEditWeeklyTicket = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'canEditWeekly', 'WRITE');
const alertLevel = state ? state.alertLevel : null; const alertLevel = state ? state.alertLevel : null;
const ticket = await models.Ticket.findById(id, { const ticket = await models.Ticket.findById(id, {
fields: ['clientFk'], fields: ['clientFk'], include: {relation: 'client'}
include: {
relation: 'client'
}
}, myOptions); }, myOptions);
const isLocked = await models.Ticket.isLocked(id, myOptions); const isLocked = await models.Ticket.isLocked(id, myOptions);
@ -29,10 +24,24 @@ module.exports = Self => {
const isNormalClient = ticket && ticket.client().typeFk == 'normal'; const isNormalClient = ticket && ticket.client().typeFk == 'normal';
const isEditable = !(alertLevelGreaterThanZero && isNormalClient); const isEditable = !(alertLevelGreaterThanZero && isNormalClient);
const ticketCollection = await models.TicketCollection.findOne({
include: {relation: 'collection'}, where: {ticketFk: id}
}, myOptions);
let isOwner = ticketCollection?.collection()?.workerFk === ctx.req.accessToken.userId;
if (!isOwner) {
const saleGroup = await models.SaleGroup.findOne({fields: ['id'], where: {ticketFk: id}}, myOptions);
const sectorCollectionSaleGroup = saleGroup && await models.SectorCollectionSaleGroup.findOne({
include: {relation: 'sectorCollection'}, where: {saleGroupFk: saleGroup.id}
}, myOptions);
isOwner = sectorCollectionSaleGroup?.sectorCollection()?.userFk === ctx.req.accessToken.userId;
}
if (!ticket) if (!ticket)
throw new ForbiddenError(`The ticket doesn't exist.`); throw new ForbiddenError(`The ticket doesn't exist.`);
if (!isEditable && !isRoleAdvanced) if (!isEditable && !isRoleAdvanced && !isProductionReviewer && !isOwner)
throw new ForbiddenError(`This ticket is not editable.`); throw new ForbiddenError(`This ticket is not editable.`);
if (isLocked && !isWeekly) if (isLocked && !isWeekly)

View File

@ -1,39 +0,0 @@
const {models} = require('vn-loopback/server/server');
const LoopBackContext = require('loopback-context');
describe('Ticket addSaleByCode()', () => {
const quantity = 3;
const ticketFk = 13;
const warehouseFk = 1;
beforeAll(async() => {
activeCtx = {
req: {
accessToken: {userId: 9},
headers: {origin: 'http://localhost'},
__: value => value
}
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
it('should add a new sale', async() => {
const tx = await models.Ticket.beginTransaction({});
try {
const options = {transaction: tx};
const code = '1111111111';
const salesBefore = await models.Sale.find(null, options);
await models.Ticket.addSaleByCode(activeCtx, code, quantity, ticketFk, warehouseFk, options);
const salesAfter = await models.Sale.find(null, options);
expect(salesAfter.length).toEqual(salesBefore.length + 1);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -68,7 +68,7 @@ describe('ticket filter()', () => {
const filter = {}; const filter = {};
const result = await models.Ticket.filter(ctx, filter, options); const result = await models.Ticket.filter(ctx, filter, options);
expect(result.length).toEqual(7); expect(result.length).toEqual(10);
await tx.rollback(); await tx.rollback();
} catch (e) { } catch (e) {

View File

@ -42,7 +42,7 @@ describe('sale priceDifference()', () => {
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
const ctx = {req: {accessToken: {userId: 1106}}}; const ctx = {req: {accessToken: {userId: 1105}}};
ctx.args = { ctx.args = {
id: 1, id: 1,
landed: Date.vnNew(), landed: Date.vnNew(),
@ -84,7 +84,7 @@ describe('sale priceDifference()', () => {
const {items} = await models.Ticket.priceDifference(ctx, options); const {items} = await models.Ticket.priceDifference(ctx, options);
expect(items[0].movable).toEqual(410); expect(items[0].movable).toEqual(386);
expect(items[1].movable).toEqual(1810); expect(items[1].movable).toEqual(1810);
await tx.rollback(); await tx.rollback();

View File

@ -7,6 +7,7 @@ describe('ticket state()', () => {
const productionId = 49; const productionId = 49;
const activeCtx = { const activeCtx = {
accessToken: {userId: 9}, accessToken: {userId: 9},
__: value => value
}; };
const ctx = {req: activeCtx}; const ctx = {req: activeCtx};
const now = Date.vnNew(); const now = Date.vnNew();
@ -88,7 +89,8 @@ describe('ticket state()', () => {
const ticket = await models.Ticket.create(sampleTicket, options); const ticket = await models.Ticket.create(sampleTicket, options);
activeCtx.accessToken.userId = productionId; activeCtx.accessToken.userId = productionId;
const params = {ticketFk: ticket.id, stateFk: 3}; const stateOk = await models.State.findOne({where: {code: 'OK'}}, options);
const params = {ticketFk: ticket.id, stateFk: stateOk.id};
const ticketTracking = await models.Ticket.state(ctx, params, options); const ticketTracking = await models.Ticket.state(ctx, params, options);
@ -112,16 +114,68 @@ describe('ticket state()', () => {
const options = {transaction: tx}; const options = {transaction: tx};
const ticket = await models.Ticket.create(sampleTicket, options); const ticket = await models.Ticket.create(sampleTicket, options);
const ctx = {req: {accessToken: {userId: 18}}}; activeCtx.accessToken.userId = salesPersonId;
const assignedState = await models.State.findOne({where: {code: 'PICKER_DESIGNED'}}, options); const assignedState = await models.State.findOne({where: {code: 'PICKER_DESIGNED'}}, options);
const params = {ticketFk: ticket.id, stateFk: assignedState.id, userFk: 1}; const paramsAssigned = {ticketFk: ticket.id, stateFk: assignedState.id, userFk: 1};
const res = await models.Ticket.state(ctx, params, options); const resAssigned = await models.Ticket.state(ctx, paramsAssigned, options);
expect(res.ticketFk).toBe(params.ticketFk); expect(resAssigned.ticketFk).toBe(paramsAssigned.ticketFk);
expect(res.stateFk).toBe(params.stateFk); expect(resAssigned.stateFk).toBe(paramsAssigned.stateFk);
expect(res.userFk).toBe(params.userFk); expect(resAssigned.userFk).toBe(paramsAssigned.userFk);
expect(res.userFk).toBe(1); expect(resAssigned.userFk).toBe(1);
expect(res.id).toBeDefined(); expect(resAssigned.id).toBeDefined();
activeCtx.accessToken.userId = productionId;
const packedState = await models.State.findOne({where: {code: 'PACKED'}}, options);
const paramsPacked = {ticketFk: ticket.id, stateFk: packedState.id, userFk: salesPersonId};
const resPacked = await models.Ticket.state(ctx, paramsPacked, options);
expect(resPacked.stateFk).toBe(paramsPacked.stateFk);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('Should equalize the quantities of quantity and originalQuantity' +
' if they are different', async() => {
const tx = await models.TicketTracking.beginTransaction({});
try {
const options = {transaction: tx};
const ticket = await models.Ticket.create(sampleTicket, options);
activeCtx.accessToken.userId = salesPersonId;
const sampleSale = {
ticketFk: ticket.id,
itemFk: 1,
concept: 'Test',
quantity: 10,
originalQuantity: 6
};
await models.Sale.create(sampleSale, options);
const assignedState = await models.State.findOne({where: {code: 'PICKER_DESIGNED'}}, options);
const paramsAssigned = {ticketFk: ticket.id, stateFk: assignedState.id, userFk: 1};
const resAssigned = await models.Ticket.state(ctx, paramsAssigned, options);
expect(resAssigned.ticketFk).toBe(paramsAssigned.ticketFk);
expect(resAssigned.stateFk).toBe(paramsAssigned.stateFk);
expect(resAssigned.userFk).toBe(paramsAssigned.userFk);
expect(resAssigned.userFk).toBe(1);
expect(resAssigned.id).toBeDefined();
activeCtx.accessToken.userId = productionId;
const packedState = await models.State.findOne({where: {code: 'PACKED'}}, options);
const paramsPacked = {ticketFk: ticket.id, stateFk: packedState.id, userFk: salesPersonId};
const resPacked = await models.Ticket.state(ctx, paramsPacked, options);
const sale = await models.Sale.findOne({where: {ticketFk: ticket.id}}, options);
expect(resPacked.stateFk).toBe(paramsPacked.stateFk);
expect(sale.quantity).toBe(sale.originalQuantity);
await tx.rollback(); await tx.rollback();
} catch (e) { } catch (e) {

Some files were not shown because too many files have changed in this diff Show More