1361 - Añadir filtro por año #348

Merged
joan merged 16 commits from 1361-calendar_date_filter into dev 2020-08-18 12:18:41 +00:00
25 changed files with 1941 additions and 909 deletions
Showing only changes of commit 55b3e962a4 - Show all commits

View File

@ -560,7 +560,7 @@ INSERT INTO `vn`.`ticket`(`id`, `priority`, `agencyModeFk`,`warehouseFk`,`routeF
(16, 1, 7, 1, 6, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 106, 'Many Places', 126, NULL, 0, 3, CURDATE()), (16, 1, 7, 1, 6, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 106, 'Many Places', 126, NULL, 0, 3, CURDATE()),
(17, 1, 7, 2, 6, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 106, 'Many Places', 126, NULL, 0, 3, CURDATE()), (17, 1, 7, 2, 6, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 106, 'Many Places', 126, NULL, 0, 3, CURDATE()),
(18, 1, 4, 4, 4, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 108, 'Cerebro', 128, NULL, 0, 12, CURDATE()), (18, 1, 4, 4, 4, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 108, 'Cerebro', 128, NULL, 0, 12, CURDATE()),
(19, 1, 5, 5, 3, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 109, 'Somewhere in Thailand', 129, NULL, 1, 13, CURDATE()), (19, 1, 5, 5, NULL, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 109, 'Somewhere in Thailand', 129, NULL, 1, 13, CURDATE()),
(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)), (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, 5, 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)), (21, NULL, 5, 5, 5, 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, 5, 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)), (22, NULL, 5, 5, 5, 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)),

View File

@ -544,6 +544,7 @@ export default {
logButton: 'vn-left-menu a[ui-sref="ticket.card.log"]', logButton: 'vn-left-menu a[ui-sref="ticket.card.log"]',
changedBy: 'vn-ticket-log > vn-log vn-tr:nth-child(1) > vn-td:nth-child(2) > span', changedBy: 'vn-ticket-log > vn-log vn-tr:nth-child(1) > vn-td:nth-child(2) > span',
actionTaken: 'vn-ticket-log > vn-log vn-td:nth-child(1) > div > div:nth-child(3) > span.value', actionTaken: 'vn-ticket-log > vn-log vn-td:nth-child(1) > div > div:nth-child(3) > span.value',
changes: 'vn-ticket-log vn-data-viewer vn-tbody > vn-tr > vn-td:nth-child(7)',
id: 'vn-ticket-log > vn-log vn-td.before > vn-one:nth-child(1) > div > span.value' id: 'vn-ticket-log > vn-log vn-td.before > vn-one:nth-child(1) > div > span.value'
}, },
ticketService: { ticketService: {
@ -868,6 +869,13 @@ export default {
createdThermograph: 'vn-travel-thermograph-index vn-tbody > vn-tr', createdThermograph: 'vn-travel-thermograph-index vn-tbody > vn-tr',
upload: 'vn-travel-thermograph-create button[type=submit]' upload: 'vn-travel-thermograph-create button[type=submit]'
}, },
zoneIndex: {
searchResult: 'vn-zone-index a.vn-tr',
},
zoneDescriptor: {
menu: 'vn-zone-descriptor vn-icon-button[vn-popover="menu"]',
deleteZone: 'slot-menu vn-item[ng-click="$ctrl.onDelete()"]'
},
zoneBasicData: { zoneBasicData: {
name: 'vn-zone-basic-data vn-textfield[ng-model="$ctrl.zone.name"]', name: 'vn-zone-basic-data vn-textfield[ng-model="$ctrl.zone.name"]',
agency: 'vn-zone-basic-data vn-autocomplete[ng-model="$ctrl.zone.agencyModeFk"]', agency: 'vn-zone-basic-data vn-autocomplete[ng-model="$ctrl.zone.agencyModeFk"]',

View File

@ -0,0 +1,42 @@
import selectors from '../../helpers/selectors.js';
import getBrowser from '../../helpers/puppeteer';
describe('Zone descriptor path', () => {
let browser;
let page;
beforeAll(async() => {
browser = await getBrowser();
page = browser.page;
await page.loginAndModule('deliveryBoss', 'zone');
await page.accessToSearchResult('13');
});
afterAll(async() => {
await browser.close();
});
it('should eliminate the zone using the descriptor option', async() => {
await page.waitToClick(selectors.zoneDescriptor.menu);
await page.waitToClick(selectors.zoneDescriptor.deleteZone);
await page.respondToDialog('accept');
await page.waitForState('zone.index');
});
it('should search for the deleted zone to find no results', async() => {
await page.doSearch('13');
const count = await page.countElement(selectors.zoneIndex.searchResult);
expect(count).toEqual(0);
});
it('should check the ticket whom lost the zone and see evidence on the logs', async() => {
await page.waitToClick(selectors.globalItems.homeButton);
await page.selectModule('ticket');
await page.accessToSearchResult('20');
await page.accessToSection('ticket.card.log');
const lastChanges = await page.waitToGetProperty(selectors.ticketLog.changes, 'innerText');
expect(lastChanges).toContain('Arreglar');
});
});

View File

@ -70,7 +70,8 @@ module.exports = {
`front`, `front`,
`modules`, `modules`,
`front/node_modules`, `front/node_modules`,
`node_modules` `node_modules`,
`print`
], ],
// An array of file extensions your modules use // An array of file extensions your modules use
@ -153,6 +154,7 @@ module.exports = {
// The glob patterns Jest uses to detect test files // The glob patterns Jest uses to detect test files
testMatch: [ testMatch: [
'**/front/**/*.spec.js', '**/front/**/*.spec.js',
'**/print/**/*.spec.js',
// 'loopback/**/*.spec.js', // 'loopback/**/*.spec.js',
// 'modules/*/back/**/*.spec.js' // 'modules/*/back/**/*.spec.js'
// "**/__tests__/**/*.[jt]s?(x)", // "**/__tests__/**/*.[jt]s?(x)",

View File

@ -134,5 +134,5 @@
"This ticket is deleted": "Este ticket está eliminado", "This ticket is deleted": "Este ticket está eliminado",
"A travel with this data already exists": "Ya existe un travel con estos datos", "A travel with this data already exists": "Ya existe un travel con estos datos",
"This thermograph id already exists": "La id del termógrafo ya existe", "This thermograph id already exists": "La id del termógrafo ya existe",
"ORDER_ALREADY_CONFIRMED": "ORDER_ALREADY_CONFIRMED" "Choose a date range or days forward": "Selecciona un rango de fechas o días en adelante"
} }

View File

@ -36,7 +36,7 @@ module.exports = Self => {
relation: 'client', relation: 'client',
scope: { scope: {
include: { include: {
relation: 'salesPerson' relation: 'salesPersonUser'
} }
} }
} }
@ -53,7 +53,7 @@ module.exports = Self => {
const updatedClaim = await claim.updateAttributes(data); const updatedClaim = await claim.updateAttributes(data);
// Get sales person from claim client // Get sales person from claim client
const salesPerson = claim.client().salesPerson(); const salesPerson = claim.client().salesPersonUser();
if (salesPerson && changedHasToPickUp && updatedClaim.hasToPickUp) { if (salesPerson && changedHasToPickUp && updatedClaim.hasToPickUp) {
const origin = ctx.req.headers.origin; const origin = ctx.req.headers.origin;
const message = $t('Claim will be picked', { const message = $t('Claim will be picked', {

View File

@ -34,17 +34,7 @@ class Controller extends ModuleCard {
scope: { scope: {
fields: ['salesPersonFk', 'name', 'email'], fields: ['salesPersonFk', 'name', 'email'],
include: { include: {
relation: 'salesPerson', relation: 'salesPersonUser'
scope: {
fields: ['userFk'],
include: {
relation: 'user',
scope: {
fields: ['nickname']
}
}
}
} }
} }
} }

View File

@ -33,7 +33,7 @@
</vn-label-value> </vn-label-value>
<vn-label-value <vn-label-value
label="Salesperson" label="Salesperson"
value="{{$ctrl.claim.client.salesPerson.user.nickname}}"> value="{{$ctrl.claim.client.salesPersonUser.nickname}}">
</vn-label-value> </vn-label-value>
<vn-label-value <vn-label-value
label="Attended by" label="Attended by"
@ -78,4 +78,4 @@
on-accept="$ctrl.deleteClaim()" on-accept="$ctrl.deleteClaim()"
question="Delete claim" question="Delete claim"
message="Are you sure you want to delete this claim?"> message="Are you sure you want to delete this claim?">
</vn-confirm> </vn-confirm>

View File

@ -20,7 +20,8 @@ module.exports = Self => {
const models = Self.app.models; const models = Self.app.models;
try { try {
const imageQueue = await Self.find({limit: 25}); const imageQueue = await Self.find({where: {error: null}, limit: 25});
/* const tempPath = path.join('/tmp/salix-image'); */
const rootPath = models.Image.getPath(); const rootPath = models.Image.getPath();
const tempPath = path.join(rootPath, 'temp'); const tempPath = path.join(rootPath, 'temp');
@ -33,24 +34,41 @@ module.exports = Self => {
const file = fs.createWriteStream(filePath); const file = fs.createWriteStream(filePath);
https.get(image.url, async response => { https.get(image.url, async response => {
if (response.statusCode != 200) {
const error = new Error(`Could not download the image. Status code ${response.statusCode}`);
file.close();
await errorHandler(image.itemFk, error, filePath);
}
response.pipe(file); response.pipe(file);
});
file.on('finish', async function() { file.on('error', async error => {
await models.Image.registerImage('catalog', fileName, filePath); await errorHandler(image.itemFk, error, filePath);
await image.destroy(); });
});
file.on('error', err => { file.on('finish', async function() {
fs.unlink(filePath); try {
await models.Image.registerImage('catalog', fileName, filePath);
throw err; await image.destroy();
} catch (error) {
await errorHandler(image.itemFk, error, filePath);
}
});
}).on('error', async error => {
await errorHandler(image.itemFk, error, filePath);
}); });
} }
} catch (error) {
await errorHandler(image.itemFk, error);
}
return imageQueue; async function errorHandler(rowId, error, filePath) {
} catch (e) { const row = await Self.findById(rowId);
throw e; await row.updateAttribute('error', error);
if (filePath)
await fs.unlink(filePath);
} }
}; };
}; };

View File

@ -16,6 +16,10 @@
"url": { "url": {
"type": "String", "type": "String",
"required": true "required": true
},
"error": {
"type": "String",
"required": true
} }
}, },
"relations": { "relations": {

View File

@ -2,6 +2,7 @@
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
const buildFilter = require('vn-loopback/util/filter').buildFilter; const buildFilter = require('vn-loopback/util/filter').buildFilter;
const mergeFilters = require('vn-loopback/util/filter').mergeFilters; const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => { module.exports = Self => {
Self.remoteMethod('filter', { Self.remoteMethod('filter', {
@ -233,7 +234,7 @@ module.exports = Self => {
}); });
} }
stmt.merge(conn.makeSuffix(filter)); stmt.merge(conn.makeWhere(filter.where));
stmts.push(stmt); stmts.push(stmt);
stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.ticketGetProblems'); stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.ticketGetProblems');
@ -241,9 +242,11 @@ module.exports = Self => {
CREATE TEMPORARY TABLE tmp.ticketGetProblems CREATE TEMPORARY TABLE tmp.ticketGetProblems
(INDEX (ticketFk)) (INDEX (ticketFk))
ENGINE = MEMORY ENGINE = MEMORY
SELECT id ticketFk, clientFk, warehouseFk, shipped SELECT f.id ticketFk, f.clientFk, f.warehouseFk, f.shipped
FROM tmp.filter FROM tmp.filter f
WHERE alertLevel = 0 OR alertLevel IS NULL`); LEFT JOIN alertLevel al ON al.alertLevel = f.alertLevel
WHERE (f.alertLevelCode = 'FREE' OR f.alertLevel IS NULL)
AND f.shipped >= CURDATE()`);
stmts.push('CALL ticketGetProblems()'); stmts.push('CALL ticketGetProblems()');
stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.ticket'); stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.ticket');
@ -262,6 +265,9 @@ module.exports = Self => {
LEFT JOIN tmp.ticketProblems tp ON tp.ticketFk = f.id LEFT JOIN tmp.ticketProblems tp ON tp.ticketFk = f.id
LEFT JOIN tmp.ticketTotal tt ON tt.ticketFk = f.id`); LEFT JOIN tmp.ticketTotal tt ON tt.ticketFk = f.id`);
if (args.problems != undefined && (!args.from || !args.to))
throw new UserError('Choose a date range or days forward');
let condition; let condition;
let hasProblem; let hasProblem;
let range; let range;
@ -293,6 +299,7 @@ module.exports = Self => {
stmt.merge(conn.makeWhere(problems)); stmt.merge(conn.makeWhere(problems));
stmt.merge(conn.makeOrderBy(filter.order)); stmt.merge(conn.makeOrderBy(filter.order));
stmt.merge(conn.makeLimit(filter));
let ticketsIndex = stmts.push(stmt); let ticketsIndex = stmts.push(stmt);
stmts.push( stmts.push(

View File

@ -2,7 +2,7 @@
vn-id="model" vn-id="model"
url="Tickets/filter" url="Tickets/filter"
limit="20" limit="20"
order="shipped DESC, zoneHour ASC, zoneMinute ASC, clientFk"> order="shipped DESC, zoneHour DESC, zoneMinute DESC, clientFk">
</vn-crud-model> </vn-crud-model>
<vn-portal slot="topbar"> <vn-portal slot="topbar">
<vn-searchbar <vn-searchbar

2588
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -40,7 +40,7 @@
"@babel/core": "^7.7.7", "@babel/core": "^7.7.7",
"@babel/plugin-syntax-dynamic-import": "^7.7.4", "@babel/plugin-syntax-dynamic-import": "^7.7.4",
"@babel/polyfill": "^7.7.0", "@babel/polyfill": "^7.7.0",
"@babel/preset-env": "^7.7.7", "@babel/preset-env": "^7.11.0",
"@babel/register": "^7.7.7", "@babel/register": "^7.7.7",
"angular-mocks": "^1.7.9", "angular-mocks": "^1.7.9",
"babel-jest": "^26.0.1", "babel-jest": "^26.0.1",

View File

@ -4,8 +4,8 @@ let env = process.env.NODE_ENV ? process.env.NODE_ENV : 'development';
let configPath = `/etc/salix`; let configPath = `/etc/salix`;
let config = require('../config/print.json'); let config = require('../config/print.json');
let configFiles = [ let configFiles = [
`${appPath}/config/print.local.json`, `../config/print.local.json`,
`${appPath}/config/print.${env}.json`, `../config/print.${env}.json`,
`${configPath}/print.json`, `${configPath}/print.json`,
`${configPath}/print.local.json`, `${configPath}/print.local.json`,
`${configPath}/print.${env}.json` `${configPath}/print.${env}.json`

View File

@ -2,9 +2,13 @@ const Vue = require('vue');
const config = require('../config'); const config = require('../config');
const defaultLocale = config.i18n.locale; const defaultLocale = config.i18n.locale;
Vue.filter('currency', function(value, currency = 'EUR', locale = defaultLocale) { const currency = function(value, currency = 'EUR', locale = defaultLocale) {
if (!locale) locale = defaultLocale; if (!locale) locale = defaultLocale;
return new Intl.NumberFormat(locale, { return new Intl.NumberFormat(locale, {
style: 'currency', currency style: 'currency', currency
}).format(parseFloat(value)); }).format(parseFloat(value));
}); };
Vue.filter('currency', currency);
module.exports = currency;

View File

@ -1,7 +1,11 @@
const Vue = require('vue'); const Vue = require('vue');
const strftime = require('strftime'); const strftime = require('strftime');
Vue.filter('date', function(value, specifiers = '%d-%m-%Y') { const date = function(value, specifiers = '%d-%m-%Y') {
if (!(value instanceof Date)) value = new Date(value); if (!(value instanceof Date)) value = new Date(value);
return strftime(specifiers, value); return strftime(specifiers, value);
}); };
Vue.filter('date', date);
module.exports = date;

View File

@ -2,9 +2,13 @@ const Vue = require('vue');
const config = require('../config'); const config = require('../config');
const defaultLocale = config.i18n.locale; const defaultLocale = config.i18n.locale;
Vue.filter('number', function(value, locale = defaultLocale) { const number = function(value, locale = defaultLocale) {
if (!locale) locale = defaultLocale; if (!locale) locale = defaultLocale;
return new Intl.NumberFormat(locale, { return new Intl.NumberFormat(locale, {
style: 'decimal' style: 'decimal'
}).format(parseFloat(value)); }).format(parseFloat(value));
}); };
Vue.filter('number', number);
module.exports = number;

View File

@ -2,11 +2,15 @@ const Vue = require('vue');
const config = require('../config'); const config = require('../config');
const defaultLocale = config.i18n.locale; const defaultLocale = config.i18n.locale;
Vue.filter('percentage', function(value, minFraction = 2, maxFraction = 2, locale = defaultLocale) { const percentage = function(value, minFraction = 2, maxFraction = 2, locale = defaultLocale) {
if (!locale) locale = defaultLocale; if (!locale) locale = defaultLocale;
return new Intl.NumberFormat(locale, { return new Intl.NumberFormat(locale, {
style: 'percent', style: 'percent',
minimumFractionDigits: minFraction, minimumFractionDigits: minFraction,
maximumFractionDigits: maxFraction maximumFractionDigits: maxFraction
}).format(parseFloat(value)); }).format(parseFloat(value));
}); };
Vue.filter('percentage', percentage);
module.exports = percentage;

View File

@ -0,0 +1,16 @@
// Extended locale intl polyfill
const IntlPolyfill = require('intl');
Intl.NumberFormat = IntlPolyfill.NumberFormat;
Intl.DateTimeFormat = IntlPolyfill.DateTimeFormat;
import currency from '../currency.js';
describe('currency filter', () => {
it('should filter the currency in spanish as default', () => {
expect(currency(999, 'EUR')).toEqual('999,00 €');
});
it('should filter the currency in english', () => {
expect(currency(999, 'EUR', 'en')).toEqual('€999.00');
});
});

View File

@ -0,0 +1,27 @@
import date from '../date.js';
describe('date filter', () => {
const superDuperDate = new Date('February 18, 1984 @ 11:30:00 am');
it('should filter the date as %d-%m-%Y by default', () => {
expect(date(superDuperDate)).toEqual('18-02-1984');
});
it('should filter the date as %m-%d-%Y', () => {
const dateFormat = '%m-%d-%Y';
expect(date(superDuperDate, dateFormat)).toEqual('02-18-1984');
});
it('should filter the date as %y-%d-%m', () => {
const dateFormat = '%y-%d-%m';
expect(date(superDuperDate, dateFormat)).toEqual('84-18-02');
});
it('should filter the date as %Y-%d-%m', () => {
const dateFormat = '%Y-%d-%m';
expect(date(superDuperDate, dateFormat)).toEqual('1984-18-02');
});
});

View File

@ -0,0 +1,9 @@
import number from '../number.js';
describe('number filter', () => {
const superDuperNumber = 18021984;
it('should filter the number with commas by default', () => {
expect(number(superDuperNumber)).toEqual('18,021,984');
});
});

View File

@ -0,0 +1,11 @@
import percentage from '../percentage.js';
describe('percentage filter', () => {
it('should filter the percentage also round it correctly', () => {
expect(percentage(99.9999999999999999 / 100)).toEqual('100.00%');
});
it('should filter the percentage and round it correctly', () => {
expect(percentage(1.25444444444444444 / 100)).toEqual('1.25%');
});
});

View File

@ -0,0 +1,10 @@
import uppercase from '../uppercase.js';
describe('uppercase filter', () => {
it('should filter the string to uppercase', () => {
let lowerCase = 'text';
let upperCase = 'TEXT';
expect(uppercase(lowerCase)).toEqual(upperCase);
});
});

View File

@ -1,5 +1,9 @@
const Vue = require('vue'); const Vue = require('vue');
Vue.filter('uppercase', function(value) { const uppercase = function(value) {
return value.toUpperCase(); return value.toUpperCase();
}); };
Vue.filter('uppercase', uppercase);
module.exports = uppercase;