diff --git a/CHANGELOG.md b/CHANGELOG.md
index 708ebbc4b6..8967a1633b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,7 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
-
-## [2324.01] - 2023-06-08
+## [2324.01] - 2023-06-15
### Added
- (Tickets -> Abono) Al abonar permite crear el ticket abono con almacén o sin almmacén
diff --git a/README.md b/README.md
index f73a8551be..59f5dbcf78 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@ Salix is also the scientific name of a beautifull tree! :)
Required applications.
-* Node.js = 14.x LTS
+* Node.js >= 16.x LTS
* Docker
* Git
@@ -71,7 +71,7 @@ $ npm run test:e2e
Open Visual Studio Code, press Ctrl+P and paste the following commands.
-In Visual Studio Code we use the ESLint extension.
+In Visual Studio Code we use the ESLint extension.
```
ext install dbaeumer.vscode-eslint
```
diff --git a/back/methods/docuware/specs/upload.spec.js b/back/methods/docuware/specs/upload.spec.js
index 7ac873e95f..3b8c55a504 100644
--- a/back/methods/docuware/specs/upload.spec.js
+++ b/back/methods/docuware/specs/upload.spec.js
@@ -2,8 +2,9 @@ const models = require('vn-loopback/server/server').models;
describe('docuware upload()', () => {
const userId = 9;
- const ticketId = 10;
+ const ticketIds = [10];
const ctx = {
+ args: {ticketIds},
req: {
getLocale: () => {
return 'en';
@@ -27,7 +28,7 @@ describe('docuware upload()', () => {
let error;
try {
- await models.Docuware.upload(ctx, ticketId, fileCabinetName);
+ await models.Docuware.upload(ctx, ticketIds, fileCabinetName);
} catch (e) {
error = e.message;
}
diff --git a/back/methods/docuware/upload.js b/back/methods/docuware/upload.js
index ea9ee36228..096301e563 100644
--- a/back/methods/docuware/upload.js
+++ b/back/methods/docuware/upload.js
@@ -3,34 +3,34 @@ const axios = require('axios');
module.exports = Self => {
Self.remoteMethodCtx('upload', {
- description: 'Upload an docuware PDF',
+ description: 'Upload docuware PDFs',
accessType: 'WRITE',
accepts: [
{
- arg: 'id',
- type: 'number',
- description: 'The ticket id',
- http: {source: 'path'}
+ arg: 'ticketIds',
+ type: ['number'],
+ description: 'The ticket ids',
+ required: true
},
{
arg: 'fileCabinet',
type: 'string',
- description: 'The file cabinet'
- },
- {
- arg: 'dialog',
- type: 'string',
- description: 'The dialog'
+ description: 'The file cabinet',
+ required: true
}
],
- returns: [],
+ returns: {
+ type: 'object',
+ root: true
+ },
http: {
- path: `/:id/upload`,
+ path: `/upload`,
verb: 'POST'
}
});
- Self.upload = async function(ctx, id, fileCabinet) {
+ Self.upload = async function(ctx, ticketIds, fileCabinet) {
+ delete ctx.args.ticketIds;
const models = Self.app.models;
const action = 'store';
@@ -38,104 +38,114 @@ module.exports = Self => {
const fileCabinetId = await Self.getFileCabinet(fileCabinet);
const dialogId = await Self.getDialog(fileCabinet, action, fileCabinetId);
- // get delivery note
- const deliveryNote = await models.Ticket.deliveryNotePdf(ctx, {
- id,
- type: 'deliveryNote'
- });
-
- // get ticket data
- const ticket = await models.Ticket.findById(id, {
- include: [{
- relation: 'client',
- scope: {
- fields: ['id', 'socialName', 'fi']
- }
- }]
- });
-
- // upload file
- const templateJson = {
- 'Fields': [
- {
- 'FieldName': 'N__ALBAR_N',
- 'ItemElementName': 'string',
- 'Item': id,
- },
- {
- 'FieldName': 'CIF_PROVEEDOR',
- 'ItemElementName': 'string',
- 'Item': ticket.client().fi,
- },
- {
- 'FieldName': 'CODIGO_PROVEEDOR',
- 'ItemElementName': 'string',
- 'Item': ticket.client().id,
- },
- {
- 'FieldName': 'NOMBRE_PROVEEDOR',
- 'ItemElementName': 'string',
- 'Item': ticket.client().socialName,
- },
- {
- 'FieldName': 'FECHA_FACTURA',
- 'ItemElementName': 'date',
- 'Item': ticket.shipped,
- },
- {
- 'FieldName': 'TOTAL_FACTURA',
- 'ItemElementName': 'Decimal',
- 'Item': ticket.totalWithVat,
- },
- {
- 'FieldName': 'ESTADO',
- 'ItemElementName': 'string',
- 'Item': 'Pendiente procesar',
- },
- {
- 'FieldName': 'FIRMA_',
- 'ItemElementName': 'string',
- 'Item': 'Si',
- },
- {
- 'FieldName': 'FILTRO_TABLET',
- 'ItemElementName': 'string',
- 'Item': 'Tablet1',
- }
- ]
- };
-
- if (process.env.NODE_ENV != 'production')
- throw new UserError('Action not allowed on the test environment');
-
- // delete old
- const docuwareFile = await models.Docuware.checkFile(ctx, id, fileCabinet, false);
- if (docuwareFile) {
- const deleteJson = {
- 'Field': [{'FieldName': 'ESTADO', 'Item': 'Pendiente eliminar', 'ItemElementName': 'String'}]
- };
- const deleteUri = `${options.url}/FileCabinets/${fileCabinetId}/Documents/${docuwareFile.id}/Fields`;
- await axios.put(deleteUri, deleteJson, options.headers);
- }
-
- const uploadUri = `${options.url}/FileCabinets/${fileCabinetId}/Documents?StoreDialogId=${dialogId}`;
- const FormData = require('form-data');
- const data = new FormData();
-
- data.append('document', JSON.stringify(templateJson), 'schema.json');
- data.append('file[]', deliveryNote[0], 'file.pdf');
- const uploadOptions = {
- headers: {
- 'Content-Type': 'multipart/form-data',
- 'X-File-ModifiedDate': Date.vnNew(),
- 'Cookie': options.headers.headers.Cookie,
- ...data.getHeaders()
- },
- };
-
- return await axios.post(uploadUri, data, uploadOptions)
- .catch(() => {
- throw new UserError('Failed to upload file');
+ const uploaded = [];
+ for (id of ticketIds) {
+ // get delivery note
+ ctx.args.id = id;
+ const deliveryNote = await models.Ticket.deliveryNotePdf(ctx, {
+ id,
+ type: 'deliveryNote'
});
+ // get ticket data
+ const ticket = await models.Ticket.findById(id, {
+ include: [{
+ relation: 'client',
+ scope: {
+ fields: ['id', 'name', 'fi']
+ }
+ }]
+ });
+
+ // upload file
+ const templateJson = {
+ 'Fields': [
+ {
+ 'FieldName': 'N__ALBAR_N',
+ 'ItemElementName': 'string',
+ 'Item': id,
+ },
+ {
+ 'FieldName': 'CIF_PROVEEDOR',
+ 'ItemElementName': 'string',
+ 'Item': ticket.client().fi,
+ },
+ {
+ 'FieldName': 'CODIGO_PROVEEDOR',
+ 'ItemElementName': 'string',
+ 'Item': ticket.client().id,
+ },
+ {
+ 'FieldName': 'NOMBRE_PROVEEDOR',
+ 'ItemElementName': 'string',
+ 'Item': ticket.client().name + ' - ' + id,
+ },
+ {
+ 'FieldName': 'FECHA_FACTURA',
+ 'ItemElementName': 'date',
+ 'Item': ticket.shipped,
+ },
+ {
+ 'FieldName': 'TOTAL_FACTURA',
+ 'ItemElementName': 'Decimal',
+ 'Item': ticket.totalWithVat,
+ },
+ {
+ 'FieldName': 'ESTADO',
+ 'ItemElementName': 'string',
+ 'Item': 'Pendiente procesar',
+ },
+ {
+ 'FieldName': 'FIRMA_',
+ 'ItemElementName': 'string',
+ 'Item': 'Si',
+ },
+ {
+ 'FieldName': 'FILTRO_TABLET',
+ 'ItemElementName': 'string',
+ 'Item': 'Tablet1',
+ }
+ ]
+ };
+
+ if (process.env.NODE_ENV != 'production')
+ throw new UserError('Action not allowed on the test environment');
+
+ // delete old
+ const docuwareFile = await models.Docuware.checkFile(ctx, id, fileCabinet, false);
+ if (docuwareFile) {
+ const deleteJson = {
+ 'Field': [{'FieldName': 'ESTADO', 'Item': 'Pendiente eliminar', 'ItemElementName': 'String'}]
+ };
+ const deleteUri = `${options.url}/FileCabinets/${fileCabinetId}/Documents/${docuwareFile.id}/Fields`;
+ await axios.put(deleteUri, deleteJson, options.headers);
+ }
+
+ const uploadUri = `${options.url}/FileCabinets/${fileCabinetId}/Documents?StoreDialogId=${dialogId}`;
+ const FormData = require('form-data');
+ const data = new FormData();
+
+ data.append('document', JSON.stringify(templateJson), 'schema.json');
+ data.append('file[]', deliveryNote[0], 'file.pdf');
+ const uploadOptions = {
+ headers: {
+ 'Content-Type': 'multipart/form-data',
+ 'X-File-ModifiedDate': Date.vnNew(),
+ 'Cookie': options.headers.headers.Cookie,
+ ...data.getHeaders()
+ },
+ };
+
+ try {
+ await axios.post(uploadUri, data, uploadOptions);
+ } catch (err) {
+ const $t = ctx.req.__;
+ const message = $t('Failed to upload delivery note', {id});
+ if (uploaded.length)
+ await models.TicketTracking.setDelivered(ctx, uploaded);
+ throw new UserError(message);
+ }
+ uploaded.push(id);
+ }
+ return models.TicketTracking.setDelivered(ctx, ticketIds);
};
};
diff --git a/back/methods/vn-user/signIn.js b/back/methods/vn-user/signIn.js
index d7db90a21e..6615cb5f13 100644
--- a/back/methods/vn-user/signIn.js
+++ b/back/methods/vn-user/signIn.js
@@ -62,10 +62,9 @@ module.exports = Self => {
scopes: ['change-password'],
userId: vnUser.id
});
- throw new UserError('Pass expired', 'passExpired', {
- id: vnUser.id,
- token: changePasswordToken.id
- });
+ const err = new UserError('Pass expired', 'passExpired');
+ err.details = {token: changePasswordToken};
+ throw err;
}
try {
diff --git a/db/changes/232601/.gitkeep b/db/changes/232601/.gitkeep
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/db/changes/232601/00-packingSiteAdvanced.sql b/db/changes/232601/00-packingSiteAdvanced.sql
new file mode 100644
index 0000000000..0e33744cd8
--- /dev/null
+++ b/db/changes/232601/00-packingSiteAdvanced.sql
@@ -0,0 +1,71 @@
+CREATE TABLE `vn`.`packingSiteAdvanced` (
+ `ticketFk` int(11),
+ `workerFk` int(10) unsigned,
+ PRIMARY KEY (`ticketFk`),
+ KEY `packingSiteAdvanced_FK_1` (`workerFk`),
+ CONSTRAINT `packingSiteAdvanced_FK` FOREIGN KEY (`ticketFk`) REFERENCES `ticket` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT `packingSiteAdvanced_FK_1` FOREIGN KEY (`workerFk`) REFERENCES `worker` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
+
+
+INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
+ VALUES
+ ('PackingSiteAdvanced', '*', '*', 'ALLOW', 'ROLE', 'production');
+
+ DROP PROCEDURE IF EXISTS `vn`.`packingSite_startCollection`;
+
+DELIMITER $$
+$$
+CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`packingSite_startCollection`(vSelf INT, vTicketFk INT)
+proc: BEGIN
+/**
+ * @param vSelf packingSite id
+ * @param vTicketFk A ticket id from the collection to start
+ */
+ DECLARE vExists BOOL;
+ DECLARE vIsAdvanced BOOL;
+ DECLARE vNewCollectionFk INT;
+ DECLARE vOldCollectionFk INT;
+ DECLARE vIsPackingByOther BOOL;
+
+ SELECT id, collectionFk
+ INTO vExists, vOldCollectionFk
+ FROM packingSite
+ WHERE id = vSelf;
+
+ IF NOT vExists THEN
+ CALL util.throw('packingSiteNotExists');
+ END IF;
+
+ SELECT COUNT(*) > 0
+ INTO vIsAdvanced
+ FROM packingSiteAdvanced
+ WHERE ticketFk = vTicketFk;
+
+ IF vIsAdvanced THEN
+ LEAVE proc;
+ END IF;
+
+ SELECT collectionFk INTO vNewCollectionFk
+ FROM ticketCollection WHERE ticketFk = vTicketFk;
+
+ IF vOldCollectionFk IS NOT NULL
+ AND vOldCollectionFk <> vNewCollectionFk THEN
+ SELECT COUNT(*) > 0
+ INTO vIsPackingByOther
+ FROM packingSite
+ WHERE id <> vSelf
+ AND collectionFk = vOldCollectionFk;
+
+ IF NOT vIsPackingByOther AND NOT collection_isPacked(vOldCollectionFk) THEN
+ CALL util.throw('cannotChangeCollection');
+ END IF;
+ END IF;
+
+ UPDATE packingSite SET collectionFk = vNewCollectionFk
+ WHERE id = vSelf;
+END$$
+DELIMITER ;
+
+
+
diff --git a/db/dump/dumpedFixtures.sql b/db/dump/dumpedFixtures.sql
index 67b77d5870..52c6e1073e 100644
--- a/db/dump/dumpedFixtures.sql
+++ b/db/dump/dumpedFixtures.sql
@@ -782,6 +782,38 @@ USE `sage`;
-- Dumping data for table `TiposIva`
--
+LOCK TABLES `taxType` WRITE;
+/*!40000 ALTER TABLE `taxType` DISABLE KEYS */;
+INSERT INTO `sage`.`taxType` (id, code, isIntracommunity) VALUES
+ (2, NULL, 0),
+ (4, 'national4', 0),
+ (5, NULL, 0),
+ (6, NULL, 1),
+ (7, NULL, 1),
+ (8, NULL, 1),
+ (10, 'national10', 0),
+ (11, NULL, 0),
+ (16, 'CEEServices21', 1),
+ (18, NULL, 0),
+ (20, 'national0', 0),
+ (21, 'national21', 0),
+ (22, 'import10', 0),
+ (26, NULL, 0),
+ (90, 'import21', 0),
+ (91, NULL, 0),
+ (92, NULL, 0),
+ (93, NULL, 0),
+ (94, NULL, 0),
+ (100, NULL, 0),
+ (108, NULL, 0),
+ (109, NULL, 0),
+ (110, NULL, 1),
+ (111, NULL, 0),
+ (112, NULL, 0),
+ (113, 'ISP21', 0),
+ (114, NULL, 0),
+ (115, 'import4', 0);
+
LOCK TABLES `TiposIva` WRITE;
/*!40000 ALTER TABLE `TiposIva` DISABLE KEYS */;
INSERT INTO `TiposIva` VALUES (2,0,'Operaciones no sujetas',0.0000000000,0.0000000000,0.0000000000,'','4770000020','','','','','','','95B21A93-5910-489D-83BB-C32788C9B19D','','','','','','','','','',0,0),(4,0,'I.V.A. 4%',0.0000000000,4.0000000000,0.0000000000,'4720000004','4770000004','','6310000000','','','','','9E6160D5-984E-4643-ACBC-1EBC3BF73360','','','','','','','','','',0,0),(5,0,'I.V.A. 4% y R.E. 0.5%',0.0000000000,4.0000000000,0.5000000000,'','4770000504','4770000405','','','','','','DBEFA562-63FB-4FFC-8171-64F0C6F065FF','','','','','','','','','',0,0),(6,0,'H.P. IVA 4% CEE',0.0000000000,4.0000000000,0.0000000000,'4721000004','4771000004','','','','','','','DD0ECBA8-2EF5-425E-911B-623580BADA77','','','','','','','','','',0,1),(7,0,'H.P. IVA 10% CEE',0.0000000000,10.0000000000,0.0000000000,'4721000011','4771000010','','','','','','','593208CD-6F28-4489-B6EC-907AD689EAC9','','','','','','','','','',0,1),(8,0,'H.P. IVA 21% CEE',0.0000000000,21.0000000000,0.0000000000,'4721000021','4771000021','','','','','','','27061852-9BC1-4C4F-9B6E-69970E208F23','','','','','','','','','',0,1),(10,0,'I.V.A. 10% Nacional',0.0000000000,10.0000000000,0.0000000000,'4720000011','4770000010','','6290000553','','','','','828A9D6F-5C01-4C3A-918A-B2E4482830D3','','','','','','','','','',0,0),(11,0,'I.V.A. 10% y R.E. 1,4%',0.0000000000,10.0000000000,1.4000000000,'','4770000101','4770000110','','','','','','C1F2D910-83A1-4191-A76C-8B3D7AB98348','','','','','','','','','',0,0),(16,0,'I.V.A. Adqui. servicios CEE',0.0000000000,21.0000000000,0.0000000000,'4721000015','4771000016','','','','','','','E3EDE961-CE8F-41D4-9E6C-D8BCD32275A1','','','','','','','','','',0,1),(18,0,'H.P. Iva Importación 0% ISP',0.0000000000,0.0000000000,0.0000000000,'4720000005','4770000005','','','','','','','27AD4158-2349-49C2-B53A-A4E0EFAC5D09','','','','','','','','','',0,0),(20,0,'I.V.A 0% Nacional',0.0000000000,0.0000000000,0.0000000000,'4720000000','','','','','','','','B90B0FBD-E513-4F04-9721-C873504E08DF','','','','','','','','','',0,0),(21,0,'I.V.A. 21%',0.0000000000,21.0000000000,0.0000000000,'4720000021','4770000021','4770000000','','','','','','BA8C4E28-DCFA-4F7B-AE4F-CA044626B55E','','','','','','','','','',0,0),(22,0,'IVA 10% importaciones',0.0000000000,10.0000000000,0.0000000000,'4722000010','','','','','','','','540450A8-4B41-4607-96D1-E7F296FB6933','','','','','','','','','',0,0),(26,0,'I.V.A. 21% y R.E. 5,2%',0.0000000000,21.0000000000,5.2000000000,'4720000021','4770000215','4770000521','631000000','','','','','2BC0765F-7739-49AE-A5F0-28B648B81677','','','','','','','','','',0,0),(90,0,'IVA 21% importaciones',0.0000000000,21.0000000000,0.0000000000,'4722000021','','','','','','','','EB675F91-5FF2-4E26-A31E-EEB674125945','','','','','','','','','',0,0),(91,0,'IVA 0% importaciones',0.0000000000,0.0000000000,0.0000000000,'4723000000','','','','','','','','5E5EFA56-2A99-4D54-A16B-5D818274CA18','','','','','','','','','',0,0),(92,0,'8.5% comp. ganadera o pesquera',0.0000000000,8.5000000000,0.0000000000,'4720000000','4770000000','477000000','631000000','','','','','','','','','','','','','','',0,0),(93,0,'12% com. agrícola o forestal',0.0000000000,12.0000000000,0.0000000000,'4720000012','','','','','','','','267B1DDB-247F-4A71-AB95-3349FEFC5F92','','','','','','','','','',0,0),(94,0,'10,5% com. ganadera o pesquera',0.0000000000,10.5000000000,0.0000000000,'4770000000','4720000000','631000000','477000000','','','','','','','','','','','','','','',0,0),(100,0,'HP IVA SOPORTADO 5%',0.0000000000,5.0000000000,0.0000000000,'4720000055','','','','','','','','3AD36CB2-4172-4CC9-9F87-2BF2B56AAC80','','','','','','','','','',0,0),(108,0,'I.V.A. 8%',0.0000000000,8.0000000000,0.0000000000,'4720000000','4770000000','477000000','631000000','','','','','','','','','','','','','','',0,0),(109,0,'I.V.A. 8% y R.E. 1%',0.0000000000,8.0000000000,1.0000000000,'4720000000','4770000000','477000000','631000000','','','','','','','','','','','','','','',0,0),(110,0,'HP IVA Devengado Exento CEE',0.0000000000,0.0000000000,0.0000000000,'','4771000000','','','','','','','C605BC32-E161-42FD-83F3-3A66B1FBE399','','','','','','','','','',0,1),(111,0,'H.P. Iva Devengado Exento Ser',0.0000000000,0.0000000000,0.0000000000,'','4771000001','','','','','','','F1AEC4DC-AFE5-498E-A713-2648FFB6DA32','','','','','','','','','',0,0),(112,0,'H.P. IVA Devengado en exportac',0.0000000000,0.0000000000,0.0000000000,'','4770000002','','','','','','','F980AE74-BF75-4F4C-927F-0CCCE0DB8D15','','','','','','','','','',0,0),(113,0,'HP DEVENGADO 21 ISP ',0.0000000000,21.0000000000,0.0000000000,'4720000006','4770000006','','','','','','','728D7A76-E936-438C-AF05-3CA38FE16EA5','','','','','','','','','',0,0),(114,0,'HP.IVA NO DEDUCIBLE 10%',0.0000000000,0.0000000000,0.0000000000,'4720000026','','','','','','','','','','','','','','','','','',0,0),(115,0,'H.P. IVA Soportado Impor 4% ',0.0000000000,4.0000000000,0.0000000000,'4722000004','','','','','','','','','','','','','','','','','',0,0);
diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql
index 35d19da455..3f4433fa1b 100644
--- a/db/dump/fixtures.sql
+++ b/db/dump/fixtures.sql
@@ -2736,7 +2736,8 @@ INSERT INTO `util`.`notification` (`id`, `name`, `description`)
(1, 'print-email', 'notification fixture one'),
(2, 'invoice-electronic', 'A electronic invoice has been generated'),
(3, 'not-main-printer-configured', 'A printer distinct than main has been configured'),
- (4, 'supplier-pay-method-update', 'A supplier pay method has been updated');
+ (4, 'supplier-pay-method-update', 'A supplier pay method has been updated'),
+ (5, 'modified-entry', 'An entry has been modified');
INSERT INTO `util`.`notificationAcl` (`notificationFk`, `roleFk`)
VALUES
@@ -2901,3 +2902,10 @@ INSERT INTO `vn`.`travelConfig` (`id`, `warehouseInFk`, `warehouseOutFk`, `agenc
INSERT INTO `vn`.`buyConfig` (`id`, `monthsAgo`)
VALUES
(1, 6);
+
+INSERT INTO `vn`.`invoiceInSerial` (`code`, `description`, `cplusTerIdNifFk`, `taxAreaFk`)
+ VALUES
+ ('C', 'Asgard', 1, 'WORLD'),
+ ('E', 'Midgard', 1, 'CEE'),
+ ('R', 'Jotunheim', 1, 'NATIONAL'),
+ ('W', 'Vanaheim', 1, 'WORLD');
diff --git a/db/dump/structure.sql b/db/dump/structure.sql
index 3ce7f7bb54..b07e88fde4 100644
--- a/db/dump/structure.sql
+++ b/db/dump/structure.sql
@@ -15620,6 +15620,18 @@ CREATE TABLE `ClavesOperacion` (
--
-- Table structure for table `Municipios`
--
+DROP TABLE IF EXISTS `taxType`;
+
+CREATE TABLE `taxType` (
+ id INT(11) NOT NULL,
+ code VARCHAR(25) DEFAULT NULL NULL,
+ isIntracommunity TINYINT(1) DEFAULT FALSE NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `taxType_UN` (`code`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci COMMENT='Coincidencia del id con Sage.TiposIVA.CodigoIva(propia de Sage), en ningún caso vincular mediate FK';
+
+ALTER TABLE `sage`.`taxType` ADD CONSTRAINT taxType_PK PRIMARY KEY IF NOT EXISTS (id);
+ALTER TABLE `sage`.`taxType` ADD CONSTRAINT taxType_UN UNIQUE KEY IF NOT EXISTS (code);
DROP TABLE IF EXISTS `Municipios`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
@@ -22074,12 +22086,14 @@ CREATE TABLE `autonomy` (
`name` varchar(100) NOT NULL,
`countryFk` mediumint(8) unsigned NOT NULL,
`geoFk` int(11) DEFAULT NULL,
+ `isUeeMember` tinyint(1) DEFAULT NULL,
+ `hasDailyInvoice` tinyint(4) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `autonomy_FK` (`countryFk`),
KEY `autonomy_FK_1` (`geoFk`),
CONSTRAINT `autonomy_FK` FOREIGN KEY (`countryFk`) REFERENCES `country` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `autonomy_FK_1` FOREIGN KEY (`geoFk`) REFERENCES `zoneGeo` (`id`) ON UPDATE CASCADE
-) ENGINE=InnoDBDEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci COMMENT='Comunidades autónomas o su equivalente en otros paises. Agrupación de provincias, en una categoria inferior a country.';
+) ENGINE=InnoDB AUTO_INCREMENT=109 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci COMMENT='Comunidades autónomas o su equivalente en otros paises. Agrupación de provincias, en una categoria inferior a country.';
/*!40101 SET character_set_client = @saved_cs_client */;
/*!50003 SET @saved_cs_client = @@character_set_client */ ;
/*!50003 SET @saved_cs_results = @@character_set_results */ ;
@@ -28805,7 +28819,10 @@ CREATE TABLE `expence` (
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
-
+ALTER TABLE `vn`.`expence`
+ ADD code VARCHAR(25) DEFAULT NULL NULL;
+ALTER TABLE `vn`.`expence`
+ ADD CONSTRAINT expence_UN UNIQUE KEY IF NOT EXISTS (code);
--
-- Table structure for table `farming`
--
@@ -57317,7 +57334,7 @@ DELIMITER ;
/*!50003 SET character_set_client = @saved_cs_client */ ;
/*!50003 SET character_set_results = @saved_cs_results */ ;
/*!50003 SET collation_connection = @saved_col_connection */ ;
-/*!50003 DROP PROCEDURE IF EXISTS `invoiceInBookingMain` */;
+/*!50003 DROP PROCEDURE IF EXISTS `invoiceIn_booking` */;
/*!50003 SET @saved_cs_client = @@character_set_client */ ;
/*!50003 SET @saved_cs_results = @@character_set_results */ ;
/*!50003 SET @saved_col_connection = @@collation_connection */ ;
@@ -57326,28 +57343,71 @@ DELIMITER ;
/*!50003 SET collation_connection = utf8mb4_general_ci */ ;
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
/*!50003 SET sql_mode = 'NO_ENGINE_SUBSTITUTION' */ ;
+
+
+
DELIMITER ;;
-CREATE DEFINER=`root`@`localhost` PROCEDURE `invoiceInBookingMain`(vInvoiceInId INT)
+CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`invoiceIn_booking`(vSelf INT)
BEGIN
- DECLARE vTotalAmount,vTotalAmountDivisa DECIMAL(10,2);
- DECLARE vBookNumber,vSerialNumber INT;
- DECLARE vRate DECIMAL(10,4);
+ DECLARE vBookNumber INT;
- CALL invoiceInBookingCommon(vInvoiceInId,vSerialNumber);
-
- SELECT SUM(iit.taxableBase * IF( i.serial= 'R' AND ti.Iva <> 'HP DEVENGADO 21 ISP', 1 +(ti.PorcentajeIva/100),1)),
- SUM(iit.foreignValue * IF( i.serial= 'R', 1 + (ti.PorcentajeIva/100),1)),
- iit.taxableBase/iit.foreignValue
- INTO vTotalAmount, vTotalAmountDivisa, vRate
- FROM newInvoiceIn i
- JOIN invoiceInTax iit ON iit.invoiceInFk = i.id
- LEFT JOIN sage.TiposIva ti ON ti.CodigoIva = iit.taxTypeSageFk;
+ DROP TEMPORARY TABLE IF EXISTS tInvoiceIn;
+ CREATE TEMPORARY TABLE tInvoiceIn
+ ENGINE = MEMORY
+ SELECT ii.bookEntried,
+ iit.foreignValue,
+ ii.companyFk,
+ ii.expenceFkDeductible,
+ iit.taxableBase,
+ ii.serial,
+ ii.issued,
+ ii.operated,
+ ii.supplierRef,
+ ii.cplusTrascendency472Fk,
+ ii.cplusTaxBreakFk,
+ ii.cplusSubjectOpFk,
+ ii.cplusInvoiceType472Fk,
+ ii.cplusRectificationTypeFk,
+ ii.booked,
+ IFNULL(a.isUeeMember, c.isUeeMember) isUeeMember,
+ (c.id = cc.id) isSameCountry,
+ s.account supplierAccount,
+ s.name supplierName,
+ s.nif,
+ iit.taxTypeSageFk,
+ tt.code taxCode,
+ ti.Iva,
+ ti.CuentaIvaSoportado,
+ ti.PorcentajeIva,
+ ti.CuentaIvaRepercutido,
+ ttr.ClaveOperacionDefecto,
+ iis.cplusTerIdNifFk,
+ cit.id invoicesCount,
+ e.code,
+ e.isWithheld,
+ e.id expenceFk,
+ e.name expenceName
+ FROM invoiceIn ii
+ JOIN supplier s ON s.id = ii.supplierFk
+ LEFT JOIN province p ON p.id = s.provinceFk
+ LEFT JOIN autonomy a ON a.id = p.autonomyFk
+ JOIN country c ON c.id = s.countryFk
+ JOIN supplier sc ON sc.id = ii.companyFk
+ JOIN country cc ON cc.id = sc.countryFk
+ JOIN invoiceInSerial iis ON iis.code = ii.serial
+ JOIN cplusInvoiceType472 cit ON cit.id = ii.cplusInvoiceType472Fk
+ LEFT JOIN invoiceInTax iit ON iit.invoiceInFk = ii.id
+ LEFT JOIN sage.TiposTransacciones ttr ON ttr.CodigoTransaccion = iit.transactionTypeSageFk
+ LEFT JOIN expence e ON e.id = iit.expenceFk
+ LEFT JOIN sage.TiposIva ti ON ti.CodigoIva = iit.taxTypeSageFk
+ LEFT JOIN sage.taxType tt ON tt.id = ti.CodigoIva
+ WHERE ii.id = vSelf;
CALL vn.ledger_next(vBookNumber);
-- Apunte del proveedor
-
- INSERT INTO XDiario(ASIEN,
+ INSERT INTO XDiario(
+ ASIEN,
FECHA,
SUBCTA,
EUROHABER,
@@ -57356,24 +57416,30 @@ BEGIN
HABERME,
NFACTICK,
CLAVE,
- empresa_id
- )
+ empresa_id)
SELECT
- vBookNumber,
- n.bookEntried,
- s.supplierAccount,
- vTotalAmount EUROHABER,
- n.conceptWithSupplier,
- vRate,
- vTotalAmountDivisa,
- n.invoicesCount,
- vInvoiceInId,
- n.companyFk
- FROM newInvoiceIn n
- JOIN newSupplier s;
+ vBookNumber ASIEN,
+ tii.bookEntried FECHA,
+ tii.supplierAccount SUBCTA,
+ SUM(tii.taxableBase *
+ IF(tii.serial= 'R' AND ((tii.taxCode IS NULL OR tii.taxCode <> 'ISP21')
+ AND tii.taxTypeSageFk IS NOT NULL),
+ 1 + (tii.PorcentajeIva / 100),
+ 1)) EUROHABER,
+ CONCAT('s/fra',
+ RIGHT(tii.supplierRef, 8),
+ ':',
+ LEFT(tii.supplierName, 10)) CONCEPTO,
+ CAST(tii.taxableBase / tii.foreignValue AS DECIMAL (10,4)) CAMBIO,
+ SUM(tii.foreignValue * IF(tii.serial = 'R', 1 + (tii.PorcentajeIva / 100), 1)) HABERME,
+ tii.invoicesCount NFACTICK,
+ vSelf CLAVE,
+ tii.companyFk empresa_id
+ FROM tInvoiceIn tii;
-- Línea de Gastos
- INSERT INTO XDiario ( ASIEN,
+ INSERT INTO XDiario(
+ ASIEN,
FECHA,
SUBCTA,
CONTRA,
@@ -57384,30 +57450,29 @@ BEGIN
DEBEME,
HABERME,
NFACTICK,
- empresa_id
- )
+ empresa_id)
SELECT vBookNumber ASIEN,
- n.bookEntried FECHA,
- IF(e.isWithheld , LPAD(RIGHT(s.supplierAccount,5),10,iit.expenceFk),iit.expenceFk) SUBCTA,
- s.supplierAccount CONTRA,
- IF(e.isWithheld AND iit.taxableBase < 0, NULL, ROUND(SUM(iit.taxableBase),2)) EURODEBE,
- IF(e.isWithheld AND iit.taxableBase < 0,ROUND(SUM(-iit.taxableBase),2),NULL) EUROHABER,
- n.conceptWithSupplier CONCEPTO,
- vRate,
- IF(e.isWithheld,NULL,ABS(ROUND(SUM(iit.foreignValue),2))) DEBEME,
- IF(e.isWithheld,ABS(ROUND(SUM(iit.foreignValue),2)),NULL) HABERME,
- n.invoicesCount NFACTICK,
- n.companyFk empresa_id
- FROM newInvoiceIn n
- JOIN newSupplier s
- JOIN invoiceInTax iit ON iit.invoiceInFk = n.id
- JOIN (SELECT * FROM expence e GROUP BY e.id)e ON e.id = iit.expenceFk
- WHERE e.name != 'Suplidos Transitarios nacionales'
- GROUP BY iit.expenceFk;
+ tii.bookEntried FECHA,
+ IF(tii.isWithheld, LPAD(RIGHT(tii.supplierAccount, 5), 10, tii.expenceFk),tii.expenceFk) SUBCTA,
+ tii.supplierAccount CONTRA,
+ IF(tii.isWithheld AND tii.taxableBase < 0, NULL, ROUND(SUM(tii.taxableBase),2)) EURODEBE,
+ IF(tii.isWithheld AND tii.taxableBase < 0, ROUND(SUM(-tii.taxableBase), 2), NULL) EUROHABER,
+ CONCAT('s/fra',
+ RIGHT(tii.supplierRef, 8),
+ ':',
+ LEFT(tii.supplierName, 10)) CONCEPTO,
+ CAST(tii.taxableBase / tii.foreignValue AS DECIMAL (10, 4)) CAMBIO,
+ IF(tii.isWithheld, NULL,ABS(ROUND(SUM(tii.foreignValue), 2))) DEBEME,
+ IF(tii.isWithheld, ABS(ROUND(SUM(tii.foreignValue), 2)) ,NULL) HABERME,
+ tii.invoicesCount NFACTICK,
+ tii.companyFk empresa_id
+ FROM tInvoiceIn tii
+ WHERE tii.code IS NULL OR tii.code <> 'suplido'
+ GROUP BY tii.expenceFk;
-- Líneas de IVA
-
- INSERT INTO XDiario( ASIEN,
+ INSERT INTO XDiario(
+ ASIEN,
FECHA,
SUBCTA,
CONTRA,
@@ -57434,56 +57499,50 @@ BEGIN
TERNIF,
TERNOM,
FECREGCON,
- empresa_id
- )
+ empresa_id)
SELECT vBookNumber ASIEN,
- n.bookEntried FECHA,
- IF(n.expenceFkDeductible>0, n.expenceFkDeductible, ti.CuentaIvaSoportado) SUBCTA,
- s.supplierAccount CONTRA,
- SUM(ROUND(ti.PorcentajeIva * it.taxableBase / 100 /* + 0.0001*/ , 2)) EURODEBE,
- SUM(it.taxableBase) BASEEURO,
- GROUP_CONCAT(DISTINCT e.`name` SEPARATOR ', ') CONCEPTO,
- vSerialNumber FACTURA,
- ti.PorcentajeIva IVA,
- IF(isUeeMember AND eWithheld.id IS NULL,'','*') AUXILIAR,
- n.serial SERIE,
- ttr.ClaveOperacionDefecto,
- n.issued FECHA_EX,
- n.operated FECHA_OP,
- n.invoicesCount NFACTICK,
- n.supplierRef FACTURAEX,
+ tii.bookEntried FECHA,
+ IF(tii.expenceFkDeductible>0, tii.expenceFkDeductible, tii.CuentaIvaSoportado) SUBCTA,
+ tii.supplierAccount CONTRA,
+ SUM(ROUND(tii.PorcentajeIva * tii.taxableBase / 100, 2)) EURODEBE,
+ SUM(tii.taxableBase) BASEEURO,
+ GROUP_CONCAT(DISTINCT tii.expenceName SEPARATOR ', ') CONCEPTO,
+ vSelf FACTURA,
+ tii.PorcentajeIva IVA,
+ IF(tii.isUeeMember AND eWithheld.id IS NULL, '', '*') AUXILIAR,
+ tii.serial SERIE,
+ tii.ClaveOperacionDefecto,
+ tii.issued FECHA_EX,
+ tii.operated FECHA_OP,
+ tii.invoicesCount NFACTICK,
+ tii.supplierRef FACTURAEX,
TRUE L340,
- (isSameCountry OR NOT isUeeMember) LRECT349,
- n.cplusTrascendency472Fk TIPOCLAVE,
- n.cplusTaxBreakFk TIPOEXENCI,
- n.cplusSubjectOpFk TIPONOSUJE,
- n.cplusInvoiceType472Fk TIPOFACT,
- n.cplusRectificationTypeFk TIPORECTIF,
- iis.cplusTerIdNifFk TERIDNIF,
- s.nif AS TERNIF,
- s.name AS TERNOM,
- n.booked FECREGCON,
- n.companyFk
- FROM newInvoiceIn n
- JOIN newSupplier s
- JOIN invoiceInTax it ON n.id = it.invoiceInFk
- JOIN sage.TiposIva ti ON ti.CodigoIva = it.taxTypeSageFk
- JOIN sage.TiposTransacciones ttr ON ttr.CodigoTransaccion = it.transactionTypeSageFk
- JOIN invoiceInSerial iis ON iis.code = n.serial
- JOIN (SELECT * FROM expence e GROUP BY e.id)e ON e.id = it.expenceFk
+ (tii.isSameCountry OR NOT tii.isUeeMember) LRECT349,
+ tii.cplusTrascendency472Fk TIPOCLAVE,
+ tii.cplusTaxBreakFk TIPOEXENCI,
+ tii.cplusSubjectOpFk TIPONOSUJE,
+ tii.cplusInvoiceType472Fk TIPOFACT,
+ tii.cplusRectificationTypeFk TIPORECTIF,
+ tii.cplusTerIdNifFk TERIDNIF,
+ tii.nif TERNIF,
+ tii.supplierName TERNOM,
+ tii.booked FECREGCON,
+ tii.companyFk
+ FROM tInvoiceIn tii
LEFT JOIN (
- SELECT eWithheld.id
- FROM invoiceInTax hold
- JOIN expence eWithheld ON eWithheld.id = hold.expenceFk AND eWithheld.isWithheld
- WHERE hold.invoiceInFk = vInvoiceInId LIMIT 1
+ SELECT e.id
+ FROM tInvoiceIn tii
+ JOIN expence e ON e.id = tii.expenceFk
+ WHERE e.isWithheld
+ LIMIT 1
) eWithheld ON TRUE
- WHERE it.taxTypeSageFk IS NOT NULL
- AND it.taxTypeSageFk NOT IN (22, 90)
- GROUP BY ti.PorcentajeIva, e.id;
+ WHERE tii.taxTypeSageFk IS NOT NULL
+ AND (tii.taxCode IS NULL OR tii.taxCode NOT IN ('import10', 'import21'))
+ GROUP BY tii.PorcentajeIva, tii.expenceFk;
-- Línea iva inversor sujeto pasivo
-
- INSERT INTO XDiario( ASIEN,
+ INSERT INTO XDiario(
+ ASIEN,
FECHA,
SUBCTA,
CONTRA,
@@ -57509,50 +57568,43 @@ BEGIN
TERIDNIF,
TERNIF,
TERNOM,
- empresa_id
- )
+ empresa_id)
SELECT vBookNumber ASIEN,
- n.bookEntried FECHA,
- ti.CuentaIvaRepercutido SUBCTA,
- s.supplierAccount CONTRA,
- SUM(ROUND(ti.PorcentajeIva * it.taxableBase / 100,2)) EUROHABER,
- ROUND(SUM(it.taxableBase),2) BASEEURO,
- GROUP_CONCAT(DISTINCT e.`name` SEPARATOR ', ') CONCEPTO,
- vSerialNumber FACTURA,
- ti.PorcentajeIva IVA,
+ tii.bookEntried FECHA,
+ tii.CuentaIvaRepercutido SUBCTA,
+ tii.supplierAccount CONTRA,
+ SUM(ROUND(tii.PorcentajeIva * tii.taxableBase / 100,2)) EUROHABER,
+ ROUND(SUM(tii.taxableBase),2) BASEEURO,
+ GROUP_CONCAT(DISTINCT tii.expenceName SEPARATOR ', ') CONCEPTO,
+ vSelf FACTURA,
+ tii.PorcentajeIva IVA,
'*' AUXILIAR,
- n.serial SERIE,
- ttr.ClaveOperacionDefecto,
- n.issued FECHA_EX,
- n.operated FECHA_OP,
- n.invoicesCount NFACTICK,
- n.supplierRef FACTURAEX,
+ tii.serial SERIE,
+ tii.ClaveOperacionDefecto,
+ tii.issued FECHA_EX,
+ tii.operated FECHA_OP,
+ tii.invoicesCount NFACTICK,
+ tii.supplierRef FACTURAEX,
FALSE L340,
- (isSameCountry OR NOT isUeeMember) LRECT349,
+ (tii.isSameCountry OR NOT tii.isUeeMember) LRECT349,
1 TIPOCLAVE,
- n.cplusTaxBreakFk TIPOEXENCI,
- n.cplusSubjectOpFk TIPONOSUJE,
- n.cplusInvoiceType472Fk TIPOFACT,
- n.cplusRectificationTypeFk TIPORECTIF,
- iis.cplusTerIdNifFk TERIDNIF,
- s.nif AS TERNIF,
- s.name AS TERNOM,
- n.companyFk
- FROM newInvoiceIn n
- JOIN newSupplier s
- JOIN invoiceInTax it ON n.id = it.invoiceInFk
- JOIN sage.TiposIva ti ON ti.CodigoIva = it.taxTypeSageFk
- JOIN sage.TiposTransacciones ttr ON ttr.CodigoTransaccion = it.transactionTypeSageFk
- JOIN invoiceInSerial iis ON iis.code = n.serial
- JOIN (SELECT * FROM expence e GROUP BY e.id)e ON e.id = it.expenceFk
- WHERE ti.Iva = 'HP DEVENGADO 21 ISP' OR MID(s.account, 4, 1) = '1'
- GROUP BY ti.PorcentajeIva, e.id;
+ tii.cplusTaxBreakFk TIPOEXENCI,
+ tii.cplusSubjectOpFk TIPONOSUJE,
+ tii.cplusInvoiceType472Fk TIPOFACT,
+ tii.cplusRectificationTypeFk TIPORECTIF,
+ tii.cplusTerIdNifFk TERIDNIF,
+ tii.nif TERNIF,
+ tii.supplierName TERNOM,
+ tii.companyFk
+ FROM tInvoiceIn tii
+ WHERE tii.taxCode = 'ISP21' OR MID(tii.supplierAccount, 4, 1) = '1'
+ AND tii.taxTypeSageFk IS NOT NULL
+ GROUP BY tii.PorcentajeIva, tii.expenceFk;
-- Actualización del registro original
UPDATE invoiceIn ii
- JOIN newInvoiceIn ni ON ii.id = ni.id
- SET ii.serialNumber = vSerialNumber,
- ii.isBooked = TRUE;
+ SET ii.isBooked = TRUE
+ WHERE ii.id = vSelf;
-- Problemas derivados de la precisión en los decimales al calcular los impuestos
UPDATE XDiario
@@ -57569,8 +57621,12 @@ BEGIN
ORDER BY id DESC
LIMIT 1;
+ DROP TEMPORARY TABLE tInvoiceIn;
END ;;
DELIMITER ;
+
+
+
/*!50003 SET sql_mode = @saved_sql_mode */ ;
/*!50003 SET character_set_client = @saved_cs_client */ ;
/*!50003 SET character_set_results = @saved_cs_results */ ;
diff --git a/db/export-data.sh b/db/export-data.sh
index 2288c1c62c..1df4db0307 100755
--- a/db/export-data.sh
+++ b/db/export-data.sh
@@ -110,5 +110,6 @@ TABLES=(
TiposIva
TiposTransacciones
TiposRetencion
+ taxType
)
dump_tables ${TABLES[@]}
diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js
index 039f6ee8fc..b8eaa99a1d 100644
--- a/e2e/helpers/selectors.js
+++ b/e2e/helpers/selectors.js
@@ -311,9 +311,9 @@ export default {
},
clientDefaulter: {
anyClient: 'vn-client-defaulter tbody > tr',
- firstClientName: 'vn-client-defaulter tbody > tr:nth-child(1) > td:nth-child(2) > span',
- firstSalesPersonName: 'vn-client-defaulter tbody > tr:nth-child(1) > td:nth-child(3) > span',
- firstObservation: 'vn-client-defaulter tbody > tr:nth-child(1) > td:nth-child(8) > vn-textarea[ng-model="defaulter.observation"]',
+ firstClientName: 'vn-client-defaulter tbody > tr:nth-child(2) > td:nth-child(2) > span',
+ firstSalesPersonName: 'vn-client-defaulter tbody > tr:nth-child(2) > td:nth-child(3) > span',
+ firstObservation: 'vn-client-defaulter tbody > tr:nth-child(2) > td:nth-child(8) > vn-textarea[ng-model="defaulter.observation"]',
allDefaulterCheckbox: 'vn-client-defaulter thead vn-multi-check',
addObservationButton: 'vn-client-defaulter vn-button[icon="icon-notes"]',
observation: '.vn-dialog.shown vn-textarea[ng-model="$ctrl.defaulter.observation"]',
@@ -334,15 +334,15 @@ export default {
},
itemsIndex: {
createItemButton: `vn-float-button`,
- firstSearchResult: 'vn-item-index tbody tr:nth-child(1)',
+ firstSearchResult: 'vn-item-index tbody tr:nth-child(2)',
searchResult: 'vn-item-index tbody tr:not(.empty-rows)',
- firstResultPreviewButton: 'vn-item-index tbody > :nth-child(1) .buttons > [icon="preview"]',
+ firstResultPreviewButton: 'vn-item-index tbody > :nth-child(2) .buttons > [icon="preview"]',
searchResultCloneButton: 'vn-item-index .buttons > [icon="icon-clone"]',
acceptClonationAlertButton: '.vn-confirm.shown [response="accept"]',
closeItemSummaryPreview: '.vn-popup.shown',
shownColumns: 'vn-item-index vn-button[id="shownColumns"]',
shownColumnsList: '.vn-popover.shown .content',
- firstItemImage: 'vn-item-index tbody > tr:nth-child(1) > td:nth-child(1) > img',
+ firstItemImage: 'vn-item-index tbody > tr:nth-child(2) > td:nth-child(1) > img',
firstItemImageTd: 'vn-item-index smart-table tr:nth-child(1) td:nth-child(1)',
firstItemId: 'vn-item-index tbody > tr:nth-child(1) > td:nth-child(2)',
idCheckbox: '.vn-popover.shown vn-horizontal:nth-child(3) > vn-check[label="Identifier"]',
@@ -523,11 +523,11 @@ export default {
searchResultDate: 'vn-ticket-summary [label=Landed] span',
topbarSearch: 'vn-searchbar',
moreMenu: 'vn-ticket-index vn-icon-button[icon=more_vert]',
- fourthWeeklyTicket: 'vn-ticket-weekly-index vn-card smart-table slot-table tr:nth-child(4)',
- fiveWeeklyTicket: 'vn-ticket-weekly-index vn-card smart-table slot-table tr:nth-child(5)',
+ fourthWeeklyTicket: 'vn-ticket-weekly-index vn-card smart-table slot-table tr:nth-child(5)',
+ fiveWeeklyTicket: 'vn-ticket-weekly-index vn-card smart-table slot-table tr:nth-child(6)',
weeklyTicket: 'vn-ticket-weekly-index vn-card smart-table slot-table table tbody tr',
- firstWeeklyTicketDeleteIcon: 'vn-ticket-weekly-index vn-card smart-table slot-table tr:nth-child(1) vn-icon-button[icon="delete"]',
- firstWeeklyTicketAgency: 'vn-ticket-weekly-index vn-card smart-table slot-table tr:nth-child(1) [ng-model="weekly.agencyModeFk"]',
+ firstWeeklyTicketDeleteIcon: 'vn-ticket-weekly-index vn-card smart-table slot-table tr:nth-child(2) vn-icon-button[icon="delete"]',
+ firstWeeklyTicketAgency: 'vn-ticket-weekly-index vn-card smart-table slot-table tr:nth-child(2) [ng-model="weekly.agencyModeFk"]',
acceptDeleteTurn: '.vn-confirm.shown button[response="accept"]'
},
createTicketView: {
@@ -572,8 +572,8 @@ export default {
submitNotesButton: 'button[type=submit]'
},
ticketExpedition: {
- firstSaleCheckbox: 'vn-ticket-expedition tr:nth-child(1) vn-check[ng-model="expedition.checked"]',
- thirdSaleCheckbox: 'vn-ticket-expedition tr:nth-child(3) vn-check[ng-model="expedition.checked"]',
+ firstSaleCheckbox: 'vn-ticket-expedition tr:nth-child(2) vn-check[ng-model="expedition.checked"]',
+ thirdSaleCheckbox: 'vn-ticket-expedition tr:nth-child(4) vn-check[ng-model="expedition.checked"]',
deleteExpeditionButton: 'vn-ticket-expedition slot-actions > vn-button[icon="delete"]',
moveExpeditionButton: 'vn-ticket-expedition slot-actions > vn-button[icon="keyboard_arrow_down"]',
moreMenuWithoutRoute: 'vn-item[name="withoutRoute"]',
@@ -712,7 +712,7 @@ export default {
problems: 'vn-check[label="With problems"]',
tableButtonSearch: 'vn-button[vn-tooltip="Search"]',
moveButton: 'vn-button[vn-tooltip="Future tickets"]',
- firstCheck: 'tbody > tr:nth-child(1) > td > vn-check',
+ firstCheck: 'tbody > tr:nth-child(2) > td > vn-check',
multiCheck: 'vn-multi-check',
tableId: 'vn-textfield[name="id"]',
tableFutureId: 'vn-textfield[name="futureId"]',
@@ -736,7 +736,7 @@ export default {
tableButtonSearch: 'vn-button[vn-tooltip="Search"]',
moveButton: 'vn-button[vn-tooltip="Advance tickets"]',
acceptButton: '.vn-confirm.shown button[response="accept"]',
- firstCheck: 'tbody > tr:nth-child(1) > td > vn-check',
+ firstCheck: 'tbody > tr:nth-child(2) > td > vn-check',
tableId: 'vn-textfield[name="id"]',
tableFutureId: 'vn-textfield[name="futureId"]',
tableLiters: 'vn-textfield[name="liters"]',
@@ -810,7 +810,7 @@ export default {
claimAction: {
importClaimButton: 'vn-claim-action vn-button[label="Import claim"]',
anyLine: 'vn-claim-action vn-tbody > vn-tr',
- firstDeleteLine: 'vn-claim-action tr:nth-child(1) vn-icon-button[icon="delete"]',
+ firstDeleteLine: 'vn-claim-action tr:nth-child(2) vn-icon-button[icon="delete"]',
isPaidWithManaCheckbox: 'vn-claim-action vn-check[ng-model="$ctrl.claim.isChargedToMana"]'
},
ordersIndex: {
@@ -1216,7 +1216,7 @@ export default {
addTagButton: 'vn-icon-button[vn-tooltip="Add tag"]',
itemTagInput: 'vn-autocomplete[ng-model="itemTag.tagFk"]',
itemTagValueInput: 'vn-autocomplete[ng-model="itemTag.value"]',
- firstBuy: 'vn-entry-latest-buys tbody > tr:nth-child(1)',
+ firstBuy: 'vn-entry-latest-buys tbody > tr:nth-child(2)',
allBuysCheckBox: 'vn-entry-latest-buys thead vn-check',
secondBuyCheckBox: 'vn-entry-latest-buys tbody tr:nth-child(2) vn-check[ng-model="buy.checked"]',
editBuysButton: 'vn-entry-latest-buys vn-button[icon="edit"]',
diff --git a/e2e/paths/01-salix/03_smartTable_searchBar_integrations.spec.js b/e2e/paths/01-salix/03_smartTable_searchBar_integrations.spec.js
index 526afa1405..9c37ce9ba0 100644
--- a/e2e/paths/01-salix/03_smartTable_searchBar_integrations.spec.js
+++ b/e2e/paths/01-salix/03_smartTable_searchBar_integrations.spec.js
@@ -19,15 +19,14 @@ describe('SmartTable SearchBar integration', () => {
await page.waitToClick(selectors.itemsIndex.openAdvancedSearchButton);
await page.autocompleteSearch(selectors.itemsIndex.advancedSearchItemType, 'Anthurium');
await page.waitToClick(selectors.itemsIndex.advancedSearchButton);
- await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 3);
+ await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 4);
await page.reload({
waitUntil: 'networkidle2'
});
- await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 3);
+ await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 4);
- await page.waitToClick(selectors.itemsIndex.advancedSmartTableButton);
await page.write(selectors.itemsIndex.advancedSmartTableGrouping, '1');
await page.keyboard.press('Enter');
await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 2);
@@ -36,7 +35,7 @@ describe('SmartTable SearchBar integration', () => {
waitUntil: 'networkidle2'
});
- await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 2);
+ await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 1);
});
it('should filter in section without smart-table and search in searchBar go to zone section', async() => {
diff --git a/e2e/paths/02-client/21_defaulter.spec.js b/e2e/paths/02-client/21_defaulter.spec.js
index 97e62abef4..2bb3d62546 100644
--- a/e2e/paths/02-client/21_defaulter.spec.js
+++ b/e2e/paths/02-client/21_defaulter.spec.js
@@ -19,7 +19,7 @@ describe('Client defaulter path', () => {
it('should count the amount of clients in the turns section', async() => {
const result = await page.countElement(selectors.clientDefaulter.anyClient);
- expect(result).toEqual(5);
+ expect(result).toEqual(6);
});
it('should check contain expected client', async() => {
diff --git a/e2e/paths/04-item/01_summary.spec.js b/e2e/paths/04-item/01_summary.spec.js
index e24fa6a9f1..e09ecb7787 100644
--- a/e2e/paths/04-item/01_summary.spec.js
+++ b/e2e/paths/04-item/01_summary.spec.js
@@ -18,11 +18,11 @@ describe('Item summary path', () => {
await page.doSearch('Ranged weapon');
const resultsCount = await page.countElement(selectors.itemsIndex.searchResult);
- await page.waitForTextInElement(selectors.itemsIndex.searchResult, 'Ranged weapon');
+ await page.waitForTextInElement(selectors.itemsIndex.firstSearchResult, 'Ranged weapon');
await page.waitToClick(selectors.itemsIndex.firstResultPreviewButton);
const isVisible = await page.isVisible(selectors.itemSummary.basicData);
- expect(resultsCount).toBe(3);
+ expect(resultsCount).toBe(4);
expect(isVisible).toBeTruthy();
});
@@ -66,7 +66,7 @@ describe('Item summary path', () => {
await page.waitToClick(selectors.itemsIndex.firstResultPreviewButton);
await page.waitForSelector(selectors.itemSummary.basicData, {visible: true});
- expect(resultsCount).toBe(2);
+ expect(resultsCount).toBe(3);
});
it(`should now check the item summary preview shows fields from basic data`, async() => {
diff --git a/e2e/paths/04-item/10_item_log.spec.js b/e2e/paths/04-item/10_item_log.spec.js
index dc467044dc..c88fbd337e 100644
--- a/e2e/paths/04-item/10_item_log.spec.js
+++ b/e2e/paths/04-item/10_item_log.spec.js
@@ -18,7 +18,7 @@ describe('Item log path', () => {
await page.doSearch('Knowledge artifact');
const nResults = await page.countElement(selectors.itemsIndex.searchResult);
- expect(nResults).toEqual(0);
+ expect(nResults).toEqual(1);
});
it('should access to the create item view by clicking the create floating button', async() => {
diff --git a/e2e/paths/05-ticket/02_expeditions_and_log.spec.js b/e2e/paths/05-ticket/02_expeditions_and_log.spec.js
index edccd55610..b97576940b 100644
--- a/e2e/paths/05-ticket/02_expeditions_and_log.spec.js
+++ b/e2e/paths/05-ticket/02_expeditions_and_log.spec.js
@@ -27,6 +27,6 @@ describe('Ticket expeditions and log path', () => {
const result = await page
.countElement(selectors.ticketExpedition.expeditionRow);
- expect(result).toEqual(3);
+ expect(result).toEqual(4);
});
});
diff --git a/e2e/paths/05-ticket/09_weekly.spec.js b/e2e/paths/05-ticket/09_weekly.spec.js
index 0ba57aa9dc..a9cce2ead1 100644
--- a/e2e/paths/05-ticket/09_weekly.spec.js
+++ b/e2e/paths/05-ticket/09_weekly.spec.js
@@ -19,7 +19,7 @@ describe('Ticket descriptor path', () => {
it('should count the amount of tickets in the turns section', async() => {
const result = await page.countElement(selectors.ticketsIndex.weeklyTicket);
- expect(result).toEqual(6);
+ expect(result).toEqual(7);
});
it('should go back to the ticket index then search and access a ticket summary', async() => {
@@ -89,7 +89,7 @@ describe('Ticket descriptor path', () => {
await page.doSearch('11');
const nResults = await page.countElement(selectors.ticketsIndex.searchWeeklyResult);
- expect(nResults).toEqual(1);
+ expect(nResults).toEqual(2);
});
it('should delete the weekly ticket 11', async() => {
@@ -104,7 +104,7 @@ describe('Ticket descriptor path', () => {
await page.doSearch();
const nResults = await page.countElement(selectors.ticketsIndex.searchWeeklyResult);
- expect(nResults).toEqual(6);
+ expect(nResults).toEqual(7);
});
it('should update the agency then remove it afterwards', async() => {
diff --git a/e2e/paths/05-ticket/20_moveExpedition.spec.js b/e2e/paths/05-ticket/20_moveExpedition.spec.js
index cf1c5ded32..ae23c9c999 100644
--- a/e2e/paths/05-ticket/20_moveExpedition.spec.js
+++ b/e2e/paths/05-ticket/20_moveExpedition.spec.js
@@ -29,7 +29,7 @@ describe('Ticket expeditions', () => {
const result = await page
.countElement(selectors.ticketExpedition.expeditionRow);
- expect(result).toEqual(1);
+ expect(result).toEqual(2);
});
it(`should move one expedition to new ticket with route`, async() => {
@@ -45,6 +45,6 @@ describe('Ticket expeditions', () => {
const result = await page
.countElement(selectors.ticketExpedition.expeditionRow);
- expect(result).toEqual(1);
+ expect(result).toEqual(2);
});
});
diff --git a/e2e/paths/05-ticket/21_future.spec.js b/e2e/paths/05-ticket/21_future.spec.js
index c854dcbaf3..7b7d478f73 100644
--- a/e2e/paths/05-ticket/21_future.spec.js
+++ b/e2e/paths/05-ticket/21_future.spec.js
@@ -87,7 +87,7 @@ describe('Ticket Future path', () => {
await page.clearInput(selectors.ticketFuture.futureState);
await page.waitToClick(selectors.ticketFuture.submit);
- await page.waitForNumberOfElements(selectors.ticketFuture.searchResult, 4);
+ await page.waitForNumberOfElements(selectors.ticketFuture.searchResult, 5);
await page.waitToClick(selectors.ticketFuture.multiCheck);
await page.waitToClick(selectors.ticketFuture.firstCheck);
await page.waitToClick(selectors.ticketFuture.moveButton);
diff --git a/front/core/components/smart-table/index.js b/front/core/components/smart-table/index.js
index b2380a62f8..c3b927c62b 100644
--- a/front/core/components/smart-table/index.js
+++ b/front/core/components/smart-table/index.js
@@ -40,6 +40,8 @@ export default class SmartTable extends Component {
this._options = options;
if (!options) return;
+ options.defaultSearch = true;
+
if (options.defaultSearch)
this.displaySearch();
diff --git a/front/salix/components/change-password/index.js b/front/salix/components/change-password/index.js
index 3d660e894c..baa9d96e52 100644
--- a/front/salix/components/change-password/index.js
+++ b/front/salix/components/change-password/index.js
@@ -15,7 +15,7 @@ export default class Controller {
}
$onInit() {
- if (!this.$state.params || !this.$state.params.id || !this.$state.params.token)
+ if (!this.$state.params.id)
this.$state.go('login');
this.$http.get('UserPasswords/findOne')
@@ -25,7 +25,7 @@ export default class Controller {
}
submit() {
- const id = this.$state.params.id;
+ const userId = this.$state.params.userId;
const newPassword = this.newPassword;
const oldPassword = this.oldPassword;
@@ -35,12 +35,12 @@ export default class Controller {
throw new UserError(`Passwords don't match`);
const headers = {
- Authorization: this.$state.params.token
+ Authorization: this.$state.params.id
};
this.$http.post('VnUsers/change-password',
{
- id,
+ id: userId,
oldPassword,
newPassword
},
diff --git a/front/salix/components/login/index.js b/front/salix/components/login/index.js
index 0412f3b742..8e8f082444 100644
--- a/front/salix/components/login/index.js
+++ b/front/salix/components/login/index.js
@@ -27,10 +27,9 @@ export default class Controller {
this.loading = false;
this.password = '';
this.focusUser();
- if (req?.data?.error?.code == 'passExpired') {
- const [args] = req.data.error.translateArgs;
- this.$state.go('change-password', args);
- }
+ const err = req.data?.error;
+ if (err?.code == 'passExpired')
+ this.$state.go('change-password', err.details.token);
throw req;
});
diff --git a/front/salix/routes.js b/front/salix/routes.js
index d6dea244a5..675da719a5 100644
--- a/front/salix/routes.js
+++ b/front/salix/routes.js
@@ -38,7 +38,7 @@ function config($stateProvider, $urlRouterProvider) {
})
.state('change-password', {
parent: 'outLayout',
- url: '/change-password?id&token',
+ url: '/change-password?id&userId',
description: 'Change password',
template: ''
})
diff --git a/loopback/locale/en.json b/loopback/locale/en.json
index 8bc9d40563..43ff4b86a4 100644
--- a/loopback/locale/en.json
+++ b/loopback/locale/en.json
@@ -174,5 +174,6 @@
"A claim with that sale already exists": "A claim with that sale already exists",
"Pass expired": "The password has expired, change it from Salix",
"Can't transfer claimed sales": "Can't transfer claimed sales",
- "Invalid quantity": "Invalid quantity"
+ "Invalid quantity": "Invalid quantity",
+ "Failed to upload delivery note": "Error to upload delivery note {{id}}"
}
diff --git a/loopback/locale/es.json b/loopback/locale/es.json
index 5dcfab3641..7e2701f953 100644
--- a/loopback/locale/es.json
+++ b/loopback/locale/es.json
@@ -258,7 +258,7 @@
"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 file": "Error al subir archivo",
+ "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",
diff --git a/modules/account/back/locale/account/en.yml b/modules/account/back/locale/account/en.yml
new file mode 100644
index 0000000000..221afef5f5
--- /dev/null
+++ b/modules/account/back/locale/account/en.yml
@@ -0,0 +1,3 @@
+name: account
+columns:
+ id: id
diff --git a/modules/account/back/locale/account/es.yml b/modules/account/back/locale/account/es.yml
new file mode 100644
index 0000000000..a79b1f40c3
--- /dev/null
+++ b/modules/account/back/locale/account/es.yml
@@ -0,0 +1,3 @@
+name: cuenta
+columns:
+ id: id
diff --git a/modules/account/back/locale/mail-alias-account/en.yml b/modules/account/back/locale/mail-alias-account/en.yml
new file mode 100644
index 0000000000..bf805d66f3
--- /dev/null
+++ b/modules/account/back/locale/mail-alias-account/en.yml
@@ -0,0 +1,5 @@
+name: mail alias
+columns:
+ id: id
+ mailAlias: alias
+ account: account
diff --git a/modules/account/back/locale/mail-alias-account/es.yml b/modules/account/back/locale/mail-alias-account/es.yml
new file mode 100644
index 0000000000..b53ade9967
--- /dev/null
+++ b/modules/account/back/locale/mail-alias-account/es.yml
@@ -0,0 +1,5 @@
+name: alias de correo
+columns:
+ id: id
+ mailAlias: alias
+ account: cuenta
diff --git a/modules/account/front/accounts/index.js b/modules/account/front/accounts/index.js
index 7a341b0b03..0e78ab8d6d 100644
--- a/modules/account/front/accounts/index.js
+++ b/modules/account/front/accounts/index.js
@@ -5,8 +5,7 @@ import UserError from 'core/lib/user-error';
export default class Controller extends Section {
onSynchronizeAll() {
this.vnApp.showSuccess(this.$t('Synchronizing in the background'));
- this.$http.patch(`Accounts/syncAll`)
- .then(() => this.vnApp.showSuccess(this.$t('Users synchronized!')));
+ this.$http.patch(`Accounts/syncAll`);
}
onUserSync() {
diff --git a/modules/client/back/methods/tpv-transaction/confirm.js b/modules/client/back/methods/tpv-transaction/confirm.js
index 4faa21bb5e..41229a1fd0 100644
--- a/modules/client/back/methods/tpv-transaction/confirm.js
+++ b/modules/client/back/methods/tpv-transaction/confirm.js
@@ -2,7 +2,7 @@ const UserError = require('vn-loopback/util/user-error');
const base64url = require('base64url');
module.exports = Self => {
- Self.remoteMethodCtx('confirm', {
+ Self.remoteMethod('confirm', {
description: 'Confirms electronic payment transaction',
accessType: 'WRITE',
accepts: [
@@ -30,7 +30,7 @@ module.exports = Self => {
}
});
- Self.confirm = async(ctx, signatureVersion, merchantParameters, signature) => {
+ Self.confirm = async(signatureVersion, merchantParameters, signature) => {
const $ = Self.app.models;
let transaction;
@@ -83,7 +83,7 @@ module.exports = Self => {
params['Ds_Currency'],
params['Ds_Response'],
params['Ds_ErrorCode']
- ], {userId: ctx.req.accessToken.userId});
+ ]);
return true;
} catch (err) {
diff --git a/modules/entry/back/methods/entry/addFromBuy.js b/modules/entry/back/methods/entry/addFromBuy.js
index f7e1b637e1..bfbd1b4160 100644
--- a/modules/entry/back/methods/entry/addFromBuy.js
+++ b/modules/entry/back/methods/entry/addFromBuy.js
@@ -46,7 +46,7 @@ module.exports = Self => {
}
try {
- let buy = await models.Buy.findOne({where: {entryFk: args.id}}, myOptions);
+ let buy = await models.Buy.findOne({where: {entryFk: args.id, itemFk: args.item}}, myOptions);
if (buy)
await buy.updateAttribute('printedStickers', args.printedStickers, myOptions);
else {
diff --git a/modules/invoiceIn/back/methods/invoice-in/toBook.js b/modules/invoiceIn/back/methods/invoice-in/toBook.js
index 877552f41e..778742911f 100644
--- a/modules/invoiceIn/back/methods/invoice-in/toBook.js
+++ b/modules/invoiceIn/back/methods/invoice-in/toBook.js
@@ -32,7 +32,7 @@ module.exports = Self => {
}
try {
- await Self.rawSql(`CALL vn.invoiceInBookingMain(?)`, [id], myOptions);
+ await Self.rawSql(`CALL vn.invoiceIn_booking(?)`, [id], myOptions);
if (tx) await tx.commit();
} catch (e) {
if (tx) await tx.rollback();
diff --git a/modules/invoiceOut/front/global-invoicing/index.html b/modules/invoiceOut/front/global-invoicing/index.html
index 6d5b16329f..3f0a106507 100644
--- a/modules/invoiceOut/front/global-invoicing/index.html
+++ b/modules/invoiceOut/front/global-invoicing/index.html
@@ -118,7 +118,8 @@
label="Company"
show-field="code"
value-field="id"
- ng-model="$ctrl.companyFk">
+ ng-model="$ctrl.companyFk"
+ on-change="$ctrl.getInvoiceDate(value)">
{
- this.companyFk = res.data.companyFk;
- const params = {
- companyFk: this.companyFk
- };
- return this.$http.get('InvoiceOuts/getInvoiceDate', {params});
- })
- .then(res => {
- this.minInvoicingDate = res.data.issued ? new Date(res.data.issued) : null;
- this.invoiceDate = this.minInvoicingDate;
- });
- }
+ .then(res => {
+ this.companyFk = res.data.companyFk;
+ this.getInvoiceDate(this.companyFk);
+ });
+ }
+
+ getInvoiceDate(companyFk) {
+ const params = { companyFk: companyFk };
+ this.fetchInvoiceDate(params);
+ }
+
+ fetchInvoiceDate(params) {
+ this.$http.get('InvoiceOuts/getInvoiceDate', { params })
+ .then(res => {
+ this.minInvoicingDate = res.data.issued ? new Date(res.data.issued) : null;
+ this.invoiceDate = this.minInvoicingDate;
+ });
+ }
stopInvoicing() {
this.status = 'stopping';
@@ -42,7 +48,7 @@ class Controller extends Section {
throw new UserError('Invoice date and the max date should be filled');
if (this.invoiceDate < this.maxShipped)
throw new UserError('Invoice date can\'t be less than max date');
- if (this.invoiceDate.getTime() < this.minInvoicingDate.getTime())
+ if (this.minInvoicingDate && this.invoiceDate.getTime() < this.minInvoicingDate.getTime())
throw new UserError('Exists an invoice with a previous date');
if (!this.companyFk)
throw new UserError('Choose a valid company');
diff --git a/modules/invoiceOut/front/negative-bases/index.js b/modules/invoiceOut/front/negative-bases/index.js
index 1a838507ca..f60668b200 100644
--- a/modules/invoiceOut/front/negative-bases/index.js
+++ b/modules/invoiceOut/front/negative-bases/index.js
@@ -19,7 +19,8 @@ export default class Controller extends Section {
this.smartTableOptions = {
activeButtons: {
search: true,
- }, columns: [
+ },
+ columns: [
{
field: 'isActive',
searchable: false
diff --git a/modules/item/front/fixed-price/index.js b/modules/item/front/fixed-price/index.js
index a39cd66027..fe6788e9cb 100644
--- a/modules/item/front/fixed-price/index.js
+++ b/modules/item/front/fixed-price/index.js
@@ -13,7 +13,6 @@ export default class Controller extends Section {
activeButtons: {
search: true
},
- defaultSearch: true,
columns: [
{
field: 'warehouseFk',
diff --git a/modules/route/front/index/index.html b/modules/route/front/index/index.html
index 7a64a9affe..9384af6be6 100644
--- a/modules/route/front/index/index.html
+++ b/modules/route/front/index/index.html
@@ -1,11 +1,26 @@
+
+
+
+
+
+
-