Merge branch 'dev' into 5834-billingDataAutoFillBic
gitea/salix/pipeline/pr-dev This commit looks good Details

This commit is contained in:
Javier Segarra 2024-02-06 17:33:27 +01:00
commit 4d6e631fca
98 changed files with 18229 additions and 51300 deletions

View File

@ -13,7 +13,7 @@ RUN apt-get update \
graphicsmagick \
&& curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \
&& npm install -g npm@9.6.6
&& corepack enable pnpm
# Puppeteer
@ -39,12 +39,12 @@ RUN apt-get update \
WORKDIR /salix
COPY print/package.json print/package-lock.json print/
RUN npm ci --no-audit --prefer-offline --omit=dev --prefix=print
COPY print/package.json print/pnpm-lock.yaml print/
RUN pnpm install --prod --prefix=print
COPY package.json package-lock.json ./
COPY package.json pnpm-lock.yaml ./
COPY loopback/package.json loopback/
RUN npm ci --no-audit --prefer-offline --omit=dev
RUN pnpm install --prod
COPY loopback loopback
COPY back back

186
Jenkinsfile vendored
View File

@ -3,34 +3,46 @@
def PROTECTED_BRANCH
def FROM_GIT
def RUN_TESTS
def RUN_BUILD
pre: {
switch (env.BRANCH_NAME) {
case 'test':
env.NODE_ENV = 'test'
env.BACK_REPLICAS = 2
break
case 'master':
env.NODE_ENV = 'production'
env.BACK_REPLICAS = 4
break
default:
env.NODE_ENV = 'dev'
env.BACK_REPLICAS = 1
node {
stage('Setup') {
env.NODE_ENV = 'dev'
PROTECTED_BRANCH = [
'dev',
'test',
'master'
].contains(env.BRANCH_NAME)
FROM_GIT = env.JOB_NAME.startsWith('gitea/')
RUN_TESTS = !PROTECTED_BRANCH && FROM_GIT
RUN_BUILD = PROTECTED_BRANCH && FROM_GIT
// https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#using-environment-variables
echo "NODE_NAME: ${env.NODE_NAME}"
echo "WORKSPACE: ${env.WORKSPACE}"
configFileProvider([
configFile(fileId: 'salix.properties',
variable: 'PROPS_FILE')
]) {
def props = readProperties file: PROPS_FILE
props.each {key, value -> env."${key}" = value }
props.each {key, value -> echo "${key}: ${value}" }
}
if (PROTECTED_BRANCH) {
configFileProvider([
configFile(fileId: "salix.branch.${env.BRANCH_NAME}",
variable: 'BRANCH_PROPS_FILE')
]) {
def props = readProperties file: BRANCH_PROPS_FILE
props.each {key, value -> env."${key}" = value }
props.each {key, value -> echo "${key}: ${value}" }
}
}
}
PROTECTED_BRANCH = [
'dev',
'test',
'master'
].contains(env.BRANCH_NAME)
FROM_GIT = env.JOB_NAME.startsWith('gitea/')
RUN_TESTS = !PROTECTED_BRANCH && FROM_GIT
// Uncomment to enable debugging
// https://loopback.io/doc/en/lb3/Setting-debug-strings.html#debug-strings-reference
//env.DEBUG = 'strong-remoting:shared-method'
}
pipeline {
agent any
@ -47,20 +59,12 @@ pipeline {
stages {
stage('Install') {
environment {
NODE_ENV = ""
NODE_ENV = ''
}
parallel {
stage('Backend') {
stage('Back') {
steps {
sh 'npm install --no-audit --prefer-offline'
}
}
stage('Frontend') {
when {
expression { FROM_GIT }
}
steps {
sh 'npm install --no-audit --prefer-offline --prefix=front'
sh 'pnpm install --prefer-offline'
}
}
stage('Print') {
@ -68,35 +72,99 @@ pipeline {
expression { FROM_GIT }
}
steps {
sh 'npm install --no-audit --prefer-offline --prefix=print'
sh 'pnpm install --prefer-offline --prefix=print'
}
}
stage('Front') {
when {
expression { FROM_GIT }
}
steps {
sh 'pnpm install --prefer-offline --prefix=front'
}
}
}
}
stage('Test') {
when {
expression { RUN_TESTS }
}
stage('Stack') {
environment {
NODE_ENV = ""
TZ = 'Europe/Madrid'
}
parallel {
stage('Backend') {
steps {
sh 'npm run test:back:ci'
stage('Back') {
stages {
stage('Test') {
when {
expression { RUN_TESTS }
}
environment {
NODE_ENV = ''
}
steps {
sh 'npm run test:back:ci'
}
post {
always {
script {
try {
junit 'junitresults.xml'
junit 'junit.xml'
} catch (e) {
echo e.toString()
}
}
}
}
}
stage('Build') {
when {
expression { RUN_BUILD }
}
steps {
script {
def packageJson = readJSON file: 'package.json'
env.VERSION = packageJson.version
}
sh 'docker-compose build back'
}
}
}
}
stage('Frontend') {
steps {
sh 'jest --ci --reporters=default --reporters=jest-junit --maxWorkers=6'
stage('Front') {
when {
expression { FROM_GIT }
}
stages {
stage('Test') {
when {
expression { RUN_TESTS }
}
environment {
NODE_ENV = ''
}
steps {
sh 'jest --ci --reporters=default --reporters=jest-junit --maxWorkers=10'
}
}
stage('Build') {
when {
expression { RUN_BUILD }
}
steps {
script {
def packageJson = readJSON file: 'package.json'
env.VERSION = packageJson.version
}
sh 'gulp build'
sh 'docker-compose build front'
}
}
}
}
}
}
stage('Build') {
stage('Push') {
when {
expression { PROTECTED_BRANCH && FROM_GIT }
expression { RUN_BUILD }
}
environment {
CREDENTIALS = credentials('docker-registry')
@ -106,8 +174,8 @@ pipeline {
def packageJson = readJSON file: 'package.json'
env.VERSION = packageJson.version
}
sh 'gulp build'
dockerBuild()
sh 'docker login --username $CREDENTIALS_USR --password $CREDENTIALS_PSW $REGISTRY'
sh 'docker-compose push'
}
}
stage('Deploy') {
@ -147,18 +215,6 @@ pipeline {
}
}
post {
always {
script {
if (RUN_TESTS) {
try {
junit 'junitresults.xml'
junit 'junit.xml'
} catch (e) {
echo e.toString()
}
}
}
}
success {
script {
if (env.BRANCH_NAME == 'master' && FROM_GIT) {

34
back/tests-helper.js Normal file
View File

@ -0,0 +1,34 @@
/* eslint-disable no-console */
const app = require('vn-loopback/server/server');
let dataSources = require('../loopback/server/datasources.json');
async function init() {
console.log('Initializing backend.');
dataSources = JSON.parse(JSON.stringify(dataSources));
Object.assign(dataSources.vn, {
host: process.env.DB_HOST,
port: process.env.DB_PORT
});
const bootOptions = {dataSources};
await new Promise((resolve, reject) => {
app.boot(bootOptions,
err => err ? reject(err) : resolve());
});
// FIXME: Workaround to wait for loopback to be ready
await app.models.Application.status();
}
async function deinit() {
console.log('Stopping backend.');
await app.disconnect();
}
module.exports = {
init,
deinit
};
if (require.main === module)
init();

View File

@ -2,30 +2,21 @@
const path = require('path');
const Myt = require('@verdnatura/myt/myt');
const Run = require('@verdnatura/myt/myt-run');
let dataSources = require('../loopback/server/datasources.json');
const helper = require('./tests-helper');
let server;
const isCI = process.argv[2] === 'ci';
const PARALLEL = false;
const TIMEOUT = 900000;
process.on('warning', warning => {
console.log(warning.name);
console.log(warning.message);
console.log(warning.stack);
});
process.on('SIGINT', teardown);
process.on('exit', teardown);
process.on('uncaughtException', onError);
process.on('unhandledRejection', onError);
process.on('SIGUSR2', rmServer);
process.on('exit', rmServer);
async function rmServer() {
if (!server) return;
await server.rm();
server = null;
}
async function test() {
async function setup() {
console.log('Building and running DB container.');
const isCI = process.argv[2] === 'ci';
const myt = new Myt();
await myt.init({
workspace: path.join(__dirname, '..'),
@ -36,69 +27,76 @@ async function test() {
});
server = await myt.run(Run);
await myt.deinit();
const {dbConfig} = server;
process.env.DB_HOST = dbConfig.host;
process.env.DB_PORT = dbConfig.port;
console.log('Initializing backend.');
if (!PARALLEL)
await helper.init();
}
dataSources = JSON.parse(JSON.stringify(dataSources));
Object.assign(dataSources.vn, {
host: dbConfig.host,
port: dbConfig.port
});
async function teardown() {
if (!server) return;
const bootOptions = {dataSources};
const app = require('vn-loopback/server/server');
await new Promise((resolve, reject) => {
app.boot(bootOptions,
err => err ? reject(err) : resolve());
});
// FIXME: Workaround to wait for loopback to be ready
await app.models.Application.status();
if (!PARALLEL)
await helper.deinit();
console.log('Running tests.');
console.log('Stopping and removing DB container.');
await server.rm();
server = null;
}
const Jasmine = require('jasmine');
const jasmine = new Jasmine();
async function onError(err) {
await teardown();
console.error(err);
}
const SpecReporter = require('jasmine-spec-reporter').SpecReporter;
jasmine.addReporter(new SpecReporter({
spec: {
displaySuccessful: isCI,
displayPending: isCI
},
summary: {
displayPending: false,
}
}));
async function test() {
let runner;
const config = {
globalSetup: setup,
globalSetupTimeout: TIMEOUT,
globalTeardown: teardown,
globalTeardownTimeout: TIMEOUT,
spec_dir: '.',
spec_files: [
'back/**/*[sS]pec.js',
'loopback/**/*[sS]pec.js',
'modules/*/back/**/*.[sS]pec.js'
],
helpers: []
};
if (PARALLEL) {
const ParallelRunner = require('jasmine/parallel');
runner = new ParallelRunner({numWorkers: 1});
config.helpers.push(`back/tests-helper.js`);
} else {
const Jasmine = require('jasmine');
runner = new Jasmine();
const SpecReporter = require('jasmine-spec-reporter').SpecReporter;
runner.addReporter(new SpecReporter({
spec: {
displaySuccessful: isCI,
displayPending: isCI
},
summary: {
displayPending: false,
}
}));
}
if (isCI) {
const JunitReporter = require('jasmine-reporters');
jasmine.addReporter(new JunitReporter.JUnitXmlReporter());
jasmine.exitOnCompletion = true;
jasmine.jasmine.DEFAULT_TIMEOUT_INTERVAL = 900000;
runner.addReporter(new JunitReporter.JUnitXmlReporter());
runner.jasmine.DEFAULT_TIMEOUT_INTERVAL = TIMEOUT;
}
const backSpecs = [
'./back/**/*[sS]pec.js',
'./loopback/**/*[sS]pec.js',
'./modules/*/back/**/*.[sS]pec.js'
];
jasmine.loadConfig({
spec_dir: '.',
spec_files: backSpecs,
helpers: [],
});
await jasmine.execute();
console.log('Stopping.');
if (app) await app.disconnect();
await rmServer();
console.log('Tests ended.\n');
// runner.loadConfigFile('back/jasmine.json');
runner.loadConfig(config);
await runner.execute();
}
test();

View File

@ -73,9 +73,10 @@ INSERT INTO vn.cmr (id, truckPlate, observations, senderInstruccions, paymentIns
UPDATE `vn`.`claimRatio` SET `claimAmount` = '10' WHERE (`clientFk` = '1101');
INSERT INTO `vn`.`agency` (`name`, `warehouseFk`, `warehouseAliasFk`, `isOwn`, `isAnyVolumeAllowed`) VALUES
('Agencia', '1', '1', '1', '1'),
('Otra agencia ', '1', '2', '0', '0');
INSERT INTO `vn`.`agency` (`name`, `warehouseFk`, `isOwn`, `isAnyVolumeAllowed`)
VALUES
('Agencia', '1', '1', '1'),
('Otra agencia ', '1', '0', '0');
INSERT INTO `vn`.`expedition` (`agencyModeFk`, `ticketFk`, `isBox`, `counter`, `workerFk`, `externalId`, `packagingFk`, `hostFk`, `itemPackingTypeFk`, `hasNewRoute`) VALUES
('1', '1', 1, '1', '1', '1', '1', 'pc00', 'F', 0),

View File

@ -174,20 +174,15 @@ INSERT INTO `vn`.`country`(`id`, `country`, `isUeeMember`, `code`, `currencyFk`,
(19,'Francia', 1, 'FR', 1, 27, 4, 0, 1),
(30,'Canarias', 1, 'IC', 1, 24, 4, 1, 2);
INSERT INTO `vn`.`warehouseAlias`(`id`, `name`)
INSERT INTO `vn`.`warehouse`(`id`, `name`, `code`, `isComparative`, `isInventory`, `hasAvailable`, `isManaged`, `hasDms`, `hasComission`, `countryFk`, `hasProduction`, `isOrigin`, `isDestiny`)
VALUES
(1, 'Main Warehouse'),
(2, 'Gotham');
INSERT INTO `vn`.`warehouse`(`id`, `name`, `code`, `isComparative`, `isInventory`, `hasAvailable`, `isManaged`, `hasDms`, `hasComission`, `aliasFk`, `countryFk`, `hasProduction`)
VALUES
(1, 'Warehouse One', 'ALG', 1, 1, 1, 1, 1, 1, 2, 1, 1),
(2, 'Warehouse Two', NULL, 1, 1, 1, 1, 0, 1, 2, 13, 1),
(3, 'Warehouse Three', NULL, 1, 1, 1, 1, 0, 0, 2, 1, 1),
(4, 'Warehouse Four', NULL, 1, 1, 1, 1, 0, 0, 2, 1, 1),
(5, 'Warehouse Five', NULL, 1, 1, 1, 1, 0, 0, 2, 1, 1),
(13, 'Inventory', 'inv', 1, 1, 1, 0, 0, 0, 2, 1, 0),
(60, 'Algemesi', NULL, 1, 1, 1, 0, 0, 0, 2, 1, 0);
(1, 'Warehouse One', 'ALG', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
(2, 'Warehouse Two', NULL, 1, 1, 1, 1, 0, 1, 13, 1, 1, 0),
(3, 'Warehouse Three', NULL, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0),
(4, 'Warehouse Four', NULL, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1),
(5, 'Warehouse Five', NULL, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0),
(13, 'Inventory', 'inv', 1, 1, 1, 0, 0, 0, 1, 0, 0, 0),
(60, 'Algemesi', NULL, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0);
INSERT INTO `vn`.`sectorType` (id,description)
VALUES (1,'First type');
@ -271,18 +266,18 @@ INSERT INTO `vn`.`deliveryMethod`(`id`, `code`, `description`)
(3, 'PICKUP', 'Recogida'),
(4, 'OTHER', 'Otros');
INSERT INTO `vn`.`agency`(`id`, `name`, `warehouseFk`, `warehouseAliasFk`)
INSERT INTO `vn`.`agency`(`id`, `name`, `warehouseFk`)
VALUES
(1, 'inhouse pickup' , 1, 1),
(2, 'Super-Man delivery' , 1, 1),
(3, 'Teleportation device' , 1, 1),
(4, 'Entanglement' , 1, 1),
(5, 'Quantum break device' , 1, 1),
(6, 'Walking' , 1, 1),
(7, 'Gotham247' , 1, 1),
(8, 'Gotham247Expensive' , 1, 1),
(9, 'Refund' , 1, 1),
(10, 'Other agency' , 1, 1);
(1, 'inhouse pickup' , 1),
(2, 'Super-Man delivery' , 1),
(3, 'Teleportation device' , 1),
(4, 'Entanglement' , 1),
(5, 'Quantum break device' , 1),
(6, 'Walking' , 1),
(7, 'Gotham247' , 1),
(8, 'Gotham247Expensive' , 1),
(9, 'Refund' , 1),
(10, 'Other agency' , 1);
UPDATE `vn`.`agencyMode` SET `id` = 1 WHERE `name` = 'inhouse pickup';
UPDATE `vn`.`agencyMode` SET `id` = 2 WHERE `name` = 'Super-Man delivery';
@ -569,13 +564,13 @@ INSERT INTO `vn`.`supplierActivity`(`code`, `name`)
INSERT INTO `vn`.`supplier`(`id`, `name`, `nickname`,`account`,`countryFk`,`nif`, `commission`, `created`, `isActive`, `street`, `city`, `provinceFk`, `postCode`, `payMethodFk`, `payDemFk`, `payDay`, `taxTypeSageFk`, `withholdingSageFk`, `transactionTypeSageFk`, `workerFk`, `supplierActivityFk`, `isPayMethodChecked`, `healthRegister`)
VALUES
(1, 'Plants SL', 'Plants nick', 4100000001, 1, '06089160W', 0, util.VN_CURDATE(), 1, 'supplier address 1', 'PONTEVEDRA', 1, 15214, 1, 1, 15, 4, 1, 1, 18, 'flowerPlants', 1, '400664487V'),
(2, 'Farmer King', 'The farmer', 4000020002, 1, '87945234L', 0, util.VN_CURDATE(), 1, 'supplier address 2', 'GOTHAM', 2, 43022, 1, 2, 10, 93, 2, 8, 18, 'animals', 1, '400664487V'),
(69, 'Packaging', 'Packaging nick', 4100000069, 1, '94935005K', 0, util.VN_CURDATE(), 1, 'supplier address 5', 'ASGARD', 3, 46600, 1, 1, 15, 4, 1, 1, 18, 'flowerPlants', 1, '400664487V'),
(442, 'Verdnatura Levante SL', 'Verdnatura', 5115000442, 1, '06815934E', 0, util.VN_CURDATE(), 1, 'supplier address 3', 'GOTHAM', 1, 43022, 1, 2, 15, 6, 9, 3, 18, 'complements', 1, '400664487V'),
(567, 'Holland', 'Holland nick', 4000020567, 1, '14364089Z', 0, util.VN_CURDATE(), 1, 'supplier address 6', 'ASGARD', 3, 46600, 1, 2, 10, 93, 2, 8, 18, 'animals', 1, '400664487V'),
(791, 'Bros SL', 'Bros nick', 5115000791, 1, '37718083S', 0, util.VN_CURDATE(), 1, 'supplier address 7', 'ASGARD', 3, 46600, 1, 2, 15, 6, 9, 3, 18, 'complements', 1, '400664487V'),
(1381, 'Ornamentales', 'Ornamentales', 7185001381, 1, '07972486L', 0, util.VN_CURDATE(), 1, 'supplier address 4', 'GOTHAM', 1, 43022, 1, 2, 15, 6, 9, 3, 18, 'complements', 1, '400664487V');
(1, 'PLANTS SL', 'Plants nick', 4100000001, 1, '06089160W', 0, util.VN_CURDATE(), 1, 'supplier address 1', 'PONTEVEDRA', 1, 15214, 1, 1, 15, 4, 1, 1, 18, 'flowerPlants', 1, '400664487V'),
(2, 'FARMER KING', 'The farmer', 4000020002, 1, '87945234L', 0, util.VN_CURDATE(), 1, 'supplier address 2', 'GOTHAM', 2, 43022, 1, 2, 10, 93, 2, 8, 18, 'animals', 1, '400664487V'),
(69, 'PACKAGING', 'Packaging nick', 4100000069, 1, '94935005K', 0, util.VN_CURDATE(), 1, 'supplier address 5', 'ASGARD', 3, 46600, 1, 1, 15, 4, 1, 1, 18, 'flowerPlants', 1, '400664487V'),
(442, 'VERDNATURA LEVANTE SL', 'Verdnatura', 5115000442, 1, '06815934E', 0, util.VN_CURDATE(), 1, 'supplier address 3', 'GOTHAM', 1, 43022, 1, 2, 15, 6, 9, 3, 18, 'complements', 1, '400664487V'),
(567, 'HOLLAND', 'Holland nick', 4000020567, 1, '14364089Z', 0, util.VN_CURDATE(), 1, 'supplier address 6', 'ASGARD', 3, 46600, 1, 2, 10, 93, 2, 8, 18, 'animals', 1, '400664487V'),
(791, 'BROS SL', 'Bros nick', 5115000791, 1, '37718083S', 0, util.VN_CURDATE(), 1, 'supplier address 7', 'ASGARD', 3, 46600, 1, 2, 15, 6, 9, 3, 18, 'complements', 1, '400664487V'),
(1381, 'ORNAMENTALES', 'Ornamentales', 7185001381, 1, '07972486L', 0, util.VN_CURDATE(), 1, 'supplier address 4', 'GOTHAM', 1, 43022, 1, 2, 15, 6, 9, 3, 18, 'complements', 1, '400664487V');
INSERT INTO `vn`.`supplierAddress`(`id`, `supplierFk`, `nickname`, `street`, `provinceFk`, `postalCode`, `city`, `phone`, `mobile`)
VALUES

View File

@ -20,16 +20,16 @@ BEGIN
c.movil,
c.POBLACION poblacion,
p.`name` provincia,
vn2008.red(f.futur) futur,
ROUND(f.futur, 2) futur,
c.Credito credito,
pm.`name` forma_pago,
vn2008.red(c365 / 12) consumo_medio365,
vn2008.red(c365) consumo365,
vn2008.red(CmLy.peso) peso_mes_año_pasado,
vn2008.red(CmLy.peso * 1.19) objetivo,
ROUND(c365 / 12, 2) consumo_medio365,
ROUND(c365, 2) consumo365,
ROUND(CmLy.peso, 2) peso_mes_año_pasado,
ROUND(CmLy.peso * 1.19, 2) objetivo,
tr.CodigoTrabajador,
vn2008.red(mes_actual.consumo) consumoMes,
vn2008.red(IFNULL(mes_actual.consumo, 0) - IFNULL(CmLy.peso * 1.19, 0)) como_lo_llevo,
ROUND(mes_actual.consumo, 2) consumoMes,
ROUND(IFNULL(mes_actual.consumo, 0) - IFNULL(CmLy.peso * 1.19, 0), 2) como_lo_llevo,
DATE(LastTicket) ultimo_ticket,
dead.muerto,
g.Greuge,

View File

@ -5,7 +5,8 @@ proc: BEGIN
DECLARE vReserveDate DATETIME;
DECLARE vParams CHAR(100);
DECLARE vInventoryDate DATE;
DECLARE vIsLogifloraDay BOOLEAN;
DECLARE vLifeScope DATE;
DECLARE vWarehouseFkInventory INT;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
@ -26,43 +27,42 @@ proc: BEGIN
LEAVE proc;
END IF;
-- Invoca al procedimiento que genera el stock virtual de Logiflora, si coincide con la peticion de refresco del disponible
IF vn.isLogifloraDay(vDated, vWarehouse) THEN
-- CALL edi.floramondo_offerRefresh;
SET vIsLogifloraDay = TRUE;
ELSE
SET vIsLogifloraDay = FALSE;
END IF;
-- Calcula algunos parámetros necesarios
SET vStartDate = TIMESTAMP(vDated, '00:00:00');
SELECT inventoried INTO vInventoryDate FROM vn.config;
SELECT DATE_SUB(vStartDate, INTERVAL MAX(life) DAY) INTO vLifeScope FROM vn.itemType;
SELECT SUBTIME(util.VN_NOW(), reserveTime) INTO vReserveDate
FROM hedera.orderConfig;
SELECT w.id INTO vWarehouseFkInventory
FROM vn.warehouse w
WHERE w.code = 'inv';
-- Calcula el ultimo dia de vida para cada producto
DROP TEMPORARY TABLE IF EXISTS itemRange;
CREATE TEMPORARY TABLE itemRange
(PRIMARY KEY (itemFk))
ENGINE = MEMORY
SELECT c.itemFk,
IF(it.life IS NULL,
NULL,
TIMESTAMP(TIMESTAMPADD(DAY, it.life, c.landing), '23:59:59')) ended
FROM (
SELECT b.itemFk, MAX(t.landed) landing
FROM vn.buy b
JOIN vn.entry e ON b.entryFk = e.id
JOIN vn.travel t ON t.id = e.travelFk
JOIN vn.warehouse w ON w.id = t.warehouseInFk
WHERE t.landed BETWEEN vInventoryDate AND vStartDate
AND t.warehouseInFk = vWarehouse
AND NOT e.isExcludedFromAvailable
GROUP BY b.itemFk
) c
JOIN vn.item i ON i.id = c.itemFk
SELECT i.id itemFk,
util.dayEnd(DATE_ADD(c.maxLanded, INTERVAL it.life DAY)) ended, it.life
FROM vn.item i
LEFT JOIN (
SELECT b.itemFk, MAX(t.landed) maxLanded
FROM vn.buy b
JOIN vn.entry e ON b.entryFk = e.id
JOIN vn.travel t ON t.id = e.travelFk
JOIN vn.warehouse w ON w.id = t.warehouseInFk
JOIN vn.item i ON i.id = b.itemFk
JOIN vn.itemType it ON it.id = i.typeFk
WHERE t.landed BETWEEN vLifeScope AND vStartDate
AND t.warehouseInFk = vWarehouse
AND t.warehouseOutFk <> vWarehouseFkInventory
AND it.life
AND NOT e.isExcludedFromAvailable
GROUP BY b.itemFk
) c ON i.id = c.itemFk
JOIN vn.itemType it ON it.id = i.typeFk
HAVING ended >= vStartDate OR ended IS NULL;
HAVING ended >= vStartDate OR life IS NULL;
-- Calcula el ATP
DELETE FROM available WHERE calc_id = vCalc;
@ -86,7 +86,7 @@ proc: BEGIN
WHERE i.landed >= vStartDate
AND (ir.ended IS NULL OR i.landed <= ir.ended)
AND i.warehouseInFk = vWarehouse
AND (ISNULL(wf.entryFk) OR vIsLogifloraDay)
AND ISNULL(wf.entryFk)
UNION ALL
SELECT i.itemFk, i.shipped, i.quantity
FROM vn.itemEntryOut i

View File

@ -0,0 +1,32 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` FUNCTION `vn`.`intrastat_estimateNet`(
vSelf INT,
vStems INT
)
RETURNS double
DETERMINISTIC
BEGIN
/**
* Calcula un valor neto estimado en función de
* datos históricos de facturas intrastat.
*
* @param vSelf Id de intrastat
* @param vStems Número de unidades
* @return vNet
*/
DECLARE vNet DOUBLE;
SELECT ROUND(vStems / (SUM(average) / COUNT(average)), 2) INTO vNet
FROM (
SELECT *, stems / net average
FROM invoiceInIntrastat
WHERE intrastatFk = vSelf
AND net
AND stems > 0
ORDER BY dated DESC
LIMIT 20
) sub;
RETURN vNet/2;
END$$
DELIMITER ;

View File

@ -1,79 +0,0 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`fustControl`(vFromDated DATE, vToDated DATE)
BEGIN
DECLARE vSijsnerClientFk INT DEFAULT 19752;
DECLARE vDateStart DATETIME;
DECLARE vDateEnd DATETIME;
SET vDateStart = vFromDated;
SET vDateEnd = util.Dayend(vToDated);
SELECT p.id FustCode,
CAST(sent.stucks AS DECIMAL(10,0)) FH,
CAST(tp.stucks AS DECIMAL(10,0)) Tickets,
CAST(-sj.stucks AS DECIMAL(10,0)) Sijsner,
CAST(IFNULL(sent.stucks,0) - IFNULL(tp.stucks,0) + IFNULL(sj.stucks,0) AS DECIMAL(10,0)) saldo
FROM vn.packaging p
LEFT JOIN (
SELECT FustCode, sum(fustQuantity) stucks
FROM (
SELECT IFNULL(pe.equivalentFk ,b.packagingFk) FustCode, s.quantity / b.packing AS fustQuantity
FROM vn.sale s
JOIN vn.ticket t ON t.id = s.ticketFk
JOIN vn.warehouse w ON w.id = t.warehouseFk
JOIN vn.warehouseAlias wa ON wa.id = w.aliasFk
JOIN cache.last_buy lb ON lb.item_id = s.itemFk AND lb.warehouse_id = t.warehouseFk
JOIN vn.buy b ON b.id = lb.buy_id
JOIN vn.packaging p ON p.id = b.packagingFk
LEFT JOIN vn.packageEquivalent pe ON pe.packagingFk = p.id
JOIN vn.address a ON a.id = t.addressFk
JOIN vn.province p2 ON p2.id = a.provinceFk
JOIN vn.country c ON c.id = p2.countryFk
WHERE t.shipped BETWEEN vDateStart AND vDateEnd
AND wa.name = 'VNH'
AND p.isPackageReturnable
AND c.country = 'FRANCIA') sub
GROUP BY FustCode) sent ON sent.FustCode = p.id
LEFT JOIN (
SELECT FustCode, sum(quantity) stucks
FROM (
SELECT IFNULL(pe.equivalentFk ,tp.packagingFk) FustCode, tp.quantity
FROM vn.ticketPackaging tp
JOIN vn.ticket t ON t.id = tp.ticketFk
JOIN vn.warehouse w ON w.id = t.warehouseFk
JOIN vn.warehouseAlias wa ON wa.id = w.aliasFk
JOIN vn.packaging p ON p.id = tp.packagingFk
LEFT JOIN vn.packageEquivalent pe ON pe.packagingFk = p.id
JOIN vn.address a ON a.id = t.addressFk
JOIN vn.province p2 ON p2.id = a.provinceFk
JOIN vn.country c ON c.id = p2.countryFk
WHERE t.shipped BETWEEN vDateStart AND vDateEnd
AND wa.name = 'VNH'
AND p.isPackageReturnable
AND c.country = 'FRANCIA'
AND t.clientFk != vSijsnerClientFk
AND tp.quantity > 0) sub
GROUP BY FustCode) tp ON tp.FustCode = p.id
LEFT JOIN (
SELECT FustCode, sum(quantity) stucks
FROM (
SELECT IFNULL(pe.equivalentFk ,tp.packagingFk) FustCode, tp.quantity
FROM vn.ticketPackaging tp
JOIN vn.ticket t ON t.id = tp.ticketFk
JOIN vn.warehouse w ON w.id = t.warehouseFk
JOIN vn.warehouseAlias wa ON wa.id = w.aliasFk
JOIN vn.packaging p ON p.id = tp.packagingFk
LEFT JOIN vn.packageEquivalent pe ON pe.packagingFk = p.id
WHERE t.shipped BETWEEN TIMESTAMPADD(DAY, 1, vDateStart ) AND TIMESTAMPADD(DAY, 1, vDateEnd )
AND wa.name = 'VNH'
AND p.isPackageReturnable
AND t.clientFk = vSijsnerClientFk) sub
GROUP BY FustCode) sj ON sj.FustCode = p.id
WHERE sent.stucks
OR tp.stucks
OR sj.stucks;
END$$
DELIMITER ;

View File

@ -1,36 +0,0 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`fustControlDetail`(vFromDated DATE, vToDated DATE)
BEGIN
DECLARE vSijsnerClientFk INT DEFAULT 19752;
DECLARE vDateStart DATETIME;
DECLARE vDateEnd DATETIME;
SET vDateStart = vFromDated;
SET vDateEnd = util.Dayend(vToDated);
SELECT a.nickname shopName,
a.city ,
IFNULL(pe.equivalentFk ,tp.packagingFk) FustCode,
tp.quantity,
tp.ticketFk,
CONCAT('From ', vFromDated,' to ', vToDated) AS dateRange
FROM vn.ticketPackaging tp
JOIN vn.ticket t ON t.id = tp.ticketFk
JOIN vn.warehouse w ON w.id = t.warehouseFk
JOIN vn.warehouseAlias wa ON wa.id = w.aliasFk
JOIN vn.packaging p ON p.id = tp.packagingFk
LEFT JOIN vn.packageEquivalent pe ON pe.packagingFk = p.id
JOIN vn.address a ON a.id = t.addressFk
JOIN vn.province p2 ON p2.id = a.provinceFk
JOIN vn.country c ON c.id = p2.countryFk
WHERE t.shipped BETWEEN vFromDated AND util.dayend(vToDated)
AND wa.name = 'VNH'
AND p.isPackageReturnable
AND c.country = 'FRANCIA'
AND t.clientFk != vSijsnerClientFk
AND tp.quantity > 0;
END$$
DELIMITER ;

View File

@ -0,0 +1,234 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `sage`.`invoiceIn_add`(vInvoiceInFk INT, vXDiarioFk INT)
BEGIN
/**
* Traslada la info de contabilidad relacionada con las facturas recibidas
*
* @vInvoiceInFk Factura recibida
* @vXDiarioFk Id tabla XDiario
*/
DECLARE vInvoiceInOriginalFk INT;
DECLARE vDone BOOL DEFAULT FALSE;
DECLARE vBase DOUBLE;
DECLARE vVat DOUBLE;
DECLARE vRate DOUBLE;
DECLARE vTransactionCode INT;
DECLARE vCounter INT DEFAULT 0;
DECLARE vTransactionCodeOld INT;
DECLARE vTaxCode INT;
DECLARE vTaxCodeOld INT;
DECLARE vOperationCode VARCHAR(1);
DECLARE vIsIntracommunity BOOL DEFAULT FALSE;
DECLARE vSerialDua VARCHAR(1) DEFAULT 'D';
DECLARE vInvoiceTypeReceived VARCHAR(1);
DECLARE vInvoiceTypeInformative VARCHAR(1);
DECLARE vIsInformativeExportation BOOL DEFAULT FALSE;
DECLARE vCursor CURSOR FOR
SELECT it.taxableBase,
CAST((( it.taxableBase / 100) * t.PorcentajeIva) AS DECIMAL (10,2)),
t.PorcentajeIva,
it.transactionTypeSageFk,
it.taxTypeSageFk,
tty.isIntracommunity,
tt.ClaveOperacionDefecto
FROM vn.invoiceIn i
JOIN vn.invoiceInTax it ON it.InvoiceInFk = i.id
JOIN TiposIva t ON t.CodigoIva = it.taxTypeSageFk
JOIN taxType tty ON tty.id = t.CodigoIva
JOIN TiposTransacciones tt ON tt.CodigoTransaccion = it.transactionTypeSageFk
LEFT JOIN vn.dua d ON d.id = vInvoiceInFk
WHERE i.id = vInvoiceInFk
AND d.id IS NULL;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
DELETE FROM movContaIVA
WHERE id = vXDiarioFk;
SELECT codeSage INTO vInvoiceTypeReceived
FROM invoiceType WHERE code ='received';
SELECT codeSage INTO vInvoiceTypeInformative
FROM invoiceType WHERE code ='informative';
INSERT INTO movContaIVA(id, LibreA1)
VALUES (vXDiarioFk, vInvoiceInFk);
OPEN vCursor;
l: LOOP
FETCH vCursor INTO vBase,
vVat,
vRate,
vTransactionCode,
vTaxCode,
vIsIntracommunity,
vOperationCode;
IF vDone THEN
LEAVE l;
END IF;
SET vTransactionCodeOld = vTransactionCode;
SET vTaxCodeOld = vTaxCode;
IF vOperationCode IS NOT NULL THEN
UPDATE movContaIVA
SET ClaveOperacionFactura = vOperationCode
WHERE id = vXDiarioFk;
END IF;
SET vCounter = vCounter + 1;
CASE vCounter
WHEN 1 THEN
UPDATE movContaIVA
SET BaseIva1 = vBase,
PorIva1 = vRate,
CuotaIva1 = vVat,
CodigoTransaccion1 = vTransactionCode,
CodigoIva1 = vTaxCode
WHERE id = vXDiarioFk;
WHEN 2 THEN
UPDATE movContaIVA
SET BaseIva2 = vBase,
PorIva2 = vRate,
CuotaIva2 = vVat,
CodigoTransaccion2 = vTransactionCode,
CodigoIva2 = vTaxCode
WHERE id = vXDiarioFk;
WHEN 3 THEN
UPDATE movContaIVA
SET BaseIva3 = vBase,
PorIva3 = vRate,
CuotaIva3 = vVat,
CodigoTransaccion3 = vTransactionCode,
CodigoIva3 = vTaxCode
WHERE id = vXDiarioFk;
WHEN 4 THEN
UPDATE movContaIVA
SET BaseIva4 = vBase,
PorIva4 = vRate,
CuotaIva4 = vVat,
CodigoTransaccion4 = vTransactionCode,
CodigoIva4 = vTaxCode
WHERE id = vXDiarioFk;
ELSE
SELECT vXDiarioFk INTO vXDiarioFk;
END CASE;
IF vIsIntracommunity THEN
UPDATE movContaIVA
SET Intracomunitaria = TRUE
WHERE id = vXDiarioFk;
END IF;
SET vTransactionCodeOld = vTransactionCode;
SET vTaxCodeOld = vTaxCode;
END LOOP;
CLOSE vCursor;
SELECT d.ASIEN AND x.ASIEN IS NULL INTO vIsInformativeExportation
FROM vn.dua d
LEFT JOIN vn.XDiario x ON x.ASIEN = d.ASIEN
AND x.SERIE = vSerialDua COLLATE utf8mb3_unicode_ci
WHERE d.ASIEN = (
SELECT ASIEN
FROM vn.XDiario
WHERE id = vXDiarioFk)
LIMIT 1;
UPDATE movContaIVA mci
JOIN tmp.invoiceIn ii ON ii.id = vInvoiceInFk
JOIN vn.XDiario x ON x.id = mci.id
LEFT JOIN tmp.invoiceDua id ON id.id = mci.id
JOIN vn.supplier s ON s.id = ii.supplierFk
JOIN Naciones n ON n.countryFk = s.countryFk
SET mci.CodigoDivisa = ii.currencyFk,
mci.Año = YEAR(ii.issued),
mci.Serie = ii.serial,
mci.Factura = ii.id,
mci.FechaFactura = ii.issued,
mci.ImporteFactura = IFNULL(mci.BaseIva1, 0) + IFNULL(mci.CuotaIva1, 0) +
IFNULL(mci.BaseIva2, 0) + IFNULL(mci.CuotaIva2, 0) +
IFNULL(mci.BaseIva3, 0) + IFNULL(mci.CuotaIva3, 0) +
IFNULL(mci.BaseIva4, 0) + IFNULL(mci.CuotaIva4, 0),
mci.TipoFactura = IF(id.id,
IF( ii.serial = vSerialDua COLLATE utf8mb3_unicode_ci, vInvoiceTypeReceived, vInvoiceTypeInformative),
IF(vIsInformativeExportation,vInvoiceTypeInformative, vInvoiceTypeReceived)),
mci.CodigoCuentaFactura = x.SUBCTA,
mci.CifDni = IF(LEFT(TRIM(s.nif), 2) = n.SiglaNacion, SUBSTRING(TRIM(s.nif), 3), s.nif),
mci.Nombre = s.name,
mci.SiglaNacion = n.SiglaNacion,
mci.EjercicioFactura = YEAR(ii.issued),
mci.FechaOperacion = ii.issued,
mci.MantenerAsiento = TRUE,
mci.SuFacturaNo = ii.supplierRef,
mci.IvaDeducible1 = IF(id.id, FALSE, IF(IFNULL(mci.BaseIva1, FALSE) = FALSE, FALSE, ii.isVatDeductible)),
mci.IvaDeducible2 = IF(id.id, FALSE, IF(IFNULL(mci.BaseIva2, FALSE) = FALSE, FALSE, ii.isVatDeductible)),
mci.IvaDeducible3 = IF(id.id, FALSE, IF(IFNULL(mci.BaseIva3, FALSE) = FALSE, FALSE, ii.isVatDeductible)),
mci.IvaDeducible4 = IF(id.id, FALSE, IF(IFNULL(mci.BaseIva4, FALSE) = FALSE, FALSE, ii.isVatDeductible)),
mci.FechaFacturaOriginal = x.FECHA_EX
WHERE mci.id = vXDiarioFk;
-- RETENCIONES
UPDATE movContaIVA mci
JOIN vn.invoiceIn ii ON ii.id = vInvoiceInFk
JOIN vn.XDiario x ON x.id = mci.id
JOIN vn.supplier s ON s.id = supplierFk
JOIN vn.invoiceInTax iit ON iit.invoiceInFk = ii.id
JOIN vn.expense e ON e.id = iit.expenseFk
JOIN TiposRetencion t ON t.CodigoRetencion = ii.withholdingSageFk
LEFT JOIN tmp.invoiceDua id ON id.id = mci.id
JOIN (SELECT SUM(x2.BASEEURO) taxableBase, SUM(x2.EURODEBE) taxBase
FROM vn.XDiario x1
JOIN vn.XDiario x2 ON x1.ASIEN = x2.ASIEN
WHERE x2.BASEEURO <> 0
AND x1.id = vXDiarioFk
)sub
JOIN ClavesOperacion co ON co.Descripcion = 'Arrendamiento de locales de negocio'
SET mci.CodigoRetencion = t.CodigoRetencion,
mci.ClaveOperacionFactura = IF( t.Retencion = 'ARRENDAMIENTO Y SUBARRENDAMIENTO', co.ClaveOperacionFactura_, mci.ClaveOperacionFactura),
mci.BaseRetencion = IF (t.Retencion = 'ACTIVIDADES AGRICOLAS O GANADERAS', sub.taxableBase + sub.taxBase, sub.taxableBase),
mci.PorRetencion = t.PorcentajeRetencion,
mci.ImporteRetencion = iit.taxableBase * - 1
WHERE mci.id = vXDiarioFk
AND e.name = 'Retenciones'
AND id.id IS NULL;
SELECT correctedFk INTO vInvoiceInOriginalFk
FROM vn.invoiceInCorrection
WHERE correctingFk = vInvoiceInFk;
IF vInvoiceInOriginalFk THEN
UPDATE movContaIVA mci
JOIN vn.invoiceInRefund iir ON iir.invoiceInRefundFk = vInvoiceInFk
JOIN (SELECT issued,
SUM(sub.taxableBase) taxableBase,
SUM(ROUND((sub.taxableBase * sub.PorcentajeIva) / 100 , 2)) vat
FROM(SELECT issued,
SUM(iit.taxableBase) taxableBase,
ti.PorcentajeIva
FROM vn.invoiceIn i
JOIN vn.invoiceInTax iit ON iit.invoiceInFk = i.id
JOIN sage.TiposIva ti ON ti.CodigoIva = iit.taxTypeSageFk
WHERE i.id = vInvoiceInOriginalFk
GROUP BY ti.CodigoIva)sub
)invoiceInOriginal
JOIN ClavesOperacion co ON co.Descripcion = 'Factura rectificativa'
SET mci.TipoRectificativa = iir.refundCategoryFk,
mci.ClaseAbonoRectificativas = iir.refundType,
mci.FechaFacturaOriginal = invoiceInOriginal.issued,
mci.FechaOperacion = invoiceInOriginal.issued,
mci.BaseImponibleOriginal = invoiceInOriginal.taxableBase,
mci.CuotaIvaOriginal = invoiceInOriginal.vat,
mci.ClaveOperacionFactura = co.ClaveOperacionFactura_
WHERE mci.id = vXDiarioFk;
END IF;
END$$
DELIMITER ;

View File

@ -8,27 +8,22 @@ BEGIN
* @param vItemFk Identificador de vn.item
* @param vSectorFk Identificador de vn.sector
*/
DECLARE vWarehouseAliasFk INT;
SELECT w.aliasFk INTO vWarehouseAliasFk
FROM vn.sector s
JOIN vn.warehouse w ON w.id = s.warehouseFk
WHERE s.id = vSectorFk;
SELECT ish.shelvingFk shelving,
p.code parking,
sum(ish.visible) as stockTotal,
ish.created,
p.pickingOrder
p.code parking,
SUM(ish.visible) stockTotal,
ish.created,
p.pickingOrder
FROM vn.itemShelving ish
JOIN vn.shelving sh ON sh.code = ish.shelvingFk
JOIN vn.parking p ON p.id = sh.parkingFk
JOIN vn.sector sc ON sc.id = p.sectorFk
JOIN vn.warehouse w ON w.id = sc.warehouseFk
WHERE w.aliasFk = vWarehouseAliasFk
AND ish.visible > 0
AND ish.itemFk = vItemFk
WHERE sc.id = vSectorFk
AND ish.visible > 0
AND ish.itemFk = vItemFk
GROUP BY ish.id
ORDER BY (sc.id = vSectorFk) DESC, sh.priority DESC, ish.created, p.pickingOrder;
ORDER BY sh.priority DESC,
ish.created,
p.pickingOrder;
END$$
DELIMITER ;

View File

@ -1,7 +1,13 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`itemShelvingRadar`(vSectorFk INT)
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`itemShelvingRadar`(
vSectorFk INT
)
proc:BEGIN
/**
* Calcula la información detallada respecto un sector.
*
* @param vSectorFk Id de sector
*/
DECLARE vCalcVisibleFk INT;
DECLARE vCalcAvailableFk INT;
DECLARE hasFatherSector BOOLEAN;

View File

@ -1,12 +0,0 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`warehouse_afterUpdate`
AFTER UPDATE ON `warehouse`
FOR EACH ROW
BEGIN
IF NEW.isFeedStock IS TRUE AND OLD.isFeedStock IS FALSE THEN
INSERT IGNORE INTO warehouseAlias(`name`) VALUES(NEW.`name`);
INSERT IGNORE INTO warehouseJoined(warehouseFk, warehouseAliasFk)
VALUES(NEW.id,LAST_INSERT_ID());
END IF;
END$$
DELIMITER ;

View File

@ -1,7 +1,7 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn`.`itemShelvingAvailable`
AS SELECT `s`.`id` AS `saleFk`,
AS SELECT `s`.`id` `saleFk`,
`tst`.`updated` AS `Modificado`,
`s`.`ticketFk` AS `ticketFk`,
0 AS `isPicked`,
@ -38,7 +38,7 @@ FROM (
)
JOIN `vn`.`agencyMode` `am` ON(`am`.`id` = `t`.`agencyModeFk`)
)
JOIN `vn`.`ticketStateToday` `tst` ON(`tst`.`ticket` = `t`.`id`)
JOIN `vn`.`ticketStateToday` `tst` ON(`tst`.`ticketFk` = `t`.`id`)
)
JOIN `vn`.`state` `st` ON(`st`.`id` = `tst`.`state`)
)

View File

@ -1,16 +1,15 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn`.`ticketStateToday`
AS SELECT `ts`.`ticketFk` AS `ticket`,
AS SELECT
`ts`.`ticketFk` AS `ticketFk`,
`ts`.`state` AS `state`,
`ts`.`productionOrder` AS `productionOrder`,
`ts`.`alertLevel` AS `alertLevel`,
`ts`.`userFk` AS `worker`,
`ts`.`userFk` AS `userFk`,
`ts`.`code` AS `code`,
`ts`.`updated` AS `updated`,
`ts`.`isPicked` AS `isPicked`
FROM (
`vn`.`ticketState` `ts`
JOIN `vn`.`ticket` `t` ON(`t`.`id` = `ts`.`ticketFk`)
)
WHERE `t`.`shipped` BETWEEN `util`.`VN_CURDATE`() AND `MIDNIGHT`(`util`.`VN_CURDATE`())
FROM `ticketState` `ts`
JOIN `ticket` `t` ON `t`.`id` = `ts`.`ticketFk`
WHERE `t`.`shipped` BETWEEN `util`.`VN_CURDATE`() AND `MIDNIGHT`(`util`.`VN_CURDATE`());

View File

@ -1,6 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn`.`warehouseJoined`
AS SELECT `wj`.`warehouse_id` AS `warehouseFk`,
`wj`.`warehouse_alias_id` AS `warehouseAliasFk`
FROM `vn2008`.`warehouse_joined` `wj`

View File

@ -9,12 +9,11 @@ CREATE OR REPLACE DEFINER=`root`@`localhost`
lhp.m3,
dl.minSpeed
FROM ticket t
JOIN ticketStateToday tst ON tst.ticket = t.id
JOIN ticketStateToday tst ON tst.ticketFk = t.id
JOIN state s ON s.id = tst.state
JOIN saleVolume sv ON sv.ticketFk = t.id
LEFT JOIN lastHourProduction lhp ON lhp.warehouseFk = t.warehouseFk
JOIN warehouse w ON w.id = t.warehouseFk
JOIN warehouseAlias wa ON wa.id = w.aliasFk
STRAIGHT_JOIN `zone` z ON z.id = t.zoneFk
LEFT JOIN zoneClosure zc ON zc.zoneFk = t.zoneFk
AND zc.dated = util.VN_CURDATE()

View File

@ -1,20 +0,0 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` FUNCTION `vn2008`.`intrastat_neto`(intINSTRASTAT INTEGER,intUNIDADES INTEGER)
RETURNS double
DETERMINISTIC
BEGIN
DECLARE n DOUBLE;
SELECT ROUND(intUNIDADES / (SUM(MEDIA) / COUNT(media)), 2) INTO n FROM
(SELECT *, unidades / neto MEDIA
FROM intrastat_data
WHERE intrastat_id = intINSTRASTAT AND neto
AND unidades > 0
ORDER BY odbc_date DESC
LIMIT 20) t;
-- JGF 01/06 per a evitar Kg en negatiu
RETURN n/2;
END$$
DELIMITER ;

View File

@ -1,14 +0,0 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` FUNCTION `vn2008`.`red`(intCANTIDAD DOUBLE)
RETURNS double
DETERMINISTIC
BEGIN
DECLARE n DOUBLE;
SET n = SIGN(intCANTIDAD) * TRUNCATE( (ABS(intCANTIDAD) * 100) + 0.5001 ,0) /100 ;
RETURN n;
END$$
DELIMITER ;

View File

@ -1,82 +0,0 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn2008`.`desglose_volume`(IN vAgencyFk INT)
BEGIN
DECLARE vStarted DATETIME DEFAULT TIMESTAMP(util.VN_CURDATE());
DECLARE vEnded DATETIME DEFAULT TIMESTAMP(util.VN_CURDATE(), '23:59:59');
DECLARE vIsHolland BOOL;
SELECT (wa.name = 'Holanda') INTO vIsHolland
FROM vn.agency a
JOIN vn.warehouseAlias wa ON wa.id = a.warehouseAliasFk
WHERE a.id = vAgencyFk;
IF vIsHolland THEN
DROP TEMPORARY TABLE IF EXISTS tmp.ticket_PackagingEstimated;
CREATE TEMPORARY TABLE tmp.ticket_PackagingEstimated
(
ticketFk INT PRIMARY KEY
,carros DECIMAL(5,1) DEFAULT 0
);
INSERT INTO tmp.ticket_PackagingEstimated(ticketFk, carros)
SELECT sv.ticketFk, ROUND(vc.dutchCompressionRate * sum(sv.volume) / vc.trolleyM3,0)
FROM vn.ticket t
JOIN vn.saleVolume sv ON sv.ticketFk = t.id
JOIN vn.agencyMode am ON am.id = t.agencyModeFk
JOIN vn.volumeConfig vc
WHERE t.shipped BETWEEN vStarted AND vEnded
AND am.agencyFk = vAgencyFk
GROUP BY t.id;
SELECT a.nickname Provincia,
count(*) expediciones,
0 Bultos,
sum(tpe.carros) Prevision
FROM vn.ticket t
JOIN vn.address a ON a.id = t.addressFk
JOIN tmp.ticket_PackagingEstimated tpe ON tpe.ticketFk = t.id
GROUP BY a.nickname;
ELSE
DROP TEMPORARY TABLE IF EXISTS tmp.ticket_PackagingEstimated;
CREATE TEMPORARY TABLE tmp.ticket_PackagingEstimated
(
ticketFk INT PRIMARY KEY
,boxes INT DEFAULT 0
);
INSERT INTO tmp.ticket_PackagingEstimated(ticketFk, boxes)
SELECT sv.ticketFk, CEIL(1000 * sum(sv.volume) / vc.standardFlowerBox)
FROM vn.ticket t
JOIN vn.saleVolume sv ON sv.ticketFk = t.id
JOIN vn.agencyMode am ON am.id = t.agencyModeFk
JOIN vn.volumeConfig vc
WHERE t.shipped BETWEEN vStarted AND vEnded
AND IFNULL(t.packages,0) = 0
AND am.agencyFk = vAgencyFk
GROUP BY t.id;
SELECT p.name Provincia,
count(*) expediciones,
sum(t.packages) Bultos,
sum(tpe.boxes) Prevision
FROM vn.ticket t
JOIN vn.address a ON a.id = t.addressFk
JOIN vn.province p ON a.provinceFk = p.id
JOIN vn.agencyMode am ON am.id = t.agencyModeFk
JOIN tmp.ticket_PackagingEstimated tpe ON tpe.ticketFk = t.id
WHERE t.warehouseFk = 60
AND t.shipped BETWEEN vStarted AND vEnded
AND am.agencyFk = vAgencyFk
GROUP BY p.name;
END IF;
SELECT * FROM tmp.ticket_PackagingEstimated;
DROP TEMPORARY TABLE tmp.ticket_PackagingEstimated;
END$$
DELIMITER ;

View File

@ -1,7 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`Articles_botanical`
AS SELECT `ab`.`itemFk` AS `Id_Article`,
`ab`.`genusFk` AS `genus_id`,
`ab`.`specieFk` AS `specie_id`
FROM `vn`.`itemBotanical` `ab`

View File

@ -1,8 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`Equipos`
AS SELECT `h`.`code` AS `alias`,
`h`.`description` AS `descripcion`,
`h`.`workerFk` AS `trabajador_id`,
`h`.`windowsSerial` AS `windowsSerial`
FROM `vn`.`host` `h`

View File

@ -1,6 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`Prioridades`
AS SELECT `qp`.`id` AS `Id_Prioridad`,
`qp`.`priority` AS `Prioridad`
FROM `vn`.`queuePriority` `qp`

View File

@ -4,7 +4,6 @@ CREATE OR REPLACE DEFINER=`root`@`localhost`
AS SELECT `a`.`id` AS `agency_id`,
`a`.`name` AS `name`,
`a`.`warehouseFk` AS `warehouse_id`,
`a`.`warehouseAliasFk` AS `warehouse_alias_id`,
`a`.`isOwn` AS `propios`,
`a`.`workCenterFk` AS `workCenterFk`
FROM `vn`.`agency` `a`

View File

@ -1,6 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`bionic_updating_options`
AS SELECT `t`.`id` AS `buo_id`,
`t`.`description` AS `description`
FROM `vn`.`ticketUpdateAction` `t`

View File

@ -1,6 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`businessReasonEnd`
AS SELECT `b`.`id` AS `id`,
`b`.`reason` AS `reason`
FROM `vn`.`businessReasonEnd` `b`

View File

@ -1,6 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`cl_dev`
AS SELECT `c`.`id` AS `id`,
`c`.`description` AS `devolucion`
FROM `vn`.`claimRedelivery` `c`

View File

@ -1,7 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`cl_est`
AS SELECT `c`.`id` AS `id`,
`c`.`description` AS `estado`,
`c`.`roleFk` AS `roleFk`
FROM `vn`.`claimState` `c`

View File

@ -1,7 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`deliveryPoint`
AS SELECT `dp`.`id` AS `id`,
`dp`.`name` AS `name`,
`dp`.`ubication` AS `ubication`
FROM `vn`.`deliveryPoint` `dp`

View File

@ -1,6 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`device_user`
AS SELECT `dpu`.`deviceProductionFk` AS `device_id`,
`dpu`.`userFk` AS `user_id`
FROM `vn`.`deviceProductionUser` `dpu`

View File

@ -1,10 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`edi_feature`
AS SELECT `edi`.`feature`.`item_id` AS `item_id`,
`edi`.`feature`.`feature_type_id` AS `feature_type_id`,
`edi`.`feature`.`feature_value` AS `feature_value`,
`edi`.`feature`.`entry_date` AS `entry_date`,
`edi`.`feature`.`expiry_date` AS `expiry_date`,
`edi`.`feature`.`change_date_time` AS `change_date_time`
FROM `edi`.`feature`

View File

@ -1,9 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`edi_genus`
AS SELECT `edi`.`genus`.`genus_id` AS `genus_id`,
`edi`.`genus`.`latin_genus_name` AS `latin_genus_name`,
`edi`.`genus`.`entry_date` AS `entry_date`,
`edi`.`genus`.`expiry_date` AS `expiry_date`,
`edi`.`genus`.`change_date_time` AS `change_date_time`
FROM `edi`.`genus`

View File

@ -1,11 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`edi_item_feature`
AS SELECT `edi`.`item_feature`.`item_id` AS `item_id`,
`edi`.`item_feature`.`presentation_order` AS `presentation_order`,
`edi`.`item_feature`.`feature` AS `feature`,
`edi`.`item_feature`.`regulation_type` AS `regulation_type`,
`edi`.`item_feature`.`entry_date` AS `entry_date`,
`edi`.`item_feature`.`expiry_date` AS `expiry_date`,
`edi`.`item_feature`.`change_date_time` AS `change_date_time`
FROM `edi`.`item_feature`

View File

@ -1,10 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`edi_plant`
AS SELECT `edi`.`plant`.`plant_id` AS `plant_id`,
`edi`.`plant`.`genus_id` AS `genus_id`,
`edi`.`plant`.`specie_id` AS `specie_id`,
`edi`.`plant`.`entry_date` AS `entry_date`,
`edi`.`plant`.`expiry_date` AS `expiry_date`,
`edi`.`plant`.`change_date_time` AS `change_date_time`
FROM `edi`.`plant`

View File

@ -1,10 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`edi_type`
AS SELECT `edi`.`type`.`type_id` AS `type_id`,
`edi`.`type`.`type_group_id` AS `type_group_id`,
`edi`.`type`.`description` AS `description`,
`edi`.`type`.`entry_date` AS `entry_date`,
`edi`.`type`.`expiry_date` AS `expiry_date`,
`edi`.`type`.`change_date_time` AS `change_date_time`
FROM `edi`.`type`

View File

@ -1,10 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`edi_value`
AS SELECT `edi`.`value`.`type_id` AS `type_id`,
`edi`.`value`.`type_value` AS `type_value`,
`edi`.`value`.`type_description` AS `type_description`,
`edi`.`value`.`entry_date` AS `entry_date`,
`edi`.`value`.`expiry_date` AS `expiry_date`,
`edi`.`value`.`change_date_time` AS `change_date_time`
FROM `edi`.`value`

View File

@ -1,9 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`escritos`
AS SELECT `s`.`id` AS `id`,
`s`.`code` AS `abrev`,
`s`.`description` AS `descripcion`,
`s`.`isVisible` AS `visible`,
`s`.`hasCompany` AS `hasCompany`
FROM `vn`.`sample` `s`

View File

@ -1,10 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`person_user`
AS SELECT `u`.`id` AS `id`,
`u`.`role` AS `mysql_user_id`,
`u`.`name` AS `name`,
`u`.`password` AS `password`,
`u`.`active` AS `active`,
`u`.`lastPassChange` AS `last_pass_change`
FROM `account`.`user` `u`

View File

@ -1,9 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`person_user_idtrabajador`
AS SELECT `t`.`Id_Trabajador` AS `Id_Trabajador`
FROM (
`vn2008`.`person_user` `p`
JOIN `vn2008`.`Trabajadores` `t` ON(`p`.`id` = `t`.`user_id`)
)
WHERE `t`.`user_id` = `account`.`myUser_getId`()

View File

@ -1,7 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`reference_min`
AS SELECT `rc`.`dated` AS `date`,
`rc`.`value` AS `rate`,
`rc`.`currencyFk` AS `moneda_id`
FROM `vn`.`referenceCurrent` `rc`

View File

@ -0,0 +1,4 @@
UPDATE salix.ACL
SET property='clone'
WHERE model = 'Sale'
AND property = 'refund'

View File

@ -0,0 +1,8 @@
ALTER TABLE vn.agency
CHANGE warehouseAliasFk warehouseAliasFk__ SMALLINT(5) UNSIGNED DEFAULT NULL NULL COMMENT '@deprecated 2024-01-23 refs #5167';
ALTER TABLE vn.warehouse
CHANGE aliasFk aliasFk__ SMALLINT(5) UNSIGNED DEFAULT NULL NULL COMMENT '@deprecated 2024-01-23 refs #5167';
RENAME TABLE vn.warehouseAlias TO vn.warehouseAlias__;
ALTER TABLE vn.warehouseAlias__ COMMENT='@deprecated 2024-01-23 refs #5167';

View File

@ -0,0 +1,4 @@
-- Place your SQL code here
UPDATE vn.supplier
SET name = UPPER(name),
nickname = UPPER(nickname);

View File

@ -0,0 +1 @@
REVOKE EXECUTE ON FUNCTION vn2008.red FROM hrBoss, salesPerson;

View File

@ -0,0 +1,4 @@
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('InvoiceIn', 'corrective', 'WRITE', 'ALLOW', 'ROLE', 'administrative'),
('InvoiceInCorrection', '*', '*', 'ALLOW', 'ROLE', 'administrative');

View File

@ -0,0 +1,17 @@
CREATE TABLE IF NOT EXISTS `vn`.`invoiceInCorrection` (
`correctingFk` mediumint(8) UNSIGNED NOT NULL COMMENT 'Factura rectificativa',
`correctedFk` mediumint(8) UNSIGNED NOT NULL COMMENT 'Factura rectificada',
`cplusRectificationTypeFk` int(10) UNSIGNED NOT NULL,
`siiTypeInvoiceOutFk` int(10) UNSIGNED NOT NULL,
`invoiceCorrectionTypeFk` int(11) NOT NULL DEFAULT 3,
PRIMARY KEY (`correctingFk`),
KEY `invoiceInCorrection_correctedFk` (`correctedFk`),
KEY `invoiceInCorrection_cplusRectificationTypeFk` (`cplusRectificationTypeFk`),
KEY `invoiceInCorrection_siiTypeInvoiceOut` (`siiTypeInvoiceOutFk`),
KEY `invoiceInCorrection_invoiceCorrectionTypeFk` (`invoiceCorrectionTypeFk`),
CONSTRAINT `invoiceInCorrection_correctedFk` FOREIGN KEY (`correctedFk`) REFERENCES `invoiceIn` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `invoiceInCorrection_correctingFk` FOREIGN KEY (`correctingFk`) REFERENCES `invoiceIn` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `invoiceInCorrection_siiTypeInvoiceOut` FOREIGN KEY (`siiTypeInvoiceOutFk`) REFERENCES `siiTypeInvoiceOut` (`id`) ON UPDATE CASCADE,
CONSTRAINT `invoiceInCorrection_invoiceCorrectionTypeFk` FOREIGN KEY (`invoiceCorrectionTypeFk`) REFERENCES `invoiceCorrectionType` (`id`) ON UPDATE CASCADE,
CONSTRAINT `invoiceInCorrection_cplusRectificationTypeFk` FOREIGN KEY (`cplusRectificationTypeFk`) REFERENCES `cplusRectificationType` (`id`) ON UPDATE CASCADE
);

View File

@ -0,0 +1 @@
REVOKE SELECT ON TABLE vn2008.reference_min FROM logistic;

View File

@ -0,0 +1 @@
REVOKE SELECT ON TABLE vn2008.Articles_botanical FROM buyer, administrative;

View File

@ -24,7 +24,7 @@ describe('Supplier summary & descriptor path', () => {
it(`should confirm there's data on the summary header`, async() => {
const result = await page.waitToGetProperty(selectors.supplierSummary.header, 'innerText');
expect(result).toContain('Plants SL - 1');
expect(result).toContain('PLANTS SL - 1');
});
it(`should confirm there's data on the summary basic data`, async() => {

View File

@ -24,7 +24,7 @@ describe('Supplier fiscal data path', () => {
country: null,
postcode: null,
city: 'Valencia',
socialName: 'Farmer King SL',
socialName: 'FARMER KING SL',
taxNumber: '12345678Z',
account: '0123456789',
sageWithholding: 'retencion estimacion objetiva',
@ -46,7 +46,7 @@ describe('Supplier fiscal data path', () => {
country: 'España',
postcode: '46000',
city: 'Valencia',
socialName: 'Farmer King SL',
socialName: 'FARMER KING SL',
taxNumber: '12345678Z',
account: '0123456789',
sageWithholding: 'RETENCION ESTIMACION OBJETIVA',

258
front/package-lock.json generated
View File

@ -1,258 +0,0 @@
{
"name": "salix-front",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "salix-front",
"version": "1.0.0",
"license": "GPL-3.0",
"dependencies": {
"@uirouter/angularjs": "^1.0.20",
"angular": "^1.7.5",
"angular-animate": "^1.7.8",
"angular-moment": "^1.3.0",
"angular-translate": "^2.18.1",
"angular-translate-loader-partial": "^2.18.1",
"croppie": "^2.6.5",
"js-yaml": "^3.13.1",
"mg-crud": "^1.1.2",
"oclazyload": "^0.6.3",
"require-yaml": "0.0.1",
"validator": "^6.3.0"
}
},
"node_modules/@uirouter/angularjs": {
"version": "1.0.30",
"license": "MIT",
"dependencies": {
"@uirouter/core": "6.0.8"
},
"engines": {
"node": ">=4.0.0"
},
"peerDependencies": {
"angular": ">=1.2.0"
}
},
"node_modules/@uirouter/core": {
"version": "6.0.8",
"license": "MIT",
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/angular": {
"version": "1.8.3",
"license": "MIT"
},
"node_modules/angular-animate": {
"version": "1.8.2",
"license": "MIT"
},
"node_modules/angular-moment": {
"version": "1.3.0",
"license": "MIT",
"dependencies": {
"moment": ">=2.8.0 <3.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/angular-translate": {
"version": "2.19.1",
"resolved": "https://registry.npmjs.org/angular-translate/-/angular-translate-2.19.1.tgz",
"integrity": "sha512-SrU40ndnL422vXiVoqVveCmSnCzMcIXxQgnl7Cv9krOKUg6B8KZK3ddYzidHR/rxVuySezYHNDgRvzQNKwAdNQ==",
"deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
"dependencies": {
"angular": "^1.8.0"
},
"engines": {
"node": "*"
}
},
"node_modules/angular-translate-loader-partial": {
"version": "2.19.0",
"license": "MIT",
"dependencies": {
"angular-translate": "~2.19.0"
}
},
"node_modules/argparse": {
"version": "1.0.10",
"license": "MIT",
"dependencies": {
"sprintf-js": "~1.0.2"
}
},
"node_modules/croppie": {
"version": "2.6.5",
"license": "MIT"
},
"node_modules/esprima": {
"version": "4.0.1",
"license": "BSD-2-Clause",
"bin": {
"esparse": "bin/esparse.js",
"esvalidate": "bin/esvalidate.js"
},
"engines": {
"node": ">=4"
}
},
"node_modules/js-yaml": {
"version": "3.14.1",
"license": "MIT",
"dependencies": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/mg-crud": {
"version": "1.1.2",
"license": "MIT",
"dependencies": {
"angular": "^1.6.1"
}
},
"node_modules/moment": {
"version": "2.29.4",
"license": "MIT",
"engines": {
"node": "*"
}
},
"node_modules/oclazyload": {
"version": "0.6.3",
"license": "MIT"
},
"node_modules/require-yaml": {
"version": "0.0.1",
"license": "BSD",
"dependencies": {
"js-yaml": ""
}
},
"node_modules/require-yaml/node_modules/argparse": {
"version": "2.0.1",
"license": "Python-2.0"
},
"node_modules/require-yaml/node_modules/js-yaml": {
"version": "4.1.0",
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/sprintf-js": {
"version": "1.0.3",
"license": "BSD-3-Clause"
},
"node_modules/validator": {
"version": "6.3.0",
"license": "MIT",
"engines": {
"node": ">= 0.10"
}
}
},
"dependencies": {
"@uirouter/angularjs": {
"version": "1.0.30",
"requires": {
"@uirouter/core": "6.0.8"
}
},
"@uirouter/core": {
"version": "6.0.8"
},
"angular": {
"version": "1.8.3"
},
"angular-animate": {
"version": "1.8.2"
},
"angular-moment": {
"version": "1.3.0",
"requires": {
"moment": ">=2.8.0 <3.0.0"
}
},
"angular-translate": {
"version": "2.19.1",
"resolved": "https://registry.npmjs.org/angular-translate/-/angular-translate-2.19.1.tgz",
"integrity": "sha512-SrU40ndnL422vXiVoqVveCmSnCzMcIXxQgnl7Cv9krOKUg6B8KZK3ddYzidHR/rxVuySezYHNDgRvzQNKwAdNQ==",
"requires": {
"angular": "^1.8.0"
}
},
"angular-translate-loader-partial": {
"version": "2.19.0",
"requires": {
"angular-translate": "~2.19.0"
}
},
"argparse": {
"version": "1.0.10",
"requires": {
"sprintf-js": "~1.0.2"
}
},
"croppie": {
"version": "2.6.5"
},
"esprima": {
"version": "4.0.1"
},
"js-yaml": {
"version": "3.14.1",
"requires": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
}
},
"mg-crud": {
"version": "1.1.2",
"requires": {
"angular": "^1.6.1"
}
},
"moment": {
"version": "2.29.4"
},
"oclazyload": {
"version": "0.6.3"
},
"require-yaml": {
"version": "0.0.1",
"requires": {
"js-yaml": ""
},
"dependencies": {
"argparse": {
"version": "2.0.1"
},
"js-yaml": {
"version": "4.1.0",
"requires": {
"argparse": "^2.0.1"
}
}
}
},
"sprintf-js": {
"version": "1.0.3"
},
"validator": {
"version": "6.3.0"
}
}
}

View File

@ -8,6 +8,7 @@
"type": "git",
"url": "https://gitea.verdnatura.es/verdnatura/salix"
},
"packageManager": "pnpm@8.15.1",
"dependencies": {
"@uirouter/angularjs": "^1.0.20",
"angular": "^1.7.5",

156
front/pnpm-lock.yaml Normal file
View File

@ -0,0 +1,156 @@
lockfileVersion: '6.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
dependencies:
'@uirouter/angularjs':
specifier: ^1.0.20
version: 1.1.0(@uirouter/core@6.1.0)(angular@1.8.3)
angular:
specifier: ^1.7.5
version: 1.8.3
angular-animate:
specifier: ^1.7.8
version: 1.8.3
angular-moment:
specifier: ^1.3.0
version: 1.3.0
angular-translate:
specifier: ^2.18.1
version: 2.19.1
angular-translate-loader-partial:
specifier: ^2.18.1
version: 2.19.1
croppie:
specifier: ^2.6.5
version: 2.6.5
js-yaml:
specifier: ^3.13.1
version: 3.14.1
mg-crud:
specifier: ^1.1.2
version: 1.1.2
oclazyload:
specifier: ^0.6.3
version: 0.6.3
require-yaml:
specifier: 0.0.1
version: 0.0.1
validator:
specifier: ^6.3.0
version: 6.3.0
packages:
/@uirouter/angularjs@1.1.0(@uirouter/core@6.1.0)(angular@1.8.3):
resolution: {integrity: sha512-AhgxXhMfN6FU2HxDQqwDPbzmd6kTgvYCgV/kgoCAXfxAH6cFQrifViToC90Wdg6djBynHwA3L/KYP+iOYHkw6A==}
engines: {node: '>=4.0.0'}
peerDependencies:
'@uirouter/core': ^6.0.8
angular: '>=1.2.0'
dependencies:
'@uirouter/core': 6.1.0
angular: 1.8.3
dev: false
/@uirouter/core@6.1.0:
resolution: {integrity: sha512-WFYh5NPAqRX4L2qlI4k62tgR6pxoqOBSW1CM1uBWCau4mAmgasYd5etJ9RoSJrSnCpCQ2km2Jltf0n5ql684MQ==}
engines: {node: '>=4.0.0'}
dev: false
/angular-animate@1.8.3:
resolution: {integrity: sha512-/LtTKvy5sD6MZbV0v+nHgOIpnFF0mrUp+j5WIxVprVhcrJriYpuCZf4S7Owj1o76De/J0eRzANUozNJ6hVepnQ==}
deprecated: For the actively supported Angular, see https://www.npmjs.com/package/@angular/core. AngularJS support has officially ended. For extended AngularJS support options, see https://goo.gle/angularjs-path-forward.
dev: false
/angular-moment@1.3.0:
resolution: {integrity: sha512-KG8rvO9MoaBLwtGnxTeUveSyNtrL+RNgGl1zqWN36+HDCCVGk2DGWOzqKWB6o+eTTbO3Opn4hupWKIElc8XETA==}
engines: {node: '>=0.10.0'}
dependencies:
moment: 2.30.1
dev: false
/angular-translate-loader-partial@2.19.1:
resolution: {integrity: sha512-1rDe314zG09gwl/2qsLPwrxp5yehSsRi2vNJn/UwIJq20n0E0Fia/1K0nW9QAv67UFyvFuBOhl34n59I1qEHog==}
deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
dependencies:
angular-translate: 2.19.1
dev: false
/angular-translate@2.19.1:
resolution: {integrity: sha512-SrU40ndnL422vXiVoqVveCmSnCzMcIXxQgnl7Cv9krOKUg6B8KZK3ddYzidHR/rxVuySezYHNDgRvzQNKwAdNQ==}
deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
dependencies:
angular: 1.8.3
dev: false
/angular@1.8.3:
resolution: {integrity: sha512-5qjkWIQQVsHj4Sb5TcEs4WZWpFeVFHXwxEBHUhrny41D8UrBAd6T/6nPPAsLngJCReIOqi95W3mxdveveutpZw==}
deprecated: For the actively supported Angular, see https://www.npmjs.com/package/@angular/core. AngularJS support has officially ended. For extended AngularJS support options, see https://goo.gle/angularjs-path-forward.
dev: false
/argparse@1.0.10:
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
dependencies:
sprintf-js: 1.0.3
dev: false
/argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
dev: false
/croppie@2.6.5:
resolution: {integrity: sha512-IlChnVUGG5T3w2gRZIaQgBtlvyuYnlUWs2YZIXXR3H9KrlO1PtBT3j+ykxvy9eZIWhk+V5SpBmhCQz5UXKrEKQ==}
dev: false
/esprima@4.0.1:
resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
engines: {node: '>=4'}
hasBin: true
dev: false
/js-yaml@3.14.1:
resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
hasBin: true
dependencies:
argparse: 1.0.10
esprima: 4.0.1
dev: false
/js-yaml@4.1.0:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
dependencies:
argparse: 2.0.1
dev: false
/mg-crud@1.1.2:
resolution: {integrity: sha512-mAR6t0aQHKnT0QHKHpLOi0kNPZfO36iMpIoiLjFHxuio6mIJyuveBJ4VNlNXJRxLh32/FLADEb41/sYo7QUKFw==}
dependencies:
angular: 1.8.3
dev: false
/moment@2.30.1:
resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==}
dev: false
/oclazyload@0.6.3:
resolution: {integrity: sha512-HpOSYUgjtt6sTB/C6+FWsExR+9HCnXKsUA96RWkDXfv11C8Cc9X2DlR0WIZwFIiG6FQU0pwB5dhoYyut8bFAOQ==}
dev: false
/require-yaml@0.0.1:
resolution: {integrity: sha512-M6eVEgLPRbeOhgSCnOTtdrOOEQzbXRchg24Xa13c39dMuraFKdI9emUo97Rih0YEFzSICmSKg8w4RQp+rd9pOQ==}
dependencies:
js-yaml: 4.1.0
dev: false
/sprintf-js@1.0.3:
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
dev: false
/validator@6.3.0:
resolution: {integrity: sha512-BylxTwhqwjQI5MDJF7amCy/L0ejJO+74DvCsLV52Lq3+3bhVcVMKqNqOiNcQJm2G48u9EAcw4xFERAmFbwXM9Q==}
engines: {node: '>= 0.10'}
dev: false

View File

@ -22,7 +22,7 @@ module.exports = Self => {
});
const modelsLocale = new Map();
const modulesDir = path.resolve(`${__dirname}/../../../../modules`);
const modulesDir = path.resolve(`${process.cwd()}/modules`);
const modules = fs.readdirSync(modulesDir);
for (const mod of modules) {

View File

@ -204,5 +204,8 @@
"Cannot past travels with entries": "Cannot past travels with entries",
"It was not able to remove the next expeditions:": "It was not able to remove the next expeditions: {{expeditions}}",
"Incorrect pin": "Incorrect pin.",
"The notification subscription of this worker cant be modified": "The notification subscription of this worker cant be modified"
"The notification subscription of this worker cant be modified": "The notification subscription of this worker cant be modified",
"Name should be uppercase": "Name should be uppercase",
"Fecha fuera de rango": "Fecha fuera de rango",
"There is no zone for these parameters 34": "There is no zone for these parameters 34"
}

View File

@ -1,343 +1,343 @@
{
"Phone format is invalid": "El formato del teléfono no es correcto",
"You are not allowed to change the credit": "No tienes privilegios para modificar el crédito",
"Unable to mark the equivalence surcharge": "No se puede marcar el recargo de equivalencia",
"The default consignee can not be unchecked": "No se puede desmarcar el consignatario predeterminado",
"Unable to default a disabled consignee": "No se puede poner predeterminado un consignatario desactivado",
"Can't be blank": "No puede estar en blanco",
"Invalid TIN": "NIF/CIF inválido",
"TIN must be unique": "El NIF/CIF debe ser único",
"A client with that Web User name already exists": "Ya existe un cliente con ese Usuario Web",
"Is invalid": "Es inválido",
"Quantity cannot be zero": "La cantidad no puede ser cero",
"Enter an integer different to zero": "Introduce un entero distinto de cero",
"Package cannot be blank": "El embalaje no puede estar en blanco",
"The company name must be unique": "La razón social debe ser única",
"Invalid email": "Correo electrónico inválido",
"The IBAN does not have the correct format": "El IBAN no tiene el formato correcto",
"That payment method requires an IBAN": "El método de pago seleccionado requiere un IBAN",
"That payment method requires a BIC": "El método de pago seleccionado requiere un BIC",
"State cannot be blank": "El estado no puede estar en blanco",
"Worker cannot be blank": "El trabajador no puede estar en blanco",
"Cannot change the payment method if no salesperson": "No se puede cambiar la forma de pago si no hay comercial asignado",
"can't be blank": "El campo no puede estar vacío",
"Observation type must be unique": "El tipo de observación no puede repetirse",
"The credit must be an integer greater than or equal to zero": "The credit must be an integer greater than or equal to zero",
"The grade must be similar to the last one": "El grade debe ser similar al último",
"Only manager can change the credit": "Solo el gerente puede cambiar el credito de este cliente",
"Name cannot be blank": "El nombre no puede estar en blanco",
"Phone cannot be blank": "El teléfono no puede estar en blanco",
"Period cannot be blank": "El periodo no puede estar en blanco",
"Choose a company": "Selecciona una empresa",
"Se debe rellenar el campo de texto": "Se debe rellenar el campo de texto",
"Description should have maximum of 45 characters": "La descripción debe tener maximo 45 caracteres",
"Cannot be blank": "El campo no puede estar en blanco",
"The grade must be an integer greater than or equal to zero": "El grade debe ser un entero mayor o igual a cero",
"Sample type cannot be blank": "El tipo de plantilla no puede quedar en blanco",
"Description cannot be blank": "Se debe rellenar el campo de texto",
"The price of the item changed": "El precio del artículo cambió",
"The value should not be greater than 100%": "El valor no debe de ser mayor de 100%",
"The value should be a number": "El valor debe ser un numero",
"This order is not editable": "Esta orden no se puede modificar",
"You can't create an order for a frozen client": "No puedes crear una orden para un cliente congelado",
"You can't create an order for a client that has a debt": "No puedes crear una orden para un cliente con deuda",
"is not a valid date": "No es una fecha valida",
"Barcode must be unique": "El código de barras debe ser único",
"The warehouse can't be repeated": "El almacén no puede repetirse",
"The tag or priority can't be repeated for an item": "El tag o prioridad no puede repetirse para un item",
"The observation type can't be repeated": "El tipo de observación no puede repetirse",
"A claim with that sale already exists": "Ya existe una reclamación para esta línea",
"You don't have enough privileges to change that field": "No tienes permisos para cambiar ese campo",
"Warehouse cannot be blank": "El almacén no puede quedar en blanco",
"Agency cannot be blank": "La agencia no puede quedar en blanco",
"Not enough privileges to edit a client with verified data": "No tienes permisos para hacer cambios en un cliente con datos comprobados",
"This address doesn't exist": "Este consignatario no existe",
"You must delete the claim id %d first": "Antes debes borrar la reclamación %d",
"You don't have enough privileges": "No tienes suficientes permisos",
"Cannot check Equalization Tax in this NIF/CIF": "No se puede marcar RE en este NIF/CIF",
"You can't make changes on the basic data of an confirmed order or with rows": "No puedes cambiar los datos básicos de una orden con artículos",
"INVALID_USER_NAME": "El nombre de usuario solo debe contener letras minúsculas o, a partir del segundo carácter, números o subguiones, no está permitido el uso de la letra ñ",
"You can't create a ticket for a frozen client": "No puedes crear un ticket para un cliente congelado",
"You can't create a ticket for an inactive client": "No puedes crear un ticket para un cliente inactivo",
"Tag value cannot be blank": "El valor del tag no puede quedar en blanco",
"ORDER_EMPTY": "Cesta vacía",
"You don't have enough privileges to do that": "No tienes permisos para cambiar esto",
"NO SE PUEDE DESACTIVAR EL CONSIGNAT": "NO SE PUEDE DESACTIVAR EL CONSIGNAT",
"Error. El NIF/CIF está repetido": "Error. El NIF/CIF está repetido",
"Street cannot be empty": "Dirección no puede estar en blanco",
"City cannot be empty": "Ciudad no puede estar en blanco",
"Code cannot be blank": "Código no puede estar en blanco",
"You cannot remove this department": "No puedes eliminar este departamento",
"The extension must be unique": "La extensión debe ser unica",
"The secret can't be blank": "La contraseña no puede estar en blanco",
"We weren't able to send this SMS": "No hemos podido enviar el SMS",
"This client can't be invoiced": "Este cliente no puede ser facturado",
"You must provide the correction information to generate a corrective invoice": "Debes informar la información de corrección para generar una factura rectificativa",
"This ticket can't be invoiced": "Este ticket no puede ser facturado",
"You cannot add or modify services to an invoiced ticket": "No puedes añadir o modificar servicios a un ticket facturado",
"This ticket can not be modified": "Este ticket no puede ser modificado",
"The introduced hour already exists": "Esta hora ya ha sido introducida",
"INFINITE_LOOP": "Existe una dependencia entre dos Jefes",
"The sales of the receiver ticket can't be modified": "Las lineas del ticket al que envias no pueden ser modificadas",
"NO_AGENCY_AVAILABLE": "No hay una zona de reparto disponible con estos parámetros",
"ERROR_PAST_SHIPMENT": "No puedes seleccionar una fecha de envío en pasado",
"The current ticket can't be modified": "El ticket actual no puede ser modificado",
"The current claim can't be modified": "La reclamación actual no puede ser modificada",
"The sales of this ticket can't be modified": "Las lineas de este ticket no pueden ser modificadas",
"The sales do not exists": "La(s) línea(s) seleccionada(s) no existe(n)",
"Please select at least one sale": "Por favor selecciona al menos una linea",
"All sales must belong to the same ticket": "Todas las lineas deben pertenecer al mismo ticket",
"NO_ZONE_FOR_THIS_PARAMETERS": "Para este día no hay ninguna zona configurada",
"This item doesn't exists": "El artículo no existe",
"NOT_ZONE_WITH_THIS_PARAMETERS": "Para este día no hay ninguna zona configurada",
"Extension format is invalid": "El formato de la extensión es inválido",
"Invalid parameters to create a new ticket": "Parámetros inválidos para crear un nuevo ticket",
"This item is not available": "Este artículo no está disponible",
"This postcode already exists": "Este código postal ya existe",
"Concept cannot be blank": "El concepto no puede quedar en blanco",
"File doesn't exists": "El archivo no existe",
"You don't have privileges to change the zone": "No tienes permisos para cambiar la zona o para esos parámetros hay más de una opción de envío, hable con las agencias",
"This ticket is already on weekly tickets": "Este ticket ya está en tickets programados",
"Ticket id cannot be blank": "El id de ticket no puede quedar en blanco",
"Weekday cannot be blank": "El día de la semana no puede quedar en blanco",
"You can't delete a confirmed order": "No puedes borrar un pedido confirmado",
"The social name has an invalid format": "El nombre fiscal tiene un formato incorrecto",
"Invalid quantity": "Cantidad invalida",
"This postal code is not valid": "Este código postal no es válido",
"is invalid": "es inválido",
"The postcode doesn't exist. Please enter a correct one": "El código postal no existe. Por favor, introduce uno correcto",
"The department name can't be repeated": "El nombre del departamento no puede repetirse",
"This phone already exists": "Este teléfono ya existe",
"You cannot move a parent to its own sons": "No puedes mover un elemento padre a uno de sus hijos",
"You can't create a claim for a removed ticket": "No puedes crear una reclamación para un ticket eliminado",
"You cannot delete a ticket that part of it is being prepared": "No puedes eliminar un ticket en el que una parte que está siendo preparada",
"You must delete all the buy requests first": "Debes eliminar todas las peticiones de compra primero",
"You should specify a date": "Debes especificar una fecha",
"You should specify at least a start or end date": "Debes especificar al menos una fecha de inicio o de fin",
"Start date should be lower than end date": "La fecha de inicio debe ser menor que la fecha de fin",
"You should mark at least one week day": "Debes marcar al menos un día de la semana",
"Swift / BIC can't be empty": "Swift / BIC no puede estar vacío",
"Customs agent is required for a non UEE member": "El agente de aduanas es requerido para los clientes extracomunitarios",
"Incoterms is required for a non UEE member": "El incoterms es requerido para los clientes extracomunitarios",
"Deleted sales from ticket": "He eliminado las siguientes lineas del ticket [{{ticketId}}]({{{ticketUrl}}}): {{{deletions}}}",
"Added sale to ticket": "He añadido la siguiente linea al ticket [{{ticketId}}]({{{ticketUrl}}}): {{{addition}}}",
"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}}}",
"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}}})",
"State": "Estado",
"regular": "normal",
"reserved": "reservado",
"Changed sale reserved state": "He cambiado el estado reservado de las siguientes lineas al ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
"Bought units from buy request": "Se ha comprado {{quantity}} unidades de [{{itemId}} {{concept}}]({{{urlItem}}}) para el ticket id [{{ticketId}}]({{{url}}})",
"Deny buy request": "Se ha rechazado la petición de compra para el ticket id [{{ticketId}}]({{{url}}}). Motivo: {{observation}}",
"MESSAGE_INSURANCE_CHANGE": "He cambiado el crédito asegurado del cliente [{{clientName}} ({{clientId}})]({{{url}}}) a *{{credit}} €*",
"Changed client paymethod": "He cambiado la forma de pago del cliente [{{clientName}} ({{clientId}})]({{{url}}})",
"Sent units from ticket": "Envio *{{quantity}}* unidades de [{{concept}} ({{itemId}})]({{{itemUrl}}}) a *\"{{nickname}}\"* provenientes del ticket id [{{ticketId}}]({{{ticketUrl}}})",
"Change quantity": "{{concept}} cambia de {{oldQuantity}} a {{newQuantity}}",
"Claim will be picked": "Se recogerá el género de la reclamación [({{claimId}})]({{{claimUrl}}}) del cliente *{{clientName}}*",
"Claim state has changed to": "Se ha cambiado el estado de la reclamación [({{claimId}})]({{{claimUrl}}}) del cliente *{{clientName}}* a *{{newState}}*",
"Client checked as validated despite of duplication": "Cliente comprobado a pesar de que existe el cliente id {{clientId}}",
"ORDER_ROW_UNAVAILABLE": "No hay disponibilidad de este producto",
"Distance must be lesser than 1000": "La distancia debe ser inferior a 1000",
"This ticket is deleted": "Este ticket está eliminado",
"Unable to clone this travel": "No ha sido posible clonar este travel",
"This thermograph id already exists": "La id del termógrafo ya existe",
"Choose a date range or days forward": "Selecciona un rango de fechas o días en adelante",
"ORDER_ALREADY_CONFIRMED": "ORDEN YA CONFIRMADA",
"Invalid password": "Invalid password",
"Password does not meet requirements": "La contraseña no cumple los requisitos",
"Role already assigned": "Rol ya asignado",
"Invalid role name": "Nombre de rol no válido",
"Role name must be written in camelCase": "El nombre del rol debe escribirse en camelCase",
"Email already exists": "El correo ya existe",
"User already exists": "El/La usuario/a ya existe",
"Absence change notification on the labour calendar": "Notificación de cambio de ausencia en el calendario laboral",
"Record of hours week": "Registro de horas semana {{week}} año {{year}} ",
"Created absence": "El empleado <strong>{{author}}</strong> ha añadido una ausencia de tipo '{{absenceType}}' a <a href='{{{workerUrl}}}'><strong>{{employee}}</strong></a> para el día {{dated}}.",
"Deleted absence": "El empleado <strong>{{author}}</strong> ha eliminado una ausencia de tipo '{{absenceType}}' a <a href='{{{workerUrl}}}'><strong>{{employee}}</strong></a> del día {{dated}}.",
"I have deleted the ticket id": "He eliminado el ticket id [{{id}}]({{{url}}})",
"I have restored the ticket id": "He restaurado el ticket id [{{id}}]({{{url}}})",
"You can only restore a ticket within the first hour after deletion": "Únicamente puedes restaurar el ticket dentro de la primera hora después de su eliminación",
"Changed this data from the ticket": "He cambiado estos datos del ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
"agencyModeFk": "Agencia",
"clientFk": "Cliente",
"zoneFk": "Zona",
"warehouseFk": "Almacén",
"shipped": "F. envío",
"landed": "F. entrega",
"addressFk": "Consignatario",
"companyFk": "Empresa",
"The social name cannot be empty": "La razón social no puede quedar en blanco",
"The nif cannot be empty": "El NIF no puede quedar en blanco",
"You need to fill sage information before you check verified data": "Debes rellenar la información de sage antes de marcar datos comprobados",
"ASSIGN_ZONE_FIRST": "Asigna una zona primero",
"Amount cannot be zero": "El importe no puede ser cero",
"Company has to be official": "Empresa inválida",
"You can not select this payment method without a registered bankery account": "No se puede utilizar este método de pago si no has registrado una cuenta bancaria",
"Action not allowed on the test environment": "Esta acción no está permitida en el entorno de pruebas",
"The selected ticket is not suitable for this route": "El ticket seleccionado no es apto para esta ruta",
"New ticket request has been created with price": "Se ha creado una nueva petición de compra '{{description}}' para el día *{{shipped}}*, con una cantidad de *{{quantity}}* y un precio de *{{price}} €*",
"New ticket request has been created": "Se ha creado una nueva petición de compra '{{description}}' para el día *{{shipped}}*, con una cantidad de *{{quantity}}*",
"Swift / BIC cannot be empty": "Swift / BIC no puede estar vacío",
"CountryFK cannot be empty": "El país no puede estar vacío",
"This BIC already exist": "Este BIC ya existe",
"That item doesn't exists": "Ese artículo no existe",
"There's a new urgent ticket:": "Hay un nuevo ticket urgente:",
"Invalid account": "Cuenta inválida",
"Compensation account is empty": "La cuenta para compensar está vacia",
"This genus already exist": "Este genus ya existe",
"This specie already exist": "Esta especie ya existe",
"Client assignment has changed": "He cambiado el comercial ~*\"<{{previousWorkerName}}>\"*~ por *\"<{{currentWorkerName}}>\"* del cliente [{{clientName}} ({{clientId}})]({{{url}}})",
"None": "Ninguno",
"The contract was not active during the selected date": "El contrato no estaba activo durante la fecha seleccionada",
"Cannot add more than one '1/2 day vacation'": "No puedes añadir más de un 'Vacaciones 1/2 dia'",
"This document already exists on this ticket": "Este documento ya existe en el ticket",
"Some of the selected tickets are not billable": "Algunos de los tickets seleccionados no son facturables",
"You can't invoice tickets from multiple clients": "No puedes facturar tickets de multiples clientes",
"nickname": "nickname",
"INACTIVE_PROVIDER": "Proveedor inactivo",
"This client is not invoiceable": "Este cliente no es facturable",
"serial non editable": "Esta serie no permite asignar la referencia",
"Max shipped required": "La fecha límite es requerida",
"Can't invoice to future": "No se puede facturar a futuro",
"Can't invoice to past": "No se puede facturar a pasado",
"This ticket is already invoiced": "Este ticket ya está facturado",
"A ticket with an amount of zero can't be invoiced": "No se puede facturar un ticket con importe cero",
"A ticket with a negative base can't be invoiced": "No se puede facturar un ticket con una base negativa",
"Global invoicing failed": "[Facturación global] No se han podido facturar algunos clientes",
"Wasn't able to invoice the following clients": "No se han podido facturar los siguientes clientes",
"Can't verify data unless the client has a business type": "No se puede verificar datos de un cliente que no tiene tipo de negocio",
"You don't have enough privileges to set this credit amount": "No tienes suficientes privilegios para establecer esta cantidad de crédito",
"You can't change the credit set to zero from a financialBoss": "No puedes cambiar el cŕedito establecido a cero por un jefe de finanzas",
"Amounts do not match": "Las cantidades no coinciden",
"The PDF document does not exist": "El documento PDF no existe. Prueba a regenerarlo desde la opción 'Regenerar PDF factura'",
"The type of business must be filled in basic data": "El tipo de negocio debe estar rellenado en datos básicos",
"You can't create a claim from a ticket delivered more than seven days ago": "No puedes crear una reclamación de un ticket entregado hace más de siete días",
"The worker has hours recorded that day": "El trabajador tiene horas fichadas ese día",
"The worker has a marked absence that day": "El trabajador tiene marcada una ausencia ese día",
"You can not modify is pay method checked": "No se puede modificar el campo método de pago validado",
"The account size must be exactly 10 characters": "El tamaño de la cuenta debe ser exactamente de 10 caracteres",
"Can't transfer claimed sales": "No puedes transferir lineas reclamadas",
"You don't have privileges to create refund": "No tienes permisos para crear un abono",
"The item is required": "El artículo es requerido",
"The agency is already assigned to another autonomous": "La agencia ya está asignada a otro autónomo",
"date in the future": "Fecha en el futuro",
"reference duplicated": "Referencia duplicada",
"This ticket is already a refund": "Este ticket ya es un abono",
"isWithoutNegatives": "Sin negativos",
"routeFk": "routeFk",
"Can't change the password of another worker": "No se puede cambiar la contraseña de otro trabajador",
"No hay un contrato en vigor": "No hay un contrato en vigor",
"No se permite fichar a futuro": "No se permite fichar a futuro",
"No está permitido trabajar": "No está permitido trabajar",
"Fichadas impares": "Fichadas impares",
"Descanso diario 12h.": "Descanso diario 12h.",
"Descanso semanal 36h. / 72h.": "Descanso semanal 36h. / 72h.",
"Dirección incorrecta": "Dirección incorrecta",
"Modifiable user details only by an administrator": "Detalles de usuario modificables solo por un administrador",
"Modifiable password only via recovery or by an administrator": "Contraseña modificable solo a través de la recuperación o por un administrador",
"Not enough privileges to edit a client": "No tienes suficientes privilegios para editar un cliente",
"This route does not exists": "Esta ruta no existe",
"Claim pickup order sent": "Reclamación Orden de recogida enviada [{{claimId}}]({{{claimUrl}}}) al cliente *{{clientName}}*",
"You don't have grant privilege": "No tienes privilegios para dar privilegios",
"You don't own the role and you can't assign it to another user": "No eres el propietario del rol y no puedes asignarlo a otro usuario",
"Ticket merged": "Ticket [{{originId}}]({{{originFullPath}}}) ({{{originDated}}}) fusionado con [{{destinationId}}]({{{destinationFullPath}}}) ({{{destinationDated}}})",
"Already has this status": "Ya tiene este estado",
"There aren't records for this week": "No existen registros para esta semana",
"Empty data source": "Origen de datos vacio",
"App locked": "Aplicación bloqueada por el usuario {{userId}}",
"Email verify": "Correo de verificación",
"Landing cannot be lesser than shipment": "Landing cannot be lesser than shipment",
"Receipt's bank was not found": "No se encontró el banco del recibo",
"This receipt was not compensated": "Este recibo no ha sido compensado",
"Client's email was not found": "No se encontró el email del cliente",
"Negative basis": "Base negativa",
"This worker code already exists": "Este codigo de trabajador ya existe",
"This personal mail already exists": "Este correo personal ya existe",
"This worker already exists": "Este trabajador ya existe",
"App name does not exist": "El nombre de aplicación no es válido",
"Try again": "Vuelve a intentarlo",
"Aplicación bloqueada por el usuario 9": "Aplicación bloqueada por el usuario 9",
"Failed to upload delivery note": "Error al subir albarán {{id}}",
"The DOCUWARE PDF document does not exists": "El documento PDF Docuware no existe",
"It is not possible to modify tracked sales": "No es posible modificar líneas de pedido que se hayan empezado a preparar",
"It is not possible to modify sales that their articles are from Floramondo": "No es posible modificar líneas de pedido cuyos artículos sean de Floramondo",
"It is not possible to modify cloned sales": "No es posible modificar líneas de pedido clonadas",
"A supplier with the same name already exists. Change the country.": "Un proveedor con el mismo nombre ya existe. Cambie el país.",
"There is no assigned email for this client": "No hay correo asignado para este cliente",
"Exists an invoice with a future date": "Existe una factura con fecha posterior",
"Invoice date can't be less than max date": "La fecha de factura no puede ser inferior a la fecha límite",
"Warehouse inventory not set": "El almacén inventario no está establecido",
"This locker has already been assigned": "Esta taquilla ya ha sido asignada",
"Tickets with associated refunds": "No se pueden borrar tickets con abonos asociados. Este ticket está asociado al abono Nº %d",
"Not exist this branch": "La rama no existe",
"This ticket cannot be signed because it has not been boxed": "Este ticket no puede firmarse porque no ha sido encajado",
"Collection does not exist": "La colección no existe",
"Cannot obtain exclusive lock": "No se puede obtener un bloqueo exclusivo",
"Insert a date range": "Inserte un rango de fechas",
"Added observation": "{{user}} añadió esta observacion: {{text}}",
"Comment added to client": "Observación añadida al cliente {{clientFk}}",
"Invalid auth code": "Código de verificación incorrecto",
"Invalid or expired verification code": "Código de verificación incorrecto o expirado",
"Cannot create a new claimBeginning from a different ticket": "No se puede crear una línea de reclamación de un ticket diferente al origen",
"company": "Compañía",
"country": "País",
"clientId": "Id cliente",
"clientSocialName": "Cliente",
"amount": "Importe",
"taxableBase": "Base",
"ticketFk": "Id ticket",
"isActive": "Activo",
"hasToInvoice": "Facturar",
"isTaxDataChecked": "Datos comprobados",
"comercialId": "Id comercial",
"comercialName": "Comercial",
"Pass expired": "La contraseña ha caducado, cambiela desde Salix",
"Invalid NIF for VIES": "Invalid NIF for VIES",
"Ticket does not exist": "Este ticket no existe",
"Ticket is already signed": "Este ticket ya ha sido firmado",
"Authentication failed": "Autenticación fallida",
"You can't use the same password": "No puedes usar la misma contraseña",
"You can only add negative amounts in refund tickets": "Solo se puede añadir cantidades negativas en tickets abono",
"Fecha fuera de rango": "Fecha fuera de rango",
"Error while generating PDF": "Error al generar PDF",
"Error when sending mail to client": "Error al enviar el correo al cliente",
"Mail not sent": "Se ha producido un fallo al enviar la factura al cliente [{{clientId}}]({{{clientUrl}}}), por favor revisa la dirección de correo electrónico",
"The renew period has not been exceeded": "El periodo de renovación no ha sido superado",
"Valid priorities": "Prioridades válidas: %d",
"hasAnyNegativeBase": "Base negativa para los tickets: {{ticketsIds}}",
"hasAnyPositiveBase": "Base positivas para los tickets: {{ticketsIds}}",
"You cannot assign an alias that you are not assigned to": "No puede asignar un alias que no tenga asignado",
"This ticket cannot be left empty.": "Este ticket no se puede dejar vacío. %s",
"The company has not informed the supplier account for bank transfers": "La empresa no tiene informado la cuenta de proveedor para transferencias bancarias",
"You cannot assign/remove an alias that you are not assigned to": "No puede asignar/eliminar un alias que no tenga asignado",
"This invoice has a linked vehicle.": "Esta factura tiene un vehiculo vinculado",
"You don't have enough privileges.": "No tienes suficientes permisos.",
"This ticket is locked": "Este ticket está bloqueado.",
"This ticket is not editable.": "Este ticket no es editable.",
"The ticket doesn't exist.": "No existe el ticket.",
"Social name should be uppercase": "La razón social debe ir en mayúscula",
"Street should be uppercase": "La dirección fiscal debe ir en mayúscula",
"Ticket without Route": "Ticket sin ruta",
"Select a different client": "Seleccione un cliente distinto",
"Fill all the fields": "Rellene todos los campos",
"The response is not a PDF": "La respuesta no es un PDF",
"Booking completed": "Reserva completada",
"The ticket is in preparation": "El ticket [{{ticketId}}]({{{ticketUrl}}}) del comercial {{salesPersonId}} está en preparación",
"Incoterms data for consignee is missing": "Faltan los datos de los Incoterms para el consignatario",
"The notification subscription of this worker cant be modified": "La subscripción a la notificación de este trabajador no puede ser modificada",
"User disabled": "Usuario desactivado",
"The amount cannot be less than the minimum": "La cantidad no puede ser menor que la cantidad mínima",
"quantityLessThanMin": "La cantidad no puede ser menor que la cantidad mínima",
"Cannot past travels with entries": "No se pueden pasar envíos con entradas",
"It was not able to remove the next expeditions:": "No se pudo eliminar las siguientes expediciones: {{expeditions}}",
"This claim has been updated": "La reclamación con Id: {{claimId}}, ha sido actualizada",
"This user does not have an assigned tablet": "Este usuario no tiene tablet asignada",
"Incorrect pin": "Pin incorrecto",
"You already have the mailAlias": "Ya tienes este alias de correo",
"The alias cant be modified": "Este alias de correo no puede ser modificado",
"No tickets to invoice": "No hay tickets para facturar",
"Phone format is invalid": "El formato del teléfono no es correcto",
"You are not allowed to change the credit": "No tienes privilegios para modificar el crédito",
"Unable to mark the equivalence surcharge": "No se puede marcar el recargo de equivalencia",
"The default consignee can not be unchecked": "No se puede desmarcar el consignatario predeterminado",
"Unable to default a disabled consignee": "No se puede poner predeterminado un consignatario desactivado",
"Can't be blank": "No puede estar en blanco",
"Invalid TIN": "NIF/CIF inválido",
"TIN must be unique": "El NIF/CIF debe ser único",
"A client with that Web User name already exists": "Ya existe un cliente con ese Usuario Web",
"Is invalid": "Es inválido",
"Quantity cannot be zero": "La cantidad no puede ser cero",
"Enter an integer different to zero": "Introduce un entero distinto de cero",
"Package cannot be blank": "El embalaje no puede estar en blanco",
"The company name must be unique": "La razón social debe ser única",
"Invalid email": "Correo electrónico inválido",
"The IBAN does not have the correct format": "El IBAN no tiene el formato correcto",
"That payment method requires an IBAN": "El método de pago seleccionado requiere un IBAN",
"That payment method requires a BIC": "El método de pago seleccionado requiere un BIC",
"State cannot be blank": "El estado no puede estar en blanco",
"Worker cannot be blank": "El trabajador no puede estar en blanco",
"Cannot change the payment method if no salesperson": "No se puede cambiar la forma de pago si no hay comercial asignado",
"can't be blank": "El campo no puede estar vacío",
"Observation type must be unique": "El tipo de observación no puede repetirse",
"The credit must be an integer greater than or equal to zero": "The credit must be an integer greater than or equal to zero",
"The grade must be similar to the last one": "El grade debe ser similar al último",
"Only manager can change the credit": "Solo el gerente puede cambiar el credito de este cliente",
"Name cannot be blank": "El nombre no puede estar en blanco",
"Phone cannot be blank": "El teléfono no puede estar en blanco",
"Period cannot be blank": "El periodo no puede estar en blanco",
"Choose a company": "Selecciona una empresa",
"Se debe rellenar el campo de texto": "Se debe rellenar el campo de texto",
"Description should have maximum of 45 characters": "La descripción debe tener maximo 45 caracteres",
"Cannot be blank": "El campo no puede estar en blanco",
"The grade must be an integer greater than or equal to zero": "El grade debe ser un entero mayor o igual a cero",
"Sample type cannot be blank": "El tipo de plantilla no puede quedar en blanco",
"Description cannot be blank": "Se debe rellenar el campo de texto",
"The price of the item changed": "El precio del artículo cambió",
"The value should not be greater than 100%": "El valor no debe de ser mayor de 100%",
"The value should be a number": "El valor debe ser un numero",
"This order is not editable": "Esta orden no se puede modificar",
"You can't create an order for a frozen client": "No puedes crear una orden para un cliente congelado",
"You can't create an order for a client that has a debt": "No puedes crear una orden para un cliente con deuda",
"is not a valid date": "No es una fecha valida",
"Barcode must be unique": "El código de barras debe ser único",
"The warehouse can't be repeated": "El almacén no puede repetirse",
"The tag or priority can't be repeated for an item": "El tag o prioridad no puede repetirse para un item",
"The observation type can't be repeated": "El tipo de observación no puede repetirse",
"A claim with that sale already exists": "Ya existe una reclamación para esta línea",
"You don't have enough privileges to change that field": "No tienes permisos para cambiar ese campo",
"Warehouse cannot be blank": "El almacén no puede quedar en blanco",
"Agency cannot be blank": "La agencia no puede quedar en blanco",
"Not enough privileges to edit a client with verified data": "No tienes permisos para hacer cambios en un cliente con datos comprobados",
"This address doesn't exist": "Este consignatario no existe",
"You must delete the claim id %d first": "Antes debes borrar la reclamación %d",
"You don't have enough privileges": "No tienes suficientes permisos",
"Cannot check Equalization Tax in this NIF/CIF": "No se puede marcar RE en este NIF/CIF",
"You can't make changes on the basic data of an confirmed order or with rows": "No puedes cambiar los datos básicos de una orden con artículos",
"INVALID_USER_NAME": "El nombre de usuario solo debe contener letras minúsculas o, a partir del segundo carácter, números o subguiones, no está permitido el uso de la letra ñ",
"You can't create a ticket for a frozen client": "No puedes crear un ticket para un cliente congelado",
"You can't create a ticket for an inactive client": "No puedes crear un ticket para un cliente inactivo",
"Tag value cannot be blank": "El valor del tag no puede quedar en blanco",
"ORDER_EMPTY": "Cesta vacía",
"You don't have enough privileges to do that": "No tienes permisos para cambiar esto",
"NO SE PUEDE DESACTIVAR EL CONSIGNAT": "NO SE PUEDE DESACTIVAR EL CONSIGNAT",
"Error. El NIF/CIF está repetido": "Error. El NIF/CIF está repetido",
"Street cannot be empty": "Dirección no puede estar en blanco",
"City cannot be empty": "Ciudad no puede estar en blanco",
"Code cannot be blank": "Código no puede estar en blanco",
"You cannot remove this department": "No puedes eliminar este departamento",
"The extension must be unique": "La extensión debe ser unica",
"The secret can't be blank": "La contraseña no puede estar en blanco",
"We weren't able to send this SMS": "No hemos podido enviar el SMS",
"This client can't be invoiced": "Este cliente no puede ser facturado",
"You must provide the correction information to generate a corrective invoice": "Debes informar la información de corrección para generar una factura rectificativa",
"This ticket can't be invoiced": "Este ticket no puede ser facturado",
"You cannot add or modify services to an invoiced ticket": "No puedes añadir o modificar servicios a un ticket facturado",
"This ticket can not be modified": "Este ticket no puede ser modificado",
"The introduced hour already exists": "Esta hora ya ha sido introducida",
"INFINITE_LOOP": "Existe una dependencia entre dos Jefes",
"The sales of the receiver ticket can't be modified": "Las lineas del ticket al que envias no pueden ser modificadas",
"NO_AGENCY_AVAILABLE": "No hay una zona de reparto disponible con estos parámetros",
"ERROR_PAST_SHIPMENT": "No puedes seleccionar una fecha de envío en pasado",
"The current ticket can't be modified": "El ticket actual no puede ser modificado",
"The current claim can't be modified": "La reclamación actual no puede ser modificada",
"The sales of this ticket can't be modified": "Las lineas de este ticket no pueden ser modificadas",
"The sales do not exists": "La(s) línea(s) seleccionada(s) no existe(n)",
"Please select at least one sale": "Por favor selecciona al menos una linea",
"All sales must belong to the same ticket": "Todas las lineas deben pertenecer al mismo ticket",
"NO_ZONE_FOR_THIS_PARAMETERS": "Para este día no hay ninguna zona configurada",
"This item doesn't exists": "El artículo no existe",
"NOT_ZONE_WITH_THIS_PARAMETERS": "Para este día no hay ninguna zona configurada",
"Extension format is invalid": "El formato de la extensión es inválido",
"Invalid parameters to create a new ticket": "Parámetros inválidos para crear un nuevo ticket",
"This item is not available": "Este artículo no está disponible",
"This postcode already exists": "Este código postal ya existe",
"Concept cannot be blank": "El concepto no puede quedar en blanco",
"File doesn't exists": "El archivo no existe",
"You don't have privileges to change the zone": "No tienes permisos para cambiar la zona o para esos parámetros hay más de una opción de envío, hable con las agencias",
"This ticket is already on weekly tickets": "Este ticket ya está en tickets programados",
"Ticket id cannot be blank": "El id de ticket no puede quedar en blanco",
"Weekday cannot be blank": "El día de la semana no puede quedar en blanco",
"You can't delete a confirmed order": "No puedes borrar un pedido confirmado",
"The social name has an invalid format": "El nombre fiscal tiene un formato incorrecto",
"Invalid quantity": "Cantidad invalida",
"This postal code is not valid": "Este código postal no es válido",
"is invalid": "es inválido",
"The postcode doesn't exist. Please enter a correct one": "El código postal no existe. Por favor, introduce uno correcto",
"The department name can't be repeated": "El nombre del departamento no puede repetirse",
"This phone already exists": "Este teléfono ya existe",
"You cannot move a parent to its own sons": "No puedes mover un elemento padre a uno de sus hijos",
"You can't create a claim for a removed ticket": "No puedes crear una reclamación para un ticket eliminado",
"You cannot delete a ticket that part of it is being prepared": "No puedes eliminar un ticket en el que una parte que está siendo preparada",
"You must delete all the buy requests first": "Debes eliminar todas las peticiones de compra primero",
"You should specify a date": "Debes especificar una fecha",
"You should specify at least a start or end date": "Debes especificar al menos una fecha de inicio o de fin",
"Start date should be lower than end date": "La fecha de inicio debe ser menor que la fecha de fin",
"You should mark at least one week day": "Debes marcar al menos un día de la semana",
"Swift / BIC can't be empty": "Swift / BIC no puede estar vacío",
"Customs agent is required for a non UEE member": "El agente de aduanas es requerido para los clientes extracomunitarios",
"Incoterms is required for a non UEE member": "El incoterms es requerido para los clientes extracomunitarios",
"Deleted sales from ticket": "He eliminado las siguientes lineas del ticket [{{ticketId}}]({{{ticketUrl}}}): {{{deletions}}}",
"Added sale to ticket": "He añadido la siguiente linea al ticket [{{ticketId}}]({{{ticketUrl}}}): {{{addition}}}",
"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}}}",
"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}}})",
"State": "Estado",
"regular": "normal",
"reserved": "reservado",
"Changed sale reserved state": "He cambiado el estado reservado de las siguientes lineas al ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
"Bought units from buy request": "Se ha comprado {{quantity}} unidades de [{{itemId}} {{concept}}]({{{urlItem}}}) para el ticket id [{{ticketId}}]({{{url}}})",
"Deny buy request": "Se ha rechazado la petición de compra para el ticket id [{{ticketId}}]({{{url}}}). Motivo: {{observation}}",
"MESSAGE_INSURANCE_CHANGE": "He cambiado el crédito asegurado del cliente [{{clientName}} ({{clientId}})]({{{url}}}) a *{{credit}} €*",
"Changed client paymethod": "He cambiado la forma de pago del cliente [{{clientName}} ({{clientId}})]({{{url}}})",
"Sent units from ticket": "Envio *{{quantity}}* unidades de [{{concept}} ({{itemId}})]({{{itemUrl}}}) a *\"{{nickname}}\"* provenientes del ticket id [{{ticketId}}]({{{ticketUrl}}})",
"Change quantity": "{{concept}} cambia de {{oldQuantity}} a {{newQuantity}}",
"Claim will be picked": "Se recogerá el género de la reclamación [({{claimId}})]({{{claimUrl}}}) del cliente *{{clientName}}*",
"Claim state has changed to": "Se ha cambiado el estado de la reclamación [({{claimId}})]({{{claimUrl}}}) del cliente *{{clientName}}* a *{{newState}}*",
"Client checked as validated despite of duplication": "Cliente comprobado a pesar de que existe el cliente id {{clientId}}",
"ORDER_ROW_UNAVAILABLE": "No hay disponibilidad de este producto",
"Distance must be lesser than 1000": "La distancia debe ser inferior a 1000",
"This ticket is deleted": "Este ticket está eliminado",
"Unable to clone this travel": "No ha sido posible clonar este travel",
"This thermograph id already exists": "La id del termógrafo ya existe",
"Choose a date range or days forward": "Selecciona un rango de fechas o días en adelante",
"ORDER_ALREADY_CONFIRMED": "ORDEN YA CONFIRMADA",
"Invalid password": "Invalid password",
"Password does not meet requirements": "La contraseña no cumple los requisitos",
"Role already assigned": "Rol ya asignado",
"Invalid role name": "Nombre de rol no válido",
"Role name must be written in camelCase": "El nombre del rol debe escribirse en camelCase",
"Email already exists": "El correo ya existe",
"User already exists": "El/La usuario/a ya existe",
"Absence change notification on the labour calendar": "Notificación de cambio de ausencia en el calendario laboral",
"Record of hours week": "Registro de horas semana {{week}} año {{year}} ",
"Created absence": "El empleado <strong>{{author}}</strong> ha añadido una ausencia de tipo '{{absenceType}}' a <a href='{{{workerUrl}}}'><strong>{{employee}}</strong></a> para el día {{dated}}.",
"Deleted absence": "El empleado <strong>{{author}}</strong> ha eliminado una ausencia de tipo '{{absenceType}}' a <a href='{{{workerUrl}}}'><strong>{{employee}}</strong></a> del día {{dated}}.",
"I have deleted the ticket id": "He eliminado el ticket id [{{id}}]({{{url}}})",
"I have restored the ticket id": "He restaurado el ticket id [{{id}}]({{{url}}})",
"You can only restore a ticket within the first hour after deletion": "Únicamente puedes restaurar el ticket dentro de la primera hora después de su eliminación",
"Changed this data from the ticket": "He cambiado estos datos del ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
"agencyModeFk": "Agencia",
"clientFk": "Cliente",
"zoneFk": "Zona",
"warehouseFk": "Almacén",
"shipped": "F. envío",
"landed": "F. entrega",
"addressFk": "Consignatario",
"companyFk": "Empresa",
"The social name cannot be empty": "La razón social no puede quedar en blanco",
"The nif cannot be empty": "El NIF no puede quedar en blanco",
"You need to fill sage information before you check verified data": "Debes rellenar la información de sage antes de marcar datos comprobados",
"ASSIGN_ZONE_FIRST": "Asigna una zona primero",
"Amount cannot be zero": "El importe no puede ser cero",
"Company has to be official": "Empresa inválida",
"You can not select this payment method without a registered bankery account": "No se puede utilizar este método de pago si no has registrado una cuenta bancaria",
"Action not allowed on the test environment": "Esta acción no está permitida en el entorno de pruebas",
"The selected ticket is not suitable for this route": "El ticket seleccionado no es apto para esta ruta",
"New ticket request has been created with price": "Se ha creado una nueva petición de compra '{{description}}' para el día *{{shipped}}*, con una cantidad de *{{quantity}}* y un precio de *{{price}} €*",
"New ticket request has been created": "Se ha creado una nueva petición de compra '{{description}}' para el día *{{shipped}}*, con una cantidad de *{{quantity}}*",
"Swift / BIC cannot be empty": "Swift / BIC no puede estar vacío",
"This BIC already exist.": "Este BIC ya existe.",
"That item doesn't exists": "Ese artículo no existe",
"There's a new urgent ticket:": "Hay un nuevo ticket urgente:",
"Invalid account": "Cuenta inválida",
"Compensation account is empty": "La cuenta para compensar está vacia",
"This genus already exist": "Este genus ya existe",
"This specie already exist": "Esta especie ya existe",
"Client assignment has changed": "He cambiado el comercial ~*\"<{{previousWorkerName}}>\"*~ por *\"<{{currentWorkerName}}>\"* del cliente [{{clientName}} ({{clientId}})]({{{url}}})",
"None": "Ninguno",
"The contract was not active during the selected date": "El contrato no estaba activo durante la fecha seleccionada",
"Cannot add more than one '1/2 day vacation'": "No puedes añadir más de un 'Vacaciones 1/2 dia'",
"This document already exists on this ticket": "Este documento ya existe en el ticket",
"Some of the selected tickets are not billable": "Algunos de los tickets seleccionados no son facturables",
"You can't invoice tickets from multiple clients": "No puedes facturar tickets de multiples clientes",
"nickname": "nickname",
"INACTIVE_PROVIDER": "Proveedor inactivo",
"This client is not invoiceable": "Este cliente no es facturable",
"serial non editable": "Esta serie no permite asignar la referencia",
"Max shipped required": "La fecha límite es requerida",
"Can't invoice to future": "No se puede facturar a futuro",
"Can't invoice to past": "No se puede facturar a pasado",
"This ticket is already invoiced": "Este ticket ya está facturado",
"A ticket with an amount of zero can't be invoiced": "No se puede facturar un ticket con importe cero",
"A ticket with a negative base can't be invoiced": "No se puede facturar un ticket con una base negativa",
"Global invoicing failed": "[Facturación global] No se han podido facturar algunos clientes",
"Wasn't able to invoice the following clients": "No se han podido facturar los siguientes clientes",
"Can't verify data unless the client has a business type": "No se puede verificar datos de un cliente que no tiene tipo de negocio",
"You don't have enough privileges to set this credit amount": "No tienes suficientes privilegios para establecer esta cantidad de crédito",
"You can't change the credit set to zero from a financialBoss": "No puedes cambiar el cŕedito establecido a cero por un jefe de finanzas",
"Amounts do not match": "Las cantidades no coinciden",
"The PDF document does not exist": "El documento PDF no existe. Prueba a regenerarlo desde la opción 'Regenerar PDF factura'",
"The type of business must be filled in basic data": "El tipo de negocio debe estar rellenado en datos básicos",
"You can't create a claim from a ticket delivered more than seven days ago": "No puedes crear una reclamación de un ticket entregado hace más de siete días",
"The worker has hours recorded that day": "El trabajador tiene horas fichadas ese día",
"The worker has a marked absence that day": "El trabajador tiene marcada una ausencia ese día",
"You can not modify is pay method checked": "No se puede modificar el campo método de pago validado",
"The account size must be exactly 10 characters": "El tamaño de la cuenta debe ser exactamente de 10 caracteres",
"Can't transfer claimed sales": "No puedes transferir lineas reclamadas",
"You don't have privileges to create refund": "No tienes permisos para crear un abono",
"The item is required": "El artículo es requerido",
"The agency is already assigned to another autonomous": "La agencia ya está asignada a otro autónomo",
"date in the future": "Fecha en el futuro",
"reference duplicated": "Referencia duplicada",
"This ticket is already a refund": "Este ticket ya es un abono",
"isWithoutNegatives": "Sin negativos",
"routeFk": "routeFk",
"Can't change the password of another worker": "No se puede cambiar la contraseña de otro trabajador",
"No hay un contrato en vigor": "No hay un contrato en vigor",
"No se permite fichar a futuro": "No se permite fichar a futuro",
"No está permitido trabajar": "No está permitido trabajar",
"Fichadas impares": "Fichadas impares",
"Descanso diario 12h.": "Descanso diario 12h.",
"Descanso semanal 36h. / 72h.": "Descanso semanal 36h. / 72h.",
"Dirección incorrecta": "Dirección incorrecta",
"Modifiable user details only by an administrator": "Detalles de usuario modificables solo por un administrador",
"Modifiable password only via recovery or by an administrator": "Contraseña modificable solo a través de la recuperación o por un administrador",
"Not enough privileges to edit a client": "No tienes suficientes privilegios para editar un cliente",
"This route does not exists": "Esta ruta no existe",
"Claim pickup order sent": "Reclamación Orden de recogida enviada [{{claimId}}]({{{claimUrl}}}) al cliente *{{clientName}}*",
"You don't have grant privilege": "No tienes privilegios para dar privilegios",
"You don't own the role and you can't assign it to another user": "No eres el propietario del rol y no puedes asignarlo a otro usuario",
"Ticket merged": "Ticket [{{originId}}]({{{originFullPath}}}) ({{{originDated}}}) fusionado con [{{destinationId}}]({{{destinationFullPath}}}) ({{{destinationDated}}})",
"Already has this status": "Ya tiene este estado",
"There aren't records for this week": "No existen registros para esta semana",
"Empty data source": "Origen de datos vacio",
"App locked": "Aplicación bloqueada por el usuario {{userId}}",
"Email verify": "Correo de verificación",
"Landing cannot be lesser than shipment": "Landing cannot be lesser than shipment",
"Receipt's bank was not found": "No se encontró el banco del recibo",
"This receipt was not compensated": "Este recibo no ha sido compensado",
"Client's email was not found": "No se encontró el email del cliente",
"Negative basis": "Base negativa",
"This worker code already exists": "Este codigo de trabajador ya existe",
"This personal mail already exists": "Este correo personal ya existe",
"This worker already exists": "Este trabajador ya existe",
"App name does not exist": "El nombre de aplicación no es válido",
"Try again": "Vuelve a intentarlo",
"Aplicación bloqueada por el usuario 9": "Aplicación bloqueada por el usuario 9",
"Failed to upload delivery note": "Error al subir albarán {{id}}",
"The DOCUWARE PDF document does not exists": "El documento PDF Docuware no existe",
"It is not possible to modify tracked sales": "No es posible modificar líneas de pedido que se hayan empezado a preparar",
"It is not possible to modify sales that their articles are from Floramondo": "No es posible modificar líneas de pedido cuyos artículos sean de Floramondo",
"It is not possible to modify cloned sales": "No es posible modificar líneas de pedido clonadas",
"A supplier with the same name already exists. Change the country.": "Un proveedor con el mismo nombre ya existe. Cambie el país.",
"There is no assigned email for this client": "No hay correo asignado para este cliente",
"Exists an invoice with a future date": "Existe una factura con fecha posterior",
"Invoice date can't be less than max date": "La fecha de factura no puede ser inferior a la fecha límite",
"Warehouse inventory not set": "El almacén inventario no está establecido",
"This locker has already been assigned": "Esta taquilla ya ha sido asignada",
"Tickets with associated refunds": "No se pueden borrar tickets con abonos asociados. Este ticket está asociado al abono Nº %d",
"Not exist this branch": "La rama no existe",
"This ticket cannot be signed because it has not been boxed": "Este ticket no puede firmarse porque no ha sido encajado",
"Collection does not exist": "La colección no existe",
"Cannot obtain exclusive lock": "No se puede obtener un bloqueo exclusivo",
"Insert a date range": "Inserte un rango de fechas",
"Added observation": "{{user}} añadió esta observacion: {{text}}",
"Comment added to client": "Observación añadida al cliente {{clientFk}}",
"Invalid auth code": "Código de verificación incorrecto",
"Invalid or expired verification code": "Código de verificación incorrecto o expirado",
"Cannot create a new claimBeginning from a different ticket": "No se puede crear una línea de reclamación de un ticket diferente al origen",
"company": "Compañía",
"country": "País",
"clientId": "Id cliente",
"clientSocialName": "Cliente",
"amount": "Importe",
"taxableBase": "Base",
"ticketFk": "Id ticket",
"isActive": "Activo",
"hasToInvoice": "Facturar",
"isTaxDataChecked": "Datos comprobados",
"comercialId": "Id comercial",
"comercialName": "Comercial",
"Pass expired": "La contraseña ha caducado, cambiela desde Salix",
"Invalid NIF for VIES": "Invalid NIF for VIES",
"Ticket does not exist": "Este ticket no existe",
"Ticket is already signed": "Este ticket ya ha sido firmado",
"Authentication failed": "Autenticación fallida",
"You can't use the same password": "No puedes usar la misma contraseña",
"You can only add negative amounts in refund tickets": "Solo se puede añadir cantidades negativas en tickets abono",
"Fecha fuera de rango": "Fecha fuera de rango",
"Error while generating PDF": "Error al generar PDF",
"Error when sending mail to client": "Error al enviar el correo al cliente",
"Mail not sent": "Se ha producido un fallo al enviar la factura al cliente [{{clientId}}]({{{clientUrl}}}), por favor revisa la dirección de correo electrónico",
"The renew period has not been exceeded": "El periodo de renovación no ha sido superado",
"Valid priorities": "Prioridades válidas: %d",
"hasAnyNegativeBase": "Base negativa para los tickets: {{ticketsIds}}",
"hasAnyPositiveBase": "Base positivas para los tickets: {{ticketsIds}}",
"You cannot assign an alias that you are not assigned to": "No puede asignar un alias que no tenga asignado",
"This ticket cannot be left empty.": "Este ticket no se puede dejar vacío. %s",
"The company has not informed the supplier account for bank transfers": "La empresa no tiene informado la cuenta de proveedor para transferencias bancarias",
"You cannot assign/remove an alias that you are not assigned to": "No puede asignar/eliminar un alias que no tenga asignado",
"This invoice has a linked vehicle.": "Esta factura tiene un vehiculo vinculado",
"You don't have enough privileges.": "No tienes suficientes permisos.",
"This ticket is locked": "Este ticket está bloqueado.",
"This ticket is not editable.": "Este ticket no es editable.",
"The ticket doesn't exist.": "No existe el ticket.",
"Social name should be uppercase": "La razón social debe ir en mayúscula",
"Street should be uppercase": "La dirección fiscal debe ir en mayúscula",
"Ticket without Route": "Ticket sin ruta",
"Select a different client": "Seleccione un cliente distinto",
"Fill all the fields": "Rellene todos los campos",
"The response is not a PDF": "La respuesta no es un PDF",
"Booking completed": "Reserva completada",
"The ticket is in preparation": "El ticket [{{ticketId}}]({{{ticketUrl}}}) del comercial {{salesPersonId}} está en preparación",
"Incoterms data for consignee is missing": "Faltan los datos de los Incoterms para el consignatario",
"The notification subscription of this worker cant be modified": "La subscripción a la notificación de este trabajador no puede ser modificada",
"User disabled": "Usuario desactivado",
"The amount cannot be less than the minimum": "La cantidad no puede ser menor que la cantidad mínima",
"quantityLessThanMin": "La cantidad no puede ser menor que la cantidad mínima",
"Cannot past travels with entries": "No se pueden pasar envíos con entradas",
"It was not able to remove the next expeditions:": "No se pudo eliminar las siguientes expediciones: {{expeditions}}",
"This claim has been updated": "La reclamación con Id: {{claimId}}, ha sido actualizada",
"This user does not have an assigned tablet": "Este usuario no tiene tablet asignada",
"Incorrect pin": "Pin incorrecto",
"You already have the mailAlias": "Ya tienes este alias de correo",
"The alias cant be modified": "Este alias de correo no puede ser modificado",
"No tickets to invoice": "No hay tickets para facturar",
"Name should be uppercase": "El nombre debe ir en mayúscula",
"Bank entity must be specified": "La entidad bancaria es obligatoria",
"An email is necessary": "Es necesario un email"
"An email is necessary": "Es necesario un email"
}

View File

@ -1,4 +1,4 @@
const packageJson = require('../../../package.json');
const packageJson = require(`${process.cwd()}/package.json`);
module.exports = function(options) {
return function(req, res, next) {

View File

@ -28,7 +28,7 @@ module.exports = app;
let rootDir = __dirname;
let lbDir = path.resolve(`${rootDir}/..`);
let appDir = path.resolve(`${__dirname}/../..`);
let appDir = process.cwd();
let localeDir = `${lbDir}/locale`;
let modulesDir = `${appDir}/modules`;
@ -80,13 +80,13 @@ app.boot = function(bootOptions, callback) {
`${__dirname}/model-config.json`
];
let modelSources = [
`loopback/common/models`,
`loopback/server/models`,
`${lbDir}/common/models`,
`${lbDir}/server/models`,
`${__dirname}/../common/models`
];
let mixinDirs = [
`loopback/common/mixins`,
`loopback/server/mixins`,
`${lbDir}/common/mixins`,
`${lbDir}/server/mixins`,
`${__dirname}/../common/mixins`
];
let bootDirs = [

View File

@ -2,13 +2,17 @@ module.exports = Self => {
Self.remoteMethodCtx('clone', {
description: 'Clone the invoiceIn and as many invoiceInTax and invoiceInDueDay referencing it',
accessType: 'WRITE',
accepts: {
accepts: [{
arg: 'id',
type: 'number',
required: true,
description: 'The invoiceIn id',
http: {source: 'path'}
},
}, {
arg: 'isRectification',
type: 'boolean',
description: 'Clone quantities in negative and clone Intrastat'
}],
returns: {
type: 'object',
root: true
@ -19,7 +23,7 @@ module.exports = Self => {
}
});
Self.clone = async(ctx, id, options) => {
Self.clone = async(ctx, id, isRectification, options) => {
const models = Self.app.models;
let tx;
const myOptions = {};
@ -45,14 +49,28 @@ module.exports = Self => {
'isVatDeductible',
'withholdingSageFk',
'deductibleExpenseFk',
]
],
include: [
{
relation: 'invoiceInTax',
},
{
relation: 'invoiceInDueDay',
},
{
relation: 'invoiceInIntrastat'
}
],
}, myOptions);
const sourceInvoiceInTax = await models.InvoiceInTax.find({where: {invoiceInFk: id}}, myOptions);
const sourceInvoiceInDueDay = await models.InvoiceInDueDay.find({where: {invoiceInFk: id}}, myOptions);
const invoiceInTax = sourceInvoiceIn.invoiceInTax();
const invoiceInDueDay = sourceInvoiceIn.invoiceInDueDay();
const invoiceInIntrastat = sourceInvoiceIn.invoiceInIntrastat();
const issued = new Date(sourceInvoiceIn.issued);
issued.setMonth(issued.getMonth() + 1);
const clonedRef = sourceInvoiceIn.supplierRef + '(2)';
const totalCorrections = await models.InvoiceInCorrection.count({correctedFk: id}, myOptions);
const clonedRef = sourceInvoiceIn.supplierRef + `(${totalCorrections + 2})`;
const clone = await models.InvoiceIn.create({
serial: sourceInvoiceIn.serial,
@ -68,30 +86,44 @@ module.exports = Self => {
const promises = [];
for (let tax of sourceInvoiceInTax) {
for (let tax of invoiceInTax) {
promises.push(models.InvoiceInTax.create({
invoiceInFk: clone.id,
taxableBase: tax.taxableBase,
taxableBase: isRectification ? -tax.taxableBase : tax.taxableBase,
expenseFk: tax.expenseFk,
foreignValue: tax.foreignValue,
foreignValue: isRectification ? -tax.foreignValue : tax.foreignValue,
taxTypeSageFk: tax.taxTypeSageFk,
transactionTypeSageFk: tax.transactionTypeSageFk
}, myOptions));
}
for (let dueDay of sourceInvoiceInDueDay) {
const dueDated = dueDay.dueDated;
dueDated.setMonth(dueDated.getMonth() + 1);
if (!isRectification) {
for (let dueDay of invoiceInDueDay) {
const dueDated = dueDay.dueDated;
dueDated.setMonth(dueDated.getMonth() + 1);
promises.push(models.InvoiceInDueDay.create({
invoiceInFk: clone.id,
dueDated: dueDated,
bankFk: dueDay.bankFk,
amount: dueDay.amount,
foreignValue: dueDated.foreignValue,
}, myOptions));
promises.push(models.InvoiceInDueDay.create({
invoiceInFk: clone.id,
dueDated: dueDated,
bankFk: dueDay.bankFk,
amount: dueDay.amount,
foreignValue: dueDated.foreignValue,
}, myOptions));
}
} else {
for (let intrastat of invoiceInIntrastat) {
promises.push(models.InvoiceInIntrastat.create({
invoiceInFk: clone.id,
net: -intrastat.net,
intrastatFk: intrastat.intrastatFk,
amount: -intrastat.amount,
stems: -intrastat.stems,
country: intrastat.countryFk,
dated: Date.vnNew(),
statisticalValue: intrastat.statisticalValue
}, myOptions));
}
}
await Promise.all(promises);
if (tx) await tx.commit();

View File

@ -0,0 +1,58 @@
module.exports = Self => {
Self.remoteMethodCtx('corrective', {
description: 'Creates a rectificated invoice in',
accessType: 'WRITE',
accepts: [{
arg: 'id',
type: 'number'
}, {
arg: 'invoiceReason',
type: 'number',
}, {
arg: 'invoiceType',
type: 'number',
}, {
arg: 'invoiceClass',
type: 'number'
}],
returns: {
type: 'number',
root: true
},
http: {
path: '/corrective',
verb: 'POST'
}
});
Self.corrective = async(ctx, id, invoiceReason, invoiceType, invoiceClass, options) => {
const models = Self.app.models;
const myOptions = {};
let tx;
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const clone = await Self.clone(ctx, id, true, myOptions);
await models.InvoiceInCorrection.create({
correctingFk: clone.id,
correctedFk: id,
cplusRectificationTypeFk: invoiceType,
siiTypeInvoiceOutFk: invoiceClass,
invoiceCorrectionTypeFk: invoiceReason
}, myOptions);
if (tx) await tx.commit();
return clone.id;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
};
};

View File

@ -1,4 +1,3 @@
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
const buildFilter = require('vn-loopback/util/filter').buildFilter;
const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
@ -80,6 +79,11 @@ module.exports = Self => {
type: 'boolean',
description: 'Whether the invoice is booked or not',
},
{
arg: 'correctedFk',
type: 'number',
description: 'The corrected invoice',
}
],
returns: {
type: ['object'],
@ -93,6 +97,7 @@ module.exports = Self => {
Self.filter = async(ctx, filter, options) => {
const conn = Self.dataSource.connector;
const models = Self.app.models;
const args = ctx.args;
const myOptions = {};
@ -105,6 +110,14 @@ module.exports = Self => {
dateTo.setHours(23, 59, 0, 0);
}
let correctings;
if (args.correctedFk) {
correctings = await models.InvoiceInCorrection.find({
fields: ['correctingFk'],
where: {correctedFk: args.correctedFk}
});
}
const where = buildFilter(ctx.args, (param, value) => {
switch (param) {
case 'search':
@ -128,6 +141,8 @@ module.exports = Self => {
return {[`ii.${param}`]: value};
case 'awbCode':
return {'sub.code': value};
case 'correctedFk':
return {'ii.id': {inq: correctings.map(x => x.correctingFk)}};
}
});

View File

@ -2,50 +2,75 @@ const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('invoiceIn clone()', () => {
beforeAll(async() => {
const activeCtx = {
accessToken: {userId: 9},
http: {
req: {
headers: {origin: 'http://localhost'}
}
}
let ctx;
let options;
let tx;
beforeEach(async() => {
ctx = {
req: {
accessToken: {userId: 1},
headers: {origin: 'http://localhost'}
},
args: {}
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
active: ctx.req
});
options = {transaction: tx};
tx = await models.Sale.beginTransaction({});
options.transaction = tx;
});
afterEach(async() => {
await tx.rollback();
});
it('should return the cloned invoiceIn and also clone invoiceInDueDays and invoiceInTaxes if there are any referencing the invoiceIn', async() => {
const userId = 1;
const ctx = {
req: {
const clone = await models.InvoiceIn.clone(ctx, 1, false, options);
accessToken: {userId: userId},
headers: {origin: 'http://localhost:5000'},
expect(clone.supplierRef).toEqual('1234(2)');
const invoiceIn = await models.InvoiceIn.findOne({
include: [
{
relation: 'invoiceInTax',
},
{
relation: 'invoiceInDueDay',
}
], where: {
id: clone.id
}
};
}, options);
const invoiceInTax = invoiceIn.invoiceInTax();
const invoiceInDueDay = invoiceIn.invoiceInDueDay();
const tx = await models.InvoiceIn.beginTransaction({});
const options = {transaction: tx};
expect(invoiceInTax.length).toEqual(2);
expect(invoiceInDueDay.length).toEqual(2);
});
try {
const clone = await models.InvoiceIn.clone(ctx, 1, options);
it('should return the cloned invoiceIn and also clone invoiceInIntrastat and invoiceInTaxes if it is rectificative', async() => {
const clone = await models.InvoiceIn.clone(ctx, 1, true, options);
expect(clone.supplierRef).toEqual('1234(2)');
expect(clone.supplierRef).toEqual('1234(2)');
const invoiceIn = await models.InvoiceIn.findOne({
include: [
{
relation: 'invoiceInTax',
},
{
relation: 'invoiceInIntrastat',
}
], where: {
id: clone.id
}
}, options);
const invoiceInTax = invoiceIn.invoiceInTax();
const invoiceInIntrastat = invoiceIn.invoiceInIntrastat();
const invoiceInTaxes = await models.InvoiceInTax.find({where: {invoiceInFk: clone.id}}, options);
expect(invoiceInTaxes.length).toEqual(2);
const invoiceInDueDays = await models.InvoiceInDueDay.find({where: {invoiceInFk: clone.id}}, options);
expect(invoiceInDueDays.length).toEqual(2);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
expect(invoiceInTax.length).toEqual(2);
expect(invoiceInIntrastat.length).toEqual(2);
});
});

View File

@ -0,0 +1,49 @@
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('invoiceIn corrective()', () => {
let ctx;
let options;
let tx;
beforeEach(async() => {
ctx = {
req: {
accessToken: {userId: 9},
headers: {origin: 'http://localhost'}
},
args: {}
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: ctx.req
});
options = {transaction: tx};
tx = await models.Sale.beginTransaction({});
options.transaction = tx;
});
afterEach(async() => {
await tx.rollback();
});
it('La función corrective debería devolver un id cuando se ejecuta correctamente', async() => {
const originalId = 1;
const invoiceReason = 3;
const invoiceType = 2;
const invoiceClass = 1;
const cloneId = await models.InvoiceIn.corrective(ctx,
originalId, invoiceReason, invoiceType, invoiceClass, options);
expect(cloneId).toBeDefined();
const correction = await models.InvoiceInCorrection.findOne({
where: {correctedFk: originalId, correctingFk: cloneId}
}, options);
expect(correction.cplusRectificationTypeFk).toEqual(invoiceType);
expect(correction.siiTypeInvoiceOutFk).toEqual(invoiceClass);
expect(correction.invoiceCorrectionTypeFk).toEqual(invoiceReason);
});
});

View File

@ -8,14 +8,14 @@ describe('InvoiceIn filter()', () => {
try {
const ctx = {
args: {
search: 'Plants SL',
search: 'PLANTS SL',
}
};
const result = await models.InvoiceIn.filter(ctx, {}, options);
expect(result.length).toEqual(5);
expect(result[0].supplierName).toEqual('Plants SL');
expect(result[0].supplierName).toEqual('PLANTS SL');
await tx.rollback();
} catch (e) {

View File

@ -5,6 +5,9 @@
"InvoiceInConfig": {
"dataSource": "vn"
},
"InvoiceInCorrection": {
"dataSource": "vn"
},
"InvoiceInDueDay": {
"dataSource": "vn"
},

View File

@ -0,0 +1,38 @@
{
"name": "InvoiceInCorrection",
"base": "VnModel",
"options": {
"mysql": {
"table": "invoiceInCorrection"
}
},
"properties": {
"correctingFk": {
"id": true,
"type": "number"
}
},
"relations": {
"invoiceIn": {
"type": "belongsTo",
"model": "InvoiceIn",
"foreignKey": "correctedFk"
},
"cplusRectificationType": {
"type": "belongsTo",
"model": "CplusRectificationType",
"foreignKey": "cplusRectificationTypeFk"
},
"invoiceCorrectionType": {
"type": "belongsTo",
"model": "InvoiceCorrectionType",
"foreignKey": "invoiceCorrectionTypeFk"
},
"siiTypeInvoiceOut": {
"type": "belongsTo",
"model": "SiiTypeInvoiceOut",
"foreignKey": "siiTypeInvoiceOutFk"
}
}
}

View File

@ -9,6 +9,8 @@ module.exports = Self => {
require('../methods/invoice-in/invoiceInPdf')(Self);
require('../methods/invoice-in/invoiceInEmail')(Self);
require('../methods/invoice-in/getSerial')(Self);
require('../methods/invoice-in/corrective')(Self);
Self.rewriteDbError(function(err) {
if (err.code === 'ER_ROW_IS_REFERENCED_2' && err.sqlMessage.includes('vehicleInvoiceIn'))
return new UserError(`This invoice has a linked vehicle.`);

View File

@ -103,6 +103,11 @@
"type": "belongsTo",
"model": "Dms",
"foreignKey": "dmsFk"
},
"invoiceInCorrection": {
"type": "hasOne",
"model": "InvoiceInCorrection",
"foreignKey": "correctedFk"
}
}
}

View File

@ -17,6 +17,9 @@
},
"description": {
"type": "string"
},
"code": {
"type": "string"
}
}
}

View File

@ -5,7 +5,7 @@ describe('Supplier getSummary()', () => {
const supplier = await app.models.Supplier.getSummary(1);
expect(supplier.id).toEqual(1);
expect(supplier.name).toEqual('Plants SL');
expect(supplier.name).toEqual('PLANTS SL');
expect(supplier.nif).toEqual('06089160W');
expect(supplier.account).toEqual('4100000001');
expect(supplier.payDay).toEqual(15);

View File

@ -25,13 +25,13 @@ describe('Supplier newSupplier()', () => {
try {
const options = {transaction: tx};
ctx.args = {
name: 'newSupplier',
name: 'NEWSUPPLIER',
nif: '12345678Z'
};
const result = await models.Supplier.newSupplier(ctx, options);
expect(result.name).toEqual('newSupplier');
expect(result.name).toEqual('NEWSUPPLIER');
await tx.rollback();
} catch (e) {
await tx.rollback();

View File

@ -6,7 +6,7 @@ describe('Supplier updateFiscalData', () => {
const administrativeId = 5;
const employeeId = 1;
const defaultData = {
name: 'Plants SL',
name: 'PLANTS SL',
nif: '06089160W',
account: '4100000001',
sageTaxTypeFk: 4,
@ -56,7 +56,7 @@ describe('Supplier updateFiscalData', () => {
});
ctx.args = {
name: 'Weapon Dealer',
name: 'WEAPON DEALER',
nif: 'A68446004',
account: '4000000005',
sageTaxTypeFk: 5,
@ -72,7 +72,7 @@ describe('Supplier updateFiscalData', () => {
const result = await app.models.Supplier.updateFiscalData(ctx, supplierId);
expect(result.name).toEqual('Weapon Dealer');
expect(result.name).toEqual('WEAPON DEALER');
expect(result.nif).toEqual('A68446004');
expect(result.account).toEqual('4000000005');
expect(result.sageTaxTypeFk).toEqual(5);

View File

@ -129,7 +129,7 @@ describe('loopback model Supplier', () => {
const options = {transaction: tx};
try {
const newSupplier = await models.Supplier.create({name: 'Alfred Pennyworth'}, options);
const newSupplier = await models.Supplier.create({name: 'ALFRED PENNYWORTH'}, options);
const fetchedSupplier = await models.Supplier.findById(newSupplier.id, null, options);
expect(Number(fetchedSupplier.account)).toEqual(4100000000 + newSupplier.id);

View File

@ -46,6 +46,12 @@ module.exports = Self => {
Self.validateAsync('postCode', hasValidPostcode, {
message: `The postcode doesn't exist. Please enter a correct one`
});
Self.validatesFormatOf('name', {
message: 'Name should be uppercase',
allowNull: false,
allowBlank: false,
with: /^[^a-z]*$/
});
async function hasValidPostcode(err, done) {
if (!this.postcode)

View File

@ -12,7 +12,8 @@
<vn-textfield
label="Supplier name"
ng-model="$ctrl.supplier.name"
vn-focus>
vn-focus
ng-keyup="$ctrl.supplier.name = $ctrl.supplier.name.toUpperCase()">
</vn-textfield>
</vn-horizontal>
</vn-card>

View File

@ -1,4 +1,32 @@
module.exports = Self => {
Self.remoteMethodCtx('clone', {
description: 'Clone sales and services provided',
accessType: 'WRITE',
accepts: [
{
arg: 'salesIds',
type: ['number'],
}, {
arg: 'servicesIds',
type: ['number']
}, {
arg: 'withWarehouse',
type: 'boolean',
required: true
}, {
arg: 'negative',
type: 'boolean'
}
],
returns: {
type: ['object'],
root: true
},
http: {
path: `/clone`,
verb: 'POST'
}
});
Self.clone = async(ctx, salesIds, servicesIds, withWarehouse, negative, options) => {
const models = Self.app.models;
const myOptions = {};

View File

@ -1,61 +0,0 @@
module.exports = Self => {
Self.remoteMethodCtx('refund', {
description: 'Create refund tickets with sales and services if provided',
accessType: 'WRITE',
accepts: [
{
arg: 'salesIds',
type: ['number'],
},
{
arg: 'servicesIds',
type: ['number']
},
{
arg: 'withWarehouse',
type: 'boolean',
required: true
}
],
returns: {
type: ['object'],
root: true
},
http: {
path: `/refund`,
verb: 'post'
}
});
Self.refund = async(ctx, salesIds, servicesIds, withWarehouse, options) => {
const models = Self.app.models;
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 refundsTicket = await models.Sale.clone(
ctx,
salesIds,
servicesIds,
withWarehouse,
true,
myOptions
);
if (tx) await tx.commit();
return refundsTicket;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
};
};

View File

@ -67,4 +67,34 @@ describe('Ticket cloning - clone function', () => {
expect(services.length).toBeGreaterThan(0);
}
});
it('should create a ticket without sales', async() => {
const servicesIds = [4];
const tickets = await models.Sale.clone(ctx, null, servicesIds, false, false, options);
const refundedTicket = await getTicketRefund(tickets[0].id, options);
expect(refundedTicket).toBeDefined();
});
});
async function getTicketRefund(id, options) {
return models.Ticket.findOne({
where: {
id
},
include: [
{
relation: 'ticketSales',
scope: {
include: {
relation: 'components'
}
}
},
{
relation: 'ticketServices',
}
]
}, options);
}

View File

@ -1,101 +0,0 @@
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('Sale refund()', () => {
const userId = 5;
const ctx = {req: {accessToken: userId}, args: {}};
const activeCtx = {
accessToken: {userId},
};
const servicesIds = [3];
const withWarehouse = true;
beforeEach(() => {
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
it('should create ticket with the selected lines', async() => {
const tx = await models.Sale.beginTransaction({});
const salesIds = [7, 8];
try {
const options = {transaction: tx};
const refundedTickets = await models.Sale.refund(ctx, salesIds, servicesIds, withWarehouse, options);
expect(refundedTickets).toBeDefined();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should create one ticket for each unique ticketFk in the sales', async() => {
const tx = await models.Sale.beginTransaction({});
const salesIds = [6, 7];
try {
const options = {transaction: tx};
const ticketsBefore = await models.Ticket.find({}, options);
const tickets = await models.Sale.refund(ctx, salesIds, servicesIds, withWarehouse, options);
const refundedTicket = await getTicketRefund(tickets[0].id, options);
const ticketsAfter = await models.Ticket.find({}, options);
const salesLength = refundedTicket.ticketSales().length;
const componentsLength = refundedTicket.ticketSales()[0].components().length;
expect(refundedTicket).toBeDefined();
expect(salesLength).toEqual(1);
expect(ticketsBefore.length).toEqual(ticketsAfter.length - 2);
expect(componentsLength).toEqual(4);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should create a ticket without sales', async() => {
const servicesIds = [4];
const tx = await models.Sale.beginTransaction({});
const options = {transaction: tx};
try {
const tickets = await models.Sale.refund(ctx, null, servicesIds, withWarehouse, options);
const refundedTicket = await getTicketRefund(tickets[0].id, options);
expect(refundedTicket).toBeDefined();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});
async function getTicketRefund(id, options) {
return models.Ticket.findOne({
where: {
id
},
include: [
{
relation: 'ticketSales',
scope: {
include: {
relation: 'components'
}
}
},
{
relation: 'ticketServices',
}
]
}, options);
}

View File

@ -108,6 +108,23 @@ module.exports = function(Self) {
await Self.rawSql('CALL invoiceOutBooking(?)', [resultInvoice.id], myOptions);
const client = await models.Client.findById(clientId,
{fields: ['hasElectronicInvoice', 'name', 'email']}, myOptions);
if (client.hasElectronicInvoice) {
const url = await models.Url.getUrl();
await models.NotificationQueue.create({
notificationFk: 'invoice-electronic',
authorFk: client.id,
params: JSON.stringify(
{
'name': client.name,
'email': client.email,
'ticketId': ticketsIds.join(','),
'url': url + 'ticket/index?q=' + encodeURIComponent(JSON.stringify({clientFk: clientId}))
})
}, myOptions);
}
if (tx) await tx.commit();
return resultInvoice.id;

View File

@ -20,7 +20,7 @@ module.exports = Self => {
},
http: {
path: `/refund`,
verb: 'post'
verb: 'POST'
}
});
@ -45,7 +45,7 @@ module.exports = Self => {
const services = await models.TicketService.find(filter, myOptions);
const servicesIds = services.map(service => service.id);
const refundedTickets = await models.Sale.refund(ctx, salesIds, servicesIds, withWarehouse, myOptions);
const refundedTickets = await models.Sale.clone(ctx, salesIds, servicesIds, withWarehouse, true, myOptions);
if (tx) await tx.commit();

View File

@ -9,7 +9,6 @@ module.exports = Self => {
require('../methods/sale/updateQuantity')(Self);
require('../methods/sale/updateConcept')(Self);
require('../methods/sale/recalculatePrice')(Self);
require('../methods/sale/refund')(Self);
require('../methods/sale/canEdit')(Self);
require('../methods/sale/usesMana')(Self);
require('../methods/sale/clone')(Self);

View File

@ -248,23 +248,6 @@ class Controller extends Section {
if (this.ticket.address.incotermsFk && !this.ticket.weight && !force)
return this.$.withoutWeightConfirmation.show();
const client = this.ticket.client;
if (client.hasElectronicInvoice) {
this.$http.post(`NotificationQueues`, {
notificationFk: 'invoice-electronic',
authorFk: client.id,
params: JSON.stringify(
{
'name': client.name,
'email': client.email,
'ticketId': this.id,
'url': window.location.href
})
}).then(() => {
this.vnApp.showSuccess(this.$t('Invoice sent'));
});
}
return this.$http.post(`Tickets/invoiceTicketsAndPdf`, {ticketsIds: [this.id]})
.then(() => this.reload())
.then(() => this.vnApp.showSuccess(this.$t('Ticket invoiced')));

View File

@ -523,8 +523,8 @@ class Controller extends Section {
if (!sales) return;
const salesIds = sales.map(sale => sale.id);
const params = {salesIds: salesIds, withWarehouse: withWarehouse};
const query = 'Sales/refund';
const params = {salesIds: salesIds, withWarehouse: withWarehouse, negative: true};
const query = 'Sales/clone';
this.$http.post(query, params).then(res => {
const [refundTicket] = res.data;
this.vnApp.showSuccess(this.$t('The following refund ticket have been created', {

View File

@ -727,9 +727,10 @@ describe('Ticket', () => {
jest.spyOn(controller.$state, 'go');
const params = {
salesIds: [1, 4],
negative: true
};
const refundTicket = {id: 99};
$httpBackend.expect('POST', 'Sales/refund', params).respond(200, [refundTicket]);
$httpBackend.expect('POST', 'Sales/clone', params).respond(200, [refundTicket]);
controller.createRefund();
$httpBackend.flush();

View File

@ -55,10 +55,10 @@ class Controller extends Section {
createRefund() {
if (!this.checkeds.length) return;
const params = {servicesIds: this.checkeds, withWarehouse: false};
const query = 'Sales/refund';
const params = {servicesIds: this.checkeds, withWarehouse: false, negative: true};
const query = 'Sales/clone';
this.$http.post(query, params).then(res => {
const refundTicket = res.data;
const [refundTicket] = res.data;
this.vnApp.showSuccess(this.$t('The following refund ticket have been created', {
ticketId: refundTicket.id
}));

View File

@ -30,13 +30,12 @@ module.exports = Self => {
if (typeof options == 'object')
Object.assign(myOptions, options);
stmts.push(new ParameterizedSQL('CALL vn.subordinateGetList(?)', [userId]));
const queryIndex = stmts.push('SELECT * FROM tmp.subordinate') - 1;
stmts.push('DROP TEMPORARY TABLE tmp.subordinate');
stmts.push(new ParameterizedSQL('CALL vn.worker_getHierarchy(?)', [userId]));
const queryIndex = stmts.push('SELECT * FROM tmp.workerHierarchyList') - 1;
stmts.push('DROP TEMPORARY TABLE tmp.workerHierarchyList');
const sql = ParameterizedSQL.join(stmts, ';');
const result = await conn.executeStmt(sql, myOptions);
return result[queryIndex];
};
};

47055
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -11,10 +11,13 @@
"engines": {
"node": ">=20"
},
"packageManager": "pnpm@8.15.1",
"dependencies": {
"axios": "^1.2.2",
"base64url": "^3.0.1",
"body-parser": "^1.19.2",
"compression": "^1.7.3",
"ejs": "2.3.1",
"form-data": "^4.0.0",
"fs-extra": "^5.0.0",
"ftps": "^1.2.0",
@ -30,18 +33,22 @@
"loopback-boot": "3.3.1",
"loopback-component-explorer": "^6.5.0",
"loopback-component-storage": "3.6.1",
"loopback-connector-mysql": "^6.2.0",
"loopback-connector": "4.11.1",
"loopback-connector-mysql": "6.2.0",
"loopback-connector-remote": "^3.4.1",
"loopback-context": "^3.5.2",
"loopback-datasource-juggler": "3.36.1",
"md5": "^2.2.1",
"mysql": "2.18.1",
"node-ssh": "^11.0.0",
"object.pick": "^1.3.0",
"puppeteer": "^21.10.0",
"require-yaml": "0.0.1",
"smbhash": "0.0.1",
"strong-error-handler": "^2.3.2",
"vn-loopback": "file:./loopback",
"vn-print": "file:./print"
"vn-loopback": "link:./loopback",
"vn-print": "link:./print",
"xmldom": "^0.6.0"
},
"devDependencies": {
"@babel/core": "^7.7.7",
@ -74,11 +81,12 @@
"html-loader-jest": "^0.2.1",
"html-webpack-plugin": "^5.5.1",
"identity-obj-proxy": "^3.0.0",
"jasmine": "^5.0.0",
"jasmine": "^5.0.2",
"jasmine-reporters": "^2.4.0",
"jasmine-spec-reporter": "^7.0.0",
"jest": "^26.0.1",
"jest-junit": "^8.0.0",
"js-yaml": "^4.1.0",
"json-loader": "^0.5.7",
"merge-stream": "^1.0.1",
"minimist": "^1.2.5",

14432
pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load Diff

2725
print/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,9 @@
"url": "https://git.verdnatura.es/salix"
},
"license": "GPL-3.0",
"packageManager": "pnpm@8.15.1",
"dependencies": {
"express": "4.14.0",
"fs-extra": "^7.0.1",
"intl": "^1.2.5",
"js-yaml": "^3.13.1",

2251
print/pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -10,7 +10,7 @@ module.exports = {
required: true
},
ticketId: {
type: [Number],
type: [String],
required: true
},
url: {

View File

@ -15,7 +15,7 @@ SELECT pack.packages,
LEFT JOIN vn.province p ON p.id = c.provinceFk
JOIN vn.ticket t ON t.refFk = io.ref
JOIN vn.address a ON a.id = t.addressFk
LEFT JOIN vn.incoterms ic ON ic.code = a.incotermsFk
JOIN vn.incoterms ic ON ic.code = a.incotermsFk
LEFT JOIN vn.customsAgent ca ON ca.id = a.customsAgentFk
JOIN vn.sale s ON s.ticketFk = t.id
JOIN (

View File

@ -1,8 +1,5 @@
SELECT IF(incotermsFk IS NULL, FALSE, TRUE) AS hasIncoterms
FROM ticket t
JOIN invoiceOut io ON io.ref = t.refFk
JOIN client c ON c.id = t.clientFk
JOIN address a ON a.id = t.addressFk
WHERE t.refFk = ?
AND IF(c.hasToinvoiceByAddress = FALSE, c.defaultAddressFk, TRUE)
LIMIT 1
SELECT COUNT(*) AS hasIncoterms
FROM invoiceOut io
JOIN vn.invoiceOutSerial ios ON ios.code = io.serial
AND ios.taxAreaFk = 'WORLD'
WHERE io.ref = ?