Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into puppeteer
gitea/salix/puppeteer There was a failure building this commit
Details
gitea/salix/puppeteer There was a failure building this commit
Details
This commit is contained in:
commit
cb2f94cdaf
|
@ -34,5 +34,5 @@ COPY \
|
|||
|
||||
CMD ["pm2-runtime", "./back/process.yml"]
|
||||
|
||||
HEALTHCHECK --interval=1m --timeout=10s \
|
||||
HEALTHCHECK --interval=15s --timeout=10s \
|
||||
CMD curl -f http://localhost:3000/api/Applications/status || exit 1
|
||||
|
|
|
@ -6,20 +6,13 @@ pipeline {
|
|||
disableConcurrentBuilds()
|
||||
}
|
||||
environment {
|
||||
PROJECT_NAME = 'salix'
|
||||
REGISTRY = 'registry.verdnatura.es'
|
||||
PORT_MASTER_FRONT = '5002'
|
||||
PORT_MASTER_BACK = '3001'
|
||||
PORT_TEST_FRONT = '5001'
|
||||
PORT_TEST_BACK = '4001'
|
||||
TAG = "${env.BRANCH_NAME}"
|
||||
PROJECT_NAME = 'salix'
|
||||
STACK_NAME = "${env.PROJECT_NAME}-${env.BRANCH_NAME}"
|
||||
}
|
||||
stages {
|
||||
stage('Checkout') {
|
||||
steps {
|
||||
script {
|
||||
env.STACK_NAME = "${env.PROJECT_NAME}-${env.BRANCH_NAME}"
|
||||
|
||||
if (!env.GIT_COMMITTER_EMAIL) {
|
||||
env.COMMITTER_EMAIL = sh(
|
||||
script: 'git --no-pager show -s --format="%ae"',
|
||||
|
@ -29,16 +22,6 @@ pipeline {
|
|||
env.COMMITTER_EMAIL = env.GIT_COMMITTER_EMAIL;
|
||||
}
|
||||
|
||||
switch (env.BRANCH_NAME) {
|
||||
case 'master':
|
||||
env.PORT_FRONT = PORT_MASTER_FRONT
|
||||
env.PORT_BACK = PORT_MASTER_BACK
|
||||
break
|
||||
case 'test':
|
||||
env.PORT_FRONT = PORT_TEST_FRONT
|
||||
env.PORT_BACK = PORT_TEST_BACK
|
||||
break
|
||||
}
|
||||
switch (env.BRANCH_NAME) {
|
||||
case 'master':
|
||||
env.NODE_ENV = 'production'
|
||||
|
@ -48,6 +31,14 @@ pipeline {
|
|||
break
|
||||
}
|
||||
}
|
||||
|
||||
configFileProvider([
|
||||
configFile(fileId: "salix.groovy",
|
||||
variable: 'GROOVY_FILE')
|
||||
]) {
|
||||
load env.GROOVY_FILE
|
||||
}
|
||||
|
||||
sh 'printenv'
|
||||
}
|
||||
}
|
||||
|
@ -57,8 +48,8 @@ pipeline {
|
|||
}
|
||||
steps {
|
||||
nodejs('node-lts') {
|
||||
sh 'npm install --no-audit'
|
||||
sh 'gulp install'
|
||||
sh 'npm install --no-audit --prefer-offline'
|
||||
sh 'gulp install --ci'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,4 +2,5 @@ apps:
|
|||
- script: ./loopback/server/server.js
|
||||
name: salix-back
|
||||
instances: 1
|
||||
max_restarts: 5
|
||||
max_restarts: 3
|
||||
restart_delay: 15000
|
||||
|
|
|
@ -125,13 +125,13 @@ proc: BEGIN
|
|||
INSERT INTO tmp.ticketComponent
|
||||
SELECT tcb.warehouseFk,
|
||||
tcb.itemFk,
|
||||
cr.id,
|
||||
GREATEST(IFNULL(ROUND(tcb.base * cr.tax, 4), 0), tcc.minPrice - tcc.rate3)
|
||||
c.id,
|
||||
GREATEST(IFNULL(ROUND(tcb.base * c.tax, 4), 0), tcc.minPrice - tcc.rate3)
|
||||
FROM tmp.ticketComponentBase tcb
|
||||
JOIN componentRate cr
|
||||
JOIN component c
|
||||
JOIN tmp.ticketComponentCalculate tcc ON tcc.itemFk = tcb.itemFk AND tcc.warehouseFk = tcb.warehouseFk
|
||||
LEFT JOIN specialPrice sp ON sp.clientFk = vClientFk AND sp.itemFk = tcc.itemFk
|
||||
WHERE cr.id = vDiscountLastItemComponent AND cr.tax <> 0 AND tcc.minPrice < tcc.rate3 AND sp.value IS NULL;
|
||||
WHERE c.id = vDiscountLastItemComponent AND c.tax <> 0 AND tcc.minPrice < tcc.rate3 AND sp.value IS NULL;
|
||||
|
||||
INSERT INTO tmp.ticketComponent
|
||||
SELECT tcc.warehouseFk, tcc.itemFk, vSellByPacketComponent, tcc.rate2 - tcc.rate3
|
||||
|
@ -178,9 +178,9 @@ proc: BEGIN
|
|||
vSpecialPriceComponent,
|
||||
sp.value - SUM(tcc.cost) sumCost
|
||||
FROM tmp.ticketComponentCopy tcc
|
||||
JOIN componentRate cr ON cr.id = tcc.componentFk
|
||||
JOIN component c ON c.id = tcc.componentFk
|
||||
JOIN specialPrice sp ON sp.clientFk = vClientFK AND sp.itemFk = tcc.itemFk
|
||||
WHERE cr.classRate IS NULL
|
||||
WHERE c.classRate IS NULL
|
||||
GROUP BY tcc.itemFk, tcc.warehouseFk
|
||||
HAVING ABS(sumCost) > 0.001;
|
||||
|
||||
|
@ -188,10 +188,10 @@ proc: BEGIN
|
|||
CREATE TEMPORARY TABLE tmp.ticketComponentSum
|
||||
(INDEX (itemFk, warehouseFk))
|
||||
ENGINE = MEMORY
|
||||
SELECT SUM(cost) sumCost, tc.itemFk, tc.warehouseFk, cr.classRate
|
||||
SELECT SUM(cost) sumCost, tc.itemFk, tc.warehouseFk, c.classRate
|
||||
FROM tmp.ticketComponent tc
|
||||
JOIN componentRate cr ON cr.id = tc.componentFk
|
||||
GROUP BY tc.itemFk, tc.warehouseFk, cr.classRate;
|
||||
JOIN component c ON c.id = tc.componentFk
|
||||
GROUP BY tc.itemFk, tc.warehouseFk, c.classRate;
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.ticketComponentRate;
|
||||
CREATE TEMPORARY TABLE tmp.ticketComponentRate ENGINE = MEMORY
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('Thermograph', '*', '*', 'ALLOW', 'ROLE', 'buyer');
|
||||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('TravelThermograph', '*', '*', 'ALLOW', 'ROLE', 'buyer');
|
||||
|
File diff suppressed because one or more lines are too long
|
@ -53,20 +53,20 @@ INSERT INTO `hedera`.`tpvConfig`(`id`, `currency`, `terminal`, `transactionType`
|
|||
VALUES
|
||||
(1, 978, 1, 0, 2000, 9, 0);
|
||||
|
||||
INSERT INTO `account`.`user`(`id`,`name`,`password`,`role`,`active`,`email`,`lang`)
|
||||
INSERT INTO `account`.`user`(`id`,`name`,`nickname`, `password`,`role`,`active`,`email`,`lang`)
|
||||
VALUES
|
||||
(101, 'BruceWayne', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'BruceWayne@mydomain.com', 'es'),
|
||||
(102, 'PetterParker', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'PetterParker@mydomain.com', 'en'),
|
||||
(103, 'ClarkKent', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'ClarkKent@mydomain.com', 'fr'),
|
||||
(104, 'TonyStark', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'TonyStark@mydomain.com', 'es'),
|
||||
(105, 'MaxEisenhardt', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'MaxEisenhardt@mydomain.com', 'pt'),
|
||||
(106, 'DavidCharlesHaller', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'DavidCharlesHaller@mydomain.com', 'es'),
|
||||
(107, 'HankPym', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'HankPym@mydomain.com', 'es'),
|
||||
(108, 'CharlesXavier', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'CharlesXavier@mydomain.com', 'es'),
|
||||
(109, 'BruceBanner', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'BruceBanner@mydomain.com', 'es'),
|
||||
(110, 'JessicaJones', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'JessicaJones@mydomain.com', 'es'),
|
||||
(111, 'Missing', 'ac754a330530832ba1bf7687f577da91', 2, 0, NULL, 'es'),
|
||||
(112, 'Trash', 'ac754a330530832ba1bf7687f577da91', 2, 0, NULL, 'es');
|
||||
(101, 'BruceWayne', 'Bruce Wayne', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'BruceWayne@mydomain.com', 'es'),
|
||||
(102, 'PetterParker', 'Petter Parker', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'PetterParker@mydomain.com', 'en'),
|
||||
(103, 'ClarkKent', 'Clark Kent', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'ClarkKent@mydomain.com', 'fr'),
|
||||
(104, 'TonyStark', 'Tony Stark', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'TonyStark@mydomain.com', 'es'),
|
||||
(105, 'MaxEisenhardt', 'Max Eisenhardt', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'MaxEisenhardt@mydomain.com', 'pt'),
|
||||
(106, 'DavidCharlesHaller', 'David Charles Haller', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'DavidCharlesHaller@mydomain.com', 'es'),
|
||||
(107, 'HankPym', 'Hank Pym', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'HankPym@mydomain.com', 'es'),
|
||||
(108, 'CharlesXavier', 'Charles Xavier', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'CharlesXavier@mydomain.com', 'es'),
|
||||
(109, 'BruceBanner', 'Bruce Banner', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'BruceBanner@mydomain.com', 'es'),
|
||||
(110, 'JessicaJones', 'Jessica Jones', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'JessicaJones@mydomain.com', 'es'),
|
||||
(111, 'Missing', 'Missing', 'ac754a330530832ba1bf7687f577da91', 2, 0, NULL, 'es'),
|
||||
(112, 'Trash', 'Trash', 'ac754a330530832ba1bf7687f577da91', 2, 0, NULL, 'es');
|
||||
|
||||
INSERT INTO `vn`.`worker`(`id`, `code`, `firstName`, `lastName`, `userFk`,`bossFk`)
|
||||
VALUES
|
||||
|
@ -643,7 +643,8 @@ INSERT INTO `vn`.`itemType`(`id`, `code`, `name`, `categoryFk`, `life`,`workerFk
|
|||
(2, 'ITG', 'Anthurium', 1, 31, 5, 0),
|
||||
(3, 'WPN', 'Paniculata', 2, 31, 5, 0),
|
||||
(4, 'PRT', 'Delivery ports', 3, NULL, 5, 1),
|
||||
(5, 'CON', 'Container', 3, NULL, 5, 1);
|
||||
(5, 'CON', 'Container', 3, NULL, 5, 1),
|
||||
(6, 'ALS', 'Alstroemeria', 1, 31, 5, 0);
|
||||
|
||||
INSERT INTO `vn`.`ink`(`id`, `name`, `picture`, `showOrder`)
|
||||
VALUES
|
||||
|
@ -1549,7 +1550,7 @@ INSERT INTO `postgresql`.`profile`(`profile_id`, `person_id`, `profile_type_id`)
|
|||
FROM `postgresql`.`person` `p`;
|
||||
|
||||
INSERT INTO `postgresql`.`business`(`business_id`, `client_id`, `provider_id`, `date_start`, `date_end`, `workerBusiness`, `reasonEndFk`)
|
||||
SELECT p.profile_id, p.profile_id, 1000, CONCAT(YEAR(DATE_ADD(CURDATE(), INTERVAL -1 YEAR)), '-12-31'), CONCAT(YEAR(DATE_ADD(CURDATE(), INTERVAL +1 YEAR)), '-01-25'), CONCAT('E-46-',RPAD(CONCAT(p.profile_id,9),8,p.profile_id)), NULL
|
||||
SELECT p.profile_id, p.profile_id, 1000, CONCAT(YEAR(DATE_ADD(CURDATE(), INTERVAL -1 YEAR)), '-12-25'), CONCAT(YEAR(DATE_ADD(CURDATE(), INTERVAL +1 YEAR)), '-01-25'), CONCAT('E-46-',RPAD(CONCAT(p.profile_id,9),8,p.profile_id)), NULL
|
||||
FROM `postgresql`.`profile` `p`;
|
||||
|
||||
INSERT INTO `postgresql`.`business_labour`(`business_id`, `notes`, `department_id`, `professional_category_id`, `incentivo`, `calendar_labour_type_id`, `porhoras`, `labour_agreement_id`, `workcenter_id`)
|
||||
|
@ -1586,20 +1587,20 @@ INSERT INTO `postgresql`.`calendar_state` (`calendar_state_id`, `type`, `rgb`, `
|
|||
|
||||
INSERT INTO `postgresql`.`calendar_employee` (`business_id`, `calendar_state_id`, `date`)
|
||||
VALUES
|
||||
(106, 1, DATE_ADD(CURDATE(), INTERVAL 10 DAY)),
|
||||
(106, 1, DATE_ADD(CURDATE(), INTERVAL 11 DAY)),
|
||||
(106, 1, DATE_ADD(CURDATE(), INTERVAL 12 DAY)),
|
||||
(106, 1, DATE_ADD(CURDATE(), INTERVAL 20 DAY)),
|
||||
(106, 2, DATE_ADD(CURDATE(), INTERVAL -10 DAY)),
|
||||
(106, 1, DATE_ADD(CURDATE(), INTERVAL -12 DAY)),
|
||||
(106, 2, DATE_ADD(CURDATE(), INTERVAL -20 DAY)),
|
||||
(107, 1, DATE_ADD(CURDATE(), INTERVAL 15 DAY)),
|
||||
(107, 1, DATE_ADD(CURDATE(), INTERVAL 16 DAY)),
|
||||
(107, 1, DATE_ADD(CURDATE(), INTERVAL 20 DAY)),
|
||||
(107, 1, DATE_ADD(CURDATE(), INTERVAL 30 DAY)),
|
||||
(107, 2, DATE_ADD(CURDATE(), INTERVAL -10 DAY)),
|
||||
(107, 1, DATE_ADD(CURDATE(), INTERVAL -12 DAY)),
|
||||
(107, 2, DATE_ADD(CURDATE(), INTERVAL -20 DAY));
|
||||
(106, 1, IF(MONTH(CURDATE()) = 12 AND DAY(CURDATE()) > 10, DATE_ADD(CURDATE(), INTERVAL -10 DAY), DATE_ADD(CURDATE(), INTERVAL 10 DAY))),
|
||||
(106, 1, IF(MONTH(CURDATE()) = 12 AND DAY(CURDATE()) > 10, DATE_ADD(CURDATE(), INTERVAL -11 DAY), DATE_ADD(CURDATE(), INTERVAL 11 DAY))),
|
||||
(106, 1, IF(MONTH(CURDATE()) = 12 AND DAY(CURDATE()) > 10, DATE_ADD(CURDATE(), INTERVAL -12 DAY), DATE_ADD(CURDATE(), INTERVAL 12 DAY))),
|
||||
(106, 1, IF(MONTH(CURDATE()) = 12 AND DAY(CURDATE()) > 10, DATE_ADD(CURDATE(), INTERVAL -20 DAY), DATE_ADD(CURDATE(), INTERVAL 20 DAY))),
|
||||
(106, 2, IF(MONTH(CURDATE()) >= 1 AND DAY(CURDATE()) > 20, DATE_ADD(CURDATE(), INTERVAL -13 DAY), DATE_ADD(CURDATE(), INTERVAL 13 DAY))),
|
||||
(106, 1, IF(MONTH(CURDATE()) >= 1 AND DAY(CURDATE()) > 20, DATE_ADD(CURDATE(), INTERVAL -14 DAY), DATE_ADD(CURDATE(), INTERVAL 14 DAY))),
|
||||
(106, 2, IF(MONTH(CURDATE()) >= 1 AND DAY(CURDATE()) > 20, DATE_ADD(CURDATE(), INTERVAL -15 DAY), DATE_ADD(CURDATE(), INTERVAL 15 DAY))),
|
||||
(107, 1, IF(MONTH(CURDATE()) = 12 AND DAY(CURDATE()) > 10, DATE_ADD(CURDATE(), INTERVAL -10 DAY), DATE_ADD(CURDATE(), INTERVAL 10 DAY))),
|
||||
(107, 1, IF(MONTH(CURDATE()) = 12 AND DAY(CURDATE()) > 10, DATE_ADD(CURDATE(), INTERVAL -11 DAY), DATE_ADD(CURDATE(), INTERVAL 11 DAY))),
|
||||
(107, 1, IF(MONTH(CURDATE()) = 12 AND DAY(CURDATE()) > 10, DATE_ADD(CURDATE(), INTERVAL -12 DAY), DATE_ADD(CURDATE(), INTERVAL 12 DAY))),
|
||||
(107, 1, IF(MONTH(CURDATE()) = 12 AND DAY(CURDATE()) > 10, DATE_ADD(CURDATE(), INTERVAL -20 DAY), DATE_ADD(CURDATE(), INTERVAL 20 DAY))),
|
||||
(107, 2, IF(MONTH(CURDATE()) >= 1 AND DAY(CURDATE()) > 20, DATE_ADD(CURDATE(), INTERVAL -13 DAY), DATE_ADD(CURDATE(), INTERVAL 13 DAY))),
|
||||
(107, 1, IF(MONTH(CURDATE()) >= 1 AND DAY(CURDATE()) > 20, DATE_ADD(CURDATE(), INTERVAL -14 DAY), DATE_ADD(CURDATE(), INTERVAL 14 DAY))),
|
||||
(107, 2, IF(MONTH(CURDATE()) >= 1 AND DAY(CURDATE()) > 20, DATE_ADD(CURDATE(), INTERVAL -15 DAY), DATE_ADD(CURDATE(), INTERVAL 15 DAY)));
|
||||
|
||||
INSERT INTO `vn`.`smsConfig` (`id`, `uri`, `title`)
|
||||
VALUES
|
||||
|
@ -1901,7 +1902,8 @@ INSERT INTO `vn`.`dms`(`id`, `dmsTypeFk`, `file`, `contentType`, `workerFk`, `wa
|
|||
(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()),
|
||||
(4, 3, '3.txt', 'text/plain', 5, 1, 442, NULL, TRUE, 'Worker: 106', 'Worker:106 readme', CURDATE());
|
||||
(4, 3, '4.txt', 'text/plain', 5, 1, 442, NULL, TRUE, 'Worker: 106', 'Worker:106 readme', CURDATE()),
|
||||
(5, 5, '5.txt', 'text/plain', 5, 1, 442, NULL, TRUE, 'travel: 1', 'dmsForThermograph', CURDATE());
|
||||
|
||||
INSERT INTO `vn`.`ticketDms`(`ticketFk`, `dmsFk`)
|
||||
VALUES
|
||||
|
@ -1998,3 +2000,16 @@ INSERT INTO `vn`.`workerTimeControlParams` (`id`, `dayBreak`, `weekBreak`, `week
|
|||
(1, 43200, 129600, 734400, 43200, 50400);
|
||||
|
||||
INSERT IGNORE INTO `vn`.`greugeConfig` (`id`, `freightPickUpPrice`) VALUES ('1', '11');
|
||||
|
||||
INSERT INTO `vn`.`thermograph`(`id`, `model`)
|
||||
VALUES
|
||||
('TMM190901395', 'TEMPMATE'),
|
||||
('TL.BBA85422', 'TL30'),
|
||||
('TZ1905012010', 'DISPOSABLE');
|
||||
|
||||
INSERT INTO `vn`.`travelThermograph`(`thermographFk`, `created`, `warehouseFk`, `travelFk`, `temperature`, `result`, `dmsFk`)
|
||||
VALUES
|
||||
('TMM190901395', CURDATE(), 1, 1, 'WARM', 'Ok', NULL),
|
||||
('TL.BBA85422', DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 2, 2, 'COOL', 'Ok', NULL),
|
||||
('TL.BBA85422', CURDATE(), 2, 1, 'COOL', 'can not read the temperature', NULL),
|
||||
('TZ1905012010', CURDATE(), 1, 1, 'WARM', 'Temperature in range', 5);
|
File diff suppressed because it is too large
Load Diff
|
@ -1,28 +1,45 @@
|
|||
version: '3.5'
|
||||
version: '3.7'
|
||||
services:
|
||||
front:
|
||||
image: registry.verdnatura.es/salix-front:${TAG}
|
||||
restart: unless-stopped
|
||||
build:
|
||||
context: .
|
||||
dockerfile: front/Dockerfile
|
||||
ports:
|
||||
- ${PORT_FRONT}:80
|
||||
links:
|
||||
- back
|
||||
deploy:
|
||||
replicas: 3
|
||||
back:
|
||||
image: registry.verdnatura.es/salix-back:${TAG}
|
||||
restart: unless-stopped
|
||||
build: .
|
||||
ports:
|
||||
- ${PORT_BACK}:3000
|
||||
environment:
|
||||
- NODE_ENV
|
||||
volumes:
|
||||
- /mnt/storage/containers/salix:/etc/salix
|
||||
- /mnt/storage/pdfs:/var/lib/salix/pdfs
|
||||
- /mnt/storage/dms:/var/lib/salix/dms
|
||||
deploy:
|
||||
replicas: 6
|
||||
front:
|
||||
image: registry.verdnatura.es/salix-front:${BRANCH_NAME:?}
|
||||
build:
|
||||
context: .
|
||||
dockerfile: front/Dockerfile
|
||||
ports:
|
||||
- ${FRONT_PORT:?}:80
|
||||
deploy:
|
||||
replicas: 3
|
||||
back:
|
||||
image: registry.verdnatura.es/salix-back:${BRANCH_NAME:?}
|
||||
build: .
|
||||
ports:
|
||||
- ${BACK_PORT:?}:3000
|
||||
environment:
|
||||
- NODE_ENV
|
||||
configs:
|
||||
- source: datasources
|
||||
target: /etc/salix/datasources.json
|
||||
- source: datasources_local
|
||||
target: /etc/salix/datasources.local.json
|
||||
- source: print
|
||||
target: /etc/salix/print.json
|
||||
- source: print_local
|
||||
target: /etc/salix/print.local.json
|
||||
volumes:
|
||||
- /mnt/storage/pdfs:/var/lib/salix/pdfs
|
||||
- /mnt/storage/dms:/var/lib/salix/dms
|
||||
deploy:
|
||||
replicas: 6
|
||||
configs:
|
||||
datasources:
|
||||
external: true
|
||||
name: salix_datasources
|
||||
datasources_local:
|
||||
external: true
|
||||
name: salix-${BRANCH_NAME:?}_datasources
|
||||
print:
|
||||
external: true
|
||||
name: salix_print
|
||||
print_local:
|
||||
external: true
|
||||
name: salix-${BRANCH_NAME:?}_print
|
||||
|
|
|
@ -164,8 +164,8 @@ export default {
|
|||
},
|
||||
clientBalance: {
|
||||
balanceButton: 'vn-left-menu a[ui-sref="client.card.balance.index"]',
|
||||
companyAutocomplete: 'vn-client-balance-index vn-autocomplete[ng-model="$ctrl.companyFk"]',
|
||||
newPaymentButton: 'vn-float-button',
|
||||
companyAutocomplete: 'vn-client-balance-index vn-autocomplete[ng-model="$ctrl.companyId"]',
|
||||
newPaymentButton: `vn-float-button`,
|
||||
newPaymentBank: '.vn-dialog.shown vn-autocomplete[ng-model="$ctrl.receipt.bankFk"]',
|
||||
newPaymentAmountInput: '.vn-dialog.shown [ng-model="$ctrl.receipt.amountPaid"]',
|
||||
saveButton: '.vn-dialog.shown vn-button[label="Save"]',
|
||||
|
@ -603,8 +603,8 @@ export default {
|
|||
orderByAutocomplete: 'vn-autocomplete[label="Order by"]',
|
||||
plantRealmButton: 'vn-order-catalog > vn-side-menu vn-icon[icon="icon-plant"]',
|
||||
typeAutocomplete: 'vn-autocomplete[data="$ctrl.itemTypes"]',
|
||||
itemIdInput: 'vn-catalog-filter [ng-model="$ctrl.itemFk"]',
|
||||
itemTagValueInput: 'vn-catalog-filter [ng-model="$ctrl.value"]',
|
||||
itemIdInput: 'vn-catalog-filter vn-textfield[ng-model="$ctrl.itemId"]',
|
||||
itemTagValueInput: 'vn-catalog-filter vn-textfield[ng-model="$ctrl.value"]',
|
||||
openTagSearch: 'vn-catalog-filter > div > vn-vertical > vn-textfield[ng-model="$ctrl.value"] .append i',
|
||||
tagAutocomplete: 'vn-order-catalog-search-panel vn-autocomplete[ng-model="filter.tagFk"]',
|
||||
tagValueInput: 'vn-order-catalog-search-panel [ng-model="filter.value"]',
|
||||
|
|
|
@ -34,7 +34,7 @@ describe('Route basic Data path', () => {
|
|||
.waitToGetProperty(`${selectors.routeBasicData.workerAutoComplete} input`, 'value');
|
||||
|
||||
|
||||
expect(worker).toEqual('adminBossNick');
|
||||
expect(worker).toEqual('adminBoss - adminBossNick');
|
||||
});
|
||||
|
||||
it('should confirm the vehicle was edited', async() => {
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
No service for the specified zone: No hay servicio para la zona especificada
|
|
@ -11,11 +11,9 @@
|
|||
|
||||
.vn-droppable,
|
||||
[vn-droppable] {
|
||||
display: block;
|
||||
|
||||
&.dropping {
|
||||
background-color: $color-hover-cd;
|
||||
border-color: $color-bg-dark;
|
||||
border-color: $color-font-secondary;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
module.exports = {
|
||||
const crudModel = {
|
||||
_data: [1, 2, 3],
|
||||
data: [],
|
||||
filter: {},
|
||||
order: {},
|
||||
|
@ -31,7 +32,28 @@ module.exports = {
|
|||
}
|
||||
};
|
||||
},
|
||||
refresh: () => {},
|
||||
addFilter: () => {},
|
||||
applyFilter: () => {},
|
||||
refresh: () => {
|
||||
return {
|
||||
then: callback => {
|
||||
return callback({data: {id: 1234}});
|
||||
}
|
||||
};
|
||||
},
|
||||
addFilter: () => {
|
||||
return {
|
||||
then: callback => {
|
||||
return callback({data: {id: 1234}});
|
||||
}
|
||||
};
|
||||
},
|
||||
applyFilter: () => {
|
||||
crudModel.data = crudModel._data;
|
||||
return {
|
||||
then: callback => {
|
||||
return callback({data: {id: 1234}});
|
||||
}
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = crudModel;
|
||||
|
|
|
@ -7,7 +7,7 @@ vn-app {
|
|||
ui-view {
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
height: inherit;
|
||||
height: 100%;
|
||||
|
||||
&.ng-enter {
|
||||
animation-name: nothing, slideIn;
|
||||
|
|
|
@ -87,6 +87,8 @@ vn-layout {
|
|||
& > * {
|
||||
display: block;
|
||||
padding: $spacing-md;
|
||||
box-sizing: border-box;
|
||||
height: 100%
|
||||
}
|
||||
&.ng-enter {
|
||||
vn-side-menu {
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
transition: all 0.5s;
|
||||
padding: $spacing-sm;
|
||||
position: relative;
|
||||
opacity: 0.7;
|
||||
width: 28em;
|
||||
|
||||
.image {
|
||||
|
@ -20,6 +19,7 @@
|
|||
0 1px 5px 0 rgba(0,0,0,.12);
|
||||
background: no-repeat center center fixed;
|
||||
background-size: cover !important;
|
||||
border: 2px solid transparent;
|
||||
overflow: hidden;
|
||||
cursor: zoom-in;
|
||||
height: 100%;
|
||||
|
@ -34,7 +34,7 @@
|
|||
top: 1em
|
||||
}
|
||||
}
|
||||
.photo:hover {
|
||||
opacity: 1
|
||||
.photo:hover .image {
|
||||
border: 2px solid $color-primary
|
||||
}
|
||||
}
|
49
gulpfile.js
49
gulpfile.js
|
@ -101,6 +101,7 @@ async function backTestOnce() {
|
|||
gulp.src(backSpecFiles)
|
||||
.pipe(jasmine(options))
|
||||
.on('end', resolve)
|
||||
.on('error', reject)
|
||||
.resume();
|
||||
});
|
||||
|
||||
|
@ -110,27 +111,33 @@ backTestOnce.description = `Runs the backend tests once, can receive --junit arg
|
|||
|
||||
async function backTestDockerOnce() {
|
||||
let containerId = await docker();
|
||||
let err;
|
||||
|
||||
try {
|
||||
await backTestOnce();
|
||||
} catch (e) {
|
||||
throw e;
|
||||
} finally {
|
||||
if (argv['random'])
|
||||
await execP(`docker rm -fv ${containerId}`);
|
||||
err = e;
|
||||
}
|
||||
|
||||
if (argv['random'])
|
||||
await execP(`docker rm -fv ${containerId}`);
|
||||
if (err) throw err;
|
||||
}
|
||||
backTestDockerOnce.description = `Runs backend tests using in site container once`;
|
||||
|
||||
async function backTestDocker() {
|
||||
let containerId = await docker();
|
||||
let err;
|
||||
|
||||
try {
|
||||
await backTest();
|
||||
} catch (e) {
|
||||
throw e;
|
||||
} finally {
|
||||
if (argv['random'])
|
||||
await execP(`docker rm -fv ${containerId}`);
|
||||
err = e;
|
||||
}
|
||||
|
||||
if (argv['random'])
|
||||
await execP(`docker rm -fv ${containerId}`);
|
||||
if (err) throw err;
|
||||
}
|
||||
backTestDocker.description = `Runs backend tests restoring fixtures first`;
|
||||
|
||||
|
@ -283,14 +290,15 @@ function install() {
|
|||
const install = require('gulp-install');
|
||||
const print = require('gulp-print');
|
||||
|
||||
let npmArgs = [];
|
||||
if (argv.ci) npmArgs = ['--no-audit', '--prefer-offline'];
|
||||
|
||||
let packageFiles = ['front/package.json', 'print/package.json'];
|
||||
return gulp.src(packageFiles)
|
||||
.pipe(print(filepath => {
|
||||
return `Installing packages in ${filepath}`;
|
||||
}))
|
||||
.pipe(install({
|
||||
npm: ['--no-package-lock']
|
||||
}));
|
||||
.pipe(install({npm: npmArgs}));
|
||||
}
|
||||
install.description = `Installs node dependencies in all directories`;
|
||||
|
||||
|
@ -472,15 +480,22 @@ async function docker() {
|
|||
let result = await execP(`docker run --env RUN_CHOWN=${runChown} -d ${dockerArgs} salix-db`);
|
||||
containerId = result.stdout;
|
||||
|
||||
if (argv['random']) {
|
||||
let inspect = await execP(`docker inspect -f "{{json .NetworkSettings}}" ${containerId}`);
|
||||
let netSettings = JSON.parse(inspect.stdout);
|
||||
try {
|
||||
if (argv['random']) {
|
||||
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'];
|
||||
dbConf.host = netSettings.Gateway;
|
||||
dbConf.port = netSettings.Ports['3306/tcp'][0]['HostPort'];
|
||||
}
|
||||
|
||||
if (runChown) await dockerWait();
|
||||
} catch (err) {
|
||||
if (argv['random'])
|
||||
await execP(`docker rm -fv ${containerId}`);
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (runChown) await dockerWait();
|
||||
return containerId;
|
||||
}
|
||||
docker.description = `Builds the database image and runs a container`;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
"multipleStatements": true,
|
||||
"legacyUtcDateProcessing": false,
|
||||
"timezone": "local",
|
||||
"connectTimeout": 20000,
|
||||
"connectTimeout": 40000,
|
||||
"acquireTimeout": 20000
|
||||
},
|
||||
"storage": {
|
||||
|
|
|
@ -9,7 +9,7 @@ module.exports = Self => {
|
|||
description: 'The province id',
|
||||
required: true
|
||||
}, {
|
||||
arg: 'search',
|
||||
arg: 'postCode',
|
||||
type: 'String',
|
||||
description: 'The postcode'
|
||||
}, {
|
||||
|
|
|
@ -8,8 +8,14 @@ class Controller extends Section {
|
|||
}
|
||||
|
||||
onSubmit() {
|
||||
this.$.data = null;
|
||||
this.$http.get(`Zones/getEvents`, {params: this.$.params})
|
||||
.then(res => this.$.data = res.data);
|
||||
.then(res => {
|
||||
let data = res.data;
|
||||
this.$.data = data;
|
||||
if (!data.events.length)
|
||||
this.vnApp.showMessage(this.$t('No service for the specified zone'));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -160,12 +160,12 @@
|
|||
response="cancel"
|
||||
translate-attr="{value: 'Cancel'}">
|
||||
</input>
|
||||
<button
|
||||
<input
|
||||
type="button"
|
||||
ng-if="!$ctrl.isNew"
|
||||
response="delete"
|
||||
translate>
|
||||
Delete
|
||||
</button>
|
||||
translate-attr="{value: 'Delete'}">
|
||||
</input>
|
||||
<button response="accept">
|
||||
<span ng-if="$ctrl.isNew" translate>Add</span>
|
||||
<span ng-if="!$ctrl.isNew" translate>Save</span>
|
||||
|
|
|
@ -54,8 +54,8 @@
|
|||
</vn-td>
|
||||
<vn-td number>{{::saleClaimed.sale.price | currency: 'EUR':2}}</vn-td>
|
||||
<vn-td number>
|
||||
<span class="link"
|
||||
vn-tooltip="Edit discount"
|
||||
<span ng-class="{'link': $ctrl.isEditable}"
|
||||
title="{{$ctrl.isEditable ? 'Edit discount' : ''}}"
|
||||
ng-click="$ctrl.showEditPopover($event, saleClaimed)">
|
||||
{{saleClaimed.sale.discount}} %
|
||||
</span>
|
||||
|
|
|
@ -29,8 +29,10 @@ class Controller {
|
|||
set salesClaimed(value) {
|
||||
this._salesClaimed = value;
|
||||
|
||||
if (value)
|
||||
if (value) {
|
||||
this.calculateTotals();
|
||||
this.isClaimEditable();
|
||||
}
|
||||
}
|
||||
|
||||
get salesClaimed() {
|
||||
|
@ -119,13 +121,14 @@ class Controller {
|
|||
}
|
||||
|
||||
showEditPopover(event, saleClaimed) {
|
||||
this.saleClaimed = saleClaimed;
|
||||
if (this.isEditable) {
|
||||
if (!this.aclService.hasAny(['salesAssistant']))
|
||||
return this.vnApp.showError(this.$translate.instant('Insuficient permisos'));
|
||||
|
||||
if (!this.aclService.hasAny(['salesAssistant']))
|
||||
return this.vnApp.showError(this.$translate.instant('Insuficient permisos'));
|
||||
|
||||
this.$.editPopover.parent = event.target;
|
||||
this.$.editPopover.show();
|
||||
this.saleClaimed = saleClaimed;
|
||||
this.$.editPopover.parent = event.target;
|
||||
this.$.editPopover.show();
|
||||
}
|
||||
}
|
||||
|
||||
getSalespersonMana() {
|
||||
|
@ -134,6 +137,12 @@ class Controller {
|
|||
});
|
||||
}
|
||||
|
||||
isClaimEditable() {
|
||||
this.$http.get(`Tickets/${this.claim.ticketFk}/isEditable`).then(res => {
|
||||
this.isEditable = res.data;
|
||||
});
|
||||
}
|
||||
|
||||
updateDiscount() {
|
||||
const claimedSale = this.saleClaimed.sale;
|
||||
if (this.newDiscount != claimedSale.discount) {
|
||||
|
|
|
@ -17,13 +17,14 @@ describe('claim', () => {
|
|||
show: () => {}
|
||||
};
|
||||
$httpBackend = _$httpBackend_;
|
||||
$httpBackend.when('GET', 'Claims/ClaimBeginnings').respond({});
|
||||
$httpBackend.whenGET('Claims/ClaimBeginnings').respond({});
|
||||
$httpBackend.whenGET(`Tickets/1/isEditable`).respond(true);
|
||||
$state = _$state_;
|
||||
aclService = {hasAny: () => true};
|
||||
controller = $componentController('vnClaimDetail', {$state, aclService, $scope});
|
||||
controller.claim = {ticketFk: 1};
|
||||
controller.salesToClaim = [{saleFk: 1}, {saleFk: 2}];
|
||||
controller.salesClaimed = [{id: 1, sale: {}}];
|
||||
controller.claim = {ticketFk: 1};
|
||||
controller.$.model = crudModel;
|
||||
controller.$.addSales = {
|
||||
hide: () => {},
|
||||
|
@ -36,7 +37,6 @@ describe('claim', () => {
|
|||
|
||||
describe('openAddSalesDialog()', () => {
|
||||
it('should call getClaimableFromTicket and $.addSales.show', () => {
|
||||
controller.$ = {addSales: {show: () => {}}};
|
||||
spyOn(controller, 'getClaimableFromTicket');
|
||||
spyOn(controller.$.addSales, 'show');
|
||||
controller.openAddSalesDialog();
|
||||
|
@ -146,5 +146,14 @@ describe('claim', () => {
|
|||
expect(controller.$.descriptor.show).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
|
||||
describe('isClaimEditable()', () => {
|
||||
it('should check if the claim is editable', () => {
|
||||
controller.isClaimEditable();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.isEditable).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,31 +5,28 @@
|
|||
data="$ctrl.photos">
|
||||
</vn-crud-model>
|
||||
|
||||
<section class="drop-zone" vn-droppable="$ctrl.onDrop($event)">
|
||||
<section><vn-icon icon="add_circle"></vn-icon></section>
|
||||
<section translate>Drag & Drop files here...</section>
|
||||
</section>
|
||||
<vn-data-viewer
|
||||
model="model"
|
||||
class="vn-w-xl">
|
||||
<vn-horizontal class="photo-list">
|
||||
<section class="photo" ng-repeat="photo in $ctrl.photos">
|
||||
<section class="image vn-shadow" on-error-src
|
||||
ng-style="{'background': 'url(/api/dms/' + photo.dmsFk + '/downloadFile?access_token=' + $ctrl.accessToken + ')'}"
|
||||
zoom-image="/api/dms/{{::photo.dmsFk}}/downloadFile?access_token={{::$ctrl.accessToken}}">
|
||||
</section>
|
||||
<section class="actions">
|
||||
<vn-button
|
||||
class="round"
|
||||
ng-click="$ctrl.showDeleteConfirm($index)"
|
||||
title="{{'Remove file' | translate}}"
|
||||
tabindex="-1"
|
||||
icon="delete">
|
||||
</vn-button>
|
||||
</section>
|
||||
<vn-horizontal class="photo-list drop-zone" vn-droppable="$ctrl.onDrop($event)">
|
||||
<section class="empty-rows" ng-if="!$ctrl.photos.length">
|
||||
<section><vn-icon icon="image"></vn-icon></section>
|
||||
<section translate>Drag & Drop photos here...</section>
|
||||
</section>
|
||||
<section class="photo" ng-repeat="photo in $ctrl.photos">
|
||||
<section class="image vn-shadow" on-error-src
|
||||
ng-style="{'background': 'url(/api/dms/' + photo.dmsFk + '/downloadFile?access_token=' + $ctrl.accessToken + ')'}"
|
||||
zoom-image="/api/dms/{{::photo.dmsFk}}/downloadFile?access_token={{::$ctrl.accessToken}}">
|
||||
</section>
|
||||
</vn-horizontal>
|
||||
</vn-data-viewer>
|
||||
<section class="actions">
|
||||
<vn-button
|
||||
class="round"
|
||||
ng-click="$ctrl.showDeleteConfirm($index)"
|
||||
title="{{'Remove file' | translate}}"
|
||||
tabindex="-1"
|
||||
icon="delete">
|
||||
</vn-button>
|
||||
</section>
|
||||
</section>
|
||||
</vn-horizontal>
|
||||
|
||||
<vn-worker-descriptor-popover
|
||||
vn-id="workerDescriptor">
|
||||
</vn-worker-descriptor-popover>
|
||||
|
@ -38,4 +35,10 @@
|
|||
message="This file will be deleted"
|
||||
question="Are you sure you want to continue?"
|
||||
on-response="$ctrl.deleteDms($response)">
|
||||
</vn-confirm>
|
||||
</vn-confirm>
|
||||
<vn-float-button fixed-bottom-right
|
||||
icon="add"
|
||||
vn-tooltip="Select photo"
|
||||
vn-bind="+"
|
||||
ng-click="$ctrl.openUploadDialog()">
|
||||
</vn-float-button>
|
||||
|
|
|
@ -68,6 +68,19 @@ class Controller {
|
|||
});
|
||||
}
|
||||
|
||||
openUploadDialog() {
|
||||
const element = document.createElement('input');
|
||||
element.setAttribute('type', 'file');
|
||||
element.setAttribute('multiple', true);
|
||||
element.click();
|
||||
|
||||
element.addEventListener('change', () =>
|
||||
this.setDefaultParams().then(() => {
|
||||
this.dms.files = element.files;
|
||||
this.create();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
create() {
|
||||
const query = `claims/${this.claim.id}/uploadFile`;
|
||||
|
|
|
@ -2,13 +2,16 @@
|
|||
|
||||
vn-claim-dms-index {
|
||||
.drop-zone {
|
||||
border: 2px dashed $color-font-secondary;
|
||||
color: $color-font-secondary;
|
||||
box-sizing: border-box;
|
||||
padding: 2em $spacing-md;
|
||||
border-radius: 0.5em;
|
||||
text-align: center;
|
||||
font-size: 1.4em;
|
||||
min-height: 100%;
|
||||
|
||||
.empty-rows {
|
||||
padding: 5em $spacing-md;
|
||||
font-size: 1.4em
|
||||
}
|
||||
|
||||
vn-icon {
|
||||
font-size: 3em
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
FileDescription: Ticket id {{ticketId}} from client {{clientName}} id {{clientId}}
|
||||
ContentTypesInfo: Allowed file types {{allowedContentTypes}}
|
|
@ -1,4 +1,5 @@
|
|||
Are you sure you want to continue?: ¿Seguro que quieres continuar?
|
||||
Drag & Drop files here...: Arrastra y suelta archivos aquí...
|
||||
Drag & Drop photos here...: Arrastra y suelta fotos aquí...
|
||||
Photo deleted: Foto eliminada
|
||||
Photo uploaded!: Foto subida!
|
||||
Photo uploaded!: Foto subida!
|
||||
Select photo: Seleccionar foto
|
|
@ -1,12 +1,10 @@
|
|||
@import "./variables";
|
||||
|
||||
vn-claim-summary {
|
||||
.photo {
|
||||
height: 15.5em;
|
||||
section.photo {
|
||||
height: 15.5em
|
||||
}
|
||||
.photo .image {
|
||||
border: 2px solid $color-bg-dark;
|
||||
border-radius: 0.2em;
|
||||
.photo .image {
|
||||
border-radius: 0.2em
|
||||
}
|
||||
|
||||
}
|
|
@ -7,7 +7,7 @@ describe('Client activeWorkersWithRole', () => {
|
|||
|
||||
let isSalesPerson = await app.models.Account.hasRole(result[0].id, 'salesPerson');
|
||||
|
||||
expect(result.length).toEqual(13);
|
||||
expect(result.length).toEqual(14);
|
||||
expect(isSalesPerson).toBeTruthy();
|
||||
});
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ describe('Client listWorkers', () => {
|
|||
.then(result => {
|
||||
let amountOfEmployees = Object.keys(result).length;
|
||||
|
||||
expect(amountOfEmployees).toEqual(48);
|
||||
expect(amountOfEmployees).toEqual(49);
|
||||
done();
|
||||
})
|
||||
.catch(done.fail);
|
||||
|
|
|
@ -11,10 +11,15 @@ module.exports = Self => {
|
|||
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
arg: 'params',
|
||||
type: 'Object',
|
||||
description: 'clientFk',
|
||||
http: {source: 'query'}
|
||||
arg: 'clientId',
|
||||
type: 'Number',
|
||||
description: 'The client id',
|
||||
required: true,
|
||||
}, {
|
||||
arg: 'companyId',
|
||||
type: 'Number',
|
||||
description: 'The company id',
|
||||
required: true,
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
|
@ -27,7 +32,7 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
Self.filter = async(filter, params) => {
|
||||
Self.filter = async(filter, clientId, companyId) => {
|
||||
let stmt = new ParameterizedSQL(
|
||||
`SELECT * FROM (
|
||||
SELECT
|
||||
|
@ -72,10 +77,10 @@ module.exports = Self => {
|
|||
ORDER BY payed DESC, created DESC
|
||||
) t
|
||||
ORDER BY payed DESC, created DESC`, [
|
||||
params.clientFk,
|
||||
params.companyFk,
|
||||
params.clientFk,
|
||||
params.companyFk,
|
||||
clientId,
|
||||
companyId,
|
||||
clientId,
|
||||
companyId,
|
||||
]
|
||||
);
|
||||
|
||||
|
|
|
@ -2,12 +2,10 @@ const app = require('vn-loopback/server/server');
|
|||
|
||||
describe('receipt filter()', () => {
|
||||
it('should return the receipts', async() => {
|
||||
let filter = {limit: 20};
|
||||
let params = {
|
||||
clientFk: 101,
|
||||
companyFk: 442
|
||||
};
|
||||
let result = await app.models.Receipt.filter(filter, params);
|
||||
const filter = {limit: 20};
|
||||
const clientId = 101;
|
||||
const companyId = 442;
|
||||
let result = await app.models.Receipt.filter(filter, clientId, companyId);
|
||||
|
||||
expect(result.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
|
|
@ -2,10 +2,12 @@ import ngModule from '../../module';
|
|||
import './style.scss';
|
||||
|
||||
class Controller {
|
||||
constructor($http, $scope, $stateParams) {
|
||||
constructor($http, $scope, $stateParams, $translate, vnApp) {
|
||||
this.$http = $http;
|
||||
this.$scope = $scope;
|
||||
this.$stateParams = $stateParams;
|
||||
this.$translate = $translate;
|
||||
this.vnApp = vnApp;
|
||||
this.filter = {
|
||||
fields: [
|
||||
'id',
|
||||
|
@ -51,6 +53,7 @@ class Controller {
|
|||
if (res.data) {
|
||||
this.client.defaultAddressFk = res.data.defaultAddressFk;
|
||||
this.sortAddresses();
|
||||
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -69,7 +72,7 @@ class Controller {
|
|||
});
|
||||
}
|
||||
}
|
||||
Controller.$inject = ['$http', '$scope', '$stateParams'];
|
||||
Controller.$inject = ['$http', '$scope', '$stateParams', '$translate', 'vnApp'];
|
||||
|
||||
ngModule.component('vnClientAddressIndex', {
|
||||
template: require('./index.html'),
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="receipts/filter"
|
||||
params="$ctrl.params"
|
||||
limit="20"
|
||||
data="$ctrl.balances"
|
||||
auto-load="true">
|
||||
data="$ctrl.balances">
|
||||
</vn-crud-model>
|
||||
<vn-crud-model
|
||||
vn-id="riskModel"
|
||||
|
@ -21,8 +19,7 @@
|
|||
<vn-autocomplete
|
||||
vn-id="company"
|
||||
class="dense"
|
||||
ng-model="$ctrl.companyFk"
|
||||
on-change="$ctrl.setOrder(value)"
|
||||
ng-model="$ctrl.companyId"
|
||||
url="Companies"
|
||||
show-field="code"
|
||||
value-field="id"
|
||||
|
|
|
@ -16,75 +16,53 @@ class Controller {
|
|||
scope: {
|
||||
fields: ['code'],
|
||||
},
|
||||
},
|
||||
where: {
|
||||
clientFk: $stateParams.id,
|
||||
companyFk: this.companyFk
|
||||
},
|
||||
};
|
||||
this.params = {
|
||||
params: {
|
||||
clientFk: this.$stateParams.id,
|
||||
companyFk: this.companyFk,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
get companyFk() {
|
||||
if (!this._companyFk)
|
||||
return this.vnConfig.companyFk;
|
||||
|
||||
return this._companyFk;
|
||||
}
|
||||
|
||||
set companyFk(id) {
|
||||
this._companyFk = id;
|
||||
}
|
||||
setOrder(value) {
|
||||
this.params.params.companyFk = value;
|
||||
this.filter.where.companyFk = value;
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.$.model.refresh();
|
||||
this.$.riskModel.refresh();
|
||||
}
|
||||
|
||||
set balances(value) {
|
||||
this._balances = value;
|
||||
|
||||
if (!value) return;
|
||||
const params = {filter: this.filter};
|
||||
this.$http.get(`ClientRisks`, {params}).then(response => {
|
||||
if (response.data) {
|
||||
this.clientRisks = response.data;
|
||||
|
||||
this.getBalances();
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
get balances() {
|
||||
return this._balances;
|
||||
get companyId() {
|
||||
if (!this._companyId)
|
||||
this.companyId = this.vnConfig.companyFk;
|
||||
|
||||
return this._companyId;
|
||||
}
|
||||
|
||||
set companyId(value) {
|
||||
this._companyId = value;
|
||||
|
||||
if (value) this.getData();
|
||||
}
|
||||
|
||||
getData() {
|
||||
return this.$.model.applyFilter(null, {
|
||||
clientId: this.$stateParams.id,
|
||||
companyId: this.companyId
|
||||
}).then(() => this.$.riskModel.applyFilter({
|
||||
where: {
|
||||
clientFk: this.$stateParams.id,
|
||||
companyFk: this.companyId
|
||||
}
|
||||
})).then(() => this.getBalances());
|
||||
}
|
||||
|
||||
|
||||
getCurrentBalance() {
|
||||
const selectedCompany = this.$.company.selection;
|
||||
const currentBalance = this.clientRisks.find(balance => {
|
||||
return balance.companyFk === selectedCompany.id;
|
||||
const clientRisks = this.$.riskModel.data;
|
||||
const selectedCompany = this.companyId;
|
||||
const currentBalance = clientRisks.find(balance => {
|
||||
return balance.companyFk === selectedCompany;
|
||||
});
|
||||
|
||||
return currentBalance.amount;
|
||||
}
|
||||
|
||||
getBalances() {
|
||||
this.balances.forEach((balance, index) => {
|
||||
const balances = this.$.model.data;
|
||||
balances.forEach((balance, index) => {
|
||||
if (index === 0)
|
||||
balance.balance = this.getCurrentBalance();
|
||||
if (index > 0) {
|
||||
let previousBalance = this.balances[index - 1];
|
||||
|
||||
let previousBalance = balances[index - 1];
|
||||
balance.balance = previousBalance.balance - (previousBalance.debit - previousBalance.credit);
|
||||
}
|
||||
});
|
||||
|
@ -92,10 +70,8 @@ class Controller {
|
|||
|
||||
|
||||
openCreateDialog() {
|
||||
this.$.balanceCreateDialog.companyFk = this.companyFk;
|
||||
this.$.balanceCreateDialog.onResponse = () => {
|
||||
this.refresh();
|
||||
};
|
||||
this.$.balanceCreateDialog.companyFk = this.companyId;
|
||||
this.$.balanceCreateDialog.onResponse = () => this.getData();
|
||||
this.$.balanceCreateDialog.show();
|
||||
}
|
||||
|
||||
|
|
|
@ -3,41 +3,98 @@ import './index';
|
|||
describe('Client', () => {
|
||||
describe('Component vnClientBalanceIndex', () => {
|
||||
let $componentController;
|
||||
let $scope;
|
||||
let $httpBackend;
|
||||
let $httpParamSerializer;
|
||||
let controller;
|
||||
|
||||
beforeEach(ngModule('client'));
|
||||
|
||||
beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$httpBackend_, _$httpParamSerializer_) => {
|
||||
beforeEach(angular.mock.inject((_$componentController_, $rootScope) => {
|
||||
$componentController = _$componentController_;
|
||||
$httpBackend = _$httpBackend_;
|
||||
$httpParamSerializer = _$httpParamSerializer_;
|
||||
$scope = $rootScope.$new();
|
||||
let $scope = $rootScope.$new();
|
||||
controller = $componentController('vnClientBalanceIndex', {$scope});
|
||||
controller.$.model = {applyFilter: () => {}};
|
||||
controller.$.riskModel = {
|
||||
applyFilter: () => {},
|
||||
data:
|
||||
[{
|
||||
clientFk: 101,
|
||||
companyFk: 442,
|
||||
amount: 713.24,
|
||||
company: {
|
||||
id: 442,
|
||||
code: 'VNL'
|
||||
}
|
||||
}]
|
||||
};
|
||||
}));
|
||||
|
||||
describe('balances() setter', () => {
|
||||
it('should calculate the balance for each line from the oldest date to the newest', () => {
|
||||
controller.getCurrentBalance = jasmine.createSpy(controller, 'getCurrentBalance').and.returnValue(1000);
|
||||
let balances = [
|
||||
{credit: -100, debit: 0},
|
||||
{credit: 0, debit: 300},
|
||||
{credit: 100, debit: 0},
|
||||
{credit: 0, debit: -300}
|
||||
];
|
||||
const params = {filter: controller.filter};
|
||||
let serializedParams = $httpParamSerializer(params);
|
||||
$httpBackend.when('GET', `ClientRisks?${serializedParams}`).respond(balances);
|
||||
$httpBackend.expect('GET', `ClientRisks?${serializedParams}`);
|
||||
controller.balances = balances;
|
||||
$httpBackend.flush();
|
||||
describe('getData()', () => {
|
||||
it('should apply the filters on he models and get the client balance', () => {
|
||||
controller._companyId = 442;
|
||||
controller.$stateParams.id = 101;
|
||||
spyOn(controller, 'getBalances');
|
||||
spyOn(controller.$.model, 'applyFilter').and.returnValue(Promise.resolve());
|
||||
spyOn(controller.$.riskModel, 'applyFilter').and.returnValue(Promise.resolve());
|
||||
|
||||
expect(controller.balances[0].balance).toEqual(1000);
|
||||
expect(controller.balances[1].balance).toEqual(900);
|
||||
expect(controller.balances[2].balance).toEqual(600);
|
||||
expect(controller.balances[3].balance).toEqual(700);
|
||||
controller.getData().then(() => {
|
||||
expect(controller.$.model.applyFilter).toHaveBeenCalledWith(null, {'clientId': 101, 'companyId': 442});
|
||||
expect(controller.$.riskModel.applyFilter).toHaveBeenCalledWith({'where': {'clientFk': 101, 'companyFk': 442}});
|
||||
expect(controller.getBalances).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('company setter/getter', () => {
|
||||
it('should return the company', () => {
|
||||
controller.companyId = null;
|
||||
|
||||
expect(controller._companyId).toEqual(jasmine.any(Object));
|
||||
});
|
||||
|
||||
it('should return the company and then call getData()', () => {
|
||||
spyOn(controller, 'getData');
|
||||
controller.companyId = 442;
|
||||
|
||||
expect(controller._companyId).toEqual(442);
|
||||
expect(controller.getData).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCurrentBalance()', () => {
|
||||
it('should return the client balance amount', () => {
|
||||
controller._companyId = 442;
|
||||
let result = controller.getCurrentBalance();
|
||||
|
||||
expect(result).toEqual(713.24);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getBalances()', () => {
|
||||
it('should return the total client balance amount', () => {
|
||||
spyOn(controller, 'getCurrentBalance').and.callThrough();
|
||||
controller._companyId = 442;
|
||||
controller.$.model = {data:
|
||||
[{
|
||||
id: 1,
|
||||
debit: 1000,
|
||||
credit: null
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
debit: null,
|
||||
credit: 500
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
debit: null,
|
||||
credit: 300
|
||||
}
|
||||
]};
|
||||
controller.getBalances();
|
||||
const expectedBalances = controller.$.model.data;
|
||||
|
||||
expect(expectedBalances[0].balance).toEqual(713.24);
|
||||
expect(expectedBalances[1].balance).toEqual(-286.76);
|
||||
expect(expectedBalances[2].balance).toEqual(213.24);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -29,13 +29,24 @@ describe('Component VnClientWebAccess', () => {
|
|||
});
|
||||
|
||||
describe('isCustomer()', () => {
|
||||
it(`should perform a query if client is defined with an ID`, () => {
|
||||
it('should return true if the password can be modified', () => {
|
||||
controller.client = {id: '1234'};
|
||||
controller.isCustomer();
|
||||
|
||||
$httpBackend.when('GET', `Clients/${controller.client.id}/hasCustomerRole`).respond('ok');
|
||||
$httpBackend.expectGET(`Clients/${controller.client.id}/hasCustomerRole`);
|
||||
$httpBackend.expectGET(`Clients/${controller.client.id}/hasCustomerRole`).respond({isCustomer: true});
|
||||
controller.isCustomer();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.canChangePassword).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should return a false if the password can't be modified`, () => {
|
||||
controller.client = {id: '1234'};
|
||||
|
||||
$httpBackend.expectGET(`Clients/${controller.client.id}/hasCustomerRole`).respond({isCustomer: false});
|
||||
controller.isCustomer();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.canChangePassword).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
|
||||
describe('invoiceOut book()', () => {
|
||||
const invoiceOutId = 1;
|
||||
const invoiceOutId = 5;
|
||||
let bookedDate;
|
||||
let OriginalInvoiceOut;
|
||||
let updatedInvoiceOut;
|
||||
|
|
|
@ -53,7 +53,7 @@ class Controller {
|
|||
}
|
||||
|
||||
showInvoiceOutPdf() {
|
||||
let url = `InvoiceOuts/${this.invoiceOut.id}/download?access_token=${this.accessToken}`;
|
||||
let url = `api/InvoiceOuts/${this.invoiceOut.id}/download?access_token=${this.accessToken}`;
|
||||
window.open(url, '_blank');
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ export default class Controller {
|
|||
}
|
||||
|
||||
openPdf(id, event) {
|
||||
let url = `InvoiceOuts/${id}/download?access_token=${this.accessToken}`;
|
||||
let url = `api/InvoiceOuts/${id}/download?access_token=${this.accessToken}`;
|
||||
window.open(url, '_blank');
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
|
|
|
@ -20,7 +20,7 @@ class Controller {
|
|||
];
|
||||
this.orderFields = [].concat(this.defaultOrderFields);
|
||||
this._orderWay = this.orderWays[0].way;
|
||||
this._orderField = this.orderFields[0].field;
|
||||
this.orderField = this.orderFields[0].field;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -76,15 +76,13 @@ class Controller {
|
|||
if (value) this.applyOrder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get order fields
|
||||
*/
|
||||
get orderField() {
|
||||
return this._orderField;
|
||||
get orderSelection() {
|
||||
return this._orderSelection;
|
||||
}
|
||||
|
||||
set orderField(value) {
|
||||
this._orderField = value;
|
||||
set orderSelection(value) {
|
||||
this._orderSelection = value;
|
||||
|
||||
if (value) this.applyOrder();
|
||||
}
|
||||
|
||||
|
@ -94,10 +92,11 @@ class Controller {
|
|||
* @return {Object} - Order param
|
||||
*/
|
||||
getOrderBy() {
|
||||
const isTag = !!(this.orderSelection && this.orderSelection.isTag);
|
||||
return {
|
||||
field: this.orderField,
|
||||
way: this.orderWay,
|
||||
isTag: !!(this.orderSelection && this.orderSelection.isTag)
|
||||
isTag: isTag
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -6,27 +6,26 @@
|
|||
</vn-crud-model>
|
||||
<div>
|
||||
<vn-horizontal class="item-category">
|
||||
<vn-autocomplete vn-id="category"
|
||||
data="categories"
|
||||
ng-model="$ctrl.categoryId"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
label="Category">
|
||||
</vn-autocomplete>
|
||||
<vn-one ng-repeat="category in categories">
|
||||
<vn-icon
|
||||
ng-class="{'active': $ctrl.category.id == category.id}"
|
||||
ng-class="{'active': $ctrl.categoryId == category.id}"
|
||||
icon="{{::category.icon}}"
|
||||
vn-tooltip="{{::category.name}}"
|
||||
ng-click="$ctrl.category = {
|
||||
id: category.id,
|
||||
value: category.name
|
||||
}">
|
||||
ng-click="$ctrl.categoryId = category.id">
|
||||
</vn-icon>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
<vn-vertical class="input">
|
||||
<vn-autocomplete
|
||||
vn-id="type"
|
||||
<vn-autocomplete vn-id="type"
|
||||
data="$ctrl.itemTypes"
|
||||
on-change="$ctrl.type = {
|
||||
id: value,
|
||||
value: type.selection.name
|
||||
}"
|
||||
ng-model="$ctrl.type.id"
|
||||
ng-model="$ctrl.typeId"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
label="Type"
|
||||
|
@ -38,9 +37,6 @@
|
|||
{{categoryName}}
|
||||
</div>
|
||||
</tpl-item>
|
||||
<prepend>
|
||||
<vn-icon icon="search"></vn-icon>
|
||||
</prepend>
|
||||
</vn-autocomplete>
|
||||
</vn-vertical>
|
||||
<vn-vertical class="input vn-pt-md">
|
||||
|
@ -73,7 +69,7 @@
|
|||
<vn-textfield
|
||||
ng-keyUp="$ctrl.onSearchById($event)"
|
||||
label="Item id"
|
||||
ng-model="$ctrl.itemFk">
|
||||
ng-model="$ctrl.itemId">
|
||||
<prepend>
|
||||
<vn-icon icon="icon-item"></vn-icon>
|
||||
</prepend>
|
||||
|
@ -106,20 +102,20 @@
|
|||
</vn-popover>
|
||||
<div class="chips">
|
||||
<vn-chip
|
||||
ng-if="$ctrl.category"
|
||||
ng-if="category.selection"
|
||||
removable="true"
|
||||
translate-attr="{title: 'Category'}"
|
||||
on-remove="$ctrl.category = null"
|
||||
on-remove="$ctrl.categoryId = null"
|
||||
class="colored">
|
||||
<span translate>{{$ctrl.category.value}}</span>
|
||||
<span translate>{{category.selection.name}}</span>
|
||||
</vn-chip>
|
||||
<vn-chip
|
||||
ng-if="$ctrl.type"
|
||||
ng-if="type.selection"
|
||||
removable="true"
|
||||
translate-attr="{title: 'Type'}"
|
||||
on-remove="$ctrl.type = null"
|
||||
on-remove="$ctrl.typeId = null"
|
||||
class="colored">
|
||||
<span translate>{{$ctrl.type.value}}</span>
|
||||
<span translate>{{type.selection.name}}</span>
|
||||
</vn-chip>
|
||||
<vn-chip
|
||||
ng-repeat="tag in $ctrl.tags"
|
||||
|
|
|
@ -24,65 +24,50 @@ class Controller {
|
|||
* @param {Object} value - Order data
|
||||
*/
|
||||
set order(value) {
|
||||
if (!value || !value.id || this._order) return;
|
||||
this._order = value;
|
||||
|
||||
if (!value) return;
|
||||
|
||||
this.$.$applyAsync(() => {
|
||||
let category;
|
||||
let type;
|
||||
if (this.$stateParams.categoryId)
|
||||
this.categoryId = this.$stateParams.categoryId;
|
||||
|
||||
if (this.$stateParams.category)
|
||||
category = JSON.parse(this.$stateParams.category);
|
||||
|
||||
if (this.$stateParams.type)
|
||||
type = JSON.parse(this.$stateParams.type);
|
||||
|
||||
if (category && category.id)
|
||||
this.category = category;
|
||||
|
||||
if (type && type.id)
|
||||
this.type = type;
|
||||
if (this.$stateParams.typeId)
|
||||
this.typeId = this.$stateParams.typeId;
|
||||
});
|
||||
}
|
||||
|
||||
get category() {
|
||||
return this._category;
|
||||
get categoryId() {
|
||||
return this._categoryId;
|
||||
}
|
||||
|
||||
set category(value) {
|
||||
this.catalog.$scope.model.data = [];
|
||||
this.itemTypes = [];
|
||||
this.type = null;
|
||||
set categoryId(value) {
|
||||
if (!value || (this.categoryId == value))
|
||||
value = null;
|
||||
|
||||
if (!value || (this.category && this.category.id == value.id))
|
||||
this._category = null;
|
||||
else
|
||||
this._category = value;
|
||||
this._categoryId = value;
|
||||
this.itemTypes = [];
|
||||
this.typeId = null;
|
||||
|
||||
this.updateStateParams();
|
||||
|
||||
if (this.tags.length > 0)
|
||||
this.applyFilters();
|
||||
|
||||
if (this._category)
|
||||
if (value)
|
||||
this.updateItemTypes();
|
||||
}
|
||||
|
||||
get type() {
|
||||
return this._type;
|
||||
get typeId() {
|
||||
return this._typeId;
|
||||
}
|
||||
|
||||
set type(value) {
|
||||
if (value && this.type && this.type.id == value.id) return;
|
||||
|
||||
this._type = value;
|
||||
|
||||
if (!value || !value.id)
|
||||
this._type = null;
|
||||
set typeId(value) {
|
||||
this._typeId = value;
|
||||
|
||||
this.updateStateParams();
|
||||
|
||||
if ((value && value.id) || this.tags.length > 0)
|
||||
if ((value) || this.tags.length > 0)
|
||||
this.applyFilters();
|
||||
}
|
||||
|
||||
|
@ -91,17 +76,17 @@ class Controller {
|
|||
*/
|
||||
updateItemTypes() {
|
||||
let params = {
|
||||
itemCategoryId: this.category.id
|
||||
itemCategoryId: this.categoryId
|
||||
};
|
||||
|
||||
const query = `Orders/${this.order.id}/getItemTypeAvailable`;
|
||||
this.$http.get(query, {params}).then(res => {
|
||||
this.itemTypes = res.data;
|
||||
});
|
||||
this.$http.get(query, {params}).then(res =>
|
||||
this.itemTypes = res.data);
|
||||
}
|
||||
|
||||
onSearchById(event) {
|
||||
if (event.key === 'Enter' && (this.tags.length > 0 || this.itemFk || this.type))
|
||||
const hasValue = this.tags.length > 0 || this.itemId || this.typeId;
|
||||
if (event.key === 'Enter' && hasValue)
|
||||
this.applyFilters();
|
||||
}
|
||||
|
||||
|
@ -117,7 +102,7 @@ class Controller {
|
|||
remove(index) {
|
||||
this.tags.splice(index, 1);
|
||||
|
||||
if (this.tags.length >= 0 || this.itemFk || this.type)
|
||||
if (this.tags.length >= 0 || this.itemId || this.typeId)
|
||||
this.applyFilters();
|
||||
}
|
||||
|
||||
|
@ -126,14 +111,14 @@ class Controller {
|
|||
let newFilter = {};
|
||||
const model = this.catalog.$scope.model;
|
||||
|
||||
if (this.category)
|
||||
newFilter.categoryFk = this.category.id;
|
||||
if (this.categoryId)
|
||||
newFilter.categoryFk = this.categoryId;
|
||||
|
||||
if (this.type)
|
||||
newFilter.typeFk = this.type.id;
|
||||
if (this.typeId)
|
||||
newFilter.typeFk = this.typeId;
|
||||
|
||||
if (this.itemFk)
|
||||
newFilter = {'i.id': this.itemFk};
|
||||
if (this.itemId)
|
||||
newFilter = {'i.id': this.itemId};
|
||||
|
||||
newParams = {
|
||||
orderFk: this.order.id,
|
||||
|
@ -164,13 +149,13 @@ class Controller {
|
|||
updateStateParams() {
|
||||
const params = {};
|
||||
|
||||
if (this.category)
|
||||
params.category = JSON.stringify(this.category);
|
||||
if (this.categoryId)
|
||||
params.categoryId = this.categoryId;
|
||||
else params.categoryId = undefined;
|
||||
|
||||
if (this.type)
|
||||
params.type = JSON.stringify(this.type);
|
||||
else
|
||||
params.type = undefined;
|
||||
if (this.typeId)
|
||||
params.typeId = this.typeId;
|
||||
else params.typeId = undefined;
|
||||
|
||||
this.$state.go(this.$state.current.name, params);
|
||||
}
|
||||
|
|
|
@ -16,8 +16,8 @@ describe('Order', () => {
|
|||
$scope.model = crudModel;
|
||||
$scope.search = {};
|
||||
$state = _$state_;
|
||||
$state.params.category = '{"id": 1, "value": "My Category"}';
|
||||
$state.params.type = '{"id": 1, "value": "My type"}';
|
||||
$state.params.categoryId = 1;
|
||||
$state.params.typeId = 2;
|
||||
$state.current.name = 'my.current.state';
|
||||
controller = $componentController('vnCatalogFilter', {$element: null, $scope, $state});
|
||||
controller.catalog = {
|
||||
|
@ -35,15 +35,15 @@ describe('Order', () => {
|
|||
|
||||
$scope.$apply();
|
||||
|
||||
expect(controller.category).toEqual({id: 1, value: 'My Category'});
|
||||
expect(controller.type).toEqual({id: 1, value: 'My type'});
|
||||
expect(controller.categoryId).toEqual(1);
|
||||
expect(controller.typeId).toEqual(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('category() setter', () => {
|
||||
describe('categoryId() setter', () => {
|
||||
it(`should set category property to null, call updateStateParams() method and not call applyFilters()`, () => {
|
||||
spyOn(controller, 'updateStateParams');
|
||||
controller.category = null;
|
||||
controller.categoryId = null;
|
||||
|
||||
expect(controller.updateStateParams).toHaveBeenCalledWith();
|
||||
});
|
||||
|
@ -51,17 +51,17 @@ describe('Order', () => {
|
|||
it(`should set category property and then call updateStateParams() and applyFilters() methods`, () => {
|
||||
spyOn(controller, 'updateStateParams');
|
||||
controller._order = {id: 4};
|
||||
controller.category = {id: 2, value: 'My category'};
|
||||
controller.categoryId = 2;
|
||||
|
||||
expect(controller.updateStateParams).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
|
||||
describe('type() setter', () => {
|
||||
describe('typeId() setter', () => {
|
||||
it(`should set type property to null, call updateStateParams() method and not call applyFilters()`, () => {
|
||||
spyOn(controller, 'updateStateParams');
|
||||
spyOn(controller, 'applyFilters');
|
||||
controller.type = null;
|
||||
controller.typeId = null;
|
||||
|
||||
expect(controller.updateStateParams).toHaveBeenCalledWith();
|
||||
expect(controller.applyFilters).not.toHaveBeenCalledWith();
|
||||
|
@ -70,7 +70,7 @@ describe('Order', () => {
|
|||
it(`should set category property and then call updateStateParams() and applyFilters() methods`, () => {
|
||||
spyOn(controller, 'updateStateParams');
|
||||
spyOn(controller, 'applyFilters');
|
||||
controller.type = {id: 2, value: 'My type'};
|
||||
controller.typeId = 2;
|
||||
|
||||
expect(controller.updateStateParams).toHaveBeenCalledWith();
|
||||
expect(controller.applyFilters).toHaveBeenCalledWith();
|
||||
|
@ -101,7 +101,7 @@ describe('Order', () => {
|
|||
describe('onSearchById()', () => {
|
||||
it(`should not filter by id if the event key code doesn't equals to 'Enter'`, () => {
|
||||
spyOn(controller, 'applyFilters');
|
||||
controller.itemFk = 1;
|
||||
controller.itemId = 1;
|
||||
controller.onSearchById({key: 'Tab'});
|
||||
|
||||
expect(controller.applyFilters).not.toHaveBeenCalledWith();
|
||||
|
@ -109,7 +109,7 @@ describe('Order', () => {
|
|||
|
||||
it(`should filter by id if the event key code equals to 'Enter' an then call applyFilters()`, () => {
|
||||
spyOn(controller, 'applyFilters');
|
||||
controller.itemFk = 1;
|
||||
controller.itemId = 1;
|
||||
|
||||
controller.onSearchById({key: 'Enter'});
|
||||
|
||||
|
@ -121,14 +121,14 @@ describe('Order', () => {
|
|||
it(`should call model applyFilter() method with a new filter`, () => {
|
||||
let model = controller.catalog.$scope.model;
|
||||
spyOn(model, 'applyFilter');
|
||||
controller._category = {id: 1, value: 'My Category'};
|
||||
controller._type = {id: 1, value: 'My type'};
|
||||
controller._categoryId = 2;
|
||||
controller._typeId = 4;
|
||||
controller._order = {id: 4};
|
||||
|
||||
controller.applyFilters();
|
||||
|
||||
expect(model.applyFilter).toHaveBeenCalledWith(
|
||||
{where: {categoryFk: 1, typeFk: 1}},
|
||||
{where: {categoryFk: 2, typeFk: 4}},
|
||||
{orderFk: 4, orderBy: controller.catalog.getOrderBy(), tags: []});
|
||||
});
|
||||
});
|
||||
|
@ -146,8 +146,8 @@ describe('Order', () => {
|
|||
|
||||
it(`should remove a tag from tags property and call applyFilters() if there's no more tags`, () => {
|
||||
spyOn(controller, 'applyFilters');
|
||||
controller._category = {id: 1, value: 'My Category'};
|
||||
controller._type = {id: 1, value: 'My type'};
|
||||
controller._categoryId = 1;
|
||||
controller._typeId = 1;
|
||||
controller.tags = [{tagFk: 1, value: 'Blue'}];
|
||||
controller.remove(0);
|
||||
|
||||
|
@ -159,9 +159,9 @@ describe('Order', () => {
|
|||
describe('updateStateParams()', () => {
|
||||
it(`should call state go() method passing category and type state params`, () => {
|
||||
spyOn(controller.$state, 'go');
|
||||
controller._category = {id: 1, value: 'My Category'};
|
||||
controller._type = {id: 1, value: 'My type'};
|
||||
let result = {category: '{"id":1,"value":"My Category"}', type: '{"id":1,"value":"My type"}'};
|
||||
controller._categoryId = 2;
|
||||
controller._typeId = 4;
|
||||
let result = {categoryId: 2, typeId: 4};
|
||||
controller.updateStateParams();
|
||||
|
||||
expect(controller.$state.go).toHaveBeenCalledWith('my.current.state', result);
|
||||
|
|
|
@ -14,6 +14,10 @@ vn-catalog-filter > div {
|
|||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
|
||||
vn-autocomplete[vn-id="category"] {
|
||||
display: none
|
||||
}
|
||||
|
||||
& > vn-one {
|
||||
padding: $spacing-sm;
|
||||
min-width: 33.33%;
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
"order": "$ctrl.order"
|
||||
}
|
||||
}, {
|
||||
"url": "/catalog?category&type",
|
||||
"url": "/catalog?categoryId&typeId",
|
||||
"state": "order.card.catalog",
|
||||
"component": "vn-order-catalog",
|
||||
"description": "Catalog",
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<form name="form" ng-submit="$ctrl.onSubmit()" class="vn-w-md">
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
ng-model="$ctrl.route.workerFk"
|
||||
url="Clients/activeWorkersWithRole"
|
||||
|
@ -17,6 +17,9 @@
|
|||
value-field="id"
|
||||
where="{role: 'employee'}"
|
||||
label="Worker">
|
||||
<tpl-item>
|
||||
<div>{{name}} - {{nickname}}</div>
|
||||
</tpl-item>
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
|
|
|
@ -7,5 +7,9 @@
|
|||
"dataSource": "vn"
|
||||
},"Currency": {
|
||||
"dataSource": "vn"
|
||||
},"Thermograph": {
|
||||
"dataSource": "vn"
|
||||
},"TravelThermograph": {
|
||||
"dataSource": "vn"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "Thermograph",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "thermograph"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "String",
|
||||
"id": true,
|
||||
"description": "Identifier"
|
||||
},
|
||||
"model": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"name": "TravelThermograph",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "travelThermograph"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"thermographFk": {
|
||||
"type": "String",
|
||||
"id": 1,
|
||||
"description": "Identifier"
|
||||
},
|
||||
"created": {
|
||||
"type": "Date",
|
||||
"id": 2,
|
||||
"description": "Identifier"
|
||||
},
|
||||
"temperature": {
|
||||
"type": "String"
|
||||
},
|
||||
"result": {
|
||||
"type": "String"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"travel": {
|
||||
"type": "belongsTo",
|
||||
"model": "Travel",
|
||||
"foreignKey": "travelFk"
|
||||
},
|
||||
"warehouse": {
|
||||
"type": "belongsTo",
|
||||
"model": "Warehouse",
|
||||
"foreignKey": "warehouseFk"
|
||||
},
|
||||
"dms": {
|
||||
"type": "belongsTo",
|
||||
"model": "Dms",
|
||||
"foreignKey": "dmsFk"
|
||||
},
|
||||
"thermograph": {
|
||||
"type": "belongsTo",
|
||||
"model": "Thermograph",
|
||||
"foreignKey": "thermographFk"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -43,7 +43,7 @@
|
|||
</vn-one>
|
||||
<vn-auto>
|
||||
<h4 translate>Entries</h4>
|
||||
<vn-table model="model">
|
||||
<vn-table>
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th shrink>Confirmed</vn-th>
|
||||
|
@ -51,8 +51,8 @@
|
|||
<vn-th shrink>Supplier</vn-th>
|
||||
<vn-th shrink>Reference</vn-th>
|
||||
<vn-th shrink title="Half box">HB</vn-th>
|
||||
<vn-th shrink>Freight cost</vn-th>
|
||||
<vn-th shrink>Package cost</vn-th>
|
||||
<vn-th shrink>Freight</vn-th>
|
||||
<vn-th shrink>Package</vn-th>
|
||||
<vn-th shrink>CC</vn-th>
|
||||
<vn-th shrink>Pallet</vn-th>
|
||||
<vn-th shrink>m3</vn-th>
|
||||
|
@ -61,16 +61,18 @@
|
|||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="entry in $ctrl.entries">
|
||||
<vn-check
|
||||
value="{{entry.isConfirmed}}"
|
||||
disabled="true">
|
||||
</vn-check>
|
||||
<vn-td shrink>
|
||||
<vn-check
|
||||
value="{{entry.isConfirmed}}"
|
||||
disabled="true">
|
||||
</vn-check>
|
||||
</vn-td>
|
||||
<vn-td shrink>{{entry.id}} </vn-td>
|
||||
<vn-td shrink>{{entry.supplierName}}</vn-td>
|
||||
<vn-td shrink>{{entry.ref}}</vn-td>
|
||||
<vn-td shrink>{{entry.hb}}</vn-td>
|
||||
<vn-td shrink>{{entry.freightValue}}</vn-td>
|
||||
<vn-td shrink>{{entry.packageValue}}</vn-td>
|
||||
<vn-td shrink>{{entry.freightValue | currency: 'EUR': 2}}</vn-td>
|
||||
<vn-td shrink>{{entry.packageValue | currency: 'EUR': 2}}</vn-td>
|
||||
<vn-td shrink>{{entry.cc}}</vn-td>
|
||||
<vn-td shrink>{{entry.pallet}}</vn-td>
|
||||
<vn-td shrink>{{entry.m3}}</vn-td>
|
||||
|
@ -81,13 +83,28 @@
|
|||
icon="insert_drive_file">
|
||||
</vn-icon>
|
||||
<vn-icon
|
||||
ng-if="entry.notes.length"
|
||||
ng-if="entry.observation.length"
|
||||
vn-tooltip="{{entry.observation}}"
|
||||
icon="insert_drive_file">
|
||||
</vn-icon>
|
||||
</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
<vn-tfoot>
|
||||
<vn-tr>
|
||||
<vn-td></vn-td>
|
||||
<vn-td></vn-td>
|
||||
<vn-td></vn-td>
|
||||
<vn-td></vn-td>
|
||||
<vn-td shrink><strong>{{$ctrl.total('hb')}}</strong></vn-td>
|
||||
<vn-td shrink><strong>{{$ctrl.total('freightValue') | currency: 'EUR': 2}}</strong></vn-td>
|
||||
<vn-td shrink><strong>{{$ctrl.total('packageValue') | currency: 'EUR': 2}}</strong></vn-td>
|
||||
<vn-td shrink><strong>{{$ctrl.total('cc')}}</strong></vn-td>
|
||||
<vn-td shrink><strong>{{$ctrl.total('pallet')}}</strong></vn-td>
|
||||
<vn-td shrink><strong>{{$ctrl.total('m3')}}</strong></vn-td>
|
||||
<vn-td></vn-td>
|
||||
</vn-tr>
|
||||
</vn-tfoot>
|
||||
</vn-table>
|
||||
</vn-auto>
|
||||
</vn-horizontal>
|
||||
|
|
|
@ -5,6 +5,7 @@ class Controller {
|
|||
constructor($scope, $http) {
|
||||
this.$ = $scope;
|
||||
this.$http = $http;
|
||||
this.entries = [];
|
||||
}
|
||||
|
||||
get travel() {
|
||||
|
@ -31,6 +32,15 @@ class Controller {
|
|||
this.entries = response.data;
|
||||
});
|
||||
}
|
||||
|
||||
total(field) {
|
||||
let total = 0;
|
||||
|
||||
for (let entry of this.entries)
|
||||
total += entry[field];
|
||||
|
||||
return total;
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$scope', '$http'];
|
||||
|
|
|
@ -58,4 +58,18 @@ describe('component vnTravelSummary', () => {
|
|||
expect(controller.entries).toEqual('I am the entries');
|
||||
});
|
||||
});
|
||||
|
||||
describe('total()', () => {
|
||||
it('should calculate the total amount of a given property for every row', () => {
|
||||
controller.entries = [
|
||||
{id: 1, freightValue: 1, packageValue: 2, cc: 0.01},
|
||||
{id: 2, freightValue: 1, packageValue: 2, cc: 0.01},
|
||||
{id: 3, freightValue: 1, packageValue: 2, cc: 0.01}
|
||||
];
|
||||
|
||||
expect(controller.total('freightValue')).toEqual(3);
|
||||
expect(controller.total('packageValue')).toEqual(6);
|
||||
expect(controller.total('cc')).toEqual(0.03);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -12,6 +12,6 @@ Confirmed: Confirmada
|
|||
Entry Id: Entrada Id
|
||||
Supplier: Proveedor
|
||||
Pallet: Pallet
|
||||
Freight cost: Coste porte
|
||||
Package cost: Coste embalaje
|
||||
Freight: Porte
|
||||
Package: Embalaje
|
||||
Half box: Media caja
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
|
||||
// #1924 - Fix hours
|
||||
xdescribe('Worker absences()', () => {
|
||||
describe('Worker absences()', () => {
|
||||
it('should get the absence calendar for a full year contract', async() => {
|
||||
let ctx = {req: {accessToken: {userId: 106}}};
|
||||
let workerFk = 106;
|
||||
|
@ -27,8 +26,8 @@ xdescribe('Worker absences()', () => {
|
|||
let firstType = absences[0].absenceType().name;
|
||||
let sixthType = absences[5].absenceType().name;
|
||||
|
||||
expect(firstType).toEqual('Leave of absence');
|
||||
expect(sixthType).toEqual('Holidays');
|
||||
expect(firstType).toMatch(/(Holidays|Leave of absence)/);
|
||||
expect(sixthType).toMatch(/(Holidays|Leave of absence)/);
|
||||
});
|
||||
|
||||
it('should get the absence calendar for a permanent contract', async() => {
|
||||
|
@ -64,8 +63,8 @@ xdescribe('Worker absences()', () => {
|
|||
let firstType = absences[0].absenceType().name;
|
||||
let sixthType = absences[5].absenceType().name;
|
||||
|
||||
expect(firstType).toEqual('Leave of absence');
|
||||
expect(sixthType).toEqual('Holidays');
|
||||
expect(firstType).toMatch(/(Holidays|Leave of absence)/);
|
||||
expect(sixthType).toMatch(/(Holidays|Leave of absence)/);
|
||||
|
||||
// restores the contract end date
|
||||
await app.models.WorkerLabour.rawSql(
|
||||
|
@ -146,8 +145,8 @@ xdescribe('Worker absences()', () => {
|
|||
let firstType = absences[0].absenceType().name;
|
||||
let sixthType = absences[5].absenceType().name;
|
||||
|
||||
expect(firstType).toEqual('Leave of absence');
|
||||
expect(sixthType).toEqual('Holidays');
|
||||
expect(firstType).toMatch(/(Holidays|Leave of absence)/);
|
||||
expect(sixthType).toMatch(/(Holidays|Leave of absence)/);
|
||||
|
||||
// resets the holidays per year with originalHolidaysValue and the contract starting date
|
||||
await app.models.WorkCenterHoliday.updateAll(
|
||||
|
|
|
@ -29,7 +29,7 @@ module.exports = Self => {
|
|||
|
||||
const mySubordinates = await Self.mySubordinates(ctx);
|
||||
const isSubordinate = mySubordinates.find(subordinate => {
|
||||
return subordinate.workerFk === id;
|
||||
return subordinate.workerFk == id;
|
||||
});
|
||||
|
||||
const isHr = await models.Account.hasRole(myUserId, 'hr');
|
||||
|
|
|
@ -19,7 +19,7 @@ vn-log {
|
|||
}
|
||||
|
||||
@media screen and (max-width: 1570px) {
|
||||
.expendable {
|
||||
vn-table .expendable {
|
||||
display: none;
|
||||
}
|
||||
.changes {
|
||||
|
|
|
@ -4,8 +4,10 @@ let env = process.env.NODE_ENV ? process.env.NODE_ENV : 'development';
|
|||
let configPath = `/etc/salix`;
|
||||
let config = require('../config/print.json');
|
||||
let configFiles = [
|
||||
`${appPath}/config/print.local.json`,
|
||||
`${appPath}/config/print.${env}.json`,
|
||||
`${configPath}/print.json`,
|
||||
`${configPath}/print.local.json`,
|
||||
`${configPath}/print.${env}.json`
|
||||
];
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
const Stylesheet = require(`${appPath}/core/stylesheet`);
|
||||
|
||||
module.exports = new Stylesheet([
|
||||
`${appPath}/common/css/spacing.css`,
|
||||
`${appPath}/common/css/misc.css`,
|
||||
`${appPath}/common/css/layout.css`,
|
||||
`${appPath}/common/css/email.css`])
|
||||
.mergeStyles();
|
|
@ -0,0 +1,69 @@
|
|||
<!DOCTYPE html>
|
||||
<html v-bind:lang="locale">
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<title>{{ $t('subject') }}</title>
|
||||
</head>
|
||||
<body>
|
||||
<table class="grid">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<!-- Empty block -->
|
||||
<div class="grid-row">
|
||||
<div class="grid-block empty"></div>
|
||||
</div>
|
||||
<!-- Header block -->
|
||||
<div class="grid-row">
|
||||
<div class="grid-block">
|
||||
<email-header v-bind="$props"></email-header>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Block -->
|
||||
<div class="grid-row">
|
||||
<div class="grid-block vn-pa-lg">
|
||||
<h1>{{ $t('title') }}</h1>
|
||||
<p>{{$t('dear')}},</p>
|
||||
<p v-html="$t('description', [dated])"></p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Block -->
|
||||
<div class="grid-row">
|
||||
<div class="grid-block vn-pa-lg">
|
||||
<table class="column-oriented">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{$t('buyer')}}</th>
|
||||
<th class="number">{{$t('percentage')}}</th>
|
||||
<th class="number">{{$t('dwindle')}}</th>
|
||||
<th class="number">{{$t('total')}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="waste in wastes" v-bind:key="waste.buyer">
|
||||
<td class="font gray">{{waste.buyer}}</td>
|
||||
<td class="number">{{(waste.percentage / 100) | percentage(4, 4, locale)}}</td>
|
||||
<td class="number">{{waste.dwindle | currency('EUR', locale)}}</td>
|
||||
<td class="number">{{waste.total | currency('EUR', locale)}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer block -->
|
||||
<div class="grid-row">
|
||||
<div class="grid-block">
|
||||
<email-footer v-bind="$props"></email-footer>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Empty block -->
|
||||
<div class="grid-row">
|
||||
<div class="grid-block empty"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,31 @@
|
|||
const Component = require(`${appPath}/core/component`);
|
||||
const db = require(`${appPath}/core/database`);
|
||||
const emailHeader = new Component('email-header');
|
||||
const emailFooter = new Component('email-footer');
|
||||
|
||||
module.exports = {
|
||||
name: 'buyer-week-waste',
|
||||
async serverPrefetch() {
|
||||
this.wastes = await this.fetchWastes();
|
||||
|
||||
if (!this.wastes)
|
||||
throw new Error('Something went wrong');
|
||||
},
|
||||
computed: {
|
||||
dated: function() {
|
||||
const filters = this.$options.filters;
|
||||
|
||||
return filters.date(new Date(), '%d-%m-%Y');
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
fetchWastes() {
|
||||
return db.findOne(`CALL bs.weekWaste()`);
|
||||
}
|
||||
},
|
||||
components: {
|
||||
'email-header': emailHeader.build(),
|
||||
'email-footer': emailFooter.build()
|
||||
},
|
||||
props: {}
|
||||
};
|
|
@ -0,0 +1,8 @@
|
|||
subject: Merma semanal
|
||||
title: Merma semanal
|
||||
dear: Hola
|
||||
description: A continuación se muestra la merma semanal a fecha de <strong>{0}</strong>.
|
||||
buyer: Comprador
|
||||
percentage: Porcentaje
|
||||
weakening: Mermas
|
||||
total: Total
|
|
@ -12,4 +12,4 @@ claim: Reclamación {0}
|
|||
sections:
|
||||
agency:
|
||||
description: 'Para agilizar tu recogida, por favor, pónte en contacto con la oficina
|
||||
de integrados. <br/> Tlf: 96 166 77 88 - Ana Gómez (Ext. 2133) <em>(agomezf@integra2.es)</em>'
|
||||
de integrados. <br/> Tlf: 96 166 77 88 - Ana Gómez (Ext. 2113) <em>(agomezf@integra2.es)</em>'
|
||||
|
|
Loading…
Reference in New Issue