Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 6372-Delete-views-from-vn2008

This commit is contained in:
David Domenech 2024-01-31 14:43:16 +01:00
commit a81a42c2e7
46 changed files with 424 additions and 209 deletions

180
Jenkinsfile vendored
View File

@ -1,4 +1,9 @@
#!/usr/bin/env groovy
def PROTECTED_BRANCH
def FROM_GIT
def RUN_TESTS
pipeline {
agent any
options {
@ -6,31 +11,47 @@ pipeline {
}
environment {
PROJECT_NAME = 'salix'
STACK_NAME = "${env.PROJECT_NAME}-${env.BRANCH_NAME}"
STACK_NAME = "${env.PROJECT_NAME}-${env.BRANCH_NAME}"
}
tools {
nodejs 'node-v20'
}
stages {
stage('Checkout') {
steps {
script {
switch (env.BRANCH_NAME) {
case 'master':
env.NODE_ENV = 'production'
env.BACK_REPLICAS = 4
case 'dev':
env.NODE_ENV = 'dev'
env.BACK_REPLICAS = 1
break
case 'test':
env.NODE_ENV = 'test'
env.BACK_REPLICAS = 2
break
case 'master':
env.NODE_ENV = 'production'
env.BACK_REPLICAS = 4
break
}
}
configFileProvider([
configFile(fileId: "salix.groovy",
variable: 'GROOVY_FILE')
]) {
load env.GROOVY_FILE
}
def packageJson = readJSON file: 'package.json'
env.VERSION = packageJson.version
env.GIT_COMMIT_MSG = sh(
script: 'git log -1 --pretty=%B ${GIT_COMMIT}',
returnStdout: true
).trim()
PROTECTED_BRANCH = [
'dev',
'test',
'master'
].contains(env.BRANCH_NAME)
FROM_GIT = JOB_NAME.startsWith('gitea/')
RUN_TESTS = !PROTECTED_BRANCH && FROM_GIT
}
setEnv()
}
}
@ -38,82 +59,91 @@ pipeline {
environment {
NODE_ENV = ""
}
steps {
nodejs('node-v20') {
sh 'npm install --no-audit --prefer-offline'
sh 'gulp install --ci'
parallel {
stage('Backend') {
steps {
sh 'npm install --no-audit --prefer-offline'
}
}
stage('Frontend') {
when {
expression { return FROM_GIT }
}
steps {
sh 'npm install --no-audit --prefer-offline --prefix=front'
}
}
stage('Print') {
when {
expression { return FROM_GIT }
}
steps {
sh 'npm install --no-audit --prefer-offline --prefix=print'
}
}
}
}
stage('Test') {
when { not { anyOf {
branch 'test'
branch 'master'
}}}
when {
expression { return RUN_TESTS }
}
environment {
NODE_ENV = ""
TZ = 'Europe/Madrid'
}
parallel {
stage('Frontend') {
steps {
nodejs('node-v20') {
sh 'jest --ci --reporters=default --reporters=jest-junit --maxWorkers=4'
}
}
}
stage('Backend') {
steps {
nodejs('node-v20') {
sh 'npm run test:back:ci'
}
sh 'npm run test:back:ci'
}
}
stage('Frontend') {
steps {
sh 'jest --ci --reporters=default --reporters=jest-junit --maxWorkers=6'
}
}
}
}
stage('Build') {
when { anyOf {
branch 'test'
branch 'master'
}}
when {
expression { return PROTECTED_BRANCH && FROM_GIT }
}
environment {
CREDENTIALS = credentials('docker-registry')
}
steps {
nodejs('node-v20') {
sh 'gulp build'
}
sh 'gulp build'
dockerBuild()
}
}
stage('Deploy') {
when { anyOf {
branch 'test'
branch 'master'
}}
environment {
DOCKER_HOST = "${env.SWARM_HOST}"
when {
expression { return PROTECTED_BRANCH }
}
steps {
sh "docker stack deploy --with-registry-auth --compose-file docker-compose.yml ${env.STACK_NAME}"
}
}
stage('Database') {
when { anyOf {
branch 'test'
branch 'master'
}}
steps {
configFileProvider([
configFile(fileId: "config.${NODE_ENV}.ini",
variable: 'MYSQL_CONFIG')
]) {
sh 'mkdir -p db/remotes'
sh 'cp "$MYSQL_CONFIG" db/remotes/$NODE_ENV.ini'
parallel {
stage('Database') {
steps {
configFileProvider([
configFile(fileId: "config.${env.NODE_ENV}.ini",
variable: 'MYSQL_CONFIG')
]) {
sh 'mkdir -p db/remotes'
sh 'cp "$MYSQL_CONFIG" db/remotes/$NODE_ENV.ini'
}
sh 'npx myt push $NODE_ENV --force --commit'
}
}
nodejs('node-v20') {
sh 'npx myt push $NODE_ENV --force --commit'
stage('Docker') {
when {
expression { return FROM_GIT }
}
environment {
DOCKER_HOST = "${env.SWARM_HOST}"
}
steps {
sh "docker stack deploy --with-registry-auth --compose-file docker-compose.yml ${env.STACK_NAME}"
}
}
}
}
@ -121,7 +151,7 @@ pipeline {
post {
always {
script {
if (!['master', 'test'].contains(env.BRANCH_NAME)) {
if (RUN_TESTS) {
try {
junit 'junitresults.xml'
junit 'junit.xml'
@ -129,18 +159,28 @@ pipeline {
echo e.toString()
}
}
}
}
success {
script {
if (env.BRANCH_NAME == 'master' && FROM_GIT) {
String message = env.GIT_COMMIT_MSG
int index = message.indexOf('\n')
if (index != -1)
message = message.substring(0, index)
if (!env.COMMITTER_EMAIL || currentBuild.currentResult == 'SUCCESS') return;
try {
mail(
to: env.COMMITTER_EMAIL,
subject: "Pipeline: ${env.JOB_NAME} (${env.BUILD_NUMBER}): ${currentBuild.currentResult}",
body: "Check status at ${env.BUILD_URL}"
rocketSend(
channel: 'vn-database',
message: "*DB version uploaded:* ${message}"
+"\n$COMMITTER_EMAIL ($BRANCH_NAME)"
+"\n$GIT_URL/commit/$GIT_COMMIT",
rawMessage: true
)
} catch (e) {
echo e.toString()
}
}
}
unsuccessful {
sendEmail()
}
}
}

View File

@ -1,9 +1,10 @@
/* eslint-disable no-console */
const path = require('path');
const Myt = require('@verdnatura/myt/myt');
const Run = require('@verdnatura/myt/myt-run');
let dataSources = require('../loopback/server/datasources.json');
let myt;
let server;
process.on('warning', warning => {
console.log(warning.name);
@ -11,25 +12,33 @@ process.on('warning', warning => {
console.log(warning.stack);
});
process.on('SIGUSR2', async() => {
if (myt) await myt.deinit();
});
process.on('SIGUSR2', rmServer);
process.on('exit', rmServer);
process.on('exit', async function() {
if (myt) await myt.deinit();
});
async function rmServer() {
if (!server) return;
await server.rm();
server = null;
}
async function test() {
console.log('Building and running DB container.');
const isCI = process.argv[2] === 'ci';
myt = new Myt();
const myt = new Myt();
await myt.init({
workspace: path.join(__dirname, '..'),
random: true,
ci: isCI,
tmpfs: process.platform == 'linux',
network: isCI ? 'jenkins' : null
});
const {dbConfig} = await myt.run(Run);
server = await myt.run(Run);
await myt.deinit();
const {dbConfig} = server;
console.log('Initializing backend.');
dataSources = JSON.parse(JSON.stringify(dataSources));
Object.assign(dataSources.vn, {
@ -46,6 +55,8 @@ async function test() {
// FIXME: Workaround to wait for loopback to be ready
await app.models.Application.status();
console.log('Running tests.');
const Jasmine = require('jasmine');
const jasmine = new Jasmine();
@ -81,9 +92,13 @@ async function test() {
});
await jasmine.execute();
console.log('Stopping.');
if (app) await app.disconnect();
if (myt) await myt.deinit();
console.log('App disconnected & container removed');
await rmServer();
console.log('Tests ended.\n');
}
test();

View File

@ -6,9 +6,10 @@
*/
SET foreign_key_checks = 0;
-- CREATE ROLE 'salix';
-- GRANT 'salix' TO 'root'@'%';
-- SET DEFAULT ROLE 'salix' FOR 'root'@'%';
DROP ROLE 'salix';
CREATE ROLE 'salix';
GRANT 'salix' TO 'root'@'%';
SET DEFAULT ROLE 'salix' FOR 'root'@'%';
CREATE SCHEMA IF NOT EXISTS `vn2008`;
CREATE SCHEMA IF NOT EXISTS `tmp`;
@ -941,25 +942,25 @@ INSERT INTO `vn`.`itemFamily`(`code`, `description`)
('VT', 'Sales');
INSERT INTO `vn`.`item`(`id`, `typeFk`, `stems`, `originFk`, `description`, `producerFk`, `intrastatFk`, `expenseFk`,
`comment`, `relevancy`, `image`, `subName`, `minPrice`, `family`, `isFloramondo`, `genericFk`, `itemPackingTypeFk`, `hasMinPrice`, `packingShelve`, `weightByPiece`)
`comment`, `relevancy`, `image`, `subName`, `minPrice`, `family`, `isFloramondo`, `genericFk`, `itemPackingTypeFk`, `hasMinPrice`, `weightByPiece`)
VALUES
(1, 2, 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '1', NULL, 0, 'EMB', 0, NULL, 'V', 0, 15,3),
(2, 2, 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '2', NULL, 0, 'VT', 0, NULL, 'H', 0, 10,2),
(3, 1, 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '3', NULL, 0, 'VT', 0, NULL, NULL, 0, 5,5),
(4, 1, 1, 1, 'Increases block', 1, 05080000, 4751000000, NULL, 0, '4', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL,NULL),
(5, 3, 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '5', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL,NULL),
(6, 5, 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '6', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL,NULL),
(7, 5, 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '7', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL,NULL),
(8, 2, 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '8', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL,NULL),
(9, 2, 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '9', NULL, 0, 'VT', 1, NULL, NULL, 0, NULL,NULL),
(10, 1, 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '10', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL,NULL),
(11, 1, 1, 1, NULL, 1, 05080000, 4751000000, NULL, 0, '11', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL,NULL),
(12, 3, 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '12', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL,NULL),
(13, 5, 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '13', NULL, 1, 'VT', 1, NULL, NULL, 1, NULL,NULL),
(14, 5, 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 'VT', 1, NULL, NULL, 0, NULL,NULL),
(15, 4, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 'EMB', 0, NULL, NULL, 0, NULL,NULL),
(16, 6, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 'EMB', 0, NULL, NULL, 0, NULL,NULL),
(71, 6, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL,NULL);
(1, 2, 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '1', NULL, 0, 'EMB', 0, NULL, 'V', 0, 3),
(2, 2, 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '2', NULL, 0, 'VT', 0, NULL, 'H', 0, 2),
(3, 1, 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '3', NULL, 0, 'VT', 0, NULL, NULL, 0, 5),
(4, 1, 1, 1, 'Increases block', 1, 05080000, 4751000000, NULL, 0, '4', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL),
(5, 3, 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '5', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL),
(6, 5, 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '6', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL),
(7, 5, 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '7', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL),
(8, 2, 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '8', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL),
(9, 2, 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '9', NULL, 0, 'VT', 1, NULL, NULL, 0, NULL),
(10, 1, 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '10', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL),
(11, 1, 1, 1, NULL, 1, 05080000, 4751000000, NULL, 0, '11', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL),
(12, 3, 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '12', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL),
(13, 5, 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '13', NULL, 1, 'VT', 1, NULL, NULL, 1, NULL),
(14, 5, 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 'VT', 1, NULL, NULL, 0, NULL),
(15, 4, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 'EMB', 0, NULL, NULL, 0, NULL),
(16, 6, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 'EMB', 0, NULL, NULL, 0, NULL),
(71, 6, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL);
-- Update the taxClass after insert of the items
UPDATE `vn`.`itemTaxCountry` SET `taxClassFk` = 2

View File

@ -1,17 +0,0 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`item_updatePackingShelve`(vSelf INT, vPacking INT)
BEGIN
/**
* Actualiza el valor de item.packingShelve
*
* @param vSelf Identificador de vn.item
* @param vPacking Cantidad de unidades de venta que caben en una bandeja
*/
UPDATE vn.item i
SET i.packingShelve = vPacking
WHERE i.id = vSelf;
END$$
DELIMITER ;

View File

@ -77,7 +77,6 @@ DECLARE vIsCollection BOOL;
s.isAdded,
IF(c.workerFk IS NULL, getUser(), c.workerFk) workerFk,
IF(SUM(iss.quantity) IS NULL, 0, SUM(iss.quantity)) pickedQuantity,
i.packingShelve,
MIN(iss.created) picked,
IF(sm.id, TRUE, FALSE) hasMistake,
sg.sectorFk

View File

@ -6,15 +6,7 @@ BEGIN
DECLARE vNewPackingShelve INT;
SET NEW.editorFk = account.myUser_getId();
IF ISNULL(NEW.packingShelve) AND NOT ISNULL(NEW.packingOut) THEN
SELECT NEW.packingOut * vc.shelveVolume / vc.standardFlowerBox
INTO vNewPackingShelve
FROM vn.volumeConfig vc;
SET NEW.packingShelve = vNewPackingShelve;
END IF;
IF NEW.itemPackingTypeFk = '' THEN
SET NEW.itemPackingTypeFk = NULL;
END IF;

View File

@ -1,48 +1,25 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn`.`zoneEstimatedDelivery`
AS SELECT `t`.`zoneFk` AS `zoneFk`,
`zc`.`hour` AS `zoneClosureHour`,
`z`.`hour` AS `zoneHour`,
`sv`.`volume` AS `volume`,
`al`.`hasToRecalcPrice` AS `hasToRecalcPrice`,
`lhp`.`m3` AS `m3`,
`dl`.`minSpeed` AS `minSpeed`
FROM (
(
(
(
(
(
(
(
(
(
`vn`.`ticket` `t`
JOIN `vn`.`ticketStateToday` `tst` ON(`tst`.`ticket` = `t`.`id`)
)
JOIN `vn`.`state` `s` ON(`s`.`id` = `tst`.`state`)
)
JOIN `vn`.`saleVolume` `sv` ON(`sv`.`ticketFk` = `t`.`id`)
)
LEFT JOIN `vn`.`lastHourProduction` `lhp` ON(`lhp`.`warehouseFk` = `t`.`warehouseFk`)
)
JOIN `vn`.`warehouse` `w` ON(`w`.`id` = `t`.`warehouseFk`)
)
JOIN `vn`.`warehouseAlias` `wa` ON(`wa`.`id` = `w`.`aliasFk`)
) STRAIGHT_JOIN `vn`.`zone` `z` ON(`z`.`id` = `t`.`zoneFk`)
)
LEFT JOIN `vn`.`zoneClosure` `zc` ON(
`zc`.`zoneFk` = `t`.`zoneFk`
AND `zc`.`dated` = `util`.`VN_CURDATE`()
)
)
LEFT JOIN `cache`.`departure_limit` `dl` ON(
`dl`.`warehouse_id` = `t`.`warehouseFk`
AND `dl`.`fecha` = `util`.`VN_CURDATE`()
)
)
JOIN `vn`.`alertLevel` `al` ON(`al`.`id` = `s`.`alertLevel`)
)
WHERE `w`.`hasProduction` <> 0
AND cast(`t`.`shipped` AS date) = `util`.`VN_CURDATE`()
AS SELECT t.zoneFk,
zc.`hour` zoneClosureHour,
z.`hour` zoneHour,
sv.volume volume,
al.hasToRecalcPrice,
lhp.m3,
dl.minSpeed
FROM ticket t
JOIN ticketStateToday tst ON tst.ticket = 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()
LEFT JOIN cache.departure_limit dl ON dl.warehouse_id = t.warehouseFk
AND dl.fecha = util.VN_CURDATE()
JOIN alertLevel al ON al.id = s.alertLevel
WHERE w.hasProduction
AND DATE(t.shipped) = util.VN_CURDATE()

View File

@ -0,0 +1,3 @@
ALTER TABLE `vn`.`operator` MODIFY COLUMN linesLimit int(11) DEFAULT 20 NULL COMMENT 'Límite de lineas en una colección para la asignación de pedidos';
ALTER TABLE `vn`.`operator` MODIFY COLUMN volumeLimit decimal(10,6) DEFAULT 0.5 NULL COMMENT 'Límite de volumen en una colección para la asignación de pedidos';
ALTER TABLE `vn`.`operator` MODIFY COLUMN numberOfWagons int(11) DEFAULT 2 NULL;

View File

@ -0,0 +1,3 @@
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES
('Ticket', 'makePdfList', '*', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'invoiceTicketsAndPdf', '*', 'ALLOW', 'ROLE', 'employee');

View File

@ -0,0 +1 @@
ALTER TABLE account.roleLog DROP FOREIGN KEY roleLog_ibfk_1;

View File

@ -0,0 +1 @@
ALTER TABLE account.userLog DROP FOREIGN KEY userLog_ibfk_1;

View File

@ -0,0 +1 @@
ALTER TABLE vn.entryLog DROP FOREIGN KEY entryLog_ibfk_1;

View File

@ -0,0 +1 @@
ALTER TABLE vn.clientLog DROP FOREIGN KEY clientLog_ibfk_1;

View File

@ -0,0 +1 @@
ALTER TABLE vn.itemLog DROP FOREIGN KEY itemLogItemFk;

View File

@ -0,0 +1 @@
ALTER TABLE vn.shelvingLog DROP FOREIGN KEY shelvingLog_ibfk_1;

View File

@ -0,0 +1 @@
ALTER TABLE vn.workerLog DROP FOREIGN KEY workerFk;

View File

@ -0,0 +1 @@
ALTER TABLE vn.deviceProductionLog DROP FOREIGN KEY deviceProductionOriginFk;

View File

@ -0,0 +1 @@
ALTER TABLE vn.zoneLog DROP FOREIGN KEY zoneLog_ibfk_1;

View File

@ -0,0 +1 @@
ALTER TABLE vn.rateLog DROP FOREIGN KEY rateOriginFk;

View File

@ -0,0 +1 @@
ALTER TABLE vn.ticketLog DROP FOREIGN KEY ticketLog_ibfk_1;

View File

@ -0,0 +1 @@
ALTER TABLE vn.userLog DROP FOREIGN KEY userLog_ibfk_1;

View File

@ -0,0 +1 @@
ALTER TABLE vn.routeLog DROP FOREIGN KEY routeLog_ibfk_1;

View File

@ -0,0 +1 @@
ALTER TABLE vn.claimLog DROP FOREIGN KEY claimOriginFk;

View File

@ -0,0 +1 @@
ALTER TABLE vn.supplierLog DROP FOREIGN KEY supplierLog_supplierFk;

View File

@ -0,0 +1 @@
ALTER TABLE vn.invoiceInLog DROP FOREIGN KEY invoiceInLog_ibfk_1;

View File

@ -0,0 +1 @@
ALTER TABLE vn.travelLog DROP FOREIGN KEY travelLog_ibfk_1;

View File

@ -0,0 +1 @@
ALTER TABLE vn.packingSiteDeviceLog DROP FOREIGN KEY packingSiteDeviceLog_ibfk_1;

View File

@ -0,0 +1,6 @@
-- Place your SQL code here
USE vn;
ALTER TABLE vn.item CHANGE packingShelve packingShelve__ int(11) DEFAULT NULL NULL COMMENT '@deprecated 2024-31-01';

View File

@ -1,7 +1,7 @@
version: '3.7'
services:
front:
image: registry.verdnatura.es/salix-front:${BRANCH_NAME:?}
image: registry.verdnatura.es/salix-front:${VERSION:?}
build:
context: .
dockerfile: front/Dockerfile
@ -16,7 +16,7 @@ services:
limits:
memory: 1G
back:
image: registry.verdnatura.es/salix-back:${BRANCH_NAME:?}
image: registry.verdnatura.es/salix-back:${VERSION:?}
build: .
ports:
- 3000

View File

@ -27,6 +27,6 @@ describe('Ticket expeditions and log path', () => {
const result = await page
.countElement(selectors.ticketExpedition.expeditionRow);
expect(result).toEqual(4);
expect(result).toEqual(6);
});
});

View File

@ -41,10 +41,10 @@ describe('Supplier basic data path', () => {
expect(result).toEqual('Plants Nick SL');
});
it('should check the isSerious checkbox is now unchecked', async() => {
it('should check the isSerious checkbox is now checked', async() => {
const result = await page.checkboxState(selectors.supplierBasicData.isSerious);
expect(result).toBe('unchecked');
expect(result).toBe('checked');
});
it('should check the isActive checkbox is now unchecked', async() => {

View File

@ -0,0 +1,31 @@
module.exports = Self => {
Self.remoteMethodCtx('makePdfList', {
description: 'Handle a list of invoices to generate PDF and send it to client',
accessType: 'WRITE',
accepts: [
{
arg: 'ids',
type: ['number'],
description: 'The invoice id',
required: true,
http: {source: 'path'}
}, {
arg: 'printerFk',
type: 'number',
description: 'The printer to print'
}
],
http: {
path: '/:id/makePdfList',
verb: 'POST'
}
});
Self.makePdfList = async function(ctx, ids, printerFk, options) {
const pdfs = ids.map(id =>
Self.makePdfAndNotify(ctx, id, printerFk, options)
);
await Promise.all(pdfs);
};
};

View File

@ -17,6 +17,7 @@ describe('InvoiceOut transferInvoice()', () => {
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
spyOn(models.InvoiceOut, 'makePdfAndNotify');
});
it('should return the id of the created issued invoice', async() => {

View File

@ -86,17 +86,17 @@ module.exports = Self => {
clonedTicketIds.push(clonedTicket.id);
}
const invoiceCorrection =
{correctedFk: id, cplusRectificationTypeFk, siiTypeInvoiceOutFk, invoiceCorrectionTypeFk};
const invoiceCorrection = {
correctedFk: id,
cplusRectificationTypeFk,
siiTypeInvoiceOutFk,
invoiceCorrectionTypeFk
};
const refundTicketIds = refundTickets.map(ticket => ticket.id);
await models.Ticket.invoiceTickets(ctx, refundTicketIds, invoiceCorrection, myOptions);
const [invoiceId] = await models.Ticket.invoiceTickets(ctx, clonedTicketIds, null, myOptions);
if (tx) {
await tx.commit();
await models.InvoiceOut.makePdfAndNotify(ctx, invoiceId, null);
}
const [invoiceId] = await models.Ticket.invoiceTicketsAndPdf(ctx, clonedTicketIds, null, myOptions);
return invoiceId;
} catch (e) {

View File

@ -13,6 +13,7 @@ module.exports = Self => {
require('../methods/invoiceOut/createManualInvoice')(Self);
require('../methods/invoiceOut/clientsToInvoice')(Self);
require('../methods/invoiceOut/invoiceClient')(Self);
require('../methods/invoiceOut/makePdfList')(Self);
require('../methods/invoiceOut/makePdfAndNotify')(Self);
require('../methods/invoiceOut/refund')(Self);
require('../methods/invoiceOut/invoiceEmail')(Self);

View File

@ -143,15 +143,12 @@
"isFloramondo": {
"type": "boolean"
},
"packingShelve": {
"type": "number"
},
"isLaid": {
"type": "boolean"
},
"isPhotoRequested": {
"type": "boolean",
"mysql":{
"mysql": {
"columnName": "doPhoto"
}
},
@ -226,4 +223,4 @@
}
}
}
}
}

View File

@ -76,15 +76,11 @@ module.exports = function(Self) {
for (const ticketIds of ticketsByAddress)
invoicesIds.push(await createInvoice(ctx, companyId, ticketIds, invoiceCorrection, myOptions));
if (tx) await tx.commit();
tx && await tx.commit();
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
if (tx) {
for (const invoiceId of invoicesIds)
await models.InvoiceOut.makePdfAndNotify(ctx, invoiceId, null);
}
return invoicesIds;
};

View File

@ -0,0 +1,36 @@
module.exports = function(Self) {
Self.remoteMethodCtx('invoiceTicketsAndPdf', {
description: 'Make out an invoice from one or more tickets',
accessType: 'WRITE',
accepts: [
{
arg: 'ticketsIds',
description: 'The tickets id',
type: ['number'],
required: true
},
{
arg: 'invoiceCorrection',
description: 'The invoice correction',
type: 'object',
}
],
returns: {
type: ['object'],
root: true
},
http: {
path: `/invoiceTicketsAndPdf`,
verb: 'POST'
}
});
Self.invoiceTicketsAndPdf = async(ctx, ticketsIds, invoiceCorrection, options) => {
const invoiceIds = await Self.invoiceTickets(ctx, ticketsIds, invoiceCorrection, options);
await Self.app.models.InvoiceOut.makePdfList(ctx, invoiceIds, null, options);
return invoiceIds;
};
};

View File

@ -102,7 +102,7 @@ describe('ticket invoiceTickets()', () => {
const options = {transaction: tx};
const ticketsIds = [11];
const invoicesIds = await models.Ticket.invoiceTickets(ctx, ticketsIds, null, options);
const invoicesIds = await models.Ticket.invoiceTicketsAndPdf(ctx, ticketsIds, null, options);
expect(invoicesIds.length).toBeGreaterThan(0);

View File

@ -0,0 +1,115 @@
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('ticket invoiceTicketsAndPdf()', () => {
const userId = 19;
const clientId = 1102;
const activeCtx = {
getLocale: () => {
return 'en';
},
accessToken: {userId: userId},
headers: {origin: 'http://localhost:5000'},
};
const ctx = {req: activeCtx};
beforeAll(async() => {
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
it('should throw an error when invoicing tickets from multiple clients', async() => {
const invoiceOutModel = models.InvoiceOut;
spyOn(invoiceOutModel, 'makePdfAndNotify');
const tx = await models.Ticket.beginTransaction({});
let error;
try {
const options = {transaction: tx};
const ticketsIds = [11, 16];
await models.Ticket.invoiceTicketsAndPdf(ctx, ticketsIds, null, options);
await tx.rollback();
} catch (e) {
error = e;
await tx.rollback();
}
expect(error.message).toEqual(`You can't invoice tickets from multiple clients`);
});
it(`should throw an error when invoicing a client without tax data checked`, async() => {
const invoiceOutModel = models.InvoiceOut;
spyOn(invoiceOutModel, 'makePdfAndNotify');
const tx = await models.Ticket.beginTransaction({});
let error;
try {
const options = {transaction: tx};
const client = await models.Client.findById(clientId, null, options);
await client.updateAttribute('isTaxDataChecked', false, options);
const ticketsIds = [11];
await models.Ticket.invoiceTicketsAndPdf(ctx, ticketsIds, null, options);
await tx.rollback();
} catch (e) {
error = e;
await tx.rollback();
}
expect(error.message).toEqual(`This client can't be invoiced`);
});
it('should invoice a ticket, then try again to fail', async() => {
const invoiceOutModel = models.InvoiceOut;
spyOn(invoiceOutModel, 'makePdfAndNotify');
const tx = await models.Ticket.beginTransaction({});
let error;
try {
const options = {transaction: tx};
const ticketsIds = [11];
await models.Ticket.invoiceTicketsAndPdf(ctx, ticketsIds, null, options);
await models.Ticket.invoiceTicketsAndPdf(ctx, ticketsIds, null, options);
await tx.rollback();
} catch (e) {
error = e;
await tx.rollback();
}
expect(error.message).toEqual(`This ticket is already invoiced`);
});
it('should success to invoice a ticket', async() => {
const invoiceOutModel = models.InvoiceOut;
spyOn(invoiceOutModel, 'makePdfAndNotify');
const tx = await models.Ticket.beginTransaction({});
try {
const options = {transaction: tx};
const ticketsIds = [11];
const invoicesIds = await models.Ticket.invoiceTicketsAndPdf(ctx, ticketsIds, null, options);
expect(invoicesIds.length).toBeGreaterThan(0);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -42,5 +42,6 @@ module.exports = function(Self) {
require('../methods/ticket/expeditionPalletLabel')(Self);
require('../methods/ticket/saveSign')(Self);
require('../methods/ticket/invoiceTickets')(Self);
require('../methods/ticket/invoiceTicketsAndPdf')(Self);
require('../methods/ticket/docuwareDownload')(Self);
};

View File

@ -265,7 +265,7 @@ class Controller extends Section {
});
}
return this.$http.post(`Tickets/invoiceTickets`, {ticketsIds: [this.id]})
return this.$http.post(`Tickets/invoiceTicketsAndPdf`, {ticketsIds: [this.id]})
.then(() => this.reload())
.then(() => this.vnApp.showSuccess(this.$t('Ticket invoiced')));
}

View File

@ -191,7 +191,7 @@ describe('Ticket Component vnTicketDescriptorMenu', () => {
jest.spyOn(controller.vnApp, 'showSuccess');
const expectedParams = {ticketsIds: [ticket.id]};
$httpBackend.expectPOST(`Tickets/invoiceTickets`, expectedParams).respond();
$httpBackend.expectPOST(`Tickets/invoiceTicketsAndPdf`, expectedParams).respond();
controller.makeInvoice();
$httpBackend.flush();

View File

@ -163,7 +163,7 @@ export default class Controller extends Section {
makeInvoice() {
const ticketsIds = this.checked.map(ticket => ticket.id);
return this.$http.post(`Tickets/invoiceTickets`, {ticketsIds})
return this.$http.post(`Tickets/invoiceTicketsAndPdf`, {ticketsIds})
.then(() => this.$.model.refresh())
.then(() => this.vnApp.showSuccess(this.$t('Ticket invoiced')));
}

14
package-lock.json generated
View File

@ -54,7 +54,7 @@
"@babel/plugin-syntax-dynamic-import": "^7.7.4",
"@babel/preset-env": "^7.11.0",
"@babel/register": "^7.7.7",
"@verdnatura/myt": "^1.6.0",
"@verdnatura/myt": "^1.6.3",
"angular-mocks": "^1.7.9",
"babel-jest": "^26.0.1",
"babel-loader": "^8.2.4",
@ -3375,9 +3375,9 @@
}
},
"node_modules/@verdnatura/myt": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@verdnatura/myt/-/myt-1.6.0.tgz",
"integrity": "sha512-bQWWMTkvX4wQzojp//XmTRLFGTBuVJ+pwNZxSoIl4LjsidCq5FId48qpkFG9E/CBi3gaf7AkbYDD+A8pv1WMUQ==",
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@verdnatura/myt/-/myt-1.6.3.tgz",
"integrity": "sha512-VRoTB5sEPL8a7VaX9l2afpaPNT6pBa+If1tP9tpaJ4enFQbNITlApcC0GK6XYmWMkJQjl2lgdN4/u0UCiNb2MQ==",
"dev": true,
"dependencies": {
"@sqltools/formatter": "^1.2.5",
@ -30604,9 +30604,9 @@
}
},
"@verdnatura/myt": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@verdnatura/myt/-/myt-1.6.0.tgz",
"integrity": "sha512-bQWWMTkvX4wQzojp//XmTRLFGTBuVJ+pwNZxSoIl4LjsidCq5FId48qpkFG9E/CBi3gaf7AkbYDD+A8pv1WMUQ==",
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@verdnatura/myt/-/myt-1.6.3.tgz",
"integrity": "sha512-VRoTB5sEPL8a7VaX9l2afpaPNT6pBa+If1tP9tpaJ4enFQbNITlApcC0GK6XYmWMkJQjl2lgdN4/u0UCiNb2MQ==",
"dev": true,
"requires": {
"@sqltools/formatter": "^1.2.5",

View File

@ -1,6 +1,6 @@
{
"name": "salix-back",
"version": "24.06.01",
"version": "24.6.0",
"author": "Verdnatura Levante SL",
"description": "Salix backend",
"license": "GPL-3.0",
@ -57,7 +57,7 @@
"@babel/plugin-syntax-dynamic-import": "^7.7.4",
"@babel/preset-env": "^7.11.0",
"@babel/register": "^7.7.7",
"@verdnatura/myt": "^1.6.0",
"@verdnatura/myt": "^1.6.3",
"angular-mocks": "^1.7.9",
"babel-jest": "^26.0.1",
"babel-loader": "^8.2.4",