5914-transferInvoiceOut #1761
18
CHANGELOG.md
18
CHANGELOG.md
|
@ -5,7 +5,8 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [2330.01] - 2023-07-27
|
||||
|
||||
## [2334.01] - 2023-08-24
|
||||
|
||||
### Added
|
||||
|
||||
|
@ -14,6 +15,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
### Fixed
|
||||
|
||||
|
||||
## [2332.01] - 2023-08-09
|
||||
|
||||
### Added
|
||||
- (Trabajadores -> Gestión documental) Soporte para Docuware
|
||||
- (General -> Agencia) Soporte para Viaexpress
|
||||
|
||||
### Changed
|
||||
- (General -> Tickets) Devuelve el motivo por el cual no es editable
|
||||
- (Desplegables -> Trabajadores) Mejorados
|
||||
|
||||
### Fixed
|
||||
|
||||
|
||||
## [2330.01] - 2023-07-27
|
||||
|
||||
### Added
|
||||
|
@ -24,7 +38,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
### Changed
|
||||
- (General -> Iconos) Añadidos nuevos iconos
|
||||
- (Clientes -> Razón social) Nuevas restricciones por pais
|
||||
- (Clientes -> Razón social) Permite crear clientes con la misma razón social según el país
|
||||
|
||||
|
||||
### Fixed
|
||||
|
|
|
@ -47,7 +47,7 @@ module.exports = Self => {
|
|||
const user = await Self.findById(userId, {fields: ['hasGrant']}, myOptions);
|
||||
|
||||
const userToUpdate = await Self.findById(id, {
|
||||
fields: ['id', 'name', 'hasGrant', 'roleFk', 'password'],
|
||||
fields: ['id', 'name', 'hasGrant', 'roleFk', 'password', 'email'],
|
||||
include: {
|
||||
relation: 'role',
|
||||
scope: {
|
||||
|
|
|
@ -20,7 +20,7 @@ module.exports = function(Self) {
|
|||
Self.validatesFormatOf('email', {
|
||||
message: 'Invalid email',
|
||||
allowNull: true,
|
||||
allowBlank: true,
|
||||
allowBlank: false,
|
||||
with: /^[\w|.|-]+@[\w|-]+(\.[\w|-]+)*(,[\w|.|-]+@[\w|-]+(\.[\w|-]+)*)*$/
|
||||
});
|
||||
|
||||
|
@ -115,6 +115,14 @@ module.exports = function(Self) {
|
|||
Self.validateLogin = async function(user, password) {
|
||||
let loginInfo = Object.assign({password}, Self.userUses(user));
|
||||
token = await Self.login(loginInfo, 'user');
|
||||
|
||||
const userToken = await token.user.get();
|
||||
try {
|
||||
await Self.app.models.Account.sync(userToken.name, password);
|
||||
} catch (err) {
|
||||
console.warn(err);
|
||||
}
|
||||
|
||||
return {token: token.id, ttl: token.ttl};
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
DELIMITER $$
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`client_create`(
|
||||
vFirstname VARCHAR(50),
|
||||
vSurnames VARCHAR(50),
|
||||
vFi VARCHAR(9),
|
||||
vAddress TEXT,
|
||||
vPostcode CHAR(5),
|
||||
vCity VARCHAR(25),
|
||||
vProvinceFk SMALLINT(5),
|
||||
vCompanyFk SMALLINT(5),
|
||||
vPhone VARCHAR(11),
|
||||
vEmail VARCHAR(255),
|
||||
vUserFk INT
|
||||
)
|
||||
BEGIN
|
||||
/**
|
||||
* Create new client
|
||||
*
|
||||
* @params vFirstname firstName
|
||||
* @params vSurnames surnames
|
||||
* @params vFi company code from accounting transactions
|
||||
* @params vAddress address
|
||||
* @params vPostcode postCode
|
||||
* @params vCity city
|
||||
* @params vProvinceFk province
|
||||
* @params vCompanyFk company in which he has become a client
|
||||
* @params vPhone telephone number
|
||||
* @params vEmail email address
|
||||
* @params vUserFk user id
|
||||
*/
|
||||
DECLARE vPayMethodFk INT;
|
||||
DECLARE vDueDay INT;
|
||||
DECLARE vDefaultCredit DECIMAL(10, 2);
|
||||
DECLARE vIsTaxDataChecked TINYINT(1);
|
||||
DECLARE vHasCoreVnl BOOLEAN;
|
||||
DECLARE vMandateTypeFk INT;
|
||||
|
||||
SELECT defaultPayMethodFk,
|
||||
defaultDueDay,
|
||||
defaultCredit,
|
||||
defaultIsTaxDataChecked,
|
||||
defaultHasCoreVnl,
|
||||
defaultMandateTypeFk
|
||||
INTO vPayMethodFk,
|
||||
vDueDay,
|
||||
vDefaultCredit,
|
||||
vIsTaxDataChecked,
|
||||
vHasCoreVnl,
|
||||
vMandateTypeFk
|
||||
FROM clientConfig;
|
||||
|
||||
INSERT INTO `client`
|
||||
SET id = vUserFk,
|
||||
name = CONCAT(vFirstname, ' ', vSurnames),
|
||||
street = vAddress,
|
||||
fi = TRIM(vFi),
|
||||
phone = vPhone,
|
||||
email = vEmail,
|
||||
provinceFk = vProvinceFk,
|
||||
city = vCity,
|
||||
postcode = vPostcode,
|
||||
socialName = UPPER(CONCAT(vSurnames, ' ', vFirstname)),
|
||||
payMethodFk = vPayMethodFk,
|
||||
dueDay = vDueDay,
|
||||
credit = vDefaultCredit,
|
||||
isTaxDataChecked = vIsTaxDataChecked,
|
||||
hasCoreVnl = vHasCoreVnl,
|
||||
isEqualizated = FALSE
|
||||
ON duplicate KEY UPDATE
|
||||
payMethodFk = vPayMethodFk,
|
||||
dueDay = vDueDay,
|
||||
credit = vDefaultCredit,
|
||||
isTaxDataChecked = vIsTaxDataChecked,
|
||||
hasCoreVnl = vHasCoreVnl,
|
||||
isActive = TRUE;
|
||||
|
||||
INSERT INTO mandate (clientFk, companyFk, mandateTypeFk)
|
||||
SELECT vUserFk, vCompanyFk, vMandateTypeFk
|
||||
WHERE NOT EXISTS (
|
||||
SELECT id
|
||||
FROM mandate
|
||||
WHERE clientFk = vUserFk
|
||||
AND companyFk = vCompanyFk
|
||||
AND mandateTypeFk = vMandateTypeFk
|
||||
);
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -360,13 +360,13 @@ INSERT INTO `vn`.`contactChannel`(`id`, `name`)
|
|||
|
||||
INSERT INTO `vn`.`client`(`id`,`name`,`fi`,`socialName`,`contact`,`street`,`city`,`postcode`,`phone`,`mobile`,`isRelevant`,`email`,`iban`,`dueDay`,`accountingAccount`,`isEqualizated`,`provinceFk`,`hasToInvoice`,`credit`,`countryFk`,`isActive`,`gestdocFk`,`quality`,`payMethodFk`,`created`,`isToBeMailed`,`contactChannelFk`,`hasSepaVnl`,`hasCoreVnl`,`hasCoreVnh`,`riskCalculated`,`clientTypeFk`, `hasToInvoiceByAddress`,`isTaxDataChecked`,`isFreezed`,`creditInsurance`,`isCreatedAsServed`,`hasInvoiceSimplified`,`salesPersonFk`,`isVies`,`eypbc`, `businessTypeFk`)
|
||||
VALUES
|
||||
(1101, 'Bruce Wayne', '84612325V', 'Batman', 'Alfred', '1007 Mountain Drive, Gotham', 'Gotham', 46460, 1111111111, 222222222, 1, 'BruceWayne@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'),
|
||||
(1102, 'Petter Parker', '87945234L', 'Spider man', 'Aunt May', '20 Ingram Street, Queens, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'PetterParker@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'),
|
||||
(1101, 'Bruce Wayne', '84612325V', 'BATMAN', 'Alfred', '1007 MOUNTAIN DRIVE, GOTHAM', 'Gotham', 46460, 1111111111, 222222222, 1, 'BruceWayne@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'),
|
||||
(1102, 'Petter Parker', '87945234L', 'SPIDER MAN', 'Aunt May', '20 INGRAM STREET, QUEENS, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'PetterParker@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'),
|
||||
(1103, 'Clark Kent', '06815934E', 'Super man', 'lois lane', '344 Clinton Street, Apartament 3-D', 'Gotham', 46460, 1111111111, 222222222, 1, 'ClarkKent@mydomain.com', NULL, 0, 1234567890, 0, 3, 1, 0, 19, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'),
|
||||
(1104, 'Tony Stark', '06089160W', 'Iron man', 'Pepper Potts', '10880 Malibu Point, 90265', 'Gotham', 46460, 1111111111, 222222222, 1, 'TonyStark@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'),
|
||||
(1105, 'Max Eisenhardt', '251628698', 'Magneto', 'Rogue', 'Unknown Whereabouts', 'Gotham', 46460, 1111111111, 222222222, 1, 'MaxEisenhardt@mydomain.com', NULL, 0, 1234567890, 0, 3, 1, 300, 8, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, NULL, 0, 0, 18, 0, 1, 'florist'),
|
||||
(1106, 'DavidCharlesHaller', '53136686Q', 'Legion', 'Charles Xavier', 'City of New York, New York, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'DavidCharlesHaller@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 0, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 19, 0, 1, 'florist'),
|
||||
(1107, 'Hank Pym', '09854837G', 'Ant man', 'Hawk', 'Anthill, San Francisco, California', 'Gotham', 46460, 1111111111, 222222222, 1, 'HankPym@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, 0, NULL, 0, 0, 19, 0, 1, 'florist'),
|
||||
(1106, 'DavidCharlesHaller', '53136686Q', 'LEGION', 'Charles Xavier', 'CITY OF NEW YORK, NEW YORK, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'DavidCharlesHaller@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 0, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 19, 0, 1, 'florist'),
|
||||
(1107, 'Hank Pym', '09854837G', 'ANT MAN', 'Hawk', 'ANTHILL, SAN FRANCISCO, CALIFORNIA', 'Gotham', 46460, 1111111111, 222222222, 1, 'HankPym@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, 0, NULL, 0, 0, 19, 0, 1, 'florist'),
|
||||
(1108, 'Charles Xavier', '22641921P', 'Professor X', 'Beast', '3800 Victory Pkwy, Cincinnati, OH 45207, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'CharlesXavier@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, NULL, 0, 0, 19, 0, 1, 'florist'),
|
||||
(1109, 'Bruce Banner', '16104829E', 'Hulk', 'Black widow', 'Somewhere in New York', 'Gotham', 46460, 1111111111, 222222222, 1, 'BruceBanner@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, 0, NULL, 0, 0, 9, 0, 1, 'florist'),
|
||||
(1110, 'Jessica Jones', '58282869H', 'Jessica Jones', 'Luke Cage', 'NYCC 2015 Poster', 'Gotham', 46460, 1111111111, 222222222, 1, 'JessicaJones@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, 0, NULL, 0, 0, NULL, 0, 1, 'florist'),
|
||||
|
|
|
@ -73,8 +73,8 @@ describe('Client create path', () => {
|
|||
|
||||
it(`should attempt to create a new user with all it's data but wrong email`, async() => {
|
||||
await page.write(selectors.createClientView.name, 'Carol Danvers');
|
||||
await page.write(selectors.createClientView.socialName, 'AVG tax');
|
||||
await page.write(selectors.createClientView.street, 'Many places');
|
||||
await page.write(selectors.createClientView.socialName, 'AVG TAX');
|
||||
await page.write(selectors.createClientView.street, 'MANY PLACES');
|
||||
await page.clearInput(selectors.createClientView.email);
|
||||
await page.write(selectors.createClientView.email, 'incorrect email format');
|
||||
await page.waitToClick(selectors.createClientView.createButton);
|
||||
|
|
|
@ -61,7 +61,7 @@ describe('Client Edit fiscalData path', () => {
|
|||
await page.clearInput(selectors.clientFiscalData.fiscalId);
|
||||
await page.write(selectors.clientFiscalData.fiscalId, 'INVALID!');
|
||||
await page.clearInput(selectors.clientFiscalData.address);
|
||||
await page.write(selectors.clientFiscalData.address, 'Somewhere edited');
|
||||
await page.write(selectors.clientFiscalData.address, 'SOMEWHERE EDITED');
|
||||
await page.autocompleteSearch(selectors.clientFiscalData.country, 'España');
|
||||
await page.autocompleteSearch(selectors.clientFiscalData.province, 'Province one');
|
||||
await page.clearInput(selectors.clientFiscalData.city);
|
||||
|
@ -190,7 +190,7 @@ describe('Client Edit fiscalData path', () => {
|
|||
const verifiedData = await page.checkboxState(selectors.clientFiscalData.verifiedDataCheckbox);
|
||||
|
||||
expect(fiscalId).toEqual('94980061C');
|
||||
expect(address).toEqual('Somewhere edited');
|
||||
expect(address).toEqual('SOMEWHERE EDITED');
|
||||
expect(postcode).toContain('46000');
|
||||
expect(sageTax).toEqual('Operaciones no sujetas');
|
||||
expect(sageTransaction).toEqual('Regularización de inversiones');
|
||||
|
|
|
@ -28,7 +28,7 @@ describe('Client lock verified data path', () => {
|
|||
it('should edit the social name', async() => {
|
||||
await page.waitForSelector(selectors.clientFiscalData.socialName);
|
||||
await page.clearInput(selectors.clientFiscalData.socialName);
|
||||
await page.write(selectors.clientFiscalData.socialName, 'Captain America Civil War');
|
||||
await page.write(selectors.clientFiscalData.socialName, 'CAPTAIN AMERICA CIVIL WAR');
|
||||
await page.waitToClick(selectors.clientFiscalData.saveButton);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
|
@ -39,7 +39,7 @@ describe('Client lock verified data path', () => {
|
|||
await page.reloadSection('client.card.fiscalData');
|
||||
const result = await page.waitToGetProperty(selectors.clientFiscalData.socialName, 'value');
|
||||
|
||||
expect(result).toEqual('Captain America Civil War');
|
||||
expect(result).toEqual('CAPTAIN AMERICA CIVIL WAR');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -88,7 +88,7 @@ describe('Client lock verified data path', () => {
|
|||
await page.reloadSection('client.card.fiscalData');
|
||||
const result = await page.waitToGetProperty(selectors.clientFiscalData.socialName, 'value');
|
||||
|
||||
expect(result).toEqual('Ant man and the Wasp');
|
||||
expect(result).toEqual('ANT MAN AND THE WASP');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -142,7 +142,7 @@ describe('Client lock verified data path', () => {
|
|||
await page.reloadSection('client.card.fiscalData');
|
||||
const result = await page.waitToGetProperty(selectors.clientFiscalData.socialName, 'value');
|
||||
|
||||
expect(result).toEqual('new social name edition');
|
||||
expect(result).toEqual('NEW SOCIAL NAME EDITION');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ describe('Client summary path', () => {
|
|||
it('should display fiscal address details', async() => {
|
||||
const result = await page.waitToGetProperty(selectors.clientSummary.street, 'innerText');
|
||||
|
||||
expect(result).toContain('20 Ingram Street');
|
||||
expect(result).toContain('20 INGRAM STREET');
|
||||
});
|
||||
|
||||
it('should display some fiscal data', async() => {
|
||||
|
|
|
@ -23,7 +23,7 @@ describe('Worker create path', () => {
|
|||
await page.write(selectors.workerCreate.fi, '78457139E');
|
||||
await page.write(selectors.workerCreate.phone, '12356789');
|
||||
await page.write(selectors.workerCreate.postcode, '46680');
|
||||
await page.write(selectors.workerCreate.street, 'S/ Doomstadt');
|
||||
await page.write(selectors.workerCreate.street, 'S/ DOOMSTADT');
|
||||
await page.write(selectors.workerCreate.email, 'doctorDoom@marvel.com');
|
||||
await page.write(selectors.workerCreate.iban, 'ES9121000418450200051332');
|
||||
|
||||
|
|
|
@ -339,8 +339,9 @@ export default class SmartTable extends Component {
|
|||
if (!header) return;
|
||||
|
||||
const tbody = this.element.querySelector('tbody');
|
||||
const columns = header.querySelectorAll('th');
|
||||
if (!tbody) return;
|
||||
|
||||
const columns = header.querySelectorAll('th');
|
||||
const hasSearchRow = tbody.querySelector('tr#searchRow');
|
||||
if (hasSearchRow) {
|
||||
if (this.$inputsScope)
|
||||
|
|
|
@ -179,6 +179,8 @@
|
|||
"You can not use the same password": "You can not use the same password",
|
||||
"Valid priorities": "Valid priorities: %d",
|
||||
"Negative basis of tickets": "Negative basis of tickets: {{ticketsIds}}",
|
||||
"Social name should be uppercase": "Social name should be uppercase",
|
||||
"Street should be uppercase": "Street should be uppercase",
|
||||
"You don't have enough privileges.": "You don't have enough privileges.",
|
||||
"This ticket is locked.": "This ticket is locked.",
|
||||
"This ticket is not editable.": "This ticket is not editable.",
|
||||
|
|
|
@ -305,12 +305,19 @@
|
|||
"The renew period has not been exceeded": "El periodo de renovación no ha sido superado",
|
||||
"Valid priorities": "Prioridades válidas: %d",
|
||||
"Negative basis of tickets": "Base negativa para los tickets: {{ticketsIds}}",
|
||||
"The company has not informed the supplier account for bank transfers": "La empresa no tiene informado la cuenta de proveedor para transferencias bancarias",
|
||||
"You cannot assign an alias that you are not assigned to": "No puede asignar un alias que no tenga asignado",
|
||||
"The company has not informed the supplier account for bank transfers": "La empresa no tiene informado la cuenta de proveedor para transferencias bancarias",
|
||||
"You cannot assign/remove an alias that you are not assigned to": "No puede asignar/eliminar un alias que no tenga asignado",
|
||||
"This invoice has a linked vehicle.": "Esta factura tiene un vehiculo vinculado",
|
||||
"You don't have enough privileges.": "No tienes suficientes permisos.",
|
||||
"This ticket is locked.": "Este ticket está bloqueado.",
|
||||
"This ticket is not editable.": "Este ticket no es editable.",
|
||||
"The ticket doesn't exist.": "No existe el ticket.",
|
||||
<<<<<<< HEAD
|
||||
"There are missing fields.": "There are missing fields."
|
||||
}
|
||||
}
|
||||
=======
|
||||
"Social name should be uppercase": "La razón social debe ir en mayúscula",
|
||||
"Street should be uppercase": "La dirección fiscal debe ir en mayúscula"
|
||||
}
|
||||
jorgep marked this conversation as resolved
Outdated
|
||||
>>>>>>> ce78fc8e5dd383b3c6457fe5f78a45b21b246858
|
||||
|
|
|
@ -7,8 +7,8 @@ describe('Client Create', () => {
|
|||
email: 'Deadpool@marvel.com',
|
||||
fi: '16195279J',
|
||||
name: 'Wade',
|
||||
socialName: 'Deadpool Marvel',
|
||||
street: 'Wall Street',
|
||||
socialName: 'DEADPOOL MARVEL',
|
||||
street: 'WALL STREET',
|
||||
city: 'New York',
|
||||
businessTypeFk: 'florist',
|
||||
provinceFk: 1
|
||||
|
|
|
@ -36,6 +36,20 @@ module.exports = Self => {
|
|||
min: 3, max: 10
|
||||
});
|
||||
|
||||
Self.validatesFormatOf('street', {
|
||||
message: 'Street should be uppercase',
|
||||
allowNull: false,
|
||||
allowBlank: false,
|
||||
with: /^[^a-z]*$/
|
||||
});
|
||||
|
||||
Self.validatesFormatOf('socialName', {
|
||||
message: 'Social name should be uppercase',
|
||||
allowNull: false,
|
||||
allowBlank: false,
|
||||
with: /^[^a-z]*$/
|
||||
});
|
||||
|
||||
Self.validateAsync('socialName', socialNameIsUnique, {
|
||||
message: 'The company name must be unique'
|
||||
});
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
ng-model="$ctrl.client.socialName"
|
||||
info="Only letters, numbers and spaces can be used"
|
||||
required="true"
|
||||
ng-keyup="$ctrl.client.socialName = $ctrl.client.socialName.toUpperCase()"
|
||||
rule>
|
||||
</vn-textfield>
|
||||
<vn-textfield
|
||||
|
@ -46,6 +47,7 @@
|
|||
vn-two
|
||||
label="Street"
|
||||
ng-model="$ctrl.client.street"
|
||||
ng-keyup="$ctrl.client.street = $ctrl.client.street.toUpperCase()"
|
||||
rule>
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
label="Recovery email"
|
||||
ng-model="$ctrl.account.email"
|
||||
info="This email is used for user to regain access their account."
|
||||
rule="VnUser.name">
|
||||
rule="VnUser.email">
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
</vn-card>
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
name: invoice in
|
||||
columns:
|
||||
id: id
|
||||
serialNumber: serial number
|
||||
serial: serial
|
||||
supplierFk: supplier
|
||||
issued: issued
|
||||
supplierRef: supplierRef
|
||||
isBooked: is booked
|
||||
currencyFk: currency
|
||||
created: created
|
||||
companyFk: company
|
||||
docFk: document
|
||||
booked: booked
|
||||
operated: operated
|
||||
bookEntried: book entried
|
||||
isVatDeductible: is VAT deductible
|
||||
withholdingSageFk: withholding
|
||||
expenceFkDeductible: expence deductible
|
||||
editorFk: editor
|
|
@ -0,0 +1,20 @@
|
|||
name: factura recibida
|
||||
columns:
|
||||
id: id
|
||||
serialNumber: número de serie
|
||||
serial: serie
|
||||
supplierFk: proveedor
|
||||
issued: fecha emisión
|
||||
supplierRef: referéncia proveedor
|
||||
isBooked: facturado
|
||||
currencyFk: moneda
|
||||
created: creado
|
||||
companyFk: empresa
|
||||
docFk: documento
|
||||
booked: fecha contabilización
|
||||
operated: fecha entrega
|
||||
bookEntried: fecha asiento
|
||||
isVatDeductible: impuesto deducible
|
||||
withholdingSageFk: código de retención
|
||||
expenceFkDeductible: gasto deducible
|
||||
editorFk: editor
|
|
@ -0,0 +1,9 @@
|
|||
name: invoice in due day
|
||||
columns:
|
||||
id: id
|
||||
invoiceInFk: invoice in
|
||||
dueDated: due date
|
||||
bankFk: bank
|
||||
amount: amount
|
||||
foreignValue : foreign amount
|
||||
created: created
|
|
@ -0,0 +1,9 @@
|
|||
name: vencimientos factura recibida
|
||||
columns:
|
||||
id: id
|
||||
invoiceInFk: factura
|
||||
dueDated: fecha vto.
|
||||
bankFk: banco
|
||||
amount: importe
|
||||
foreignValue : importe divisa
|
||||
created: creado
|
|
@ -0,0 +1,12 @@
|
|||
name: invoice in tax
|
||||
columns:
|
||||
id: id
|
||||
invoiceInFk: invoice in
|
||||
taxCodeFk: tax
|
||||
taxableBase: taxable base
|
||||
expenceFk: expence
|
||||
foreignValue: foreign amount
|
||||
taxTypeSageFk: tax type
|
||||
transactionTypeSageFk: transaction type
|
||||
created: created
|
||||
editorFk: editor
|
|
@ -0,0 +1,12 @@
|
|||
name: factura recibida impuesto
|
||||
columns:
|
||||
id: id
|
||||
invoiceInFk: factura recibida
|
||||
taxCodeFk: código IVA
|
||||
taxableBase: base imponible
|
||||
expenceFk: código gasto
|
||||
foreignValue: importe divisa
|
||||
taxTypeSageFk: código impuesto
|
||||
transactionTypeSageFk: código transacción
|
||||
created: creado
|
||||
editorFk: editor
|
|
@ -1,40 +1,40 @@
|
|||
<vn-horizontal>
|
||||
<vn-auto>
|
||||
<section
|
||||
<vn-auto>
|
||||
<section
|
||||
class="inline-tag ellipsize"
|
||||
ng-class="::{empty: !$ctrl.item.value5}"
|
||||
ng-class="::{empty: !$ctrl.item.tag5}"
|
||||
title="{{::$ctrl.item.tag5}}: {{::$ctrl.item.value5}}">
|
||||
{{::$ctrl.item.value5}}
|
||||
</section>
|
||||
<section
|
||||
<section
|
||||
class="inline-tag ellipsize"
|
||||
ng-class="::{empty: !$ctrl.item.value6}"
|
||||
ng-class="::{empty: !$ctrl.item.tag6}"
|
||||
title="{{::$ctrl.item.tag6}}: {{::$ctrl.item.value6}}">
|
||||
{{::$ctrl.item.value6}}
|
||||
</section>
|
||||
<section
|
||||
<section
|
||||
class="inline-tag ellipsize"
|
||||
ng-class="::{empty: !$ctrl.item.value7}"
|
||||
ng-class="::{empty: !$ctrl.item.tag7}"
|
||||
title="{{::$ctrl.item.tag7}}: {{::$ctrl.item.value7}}">
|
||||
{{::$ctrl.item.value7}}
|
||||
</section>
|
||||
<section
|
||||
<section
|
||||
class="inline-tag ellipsize"
|
||||
ng-class="::{empty: !$ctrl.item.value8}"
|
||||
ng-class="::{empty: !$ctrl.item.tag8}"
|
||||
title="{{::$ctrl.item.tag8}}: {{::$ctrl.item.value8}}">
|
||||
{{::$ctrl.item.value8}}
|
||||
</section>
|
||||
<section
|
||||
<section
|
||||
class="inline-tag ellipsize"
|
||||
ng-class="::{empty: !$ctrl.item.value9}"
|
||||
ng-class="::{empty: !$ctrl.item.tag9}"
|
||||
title="{{::$ctrl.item.tag9}}: {{::$ctrl.item.value9}}">
|
||||
{{::$ctrl.item.value9}}
|
||||
</section>
|
||||
<section
|
||||
<section
|
||||
class="inline-tag ellipsize"
|
||||
ng-class="::{empty: !$ctrl.item.value10}"
|
||||
ng-class="::{empty: !$ctrl.item.tag10}"
|
||||
title="{{::$ctrl.item.tag10}}: {{::$ctrl.item.value10}}">
|
||||
{{::$ctrl.item.value10}}
|
||||
</section>
|
||||
</vn-auto>
|
||||
</vn-horizontal>
|
||||
</vn-horizontal>
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
vn-fetched-tags {
|
||||
& > vn-horizontal {
|
||||
align-items: center;
|
||||
|
||||
max-width: 210px;
|
||||
& > vn-auto {
|
||||
flex-wrap: wrap;
|
||||
|
||||
|
@ -43,19 +43,19 @@ vn-fetched-tags {
|
|||
& > .inline-tag {
|
||||
color: $color-font-secondary;
|
||||
text-align: center;
|
||||
font-size: .75rem;
|
||||
height: 12px;
|
||||
font-size: .8rem;
|
||||
height: 13px;
|
||||
padding: 1px;
|
||||
width: 64px;
|
||||
min-width: 64px;
|
||||
max-width: 64px;
|
||||
flex: 1;
|
||||
border: 1px solid $color-spacer;
|
||||
|
||||
border: 1px solid $color-font-secondary;
|
||||
|
||||
&.empty {
|
||||
border: 1px solid $color-spacer-light;
|
||||
border: 1px solid darken($color-font-secondary, 30%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('cmr', {
|
||||
description: 'Returns the cmr',
|
||||
accessType: 'READ',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'id',
|
||||
type: 'number',
|
||||
required: true,
|
||||
description: 'The cmr id',
|
||||
http: {source: 'path'}
|
||||
}
|
||||
],
|
||||
returns: [
|
||||
{
|
||||
arg: 'body',
|
||||
type: 'file',
|
||||
root: true
|
||||
}, {
|
||||
arg: 'Content-Type',
|
||||
type: 'String',
|
||||
http: {target: 'header'}
|
||||
}, {
|
||||
arg: 'Content-Disposition',
|
||||
type: 'String',
|
||||
http: {target: 'header'}
|
||||
}
|
||||
],
|
||||
http: {
|
||||
path: '/:id/cmr',
|
||||
verb: 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
Self.cmr = (ctx, id) => Self.printReport(ctx, id, 'cmr');
|
||||
};
|
|
@ -14,6 +14,7 @@ module.exports = Self => {
|
|||
require('../methods/route/driverRouteEmail')(Self);
|
||||
require('../methods/route/sendSms')(Self);
|
||||
require('../methods/route/downloadZip')(Self);
|
||||
require('../methods/route/cmr')(Self);
|
||||
|
||||
Self.validate('kmStart', validateDistance, {
|
||||
message: 'Distance must be lesser than 1000'
|
||||
|
@ -28,5 +29,5 @@ module.exports = Self => {
|
|||
const routeMaxKm = 1000;
|
||||
if (routeTotalKm > routeMaxKm || this.kmStart > this.kmEnd)
|
||||
err();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -67,7 +67,7 @@ module.exports = function(Self) {
|
|||
throw new UserError(`This ticket is already invoiced`);
|
||||
|
||||
const priceZero = ticket.totalWithVat == 0;
|
||||
if (priceZero)
|
||||
if (ticketsIds.length == 1 && priceZero)
|
||||
throw new UserError(`A ticket with an amount of zero can't be invoiced`);
|
||||
});
|
||||
|
||||
|
|
|
@ -5,177 +5,177 @@ const config = require('vn-print/core/config');
|
|||
const storage = require('vn-print/core/storage');
|
||||
|
||||
module.exports = async function(ctx, Self, tickets, reqArgs = {}) {
|
||||
const userId = ctx.req.accessToken.userId;
|
||||
if (tickets.length == 0) return;
|
||||
const userId = ctx.req.accessToken.userId;
|
||||
if (tickets.length == 0) return;
|
||||
|
||||
const failedtickets = [];
|
||||
for (const ticket of tickets) {
|
||||
try {
|
||||
await Self.rawSql(`CALL vn.ticket_closeByTicket(?)`, [ticket.id], {userId});
|
||||
const failedtickets = [];
|
||||
for (const ticket of tickets) {
|
||||
try {
|
||||
await Self.rawSql(`CALL vn.ticket_closeByTicket(?)`, [ticket.id], {userId});
|
||||
|
||||
const [invoiceOut] = await Self.rawSql(`
|
||||
SELECT io.id, io.ref, io.serial, cny.code companyCode, io.issued
|
||||
FROM ticket t
|
||||
JOIN invoiceOut io ON io.ref = t.refFk
|
||||
JOIN company cny ON cny.id = io.companyFk
|
||||
WHERE t.id = ?
|
||||
`, [ticket.id]);
|
||||
const [invoiceOut] = await Self.rawSql(`
|
||||
SELECT io.id, io.ref, io.serial, cny.code companyCode, io.issued
|
||||
FROM ticket t
|
||||
JOIN invoiceOut io ON io.ref = t.refFk
|
||||
JOIN company cny ON cny.id = io.companyFk
|
||||
WHERE t.id = ?
|
||||
`, [ticket.id]);
|
||||
|
||||
const mailOptions = {
|
||||
overrideAttachments: true,
|
||||
attachments: []
|
||||
};
|
||||
const mailOptions = {
|
||||
overrideAttachments: true,
|
||||
attachments: []
|
||||
};
|
||||
|
||||
const isToBeMailed = ticket.recipient && ticket.salesPersonFk && ticket.isToBeMailed;
|
||||
const isToBeMailed = ticket.recipient && ticket.salesPersonFk && ticket.isToBeMailed;
|
||||
|
||||
if (invoiceOut) {
|
||||
const args = {
|
||||
reference: invoiceOut.ref,
|
||||
recipientId: ticket.clientFk,
|
||||
recipient: ticket.recipient,
|
||||
replyTo: ticket.salesPersonEmail
|
||||
};
|
||||
if (invoiceOut) {
|
||||
const args = {
|
||||
reference: invoiceOut.ref,
|
||||
recipientId: ticket.clientFk,
|
||||
recipient: ticket.recipient,
|
||||
replyTo: ticket.salesPersonEmail
|
||||
};
|
||||
|
||||
const invoiceReport = new Report('invoice', args);
|
||||
const stream = await invoiceReport.toPdfStream();
|
||||
const invoiceReport = new Report('invoice', args);
|
||||
const stream = await invoiceReport.toPdfStream();
|
||||
|
||||
const issued = invoiceOut.issued;
|
||||
const year = issued.getFullYear().toString();
|
||||
const month = (issued.getMonth() + 1).toString();
|
||||
const day = issued.getDate().toString();
|
||||
const issued = invoiceOut.issued;
|
||||
const year = issued.getFullYear().toString();
|
||||
const month = (issued.getMonth() + 1).toString();
|
||||
const day = issued.getDate().toString();
|
||||
|
||||
const fileName = `${year}${invoiceOut.ref}.pdf`;
|
||||
const fileName = `${year}${invoiceOut.ref}.pdf`;
|
||||
|
||||
// Store invoice
|
||||
await storage.write(stream, {
|
||||
type: 'invoice',
|
||||
path: `${year}/${month}/${day}`,
|
||||
fileName: fileName
|
||||
});
|
||||
// Store invoice
|
||||
await storage.write(stream, {
|
||||
type: 'invoice',
|
||||
path: `${year}/${month}/${day}`,
|
||||
fileName: fileName
|
||||
});
|
||||
|
||||
await Self.rawSql('UPDATE invoiceOut SET hasPdf = true WHERE id = ?', [invoiceOut.id], {userId});
|
||||
await Self.rawSql('UPDATE invoiceOut SET hasPdf = true WHERE id = ?', [invoiceOut.id], {userId});
|
||||
|
||||
if (isToBeMailed) {
|
||||
const invoiceAttachment = {
|
||||
filename: fileName,
|
||||
content: stream
|
||||
};
|
||||
if (isToBeMailed) {
|
||||
const invoiceAttachment = {
|
||||
filename: fileName,
|
||||
content: stream
|
||||
};
|
||||
|
||||
if (invoiceOut.serial == 'E' && invoiceOut.companyCode == 'VNL') {
|
||||
const exportation = new Report('exportation', args);
|
||||
const stream = await exportation.toPdfStream();
|
||||
const fileName = `CITES-${invoiceOut.ref}.pdf`;
|
||||
if (invoiceOut.serial == 'E' && invoiceOut.companyCode == 'VNL') {
|
||||
const exportation = new Report('exportation', args);
|
||||
const stream = await exportation.toPdfStream();
|
||||
const fileName = `CITES-${invoiceOut.ref}.pdf`;
|
||||
|
||||
mailOptions.attachments.push({
|
||||
filename: fileName,
|
||||
content: stream
|
||||
});
|
||||
}
|
||||
mailOptions.attachments.push({
|
||||
filename: fileName,
|
||||
content: stream
|
||||
});
|
||||
}
|
||||
|
||||
mailOptions.attachments.push(invoiceAttachment);
|
||||
mailOptions.attachments.push(invoiceAttachment);
|
||||
|
||||
const email = new Email('invoice', args);
|
||||
await email.send(mailOptions);
|
||||
}
|
||||
} else if (isToBeMailed) {
|
||||
const args = {
|
||||
id: ticket.id,
|
||||
recipientId: ticket.clientFk,
|
||||
recipient: ticket.recipient,
|
||||
replyTo: ticket.salesPersonEmail
|
||||
};
|
||||
const email = new Email('invoice', args);
|
||||
await email.send(mailOptions);
|
||||
}
|
||||
} else if (isToBeMailed) {
|
||||
const args = {
|
||||
id: ticket.id,
|
||||
recipientId: ticket.clientFk,
|
||||
recipient: ticket.recipient,
|
||||
replyTo: ticket.salesPersonEmail
|
||||
};
|
||||
|
||||
const email = new Email('delivery-note-link', args);
|
||||
await email.send();
|
||||
}
|
||||
const email = new Email('delivery-note-link', args);
|
||||
await email.send();
|
||||
}
|
||||
|
||||
// Incoterms authorization
|
||||
const [{firstOrder}] = await Self.rawSql(`
|
||||
SELECT COUNT(*) as firstOrder
|
||||
FROM ticket t
|
||||
JOIN client c ON c.id = t.clientFk
|
||||
WHERE t.clientFk = ?
|
||||
AND NOT t.isDeleted
|
||||
AND c.isVies
|
||||
`, [ticket.clientFk]);
|
||||
// Incoterms authorization
|
||||
const [{firstOrder}] = await Self.rawSql(`
|
||||
SELECT COUNT(*) as firstOrder
|
||||
FROM ticket t
|
||||
JOIN client c ON c.id = t.clientFk
|
||||
WHERE t.clientFk = ?
|
||||
AND NOT t.isDeleted
|
||||
AND c.isVies
|
||||
`, [ticket.clientFk]);
|
||||
|
||||
if (firstOrder == 1) {
|
||||
const args = {
|
||||
id: ticket.clientFk,
|
||||
companyId: ticket.companyFk,
|
||||
recipientId: ticket.clientFk,
|
||||
recipient: ticket.recipient,
|
||||
replyTo: ticket.salesPersonEmail
|
||||
};
|
||||
if (firstOrder == 1) {
|
||||
const args = {
|
||||
id: ticket.clientFk,
|
||||
companyId: ticket.companyFk,
|
||||
recipientId: ticket.clientFk,
|
||||
recipient: ticket.recipient,
|
||||
replyTo: ticket.salesPersonEmail
|
||||
};
|
||||
|
||||
const email = new Email('incoterms-authorization', args);
|
||||
await email.send();
|
||||
const email = new Email('incoterms-authorization', args);
|
||||
await email.send();
|
||||
|
||||
const [sample] = await Self.rawSql(
|
||||
`SELECT id
|
||||
FROM sample
|
||||
WHERE code = 'incoterms-authorization'
|
||||
`);
|
||||
const [sample] = await Self.rawSql(
|
||||
`SELECT id
|
||||
FROM sample
|
||||
WHERE code = 'incoterms-authorization'
|
||||
`);
|
||||
|
||||
await Self.rawSql(`
|
||||
INSERT INTO clientSample (clientFk, typeFk, companyFk) VALUES(?, ?, ?)
|
||||
`, [ticket.clientFk, sample.id, ticket.companyFk], {userId});
|
||||
}
|
||||
} catch (error) {
|
||||
// Domain not found
|
||||
if (error.responseCode == 450)
|
||||
return invalidEmail(ticket);
|
||||
await Self.rawSql(`
|
||||
INSERT INTO clientSample (clientFk, typeFk, companyFk) VALUES(?, ?, ?)
|
||||
`, [ticket.clientFk, sample.id, ticket.companyFk], {userId});
|
||||
};
|
||||
} catch (error) {
|
||||
// Domain not found
|
||||
if (error.responseCode == 450)
|
||||
return invalidEmail(ticket);
|
||||
|
||||
// Save tickets on a list of failed ids
|
||||
failedtickets.push({
|
||||
id: ticket.id,
|
||||
stacktrace: error
|
||||
});
|
||||
}
|
||||
}
|
||||
// Save tickets on a list of failed ids
|
||||
failedtickets.push({
|
||||
id: ticket.id,
|
||||
stacktrace: error
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Send email with failed tickets
|
||||
if (failedtickets.length > 0) {
|
||||
let body = 'This following tickets have failed:<br/><br/>';
|
||||
// Send email with failed tickets
|
||||
if (failedtickets.length > 0) {
|
||||
let body = 'This following tickets have failed:<br/><br/>';
|
||||
|
||||
for (const ticket of failedtickets) {
|
||||
body += `Ticket: <strong>${ticket.id}</strong>
|
||||
<br/> <strong>${ticket.stacktrace}</strong><br/><br/>`;
|
||||
}
|
||||
for (const ticket of failedtickets) {
|
||||
body += `Ticket: <strong>${ticket.id}</strong>
|
||||
<br/> <strong>${ticket.stacktrace}</strong><br/><br/>`;
|
||||
}
|
||||
|
||||
smtp.send({
|
||||
to: config.app.reportEmail,
|
||||
subject: '[API] Nightly ticket closure report',
|
||||
html: body
|
||||
});
|
||||
}
|
||||
smtp.send({
|
||||
to: config.app.reportEmail,
|
||||
subject: '[API] Nightly ticket closure report',
|
||||
html: body
|
||||
});
|
||||
}
|
||||
|
||||
async function invalidEmail(ticket) {
|
||||
await Self.rawSql(`UPDATE client SET email = NULL WHERE id = ?`, [
|
||||
ticket.clientFk
|
||||
], {userId});
|
||||
async function invalidEmail(ticket) {
|
||||
await Self.rawSql(`UPDATE client SET email = NULL WHERE id = ?`, [
|
||||
ticket.clientFk
|
||||
], {userId});
|
||||
|
||||
const oldInstance = `{"email": "${ticket.recipient}"}`;
|
||||
const newInstance = `{"email": ""}`;
|
||||
await Self.rawSql(`
|
||||
INSERT INTO clientLog (originFk, userFk, action, changedModel, oldInstance, newInstance)
|
||||
VALUES (?, NULL, 'UPDATE', 'Client', ?, ?)`, [
|
||||
ticket.clientFk,
|
||||
oldInstance,
|
||||
newInstance
|
||||
], {userId});
|
||||
const oldInstance = `{"email": "${ticket.recipient}"}`;
|
||||
const newInstance = `{"email": ""}`;
|
||||
await Self.rawSql(`
|
||||
INSERT INTO clientLog (originFk, userFk, action, changedModel, oldInstance, newInstance)
|
||||
VALUES (?, NULL, 'UPDATE', 'Client', ?, ?)`, [
|
||||
ticket.clientFk,
|
||||
oldInstance,
|
||||
newInstance
|
||||
], {userId});
|
||||
|
||||
const body = `No se ha podido enviar el albarán <strong>${ticket.id}</strong>
|
||||
al cliente <strong>${ticket.clientFk} - ${ticket.clientName}</strong>
|
||||
porque la dirección de email <strong>"${ticket.recipient}"</strong> no es correcta
|
||||
o no está disponible.<br/><br/>
|
||||
Para evitar que se repita este error, se ha eliminado la dirección de email de la ficha del cliente.
|
||||
Actualiza la dirección de email con una correcta.`;
|
||||
const body = `No se ha podido enviar el albarán <strong>${ticket.id}</strong>
|
||||
al cliente <strong>${ticket.clientFk} - ${ticket.clientName}</strong>
|
||||
porque la dirección de email <strong>"${ticket.recipient}"</strong> no es correcta
|
||||
o no está disponible.<br/><br/>
|
||||
Para evitar que se repita este error, se ha eliminado la dirección de email de la ficha del cliente.
|
||||
Actualiza la dirección de email con una correcta.`;
|
||||
|
||||
smtp.send({
|
||||
to: ticket.salesPersonEmail,
|
||||
subject: 'No se ha podido enviar el albarán',
|
||||
html: body
|
||||
});
|
||||
}
|
||||
smtp.send({
|
||||
to: ticket.salesPersonEmail,
|
||||
subject: 'No se ha podido enviar el albarán',
|
||||
html: body
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
const loggable = require('vn-loopback/util/log');
|
||||
const UserError = require('vn-loopback/util/user-error');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('componentUpdate', {
|
||||
|
@ -112,7 +113,6 @@ module.exports = Self => {
|
|||
}
|
||||
|
||||
try {
|
||||
const userId = ctx.req.accessToken.userId;
|
||||
const models = Self.app.models;
|
||||
const $t = ctx.req.__; // $translate
|
||||
await models.Ticket.isEditableOrThrow(ctx, args.id, myOptions);
|
||||
|
@ -127,11 +127,8 @@ module.exports = Self => {
|
|||
args.warehouseFk,
|
||||
myOptions);
|
||||
|
||||
if (!zoneShipped || zoneShipped.zoneFk != args.zoneFk) {
|
||||
const error = `You don't have privileges to change the zone`;
|
||||
|
||||
throw new UserError(error);
|
||||
}
|
||||
if (!zoneShipped || zoneShipped.zoneFk != args.zoneFk)
|
||||
throw new UserError(`You don't have privileges to change the zone`);
|
||||
}
|
||||
|
||||
if (args.isWithoutNegatives) {
|
||||
|
|
|
@ -248,6 +248,7 @@ module.exports = Self => {
|
|||
am.name AS agencyMode,
|
||||
am.id AS agencyModeFk,
|
||||
st.name AS state,
|
||||
st.classColor,
|
||||
wk.lastName AS salesPerson,
|
||||
ts.stateFk AS stateFk,
|
||||
ts.alertLevel AS alertLevel,
|
||||
|
@ -339,7 +340,8 @@ module.exports = Self => {
|
|||
{'tp.isFreezed': hasProblem},
|
||||
{'tp.risk': hasProblem},
|
||||
{'tp.hasTicketRequest': hasProblem},
|
||||
{'tp.itemShortage': range}
|
||||
{'tp.itemShortage': range},
|
||||
{'tp.hasRounding': hasProblem}
|
||||
]};
|
||||
|
||||
if (hasWhere)
|
||||
|
|
|
@ -194,7 +194,8 @@ module.exports = Self => {
|
|||
{'tp.hasTicketRequest': hasProblem},
|
||||
{'tp.itemShortage': range},
|
||||
{'tp.hasComponentLack': hasProblem},
|
||||
{'tp.isTooLittle': hasProblem}
|
||||
{'tp.isTooLittle': hasProblem},
|
||||
{'tp.hasRounding': hasProblem}
|
||||
]
|
||||
};
|
||||
|
||||
|
|
|
@ -27,6 +27,9 @@
|
|||
"code": {
|
||||
"type": "string",
|
||||
"required": false
|
||||
},
|
||||
"classColor": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,6 +123,12 @@
|
|||
class="bright"
|
||||
icon="icon-components">
|
||||
</vn-icon>
|
||||
<vn-icon
|
||||
ng-show="::ticket.hasRounding"
|
||||
translate-attr="{title: 'Rounding'}"
|
||||
class="bright"
|
||||
icon="sync_problem">
|
||||
</vn-icon>
|
||||
</td>
|
||||
<td><span
|
||||
ng-click="ticketDescriptor.show($event, ticket.id)"
|
||||
|
|
|
@ -75,6 +75,12 @@
|
|||
class="bright"
|
||||
icon="icon-components">
|
||||
</vn-icon>
|
||||
<vn-icon
|
||||
ng-show="::ticket.hasRounding"
|
||||
translate-attr="{title: 'Rounding'}"
|
||||
class="bright"
|
||||
icon="sync_problem">
|
||||
</vn-icon>
|
||||
</vn-td>
|
||||
<vn-td shrink>{{::ticket.id}}</vn-td>
|
||||
<vn-td class="expendable">
|
||||
|
|
|
@ -71,8 +71,9 @@ module.exports = Self => {
|
|||
'Stored on': 'created',
|
||||
'Document ID': 'id'
|
||||
};
|
||||
|
||||
workerDocuware =
|
||||
await models.Docuware.getById('hr', worker.lastName + worker.firstName, docuwareParse) ?? [];
|
||||
await models.Docuware.getById('hr', worker.lastName + ' ' + worker.firstName, docuwareParse) ?? [];
|
||||
for (document of workerDocuware) {
|
||||
const defaultData = {
|
||||
file: 'dw' + document.id + '.png',
|
||||
|
|
|
@ -36,9 +36,9 @@ module.exports = Self => {
|
|||
if (isSubordinate === false)
|
||||
throw new UserError(`You don't have enough privileges`);
|
||||
|
||||
const subordinate = await Worker.findById(ctx.args.workerFk);
|
||||
const subordinate = await Worker.findById(ctx.args.workerFk, {fields: ['id']});
|
||||
filter = mergeFilters(filter, {where: {
|
||||
userFk: subordinate.userFk
|
||||
userFk: subordinate.id
|
||||
}});
|
||||
|
||||
return Self.find(filter);
|
||||
|
|
|
@ -20,11 +20,11 @@ describe('Worker new', () => {
|
|||
const employeeId = 1;
|
||||
const defaultWorker = {
|
||||
fi: '78457139E',
|
||||
name: 'defaultWorker',
|
||||
firstName: 'default',
|
||||
lastNames: 'worker',
|
||||
name: 'DEFAULTERWORKER',
|
||||
firstName: 'DEFAULT',
|
||||
lastNames: 'WORKER',
|
||||
email: 'defaultWorker@mydomain.com',
|
||||
street: 'S/ defaultWorkerStreet',
|
||||
street: 'S/ DEFAULTWORKERSTREET',
|
||||
city: 'defaultWorkerCity',
|
||||
provinceFk: 1,
|
||||
companyFk: 442,
|
||||
|
|
|
@ -25,8 +25,7 @@
|
|||
"type" : "string"
|
||||
},
|
||||
"userFk": {
|
||||
"type" : "number",
|
||||
"required": true
|
||||
"type" : "number"
|
||||
},
|
||||
"bossFk": {
|
||||
"type" : "number"
|
||||
|
|
|
@ -32,6 +32,28 @@ class Controller extends Descriptor {
|
|||
this.vnApp.showSuccess(this.$t('Department deleted.'));
|
||||
});
|
||||
}
|
||||
|
||||
loadData() {
|
||||
const filter = {
|
||||
fields: ['id', 'name', 'code', 'workerFk', 'isProduction', 'chatName',
|
||||
'isTeleworking', 'notificationEmail', 'hasToRefill', 'hasToSendMail', 'hasToMistake', 'clientFk'],
|
||||
include: [
|
||||
{relation: 'client',
|
||||
scope: {
|
||||
fields: ['id', 'name']
|
||||
}},
|
||||
{
|
||||
relation: 'worker',
|
||||
scope: {
|
||||
fields: ['id', 'firstName', 'lastName']
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
return this.getData(`Departments/${this.id}`, {filter})
|
||||
.then(res => this.entity = res.data);
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$element', '$scope', '$rootScope'];
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
filter="::$ctrl.filter"
|
||||
data="$ctrl.hours">
|
||||
</vn-crud-model>
|
||||
<div ng-if="$ctrl.card.hasWorkCenter">
|
||||
<div>
|
||||
<vn-card class="vn-pa-lg vn-w-lg">
|
||||
<vn-table model="model" auto-load="false">
|
||||
<vn-thead>
|
||||
|
@ -106,12 +106,6 @@
|
|||
</vn-button>
|
||||
</vn-button-bar>
|
||||
</div>
|
||||
<div
|
||||
ng-if="!$ctrl.card.hasWorkCenter"
|
||||
class="bg-title"
|
||||
translate>
|
||||
Autonomous worker
|
||||
</div>
|
||||
|
||||
<vn-side-menu side="right">
|
||||
<div class="vn-pa-md">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "salix-back",
|
||||
"version": "23.32.01",
|
||||
"version": "23.34.01",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "salix-back",
|
||||
"version": "23.32.01",
|
||||
"version": "23.34.01",
|
||||
"author": "Verdnatura Levante SL",
|
||||
"description": "Salix backend",
|
||||
"license": "GPL-3.0",
|
||||
|
|
|
@ -539,9 +539,9 @@
|
|||
<Stroke>2</Stroke>
|
||||
<Width>4</Width>
|
||||
</GraphicShape>
|
||||
<GraphicShape xsi:type="WindowText" Style="Cross" IsPrint="true" PageAlignment="None" Locked="false" bStroke="true" bFill="true" Direction="Angle90" X="613" Y="24" Alignment="Left" AlignPointX="613" AlignPointY="24" FontScript="Default" FontCmd="Arial,118.2266,B
" FontHeight="1" FontWidth="1" TextSpace="0" bSpaceCropping="false">
|
||||
<GraphicShape xsi:type="WindowText" Style="Cross" IsPrint="true" PageAlignment="None" Locked="false" bStroke="true" bFill="true" Direction="Angle90" X="564" Y="32" Alignment="Left" AlignPointX="564" AlignPointY="32" FontScript="Default" FontCmd="Arial,118.2266,B
" FontHeight="1" FontWidth="1" TextSpace="0" bSpaceCropping="false">
|
||||
<qHitOnCircumferance>false</qHitOnCircumferance>
|
||||
<Selected>false</Selected>
|
||||
<Selected>true</Selected>
|
||||
<iBackground_color>4294967295</iBackground_color>
|
||||
<Id>5</Id>
|
||||
<ItemLabel>W5</ItemLabel>
|
||||
|
@ -571,15 +571,15 @@
|
|||
<BoundRectHeight>2896</BoundRectHeight>
|
||||
<BoundRect>
|
||||
<Location>
|
||||
<X>187</X>
|
||||
<Y>24</Y>
|
||||
<X>138</X>
|
||||
<Y>32</Y>
|
||||
</Location>
|
||||
<Size>
|
||||
<Width>426</Width>
|
||||
<Height>2896</Height>
|
||||
</Size>
|
||||
<X>187</X>
|
||||
<Y>24</Y>
|
||||
<X>138</X>
|
||||
<Y>32</Y>
|
||||
<Width>426</Width>
|
||||
<Height>2896</Height>
|
||||
</BoundRect>
|
||||
|
@ -621,14 +621,14 @@
|
|||
<Setup bInfinityPrint="false" LabelLength="610" LabelWidth="100" LeftMargin="0" TopMargin="0" LabelType="1" GapLength="3" FeedLength="0" ZSign="43" BlackMark="3" Position="0" Speed="2" Copy="1" bCopyDataBase="false" CopyField="None" Stripper="0" LabelsPerCut="0" DoubleCut_Enable="false" DoubleCut_OffsetLen="0" DoubleCut_FirstCutMode="1" Rotate180="200" Stop="35" Darkness="5" Number="1" bCutDataBase="false" bBatchCut="false" bNumberDataBase="false" NumberField="None" PageDirection="Portrait" PrintMode="0" PowerRFID="10" LengthRFID="0" RetryRFID="3" DrawMode="0">
|
||||
<Layout Shape="0" AcrossType="Copied" PageDirection="Portrait" HorAcross="1" VerAcross="1" HorGap="0" VerGap="0" HorAcrossMode1="1" VerAcrossMode1="1" LabelMode="0" HorGapMode1="0" VerGapMode1="0" BottomMargin="0" RightMargin="0" />
|
||||
<Description>New label
|
||||
Lang:(es-ES) OS:Microsoft Windows NT 10.0.22000.0(Win32NT)</Description>
|
||||
Lang:(es-ES) OS:Microsoft Windows NT 10.0.19045.0(Win32NT)</Description>
|
||||
<UnitType>Mm</UnitType>
|
||||
<Dpi>203</Dpi>
|
||||
</Setup>
|
||||
<PrinterModel />
|
||||
<PrinterLanguage>EZPL</PrinterLanguage>
|
||||
<USBName>GODEX G300#132207AB</USBName>
|
||||
<COMName>None</COMName>
|
||||
<USBName>00000000</USBName>
|
||||
<COMName>COM1</COMName>
|
||||
<CommunicationType>USB</CommunicationType>
|
||||
<NetworkIPAddress>2886794855</NetworkIPAddress>
|
||||
<NetworkPort>9100</NetworkPort>
|
|
@ -1,9 +1,9 @@
|
|||
[
|
||||
{
|
||||
"filename": "model.ezp",
|
||||
"filename": "model.ezpx",
|
||||
"component": "printer-setup",
|
||||
"path": "/assets/files/model.ezp",
|
||||
"cid": "model.ezp"
|
||||
"path": "/assets/files/model.ezpx",
|
||||
"cid": "model.ezpx"
|
||||
},
|
||||
{
|
||||
"filename": "port.png",
|
||||
|
@ -11,4 +11,4 @@
|
|||
"path": "/assets/files/port.png",
|
||||
"cid": "port.png"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
const Stylesheet = require(`vn-print/core/stylesheet`);
|
||||
|
||||
const path = require('path');
|
||||
const vnPrintPath = path.resolve('print');
|
||||
|
||||
module.exports = new Stylesheet([
|
||||
`${vnPrintPath}/common/css/spacing.css`,
|
||||
`${vnPrintPath}/common/css/misc.css`,
|
||||
`${vnPrintPath}/common/css/layout.css`,
|
||||
`${vnPrintPath}/common/css/report.css`,
|
||||
`${__dirname}/style.css`])
|
||||
.mergeStyles();
|
|
@ -0,0 +1,101 @@
|
|||
html {
|
||||
font-family: "Roboto", "Helvetica", "Arial", sans-serif;
|
||||
margin: 10px;
|
||||
font-size: 22px;
|
||||
}
|
||||
.mainTable, .specialTable, .categoryTable {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: inherit;
|
||||
}
|
||||
.mainTable td {
|
||||
width: 50%;
|
||||
border: 1px solid black;
|
||||
vertical-align: top;
|
||||
padding: 15px;
|
||||
font-size: inherit;
|
||||
}
|
||||
.signTable {
|
||||
height: 12%;
|
||||
}
|
||||
.signTable td {
|
||||
width: calc(100% / 3);
|
||||
border: 1px solid black;
|
||||
vertical-align: top;
|
||||
font-size: inherit;
|
||||
padding: 15px;
|
||||
border-top: none;
|
||||
}
|
||||
#title {
|
||||
font-weight: bold;
|
||||
font-size: 85px;
|
||||
}
|
||||
hr {
|
||||
border: 1px solid #cccccc;
|
||||
height: 0px;
|
||||
border-radius: 25px;
|
||||
}
|
||||
#cellHeader {
|
||||
border: 0px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
#label, #merchandiseLabels {
|
||||
font-size: 13px;
|
||||
}
|
||||
#merchandiseLabels {
|
||||
border: none;
|
||||
}
|
||||
.imgSection {
|
||||
text-align: center;
|
||||
height: 200px;
|
||||
overflow: hidden;
|
||||
}
|
||||
img {
|
||||
object-fit: contain;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
#lineBreak {
|
||||
white-space: pre-line;
|
||||
}
|
||||
.specialTable td {
|
||||
border: 1px solid black;
|
||||
vertical-align: top;
|
||||
padding: 15px;
|
||||
font-size: inherit;
|
||||
border-top: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
.specialTable #itemCategoryList {
|
||||
width: 70%;
|
||||
padding-top: 10px;
|
||||
}
|
||||
.categoryTable {
|
||||
padding-bottom: none;
|
||||
}
|
||||
.categoryTable td {
|
||||
vertical-align: top;
|
||||
font-size: inherit;
|
||||
border: none;
|
||||
padding: 5px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.categoryTable #merchandiseLabels {
|
||||
border-bottom: 4px solid #cccccc;
|
||||
padding: none;
|
||||
}
|
||||
#merchandiseDetail {
|
||||
font-weight: bold;
|
||||
padding-top: 10px;
|
||||
}
|
||||
#merchandiseData {
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
#merchandiseLabels td {
|
||||
padding-bottom: 11px;
|
||||
max-width: 300px;
|
||||
}
|
|
@ -0,0 +1,212 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<body>
|
||||
<table class="mainTable">
|
||||
<tr>
|
||||
<td>
|
||||
<span id="label">1. Remitente / Expediteur / Sender</span>
|
||||
<hr>
|
||||
<b>{{data.senderName}}</b><br>
|
||||
{{data.senderStreet}}<br>
|
||||
{{data.senderPostCode}} {{data.senderCity}} {{(data.senderCountry) ? `(${data.senderCountry})` : null}}
|
||||
</td>
|
||||
<td id="cellHeader">
|
||||
<span id="title">CMR</span><br>
|
||||
{{data.cmrFk}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span id="label">2. Consignatario / Destinataire / Consignee</span>
|
||||
<hr>
|
||||
<b>{{data.deliveryAddressFk}}<br>
|
||||
{{data.deliveryName}}<br>
|
||||
{{data.deliveryPhone || data.clientPhone}}
|
||||
{{((data.deliveryPhone || data.clientPhone) && data.deliveryMobile) ? '/' : null}}
|
||||
{{data.deliveryMobile}}</b>
|
||||
</td>
|
||||
<td>
|
||||
<span id="label">16. Transportista / Transporteur / Carrier</span>
|
||||
<hr>
|
||||
<b>{{data.carrierName}}</b><br>
|
||||
{{data.carrierStreet}}<br>
|
||||
{{data.carrierPostalCode}} {{data.carrierCity}} {{(data.carrierCountry) ? `(${data.carrierCountry})` : null}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span id="label">
|
||||
3. Lugar y fecha de entrega /
|
||||
Lieu et date de livraison /
|
||||
Place and date of delivery
|
||||
</span>
|
||||
<hr>
|
||||
<b>{{data.deliveryStreet}}<br>
|
||||
{{data.deliveryPostalCode}} {{data.deliveryCity}} {{(data.deliveryCountry) ? `(${data.deliveryCountry})` : null}}<br>
|
||||
{{(data.ead) ? formatDate(data.ead, '%d/%m/%Y') : null}}</b>
|
||||
|
||||
</td>
|
||||
<td>
|
||||
<span id="label">17. Porteadores sucesivos / Transporteurs succesifs / Succesive Carriers</span>
|
||||
<hr>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span id="label">
|
||||
4. Lugar y fecha de carga /
|
||||
Lieu et date del prise en charge de la merchandise /
|
||||
Place and date of taking over the goods
|
||||
</span>
|
||||
<hr>
|
||||
<b>{{data.loadStreet}}<br>
|
||||
{{data.loadPostalCode}} {{data.loadCity}} {{(data.loadCountry) ? `(${data.loadCountry})` : null}}<br>
|
||||
{{formatDate(data.created, '%d/%m/%Y')}}</b>
|
||||
</td>
|
||||
<td rowspan="2">
|
||||
<span id="label">
|
||||
18. Obervaciones del transportista /
|
||||
Reserves et observations du transporteur /
|
||||
Carrier's reservations and observations
|
||||
</span>
|
||||
<hr>
|
||||
<b>{{data.truckPlate}}</b><br>
|
||||
{{data.observations}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span id="label">5. Documentos anexos / Documents annexes / Documents attached</span>
|
||||
<hr>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="specialTable">
|
||||
<tr>
|
||||
<td>
|
||||
<span id="label">
|
||||
7 & 8. Número de bultos y clase de embalage /
|
||||
Number of packages and packaging class /
|
||||
Nombre de colis et classe d'emballage
|
||||
</span>
|
||||
<hr>
|
||||
<div id="lineBreak">
|
||||
<b>{{data.packagesList}}</b>
|
||||
</div>
|
||||
</td>
|
||||
<td id="itemCategoryList">
|
||||
<table class="categoryTable">
|
||||
<tr id="merchandiseLabels">
|
||||
<td>6. Marcas y números / Brands and numbers / Marques et numéros</td>
|
||||
<td>9. Naturaleza de la merc. / Nature of goods / Nature des marchandises</td>
|
||||
<td>10. nº Estadístico / Statistical no. / n° statistique</td>
|
||||
<td>11. Peso bruto / Gross weight / Poids brut (kg)</td>
|
||||
<td>12. Volumen / Volume (m3)</td>
|
||||
</tr>
|
||||
<tr v-for="merchandise in merchandises" id="merchandiseData">
|
||||
<td>{{merchandise.ticketFk}}</td>
|
||||
<td>{{merchandise.name}}</td>
|
||||
<td>N/A</td>
|
||||
<td>{{merchandise.weight}}</td>
|
||||
<td>{{merchandise.volume}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div v-if="!merchandises" id="merchandiseDetail">
|
||||
{{data.merchandiseDetail}}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="mainTable">
|
||||
<tr>
|
||||
<td>
|
||||
<span id="label">
|
||||
13. Instrucciones del remitente /
|
||||
Instrunstions de l'expèditeur / Sender
|
||||
instruccions
|
||||
</span>
|
||||
<hr>
|
||||
<b>{{data.senderInstruccions}}</b>
|
||||
</td>
|
||||
<td>
|
||||
<span id="label">
|
||||
19. Estipulaciones particulares /
|
||||
Conventions particulieres /
|
||||
Special agreements
|
||||
</span>
|
||||
<hr>
|
||||
<b>{{data.specialAgreements}}</b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span id="label">
|
||||
14. Forma de pago /
|
||||
Prescriptions d'affranchissement /
|
||||
Instruction as to payment for carriage
|
||||
</span>
|
||||
<hr>
|
||||
<b>{{data.paymentInstruccions}}</b>
|
||||
</td>
|
||||
<td>
|
||||
<span id="label">20. A pagar por / Être payé pour / To be paid by</span>
|
||||
<hr>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span id="label">21. Formalizado en / Etabile a / Estabilshed in</span>
|
||||
<hr>
|
||||
<b>{{data.loadStreet}}</b><br>
|
||||
{{data.loadPostalCode}} {{data.loadCity}} {{(data.loadCountry) ? `(${data.loadCountry})` : null}} <br>
|
||||
</td>
|
||||
<td>
|
||||
<span id="label">15. Reembolso / Remboursement / Cash on delivery</span>
|
||||
<hr>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
<table class="signTable">
|
||||
<tr>
|
||||
<td>
|
||||
<span id="label">
|
||||
22. Firma y sello del remitente /
|
||||
Signature et timbre de l'expèditeur /
|
||||
Signature and stamp of the sender
|
||||
</span>
|
||||
<hr>
|
||||
<div class="imgSection">
|
||||
<img :src="senderStamp"/>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span id="label">
|
||||
23. Firma y sello del transportista /
|
||||
Signature et timbre du transporteur /
|
||||
Signature and stamp of the carrier
|
||||
</span>
|
||||
<hr>
|
||||
<div class="imgSection">
|
||||
<img :src="deliveryStamp"/>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span id="label">
|
||||
24. Firma y sello del consignatario /
|
||||
Signature et timbre du destinataire /
|
||||
Signature and stamp of the consignee
|
||||
</span>
|
||||
<hr>
|
||||
<div class="imgSection">
|
||||
<img :src="signPath"/>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,45 @@
|
|||
const config = require(`vn-print/core/config`);
|
||||
const vnReport = require('../../../core/mixins/vn-report.js');
|
||||
const md5 = require('md5');
|
||||
const fs = require('fs-extra');
|
||||
|
||||
const prefixBase64 = 'data:image/png;base64,';
|
||||
|
||||
module.exports = {
|
||||
name: 'cmr',
|
||||
mixins: [vnReport],
|
||||
async serverPrefetch() {
|
||||
this.data = await this.findOneFromDef('data', [this.id]);
|
||||
if (this.data.ticketFk) {
|
||||
this.merchandises = await this.rawSqlFromDef('merchandise', [this.data.ticketFk]);
|
||||
this.signature = await this.findOneFromDef('signature', [this.data.ticketFk]);
|
||||
} else
|
||||
this.merchandises = null;
|
||||
|
||||
this.senderStamp = (this.data.senderStamp)
|
||||
? `${prefixBase64} ${this.data.senderStamp.toString('base64')}`
|
||||
: null;
|
||||
this.deliveryStamp = (this.data.deliveryStamp)
|
||||
? `${prefixBase64} ${this.data.deliveryStamp.toString('base64')}`
|
||||
: null;
|
||||
},
|
||||
props: {
|
||||
id: {
|
||||
type: Number,
|
||||
required: true,
|
||||
description: 'The cmr id'
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
signPath() {
|
||||
if (!this.signature) return;
|
||||
|
||||
const signatureName = this.signature.signature
|
||||
const hash = md5(signatureName.toString()).substring(0, 3);
|
||||
const file = `${config.storage.root}/${hash}/${signatureName}.png`;
|
||||
if (!fs.existsSync(file)) return null;
|
||||
|
||||
return `${prefixBase64} ${Buffer.from(fs.readFileSync(file), 'utf8').toString('base64')}`;
|
||||
},
|
||||
}
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
reportName: cmr
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"format": "A4"
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
SELECT c.id cmrFk,
|
||||
t.id ticketFk,
|
||||
c.truckPlate,
|
||||
c.observations,
|
||||
c.senderInstruccions,
|
||||
c.paymentInstruccions,
|
||||
c.specialAgreements,
|
||||
c.created,
|
||||
c.packagesList,
|
||||
c.merchandiseDetail,
|
||||
c.ead,
|
||||
s.name carrierName,
|
||||
s.street carrierStreet,
|
||||
s.postCode carrierPostCode,
|
||||
s.city carrierCity,
|
||||
cou.country carrierCountry,
|
||||
s2.name senderName,
|
||||
s2.street senderStreet,
|
||||
s2.postCode senderPostCode,
|
||||
s2.city senderCity,
|
||||
cou2.country senderCountry,
|
||||
a.street deliveryStreet,
|
||||
a.id deliveryAddressFk,
|
||||
a.postalCode deliveryPostalCode,
|
||||
a.city deliveryCity,
|
||||
a.nickname deliveryName,
|
||||
a.phone deliveryPhone,
|
||||
a.mobile deliveryMobile,
|
||||
cou3.country deliveryCountry,
|
||||
cl.phone clientPhone,
|
||||
a2.street loadStreet,
|
||||
a2.postalCode loadPostalCode,
|
||||
a2.city loadCity,
|
||||
cou4.country loadCountry,
|
||||
co.stamp senderStamp,
|
||||
s.stamp deliveryStamp
|
||||
FROM cmr c
|
||||
LEFT JOIN supplier s ON s.id = c.supplierFk
|
||||
LEFT JOIN country cou ON cou.id = s.countryFk
|
||||
LEFT JOIN company co ON co.id = c.companyFk
|
||||
LEFT JOIN supplierAccount sa ON sa.id = co.supplierAccountFk
|
||||
LEFT JOIN supplier s2 ON s2.id = sa.supplierFk
|
||||
LEFT JOIN country cou2 ON cou2.id = s2.countryFk
|
||||
LEFT JOIN `address` a ON a.id = c.addressToFk
|
||||
LEFT JOIN province p ON p.id = a.provinceFk
|
||||
LEFT JOIN country cou3 ON cou3.id = p.countryFk
|
||||
LEFT JOIN client cl ON cl.id = a.clientFk
|
||||
LEFT JOIN `address` a2 ON a2.id = c.addressFromFk
|
||||
LEFT JOIN province p2 ON p2.id = a2.provinceFk
|
||||
LEFT JOIN country cou4 ON cou4.id = p2.countryFk
|
||||
LEFT JOIN ticket t ON t.cmrFk = c.id
|
||||
WHERE c.id = ?
|
|
@ -0,0 +1,11 @@
|
|||
SELECT s.ticketFk,
|
||||
ic.name,
|
||||
CAST(SUM(sv.weight) AS DECIMAL(10,2)) `weight`,
|
||||
CAST(SUM(sv.volume) AS DECIMAL(10,3)) volume
|
||||
FROM sale s
|
||||
JOIN saleVolume sv ON sv.saleFk = s.id
|
||||
JOIN item i ON i.id = s.itemFk
|
||||
JOIN itemType it ON it.id = i.typeFk
|
||||
JOIN itemCategory ic ON ic.id = it.categoryFk
|
||||
WHERE sv.ticketFk = ?
|
||||
GROUP BY ic.id
|
|
@ -0,0 +1,5 @@
|
|||
SELECT dc.id `signature`
|
||||
FROM ticket t
|
||||
JOIN ticketDms dt ON dt.ticketFk = t.id
|
||||
LEFT JOIN dms dc ON dc.id = dt.dmsFk
|
||||
WHERE t.id = ?
|
Loading…
Reference in New Issue
"NIF/CIF invalido" podría llevar una tilde: "NIF/CIF inválido".
"Cuidad no puede estar en blanco" tiene un pequeño error tipográfico, debe ser "Ciudad no puede estar en blanco".
"Is invalid" y "is invalid" no se han traducido al español.
"This postal code is not valid" también está en inglés.
"Role already assigned", "Invalid role name", etc. están en inglés y no se han traducido.
"No puedes cambiar los datos basicos de una orden con artículos" podría llevar tilde en "básicos".
"El nombre de usuario solo debe contener letras minúsculas o, a partir del segundo carácter, números o subguiones, no esta permitido el uso de la letra ñ" podría llevar tilde en "está"
"La fecha de inicio debe ser menor que la fecha de fín" sin tilde en "fin".
"Debes especificar una fecha de inicio o de fín" sin tilde en "fin".
[chatgpt]