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

This commit is contained in:
Vicent Llopis 2023-03-24 10:02:51 +00:00
commit dca760d4e4
50 changed files with 480 additions and 128 deletions

View File

@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [2312.01] - 2023-04-06
### Added
-
- (Monitor tickets) Muestra un icono al lado de la zona, si el ticket es frágil y se envía por agencia
### Changed
-

View File

@ -1,6 +1,21 @@
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('setSaleQuantity()', () => {
beforeAll(async() => {
const activeCtx = {
accessToken: {userId: 9},
http: {
req: {
headers: {origin: 'http://localhost'}
}
}
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
it('should change quantity sale', async() => {
const tx = await models.Ticket.beginTransaction({});

View File

@ -0,0 +1,14 @@
ALTER TABLE `vn`.`itemType` ADD isFragile tinyint(1) NULL;
ALTER TABLE `vn`.`itemType` MODIFY COLUMN isFragile tinyint(1) DEFAULT 0 NOT NULL;
UPDATE `vn`.`itemType`
SET isFragile = 1
WHERE code IN ('ZKA', 'ZKE');
UPDATE `vn`.`itemType`
SET isFragile = 1
WHERE id IN (SELECT it.id
FROM itemCategory ic
JOIN itemType it ON it.categoryFk = ic.id
WHERE ic.code = 'plant');

View File

@ -0,0 +1,47 @@
DROP PROCEDURE IF EXISTS `vn`.`ticket_getWarnings`;
DELIMITER $$
$$
CREATE PROCEDURE `vn`.`ticket_getWarnings`()
BEGIN
/**
* Calcula las adventencias para un conjunto de tickets.
* Agrupados por ticket
*
* @table tmp.sale_getWarnings(ticketFk) Identificadores de los tickets a calcular
* @return tmp.ticket_warnings
*/
DROP TEMPORARY TABLE IF EXISTS tmp.sale_warnings;
CREATE TEMPORARY TABLE tmp.sale_warnings (
ticketFk INT(11),
saleFk INT(11),
isFragile INTEGER(1) DEFAULT 0,
PRIMARY KEY (ticketFk, saleFk)
) ENGINE = MEMORY;
-- Frágil
INSERT INTO tmp.sale_warnings(ticketFk, saleFk, isFragile)
SELECT tt.ticketFk, s.id, TRUE
FROM tmp.sale_getWarnings tt
LEFT JOIN sale s ON s.ticketFk = tt.ticketFk
LEFT JOIN item i ON i.id = s.itemFk
LEFT JOIN itemType it ON it.id = i.typeFk
LEFT JOIN agencyMode am ON am.id = tt.agencyModeFk
LEFT JOIN deliveryMethod dm ON dm.id = am.deliveryMethodFk
WHERE dm.code IN ('AGENCY')
AND it.isFragile;
DROP TEMPORARY TABLE IF EXISTS tmp.ticket_warnings;
CREATE TEMPORARY TABLE tmp.ticket_warnings
(PRIMARY KEY (ticketFk))
ENGINE = MEMORY
SELECT
sw.ticketFk,
MAX(sw.isFragile) AS isFragile
FROM tmp.sale_warnings sw
GROUP BY sw.ticketFk;
DROP TEMPORARY TABLE
tmp.sale_warnings;
END$$
DELIMITER ;

View File

@ -501,7 +501,8 @@ INSERT INTO `vn`.`observationType`(`id`,`description`, `code`)
(3, 'Delivery', 'delivery'),
(4, 'SalesPerson', 'salesPerson'),
(5, 'Administrative', 'administrative'),
(6, 'Weight', 'weight');
(6, 'Weight', 'weight'),
(7, 'InvoiceOut', 'invoiceOut');
INSERT INTO `vn`.`addressObservation`(`id`,`addressFk`,`observationTypeFk`,`description`)
VALUES
@ -738,7 +739,9 @@ INSERT INTO `vn`.`ticketObservation`(`id`, `ticketFk`, `observationTypeFk`, `des
(9, 23, 5, 'care with the dog'),
(10, 23, 4, 'Reclama ticket: 8'),
(11, 24, 4, 'Reclama ticket: 7'),
(12, 11, 3, 'Delivery after 10am');
(12, 11, 3, 'Delivery after 10am'),
(13, 1, 7, 'observation of ticket one'),
(14, 2, 7, 'observation of ticket two');
-- FIX for state hours on local, inter_afterInsert
-- UPDATE vncontrol.inter SET odbc_date = DATE_ADD(util.VN_CURDATE(), INTERVAL -10 SECOND);
@ -838,14 +841,14 @@ INSERT INTO `vn`.`temperature`(`code`, `name`, `description`)
('warm', 'Warm', 'Warm'),
('cool', 'Cool', 'Cool');
INSERT INTO `vn`.`itemType`(`id`, `code`, `name`, `categoryFk`, `life`, `workerFk`, `isPackaging`, `temperatureFk`)
INSERT INTO `vn`.`itemType`(`id`, `code`, `name`, `categoryFk`, `life`, `workerFk`, `isPackaging`, `temperatureFk`, `isFragile`)
VALUES
(1, 'CRI', 'Crisantemo', 2, 31, 35, 0, 'cool'),
(2, 'ITG', 'Anthurium', 1, 31, 35, 0, 'cool'),
(3, 'WPN', 'Paniculata', 2, 31, 35, 0, 'cool'),
(4, 'PRT', 'Delivery ports', 3, NULL, 35, 1, 'warm'),
(5, 'CON', 'Container', 3, NULL, 35, 1, 'warm'),
(6, 'ALS', 'Alstroemeria', 1, 31, 16, 0, 'warm');
(1, 'CRI', 'Crisantemo', 2, 31, 35, 0, 'cool', 0),
(2, 'ITG', 'Anthurium', 1, 31, 35, 0, 'cool', 1),
(3, 'WPN', 'Paniculata', 2, 31, 35, 0, 'cool', 0),
(4, 'PRT', 'Delivery ports', 3, NULL, 35, 1, 'warm', 0),
(5, 'CON', 'Container', 3, NULL, 35, 1, 'warm', 0),
(6, 'ALS', 'Alstroemeria', 1, 31, 16, 0, 'warm', 1);
INSERT INTO `vn`.`ink`(`id`, `name`, `picture`, `showOrder`, `hex`)
VALUES

View File

@ -524,7 +524,6 @@ export default {
},
itemLog: {
anyLineCreated: 'vn-item-log > vn-log vn-tbody > vn-tr',
fifthLineCreatedProperty: 'vn-item-log > vn-log vn-tbody > vn-tr:nth-child(5) table tr:nth-child(4) td.after',
},
ticketSummary: {
header: 'vn-ticket-summary > vn-card > h5',
@ -1040,7 +1039,6 @@ export default {
boss: 'vn-worker-create vn-autocomplete[ng-model="$ctrl.worker.bossFk"]',
role: 'vn-worker-create vn-autocomplete[ng-model="$ctrl.worker.roleFk"]',
iban: 'vn-worker-create vn-textfield[ng-model="$ctrl.worker.iban"]',
switft: 'vn-worker-create vn-autocomplete[ng-model="$ctrl.worker.bankEntityFk"]',
createButton: 'vn-worker-create vn-submit[label="Create"]',
},
workerPda: {

View File

@ -27,7 +27,7 @@ describe('Worker time control path', () => {
date.setMonth(date.getMonth() + 1);
let month = date.toLocaleString('default', {month: 'long'});
await page.click(selectors.workerTimeControl.nextMonthButton);
await page.waitToClick(selectors.workerTimeControl.nextMonthButton);
let result = await page.getProperty(selectors.workerTimeControl.monthName, 'innerText');
expect(result).toContain(month);
@ -36,7 +36,7 @@ describe('Worker time control path', () => {
date.setDate(1);
month = date.toLocaleString('default', {month: 'long'});
await page.click(selectors.workerTimeControl.previousMonthButton);
await page.waitToClick(selectors.workerTimeControl.previousMonthButton);
result = await page.getProperty(selectors.workerTimeControl.monthName, 'innerText');
expect(result).toContain(month);
@ -49,7 +49,7 @@ describe('Worker time control path', () => {
await page.loginAndModule('salesBoss', 'worker');
await page.goto(`http://localhost:5000/#!/worker/${hankPymId}/time-control?timestamp=${timestamp}`);
await page.click(selectors.workerTimeControl.secondWeekDay);
await page.waitToClick(selectors.workerTimeControl.secondWeekDay);
result = await page.getProperty(selectors.workerTimeControl.monthName, 'innerText');

View File

@ -26,7 +26,6 @@ describe('Worker create path', () => {
await page.write(selectors.workerCreate.street, 'S/ Doomstadt');
await page.write(selectors.workerCreate.email, 'doctorDoom@marvel.com');
await page.write(selectors.workerCreate.iban, 'ES9121000418450200051332');
await page.autocompleteSearch(selectors.workerCreate.switft, 'BBKKESMMMMM');
// should check for autocompleted worker code and worker user name
const workerCode = await page

View File

@ -48,14 +48,14 @@ describe('Item log path', () => {
await page.accessToSection('item.card.log');
});
it(`should confirm the log is showing 5 entries`, async() => {
it(`should confirm the log is showing 4 entries`, async() => {
await page.waitForSelector(selectors.itemLog.anyLineCreated);
const anyLineCreatedCount = await page.countElement(selectors.itemLog.anyLineCreated);
expect(anyLineCreatedCount).toEqual(5);
expect(anyLineCreatedCount).toEqual(4);
});
it(`should confirm the log is showing the intrastat for the created item`, async() => {
xit(`should confirm the log is showing the intrastat for the created item`, async() => {
const fifthLineCreatedProperty = await page
.waitToGetProperty(selectors.itemLog.fifthLineCreatedProperty, 'innerText');

View File

@ -197,6 +197,7 @@ describe('Ticket Edit sale path', () => {
});
it('should check in the history that logs has been added', async() => {
pending('https://redmine.verdnatura.es/issues/5455');
await page.reload({waitUntil: ['networkidle0', 'domcontentloaded']});
await page.waitToClick(selectors.ticketSales.firstSaleHistoryButton);
await page.waitForSelector(selectors.ticketSales.firstSaleHistory);

View File

@ -54,7 +54,7 @@ describe('Ticket Future path', () => {
it('should search with the origin IPT', async() => {
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
await page.autocompleteSearch(selectors.ticketFuture.ipt, 'Horizontal');
await page.autocompleteSearch(selectors.ticketFuture.ipt, 'H');
await page.waitToClick(selectors.ticketFuture.submit);
expect(httpRequest).toContain('ipt=H');
@ -65,7 +65,7 @@ describe('Ticket Future path', () => {
await page.clearInput(selectors.ticketFuture.ipt);
await page.autocompleteSearch(selectors.ticketFuture.futureIpt, 'Horizontal');
await page.autocompleteSearch(selectors.ticketFuture.futureIpt, 'H');
await page.waitToClick(selectors.ticketFuture.submit);
expect(httpRequest).toContain('futureIpt=H');
@ -108,7 +108,7 @@ describe('Ticket Future path', () => {
it('should search in smart-table with an IPT Destination', async() => {
await page.waitToClick(selectors.ticketFuture.tableButtonSearch);
await page.autocompleteSearch(selectors.ticketFuture.tableFutureIpt, 'Horizontal');
await page.autocompleteSearch(selectors.ticketFuture.tableFutureIpt, 'H');
expect(httpRequest).toContain('futureIpt');
await page.waitToClick(selectors.ticketFuture.tableButtonSearch);

View File

@ -54,7 +54,7 @@ describe('Ticket Advance path', () => {
it('should search with the origin IPT', async() => {
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
await page.autocompleteSearch(selectors.ticketAdvance.futureIpt, 'Horizontal');
await page.autocompleteSearch(selectors.ticketAdvance.futureIpt, 'H');
await page.waitToClick(selectors.ticketAdvance.submit);
expect(httpRequest).toContain('futureIpt=H');
@ -66,7 +66,7 @@ describe('Ticket Advance path', () => {
it('should search with the destination IPT', async() => {
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
await page.autocompleteSearch(selectors.ticketAdvance.ipt, 'Horizontal');
await page.autocompleteSearch(selectors.ticketAdvance.ipt, 'H');
await page.waitToClick(selectors.ticketAdvance.submit);
expect(httpRequest).toContain('ipt=H');
@ -78,7 +78,7 @@ describe('Ticket Advance path', () => {
it('should search in smart-table with an IPT Origin', async() => {
await page.waitToClick(selectors.ticketAdvance.tableButtonSearch);
await page.autocompleteSearch(selectors.ticketAdvance.tableFutureIpt, 'Vertical');
await page.autocompleteSearch(selectors.ticketAdvance.tableFutureIpt, 'V');
expect(httpRequest).toContain('futureIpt');
@ -89,7 +89,7 @@ describe('Ticket Advance path', () => {
it('should search in smart-table with an IPT Destination', async() => {
await page.waitToClick(selectors.ticketAdvance.tableButtonSearch);
await page.autocompleteSearch(selectors.ticketAdvance.tableIpt, 'Vertical');
await page.autocompleteSearch(selectors.ticketAdvance.tableIpt, 'V');
expect(httpRequest).toContain('ipt');

View File

@ -89,11 +89,13 @@ describe('Travel basic data path', () => {
});
it('should navigate to the travel logs', async() => {
pending('https://redmine.verdnatura.es/issues/5455');
await page.accessToSection('travel.card.log');
await page.waitForState('travel.card.log');
});
it('should check the 1st log contains details from the changes made', async() => {
pending('https://redmine.verdnatura.es/issues/5455');
const result = await page.waitToGetProperty(selectors.travelLog.firstLogFirstTD, 'innerText');
expect(result).toContain('new reference!');

View File

@ -1,7 +1,7 @@
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
const buildFilter = require('vn-loopback/util/filter').buildFilter;
const {mergeFilters, mergeWhere} = require('vn-loopback/util/filter');
const { mergeFilters, mergeWhere } = require('vn-loopback/util/filter');
module.exports = Self => {
Self.remoteMethodCtx('logs', {
@ -12,27 +12,27 @@ module.exports = Self => {
arg: 'id',
type: 'Number',
description: 'The claim id',
http: {source: 'path'}
http: { source: 'path' }
},
{
arg: 'filter',
type: 'object',
http: {source: 'query'}
http: { source: 'query' }
},
{
arg: 'search',
type: 'string',
http: {source: 'query'}
http: { source: 'query' }
},
{
arg: 'userFk',
type: 'number',
http: {source: 'query'}
http: { source: 'query' }
},
{
arg: 'created',
type: 'date',
http: {source: 'query'}
http: { source: 'query' }
},
],
returns: {
@ -45,7 +45,7 @@ module.exports = Self => {
}
});
Self.logs = async(ctx, id, filter, options) => {
Self.logs = async (ctx, id, filter, options) => {
const conn = Self.dataSource.connector;
const args = ctx.args;
const myOptions = {};
@ -59,22 +59,22 @@ module.exports = Self => {
case 'search':
return {
or: [
{changedModel: {like: `%${value}%`}},
{oldInstance: {like: `%${value}%`}}
{ changedModel: { like: `%${value}%` } },
{ oldInstance: { like: `%${value}%` } }
]
};
case 'userFk':
return {'cl.userFk': value};
return { 'cl.userFk': value };
case 'created':
value.setHours(0, 0, 0, 0);
to = new Date(value);
to.setHours(23, 59, 59, 999);
return {creationDate: {between: [value, to]}};
return { creationDate: { between: [value, to] } };
}
});
where = mergeWhere(where, {['cl.originFk']: id});
filter = mergeFilters(args.filter, {where});
where = mergeWhere(where, { ['cl.originFk']: id });
filter = mergeFilters(args.filter, { where });
const stmts = [];
@ -102,8 +102,8 @@ module.exports = Self => {
const logs = [];
for (const row of result) {
const changes = [];
const oldInstance = JSON.parse(row.oldInstance);
const newInstance = JSON.parse(row.newInstance);
const oldInstance = JSON.parse(row.oldInstance) || {};
const newInstance = JSON.parse(row.newInstance) || {};
const mergedProperties = [...Object.keys(oldInstance), ...Object.keys(newInstance)];
const properties = new Set(mergedProperties);
for (const property of properties) {

View File

@ -1,4 +1,5 @@
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('claim regularizeClaim()', () => {
const userId = 18;
@ -39,6 +40,20 @@ describe('claim regularizeClaim()', () => {
return await models.ClaimEnd.create(claimEnds, options);
}
beforeAll(async() => {
const activeCtx = {
accessToken: {userId: 9},
http: {
req: {
headers: {origin: 'http://localhost'}
}
}
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
it('should send a chat message with value "Trash" and then change claim state to resolved', async() => {
const tx = await models.Claim.beginTransaction({});

View File

@ -82,6 +82,11 @@
"type": "hasMany",
"model": "ClaimDms",
"foreignKey": "claimFk"
},
"lines": {
"type": "hasMany",
"model": "ClaimBeginning",
"foreignKey": "claimFk"
}
}
}

View File

@ -151,7 +151,7 @@ class Controller extends Section {
isClaimEditable() {
if (!this.claim) return;
this.$http.get(`ClaimStates/${this.claim.id}/isEditable`).then(res => {
this.$http.get(`ClaimStates/${this.claim.claimStateFk}/isEditable`).then(res => {
this.isRewritable = res.data;
});
}

View File

@ -22,7 +22,8 @@ describe('claim', () => {
controller = $componentController('vnClaimDetail', {$element, $scope});
controller.claim = {
ticketFk: 1,
id: 2}
id: 2,
claimStateFk: 2}
;
controller.salesToClaim = [{saleFk: 1}, {saleFk: 2}];
controller.salesClaimed = [{id: 1, sale: {}}];

View File

@ -1,6 +1,22 @@
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('Buy editLatestsBuys()', () => {
beforeAll(async() => {
const activeCtx = {
accessToken: {userId: 9},
http: {
req: {
headers: {origin: 'http://localhost'}
}
}
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
it('should change the value of a given column for the selected buys', async() => {
const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};

View File

@ -3,7 +3,8 @@
"base": "Loggable",
"log": {
"model": "EntryLog",
"relation": "entry"
"relation": "entry",
"grabUser": true
},
"options": {
"mysql": {

View File

@ -2,7 +2,8 @@
"name": "Entry",
"base": "Loggable",
"log": {
"model":"EntryLog"
"model":"EntryLog",
"grabUser": true
},
"options": {
"mysql": {

View File

@ -1,4 +1,5 @@
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('upsertFixedPrice()', () => {
const now = Date.vnNew();
@ -7,6 +8,17 @@ describe('upsertFixedPrice()', () => {
beforeAll(async() => {
originalFixedPrice = await models.FixedPrice.findById(fixedPriceId);
const activeCtx = {
accessToken: {userId: 9},
http: {
req: {
headers: {origin: 'http://localhost'}
}
}
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
it(`should toggle the hasMinPrice boolean if there's a minPrice and update the rest of the data`, async() => {

View File

@ -1,7 +1,21 @@
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('item clone()', () => {
let nextItemId;
beforeAll(async() => {
const activeCtx = {
accessToken: {userId: 9},
http: {
req: {
headers: {origin: 'http://localhost'}
}
}
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
beforeEach(async() => {
let query = `SELECT i1.id + 1 as id FROM vn.item i1

View File

@ -1,6 +1,21 @@
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('item new()', () => {
beforeAll(async() => {
const activeCtx = {
accessToken: {userId: 9},
http: {
req: {
headers: {origin: 'http://localhost'}
}
}
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
it('should create a new item, adding the name as a tag', async() => {
const tx = await models.Item.beginTransaction({});
const options = {transaction: tx};

View File

@ -1,6 +1,21 @@
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('regularize()', () => {
beforeAll(async() => {
const activeCtx = {
accessToken: {userId: 18},
http: {
req: {
headers: {origin: 'http://localhost'}
}
}
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
it('should create a new ticket and add a line', async() => {
const tx = await models.Item.beginTransaction({});
const options = {transaction: tx};

View File

@ -3,7 +3,8 @@
"base": "Loggable",
"log": {
"model": "ItemLog",
"showField": "id"
"showField": "id",
"grabUser": true
},
"options": {
"mysql": {

View File

@ -295,11 +295,26 @@ module.exports = Self => {
risk = t.debt + t.credit, totalProblems = totalProblems + 1
`);
stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.sale_getWarnings');
stmt = new ParameterizedSQL(`
SELECT t.*, tp.*,
((tp.risk) + cc.riskTolerance < 0) AS hasHighRisk
CREATE TEMPORARY TABLE tmp.sale_getWarnings
(INDEX (ticketFk, agencyModeFk))
ENGINE = MEMORY
SELECT f.id ticketFk, f.agencyModeFk
FROM tmp.filter f`);
stmts.push(stmt);
stmts.push('CALL ticket_getWarnings()');
stmt = new ParameterizedSQL(`
SELECT t.*,
tp.*,
((tp.risk) + cc.riskTolerance < 0) AS hasHighRisk,
tw.*
FROM tmp.tickets t
LEFT JOIN tmp.ticket_problems tp ON tp.ticketFk = t.id
LEFT JOIN tmp.ticket_warnings tw ON tw.ticketFk = t.id
JOIN clientConfig cc`);
const hasProblems = args.problems;
@ -387,6 +402,8 @@ module.exports = Self => {
tmp.filter,
tmp.ticket_problems,
tmp.sale_getProblems,
tmp.sale_getWarnings,
tmp.ticket_warnings,
tmp.risk`);
const sql = ParameterizedSQL.join(stmts, ';');

View File

@ -13,3 +13,4 @@ Practical: Práctica
Preparation: Preparación
Auto-refresh: Auto-refresco
Toggle auto-refresh every 2 minutes: Conmuta el refresco automático cada 2 minutos
Is fragile: Es frágil

View File

@ -68,6 +68,7 @@
<th field="stateFk">
<span translate>State</span>
</th>
<th field="isFragile"></th>
<th field="zoneFk">
<span translate>Zone</span>
</th>
@ -175,6 +176,14 @@
{{ticket.state}}
</span>
</td>
<td number>
<vn-icon
ng-show="ticket.isFragile"
translate-attr="{title: 'Is fragile'}"
class="bright"
icon="local_bar">
</vn-icon>
</td>
<td name="zone">
<span
title="{{ticket.zoneName}}"

View File

@ -1,6 +1,22 @@
const app = require('vn-loopback/server/server');
const LoopBackContext = require('loopback-context');
describe('route clone()', () => {
beforeAll(async() => {
const activeCtx = {
accessToken: {userId: 9},
http: {
req: {
headers: {origin: 'http://localhost'}
}
}
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
const createdDate = Date.vnNew();
it('should throw an error if the amount of ids pased to the clone function do no match the database', async() => {
const ids = [996, 997, 998, 999];

View File

@ -1,6 +1,20 @@
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('route updateWorkCenter()', () => {
beforeAll(async() => {
const activeCtx = {
accessToken: {userId: 9},
http: {
req: {
headers: {origin: 'http://localhost'}
}
}
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
const routeId = 1;
it('should set the commission work center if the worker has workCenter', async() => {

View File

@ -2,7 +2,8 @@
"name": "Route",
"base": "Loggable",
"log": {
"model":"RouteLog"
"model":"RouteLog",
"grabUser": true
},
"options": {
"mysql": {

View File

@ -1,7 +1,21 @@
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('sale canEdit()', () => {
const employeeId = 1;
beforeAll(async() => {
const activeCtx = {
accessToken: {userId: 9},
http: {
req: {
headers: {origin: 'http://localhost'}
}
}
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
describe('sale editTracked', () => {
it('should return true if the role is production regardless of the saleTrackings', async() => {

View File

@ -1,6 +1,21 @@
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('sale deleteSales()', () => {
beforeAll(async() => {
const activeCtx = {
accessToken: {userId: 9},
http: {
req: {
headers: {origin: 'http://localhost'}
}
}
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
it('should throw an error if the ticket of the given sales is not editable', async() => {
const tx = await models.Sale.beginTransaction({});

View File

@ -1,4 +1,5 @@
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('sale reserve()', () => {
const ctx = {
@ -9,6 +10,20 @@ describe('sale reserve()', () => {
}
};
beforeAll(async() => {
const activeCtx = {
accessToken: {userId: 9},
http: {
req: {
headers: {origin: 'http://localhost'}
}
}
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
it('should throw an error if the ticket can not be modified', async() => {
const tx = await models.Sale.beginTransaction({});

View File

@ -1,6 +1,21 @@
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('sale updateConcept()', () => {
beforeAll(async() => {
const activeCtx = {
accessToken: {userId: 9},
http: {
req: {
headers: {origin: 'http://localhost'}
}
}
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
const ctx = {req: {accessToken: {userId: 9}}};
const saleId = 25;

View File

@ -1,6 +1,21 @@
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('sale updatePrice()', () => {
beforeAll(async() => {
const activeCtx = {
accessToken: {userId: 18},
http: {
req: {
headers: {origin: 'http://localhost'}
}
}
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
const ctx = {
req: {
accessToken: {userId: 18},

View File

@ -1,6 +1,21 @@
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('sale updateQuantity()', () => {
beforeAll(async() => {
const activeCtx = {
accessToken: {userId: 9},
http: {
req: {
headers: {origin: 'http://localhost'}
}
}
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
const ctx = {
req: {
accessToken: {userId: 9},

View File

@ -127,19 +127,6 @@ module.exports = Self => {
], myOptions);
const ticket = await models.Ticket.findById(result[1][0].newTicketId, null, myOptions);
const cleanInstance = JSON.parse(JSON.stringify(ticket));
const logRecord = {
originFk: cleanInstance.id,
userFk: myUserId,
action: 'insert',
changedModel: 'Ticket',
changedModelId: cleanInstance.id,
oldInstance: {},
newInstance: cleanInstance
};
await models.TicketLog.create(logRecord, myOptions);
if (tx) await tx.commit();

View File

@ -1,7 +1,21 @@
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('ticket addSale()', () => {
const ticketId = 13;
beforeAll(async() => {
const activeCtx = {
accessToken: {userId: 9},
http: {
req: {
headers: {origin: 'http://localhost'}
}
}
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
it('should create a new sale for the ticket with id 13', async() => {
const tx = await models.Ticket.beginTransaction({});

View File

@ -10,11 +10,15 @@ describe('ticket merge()', () => {
workerFk: 1
};
beforeAll(async() => {
const activeCtx = {
accessToken: {userId: 9},
http: {
req: {
headers: {origin: 'http://localhost'}
}
}
};
beforeEach(() => {
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
@ -35,16 +39,16 @@ describe('ticket merge()', () => {
try {
const options = {transaction: tx};
const chatNotificationBeforeMerge = await models.Chat.find();
const chatNotificationBeforeMerge = await models.Chat.find(null, options);
await models.Ticket.merge(ctx, [tickets], options);
const createdTicketLog = await models.TicketLog.find({where: {originFk: tickets.originId}}, options);
const createdTicketLog = await models.TicketLog.find({where: {originFk: tickets.destinationId}}, options);
const deletedTicket = await models.Ticket.findOne({where: {id: tickets.originId}}, options);
const salesTicketFuture = await models.Sale.find({where: {ticketFk: tickets.destinationId}}, options);
const chatNotificationAfterMerge = await models.Chat.find();
const chatNotificationAfterMerge = await models.Chat.find(null, options);
expect(createdTicketLog.length).toEqual(2);
expect(createdTicketLog.length).toEqual(1);
expect(deletedTicket.isDeleted).toEqual(true);
expect(salesTicketFuture.length).toEqual(2);
expect(chatNotificationBeforeMerge.length).toEqual(chatNotificationAfterMerge.length - 2);

View File

@ -1,6 +1,20 @@
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('sale updateDiscount()', () => {
beforeAll(async() => {
const activeCtx = {
accessToken: {userId: 9},
http: {
req: {
headers: {origin: 'http://localhost'}
}
}
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
const originalSaleId = 8;
it('should throw an error if no sales were selected', async() => {

View File

@ -4,7 +4,8 @@
"log": {
"model": "TicketLog",
"relation": "ticket",
"showField": "concept"
"showField": "concept",
"grabUser": true
},
"options": {
"mysql": {

View File

@ -3,7 +3,8 @@
"base": "Loggable",
"log": {
"model":"TicketLog",
"showField": "id"
"showField": "id",
"grabUser": true
},
"options": {
"mysql": {

View File

@ -3,7 +3,8 @@
"base": "Loggable",
"log": {
"model":"TravelLog",
"showField": "ref"
"showField": "ref",
"grabUser": true
},
"options": {
"mysql": {

View File

@ -33,7 +33,7 @@
<div class="size50">
<div class="panel">
<div class="header">{{$t('deliveryAddress')}}</div>
<div class="body">
<div class="body" v-if="address">
<h3 class="uppercase">{{address.nickname}}</h3>
<div>{{address.street}}</div>
<div>{{address.postalCode}}, {{address.city}} ({{address.province}})</div>
@ -245,13 +245,8 @@
</div>
</div>
<template v-slot:footer>
<report-footer
id="pageFooter"
v-bind:company-code="ticket.companyCode"
v-bind:left-text="footerType"
v-bind:center-text="client.socialName"
v-bind="$props"
>
<report-footer id="pageFooter" v-bind:company-code="ticket.companyCode" v-bind:left-text="footerType"
v-bind:center-text="client.socialName" v-bind="$props">
</report-footer>
</template>
</report-body>

View File

@ -240,14 +240,19 @@
</tfoot>
</table>
</div>
<div class="columns vn-mt-xl" v-if="invoice.payMethodCode == 'wireTransfer'">
<div class="columns vn-mt-xl" v-if="invoice.payMethodCode == 'wireTransfer' || ticketObservations">
<div class="size50 pull-left no-page-break">
<div class="panel">
<div class="header">{{$t('observations')}}</div>
<div class="body">
<div v-if="invoice.payMethodCode == 'wireTransfer'">
<div>{{$t('wireTransfer')}}</div>
<div>{{$t('accountNumber', [invoice.iban])}}</div>
</div>
<div v-if="ticketObservations">
{{ticketObservations}}
</div>
</div>
</div>
</div>
</div>

View File

@ -21,11 +21,15 @@ module.exports = {
const map = new Map();
this.ticketObservations = '';
for (let ticket of tickets) {
ticket.sales = [];
map.set(ticket.id, ticket);
if (ticket.description) this.ticketObservations += ticket.description + ' ';
}
this.ticketObservations = this.ticketObservations.trim();
for (let sale of sales) {
const ticket = map.get(sale.ticketFk);

View File

@ -1,8 +1,12 @@
SELECT
t.id,
t.shipped,
t.nickname
t.nickname,
tto.description
FROM invoiceOut io
JOIN ticket t ON t.refFk = io.ref
JOIN ticket t ON t.refFk = io.REF
LEFT JOIN observationType ot ON ot.code = 'invoiceOut'
LEFT JOIN ticketObservation tto ON tto.ticketFk = t.id
AND tto.observationTypeFk = ot.id
WHERE t.refFk = ?
ORDER BY t.shipped