merge
gitea/salix/test This commit looks good
Details
gitea/salix/test This commit looks good
Details
This commit is contained in:
commit
67733e6e08
|
@ -68,7 +68,6 @@ pipeline {
|
|||
environment {
|
||||
NODE_ENV = ""
|
||||
FIREFOX_BIN = "/opt/firefox/firefox-bin"
|
||||
DB_HOST = "${env.DOCKER_HOST_2}"
|
||||
}
|
||||
steps {
|
||||
nodejs('node-lts') {
|
||||
|
|
|
@ -19,8 +19,8 @@ module.exports = Self => {
|
|||
next();
|
||||
});
|
||||
|
||||
Self.remoteMethod('getCurrentUserName', {
|
||||
description: 'Gets the current user name',
|
||||
Self.remoteMethod('getCurrentUserData', {
|
||||
description: 'Gets the current user data',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'context',
|
||||
|
@ -31,21 +31,22 @@ module.exports = Self => {
|
|||
}
|
||||
],
|
||||
returns: {
|
||||
type: 'string',
|
||||
type: 'object',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
verb: 'GET',
|
||||
path: '/getCurrentUserName'
|
||||
path: '/getCurrentUserData'
|
||||
}
|
||||
});
|
||||
|
||||
Self.getCurrentUserName = async function(ctx) {
|
||||
Self.getCurrentUserData = async function(ctx) {
|
||||
let filter = {fields: ['name']};
|
||||
let userId = ctx.req.accessToken.userId;
|
||||
let account = await Self.findById(userId, filter);
|
||||
let worker = await Self.app.models.Worker.findOne({where: {userFk: userId}, fields: ['id']});
|
||||
|
||||
return account.name;
|
||||
return {accountName: account.name, workerId: worker.id};
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||
VALUES
|
||||
('Dms', '*', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||
('ClaimDms', 'removeFile', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
|
||||
('ClaimDms', '*', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||
('Claim', 'uploadFile', 'WRITE', 'ALLOW', 'ROLE', 'employee');
|
|
@ -0,0 +1,15 @@
|
|||
CREATE TABLE `vn`.`claimDms` (
|
||||
`claimFk` INT UNSIGNED NOT NULL,
|
||||
`dmsFk` INT NOT NULL,
|
||||
PRIMARY KEY (`claimFk`, `dmsFk`),
|
||||
INDEX `dmsFk_idx` (`dmsFk` ASC),
|
||||
CONSTRAINT `claimFk`
|
||||
FOREIGN KEY (`claimFk`)
|
||||
REFERENCES `vn2008`.`cl_main` (`id`)
|
||||
ON DELETE CASCADE
|
||||
ON UPDATE CASCADE,
|
||||
CONSTRAINT `dmsFk`
|
||||
FOREIGN KEY (`dmsFk`)
|
||||
REFERENCES `vn2008`.`gestdoc` (`id`)
|
||||
ON DELETE CASCADE
|
||||
ON UPDATE CASCADE);
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE `vn`.`claimLog`
|
||||
CHANGE COLUMN `id` `id` INT(11) NOT NULL AUTO_INCREMENT ;
|
File diff suppressed because one or more lines are too long
|
@ -133,19 +133,13 @@ INSERT INTO `vn`.`payDem`(`id`, `payDem`)
|
|||
(1, 10),
|
||||
(2, 20);
|
||||
|
||||
INSERT INTO `vn2008`.`zones`(`zone_id`, `name`, `printingOrder`)
|
||||
VALUES
|
||||
(1, 'zone one', 1),
|
||||
(2, 'zone two', 2),
|
||||
(3, 'zone three', 3);
|
||||
|
||||
INSERT INTO `vn`.`province`(`id`, `name`, `countryFk`, `warehouseFk`, `zoneFk`)
|
||||
INSERT INTO `vn`.`province`(`id`, `name`, `countryFk`, `warehouseFk`)
|
||||
VALUES
|
||||
(1, 'Province one', 1, NULL, 1),
|
||||
(2, 'Province two', 1, NULL, 2),
|
||||
(3, 'Province three', 1, NULL, 3),
|
||||
(4, 'Province four', 1, NULL, 2),
|
||||
(5, 'Province five', 1, NULL, 1);
|
||||
(1, 'Province one', 1, NULL),
|
||||
(2, 'Province two', 1, NULL),
|
||||
(3, 'Province three', 1, NULL),
|
||||
(4, 'Province four', 1, NULL),
|
||||
(5, 'Province five', 1, NULL);
|
||||
|
||||
INSERT INTO `vn`.`town`(`id`, `name`, `provinceFk`)
|
||||
VALUES
|
||||
|
@ -397,12 +391,24 @@ UPDATE `vn`.`invoiceOut` SET ref = 'A1111111' WHERE id = 5;
|
|||
|
||||
INSERT INTO `vn`.`invoiceOutTax` (`invoiceOutFk`, `taxableBase`, `vat`, `pgcFk`)
|
||||
VALUES
|
||||
(1, 895.76, 89.58, 4722000010),
|
||||
(1, 33.80, 7.10, 4722000021),
|
||||
(2, 110.33, 11.03, 4770000010),
|
||||
(3, 8.07, 0.81, 4770000010),
|
||||
(4, 8.07, 0.81, 4770000010),
|
||||
(5, 8.07, 0.81, 4770000010);
|
||||
(1, 895.76, 89.58, 4722000010),
|
||||
(1, 33.80, 7.10, 4722000021),
|
||||
(2, 110.33, 11.03, 4770000010),
|
||||
(3, 8.07, 0.81, 4770000010),
|
||||
(4, 8.07, 0.81, 4770000010),
|
||||
(5, 8.07, 0.81, 4770000010);
|
||||
|
||||
INSERT INTO `vn`.`expence`(`id`, `taxTypeFk`, `name`, `isWithheld`)
|
||||
VALUES
|
||||
(2000000000, 1, 'Inmovilizado pendiente', 0),
|
||||
(2000000000, 3, 'Compra de bienes de inmovilizado', 0),
|
||||
(4751000000, 0, 'Retenciones', 1),
|
||||
(4751000000, 1, 'Retenciones', 1),
|
||||
(4751000000, 6, 'Retencion', 0),
|
||||
(6210000567, 0, 'Alquiler VNH', 0),
|
||||
(7001000000, 1, 'Mercaderia', 0);
|
||||
|
||||
|
||||
|
||||
INSERT INTO `vn`.`invoiceOutExpence`(`id`, `invoiceOutFk`, `amount`, `expenceFk`, `created`)
|
||||
VALUES
|
||||
|
@ -427,7 +433,7 @@ INSERT INTO `vn`.`invoiceOutSerial` (`code`, `description`, `isTaxed`, `taxAreaF
|
|||
('T', 'Española rapida', 1, 'NATIONAL', 0),
|
||||
('V', 'Intracomunitaria global', 0, 'CEE', 1);
|
||||
|
||||
INSERT INTO `vn`.`zone` (`id`, `name`, `hour`, `warehouseFk`, `agencyModeFk`, `travelingDays`, `price`, `bonus`)
|
||||
INSERT INTO `vn`.`zone` (`id`, `name`, `hour`, `warehouseFk`, `agencyModeFk`, `travelingDays`, `price`, `bonus`)
|
||||
VALUES
|
||||
(1, 'Zone pickup A', CONCAT(CURRENT_DATE(), ' ', TIME('22:00')), 1, 1, 0, 0, 0),
|
||||
(2, 'Zone pickup B', CONCAT(CURRENT_DATE(), ' ', TIME('22:00')), 2, 1, 0, 0, 0),
|
||||
|
@ -435,8 +441,8 @@ INSERT INTO `vn`.`zone` (`id`, `name`, `hour`, `warehouseFk`, `agencyModeFk`, `t
|
|||
(4, 'Zone 247 B', CONCAT(CURRENT_DATE(), ' ', TIME('22:00')), 2, 7, 1, 2, 0),
|
||||
(5, 'Zone expensive A', CONCAT(CURRENT_DATE(), ' ', TIME('22:00')), 1, 8, 1, 1000, 0),
|
||||
(6, 'Zone expensive B', CONCAT(CURRENT_DATE(), ' ', TIME('22:00')), 2, 8, 1, 1000, 0),
|
||||
(7, 'Zone refund', CONCAT(CURRENT_DATE(), ' ', TIME('22:00')), 1, 10, 0, 0, 0),
|
||||
(8, 'Zone others', CONCAT(CURRENT_DATE(), ' ', TIME('22:00')), 1, 23, 0, 0, 0),
|
||||
(7, 'Zone refund', CONCAT(CURRENT_DATE(), ' ', TIME('22:00')), 1, 23, 0, 0, 0),
|
||||
(8, 'Zone others', CONCAT(CURRENT_DATE(), ' ', TIME('22:00')), 1, 10, 0, 0, 0),
|
||||
(9, 'Zone superMan', CONCAT(CURRENT_DATE(), ' ', TIME('22:00')), 1, 2, 0, 0, 0),
|
||||
(10, 'Zone teleportation', CONCAT(CURRENT_DATE(), ' ', TIME('22:00')), 3, 3, 0, 0, 0),
|
||||
(11, 'Zone pickup C', CONCAT(CURRENT_DATE(), ' ', TIME('22:00')), 5, 1, 0, 0, 0),
|
||||
|
@ -467,8 +473,8 @@ INSERT INTO `vn`.`ticket`(`id`, `priority`, `agencyModeFk`,`warehouseFk`,`routeF
|
|||
(20, 1, 5, 5, 3, DATE_ADD(CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 109, 'Somewhere in Thailand', 129, NULL, 0, 13, DATE_ADD(CURDATE(), INTERVAL +1 MONTH)),
|
||||
(21, NULL, 5, 5, NULL, DATE_ADD(CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 109, 'Somewhere in Holland', 102, NULL, 0, 13, DATE_ADD(CURDATE(), INTERVAL +1 MONTH)),
|
||||
(22, NULL, 5, 5, NULL, DATE_ADD(CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 109, 'Somewhere in Japan', 103, NULL, 0, 13, DATE_ADD(CURDATE(), INTERVAL +1 MONTH)),
|
||||
(23, NULL, 23, 1, NULL, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 101, 'address 21', 121, NULL, 0, 8, CURDATE()),
|
||||
(24 ,NULL, 23, 1, NULL, CURDATE(), CURDATE(), 101, 'Bruce Wayne', 1, NULL, 0, 8, CURDATE());
|
||||
(23, NULL, 10, 1, NULL, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 101, 'address 21', 121, NULL, 0, 8, CURDATE()),
|
||||
(24 ,NULL, 10, 1, NULL, CURDATE(), CURDATE(), 101, 'Bruce Wayne', 1, NULL, 0, 8, CURDATE());
|
||||
|
||||
INSERT INTO `vn`.`ticketObservation`(`id`, `ticketFk`, `observationTypeFk`, `description`)
|
||||
VALUES
|
||||
|
@ -1056,7 +1062,7 @@ INSERT INTO `vn`.`entry`(`id`, `supplierFk`, `created`, `travelFk`, `companyFk`,
|
|||
INSERT INTO `bi`.`claims_ratio`(`id_Cliente`, `Consumo`, `Reclamaciones`, `Ratio`, `recobro`, `inflacion`)
|
||||
VALUES
|
||||
(101, 500, NULL, 0.00, 0.00, 1.00),
|
||||
(102, 1000, 2.00, 0.01, 0.05, 1.00),
|
||||
(102, 1000, 2.00, 0.01, 0.05, 1.00),
|
||||
(103, 2000, 0.00, 0.00, 0.02, 1.00),
|
||||
(104, 2500, 150.00, 0.02, 0.10, 1.00);
|
||||
|
||||
|
@ -1082,14 +1088,6 @@ INSERT INTO `vn2008`.`tblContadores`(`id`,`FechaInventario`)
|
|||
VALUES
|
||||
(1,DATE_ADD(CURDATE(),INTERVAL -1 MONTH));
|
||||
|
||||
INSERT INTO `vn2008`.`Estados` (`Id_Estado`, `Estado`)
|
||||
VALUES
|
||||
('1', 'En Espera');
|
||||
|
||||
INSERT INTO `vn2008`.`Informes` (`Id_Informe`, `Informe`)
|
||||
VALUES
|
||||
('30', 'Generar factura PDF');
|
||||
|
||||
INSERT INTO `vn`.`deliveryMethod`(`id`, `code`, `description`)
|
||||
VALUES
|
||||
(1, 'AGENCY', 'Agencia'),
|
||||
|
@ -1508,7 +1506,7 @@ INSERT INTO `vn`.`workCenter` (`id`, `name`, `warehouseFk`)
|
|||
('1', 'Silla', '1'),
|
||||
('5', 'Madrid', '5');
|
||||
|
||||
INSERT INTO `vn2008`.`workcenter_holiday` (`workcenter_id`, `day`, `year`)
|
||||
INSERT INTO `vn`.`workCenterHoliday` (`workCenterFk`, `days`, `year`)
|
||||
VALUES
|
||||
('1', '27.5', YEAR(CURDATE())),
|
||||
('5', '22', YEAR(CURDATE())),
|
||||
|
@ -1551,6 +1549,17 @@ INSERT INTO `vn`.`sharingCart`(`id`, `workerFk`, `started`, `ended`, `workerSubs
|
|||
VALUES
|
||||
(1, 18, DATE_ADD(CURDATE(), INTERVAL -5 DAY), DATE_ADD(CURDATE(), INTERVAL +15 DAY), 19, DATE_ADD(CURDATE(), INTERVAL -5 DAY));
|
||||
|
||||
INSERT INTO `vn`.`zoneGeo`(`id`, `name`, `lft`, `rgt`, `depth`, `sons`)
|
||||
VALUES
|
||||
(1, 'Origin', 1, 16, 0, 5),
|
||||
(2, 'España', 2, 9, 1, 3),
|
||||
(6, 'Valencia', 3, 8, 2, 2),
|
||||
(7, 'Silla', 4, 7, 3, 1),
|
||||
(8, '46460', 5, 6, 4, 0),
|
||||
(3, 'Francia', 10, 11, 1, 0),
|
||||
(4, 'Holanda', 12, 13, 1, 0),
|
||||
(5, 'Portugal', 14, 15, 1, 0);
|
||||
|
||||
INSERT INTO `vn`.`zoneIncluded` (`zoneFk`, `geoFk`, `isIncluded`)
|
||||
VALUES
|
||||
(1, 3, 0),
|
||||
|
@ -1828,13 +1837,14 @@ INSERT INTO `vn`.`dmsType`(`id`, `name`, `path`, `readRoleFk`, `writeRoleFk`, `c
|
|||
(16, 'Logistica', 'logistica', NULL, NULL, 'logistics'),
|
||||
(17, 'cmr', 'cmr', NULL, NULL, 'cmr'),
|
||||
(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');
|
||||
|
||||
INSERT INTO `vn`.`dms`(`id`, `dmsTypeFk`, `file`, `contentType`, `workerFk`, `warehouseFk`, `companyFk`, `hardCopyNumber`, `hasFile`, `reference`, `description`, `created`)
|
||||
VALUES
|
||||
(1, 14, '1.txt', 'text/plain', 5, 1, 442, NULL, FALSE, 'Ticket:11', 'Ticket:11 dms for the ticket', CURDATE()),
|
||||
(2, 5, '2.txt', 'text/plain', 5, 1, 442, 1, TRUE, 'Client:101', 'Client:101 dms for the client', CURDATE()),
|
||||
(3, 5, '3.txt', 'text/plain', 5, 1, 442, NULL, TRUE, 'Client: 101', 'Client:101 readme', CURDATE());
|
||||
(1, 14, '1.txt', 'text/plain', 5, 1, 442, NULL, FALSE, 'Ticket:11', 'Ticket:11 dms for the ticket', CURDATE()),
|
||||
(2, 5, '2.txt', 'text/plain', 5, 1, 442, 1, TRUE, 'Client:104', 'Client:104 dms for the client', CURDATE()),
|
||||
(3, 5, '3.txt', 'text/plain', 5, 1, 442, NULL, TRUE, 'Client: 104', 'Client:104 readme', CURDATE());
|
||||
|
||||
INSERT INTO `vn`.`ticketDms`(`ticketFk`, `dmsFk`)
|
||||
VALUES
|
||||
|
@ -1842,8 +1852,8 @@ INSERT INTO `vn`.`ticketDms`(`ticketFk`, `dmsFk`)
|
|||
|
||||
INSERT INTO `vn`.`clientDms`(`clientFk`, `dmsFk`)
|
||||
VALUES
|
||||
(101, 2),
|
||||
(101, 3);
|
||||
(104, 2),
|
||||
(104, 3);
|
||||
|
||||
INSERT INTO `vn`.`device` (`sn`, `model`, `userFk`)
|
||||
VALUES
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -41,7 +41,6 @@ TABLES=(
|
|||
cplusTaxBreak
|
||||
pgc
|
||||
tag
|
||||
zoneGeo
|
||||
)
|
||||
dump_tables ${TABLES[@]}
|
||||
|
||||
|
@ -57,14 +56,12 @@ TABLES=(
|
|||
container
|
||||
department
|
||||
escritos
|
||||
Gastos
|
||||
Grupos
|
||||
iva_group_codigo
|
||||
Monedas
|
||||
state
|
||||
tarifa_componentes
|
||||
tarifa_componentes_series
|
||||
Tintas
|
||||
)
|
||||
dump_tables ${TABLES[@]}
|
||||
|
||||
|
|
|
@ -14,9 +14,10 @@ module.exports = function createNightmare(width = 1280, height = 720) {
|
|||
}).viewport(width, height);
|
||||
|
||||
nightmare.on('console', (type, message, ...args) => {
|
||||
if (type === 'error')
|
||||
if (type === 'error') {
|
||||
console[type](message, ...args);
|
||||
throw new Error(message);
|
||||
else
|
||||
} else
|
||||
console[type](message, ...args);
|
||||
});
|
||||
|
||||
|
|
|
@ -106,10 +106,10 @@ export default {
|
|||
agencyAutocomplete: 'vn-autocomplete[field="$ctrl.address.agencyModeFk"]',
|
||||
phoneInput: `${components.vnTextfield}[name="phone"]`,
|
||||
mobileInput: `${components.vnTextfield}[name="mobile"]`,
|
||||
defaultAddress: 'vn-client-address-index vn-horizontal:nth-child(1) div[name="street"]',
|
||||
secondMakeDefaultStar: 'vn-client-address-index vn-card vn-horizontal:nth-child(2) vn-icon-button[icon="star_border"]',
|
||||
firstEditButton: 'vn-client-address-index vn-icon-button[icon="edit"]',
|
||||
secondEditButton: 'vn-client-address-index vn-horizontal:nth-child(2) vn-icon-button[icon="edit"]',
|
||||
defaultAddress: 'vn-client-address-index div:nth-child(1) div[name="street"]',
|
||||
secondMakeDefaultStar: 'vn-client-address-index vn-card div:nth-child(2) vn-icon-button[icon="star_border"]',
|
||||
firstEditAddress: 'vn-client-address-index div:nth-child(1) > a',
|
||||
secondEditAddress: 'vn-client-address-index div:nth-child(2) > a',
|
||||
activeCheckbox: 'vn-check[label="Enabled"] md-checkbox',
|
||||
equalizationTaxCheckbox: 'vn-client-address-edit vn-check[label="Is equalizated"] md-checkbox',
|
||||
firstObservationTypeAutocomplete: 'vn-client-address-edit [name=observations] :nth-child(1) [field="observation.observationTypeFk"]',
|
||||
|
@ -174,6 +174,12 @@ export default {
|
|||
confirmFirstPaymentButton: 'vn-client-web-payment vn-tr:nth-child(1) vn-icon-button[icon="done_all"]',
|
||||
firstPaymentConfirmed: 'vn-client-web-payment vn-tr:nth-child(1) vn-icon[icon="check"][aria-hidden="false"]'
|
||||
},
|
||||
dms: {
|
||||
deleteFileButton: 'vn-client-dms-index vn-table vn-tr:nth-child(1) vn-icon-button[icon="delete"]',
|
||||
firstDocWorker: 'vn-client-dms-index vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(8) > span',
|
||||
firstDocWorkerDescriptor: 'vn-client-dms-index > vn-worker-descriptor-popover > vn-popover',
|
||||
acceptDeleteButton: 'vn-client-dms-index > vn-confirm button[response="ACCEPT"]'
|
||||
},
|
||||
itemsIndex: {
|
||||
searchIcon: 'vn-item-index vn-searchbar vn-icon[icon="search"]',
|
||||
createItemButton: `${components.vnFloatButton}`,
|
||||
|
@ -320,16 +326,20 @@ export default {
|
|||
advancedSearchInvoiceOut: 'vn-ticket-index vn-searchbar vn-ticket-search-panel vn-textfield[model="filter.refFk"] input',
|
||||
newTicketButton: 'vn-ticket-index > a',
|
||||
searchResult: 'vn-ticket-index vn-card > div > vn-table > div > vn-tbody > a.vn-tr',
|
||||
searchWeeklyResult: 'vn-ticket-weekly-index vn-table vn-tbody > vn-tr',
|
||||
searchResultDate: 'vn-ticket-index vn-table vn-tbody > a:nth-child(1) > vn-td:nth-child(5)',
|
||||
searchTicketInput: `vn-ticket-index ${components.vnTextfield}`,
|
||||
searchWeeklyTicketInput: `vn-ticket-weekly-index ${components.vnTextfield}`,
|
||||
searchWeeklyClearInput: 'vn-ticket-weekly-index vn-searchbar i[class="material-icons clear"]',
|
||||
advancedSearchButton: 'vn-ticket-index vn-searchbar > vn-popover vn-ticket-search-panel vn-submit[label="Search"] input',
|
||||
searchButton: 'vn-ticket-index vn-searchbar vn-icon[icon="search"]',
|
||||
searchWeeklyButton: 'vn-ticket-weekly-index vn-searchbar vn-icon[icon="search"]',
|
||||
moreMenu: 'vn-ticket-index vn-icon-menu[vn-id="more-button"] > div > vn-icon',
|
||||
moreMenuTurns: 'vn-ticket-index vn-icon-menu vn-drop-down > vn-popover li:nth-child(2)',
|
||||
sixthWeeklyTicketTurn: 'vn-ticket-weekly vn-table vn-tr:nth-child(6) vn-autocomplete[field="weekly.weekDay"] input',
|
||||
weeklyTicket: 'vn-ticket-weekly vn-table > div > vn-tbody > vn-tr',
|
||||
sixthWeeklyTicketDeleteIcon: 'vn-ticket-weekly vn-tr:nth-child(6) vn-icon-button[icon="delete"]',
|
||||
acceptDeleteTurn: 'vn-ticket-weekly > vn-confirm[vn-id="deleteWeekly"] button[response="ACCEPT"]'
|
||||
moreMenuWeeklyTickets: 'vn-ticket-index vn-icon-menu vn-drop-down > vn-popover li:nth-child(2)',
|
||||
sixthWeeklyTicket: 'vn-ticket-weekly-index vn-table vn-tr:nth-child(6) vn-autocomplete[field="weekly.weekDay"] input',
|
||||
weeklyTicket: 'vn-ticket-weekly-index vn-table > div > vn-tbody > vn-tr',
|
||||
firstWeeklyTicketDeleteIcon: 'vn-ticket-weekly-index vn-tr:nth-child(1) vn-icon-button[icon="delete"]',
|
||||
acceptDeleteTurn: 'vn-ticket-weekly-index > vn-confirm[vn-id="deleteWeekly"] button[response="ACCEPT"]'
|
||||
},
|
||||
createTicketView: {
|
||||
clientAutocomplete: 'vn-ticket-create vn-autocomplete[field="$ctrl.clientFk"]',
|
||||
|
@ -349,12 +359,16 @@ export default {
|
|||
moreMenuAddToTurn: 'vn-ticket-descriptor vn-drop-down > vn-popover ul > li[name="Add turn"]',
|
||||
moreMenuDeleteTicket: 'vn-ticket-descriptor vn-drop-down > vn-popover ul > li[name="Delete ticket"]',
|
||||
moreMenuMakeInvoice: 'vn-ticket-descriptor vn-drop-down > vn-popover ul > li[name="Make invoice"]',
|
||||
moreMenuChangeShippedHour: 'vn-ticket-descriptor vn-drop-down > vn-popover ul > li[name="Change shipped hour"]',
|
||||
changeShippedHourInput: 'vn-ticket-descriptor > vn-dialog.ng-isolate-scope.vn-dialog.shown vn-input-time input',
|
||||
addStowawayDialogFirstTicket: 'vn-ticket-descriptor > vn-add-stowaway > vn-dialog vn-table vn-tbody vn-tr',
|
||||
shipButton: 'vn-ticket-descriptor > div > div.body > div.quicklinks vn-icon[icon="icon-stowaway"]',
|
||||
thursdayButton: 'vn-ticket-descriptor > vn-dialog > div > form > div.body > tpl-body > div > vn-tool-bar > vn-button:nth-child(4)',
|
||||
saturdayButton: 'vn-ticket-descriptor > vn-dialog > div > form > div.body > tpl-body > div > vn-tool-bar > vn-button:nth-child(6)',
|
||||
closeStowawayDialog: 'vn-ticket-descriptor > vn-add-stowaway > vn-dialog > div > button[class="close"]',
|
||||
acceptDeleteButton: 'vn-ticket-descriptor button[response="ACCEPT"]',
|
||||
acceptChangeHourButton: 'vn-ticket-descriptor vn-dialog[vn-id="changeShippedDialog"] button[response="ACCEPT"]',
|
||||
descriptorDeliveryDate: 'vn-ticket-descriptor > div > div.body > div.attributes > vn-label-value:nth-child(6) > section > span',
|
||||
acceptInvoiceOutButton: 'vn-ticket-descriptor vn-confirm[vn-id="makeInvoiceConfirmation"] button[response="ACCEPT"]',
|
||||
acceptDeleteStowawayButton: 'vn-ticket-descriptor > vn-remove-stowaway button[response="ACCEPT"]'
|
||||
},
|
||||
|
@ -393,6 +407,8 @@ export default {
|
|||
moreMenuUnmarkReseved: 'vn-ticket-sale vn-tool-bar > vn-button-menu[vn-id="more-button"] vn-drop-down > vn-popover ul > li[name="Unmark as reserved"]',
|
||||
moreMenuUpdateDiscount: 'vn-ticket-sale vn-tool-bar > vn-button-menu[vn-id="more-button"] vn-drop-down > vn-popover ul > li[name="Update discount"]',
|
||||
moreMenuUpdateDiscountInput: 'vn-ticket-sale vn-dialog form vn-ticket-sale-edit-discount vn-input-number[model="$ctrl.newDiscount"] input',
|
||||
transferQuantityInput: 'vn-ticket-sale vn-popover.transfer.ng-isolate-scope.vn-popover.shown vn-table > div > vn-tbody > vn-tr > vn-td-editable > span > text',
|
||||
transferQuantityCell: 'vn-ticket-sale vn-popover.transfer.ng-isolate-scope.vn-popover.shown vn-table > div > vn-tbody > vn-tr > vn-td-editable',
|
||||
firstSaleClaimIcon: 'vn-ticket-sale vn-table vn-tbody > vn-tr:nth-child(1) vn-icon[icon="icon-claims"]',
|
||||
firstSaleDescriptorImage: 'vn-ticket-sale vn-item-descriptor-popover > vn-popover vn-item-descriptor img',
|
||||
firstSaleText: 'vn-table div > vn-tbody > vn-tr:nth-child(1)',
|
||||
|
@ -416,13 +432,15 @@ export default {
|
|||
secondSaleDiscount: 'vn-ticket-sale vn-tr:nth-child(2) vn-td:nth-child(8)',
|
||||
secondSaleImport: 'vn-ticket-sale vn-tr:nth-child(2) vn-td:nth-child(9)',
|
||||
secondSaleText: 'vn-table div > vn-tbody > vn-tr:nth-child(2)',
|
||||
secondSaleQuantity: 'vn-input-number[model="sale.quantity"]:nth-child(2) input',
|
||||
secondSaleQuantityCell: 'vn-ticket-sale vn-tr:nth-child(2) > vn-td-editable:nth-child(5)',
|
||||
totalImport: 'vn-ticket-sale > vn-vertical > vn-card > div > vn-vertical > vn-horizontal > vn-one > p:nth-child(3) > strong',
|
||||
selectAllSalesCheckbox: 'vn-ticket-sale vn-thead vn-check md-checkbox',
|
||||
secondSaleCheckbox: 'vn-ticket-sale vn-tr:nth-child(2) vn-check[field="sale.checked"] md-checkbox',
|
||||
thirdSaleCheckbox: 'vn-ticket-sale vn-tr:nth-child(3) vn-check[field="sale.checked"] md-checkbox',
|
||||
deleteSaleButton: 'vn-ticket-sale vn-tool-bar > vn-button[icon="delete"]',
|
||||
transferSaleButton: 'vn-ticket-sale vn-tool-bar > vn-button[icon="call_split"]',
|
||||
moveToTicketInput: 'vn-ticket-sale vn-popover.transfer vn-textfield[model="$ctrl.receiverTicketId"] input',
|
||||
moveToTicketInput: 'vn-ticket-sale vn-popover.transfer vn-textfield[model="$ctrl.transfer.ticketId"] input',
|
||||
moveToTicketInputClearButton: 'vn-popover.shown i[title="Clear"]',
|
||||
moveToTicketButton: 'vn-ticket-sale vn-popover.transfer vn-icon[icon="arrow_forward_ios"]',
|
||||
moveToNewTicketButton: 'vn-ticket-sale vn-popover.transfer vn-button[label="New ticket"]',
|
||||
|
@ -520,7 +538,7 @@ export default {
|
|||
saveButton: `${components.vnSubmit}`
|
||||
},
|
||||
claimDetail: {
|
||||
secondItemDiscount: 'vn-claim-detail > vn-vertical > vn-card > div > vn-vertical > vn-table > div > vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(7) > span',
|
||||
secondItemDiscount: 'vn-claim-detail > vn-vertical > vn-card > div > vn-vertical > vn-table > div > vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(6) > span',
|
||||
discountInput: 'vn-claim-detail vn-popover vn-input-number[model="$ctrl.newDiscount"] > div > div > div.infix > input',
|
||||
discoutPopoverMana: 'vn-claim-detail > vn-popover > div > div.content > div > vn-horizontal > h5',
|
||||
addItemButton: 'vn-claim-detail a vn-float-button',
|
||||
|
@ -528,7 +546,7 @@ export default {
|
|||
claimDetailLine: 'vn-claim-detail > vn-vertical > vn-card > div > vn-vertical > vn-table > div > vn-tbody > vn-tr',
|
||||
firstItemQuantityInput: 'vn-claim-detail vn-tr:nth-child(1) vn-input-number[model="saleClaimed.quantity"] input',
|
||||
totalClaimed: 'vn-claim-detail > vn-vertical > vn-card > div > vn-vertical > vn-horizontal > div > vn-label-value:nth-child(2) > section > span',
|
||||
secondItemDeleteButton: 'vn-claim-detail > vn-vertical > vn-card > div > vn-vertical > vn-table > div > vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(9) > vn-icon-button > button > vn-icon > i'
|
||||
secondItemDeleteButton: 'vn-claim-detail > vn-vertical > vn-card > div > vn-vertical > vn-table > div > vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(8) > vn-icon-button > button > vn-icon > i'
|
||||
},
|
||||
claimDevelopment: {
|
||||
addDevelopmentButton: 'vn-claim-development > vn-vertical > vn-card > div > vn-vertical > vn-one > vn-icon-button > button > vn-icon',
|
||||
|
@ -562,6 +580,10 @@ export default {
|
|||
searchButton: 'vn-order-index vn-searchbar vn-icon[icon="search"]',
|
||||
createOrderButton: `${components.vnFloatButton}`,
|
||||
},
|
||||
orderDescriptor: {
|
||||
returnToModuleIndexButton: 'vn-order-descriptor a[ui-sref="order.index"]',
|
||||
acceptNavigationButton: 'vn-order-basic-data vn-confirm button[response=ACCEPT]'
|
||||
},
|
||||
createOrderView: {
|
||||
clientAutocomplete: 'vn-autocomplete[label="Client"]',
|
||||
addressAutocomplete: 'vn-autocomplete[label="Address"]',
|
||||
|
|
|
@ -14,7 +14,7 @@ describe('Client Edit fiscalData path', () => {
|
|||
// Confirms all addresses have EQtax false for future propagation test step 1
|
||||
it(`should click on the 1st edit icon to check EQtax isnt checked`, async() => {
|
||||
const result = await nightmare
|
||||
.waitToClick(selectors.clientAddresses.firstEditButton)
|
||||
.waitToClick(selectors.clientAddresses.firstEditAddress)
|
||||
.checkboxState(selectors.clientAddresses.equalizationTaxCheckbox);
|
||||
|
||||
expect(result).toBe('unchecked');
|
||||
|
@ -24,7 +24,7 @@ describe('Client Edit fiscalData path', () => {
|
|||
it(`should go back to addresses then select the second one and confirm the EQtax isnt checked`, async() => {
|
||||
const result = await nightmare
|
||||
.waitToClick(selectors.clientAddresses.addressesButton)
|
||||
.waitToClick(selectors.clientAddresses.secondEditButton)
|
||||
.waitToClick(selectors.clientAddresses.secondEditAddress)
|
||||
.checkboxState(selectors.clientAddresses.equalizationTaxCheckbox);
|
||||
|
||||
expect(result).toBe('unchecked');
|
||||
|
@ -67,6 +67,7 @@ describe('Client Edit fiscalData path', () => {
|
|||
.write(selectors.clientFiscalData.fiscalIdInput, 'INVALID!')
|
||||
.clearInput(selectors.clientFiscalData.addressInput)
|
||||
.write(selectors.clientFiscalData.addressInput, 'Somewhere edited')
|
||||
.autocompleteSearch(selectors.clientFiscalData.cityAutocomplete, 'Valencia')
|
||||
.autocompleteSearch(selectors.clientFiscalData.postcodeAutocomplete, '46000')
|
||||
.waitToClick(selectors.clientFiscalData.activeCheckbox)
|
||||
.waitToClick(selectors.clientFiscalData.frozenCheckbox)
|
||||
|
@ -80,7 +81,7 @@ describe('Client Edit fiscalData path', () => {
|
|||
.waitForLastSnackbar();
|
||||
|
||||
expect(result).toEqual('Invalid Tax number');
|
||||
}, 15000);
|
||||
});
|
||||
|
||||
it(`should edit the fiscal this time with a valid fiscal id`, async() => {
|
||||
const result = await nightmare
|
||||
|
@ -134,7 +135,7 @@ describe('Client Edit fiscalData path', () => {
|
|||
// confirm all addresses have now EQtax checked step 2
|
||||
it(`should click on the 1st edit icon to confirm EQtax is checked`, async() => {
|
||||
const result = await nightmare
|
||||
.waitToClick(selectors.clientAddresses.firstEditButton)
|
||||
.waitToClick(selectors.clientAddresses.firstEditAddress)
|
||||
.checkboxState(selectors.clientAddresses.equalizationTaxCheckbox);
|
||||
|
||||
expect(result).toBe('checked');
|
||||
|
@ -144,7 +145,7 @@ describe('Client Edit fiscalData path', () => {
|
|||
it(`should go back to addresses then select the second one and confirm the EQtax is checked`, async() => {
|
||||
const result = await nightmare
|
||||
.waitToClick(selectors.clientAddresses.addressesButton)
|
||||
.waitToClick(selectors.clientAddresses.secondEditButton)
|
||||
.waitToClick(selectors.clientAddresses.secondEditAddress)
|
||||
.checkboxState(selectors.clientAddresses.equalizationTaxCheckbox);
|
||||
|
||||
expect(result).toBe('checked');
|
||||
|
@ -289,7 +290,7 @@ describe('Client Edit fiscalData path', () => {
|
|||
// confirm invoice by address checkbox gets checked if the EQtax differs between addresses step 2
|
||||
it(`should click on the 1st edit icon to access the address details and uncheck EQtax checkbox`, async() => {
|
||||
const result = await nightmare
|
||||
.waitToClick(selectors.clientAddresses.firstEditButton)
|
||||
.waitToClick(selectors.clientAddresses.firstEditAddress)
|
||||
.waitToClick(selectors.clientAddresses.equalizationTaxCheckbox)
|
||||
.waitToClick(selectors.clientAddresses.saveButton)
|
||||
.waitForLastSnackbar();
|
||||
|
|
|
@ -68,7 +68,7 @@ describe('Client Add address path', () => {
|
|||
|
||||
it(`should click on the addresses button confirm the new address exists and it's the default one`, async() => {
|
||||
const result = await nightmare
|
||||
.waitToClick(selectors.clientAddresses.addressesButton)
|
||||
// .waitToClick(selectors.clientAddresses.addressesButton)
|
||||
.waitToGetProperty(selectors.clientAddresses.defaultAddress, 'innerText');
|
||||
|
||||
expect(result).toContain('320 Park Avenue New York');
|
||||
|
@ -86,7 +86,7 @@ describe('Client Add address path', () => {
|
|||
it(`should click on the edit icon of the default address`, async() => {
|
||||
const url = await nightmare
|
||||
.waitForTextInElement(selectors.clientAddresses.defaultAddress, 'Somewhere in Thailand')
|
||||
.waitToClick(selectors.clientAddresses.firstEditButton)
|
||||
.waitToClick(selectors.clientAddresses.firstEditAddress)
|
||||
.waitForURL('/edit')
|
||||
.parsedUrl();
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ describe('Client add address notes path', () => {
|
|||
it(`should click on the edit icon of the default address`, async() => {
|
||||
const url = await nightmare
|
||||
.waitForTextInElement(selectors.clientAddresses.defaultAddress, '20 Ingram Street')
|
||||
.waitToClick(selectors.clientAddresses.firstEditButton)
|
||||
.waitToClick(selectors.clientAddresses.firstEditAddress)
|
||||
.waitForURL('/edit')
|
||||
.parsedUrl();
|
||||
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
import selectors from '../../helpers/selectors.js';
|
||||
import createNightmare from '../../helpers/nightmare';
|
||||
|
||||
describe('Client DMS', () => {
|
||||
const nightmare = createNightmare();
|
||||
|
||||
describe('as salesPerson', () => {
|
||||
beforeAll(() => {
|
||||
nightmare
|
||||
.loginAndModule('salesPerson', 'client')
|
||||
.accessToSearchResult('Tony Stark')
|
||||
.accessToSection('client.card.dms.index');
|
||||
});
|
||||
|
||||
it('should delete de first file', async() => {
|
||||
let result = await nightmare
|
||||
.waitToClick(selectors.dms.deleteFileButton)
|
||||
.waitToClick(selectors.dms.acceptDeleteButton)
|
||||
.waitForLastSnackbar();
|
||||
|
||||
expect(result).toEqual('Data saved!');
|
||||
});
|
||||
|
||||
it(`should click on the first document line worker name making the descriptor visible`, async() => {
|
||||
const visible = await nightmare
|
||||
.waitToClick(selectors.dms.firstDocWorker)
|
||||
.waitForClassPresent(selectors.dms.firstDocWorkerDescriptor, 'shown')
|
||||
.isVisible(selectors.dms.firstDocWorkerDescriptor);
|
||||
|
||||
expect(visible).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -11,6 +11,7 @@ describe('Item summary path', () => {
|
|||
|
||||
it('should search for an item', async() => {
|
||||
const result = await nightmare
|
||||
.clearInput(selectors.itemsIndex.searchItemInput)
|
||||
.write(selectors.itemsIndex.searchItemInput, 'Ranged weapon longbow 2m')
|
||||
.waitToClick(selectors.itemsIndex.searchButton)
|
||||
.waitForNumberOfElements(selectors.itemsIndex.searchResult, 1)
|
||||
|
|
|
@ -11,6 +11,7 @@ describe('Item Create/Clone path', () => {
|
|||
|
||||
it(`should search for the item Infinity Gauntlet to confirm it isn't created yet`, async() => {
|
||||
const result = await nightmare
|
||||
.clearInput(selectors.itemsIndex.searchItemInput)
|
||||
.write(selectors.itemsIndex.searchItemInput, 'Infinity Gauntlet')
|
||||
.waitToClick(selectors.itemsIndex.searchButton)
|
||||
.waitForNumberOfElements(selectors.itemsIndex.searchResult, 0)
|
||||
|
@ -95,6 +96,7 @@ describe('Item Create/Clone path', () => {
|
|||
|
||||
it(`should search for the item Infinity Gauntlet`, async() => {
|
||||
const result = await nightmare
|
||||
.clearInput(selectors.itemsIndex.searchItemInput)
|
||||
.write(selectors.itemsIndex.searchItemInput, 'Infinity Gauntlet')
|
||||
.waitToClick(selectors.itemsIndex.searchButton)
|
||||
.waitForNumberOfElements(selectors.itemsIndex.searchResult, 1)
|
||||
|
@ -117,6 +119,7 @@ describe('Item Create/Clone path', () => {
|
|||
it('should search for the item Infinity Gauntlet and find two', async() => {
|
||||
const result = await nightmare
|
||||
.waitToClick(selectors.itemTags.goToItemIndexButton)
|
||||
.clearInput(selectors.itemsIndex.searchItemInput)
|
||||
.write(selectors.itemsIndex.searchItemInput, 'Infinity Gauntlet')
|
||||
.waitToClick(selectors.itemsIndex.searchButton)
|
||||
.waitForNumberOfElements(selectors.itemsIndex.searchResult, 2)
|
||||
|
|
|
@ -11,6 +11,7 @@ describe('Item regularize path', () => {
|
|||
|
||||
it('should edit the user local warehouse', async() => {
|
||||
let result = await nightmare
|
||||
.waitForSpinnerLoad()
|
||||
.waitToClick(selectors.globalItems.userMenuButton)
|
||||
.autocompleteSearch(selectors.globalItems.userLocalWarehouse, 'Warehouse Four')
|
||||
.waitForLastSnackbar();
|
||||
|
@ -28,6 +29,7 @@ describe('Item regularize path', () => {
|
|||
|
||||
it('should search for the item', async() => {
|
||||
const resultCount = await nightmare
|
||||
.clearInput(selectors.itemsIndex.searchItemInput)
|
||||
.write(selectors.itemsIndex.searchItemInput, 'Ranged weapon pistol 9mm')
|
||||
.waitToClick(selectors.itemsIndex.searchButton)
|
||||
.waitForNumberOfElements(selectors.itemsIndex.searchResult, 1)
|
||||
|
@ -133,6 +135,7 @@ describe('Item regularize path', () => {
|
|||
|
||||
it('should search for the item once again', async() => {
|
||||
const resultCount = await nightmare
|
||||
.clearInput(selectors.itemsIndex.searchItemInput)
|
||||
.write(selectors.itemsIndex.searchItemInput, 'Ranged weapon pistol 9mm')
|
||||
.waitToClick(selectors.itemsIndex.searchButton)
|
||||
.waitForNumberOfElements(selectors.itemsIndex.searchResult, 1)
|
||||
|
|
|
@ -30,17 +30,6 @@ describe('Ticket Create new tracking state path', () => {
|
|||
expect(result).toEqual('State cannot be blank');
|
||||
});
|
||||
|
||||
it(`should attempt create a new state then clear and save it`, async() => {
|
||||
let result = await nightmare
|
||||
.autocompleteSearch(selectors.createStateView.stateAutocomplete, '¿Fecha?')
|
||||
.waitToClick(selectors.createStateView.clearStateInputButton)
|
||||
.waitToClick(selectors.createStateView.saveStateButton)
|
||||
.waitForLastSnackbar();
|
||||
|
||||
expect(result).toEqual('State cannot be blank');
|
||||
});
|
||||
|
||||
|
||||
it(`should create a new state`, async() => {
|
||||
let result = await nightmare
|
||||
.autocompleteSearch(selectors.createStateView.stateAutocomplete, '¿Fecha?')
|
||||
|
@ -77,18 +66,16 @@ describe('Ticket Create new tracking state path', () => {
|
|||
expect(result).toEqual(`You don't have enough privileges`);
|
||||
});
|
||||
|
||||
it(`should attempt to create an state for the type salesPerson has rights but fail as worker is blank`, async() => {
|
||||
it(`should make sure the worker gets autocomplete uppon selecting the assigned state`, async() => {
|
||||
let result = await nightmare
|
||||
.autocompleteSearch(selectors.createStateView.stateAutocomplete, 'asignado')
|
||||
.waitToClick(selectors.createStateView.saveStateButton)
|
||||
.waitForLastSnackbar();
|
||||
.waitToGetProperty(`${selectors.createStateView.workerAutocomplete} input`, 'value');
|
||||
|
||||
expect(result).toEqual(`Worker cannot be blank`);
|
||||
expect(result).toEqual('salesPersonNick');
|
||||
});
|
||||
|
||||
it(`should create a new state with all it's data`, async() => {
|
||||
it(`should succesfully create a valid state`, async() => {
|
||||
let result = await nightmare
|
||||
.autocompleteSearch(selectors.createStateView.workerAutocomplete, 'replenisher')
|
||||
.waitToClick(selectors.createStateView.saveStateButton)
|
||||
.waitForLastSnackbar();
|
||||
|
||||
|
|
|
@ -11,10 +11,58 @@ describe('Ticket Edit basic data path', () => {
|
|||
.accessToSection('ticket.card.basicData.stepOne');
|
||||
});
|
||||
|
||||
it(`should edit the ticket agency then click next`, async() => {
|
||||
it(`should confirm the zone autocomplete is disabled unless your role is productionBoss`, async() => {
|
||||
const disabled = await nightmare
|
||||
.wait(selectors.ticketBasicData.zoneAutocomplete)
|
||||
.evaluate(selector => {
|
||||
return document.querySelector(selector).disabled;
|
||||
}, `${selectors.ticketBasicData.zoneAutocomplete} input`);
|
||||
|
||||
expect(disabled).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should now log as productionBoss to perform the rest of the tests`, async() => {
|
||||
await nightmare
|
||||
.loginAndModule('productionBoss', 'ticket')
|
||||
.accessToSearchResult(11)
|
||||
.accessToSection('ticket.card.basicData.stepOne');
|
||||
});
|
||||
|
||||
it(`should confirm the zone autocomplete is enabled for the role productionBoss`, async() => {
|
||||
const disabled = await nightmare
|
||||
.wait(selectors.ticketBasicData.zoneAutocomplete)
|
||||
.evaluate(selector => {
|
||||
return document.querySelector(selector).disabled;
|
||||
}, `${selectors.ticketBasicData.zoneAutocomplete} input`);
|
||||
|
||||
expect(disabled).toBeFalsy();
|
||||
});
|
||||
|
||||
it(`should check the zone is for Silla247`, async() => {
|
||||
let zone = await nightmare
|
||||
.waitToGetProperty(`${selectors.ticketBasicData.zoneAutocomplete} input`, 'value');
|
||||
|
||||
expect(zone).toContain('Zone 247 A');
|
||||
});
|
||||
|
||||
it(`should edit the ticket agency then check there are no zones for it`, async() => {
|
||||
let zone = await nightmare
|
||||
.autocompleteSearch(selectors.ticketBasicData.agencyAutocomplete, 'Entanglement')
|
||||
.getProperty(`${selectors.ticketBasicData.zoneAutocomplete} input`, 'value');
|
||||
|
||||
expect(zone.length).toEqual(0);
|
||||
});
|
||||
|
||||
it(`should edit the ticket zone then check the agency is for the new zone`, async() => {
|
||||
let zone = await nightmare
|
||||
.autocompleteSearch(selectors.ticketBasicData.zoneAutocomplete, 'Zone expensive A')
|
||||
.waitToGetProperty(`${selectors.ticketBasicData.agencyAutocomplete} input`, 'value');
|
||||
|
||||
expect(zone).toContain('Silla247Expensive');
|
||||
});
|
||||
|
||||
it(`should click next`, async() => {
|
||||
let url = await nightmare
|
||||
.autocompleteSearch(selectors.ticketBasicData.agencyAutocomplete, 'Silla247Expensive')
|
||||
.waitToGetProperty(`${selectors.ticketBasicData.zoneAutocomplete} input`, 'value')
|
||||
.waitToClick(selectors.ticketBasicData.nextStepButton)
|
||||
.waitForURL('data/step-two')
|
||||
.parsedUrl();
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import selectors from '../../helpers/selectors.js';
|
||||
import createNightmare from '../../helpers/nightmare';
|
||||
|
||||
describe('Ticket Edit sale path', () => {
|
||||
// #1632 [e2e] ticket.sale - Transferir líneas
|
||||
xdescribe('Ticket Edit sale path', () => {
|
||||
const nightmare = createNightmare();
|
||||
|
||||
beforeAll(() => {
|
||||
|
@ -257,12 +258,14 @@ describe('Ticket Edit sale path', () => {
|
|||
expect(result).toEqual(3);
|
||||
});
|
||||
|
||||
it('should select the third sale and transfer it to a valid ticket', async() => {
|
||||
it('should select the second sale and transfer it to a valid ticket', async() => {
|
||||
const targetTicketId = 12;
|
||||
|
||||
const result = await nightmare
|
||||
.waitToClick(selectors.ticketSales.thirdSaleCheckbox)
|
||||
.waitToClick(selectors.ticketSales.secondSaleCheckbox)
|
||||
.waitToClick(selectors.ticketSales.transferSaleButton)
|
||||
.focusElement(selectors.ticketSales.transferQuantityCell)
|
||||
.write(selectors.ticketSales.transferQuantityInput, '10\u000d')
|
||||
.write(selectors.ticketSales.moveToTicketInput, targetTicketId)
|
||||
.waitToClick(selectors.ticketSales.moveToTicketButton)
|
||||
.waitForURL(`ticket/${targetTicketId}/sale`)
|
||||
|
@ -276,7 +279,14 @@ describe('Ticket Edit sale path', () => {
|
|||
.wait(selectors.ticketSales.secondSaleText)
|
||||
.waitToGetProperty(selectors.ticketSales.secondSaleText, 'innerText');
|
||||
|
||||
expect(result).toContain(`Ranged weapon longbow 2m`);
|
||||
expect(result).toContain(`Melee weapon heavy shield`);
|
||||
});
|
||||
|
||||
it('should confirm the transfered quantity is the correct one', async() => {
|
||||
const result = await nightmare
|
||||
.waitToGetProperty(selectors.ticketSales.secondSaleQuantityCell, 'innerText');
|
||||
|
||||
expect(result).toContain('10');
|
||||
});
|
||||
|
||||
it('should go back to the original ticket sales section', async() => {
|
||||
|
@ -290,12 +300,19 @@ describe('Ticket Edit sale path', () => {
|
|||
expect(url.hash).toContain('/sale');
|
||||
});
|
||||
|
||||
it(`should confirm the original ticket has only two lines now`, async() => {
|
||||
it(`should confirm the original ticket has still three lines`, async() => {
|
||||
const result = await nightmare
|
||||
.wait(selectors.ticketSales.saleLine)
|
||||
.countElement(selectors.ticketSales.saleLine);
|
||||
|
||||
expect(result).toEqual(2);
|
||||
expect(result).toEqual(3);
|
||||
});
|
||||
|
||||
it(`should confirm the second sale quantity is now half of it's original value after the transfer`, async() => {
|
||||
const result = await nightmare
|
||||
.waitToGetProperty(selectors.ticketSales.secondSaleQuantityCell, 'innerText');
|
||||
|
||||
expect(result).toContain('10');
|
||||
});
|
||||
|
||||
it('should go back to the receiver ticket sales section', async() => {
|
||||
|
@ -324,11 +341,12 @@ describe('Ticket Edit sale path', () => {
|
|||
});
|
||||
|
||||
it('should confirm the original ticket received the line', async() => {
|
||||
const expectedLines = 4;
|
||||
const result = await nightmare
|
||||
.waitForNumberOfElements(selectors.ticketSales.saleLine, 3)
|
||||
.waitForNumberOfElements(selectors.ticketSales.saleLine, expectedLines)
|
||||
.countElement(selectors.ticketSales.saleLine);
|
||||
|
||||
expect(result).toEqual(3);
|
||||
expect(result).toEqual(expectedLines);
|
||||
});
|
||||
|
||||
it(`should throw an error when attempting to create a ticket for an inactive client`, async() => {
|
||||
|
@ -357,7 +375,7 @@ describe('Ticket Edit sale path', () => {
|
|||
const senderTicketId = 13;
|
||||
|
||||
const url = await nightmare
|
||||
.waitToClick(selectors.ticketSales.firstSaleCheckbox)
|
||||
.waitToClick(selectors.ticketSales.selectAllSalesCheckbox)
|
||||
.waitToClick(selectors.ticketSales.transferSaleButton)
|
||||
.waitToClick(selectors.ticketSales.moveToNewTicketButton)
|
||||
.waitToClick(selectors.ticketSales.acceptDeleteTicketButton)
|
||||
|
|
|
@ -9,10 +9,10 @@ describe('Ticket descriptor path', () => {
|
|||
.loginAndModule('employee', 'ticket');
|
||||
});
|
||||
|
||||
it('should count the mount of tickets in the turns section', async() => {
|
||||
it('should count the amount of tickets in the turns section', async() => {
|
||||
const result = await nightmare
|
||||
.waitToClick(selectors.ticketsIndex.moreMenu)
|
||||
.waitToClick(selectors.ticketsIndex.moreMenuTurns)
|
||||
.waitToClick(selectors.ticketsIndex.moreMenuWeeklyTickets)
|
||||
.wait(selectors.ticketsIndex.weeklyTicket)
|
||||
.countElement(selectors.ticketsIndex.weeklyTicket);
|
||||
|
||||
|
@ -32,7 +32,7 @@ describe('Ticket descriptor path', () => {
|
|||
|
||||
it('should search for the ticket 11', async() => {
|
||||
const result = await nightmare
|
||||
.write(selectors.ticketsIndex.searchTicketInput, 'id:11')
|
||||
.write(selectors.ticketsIndex.searchTicketInput, 11)
|
||||
.waitToClick(selectors.ticketsIndex.searchButton)
|
||||
.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1)
|
||||
.countElement(selectors.ticketsIndex.searchResult);
|
||||
|
@ -73,8 +73,8 @@ describe('Ticket descriptor path', () => {
|
|||
it('should confirm the ticket 11 was added on thursday', async() => {
|
||||
const result = await nightmare
|
||||
.waitToClick(selectors.ticketsIndex.moreMenu)
|
||||
.waitToClick(selectors.ticketsIndex.moreMenuTurns)
|
||||
.waitToGetProperty(selectors.ticketsIndex.sixthWeeklyTicketTurn, 'value');
|
||||
.waitToClick(selectors.ticketsIndex.moreMenuWeeklyTickets)
|
||||
.waitToGetProperty(selectors.ticketsIndex.sixthWeeklyTicket, 'value');
|
||||
|
||||
expect(result).toEqual('Thursday');
|
||||
});
|
||||
|
@ -92,7 +92,7 @@ describe('Ticket descriptor path', () => {
|
|||
|
||||
it('should now search for the ticket 11', async() => {
|
||||
const result = await nightmare
|
||||
.write(selectors.ticketsIndex.searchTicketInput, 'id:11')
|
||||
.write(selectors.ticketsIndex.searchTicketInput, 11)
|
||||
.waitToClick(selectors.ticketsIndex.searchButton)
|
||||
.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1)
|
||||
.countElement(selectors.ticketsIndex.searchResult);
|
||||
|
@ -133,17 +133,25 @@ describe('Ticket descriptor path', () => {
|
|||
it('should confirm the ticket 11 was added on saturday', async() => {
|
||||
const result = await nightmare
|
||||
.waitToClick(selectors.ticketsIndex.moreMenu)
|
||||
.waitToClick(selectors.ticketsIndex.moreMenuTurns)
|
||||
.waitToGetProperty(selectors.ticketsIndex.sixthWeeklyTicketTurn, 'value');
|
||||
.waitToClick(selectors.ticketsIndex.moreMenuWeeklyTickets)
|
||||
.waitToGetProperty(selectors.ticketsIndex.sixthWeeklyTicket, 'value');
|
||||
|
||||
expect(result).toEqual('Saturday');
|
||||
});
|
||||
|
||||
// Test #1450 here
|
||||
it('should now search for the weekly ticket 11', async() => {
|
||||
const result = await nightmare
|
||||
.write(selectors.ticketsIndex.searchWeeklyTicketInput, 11)
|
||||
.waitToClick(selectors.ticketsIndex.searchWeeklyButton)
|
||||
.waitForNumberOfElements(selectors.ticketsIndex.searchWeeklyResult, 1)
|
||||
.countElement(selectors.ticketsIndex.searchWeeklyResult);
|
||||
|
||||
expect(result).toEqual(1);
|
||||
});
|
||||
|
||||
it('should delete the weekly ticket 11', async() => {
|
||||
const result = await nightmare
|
||||
.waitToClick(selectors.ticketsIndex.sixthWeeklyTicketDeleteIcon)
|
||||
.waitToClick(selectors.ticketsIndex.firstWeeklyTicketDeleteIcon)
|
||||
.waitToClick(selectors.ticketsIndex.acceptDeleteTurn)
|
||||
.waitForLastSnackbar();
|
||||
|
||||
|
@ -152,7 +160,10 @@ describe('Ticket descriptor path', () => {
|
|||
|
||||
it('should confirm the sixth weekly ticket was deleted', async() => {
|
||||
const result = await nightmare
|
||||
.countElement(selectors.ticketsIndex.weeklyTicket);
|
||||
.waitToClick('vn-ticket-weekly-index vn-searchbar i[class="material-icons clear"]')
|
||||
.waitToClick(selectors.ticketsIndex.searchWeeklyButton)
|
||||
.waitForNumberOfElements(selectors.ticketsIndex.searchWeeklyResult, 5)
|
||||
.countElement(selectors.ticketsIndex.searchWeeklyResult);
|
||||
|
||||
expect(result).toEqual(5);
|
||||
});
|
|
@ -30,6 +30,33 @@ describe('Ticket descriptor path', () => {
|
|||
expect(url.hash).toContain('/summary');
|
||||
});
|
||||
|
||||
it('should open the change shipped hours dialog by using the more menu option', async() => {
|
||||
const visible = await nightmare
|
||||
.waitToClick(selectors.ticketDescriptor.moreMenu)
|
||||
.waitToClick(selectors.ticketDescriptor.moreMenuChangeShippedHour)
|
||||
.wait(selectors.ticketDescriptor.changeShippedHourInput)
|
||||
.isVisible(selectors.ticketDescriptor.changeShippedHourInput);
|
||||
|
||||
|
||||
expect(visible).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should update the shipped hour`, async() => {
|
||||
const result = await nightmare
|
||||
.write(selectors.ticketDescriptor.changeShippedHourInput, '0815')
|
||||
.waitToClick(selectors.ticketDescriptor.acceptChangeHourButton)
|
||||
.waitForLastSnackbar();
|
||||
|
||||
expect(result).toEqual('Shipped hour updated');
|
||||
});
|
||||
|
||||
it(`should confirm the ticket descriptor shows the correct shipping hour`, async() => {
|
||||
const result = await nightmare
|
||||
.waitToGetProperty(selectors.ticketDescriptor.descriptorDeliveryDate, 'innerText');
|
||||
|
||||
expect(result).toContain('08:15');
|
||||
});
|
||||
|
||||
it('should delete the ticket using the descriptor more menu', async() => {
|
||||
const result = await nightmare
|
||||
.waitToClick(selectors.ticketDescriptor.moreMenu)
|
||||
|
|
|
@ -69,14 +69,6 @@ describe('Ticket Summary path', () => {
|
|||
expect(exists).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should click on the SET OK button and throw a privileges error', async() => {
|
||||
let result = await nightmare
|
||||
.waitToClick(selectors.ticketSummary.setOk)
|
||||
.waitForLastSnackbar();
|
||||
|
||||
expect(result).toEqual(`You don't have enough privileges`);
|
||||
});
|
||||
|
||||
it('should log in as production then navigate to the summary of the same ticket', async() => {
|
||||
let url = await nightmare
|
||||
.loginAndModule('production', 'ticket')
|
||||
|
|
|
@ -7,7 +7,7 @@ describe('Claim action path', () => {
|
|||
beforeAll(() => {
|
||||
nightmare
|
||||
.loginAndModule('administrative', 'claim')
|
||||
.accessToSearchResult(4)
|
||||
.accessToSearchResult(2)
|
||||
.accessToSection('claim.card.action');
|
||||
});
|
||||
|
||||
|
|
|
@ -28,8 +28,8 @@ describe('Order edit basic data path', () => {
|
|||
it('should now navigate to order index', async() => {
|
||||
const orderId = 16;
|
||||
const url = await nightmare
|
||||
.waitToClick(selectors.globalItems.returnToModuleIndexButton)
|
||||
.waitToClick(selectors.globalItems.acceptButton)
|
||||
.waitToClick(selectors.orderDescriptor.returnToModuleIndexButton)
|
||||
.waitToClick(selectors.orderDescriptor.acceptNavigationButton)
|
||||
.wait(selectors.ordersIndex.createOrderButton)
|
||||
.accessToSearchResult(orderId)
|
||||
.accessToSection('order.card.basicData')
|
||||
|
|
|
@ -18,7 +18,10 @@
|
|||
ng-blur="$ctrl.hasFocus = false"
|
||||
tabindex="{{$ctrl.input.tabindex}}"
|
||||
accept="{{$ctrl.accept}}"/>
|
||||
<label class="label" translate>{{$ctrl.label}}</label>
|
||||
<label class="label">
|
||||
<span translate>{{::$ctrl.label}}</span>
|
||||
<span translate ng-show="::$ctrl.required">*</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="underline"></div>
|
||||
<div class="selected underline"></div>
|
||||
|
|
|
@ -122,6 +122,7 @@ ngModule.component('vnInputFile', {
|
|||
name: '@?',
|
||||
disabled: '<?',
|
||||
multiple: '<?',
|
||||
required: '@?',
|
||||
accept: '@?',
|
||||
rule: '@?',
|
||||
files: '=model',
|
||||
|
|
|
@ -73,6 +73,14 @@ export default class Popover extends Component {
|
|||
if (this._shown) return;
|
||||
|
||||
if (parent) this.parent = parent;
|
||||
|
||||
let isDescriptorMoreMenu = parent && parent.attributes[0].nodeValue == 'more-button';
|
||||
const leftMenu = this.document.querySelector('div[class="menu left"]');
|
||||
if (isDescriptorMoreMenu && leftMenu) {
|
||||
leftMenu.style.overflow = 'hidden';
|
||||
this.restoreOverflow = true;
|
||||
}
|
||||
|
||||
this._shown = true;
|
||||
this.element.style.display = 'block';
|
||||
this.$timeout.cancel(this.showTimeout);
|
||||
|
@ -96,6 +104,11 @@ export default class Popover extends Component {
|
|||
hide() {
|
||||
if (!this._shown) return;
|
||||
|
||||
if (this.restoreOverflow) {
|
||||
const leftMenu = this.document.querySelector('div[class="menu left"]');
|
||||
leftMenu.style.overflow = 'auto';
|
||||
this.restoreOverflow = false;
|
||||
}
|
||||
this._shown = false;
|
||||
this.$element.removeClass('shown');
|
||||
this.$timeout.cancel(this.showTimeout);
|
||||
|
|
|
@ -28,7 +28,6 @@ export default class Controller extends Component {
|
|||
() => this.onStateChange());
|
||||
|
||||
this._filter = null;
|
||||
this.searchString = '';
|
||||
this.autoLoad = false;
|
||||
}
|
||||
|
||||
|
@ -58,6 +57,10 @@ export default class Controller extends Component {
|
|||
this.doSearch();
|
||||
}
|
||||
|
||||
get shownFilter() {
|
||||
return this._filter != null ? this._filter : this.suggestedFilter;
|
||||
}
|
||||
|
||||
openPanel(event) {
|
||||
if (event.defaultPrevented) return;
|
||||
event.preventDefault();
|
||||
|
@ -65,7 +68,8 @@ export default class Controller extends Component {
|
|||
this.$panelScope = this.$.$new();
|
||||
this.$panel = this.$compile(`<${this.panel}/>`)(this.$panelScope);
|
||||
let panel = this.$panel.isolateScope().$ctrl;
|
||||
panel.filter = this._filter;
|
||||
if (this.shownFilter)
|
||||
panel.filter = JSON.parse(JSON.stringify(this.shownFilter));
|
||||
panel.onSubmit = filter => this.onPanelSubmit(filter);
|
||||
|
||||
this.$.popover.parent = this.element;
|
||||
|
@ -94,13 +98,12 @@ export default class Controller extends Component {
|
|||
}
|
||||
|
||||
doSearch() {
|
||||
let filter = this._filter;
|
||||
this.searchString = this.getStringFromObject(this.shownFilter);
|
||||
|
||||
let filter = this._filter;
|
||||
if (filter == null && this.autoload)
|
||||
filter = {};
|
||||
|
||||
this.searchString = this.getStringFromObject(filter);
|
||||
|
||||
if (this.onSearch)
|
||||
this.onSearch({$params: filter});
|
||||
|
||||
|
@ -214,6 +217,7 @@ ngModule.component('vnSearchbar', {
|
|||
template: require('./searchbar.html'),
|
||||
bindings: {
|
||||
filter: '<?',
|
||||
suggestedFilter: '<?',
|
||||
onSearch: '&?',
|
||||
panel: '@',
|
||||
model: '<?',
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
tabindex="{{$ctrl.input.tabindex}}"/>
|
||||
<label class="label">
|
||||
<span translate>{{::$ctrl.label}}</span>
|
||||
<span translate vn-tooltip="Required" ng-show="::$ctrl.required">*</span>
|
||||
<span translate ng-show="::$ctrl.required">*</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="underline"></div>
|
||||
|
|
|
@ -16,9 +16,10 @@ export default class MainMenu {
|
|||
}
|
||||
|
||||
getCurrentUserName() {
|
||||
this.$http.get('/api/Accounts/getCurrentUserName')
|
||||
this.$http.get('/api/Accounts/getCurrentUserData')
|
||||
.then(json => {
|
||||
this.$.currentUserName = json.data;
|
||||
this.$.currentUserName = json.data.accountName;
|
||||
window.localStorage.currentUserWorkerId = json.data.workerId;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -14,8 +14,8 @@ describe('Component vnMainMenu', () => {
|
|||
|
||||
describe('getCurrentUserName()', () => {
|
||||
it(`should set the user name property in the controller`, () => {
|
||||
$httpBackend.when('GET', `/api/Accounts/getCurrentUserName`).respond('Batman');
|
||||
$httpBackend.expect('GET', `/api/Accounts/getCurrentUserName`);
|
||||
$httpBackend.when('GET', `/api/Accounts/getCurrentUserData`).respond({accountName: 'Batman'});
|
||||
$httpBackend.expect('GET', `/api/Accounts/getCurrentUserData`);
|
||||
controller.getCurrentUserName();
|
||||
$httpBackend.flush();
|
||||
|
||||
|
|
11
gulpfile.js
11
gulpfile.js
|
@ -23,9 +23,6 @@ let containerId = 'salix-db';
|
|||
let dataSources = require('./loopback/server/datasources.json');
|
||||
let dbConf = dataSources.vn;
|
||||
|
||||
if (process.env.DB_HOST)
|
||||
dbConf.host = process.env.DB_HOST;
|
||||
|
||||
let backSources = [
|
||||
'!node_modules',
|
||||
'loopback',
|
||||
|
@ -423,9 +420,11 @@ async function docker() {
|
|||
containerId = result.stdout;
|
||||
|
||||
if (argv['random']) {
|
||||
let inspect = await execP(`docker inspect -f "{{json .NetworkSettings.Ports}}" ${containerId}`);
|
||||
let ports = JSON.parse(inspect.stdout);
|
||||
dbConf.port = ports['3306/tcp'][0]['HostPort'];
|
||||
let inspect = await execP(`docker inspect -f "{{json .NetworkSettings}}" ${containerId}`);
|
||||
let netSettings = JSON.parse(inspect.stdout);
|
||||
|
||||
dbConf.host = netSettings.Gateway;
|
||||
dbConf.port = netSettings.Ports['3306/tcp'][0]['HostPort'];
|
||||
}
|
||||
|
||||
if (runChown) await dockerWait();
|
||||
|
|
|
@ -49,5 +49,9 @@
|
|||
"This client can't be invoiced": "This client can't be invoiced",
|
||||
"The introduced hour already exists": "The introduced hour already exists",
|
||||
"Invalid parameters to create a new ticket": "Invalid parameters to create a new ticket",
|
||||
"Concept cannot be blank": "Concept cannot be blank"
|
||||
"Concept cannot be blank": "Concept cannot be blank",
|
||||
"Ticket id cannot be blank": "Ticket id cannot be blank",
|
||||
"Weekday cannot be blank": "Weekday cannot be blank",
|
||||
"This ticket can not be modified": "This ticket can not be modified",
|
||||
"You can't delete a confirmed order": "You can't delete a confirmed order"
|
||||
}
|
|
@ -97,5 +97,9 @@
|
|||
"This postcode already exists": "Este código postal ya existe",
|
||||
"Concept cannot be blank": "El concepto no puede quedar en blanco",
|
||||
"File doesn't exists": "El archivo no existe",
|
||||
"You don't have privileges to change the zone": "No tienes permisos para cambiar la zona"
|
||||
"You don't have privileges to change the zone": "No tienes permisos para cambiar la zona",
|
||||
"This ticket is already on weekly tickets": "Este ticket ya está en tickets programados",
|
||||
"Ticket id cannot be blank": "El id de ticket no puede quedar en blanco",
|
||||
"Weekday cannot be blank": "El día de la semana no puede quedar en blanco",
|
||||
"You can't delete a confirmed order": "No puedes borrar un pedido confirmado"
|
||||
}
|
|
@ -20,11 +20,16 @@
|
|||
"connector": "loopback-component-storage",
|
||||
"provider": "filesystem",
|
||||
"root": "./e2e/dms",
|
||||
"maxFileSize": "10485760",
|
||||
"maxFileSize": "52428800",
|
||||
"allowedContentTypes": [
|
||||
"application/x-7z-compressed",
|
||||
"application/x-zip-compressed",
|
||||
"application/x-rar-compressed",
|
||||
"application/octet-stream",
|
||||
"application/pdf",
|
||||
"application/zip",
|
||||
"application/rar",
|
||||
"multipart/x-zip",
|
||||
"image/png",
|
||||
"image/jpeg",
|
||||
"image/jpg"
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('allowedContentTypes', {
|
||||
description: 'Returns a list of allowed contentTypes',
|
||||
accessType: 'READ',
|
||||
returns: {
|
||||
type: ['Object'],
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/allowedContentTypes`,
|
||||
verb: 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
Self.allowedContentTypes = async() => {
|
||||
const storageConnector = Self.app.dataSources.storage.connector;
|
||||
const allowedContentTypes = storageConnector.allowedContentTypes;
|
||||
const modelAllowedContentTypes = Self.definition.settings.allowedContentTypes;
|
||||
|
||||
return modelAllowedContentTypes || allowedContentTypes;
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('removeFile', {
|
||||
description: 'Removes a ticket document',
|
||||
accessType: 'WRITE',
|
||||
accepts: {
|
||||
arg: 'id',
|
||||
type: 'Number',
|
||||
description: 'The document id',
|
||||
http: {source: 'path'}
|
||||
},
|
||||
returns: {
|
||||
type: 'Object',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/:id/removeFile`,
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
Self.removeFile = async(ctx, id) => {
|
||||
const models = Self.app.models;
|
||||
const targetClaimDms = await models.ClaimDms.findById(id);
|
||||
const targetDms = await models.Dms.findById(targetClaimDms.dmsFk);
|
||||
const trashDmsType = await models.DmsType.findOne({where: {code: 'trash'}});
|
||||
|
||||
await models.Dms.removeFile(ctx, targetClaimDms.dmsFk);
|
||||
await targetClaimDms.destroy();
|
||||
|
||||
return targetDms.updateAttribute('dmsTypeFk', trashDmsType.id);
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
|
||||
describe('TicketDms removeFile()', () => {
|
||||
const ticketDmsId = 1;
|
||||
it(`should return an error for a user without enough privileges`, async() => {
|
||||
let clientId = 101;
|
||||
let ctx = {req: {accessToken: {userId: clientId}}};
|
||||
|
||||
let error;
|
||||
await app.models.TicketDms.removeFile(ctx, ticketDmsId).catch(e => {
|
||||
error = e;
|
||||
}).finally(() => {
|
||||
expect(error.message).toEqual(`You don't have enough privileges`);
|
||||
});
|
||||
|
||||
expect(error).toBeDefined();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,78 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('uploadFile', {
|
||||
description: 'Upload and attach a document',
|
||||
accessType: 'WRITE',
|
||||
accepts: [{
|
||||
arg: 'id',
|
||||
type: 'Number',
|
||||
description: 'The claim id',
|
||||
http: {source: 'path'}
|
||||
},
|
||||
{
|
||||
arg: 'warehouseId',
|
||||
type: 'Number',
|
||||
description: ''
|
||||
},
|
||||
{
|
||||
arg: 'companyId',
|
||||
type: 'Number',
|
||||
description: ''
|
||||
},
|
||||
{
|
||||
arg: 'dmsTypeId',
|
||||
type: 'Number',
|
||||
description: ''
|
||||
},
|
||||
{
|
||||
arg: 'reference',
|
||||
type: 'String',
|
||||
description: ''
|
||||
},
|
||||
{
|
||||
arg: 'description',
|
||||
type: 'String',
|
||||
description: ''
|
||||
},
|
||||
{
|
||||
arg: 'hasFile',
|
||||
type: 'Boolean',
|
||||
description: ''
|
||||
}],
|
||||
returns: {
|
||||
type: 'Object',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/:id/uploadFile`,
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
Self.uploadFile = async(ctx, id) => {
|
||||
const models = Self.app.models;
|
||||
const promises = [];
|
||||
const tx = await Self.beginTransaction({});
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
const uploadedFiles = await models.Dms.uploadFile(ctx, options);
|
||||
uploadedFiles.forEach(dms => {
|
||||
const newClaimDms = models.ClaimDms.create({
|
||||
claimFk: id,
|
||||
dmsFk: dms.id
|
||||
}, options);
|
||||
|
||||
promises.push(newClaimDms);
|
||||
});
|
||||
const resolvedPromises = await Promise.all(promises);
|
||||
|
||||
await tx.commit();
|
||||
|
||||
return resolvedPromises;
|
||||
} catch (err) {
|
||||
await tx.rollback();
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
};
|
|
@ -31,5 +31,11 @@
|
|||
},
|
||||
"ClaimState": {
|
||||
"dataSource": "vn"
|
||||
}
|
||||
},
|
||||
"ClaimDms": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"ClaimLog": {
|
||||
"dataSource": "vn"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
module.exports = Self => {
|
||||
require('../methods/claim-dms/removeFile')(Self);
|
||||
require('../methods/claim-dms/allowedContentTypes')(Self);
|
||||
};
|
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"name": "ClaimDms",
|
||||
"base": "Loggable",
|
||||
"log": {
|
||||
"model": "ClaimLog",
|
||||
"relation": "claim"
|
||||
},
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "claimDms"
|
||||
}
|
||||
},
|
||||
"allowedContentTypes": [
|
||||
"image/png",
|
||||
"image/jpeg",
|
||||
"image/jpg"
|
||||
],
|
||||
"properties": {
|
||||
"dmsFk": {
|
||||
"type": "Number",
|
||||
"id": true,
|
||||
"required": true
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"claim": {
|
||||
"type": "belongsTo",
|
||||
"model": "Claim",
|
||||
"foreignKey": "claimFk"
|
||||
},
|
||||
"dms": {
|
||||
"type": "belongsTo",
|
||||
"model": "Dms",
|
||||
"foreignKey": "dmsFk"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
{
|
||||
"name": "ClaimLog",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "claimLog"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "Number",
|
||||
"forceId": false
|
||||
},
|
||||
"originFk": {
|
||||
"type": "Number",
|
||||
"required": true
|
||||
},
|
||||
"userFk": {
|
||||
"type": "Number"
|
||||
},
|
||||
"action": {
|
||||
"type": "String",
|
||||
"required": true
|
||||
},
|
||||
"changedModel": {
|
||||
"type": "String"
|
||||
},
|
||||
"oldInstance": {
|
||||
"type": "Object"
|
||||
},
|
||||
"newInstance": {
|
||||
"type": "Object"
|
||||
},
|
||||
"creationDate": {
|
||||
"type": "Date"
|
||||
},
|
||||
"changedModelId": {
|
||||
"type": "Number"
|
||||
},
|
||||
"changedModelValue": {
|
||||
"type": "String"
|
||||
},
|
||||
"description": {
|
||||
"type": "String"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"user": {
|
||||
"type": "belongsTo",
|
||||
"model": "Account",
|
||||
"foreignKey": "userFk"
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"order": ["creationDate DESC", "id DESC"]
|
||||
}
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
module.exports = Self => {
|
||||
require('../methods/claim/filter')(Self);
|
||||
require('../methods/claim/getSummary')(Self);
|
||||
require('../methods/claim/createFromSales')(Self);
|
||||
require('../methods/claim/updateClaim')(Self);
|
||||
require('../methods/claim/regularizeClaim')(Self);
|
||||
require('../methods/claim/filter')(Self);
|
||||
require('../methods/claim/uploadFile')(Self);
|
||||
};
|
||||
|
|
|
@ -18,11 +18,13 @@
|
|||
<vn-tool-bar margin-medium-bottom>
|
||||
<vn-button
|
||||
label="Import claim"
|
||||
vn-http-click="$ctrl.importToNewRefundTicket()"
|
||||
disabled="$ctrl.claim.claimStateFk == $ctrl.resolvedState"
|
||||
vn-http-click="$ctrl.importToNewRefundTicket()"p
|
||||
vn-tooltip="Imports claim details">
|
||||
</vn-button>
|
||||
<vn-button
|
||||
label="Import ticket"
|
||||
disabled="$ctrl.claim.claimStateFk == $ctrl.resolvedState"
|
||||
ng-click="$ctrl.showLastTickets($event)"
|
||||
vn-tooltip="Imports ticket lines">
|
||||
</vn-button>
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th number>Id</vn-th>
|
||||
<vn-th center>Landed</vn-th>
|
||||
<vn-th number>Quantity</vn-th>
|
||||
<vn-th>Claimed</vn-th>
|
||||
|
@ -35,13 +34,6 @@
|
|||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="saleClaimed in $ctrl.salesClaimed" vn-repeat-last>
|
||||
<vn-td number>
|
||||
<span
|
||||
ng-click="$ctrl.showDescriptor($event, saleClaimed.sale.itemFk)"
|
||||
class="link">
|
||||
{{::saleClaimed.sale.itemFk | zeroFill:6}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td center>{{::saleClaimed.sale.ticket.landed | dateTime:'dd/MM/yyyy'}}</vn-td>
|
||||
<vn-td number>{{::saleClaimed.sale.quantity}}</vn-td>
|
||||
<vn-td>
|
||||
|
@ -50,7 +42,13 @@
|
|||
on-change="$ctrl.setClaimedQuantity(saleClaimed.id, saleClaimed.quantity)">
|
||||
</vn-input-number>
|
||||
</vn-td>
|
||||
<vn-td expand>{{::saleClaimed.sale.concept}}</vn-td>
|
||||
<vn-td expand title="{{::saleClaimed.sale.concept}}">
|
||||
<span
|
||||
class="link"
|
||||
ng-click="$ctrl.showDescriptor($event, saleClaimed.sale.itemFk)">
|
||||
{{::saleClaimed.sale.concept}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td number>{{::saleClaimed.sale.price | currency: 'EUR':2}}</vn-td>
|
||||
<vn-td number>
|
||||
<span class="link"
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
data="$ctrl.dms">
|
||||
</vn-watcher>
|
||||
<form name="form" ng-submit="$ctrl.onSubmit()" margin-medium enctype="multipart/form-data">
|
||||
<div compact>
|
||||
<vn-card pad-large>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one vn-focus
|
||||
label="Reference"
|
||||
field="$ctrl.dms.reference">
|
||||
</vn-textfield>
|
||||
<vn-autocomplete vn-one
|
||||
label="Company"
|
||||
field="$ctrl.dms.companyId"
|
||||
url="/api/Companies"
|
||||
show-field="code"
|
||||
value-field="id">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete vn-one
|
||||
label="Warehouse"
|
||||
field="$ctrl.dms.warehouseId"
|
||||
url="/api/Warehouses"
|
||||
show-field="name"
|
||||
value-field="id">
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete vn-one
|
||||
label="Type"
|
||||
field="$ctrl.dms.dmsTypeId"
|
||||
url="/api/DmsTypes"
|
||||
show-field="name"
|
||||
value-field="id">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textarea vn-one
|
||||
label="Description"
|
||||
field="$ctrl.dms.description">
|
||||
</vn-textarea>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-input-file vn-one
|
||||
label="File"
|
||||
model="$ctrl.dms.files"
|
||||
on-change="$ctrl.onFileChange(files)"
|
||||
accept="{{$ctrl.allowedContentTypes}}"
|
||||
multiple="true">
|
||||
<t-right-icons>
|
||||
<vn-icon vn-none
|
||||
color-secondary
|
||||
title="{{$ctrl.contentTypesInfo}}"
|
||||
icon="info">
|
||||
</vn-icon>
|
||||
</t-right-icons>
|
||||
</vn-input-file>
|
||||
</vn-horizontal>
|
||||
<vn-vertical>
|
||||
<vn-check
|
||||
label="Generate identifier for original file"
|
||||
field="$ctrl.dms.hasFile">
|
||||
</vn-check>
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
<vn-submit label="Upload"></vn-submit>
|
||||
<vn-button ui-sref="claim.card.dms.index" label="Cancel"></vn-button>
|
||||
</vn-button-bar>
|
||||
</div>
|
||||
</form>
|
|
@ -0,0 +1,115 @@
|
|||
import ngModule from '../../module';
|
||||
import './style.scss';
|
||||
|
||||
class Controller {
|
||||
constructor($scope, $http, $state, $translate, vnApp) {
|
||||
this.$ = $scope;
|
||||
this.$http = $http;
|
||||
this.$state = $state;
|
||||
this.$translate = $translate;
|
||||
this.vnApp = vnApp;
|
||||
this.dms = {
|
||||
files: [],
|
||||
hasFile: false,
|
||||
hasFileAttached: false
|
||||
};
|
||||
}
|
||||
|
||||
get claim() {
|
||||
return this._claim;
|
||||
}
|
||||
|
||||
set claim(value) {
|
||||
this._claim = value;
|
||||
|
||||
if (value) {
|
||||
this.setDefaultParams();
|
||||
this.getAllowedContentTypes();
|
||||
}
|
||||
}
|
||||
|
||||
getAllowedContentTypes() {
|
||||
this.$http.get('/api/claimDms/allowedContentTypes').then(res => {
|
||||
const contentTypes = res.data.join(', ');
|
||||
this.allowedContentTypes = contentTypes;
|
||||
});
|
||||
}
|
||||
|
||||
get contentTypesInfo() {
|
||||
return this.$translate.instant('ContentTypesInfo', {
|
||||
allowedContentTypes: this.allowedContentTypes
|
||||
});
|
||||
}
|
||||
|
||||
setDefaultParams() {
|
||||
const params = {filter: {
|
||||
where: {code: 'claim'}
|
||||
}};
|
||||
this.$http.get('/api/DmsTypes/findOne', {params}).then(res => {
|
||||
const dmsTypeId = res.data && res.data.id;
|
||||
const companyId = window.localStorage.defaultCompanyFk;
|
||||
const warehouseId = window.localStorage.defaultWarehouseFk;
|
||||
const defaultParams = {
|
||||
reference: this.claim.id,
|
||||
warehouseId: warehouseId,
|
||||
companyId: companyId,
|
||||
dmsTypeId: dmsTypeId,
|
||||
description: this.$translate.instant('FileDescription', {
|
||||
claimId: this.claim.id,
|
||||
clientId: this.claim.client.id,
|
||||
clientName: this.claim.client.name
|
||||
}).toUpperCase()
|
||||
};
|
||||
|
||||
this.dms = Object.assign(this.dms, defaultParams);
|
||||
});
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
const query = `/api/claims/${this.claim.id}/uploadFile`;
|
||||
const options = {
|
||||
method: 'POST',
|
||||
url: query,
|
||||
params: this.dms,
|
||||
headers: {
|
||||
'Content-Type': undefined
|
||||
},
|
||||
transformRequest: files => {
|
||||
const formData = new FormData();
|
||||
|
||||
for (let i = 0; i < files.length; i++)
|
||||
formData.append(files[i].name, files[i]);
|
||||
|
||||
return formData;
|
||||
},
|
||||
data: this.dms.files
|
||||
};
|
||||
this.$http(options).then(res => {
|
||||
if (res) {
|
||||
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
|
||||
this.$.watcher.updateOriginalData();
|
||||
this.$state.go('claim.card.dms.index');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onFileChange(files) {
|
||||
let hasFileAttached = false;
|
||||
if (files.length > 0)
|
||||
hasFileAttached = true;
|
||||
|
||||
this.$.$applyAsync(() => {
|
||||
this.dms.hasFileAttached = hasFileAttached;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$scope', '$http', '$state', '$translate', 'vnApp'];
|
||||
|
||||
ngModule.component('vnClaimDmsCreate', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller,
|
||||
bindings: {
|
||||
claim: '<'
|
||||
}
|
||||
});
|
|
@ -0,0 +1,81 @@
|
|||
import './index';
|
||||
|
||||
describe('Claim', () => {
|
||||
describe('Component vnClaimDmsCreate', () => {
|
||||
let controller;
|
||||
let $scope;
|
||||
let $httpBackend;
|
||||
let $httpParamSerializer;
|
||||
|
||||
beforeEach(ngModule('claim'));
|
||||
|
||||
beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_, _$httpParamSerializer_) => {
|
||||
$scope = $rootScope.$new();
|
||||
$httpBackend = _$httpBackend_;
|
||||
$httpParamSerializer = _$httpParamSerializer_;
|
||||
controller = $componentController('vnClaimDmsCreate', {$scope});
|
||||
controller._claim = {
|
||||
id: 15,
|
||||
client: {id: 101, name: 'Bruce wayne'},
|
||||
ticketFk: 16
|
||||
};
|
||||
}));
|
||||
|
||||
describe('claim() setter', () => {
|
||||
it('should set the claim data and then call setDefaultParams() and getAllowedContentTypes()', () => {
|
||||
spyOn(controller, 'setDefaultParams');
|
||||
spyOn(controller, 'getAllowedContentTypes');
|
||||
controller._claim = undefined;
|
||||
controller.claim = {
|
||||
id: 15,
|
||||
client: {id: 101, name: 'Bruce wayne'},
|
||||
ticketFk: 16
|
||||
};
|
||||
|
||||
expect(controller.claim).toBeDefined();
|
||||
expect(controller.setDefaultParams).toHaveBeenCalledWith();
|
||||
expect(controller.getAllowedContentTypes).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
|
||||
describe('setDefaultParams()', () => {
|
||||
it('should perform a GET query and define the dms property on controller', () => {
|
||||
const params = {filter: {
|
||||
where: {code: 'claim'}
|
||||
}};
|
||||
let serializedParams = $httpParamSerializer(params);
|
||||
$httpBackend.when('GET', `/api/DmsTypes/findOne?${serializedParams}`).respond({id: 14, code: 'claim'});
|
||||
$httpBackend.expect('GET', `/api/DmsTypes/findOne?${serializedParams}`);
|
||||
controller.setDefaultParams();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.dms).toBeDefined();
|
||||
expect(controller.dms.reference).toEqual(15);
|
||||
expect(controller.dms.dmsTypeId).toEqual(14);
|
||||
});
|
||||
});
|
||||
|
||||
describe('onFileChange()', () => {
|
||||
it('should set dms hasFileAttached property to true if has any files', () => {
|
||||
const files = [{id: 1, name: 'MyFile'}];
|
||||
controller.onFileChange(files);
|
||||
$scope.$apply();
|
||||
|
||||
expect(controller.dms.hasFileAttached).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getAllowedContentTypes()', () => {
|
||||
it('should make an HTTP GET request to get the allowed content types', () => {
|
||||
const expectedResponse = ['image/png', 'image/jpg'];
|
||||
$httpBackend.when('GET', `/api/claimDms/allowedContentTypes`).respond(expectedResponse);
|
||||
$httpBackend.expect('GET', `/api/claimDms/allowedContentTypes`);
|
||||
controller.getAllowedContentTypes();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.allowedContentTypes).toBeDefined();
|
||||
expect(controller.allowedContentTypes).toEqual('image/png, image/jpg');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,7 @@
|
|||
vn-ticket-request {
|
||||
vn-textfield {
|
||||
margin: 0!important;
|
||||
max-width: 100px;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
data="$ctrl.dms">
|
||||
</vn-watcher>
|
||||
<form name="form" ng-submit="$ctrl.onSubmit()" margin-medium enctype="multipart/form-data">
|
||||
<div compact>
|
||||
<vn-card pad-large>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one vn-focus
|
||||
label="Reference"
|
||||
field="$ctrl.dms.reference">
|
||||
</vn-textfield>
|
||||
<vn-autocomplete vn-one required="true"
|
||||
label="Company"
|
||||
field="$ctrl.dms.companyId"
|
||||
url="/api/Companies"
|
||||
show-field="code"
|
||||
value-field="id">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete vn-one required="true"
|
||||
label="Warehouse"
|
||||
field="$ctrl.dms.warehouseId"
|
||||
url="/api/Warehouses"
|
||||
show-field="name"
|
||||
value-field="id">
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete vn-one required="true"
|
||||
label="Type"
|
||||
field="$ctrl.dms.dmsTypeId"
|
||||
url="/api/DmsTypes"
|
||||
show-field="name"
|
||||
value-field="id">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textarea vn-one required="true"
|
||||
label="Description"
|
||||
field="$ctrl.dms.description">
|
||||
</vn-textarea>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-input-file vn-one
|
||||
label="File"
|
||||
model="$ctrl.dms.files"
|
||||
on-change="$ctrl.onFileChange(files)"
|
||||
accept="{{$ctrl.allowedContentTypes}}"
|
||||
multiple="true">
|
||||
<t-right-icons>
|
||||
<vn-icon vn-none
|
||||
color-secondary
|
||||
title="{{$ctrl.contentTypesInfo}}"
|
||||
icon="info">
|
||||
</vn-icon>
|
||||
</t-right-icons>
|
||||
</vn-input-file>
|
||||
</vn-horizontal>
|
||||
<vn-vertical>
|
||||
<vn-check disabled="true"
|
||||
label="Generate identifier for original file"
|
||||
field="$ctrl.dms.hasFile">
|
||||
</vn-check>
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
<vn-submit label="Save"></vn-submit>
|
||||
<vn-button ui-sref="claim.card.dms.index" label="Cancel"></vn-button>
|
||||
</vn-button-bar>
|
||||
</div>
|
||||
</form>
|
|
@ -0,0 +1,104 @@
|
|||
import ngModule from '../../module';
|
||||
import './style.scss';
|
||||
|
||||
class Controller {
|
||||
constructor($scope, $http, $state, $translate, vnApp) {
|
||||
this.$ = $scope;
|
||||
this.$http = $http;
|
||||
this.$state = $state;
|
||||
this.$stateParams = $state.params;
|
||||
this.$translate = $translate;
|
||||
this.vnApp = vnApp;
|
||||
}
|
||||
|
||||
get claim() {
|
||||
return this._claim;
|
||||
}
|
||||
|
||||
set claim(value) {
|
||||
this._claim = value;
|
||||
|
||||
if (value) {
|
||||
this.setDefaultParams();
|
||||
this.getAllowedContentTypes();
|
||||
}
|
||||
}
|
||||
|
||||
getAllowedContentTypes() {
|
||||
this.$http.get('/api/claimDms/allowedContentTypes').then(res => {
|
||||
const contentTypes = res.data.join(', ');
|
||||
this.allowedContentTypes = contentTypes;
|
||||
});
|
||||
}
|
||||
|
||||
get contentTypesInfo() {
|
||||
return this.$translate.instant('ContentTypesInfo', {
|
||||
allowedContentTypes: this.allowedContentTypes
|
||||
});
|
||||
}
|
||||
|
||||
setDefaultParams() {
|
||||
const path = `/api/Dms/${this.$stateParams.dmsId}`;
|
||||
this.$http.get(path).then(res => {
|
||||
const dms = res.data && res.data;
|
||||
this.dms = {
|
||||
reference: dms.reference,
|
||||
warehouseId: dms.warehouseFk,
|
||||
companyId: dms.companyFk,
|
||||
dmsTypeId: dms.dmsTypeFk,
|
||||
description: dms.description,
|
||||
hasFile: dms.hasFile,
|
||||
hasFileAttached: false,
|
||||
files: []
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
const query = `/api/dms/${this.$stateParams.dmsId}/updateFile`;
|
||||
const options = {
|
||||
method: 'POST',
|
||||
url: query,
|
||||
params: this.dms,
|
||||
headers: {
|
||||
'Content-Type': undefined
|
||||
},
|
||||
transformRequest: files => {
|
||||
const formData = new FormData();
|
||||
|
||||
for (let i = 0; i < files.length; i++)
|
||||
formData.append(files[i].name, files[i]);
|
||||
|
||||
return formData;
|
||||
},
|
||||
data: this.dms.files
|
||||
};
|
||||
this.$http(options).then(res => {
|
||||
if (res) {
|
||||
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
|
||||
this.$.watcher.updateOriginalData();
|
||||
this.$state.go('claim.card.dms.index');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onFileChange(files) {
|
||||
let hasFileAttached = false;
|
||||
if (files.length > 0)
|
||||
hasFileAttached = true;
|
||||
|
||||
this.$.$applyAsync(() => {
|
||||
this.dms.hasFileAttached = hasFileAttached;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$scope', '$http', '$state', '$translate', 'vnApp'];
|
||||
|
||||
ngModule.component('vnClaimDmsEdit', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller,
|
||||
bindings: {
|
||||
claim: '<'
|
||||
}
|
||||
});
|
|
@ -0,0 +1,84 @@
|
|||
import './index';
|
||||
|
||||
describe('Claim', () => {
|
||||
describe('Component vnClaimDmsEdit', () => {
|
||||
let controller;
|
||||
let $scope;
|
||||
let $httpBackend;
|
||||
let $state;
|
||||
|
||||
beforeEach(ngModule('claim'));
|
||||
|
||||
beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_) => {
|
||||
$scope = $rootScope.$new();
|
||||
$httpBackend = _$httpBackend_;
|
||||
$state = {params: {dmsId: 1}};
|
||||
controller = $componentController('vnClaimDmsEdit', {$scope, $state});
|
||||
controller._claim = {id: 1, ticketFk: 16};
|
||||
}));
|
||||
|
||||
describe('claim() setter', () => {
|
||||
it('should set the claim data and then call setDefaultParams() and getAllowedContentTypes()', () => {
|
||||
spyOn(controller, 'setDefaultParams');
|
||||
spyOn(controller, 'getAllowedContentTypes');
|
||||
controller._claim = undefined;
|
||||
controller.claim = {
|
||||
id: 15,
|
||||
ticketFk: 16
|
||||
};
|
||||
|
||||
expect(controller.setDefaultParams).toHaveBeenCalledWith();
|
||||
expect(controller.claim).toBeDefined();
|
||||
expect(controller.getAllowedContentTypes).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
|
||||
describe('setDefaultParams()', () => {
|
||||
it('should perform a GET query and define the dms property on controller', () => {
|
||||
const dmsId = 1;
|
||||
const expectedResponse = {
|
||||
reference: 101,
|
||||
warehouseFk: 1,
|
||||
companyFk: 442,
|
||||
dmsTypeFk: 20,
|
||||
description: 'Test',
|
||||
hasFile: false,
|
||||
hasFileAttached: false
|
||||
};
|
||||
|
||||
$httpBackend.when('GET', `/api/Dms/${dmsId}`).respond(expectedResponse);
|
||||
$httpBackend.expect('GET', `/api/Dms/${dmsId}`).respond(expectedResponse);
|
||||
controller.setDefaultParams();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.dms).toBeDefined();
|
||||
expect(controller.dms.reference).toEqual(101);
|
||||
expect(controller.dms.dmsTypeId).toEqual(20);
|
||||
});
|
||||
});
|
||||
|
||||
describe('onFileChange()', () => {
|
||||
it('should set dms hasFileAttached property to true if has any files', () => {
|
||||
const files = [{id: 1, name: 'MyFile'}];
|
||||
controller.dms = {hasFileAttached: false};
|
||||
controller.onFileChange(files);
|
||||
$scope.$apply();
|
||||
|
||||
expect(controller.dms.hasFileAttached).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getAllowedContentTypes()', () => {
|
||||
it('should make an HTTP GET request to get the allowed content types', () => {
|
||||
const expectedResponse = ['image/png', 'image/jpg'];
|
||||
$httpBackend.when('GET', `/api/claimDms/allowedContentTypes`).respond(expectedResponse);
|
||||
$httpBackend.expect('GET', `/api/claimDms/allowedContentTypes`);
|
||||
controller.getAllowedContentTypes();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.allowedContentTypes).toBeDefined();
|
||||
expect(controller.allowedContentTypes).toEqual('image/png, image/jpg');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,7 @@
|
|||
vn-ticket-request {
|
||||
vn-textfield {
|
||||
margin: 0!important;
|
||||
max-width: 100px;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="/api/ClaimDms"
|
||||
link="{claimFk: $ctrl.$stateParams.id}"
|
||||
filter="::$ctrl.filter"
|
||||
limit="20"
|
||||
data="$ctrl.claimDms">
|
||||
</vn-crud-model>
|
||||
<vn-vertical>
|
||||
<vn-card pad-large>
|
||||
<vn-vertical>
|
||||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th field="dmsFk" default-order="DESC" shrink>Id</vn-th>
|
||||
<vn-th shrink>Type</vn-th>
|
||||
<vn-th shrink number>Order</vn-th>
|
||||
<vn-th shrink>Reference</vn-th>
|
||||
<vn-th>Description</vn-th>
|
||||
<vn-th shrink>Original</vn-th>
|
||||
<vn-th>File</vn-th>
|
||||
<vn-th shrink>Employee</vn-th>
|
||||
<vn-th>Created</vn-th>
|
||||
<vn-th number></vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="document in $ctrl.claimDms">
|
||||
<vn-td number shrink>{{::document.dmsFk}}</vn-td>
|
||||
<vn-td shrink>
|
||||
<span title="{{::document.dms.dmsType.name}}">
|
||||
{{::document.dms.dmsType.name}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td shrink number>
|
||||
<span title="{{::document.dms.hardCopyNumber}}">
|
||||
{{::document.dms.hardCopyNumber}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td shrink>
|
||||
<span title="{{::document.dms.reference}}">
|
||||
{{::document.dms.reference}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td>
|
||||
<span title="{{::document.dms.description}}">
|
||||
{{::document.dms.description}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td shrink>
|
||||
<vn-check disabled="true"
|
||||
field="document.dms.hasFile">
|
||||
</vn-check>
|
||||
</vn-td>
|
||||
<vn-td>
|
||||
<a target="_blank"
|
||||
title="{{'Download file' | translate}}"
|
||||
href="api/dms/{{::document.dmsFk}}/downloadFile?access_token={{::$ctrl.accessToken}}">
|
||||
{{::document.dms.file}}
|
||||
</a>
|
||||
</vn-td>
|
||||
<vn-td shrink>
|
||||
<span class="link"
|
||||
ng-click="$ctrl.showWorkerDescriptor($event, document.dms.workerFk)">
|
||||
{{::document.dms.worker.user.nickname | dashIfEmpty}}
|
||||
</span></vn-td>
|
||||
<vn-td>
|
||||
{{::document.dms.created | dateTime:'dd/MM/yyyy HH:mm'}}
|
||||
</vn-td>
|
||||
<vn-td number>
|
||||
<a target="_blank"
|
||||
href="api/dms/{{::document.dmsFk}}/downloadFile?access_token={{::$ctrl.accessToken}}">
|
||||
<vn-icon-button
|
||||
icon="cloud_download"
|
||||
title="{{'Download file' | translate}}">
|
||||
</vn-icon-button>
|
||||
</a>
|
||||
<vn-icon-button ui-sref="claim.card.dms.edit({dmsId: {{::document.dmsFk}}})"
|
||||
icon="edit"
|
||||
title="{{'Edit file' | translate}}">
|
||||
</vn-icon-button>
|
||||
<vn-icon-button
|
||||
icon="delete"
|
||||
ng-click="$ctrl.showDeleteConfirm($index)"
|
||||
title="{{'Remove file' | translate}}"
|
||||
tabindex="-1">
|
||||
</vn-icon-button>
|
||||
</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-vertical>
|
||||
<vn-pagination model="model"></vn-pagination>
|
||||
</vn-card>
|
||||
</vn-vertical>
|
||||
<vn-worker-descriptor-popover
|
||||
vn-id="workerDescriptor">
|
||||
</vn-worker-descriptor-popover>
|
||||
<a ui-sref="claim.card.dms.create"
|
||||
vn-tooltip="Upload file"
|
||||
vn-bind="+"
|
||||
fixed-bottom-right>
|
||||
<vn-float-button icon="add"></vn-float-button>
|
||||
</a>
|
||||
<vn-confirm
|
||||
vn-id="confirm"
|
||||
message="This file will be deleted"
|
||||
question="Are you sure you want to continue?"
|
||||
on-response="$ctrl.deleteDms(response)">
|
||||
</vn-confirm>
|
|
@ -0,0 +1,79 @@
|
|||
import ngModule from '../../module';
|
||||
import './style.scss';
|
||||
|
||||
class Controller {
|
||||
constructor($stateParams, $scope, $http, $translate, vnToken, vnApp) {
|
||||
this.$stateParams = $stateParams;
|
||||
this.$ = $scope;
|
||||
this.$http = $http;
|
||||
this.$translate = $translate;
|
||||
this.accessToken = vnToken.token;
|
||||
this.vnApp = vnApp;
|
||||
this.filter = {
|
||||
include: {
|
||||
relation: 'dms',
|
||||
scope: {
|
||||
fields: [
|
||||
'dmsTypeFk',
|
||||
'workerFk',
|
||||
'hardCopyNumber',
|
||||
'reference',
|
||||
'description',
|
||||
'hasFile',
|
||||
'file',
|
||||
'created',
|
||||
],
|
||||
include: [{
|
||||
relation: 'dmsType',
|
||||
scope: {
|
||||
fields: ['name']
|
||||
}
|
||||
},
|
||||
{
|
||||
relation: 'worker',
|
||||
scope: {
|
||||
fields: ['userFk'],
|
||||
include: {
|
||||
relation: 'user',
|
||||
scope: {
|
||||
fields: ['nickname']
|
||||
}
|
||||
},
|
||||
}
|
||||
}]
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
showWorkerDescriptor(event, workerFk) {
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
this.$.workerDescriptor.parent = event.target;
|
||||
this.$.workerDescriptor.workerFk = workerFk;
|
||||
this.$.workerDescriptor.show();
|
||||
}
|
||||
|
||||
showDeleteConfirm(index) {
|
||||
this.dmsIndex = index;
|
||||
this.$.confirm.show();
|
||||
}
|
||||
|
||||
deleteDms(response) {
|
||||
if (response === 'ACCEPT') {
|
||||
const dmsFk = this.claimDms[this.dmsIndex].dmsFk;
|
||||
const query = `/api/claimDms/${dmsFk}/removeFile`;
|
||||
this.$http.post(query).then(() => {
|
||||
this.$.model.remove(this.dmsIndex);
|
||||
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$stateParams', '$scope', '$http', '$translate', 'vnToken', 'vnApp'];
|
||||
|
||||
ngModule.component('vnClaimDmsIndex', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller,
|
||||
});
|
|
@ -0,0 +1,40 @@
|
|||
import './index';
|
||||
import crudModel from 'core/mocks/crud-model';
|
||||
|
||||
describe('Claim', () => {
|
||||
describe('Component vnClaimDmsIndex', () => {
|
||||
let $componentController;
|
||||
let $scope;
|
||||
let $httpBackend;
|
||||
let controller;
|
||||
|
||||
beforeEach(ngModule('claim'));
|
||||
|
||||
beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$httpBackend_) => {
|
||||
$componentController = _$componentController_;
|
||||
$httpBackend = _$httpBackend_;
|
||||
$scope = $rootScope.$new();
|
||||
controller = $componentController('vnClaimDmsIndex', {$: $scope});
|
||||
controller.$.model = crudModel;
|
||||
}));
|
||||
|
||||
describe('deleteDms()', () => {
|
||||
it('should make an HTTP Post query', () => {
|
||||
const dmsId = 1;
|
||||
const dmsIndex = 0;
|
||||
spyOn(controller.vnApp, 'showSuccess');
|
||||
spyOn(controller.$.model, 'remove');
|
||||
controller.claimDms = [{dmsFk: 1}];
|
||||
controller.dmsIndex = dmsIndex;
|
||||
|
||||
$httpBackend.when('POST', `/api/claimDms/${dmsId}/removeFile`).respond({});
|
||||
$httpBackend.expect('POST', `/api/claimDms/${dmsId}/removeFile`);
|
||||
controller.deleteDms('ACCEPT');
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.$.model.remove).toHaveBeenCalledWith(dmsIndex);
|
||||
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,6 @@
|
|||
vn-client-risk-index {
|
||||
.totalBox {
|
||||
display: table;
|
||||
float: right;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
FileDescription: Ticket id {{ticketId}} from client {{clientName}} id {{clientId}}
|
||||
ContentTypesInfo: Allowed file types {{allowedContentTypes}}
|
|
@ -0,0 +1,8 @@
|
|||
Upload file: Subir fichero
|
||||
Edit file: Editar fichero
|
||||
Upload: Subir
|
||||
File: Fichero
|
||||
FileDescription: Reclamación id {{claimId}} del cliente "{{clientName}}" id {{clientId}}
|
||||
Generate identifier for original file: Generar identificador para archivo original
|
||||
ContentTypesInfo: "Tipos de archivo permitidos: {{allowedContentTypes}}"
|
||||
Are you sure you want to continue?: ¿Seguro que quieres continuar?
|
|
@ -9,3 +9,6 @@ import './descriptor';
|
|||
import './development';
|
||||
import './search-panel';
|
||||
import './summary';
|
||||
import './dms/index';
|
||||
import './dms/create';
|
||||
import './dms/edit';
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
{"state": "claim.card.basicData", "icon": "settings"},
|
||||
{"state": "claim.card.detail", "icon": "icon-details"},
|
||||
{"state": "claim.card.development", "icon": "icon-traceability"},
|
||||
{"state": "claim.card.action", "icon": "icon-actions"}
|
||||
{"state": "claim.card.action", "icon": "icon-actions"},
|
||||
{"state": "claim.card.dms.index", "icon": "image"}
|
||||
],
|
||||
"keybindings": [
|
||||
{"key": "r", "state": "claim.index"}
|
||||
|
@ -74,6 +75,35 @@
|
|||
"claim": "$ctrl.claim"
|
||||
},
|
||||
"acl": ["salesAssistant"]
|
||||
}, {
|
||||
"url": "/dms",
|
||||
"state": "claim.card.dms",
|
||||
"abstract": true,
|
||||
"component": "ui-view"
|
||||
}, {
|
||||
"url" : "/index",
|
||||
"state": "claim.card.dms.index",
|
||||
"component": "vn-claim-dms-index",
|
||||
"description": "Pictures",
|
||||
"params": {
|
||||
"claim": "$ctrl.claim"
|
||||
}
|
||||
}, {
|
||||
"url" : "/create",
|
||||
"state": "claim.card.dms.create",
|
||||
"component": "vn-claim-dms-create",
|
||||
"description": "Upload file",
|
||||
"params": {
|
||||
"claim": "$ctrl.claim"
|
||||
}
|
||||
}, {
|
||||
"url": "/:dmsId/edit",
|
||||
"state": "claim.card.dms.edit",
|
||||
"component": "vn-claim-dms-edit",
|
||||
"description": "Edit file",
|
||||
"params": {
|
||||
"claim": "$ctrl.claim"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
|
||||
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethod('filter', {
|
||||
description: 'Find all instances of the model matched by filter from the data source.',
|
||||
accessType: 'READ',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'filter',
|
||||
type: 'Object',
|
||||
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
|
||||
http: {source: 'query'}
|
||||
}
|
||||
|
||||
],
|
||||
returns: {
|
||||
type: ['Object'],
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/filter`,
|
||||
verb: 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
Self.filter = async filter => {
|
||||
let conn = Self.dataSource.connector;
|
||||
|
||||
let stmts = [];
|
||||
let stmt;
|
||||
|
||||
filter.order = [
|
||||
'c.defaultAddressFk DESC',
|
||||
'a.isActive DESC',
|
||||
'a.nickname ASC'
|
||||
];
|
||||
|
||||
stmt = new ParameterizedSQL(
|
||||
`SELECT a.*
|
||||
FROM vn.address a
|
||||
LEFT JOIN vn.client c ON c.defaultAddressFk = a.id`
|
||||
);
|
||||
|
||||
stmt.merge(conn.makeSuffix(filter));
|
||||
let itemsIndex = stmts.push(stmt) - 1;
|
||||
|
||||
let sql = ParameterizedSQL.join(stmts, ';');
|
||||
let result = await conn.executeStmt(sql);
|
||||
return itemsIndex === 0 ? result : result[itemsIndex];
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('allowedContentTypes', {
|
||||
description: 'Returns a list of allowed contentTypes',
|
||||
accessType: 'READ',
|
||||
returns: {
|
||||
type: ['Object'],
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/allowedContentTypes`,
|
||||
verb: 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
Self.allowedContentTypes = async() => {
|
||||
const storageConnector = Self.app.dataSources.storage.connector;
|
||||
const allowedContentTypes = storageConnector.allowedContentTypes;
|
||||
const modelAllowedContentTypes = Self.definition.settings.allowedContentTypes;
|
||||
|
||||
return modelAllowedContentTypes || allowedContentTypes;
|
||||
};
|
||||
};
|
||||
|
|
@ -1,34 +1,39 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethod('threeLastActive', {
|
||||
Self.remoteMethod('lastActiveTickets', {
|
||||
description: 'Returns the last three tickets of a client that have the alertLevel at 0 and the shiped day is gt today',
|
||||
accessType: 'READ',
|
||||
accepts: [{
|
||||
arg: 'filter',
|
||||
type: 'object',
|
||||
arg: 'id',
|
||||
type: 'Number',
|
||||
required: true,
|
||||
description: 'client id, ticketFk'
|
||||
description: 'Client id',
|
||||
http: {source: 'path'}
|
||||
}, {
|
||||
arg: 'ticketId',
|
||||
type: 'Number',
|
||||
required: true
|
||||
}],
|
||||
returns: {
|
||||
type: [this.modelName],
|
||||
type: ['Object'],
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/threeLastActive`,
|
||||
path: `/:id/lastActiveTickets`,
|
||||
verb: 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
Self.threeLastActive = async params => {
|
||||
let query = `
|
||||
Self.lastActiveTickets = async(id, ticketId) => {
|
||||
const query = `
|
||||
SELECT t.id, t.shipped, a.name AS agencyName, w.name AS warehouseName
|
||||
FROM vn.ticket t
|
||||
JOIN vn.ticketState ts ON t.id = ts.ticketFk
|
||||
JOIN vn.agencyMode a ON t.agencyModeFk = a.id
|
||||
JOIN vn.warehouse w ON t.warehouseFk = w.id
|
||||
WHERE t.shipped > CURDATE() AND t.clientFk = ? AND ts.alertLevel = 0 AND t.id <> ?
|
||||
WHERE t.shipped >= CURDATE() AND t.clientFk = ? AND ts.alertLevel = 0 AND t.id <> ?
|
||||
ORDER BY t.shipped
|
||||
LIMIT 3`;
|
||||
let tickets = await Self.rawSql(query, [params.clientFk, params.ticketFk]);
|
||||
return tickets;
|
||||
|
||||
return Self.rawSql(query, [id, ticketId]);
|
||||
};
|
||||
};
|
|
@ -0,0 +1,12 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
|
||||
describe('client lastActiveTickets()', () => {
|
||||
it('should return the last three active tickets', async() => {
|
||||
const clientId = 109;
|
||||
const ticketId = 19;
|
||||
|
||||
let result = await app.models.Client.lastActiveTickets(clientId, ticketId);
|
||||
|
||||
expect(result.length).toEqual(3);
|
||||
});
|
||||
});
|
|
@ -5,7 +5,6 @@ let isMultiple = require('vn-loopback/util/hook').isMultiple;
|
|||
module.exports = Self => {
|
||||
// Methods
|
||||
require('../methods/address/createDefaultAddress')(Self);
|
||||
require('../methods/address/filter')(Self);
|
||||
|
||||
Self.validateAsync('isEqualizated', cannotHaveET, {
|
||||
message: 'Cannot check Equalization Tax in this NIF/CIF'
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
module.exports = Self => {
|
||||
require('../methods/client-dms/removeFile')(Self);
|
||||
require('../methods/client-dms/allowedContentTypes')(Self);
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
"model":"ClientLog",
|
||||
"relation": "client",
|
||||
"showField": "dmsFk"
|
||||
},
|
||||
},
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "clientDms"
|
||||
|
|
|
@ -21,6 +21,7 @@ module.exports = Self => {
|
|||
require('../methods/client/confirmTransaction')(Self);
|
||||
require('../methods/client/canBeInvoiced')(Self);
|
||||
require('../methods/client/uploadFile')(Self);
|
||||
require('../methods/client/lastActiveTickets')(Self);
|
||||
|
||||
// Validations
|
||||
|
||||
|
|
|
@ -61,17 +61,11 @@
|
|||
fields="['code', 'townFk']"
|
||||
field="$ctrl.address.postalCode"
|
||||
where="{townFk: town.selection.id}"
|
||||
selection="$ctrl.postcodeSelection"
|
||||
search-function="{code: $search}"
|
||||
fetch-function="{townFk: town.selection.id}"
|
||||
order="code, townFk"
|
||||
show-field="code"
|
||||
value-field="code"
|
||||
label="Postcode">
|
||||
<tpl-item>
|
||||
{{code}}, {{town.name}} - {{town.province.name}}
|
||||
({{town.province.country.country}})
|
||||
</tpl-item>
|
||||
</vn-autocomplete>
|
||||
<vn-icon-button vn-auto margin-medium-v
|
||||
icon="add_circle"
|
||||
|
|
|
@ -20,23 +20,6 @@ export default class Controller {
|
|||
this.$state.go('client.card.address.index');
|
||||
}
|
||||
|
||||
get postcodeSelection() {
|
||||
return this._postcodeSelection;
|
||||
}
|
||||
|
||||
set postcodeSelection(selection) {
|
||||
const hasValue = this._postcodeSelection;
|
||||
this._postcodeSelection = selection;
|
||||
|
||||
if (!selection || !hasValue) return;
|
||||
|
||||
const town = selection.town;
|
||||
const province = town.province;
|
||||
|
||||
this.address.city = town.name;
|
||||
this.address.provinceFk = province.id;
|
||||
}
|
||||
|
||||
onResponse(response) {
|
||||
this.address.postalCode = response.code;
|
||||
}
|
||||
|
|
|
@ -55,31 +55,5 @@ describe('Client', () => {
|
|||
expect(controller.$state.go).toHaveBeenCalledWith('client.card.address.index');
|
||||
});
|
||||
});
|
||||
|
||||
describe('postcodeSelection() setter', () => {
|
||||
it(`should set the town, province and contry properties`, () => {
|
||||
controller.address = {};
|
||||
controller._postcodeSelection = {townFk: 2};
|
||||
controller.postcodeSelection = {
|
||||
townFk: 1,
|
||||
code: 46001,
|
||||
town: {
|
||||
id: 1,
|
||||
name: 'New York',
|
||||
province: {
|
||||
id: 1,
|
||||
name: 'New york',
|
||||
country: {
|
||||
id: 2,
|
||||
name: 'USA'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
expect(controller.address.city).toEqual('New York');
|
||||
expect(controller.address.provinceFk).toEqual(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,72 +1,72 @@
|
|||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="/client/api/Addresses/filter"
|
||||
url="/api/Clients/{{$ctrl.$stateParams.id}}/addresses"
|
||||
filter="$ctrl.filter"
|
||||
limit="10"
|
||||
link="{clientFk: $ctrl.$stateParams.id}"
|
||||
data="$ctrl.addresses"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<div compact>
|
||||
<vn-card pad-large>
|
||||
<vn-horizontal
|
||||
<div
|
||||
ng-repeat="address in $ctrl.addresses"
|
||||
class="pad-medium-top"
|
||||
style="align-items: center;">
|
||||
<vn-one
|
||||
border-radius
|
||||
class="address">
|
||||
<a
|
||||
ui-sref="client.card.address.edit({addressId: {{::address.id}}})"
|
||||
class="pad-small border-solid"
|
||||
ng-class="{
|
||||
'item-hightlight': $ctrl.isDefaultAddress(address),
|
||||
'item-disabled': !address.isActive && !$ctrl.isDefaultAddress(address)
|
||||
}">
|
||||
<vn-horizontal style="align-items: center;">
|
||||
<vn-none pad-medium-h>
|
||||
<vn-icon-button
|
||||
icon="star"
|
||||
ng-if="$ctrl.isDefaultAddress(address)">
|
||||
</vn-icon-button>
|
||||
<vn-icon-button
|
||||
ng-if="!address.isActive"
|
||||
icon="star_border"
|
||||
vn-tooltip="Active first to set as default">
|
||||
</vn-icon-button>
|
||||
<vn-icon-button
|
||||
ng-if="address.isActive && !$ctrl.isDefaultAddress(address)"
|
||||
icon="star_border"
|
||||
vn-tooltip="Set as default"
|
||||
ng-click="$ctrl.setDefault(address)">
|
||||
</vn-icon-button>
|
||||
</vn-none>
|
||||
<vn-one border-solid-right>
|
||||
<vn-horizontal>
|
||||
<vn-one>
|
||||
<div><b>{{::address.nickname}}</b></div>
|
||||
<div name="street">{{::address.street}}</div>
|
||||
<div>{{::address.city}}, {{::address.province}}</div>
|
||||
<div>{{::address.phone}}, {{::address.mobile}}</div>
|
||||
</vn-one>
|
||||
<vn-one>
|
||||
<vn-check
|
||||
vn-one label="Is equalizated"
|
||||
field="address.isEqualizated"
|
||||
disabled="true">
|
||||
</vn-check>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
}"
|
||||
translate-attr="{title: 'Edit address'}"
|
||||
border-radius>
|
||||
<vn-none
|
||||
pad-small-right
|
||||
ng-click="$ctrl.onStarClick($event)">
|
||||
<vn-icon-button
|
||||
icon="star"
|
||||
ng-if="$ctrl.isDefaultAddress(address)">
|
||||
</vn-icon-button>
|
||||
<vn-icon-button
|
||||
ng-if="!address.isActive"
|
||||
icon="star_border"
|
||||
vn-tooltip="Active first to set as default">
|
||||
</vn-icon-button>
|
||||
<vn-icon-button
|
||||
ng-if="address.isActive && !$ctrl.isDefaultAddress(address)"
|
||||
icon="star_border"
|
||||
vn-tooltip="Set as default"
|
||||
ng-click="$ctrl.setDefault(address)">
|
||||
</vn-icon-button>
|
||||
</vn-none>
|
||||
<vn-one
|
||||
style="overflow: hidden; min-width: 14em;">
|
||||
<div class="ellipsize"><b>{{::address.nickname}}</b></div>
|
||||
<div class="ellipsize" name="street">{{::address.street}}</div>
|
||||
<div class="ellipsize">{{::address.city}}, {{::address.province.name}}</div>
|
||||
<div class="ellipsize">
|
||||
{{::address.phone}}<span ng-if="::address.mobile">, </span>
|
||||
{{::address.mobile}}
|
||||
</div>
|
||||
<vn-check
|
||||
vn-one label="Is equalizated"
|
||||
field="address.isEqualizated"
|
||||
disabled="true">
|
||||
</vn-check>
|
||||
</vn-one>
|
||||
<vn-vertical
|
||||
vn-one
|
||||
ng-if="address.observations.length"
|
||||
border-solid-left
|
||||
pad-medium-h
|
||||
style="height: 6em; overflow: auto;">
|
||||
<vn-one ng-repeat="observation in address.observations track by $index" ng-class="{'pad-small-top': $index}">
|
||||
<b>{{::observation.observationType.description}}:</b>
|
||||
<span>{{::observation.description}}</span>
|
||||
</vn-one>
|
||||
<vn-vertical vn-one pad-medium-h>
|
||||
<vn-one ng-repeat="observation in address.observations track by $index" ng-class="{'pad-small-top': $index}">
|
||||
<b margin-medium-right>{{::observation.observationType.description}}:</b>
|
||||
<span>{{::observation.description}}</span>
|
||||
</vn-one>
|
||||
</vn-vertical>
|
||||
<a pad-medium-h vn-tooltip="Edit address"
|
||||
vn-auto ui-sref="client.card.address.edit({addressId: {{::address.id}}})">
|
||||
<vn-icon-button icon="edit"></vn-icon-button>
|
||||
</a>
|
||||
</vn-horizontal>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
</vn-vertical>
|
||||
</a>
|
||||
</div>
|
||||
</vn-card>
|
||||
<vn-float-button
|
||||
vn-bind="+"
|
||||
|
|
|
@ -1,10 +1,47 @@
|
|||
import ngModule from '../../module';
|
||||
import './style.scss';
|
||||
|
||||
class Controller {
|
||||
constructor($http, $scope, $stateParams) {
|
||||
this.$http = $http;
|
||||
this.$scope = $scope;
|
||||
this.$stateParams = $stateParams;
|
||||
this.filter = {
|
||||
fields: [
|
||||
'id',
|
||||
'isDefaultAddress',
|
||||
'isActive',
|
||||
'nickname',
|
||||
'street',
|
||||
'city',
|
||||
'provinceFk',
|
||||
'phone',
|
||||
'mobile',
|
||||
'isEqualizated'
|
||||
],
|
||||
order: [
|
||||
'isDefaultAddress DESC',
|
||||
'isActive DESC',
|
||||
'nickname ASC'],
|
||||
include: [
|
||||
{
|
||||
relation: 'observations',
|
||||
scope: {
|
||||
include: 'observationType'
|
||||
}
|
||||
}, {
|
||||
relation: 'province',
|
||||
scope: {
|
||||
fields: ['id', 'name']
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
onStarClick(event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
setDefault(address) {
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
@import "variables";
|
||||
@import "./effects";
|
||||
|
||||
vn-client-address-index {
|
||||
.address {
|
||||
padding-bottom: $pad-medium;
|
||||
|
||||
&:last-child {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
& > a {
|
||||
@extend %clickable;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
color: inherit;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@
|
|||
value-field="id"
|
||||
where="{role: 'employee'}"
|
||||
label="Salesperson">
|
||||
<tpl-item>{{firstName}} {{name}}</tpl-item>
|
||||
<tpl-item>{{firstName}} {{lastName}}</tpl-item>
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
|
|
|
@ -46,7 +46,16 @@
|
|||
label="File"
|
||||
model="$ctrl.dms.files"
|
||||
on-change="$ctrl.onFileChange(files)"
|
||||
accept=".pdf, .png, .jpg, .jpeg, application/zip, application/rar, application/x-7z-compressed">
|
||||
accept="{{$ctrl.allowedContentTypes}}"
|
||||
required="true"
|
||||
multiple="true">
|
||||
<t-right-icons>
|
||||
<vn-icon vn-none
|
||||
color-secondary
|
||||
title="{{$ctrl.contentTypesInfo}}"
|
||||
icon="info">
|
||||
</vn-icon>
|
||||
</t-right-icons>
|
||||
</vn-input-file>
|
||||
</vn-horizontal>
|
||||
<vn-vertical>
|
||||
|
|
|
@ -22,8 +22,23 @@ class Controller {
|
|||
set client(value) {
|
||||
this._client = value;
|
||||
|
||||
if (value)
|
||||
if (value) {
|
||||
this.setDefaultParams();
|
||||
this.getAllowedContentTypes();
|
||||
}
|
||||
}
|
||||
|
||||
getAllowedContentTypes() {
|
||||
this.$http.get('/api/clientDms/allowedContentTypes').then(res => {
|
||||
const contentTypes = res.data.join(', ');
|
||||
this.allowedContentTypes = contentTypes;
|
||||
});
|
||||
}
|
||||
|
||||
get contentTypesInfo() {
|
||||
return this.$translate.instant('ContentTypesInfo', {
|
||||
allowedContentTypes: this.allowedContentTypes
|
||||
});
|
||||
}
|
||||
|
||||
setDefaultParams() {
|
||||
|
|
|
@ -18,8 +18,9 @@ describe('Client', () => {
|
|||
}));
|
||||
|
||||
describe('client() setter', () => {
|
||||
it('should set the client data and then call setDefaultParams()', () => {
|
||||
it('should set the client data and then call setDefaultParams() and getAllowedContentTypes()', () => {
|
||||
spyOn(controller, 'setDefaultParams');
|
||||
spyOn(controller, 'getAllowedContentTypes');
|
||||
controller.client = {
|
||||
id: 15,
|
||||
name: 'Bruce wayne'
|
||||
|
@ -27,6 +28,7 @@ describe('Client', () => {
|
|||
|
||||
expect(controller.client).toBeDefined();
|
||||
expect(controller.setDefaultParams).toHaveBeenCalledWith();
|
||||
expect(controller.getAllowedContentTypes).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -56,5 +58,18 @@ describe('Client', () => {
|
|||
expect(controller.dms.hasFileAttached).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getAllowedContentTypes()', () => {
|
||||
it('should make an HTTP GET request to get the allowed content types', () => {
|
||||
const expectedResponse = ['image/png', 'image/jpg'];
|
||||
$httpBackend.when('GET', `/api/clientDms/allowedContentTypes`).respond(expectedResponse);
|
||||
$httpBackend.expect('GET', `/api/clientDms/allowedContentTypes`);
|
||||
controller.getAllowedContentTypes();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.allowedContentTypes).toBeDefined();
|
||||
expect(controller.allowedContentTypes).toEqual('image/png, image/jpg');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
ClientFileDescription: "{{dmsTypeName}} from client {{clientName}} id {{clientId}}"
|
|
@ -1,5 +0,0 @@
|
|||
Upload file: Subir fichero
|
||||
Upload: Subir
|
||||
File: Fichero
|
||||
ClientFileDescription: "{{dmsTypeName}} del cliente {{clientName}} id {{clientId}}"
|
||||
Generate identifier for original file: Generar identificador para archivo original
|
|
@ -18,8 +18,23 @@ class Controller {
|
|||
set client(value) {
|
||||
this._client = value;
|
||||
|
||||
if (value)
|
||||
if (value) {
|
||||
this.setDefaultParams();
|
||||
this.getAllowedContentTypes();
|
||||
}
|
||||
}
|
||||
|
||||
getAllowedContentTypes() {
|
||||
this.$http.get('/api/clientDms/allowedContentTypes').then(res => {
|
||||
const contentTypes = res.data.join(', ');
|
||||
this.allowedContentTypes = contentTypes;
|
||||
});
|
||||
}
|
||||
|
||||
get contentTypesInfo() {
|
||||
return this.$translate.instant('ContentTypesInfo', {
|
||||
allowedContentTypes: this.allowedContentTypes
|
||||
});
|
||||
}
|
||||
|
||||
setDefaultParams() {
|
||||
|
|
|
@ -1,43 +1,52 @@
|
|||
import './index';
|
||||
|
||||
describe('Client', () => {
|
||||
describe('Component vnClientDmsCreate', () => {
|
||||
describe('Component vnClientDmsEdit', () => {
|
||||
let controller;
|
||||
let $scope;
|
||||
let $httpBackend;
|
||||
let $httpParamSerializer;
|
||||
let $state;
|
||||
|
||||
beforeEach(ngModule('client'));
|
||||
|
||||
beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_, _$httpParamSerializer_) => {
|
||||
beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_) => {
|
||||
$scope = $rootScope.$new();
|
||||
$httpBackend = _$httpBackend_;
|
||||
$httpParamSerializer = _$httpParamSerializer_;
|
||||
controller = $componentController('vnClientDmsCreate', {$scope});
|
||||
controller._client = {id: 101, name: 'Bruce wayne'};
|
||||
$state = {params: {dmsId: 1}};
|
||||
controller = $componentController('vnClientDmsEdit', {$scope, $state});
|
||||
controller._client = {id: 1};
|
||||
}));
|
||||
|
||||
describe('client() setter', () => {
|
||||
it('should set the client data and then call setDefaultParams()', () => {
|
||||
it('should set the client data and then call setDefaultParams() and getAllowedContentTypes()', () => {
|
||||
spyOn(controller, 'setDefaultParams');
|
||||
spyOn(controller, 'getAllowedContentTypes');
|
||||
controller._client = undefined;
|
||||
controller.client = {
|
||||
id: 15,
|
||||
name: 'Bruce wayne'
|
||||
id: 15
|
||||
};
|
||||
|
||||
expect(controller.client).toBeDefined();
|
||||
expect(controller.setDefaultParams).toHaveBeenCalledWith();
|
||||
expect(controller.client).toBeDefined();
|
||||
expect(controller.getAllowedContentTypes).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
|
||||
describe('setDefaultParams()', () => {
|
||||
it('should perform a GET query and define the dms property on controller', () => {
|
||||
const params = {filter: {
|
||||
where: {code: 'paymentsLaw'}
|
||||
}};
|
||||
let serializedParams = $httpParamSerializer(params);
|
||||
$httpBackend.when('GET', `/api/DmsTypes/findOne?${serializedParams}`).respond({id: 12, code: 'paymentsLaw'});
|
||||
$httpBackend.expect('GET', `/api/DmsTypes/findOne?${serializedParams}`);
|
||||
const dmsId = 1;
|
||||
const expectedResponse = {
|
||||
reference: 101,
|
||||
warehouseFk: 1,
|
||||
companyFk: 442,
|
||||
dmsTypeFk: 12,
|
||||
description: 'Test',
|
||||
hasFile: false,
|
||||
hasFileAttached: false
|
||||
};
|
||||
|
||||
$httpBackend.when('GET', `/api/Dms/${dmsId}`).respond(expectedResponse);
|
||||
$httpBackend.expect('GET', `/api/Dms/${dmsId}`).respond(expectedResponse);
|
||||
controller.setDefaultParams();
|
||||
$httpBackend.flush();
|
||||
|
||||
|
@ -50,11 +59,25 @@ describe('Client', () => {
|
|||
describe('onFileChange()', () => {
|
||||
it('should set dms hasFileAttached property to true if has any files', () => {
|
||||
const files = [{id: 1, name: 'MyFile'}];
|
||||
controller.dms = {hasFileAttached: false};
|
||||
controller.onFileChange(files);
|
||||
$scope.$apply();
|
||||
|
||||
expect(controller.dms.hasFileAttached).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getAllowedContentTypes()', () => {
|
||||
it('should make an HTTP GET request to get the allowed content types', () => {
|
||||
const expectedResponse = ['image/png', 'image/jpg'];
|
||||
$httpBackend.when('GET', `/api/clientDms/allowedContentTypes`).respond(expectedResponse);
|
||||
$httpBackend.expect('GET', `/api/clientDms/allowedContentTypes`);
|
||||
controller.getAllowedContentTypes();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.allowedContentTypes).toBeDefined();
|
||||
expect(controller.allowedContentTypes).toEqual('image/png, image/jpg');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
Edit file: Editar fichero
|
||||
File: Fichero
|
||||
Generate identifier for original file: Generar identificador para archivo original
|
|
@ -13,14 +13,14 @@
|
|||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th field="dmsFk" default-order="DESC" shrink>Id</vn-th>
|
||||
<vn-th field="dmsTypeFk" shrink>Type</vn-th>
|
||||
<vn-th field="hardCopyNumber" shrink number>Order</vn-th>
|
||||
<vn-th field="reference" shrink>Reference</vn-th>
|
||||
<vn-th shrink>Type</vn-th>
|
||||
<vn-th shrink number>Order</vn-th>
|
||||
<vn-th shrink>Reference</vn-th>
|
||||
<vn-th>Description</vn-th>
|
||||
<vn-th field="hasFile" shrink>Original</vn-th>
|
||||
<vn-th shrink>Original</vn-th>
|
||||
<vn-th>File</vn-th>
|
||||
<vn-th shrink>Employee</vn-th>
|
||||
<vn-th field="created">Created</vn-th>
|
||||
<vn-th>Created</vn-th>
|
||||
<vn-th number></vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
|
@ -54,7 +54,7 @@
|
|||
</vn-td>
|
||||
<vn-td>
|
||||
<a target="_blank"
|
||||
vn-tooltip="Download file"
|
||||
title="{{'Download file' | translate}}"
|
||||
href="api/dms/{{::document.dmsFk}}/downloadFile?access_token={{::$ctrl.accessToken}}">{{::document.dms.file}}
|
||||
</a>
|
||||
</vn-td>
|
||||
|
@ -68,22 +68,20 @@
|
|||
</vn-td>
|
||||
<vn-td number>
|
||||
<a target="_blank"
|
||||
vn-tooltip="Download file"
|
||||
href="api/dms/{{::document.dmsFk}}/downloadFile?access_token={{::$ctrl.accessToken}}">
|
||||
<vn-icon-button
|
||||
icon="cloud_download"
|
||||
title="{{'Download PDF' | translate}}">
|
||||
title="{{'Download file' | translate}}">
|
||||
</vn-icon-button>
|
||||
</a>
|
||||
<vn-icon-button ui-sref="client.card.dms.edit({dmsId: {{::document.dmsFk}}})"
|
||||
vn-tooltip="Edit file"
|
||||
icon="edit"
|
||||
title="{{'Edit file' | translate}}">
|
||||
</vn-icon-button>
|
||||
<vn-icon-button
|
||||
vn-tooltip="Remove file"
|
||||
icon="delete"
|
||||
ng-click="$ctrl.showDeleteConfirm($index)"
|
||||
title="{{'Remove file' | translate}}"
|
||||
tabindex="-1">
|
||||
</vn-icon-button>
|
||||
</vn-td>
|
||||
|
|
|
@ -62,7 +62,7 @@ class Controller {
|
|||
deleteDms(response) {
|
||||
if (response === 'ACCEPT') {
|
||||
const dmsFk = this.clientDms[this.dmsIndex].dmsFk;
|
||||
const query = `/api/ClientDms/${dmsFk}/removeFile`;
|
||||
const query = `/api/clientDms/${dmsFk}/removeFile`;
|
||||
this.$http.post(query).then(() => {
|
||||
this.$.model.remove(this.dmsIndex);
|
||||
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
import './index';
|
||||
import crudModel from 'core/mocks/crud-model';
|
||||
|
||||
describe('Client', () => {
|
||||
describe('Component vnClientDmsIndex', () => {
|
||||
let $componentController;
|
||||
let $scope;
|
||||
let $httpBackend;
|
||||
let controller;
|
||||
|
||||
beforeEach(ngModule('client'));
|
||||
|
||||
beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$httpBackend_) => {
|
||||
$componentController = _$componentController_;
|
||||
$httpBackend = _$httpBackend_;
|
||||
$scope = $rootScope.$new();
|
||||
controller = $componentController('vnClientDmsIndex', {$: $scope});
|
||||
controller.$.model = crudModel;
|
||||
}));
|
||||
|
||||
describe('deleteDms()', () => {
|
||||
it('should make an HTTP Post query', () => {
|
||||
const dmsId = 1;
|
||||
const dmsIndex = 0;
|
||||
spyOn(controller.vnApp, 'showSuccess');
|
||||
spyOn(controller.$.model, 'remove');
|
||||
controller.clientDms = [{dmsFk: 1}];
|
||||
controller.dmsIndex = dmsIndex;
|
||||
|
||||
$httpBackend.when('POST', `/api/clientDms/${dmsId}/removeFile`).respond({});
|
||||
$httpBackend.expect('POST', `/api/clientDms/${dmsId}/removeFile`);
|
||||
controller.deleteDms('ACCEPT');
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.$.model.remove).toHaveBeenCalledWith(dmsIndex);
|
||||
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,2 @@
|
|||
ClientFileDescription: "{{dmsTypeName}} from client {{clientName}} id {{clientId}}"
|
||||
ContentTypesInfo: Allowed file types {{allowedContentTypes}}
|
|
@ -0,0 +1,14 @@
|
|||
Upload file: Subir fichero
|
||||
Edit file: Editar fichero
|
||||
Upload: Subir
|
||||
File: Fichero
|
||||
ClientFileDescription: "{{dmsTypeName}} del cliente {{clientName}} id {{clientId}}"
|
||||
ContentTypesInfo: "Tipos de archivo permitidos: {{allowedContentTypes}}"
|
||||
Generate identifier for original file: Generar identificador para archivo original
|
||||
File management: Gestión documental
|
||||
Hard copy: Copia
|
||||
This file will be deleted: Este fichero va a ser borrado
|
||||
Are you sure?: Estas seguro?
|
||||
File deleted: Fichero eliminado
|
||||
Remove file: Eliminar fichero
|
||||
Download file: Descargar fichero
|
|
@ -58,16 +58,12 @@
|
|||
url="/api/Postcodes/location"
|
||||
fields="['code', 'townFk']"
|
||||
field="$ctrl.client.postcode"
|
||||
selection="$ctrl.postcodeSelection"
|
||||
search-function="{code: $search}"
|
||||
where="{townFk: town.selection.id}"
|
||||
order="code, townFk"
|
||||
show-field="code"
|
||||
value-field="code"
|
||||
label="Postcode">
|
||||
<tpl-item>
|
||||
{{code}}, {{town.name}} - {{town.province.name}}
|
||||
({{town.province.country.country}})
|
||||
</tpl-item>
|
||||
label="Postcode">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal pad-small-v>
|
||||
|
|
|
@ -56,24 +56,8 @@ export default class Controller {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
get postcodeSelection() {
|
||||
return this._postcodeSelection;
|
||||
}
|
||||
|
||||
set postcodeSelection(selection) {
|
||||
const hasValue = this._postcodeSelection;
|
||||
this._postcodeSelection = selection;
|
||||
|
||||
if (!selection || !hasValue) return;
|
||||
|
||||
const town = selection.town;
|
||||
const province = town.province;
|
||||
|
||||
this.address.city = town.name;
|
||||
this.address.provinceFk = province.id;
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$scope', '$http', 'vnApp', '$translate'];
|
||||
|
||||
ngModule.component('vnClientFiscalData', {
|
||||
|
|
|
@ -21,9 +21,9 @@ module.exports = Self => {
|
|||
});
|
||||
|
||||
Self.delete = async id => {
|
||||
const tx = await Self.beginTransaction({});
|
||||
const transaction = await Self.beginTransaction({});
|
||||
try {
|
||||
let options = {transaction: tx};
|
||||
let options = {transaction: transaction};
|
||||
|
||||
let invoiceOut = await Self.findById(id);
|
||||
let tickets = await Self.app.models.Ticket.find({where: {refFk: invoiceOut.ref}});
|
||||
|
@ -35,10 +35,10 @@ module.exports = Self => {
|
|||
|
||||
await Promise.all(promises);
|
||||
await invoiceOut.destroy(options);
|
||||
await tx.commit();
|
||||
await transaction.commit();
|
||||
return tickets;
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
await transaction.rollback();
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -38,11 +38,6 @@ module.exports = Self => {
|
|||
type: 'Integer',
|
||||
description: 'Type id',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
arg: 'hasVisible',
|
||||
type: 'Boolean',
|
||||
description: 'Whether the the item has visible or not',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
arg: 'isActive',
|
||||
type: 'Boolean',
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
panel="vn-item-search-panel"
|
||||
on-search="$ctrl.onSearch($params)"
|
||||
info="Search items by id, name or barcode"
|
||||
suggested-filter="{isActive: true}"
|
||||
vn-focus>
|
||||
</vn-searchbar>
|
||||
<vn-icon-menu
|
||||
|
|
|
@ -38,9 +38,6 @@ class Controller {
|
|||
}
|
||||
|
||||
onSearch(params) {
|
||||
if (params && params.hasVisible === undefined && params.isActive === undefined)
|
||||
Object.assign(params, {hasVisible: true, isActive: true});
|
||||
|
||||
if (params)
|
||||
this.$.model.applyFilter(null, params);
|
||||
else
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethod('getItemTypeAvailable', {
|
||||
description: 'Gets the item types available for an rder and item category ',
|
||||
accessType: 'READ',
|
||||
accepts: [{
|
||||
arg: 'id',
|
||||
type: 'number',
|
||||
required: true,
|
||||
description: 'order id',
|
||||
http: {source: 'path'}
|
||||
},
|
||||
{
|
||||
arg: 'itemCategoryId',
|
||||
type: 'number',
|
||||
required: true
|
||||
}],
|
||||
returns: {
|
||||
type: 'number',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/:id/getItemTypeAvailable`,
|
||||
verb: 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
Self.getItemTypeAvailable = async(orderId, itemCategoryId) => {
|
||||
let stmts = [];
|
||||
let stmt;
|
||||
|
||||
let order = await app.models.Order.findById(orderId);
|
||||
stmt = new ParameterizedSQL('call vn.available_calc(?, ?, ?)', [
|
||||
order.landed,
|
||||
order.addressFk,
|
||||
order.agencyModeFk
|
||||
]);
|
||||
stmts.push(stmt);
|
||||
stmt = new ParameterizedSQL(`SELECT it.id, it.name
|
||||
FROM tmp.availableCalc ac
|
||||
JOIN cache.available a ON a.calc_id = ac.calcFk
|
||||
JOIN item i ON i.id = a.item_id
|
||||
JOIN itemType it ON it.id = i.typeFk
|
||||
WHERE it.categoryFk = ?
|
||||
GROUP BY it.id`, [
|
||||
itemCategoryId
|
||||
]);
|
||||
let categoriesIndex = stmts.push(stmt) - 1;
|
||||
|
||||
let sql = ParameterizedSQL.join(stmts, ';');
|
||||
let result = await Self.rawStmt(sql);
|
||||
|
||||
return result[categoriesIndex];
|
||||
};
|
||||
};
|
|
@ -0,0 +1,19 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
|
||||
describe('order getItemTypeAvailable()', () => {
|
||||
it('should call the getItemTypeAvailable method with a valid order and item category', async() => {
|
||||
let orderId = 11;
|
||||
let itemCategoryId = 1;
|
||||
let result = await app.models.Order.getItemTypeAvailable(orderId, itemCategoryId);
|
||||
|
||||
expect(result.length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should call the getItemTypeAvailable method with the same order and different item category', async() => {
|
||||
let orderId = 11;
|
||||
let itemCategoryId = 4;//
|
||||
let result = await app.models.Order.getItemTypeAvailable(orderId, itemCategoryId);
|
||||
|
||||
expect(result.length).toEqual(0);
|
||||
});
|
||||
});
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue