Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into test
gitea/salix/test This commit looks good
Details
|
@ -28,8 +28,10 @@ module.exports = Self => {
|
|||
const models = Self.app.models;
|
||||
const accessToken = ctx.req.accessToken;
|
||||
const sender = await models.Account.findById(accessToken.userId);
|
||||
const recipient = to.replace('@', '');
|
||||
|
||||
return sendMessage(to, `@${sender.name}: ${message}`);
|
||||
if (sender.name != recipient)
|
||||
return sendMessage(to, `@${sender.name}: ${message}`);
|
||||
};
|
||||
|
||||
async function sendMessage(name, message) {
|
||||
|
@ -70,6 +72,12 @@ module.exports = Self => {
|
|||
}
|
||||
|
||||
function send(uri, body) {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
return new Promise(resolve => {
|
||||
return resolve({statusCode: 200, message: 'Fake notification sent'});
|
||||
});
|
||||
}
|
||||
|
||||
const options = {
|
||||
method: 'POST',
|
||||
uri: uri,
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
|
||||
describe('chat sendMessage()', () => {
|
||||
it('should return a "Fake notification sent" as response', async() => {
|
||||
let ctx = {req: {accessToken: {userId: 1}}};
|
||||
let response = await app.models.Chat.sendMessage(ctx, '@salesPerson', 'I changed something');
|
||||
|
||||
expect(response.statusCode).toEqual(200);
|
||||
expect(response.message).toEqual('Fake notification sent');
|
||||
});
|
||||
|
||||
it('should not return a response', async() => {
|
||||
let ctx = {req: {accessToken: {userId: 18}}};
|
||||
let response = await app.models.Chat.sendMessage(ctx, '@salesPerson', 'I changed something');
|
||||
|
||||
expect(response).toBeUndefined();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
USE `vn`;
|
||||
|
||||
UPDATE `vn`.`country` SET `ibanLength` = '24' WHERE (`id` = 1);
|
||||
UPDATE `vn`.`country` SET `ibanLength` = '27' WHERE (`id` = 2);
|
||||
UPDATE `vn`.`country` SET `ibanLength` = '22' WHERE (`id` = 3);
|
||||
UPDATE `vn`.`country` SET `ibanLength` = '24' WHERE (`id` = 4);
|
||||
UPDATE `vn`.`country` SET `ibanLength` = '18' WHERE (`id` = 5);
|
||||
UPDATE `vn`.`country` SET `ibanLength` = '25' WHERE (`id` = 8);
|
||||
UPDATE `vn`.`country` SET `ibanLength` = '27' WHERE (`id` = 19);
|
||||
UPDATE `vn`.`country` SET `ibanLength` = '24' WHERE (`id` = 30);
|
|
@ -0,0 +1,8 @@
|
|||
USE `vn`;
|
||||
|
||||
UPDATE `vn`.`sample` SET `description` = 'Bienvenida como nuevo cliente' WHERE (`id` = '12');
|
||||
UPDATE `vn`.`sample` SET `description` = 'Instalación y configuración de impresora de coronas' WHERE (`id` = '13');
|
||||
UPDATE `vn`.`sample` SET `description` = 'Solicitud de domiciliación bancaria' WHERE (`id` = '14');
|
||||
UPDATE `vn`.`sample` SET `description` = 'Aviso inicial por saldo deudor' WHERE (`id` = '15');
|
||||
UPDATE `vn`.`sample` SET `description` = 'Aviso reiterado por saldo deudor' WHERE (`id` = '16');
|
||||
UPDATE `vn`.`sample` SET `isVisible` = '0' WHERE (`id` = '17');
|
|
@ -0,0 +1,86 @@
|
|||
USE `vn`;
|
||||
|
||||
ALTER TABLE `vn`.`ticketRequest`
|
||||
DROP FOREIGN KEY `fgnAtender`;
|
||||
ALTER TABLE `vn`.`ticketRequest`
|
||||
CHANGE COLUMN `atenderFk` `attenderFk` INT(11) NULL DEFAULT NULL ;
|
||||
ALTER TABLE `vn`.`ticketRequest`
|
||||
ADD CONSTRAINT `fgnAtender`
|
||||
FOREIGN KEY (`attenderFk`)
|
||||
REFERENCES `vn`.`worker` (`id`)
|
||||
ON UPDATE CASCADE;
|
||||
|
||||
USE `vn2008`;
|
||||
CREATE
|
||||
OR REPLACE ALGORITHM = UNDEFINED
|
||||
DEFINER = `root`@`%`
|
||||
SQL SECURITY DEFINER
|
||||
VIEW `vn2008`.`Ordenes` AS
|
||||
SELECT
|
||||
`tr`.`id` AS `Id_ORDEN`,
|
||||
`tr`.`description` AS `ORDEN`,
|
||||
`tr`.`requesterFk` AS `requesterFk`,
|
||||
`tr`.`attenderFk` AS `attenderFk`,
|
||||
`tr`.`quantity` AS `CANTIDAD`,
|
||||
`tr`.`itemFk` AS `Id_ARTICLE`,
|
||||
`tr`.`price` AS `PRECIOMAX`,
|
||||
`tr`.`isOk` AS `isOk`,
|
||||
`tr`.`saleFk` AS `Id_Movimiento`,
|
||||
`tr`.`ticketFk` AS `ticketFk`,
|
||||
`tr`.`response` AS `COMENTARIO`,
|
||||
`tr`.`created` AS `odbc_date`,
|
||||
`tr`.`ordered` AS `datORDEN`,
|
||||
`tr`.`shipped` AS `datTICKET`,
|
||||
`tr`.`salesPersonCode` AS `CodVENDEDOR`,
|
||||
`tr`.`buyerCode` AS `CodCOMPRADOR`,
|
||||
`tr`.`price__` AS `PREU`,
|
||||
`tr`.`clientFk` AS `Id_CLIENTE`,
|
||||
`tr`.`ok__` AS `OK`,
|
||||
`tr`.`total` AS `TOTAL`,
|
||||
`tr`.`buyed` AS `datCOMPRA`,
|
||||
`tr`.`ko__` AS `KO`
|
||||
FROM
|
||||
`vn`.`ticketRequest` `tr`;
|
||||
|
||||
USE `vn`;
|
||||
|
||||
DROP TRIGGER IF EXISTS `vn`.`ticketRequest_beforeInsert`;
|
||||
|
||||
DELIMITER $$
|
||||
USE `vn`$$
|
||||
CREATE DEFINER=`root`@`%` TRIGGER `vn`.`ticketRequest_beforeInsert` BEFORE INSERT ON `ticketRequest` FOR EACH ROW
|
||||
BEGIN
|
||||
IF NEW.ticketFk IS NULL THEN
|
||||
SET NEW.ticketFk = (SELECT s.ticketFk FROM sale s WHERE s.id = NEW.saleFk);
|
||||
END IF;
|
||||
|
||||
IF NEW.requesterFk IS NULL THEN
|
||||
SET NEW.requesterFk = (SELECT w.id FROM worker w WHERE w.code = NEW.salesPersonCode);
|
||||
END IF;
|
||||
|
||||
IF NEW.attenderFk IS NULL THEN
|
||||
SET NEW.attenderFk = (SELECT w.id FROM worker w WHERE w.code = NEW.buyerCode);
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
|
||||
DROP TRIGGER IF EXISTS `vn`.`ticketRequest_beforeUpdate`;
|
||||
|
||||
DELIMITER $$
|
||||
USE `vn`$$
|
||||
CREATE DEFINER=`root`@`%` TRIGGER `vn`.`ticketRequest_beforeUpdate` BEFORE UPDATE ON `ticketRequest` FOR EACH ROW
|
||||
BEGIN
|
||||
IF NEW.saleFk <> OLD.saleFk THEN
|
||||
SET NEW.ticketFk = (SELECT s.ticketFk FROM sale s WHERE s.id = NEW.saleFk);
|
||||
END IF;
|
||||
|
||||
IF NEW.salesPersonCode <> OLD.salesPersonCode THEN
|
||||
SET NEW.requesterFk = (SELECT w.id FROM worker w WHERE w.code = NEW.salesPersonCode);
|
||||
END IF;
|
||||
|
||||
IF NEW.buyerCode <> OLD.buyerCode THEN
|
||||
SET NEW.attenderFk = (SELECT w.id FROM worker w WHERE w.code = NEW.buyerCode);
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -53,13 +53,14 @@ INSERT INTO `vn`.`worker`(`id`, `code`, `firstName`, `lastName`, `userFk`,`bossF
|
|||
|
||||
INSERT INTO `vn`.`country`(`id`, `country`, `isUeeMember`, `code`, `currencyFk`, `ibanLength`)
|
||||
VALUES
|
||||
(1, 'España', 0, 'ES', 1, 22),
|
||||
(2, 'Italia', 1, 'IT', 1, 25),
|
||||
(3, 'Alemania', 1, 'DE', 1, 20),
|
||||
(4, 'Rumania', 1, 'RO', 1, 22),
|
||||
(5, 'Holanda', 1, 'NL', 1, 16),
|
||||
(19,'Francia', 1, 'FR', 1, 25),
|
||||
(30,'Canarias', 1, 'IC', 1, 22);
|
||||
(1, 'España', 0, 'ES', 1, 24),
|
||||
(2, 'Italia', 1, 'IT', 1, 27),
|
||||
(3, 'Alemania', 1, 'DE', 1, 22),
|
||||
(4, 'Rumania', 1, 'RO', 1, 24),
|
||||
(5, 'Holanda', 1, 'NL', 1, 18),
|
||||
(8, 'Portugal', 1, 'PT', 1, 27),
|
||||
(19,'Francia', 1, 'FR', 1, 27),
|
||||
(30,'Canarias', 1, 'IC', 1, 24);
|
||||
|
||||
INSERT INTO `vn`.`warehouse`(`id`, `name`, `isComparative`, `isInventory`, `hasAvailable`, `isManaged`, `hasStowaway`, `hasDms`)
|
||||
VALUES
|
||||
|
@ -195,9 +196,9 @@ INSERT INTO `vn`.`client`(`id`,`name`,`fi`,`socialName`,`contact`,`street`,`city
|
|||
VALUES
|
||||
(101, 'Bruce Wayne', '84612325V', 'Batman', 'Alfred', '1007 Mountain Drive, Gotham', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'BruceWayne@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1),
|
||||
(102, 'Petter Parker', '87945234L', 'Spider man', 'Aunt May', '20 Ingram Street', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'PetterParker@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1),
|
||||
(103, 'Clark Kent', '06815934E', 'Super man', 'lois lane', '344 Clinton Street', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'ClarkKent@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 0, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1),
|
||||
(103, 'Clark Kent', '06815934E', 'Super man', 'lois lane', '344 Clinton Street', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'ClarkKent@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 0, 19, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1),
|
||||
(104, 'Tony Stark', '06089160W', 'Iron man', 'Pepper Potts', '10880 Malibu Point', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'TonyStark@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1),
|
||||
(105, 'Max Eisenhardt', '251628698', 'Magneto', 'Rogue', 'Unknown Whereabouts', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'MaxEisenhardt@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 18, 0, 1),
|
||||
(105, 'Max Eisenhardt', '251628698', 'Magneto', 'Rogue', 'Unknown Whereabouts', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'MaxEisenhardt@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 8, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 18, 0, 1),
|
||||
(106, 'DavidCharlesHaller', '53136686Q', 'Legion', 'Charles Xavier', 'Evil hideout', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'DavidCharlesHaller@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 0, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 19, 0, 1),
|
||||
(107, 'Hank Pym', '09854837G', 'Ant man', 'Hawk', 'Anthill', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'HankPym@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 0, 0, NULL, 0, 0, 19, 0, 1),
|
||||
(108, 'Charles Xavier', '22641921P', 'Professor X', 'Beast', '3800 Victory Pkwy, Cincinnati, OH 45207, USA', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'CharlesXavier@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 19, 0, 1),
|
||||
|
@ -1460,7 +1461,7 @@ INSERT INTO `vn`.`receipt`(`id`, `invoiceFk`, `amountPaid`, `amountUnpaid`, `pay
|
|||
(1, 'Cobro web', 100.50, 0.00, CURDATE(), 9, 1, 101, CURDATE(), 442, 1),
|
||||
(2, 'Cobro web', 200.50, 0.00, DATE_ADD(CURDATE(), INTERVAL -5 DAY), 9, 1, 101, DATE_ADD(CURDATE(), INTERVAL -5 DAY), 442, 1),
|
||||
(3, 'Cobro en efectivo', 300.00, 100.00, DATE_ADD(CURDATE(), INTERVAL -10 DAY), 9, 1, 102, DATE_ADD(CURDATE(), INTERVAL -10 DAY), 442, 0),
|
||||
(4, 'Cobro en efectivo', -400.00, -50.00, DATE_ADD(CURDATE(), INTERVAL -15 DAY), 9, 1, 103, DATE_ADD(CURDATE(), INTERVAL -15 DAY), 442, 0);
|
||||
(4, 'Cobro en efectivo', 400.00, -50.00, DATE_ADD(CURDATE(), INTERVAL -15 DAY), 9, 1, 103, DATE_ADD(CURDATE(), INTERVAL -15 DAY), 442, 0);
|
||||
|
||||
INSERT INTO `vn2008`.`workerTeam`(`id`, `team`, `user`)
|
||||
VALUES
|
||||
|
@ -1471,7 +1472,7 @@ INSERT INTO `vn2008`.`workerTeam`(`id`, `team`, `user`)
|
|||
(5, 3, 103),
|
||||
(6, 3, 104);
|
||||
|
||||
INSERT INTO `vn`.`ticketRequest`(`id`, `description`, `requesterFk`, `atenderFk`, `quantity`, `itemFk`, `price`, `isOk`, `saleFk`, `ticketFk`, `created`)
|
||||
INSERT INTO `vn`.`ticketRequest`(`id`, `description`, `requesterFk`, `attenderFk`, `quantity`, `itemFk`, `price`, `isOk`, `saleFk`, `ticketFk`, `created`)
|
||||
VALUES
|
||||
(1, 'Ranged weapon longbow 2m', 18, 35, 5, 1, 9.10, 1, 1, 1, DATE_ADD(CURDATE(), INTERVAL -15 DAY)),
|
||||
(2, 'Melee weapon combat first 15cm', 18, 35, 10, 2, 1.07, 0, NULL, 1, DATE_ADD(CURDATE(), INTERVAL -15 DAY)),
|
||||
|
|
|
@ -47,16 +47,17 @@ TABLES=(
|
|||
claimResult
|
||||
ticketUpdateAction
|
||||
state
|
||||
sample
|
||||
)
|
||||
dump_tables ${TABLES[@]}
|
||||
|
||||
TABLES=(
|
||||
vn2008
|
||||
time
|
||||
accion_dits
|
||||
businessReasonEnd
|
||||
container
|
||||
department
|
||||
escritos
|
||||
Grupos
|
||||
iva_group_codigo
|
||||
tarifa_componentes
|
||||
|
|
|
@ -112,7 +112,7 @@
|
|||
"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 this ticket because is already invoiced, deleted or prepared": "No puedes eliminar este tiquet porque ya está facturado, eliminado o preparado",
|
||||
"You cannot delete a ticket that it's being prepared": "No puedes eliminar un ticket que está siendo preparado",
|
||||
"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",
|
||||
"Has deleted the ticket id": "Ha eliminado el ticket id [#{{id}}]({{{url}}})",
|
||||
"You cannot remove this ticket because is already invoiced, deleted or prepared": "You cannot remove this ticket because is already invoiced, deleted or prepared"
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
module.exports = function(app) {
|
||||
require('../../../print/server.js')(app);
|
||||
require('../../../print/boot.js')(app);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
/**
|
||||
* Serializes an object to a query params
|
||||
*
|
||||
* @param {Object} obj The params object
|
||||
* @return {String} Serialized params
|
||||
*/
|
||||
exports.httpParamSerializer = function(obj) {
|
||||
let query = '';
|
||||
for (let param in obj) {
|
||||
if (query != '')
|
||||
query += '&';
|
||||
query += `${param}=${obj[param]}`;
|
||||
}
|
||||
|
||||
return query;
|
||||
};
|
|
@ -15,7 +15,7 @@
|
|||
<vn-treeview vn-id="treeview" root-label="Locations"
|
||||
fetch-func="$ctrl.onFetch($item)"
|
||||
sort-func="$ctrl.onSort($a, $b)">
|
||||
<vn-check
|
||||
<vn-check acl-role="deliveryBoss"
|
||||
ng-model="item.selected"
|
||||
on-change="$ctrl.onSelection(value, item)"
|
||||
triple-state="true"
|
||||
|
|
|
@ -35,7 +35,7 @@ class Controller {
|
|||
{
|
||||
relation: 'client',
|
||||
scope: {
|
||||
fields: ['salesPersonFk', 'name'],
|
||||
fields: ['salesPersonFk', 'name', 'email'],
|
||||
include: {
|
||||
relation: 'salesPerson',
|
||||
scope: {
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import ngModule from '../module';
|
||||
|
||||
class Controller {
|
||||
constructor($scope, $state, $http, $translate, vnApp, aclService) {
|
||||
constructor($scope, $state, $http, $translate, vnApp, aclService, $httpParamSerializer) {
|
||||
this.$scope = $scope;
|
||||
this.$state = $state;
|
||||
this.$http = $http;
|
||||
this.$translate = $translate;
|
||||
this.vnApp = vnApp;
|
||||
this.aclService = aclService;
|
||||
this.$httpParamSerializer = $httpParamSerializer;
|
||||
this.moreOptions = [
|
||||
{callback: this.showPickupOrder, name: 'Show Pickup order'},
|
||||
{callback: this.confirmPickupOrder, name: 'Send Pickup order'},
|
||||
|
@ -60,7 +61,12 @@ class Controller {
|
|||
}
|
||||
|
||||
showPickupOrder() {
|
||||
let url = `report/rpt-claim-pickup-order?claimFk=${this.claim.id}`;
|
||||
const params = {
|
||||
clientId: this.claim.clientFk,
|
||||
claimId: this.claim.id
|
||||
};
|
||||
const serializedParams = this.$httpParamSerializer(params);
|
||||
let url = `api/report/claim-pickup-order?${serializedParams}`;
|
||||
window.open(url);
|
||||
}
|
||||
|
||||
|
@ -70,7 +76,14 @@ class Controller {
|
|||
|
||||
sendPickupOrder(response) {
|
||||
if (response === 'accept') {
|
||||
this.$http.post(`email/claim-pickup-order`, {claimFk: this.claim.id}).then(
|
||||
const params = {
|
||||
recipient: this.claim.client.email,
|
||||
clientId: this.claim.clientFk,
|
||||
claimId: this.claim.id
|
||||
};
|
||||
const serializedParams = this.$httpParamSerializer(params);
|
||||
const url = `email/claim-pickup-order?${serializedParams}`;
|
||||
this.$http.get(url).then(
|
||||
() => this.vnApp.showMessage(this.$translate.instant('Notification sent!'))
|
||||
);
|
||||
}
|
||||
|
@ -90,7 +103,7 @@ class Controller {
|
|||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$scope', '$state', '$http', '$translate', 'vnApp', 'aclService'];
|
||||
Controller.$inject = ['$scope', '$state', '$http', '$translate', 'vnApp', 'aclService', '$httpParamSerializer'];
|
||||
|
||||
ngModule.component('vnClaimDescriptor', {
|
||||
template: require('./index.html'),
|
||||
|
|
|
@ -1,20 +1,27 @@
|
|||
import './index.js';
|
||||
|
||||
describe('Item Component vnClaimDescriptor', () => {
|
||||
let $httpParamSerializer;
|
||||
let $httpBackend;
|
||||
let controller;
|
||||
|
||||
beforeEach(ngModule('claim'));
|
||||
|
||||
beforeEach(angular.mock.inject(($componentController, _$httpBackend_) => {
|
||||
beforeEach(angular.mock.inject(($componentController, _$httpBackend_, _$httpParamSerializer_) => {
|
||||
$httpBackend = _$httpBackend_;
|
||||
$httpParamSerializer = _$httpParamSerializer_;
|
||||
controller = $componentController('vnClaimDescriptor');
|
||||
controller.claim = {id: 2};
|
||||
controller.claim = {id: 2, clientFk: 101, client: {email: 'client@email'}};
|
||||
}));
|
||||
|
||||
describe('showPickupOrder()', () => {
|
||||
it('should open a new window showing a pickup order PDF document', () => {
|
||||
let expectedPath = 'report/rpt-claim-pickup-order?claimFk=2';
|
||||
const params = {
|
||||
clientId: controller.claim.clientFk,
|
||||
claimId: controller.claim.id
|
||||
};
|
||||
const serializedParams = $httpParamSerializer(params);
|
||||
let expectedPath = `api/report/claim-pickup-order?${serializedParams}`;
|
||||
spyOn(window, 'open');
|
||||
controller.showPickupOrder();
|
||||
|
||||
|
@ -38,8 +45,15 @@ describe('Item Component vnClaimDescriptor', () => {
|
|||
it('should make a query and call vnApp.showMessage() if the response is accept', () => {
|
||||
spyOn(controller.vnApp, 'showMessage');
|
||||
|
||||
$httpBackend.when('POST', `email/claim-pickup-order`, {claimFk: 2}).respond();
|
||||
$httpBackend.expect('POST', `email/claim-pickup-order`, {claimFk: 2}).respond();
|
||||
const params = {
|
||||
recipient: 'client@email',
|
||||
clientId: controller.claim.clientFk,
|
||||
claimId: controller.claim.id
|
||||
};
|
||||
const serializedParams = $httpParamSerializer(params);
|
||||
|
||||
$httpBackend.when('GET', `email/claim-pickup-order?${serializedParams}`).respond();
|
||||
$httpBackend.expect('GET', `email/claim-pickup-order?${serializedParams}`).respond();
|
||||
controller.sendPickupOrder('accept');
|
||||
$httpBackend.flush();
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@ let request = require('request-promise-native');
|
|||
let UserError = require('vn-loopback/util/user-error');
|
||||
let getFinalState = require('vn-loopback/util/hook').getFinalState;
|
||||
let isMultiple = require('vn-loopback/util/hook').isMultiple;
|
||||
const httpParamSerializer = require('vn-loopback/util/http').httpParamSerializer;
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
module.exports = Self => {
|
||||
// Methods
|
||||
|
@ -239,15 +241,18 @@ module.exports = Self => {
|
|||
});
|
||||
}
|
||||
|
||||
const options = {
|
||||
method: 'POST',
|
||||
uri: 'http://127.0.0.1:3000/api/email/payment-update',
|
||||
body: {
|
||||
clientFk: instance.id
|
||||
},
|
||||
json: true
|
||||
// Send email to client
|
||||
|
||||
if (!instance.email) return;
|
||||
const loopBackContext = LoopBackContext.getCurrentContext();
|
||||
const headers = loopBackContext.active.http.req.headers;
|
||||
const params = {
|
||||
clientId: instance.id,
|
||||
recipient: instance.email
|
||||
};
|
||||
await request(options);
|
||||
const serializedParams = httpParamSerializer(params);
|
||||
const query = `${headers.origin}/api/email/payment-update?${serializedParams}`;
|
||||
await request.get(query);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
<mg-ajax path="ClientSamples" options="vnPost"></mg-ajax>
|
||||
<vn-crud-model auto-load="true"
|
||||
url="Companies"
|
||||
data="companiesData"
|
||||
order="code">
|
||||
</vn-crud-model>
|
||||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
data="$ctrl.clientSample"
|
||||
|
@ -8,9 +13,13 @@
|
|||
<form name="form" ng-submit="$ctrl.onSubmit()" compact>
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
vn-id="sampleType"
|
||||
<vn-textfield vn-one
|
||||
label="Recipient"
|
||||
ng-model="$ctrl.clientSample.recipient">
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete vn-one vn-id="sampleType"
|
||||
ng-model="$ctrl.clientSample.typeFk"
|
||||
model="ClientSample.typeFk"
|
||||
fields="['code','hasCompany']"
|
||||
|
@ -19,11 +28,10 @@
|
|||
value-field="id"
|
||||
label="Sample">
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
ng-model="$ctrl.clientSample.companyFk"
|
||||
<vn-autocomplete vn-one
|
||||
ng-model="$ctrl.companyId"
|
||||
model="ClientSample.companyFk"
|
||||
url="Companies"
|
||||
data="companiesData"
|
||||
show-field="code"
|
||||
value-field="id"
|
||||
label="Company"
|
||||
|
@ -41,5 +49,9 @@
|
|||
<vn-dialog
|
||||
vn-id="show-preview"
|
||||
on-open="$ctrl.onPreviewOpen()">
|
||||
<tpl-body></tpl-body>
|
||||
<tpl-body class="client-sample-dialog">
|
||||
<div class="loading">
|
||||
<vn-spinner enable="true"></vn-spinner>
|
||||
</div>
|
||||
</tpl-body>
|
||||
</vn-dialog>
|
||||
|
|
|
@ -1,33 +1,84 @@
|
|||
import ngModule from '../../module';
|
||||
import Component from 'core/lib/component';
|
||||
import './style.scss';
|
||||
|
||||
class Controller {
|
||||
constructor($scope, $state, $http, vnApp, $translate) {
|
||||
this.$scope = $scope;
|
||||
this.$state = $state;
|
||||
this.$stateParams = $state.params;
|
||||
this.$http = $http;
|
||||
class Controller extends Component {
|
||||
constructor($element, $, vnApp, $httpParamSerializer, vnConfig) {
|
||||
super($element, $);
|
||||
this.vnApp = vnApp;
|
||||
this.$translate = $translate;
|
||||
this.$httpParamSerializer = $httpParamSerializer;
|
||||
this.vnConfig = vnConfig;
|
||||
this.clientSample = {
|
||||
clientFk: this.$stateParams.id
|
||||
clientFk: this.$params.id,
|
||||
companyFk: vnConfig.companyFk
|
||||
};
|
||||
}
|
||||
|
||||
jsonToQuery(json) {
|
||||
let query = '';
|
||||
for (let param in json) {
|
||||
if (query != '')
|
||||
query += '&';
|
||||
query += `${param}=${json[param]}`;
|
||||
}
|
||||
get client() {
|
||||
return this._client;
|
||||
}
|
||||
|
||||
return query;
|
||||
set client(value) {
|
||||
this._client = value;
|
||||
|
||||
if (value)
|
||||
this.clientSample.recipient = value.email;
|
||||
}
|
||||
|
||||
get companyId() {
|
||||
if (!this.clientSample.companyFk)
|
||||
this.clientSample.companyFk = this.vnConfig.companyFk;
|
||||
return this.clientSample.companyFk;
|
||||
}
|
||||
|
||||
set companyId(value) {
|
||||
this.clientSample.companyFk = value;
|
||||
}
|
||||
|
||||
showPreview() {
|
||||
let sampleType = this.$scope.sampleType.selection;
|
||||
let params = {clientFk: this.$stateParams.id};
|
||||
let sampleType = this.$.sampleType.selection;
|
||||
|
||||
if (!sampleType)
|
||||
return this.vnApp.showError(this.$translate.instant('Choose a sample'));
|
||||
|
||||
if (sampleType.hasCompany && !this.clientSample.companyFk)
|
||||
return this.vnApp.showError(this.$translate.instant('Choose a company'));
|
||||
|
||||
const params = {
|
||||
clientId: this.$params.id,
|
||||
recipient: this.clientSample.recipient,
|
||||
isPreview: true
|
||||
};
|
||||
|
||||
if (sampleType.hasCompany)
|
||||
params.companyId = this.clientSample.companyFk;
|
||||
|
||||
const serializedParams = this.$httpParamSerializer(params);
|
||||
const query = `email/${sampleType.code}?${serializedParams}`;
|
||||
this.$http.get(query).then(res => {
|
||||
this.$.showPreview.show();
|
||||
let dialog = document.body.querySelector('div.vn-dialog');
|
||||
let body = dialog.querySelector('tpl-body');
|
||||
let scroll = dialog.querySelector('div:first-child');
|
||||
|
||||
body.innerHTML = res.data;
|
||||
scroll.scrollTop = 0;
|
||||
});
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
this.$.watcher.check();
|
||||
this.$.watcher.realSubmit().then(() =>
|
||||
this.sendSample()
|
||||
);
|
||||
}
|
||||
|
||||
sendSample() {
|
||||
let sampleType = this.$.sampleType.selection;
|
||||
let params = {
|
||||
clientId: this.$params.id,
|
||||
recipient: this.clientSample.recipient
|
||||
};
|
||||
|
||||
if (!sampleType)
|
||||
return this.vnApp.showError(this.$translate.instant('Choose a sample'));
|
||||
|
@ -36,50 +87,22 @@ class Controller {
|
|||
return this.vnApp.showError(this.$translate.instant('Choose a company'));
|
||||
|
||||
if (sampleType.hasCompany)
|
||||
params.companyFk = this.clientSample.companyFk;
|
||||
params.companyId = this.clientSample.companyFk;
|
||||
|
||||
let query = `email/${sampleType.code}?${this.jsonToQuery(params)}`;
|
||||
const serializedParams = this.$httpParamSerializer(params);
|
||||
const query = `email/${sampleType.code}?${serializedParams}`;
|
||||
this.$http.get(query).then(res => {
|
||||
if (res.data) {
|
||||
let dialog = this.$scope.showPreview.element;
|
||||
let body = dialog.querySelector('tpl-body');
|
||||
let scroll = dialog.querySelector('div:first-child');
|
||||
|
||||
body.innerHTML = res.data;
|
||||
this.$scope.showPreview.show();
|
||||
|
||||
scroll.scrollTop = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
this.$scope.watcher.check();
|
||||
this.$scope.watcher.realSubmit().then(() =>
|
||||
this.sendSample()
|
||||
);
|
||||
}
|
||||
|
||||
sendSample() {
|
||||
let sampleType = this.$scope.sampleType.selection;
|
||||
let params = {clientFk: this.$stateParams.id};
|
||||
|
||||
if (sampleType.hasCompany)
|
||||
params.companyFk = this.clientSample.companyFk;
|
||||
|
||||
|
||||
let query = `email/${sampleType.code}?${this.jsonToQuery(params)}`;
|
||||
this.$http.post(query).then(res => {
|
||||
if (res) {
|
||||
this.vnApp.showSuccess(this.$translate.instant('Notification sent!'));
|
||||
this.$state.go('client.card.sample.index');
|
||||
}
|
||||
this.vnApp.showSuccess(this.$translate.instant('Notification sent!'));
|
||||
this.$state.go('client.card.sample.index');
|
||||
});
|
||||
}
|
||||
}
|
||||
Controller.$inject = ['$scope', '$state', '$http', 'vnApp', '$translate'];
|
||||
Controller.$inject = ['$element', '$scope', 'vnApp', '$httpParamSerializer', 'vnConfig'];
|
||||
|
||||
ngModule.component('vnClientSampleCreate', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller
|
||||
controller: Controller,
|
||||
bindings: {
|
||||
client: '<'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -2,14 +2,16 @@ import './index';
|
|||
|
||||
describe('Client', () => {
|
||||
describe('Component vnClientSampleCreate', () => {
|
||||
let $httpParamSerializer;
|
||||
let $scope;
|
||||
let $element;
|
||||
let $httpBackend;
|
||||
let $state;
|
||||
let controller;
|
||||
|
||||
beforeEach(ngModule('client'));
|
||||
|
||||
beforeEach(angular.mock.inject(($componentController, _$httpBackend_, $rootScope, _$state_) => {
|
||||
beforeEach(angular.mock.inject(($componentController, _$httpBackend_, $rootScope, _$state_, _$httpParamSerializer_) => {
|
||||
$scope = $rootScope.$new();
|
||||
$scope.sampleType = {};
|
||||
$scope.watcher = {
|
||||
|
@ -35,30 +37,24 @@ describe('Client', () => {
|
|||
$state = _$state_;
|
||||
$state.params.id = 101;
|
||||
$httpBackend = _$httpBackend_;
|
||||
controller = $componentController('vnClientSampleCreate', {$scope, $state});
|
||||
$httpParamSerializer = _$httpParamSerializer_;
|
||||
$element = angular.element('<vn-client-sample-create></vn-client-sample-create>');
|
||||
controller = $componentController('vnClientSampleCreate', {$element, $scope});
|
||||
}));
|
||||
|
||||
describe('jsonToQuery()', () => {
|
||||
it(`should convert a JSON object with clientFk property to query params`, () => {
|
||||
let myObject = {clientFk: 101};
|
||||
let result = controller.jsonToQuery(myObject);
|
||||
|
||||
expect(result).toEqual('clientFk=101');
|
||||
});
|
||||
|
||||
it(`should convert a JSON object with clientFk and companyFk properties to query params`, () => {
|
||||
let myObject = {clientFk: 101, companyFk: 442};
|
||||
let result = controller.jsonToQuery(myObject);
|
||||
|
||||
expect(result).toEqual('clientFk=101&companyFk=442');
|
||||
});
|
||||
});
|
||||
|
||||
describe('showPreview()', () => {
|
||||
it(`should perform a query (GET) and open a sample preview`, () => {
|
||||
spyOn(controller.$scope.showPreview, 'show');
|
||||
spyOn(controller.$.showPreview, 'show');
|
||||
const element = document.createElement('div');
|
||||
document.body.querySelector = () => {
|
||||
return {
|
||||
querySelector: () => {
|
||||
return element;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
controller.$scope.sampleType.selection = {
|
||||
controller.$.sampleType.selection = {
|
||||
hasCompany: false,
|
||||
code: 'MyReport'
|
||||
};
|
||||
|
@ -69,18 +65,32 @@ describe('Client', () => {
|
|||
|
||||
let event = {preventDefault: () => {}};
|
||||
|
||||
$httpBackend.when('GET', `email/MyReport?clientFk=101`).respond(true);
|
||||
$httpBackend.expect('GET', `email/MyReport?clientFk=101`);
|
||||
const params = {
|
||||
clientId: 101,
|
||||
isPreview: true
|
||||
};
|
||||
const serializedParams = $httpParamSerializer(params);
|
||||
|
||||
$httpBackend.when('GET', `email/MyReport?${serializedParams}`).respond(true);
|
||||
$httpBackend.expect('GET', `email/MyReport?${serializedParams}`);
|
||||
controller.showPreview(event);
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.$scope.showPreview.show).toHaveBeenCalledWith();
|
||||
expect(controller.$.showPreview.show).toHaveBeenCalledWith();
|
||||
});
|
||||
|
||||
it(`should perform a query (GET) with companyFk param and open a sample preview`, () => {
|
||||
spyOn(controller.$scope.showPreview, 'show');
|
||||
spyOn(controller.$.showPreview, 'show');
|
||||
const element = document.createElement('div');
|
||||
document.body.querySelector = () => {
|
||||
return {
|
||||
querySelector: () => {
|
||||
return element;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
controller.$scope.sampleType.selection = {
|
||||
controller.$.sampleType.selection = {
|
||||
hasCompany: true,
|
||||
code: 'MyReport'
|
||||
};
|
||||
|
@ -92,12 +102,19 @@ describe('Client', () => {
|
|||
|
||||
let event = {preventDefault: () => {}};
|
||||
|
||||
$httpBackend.when('GET', `email/MyReport?clientFk=101&companyFk=442`).respond(true);
|
||||
$httpBackend.expect('GET', `email/MyReport?clientFk=101&companyFk=442`);
|
||||
const params = {
|
||||
clientId: 101,
|
||||
companyId: 442,
|
||||
isPreview: true
|
||||
};
|
||||
const serializedParams = $httpParamSerializer(params);
|
||||
|
||||
$httpBackend.when('GET', `email/MyReport?${serializedParams}`).respond(true);
|
||||
$httpBackend.expect('GET', `email/MyReport?${serializedParams}`);
|
||||
controller.showPreview(event);
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.$scope.showPreview.show).toHaveBeenCalledWith();
|
||||
expect(controller.$.showPreview.show).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -114,7 +131,7 @@ describe('Client', () => {
|
|||
it(`should perform a query (GET) and call go() method`, () => {
|
||||
spyOn(controller.$state, 'go');
|
||||
|
||||
controller.$scope.sampleType.selection = {
|
||||
controller.$.sampleType.selection = {
|
||||
hasCompany: false,
|
||||
code: 'MyReport'
|
||||
};
|
||||
|
@ -123,8 +140,13 @@ describe('Client', () => {
|
|||
clientFk: 101
|
||||
};
|
||||
|
||||
$httpBackend.when('POST', `email/MyReport?clientFk=101`).respond(true);
|
||||
$httpBackend.expect('POST', `email/MyReport?clientFk=101`);
|
||||
const params = {
|
||||
clientId: 101
|
||||
};
|
||||
const serializedParams = $httpParamSerializer(params);
|
||||
|
||||
$httpBackend.when('GET', `email/MyReport?${serializedParams}`).respond(true);
|
||||
$httpBackend.expect('GET', `email/MyReport?${serializedParams}`);
|
||||
controller.sendSample();
|
||||
$httpBackend.flush();
|
||||
|
||||
|
@ -134,7 +156,7 @@ describe('Client', () => {
|
|||
it(`should perform a query (GET) with companyFk param and call go() method`, () => {
|
||||
spyOn(controller.$state, 'go');
|
||||
|
||||
controller.$scope.sampleType.selection = {
|
||||
controller.$.sampleType.selection = {
|
||||
hasCompany: true,
|
||||
code: 'MyReport'
|
||||
};
|
||||
|
@ -144,8 +166,14 @@ describe('Client', () => {
|
|||
companyFk: 442
|
||||
};
|
||||
|
||||
$httpBackend.when('POST', `email/MyReport?clientFk=101&companyFk=442`).respond(true);
|
||||
$httpBackend.expect('POST', `email/MyReport?clientFk=101&companyFk=442`);
|
||||
const params = {
|
||||
clientId: 101,
|
||||
companyId: 442
|
||||
};
|
||||
const serializedParams = $httpParamSerializer(params);
|
||||
|
||||
$httpBackend.when('GET', `email/MyReport?${serializedParams}`).respond(true);
|
||||
$httpBackend.expect('GET', `email/MyReport?${serializedParams}`);
|
||||
controller.sendSample();
|
||||
$httpBackend.flush();
|
||||
|
||||
|
|
|
@ -1,36 +1,34 @@
|
|||
vn-client-sample-create {
|
||||
vn-dialog {
|
||||
& > div {
|
||||
padding: 0 !important
|
||||
div.vn-dialog {
|
||||
tpl-body.client-sample-dialog {
|
||||
width: 800px;
|
||||
|
||||
.container, .container h1 {
|
||||
font-family: "Roboto","Helvetica","Arial",sans-serif;
|
||||
font-size: 1em !important;
|
||||
|
||||
h1 {
|
||||
font-weight: bold;
|
||||
margin: auto
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 1em 0
|
||||
}
|
||||
|
||||
footer p {
|
||||
font-size: 10px !important;
|
||||
line-height: 10px
|
||||
}
|
||||
}
|
||||
|
||||
tpl-body {
|
||||
min-width: 800px;
|
||||
|
||||
.title h1 {
|
||||
font-size: 2em !important;
|
||||
margin: 0
|
||||
}
|
||||
|
||||
.container, .container h1 {
|
||||
font-family: "Roboto","Helvetica","Arial",sans-serif;
|
||||
font-size: 1em !important;
|
||||
|
||||
h1 {
|
||||
font-weight: bold;
|
||||
margin: auto
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 1em 0
|
||||
}
|
||||
|
||||
footer p {
|
||||
font-size: 10px !important;
|
||||
line-height: 10px
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.title h1 {
|
||||
font-size: 2em !important;
|
||||
margin: 0
|
||||
}
|
||||
.loading {
|
||||
text-align: center
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,24 @@ export default class Controller {
|
|||
scope: {
|
||||
fields: ['id', 'name']
|
||||
}
|
||||
},
|
||||
{
|
||||
relation: 'worker',
|
||||
scope: {
|
||||
fields: ['userFk'],
|
||||
include: {
|
||||
relation: 'user',
|
||||
scope: {
|
||||
fields: ['id'],
|
||||
include: {
|
||||
relation: 'emailUser',
|
||||
scope: {
|
||||
fields: ['email']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import ngModule from '../module';
|
||||
|
||||
class Controller {
|
||||
constructor($, $http, vnApp, $translate, aclService) {
|
||||
constructor($, $http, vnApp, $translate, aclService, $httpParamSerializer) {
|
||||
this.$http = $http;
|
||||
this.vnApp = vnApp;
|
||||
this.$translate = $translate;
|
||||
this.$ = $;
|
||||
this.aclService = aclService;
|
||||
this.$httpParamSerializer = $httpParamSerializer;
|
||||
this.moreOptions = [
|
||||
{callback: this.showRouteReport, name: 'Show route report'},
|
||||
{callback: this.sendRouteReport, name: 'Send route report'},
|
||||
|
@ -36,13 +37,26 @@ class Controller {
|
|||
}
|
||||
|
||||
showRouteReport() {
|
||||
let url = `report/rpt-route?routeFk=${this.route.id}`;
|
||||
const user = this.route.worker.user;
|
||||
const params = {
|
||||
clientId: user.id,
|
||||
routeId: this.route.id
|
||||
};
|
||||
const serializedParams = this.$httpParamSerializer(params);
|
||||
let url = `api/report/driver-route?${serializedParams}`;
|
||||
window.open(url);
|
||||
}
|
||||
|
||||
sendRouteReport() {
|
||||
let url = `email/driver-route?routeFk=${this.route.id}`;
|
||||
this.$http.post(url).then(() => {
|
||||
const user = this.route.worker.user;
|
||||
const params = {
|
||||
recipient: user.emailUser.email,
|
||||
clientId: user.id,
|
||||
routeId: this.route.id
|
||||
};
|
||||
const serializedParams = this.$httpParamSerializer(params);
|
||||
const url = `email/driver-route?${serializedParams}`;
|
||||
this.$http.get(url).then(() => {
|
||||
this.vnApp.showSuccess(this.$translate.instant('Report sent'));
|
||||
});
|
||||
}
|
||||
|
@ -62,7 +76,7 @@ class Controller {
|
|||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$scope', '$http', 'vnApp', '$translate', 'aclService'];
|
||||
Controller.$inject = ['$scope', '$http', 'vnApp', '$translate', 'aclService', '$httpParamSerializer'];
|
||||
|
||||
ngModule.component('vnRouteDescriptor', {
|
||||
template: require('./index.html'),
|
||||
|
|
|
@ -76,7 +76,7 @@ module.exports = Self => {
|
|||
case 'ticketFk':
|
||||
return {'t.id': value};
|
||||
case 'attenderFk':
|
||||
return {'tr.atenderFk': value};
|
||||
return {'tr.attenderFk': value};
|
||||
case 'isOk':
|
||||
return {'tr.isOk': value};
|
||||
case 'clientFk':
|
||||
|
@ -106,7 +106,7 @@ module.exports = Self => {
|
|||
tr.ticketFk,
|
||||
tr.quantity,
|
||||
tr.price,
|
||||
tr.atenderFk attenderFk,
|
||||
tr.attenderFk,
|
||||
tr.description,
|
||||
tr.response,
|
||||
tr.saleFk,
|
||||
|
@ -131,7 +131,7 @@ module.exports = Self => {
|
|||
LEFT JOIN sale s ON s.id = tr.saleFk
|
||||
LEFT JOIN worker wk ON wk.id = c.salesPersonFk
|
||||
LEFT JOIN account.user u ON u.id = wk.userFk
|
||||
LEFT JOIN worker wka ON wka.id = tr.atenderFk
|
||||
LEFT JOIN worker wka ON wka.id = tr.attenderFk
|
||||
LEFT JOIN account.user ua ON ua.id = wka.userFk`);
|
||||
stmt.merge(conn.makeSuffix(filter));
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ module.exports = Self => {
|
|||
return sale.itemShelving();
|
||||
});
|
||||
if (hasItemShelvingSales)
|
||||
throw new UserError(`You cannot delete a ticket that it's being prepared`);
|
||||
throw new UserError(`You cannot delete a ticket that part of it is being prepared`);
|
||||
|
||||
// Check for existing claim
|
||||
const claimOfATicket = await models.Claim.findOne({where: {ticketFk: id}});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
|
||||
xdescribe('ticket deleted()', () => {
|
||||
describe('ticket deleted()', () => {
|
||||
let ticket;
|
||||
let ctx;
|
||||
|
||||
|
|
|
@ -33,13 +33,6 @@
|
|||
"isOk": {
|
||||
"type": "Boolean"
|
||||
},
|
||||
"attenderFk": {
|
||||
"type": "Number",
|
||||
"required": true,
|
||||
"mysql": {
|
||||
"columnName": "atenderFk"
|
||||
}
|
||||
},
|
||||
"response": {
|
||||
"type": "String"
|
||||
}
|
||||
|
|
|
@ -15,7 +15,15 @@ class Controller {
|
|||
{
|
||||
relation: 'client',
|
||||
scope: {
|
||||
fields: ['salesPersonFk', 'name', 'isActive', 'isFreezed', 'isTaxDataChecked', 'credit'],
|
||||
fields: [
|
||||
'salesPersonFk',
|
||||
'name',
|
||||
'isActive',
|
||||
'isFreezed',
|
||||
'isTaxDataChecked',
|
||||
'credit',
|
||||
'email'
|
||||
],
|
||||
include: {
|
||||
relation: 'salesPerson',
|
||||
scope: {
|
||||
|
|
|
@ -197,7 +197,7 @@
|
|||
|
||||
<vn-confirm
|
||||
vn-id="confirm-delivery-note"
|
||||
on-response="$ctrl.sendDeliveryNote($response)"
|
||||
on-accept="$ctrl.sendDeliveryNote()"
|
||||
question="Send Delivery Note"
|
||||
message="Are you sure you want to send it?">
|
||||
</vn-confirm>
|
|
@ -2,9 +2,10 @@ import ngModule from '../module';
|
|||
import Component from 'core/lib/component';
|
||||
|
||||
class Controller extends Component {
|
||||
constructor($element, $, aclService) {
|
||||
constructor($element, $, aclService, $httpParamSerializer) {
|
||||
super($element, $);
|
||||
this.aclService = aclService;
|
||||
this.$httpParamSerializer = $httpParamSerializer;
|
||||
this.moreOptions = [
|
||||
{name: 'Add turn', callback: this.showAddTurnDialog},
|
||||
{name: 'Show Delivery Note', callback: this.showDeliveryNote},
|
||||
|
@ -198,10 +199,27 @@ class Controller extends Component {
|
|||
}
|
||||
|
||||
showDeliveryNote() {
|
||||
let url = `report/rpt-delivery-note?ticketFk=${this.ticket.id}`;
|
||||
const params = {
|
||||
clientId: this.ticket.client.id,
|
||||
ticketId: this.ticket.id
|
||||
};
|
||||
const serializedParams = this.$httpParamSerializer(params);
|
||||
let url = `api/report/delivery-note?${serializedParams}`;
|
||||
window.open(url);
|
||||
}
|
||||
|
||||
sendDeliveryNote() {
|
||||
const params = {
|
||||
recipient: this.ticket.client.email,
|
||||
clientId: this.ticket.client.id,
|
||||
ticketId: this.ticket.id
|
||||
};
|
||||
const serializedParams = this.$httpParamSerializer(params);
|
||||
this.$http.get(`email/delivery-note?${serializedParams}`).then(
|
||||
() => this.vnApp.showMessage(this.$translate.instant('Notification sent!'))
|
||||
);
|
||||
}
|
||||
|
||||
showSMSDialog() {
|
||||
const address = this.ticket.address;
|
||||
this.newSMS = {
|
||||
|
@ -272,17 +290,9 @@ class Controller extends Component {
|
|||
confirmDeliveryNote() {
|
||||
this.$.confirmDeliveryNote.show();
|
||||
}
|
||||
|
||||
sendDeliveryNote(response) {
|
||||
if (response === 'accept') {
|
||||
this.$http.post(`email/delivery-note`, {ticketFk: this.ticket.id}).then(
|
||||
() => this.vnApp.showMessage(this.$translate.instant('Notification sent!'))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$element', '$scope', 'aclService'];
|
||||
Controller.$inject = ['$element', '$scope', 'aclService', '$httpParamSerializer'];
|
||||
|
||||
ngModule.component('vnTicketDescriptor', {
|
||||
template: require('./index.html'),
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import './index.js';
|
||||
|
||||
describe('Ticket Component vnTicketDescriptor', () => {
|
||||
let $httpParamSerializer;
|
||||
let $httpBackend;
|
||||
let controller;
|
||||
let $state;
|
||||
|
||||
beforeEach(ngModule('ticket'));
|
||||
|
||||
beforeEach(angular.mock.inject(($componentController, _$httpBackend_, $rootScope, $compile, _$state_) => {
|
||||
beforeEach(angular.mock.inject(($componentController, _$httpBackend_, $rootScope, $compile, _$state_, _$httpParamSerializer_) => {
|
||||
let $element = $compile(`<vn-autocomplete></vn-autocomplete>`)($rootScope);
|
||||
$state = _$state_;
|
||||
$state.getCurrentPath = () => {
|
||||
|
@ -17,8 +18,9 @@ describe('Ticket Component vnTicketDescriptor', () => {
|
|||
];
|
||||
};
|
||||
$httpBackend = _$httpBackend_;
|
||||
$httpParamSerializer = _$httpParamSerializer_;
|
||||
controller = $componentController('vnTicketDescriptor', {$element});
|
||||
controller._ticket = {id: 2, invoiceOut: {id: 1}};
|
||||
controller._ticket = {id: 2, invoiceOut: {id: 1}, client: {id: 101, email: 'client@email'}};
|
||||
controller.cardReload = ()=> {
|
||||
return true;
|
||||
};
|
||||
|
@ -82,7 +84,12 @@ describe('Ticket Component vnTicketDescriptor', () => {
|
|||
|
||||
describe('showDeliveryNote()', () => {
|
||||
it('should open a new window showing a delivery note PDF document', () => {
|
||||
let expectedPath = 'report/rpt-delivery-note?ticketFk=2';
|
||||
const params = {
|
||||
clientId: controller.ticket.client.id,
|
||||
ticketId: controller.ticket.id
|
||||
};
|
||||
const serializedParams = $httpParamSerializer(params);
|
||||
let expectedPath = `api/report/delivery-note?${serializedParams}`;
|
||||
spyOn(window, 'open');
|
||||
controller.showDeliveryNote();
|
||||
|
||||
|
@ -90,6 +97,26 @@ describe('Ticket Component vnTicketDescriptor', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('sendDeliveryNote()', () => {
|
||||
it('should make a query and call vnApp.showMessage()', () => {
|
||||
spyOn(controller.vnApp, 'showMessage');
|
||||
|
||||
const params = {
|
||||
recipient: 'client@email',
|
||||
clientId: controller.ticket.client.id,
|
||||
ticketId: controller.ticket.id
|
||||
};
|
||||
const serializedParams = $httpParamSerializer(params);
|
||||
|
||||
$httpBackend.when('GET', `email/delivery-note?${serializedParams}`).respond();
|
||||
$httpBackend.expect('GET', `email/delivery-note?${serializedParams}`).respond();
|
||||
controller.sendDeliveryNote();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.vnApp.showMessage).toHaveBeenCalledWith('Notification sent!');
|
||||
});
|
||||
});
|
||||
|
||||
describe('makeInvoice()', () => {
|
||||
it('should make a query and call $state.reload() method if the response is accept', () => {
|
||||
spyOn(controller.$state, 'reload');
|
||||
|
|
|
@ -30,8 +30,11 @@
|
|||
"isConfirmed": {
|
||||
"type": "Boolean"
|
||||
},
|
||||
"isRaid": {
|
||||
"type": "Boolean"
|
||||
"isVirtual": {
|
||||
"type": "Boolean",
|
||||
"mysql": {
|
||||
"columnName": "isRaid"
|
||||
}
|
||||
},
|
||||
"commission": {
|
||||
"type": "Number"
|
||||
|
|
|
@ -13500,7 +13500,7 @@
|
|||
"dependencies": {
|
||||
"jsesc": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "http://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
|
||||
"integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=",
|
||||
"dev": true
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
const express = require('express');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
const templatesPath = path.resolve(__dirname, './templates');
|
||||
const componentsPath = path.resolve(__dirname, './core/components');
|
||||
|
||||
module.exports = app => {
|
||||
global.appPath = __dirname;
|
||||
|
||||
process.env.OPENSSL_CONF = '/etc/ssl/';
|
||||
|
||||
// Extended locale intl polyfill
|
||||
const IntlPolyfill = require('intl');
|
||||
Intl.NumberFormat = IntlPolyfill.NumberFormat;
|
||||
Intl.DateTimeFormat = IntlPolyfill.DateTimeFormat;
|
||||
|
||||
// Init database instance
|
||||
require('./core/database').init();
|
||||
// Init SMTP Instance
|
||||
require('./core/smtp').init();
|
||||
//
|
||||
require('./core/mixins');
|
||||
require('./core/filters');
|
||||
require('./core/directives');
|
||||
// Init router
|
||||
require('./core/router')(app);
|
||||
|
||||
/**
|
||||
* Serve component static files
|
||||
*/
|
||||
const componentsDir = fs.readdirSync(componentsPath);
|
||||
componentsDir.forEach(componentName => {
|
||||
const componentDir = path.join(componentsPath, '/', componentName);
|
||||
const assetsDir = `${componentDir}/assets`;
|
||||
|
||||
app.use(`/api/${componentName}/assets`, express.static(assetsDir));
|
||||
});
|
||||
|
||||
/**
|
||||
* Serve static files
|
||||
*/
|
||||
const templatesDir = fs.readdirSync(templatesPath);
|
||||
templatesDir.forEach(directory => {
|
||||
const templateTypeDir = path.join(templatesPath, '/', directory);
|
||||
const templates = fs.readdirSync(templateTypeDir);
|
||||
|
||||
templates.forEach(templateName => {
|
||||
const templateDir = path.join(templatesPath, '/', directory, '/', templateName);
|
||||
const assetsDir = `${templateDir}/assets`;
|
||||
|
||||
app.use(`/api/${templateName}/assets`, express.static(assetsDir));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -1,40 +1,33 @@
|
|||
/**
|
||||
* Email only stylesheet
|
||||
*
|
||||
*/
|
||||
body {
|
||||
background-color: #EEE
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 600px;
|
||||
min-width: 320px;
|
||||
margin: 0 auto;
|
||||
color: #555
|
||||
}
|
||||
|
||||
.main {
|
||||
-webkit-text-size-adjust: none;
|
||||
-ms-text-size-adjust: none;
|
||||
background-color: #FFF;
|
||||
padding: 20px
|
||||
font-weight: 400;
|
||||
color: #555;
|
||||
margin: 0
|
||||
}
|
||||
|
||||
.main a {
|
||||
.grid {
|
||||
background-color: #FFF
|
||||
|
||||
}
|
||||
|
||||
.grid a {
|
||||
color: #8dba25
|
||||
}
|
||||
|
||||
.main h1 {
|
||||
color: #999
|
||||
.grid-block {
|
||||
min-width: 300px;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
color: #333
|
||||
}
|
||||
|
||||
.main h3 {
|
||||
font-size: 16px
|
||||
}
|
||||
|
||||
.title {
|
||||
background-color: #95d831;
|
||||
text-transform: uppercase;
|
||||
text-align: center;
|
||||
padding: 35px 0
|
||||
}
|
||||
|
||||
.title h1 {
|
||||
font-size: 32px;
|
||||
color: #333;
|
||||
margin: 0
|
||||
h1 {
|
||||
font-weight: 100;
|
||||
font-size: 1.5em
|
||||
}
|
||||
|
|
|
@ -1,10 +1,34 @@
|
|||
.container {
|
||||
font-family: "Roboto", "Helvetica", "Arial", sans-serif;
|
||||
font-size: 16px
|
||||
/**
|
||||
* CSS layout elements
|
||||
*
|
||||
*/
|
||||
|
||||
.grid {
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
font-size: 16px !important;
|
||||
width: 100%
|
||||
}
|
||||
|
||||
.grid-row {
|
||||
background-color: transparent
|
||||
}
|
||||
|
||||
.grid-block {
|
||||
box-sizing: border-box;
|
||||
min-height: 40px
|
||||
}
|
||||
|
||||
.grid-block.empty {
|
||||
height: 40px
|
||||
}
|
||||
|
||||
.grid-block.white {
|
||||
background-color: #FFF
|
||||
}
|
||||
|
||||
.columns {
|
||||
overflow: hidden
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.columns .size100 {
|
||||
|
@ -18,6 +42,7 @@
|
|||
}
|
||||
|
||||
.columns .size50 {
|
||||
box-sizing: border-box;
|
||||
width: 50%;
|
||||
float: left
|
||||
}
|
||||
|
@ -173,7 +198,7 @@ table {
|
|||
}
|
||||
|
||||
.panel .row-oriented td, .panel .row-oriented th {
|
||||
padding: 10px 0
|
||||
padding: 8px 10px
|
||||
}
|
||||
|
||||
.row-oriented > tbody > tr > td {
|
||||
|
@ -199,8 +224,8 @@ table {
|
|||
margin-left: -1px;
|
||||
margin-right: 1px;
|
||||
margin-top: 10px;
|
||||
padding: 5px 0;
|
||||
color: #999;
|
||||
padding: 5px 0
|
||||
}
|
||||
|
||||
.line .vertical-aligned {
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
/**
|
||||
* CSS misc classes
|
||||
*
|
||||
*/
|
||||
.uppercase {
|
||||
text-transform: uppercase
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
/**
|
||||
* Report only stylesheet
|
||||
*
|
||||
*/
|
||||
body {
|
||||
zoom: 0.55
|
||||
zoom: 0.53
|
||||
}
|
||||
|
||||
.title {
|
||||
|
|
|
@ -0,0 +1,349 @@
|
|||
/**
|
||||
* CSS spacing classes
|
||||
*
|
||||
* vn-[p|m][t|r|b|l|a|x|y]-[none|auto|xs|sm|md|lg|xl]
|
||||
* T D S
|
||||
*
|
||||
* T - type
|
||||
* - values: p (padding), m (margin)
|
||||
*
|
||||
* D - direction
|
||||
* - values:
|
||||
* t (top), r (right), b (bottom), l (left),
|
||||
* a (all), x (both left & right), y (both top & bottom)
|
||||
*
|
||||
* S - size
|
||||
* - values:
|
||||
* none,
|
||||
* auto (ONLY for specific margins: vn-ml-*, vn-mr-*, vn-mx-*),
|
||||
* xs (extra small),
|
||||
* sm (small),
|
||||
* md (medium),
|
||||
* lg (large),
|
||||
* xl (extra large)
|
||||
*/
|
||||
|
||||
/* ++++++++++++++++++++++++++++++++++++++++++++++++ Padding */
|
||||
|
||||
.vn-pa-none {
|
||||
padding: 0;
|
||||
}
|
||||
.vn-pl-none {
|
||||
padding-left: 0;
|
||||
}
|
||||
.vn-pr-none {
|
||||
padding-right: 0;
|
||||
}
|
||||
.vn-pt-none {
|
||||
padding-top: 0;
|
||||
}
|
||||
.vn-pb-none {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.vn-py-none {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.vn-px-none {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.vn-pa-xs {
|
||||
padding: 4px;
|
||||
}
|
||||
.vn-pl-xs {
|
||||
padding-left: 4px;
|
||||
}
|
||||
.vn-pr-xs {
|
||||
padding-right: 4px;
|
||||
}
|
||||
.vn-pt-xs {
|
||||
padding-top: 4px;
|
||||
}
|
||||
.vn-pb-xs {
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
.vn-py-xs {
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
.vn-px-xs {
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
/* Small */
|
||||
|
||||
.vn-pa-sm {
|
||||
padding: 8px;
|
||||
}
|
||||
.vn-pl-sm {
|
||||
padding-left: 8px;
|
||||
}
|
||||
.vn-pr-sm {
|
||||
padding-right: 8px;
|
||||
}
|
||||
.vn-pt-sm {
|
||||
padding-top: 8px;
|
||||
}
|
||||
.vn-pb-sm {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
.vn-py-sm {
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
.vn-px-sm {
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
/* Medium */
|
||||
|
||||
.vn-pa-md {
|
||||
padding: 16px;
|
||||
}
|
||||
.vn-pl-md {
|
||||
padding-left: 16px;
|
||||
}
|
||||
.vn-pr-md {
|
||||
padding-right: 16px;
|
||||
}
|
||||
.vn-pt-md {
|
||||
padding-top: 16px;
|
||||
}
|
||||
.vn-pb-md {
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
.vn-py-md {
|
||||
padding-top: 16px;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
.vn-px-md {
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
}
|
||||
|
||||
/* Large */
|
||||
|
||||
.vn-pa-lg {
|
||||
padding: 32px;
|
||||
}
|
||||
.vn-pl-lg {
|
||||
padding-left: 32px;
|
||||
}
|
||||
.vn-pr-lg {
|
||||
padding-right: 32px;
|
||||
}
|
||||
.vn-pt-lg {
|
||||
padding-top: 32px;
|
||||
}
|
||||
.vn-pb-lg {
|
||||
padding-bottom: 32px;
|
||||
}
|
||||
.vn-py-lg {
|
||||
padding-top: 32px;
|
||||
padding-bottom: 32px;
|
||||
}
|
||||
.vn-px-lg {
|
||||
padding-left: 32px;
|
||||
padding-right: 32px;
|
||||
}
|
||||
|
||||
/* Extra large */
|
||||
|
||||
.vn-pa-xl {
|
||||
padding: 100px;
|
||||
}
|
||||
.vn-pl-xl {
|
||||
padding-left: 100px;
|
||||
}
|
||||
.vn-pr-xl {
|
||||
padding-right: 100px;
|
||||
}
|
||||
.vn-pt-xl {
|
||||
padding-top: 100px;
|
||||
}
|
||||
.vn-pb-xl {
|
||||
padding-bottom: 100px;
|
||||
}
|
||||
.vn-py-xl {
|
||||
padding-top: 100px;
|
||||
padding-bottom: 100px;
|
||||
}
|
||||
.vn-px-xl {
|
||||
padding-left: 100px;
|
||||
padding-right: 100px;
|
||||
}
|
||||
|
||||
/* ++++++++++++++++++++++++++++++++++++++++++++++++ Margin */
|
||||
|
||||
/* None */
|
||||
|
||||
.vn-ma-none {
|
||||
padding: 0;
|
||||
}
|
||||
.vn-ml-none {
|
||||
padding-left: 0;
|
||||
}
|
||||
.vn-mr-none {
|
||||
padding-right: 0;
|
||||
}
|
||||
.vn-mt-none {
|
||||
padding-top: 0;
|
||||
}
|
||||
.vn-mb-none {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.vn-my-none {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.vn-mx-none {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
/* Auto */
|
||||
|
||||
.vn-ml-none {
|
||||
padding-left: auto;
|
||||
}
|
||||
.vn-mr-none {
|
||||
padding-right: auto;
|
||||
}
|
||||
.vn-mx-none {
|
||||
padding-left: auto;
|
||||
padding-right: auto;
|
||||
}
|
||||
|
||||
/* Extra small */
|
||||
|
||||
.vn-ma-xs {
|
||||
margin: 4px;
|
||||
}
|
||||
.vn-mt-xs {
|
||||
margin-top: 4px;
|
||||
}
|
||||
.vn-ml-xs {
|
||||
margin-left: 4px;
|
||||
}
|
||||
.vn-mr-xs {
|
||||
margin-right: 4px;
|
||||
}
|
||||
.vn-mb-xs {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.vn-my-xs {
|
||||
margin-top: 4px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.vn-mx-xs {
|
||||
margin-left: 4px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
/* Small */
|
||||
|
||||
.vn-ma-sm {
|
||||
margin: 8px;
|
||||
}
|
||||
.vn-mt-sm {
|
||||
margin-top: 8px;
|
||||
}
|
||||
.vn-ml-sm {
|
||||
margin-left: 8px;
|
||||
}
|
||||
.vn-mr-sm {
|
||||
margin-right: 8px;
|
||||
}
|
||||
.vn-mb-sm {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.vn-my-sm {
|
||||
margin-top: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.vn-mx-sm {
|
||||
margin-left: 8px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
/* Medium */
|
||||
|
||||
.vn-ma-md {
|
||||
margin: 16px;
|
||||
}
|
||||
.vn-mt-md {
|
||||
margin-top: 16px;
|
||||
}
|
||||
.vn-ml-md {
|
||||
margin-left: 16px;
|
||||
}
|
||||
.vn-mr-md {
|
||||
margin-right: 16px;
|
||||
}
|
||||
.vn-mb-md {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.vn-my-md {
|
||||
margin-top: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.vn-mx-md {
|
||||
margin-left: 16px;
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
/* Large */
|
||||
|
||||
.vn-ma-lg {
|
||||
margin: 32px;
|
||||
}
|
||||
.vn-mt-lg {
|
||||
margin-top: 32px;
|
||||
}
|
||||
.vn-ml-lg {
|
||||
margin-left: 32px;
|
||||
}
|
||||
.vn-mr-lg {
|
||||
margin-right: 32px;
|
||||
}
|
||||
.vn-mb-lg {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
.vn-my-lg {
|
||||
margin-top: 32px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
.vn-mx-lg {
|
||||
margin-left: 32px;
|
||||
margin-right: 32px;
|
||||
}
|
||||
|
||||
/* Extra large */
|
||||
|
||||
.vn-ma-xl {
|
||||
margin: 100px;
|
||||
}
|
||||
.vn-mt-xl {
|
||||
margin-top: 100px;
|
||||
}
|
||||
.vn-ml-xl {
|
||||
margin-left: 100px;
|
||||
}
|
||||
.vn-mr-xl {
|
||||
margin-right: 100px;
|
||||
}
|
||||
.vn-mb-xl {
|
||||
margin-bottom: 100px;
|
||||
}
|
||||
.vn-my-xl {
|
||||
margin-top: 100px;
|
||||
margin-bottom: 100px;
|
||||
}
|
||||
.vn-mx-xl {
|
||||
margin-left: 100px;
|
||||
margin-right: 100px;
|
||||
}
|
|
@ -1,10 +1,15 @@
|
|||
{
|
||||
"app": {
|
||||
"host": "http://localhost:5000",
|
||||
"port": 3000,
|
||||
"defaultLanguage": "es",
|
||||
"senderMail": "nocontestar@verdnatura.es",
|
||||
"senderName": "Verdnatura"
|
||||
},
|
||||
"i18n": {
|
||||
"locale": "es",
|
||||
"fallbackLocale": "es",
|
||||
"silentTranslationWarn": true
|
||||
},
|
||||
"pdf": {
|
||||
"format": "A4",
|
||||
"border": "1.5cm",
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
[
|
||||
{"type": "email", "name": "client-welcome"},
|
||||
{"type": "email", "name": "printer-setup"},
|
||||
{"type": "email", "name": "payment-update"},
|
||||
{"type": "email", "name": "letter-debtor-st"},
|
||||
{"type": "email", "name": "letter-debtor-nd"},
|
||||
{"type": "email", "name": "claim-pickup-order"},
|
||||
{"type": "email", "name": "sepa-core"},
|
||||
{"type": "email", "name": "client-lcr"},
|
||||
{"type": "email", "name": "driver-route"},
|
||||
{"type": "email", "name": "delivery-note"},
|
||||
{"type": "report", "name": "rpt-delivery-note"},
|
||||
{"type": "report", "name": "rpt-claim-pickup-order"},
|
||||
{"type": "report", "name": "rpt-letter-debtor"},
|
||||
{"type": "report", "name": "rpt-sepa-core"},
|
||||
{"type": "report", "name": "rpt-receipt"},
|
||||
{"type": "report", "name": "rpt-zone"},
|
||||
{"type": "report", "name": "rpt-route"},
|
||||
{"type": "report", "name": "rpt-lcr"},
|
||||
{"type": "report", "name": "rpt-item-label"},
|
||||
{"type": "static", "name": "email-header"},
|
||||
{"type": "static", "name": "email-footer"},
|
||||
{"type": "static", "name": "report-header"},
|
||||
{"type": "static", "name": "report-footer"}
|
||||
]
|
|
@ -0,0 +1,104 @@
|
|||
const Vue = require('vue');
|
||||
const VueI18n = require('vue-i18n');
|
||||
const renderer = require('vue-server-renderer').createRenderer();
|
||||
Vue.use(VueI18n);
|
||||
|
||||
const fs = require('fs');
|
||||
const yaml = require('js-yaml');
|
||||
const juice = require('juice');
|
||||
const path = require('path');
|
||||
const config = require('./config');
|
||||
|
||||
class Component {
|
||||
constructor(name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
get path() {
|
||||
return `./components/${this.name}`;
|
||||
}
|
||||
|
||||
get template() {
|
||||
const templatePath = `${this.path}/${this.name}.html`;
|
||||
const fullPath = path.resolve(__dirname, templatePath);
|
||||
|
||||
return fs.readFileSync(fullPath, 'utf8');
|
||||
}
|
||||
|
||||
get locale() {
|
||||
if (!this._locale)
|
||||
this.getLocale();
|
||||
|
||||
return this._locale;
|
||||
}
|
||||
|
||||
getLocale() {
|
||||
const mergedLocale = {messages: {}};
|
||||
const localePath = path.resolve(__dirname, `${this.path}/locale`);
|
||||
|
||||
if (!fs.existsSync(localePath))
|
||||
return mergedLocale;
|
||||
|
||||
const localeDir = fs.readdirSync(localePath);
|
||||
localeDir.forEach(locale => {
|
||||
const fullPath = path.join(localePath, '/', locale);
|
||||
const yamlLocale = fs.readFileSync(fullPath, 'utf8');
|
||||
const jsonLocale = yaml.safeLoad(yamlLocale);
|
||||
const localeName = locale.replace('.yml', '');
|
||||
|
||||
mergedLocale.messages[localeName] = jsonLocale;
|
||||
});
|
||||
|
||||
this._locale = mergedLocale;
|
||||
}
|
||||
|
||||
get stylesheet() {
|
||||
let mergedStyles = '';
|
||||
const stylePath = path.resolve(__dirname, `${this.path}/assets/css`);
|
||||
|
||||
if (!fs.existsSync(stylePath))
|
||||
return mergedStyles;
|
||||
|
||||
return require(`${stylePath}/import`);
|
||||
}
|
||||
|
||||
get attachments() {
|
||||
const attachmentsPath = `${this.path}/attachments.json`;
|
||||
const fullPath = path.resolve(__dirname, attachmentsPath);
|
||||
|
||||
if (!fs.existsSync(fullPath))
|
||||
return [];
|
||||
|
||||
return require(fullPath);
|
||||
}
|
||||
|
||||
build() {
|
||||
const fullPath = path.resolve(__dirname, this.path);
|
||||
if (!fs.existsSync(fullPath))
|
||||
throw new Error(`Sample "${this.name}" not found`);
|
||||
|
||||
const component = require(`${this.path}/${this.name}`);
|
||||
component.i18n = this.locale;
|
||||
component.attachments = this.attachments;
|
||||
component.template = juice.inlineContent(this.template, this.stylesheet, {
|
||||
inlinePseudoElements: true
|
||||
});
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
async render() {
|
||||
const component = this.build();
|
||||
const i18n = new VueI18n(config.i18n);
|
||||
const app = new Vue({
|
||||
i18n: i18n,
|
||||
render: h => h(component, {
|
||||
props: this.args
|
||||
})
|
||||
});
|
||||
|
||||
return renderer.renderToString(app);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Component;
|
|
@ -0,0 +1,9 @@
|
|||
const Stylesheet = require(`${appPath}/core/stylesheet`);
|
||||
|
||||
module.exports = new Stylesheet([
|
||||
`${appPath}/common/css/spacing.css`,
|
||||
`${appPath}/common/css/misc.css`,
|
||||
`${appPath}/common/css/layout.css`,
|
||||
`${appPath}/common/css/email.css`,
|
||||
`${__dirname}/style.css`])
|
||||
.mergeStyles();
|
|
@ -0,0 +1,22 @@
|
|||
div {
|
||||
display: inline-block;
|
||||
box-sizing: border-box
|
||||
}
|
||||
|
||||
a {
|
||||
background-color: #F5F5F5;
|
||||
border: 1px solid #CCC;
|
||||
display: flex;
|
||||
vertical-align: middle;
|
||||
box-sizing: border-box;
|
||||
min-width: 150px;
|
||||
text-decoration: none;
|
||||
border-radius: 3px;
|
||||
color: #8dba25
|
||||
}
|
||||
|
||||
a > div.icon {
|
||||
font-weight: bold;
|
||||
font-size: 18px;
|
||||
color: #555
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M2 12.5C2 9.46 4.46 7 7.5 7H18c2.21 0 4 1.79 4 4s-1.79 4-4 4H9.5C8.12 15 7 13.88 7 12.5S8.12 10 9.5 10H17v2H9.41c-.55 0-.55 1 0 1H18c1.1 0 2-.9 2-2s-.9-2-2-2H7.5C5.57 9 4 10.57 4 12.5S5.57 16 7.5 16H17v2H7.5C4.46 18 2 15.54 2 12.5z"/><path fill="none" d="M0 0h24v24H0V0z"/></svg>
|
After Width: | Height: | Size: 371 B |
|
@ -0,0 +1,6 @@
|
|||
<div class="vn-mx-xs" v-if="attachment.component">
|
||||
<a target="_blank" class="vn-py-sm vn-px-md" v-bind:href="path">
|
||||
<div class="text">{{attachment.filename}}</div>
|
||||
<div class="icon vn-pl-md">▼</div>
|
||||
</a>
|
||||
</div>
|
|
@ -0,0 +1,37 @@
|
|||
module.exports = {
|
||||
name: 'attachment',
|
||||
computed: {
|
||||
path() {
|
||||
const filename = this.attachment.filename;
|
||||
const component = this.attachment.component;
|
||||
if (this.attachment.cid)
|
||||
return `/api/${component}/assets/files/${filename}`;
|
||||
else
|
||||
return `/api/report/${component}?${this.getHttpParams()}`;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getHttpParams() {
|
||||
const props = this.args;
|
||||
let query = '';
|
||||
for (let param in props) {
|
||||
if (query != '')
|
||||
query += '&';
|
||||
query += `${param}=${props[param]}`;
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
},
|
||||
props: {
|
||||
attachment: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
args: {
|
||||
type: Object,
|
||||
required: false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
const Stylesheet = require(`${appPath}/core/stylesheet`);
|
||||
|
||||
module.exports = new Stylesheet([
|
||||
`${appPath}/common/css/spacing.css`,
|
||||
`${appPath}/common/css/misc.css`,
|
||||
`${appPath}/common/css/layout.css`,
|
||||
`${appPath}/common/css/email.css`,
|
||||
`${__dirname}/style.css`])
|
||||
.mergeStyles();
|
|
@ -1,21 +1,12 @@
|
|||
@media (max-width: 400px) {
|
||||
.buttons a {
|
||||
display: block;
|
||||
width: 100%
|
||||
}
|
||||
}
|
||||
|
||||
.buttons {
|
||||
font-size: 14px !important;
|
||||
width: 100%
|
||||
}
|
||||
|
||||
.buttons a {
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
text-decoration: none;
|
||||
font-size: 16px;
|
||||
width: 100%;
|
||||
color: #fff;
|
||||
width: 50%
|
||||
}
|
||||
|
||||
.buttons .btn {
|
||||
|
@ -23,18 +14,20 @@
|
|||
text-align: center
|
||||
}
|
||||
|
||||
.buttons .btn .text {
|
||||
display: inline-block;
|
||||
padding: 22px 0
|
||||
}
|
||||
|
||||
.buttons .btn .icon {
|
||||
background-color: #95d831;
|
||||
box-sizing: border-box;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
padding: 16.5px 0;
|
||||
float: right;
|
||||
width: 70px
|
||||
color: #333;
|
||||
float: left
|
||||
}
|
||||
|
||||
|
||||
.buttons .btn .text {
|
||||
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.networks {
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
|
@ -0,0 +1,22 @@
|
|||
[
|
||||
{
|
||||
"filename": "facebook.png",
|
||||
"path": "/assets/images/facebook.png",
|
||||
"cid": "facebook.png"
|
||||
},
|
||||
{
|
||||
"filename": "twitter.png",
|
||||
"path": "/assets/images/twitter.png",
|
||||
"cid": "twitter.png"
|
||||
},
|
||||
{
|
||||
"filename": "instagram.png",
|
||||
"path": "/assets/images/instagram.png",
|
||||
"cid": "instagram.png"
|
||||
},
|
||||
{
|
||||
"filename": "linkedin.png",
|
||||
"path": "/assets/images/linkedin.png",
|
||||
"cid": "linkedin.png"
|
||||
}
|
||||
]
|
|
@ -0,0 +1,47 @@
|
|||
<footer>
|
||||
<!-- Action button block -->
|
||||
<div class="buttons">
|
||||
<div class="columns">
|
||||
<div class="size50">
|
||||
<a href="https://www.verdnatura.es" target="_blank">
|
||||
<div class="btn">
|
||||
<!-- <span class="icon vn-pa-sm"><img v-bind:src="getEmailSrc('action.png')"/></span> -->
|
||||
<span class="text vn-pa-sm">{{ $t('buttons.webAcccess')}}</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="size50">
|
||||
<a href="https://goo.gl/forms/j8WSL151ZW6QtlT72" target="_blank">
|
||||
<div class="btn">
|
||||
<!-- <span class="icon vn-pa-sm"><img v-bind:src="getEmailSrc('info.png')"/></span> -->
|
||||
<span class="text vn-pa-sm">{{ $t('buttons.info')}}</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Networks block -->
|
||||
<div class="networks">
|
||||
<a href="https://www.facebook.com/Verdnatura" target="_blank">
|
||||
<img v-bind:src="getEmailSrc('facebook.png')" alt="Facebook"/>
|
||||
</a>
|
||||
<a href="https://www.twitter.com/Verdnatura" target="_blank">
|
||||
<img v-bind:src="getEmailSrc('twitter.png')" alt="Twitter"/>
|
||||
</a>
|
||||
<a href="https://www.instagram.com/Verdnatura" target="_blank">
|
||||
<img v-bind:src="getEmailSrc('instagram.png')" alt="Instagram"/>
|
||||
</a>
|
||||
<a href="https://www.linkedin.com/company/verdnatura" target="_blank">
|
||||
<img v-bind:src="getEmailSrc('linkedin.png')" alt="Linkedin"/>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Privacy block -->
|
||||
<div class="privacy">
|
||||
<p>{{$t('privacy.fiscalAddress')}}</p>
|
||||
<p>{{$t('privacy.disclaimer')}}</p>
|
||||
<p>{{$t('privacy.law')}}</p>
|
||||
</div>
|
||||
<!-- Privacy block end -->
|
||||
</footer>
|
|
@ -0,0 +1,4 @@
|
|||
module.exports = {
|
||||
name: 'email-footer',
|
||||
props: ['isPreview', 'locale']
|
||||
};
|
|
@ -0,0 +1,19 @@
|
|||
buttons:
|
||||
webAcccess: Visita nuestra Web
|
||||
info: Ayúdanos a mejorar
|
||||
privacy:
|
||||
fiscalAddress: VERDNATURA LEVANTE SL, B97367486 Avda. Espioca, 100, 46460 Silla
|
||||
· www.verdnatura.es · clientes@verdnatura.es
|
||||
disclaimer: '- AVISO - Este mensaje es privado y confidencial, y debe ser utilizado
|
||||
exclusivamente por la persona destinataria del mismo. Si has recibido este mensaje
|
||||
por error, te rogamos lo comuniques al remitente y borres dicho mensaje y cualquier
|
||||
documento adjunto que pudiera contener. Verdnatura Levante SL no renuncia a la
|
||||
confidencialidad ni a ningún privilegio por causa de transmisión errónea o mal
|
||||
funcionamiento. Igualmente no se hace responsable de los cambios, alteraciones,
|
||||
errores u omisiones que pudieran hacerse al mensaje una vez enviado.'
|
||||
law: En cumplimiento de lo dispuesto en la Ley Orgánica 15/1999, de Protección de
|
||||
Datos de Carácter Personal, te comunicamos que los datos personales que facilites
|
||||
se incluirán en ficheros automatizados de VERDNATURA LEVANTE S.L., pudiendo en
|
||||
todo momento ejercitar los derechos de acceso, rectificación, cancelación y oposición,
|
||||
comunicándolo por escrito al domicilio social de la entidad. La finalidad del
|
||||
fichero es la gestión administrativa, contabilidad, y facturación.
|
|
@ -0,0 +1,19 @@
|
|||
buttons:
|
||||
webAcccess: Visitez notre site web
|
||||
info: Aidez-nous à améliorer
|
||||
privacy:
|
||||
fiscalAddress: VERDNATURA LEVANTE SL, B97367486 Avda. Espioca, 100, 46460 Silla
|
||||
· www.verdnatura.es · clientes@verdnatura.es
|
||||
disclaimer: '- AVIS - Ce message est privé et confidentiel et doit être utilisé.exclusivamente
|
||||
por la persona destinataria del mismo. Si has recibido este mensajepor error,
|
||||
te rogamos lo comuniques al remitente y borres dicho mensaje y cualquier documentoadjunto
|
||||
que pudiera contener. Verdnatura Levante SL no renuncia a la confidencialidad
|
||||
ni aningún privilegio por causa de transmisión errónea o mal funcionamiento. Igualmente
|
||||
no se haceresponsable de los cambios, alteraciones, errores u omisiones que pudieran
|
||||
hacerse al mensaje una vez enviado.'
|
||||
law: En cumplimiento de lo dispuesto en la Ley Orgánica 15/1999, de Protección de
|
||||
Datos de Carácter Personal, te comunicamos que los datos personales que facilites
|
||||
se incluirán en ficheros automatizados de VERDNATURA LEVANTE S.L.,pudiendo en
|
||||
todo momento ejercitar los derechos de acceso, rectificación, cancelación y oposición,
|
||||
comunicándolo porescrito al domicilio social de la entidad. La finalidad del fichero
|
||||
es la gestión administrativa, contabilidad, y facturación.
|
|
@ -0,0 +1,9 @@
|
|||
const Stylesheet = require(`${appPath}/core/stylesheet`);
|
||||
|
||||
module.exports = new Stylesheet([
|
||||
`${appPath}/common/css/spacing.css`,
|
||||
`${appPath}/common/css/misc.css`,
|
||||
`${appPath}/common/css/layout.css`,
|
||||
`${appPath}/common/css/email.css`,
|
||||
`${__dirname}/style.css`])
|
||||
.mergeStyles();
|
|
@ -0,0 +1,19 @@
|
|||
header .logo {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
header .logo img {
|
||||
width: 50%
|
||||
}
|
||||
|
||||
header .topbar {
|
||||
background-color: #95d831;
|
||||
height: 10px
|
||||
}
|
||||
|
||||
.topbar:after {
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
content: ' ';
|
||||
clear: both;
|
||||
}
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 9.5 KiB |
|
@ -0,0 +1,131 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 13.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="500"
|
||||
height="68.596313"
|
||||
viewBox="0 0 499.99999 68.596313"
|
||||
enable-background="new 0 0 226.229 31.038"
|
||||
xml:space="preserve"
|
||||
id="svg2"
|
||||
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||
sodipodi:docname="verdnatura-white.svg"><metadata
|
||||
id="metadata61"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs59" /><sodipodi:namedview
|
||||
pagecolor="#333333"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1013"
|
||||
id="namedview57"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.5909426"
|
||||
inkscape:cx="268.25598"
|
||||
inkscape:cy="112.75218"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="30"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg2"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0" /><g
|
||||
id="Background"
|
||||
transform="translate(2.2478643e-6,43.261169)" /><g
|
||||
id="Guides"
|
||||
transform="translate(2.2478643e-6,43.261169)" /><g
|
||||
id="g883"
|
||||
transform="matrix(2.2101465,0,0,2.2101465,0,-594.44542)"><g
|
||||
transform="translate(0,268.962)"
|
||||
style="fill:#ffffff"
|
||||
id="g9"><path
|
||||
style="clip-rule:evenodd;fill:#ffffff;fill-rule:evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path11"
|
||||
d="M 10.417,30.321 0,0 h 8.233 l 4.26,15.582 0.349,1.276 c 0.521,1.866 0.918,3.431 1.191,4.693 0.15,-0.618 0.335,-1.345 0.555,-2.182 0.219,-0.837 0.528,-1.935 0.925,-3.293 L 19.981,0 h 8.19 l -10.5,30.321 z" /></g><g
|
||||
transform="translate(0,268.962)"
|
||||
id="g13"><path
|
||||
inkscape:connector-curvature="0"
|
||||
style="clip-rule:evenodd;fill:#8ed300;fill-opacity:1;fill-rule:evenodd"
|
||||
id="path15"
|
||||
d="m 139.809,19.787 c -0.665,0.357 -1.748,0.686 -3.25,0.988 -0.727,0.137 -1.283,0.254 -1.667,0.35 -0.95,0.247 -1.661,0.563 -2.134,0.947 -0.472,0.384 -0.799,0.899 -0.979,1.544 -0.223,0.796 -0.155,1.438 0.204,1.925 0.359,0.488 0.945,0.731 1.757,0.731 1.252,0 2.375,-0.36 3.369,-1.081 0.994,-0.721 1.653,-1.665 1.98,-2.831 z m 5.106,10.534 h -7.458 c 0.017,-0.356 0.048,-0.726 0.094,-1.11 l 0.159,-1.192 c -1.318,1.026 -2.627,1.786 -3.927,2.279 -1.299,0.493 -2.643,0.739 -4.031,0.739 -2.158,0 -3.7,-0.593 -4.625,-1.779 -0.925,-1.187 -1.106,-2.788 -0.542,-4.804 0.519,-1.851 1.431,-3.356 2.737,-4.515 1.307,-1.159 3.021,-1.972 5.142,-2.438 1.169,-0.247 2.641,-0.515 4.413,-0.803 2.646,-0.412 4.082,-1.016 4.304,-1.812 l 0.151,-0.539 c 0.182,-0.65 0.076,-1.145 -0.317,-1.483 -0.393,-0.339 -1.071,-0.508 -2.033,-0.508 -1.045,0 -1.934,0.214 -2.666,0.643 -0.731,0.428 -1.289,1.058 -1.673,1.887 h -6.748 c 1.065,-2.53 2.64,-4.413 4.723,-5.65 2.083,-1.237 4.724,-1.856 7.923,-1.856 1.991,0 3.602,0.241 4.833,0.722 1.231,0.481 2.095,1.209 2.59,2.185 0.339,0.701 0.483,1.536 0.432,2.504 -0.052,0.969 -0.377,2.525 -0.978,4.669 l -2.375,8.483 c -0.284,1.014 -0.416,1.812 -0.396,2.395 0.02,0.583 0.188,0.962 0.503,1.141 z" /></g><g
|
||||
transform="translate(0,268.962)"
|
||||
id="g17"><path
|
||||
inkscape:connector-curvature="0"
|
||||
style="clip-rule:evenodd;fill:#8ed300;fill-opacity:1;fill-rule:evenodd"
|
||||
id="path19"
|
||||
d="m 185.7,30.321 6.27,-22.393 h 7.049 l -1.097,3.918 c 1.213,-1.537 2.502,-2.659 3.867,-3.366 1.365,-0.707 2.951,-1.074 4.758,-1.101 l -2.03,7.25 c -0.304,-0.042 -0.608,-0.072 -0.912,-0.093 -0.303,-0.02 -0.592,-0.03 -0.867,-0.03 -1.126,0 -2.104,0.168 -2.932,0.504 -0.829,0.336 -1.561,0.854 -2.197,1.555 -0.406,0.467 -0.789,1.136 -1.149,2.007 -0.361,0.872 -0.814,2.282 -1.359,4.232 l -2.104,7.516 H 185.7 Z" /></g><g
|
||||
transform="translate(0,268.962)"
|
||||
id="g21"><path
|
||||
inkscape:connector-curvature="0"
|
||||
style="clip-rule:evenodd;fill:#8ed300;fill-opacity:1;fill-rule:evenodd"
|
||||
id="path23"
|
||||
d="m 217.631,19.787 c -0.664,0.357 -1.748,0.686 -3.25,0.988 -0.727,0.137 -1.282,0.254 -1.667,0.35 -0.95,0.247 -1.661,0.563 -2.134,0.947 -0.472,0.384 -0.799,0.899 -0.979,1.544 -0.223,0.796 -0.155,1.438 0.205,1.925 0.359,0.488 0.945,0.731 1.757,0.731 1.252,0 2.375,-0.36 3.369,-1.081 0.994,-0.721 1.654,-1.665 1.98,-2.831 z m 5.106,10.534 h -7.458 c 0.017,-0.356 0.048,-0.726 0.094,-1.11 l 0.159,-1.192 c -1.318,1.026 -2.627,1.786 -3.927,2.279 -1.299,0.493 -2.643,0.739 -4.031,0.739 -2.158,0 -3.7,-0.593 -4.625,-1.779 -0.926,-1.187 -1.106,-2.788 -0.542,-4.804 0.519,-1.851 1.431,-3.356 2.737,-4.515 1.306,-1.159 3.02,-1.972 5.142,-2.438 1.169,-0.247 2.641,-0.515 4.413,-0.803 2.647,-0.412 4.082,-1.016 4.304,-1.812 l 0.151,-0.539 c 0.182,-0.65 0.077,-1.145 -0.317,-1.483 -0.393,-0.339 -1.071,-0.508 -2.033,-0.508 -1.045,0 -1.934,0.214 -2.666,0.643 -0.731,0.428 -1.289,1.058 -1.672,1.887 h -6.748 c 1.065,-2.53 2.64,-4.413 4.723,-5.65 2.083,-1.237 4.724,-1.856 7.923,-1.856 1.99,0 3.601,0.241 4.833,0.722 1.232,0.481 2.095,1.209 2.591,2.185 0.339,0.701 0.483,1.536 0.431,2.504 -0.051,0.969 -0.377,2.525 -0.978,4.669 l -2.375,8.483 c -0.284,1.014 -0.416,1.812 -0.396,2.395 0.02,0.583 0.188,0.962 0.503,1.141 z" /></g><g
|
||||
transform="translate(0,268.962)"
|
||||
id="g25"><path
|
||||
inkscape:connector-curvature="0"
|
||||
style="clip-rule:evenodd;fill:#8ed300;fill-opacity:1;fill-rule:evenodd"
|
||||
id="path27"
|
||||
d="m 188.386,7.928 -6.269,22.393 h -7.174 l 0.864,-3.085 c -1.227,1.246 -2.476,2.163 -3.746,2.751 -1.27,0.588 -2.625,0.882 -4.067,0.882 -2.471,0 -4.154,-0.634 -5.048,-1.901 -0.895,-1.268 -0.993,-3.149 -0.294,-5.644 l 4.31,-15.396 h 7.338 l -3.508,12.53 c -0.516,1.842 -0.641,3.109 -0.375,3.803 0.266,0.694 0.967,1.041 2.105,1.041 1.275,0 2.323,-0.422 3.142,-1.267 0.819,-0.845 1.497,-2.223 2.031,-4.133 l 3.353,-11.974 z" /></g><g
|
||||
transform="translate(0,268.962)"
|
||||
id="g29"><path
|
||||
inkscape:connector-curvature="0"
|
||||
style="clip-rule:evenodd;fill:#8ed300;fill-opacity:1;fill-rule:evenodd"
|
||||
id="path31"
|
||||
d="m 149.937,12.356 1.239,-4.428 h 2.995 l 1.771,-6.326 h 7.338 l -1.771,6.326 h 3.753 l -1.24,4.428 h -3.753 l -2.716,9.702 c -0.416,1.483 -0.498,2.465 -0.247,2.946 0.25,0.48 0.905,0.721 1.964,0.721 l 0.549,-0.011 0.39,-0.031 -1.31,4.678 c -0.811,0.148 -1.596,0.263 -2.354,0.344 -0.758,0.081 -1.48,0.122 -2.167,0.122 -2.543,0 -4.108,-0.621 -4.695,-1.863 -0.587,-1.242 -0.313,-3.887 0.82,-7.936 l 2.428,-8.672 z" /></g><g
|
||||
transform="translate(0,268.962)"
|
||||
style="fill:#ffffff"
|
||||
id="g33"><path
|
||||
style="clip-rule:evenodd;fill:#ffffff;fill-rule:evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path35"
|
||||
d="m 73.875,18.896 c -0.561,2.004 -0.616,3.537 -0.167,4.601 0.449,1.064 1.375,1.595 2.774,1.595 1.399,0 2.605,-0.524 3.62,-1.574 1.015,-1.05 1.806,-2.59 2.375,-4.622 0.526,-1.879 0.556,-3.334 0.09,-4.363 -0.466,-1.029 -1.393,-1.543 -2.778,-1.543 -1.304,0 -2.487,0.528 -3.551,1.585 -1.064,1.057 -1.852,2.496 -2.363,4.321 z M 96.513,0 88.024,30.321 h -7.337 l 0.824,-2.944 c -1.166,1.22 -2.369,2.121 -3.61,2.703 -1.241,0.582 -2.583,0.874 -4.025,0.874 -2.802,0 -4.772,-1.081 -5.912,-3.243 -1.139,-2.162 -1.218,-4.993 -0.238,-8.493 0.988,-3.528 2.668,-6.404 5.042,-8.627 2.374,-2.224 4.927,-3.336 7.661,-3.336 1.47,0 2.695,0.296 3.676,0.887 0.981,0.591 1.681,1.465 2.099,2.62 L 89.217,0 Z" /><g
|
||||
style="fill:#ffffff"
|
||||
id="g37"><path
|
||||
style="clip-rule:evenodd;fill:#ffffff;fill-rule:evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path39"
|
||||
d="m 73.875,18.896 c -0.561,2.004 -0.616,3.537 -0.167,4.601 0.449,1.064 1.375,1.595 2.774,1.595 1.399,0 2.605,-0.524 3.62,-1.574 1.015,-1.05 1.806,-2.59 2.375,-4.622 0.526,-1.879 0.556,-3.334 0.09,-4.363 -0.466,-1.029 -1.393,-1.543 -2.778,-1.543 -1.304,0 -2.487,0.528 -3.551,1.585 -1.064,1.057 -1.852,2.496 -2.363,4.321 z M 96.513,0 88.024,30.321 h -7.337 l 0.824,-2.944 c -1.166,1.22 -2.369,2.121 -3.61,2.703 -1.241,0.582 -2.583,0.874 -4.025,0.874 -2.802,0 -4.772,-1.081 -5.912,-3.243 -1.139,-2.162 -1.218,-4.993 -0.238,-8.493 0.988,-3.528 2.668,-6.404 5.042,-8.627 2.374,-2.224 4.927,-3.336 7.661,-3.336 1.47,0 2.695,0.296 3.676,0.887 0.981,0.591 1.681,1.465 2.099,2.62 L 89.217,0 Z" /></g></g><g
|
||||
transform="translate(0,268.962)"
|
||||
style="fill:#ffffff"
|
||||
id="g41"><path
|
||||
style="clip-rule:evenodd;fill:#ffffff;fill-rule:evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path43"
|
||||
d="M 46.488,30.321 52.757,7.928 h 7.049 l -1.098,3.918 C 59.921,10.309 61.21,9.187 62.576,8.48 63.942,7.773 68.591,7.406 70.398,7.379 l -2.03,7.25 c -0.304,-0.042 -0.608,-0.072 -0.911,-0.093 -0.304,-0.02 -0.592,-0.03 -0.867,-0.03 -1.126,0 -5.167,0.168 -5.997,0.504 -0.829,0.336 -1.561,0.854 -2.196,1.555 -0.406,0.467 -0.789,1.136 -1.149,2.007 -0.361,0.872 -0.814,2.282 -1.36,4.232 l -2.104,7.516 h -7.296 z" /></g><g
|
||||
transform="translate(0,268.962)"
|
||||
style="fill:#ffffff"
|
||||
id="g45"><path
|
||||
style="clip-rule:evenodd;fill:#ffffff;fill-rule:evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path47"
|
||||
d="m 32.673,16.742 8.351,-0.021 c 0.375,-1.436 0.308,-2.558 -0.201,-3.365 -0.509,-0.807 -1.402,-1.211 -2.68,-1.211 -1.209,0 -2.285,0.397 -3.229,1.19 -0.944,0.793 -1.69,1.93 -2.241,3.407 z m 6.144,6.536 h 7.043 c -1.347,2.456 -3.172,4.356 -5.477,5.7 -2.305,1.345 -4.885,2.017 -7.74,2.017 -3.473,0 -5.923,-1.054 -7.351,-3.161 -1.427,-2.107 -1.632,-4.98 -0.613,-8.618 1.038,-3.707 2.875,-6.641 5.512,-8.803 2.637,-2.163 5.678,-3.244 9.123,-3.244 3.555,0 6.04,1.099 7.456,3.298 1.417,2.198 1.582,5.234 0.498,9.109 l -0.239,0.814 -0.167,0.484 H 31.721 c -0.441,1.575 -0.438,2.777 0.01,3.606 0.448,0.829 1.332,1.244 2.65,1.244 0.975,0 1.836,-0.206 2.583,-0.617 0.747,-0.411 1.366,-1.021 1.853,-1.829 z" /><g
|
||||
style="fill:#ffffff"
|
||||
id="g49"><path
|
||||
style="clip-rule:evenodd;fill:#ffffff;fill-rule:evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path51"
|
||||
d="m 32.673,16.742 8.351,-0.021 c 0.375,-1.436 0.308,-2.558 -0.201,-3.365 -0.509,-0.807 -1.402,-1.211 -2.68,-1.211 -1.209,0 -2.285,0.397 -3.229,1.19 -0.944,0.793 -1.69,1.93 -2.241,3.407 z m 6.144,6.536 h 7.043 c -1.347,2.456 -3.172,4.356 -5.477,5.7 -2.305,1.345 -4.885,2.017 -7.74,2.017 -3.473,0 -5.923,-1.054 -7.351,-3.161 -1.427,-2.107 -1.632,-4.98 -0.613,-8.618 1.038,-3.707 2.875,-6.641 5.512,-8.803 2.637,-2.163 5.678,-3.244 9.123,-3.244 3.555,0 6.04,1.099 7.456,3.298 1.417,2.198 1.582,5.234 0.498,9.109 l -0.239,0.814 -0.167,0.484 H 31.721 c -0.441,1.575 -0.438,2.777 0.01,3.606 0.448,0.829 1.332,1.244 2.65,1.244 0.975,0 1.836,-0.206 2.583,-0.617 0.747,-0.411 1.366,-1.021 1.853,-1.829 z" /></g></g><g
|
||||
transform="translate(0,268.962)"
|
||||
id="g53"><path
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#8ed300;fill-opacity:1"
|
||||
id="path55"
|
||||
d="m 112.881,30.643 -6.404,-18.639 -6.455,18.639 h -7.254 l 9.565,-30.321 h 8.19 l 4.434,15.582 0.35,1.276 c 0.521,1.866 0.917,3.431 1.191,4.693 l 0.555,-2.182 c 0.219,-0.837 0.528,-1.935 0.925,-3.293 l 4.468,-16.076 h 8.19 l -10.501,30.321 z" /></g></g></svg>
|
After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1,7 @@
|
|||
[
|
||||
{
|
||||
"filename": "logo-black.png",
|
||||
"path": "/assets/images/logo-black.png",
|
||||
"cid": "logo-black.png"
|
||||
}
|
||||
]
|
|
@ -0,0 +1,8 @@
|
|||
<header>
|
||||
<div class="logo">
|
||||
<a href="https://www.verdnatura.es" target="_blank">
|
||||
<img v-bind:src="getEmailSrc('logo-black.png')" alt="VerdNatura"/>
|
||||
</a>
|
||||
</div>
|
||||
<div class="topbar"></div>
|
||||
</header>
|
|
@ -0,0 +1,4 @@
|
|||
module.exports = {
|
||||
name: 'email-header',
|
||||
props: ['locale']
|
||||
};
|
|
@ -1,6 +1,6 @@
|
|||
const CssReader = require(`${appPath}/lib/cssReader`);
|
||||
const Stylesheet = require(`${appPath}/core/stylesheet`);
|
||||
|
||||
module.exports = new CssReader([
|
||||
module.exports = new Stylesheet([
|
||||
`${appPath}/common/css/layout.css`,
|
||||
`${appPath}/common/css/report.css`,
|
||||
`${appPath}/common/css/misc.css`,
|
|
@ -0,0 +1,10 @@
|
|||
numPages: Página {{page}} de {{pages}}
|
||||
law:
|
||||
phytosanitary: 'VERDNATURA LEVANTE SL - Pasaporte Fitosanitario R.P. Generalitat
|
||||
Valenciana - Nº Comerciante: ES17462130'
|
||||
privacy: En cumplimiento de lo dispuesto en la Ley Orgánica 15/1999, de Protección
|
||||
de Datos de Carácter Personal, le comunicamos que los datos personales que facilite
|
||||
se incluirán en ficheros automatizados de VERDNATURA LEVANTE S.L., pudiendo en
|
||||
todo momento ejercitar los derechos de acceso, rectificación, cancelación y oposición,
|
||||
comunicándolo por escrito al domicilio social de la entidad. La finalidad del
|
||||
fichero es la gestión administrativa, contabilidad, y facturación.
|
|
@ -0,0 +1,10 @@
|
|||
numPages: Page {{page}} de {{pages}}
|
||||
law:
|
||||
phytosanitary: 'VERDNATURA LEVANTE SL - Passeport Phytosanitaire R.P. Generalitat
|
||||
Valenciana - Numéro d''opérateur: ES17462130'
|
||||
privacy: Conformément aux dispositions de la loi organique 15/1999 sur la protection
|
||||
des données personnelles, nous vous informons que les données personnelles que
|
||||
vous fournissez seront incluses dans des dossiers. VERDNATURA LEVANTE S.L., vous
|
||||
pouvez à tout moment, exercer les droits d'accès, de rectification, d'annulation
|
||||
et d'opposition, en communiquant par écrit au siège social de la société. Le dossier
|
||||
a pour objet la gestion administrative, la comptabilité et la facturation.
|
|
@ -0,0 +1,10 @@
|
|||
numPages: Página {{page}} de {{pages}}
|
||||
law:
|
||||
phytosanitary: 'VERDNATURA LEVANTE S.L - Passaporte Fitossanitário R.P. Generalitat
|
||||
Valenciana - Nº Comerciante: ES17462130'
|
||||
privacy: Em cumprimento do disposto na lei Orgânica 15/1999, de Protecção de Dados
|
||||
de Carácter Pessoal, comunicamos que os dados pessoais que facilite se incluirão
|
||||
nos ficheiros automatizados de VERDNATURA LEVANTE S.L., podendo em todo momento
|
||||
exercer os direitos de acesso, rectificação, cancelação e oposição, comunicando
|
||||
por escrito ao domicílio social da entidade. A finalidade do ficheiro é a gestão
|
||||
administrativa, contabilidade e facturação.
|
|
@ -1,7 +1,7 @@
|
|||
<footer>
|
||||
<section class="page">
|
||||
<section :if="leftText">{{leftText}}</section>
|
||||
<section :if="centerText" class="uppercase">{{centerText}}</section>
|
||||
<section v-if="leftText">{{leftText}}</section>
|
||||
<section v-if="centerText" class="uppercase">{{centerText}}</section>
|
||||
<section class="number">{{$t('numPages')}}</section>
|
||||
</section>
|
||||
<p class="phytosanitary">{{$t('law.phytosanitary')}}</p>
|
|
@ -1,8 +1,4 @@
|
|||
module.exports = {
|
||||
name: 'report-footer',
|
||||
created() {
|
||||
if (this.locale)
|
||||
this.$i18n.locale = this.locale;
|
||||
},
|
||||
props: ['leftText', 'centerText', 'locale']
|
||||
};
|
|
@ -1,6 +1,6 @@
|
|||
const CssReader = require(`${appPath}/lib/cssReader`);
|
||||
const Stylesheet = require(`${appPath}/core/stylesheet`);
|
||||
|
||||
module.exports = new CssReader([
|
||||
module.exports = new Stylesheet([
|
||||
`${appPath}/common/css/layout.css`,
|
||||
`${appPath}/common/css/report.css`,
|
||||
`${appPath}/common/css/misc.css`,
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 13.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
|
||||
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" version="1.1" x="0px" y="0px" width="226.229px" height="31.038px" viewBox="0 0 226.229 31.038" enable-background="new 0 0 226.229 31.038" xml:space="preserve" id="svg2" inkscape:version="0.48.1 r9760" sodipodi:docname="logo.svg"><metadata id="metadata61"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata><defs id="defs59"/><sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="1366" inkscape:window-height="710" id="namedview57" showgrid="false" inkscape:zoom="4.0755163" inkscape:cx="138.56745" inkscape:cy="16.509992" inkscape:window-x="0" inkscape:window-y="26" inkscape:window-maximized="1" inkscape:current-layer="svg2"/>
|
||||
<g id="Background">
|
||||
</g>
|
||||
<g id="Guides">
|
||||
</g>
|
||||
<g id="Foreground">
|
||||
<g id="g7">
|
||||
<g id="g9">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.417,30.321L0,0h8.233l4.26,15.582l0.349,1.276 c0.521,1.866,0.918,3.431,1.191,4.693c0.15-0.618,0.335-1.345,0.555-2.182c0.219-0.837,0.528-1.935,0.925-3.293L19.981,0h8.19 L17.671,30.321H10.417z" id="path11"/>
|
||||
</g>
|
||||
<g id="g13">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#A0CE67" d="M139.809,19.787c-0.665,0.357-1.748,0.686-3.25,0.988 c-0.727,0.137-1.283,0.254-1.667,0.35c-0.95,0.247-1.661,0.563-2.134,0.947c-0.472,0.384-0.799,0.899-0.979,1.544 c-0.223,0.796-0.155,1.438,0.204,1.925c0.359,0.488,0.945,0.731,1.757,0.731c1.252,0,2.375-0.36,3.369-1.081 c0.994-0.721,1.653-1.665,1.98-2.831L139.809,19.787z M144.915,30.321h-7.458c0.017-0.356,0.048-0.726,0.094-1.11l0.159-1.192 c-1.318,1.026-2.627,1.786-3.927,2.279c-1.299,0.493-2.643,0.739-4.031,0.739c-2.158,0-3.7-0.593-4.625-1.779 c-0.925-1.187-1.106-2.788-0.542-4.804c0.519-1.851,1.431-3.356,2.737-4.515c1.307-1.159,3.021-1.972,5.142-2.438 c1.169-0.247,2.641-0.515,4.413-0.803c2.646-0.412,4.082-1.016,4.304-1.812l0.151-0.539c0.182-0.65,0.076-1.145-0.317-1.483 c-0.393-0.339-1.071-0.508-2.033-0.508c-1.045,0-1.934,0.214-2.666,0.643c-0.731,0.428-1.289,1.058-1.673,1.887h-6.748 c1.065-2.53,2.64-4.413,4.723-5.65s4.724-1.856,7.923-1.856c1.991,0,3.602,0.241,4.833,0.722s2.095,1.209,2.59,2.185 c0.339,0.701,0.483,1.536,0.432,2.504c-0.052,0.969-0.377,2.525-0.978,4.669l-2.375,8.483c-0.284,1.014-0.416,1.812-0.396,2.395 s0.188,0.962,0.503,1.141L144.915,30.321z" id="path15" style="fill:#8ed300;fill-opacity:1"/>
|
||||
</g>
|
||||
<g id="g17">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#A0CE67" d="M185.7,30.321l6.27-22.393h7.049l-1.097,3.918 c1.213-1.537,2.502-2.659,3.867-3.366c1.365-0.707,2.951-1.074,4.758-1.101l-2.03,7.25c-0.304-0.042-0.608-0.072-0.912-0.093 c-0.303-0.02-0.592-0.03-0.867-0.03c-1.126,0-2.104,0.168-2.932,0.504c-0.829,0.336-1.561,0.854-2.197,1.555 c-0.406,0.467-0.789,1.136-1.149,2.007c-0.361,0.872-0.814,2.282-1.359,4.232l-2.104,7.516H185.7z" id="path19" style="fill:#8ed300;fill-opacity:1"/>
|
||||
</g>
|
||||
<g id="g21">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#A0CE67" d="M217.631,19.787c-0.664,0.357-1.748,0.686-3.25,0.988 c-0.727,0.137-1.282,0.254-1.667,0.35c-0.95,0.247-1.661,0.563-2.134,0.947c-0.472,0.384-0.799,0.899-0.979,1.544 c-0.223,0.796-0.155,1.438,0.205,1.925c0.359,0.488,0.945,0.731,1.757,0.731c1.252,0,2.375-0.36,3.369-1.081 c0.994-0.721,1.654-1.665,1.98-2.831L217.631,19.787z M222.737,30.321h-7.458c0.017-0.356,0.048-0.726,0.094-1.11l0.159-1.192 c-1.318,1.026-2.627,1.786-3.927,2.279c-1.299,0.493-2.643,0.739-4.031,0.739c-2.158,0-3.7-0.593-4.625-1.779 c-0.926-1.187-1.106-2.788-0.542-4.804c0.519-1.851,1.431-3.356,2.737-4.515c1.306-1.159,3.02-1.972,5.142-2.438 c1.169-0.247,2.641-0.515,4.413-0.803c2.647-0.412,4.082-1.016,4.304-1.812l0.151-0.539c0.182-0.65,0.077-1.145-0.317-1.483 c-0.393-0.339-1.071-0.508-2.033-0.508c-1.045,0-1.934,0.214-2.666,0.643c-0.731,0.428-1.289,1.058-1.672,1.887h-6.748 c1.065-2.53,2.64-4.413,4.723-5.65s4.724-1.856,7.923-1.856c1.99,0,3.601,0.241,4.833,0.722s2.095,1.209,2.591,2.185 c0.339,0.701,0.483,1.536,0.431,2.504c-0.051,0.969-0.377,2.525-0.978,4.669l-2.375,8.483c-0.284,1.014-0.416,1.812-0.396,2.395 c0.02,0.583,0.188,0.962,0.503,1.141L222.737,30.321z" id="path23" style="fill:#8ed300;fill-opacity:1"/>
|
||||
</g>
|
||||
<g id="g25">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#A0CE67" d="M188.386,7.928l-6.269,22.393h-7.174l0.864-3.085 c-1.227,1.246-2.476,2.163-3.746,2.751s-2.625,0.882-4.067,0.882c-2.471,0-4.154-0.634-5.048-1.901 c-0.895-1.268-0.993-3.149-0.294-5.644l4.31-15.396h7.338l-3.508,12.53c-0.516,1.842-0.641,3.109-0.375,3.803 s0.967,1.041,2.105,1.041c1.275,0,2.323-0.422,3.142-1.267c0.819-0.845,1.497-2.223,2.031-4.133l3.353-11.974H188.386z" id="path27" style="fill:#8ed300;fill-opacity:1"/>
|
||||
</g>
|
||||
<g id="g29">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#A0CE67" d="M149.937,12.356l1.239-4.428h2.995l1.771-6.326h7.338 l-1.771,6.326h3.753l-1.24,4.428h-3.753l-2.716,9.702c-0.416,1.483-0.498,2.465-0.247,2.946c0.25,0.48,0.905,0.721,1.964,0.721 l0.549-0.011l0.39-0.031l-1.31,4.678c-0.811,0.148-1.596,0.263-2.354,0.344c-0.758,0.081-1.48,0.122-2.167,0.122 c-2.543,0-4.108-0.621-4.695-1.863c-0.587-1.242-0.313-3.887,0.82-7.936l2.428-8.672H149.937z" id="path31" style="fill:#8ed300;fill-opacity:1"/>
|
||||
</g>
|
||||
<g id="g33">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M73.875,18.896c-0.561,2.004-0.616,3.537-0.167,4.601 s1.375,1.595,2.774,1.595c1.399,0,2.605-0.524,3.62-1.574s1.806-2.59,2.375-4.622c0.526-1.879,0.556-3.334,0.09-4.363 c-0.466-1.029-1.393-1.543-2.778-1.543c-1.304,0-2.487,0.528-3.551,1.585S74.386,17.071,73.875,18.896z M96.513,0l-8.489,30.321 h-7.337l0.824-2.944c-1.166,1.22-2.369,2.121-3.61,2.703s-2.583,0.874-4.025,0.874c-2.802,0-4.772-1.081-5.912-3.243 c-1.139-2.162-1.218-4.993-0.238-8.493c0.988-3.528,2.668-6.404,5.042-8.627c2.374-2.224,4.927-3.336,7.661-3.336 c1.47,0,2.695,0.296,3.676,0.887c0.981,0.591,1.681,1.465,2.099,2.62L89.217,0H96.513z" id="path35"/>
|
||||
<g id="g37">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M73.875,18.896c-0.561,2.004-0.616,3.537-0.167,4.601s1.375,1.595,2.774,1.595 c1.399,0,2.605-0.524,3.62-1.574s1.806-2.59,2.375-4.622c0.526-1.879,0.556-3.334,0.09-4.363 c-0.466-1.029-1.393-1.543-2.778-1.543c-1.304,0-2.487,0.528-3.551,1.585S74.386,17.071,73.875,18.896z M96.513,0l-8.489,30.321 h-7.337l0.824-2.944c-1.166,1.22-2.369,2.121-3.61,2.703s-2.583,0.874-4.025,0.874c-2.802,0-4.772-1.081-5.912-3.243 c-1.139-2.162-1.218-4.993-0.238-8.493c0.988-3.528,2.668-6.404,5.042-8.627c2.374-2.224,4.927-3.336,7.661-3.336 c1.47,0,2.695,0.296,3.676,0.887c0.981,0.591,1.681,1.465,2.099,2.62L89.217,0H96.513z" id="path39"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="g41">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M46.488,30.321l6.269-22.393h7.049l-1.098,3.918 c1.213-1.537,2.502-2.659,3.868-3.366s6.015-1.074,7.822-1.101l-2.03,7.25c-0.304-0.042-0.608-0.072-0.911-0.093 c-0.304-0.02-0.592-0.03-0.867-0.03c-1.126,0-5.167,0.168-5.997,0.504c-0.829,0.336-1.561,0.854-2.196,1.555 c-0.406,0.467-0.789,1.136-1.149,2.007c-0.361,0.872-0.814,2.282-1.36,4.232l-2.104,7.516H46.488z" id="path43"/>
|
||||
</g>
|
||||
<g id="g45">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M32.673,16.742l8.351-0.021 c0.375-1.436,0.308-2.558-0.201-3.365s-1.402-1.211-2.68-1.211c-1.209,0-2.285,0.397-3.229,1.19S33.224,15.265,32.673,16.742z M38.817,23.278h7.043c-1.347,2.456-3.172,4.356-5.477,5.7c-2.305,1.345-4.885,2.017-7.74,2.017 c-3.473,0-5.923-1.054-7.351-3.161c-1.427-2.107-1.632-4.98-0.613-8.618c1.038-3.707,2.875-6.641,5.512-8.803 c2.637-2.163,5.678-3.244,9.123-3.244c3.555,0,6.04,1.099,7.456,3.298c1.417,2.198,1.582,5.234,0.498,9.109l-0.239,0.814 l-0.167,0.484H31.721c-0.441,1.575-0.438,2.777,0.01,3.606c0.448,0.829,1.332,1.244,2.65,1.244c0.975,0,1.836-0.206,2.583-0.617 S38.33,24.086,38.817,23.278z" id="path47"/>
|
||||
<g id="g49">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M32.673,16.742l8.351-0.021c0.375-1.436,0.308-2.558-0.201-3.365 s-1.402-1.211-2.68-1.211c-1.209,0-2.285,0.397-3.229,1.19S33.224,15.265,32.673,16.742z M38.817,23.278h7.043 c-1.347,2.456-3.172,4.356-5.477,5.7c-2.305,1.345-4.885,2.017-7.74,2.017c-3.473,0-5.923-1.054-7.351-3.161 c-1.427-2.107-1.632-4.98-0.613-8.618c1.038-3.707,2.875-6.641,5.512-8.803c2.637-2.163,5.678-3.244,9.123-3.244 c3.555,0,6.04,1.099,7.456,3.298c1.417,2.198,1.582,5.234,0.498,9.109l-0.239,0.814l-0.167,0.484H31.721 c-0.441,1.575-0.438,2.777,0.01,3.606c0.448,0.829,1.332,1.244,2.65,1.244c0.975,0,1.836-0.206,2.583-0.617 S38.33,24.086,38.817,23.278z" id="path51"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="g53">
|
||||
<path fill="#A0CE67" d="M112.881,30.643l-6.404-18.639l-6.455,18.639h-7.254l9.565-30.321h8.19l4.434,15.582l0.35,1.276 c0.521,1.866,0.917,3.431,1.191,4.693l0.555-2.182c0.219-0.837,0.528-1.935,0.925-3.293l4.468-16.076h8.19l-10.501,30.321 H112.881z" id="path55" style="fill:#8ed300;fill-opacity:1"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 9.5 KiB |
|
@ -0,0 +1,5 @@
|
|||
company:
|
||||
fiscalAddress: VERDNATURA LEVANTE S.L., B97367486 Avda. Espioca, 100, 46460 Silla
|
||||
- www.verdnatura.es - clientes@verdnatura.es
|
||||
registry: 'CIF: B97367486 Registro Mercantil de Valencia, Tomo 8041, Libro 5334,
|
||||
Folio 160, Sección 8, Hoja V 102076'
|
|
@ -0,0 +1,5 @@
|
|||
company:
|
||||
fiscalAddress: VERDNATURA LEVANTE S.L., B97367486 Avda. Espioca, 100, 46460 Silla
|
||||
- www.verdnatura.es - clientes@verdnatura.es
|
||||
registry: 'CIF: B97367486 Registro Mercantil de Valencia, Tomo 8041, Libro 5334,
|
||||
Folio 160, Sección 8, Hoja V 102076'
|
|
@ -1,5 +1,5 @@
|
|||
<header>
|
||||
<img :src="embeded['/assets/images/report-logo.svg']" alt="Verdnatura"/>
|
||||
<img v-bind:src="getReportSrc('report-logo.svg')" alt="Verdnatura"/>
|
||||
<section>{{$t('company.fiscalAddress')}}</section>
|
||||
<section>{{$t('company.registry')}}</section>
|
||||
</header>
|
|
@ -0,0 +1,4 @@
|
|||
module.exports = {
|
||||
name: 'report-header',
|
||||
props: ['isPreview', 'locale']
|
||||
};
|
|
@ -14,19 +14,6 @@ for (let configFile of configFiles) {
|
|||
Object.assign(config, require(configFile));
|
||||
}
|
||||
|
||||
/* let proxyConf = {};
|
||||
let proxyFiles = [
|
||||
'../../nginx/config.yml',
|
||||
`${configPath}/config.yml`,
|
||||
`${configPath}/config.${env}.yml`
|
||||
];
|
||||
|
||||
for (let proxyFile of proxyFiles) {
|
||||
if (fs.existsSync(proxyFile))
|
||||
Object.assign(proxyConf, require(proxyFile));
|
||||
} */
|
||||
|
||||
// config.proxy = proxyConf;
|
||||
config.env = env;
|
||||
|
||||
module.exports = config;
|
|
@ -0,0 +1,24 @@
|
|||
const mysql = require('mysql2/promise');
|
||||
const config = require('./config.js');
|
||||
|
||||
module.exports = {
|
||||
init() {
|
||||
if (!this.pool) {
|
||||
this.pool = mysql.createPool(config.mysql);
|
||||
this.pool.on('connection', connection => {
|
||||
connection.config.namedPlaceholders = true;
|
||||
});
|
||||
}
|
||||
},
|
||||
find(query, params) {
|
||||
return this.pool.query(query, params).then(([rows]) => {
|
||||
return rows;
|
||||
});
|
||||
},
|
||||
findOne(query, params) {
|
||||
return this.find(query, params).then(([rows]) => rows);
|
||||
},
|
||||
findFromDef() {
|
||||
|
||||
}
|
||||
};
|
|
@ -0,0 +1,2 @@
|
|||
// Import global directives
|
||||
require('./pin');
|
|
@ -0,0 +1,9 @@
|
|||
// DIRECTIVES NOT WORKING
|
||||
const Vue = require('vue');
|
||||
Vue.directive('pin', {
|
||||
bind: function(el, binding, vnode) {
|
||||
el.style.position = 'fixed';
|
||||
el.style.top = binding.value + 'px';
|
||||
el.style.backgroundColor = 'red';
|
||||
}
|
||||
});
|
|
@ -0,0 +1,93 @@
|
|||
const path = require('path');
|
||||
const smtp = require('./smtp');
|
||||
const Component = require('./component');
|
||||
const Report = require('./report');
|
||||
const db = require('./database');
|
||||
const config = require('./config');
|
||||
|
||||
if (!process.env.OPENSSL_CONF)
|
||||
process.env.OPENSSL_CONF = '/etc/ssl/';
|
||||
|
||||
class Email extends Component {
|
||||
constructor(name, args) {
|
||||
super(name);
|
||||
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
get path() {
|
||||
return `../templates/email/${this.name}`;
|
||||
}
|
||||
|
||||
|
||||
async getSubject() {
|
||||
if (!this.lang) await this.getLang();
|
||||
const locale = this.locale.messages;
|
||||
const userLocale = locale[this.lang];
|
||||
|
||||
if (!userLocale) {
|
||||
const fallbackLocale = config.i18n.fallbackLocale;
|
||||
|
||||
return locale[fallbackLocale].subject;
|
||||
}
|
||||
|
||||
return userLocale.subject;
|
||||
}
|
||||
|
||||
async getLang() {
|
||||
const clientId = this.args.clientId;
|
||||
const lang = await db.findOne(`
|
||||
SELECT lang FROM account.user
|
||||
WHERE id = ?`, [clientId]).then(rows => {
|
||||
return rows.lang;
|
||||
});
|
||||
this.lang = lang;
|
||||
}
|
||||
|
||||
async send() {
|
||||
const instance = this.build();
|
||||
const rendered = await this.render();
|
||||
const attachments = [];
|
||||
const getAttachments = async(componentPath, files) => {
|
||||
for (file of files) {
|
||||
const fileCopy = Object.assign({}, file);
|
||||
if (fileCopy.cid) {
|
||||
const templatePath = `${componentPath}/${file.path}`;
|
||||
const fullFilePath = path.resolve(__dirname, templatePath);
|
||||
|
||||
fileCopy.path = path.resolve(__dirname, fullFilePath);
|
||||
} else {
|
||||
const reportName = fileCopy.filename.replace('.pdf', '');
|
||||
const report = new Report(reportName, this.args);
|
||||
fileCopy.content = await report.toPdfStream();
|
||||
}
|
||||
|
||||
attachments.push(fileCopy);
|
||||
}
|
||||
};
|
||||
|
||||
if (instance.components) {
|
||||
const components = instance.components;
|
||||
for (let componentName in components) {
|
||||
const component = components[componentName];
|
||||
const componentPath = `./components/${componentName}`;
|
||||
await getAttachments(componentPath, component.attachments);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.attachments)
|
||||
await getAttachments(this.path, this.attachments);
|
||||
|
||||
const localeSubject = await this.getSubject();
|
||||
const options = {
|
||||
to: this.args.recipient,
|
||||
subject: localeSubject,
|
||||
html: rendered,
|
||||
attachments: attachments
|
||||
};
|
||||
|
||||
return smtp.send(options);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Email;
|
|
@ -0,0 +1,9 @@
|
|||
const Vue = require('vue');
|
||||
const config = require('../config');
|
||||
const defaultLocale = config.i18n.locale;
|
||||
|
||||
Vue.filter('currency', function(value, currency = 'EUR', locale = defaultLocale) {
|
||||
return new Intl.NumberFormat(locale, {
|
||||
style: 'currency', currency
|
||||
}).format(parseFloat(value));
|
||||
});
|
|
@ -0,0 +1,6 @@
|
|||
const Vue = require('vue');
|
||||
const strftime = require('strftime');
|
||||
|
||||
Vue.filter('date', function(value, specifiers) {
|
||||
return strftime(specifiers, value);
|
||||
});
|
|
@ -0,0 +1,4 @@
|
|||
// Import global filters
|
||||
require('./date');
|
||||
require('./currency');
|
||||
require('./percentage');
|
|
@ -0,0 +1,11 @@
|
|||
const Vue = require('vue');
|
||||
const config = require('../config');
|
||||
const defaultLocale = config.i18n.locale;
|
||||
|
||||
Vue.filter('percentage', function(value, minFraction = 2, maxFraction = 2, locale = defaultLocale) {
|
||||
return new Intl.NumberFormat(locale, {
|
||||
style: 'percent',
|
||||
minimumFractionDigits: minFraction,
|
||||
maximumFractionDigits: maxFraction
|
||||
}).format(parseFloat(value));
|
||||
});
|
|
@ -0,0 +1,23 @@
|
|||
const Vue = require('vue');
|
||||
const config = require('../config');
|
||||
|
||||
const imageSrc = {
|
||||
methods: {
|
||||
getEmailSrc(image) {
|
||||
let src = `cid:${image}`;
|
||||
|
||||
if (this.isPreview === 'true')
|
||||
src = `/api/${this.$options.name}/assets/images/${image}`;
|
||||
|
||||
return src;
|
||||
},
|
||||
getReportSrc(image) {
|
||||
const assetsPath = `${config.app.host}/api/${this.$options.name}`;
|
||||
const imagePath = `${assetsPath}/assets/images/${image}`;
|
||||
|
||||
return imagePath;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Vue.mixin(imageSrc);
|
|
@ -0,0 +1,4 @@
|
|||
// Import global mixins
|
||||
require('./image-src');
|
||||
require('./user-locale');
|
||||
require('./prop-validator');
|
|
@ -0,0 +1,26 @@
|
|||
const Vue = require('vue');
|
||||
const validator = {
|
||||
created() {
|
||||
const props = this.$options.props;
|
||||
const invalidProps = [];
|
||||
|
||||
for (prop in props) {
|
||||
const isObject = typeof props[prop] === 'object';
|
||||
const isRequired = props[prop].required;
|
||||
const isNotDefined = this[prop] === undefined;
|
||||
|
||||
if (isObject && isRequired && isNotDefined)
|
||||
invalidProps.push(prop);
|
||||
}
|
||||
|
||||
if (invalidProps.length > 0) {
|
||||
const required = invalidProps.join(', ');
|
||||
|
||||
throw new Error(`Required params not found [${required}]`);
|
||||
}
|
||||
},
|
||||
props: ['isPreview']
|
||||
};
|
||||
|
||||
|
||||
Vue.mixin(validator);
|
|
@ -0,0 +1,24 @@
|
|||
const Vue = require('vue');
|
||||
const db = require('../database');
|
||||
const userLocale = {
|
||||
async serverPrefetch() {
|
||||
if (this.clientId)
|
||||
this.locale = await this.getLocale(this.clientId);
|
||||
|
||||
if (this.locale)
|
||||
this.$i18n.locale = this.locale;
|
||||
},
|
||||
methods: {
|
||||
getLocale(clientId) {
|
||||
return db.findOne(`
|
||||
SELECT lang FROM account.user
|
||||
WHERE id = ?`, [clientId]).then(rows => {
|
||||
return rows.lang;
|
||||
});
|
||||
}
|
||||
},
|
||||
props: ['clientId']
|
||||
};
|
||||
|
||||
|
||||
Vue.mixin(userLocale);
|
|
@ -0,0 +1,38 @@
|
|||
const fs = require('fs');
|
||||
const pdf = require('html-pdf');
|
||||
const path = require('path');
|
||||
const config = require('./config');
|
||||
const Component = require('./component');
|
||||
|
||||
if (!process.env.OPENSSL_CONF)
|
||||
process.env.OPENSSL_CONF = '/etc/ssl/';
|
||||
|
||||
class Report extends Component {
|
||||
constructor(name, args) {
|
||||
super(name);
|
||||
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
get path() {
|
||||
return `../templates/reports/${this.name}`;
|
||||
}
|
||||
|
||||
async toPdfStream() {
|
||||
const template = await this.render();
|
||||
let options = config.pdf;
|
||||
|
||||
const optionsPath = `${this.path}/options.json`;
|
||||
const fullPath = path.resolve(__dirname, optionsPath);
|
||||
if (fs.existsSync(fullPath))
|
||||
options = Object.assign(options, require(optionsPath));
|
||||
|
||||
return new Promise(resolve => {
|
||||
pdf.create(template, options).toStream((err, stream) => {
|
||||
resolve(stream);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Report;
|
|
@ -0,0 +1,51 @@
|
|||
const Report = require('./report');
|
||||
const Email = require('./email');
|
||||
|
||||
module.exports = app => {
|
||||
app.get(`/api/report/:name`, async(req, res, next) => {
|
||||
const args = req.query;
|
||||
const requiredArgs = ['clientId'];
|
||||
|
||||
const hasRequiredArgs = requiredArgs.every(arg => {
|
||||
return args[arg];
|
||||
});
|
||||
|
||||
if (!hasRequiredArgs)
|
||||
res.json({message: 'Required params recipient, clientId'});
|
||||
|
||||
try {
|
||||
const report = new Report(req.params.name, args);
|
||||
const stream = await report.toPdfStream();
|
||||
res.setHeader('Content-type', 'application/pdf');
|
||||
stream.pipe(res);
|
||||
} catch (e) {
|
||||
next(e);
|
||||
}
|
||||
});
|
||||
|
||||
app.get(`/api/email/:name`, async(req, res, next) => {
|
||||
const args = req.query;
|
||||
const requiredArgs = ['recipient', 'clientId'];
|
||||
|
||||
const hasRequiredArgs = requiredArgs.every(arg => {
|
||||
return args[arg];
|
||||
});
|
||||
|
||||
if (!hasRequiredArgs)
|
||||
res.json({message: 'Required params recipient, clientId'});
|
||||
|
||||
try {
|
||||
const email = new Email(req.params.name, args);
|
||||
if (args.isPreview === 'true') {
|
||||
const rendered = await email.render();
|
||||
|
||||
res.send(rendered);
|
||||
} else {
|
||||
await email.send();
|
||||
res.status(200).json({message: 'Sent'});
|
||||
}
|
||||
} catch (e) {
|
||||
next(e);
|
||||
}
|
||||
});
|
||||
};
|