fixes #5633 Reutilizar accountShortToStandard en un nuevo componente #1541
23
CHANGELOG.md
23
CHANGELOG.md
|
@ -5,18 +5,32 @@ 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/),
|
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).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## [2322.01] - 2023-06-08
|
## [2324.01] - 2023-06-08
|
||||||
|
|
||||||
|
### Added
|
||||||
|
-
|
||||||
|
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
-
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
-
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2322.01] - 2023-06-01
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- (Tickets -> Crear Factura) Al facturar se envia automáticamente el pdf al cliente
|
- (Tickets -> Crear Factura) Al facturar se envia automáticamente el pdf al cliente
|
||||||
|
- (Artículos -> Histórico) Filtro para mostrar lo anterior al inventario
|
||||||
|
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- (Trabajadores -> Nuevo trabajador) Los clientes se crean sin 'TR' pero se añade tipo de negocio 'Trabajador'
|
- (Trabajadores -> Nuevo trabajador) Los clientes se crean sin 'TR' pero se añade tipo de negocio 'Trabajador'
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
-
|
- (Tickets -> Líneas) Se permite hacer split de líneas al mismo ticket
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,10 +53,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
### Added
|
### Added
|
||||||
- (Usuarios -> Histórico) Nueva sección
|
- (Usuarios -> Histórico) Nueva sección
|
||||||
- (Roles -> Histórico) Nueva sección
|
- (Roles -> Histórico) Nueva sección
|
||||||
- (General -> Traducciones) Correo de bienvenida a clientes al portugués y al francés
|
- (Trabajadores -> Dar de alta) Permite elegir el método de pago
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- (Artículo -> Precio fijado) Modificado el buscador superior por uno lateral
|
- (Artículo -> Precio fijado) Modificado el buscador superior por uno lateral
|
||||||
|
- (Trabajadores -> Dar de alta) Quitada obligatoriedad del iban
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- (Ticket -> Boxing) Arreglado selección de horas
|
- (Ticket -> Boxing) Arreglado selección de horas
|
||||||
|
|
|
@ -58,7 +58,10 @@ module.exports = Self => {
|
||||||
for (const param in args)
|
for (const param in args)
|
||||||
params[param] = args[param];
|
params[param] = args[param];
|
||||||
|
|
||||||
if (!recipient) params.recipient = models.Client.findById(recipientId, {fields: ['email']});
|
if (!recipient) {
|
||||||
|
client = await models.Client.findById(recipientId, {fields: ['email']});
|
||||||
|
params.recipient = client.email;
|
||||||
|
}
|
||||||
|
|
||||||
const email = new Email('delivery-note', params);
|
const email = new Email('delivery-note', params);
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ module.exports = Self => {
|
||||||
|
|
||||||
if (!image) return false;
|
if (!image) return false;
|
||||||
|
|
||||||
const hasReadRole = models.ImageCollection.hasReadRole(ctx, collection);
|
const hasReadRole = await models.ImageCollection.hasReadRole(ctx, collection);
|
||||||
if (!hasReadRole)
|
if (!hasReadRole)
|
||||||
throw new UserError(`You don't have enough privileges`);
|
throw new UserError(`You don't have enough privileges`);
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,11 @@ module.exports = Self => {
|
||||||
* @return {boolean} True for user with read privileges
|
* @return {boolean} True for user with read privileges
|
||||||
*/
|
*/
|
||||||
Self.hasReadRole = async(ctx, name, options) => {
|
Self.hasReadRole = async(ctx, name, options) => {
|
||||||
const collection = await Self.findOne({where: {name}}, {
|
const collection = await Self.findOne({
|
||||||
include: {
|
include: {
|
||||||
relation: 'readRole'
|
relation: 'readRole'
|
||||||
}
|
},
|
||||||
|
where: {name}
|
||||||
}, options);
|
}, options);
|
||||||
|
|
||||||
return await hasRole(ctx, collection, options);
|
return await hasRole(ctx, collection, options);
|
||||||
|
|
|
@ -27,7 +27,6 @@ INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalTyp
|
||||||
('Client', 'summary', '*', 'ALLOW', 'ROLE', 'employee'),
|
('Client', 'summary', '*', 'ALLOW', 'ROLE', 'employee'),
|
||||||
('Client', 'updateAddress', '*', 'ALLOW', 'ROLE', 'employee'),
|
('Client', 'updateAddress', '*', 'ALLOW', 'ROLE', 'employee'),
|
||||||
('Client', 'updateFiscalData', '*', 'ALLOW', 'ROLE', 'employee'),
|
('Client', 'updateFiscalData', '*', 'ALLOW', 'ROLE', 'employee'),
|
||||||
('Client', 'updateUser', '*', 'ALLOW', 'ROLE', 'employee'),
|
|
||||||
('Client', 'uploadFile', '*', 'ALLOW', 'ROLE', 'employee'),
|
('Client', 'uploadFile', '*', 'ALLOW', 'ROLE', 'employee'),
|
||||||
('Client', 'campaignMetricsPdf', '*', 'ALLOW', 'ROLE', 'employee'),
|
('Client', 'campaignMetricsPdf', '*', 'ALLOW', 'ROLE', 'employee'),
|
||||||
('Client', 'campaignMetricsEmail', '*', 'ALLOW', 'ROLE', 'employee'),
|
('Client', 'campaignMetricsEmail', '*', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
-- vn.defaulter source
|
||||||
|
|
||||||
|
CREATE OR REPLACE
|
||||||
|
ALGORITHM = UNDEFINED VIEW `vn`.`defaulter` AS
|
||||||
|
select
|
||||||
|
`d`.`clientFk` AS `clientFk`,
|
||||||
|
`d`.`created` AS `created`,
|
||||||
|
`d`.`amount` AS `amount`,
|
||||||
|
`d`.`defaulterSinced` AS `defaulterSinced`,
|
||||||
|
`d`.`hasChanged` AS `hasChanged`,
|
||||||
|
`c`.`countryFk` AS `country`,
|
||||||
|
`c`.`payMethodFk` AS `payMethod`
|
||||||
|
from
|
||||||
|
(((`bs`.`defaulter` `d`
|
||||||
|
join `vn`.`client` `c` on
|
||||||
|
(`c`.`id` = `d`.`clientFk`))
|
||||||
|
join `vn`.`country` `co` on
|
||||||
|
(`co`.`id` = `c`.`countryFk`))
|
||||||
|
join `vn`.`payMethod` `pm` on
|
||||||
|
(`pm`.`id` = `c`.`payMethodFk`));
|
|
@ -0,0 +1,7 @@
|
||||||
|
ALTER TABLE `vn`.`workerConfig` ADD payMethodFk tinyint(3) unsigned NULL;
|
||||||
|
ALTER TABLE `vn`.`workerConfig` ADD CONSTRAINT workerConfig_FK FOREIGN KEY (roleFk) REFERENCES account.`role`(id) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
ALTER TABLE `vn`.`workerConfig` ADD CONSTRAINT workerConfig_FK_1 FOREIGN KEY (payMethodFk) REFERENCES `vn`.`payMethod`(id) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
-- Cuando se apruebe el PR quitar y poner en redmine para hacerse manualmente
|
||||||
|
UPDATE `vn`.`workerConfig`
|
||||||
|
SET payMethodFk = 4
|
||||||
|
WHERE id=1;
|
|
@ -0,0 +1,121 @@
|
||||||
|
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||||
|
VALUES
|
||||||
|
('Ticket', 'editDiscount', 'WRITE', 'ALLOW', 'ROLE', 'claimManager'),
|
||||||
|
('Ticket', 'editDiscount', 'WRITE', 'ALLOW', 'ROLE', 'salesPerson'),
|
||||||
|
('Ticket', 'isRoleAdvanced', '*', 'ALLOW', 'ROLE', 'salesAssistant'),
|
||||||
|
('Ticket', 'isRoleAdvanced', '*', 'ALLOW', 'ROLE', 'deliveryBoss'),
|
||||||
|
('Ticket', 'isRoleAdvanced', '*', 'ALLOW', 'ROLE', 'buyer'),
|
||||||
|
('Ticket', 'isRoleAdvanced', '*', 'ALLOW', 'ROLE', 'claimManager'),
|
||||||
|
('Ticket', 'deleteTicketWithPartPrepared', 'WRITE', 'ALLOW', 'ROLE', 'salesAssistant'),
|
||||||
|
('Ticket', 'editZone', 'WRITE', 'ALLOW', 'ROLE', 'deliveryBoss'),
|
||||||
|
('State', 'editableStates', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('State', 'seeEditableStates', 'READ', 'ALLOW', 'ROLE', 'administrative'),
|
||||||
|
('State', 'seeEditableStates', 'READ', 'ALLOW', 'ROLE', 'production'),
|
||||||
|
('State', 'isSomeEditable', 'READ', 'ALLOW', 'ROLE', 'salesPerson'),
|
||||||
|
('State', 'isAllEditable', 'READ', 'ALLOW', 'ROLE', 'production'),
|
||||||
|
('State', 'isAllEditable', 'READ', 'ALLOW', 'ROLE', 'administrative'),
|
||||||
|
('Agency', 'seeExpired', 'READ', 'ALLOW', 'ROLE', 'administrative'),
|
||||||
|
('Agency', 'seeExpired', 'READ', 'ALLOW', 'ROLE', 'productionBoss'),
|
||||||
|
('Claim', 'createAfterDeadline', 'WRITE', 'ALLOW', 'ROLE', 'claimManager'),
|
||||||
|
('Client', 'editAddressLogifloraAllowed', 'WRITE', 'ALLOW', 'ROLE', 'salesAssistant'),
|
||||||
|
('Client', 'editFiscalDataWithoutTaxDataCheck', 'WRITE', 'ALLOW', 'ROLE', 'salesAssistant'),
|
||||||
|
('Client', 'editVerifiedDataWithoutTaxDataCheck', 'WRITE', 'ALLOW', 'ROLE', 'salesAssistant'),
|
||||||
|
('Client', 'editCredit', 'WRITE', 'ALLOW', 'ROLE', 'financialBoss'),
|
||||||
|
('Client', 'isNotEditableCredit', 'WRITE', 'ALLOW', 'ROLE', 'financialBoss'),
|
||||||
|
('InvoiceOut', 'canCreatePdf', 'WRITE', 'ALLOW', 'ROLE', 'invoicing'),
|
||||||
|
('Supplier', 'editPayMethodCheck', 'WRITE', 'ALLOW', 'ROLE', 'financial'),
|
||||||
|
('Worker', 'isTeamBoss', 'WRITE', 'ALLOW', 'ROLE', 'teamBoss'),
|
||||||
|
('Worker', 'forceIsSubordinate', 'READ', 'ALLOW', 'ROLE', 'hr'),
|
||||||
|
('Claim', 'editState', 'WRITE', 'ALLOW', 'ROLE', 'claimManager');
|
||||||
|
|
||||||
|
DELETE FROM `salix`.`ACL`
|
||||||
|
WHERE
|
||||||
|
model = 'Claim'
|
||||||
|
AND property = '*'
|
||||||
|
AND accessType = '*';
|
||||||
|
|
||||||
|
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||||
|
VALUES
|
||||||
|
('Claim', 'find', 'READ', 'ALLOW', 'ROLE', 'salesPerson'),
|
||||||
|
('Claim', 'findById', 'READ', 'ALLOW', 'ROLE', 'salesPerson'),
|
||||||
|
('Claim', 'findOne', 'READ', 'ALLOW', 'ROLE', 'salesPerson'),
|
||||||
|
('Claim', 'getSummary', 'READ', 'ALLOW', 'ROLE', 'salesPerson'),
|
||||||
|
('Claim', 'updateClaim', 'WRITE', 'ALLOW', 'ROLE', 'salesPerson'),
|
||||||
|
('Claim', 'regularizeClaim', 'WRITE', 'ALLOW', 'ROLE', 'claimManager'),
|
||||||
|
('Claim', 'updateClaimDestination', 'WRITE', 'ALLOW', 'ROLE', 'claimManager'),
|
||||||
|
('Claim', 'downloadFile', 'READ', 'ALLOW', 'ROLE', 'claimManager'),
|
||||||
|
('Claim', 'deleteById', 'WRITE', 'ALLOW', 'ROLE', 'claimManager'),
|
||||||
|
('Claim', 'filter', 'READ', 'ALLOW', 'ROLE', 'salesPerson'),
|
||||||
|
('Claim', 'logs', 'READ', 'ALLOW', 'ROLE', 'claimManager');
|
||||||
|
|
||||||
|
DELETE FROM `salix`.`ACL`
|
||||||
|
WHERE
|
||||||
|
model = 'Ticket'
|
||||||
|
AND property = '*'
|
||||||
|
AND accessType = '*';
|
||||||
|
|
||||||
|
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||||
|
VALUES
|
||||||
|
('Ticket', 'find', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Ticket', 'findById', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Ticket', 'findOne', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Ticket', 'getVolume', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Ticket', 'getTotalVolume', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Ticket', 'summary', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Ticket', 'priceDifference', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Ticket', 'componentUpdate', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Ticket', 'new', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Ticket', 'isEditable', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Ticket', 'setDeleted', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Ticket', 'restore', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Ticket', 'getSales', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Ticket', 'getSalesPersonMana', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Ticket', 'filter', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Ticket', 'makeInvoice', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Ticket', 'updateEditableTicket', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Ticket', 'updateDiscount', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Ticket', 'transferSales', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Ticket', 'sendSms', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Ticket', 'isLocked', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Ticket', 'freightCost', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Ticket', 'getComponentsSum', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Ticket', 'updateAttributes', 'WRITE', 'ALLOW', 'ROLE', 'delivery'), -- Change Priority in Route tickets
|
||||||
|
('Ticket', 'deliveryNoteCsv', 'READ', 'ALLOW', 'ROLE', 'employee');
|
||||||
|
|
||||||
|
DELETE FROM `salix`.`ACL`
|
||||||
|
WHERE
|
||||||
|
model = 'State'
|
||||||
|
AND property = '*'
|
||||||
|
AND accessType = 'READ';
|
||||||
|
|
||||||
|
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||||
|
VALUES
|
||||||
|
('State', 'find', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('State', 'findById', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('State', 'findOne', 'READ', 'ALLOW', 'ROLE', 'employee');
|
||||||
|
|
||||||
|
DELETE FROM `salix`.`ACL`
|
||||||
|
WHERE
|
||||||
|
model = 'Worker'
|
||||||
|
AND property = '*'
|
||||||
|
AND accessType = 'READ';
|
||||||
|
|
||||||
|
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||||
|
VALUES
|
||||||
|
('Worker', 'find', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Worker', 'findById', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Worker', 'findOne', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Worker', 'filter', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Worker', 'getWorkedHours', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Worker', 'active', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Worker', 'activeWithRole', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Worker', 'uploadFile', 'WRITE', 'ALLOW', 'ROLE', 'hr'),
|
||||||
|
('Worker', 'contracts', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Worker', 'holidays', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Worker', 'activeContract', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Worker', 'activeWithInheritedRole', 'READ', 'ALLOW', 'ROLE', 'employee');
|
||||||
|
|
||||||
|
DELETE FROM `salix`.`ACL`
|
||||||
|
WHERE model = 'Client'
|
||||||
|
AND property = 'updateUser'
|
||||||
|
AND accessType = '*';
|
|
@ -2332,26 +2332,26 @@ INSERT INTO `vn`.`workerTimeControl`(`userFk`, `timed`, `manual`, `direction`, `
|
||||||
|
|
||||||
INSERT INTO `vn`.`dmsType`(`id`, `name`, `path`, `readRoleFk`, `writeRoleFk`, `code`)
|
INSERT INTO `vn`.`dmsType`(`id`, `name`, `path`, `readRoleFk`, `writeRoleFk`, `code`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 'Facturas Recibidas', 'recibidas', NULL, NULL, 'invoiceIn'),
|
(1, 'Facturas Recibidas', 'recibidas', NULL, NULL, 'invoiceIn'),
|
||||||
(2, 'Doc oficial', 'oficial', NULL, NULL, 'officialDoc'),
|
(2, 'Doc oficial', 'oficial', NULL, NULL, 'officialDoc'),
|
||||||
(3, 'Laboral', 'laboral', 37, 37, 'hhrrData'),
|
(3, 'Laboral', 'laboral', 37, 37, 'hhrrData'),
|
||||||
(4, 'Albaranes recibidos', 'entradas', NULL, NULL, 'deliveryNote'),
|
(4, 'Albaranes recibidos', 'entradas', NULL, NULL, 'deliveryNote'),
|
||||||
(5, 'Otros', 'otros', 1, 1, 'miscellaneous'),
|
(5, 'Otros', 'otros', 1, 1, 'miscellaneous'),
|
||||||
(6, 'Pruebas', 'pruebas', NULL, NULL, 'tests'),
|
(6, 'Pruebas', 'pruebas', NULL, NULL, 'tests'),
|
||||||
(7, 'IAE Clientes', 'IAE_Clientes', 1, 1, 'economicActivitiesTax'),
|
(7, 'IAE Clientes', 'IAE_Clientes', 1, 1, 'economicActivitiesTax'),
|
||||||
(8, 'Fiscal', 'fiscal', NULL, NULL, 'fiscal'),
|
(8, 'Fiscal', 'fiscal', NULL, NULL, 'fiscal'),
|
||||||
(9, 'Vehiculos', 'vehiculos', NULL, NULL, 'vehicles'),
|
(9, 'Vehiculos', 'vehiculos', NULL, NULL, 'vehicles'),
|
||||||
(10, 'Plantillas', 'plantillas', NULL, NULL, 'templates'),
|
(10, 'Plantillas', 'plantillas', NULL, NULL, 'templates'),
|
||||||
(11, 'Contratos', 'contratos', NULL, NULL, 'contracts'),
|
(11, 'Contratos', 'contratos', NULL, NULL, 'contracts'),
|
||||||
(12, 'ley de pagos', 'ley pagos', 1, 1, 'paymentsLaw'),
|
(12, 'ley de pagos', 'ley pagos', 1, 1, 'paymentsLaw'),
|
||||||
(13, 'Basura', 'basura', 1, 1, 'trash'),
|
(13, 'Basura', 'basura', 1, 1, 'trash'),
|
||||||
(14, 'Ticket', 'tickets', 1, 1, 'ticket'),
|
(14, 'Ticket', 'tickets', 1, 1, 'ticket'),
|
||||||
(15, 'Presupuestos', 'Presupuestos', NULL, NULL, 'budgets'),
|
(15, 'Presupuestos', 'Presupuestos', NULL, NULL, 'budgets'),
|
||||||
(16, 'Logistica', 'logistica', NULL, NULL, 'logistics'),
|
(16, 'Logistica', 'logistica', NULL, NULL, 'logistics'),
|
||||||
(17, 'cmr', 'cmr', NULL, NULL, 'cmr'),
|
(17, 'cmr', 'cmr', NULL, NULL, 'cmr'),
|
||||||
(18, 'dua', 'dua', NULL, NULL, 'dua'),
|
(18, 'dua', 'dua', NULL, NULL, 'dua'),
|
||||||
(19, 'inmovilizado', 'inmovilizado', NULL, NULL, 'fixedAssets'),
|
(19, 'inmovilizado', 'inmovilizado', NULL, NULL, 'fixedAssets'),
|
||||||
(20, 'Reclamación', 'reclamacion', 1, 1, 'claim');
|
(20, 'Reclamación', 'reclamacion', 1, 1, 'claim');
|
||||||
|
|
||||||
INSERT INTO `vn`.`dms`(`id`, `dmsTypeFk`, `file`, `contentType`, `workerFk`, `warehouseFk`, `companyFk`, `hardCopyNumber`, `hasFile`, `reference`, `description`, `created`)
|
INSERT INTO `vn`.`dms`(`id`, `dmsTypeFk`, `file`, `contentType`, `workerFk`, `warehouseFk`, `companyFk`, `hardCopyNumber`, `hasFile`, `reference`, `description`, `created`)
|
||||||
VALUES
|
VALUES
|
||||||
|
@ -2824,9 +2824,9 @@ INSERT INTO `vn`.`payDemDetail` (`id`, `detail`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 1);
|
(1, 1);
|
||||||
|
|
||||||
INSERT INTO `vn`.`workerConfig` (`id`, `businessUpdated`, `roleFk`, `businessTypeFk`)
|
INSERT INTO `vn`.`workerConfig` (`id`, `businessUpdated`, `roleFk`, `payMethodFk`, `businessTypeFk`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, NULL, 1, 'worker');
|
(1, NULL, 1, 4, 'worker');
|
||||||
|
|
||||||
INSERT INTO `vn`.`ticketRefund`(`refundTicketFk`, `originalTicketFk`)
|
INSERT INTO `vn`.`ticketRefund`(`refundTicketFk`, `originalTicketFk`)
|
||||||
VALUES
|
VALUES
|
||||||
|
|
|
@ -61943,141 +61943,205 @@ DELIMITER ;
|
||||||
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
|
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
|
||||||
/*!50003 SET sql_mode = 'IGNORE_SPACE,NO_ENGINE_SUBSTITUTION' */ ;
|
/*!50003 SET sql_mode = 'IGNORE_SPACE,NO_ENGINE_SUBSTITUTION' */ ;
|
||||||
DELIMITER ;;
|
DELIMITER ;;
|
||||||
CREATE DEFINER=`root`@`localhost` PROCEDURE `item_getBalance`(IN vItemId int, IN vWarehouse int)
|
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`item_getBalance`(vItemFk int, vWarehouseFk int, vDate DATETIME)
|
||||||
BEGIN
|
BEGIN
|
||||||
DECLARE vDateInventory DATETIME;
|
/**
|
||||||
DECLARE vCurdate DATE DEFAULT util.VN_CURDATE();
|
* @vItemFk item a buscar
|
||||||
DECLARE vDayEnd DATETIME DEFAULT util.dayEnd(vCurdate);
|
* @vWarehouseFk almacen donde buscar
|
||||||
|
* @vDate Si la fecha es null, muestra el histórico desde el inventario. Si la fecha no es null, muestra histórico desde la fecha pasada.
|
||||||
|
*/
|
||||||
|
|
||||||
SELECT inventoried INTO vDateInventory FROM config;
|
DECLARE vDateInventory DATETIME;
|
||||||
SET @a = 0;
|
DECLARE vInvCalculated INT;
|
||||||
SET @currentLineFk = 0;
|
|
||||||
SET @shipped = '';
|
|
||||||
|
|
||||||
SELECT DATE(@shipped:= shipped) shipped,
|
IF vDate IS NULL THEN
|
||||||
alertLevel,
|
SELECT inventoried INTO vDateInventory
|
||||||
stateName,
|
FROM config;
|
||||||
origin,
|
ELSE
|
||||||
reference,
|
SELECT mockUtcTime INTO vDateInventory
|
||||||
clientFk,
|
FROM util.config;
|
||||||
name,
|
END IF;
|
||||||
`in` AS invalue,
|
|
||||||
`out`,
|
|
||||||
@a := @a + IFNULL(`in`,0) - IFNULL(`out`,0) as balance,
|
|
||||||
@currentLineFk := IF (@shipped < util.VN_CURDATE()
|
|
||||||
OR (@shipped = util.VN_CURDATE() AND (isPicked OR alertLevel >= 2)),
|
|
||||||
lineFk,@currentLineFk) lastPreparedLineFk,
|
|
||||||
isTicket,
|
|
||||||
lineFk,
|
|
||||||
isPicked,
|
|
||||||
clientType,
|
|
||||||
claimFk
|
|
||||||
FROM
|
|
||||||
( SELECT tr.landed AS shipped,
|
|
||||||
b.quantity AS `in`,
|
|
||||||
NULL AS `out`,
|
|
||||||
al.id AS alertLevel,
|
|
||||||
st.name AS stateName,
|
|
||||||
s.name AS name,
|
|
||||||
e.invoiceNumber AS reference,
|
|
||||||
e.id AS origin,
|
|
||||||
s.id AS clientFk,
|
|
||||||
IF(al.id = 3, TRUE, FALSE) isPicked,
|
|
||||||
FALSE AS isTicket,
|
|
||||||
b.id lineFk,
|
|
||||||
NULL `order`,
|
|
||||||
NULL AS clientType,
|
|
||||||
NULL AS claimFk
|
|
||||||
FROM buy b
|
|
||||||
JOIN entry e ON e.id = b.entryFk
|
|
||||||
JOIN travel tr ON tr.id = e.travelFk
|
|
||||||
JOIN supplier s ON s.id = e.supplierFk
|
|
||||||
JOIN alertLevel al ON al.id =
|
|
||||||
CASE
|
|
||||||
WHEN tr.landed < util.VN_CURDATE() THEN 3
|
|
||||||
WHEN tr.landed = util.VN_CURDATE() AND tr.isReceived = TRUE THEN 3
|
|
||||||
ELSE 0
|
|
||||||
END
|
|
||||||
JOIN state st ON st.code = al.code
|
|
||||||
WHERE tr.landed >= vDateInventory
|
|
||||||
AND vWarehouse = tr.warehouseInFk
|
|
||||||
AND b.itemFk = vItemId
|
|
||||||
AND e.isExcludedFromAvailable = FALSE
|
|
||||||
AND e.isRaid = FALSE
|
|
||||||
UNION ALL
|
|
||||||
|
|
||||||
SELECT tr.shipped,
|
CREATE OR REPLACE TEMPORARY TABLE itemDiary(
|
||||||
NULL,
|
shipped DATE,
|
||||||
b.quantity,
|
`in` INT(11),
|
||||||
al.id,
|
`out` INT(11),
|
||||||
st.name,
|
alertLevel INT(11),
|
||||||
s.name,
|
stateName VARCHAR(20),
|
||||||
e.invoiceNumber,
|
`name` VARCHAR(50),
|
||||||
e.id,
|
reference VARCHAR(50),
|
||||||
s.id,
|
origin INT(11),
|
||||||
IF(al.id = 3, TRUE, FALSE),
|
clientFk INT(11),
|
||||||
FALSE,
|
isPicked INT(11),
|
||||||
b.id,
|
isTicket TINYINT(1),
|
||||||
NULL,
|
lineFk INT(11),
|
||||||
NULL,
|
`order` TINYINT(3) UNSIGNED,
|
||||||
NULL
|
clientType VARCHAR(20),
|
||||||
FROM buy b
|
claimFk INT(10) UNSIGNED
|
||||||
JOIN entry e ON e.id = b.entryFk
|
);
|
||||||
JOIN travel tr ON tr.id = e.travelFk
|
|
||||||
JOIN warehouse w ON w.id = tr.warehouseOutFk
|
|
||||||
JOIN supplier s ON s.id = e.supplierFk
|
|
||||||
JOIN alertLevel al ON al.id =
|
|
||||||
CASE
|
|
||||||
WHEN tr.shipped < util.VN_CURDATE() THEN 3
|
|
||||||
WHEN tr.shipped = util.VN_CURDATE() AND tr.isReceived = TRUE THEN 3
|
|
||||||
ELSE 0
|
|
||||||
END
|
|
||||||
JOIN state st ON st.code = al.code
|
|
||||||
WHERE tr.shipped >= vDateInventory
|
|
||||||
AND vWarehouse =tr.warehouseOutFk
|
|
||||||
AND s.id <> 4
|
|
||||||
AND b.itemFk = vItemId
|
|
||||||
AND e.isExcludedFromAvailable = FALSE
|
|
||||||
AND w.isFeedStock = FALSE
|
|
||||||
AND e.isRaid = FALSE
|
|
||||||
UNION ALL
|
|
||||||
|
|
||||||
SELECT DATE(t.shipped),
|
INSERT INTO itemDiary
|
||||||
NULL,
|
SELECT tr.landed shipped,
|
||||||
s.quantity,
|
b.quantity `in`,
|
||||||
al.id,
|
NULL `out`,
|
||||||
st.name,
|
al.id alertLevel,
|
||||||
t.nickname,
|
st.name stateName,
|
||||||
t.refFk,
|
s.name `name`,
|
||||||
t.id,
|
e.invoiceNumber reference,
|
||||||
t.clientFk,
|
e.id origin,
|
||||||
stk.id,
|
s.id clientFk,
|
||||||
TRUE,
|
IF(al.code = 'DELIVERED', TRUE, FALSE) isPicked,
|
||||||
s.id,
|
FALSE isTicket,
|
||||||
st.`order`,
|
b.id lineFk,
|
||||||
ct.code,
|
NULL `order`,
|
||||||
cb.claimFk
|
NULL clientType,
|
||||||
FROM sale s
|
NULL claimFk
|
||||||
JOIN ticket t ON t.id = s.ticketFk
|
FROM buy b
|
||||||
LEFT JOIN ticketState ts ON ts.ticket = t.id
|
JOIN entry e ON e.id = b.entryFk
|
||||||
LEFT JOIN state st ON st.code = ts.code
|
JOIN travel tr ON tr.id = e.travelFk
|
||||||
JOIN client c ON c.id = t.clientFk
|
JOIN supplier s ON s.id = e.supplierFk
|
||||||
JOIN clientType ct ON ct.id = c.clientTypeFk
|
JOIN alertLevel al ON al.code =
|
||||||
JOIN alertLevel al ON al.id =
|
CASE
|
||||||
CASE
|
WHEN tr.landed < util.VN_CURDATE() THEN 'DELIVERED'
|
||||||
WHEN t.shipped < util.VN_CURDATE() THEN 3
|
WHEN tr.landed = util.VN_CURDATE() AND tr.isReceived = TRUE THEN 'DELIVERED'
|
||||||
WHEN t.shipped > util.dayEnd(util.VN_CURDATE()) THEN 0
|
ELSE 'FREE'
|
||||||
ELSE IFNULL(ts.alertLevel, 0)
|
END
|
||||||
END
|
JOIN state st ON st.code = al.code
|
||||||
LEFT JOIN state stPrep ON stPrep.`code` = 'PREPARED'
|
WHERE tr.landed >= vDateInventory
|
||||||
LEFT JOIN saleTracking stk ON stk.saleFk = s.id AND stk.stateFk = stPrep.id
|
AND vWarehouseFk = tr.warehouseInFk
|
||||||
LEFT JOIN claimBeginning cb ON s.id = cb.saleFk
|
AND b.itemFk = vItemFk
|
||||||
WHERE t.shipped >= vDateInventory
|
AND e.isExcludedFromAvailable = FALSE
|
||||||
AND s.itemFk = vItemId
|
AND e.isRaid = FALSE
|
||||||
AND vWarehouse =t.warehouseFk
|
UNION ALL
|
||||||
ORDER BY shipped, alertLevel DESC, isTicket, `order` DESC, isPicked DESC, `in` DESC, `out` DESC
|
SELECT tr.shipped,
|
||||||
) AS itemDiary;
|
NULL,
|
||||||
|
b.quantity,
|
||||||
|
al.id,
|
||||||
|
st.name,
|
||||||
|
s.name,
|
||||||
|
e.invoiceNumber,
|
||||||
|
e.id,
|
||||||
|
s.id,
|
||||||
|
IF(al.code = 'DELIVERED', TRUE, FALSE),
|
||||||
|
FALSE,
|
||||||
|
b.id,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
FROM buy b
|
||||||
|
JOIN entry e ON e.id = b.entryFk
|
||||||
|
JOIN travel tr ON tr.id = e.travelFk
|
||||||
|
JOIN warehouse w ON w.id = tr.warehouseOutFk
|
||||||
|
JOIN supplier s ON s.id = e.supplierFk
|
||||||
|
JOIN alertLevel al ON al.code =
|
||||||
|
CASE
|
||||||
|
WHEN tr.shipped < util.VN_CURDATE() THEN 'DELIVERED'
|
||||||
|
WHEN tr.shipped = util.VN_CURDATE() AND tr.isReceived = TRUE THEN 'DELIVERED'
|
||||||
|
ELSE 'FREE'
|
||||||
|
END
|
||||||
|
JOIN state st ON st.code = al.code
|
||||||
|
JOIN entryConfig ec
|
||||||
|
WHERE tr.shipped >= vDateInventory
|
||||||
|
AND vWarehouseFk =tr.warehouseOutFk
|
||||||
|
AND s.id <> ec.inventorySupplierFk
|
||||||
|
AND b.itemFk = vItemFk
|
||||||
|
AND e.isExcludedFromAvailable = FALSE
|
||||||
|
AND w.isFeedStock = FALSE
|
||||||
|
AND e.isRaid = FALSE
|
||||||
|
UNION ALL
|
||||||
|
SELECT DATE(t.shipped),
|
||||||
|
NULL,
|
||||||
|
s.quantity,
|
||||||
|
al3.id,
|
||||||
|
st.name,
|
||||||
|
t.nickname,
|
||||||
|
t.refFk,
|
||||||
|
t.id,
|
||||||
|
t.clientFk,
|
||||||
|
stk.id,
|
||||||
|
TRUE,
|
||||||
|
s.id,
|
||||||
|
st.`order`,
|
||||||
|
ct.code,
|
||||||
|
cb.claimFk
|
||||||
|
FROM sale s
|
||||||
|
JOIN ticket t ON t.id = s.ticketFk
|
||||||
|
LEFT JOIN ticketState ts ON ts.ticket = t.id
|
||||||
|
LEFT JOIN state st ON st.code = ts.code
|
||||||
|
JOIN client c ON c.id = t.clientFk
|
||||||
|
JOIN clientType ct ON ct.id = c.clientTypeFk
|
||||||
|
JOIN alertLevel al ON al.code = 'DELIVERED'
|
||||||
|
JOIN alertLevel al2 ON al2.code = 'FREE'
|
||||||
|
JOIN alertLevel al3 ON al3.id =
|
||||||
|
CASE
|
||||||
|
WHEN t.shipped < util.VN_CURDATE() THEN al.code
|
||||||
|
WHEN t.shipped > util.dayEnd(util.VN_CURDATE()) THEN al2.code
|
||||||
|
ELSE IFNULL(ts.alertLevel, al2.code)
|
||||||
|
END
|
||||||
|
LEFT JOIN state stPrep ON stPrep.`code` = 'PREPARED'
|
||||||
|
LEFT JOIN saleTracking stk ON stk.saleFk = s.id AND stk.stateFk = stPrep.id
|
||||||
|
LEFT JOIN claimBeginning cb ON s.id = cb.saleFk
|
||||||
|
WHERE t.shipped >= vDateInventory
|
||||||
|
AND s.itemFk = vItemFk
|
||||||
|
AND vWarehouseFk =t.warehouseFk
|
||||||
|
ORDER BY shipped, alertLevel DESC, isTicket, `order` DESC, isPicked DESC, `in` DESC, `out` DESC;
|
||||||
|
|
||||||
|
IF vDate IS NULL THEN
|
||||||
|
SET @a = 0;
|
||||||
|
SET @currentLineFk = 0;
|
||||||
|
SET @shipped = '';
|
||||||
|
|
||||||
|
SELECT DATE(@shipped:= shipped) shipped,
|
||||||
|
alertLevel,
|
||||||
|
stateName,
|
||||||
|
origin,
|
||||||
|
reference,
|
||||||
|
clientFk,
|
||||||
|
name,
|
||||||
|
`in` AS invalue,
|
||||||
|
`out`,
|
||||||
|
@a := @a + IFNULL(`in`,0) - IFNULL(`out`,0) as balance,
|
||||||
|
@currentLineFk := IF (@shipped < util.VN_CURDATE()
|
||||||
|
OR (@shipped = util.VN_CURDATE() AND (isPicked OR a.code >= 'ON_PREPARATION')),
|
||||||
|
lineFk, @currentLineFk) lastPreparedLineFk,
|
||||||
|
isTicket,
|
||||||
|
lineFk,
|
||||||
|
isPicked,
|
||||||
|
clientType,
|
||||||
|
claimFk
|
||||||
|
FROM itemDiary
|
||||||
|
JOIN alertLevel a ON a.id = itemDiary.alertLevel;
|
||||||
|
ELSE
|
||||||
|
SELECT sum(`in`) - sum(`out`) INTO vInvCalculated
|
||||||
|
FROM itemDiary
|
||||||
|
WHERE shipped < vDate;
|
||||||
|
|
||||||
|
SELECT p1.*
|
||||||
|
FROM(
|
||||||
|
SELECT vDate shipped,
|
||||||
|
0 alertLevel,
|
||||||
|
0 stateName,
|
||||||
|
0 origin,
|
||||||
|
'' reference,
|
||||||
|
0 clientFk,
|
||||||
|
'Inventario calculado',
|
||||||
|
vInvCalculated invalue,
|
||||||
|
NULL `out`,
|
||||||
|
0 balance,
|
||||||
|
0 lastPreparedLineFk,
|
||||||
|
0 isTicket,
|
||||||
|
0 lineFk,
|
||||||
|
0 isPicked,
|
||||||
|
0 clientType,
|
||||||
|
0 claimFk
|
||||||
|
UNION ALL
|
||||||
|
SELECT shipped, alertlevel, stateName, origin, reference, clientFk, name, `in`, `out`, 0,0, isTicket, lineFk, isPicked, clientType, claimFk
|
||||||
|
FROM itemDiary
|
||||||
|
WHERE shipped >= vDate
|
||||||
|
)as p1;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE itemDiary;
|
||||||
END ;;
|
END ;;
|
||||||
DELIMITER ;
|
DELIMITER ;
|
||||||
/*!50003 SET sql_mode = @saved_sql_mode */ ;
|
/*!50003 SET sql_mode = @saved_sql_mode */ ;
|
||||||
|
|
|
@ -313,7 +313,7 @@ export default {
|
||||||
anyClient: 'vn-client-defaulter tbody > tr',
|
anyClient: 'vn-client-defaulter tbody > tr',
|
||||||
firstClientName: 'vn-client-defaulter tbody > tr:nth-child(1) > td:nth-child(2) > span',
|
firstClientName: 'vn-client-defaulter tbody > tr:nth-child(1) > td:nth-child(2) > span',
|
||||||
firstSalesPersonName: 'vn-client-defaulter tbody > tr:nth-child(1) > td:nth-child(3) > span',
|
firstSalesPersonName: 'vn-client-defaulter tbody > tr:nth-child(1) > td:nth-child(3) > span',
|
||||||
firstObservation: 'vn-client-defaulter tbody > tr:nth-child(1) > td:nth-child(6) > vn-textarea[ng-model="defaulter.observation"]',
|
firstObservation: 'vn-client-defaulter tbody > tr:nth-child(1) > td:nth-child(8) > vn-textarea[ng-model="defaulter.observation"]',
|
||||||
allDefaulterCheckbox: 'vn-client-defaulter thead vn-multi-check',
|
allDefaulterCheckbox: 'vn-client-defaulter thead vn-multi-check',
|
||||||
addObservationButton: 'vn-client-defaulter vn-button[icon="icon-notes"]',
|
addObservationButton: 'vn-client-defaulter vn-button[icon="icon-notes"]',
|
||||||
observation: '.vn-dialog.shown vn-textarea[ng-model="$ctrl.defaulter.observation"]',
|
observation: '.vn-dialog.shown vn-textarea[ng-model="$ctrl.defaulter.observation"]',
|
||||||
|
|
|
@ -17,7 +17,7 @@ describe('Claim summary path', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should navigate to the target claim summary section', async() => {
|
it('should navigate to the target claim summary section', async() => {
|
||||||
await page.loginAndModule('employee', 'claim');
|
await page.loginAndModule('salesPerson', 'claim');
|
||||||
await page.accessToSearchResult(claimId);
|
await page.accessToSearchResult(claimId);
|
||||||
await page.waitForState('claim.card.summary');
|
await page.waitForState('claim.card.summary');
|
||||||
});
|
});
|
||||||
|
|
|
@ -16,7 +16,7 @@ describe('Claim descriptor path', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should now navigate to the target claim summary section', async() => {
|
it('should now navigate to the target claim summary section', async() => {
|
||||||
await page.loginAndModule('employee', 'claim');
|
await page.loginAndModule('salesPerson', 'claim');
|
||||||
await page.accessToSearchResult(claimId);
|
await page.accessToSearchResult(claimId);
|
||||||
await page.waitForState('claim.card.summary');
|
await page.waitForState('claim.card.summary');
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,20 @@
|
||||||
import getBrowser from '../../helpers/puppeteer';
|
import getBrowser from '../../helpers/puppeteer';
|
||||||
|
|
||||||
|
const $ = {
|
||||||
|
saveButton: 'vn-supplier-fiscal-data button[type="submit"]',
|
||||||
|
};
|
||||||
|
const $inputs = {
|
||||||
|
province: 'vn-supplier-fiscal-data [name="province"]',
|
||||||
|
country: 'vn-supplier-fiscal-data [name="country"]',
|
||||||
|
postcode: 'vn-supplier-fiscal-data [name="postcode"]',
|
||||||
|
city: 'vn-supplier-fiscal-data [name="city"]',
|
||||||
|
socialName: 'vn-supplier-fiscal-data [name="socialName"]',
|
||||||
|
taxNumber: 'vn-supplier-fiscal-data [name="taxNumber"]',
|
||||||
|
account: 'vn-supplier-fiscal-data [name="account"]',
|
||||||
|
sageWithholding: 'vn-supplier-fiscal-data [ng-model="$ctrl.supplier.sageWithholdingFk"]',
|
||||||
|
sageTaxType: 'vn-supplier-fiscal-data [ng-model="$ctrl.supplier.sageTaxTypeFk"]'
|
||||||
|
};
|
||||||
|
|
||||||
describe('Supplier fiscal data path', () => {
|
describe('Supplier fiscal data path', () => {
|
||||||
let browser;
|
let browser;
|
||||||
let page;
|
let page;
|
||||||
|
|
|
@ -203,7 +203,7 @@ export default class Searchbar extends Component {
|
||||||
|
|
||||||
doSearch(filter, source) {
|
doSearch(filter, source) {
|
||||||
if (filter === this.filter && !this.isIndex) return;
|
if (filter === this.filter && !this.isIndex) return;
|
||||||
let promise = this.onSearch({$params: filter});
|
let promise = this.onSearch({$params: filter}, source);
|
||||||
promise = promise || this.$q.resolve();
|
promise = promise || this.$q.resolve();
|
||||||
promise.then(data => this.onFilter(filter, source, data));
|
promise.then(data => this.onFilter(filter, source, data));
|
||||||
this.toBar(filter);
|
this.toBar(filter);
|
||||||
|
@ -259,12 +259,6 @@ export default class Searchbar extends Component {
|
||||||
|
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
|
|
||||||
if (source == 'removeBar') {
|
|
||||||
delete params[this.toRemove];
|
|
||||||
delete this.model.userParams[this.toRemove];
|
|
||||||
this.model.refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!filter && this.model)
|
if (!filter && this.model)
|
||||||
this.model.clear();
|
this.model.clear();
|
||||||
if (source != 'state')
|
if (source != 'state')
|
||||||
|
@ -279,7 +273,7 @@ export default class Searchbar extends Component {
|
||||||
return {id: params.$row.id};
|
return {id: params.$row.id};
|
||||||
}
|
}
|
||||||
|
|
||||||
onSearch(args) {
|
onSearch(args, source) {
|
||||||
if (!this.model) return;
|
if (!this.model) return;
|
||||||
let filter = args.$params;
|
let filter = args.$params;
|
||||||
|
|
||||||
|
@ -325,6 +319,12 @@ export default class Searchbar extends Component {
|
||||||
for (let param in stateFilter.tableQ)
|
for (let param in stateFilter.tableQ)
|
||||||
params[param] = stateFilter.tableQ[param];
|
params[param] = stateFilter.tableQ[param];
|
||||||
|
|
||||||
|
if (source == 'removeBar') {
|
||||||
|
delete params[this.toRemove];
|
||||||
|
delete this.model.userParams[this.toRemove];
|
||||||
|
delete stateFilter[this.toRemove];
|
||||||
|
}
|
||||||
|
|
||||||
const newParams = Object.assign(stateFilter, params);
|
const newParams = Object.assign(stateFilter, params);
|
||||||
return this.model.applyParams(newParams)
|
return this.model.applyParams(newParams)
|
||||||
.then(() => this.model.data);
|
.then(() => this.model.data);
|
||||||
|
|
|
@ -197,7 +197,7 @@ describe('Component vnSearchbar', () => {
|
||||||
controller.doSearch(filter, 'any');
|
controller.doSearch(filter, 'any');
|
||||||
$scope.$apply();
|
$scope.$apply();
|
||||||
|
|
||||||
expect(controller.onSearch).toHaveBeenCalledWith({$params: filter});
|
expect(controller.onSearch).toHaveBeenCalledWith({$params: filter}, 'any');
|
||||||
expect(controller.onFilter).toHaveBeenCalledWith(filter, 'any', undefined);
|
expect(controller.onFilter).toHaveBeenCalledWith(filter, 'any', undefined);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,11 +7,13 @@ vn-descriptor-content {
|
||||||
|
|
||||||
.photo {
|
.photo {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
& > img[ng-src] {
|
& > img[ng-src] {
|
||||||
min-height: 16em;
|
min-height: 16em;
|
||||||
display: block;
|
display: block;
|
||||||
max-width: 100%;
|
|
||||||
height: 256px;
|
height: 256px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -171,5 +171,6 @@
|
||||||
"Added observation": "Added observation",
|
"Added observation": "Added observation",
|
||||||
"Comment added to client": "Comment added to client",
|
"Comment added to client": "Comment added to client",
|
||||||
"This ticket is already a refund": "This ticket is already a refund",
|
"This ticket is already a refund": "This ticket is already a refund",
|
||||||
"A claim with that sale already exists": "A claim with that sale already exists"
|
"A claim with that sale already exists": "A claim with that sale already exists",
|
||||||
|
"ASSIGN_ZONE_FIRST": "Assign zone first"
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,6 +84,7 @@
|
||||||
"The current ticket can't be modified": "El ticket actual no puede ser modificado",
|
"The current ticket can't be modified": "El ticket actual no puede ser modificado",
|
||||||
"The current claim can't be modified": "La reclamación actual no puede ser modificada",
|
"The current claim can't be modified": "La reclamación actual no puede ser modificada",
|
||||||
"The sales of this ticket can't be modified": "Las lineas de este ticket no pueden ser modificadas",
|
"The sales of this ticket can't be modified": "Las lineas de este ticket no pueden ser modificadas",
|
||||||
|
"The sales do not exists": "La(s) línea(s) seleccionada(s) no existe(n)",
|
||||||
"Please select at least one sale": "Por favor selecciona al menos una linea",
|
"Please select at least one sale": "Por favor selecciona al menos una linea",
|
||||||
"All sales must belong to the same ticket": "Todas las lineas deben pertenecer al mismo ticket",
|
"All sales must belong to the same ticket": "Todas las lineas deben pertenecer al mismo ticket",
|
||||||
"NO_ZONE_FOR_THIS_PARAMETERS": "Para este día no hay ninguna zona configurada",
|
"NO_ZONE_FOR_THIS_PARAMETERS": "Para este día no hay ninguna zona configurada",
|
||||||
|
@ -290,5 +291,7 @@
|
||||||
"isTaxDataChecked": "Datos comprobados",
|
"isTaxDataChecked": "Datos comprobados",
|
||||||
"comercialId": "Id comercial",
|
"comercialId": "Id comercial",
|
||||||
"comercialName": "Comercial",
|
"comercialName": "Comercial",
|
||||||
"Invalid NIF for VIES": "Invalid NIF for VIES"
|
"Invalid NIF for VIES": "Invalid NIF for VIES",
|
||||||
|
"Ticket does not exist": "Este ticket no existe",
|
||||||
|
"Ticket is already signed": "Este ticket ya ha sido firmado"
|
||||||
}
|
}
|
|
@ -59,12 +59,14 @@ module.exports = Self => {
|
||||||
|
|
||||||
const landedPlusWeek = new Date(ticket.landed);
|
const landedPlusWeek = new Date(ticket.landed);
|
||||||
landedPlusWeek.setDate(landedPlusWeek.getDate() + 7);
|
landedPlusWeek.setDate(landedPlusWeek.getDate() + 7);
|
||||||
const hasClaimManagerRole = await models.VnUser.hasRole(userId, 'claimManager', myOptions);
|
|
||||||
const isClaimable = landedPlusWeek >= Date.vnNew();
|
const isClaimable = landedPlusWeek >= Date.vnNew();
|
||||||
|
|
||||||
|
const canCreateClaimAfterDeadline =
|
||||||
|
await models.ACL.checkAccessAcl(ctx, 'Claim', 'createAfterDeadline', 'WRITE');
|
||||||
|
|
||||||
if (ticket.isDeleted)
|
if (ticket.isDeleted)
|
||||||
throw new UserError(`You can't create a claim for a removed ticket`);
|
throw new UserError(`You can't create a claim for a removed ticket`);
|
||||||
if (!isClaimable && !hasClaimManagerRole)
|
if (!isClaimable && !canCreateClaimAfterDeadline)
|
||||||
throw new UserError(`You can't create a claim from a ticket delivered more than seven days ago`);
|
throw new UserError(`You can't create a claim from a ticket delivered more than seven days ago`);
|
||||||
|
|
||||||
const newClaim = await Self.create({
|
const newClaim = await Self.create({
|
||||||
|
|
|
@ -46,7 +46,6 @@ module.exports = Self => {
|
||||||
|
|
||||||
Self.updateClaim = async(ctx, id, options) => {
|
Self.updateClaim = async(ctx, id, options) => {
|
||||||
const models = Self.app.models;
|
const models = Self.app.models;
|
||||||
const userId = ctx.req.accessToken.userId;
|
|
||||||
const args = ctx.args;
|
const args = ctx.args;
|
||||||
let tx;
|
let tx;
|
||||||
const myOptions = {};
|
const myOptions = {};
|
||||||
|
@ -81,9 +80,9 @@ module.exports = Self => {
|
||||||
if (args.claimStateFk) {
|
if (args.claimStateFk) {
|
||||||
const canEditOldState = await models.ClaimState.isEditable(ctx, claim.claimStateFk, myOptions);
|
const canEditOldState = await models.ClaimState.isEditable(ctx, claim.claimStateFk, myOptions);
|
||||||
const canEditNewState = await models.ClaimState.isEditable(ctx, args.claimStateFk, myOptions);
|
const canEditNewState = await models.ClaimState.isEditable(ctx, args.claimStateFk, myOptions);
|
||||||
const isClaimManager = await models.VnUser.hasRole(userId, 'claimManager', myOptions);
|
const canEditState = await models.ACL.checkAccessAcl(ctx, 'Claim', 'editState', 'WRITE');
|
||||||
|
|
||||||
if (!canEditOldState || !canEditNewState || changedHasToPickUp && !isClaimManager)
|
if (!canEditOldState || !canEditNewState || changedHasToPickUp && !canEditState)
|
||||||
throw new UserError(`You don't have enough privileges to change that field`);
|
throw new UserError(`You don't have enough privileges to change that field`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,15 +87,15 @@ module.exports = function(Self) {
|
||||||
Self.updateAddress = async(ctx, clientId, addressId, options) => {
|
Self.updateAddress = async(ctx, clientId, addressId, options) => {
|
||||||
const models = Self.app.models;
|
const models = Self.app.models;
|
||||||
const args = ctx.args;
|
const args = ctx.args;
|
||||||
const userId = ctx.req.accessToken.userId;
|
|
||||||
const myOptions = {};
|
const myOptions = {};
|
||||||
|
|
||||||
if (typeof options == 'object')
|
if (typeof options == 'object')
|
||||||
Object.assign(myOptions, options);
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
const isSalesAssistant = await models.VnUser.hasRole(userId, 'salesAssistant', myOptions);
|
const canEditAddressLogifloraAllowed =
|
||||||
|
await models.ACL.checkAccessAcl(ctx, 'Client', 'editAddressLogifloraAllowed');
|
||||||
|
|
||||||
if (args.isLogifloraAllowed && !isSalesAssistant)
|
if (args.isLogifloraAllowed && !canEditAddressLogifloraAllowed)
|
||||||
throw new UserError(`You don't have enough privileges`);
|
throw new UserError(`You don't have enough privileges`);
|
||||||
|
|
||||||
const address = await models.Address.findOne({
|
const address = await models.Address.findOne({
|
||||||
|
|
|
@ -131,9 +131,10 @@ module.exports = Self => {
|
||||||
myOptions.transaction = tx;
|
myOptions.transaction = tx;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const isSalesAssistant = await models.VnUser.hasRole(userId, 'salesAssistant', myOptions);
|
const canEditNotTaxDataChecked =
|
||||||
|
await models.ACL.checkAccessAcl(ctx, 'Client', 'editFiscalDataWithoutTaxDataCheck', 'WRITE');
|
||||||
const client = await models.Client.findById(clientId, null, myOptions);
|
const client = await models.Client.findById(clientId, null, myOptions);
|
||||||
if (!isSalesAssistant && client.isTaxDataChecked)
|
if (!canEditNotTaxDataChecked && client.isTaxDataChecked)
|
||||||
throw new UserError(`Not enough privileges to edit a client with verified data`);
|
throw new UserError(`Not enough privileges to edit a client with verified data`);
|
||||||
// Sage data validation
|
// Sage data validation
|
||||||
const taxDataChecked = args.isTaxDataChecked;
|
const taxDataChecked = args.isTaxDataChecked;
|
||||||
|
|
|
@ -2,6 +2,7 @@ const UserError = require('vn-loopback/util/user-error');
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.remoteMethodCtx('updateUser', {
|
Self.remoteMethodCtx('updateUser', {
|
||||||
description: 'Updates the user information',
|
description: 'Updates the user information',
|
||||||
|
accessType: 'WRITE',
|
||||||
accepts: [
|
accepts: [
|
||||||
{
|
{
|
||||||
arg: 'id',
|
arg: 'id',
|
||||||
|
@ -32,7 +33,6 @@ module.exports = Self => {
|
||||||
|
|
||||||
Self.updateUser = async function(ctx, id, options) {
|
Self.updateUser = async function(ctx, id, options) {
|
||||||
const models = Self.app.models;
|
const models = Self.app.models;
|
||||||
const userId = ctx.req.accessToken.userId;
|
|
||||||
let tx;
|
let tx;
|
||||||
const myOptions = {};
|
const myOptions = {};
|
||||||
|
|
||||||
|
@ -45,9 +45,8 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const isSalesPerson = await models.VnUser.hasRole(userId, 'salesPerson', myOptions);
|
const canEdit = await models.ACL.checkAccessAcl(ctx, 'Client', 'updateUser', 'WRITE');
|
||||||
|
if (!canEdit)
|
||||||
if (!isSalesPerson)
|
|
||||||
throw new UserError(`Not enough privileges to edit a client`);
|
throw new UserError(`Not enough privileges to edit a client`);
|
||||||
|
|
||||||
const isClient = await models.Client.findById(id, null, myOptions);
|
const isClient = await models.Client.findById(id, null, myOptions);
|
||||||
|
|
|
@ -67,9 +67,13 @@ module.exports = Self => {
|
||||||
uw.id workerFk,
|
uw.id workerFk,
|
||||||
uw.name workerName,
|
uw.name workerName,
|
||||||
c.creditInsurance,
|
c.creditInsurance,
|
||||||
d.defaulterSinced
|
d.defaulterSinced,
|
||||||
|
cn.country,
|
||||||
|
pm.name payMethod
|
||||||
FROM vn.defaulter d
|
FROM vn.defaulter d
|
||||||
JOIN vn.client c ON c.id = d.clientFk
|
JOIN vn.client c ON c.id = d.clientFk
|
||||||
|
JOIN vn.country cn ON cn.id = c.countryFk
|
||||||
|
JOIN vn.payMethod pm ON pm.id = c.payMethodFk
|
||||||
LEFT JOIN vn.clientObservation co ON co.clientFk = c.id
|
LEFT JOIN vn.clientObservation co ON co.clientFk = c.id
|
||||||
LEFT JOIN account.user u ON u.id = c.salesPersonFk
|
LEFT JOIN account.user u ON u.id = c.salesPersonFk
|
||||||
LEFT JOIN account.user uw ON uw.id = co.workerFk
|
LEFT JOIN account.user uw ON uw.id = co.workerFk
|
||||||
|
|
|
@ -218,9 +218,9 @@ module.exports = Self => {
|
||||||
const models = Self.app.models;
|
const models = Self.app.models;
|
||||||
|
|
||||||
const loopBackContext = LoopBackContext.getCurrentContext();
|
const loopBackContext = LoopBackContext.getCurrentContext();
|
||||||
const userId = loopBackContext.active.accessToken.userId;
|
const accessToken = {req: loopBackContext.active.accessToken};
|
||||||
|
|
||||||
const isSalesAssistant = await models.VnUser.hasRole(userId, 'salesAssistant', ctx.options);
|
const editVerifiedDataWithoutTaxDataChecked = models.ACL.checkAccessAcl(accessToken, 'Client', 'editVerifiedDataWithoutTaxDataCheck', 'WRITE');
|
||||||
const hasChanges = orgData && changes;
|
const hasChanges = orgData && changes;
|
||||||
|
|
||||||
const isTaxDataChecked = hasChanges && (changes.isTaxDataChecked || orgData.isTaxDataChecked);
|
const isTaxDataChecked = hasChanges && (changes.isTaxDataChecked || orgData.isTaxDataChecked);
|
||||||
|
@ -232,8 +232,8 @@ module.exports = Self => {
|
||||||
const sageTransactionType = hasChanges && (changes.sageTransactionTypeFk || orgData.sageTransactionTypeFk);
|
const sageTransactionType = hasChanges && (changes.sageTransactionTypeFk || orgData.sageTransactionTypeFk);
|
||||||
const sageTransactionTypeChanged = hasChanges && orgData.sageTransactionTypeFk != sageTransactionType;
|
const sageTransactionTypeChanged = hasChanges && orgData.sageTransactionTypeFk != sageTransactionType;
|
||||||
|
|
||||||
const cantEditVerifiedData = isTaxDataCheckedChanged && !isSalesAssistant;
|
const cantEditVerifiedData = isTaxDataCheckedChanged && !editVerifiedDataWithoutTaxDataChecked;
|
||||||
const cantChangeSageData = (sageTaxTypeChanged || sageTransactionTypeChanged) && !isSalesAssistant;
|
const cantChangeSageData = (sageTaxTypeChanged || sageTransactionTypeChanged) && !editVerifiedDataWithoutTaxDataChecked;
|
||||||
|
|
||||||
if (cantEditVerifiedData || cantChangeSageData)
|
if (cantEditVerifiedData || cantChangeSageData)
|
||||||
throw new UserError(`You don't have enough privileges`);
|
throw new UserError(`You don't have enough privileges`);
|
||||||
|
@ -401,9 +401,10 @@ module.exports = Self => {
|
||||||
Self.changeCredit = async function changeCredit(ctx, finalState, changes) {
|
Self.changeCredit = async function changeCredit(ctx, finalState, changes) {
|
||||||
const models = Self.app.models;
|
const models = Self.app.models;
|
||||||
const userId = ctx.options.accessToken.userId;
|
const userId = ctx.options.accessToken.userId;
|
||||||
|
const accessToken = {req: {accessToken: ctx.options.accessToken} };
|
||||||
|
|
||||||
const isFinancialBoss = await models.VnUser.hasRole(userId, 'financialBoss', ctx.options);
|
const canEditCredit = await models.ACL.checkAccessAcl(accessToken, 'Client', 'editCredit', 'WRITE');
|
||||||
if (!isFinancialBoss) {
|
if (!canEditCredit) {
|
||||||
const lastCredit = await models.ClientCredit.findOne({
|
const lastCredit = await models.ClientCredit.findOne({
|
||||||
where: {
|
where: {
|
||||||
clientFk: finalState.id
|
clientFk: finalState.id
|
||||||
|
@ -412,10 +413,9 @@ module.exports = Self => {
|
||||||
}, ctx.options);
|
}, ctx.options);
|
||||||
|
|
||||||
const lastAmount = lastCredit && lastCredit.amount;
|
const lastAmount = lastCredit && lastCredit.amount;
|
||||||
const lastWorkerId = lastCredit && lastCredit.workerFk;
|
const lastCreditIsNotEditable = !await models.ACL.checkAccessAcl(accessToken, 'Client', 'isNotEditableCredit', 'WRITE');
|
||||||
const lastWorkerIsFinancialBoss = await models.VnUser.hasRole(lastWorkerId, 'financialBoss', ctx.options);
|
|
||||||
|
|
||||||
if (lastAmount == 0 && lastWorkerIsFinancialBoss)
|
if (lastAmount == 0 && lastCreditIsNotEditable)
|
||||||
throw new UserError(`You can't change the credit set to zero from a financialBoss`);
|
throw new UserError(`You can't change the credit set to zero from a financialBoss`);
|
||||||
|
|
||||||
const creditLimits = await models.ClientCreditLimit.find({
|
const creditLimits = await models.ClientCreditLimit.find({
|
||||||
|
|
|
@ -29,6 +29,16 @@
|
||||||
"type": "belongsTo",
|
"type": "belongsTo",
|
||||||
"model": "Client",
|
"model": "Client",
|
||||||
"foreignKey": "clientFk"
|
"foreignKey": "clientFk"
|
||||||
|
},
|
||||||
|
"country": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Country",
|
||||||
|
"foreignKey": "country"
|
||||||
|
},
|
||||||
|
"payMethod": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "PayMethod",
|
||||||
|
"foreignKey": "payMethod"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -57,6 +57,13 @@
|
||||||
<th field="salesPersonFk">
|
<th field="salesPersonFk">
|
||||||
<span translate>Comercial</span>
|
<span translate>Comercial</span>
|
||||||
</th>
|
</th>
|
||||||
|
<th field="country">
|
||||||
|
<span translate>Country</span>
|
||||||
|
</th>
|
||||||
|
<th field="payMethod"
|
||||||
|
vn-tooltip="Pay Method">
|
||||||
|
<span translate>P.Method</span>
|
||||||
|
</th>
|
||||||
<th
|
<th
|
||||||
field="amount"
|
field="amount"
|
||||||
vn-tooltip="Balance due">
|
vn-tooltip="Balance due">
|
||||||
|
@ -111,6 +118,12 @@
|
||||||
{{::defaulter.salesPersonName | dashIfEmpty}}
|
{{::defaulter.salesPersonName | dashIfEmpty}}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
{{::defaulter.country}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{::defaulter.payMethod}}
|
||||||
|
</td>
|
||||||
<td>{{::defaulter.amount | currency: 'EUR': 2}}</td>
|
<td>{{::defaulter.amount | currency: 'EUR': 2}}</td>
|
||||||
<td>
|
<td>
|
||||||
<span
|
<span
|
||||||
|
|
|
@ -20,8 +20,7 @@ export default class Controller extends Section {
|
||||||
showField: 'name',
|
showField: 'name',
|
||||||
valueField: 'id'
|
valueField: 'id'
|
||||||
}
|
}
|
||||||
},
|
}, {
|
||||||
{
|
|
||||||
field: 'salesPersonFk',
|
field: 'salesPersonFk',
|
||||||
autocomplete: {
|
autocomplete: {
|
||||||
url: 'Workers/activeWithInheritedRole',
|
url: 'Workers/activeWithInheritedRole',
|
||||||
|
@ -30,6 +29,18 @@ export default class Controller extends Section {
|
||||||
showField: 'name',
|
showField: 'name',
|
||||||
valueField: 'id',
|
valueField: 'id',
|
||||||
}
|
}
|
||||||
|
}, {
|
||||||
|
field: 'country',
|
||||||
|
autocomplete: {
|
||||||
|
showField: 'country',
|
||||||
|
valueField: 'country'
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
field: 'payMethodFk',
|
||||||
|
autocomplete: {
|
||||||
|
showField: 'name',
|
||||||
|
valueField: 'id'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'workerFk',
|
field: 'workerFk',
|
||||||
|
@ -132,7 +143,7 @@ export default class Controller extends Section {
|
||||||
sendMail() {
|
sendMail() {
|
||||||
const params = {
|
const params = {
|
||||||
defaulters: this.checked,
|
defaulters: this.checked,
|
||||||
observation: this.defaulter.observation
|
observation: this.defaulter.observation,
|
||||||
};
|
};
|
||||||
this.$http.post(`Defaulters/observationEmail`, params);
|
this.$http.post(`Defaulters/observationEmail`, params);
|
||||||
}
|
}
|
||||||
|
@ -143,6 +154,8 @@ export default class Controller extends Section {
|
||||||
case 'amount':
|
case 'amount':
|
||||||
case 'clientFk':
|
case 'clientFk':
|
||||||
case 'workerFk':
|
case 'workerFk':
|
||||||
|
case 'country':
|
||||||
|
case 'payMethod':
|
||||||
case 'salesPersonFk':
|
case 'salesPersonFk':
|
||||||
return {[`d.${param}`]: value};
|
return {[`d.${param}`]: value};
|
||||||
case 'created':
|
case 'created':
|
||||||
|
|
|
@ -9,3 +9,6 @@ Search client: Buscar clientes
|
||||||
Worker who made the last observation: Trabajador que ha realizado la última observación
|
Worker who made the last observation: Trabajador que ha realizado la última observación
|
||||||
Email sended!: Email enviado!
|
Email sended!: Email enviado!
|
||||||
Observation saved!: Observación añadida!
|
Observation saved!: Observación añadida!
|
||||||
|
P.Method: F.Pago
|
||||||
|
Pay Method: Forma de Pago
|
||||||
|
Country: Pais
|
|
@ -2,6 +2,11 @@
|
||||||
vn-id="watcher"
|
vn-id="watcher"
|
||||||
data="$ctrl.dms">
|
data="$ctrl.dms">
|
||||||
</vn-watcher>
|
</vn-watcher>
|
||||||
|
<vn-crud-model
|
||||||
|
auto-load="true"
|
||||||
|
url="Warehouses"
|
||||||
|
data="warehouses">
|
||||||
|
</vn-crud-model>
|
||||||
<form
|
<form
|
||||||
name="form"
|
name="form"
|
||||||
ng-submit="$ctrl.onSubmit()"
|
ng-submit="$ctrl.onSubmit()"
|
||||||
|
@ -29,7 +34,7 @@
|
||||||
<vn-autocomplete vn-one required="true"
|
<vn-autocomplete vn-one required="true"
|
||||||
label="Warehouse"
|
label="Warehouse"
|
||||||
ng-model="$ctrl.dms.warehouseId"
|
ng-model="$ctrl.dms.warehouseId"
|
||||||
url="Warehouses"
|
data="Warehouses"
|
||||||
show-field="name"
|
show-field="name"
|
||||||
value-field="id">
|
value-field="id">
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
|
|
|
@ -5,6 +5,11 @@
|
||||||
form="form"
|
form="form"
|
||||||
save="patch">
|
save="patch">
|
||||||
</vn-watcher>
|
</vn-watcher>
|
||||||
|
<vn-crud-model
|
||||||
|
auto-load="true"
|
||||||
|
url="Warehouses"
|
||||||
|
data="warehouses">
|
||||||
|
</vn-crud-model>
|
||||||
<form name="form" ng-submit="watcher.submit()" class="vn-w-md">
|
<form name="form" ng-submit="watcher.submit()" class="vn-w-md">
|
||||||
<vn-card class="vn-pa-lg">
|
<vn-card class="vn-pa-lg">
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
|
@ -152,14 +157,14 @@
|
||||||
<vn-autocomplete
|
<vn-autocomplete
|
||||||
label="Warehouse Out"
|
label="Warehouse Out"
|
||||||
ng-model="$ctrl.travelFilterParams.warehouseOutFk"
|
ng-model="$ctrl.travelFilterParams.warehouseOutFk"
|
||||||
url="Warehouses"
|
data="Warehouses"
|
||||||
show-field="name"
|
show-field="name"
|
||||||
value-field="id">
|
value-field="id">
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
<vn-autocomplete
|
<vn-autocomplete
|
||||||
label="Warehouse In"
|
label="Warehouse In"
|
||||||
ng-model="$ctrl.travelFilterParams.warehouseInFk"
|
ng-model="$ctrl.travelFilterParams.warehouseInFk"
|
||||||
url="Warehouses"
|
data="Warehouses"
|
||||||
show-field="name"
|
show-field="name"
|
||||||
value-field="id">
|
value-field="id">
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
|
|
|
@ -25,7 +25,6 @@ module.exports = Self => {
|
||||||
|
|
||||||
Self.createPdf = async function(ctx, id, options) {
|
Self.createPdf = async function(ctx, id, options) {
|
||||||
const models = Self.app.models;
|
const models = Self.app.models;
|
||||||
const userId = ctx.req.accessToken.userId;
|
|
||||||
|
|
||||||
if (process.env.NODE_ENV == 'test')
|
if (process.env.NODE_ENV == 'test')
|
||||||
throw new UserError(`Action not allowed on the test environment`);
|
throw new UserError(`Action not allowed on the test environment`);
|
||||||
|
@ -43,9 +42,9 @@ module.exports = Self => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const invoiceOut = await Self.findById(id, null, myOptions);
|
const invoiceOut = await Self.findById(id, null, myOptions);
|
||||||
const hasInvoicing = await models.VnUser.hasRole(userId, 'invoicing', myOptions);
|
const canCreatePdf = await models.ACL.checkAccessAcl(ctx, 'InvoiceOut', 'canCreatePdf', 'WRITE');
|
||||||
|
|
||||||
if (invoiceOut.hasPdf && !hasInvoicing)
|
if (invoiceOut.hasPdf && !canCreatePdf)
|
||||||
throw new UserError(`You don't have enough privileges`);
|
throw new UserError(`You don't have enough privileges`);
|
||||||
|
|
||||||
await invoiceOut.updateAttributes({
|
await invoiceOut.updateAttributes({
|
||||||
|
|
|
@ -26,8 +26,8 @@ module.exports = Self => {
|
||||||
Object.assign(myOptions, options);
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
const where = filter.where;
|
const where = filter.where;
|
||||||
const query = 'CALL vn.item_getBalance(?, ?)';
|
const query = 'CALL vn.item_getBalance(?, ?, ?)';
|
||||||
const [diary] = await Self.rawSql(query, [where.itemFk, where.warehouseFk], myOptions);
|
const [diary] = await Self.rawSql(query, [where.itemFk, where.warehouseFk, where.date], myOptions);
|
||||||
|
|
||||||
for (const entry of diary)
|
for (const entry of diary)
|
||||||
if (entry.clientType === 'loses') entry.highlighted = true;
|
if (entry.clientType === 'loses') entry.highlighted = true;
|
||||||
|
|
|
@ -21,7 +21,8 @@ describe('item getBalance()', () => {
|
||||||
const filter = {
|
const filter = {
|
||||||
where: {
|
where: {
|
||||||
itemFk: 1,
|
itemFk: 1,
|
||||||
warehouseFk: 1
|
warehouseFk: 1,
|
||||||
|
date: null
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const results = await models.Item.getBalance(filter, options);
|
const results = await models.Item.getBalance(filter, options);
|
||||||
|
@ -45,14 +46,16 @@ describe('item getBalance()', () => {
|
||||||
const firstFilter = {
|
const firstFilter = {
|
||||||
where: {
|
where: {
|
||||||
itemFk: 1,
|
itemFk: 1,
|
||||||
warehouseFk: 1
|
warehouseFk: 1,
|
||||||
|
date: null
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const secondFilter = {
|
const secondFilter = {
|
||||||
where: {
|
where: {
|
||||||
itemFk: 2,
|
itemFk: 2,
|
||||||
warehouseFk: 1
|
warehouseFk: 1,
|
||||||
|
date: null
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
<vn-crud-model
|
||||||
|
auto-load="true"
|
||||||
|
url="Warehouses"
|
||||||
|
data="warehouses">
|
||||||
|
</vn-crud-model>
|
||||||
<vn-descriptor-content
|
<vn-descriptor-content
|
||||||
module="item"
|
module="item"
|
||||||
description="$ctrl.item.name"
|
description="$ctrl.item.name"
|
||||||
|
@ -108,7 +113,9 @@
|
||||||
<vn-autocomplete
|
<vn-autocomplete
|
||||||
label="Warehouse"
|
label="Warehouse"
|
||||||
ng-model="$ctrl.warehouseFk"
|
ng-model="$ctrl.warehouseFk"
|
||||||
url="Warehouses">
|
data="warehouses"
|
||||||
|
show-field="name"
|
||||||
|
value="id">>
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
</tpl-body>
|
</tpl-body>
|
||||||
<tpl-buttons>
|
<tpl-buttons>
|
||||||
|
|
|
@ -25,6 +25,16 @@
|
||||||
ng-model="$ctrl.warehouseFk"
|
ng-model="$ctrl.warehouseFk"
|
||||||
label="Select warehouse">
|
label="Select warehouse">
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
|
<vn-check
|
||||||
|
ng-class="{'table-check':$ctrl.showOld}"
|
||||||
|
label="Show what's before the inventory"
|
||||||
|
ng-model="$ctrl.showOld">
|
||||||
|
</vn-check>
|
||||||
|
<vn-date-picker
|
||||||
|
label="Since"
|
||||||
|
ng-model="$ctrl.date"
|
||||||
|
ng-show="$ctrl.showOld">
|
||||||
|
</vn-date-picker>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
<vn-table model="model">
|
<vn-table model="model">
|
||||||
<vn-thead>
|
<vn-thead>
|
||||||
|
|
|
@ -38,12 +38,8 @@ class Controller extends Section {
|
||||||
if (value && value != this._warehouseFk) {
|
if (value && value != this._warehouseFk) {
|
||||||
this._warehouseFk = value;
|
this._warehouseFk = value;
|
||||||
this.card.warehouseFk = value;
|
this.card.warehouseFk = value;
|
||||||
|
this.filter.where.warehouseFk = this.warehouseFk;
|
||||||
|
|
||||||
this.$state.go(this.$state.current.name, {
|
|
||||||
warehouseFk: value
|
|
||||||
});
|
|
||||||
|
|
||||||
this.filter.where.warehouseFk = value;
|
|
||||||
this.$.model.refresh();
|
this.$.model.refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,6 +48,28 @@ class Controller extends Section {
|
||||||
return this._warehouseFk;
|
return this._warehouseFk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set date(value) {
|
||||||
|
this._date = value;
|
||||||
|
this.filter.where.date = value;
|
||||||
|
this.filter.where.warehouseFk = this.warehouseFk;
|
||||||
|
|
||||||
|
this.$.model.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
get date() {
|
||||||
|
return this._date;
|
||||||
|
}
|
||||||
|
|
||||||
|
set showOld(value) {
|
||||||
|
this._showOld = value;
|
||||||
|
if (!this._showOld) this.date = null;
|
||||||
|
else this.date = new Date();
|
||||||
|
}
|
||||||
|
|
||||||
|
get showOld() {
|
||||||
|
return this._showOld;
|
||||||
|
}
|
||||||
|
|
||||||
scrollToLine(lineFk) {
|
scrollToLine(lineFk) {
|
||||||
this.$.$applyAsync(() => {
|
this.$.$applyAsync(() => {
|
||||||
const hashFk = this.lineFk || lineFk;
|
const hashFk = this.lineFk || lineFk;
|
||||||
|
|
|
@ -2,3 +2,4 @@ In: Entrada
|
||||||
Out: Salida
|
Out: Salida
|
||||||
Visible quantity: Cantidad visible
|
Visible quantity: Cantidad visible
|
||||||
Ticket/Entry: Ticket/Entrada
|
Ticket/Entry: Ticket/Entrada
|
||||||
|
Show what's before the inventory: Mostrar lo anterior al inventario
|
||||||
|
|
|
@ -27,4 +27,7 @@ vn-item-diary {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
.table-check{
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,9 @@
|
||||||
<div class="search-panel">
|
<div class="search-panel">
|
||||||
|
<vn-crud-model
|
||||||
|
auto-load="true"
|
||||||
|
url="Warehouses"
|
||||||
|
data="warehouses">
|
||||||
|
</vn-crud-model>
|
||||||
<form id="manifold-form" ng-submit="$ctrl.onSearch()">
|
<form id="manifold-form" ng-submit="$ctrl.onSearch()">
|
||||||
<vn-horizontal class="vn-px-lg vn-pt-lg">
|
<vn-horizontal class="vn-px-lg vn-pt-lg">
|
||||||
<vn-textfield
|
<vn-textfield
|
||||||
|
@ -35,7 +40,9 @@
|
||||||
vn-one
|
vn-one
|
||||||
label="Warehouse"
|
label="Warehouse"
|
||||||
ng-model="filter.warehouseFk"
|
ng-model="filter.warehouseFk"
|
||||||
url="Warehouses">
|
data="warehouses"
|
||||||
|
show-field="name"
|
||||||
|
value-field="id">
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
<vn-horizontal class="vn-px-lg">
|
<vn-horizontal class="vn-px-lg">
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
<div class="search-panel">
|
<div class="search-panel">
|
||||||
|
<vn-crud-model
|
||||||
|
auto-load="true"
|
||||||
|
url="Warehouses"
|
||||||
|
data="warehouses">
|
||||||
|
</vn-crud-model>
|
||||||
<form id="manifold-form" ng-submit="$ctrl.onSearch()">
|
<form id="manifold-form" ng-submit="$ctrl.onSearch()">
|
||||||
<vn-horizontal class="vn-px-lg vn-pt-lg">
|
<vn-horizontal class="vn-px-lg vn-pt-lg">
|
||||||
<vn-textfield
|
<vn-textfield
|
||||||
|
@ -83,7 +88,7 @@
|
||||||
vn-one
|
vn-one
|
||||||
label="Warehouse"
|
label="Warehouse"
|
||||||
ng-model="filter.warehouseFk"
|
ng-model="filter.warehouseFk"
|
||||||
url="Warehouses">
|
data="Warehouses">
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
<vn-autocomplete
|
<vn-autocomplete
|
||||||
vn-one
|
vn-one
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
<div class="search-panel">
|
<div class="search-panel">
|
||||||
|
<vn-crud-model
|
||||||
|
auto-load="true"
|
||||||
|
url="Agencies"
|
||||||
|
data="agencies">
|
||||||
|
</vn-crud-model>
|
||||||
<form id="manifold-form" ng-submit="$ctrl.onSearch()">
|
<form id="manifold-form" ng-submit="$ctrl.onSearch()">
|
||||||
<vn-horizontal class="vn-px-lg vn-pt-lg">
|
<vn-horizontal class="vn-px-lg vn-pt-lg">
|
||||||
<vn-textfield
|
<vn-textfield
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
<div class="search-panel">
|
<div class="search-panel">
|
||||||
|
<vn-crud-model
|
||||||
|
auto-load="true"
|
||||||
|
url="Warehouses"
|
||||||
|
data="warehouses">
|
||||||
|
</vn-crud-model>
|
||||||
<form id="manifold-form" ng-submit="$ctrl.onSearch()">
|
<form id="manifold-form" ng-submit="$ctrl.onSearch()">
|
||||||
<vn-horizontal class="vn-px-lg vn-pt-lg">
|
<vn-horizontal class="vn-px-lg vn-pt-lg">
|
||||||
<vn-textfield
|
<vn-textfield
|
||||||
|
@ -79,7 +84,7 @@
|
||||||
vn-one
|
vn-one
|
||||||
label="Warehouse"
|
label="Warehouse"
|
||||||
ng-model="filter.warehouseFk"
|
ng-model="filter.warehouseFk"
|
||||||
url="Warehouses"
|
data="Warehouses"
|
||||||
show-field="name"
|
show-field="name"
|
||||||
value-field="id">
|
value-field="id">
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
|
|
|
@ -99,18 +99,20 @@ module.exports = Self => {
|
||||||
|
|
||||||
Self.observe('before save', async function(ctx) {
|
Self.observe('before save', async function(ctx) {
|
||||||
if (ctx.isNewInstance) return;
|
if (ctx.isNewInstance) return;
|
||||||
const loopbackContext = LoopBackContext.getCurrentContext();
|
|
||||||
const changes = ctx.data || ctx.instance;
|
const changes = ctx.data || ctx.instance;
|
||||||
const orgData = ctx.currentInstance;
|
const orgData = ctx.currentInstance;
|
||||||
const userId = loopbackContext.active.accessToken.userId;
|
const loopBackContext = LoopBackContext.getCurrentContext();
|
||||||
|
const accessToken = {req: loopBackContext.active.accessToken};
|
||||||
|
|
||||||
|
const editPayMethodCheck =
|
||||||
|
await Self.app.models.ACL.checkAccessAcl(accessToken, 'Supplier', 'editPayMethodCheck', 'WRITE');
|
||||||
|
|
||||||
const isNotFinancial = !await Self.app.models.VnUser.hasRole(userId, 'financial');
|
|
||||||
const isPayMethodChecked = changes.isPayMethodChecked || orgData.isPayMethodChecked;
|
const isPayMethodChecked = changes.isPayMethodChecked || orgData.isPayMethodChecked;
|
||||||
const hasChanges = orgData && changes;
|
const hasChanges = orgData && changes;
|
||||||
const isPayMethodCheckedChanged = hasChanges
|
const isPayMethodCheckedChanged = hasChanges
|
||||||
&& orgData.isPayMethodChecked != isPayMethodChecked;
|
&& orgData.isPayMethodChecked != isPayMethodChecked;
|
||||||
|
|
||||||
if (isNotFinancial && isPayMethodCheckedChanged)
|
if (!editPayMethodCheck && isPayMethodCheckedChanged)
|
||||||
throw new UserError('You can not modify is pay method checked');
|
throw new UserError('You can not modify is pay method checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,9 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
}, myOptions);
|
}, myOptions);
|
||||||
|
|
||||||
|
if (!salesData.length)
|
||||||
|
throw new UserError(`The sales do not exists`);
|
||||||
|
|
||||||
const ticketId = salesData[0].ticketFk;
|
const ticketId = salesData[0].ticketFk;
|
||||||
|
|
||||||
const isTicketEditable = await models.Ticket.isEditable(ctx, ticketId, myOptions);
|
const isTicketEditable = await models.Ticket.isEditable(ctx, ticketId, myOptions);
|
||||||
|
@ -62,7 +65,5 @@ module.exports = Self => {
|
||||||
throw new UserError('It is not possible to modify cloned sales');
|
throw new UserError('It is not possible to modify cloned sales');
|
||||||
if (!shouldEditFloramondo)
|
if (!shouldEditFloramondo)
|
||||||
throw new UserError('It is not possible to modify sales that their articles are from Floramondo');
|
throw new UserError('It is not possible to modify sales that their articles are from Floramondo');
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,6 +17,32 @@ describe('sale canEdit()', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('sale not exists', () => {
|
||||||
|
it('should return error if sale not exists', async() => {
|
||||||
|
const tx = await models.Sale.beginTransaction({});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
const developerId = 9;
|
||||||
|
const ctx = {req: {accessToken: {userId: developerId}}};
|
||||||
|
|
||||||
|
let max = await models.Sale.findOne({fields: ['id'], order: 'id DESC'}, options);
|
||||||
|
max.id = max.id + 1;
|
||||||
|
|
||||||
|
const sales = [max.id];
|
||||||
|
await models.Sale.canEdit(ctx, sales, options);
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
error = e.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error).toEqual('The sales do not exists');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('sale editTracked', () => {
|
describe('sale editTracked', () => {
|
||||||
it('should return true if the role is production regardless of the saleTrackings', async() => {
|
it('should return true if the role is production regardless of the saleTrackings', async() => {
|
||||||
const tx = await models.Sale.beginTransaction({});
|
const tx = await models.Sale.beginTransaction({});
|
||||||
|
@ -29,9 +55,7 @@ describe('sale canEdit()', () => {
|
||||||
|
|
||||||
const sales = [25];
|
const sales = [25];
|
||||||
|
|
||||||
const result = await models.Sale.canEdit(ctx, sales, options);
|
await models.Sale.canEdit(ctx, sales, options);
|
||||||
|
|
||||||
expect(result).toEqual(true);
|
|
||||||
|
|
||||||
await tx.rollback();
|
await tx.rollback();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -51,9 +75,7 @@ describe('sale canEdit()', () => {
|
||||||
|
|
||||||
const sales = [10];
|
const sales = [10];
|
||||||
|
|
||||||
const result = await models.Sale.canEdit(ctx, sales, options);
|
await models.Sale.canEdit(ctx, sales, options);
|
||||||
|
|
||||||
expect(result).toEqual(true);
|
|
||||||
|
|
||||||
await tx.rollback();
|
await tx.rollback();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -87,9 +109,7 @@ describe('sale canEdit()', () => {
|
||||||
});
|
});
|
||||||
const ctx = {req: {accessToken: {userId: role.id}}};
|
const ctx = {req: {accessToken: {userId: role.id}}};
|
||||||
|
|
||||||
const result = await models.Sale.canEdit(ctx, saleCloned, options);
|
await models.Sale.canEdit(ctx, saleCloned, options);
|
||||||
|
|
||||||
expect(result).toEqual(true);
|
|
||||||
|
|
||||||
await tx.rollback();
|
await tx.rollback();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -150,9 +170,7 @@ describe('sale canEdit()', () => {
|
||||||
const saleToEdit = await models.Sale.findById(sales[0], null, options);
|
const saleToEdit = await models.Sale.findById(sales[0], null, options);
|
||||||
await saleToEdit.updateAttribute('itemFk', 9, options);
|
await saleToEdit.updateAttribute('itemFk', 9, options);
|
||||||
|
|
||||||
const result = await models.Sale.canEdit(ctx, sales, options);
|
await models.Sale.canEdit(ctx, sales, options);
|
||||||
|
|
||||||
expect(result).toEqual(true);
|
|
||||||
|
|
||||||
await tx.rollback();
|
await tx.rollback();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -64,7 +64,7 @@ describe('sale updateQuantity()', () => {
|
||||||
try {
|
try {
|
||||||
const options = {transaction: tx};
|
const options = {transaction: tx};
|
||||||
|
|
||||||
const isRoleAdvanced = await models.Ticket.isRoleAdvanced(ctx, options);
|
const isRoleAdvanced = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'isRoleAdvanced', '*');
|
||||||
|
|
||||||
expect(isRoleAdvanced).toEqual(true);
|
expect(isRoleAdvanced).toEqual(true);
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ module.exports = Self => {
|
||||||
|
|
||||||
const sale = await models.Sale.findById(id, filter, myOptions);
|
const sale = await models.Sale.findById(id, filter, myOptions);
|
||||||
|
|
||||||
const isRoleAdvanced = await models.Ticket.isRoleAdvanced(ctx, myOptions);
|
const isRoleAdvanced = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'isRoleAdvanced', '*');
|
||||||
if (newQuantity > sale.quantity && !isRoleAdvanced)
|
if (newQuantity > sale.quantity && !isRoleAdvanced)
|
||||||
throw new UserError('The new quantity should be smaller than the old one');
|
throw new UserError('The new quantity should be smaller than the old one');
|
||||||
|
|
||||||
|
|
|
@ -19,13 +19,11 @@ module.exports = Self => {
|
||||||
|
|
||||||
Self.editableStates = async(ctx, filter, options) => {
|
Self.editableStates = async(ctx, filter, options) => {
|
||||||
const models = Self.app.models;
|
const models = Self.app.models;
|
||||||
const userId = ctx.req.accessToken.userId;
|
|
||||||
const myOptions = {...(options || {})};
|
const myOptions = {...(options || {})};
|
||||||
|
|
||||||
const isProduction = await models.VnUser.hasRole(userId, 'production', myOptions);
|
const seeEditableStates = await models.ACL.checkAccessAcl(ctx, 'State', 'seeEditableStates', 'READ');
|
||||||
const isAdministrative = await models.VnUser.hasRole(userId, 'administrative', myOptions);
|
|
||||||
|
|
||||||
if (!isProduction && !isAdministrative)
|
if (!seeEditableStates)
|
||||||
filter = mergeFilters(filter, {where: {alertLevel: 0}});
|
filter = mergeFilters(filter, {where: {alertLevel: 0}});
|
||||||
|
|
||||||
const states = await models.State.find(filter, myOptions);
|
const states = await models.State.find(filter, myOptions);
|
||||||
|
|
|
@ -19,22 +19,23 @@ module.exports = Self => {
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.isEditable = async(ctx, stateId, options) => {
|
Self.isEditable = async(ctx, stateId, options) => {
|
||||||
const accessToken = ctx.req.accessToken;
|
|
||||||
const models = Self.app.models;
|
const models = Self.app.models;
|
||||||
const userId = accessToken.userId;
|
|
||||||
const myOptions = {};
|
const myOptions = {};
|
||||||
|
|
||||||
if (typeof options == 'object')
|
if (typeof options == 'object')
|
||||||
Object.assign(myOptions, options);
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
const isProduction = await models.VnUser.hasRole(userId, 'production', myOptions);
|
const isAllEditable = await models.ACL.checkAccessAcl(ctx, 'State', 'isAllEditable', 'READ');
|
||||||
const isSalesPerson = await models.VnUser.hasRole(userId, 'salesPerson', myOptions);
|
|
||||||
const isAdministrative = await models.VnUser.hasRole(userId, 'administrative', myOptions);
|
|
||||||
const state = await models.State.findById(stateId, null, myOptions);
|
const state = await models.State.findById(stateId, null, myOptions);
|
||||||
|
const isSomeEditable = (
|
||||||
|
await models.ACL.checkAccessAcl(ctx, 'State', 'isSomeEditable', 'READ')
|
||||||
|
&& (
|
||||||
|
state.code == 'PICKER_DESIGNED' || state.code == 'PRINTED'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
const salesPersonAllowed = (isSalesPerson && (state.code == 'PICKER_DESIGNED' || state.code == 'PRINTED'));
|
const isAllowed = isAllEditable || isSomeEditable || state.alertLevel == 0;
|
||||||
|
|
||||||
const isAllowed = isProduction || isAdministrative || salesPersonAllowed || state.alertLevel == 0;
|
|
||||||
return isAllowed;
|
return isAllowed;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -52,7 +52,7 @@ module.exports = Self => {
|
||||||
JOIN province p ON p.id = c.provinceFk
|
JOIN province p ON p.id = c.provinceFk
|
||||||
JOIN country co ON co.id = p.countryFk
|
JOIN country co ON co.id = p.countryFk
|
||||||
LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk
|
LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk
|
||||||
WHERE al.code = 'PACKED' OR (am.code = 'refund' AND al.code != 'delivered')
|
WHERE (al.code = 'PACKED' OR (am.code = 'refund' AND al.code != 'delivered'))
|
||||||
AND DATE(t.shipped) BETWEEN DATE_ADD(?, INTERVAL -2 DAY)
|
AND DATE(t.shipped) BETWEEN DATE_ADD(?, INTERVAL -2 DAY)
|
||||||
AND util.dayEnd(?)
|
AND util.dayEnd(?)
|
||||||
AND t.refFk IS NULL
|
AND t.refFk IS NULL
|
||||||
|
|
|
@ -121,8 +121,8 @@ module.exports = Self => {
|
||||||
if (!isEditable)
|
if (!isEditable)
|
||||||
throw new UserError(`The sales of this ticket can't be modified`);
|
throw new UserError(`The sales of this ticket can't be modified`);
|
||||||
|
|
||||||
const isDeliveryBoss = await models.VnUser.hasRole(userId, 'deliveryBoss', myOptions);
|
const editZone = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'editZone', 'WRITE');
|
||||||
if (!isDeliveryBoss) {
|
if (!editZone) {
|
||||||
const zoneShipped = await models.Agency.getShipped(
|
const zoneShipped = await models.Agency.getShipped(
|
||||||
ctx,
|
ctx,
|
||||||
args.landed,
|
args.landed,
|
||||||
|
|
|
@ -30,7 +30,7 @@ module.exports = Self => {
|
||||||
where: {ticketFk: id}
|
where: {ticketFk: id}
|
||||||
}, myOptions);
|
}, myOptions);
|
||||||
|
|
||||||
const isRoleAdvanced = await models.Ticket.isRoleAdvanced(ctx, myOptions);
|
const isRoleAdvanced = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'isRoleAdvanced', '*');
|
||||||
|
|
||||||
const alertLevel = state ? state.alertLevel : null;
|
const alertLevel = state ? state.alertLevel : null;
|
||||||
const ticket = await models.Ticket.findById(id, {
|
const ticket = await models.Ticket.findById(id, {
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
module.exports = Self => {
|
|
||||||
Self.remoteMethodCtx('isRoleAdvanced', {
|
|
||||||
description: 'Check if a ticket is editable',
|
|
||||||
accessType: 'READ',
|
|
||||||
returns: {
|
|
||||||
type: 'boolean',
|
|
||||||
root: true
|
|
||||||
},
|
|
||||||
http: {
|
|
||||||
path: `/isRoleAdvanced`,
|
|
||||||
verb: 'GET'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Self.isRoleAdvanced = async(ctx, options) => {
|
|
||||||
const models = Self.app.models;
|
|
||||||
const userId = ctx.req.accessToken.userId;
|
|
||||||
const myOptions = {};
|
|
||||||
|
|
||||||
if (typeof options == 'object')
|
|
||||||
Object.assign(myOptions, options);
|
|
||||||
|
|
||||||
const isSalesAssistant = await models.VnUser.hasRole(userId, 'salesAssistant', myOptions);
|
|
||||||
const isDeliveryBoss = await models.VnUser.hasRole(userId, 'deliveryBoss', myOptions);
|
|
||||||
const isBuyer = await models.VnUser.hasRole(userId, 'buyer', myOptions);
|
|
||||||
const isClaimManager = await models.VnUser.hasRole(userId, 'claimManager', myOptions);
|
|
||||||
|
|
||||||
const isRoleAdvanced = isSalesAssistant || isDeliveryBoss || isBuyer || isClaimManager;
|
|
||||||
|
|
||||||
return isRoleAdvanced;
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -63,10 +63,11 @@ module.exports = Self => {
|
||||||
newInstance: {mergedTicket: ticket.originId}
|
newInstance: {mergedTicket: ticket.originId}
|
||||||
};
|
};
|
||||||
|
|
||||||
await models.TicketLog.create(ticketDestinationLogRecord, myOptions);
|
|
||||||
await models.Sale.updateAll({ticketFk: ticket.originId}, {ticketFk: ticket.destinationId}, myOptions);
|
await models.Sale.updateAll({ticketFk: ticket.originId}, {ticketFk: ticket.destinationId}, myOptions);
|
||||||
await models.Ticket.setDeleted(ctx, ticket.originId, myOptions);
|
if (await models.Ticket.setDeleted(ctx, ticket.originId, myOptions)) {
|
||||||
await models.Chat.sendCheckingPresence(ctx, ticket.workerFk, message);
|
await models.TicketLog.create(ticketDestinationLogRecord, myOptions);
|
||||||
|
await models.Chat.sendCheckingPresence(ctx, ticket.workerFk, message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (tx)
|
if (tx)
|
||||||
await tx.commit();
|
await tx.commit();
|
||||||
|
|
|
@ -60,7 +60,6 @@ module.exports = Self => {
|
||||||
Self.priceDifference = async(ctx, options) => {
|
Self.priceDifference = async(ctx, options) => {
|
||||||
const args = ctx.args;
|
const args = ctx.args;
|
||||||
const models = Self.app.models;
|
const models = Self.app.models;
|
||||||
const userId = ctx.req.accessToken.userId;
|
|
||||||
const myOptions = {};
|
const myOptions = {};
|
||||||
let tx;
|
let tx;
|
||||||
|
|
||||||
|
@ -78,8 +77,8 @@ module.exports = Self => {
|
||||||
if (!isEditable)
|
if (!isEditable)
|
||||||
throw new UserError(`The sales of this ticket can't be modified`);
|
throw new UserError(`The sales of this ticket can't be modified`);
|
||||||
|
|
||||||
const isDeliveryBoss = await models.VnUser.hasRole(userId, 'deliveryBoss', myOptions);
|
const editZone = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'editZone', 'WRITE');
|
||||||
if (!isDeliveryBoss) {
|
if (!editZone) {
|
||||||
const zoneShipped = await models.Agency.getShipped(
|
const zoneShipped = await models.Agency.getShipped(
|
||||||
ctx,
|
ctx,
|
||||||
args.landed,
|
args.landed,
|
||||||
|
|
|
@ -29,8 +29,7 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.saveSign = async(ctx, options) => {
|
Self.saveSign = async(ctx, tickets, location, signedTime, options) => {
|
||||||
const args = Object.assign({}, ctx.args);
|
|
||||||
const models = Self.app.models;
|
const models = Self.app.models;
|
||||||
const myOptions = {};
|
const myOptions = {};
|
||||||
let tx;
|
let tx;
|
||||||
|
@ -48,9 +47,9 @@ module.exports = Self => {
|
||||||
async function setLocation(ticketId) {
|
async function setLocation(ticketId) {
|
||||||
await models.Delivery.create({
|
await models.Delivery.create({
|
||||||
ticketFk: ticketId,
|
ticketFk: ticketId,
|
||||||
longitude: args.location.Longitude,
|
longitude: location.Longitude,
|
||||||
latitude: args.location.Latitude,
|
latitude: location.Latitude,
|
||||||
dated: args.signedTime || new Date()
|
dated: signedTime || new Date()
|
||||||
}, myOptions);
|
}, myOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,9 +106,9 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (let i = 0; i < args.tickets.length; i++) {
|
for (const ticketId of tickets) {
|
||||||
const ticketState = await models.TicketState.findOne(
|
const ticketState = await models.TicketState.findOne(
|
||||||
{where: {ticketFk: args.tickets[i]},
|
{where: {ticketFk: ticketId},
|
||||||
fields: ['alertLevel']
|
fields: ['alertLevel']
|
||||||
}, myOptions);
|
}, myOptions);
|
||||||
|
|
||||||
|
@ -117,16 +116,19 @@ module.exports = Self => {
|
||||||
fields: ['id']
|
fields: ['id']
|
||||||
}, myOptions);
|
}, myOptions);
|
||||||
|
|
||||||
|
if (!ticketState)
|
||||||
|
throw new UserError('Ticket does not exist');
|
||||||
if (ticketState.alertLevel < packedAlertLevel.id)
|
if (ticketState.alertLevel < packedAlertLevel.id)
|
||||||
throw new UserError('This ticket cannot be signed because it has not been boxed');
|
throw new UserError('This ticket cannot be signed because it has not been boxed');
|
||||||
else if (!await gestDocExists(args.tickets[i])) {
|
if (await gestDocExists(ticketId))
|
||||||
if (args.location) setLocation(args.tickets[i]);
|
throw new UserError('Ticket is already signed');
|
||||||
if (!gestDocCreated) await createGestDoc(args.tickets[i]);
|
|
||||||
await models.TicketDms.create({ticketFk: args.tickets[i], dmsFk: dms[0].id}, myOptions);
|
if (location) setLocation(ticketId);
|
||||||
const ticket = await models.Ticket.findById(args.tickets[i], null, myOptions);
|
if (!gestDocCreated) await createGestDoc(ticketId);
|
||||||
await ticket.updateAttribute('isSigned', true, myOptions);
|
await models.TicketDms.create({ticketFk: ticketId, dmsFk: dms[0].id}, myOptions);
|
||||||
await Self.rawSql(`CALL vn.ticket_setState(?, ?)`, [args.tickets[i], 'DELIVERED'], myOptions);
|
const ticket = await models.Ticket.findById(ticketId, null, myOptions);
|
||||||
}
|
await ticket.updateAttribute('isSigned', true, myOptions);
|
||||||
|
await Self.rawSql(`CALL vn.ticket_setState(?, ?)`, [ticketId, 'DELIVERED'], myOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tx) await tx.commit();
|
if (tx) await tx.commit();
|
||||||
|
|
|
@ -36,7 +36,9 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const userId = ctx.req.accessToken.userId;
|
const ticketToDelete = await models.Ticket.findById(id, {fields: ['isDeleted']}, myOptions);
|
||||||
|
if (ticketToDelete.isDeleted) return false;
|
||||||
|
|
||||||
const isEditable = await Self.isEditable(ctx, id, myOptions);
|
const isEditable = await Self.isEditable(ctx, id, myOptions);
|
||||||
|
|
||||||
if (!isEditable)
|
if (!isEditable)
|
||||||
|
@ -51,7 +53,8 @@ module.exports = Self => {
|
||||||
throw new UserError($t('Tickets with associated refunds', {id: ticketRefunds[0].id}));
|
throw new UserError($t('Tickets with associated refunds', {id: ticketRefunds[0].id}));
|
||||||
|
|
||||||
// Check if has sales with shelving
|
// Check if has sales with shelving
|
||||||
const isSalesAssistant = await models.VnUser.hasRole(userId, 'salesAssistant', myOptions);
|
const canDeleteTicketWithPartPrepared =
|
||||||
|
await models.ACL.checkAccessAcl(ctx, 'Ticket', 'deleteTicketWithPartPrepared', 'WRITE');
|
||||||
const sales = await models.Sale.find({
|
const sales = await models.Sale.find({
|
||||||
include: {relation: 'itemShelvingSale'},
|
include: {relation: 'itemShelvingSale'},
|
||||||
where: {ticketFk: id}
|
where: {ticketFk: id}
|
||||||
|
@ -60,7 +63,7 @@ module.exports = Self => {
|
||||||
return sale.itemShelvingSale();
|
return sale.itemShelvingSale();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (hasItemShelvingSales && !isSalesAssistant)
|
if (hasItemShelvingSales && !canDeleteTicketWithPartPrepared)
|
||||||
throw new UserError(`You cannot delete a ticket that part of it is being prepared`);
|
throw new UserError(`You cannot delete a ticket that part of it is being prepared`);
|
||||||
|
|
||||||
// Check for existing claim
|
// Check for existing claim
|
||||||
|
|
|
@ -3,6 +3,7 @@ let UserError = require('vn-loopback/util/user-error');
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.remoteMethodCtx('transferSales', {
|
Self.remoteMethodCtx('transferSales', {
|
||||||
description: 'Transfer sales to a new or a given ticket',
|
description: 'Transfer sales to a new or a given ticket',
|
||||||
|
accessType: 'WRITE',
|
||||||
accepts: [{
|
accepts: [{
|
||||||
arg: 'id',
|
arg: 'id',
|
||||||
type: 'number',
|
type: 'number',
|
||||||
|
@ -78,7 +79,7 @@ module.exports = Self => {
|
||||||
const saleIds = sales.map(sale => sale.id);
|
const saleIds = sales.map(sale => sale.id);
|
||||||
|
|
||||||
const hasClaimedSales = await models.ClaimBeginning.findOne({where: {saleFk: {inq: saleIds}}});
|
const hasClaimedSales = await models.ClaimBeginning.findOne({where: {saleFk: {inq: saleIds}}});
|
||||||
if (hasClaimedSales)
|
if (ticketId != id && hasClaimedSales)
|
||||||
throw new UserError(`Can't transfer claimed sales`);
|
throw new UserError(`Can't transfer claimed sales`);
|
||||||
|
|
||||||
for (const sale of sales) {
|
for (const sale of sales) {
|
||||||
|
|
|
@ -85,17 +85,14 @@ module.exports = Self => {
|
||||||
|
|
||||||
const userId = ctx.req.accessToken.userId;
|
const userId = ctx.req.accessToken.userId;
|
||||||
const isLocked = await models.Ticket.isLocked(id, myOptions);
|
const isLocked = await models.Ticket.isLocked(id, myOptions);
|
||||||
const roles = await models.VnUser.getRoles(userId, myOptions);
|
const canEditDiscount = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'editDiscount');
|
||||||
const hasAllowedRoles = roles.filter(role =>
|
|
||||||
role == 'salesPerson' || role == 'claimManager'
|
|
||||||
);
|
|
||||||
|
|
||||||
const state = await Self.app.models.TicketState.findOne({
|
const state = await Self.app.models.TicketState.findOne({
|
||||||
where: {ticketFk: id}
|
where: {ticketFk: id}
|
||||||
}, myOptions);
|
}, myOptions);
|
||||||
const alertLevel = state ? state.alertLevel : null;
|
const alertLevel = state ? state.alertLevel : null;
|
||||||
|
|
||||||
if (isLocked || (!hasAllowedRoles && alertLevel > 0))
|
if (isLocked || (!canEditDiscount && alertLevel > 0))
|
||||||
throw new UserError(`The sales of this ticket can't be modified`);
|
throw new UserError(`The sales of this ticket can't be modified`);
|
||||||
|
|
||||||
const usesMana = await models.Sale.usesMana(ctx, myOptions);
|
const usesMana = await models.Sale.usesMana(ctx, myOptions);
|
||||||
|
|
|
@ -36,7 +36,6 @@ module.exports = function(Self) {
|
||||||
require('../methods/ticket/getTicketsFuture')(Self);
|
require('../methods/ticket/getTicketsFuture')(Self);
|
||||||
require('../methods/ticket/merge')(Self);
|
require('../methods/ticket/merge')(Self);
|
||||||
require('../methods/ticket/getTicketsAdvance')(Self);
|
require('../methods/ticket/getTicketsAdvance')(Self);
|
||||||
require('../methods/ticket/isRoleAdvanced')(Self);
|
|
||||||
require('../methods/ticket/collectionLabel')(Self);
|
require('../methods/ticket/collectionLabel')(Self);
|
||||||
require('../methods/ticket/expeditionPalletLabel')(Self);
|
require('../methods/ticket/expeditionPalletLabel')(Self);
|
||||||
require('../methods/ticket/saveSign')(Self);
|
require('../methods/ticket/saveSign')(Self);
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
<div class="search-panel">
|
<div class="search-panel">
|
||||||
|
<vn-crud-model
|
||||||
|
auto-load="true"
|
||||||
|
url="Warehouses"
|
||||||
|
data="warehouses">
|
||||||
|
</vn-crud-model>
|
||||||
<form id="manifold-form" ng-submit="$ctrl.onSearch()">
|
<form id="manifold-form" ng-submit="$ctrl.onSearch()">
|
||||||
<vn-horizontal class="vn-px-lg vn-pt-lg">
|
<vn-horizontal class="vn-px-lg vn-pt-lg">
|
||||||
<vn-date-picker
|
<vn-date-picker
|
||||||
|
@ -49,7 +54,9 @@
|
||||||
vn-one
|
vn-one
|
||||||
label="Warehouse"
|
label="Warehouse"
|
||||||
ng-model="filter.warehouseFk"
|
ng-model="filter.warehouseFk"
|
||||||
url="Warehouses"
|
data="warehouses"
|
||||||
|
show-field="name"
|
||||||
|
value-field="id"
|
||||||
required="true">
|
required="true">
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
|
|
|
@ -4,6 +4,11 @@
|
||||||
order="name"
|
order="name"
|
||||||
auto-load="true">
|
auto-load="true">
|
||||||
</vn-crud-model>
|
</vn-crud-model>
|
||||||
|
<vn-crud-model
|
||||||
|
auto-load="true"
|
||||||
|
url="Warehouses"
|
||||||
|
data="warehouses">
|
||||||
|
</vn-crud-model>
|
||||||
<form name="form">
|
<form name="form">
|
||||||
<vn-card class="vn-w-md vn-pa-lg">
|
<vn-card class="vn-w-md vn-pa-lg">
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
|
@ -25,7 +30,7 @@
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
<vn-autocomplete vn-one
|
<vn-autocomplete vn-one
|
||||||
required="true"
|
required="true"
|
||||||
url="Warehouses"
|
data="Warehouses"
|
||||||
label="Warehouse"
|
label="Warehouse"
|
||||||
show-field="name"
|
show-field="name"
|
||||||
value-field="id"
|
value-field="id"
|
||||||
|
|
|
@ -2,6 +2,11 @@
|
||||||
vn-id="watcher"
|
vn-id="watcher"
|
||||||
data="$ctrl.dms">
|
data="$ctrl.dms">
|
||||||
</vn-watcher>
|
</vn-watcher>
|
||||||
|
<vn-crud-model
|
||||||
|
auto-load="true"
|
||||||
|
url="Warehouses"
|
||||||
|
data="warehouses">
|
||||||
|
</vn-crud-model>
|
||||||
<form
|
<form
|
||||||
name="form"
|
name="form"
|
||||||
ng-submit="$ctrl.onSubmit()"
|
ng-submit="$ctrl.onSubmit()"
|
||||||
|
@ -29,7 +34,7 @@
|
||||||
<vn-autocomplete vn-one required="true"
|
<vn-autocomplete vn-one required="true"
|
||||||
label="Warehouse"
|
label="Warehouse"
|
||||||
ng-model="$ctrl.dms.warehouseId"
|
ng-model="$ctrl.dms.warehouseId"
|
||||||
url="Warehouses"
|
data="Warehouses"
|
||||||
show-field="name"
|
show-field="name"
|
||||||
value-field="id">
|
value-field="id">
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
<div class="search-panel">
|
<div class="search-panel">
|
||||||
|
<vn-crud-model
|
||||||
|
auto-load="true"
|
||||||
|
url="Warehouses"
|
||||||
|
data="warehouses">
|
||||||
|
</vn-crud-model>
|
||||||
<form id="manifold-form" ng-submit="$ctrl.onSearch()">
|
<form id="manifold-form" ng-submit="$ctrl.onSearch()">
|
||||||
<vn-horizontal class="vn-px-lg vn-pt-lg">
|
<vn-horizontal class="vn-px-lg vn-pt-lg">
|
||||||
<vn-date-picker
|
<vn-date-picker
|
||||||
|
@ -83,7 +88,9 @@
|
||||||
vn-one
|
vn-one
|
||||||
label="Warehouse"
|
label="Warehouse"
|
||||||
ng-model="filter.warehouseFk"
|
ng-model="filter.warehouseFk"
|
||||||
url="Warehouses"
|
data="warehouses"
|
||||||
|
show-field="name"
|
||||||
|
value-field="id"
|
||||||
required="true">
|
required="true">
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import ngModule from '../module';
|
import ngModule from '../module';
|
||||||
import ModuleMain from 'salix/components/module-main';
|
import ModuleMain from 'salix/components/module-main';
|
||||||
|
const UserError = require('vn-loopback/util/user-error');
|
||||||
|
|
||||||
export default class Ticket extends ModuleMain {
|
export default class Ticket extends ModuleMain {
|
||||||
fetchParams($params) {
|
fetchParams($params) {
|
||||||
|
@ -14,10 +15,19 @@ export default class Ticket extends ModuleMain {
|
||||||
'scopeDays'
|
'scopeDays'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const seachPanelParams = Object.entries($params);
|
||||||
|
const hasFromParam = seachPanelParams.some(subarray => subarray.length > 0 && subarray[0] === 'from');
|
||||||
|
const hasToParam = seachPanelParams.some(subarray => subarray.length > 0 && subarray[0] === 'to');
|
||||||
|
|
||||||
|
if ((hasFromParam && !hasToParam) || (!hasFromParam && hasToParam))
|
||||||
|
throw new UserError(`Date range must have 'from' and 'to'`);
|
||||||
|
|
||||||
const hasExcludedParams = excludedParams.some(param => {
|
const hasExcludedParams = excludedParams.some(param => {
|
||||||
return $params && $params[param] != undefined;
|
return $params && $params[param] != undefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
const hasParams = Object.entries($params).length;
|
const hasParams = Object.entries($params).length;
|
||||||
|
|
||||||
if (!hasParams || !hasExcludedParams)
|
if (!hasParams || !hasExcludedParams)
|
||||||
$params.scopeDays = 1;
|
$params.scopeDays = 1;
|
||||||
|
|
||||||
|
@ -28,7 +38,6 @@ export default class Ticket extends ModuleMain {
|
||||||
const to = new Date(from.getTime());
|
const to = new Date(from.getTime());
|
||||||
to.setDate(to.getDate() + $params.scopeDays);
|
to.setDate(to.getDate() + $params.scopeDays);
|
||||||
to.setHours(23, 59, 59, 999);
|
to.setHours(23, 59, 59, 999);
|
||||||
|
|
||||||
Object.assign($params, {from, to});
|
Object.assign($params, {from, to});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Date range must have 'from' and 'to': El rango de fechas debe tener 'desde' y 'hasta'
|
|
@ -244,7 +244,12 @@ class Controller extends Section {
|
||||||
|
|
||||||
const query = `tickets/${this.ticket.id}/transferSales`;
|
const query = `tickets/${this.ticket.id}/transferSales`;
|
||||||
this.$http.post(query, params)
|
this.$http.post(query, params)
|
||||||
.then(res => this.$state.go('ticket.card.sale', {id: res.data.id}));
|
.then(res => {
|
||||||
|
if (res.data && res.data.id === this.ticket.id) {
|
||||||
|
this.$.transfer.hide();
|
||||||
|
this.$.model.refresh();
|
||||||
|
} else this.$state.go('ticket.card.sale', {id: res.data.id});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
showEditPricePopover(event, sale) {
|
showEditPricePopover(event, sale) {
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
<div class="search-panel">
|
<div class="search-panel">
|
||||||
|
<vn-crud-model
|
||||||
|
auto-load="true"
|
||||||
|
url="Warehouses"
|
||||||
|
data="warehouses">
|
||||||
|
</vn-crud-model>
|
||||||
<form id="manifold-form" ng-submit="$ctrl.onSearch()">
|
<form id="manifold-form" ng-submit="$ctrl.onSearch()">
|
||||||
<vn-horizontal class="vn-px-lg vn-pt-lg">
|
<vn-horizontal class="vn-px-lg vn-pt-lg">
|
||||||
<vn-textfield
|
<vn-textfield
|
||||||
|
@ -102,7 +107,7 @@
|
||||||
vn-one
|
vn-one
|
||||||
label="Warehouse"
|
label="Warehouse"
|
||||||
ng-model="filter.warehouseFk"
|
ng-model="filter.warehouseFk"
|
||||||
url="Warehouses">
|
data="Warehouses">
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
<vn-autocomplete
|
<vn-autocomplete
|
||||||
vn-one
|
vn-one
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
<div class="search-panel">
|
<div class="search-panel">
|
||||||
|
<vn-crud-model
|
||||||
|
auto-load="true"
|
||||||
|
url="Warehouses"
|
||||||
|
data="warehouses">
|
||||||
|
</vn-crud-model>
|
||||||
<form ng-submit="$ctrl.onSearch()">
|
<form ng-submit="$ctrl.onSearch()">
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
<vn-textfield
|
<vn-textfield
|
||||||
|
@ -52,14 +57,14 @@
|
||||||
<vn-autocomplete vn-one
|
<vn-autocomplete vn-one
|
||||||
label="Warehouse Out"
|
label="Warehouse Out"
|
||||||
ng-model="filter.warehouseOutFk"
|
ng-model="filter.warehouseOutFk"
|
||||||
url="Warehouses"
|
data="Warehouses"
|
||||||
show-field="name"
|
show-field="name"
|
||||||
value-field="id">
|
value-field="id">
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
<vn-autocomplete vn-one
|
<vn-autocomplete vn-one
|
||||||
label="Warehouse In"
|
label="Warehouse In"
|
||||||
ng-model="filter.warehouseInFk"
|
ng-model="filter.warehouseInFk"
|
||||||
url="Warehouses"
|
data="Warehouses"
|
||||||
show-field="name"
|
show-field="name"
|
||||||
value-field="id">
|
value-field="id">
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
const app = require('vn-loopback/server/server');
|
const models = require('vn-loopback/server/server').models;
|
||||||
|
|
||||||
describe('worker-dms downloadFile()', () => {
|
describe('worker-dms downloadFile()', () => {
|
||||||
let dmsId = 4;
|
let dmsId = 4;
|
||||||
|
@ -6,7 +6,7 @@ describe('worker-dms downloadFile()', () => {
|
||||||
it('should return a response for an employee with text content-type', async() => {
|
it('should return a response for an employee with text content-type', async() => {
|
||||||
let workerId = 1106;
|
let workerId = 1106;
|
||||||
let ctx = {req: {accessToken: {userId: workerId}}};
|
let ctx = {req: {accessToken: {userId: workerId}}};
|
||||||
const result = await app.models.WorkerDms.downloadFile(ctx, dmsId);
|
const result = await models.WorkerDms.downloadFile(ctx, dmsId);
|
||||||
|
|
||||||
expect(result[1]).toEqual('text/plain');
|
expect(result[1]).toEqual('text/plain');
|
||||||
});
|
});
|
||||||
|
@ -17,7 +17,7 @@ describe('worker-dms downloadFile()', () => {
|
||||||
|
|
||||||
let error;
|
let error;
|
||||||
try {
|
try {
|
||||||
await app.models.WorkerDms.downloadFile(ctx, dmsId);
|
await models.WorkerDms.downloadFile(ctx, dmsId);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
error = e;
|
error = e;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,10 +40,10 @@ module.exports = Self => {
|
||||||
Object.assign(myOptions, options);
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
const isSubordinate = await models.Worker.isSubordinate(ctx, workerId, myOptions);
|
const isSubordinate = await models.Worker.isSubordinate(ctx, workerId, myOptions);
|
||||||
const isTeamBoss = await models.VnUser.hasRole(currentUserId, 'teamBoss', myOptions);
|
const isTeamBoss = await models.ACL.checkAccessAcl(ctx, 'Worker', 'isTeamBoss', 'WRITE');
|
||||||
const isHimself = currentUserId == workerId;
|
const isHimself = currentUserId == workerId;
|
||||||
|
|
||||||
if (isSubordinate === false || (isSubordinate && isHimself && !isTeamBoss))
|
if (!isSubordinate || (isSubordinate && isHimself && !isTeamBoss))
|
||||||
throw new UserError(`You don't have enough privileges`);
|
throw new UserError(`You don't have enough privileges`);
|
||||||
|
|
||||||
query = `CALL vn.workerTimeControl_clockIn(?,?,?)`;
|
query = `CALL vn.workerTimeControl_clockIn(?,?,?)`;
|
||||||
|
|
|
@ -32,7 +32,7 @@ module.exports = Self => {
|
||||||
|
|
||||||
const targetTimeEntry = await Self.findById(id, null, myOptions);
|
const targetTimeEntry = await Self.findById(id, null, myOptions);
|
||||||
const isSubordinate = await models.Worker.isSubordinate(ctx, targetTimeEntry.userFk, myOptions);
|
const isSubordinate = await models.Worker.isSubordinate(ctx, targetTimeEntry.userFk, myOptions);
|
||||||
const isTeamBoss = await models.VnUser.hasRole(currentUserId, 'teamBoss', myOptions);
|
const isTeamBoss = await models.ACL.checkAccessAcl(ctx, 'Worker', 'isTeamBoss', 'WRITE');
|
||||||
const isHimself = currentUserId == targetTimeEntry.userFk;
|
const isHimself = currentUserId == targetTimeEntry.userFk;
|
||||||
|
|
||||||
if (isSubordinate === false || (isSubordinate && isHimself && !isTeamBoss))
|
if (isSubordinate === false || (isSubordinate && isHimself && !isTeamBoss))
|
||||||
|
|
|
@ -38,7 +38,7 @@ module.exports = Self => {
|
||||||
|
|
||||||
const targetTimeEntry = await Self.findById(id, null, myOptions);
|
const targetTimeEntry = await Self.findById(id, null, myOptions);
|
||||||
const isSubordinate = await models.Worker.isSubordinate(ctx, targetTimeEntry.userFk, myOptions);
|
const isSubordinate = await models.Worker.isSubordinate(ctx, targetTimeEntry.userFk, myOptions);
|
||||||
const isTeamBoss = await models.VnUser.hasRole(currentUserId, 'teamBoss', myOptions);
|
const isTeamBoss = await models.ACL.checkAccessAcl(ctx, 'Worker', 'isTeamBoss', 'WRITE');
|
||||||
const isHimself = currentUserId == targetTimeEntry.userFk;
|
const isHimself = currentUserId == targetTimeEntry.userFk;
|
||||||
|
|
||||||
const notAllowed = isSubordinate === false || (isSubordinate && isHimself && !isTeamBoss);
|
const notAllowed = isSubordinate === false || (isSubordinate && isHimself && !isTeamBoss);
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue