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/),
|
||||
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
|
||||
- (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
|
||||
- (Trabajadores -> Nuevo trabajador) Los clientes se crean sin 'TR' pero se añade tipo de negocio 'Trabajador'
|
||||
|
||||
### 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
|
||||
- (Usuarios -> 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
|
||||
- (Artículo -> Precio fijado) Modificado el buscador superior por uno lateral
|
||||
- (Trabajadores -> Dar de alta) Quitada obligatoriedad del iban
|
||||
|
||||
### Fixed
|
||||
- (Ticket -> Boxing) Arreglado selección de horas
|
||||
|
|
|
@ -58,7 +58,10 @@ module.exports = Self => {
|
|||
for (const param in args)
|
||||
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);
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ module.exports = Self => {
|
|||
|
||||
if (!image) return false;
|
||||
|
||||
const hasReadRole = models.ImageCollection.hasReadRole(ctx, collection);
|
||||
const hasReadRole = await models.ImageCollection.hasReadRole(ctx, collection);
|
||||
if (!hasReadRole)
|
||||
throw new UserError(`You don't have enough privileges`);
|
||||
|
||||
|
|
|
@ -44,4 +44,4 @@
|
|||
"principalId": "$everyone",
|
||||
"permission": "ALLOW"
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,10 +9,11 @@ module.exports = Self => {
|
|||
* @return {boolean} True for user with read privileges
|
||||
*/
|
||||
Self.hasReadRole = async(ctx, name, options) => {
|
||||
const collection = await Self.findOne({where: {name}}, {
|
||||
const collection = await Self.findOne({
|
||||
include: {
|
||||
relation: 'readRole'
|
||||
}
|
||||
},
|
||||
where: {name}
|
||||
}, 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', 'updateAddress', '*', 'ALLOW', 'ROLE', 'employee'),
|
||||
('Client', 'updateFiscalData', '*', 'ALLOW', 'ROLE', 'employee'),
|
||||
('Client', 'updateUser', '*', 'ALLOW', 'ROLE', 'employee'),
|
||||
('Client', 'uploadFile', '*', 'ALLOW', 'ROLE', 'employee'),
|
||||
('Client', 'campaignMetricsPdf', '*', '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`)
|
||||
VALUES
|
||||
(1, 'Facturas Recibidas', 'recibidas', NULL, NULL, 'invoiceIn'),
|
||||
(2, 'Doc oficial', 'oficial', NULL, NULL, 'officialDoc'),
|
||||
(3, 'Laboral', 'laboral', 37, 37, 'hhrrData'),
|
||||
(4, 'Albaranes recibidos', 'entradas', NULL, NULL, 'deliveryNote'),
|
||||
(5, 'Otros', 'otros', 1, 1, 'miscellaneous'),
|
||||
(6, 'Pruebas', 'pruebas', NULL, NULL, 'tests'),
|
||||
(7, 'IAE Clientes', 'IAE_Clientes', 1, 1, 'economicActivitiesTax'),
|
||||
(8, 'Fiscal', 'fiscal', NULL, NULL, 'fiscal'),
|
||||
(9, 'Vehiculos', 'vehiculos', NULL, NULL, 'vehicles'),
|
||||
(10, 'Plantillas', 'plantillas', NULL, NULL, 'templates'),
|
||||
(11, 'Contratos', 'contratos', NULL, NULL, 'contracts'),
|
||||
(12, 'ley de pagos', 'ley pagos', 1, 1, 'paymentsLaw'),
|
||||
(13, 'Basura', 'basura', 1, 1, 'trash'),
|
||||
(14, 'Ticket', 'tickets', 1, 1, 'ticket'),
|
||||
(15, 'Presupuestos', 'Presupuestos', NULL, NULL, 'budgets'),
|
||||
(16, 'Logistica', 'logistica', NULL, NULL, 'logistics'),
|
||||
(17, 'cmr', 'cmr', NULL, NULL, 'cmr'),
|
||||
(18, 'dua', 'dua', NULL, NULL, 'dua'),
|
||||
(19, 'inmovilizado', 'inmovilizado', NULL, NULL, 'fixedAssets'),
|
||||
(20, 'Reclamación', 'reclamacion', 1, 1, 'claim');
|
||||
(1, 'Facturas Recibidas', 'recibidas', NULL, NULL, 'invoiceIn'),
|
||||
(2, 'Doc oficial', 'oficial', NULL, NULL, 'officialDoc'),
|
||||
(3, 'Laboral', 'laboral', 37, 37, 'hhrrData'),
|
||||
(4, 'Albaranes recibidos', 'entradas', NULL, NULL, 'deliveryNote'),
|
||||
(5, 'Otros', 'otros', 1, 1, 'miscellaneous'),
|
||||
(6, 'Pruebas', 'pruebas', NULL, NULL, 'tests'),
|
||||
(7, 'IAE Clientes', 'IAE_Clientes', 1, 1, 'economicActivitiesTax'),
|
||||
(8, 'Fiscal', 'fiscal', NULL, NULL, 'fiscal'),
|
||||
(9, 'Vehiculos', 'vehiculos', NULL, NULL, 'vehicles'),
|
||||
(10, 'Plantillas', 'plantillas', NULL, NULL, 'templates'),
|
||||
(11, 'Contratos', 'contratos', NULL, NULL, 'contracts'),
|
||||
(12, 'ley de pagos', 'ley pagos', 1, 1, 'paymentsLaw'),
|
||||
(13, 'Basura', 'basura', 1, 1, 'trash'),
|
||||
(14, 'Ticket', 'tickets', 1, 1, 'ticket'),
|
||||
(15, 'Presupuestos', 'Presupuestos', NULL, NULL, 'budgets'),
|
||||
(16, 'Logistica', 'logistica', NULL, NULL, 'logistics'),
|
||||
(17, 'cmr', 'cmr', NULL, NULL, 'cmr'),
|
||||
(18, 'dua', 'dua', NULL, NULL, 'dua'),
|
||||
(19, 'inmovilizado', 'inmovilizado', NULL, NULL, 'fixedAssets'),
|
||||
(20, 'Reclamación', 'reclamacion', 1, 1, 'claim');
|
||||
|
||||
INSERT INTO `vn`.`dms`(`id`, `dmsTypeFk`, `file`, `contentType`, `workerFk`, `warehouseFk`, `companyFk`, `hardCopyNumber`, `hasFile`, `reference`, `description`, `created`)
|
||||
VALUES
|
||||
|
@ -2824,9 +2824,9 @@ INSERT INTO `vn`.`payDemDetail` (`id`, `detail`)
|
|||
VALUES
|
||||
(1, 1);
|
||||
|
||||
INSERT INTO `vn`.`workerConfig` (`id`, `businessUpdated`, `roleFk`, `businessTypeFk`)
|
||||
INSERT INTO `vn`.`workerConfig` (`id`, `businessUpdated`, `roleFk`, `payMethodFk`, `businessTypeFk`)
|
||||
VALUES
|
||||
(1, NULL, 1, 'worker');
|
||||
(1, NULL, 1, 4, 'worker');
|
||||
|
||||
INSERT INTO `vn`.`ticketRefund`(`refundTicketFk`, `originalTicketFk`)
|
||||
VALUES
|
||||
|
|
|
@ -61943,141 +61943,205 @@ DELIMITER ;
|
|||
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
|
||||
/*!50003 SET sql_mode = 'IGNORE_SPACE,NO_ENGINE_SUBSTITUTION' */ ;
|
||||
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
|
||||
DECLARE vDateInventory DATETIME;
|
||||
DECLARE vCurdate DATE DEFAULT util.VN_CURDATE();
|
||||
DECLARE vDayEnd DATETIME DEFAULT util.dayEnd(vCurdate);
|
||||
/**
|
||||
* @vItemFk item a buscar
|
||||
* @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;
|
||||
SET @a = 0;
|
||||
SET @currentLineFk = 0;
|
||||
SET @shipped = '';
|
||||
DECLARE vDateInventory DATETIME;
|
||||
DECLARE vInvCalculated INT;
|
||||
|
||||
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 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
|
||||
IF vDate IS NULL THEN
|
||||
SELECT inventoried INTO vDateInventory
|
||||
FROM config;
|
||||
ELSE
|
||||
SELECT mockUtcTime INTO vDateInventory
|
||||
FROM util.config;
|
||||
END IF;
|
||||
|
||||
SELECT tr.shipped,
|
||||
NULL,
|
||||
b.quantity,
|
||||
al.id,
|
||||
st.name,
|
||||
s.name,
|
||||
e.invoiceNumber,
|
||||
e.id,
|
||||
s.id,
|
||||
IF(al.id = 3, 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.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
|
||||
CREATE OR REPLACE TEMPORARY TABLE itemDiary(
|
||||
shipped DATE,
|
||||
`in` INT(11),
|
||||
`out` INT(11),
|
||||
alertLevel INT(11),
|
||||
stateName VARCHAR(20),
|
||||
`name` VARCHAR(50),
|
||||
reference VARCHAR(50),
|
||||
origin INT(11),
|
||||
clientFk INT(11),
|
||||
isPicked INT(11),
|
||||
isTicket TINYINT(1),
|
||||
lineFk INT(11),
|
||||
`order` TINYINT(3) UNSIGNED,
|
||||
clientType VARCHAR(20),
|
||||
claimFk INT(10) UNSIGNED
|
||||
);
|
||||
|
||||
SELECT DATE(t.shipped),
|
||||
NULL,
|
||||
s.quantity,
|
||||
al.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.id =
|
||||
CASE
|
||||
WHEN t.shipped < util.VN_CURDATE() THEN 3
|
||||
WHEN t.shipped > util.dayEnd(util.VN_CURDATE()) THEN 0
|
||||
ELSE IFNULL(ts.alertLevel, 0)
|
||||
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 = vItemId
|
||||
AND vWarehouse =t.warehouseFk
|
||||
ORDER BY shipped, alertLevel DESC, isTicket, `order` DESC, isPicked DESC, `in` DESC, `out` DESC
|
||||
) AS itemDiary;
|
||||
INSERT INTO itemDiary
|
||||
SELECT tr.landed shipped,
|
||||
b.quantity `in`,
|
||||
NULL `out`,
|
||||
al.id alertLevel,
|
||||
st.name stateName,
|
||||
s.name `name`,
|
||||
e.invoiceNumber reference,
|
||||
e.id origin,
|
||||
s.id clientFk,
|
||||
IF(al.code = 'DELIVERED', TRUE, FALSE) isPicked,
|
||||
FALSE isTicket,
|
||||
b.id lineFk,
|
||||
NULL `order`,
|
||||
NULL clientType,
|
||||
NULL 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.code =
|
||||
CASE
|
||||
WHEN tr.landed < util.VN_CURDATE() THEN 'DELIVERED'
|
||||
WHEN tr.landed = util.VN_CURDATE() AND tr.isReceived = TRUE THEN 'DELIVERED'
|
||||
ELSE 'FREE'
|
||||
END
|
||||
JOIN state st ON st.code = al.code
|
||||
WHERE tr.landed >= vDateInventory
|
||||
AND vWarehouseFk = tr.warehouseInFk
|
||||
AND b.itemFk = vItemFk
|
||||
AND e.isExcludedFromAvailable = FALSE
|
||||
AND e.isRaid = FALSE
|
||||
UNION ALL
|
||||
SELECT tr.shipped,
|
||||
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 ;;
|
||||
DELIMITER ;
|
||||
/*!50003 SET sql_mode = @saved_sql_mode */ ;
|
||||
|
|
|
@ -313,7 +313,7 @@ export default {
|
|||
anyClient: 'vn-client-defaulter tbody > tr',
|
||||
firstClientName: 'vn-client-defaulter tbody > tr:nth-child(1) > td:nth-child(2) > span',
|
||||
firstSalesPersonName: 'vn-client-defaulter tbody > tr:nth-child(1) > td:nth-child(3) > span',
|
||||
firstObservation: 'vn-client-defaulter tbody > tr:nth-child(1) > td:nth-child(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',
|
||||
addObservationButton: 'vn-client-defaulter vn-button[icon="icon-notes"]',
|
||||
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() => {
|
||||
await page.loginAndModule('employee', 'claim');
|
||||
await page.loginAndModule('salesPerson', 'claim');
|
||||
await page.accessToSearchResult(claimId);
|
||||
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() => {
|
||||
await page.loginAndModule('employee', 'claim');
|
||||
await page.loginAndModule('salesPerson', 'claim');
|
||||
await page.accessToSearchResult(claimId);
|
||||
await page.waitForState('claim.card.summary');
|
||||
});
|
||||
|
|
|
@ -1,5 +1,20 @@
|
|||
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', () => {
|
||||
let browser;
|
||||
let page;
|
||||
|
|
|
@ -203,7 +203,7 @@ export default class Searchbar extends Component {
|
|||
|
||||
doSearch(filter, source) {
|
||||
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.then(data => this.onFilter(filter, source, data));
|
||||
this.toBar(filter);
|
||||
|
@ -259,12 +259,6 @@ export default class Searchbar extends Component {
|
|||
|
||||
this.filter = filter;
|
||||
|
||||
if (source == 'removeBar') {
|
||||
delete params[this.toRemove];
|
||||
delete this.model.userParams[this.toRemove];
|
||||
this.model.refresh();
|
||||
}
|
||||
|
||||
if (!filter && this.model)
|
||||
this.model.clear();
|
||||
if (source != 'state')
|
||||
|
@ -279,7 +273,7 @@ export default class Searchbar extends Component {
|
|||
return {id: params.$row.id};
|
||||
}
|
||||
|
||||
onSearch(args) {
|
||||
onSearch(args, source) {
|
||||
if (!this.model) return;
|
||||
let filter = args.$params;
|
||||
|
||||
|
@ -325,6 +319,12 @@ export default class Searchbar extends Component {
|
|||
for (let param in stateFilter.tableQ)
|
||||
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);
|
||||
return this.model.applyParams(newParams)
|
||||
.then(() => this.model.data);
|
||||
|
|
|
@ -197,7 +197,7 @@ describe('Component vnSearchbar', () => {
|
|||
controller.doSearch(filter, 'any');
|
||||
$scope.$apply();
|
||||
|
||||
expect(controller.onSearch).toHaveBeenCalledWith({$params: filter});
|
||||
expect(controller.onSearch).toHaveBeenCalledWith({$params: filter}, 'any');
|
||||
expect(controller.onFilter).toHaveBeenCalledWith(filter, 'any', undefined);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,22 +7,24 @@ vn-descriptor-content {
|
|||
|
||||
.photo {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
|
||||
& > img[ng-src] {
|
||||
min-height: 16em;
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
height: 256px;
|
||||
}
|
||||
|
||||
vn-float-button {
|
||||
position: absolute;
|
||||
margin: 1em;
|
||||
bottom: 0;
|
||||
position: absolute;
|
||||
margin: 1em;
|
||||
bottom: 0;
|
||||
right: 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
& > vn-spinner {
|
||||
display: block;
|
||||
height: 40px;
|
||||
|
@ -39,7 +41,7 @@ vn-descriptor-content {
|
|||
align-items: stretch;
|
||||
color: $color-font-dark;
|
||||
|
||||
& > a,
|
||||
& > a,
|
||||
& > vn-icon-button {
|
||||
display: flex;
|
||||
min-width: 45px;
|
||||
|
@ -89,7 +91,7 @@ vn-descriptor-content {
|
|||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
|
||||
& > vn-icon {
|
||||
padding: $spacing-xs $spacing-sm;
|
||||
font-size: 1.5rem;
|
||||
|
|
|
@ -171,5 +171,6 @@
|
|||
"Added observation": "Added observation",
|
||||
"Comment added to client": "Comment added to client",
|
||||
"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 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 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",
|
||||
"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",
|
||||
|
@ -290,5 +291,7 @@
|
|||
"isTaxDataChecked": "Datos comprobados",
|
||||
"comercialId": "Id 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);
|
||||
landedPlusWeek.setDate(landedPlusWeek.getDate() + 7);
|
||||
const hasClaimManagerRole = await models.VnUser.hasRole(userId, 'claimManager', myOptions);
|
||||
const isClaimable = landedPlusWeek >= Date.vnNew();
|
||||
|
||||
const canCreateClaimAfterDeadline =
|
||||
await models.ACL.checkAccessAcl(ctx, 'Claim', 'createAfterDeadline', 'WRITE');
|
||||
|
||||
if (ticket.isDeleted)
|
||||
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`);
|
||||
|
||||
const newClaim = await Self.create({
|
||||
|
|
|
@ -46,7 +46,6 @@ module.exports = Self => {
|
|||
|
||||
Self.updateClaim = async(ctx, id, options) => {
|
||||
const models = Self.app.models;
|
||||
const userId = ctx.req.accessToken.userId;
|
||||
const args = ctx.args;
|
||||
let tx;
|
||||
const myOptions = {};
|
||||
|
@ -81,9 +80,9 @@ module.exports = Self => {
|
|||
if (args.claimStateFk) {
|
||||
const canEditOldState = await models.ClaimState.isEditable(ctx, claim.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`);
|
||||
}
|
||||
|
||||
|
|
|
@ -87,15 +87,15 @@ module.exports = function(Self) {
|
|||
Self.updateAddress = async(ctx, clientId, addressId, options) => {
|
||||
const models = Self.app.models;
|
||||
const args = ctx.args;
|
||||
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 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`);
|
||||
|
||||
const address = await models.Address.findOne({
|
||||
|
|
|
@ -131,9 +131,10 @@ module.exports = Self => {
|
|||
myOptions.transaction = tx;
|
||||
}
|
||||
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);
|
||||
if (!isSalesAssistant && client.isTaxDataChecked)
|
||||
if (!canEditNotTaxDataChecked && client.isTaxDataChecked)
|
||||
throw new UserError(`Not enough privileges to edit a client with verified data`);
|
||||
// Sage data validation
|
||||
const taxDataChecked = args.isTaxDataChecked;
|
||||
|
|
|
@ -2,6 +2,7 @@ const UserError = require('vn-loopback/util/user-error');
|
|||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('updateUser', {
|
||||
description: 'Updates the user information',
|
||||
accessType: 'WRITE',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'id',
|
||||
|
@ -32,7 +33,6 @@ module.exports = Self => {
|
|||
|
||||
Self.updateUser = async function(ctx, id, options) {
|
||||
const models = Self.app.models;
|
||||
const userId = ctx.req.accessToken.userId;
|
||||
let tx;
|
||||
const myOptions = {};
|
||||
|
||||
|
@ -45,9 +45,8 @@ module.exports = Self => {
|
|||
}
|
||||
|
||||
try {
|
||||
const isSalesPerson = await models.VnUser.hasRole(userId, 'salesPerson', myOptions);
|
||||
|
||||
if (!isSalesPerson)
|
||||
const canEdit = await models.ACL.checkAccessAcl(ctx, 'Client', 'updateUser', 'WRITE');
|
||||
if (!canEdit)
|
||||
throw new UserError(`Not enough privileges to edit a client`);
|
||||
|
||||
const isClient = await models.Client.findById(id, null, myOptions);
|
||||
|
|
|
@ -67,9 +67,13 @@ module.exports = Self => {
|
|||
uw.id workerFk,
|
||||
uw.name workerName,
|
||||
c.creditInsurance,
|
||||
d.defaulterSinced
|
||||
d.defaulterSinced,
|
||||
cn.country,
|
||||
pm.name payMethod
|
||||
FROM vn.defaulter d
|
||||
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 account.user u ON u.id = c.salesPersonFk
|
||||
LEFT JOIN account.user uw ON uw.id = co.workerFk
|
||||
|
|
|
@ -218,9 +218,9 @@ module.exports = Self => {
|
|||
const models = Self.app.models;
|
||||
|
||||
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 isTaxDataChecked = hasChanges && (changes.isTaxDataChecked || orgData.isTaxDataChecked);
|
||||
|
@ -232,8 +232,8 @@ module.exports = Self => {
|
|||
const sageTransactionType = hasChanges && (changes.sageTransactionTypeFk || orgData.sageTransactionTypeFk);
|
||||
const sageTransactionTypeChanged = hasChanges && orgData.sageTransactionTypeFk != sageTransactionType;
|
||||
|
||||
const cantEditVerifiedData = isTaxDataCheckedChanged && !isSalesAssistant;
|
||||
const cantChangeSageData = (sageTaxTypeChanged || sageTransactionTypeChanged) && !isSalesAssistant;
|
||||
const cantEditVerifiedData = isTaxDataCheckedChanged && !editVerifiedDataWithoutTaxDataChecked;
|
||||
const cantChangeSageData = (sageTaxTypeChanged || sageTransactionTypeChanged) && !editVerifiedDataWithoutTaxDataChecked;
|
||||
|
||||
if (cantEditVerifiedData || cantChangeSageData)
|
||||
throw new UserError(`You don't have enough privileges`);
|
||||
|
@ -401,9 +401,10 @@ module.exports = Self => {
|
|||
Self.changeCredit = async function changeCredit(ctx, finalState, changes) {
|
||||
const models = Self.app.models;
|
||||
const userId = ctx.options.accessToken.userId;
|
||||
const accessToken = {req: {accessToken: ctx.options.accessToken} };
|
||||
|
||||
const isFinancialBoss = await models.VnUser.hasRole(userId, 'financialBoss', ctx.options);
|
||||
if (!isFinancialBoss) {
|
||||
const canEditCredit = await models.ACL.checkAccessAcl(accessToken, 'Client', 'editCredit', 'WRITE');
|
||||
if (!canEditCredit) {
|
||||
const lastCredit = await models.ClientCredit.findOne({
|
||||
where: {
|
||||
clientFk: finalState.id
|
||||
|
@ -412,10 +413,9 @@ module.exports = Self => {
|
|||
}, ctx.options);
|
||||
|
||||
const lastAmount = lastCredit && lastCredit.amount;
|
||||
const lastWorkerId = lastCredit && lastCredit.workerFk;
|
||||
const lastWorkerIsFinancialBoss = await models.VnUser.hasRole(lastWorkerId, 'financialBoss', ctx.options);
|
||||
const lastCreditIsNotEditable = !await models.ACL.checkAccessAcl(accessToken, 'Client', 'isNotEditableCredit', 'WRITE');
|
||||
|
||||
if (lastAmount == 0 && lastWorkerIsFinancialBoss)
|
||||
if (lastAmount == 0 && lastCreditIsNotEditable)
|
||||
throw new UserError(`You can't change the credit set to zero from a financialBoss`);
|
||||
|
||||
const creditLimits = await models.ClientCreditLimit.find({
|
||||
|
|
|
@ -29,6 +29,16 @@
|
|||
"type": "belongsTo",
|
||||
"model": "Client",
|
||||
"foreignKey": "clientFk"
|
||||
},
|
||||
"country": {
|
||||
"type": "belongsTo",
|
||||
"model": "Country",
|
||||
"foreignKey": "country"
|
||||
},
|
||||
"payMethod": {
|
||||
"type": "belongsTo",
|
||||
"model": "PayMethod",
|
||||
"foreignKey": "payMethod"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -57,6 +57,13 @@
|
|||
<th field="salesPersonFk">
|
||||
<span translate>Comercial</span>
|
||||
</th>
|
||||
<th field="country">
|
||||
<span translate>Country</span>
|
||||
</th>
|
||||
<th field="payMethod"
|
||||
vn-tooltip="Pay Method">
|
||||
<span translate>P.Method</span>
|
||||
</th>
|
||||
<th
|
||||
field="amount"
|
||||
vn-tooltip="Balance due">
|
||||
|
@ -111,6 +118,12 @@
|
|||
{{::defaulter.salesPersonName | dashIfEmpty}}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
{{::defaulter.country}}
|
||||
</td>
|
||||
<td>
|
||||
{{::defaulter.payMethod}}
|
||||
</td>
|
||||
<td>{{::defaulter.amount | currency: 'EUR': 2}}</td>
|
||||
<td>
|
||||
<span
|
||||
|
|
|
@ -20,8 +20,7 @@ export default class Controller extends Section {
|
|||
showField: 'name',
|
||||
valueField: 'id'
|
||||
}
|
||||
},
|
||||
{
|
||||
}, {
|
||||
field: 'salesPersonFk',
|
||||
autocomplete: {
|
||||
url: 'Workers/activeWithInheritedRole',
|
||||
|
@ -30,6 +29,18 @@ export default class Controller extends Section {
|
|||
showField: 'name',
|
||||
valueField: 'id',
|
||||
}
|
||||
}, {
|
||||
field: 'country',
|
||||
autocomplete: {
|
||||
showField: 'country',
|
||||
valueField: 'country'
|
||||
}
|
||||
}, {
|
||||
field: 'payMethodFk',
|
||||
autocomplete: {
|
||||
showField: 'name',
|
||||
valueField: 'id'
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'workerFk',
|
||||
|
@ -132,7 +143,7 @@ export default class Controller extends Section {
|
|||
sendMail() {
|
||||
const params = {
|
||||
defaulters: this.checked,
|
||||
observation: this.defaulter.observation
|
||||
observation: this.defaulter.observation,
|
||||
};
|
||||
this.$http.post(`Defaulters/observationEmail`, params);
|
||||
}
|
||||
|
@ -143,6 +154,8 @@ export default class Controller extends Section {
|
|||
case 'amount':
|
||||
case 'clientFk':
|
||||
case 'workerFk':
|
||||
case 'country':
|
||||
case 'payMethod':
|
||||
case 'salesPersonFk':
|
||||
return {[`d.${param}`]: value};
|
||||
case 'created':
|
||||
|
|
|
@ -9,3 +9,6 @@ Search client: Buscar clientes
|
|||
Worker who made the last observation: Trabajador que ha realizado la última observación
|
||||
Email sended!: Email enviado!
|
||||
Observation saved!: Observación añadida!
|
||||
P.Method: F.Pago
|
||||
Pay Method: Forma de Pago
|
||||
Country: Pais
|
|
@ -2,6 +2,11 @@
|
|||
vn-id="watcher"
|
||||
data="$ctrl.dms">
|
||||
</vn-watcher>
|
||||
<vn-crud-model
|
||||
auto-load="true"
|
||||
url="Warehouses"
|
||||
data="warehouses">
|
||||
</vn-crud-model>
|
||||
<form
|
||||
name="form"
|
||||
ng-submit="$ctrl.onSubmit()"
|
||||
|
@ -29,7 +34,7 @@
|
|||
<vn-autocomplete vn-one required="true"
|
||||
label="Warehouse"
|
||||
ng-model="$ctrl.dms.warehouseId"
|
||||
url="Warehouses"
|
||||
data="Warehouses"
|
||||
show-field="name"
|
||||
value-field="id">
|
||||
</vn-autocomplete>
|
||||
|
|
|
@ -5,6 +5,11 @@
|
|||
form="form"
|
||||
save="patch">
|
||||
</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">
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-horizontal>
|
||||
|
@ -152,14 +157,14 @@
|
|||
<vn-autocomplete
|
||||
label="Warehouse Out"
|
||||
ng-model="$ctrl.travelFilterParams.warehouseOutFk"
|
||||
url="Warehouses"
|
||||
data="Warehouses"
|
||||
show-field="name"
|
||||
value-field="id">
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete
|
||||
label="Warehouse In"
|
||||
ng-model="$ctrl.travelFilterParams.warehouseInFk"
|
||||
url="Warehouses"
|
||||
data="Warehouses"
|
||||
show-field="name"
|
||||
value-field="id">
|
||||
</vn-autocomplete>
|
||||
|
|
|
@ -25,7 +25,6 @@ module.exports = Self => {
|
|||
|
||||
Self.createPdf = async function(ctx, id, options) {
|
||||
const models = Self.app.models;
|
||||
const userId = ctx.req.accessToken.userId;
|
||||
|
||||
if (process.env.NODE_ENV == 'test')
|
||||
throw new UserError(`Action not allowed on the test environment`);
|
||||
|
@ -43,9 +42,9 @@ module.exports = Self => {
|
|||
|
||||
try {
|
||||
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`);
|
||||
|
||||
await invoiceOut.updateAttributes({
|
||||
|
|
|
@ -26,8 +26,8 @@ module.exports = Self => {
|
|||
Object.assign(myOptions, options);
|
||||
|
||||
const where = filter.where;
|
||||
const query = 'CALL vn.item_getBalance(?, ?)';
|
||||
const [diary] = await Self.rawSql(query, [where.itemFk, where.warehouseFk], myOptions);
|
||||
const query = 'CALL vn.item_getBalance(?, ?, ?)';
|
||||
const [diary] = await Self.rawSql(query, [where.itemFk, where.warehouseFk, where.date], myOptions);
|
||||
|
||||
for (const entry of diary)
|
||||
if (entry.clientType === 'loses') entry.highlighted = true;
|
||||
|
|
|
@ -21,7 +21,8 @@ describe('item getBalance()', () => {
|
|||
const filter = {
|
||||
where: {
|
||||
itemFk: 1,
|
||||
warehouseFk: 1
|
||||
warehouseFk: 1,
|
||||
date: null
|
||||
}
|
||||
};
|
||||
const results = await models.Item.getBalance(filter, options);
|
||||
|
@ -45,14 +46,16 @@ describe('item getBalance()', () => {
|
|||
const firstFilter = {
|
||||
where: {
|
||||
itemFk: 1,
|
||||
warehouseFk: 1
|
||||
warehouseFk: 1,
|
||||
date: null
|
||||
}
|
||||
};
|
||||
|
||||
const secondFilter = {
|
||||
where: {
|
||||
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
|
||||
module="item"
|
||||
description="$ctrl.item.name"
|
||||
|
@ -108,7 +113,9 @@
|
|||
<vn-autocomplete
|
||||
label="Warehouse"
|
||||
ng-model="$ctrl.warehouseFk"
|
||||
url="Warehouses">
|
||||
data="warehouses"
|
||||
show-field="name"
|
||||
value="id">>
|
||||
</vn-autocomplete>
|
||||
</tpl-body>
|
||||
<tpl-buttons>
|
||||
|
|
|
@ -25,6 +25,16 @@
|
|||
ng-model="$ctrl.warehouseFk"
|
||||
label="Select warehouse">
|
||||
</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-table model="model">
|
||||
<vn-thead>
|
||||
|
@ -44,7 +54,7 @@
|
|||
<vn-tr
|
||||
ng-class="::{
|
||||
'isIn': sale.invalue,
|
||||
'balanceNegative': sale.balance < 0}"
|
||||
'balanceNegative': sale.balance < 0}"
|
||||
ng-repeat="sale in sales"
|
||||
vn-repeat-last
|
||||
on-last="$ctrl.scrollToLine(sale.lastPreparedLineFk)"
|
||||
|
@ -58,7 +68,7 @@
|
|||
</a>
|
||||
</vn-td>
|
||||
<vn-td expand>
|
||||
<span class="chip"
|
||||
<span class="chip"
|
||||
ng-class="::{warning: $ctrl.today == sale.shipped}">
|
||||
{{::sale.shipped | date:'dd/MM/yyyy' }}
|
||||
</span>
|
||||
|
@ -99,13 +109,13 @@
|
|||
</vn-vertical>
|
||||
</vn-card>
|
||||
</vn-vertical>
|
||||
<vn-ticket-descriptor-popover
|
||||
<vn-ticket-descriptor-popover
|
||||
vn-id="ticket-descriptor">
|
||||
</vn-ticket-descriptor-popover>
|
||||
<vn-client-descriptor-popover
|
||||
<vn-client-descriptor-popover
|
||||
vn-id="clientDescriptor">
|
||||
</vn-client-descriptor-popover>
|
||||
<vn-entry-descriptor-popover
|
||||
<vn-entry-descriptor-popover
|
||||
vn-id="entryDescriptor">
|
||||
</vn-entry-descriptor-popover>
|
||||
|
||||
|
|
|
@ -38,12 +38,8 @@ class Controller extends Section {
|
|||
if (value && value != this._warehouseFk) {
|
||||
this._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();
|
||||
}
|
||||
}
|
||||
|
@ -52,6 +48,28 @@ class Controller extends Section {
|
|||
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) {
|
||||
this.$.$applyAsync(() => {
|
||||
const hashFk = this.lineFk || lineFk;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
In: Entrada
|
||||
Out: Salida
|
||||
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;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
.table-check{
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
<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()">
|
||||
<vn-horizontal class="vn-px-lg vn-pt-lg">
|
||||
<vn-textfield
|
||||
|
@ -35,7 +40,9 @@
|
|||
vn-one
|
||||
label="Warehouse"
|
||||
ng-model="filter.warehouseFk"
|
||||
url="Warehouses">
|
||||
data="warehouses"
|
||||
show-field="name"
|
||||
value-field="id">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal class="vn-px-lg">
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
<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()">
|
||||
<vn-horizontal class="vn-px-lg vn-pt-lg">
|
||||
<vn-textfield
|
||||
|
@ -83,7 +88,7 @@
|
|||
vn-one
|
||||
label="Warehouse"
|
||||
ng-model="filter.warehouseFk"
|
||||
url="Warehouses">
|
||||
data="Warehouses">
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
<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()">
|
||||
<vn-horizontal class="vn-px-lg vn-pt-lg">
|
||||
<vn-textfield
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
<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()">
|
||||
<vn-horizontal class="vn-px-lg vn-pt-lg">
|
||||
<vn-textfield
|
||||
|
@ -79,7 +84,7 @@
|
|||
vn-one
|
||||
label="Warehouse"
|
||||
ng-model="filter.warehouseFk"
|
||||
url="Warehouses"
|
||||
data="Warehouses"
|
||||
show-field="name"
|
||||
value-field="id">
|
||||
</vn-autocomplete>
|
||||
|
|
|
@ -99,18 +99,20 @@ module.exports = Self => {
|
|||
|
||||
Self.observe('before save', async function(ctx) {
|
||||
if (ctx.isNewInstance) return;
|
||||
const loopbackContext = LoopBackContext.getCurrentContext();
|
||||
const changes = ctx.data || ctx.instance;
|
||||
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 hasChanges = orgData && changes;
|
||||
const isPayMethodCheckedChanged = hasChanges
|
||||
&& orgData.isPayMethodChecked != isPayMethodChecked;
|
||||
|
||||
if (isNotFinancial && isPayMethodCheckedChanged)
|
||||
if (!editPayMethodCheck && isPayMethodCheckedChanged)
|
||||
throw new UserError('You can not modify is pay method checked');
|
||||
});
|
||||
|
||||
|
|
|
@ -38,6 +38,9 @@ module.exports = Self => {
|
|||
}
|
||||
}, myOptions);
|
||||
|
||||
if (!salesData.length)
|
||||
throw new UserError(`The sales do not exists`);
|
||||
|
||||
const ticketId = salesData[0].ticketFk;
|
||||
|
||||
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');
|
||||
if (!shouldEditFloramondo)
|
||||
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', () => {
|
||||
it('should return true if the role is production regardless of the saleTrackings', async() => {
|
||||
const tx = await models.Sale.beginTransaction({});
|
||||
|
@ -29,9 +55,7 @@ describe('sale canEdit()', () => {
|
|||
|
||||
const sales = [25];
|
||||
|
||||
const result = await models.Sale.canEdit(ctx, sales, options);
|
||||
|
||||
expect(result).toEqual(true);
|
||||
await models.Sale.canEdit(ctx, sales, options);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
|
@ -51,9 +75,7 @@ describe('sale canEdit()', () => {
|
|||
|
||||
const sales = [10];
|
||||
|
||||
const result = await models.Sale.canEdit(ctx, sales, options);
|
||||
|
||||
expect(result).toEqual(true);
|
||||
await models.Sale.canEdit(ctx, sales, options);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
|
@ -87,9 +109,7 @@ describe('sale canEdit()', () => {
|
|||
});
|
||||
const ctx = {req: {accessToken: {userId: role.id}}};
|
||||
|
||||
const result = await models.Sale.canEdit(ctx, saleCloned, options);
|
||||
|
||||
expect(result).toEqual(true);
|
||||
await models.Sale.canEdit(ctx, saleCloned, options);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
|
@ -150,9 +170,7 @@ describe('sale canEdit()', () => {
|
|||
const saleToEdit = await models.Sale.findById(sales[0], null, options);
|
||||
await saleToEdit.updateAttribute('itemFk', 9, options);
|
||||
|
||||
const result = await models.Sale.canEdit(ctx, sales, options);
|
||||
|
||||
expect(result).toEqual(true);
|
||||
await models.Sale.canEdit(ctx, sales, options);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
|
|
|
@ -64,7 +64,7 @@ describe('sale updateQuantity()', () => {
|
|||
try {
|
||||
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);
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ module.exports = Self => {
|
|||
|
||||
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)
|
||||
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) => {
|
||||
const models = Self.app.models;
|
||||
const userId = ctx.req.accessToken.userId;
|
||||
const myOptions = {...(options || {})};
|
||||
|
||||
const isProduction = await models.VnUser.hasRole(userId, 'production', myOptions);
|
||||
const isAdministrative = await models.VnUser.hasRole(userId, 'administrative', myOptions);
|
||||
const seeEditableStates = await models.ACL.checkAccessAcl(ctx, 'State', 'seeEditableStates', 'READ');
|
||||
|
||||
if (!isProduction && !isAdministrative)
|
||||
if (!seeEditableStates)
|
||||
filter = mergeFilters(filter, {where: {alertLevel: 0}});
|
||||
|
||||
const states = await models.State.find(filter, myOptions);
|
||||
|
|
|
@ -19,22 +19,23 @@ module.exports = Self => {
|
|||
});
|
||||
|
||||
Self.isEditable = async(ctx, stateId, options) => {
|
||||
const accessToken = ctx.req.accessToken;
|
||||
const models = Self.app.models;
|
||||
const userId = accessToken.userId;
|
||||
const myOptions = {};
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
const isProduction = await models.VnUser.hasRole(userId, 'production', myOptions);
|
||||
const isSalesPerson = await models.VnUser.hasRole(userId, 'salesPerson', myOptions);
|
||||
const isAdministrative = await models.VnUser.hasRole(userId, 'administrative', myOptions);
|
||||
const isAllEditable = await models.ACL.checkAccessAcl(ctx, 'State', 'isAllEditable', 'READ');
|
||||
|
||||
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 = isProduction || isAdministrative || salesPersonAllowed || state.alertLevel == 0;
|
||||
const isAllowed = isAllEditable || isSomeEditable || state.alertLevel == 0;
|
||||
return isAllowed;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -52,7 +52,7 @@ module.exports = Self => {
|
|||
JOIN province p ON p.id = c.provinceFk
|
||||
JOIN country co ON co.id = p.countryFk
|
||||
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 util.dayEnd(?)
|
||||
AND t.refFk IS NULL
|
||||
|
|
|
@ -121,8 +121,8 @@ module.exports = Self => {
|
|||
if (!isEditable)
|
||||
throw new UserError(`The sales of this ticket can't be modified`);
|
||||
|
||||
const isDeliveryBoss = await models.VnUser.hasRole(userId, 'deliveryBoss', myOptions);
|
||||
if (!isDeliveryBoss) {
|
||||
const editZone = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'editZone', 'WRITE');
|
||||
if (!editZone) {
|
||||
const zoneShipped = await models.Agency.getShipped(
|
||||
ctx,
|
||||
args.landed,
|
||||
|
|
|
@ -30,7 +30,7 @@ module.exports = Self => {
|
|||
where: {ticketFk: id}
|
||||
}, 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 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}
|
||||
};
|
||||
|
||||
await models.TicketLog.create(ticketDestinationLogRecord, myOptions);
|
||||
await models.Sale.updateAll({ticketFk: ticket.originId}, {ticketFk: ticket.destinationId}, myOptions);
|
||||
await models.Ticket.setDeleted(ctx, ticket.originId, myOptions);
|
||||
await models.Chat.sendCheckingPresence(ctx, ticket.workerFk, message);
|
||||
if (await models.Ticket.setDeleted(ctx, ticket.originId, myOptions)) {
|
||||
await models.TicketLog.create(ticketDestinationLogRecord, myOptions);
|
||||
await models.Chat.sendCheckingPresence(ctx, ticket.workerFk, message);
|
||||
}
|
||||
}
|
||||
if (tx)
|
||||
await tx.commit();
|
||||
|
|
|
@ -60,7 +60,6 @@ module.exports = Self => {
|
|||
Self.priceDifference = async(ctx, options) => {
|
||||
const args = ctx.args;
|
||||
const models = Self.app.models;
|
||||
const userId = ctx.req.accessToken.userId;
|
||||
const myOptions = {};
|
||||
let tx;
|
||||
|
||||
|
@ -78,8 +77,8 @@ module.exports = Self => {
|
|||
if (!isEditable)
|
||||
throw new UserError(`The sales of this ticket can't be modified`);
|
||||
|
||||
const isDeliveryBoss = await models.VnUser.hasRole(userId, 'deliveryBoss', myOptions);
|
||||
if (!isDeliveryBoss) {
|
||||
const editZone = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'editZone', 'WRITE');
|
||||
if (!editZone) {
|
||||
const zoneShipped = await models.Agency.getShipped(
|
||||
ctx,
|
||||
args.landed,
|
||||
|
|
|
@ -29,8 +29,7 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
Self.saveSign = async(ctx, options) => {
|
||||
const args = Object.assign({}, ctx.args);
|
||||
Self.saveSign = async(ctx, tickets, location, signedTime, options) => {
|
||||
const models = Self.app.models;
|
||||
const myOptions = {};
|
||||
let tx;
|
||||
|
@ -48,9 +47,9 @@ module.exports = Self => {
|
|||
async function setLocation(ticketId) {
|
||||
await models.Delivery.create({
|
||||
ticketFk: ticketId,
|
||||
longitude: args.location.Longitude,
|
||||
latitude: args.location.Latitude,
|
||||
dated: args.signedTime || new Date()
|
||||
longitude: location.Longitude,
|
||||
latitude: location.Latitude,
|
||||
dated: signedTime || new Date()
|
||||
}, myOptions);
|
||||
}
|
||||
|
||||
|
@ -107,9 +106,9 @@ module.exports = Self => {
|
|||
}
|
||||
|
||||
try {
|
||||
for (let i = 0; i < args.tickets.length; i++) {
|
||||
for (const ticketId of tickets) {
|
||||
const ticketState = await models.TicketState.findOne(
|
||||
{where: {ticketFk: args.tickets[i]},
|
||||
{where: {ticketFk: ticketId},
|
||||
fields: ['alertLevel']
|
||||
}, myOptions);
|
||||
|
||||
|
@ -117,16 +116,19 @@ module.exports = Self => {
|
|||
fields: ['id']
|
||||
}, myOptions);
|
||||
|
||||
if (!ticketState)
|
||||
throw new UserError('Ticket does not exist');
|
||||
if (ticketState.alertLevel < packedAlertLevel.id)
|
||||
throw new UserError('This ticket cannot be signed because it has not been boxed');
|
||||
else if (!await gestDocExists(args.tickets[i])) {
|
||||
if (args.location) setLocation(args.tickets[i]);
|
||||
if (!gestDocCreated) await createGestDoc(args.tickets[i]);
|
||||
await models.TicketDms.create({ticketFk: args.tickets[i], dmsFk: dms[0].id}, myOptions);
|
||||
const ticket = await models.Ticket.findById(args.tickets[i], null, myOptions);
|
||||
await ticket.updateAttribute('isSigned', true, myOptions);
|
||||
await Self.rawSql(`CALL vn.ticket_setState(?, ?)`, [args.tickets[i], 'DELIVERED'], myOptions);
|
||||
}
|
||||
if (await gestDocExists(ticketId))
|
||||
throw new UserError('Ticket is already signed');
|
||||
|
||||
if (location) setLocation(ticketId);
|
||||
if (!gestDocCreated) await createGestDoc(ticketId);
|
||||
await models.TicketDms.create({ticketFk: ticketId, dmsFk: dms[0].id}, 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();
|
||||
|
|
|
@ -36,7 +36,9 @@ module.exports = Self => {
|
|||
}
|
||||
|
||||
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);
|
||||
|
||||
if (!isEditable)
|
||||
|
@ -51,7 +53,8 @@ module.exports = Self => {
|
|||
throw new UserError($t('Tickets with associated refunds', {id: ticketRefunds[0].id}));
|
||||
|
||||
// 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({
|
||||
include: {relation: 'itemShelvingSale'},
|
||||
where: {ticketFk: id}
|
||||
|
@ -60,7 +63,7 @@ module.exports = Self => {
|
|||
return sale.itemShelvingSale();
|
||||
});
|
||||
|
||||
if (hasItemShelvingSales && !isSalesAssistant)
|
||||
if (hasItemShelvingSales && !canDeleteTicketWithPartPrepared)
|
||||
throw new UserError(`You cannot delete a ticket that part of it is being prepared`);
|
||||
|
||||
// Check for existing claim
|
||||
|
|
|
@ -3,6 +3,7 @@ let UserError = require('vn-loopback/util/user-error');
|
|||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('transferSales', {
|
||||
description: 'Transfer sales to a new or a given ticket',
|
||||
accessType: 'WRITE',
|
||||
accepts: [{
|
||||
arg: 'id',
|
||||
type: 'number',
|
||||
|
@ -78,7 +79,7 @@ module.exports = Self => {
|
|||
const saleIds = sales.map(sale => sale.id);
|
||||
|
||||
const hasClaimedSales = await models.ClaimBeginning.findOne({where: {saleFk: {inq: saleIds}}});
|
||||
if (hasClaimedSales)
|
||||
if (ticketId != id && hasClaimedSales)
|
||||
throw new UserError(`Can't transfer claimed sales`);
|
||||
|
||||
for (const sale of sales) {
|
||||
|
|
|
@ -85,17 +85,14 @@ module.exports = Self => {
|
|||
|
||||
const userId = ctx.req.accessToken.userId;
|
||||
const isLocked = await models.Ticket.isLocked(id, myOptions);
|
||||
const roles = await models.VnUser.getRoles(userId, myOptions);
|
||||
const hasAllowedRoles = roles.filter(role =>
|
||||
role == 'salesPerson' || role == 'claimManager'
|
||||
);
|
||||
const canEditDiscount = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'editDiscount');
|
||||
|
||||
const state = await Self.app.models.TicketState.findOne({
|
||||
where: {ticketFk: id}
|
||||
}, myOptions);
|
||||
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`);
|
||||
|
||||
const usesMana = await models.Sale.usesMana(ctx, myOptions);
|
||||
|
|
|
@ -36,7 +36,6 @@ module.exports = function(Self) {
|
|||
require('../methods/ticket/getTicketsFuture')(Self);
|
||||
require('../methods/ticket/merge')(Self);
|
||||
require('../methods/ticket/getTicketsAdvance')(Self);
|
||||
require('../methods/ticket/isRoleAdvanced')(Self);
|
||||
require('../methods/ticket/collectionLabel')(Self);
|
||||
require('../methods/ticket/expeditionPalletLabel')(Self);
|
||||
require('../methods/ticket/saveSign')(Self);
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
<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()">
|
||||
<vn-horizontal class="vn-px-lg vn-pt-lg">
|
||||
<vn-date-picker
|
||||
|
@ -49,7 +54,9 @@
|
|||
vn-one
|
||||
label="Warehouse"
|
||||
ng-model="filter.warehouseFk"
|
||||
url="Warehouses"
|
||||
data="warehouses"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
required="true">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
|
|
|
@ -4,6 +4,11 @@
|
|||
order="name"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<vn-crud-model
|
||||
auto-load="true"
|
||||
url="Warehouses"
|
||||
data="warehouses">
|
||||
</vn-crud-model>
|
||||
<form name="form">
|
||||
<vn-card class="vn-w-md vn-pa-lg">
|
||||
<vn-horizontal>
|
||||
|
@ -25,7 +30,7 @@
|
|||
</vn-autocomplete>
|
||||
<vn-autocomplete vn-one
|
||||
required="true"
|
||||
url="Warehouses"
|
||||
data="Warehouses"
|
||||
label="Warehouse"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
|
|
|
@ -2,6 +2,11 @@
|
|||
vn-id="watcher"
|
||||
data="$ctrl.dms">
|
||||
</vn-watcher>
|
||||
<vn-crud-model
|
||||
auto-load="true"
|
||||
url="Warehouses"
|
||||
data="warehouses">
|
||||
</vn-crud-model>
|
||||
<form
|
||||
name="form"
|
||||
ng-submit="$ctrl.onSubmit()"
|
||||
|
@ -29,7 +34,7 @@
|
|||
<vn-autocomplete vn-one required="true"
|
||||
label="Warehouse"
|
||||
ng-model="$ctrl.dms.warehouseId"
|
||||
url="Warehouses"
|
||||
data="Warehouses"
|
||||
show-field="name"
|
||||
value-field="id">
|
||||
</vn-autocomplete>
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
<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()">
|
||||
<vn-horizontal class="vn-px-lg vn-pt-lg">
|
||||
<vn-date-picker
|
||||
|
@ -83,7 +88,9 @@
|
|||
vn-one
|
||||
label="Warehouse"
|
||||
ng-model="filter.warehouseFk"
|
||||
url="Warehouses"
|
||||
data="warehouses"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
required="true">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
|
|
|
@ -16,4 +16,4 @@
|
|||
<vn-portal slot="menu">
|
||||
<vn-left-menu></vn-left-menu>
|
||||
</vn-portal>
|
||||
<ui-view></ui-view>
|
||||
<ui-view></ui-view>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import ngModule from '../module';
|
||||
import ModuleMain from 'salix/components/module-main';
|
||||
const UserError = require('vn-loopback/util/user-error');
|
||||
|
||||
export default class Ticket extends ModuleMain {
|
||||
fetchParams($params) {
|
||||
|
@ -14,10 +15,19 @@ export default class Ticket extends ModuleMain {
|
|||
'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 => {
|
||||
return $params && $params[param] != undefined;
|
||||
});
|
||||
|
||||
const hasParams = Object.entries($params).length;
|
||||
|
||||
if (!hasParams || !hasExcludedParams)
|
||||
$params.scopeDays = 1;
|
||||
|
||||
|
@ -28,7 +38,6 @@ export default class Ticket extends ModuleMain {
|
|||
const to = new Date(from.getTime());
|
||||
to.setDate(to.getDate() + $params.scopeDays);
|
||||
to.setHours(23, 59, 59, 999);
|
||||
|
||||
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`;
|
||||
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) {
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
<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()">
|
||||
<vn-horizontal class="vn-px-lg vn-pt-lg">
|
||||
<vn-textfield
|
||||
|
@ -102,7 +107,7 @@
|
|||
vn-one
|
||||
label="Warehouse"
|
||||
ng-model="filter.warehouseFk"
|
||||
url="Warehouses">
|
||||
data="Warehouses">
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
<div class="search-panel">
|
||||
<vn-crud-model
|
||||
auto-load="true"
|
||||
url="Warehouses"
|
||||
data="warehouses">
|
||||
</vn-crud-model>
|
||||
<form ng-submit="$ctrl.onSearch()">
|
||||
<vn-horizontal>
|
||||
<vn-textfield
|
||||
|
@ -52,14 +57,14 @@
|
|||
<vn-autocomplete vn-one
|
||||
label="Warehouse Out"
|
||||
ng-model="filter.warehouseOutFk"
|
||||
url="Warehouses"
|
||||
data="Warehouses"
|
||||
show-field="name"
|
||||
value-field="id">
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete vn-one
|
||||
label="Warehouse In"
|
||||
ng-model="filter.warehouseInFk"
|
||||
url="Warehouses"
|
||||
data="Warehouses"
|
||||
show-field="name"
|
||||
value-field="id">
|
||||
</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()', () => {
|
||||
let dmsId = 4;
|
||||
|
@ -6,7 +6,7 @@ describe('worker-dms downloadFile()', () => {
|
|||
it('should return a response for an employee with text content-type', async() => {
|
||||
let workerId = 1106;
|
||||
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');
|
||||
});
|
||||
|
@ -17,7 +17,7 @@ describe('worker-dms downloadFile()', () => {
|
|||
|
||||
let error;
|
||||
try {
|
||||
await app.models.WorkerDms.downloadFile(ctx, dmsId);
|
||||
await models.WorkerDms.downloadFile(ctx, dmsId);
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
|
|
|
@ -40,10 +40,10 @@ module.exports = Self => {
|
|||
Object.assign(myOptions, options);
|
||||
|
||||
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;
|
||||
|
||||
if (isSubordinate === false || (isSubordinate && isHimself && !isTeamBoss))
|
||||
if (!isSubordinate || (isSubordinate && isHimself && !isTeamBoss))
|
||||
throw new UserError(`You don't have enough privileges`);
|
||||
|
||||
query = `CALL vn.workerTimeControl_clockIn(?,?,?)`;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue