Merge branch 'dev' into 4109-duplicated_folder
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Carlos Jimenez Ruiz 2022-05-25 07:39:42 +00:00
commit 402aa567dd
26 changed files with 405 additions and 96 deletions

View File

@ -1,5 +1,5 @@
module.exports = Self => { module.exports = Self => {
Self.remoteMethodCtx('setSaleQuantity', { Self.remoteMethod('setSaleQuantity', {
description: 'Update sale quantity', description: 'Update sale quantity',
accessType: 'WRITE', accessType: 'WRITE',
accepts: [{ accepts: [{
@ -24,11 +24,13 @@ module.exports = Self => {
} }
}); });
Self.setSaleQuantity = async ctx => { Self.setSaleQuantity = async(saleId, quantity) => {
const args = ctx.args;
const models = Self.app.models; const models = Self.app.models;
const sale = await models.Sale.findById(args.saleId); const sale = await models.Sale.findById(saleId);
return await sale.updateAttribute('quantity', args.quantity); return await sale.updateAttributes({
originalQuantity: sale.quantity,
quantity: quantity
});
}; };
}; };

View File

@ -5,19 +5,12 @@ describe('setSaleQuantity()', () => {
const saleId = 30; const saleId = 30;
const newQuantity = 10; const newQuantity = 10;
const ctx = {
args: {
saleId: saleId,
quantity: newQuantity
}
};
const originalSale = await models.Sale.findById(saleId); const originalSale = await models.Sale.findById(saleId);
await models.Collection.setSaleQuantity(ctx); await models.Collection.setSaleQuantity(saleId, newQuantity);
const updateSale = await models.Sale.findById(saleId); const updateSale = await models.Sale.findById(saleId);
expect(updateSale.quantity).toBeLessThan(originalSale.quantity); expect(updateSale.originalQuantity).toEqual(originalSale.quantity);
expect(updateSale.quantity).toEqual(newQuantity); expect(updateSale.quantity).toEqual(newQuantity);
}); });
}); });

View File

@ -1,14 +0,0 @@
create table `vn`.`invoiceOut_queue`
(
invoiceFk int(10) unsigned not null,
queued datetime default now() not null,
printed datetime null,
`status` VARCHAR(50) default '' null,
constraint invoiceOut_queue_pk
primary key (invoiceFk),
constraint invoiceOut_queue_invoiceOut_id_fk
foreign key (invoiceFk) references invoiceOut (id)
on update cascade on delete cascade
)
comment 'Queue for PDF invoicing';

View File

@ -3,7 +3,7 @@ CREATE TABLE `vn`.`clientUnpaid` (
`dated` date NOT NULL, `dated` date NOT NULL,
`amount` double DEFAULT 0, `amount` double DEFAULT 0,
PRIMARY KEY (`clientFk`), PRIMARY KEY (`clientFk`),
CONSTRAINT `clientUnpaid_clientFk` FOREIGN KEY (`clientFk`) REFERENCES `client` (`id`) ON UPDATE CASCADE CONSTRAINT `clientUnpaid_clientFk` FOREIGN KEY (`clientFk`) REFERENCES `vn`.`client` (`id`) ON UPDATE CASCADE
); );
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)

View File

@ -0,0 +1,8 @@
CREATE TABLE `vn`.`invoiceOut_queue` (
`invoiceFk` int(10) unsigned not null,
`queued` datetime default now() not null,
`printed` datetime null,
`status` VARCHAR(50) DEFAULT '' NULL,
CONSTRAINT `invoiceOut_queue_pk` PRIMARY KEY (`invoiceFk`),
CONSTRAINT `invoiceOut_queue_invoiceOut_id_fk` FOREIGN KEY (`invoiceFk`) REFERENCES `vn`.`invoiceOut` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
) comment 'Queue for PDF invoicing';

View File

@ -1641,7 +1641,9 @@ INSERT INTO `hedera`.`visit`(`id`, `firstAgentFk`)
(6, NULL), (6, NULL),
(7, NULL), (7, NULL),
(8, NULL), (8, NULL),
(9, NULL); (9, NULL),
(10, NULL),
(11, NULL);
INSERT INTO `hedera`.`visitAgent`(`id`, `visitFk`) INSERT INTO `hedera`.`visitAgent`(`id`, `visitFk`)
VALUES VALUES
@ -1653,7 +1655,9 @@ INSERT INTO `hedera`.`visitAgent`(`id`, `visitFk`)
(6, 6), (6, 6),
(7, 7), (7, 7),
(8, 8), (8, 8),
(9, 9); (9, 9),
(10, 10),
(11, 11);
INSERT INTO `hedera`.`visitAccess`(`id`, `agentFk`, `stamp`) INSERT INTO `hedera`.`visitAccess`(`id`, `agentFk`, `stamp`)
VALUES VALUES
@ -1665,7 +1669,9 @@ INSERT INTO `hedera`.`visitAccess`(`id`, `agentFk`, `stamp`)
(6, 6, CURDATE()), (6, 6, CURDATE()),
(7, 7, CURDATE()), (7, 7, CURDATE()),
(8, 8, CURDATE()), (8, 8, CURDATE()),
(9, 9, CURDATE()); (9, 9, CURDATE()),
(10, 10, CURDATE()),
(11, 11, CURDATE());
INSERT INTO `hedera`.`visitUser`(`id`, `accessFk`, `userFk`, `stamp`) INSERT INTO `hedera`.`visitUser`(`id`, `accessFk`, `userFk`, `stamp`)
VALUES VALUES
@ -1677,7 +1683,9 @@ INSERT INTO `hedera`.`visitUser`(`id`, `accessFk`, `userFk`, `stamp`)
(6, 6, 1102, CURDATE()), (6, 6, 1102, CURDATE()),
(7, 7, 1103, CURDATE()), (7, 7, 1103, CURDATE()),
(8, 8, 1103, CURDATE()), (8, 8, 1103, CURDATE()),
(9, 9, 1103, CURDATE()); (9, 9, 1103, CURDATE()),
(10, 10, 1102, DATE_SUB(CURDATE(), INTERVAL 1 DAY)),
(11, 11, 1103, DATE_SUB(CURDATE(), INTERVAL 1 DAY));
INSERT INTO `hedera`.`userSession`(`created`, `lastUpdate`, `ssid`, `data`, `userVisitFk`) INSERT INTO `hedera`.`userSession`(`created`, `lastUpdate`, `ssid`, `data`, `userVisitFk`)
VALUES VALUES

View File

@ -101,6 +101,47 @@ export default {
email: 'vn-user-mail-forwarding vn-textfield[ng-model="data.forwardTo"]', email: 'vn-user-mail-forwarding vn-textfield[ng-model="data.forwardTo"]',
save: 'vn-user-mail-forwarding vn-submit' save: 'vn-user-mail-forwarding vn-submit'
}, },
accountAcl: {
addAcl: 'vn-acl-index button vn-icon[icon="add"]',
thirdAcl: 'vn-acl-index vn-list> a:nth-child(3)',
deleteThirdAcl: 'vn-acl-index vn-list > a:nth-child(3) > vn-item-section > vn-icon-button[icon="delete"]',
role: 'vn-acl-create vn-autocomplete[ng-model="$ctrl.acl.principalId"]',
model: 'vn-acl-create vn-autocomplete[ng-model="$ctrl.acl.model"]',
property: 'vn-acl-create vn-autocomplete[ng-model="$ctrl.acl.property"]',
accessType: 'vn-acl-create vn-autocomplete[ng-model="$ctrl.acl.accessType"]',
permission: 'vn-acl-create vn-autocomplete[ng-model="$ctrl.acl.permission"]',
save: 'vn-acl-create vn-submit'
},
accountConnections: {
firstConnection: 'vn-connections vn-list > a:nth-child(1)',
deleteFirstConnection: 'vn-connections vn-list > a:nth-child(1) > vn-item-section > vn-icon-button[icon="exit_to_app"]'
},
accountAccounts: {
syncRoles: 'vn-account-accounts vn-button[label="Synchronize roles"]',
syncUser: 'vn-account-accounts vn-button[label="Synchronize user"]',
syncAll: 'vn-account-accounts vn-button[label="Synchronize all"]',
syncUserName: 'vn-textfield[ng-model="$ctrl.syncUser"]',
syncUserPassword: 'vn-textfield[ng-model="$ctrl.syncPassword"]',
buttonAccept: 'button[response="accept"]'
},
accountLdap: {
checkEnable: 'vn-account-ldap vn-check[ng-model="watcher.hasData"]',
server: 'vn-account-ldap vn-textfield[ng-model="$ctrl.config.server"]',
rdn: 'vn-account-ldap vn-textfield[ng-model="$ctrl.config.rdn"]',
password: 'vn-account-ldap vn-textfield[ng-model="$ctrl.config.password"]',
userDn: 'vn-account-ldap vn-textfield[ng-model="$ctrl.config.userDn"]',
groupDn: 'vn-account-ldap vn-textfield[ng-model="$ctrl.config.groupDn"]',
save: 'vn-account-ldap vn-submit'
},
accountSamba: {
checkEnable: 'vn-account-samba vn-check[ng-model="watcher.hasData"]',
adDomain: 'vn-account-samba vn-textfield[ng-model="$ctrl.config.adDomain"]',
adController: 'vn-account-samba vn-textfield[ng-model="$ctrl.config.adController"]',
adUser: 'vn-account-samba vn-textfield[ng-model="$ctrl.config.adUser"]',
adPassword: 'vn-account-samba vn-textfield[ng-model="$ctrl.config.adPassword"]',
verifyCert: 'vn-account-samba vn-check[ng-model="$ctrl.config.verifyCert"]',
save: 'vn-account-samba vn-submit'
},
clientsIndex: { clientsIndex: {
createClientButton: `vn-float-button` createClientButton: `vn-float-button`
}, },

View File

@ -0,0 +1,60 @@
import selectors from '../../helpers/selectors.js';
import getBrowser from '../../helpers/puppeteer';
describe('Account ACL path', () => {
let browser;
let page;
beforeAll(async() => {
browser = await getBrowser();
page = browser.page;
await page.loginAndModule('developer', 'account');
await page.accessToSection('account.acl');
});
afterAll(async() => {
await browser.close();
});
it('should go to create new acl', async() => {
await page.waitToClick(selectors.accountAcl.addAcl);
await page.waitForState('account.acl.create');
});
it('should create new acl', async() => {
await page.autocompleteSearch(selectors.accountAcl.role, 'sysadmin');
await page.autocompleteSearch(selectors.accountAcl.model, 'UserAccount');
await page.autocompleteSearch(selectors.accountAcl.accessType, '*');
await page.autocompleteSearch(selectors.accountAcl.permission, 'ALLOW');
await page.waitToClick(selectors.accountAcl.save);
const message = await page.waitForSnackbar();
expect(message.text).toContain('Data saved!');
});
it('should navigate to edit', async() => {
await page.doSearch();
await page.waitToClick(selectors.accountAcl.thirdAcl);
await page.waitForState('account.acl.edit');
});
it('should edit the third acl', async() => {
await page.autocompleteSearch(selectors.accountAcl.model, 'Supplier');
await page.autocompleteSearch(selectors.accountAcl.accessType, 'READ');
await page.waitToClick(selectors.accountAcl.save);
const message = await page.waitForSnackbar();
expect(message.text).toContain('Data saved!');
});
it('should delete the third result', async() => {
const result = await page.waitToGetProperty(selectors.accountAcl.thirdAcl, 'innerText');
await page.waitToClick(selectors.accountAcl.deleteThirdAcl);
await page.waitToClick(selectors.globalItems.acceptButton);
const message = await page.waitForSnackbar();
const newResult = await page.waitToGetProperty(selectors.accountAcl.thirdAcl, 'innerText');
expect(message.text).toContain('ACL removed');
expect(result).not.toEqual(newResult);
});
});

View File

@ -0,0 +1,33 @@
import selectors from '../../helpers/selectors.js';
import getBrowser from '../../helpers/puppeteer';
describe('Account Connections path', () => {
let browser;
let page;
const account = 'sysadmin';
beforeAll(async() => {
browser = await getBrowser();
page = browser.page;
await page.loginAndModule(account, 'account');
await page.accessToSection('account.connections');
});
afterAll(async() => {
await browser.close();
});
it('should check this is the last connection', async() => {
const firstResult = await page.waitToGetProperty(selectors.accountConnections.firstConnection, 'innerText');
expect(firstResult).toContain(account);
});
it('should kill this connection and then get redirected to the login page', async() => {
await page.waitToClick(selectors.accountConnections.deleteFirstConnection);
await page.waitToClick(selectors.globalItems.acceptButton);
const message = await page.waitForSnackbar();
expect(message.text).toContain('Your session has expired, please login again');
});
});

View File

@ -0,0 +1,49 @@
import selectors from '../../helpers/selectors.js';
import getBrowser from '../../helpers/puppeteer';
describe('Account Accounts path', () => {
let browser;
let page;
beforeAll(async() => {
browser = await getBrowser();
page = browser.page;
await page.loginAndModule('sysadmin', 'account');
await page.accessToSection('account.accounts');
});
afterAll(async() => {
await browser.close();
});
it('should sync roles', async() => {
await page.waitToClick(selectors.accountAccounts.syncRoles);
const message = await page.waitForSnackbar();
expect(message.text).toContain('Roles synchronized!');
});
it('should sync user', async() => {
await page.waitToClick(selectors.accountAccounts.syncUser);
await page.write(selectors.accountAccounts.syncUserName, 'sysadmin');
await page.write(selectors.accountAccounts.syncUserPassword, 'nightmare');
await page.waitToClick(selectors.accountAccounts.buttonAccept);
const message = await page.waitForSnackbar();
expect(message.text).toContain('User synchronized!');
});
it('should relogin', async() => {
await page.loginAndModule('sysadmin', 'account');
await page.accessToSection('account.accounts');
});
it('should sync all', async() => {
await page.waitToClick(selectors.accountAccounts.syncAll);
const message = await page.waitForSnackbar();
expect(message.text).toContain('Synchronizing in the background');
});
});

View File

@ -0,0 +1,32 @@
import selectors from '../../helpers/selectors.js';
import getBrowser from '../../helpers/puppeteer';
describe('Account LDAP path', () => {
let browser;
let page;
beforeAll(async() => {
browser = await getBrowser();
page = browser.page;
await page.loginAndModule('sysadmin', 'account');
await page.accessToSection('account.ldap');
});
afterAll(async() => {
await browser.close();
});
it('should set data and save', async() => {
await page.waitToClick(selectors.accountLdap.checkEnable);
await page.write(selectors.accountLdap.server, '1234');
await page.write(selectors.accountLdap.rdn, '1234');
await page.write(selectors.accountLdap.password, 'nightmare');
await page.write(selectors.accountLdap.userDn, 'sysadmin');
await page.write(selectors.accountLdap.groupDn, '1234');
await page.waitToClick(selectors.accountLdap.save);
const message = await page.waitForSnackbar();
expect(message.text).toContain('Data saved!');
});
});

View File

@ -0,0 +1,32 @@
import selectors from '../../helpers/selectors.js';
import getBrowser from '../../helpers/puppeteer';
describe('Account Samba path', () => {
let browser;
let page;
beforeAll(async() => {
browser = await getBrowser();
page = browser.page;
await page.loginAndModule('sysadmin', 'account');
await page.accessToSection('account.samba');
});
afterAll(async() => {
await browser.close();
});
it('should set data and save', async() => {
await page.waitToClick(selectors.accountSamba.checkEnable);
await page.write(selectors.accountSamba.adDomain, '1234');
await page.write(selectors.accountSamba.adController, '1234');
await page.write(selectors.accountSamba.adUser, 'nightmare');
await page.write(selectors.accountSamba.adPassword, 'sysadmin');
await page.waitToClick(selectors.accountSamba.verifyCert);
await page.waitToClick(selectors.accountSamba.save);
const message = await page.waitForSnackbar();
expect(message.text).toContain('Data saved!');
});
});

View File

@ -146,16 +146,17 @@ export default class MultiCheck extends FormInput {
if (!this.model || !this.model.data) return; if (!this.model || !this.model.data) return;
const data = this.model.data; const data = this.model.data;
const modelParams = this.model.userParams;
const params = { const params = {
filter: { filter: {
modelParams: modelParams,
limit: null limit: null
} }
}; };
if (this.model.userFilter)
Object.assign(params.filter, this.model.userFilter);
if (this.model.userParams)
Object.assign(params, this.model.userParams);
this.rows = data.length; this.rows = data.length;
this.$http.get(this.model.url, {params}) this.$http.get(this.model.url, {params})
.then(res => { .then(res => {
this.allRowsCount = res.data.length; this.allRowsCount = res.data.length;

View File

@ -46,12 +46,14 @@
</div> </div>
</vn-horizontal> </vn-horizontal>
<div id="table"></div> <div id="table"></div>
<div ng-transclude="pagination">
<vn-pagination <vn-pagination
ng-if="$ctrl.model" ng-if="$ctrl.model"
model="$ctrl.model" model="$ctrl.model"
class="vn-pt-md"> class="vn-pt-md">
</vn-pagination> </vn-pagination>
</div> </div>
</div>
<vn-confirm <vn-confirm
vn-id="deleteConfirmation" vn-id="deleteConfirmation"

View File

@ -497,7 +497,8 @@ ngModule.vnComponent('smartTable', {
controller: SmartTable, controller: SmartTable,
transclude: { transclude: {
table: '?slotTable', table: '?slotTable',
actions: '?slotActions' actions: '?slotActions',
pagination: '?slotPagination'
}, },
bindings: { bindings: {
model: '<?', model: '<?',

View File

@ -98,9 +98,6 @@ module.exports = Self => {
Self.latestBuysFilter = async(ctx, filter, options) => { Self.latestBuysFilter = async(ctx, filter, options) => {
const myOptions = {}; const myOptions = {};
if (filter && filter.modelParams)
ctx.args = filter.modelParams;
if (typeof options == 'object') if (typeof options == 'object')
Object.assign(myOptions, options); Object.assign(myOptions, options);

View File

@ -148,12 +148,12 @@
</td> </td>
<td number> <td number>
<vn-chip class="transparent" translate-attr="buy.groupingMode == 2 ? {title: 'Minimun amount'} : {title: 'Packing'}" ng-class="{'message': buy.groupingMode == 2}"> <vn-chip class="transparent" translate-attr="buy.groupingMode == 2 ? {title: 'Minimun amount'} : {title: 'Packing'}" ng-class="{'message': buy.groupingMode == 2}">
<span translate>{{::buy.packing | dashIfEmpty}}</span> <span>{{::buy.packing | dashIfEmpty}}</span>
</vn-chip> </vn-chip>
</td> </td>
<td number> <td number>
<vn-chip class="transparent" translate-attr="buy.groupingMode == 1 ? {title: 'Minimun amount'} : {title: 'Grouping'}" ng-class="{'message': buy.groupingMode == 1}"> <vn-chip class="transparent" translate-attr="buy.groupingMode == 1 ? {title: 'Minimun amount'} : {title: 'Grouping'}" ng-class="{'message': buy.groupingMode == 1}">
<span translate>{{::buy.grouping | dashIfEmpty}}</span> <span>{{::buy.grouping | dashIfEmpty}}</span>
</vn-chip> </vn-chip>
</td> </td>
<td number>{{::buy.quantity}}</td> <td number>{{::buy.quantity}}</td>

View File

@ -159,8 +159,22 @@ export default class Controller extends Section {
lines: rowsToEdit lines: rowsToEdit
}; };
if (this.checkedDummyCount && this.checkedDummyCount > 0) if (this.checkedDummyCount && this.checkedDummyCount > 0) {
data.filter = this.$.model.userParams; const params = {};
if (this.$.model.userParams) {
const userParams = this.$.model.userParams;
for (let param in userParams) {
let newParam = this.exprBuilder(param, userParams[param]);
if (!newParam)
newParam = {[param]: userParams[param]};
Object.assign(params, newParam);
}
}
if (this.$.model.userFilter)
Object.assign(params, this.$.model.userFilter.where);
data.filter = params;
}
return this.$http.post('Buys/editLatestBuys', data) return this.$http.post('Buys/editLatestBuys', data)
.then(() => { .then(() => {

View File

@ -43,11 +43,9 @@ module.exports = Self => {
TIME(v.stamp) AS hour, TIME(v.stamp) AS hour,
DATE(v.stamp) AS dated, DATE(v.stamp) AS dated,
wtc.workerFk wtc.workerFk
FROM hedera.userSession s FROM hedera.visitUser v
JOIN hedera.visitUser v ON v.id = s.userVisitFk
JOIN client c ON c.id = v.userFk JOIN client c ON c.id = v.userFk
LEFT JOIN account.user u ON c.salesPersonFk = u.id JOIN account.user u ON c.salesPersonFk = u.id
LEFT JOIN worker w ON c.salesPersonFk = w.id
LEFT JOIN sharingCart sc ON sc.workerFk = c.salesPersonFk LEFT JOIN sharingCart sc ON sc.workerFk = c.salesPersonFk
AND CURDATE() BETWEEN sc.started AND sc.ended AND CURDATE() BETWEEN sc.started AND sc.ended
LEFT JOIN workerTeamCollegues wtc LEFT JOIN workerTeamCollegues wtc
@ -58,7 +56,9 @@ module.exports = Self => {
const where = filter.where; const where = filter.where;
where['wtc.workerFk'] = userId; where['wtc.workerFk'] = userId;
stmt.merge(conn.makeSuffix(filter)); stmt.merge(conn.makeWhere(filter.where));
stmt.merge(`GROUP BY clientFk, v.stamp`);
stmt.merge(conn.makePagination(filter));
return conn.executeStmt(stmt, myOptions); return conn.executeStmt(stmt, myOptions);
}; };

View File

@ -6,12 +6,49 @@ describe('SalesMonitor clientsFilter()', () => {
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
const ctx = {req: {accessToken: {userId: 18}}, args: {}}; const ctx = {req: {accessToken: {userId: 18}}, args: {}};
const filter = {order: 'dated DESC'};
const from = new Date();
const to = new Date();
from.setHours(0, 0, 0, 0);
to.setHours(23, 59, 59, 59);
const filter = {
where: {
'v.stamp': {between: [from, to]}
}
};
const result = await models.SalesMonitor.clientsFilter(ctx, filter, options); const result = await models.SalesMonitor.clientsFilter(ctx, filter, options);
expect(result.length).toEqual(9); expect(result.length).toEqual(3);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return the clients web activity filtered', async() => {
const tx = await models.SalesMonitor.beginTransaction({});
try {
const options = {transaction: tx};
const ctx = {req: {accessToken: {userId: 18}}, args: {}};
const yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);
const today = new Date();
yesterday.setHours(0, 0, 0, 0);
today.setHours(23, 59, 59, 59);
const filter = {
where: {
'v.stamp': {between: [yesterday, today]}
}
};
const result = await models.SalesMonitor.clientsFilter(ctx, filter, options);
expect(result.length).toEqual(5);
await tx.rollback(); await tx.rollback();
} catch (e) { } catch (e) {

View File

@ -88,8 +88,16 @@
</td> </td>
</tr> </tr>
</tbody> </tbody>
<table> </table>
<slot-table> </slot-table>
<slot-pagination>
<vn-pagination
model="model"
class="vn-pt-xs"
scroll-selector="vn-monitor-sales-clients smart-table"
scroll-offset="100">
</vn-pagination>
</slot-pagination>
</smart-table> </smart-table>
</vn-card> </vn-card>
<vn-worker-descriptor-popover <vn-worker-descriptor-popover

View File

@ -38,6 +38,9 @@
}, },
"created": { "created": {
"type": "date" "type": "date"
},
"originalQuantity":{
"type": "number"
} }
}, },
"relations": { "relations": {

View File

@ -135,7 +135,8 @@ module.exports = Self => {
function formatDate(date) { function formatDate(date) {
let day = date.getDate(); let day = date.getDate();
if (day < 10) day = `0${day}`; if (day < 10) day = `0${day}`;
let month = date.getMonth();
let month = date.getMonth() + 1;
if (month < 10) month = `0${month}`; if (month < 10) month = `0${month}`;
let year = date.getFullYear(); let year = date.getFullYear();

View File

@ -87,7 +87,7 @@ module.exports = Self => {
function formatDate(date) { function formatDate(date) {
let day = date.getDate(); let day = date.getDate();
if (day < 10) day = `0${day}`; if (day < 10) day = `0${day}`;
let month = date.getMonth(); let month = date.getMonth() + 1;
if (month < 10) month = `0${month}`; if (month < 10) month = `0${month}`;
let year = date.getFullYear(); let year = date.getFullYear();

View File

@ -14,5 +14,6 @@ FROM route r
LEFT JOIN account.user u ON u.id = w.userFk LEFT JOIN account.user u ON u.id = w.userFk
LEFT JOIN agencyMode am ON am.id = r.agencyModeFk LEFT JOIN agencyMode am ON am.id = r.agencyModeFk
LEFT JOIN agency a ON a.id = am.agencyFk LEFT JOIN agency a ON a.id = am.agencyFk
LEFT JOIN supplier s ON s.id = a.supplierFk LEFT JOIN supplierAgencyTerm sa ON sa.agencyFk = a.id
LEFT JOIN supplier s ON s.id = sa.supplierFk
WHERE r.id IN(?) WHERE r.id IN(?)