Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 7195_roadmaps
This commit is contained in:
commit
94aef434a9
|
@ -121,7 +121,7 @@ pipeline {
|
|||
steps {
|
||||
script {
|
||||
def packageJson = readJSON file: 'package.json'
|
||||
env.VERSION = packageJson.version
|
||||
env.VERSION = "${packageJson.version}-vn${env.BUILD_ID}"
|
||||
}
|
||||
sh 'docker-compose build back'
|
||||
}
|
||||
|
@ -159,7 +159,7 @@ pipeline {
|
|||
steps {
|
||||
script {
|
||||
def packageJson = readJSON file: 'package.json'
|
||||
env.VERSION = packageJson.version
|
||||
env.VERSION = "${packageJson.version}-vn${env.BUILD_ID}"
|
||||
}
|
||||
sh 'gulp build'
|
||||
sh 'docker-compose build front'
|
||||
|
@ -179,7 +179,7 @@ pipeline {
|
|||
steps {
|
||||
script {
|
||||
def packageJson = readJSON file: 'package.json'
|
||||
env.VERSION = packageJson.version
|
||||
env.VERSION = "${packageJson.version}-vn${env.BUILD_ID}"
|
||||
}
|
||||
sh 'docker login --username $CREDENTIALS_USR --password $CREDENTIALS_PSW $REGISTRY'
|
||||
sh 'docker-compose push'
|
||||
|
@ -210,7 +210,7 @@ pipeline {
|
|||
steps {
|
||||
script {
|
||||
def packageJson = readJSON file: 'package.json'
|
||||
env.VERSION = packageJson.version
|
||||
env.VERSION = "${packageJson.version}-vn${env.BUILD_ID}"
|
||||
}
|
||||
withKubeConfig([
|
||||
serverUrl: "$KUBERNETES_API",
|
||||
|
|
|
@ -1,6 +1,16 @@
|
|||
{
|
||||
"name": "Collection",
|
||||
"base": "VnModel",
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"workerFk": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "collection"
|
||||
|
|
|
@ -762,7 +762,12 @@ INSERT INTO `vn`.`ticket`(`id`, `priority`, `agencyModeFk`,`warehouseFk`,`routeF
|
|||
(30, 1, 8, 1, 1, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE(), NULL, NULL),
|
||||
(31, 1, 8, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL + 2 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE(), NULL, NULL),
|
||||
(32, 1, 8, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL + 2 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE(), NULL, NULL),
|
||||
(33, 1, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1102, 'NY roofs', 122, NULL, 0, 3, 5, 1, util.VN_CURDATE(), NULL, NULL);
|
||||
(33, 1, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1102, 'NY roofs', 122, NULL, 0, 3, 5, 1, util.VN_CURDATE(), NULL, NULL),
|
||||
(34, 1, 1, 1, 3, util.VN_CURDATE(), util.VN_CURDATE(), 1103, 'BEJAR', 123, NULL, 0, 1, 16, 0, util.VN_CURDATE(), NULL, NULL),
|
||||
(35, 1, 1, 1, 3, util.VN_CURDATE(), util.VN_CURDATE(), 1102, 'Somewhere in Philippines', 123, NULL, 0, 1, 16, 0, util.VN_CURDATE(), NULL, NULL),
|
||||
(36, 1, 1, 1, 3, util.VN_CURDATE(), util.VN_CURDATE(), 1102, 'Ant-Man Adventure', 123, NULL, 0, 1, 16, 0, util.VN_CURDATE(), NULL, NULL),
|
||||
(37, 1, 1, 1, 3, util.VN_CURDATE(), util.VN_CURDATE(), 1110, 'Deadpool swords', 123, NULL, 0, 1, 16, 0, util.VN_CURDATE(), NULL, NULL);
|
||||
|
||||
INSERT INTO `vn`.`ticketObservation`(`id`, `ticketFk`, `observationTypeFk`, `description`)
|
||||
VALUES
|
||||
(1, 11, 1, 'ready'),
|
||||
|
@ -808,7 +813,10 @@ INSERT INTO `vn`.`ticketTracking`(`ticketFk`, `stateFk`, `userFk`, `created`)
|
|||
(21, 1, 19, DATE_ADD(util.VN_NOW(), INTERVAL +1 MONTH)),
|
||||
(22, 1, 19, DATE_ADD(util.VN_NOW(), INTERVAL +1 MONTH)),
|
||||
(23, 16, 21, util.VN_NOW()),
|
||||
(24, 16, 21, util.VN_NOW());
|
||||
(24, 16, 21, util.VN_NOW()),
|
||||
(34, 14, 49, util.VN_NOW()),
|
||||
(35, 14, 18, util.VN_NOW()),
|
||||
(36, 14, 18, util.VN_NOW());
|
||||
|
||||
INSERT INTO `vn`.`deliveryPoint` (`id`, `name`, `ubication`)
|
||||
VALUES
|
||||
|
@ -1068,7 +1076,10 @@ INSERT INTO `vn`.`sale`(`id`, `itemFk`, `ticketFk`, `concept`, `quantity`, `pric
|
|||
(37, 4, 31, 'Melee weapon heavy shield 100cm', 20, 1.72, 0, 0, 0, util.VN_CURDATE()),
|
||||
(36, 4, 30, 'Melee weapon heavy shield 100cm', 20, 1.72, 0, 0, 0, util.VN_CURDATE()),
|
||||
(38, 2, 32, 'Melee weapon combat fist 15cm', 30, 7.07, 0, 0, 0, DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH)),
|
||||
(39, 1, 32, 'Ranged weapon longbow 200cm', 2, 103.49, 0, 0, 0, util.VN_CURDATE());
|
||||
(39, 1, 32, 'Ranged weapon longbow 200cm', 2, 103.49, 0, 0, 0, util.VN_CURDATE()),
|
||||
(40, 2, 34, 'Melee weapon combat fist 15cm', 10.00, 3.91, 0, 0, 0, util.VN_CURDATE()),
|
||||
(41, 2, 35, 'Melee weapon combat fist 15cm', 8.00, 3.01, 0, 0, 0, util.VN_CURDATE()),
|
||||
(42, 2, 36, 'Melee weapon combat fist 15cm', 6.00, 2.50, 0, 0, 0, util.VN_CURDATE());
|
||||
|
||||
INSERT INTO `vn`.`saleComponent`(`saleFk`, `componentFk`, `value`)
|
||||
VALUES
|
||||
|
@ -1247,14 +1258,20 @@ INSERT INTO `vn`.`operator` (`workerFk`, `numberOfWagons`, `trainFk`, `itemPacki
|
|||
INSERT INTO `vn`.`collection`(`id`, `workerFk`, `stateFk`, `created`, `trainFk`)
|
||||
VALUES
|
||||
(1, 1106, 5, DATE_ADD(util.VN_CURDATE(),INTERVAL +1 DAY), 1),
|
||||
(2, 1106, 14, util.VN_CURDATE(), 1);
|
||||
(2, 1106, 14, util.VN_CURDATE(), 1),
|
||||
(4, 49, 5, util.VN_CURDATE(), 1),
|
||||
(5, 18, 5, util.VN_CURDATE(), 1),
|
||||
(6, 18, 5, util.VN_CURDATE(), 1);
|
||||
|
||||
INSERT INTO `vn`.`ticketCollection`(`ticketFk`, `collectionFk`, `level`)
|
||||
VALUES
|
||||
(1, 1, 1),
|
||||
(2, 1, NULL),
|
||||
(3, 2, NULL),
|
||||
(23, 1, NULL);
|
||||
(23, 1, NULL),
|
||||
(34, 4, 1),
|
||||
(35, 5, 1),
|
||||
(8, 6, 1);
|
||||
|
||||
INSERT INTO `vn`.`genus`(`id`, `name`)
|
||||
VALUES
|
||||
|
@ -3705,7 +3722,8 @@ INSERT IGNORE INTO vn.saleGroup
|
|||
SET id = 4,
|
||||
userFk = 1,
|
||||
parkingFk = 9,
|
||||
sectorFk = 9992;
|
||||
sectorFk = 9992,
|
||||
ticketFk = 36;
|
||||
|
||||
INSERT IGNORE INTO vn.sectorCollectionSaleGroup
|
||||
SET id = 9999,
|
||||
|
@ -3807,3 +3825,27 @@ INSERT INTO `vn`.`ledgerCompany` SET
|
|||
|
||||
INSERT INTO `vn`.`ledgerConfig` SET
|
||||
maxTolerance = 0.01;
|
||||
|
||||
INSERT INTO vn.sectorCollection
|
||||
SET id = 2,
|
||||
userFk = 18,
|
||||
sectorFk = 1;
|
||||
|
||||
INSERT INTO vn.sectorCollectionSaleGroup
|
||||
SET id = 8,
|
||||
sectorCollectionFk = 2,
|
||||
saleGroupFk = 4;
|
||||
|
||||
INSERT INTO vn.saleGroup (userFk, parkingFk, sectorFk, ticketFk)
|
||||
VALUES
|
||||
(1, 1, 1, 37);
|
||||
|
||||
INSERT INTO vn.sectorCollection
|
||||
SET id = 3,
|
||||
userFk = 18,
|
||||
sectorFk = 1;
|
||||
|
||||
INSERT INTO vn.sectorCollectionSaleGroup
|
||||
SET id = 9,
|
||||
sectorCollectionFk = 3,
|
||||
saleGroupFk = 6;
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE vn.item ADD COLUMN photoMotivation VARCHAR(255);
|
|
@ -0,0 +1,46 @@
|
|||
use account;
|
||||
|
||||
INSERT INTO role
|
||||
SET name = 'reviewer',
|
||||
description = 'Revisor de producción',
|
||||
hasLogin = TRUE,
|
||||
created = util.VN_CURDATE(),
|
||||
modified = util.VN_CURDATE(),
|
||||
editorFk = NULL;
|
||||
|
||||
INSERT INTO roleInherit(
|
||||
role,
|
||||
inheritsFrom
|
||||
)
|
||||
SELECT r1.id,
|
||||
r2.id
|
||||
FROM role r1
|
||||
JOIN role r2
|
||||
WHERE r1.name = 'reviewer'
|
||||
AND r2.name = 'production'
|
||||
UNION
|
||||
SELECT ri.role,
|
||||
r2.id
|
||||
FROM roleInherit ri
|
||||
JOIN role r1 ON r1.id = ri.role
|
||||
JOIN role r2 ON r2.name = 'reviewer'
|
||||
WHERE r1.name IN ('claimManager', 'productionBoss')
|
||||
GROUP BY ri.role;
|
||||
|
||||
DELETE ri
|
||||
FROM roleInherit ri
|
||||
JOIN role r1 ON ri.role = r1.id
|
||||
JOIN role r2 ON ri.inheritsFrom = r2.id
|
||||
WHERE r1.name = 'replenisher'
|
||||
AND r2.name = 'buyer';
|
||||
|
||||
UPDATE salix.ACL
|
||||
SET principalId = 'reviewer'
|
||||
WHERE property = 'isInPreparing';
|
||||
|
||||
UPDATE user u
|
||||
JOIN vn.workerDepartment wd ON wd.workerFk = u.id
|
||||
JOIN vn.department d ON wd.departmentFk = d.id
|
||||
JOIN role r ON r.name = 'reviewer'
|
||||
SET u.role = r.id
|
||||
WHERE d.name IN ('REVISION', 'PREVIA');
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
INSERT INTO salix.ACL (model,property,accessType,permission,principalType,principalId)
|
||||
VALUES ('Ticket','refund','WRITE','ALLOW','ROLE','logistic');
|
|
@ -225,7 +225,7 @@ describe('Ticket Edit sale path', () => {
|
|||
});
|
||||
|
||||
it('should show error trying to delete a ticket with a refund', async() => {
|
||||
await page.loginAndModule('production', 'ticket');
|
||||
await page.loginAndModule('salesPerson', 'ticket');
|
||||
await page.accessToSearchResult('8');
|
||||
await page.waitToClick(selectors.ticketDescriptor.moreMenu);
|
||||
await page.waitToClick(selectors.ticketDescriptor.moreMenuDeleteTicket);
|
||||
|
|
|
@ -64,7 +64,7 @@ describe('item getBalance()', () => {
|
|||
const secondItemBalance = await models.Item.getBalance(ctx, secondFilter, options);
|
||||
|
||||
expect(firstItemBalance[9].claimFk).toEqual(null);
|
||||
expect(secondItemBalance[4].claimFk).toEqual(2);
|
||||
expect(secondItemBalance[7].claimFk).toEqual(2);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
|
|
|
@ -155,6 +155,9 @@
|
|||
"minQuantity": {
|
||||
"type": "number",
|
||||
"description": "Min quantity"
|
||||
},
|
||||
"photoMotivation": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
|
|
|
@ -151,7 +151,7 @@ describe('SalesMonitor salesFilter()', () => {
|
|||
const result = await models.SalesMonitor.salesFilter(ctx, filter, options);
|
||||
const firstRow = result[0];
|
||||
|
||||
expect(result.length).toEqual(12);
|
||||
expect(result.length).toEqual(15);
|
||||
expect(firstRow.alertLevel).not.toEqual(0);
|
||||
|
||||
await tx.rollback();
|
||||
|
|
|
@ -11,6 +11,12 @@
|
|||
"Sector": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"SectorCollection": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"SectorCollectionSaleGroup": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"Train": {
|
||||
"dataSource": "vn"
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"name": "SectorCollection",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "sectorCollection"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "number",
|
||||
"id": true
|
||||
},
|
||||
"created": {
|
||||
"type": "date"
|
||||
},
|
||||
"userFk": {
|
||||
"type": "number"
|
||||
},
|
||||
"sectorFk": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"name": "SectorCollectionSaleGroup",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "sectorCollectionSaleGroup"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "number",
|
||||
"id": true
|
||||
},
|
||||
"created": {
|
||||
"type": "date"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"sectorCollection": {
|
||||
"type": "belongsTo",
|
||||
"model": "SectorCollection",
|
||||
"foreignKey": "sectorCollectionFk"
|
||||
},
|
||||
"saleGroup": {
|
||||
"type": "belongsTo",
|
||||
"model": "SaleGroup",
|
||||
"foreignKey": "saleGroupFk"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,8 +10,8 @@ module.exports = Self => {
|
|||
http: {source: 'path'}
|
||||
},
|
||||
{
|
||||
arg: 'itemId',
|
||||
type: 'number',
|
||||
arg: 'barcode',
|
||||
type: 'any',
|
||||
required: true
|
||||
},
|
||||
{
|
||||
|
@ -29,7 +29,7 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
Self.addSale = async(ctx, id, itemId, quantity, options) => {
|
||||
Self.addSale = async(ctx, id, barcode, quantity, options) => {
|
||||
const $t = ctx.req.__; // $translate
|
||||
const models = Self.app.models;
|
||||
const myOptions = {userId: ctx.req.accessToken.userId};
|
||||
|
@ -46,7 +46,9 @@ module.exports = Self => {
|
|||
try {
|
||||
await models.Ticket.isEditableOrThrow(ctx, id, myOptions);
|
||||
|
||||
const itemId = await models.ItemBarcode.toItem(barcode, myOptions);
|
||||
const item = await models.Item.findById(itemId, null, myOptions);
|
||||
|
||||
const ticket = await models.Ticket.findById(id, {
|
||||
include: {
|
||||
relation: 'client',
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
const UserError = require('vn-loopback/util/user-error');
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('addSaleByCode', {
|
||||
description: 'Add a collection',
|
||||
accessType: 'WRITE',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'barcode',
|
||||
type: 'string',
|
||||
required: true
|
||||
}, {
|
||||
arg: 'quantity',
|
||||
type: 'number',
|
||||
required: true
|
||||
}, {
|
||||
arg: 'ticketFk',
|
||||
type: 'number',
|
||||
required: true
|
||||
}, {
|
||||
arg: 'warehouseFk',
|
||||
type: 'number',
|
||||
required: true
|
||||
},
|
||||
|
||||
],
|
||||
http: {
|
||||
path: `/addSaleByCode`,
|
||||
verb: 'POST'
|
||||
},
|
||||
});
|
||||
|
||||
Self.addSaleByCode = async(ctx, barcode, quantity, ticketFk, warehouseFk, options) => {
|
||||
const myOptions = {userId: ctx.req.accessToken.userId};
|
||||
let tx;
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
if (!myOptions.transaction) {
|
||||
tx = await Self.beginTransaction({});
|
||||
myOptions.transaction = tx;
|
||||
}
|
||||
|
||||
try {
|
||||
const [[item]] = await Self.rawSql('CALL vn.item_getInfo(?,?)', [barcode, warehouseFk], myOptions);
|
||||
if (!item?.available) throw new UserError('We do not have availability for the selected item');
|
||||
|
||||
await Self.rawSql('CALL vn.collection_addItem(?, ?, ?)', [item.id, quantity, ticketFk], myOptions);
|
||||
|
||||
if (tx) await tx.commit();
|
||||
} catch (e) {
|
||||
if (tx) await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
};
|
|
@ -8,18 +8,13 @@ module.exports = Self => {
|
|||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
const state = await models.TicketState.findOne({
|
||||
where: {ticketFk: id}
|
||||
}, myOptions);
|
||||
|
||||
const state = await models.TicketState.findOne({where: {ticketFk: id}}, myOptions);
|
||||
const isRoleAdvanced = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'isRoleAdvanced', '*');
|
||||
const isProductionReviewer = await models.ACL.checkAccessAcl(ctx, 'Sale', 'isInPreparing', '*');
|
||||
const canEditWeeklyTicket = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'canEditWeekly', 'WRITE');
|
||||
const alertLevel = state ? state.alertLevel : null;
|
||||
const ticket = await models.Ticket.findById(id, {
|
||||
fields: ['clientFk'],
|
||||
include: {
|
||||
relation: 'client'
|
||||
}
|
||||
fields: ['clientFk'], include: {relation: 'client'}
|
||||
}, myOptions);
|
||||
|
||||
const isLocked = await models.Ticket.isLocked(id, myOptions);
|
||||
|
@ -29,10 +24,24 @@ module.exports = Self => {
|
|||
const isNormalClient = ticket && ticket.client().typeFk == 'normal';
|
||||
const isEditable = !(alertLevelGreaterThanZero && isNormalClient);
|
||||
|
||||
const ticketCollection = await models.TicketCollection.findOne({
|
||||
include: {relation: 'collection'}, where: {ticketFk: id}
|
||||
}, myOptions);
|
||||
let isOwner = ticketCollection?.collection()?.workerFk === ctx.req.accessToken.userId;
|
||||
|
||||
if (!isOwner) {
|
||||
const saleGroup = await models.SaleGroup.findOne({fields: ['id'], where: {ticketFk: id}}, myOptions);
|
||||
const sectorCollectionSaleGroup = saleGroup && await models.SectorCollectionSaleGroup.findOne({
|
||||
include: {relation: 'sectorCollection'}, where: {saleGroupFk: saleGroup.id}
|
||||
}, myOptions);
|
||||
|
||||
isOwner = sectorCollectionSaleGroup?.sectorCollection()?.userFk === ctx.req.accessToken.userId;
|
||||
}
|
||||
|
||||
if (!ticket)
|
||||
throw new ForbiddenError(`The ticket doesn't exist.`);
|
||||
|
||||
if (!isEditable && !isRoleAdvanced)
|
||||
if (!isEditable && !isRoleAdvanced && !isProductionReviewer && !isOwner)
|
||||
throw new ForbiddenError(`This ticket is not editable.`);
|
||||
|
||||
if (isLocked && !isWeekly)
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
const {models} = require('vn-loopback/server/server');
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('Ticket addSaleByCode()', () => {
|
||||
const quantity = 3;
|
||||
const ticketFk = 13;
|
||||
const warehouseFk = 1;
|
||||
beforeAll(async() => {
|
||||
activeCtx = {
|
||||
req: {
|
||||
accessToken: {userId: 9},
|
||||
headers: {origin: 'http://localhost'},
|
||||
__: value => value
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
|
||||
it('should add a new sale', async() => {
|
||||
const tx = await models.Ticket.beginTransaction({});
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
const code = '1111111111';
|
||||
|
||||
const salesBefore = await models.Sale.find(null, options);
|
||||
await models.Ticket.addSaleByCode(activeCtx, code, quantity, ticketFk, warehouseFk, options);
|
||||
const salesAfter = await models.Sale.find(null, options);
|
||||
|
||||
expect(salesAfter.length).toEqual(salesBefore.length + 1);
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
});
|
|
@ -68,7 +68,7 @@ describe('ticket filter()', () => {
|
|||
const filter = {};
|
||||
const result = await models.Ticket.filter(ctx, filter, options);
|
||||
|
||||
expect(result.length).toEqual(7);
|
||||
expect(result.length).toEqual(10);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
|
|
|
@ -42,7 +42,7 @@ describe('sale priceDifference()', () => {
|
|||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
const ctx = {req: {accessToken: {userId: 1106}}};
|
||||
const ctx = {req: {accessToken: {userId: 1105}}};
|
||||
ctx.args = {
|
||||
id: 1,
|
||||
landed: Date.vnNew(),
|
||||
|
@ -84,7 +84,7 @@ describe('sale priceDifference()', () => {
|
|||
|
||||
const {items} = await models.Ticket.priceDifference(ctx, options);
|
||||
|
||||
expect(items[0].movable).toEqual(410);
|
||||
expect(items[0].movable).toEqual(386);
|
||||
expect(items[1].movable).toEqual(1810);
|
||||
|
||||
await tx.rollback();
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
},
|
||||
"parkingFk": {
|
||||
"type": "number"
|
||||
},
|
||||
"ticketFk": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
|
|
|
@ -1,361 +1,318 @@
|
|||
/* eslint max-len: ["error", { "code": 150 }]*/
|
||||
|
||||
const models = require('vn-loopback/server/server').models;
|
||||
const {models} = require('vn-loopback/server/server');
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('sale model ', () => {
|
||||
const ctx = {
|
||||
req: {
|
||||
accessToken: {userId: 9},
|
||||
headers: {origin: 'localhost:5000'},
|
||||
__: () => {}
|
||||
}
|
||||
};
|
||||
function getActiveCtx(userId) {
|
||||
return {
|
||||
active: {
|
||||
accessToken: {userId},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
const developerId = 9;
|
||||
const buyerId = 35;
|
||||
const employeeId = 1;
|
||||
const productionId = 49;
|
||||
const salesPersonId = 18;
|
||||
const reviewerId = 130;
|
||||
|
||||
const barcode = '4444444444';
|
||||
const ticketCollectionProd = 34;
|
||||
const ticketCollectionSalesPerson = 35;
|
||||
const previaTicketSalesPerson = 36;
|
||||
const previaTicketProd = 37;
|
||||
const notEditableError = 'This ticket is not editable.';
|
||||
|
||||
const ctx = getCtx(developerId);
|
||||
let tx;
|
||||
let opts;
|
||||
|
||||
function getCtx(userId, active = false) {
|
||||
const accessToken = {userId};
|
||||
const headers = {origin: 'localhost:5000'};
|
||||
if (!active) return {req: {accessToken, headers, __: () => {}}};
|
||||
return {active: {accessToken, http: {req: {headers}}}};
|
||||
}
|
||||
|
||||
beforeEach(async() => {
|
||||
tx = await models.Sale.beginTransaction({});
|
||||
opts = {transaction: tx};
|
||||
});
|
||||
|
||||
afterEach(async() => await tx.rollback());
|
||||
|
||||
describe('quantity field ', () => {
|
||||
it('should add quantity if the quantity is greater than it should be and is role advanced', async() => {
|
||||
const saleId = 17;
|
||||
const buyerId = 35;
|
||||
const ctx = {
|
||||
req: {
|
||||
accessToken: {userId: buyerId},
|
||||
headers: {origin: 'localhost:5000'},
|
||||
__: () => {}
|
||||
}
|
||||
};
|
||||
const tx = await models.Sale.beginTransaction({});
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(buyerId));
|
||||
spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, options) => {
|
||||
const ctx = getCtx(buyerId);
|
||||
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(buyerId, true));
|
||||
spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => {
|
||||
if (sqlStatement.includes('catalog_calcFromItem')) {
|
||||
sqlStatement = `CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY
|
||||
SELECT 100 as available;`;
|
||||
params = null;
|
||||
}
|
||||
return models.Ticket.rawSql(sqlStatement, params, options);
|
||||
return models.Ticket.rawSql(sqlStatement, params, opts);
|
||||
});
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
const isRoleAdvanced = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'isRoleAdvanced', '*');
|
||||
|
||||
const isRoleAdvanced = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'isRoleAdvanced', '*');
|
||||
expect(isRoleAdvanced).toEqual(true);
|
||||
|
||||
expect(isRoleAdvanced).toEqual(true);
|
||||
const originalLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, opts);
|
||||
|
||||
const originalLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, options);
|
||||
expect(originalLine.quantity).toEqual(30);
|
||||
|
||||
expect(originalLine.quantity).toEqual(30);
|
||||
const newQuantity = originalLine.quantity + 1;
|
||||
await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts);
|
||||
|
||||
const newQuantity = originalLine.quantity + 1;
|
||||
await models.Sale.updateQuantity(ctx, saleId, newQuantity, options);
|
||||
const modifiedLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, opts);
|
||||
|
||||
const modifiedLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, options);
|
||||
|
||||
expect(modifiedLine.quantity).toEqual(newQuantity);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
expect(modifiedLine.quantity).toEqual(newQuantity);
|
||||
});
|
||||
|
||||
it('should update the quantity of a given sale current line', async() => {
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(9));
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(developerId, true));
|
||||
|
||||
const tx = await models.Sale.beginTransaction({});
|
||||
const saleId = 25;
|
||||
const newQuantity = 4;
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
const originalLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, opts);
|
||||
|
||||
const originalLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, options);
|
||||
expect(originalLine.quantity).toEqual(20);
|
||||
|
||||
expect(originalLine.quantity).toEqual(20);
|
||||
await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts);
|
||||
|
||||
await models.Sale.updateQuantity(ctx, saleId, newQuantity, options);
|
||||
const modifiedLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, opts);
|
||||
|
||||
const modifiedLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, options);
|
||||
|
||||
expect(modifiedLine.quantity).toEqual(newQuantity);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
expect(modifiedLine.quantity).toEqual(newQuantity);
|
||||
});
|
||||
|
||||
it('should throw an error if the quantity is negative and it is not a refund ticket', async() => {
|
||||
const ctx = {
|
||||
req: {
|
||||
accessToken: {userId: 1},
|
||||
headers: {origin: 'localhost:5000'},
|
||||
__: () => {}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(1));
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true));
|
||||
|
||||
const saleId = 17;
|
||||
const newQuantity = -10;
|
||||
|
||||
const tx = await models.Sale.beginTransaction({});
|
||||
|
||||
let error;
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
await models.Sale.updateQuantity(ctx, saleId, newQuantity, options);
|
||||
|
||||
await tx.rollback();
|
||||
await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts);
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
error = e;
|
||||
expect(e).toEqual(new Error('You can only add negative amounts in refund tickets'));
|
||||
}
|
||||
|
||||
expect(error).toEqual(new Error('You can only add negative amounts in refund tickets'));
|
||||
});
|
||||
|
||||
it('should update a negative quantity when is a ticket refund', async() => {
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(9));
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(developerId, true));
|
||||
|
||||
const tx = await models.Sale.beginTransaction({});
|
||||
const saleId = 32;
|
||||
const newQuantity = -10;
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts);
|
||||
|
||||
await models.Sale.updateQuantity(ctx, saleId, newQuantity, options);
|
||||
const modifiedLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, opts);
|
||||
|
||||
const modifiedLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, options);
|
||||
|
||||
expect(modifiedLine.quantity).toEqual(newQuantity);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
expect(modifiedLine.quantity).toEqual(newQuantity);
|
||||
});
|
||||
|
||||
it('should throw an error if the quantity is less than the minimum quantity of the item', async() => {
|
||||
const ctx = {
|
||||
req: {
|
||||
accessToken: {userId: 1},
|
||||
headers: {origin: 'localhost:5000'},
|
||||
__: () => {}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(1));
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true));
|
||||
|
||||
const tx = await models.Sale.beginTransaction({});
|
||||
const itemId = 2;
|
||||
const saleId = 17;
|
||||
const minQuantity = 30;
|
||||
const newQuantity = minQuantity - 1;
|
||||
|
||||
let error;
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
const item = await models.Item.findById(itemId, null, options);
|
||||
await item.updateAttribute('minQuantity', minQuantity, options);
|
||||
spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, options) => {
|
||||
const item = await models.Item.findById(itemId, null, opts);
|
||||
await item.updateAttribute('minQuantity', minQuantity, opts);
|
||||
spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => {
|
||||
if (sqlStatement.includes('catalog_calcFromItem')) {
|
||||
sqlStatement = `CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY
|
||||
SELECT 100 as available;`;
|
||||
params = null;
|
||||
}
|
||||
return models.Ticket.rawSql(sqlStatement, params, options);
|
||||
return models.Ticket.rawSql(sqlStatement, params, opts);
|
||||
});
|
||||
|
||||
await models.Sale.updateQuantity(ctx, saleId, newQuantity, options);
|
||||
|
||||
await tx.rollback();
|
||||
await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts);
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
error = e;
|
||||
expect(e).toEqual(new Error('The amount cannot be less than the minimum'));
|
||||
}
|
||||
|
||||
expect(error).toEqual(new Error('The amount cannot be less than the minimum'));
|
||||
});
|
||||
|
||||
it('should change quantity if has minimum quantity and new quantity is equal than item available', async() => {
|
||||
const ctx = {
|
||||
req: {
|
||||
accessToken: {userId: 1},
|
||||
headers: {origin: 'localhost:5000'},
|
||||
__: () => {}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(1));
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true));
|
||||
|
||||
const tx = await models.Sale.beginTransaction({});
|
||||
const itemId = 2;
|
||||
const saleId = 17;
|
||||
const minQuantity = 30;
|
||||
const newQuantity = minQuantity - 1;
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
const item = await models.Item.findById(itemId, null, opts);
|
||||
await item.updateAttribute('minQuantity', minQuantity, opts);
|
||||
|
||||
const item = await models.Item.findById(itemId, null, options);
|
||||
await item.updateAttribute('minQuantity', minQuantity, options);
|
||||
|
||||
spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, options) => {
|
||||
if (sqlStatement.includes('catalog_calcFromItem')) {
|
||||
sqlStatement = `CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY
|
||||
spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => {
|
||||
if (sqlStatement.includes('catalog_calcFromItem')) {
|
||||
sqlStatement = `CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY
|
||||
SELECT ${newQuantity} as available;`;
|
||||
params = null;
|
||||
}
|
||||
return models.Ticket.rawSql(sqlStatement, params, options);
|
||||
});
|
||||
params = null;
|
||||
}
|
||||
return models.Ticket.rawSql(sqlStatement, params, opts);
|
||||
});
|
||||
|
||||
await models.Sale.updateQuantity(ctx, saleId, newQuantity, options);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts);
|
||||
});
|
||||
|
||||
describe('newPrice', () => {
|
||||
it('should increase quantity if you have enough available and the new price is the same as the previous one', async() => {
|
||||
const ctx = {
|
||||
req: {
|
||||
accessToken: {userId: 1},
|
||||
headers: {origin: 'localhost:5000'},
|
||||
__: () => {}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(1));
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true));
|
||||
|
||||
const tx = await models.Sale.beginTransaction({});
|
||||
const itemId = 2;
|
||||
const saleId = 17;
|
||||
const minQuantity = 30;
|
||||
const newQuantity = 31;
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
const item = await models.Item.findById(itemId, null, options);
|
||||
await item.updateAttribute('minQuantity', minQuantity, options);
|
||||
spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, options) => {
|
||||
if (sqlStatement.includes('catalog_calcFromItem')) {
|
||||
sqlStatement = `
|
||||
const item = await models.Item.findById(itemId, null, opts);
|
||||
await item.updateAttribute('minQuantity', minQuantity, opts);
|
||||
spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => {
|
||||
if (sqlStatement.includes('catalog_calcFromItem')) {
|
||||
sqlStatement = `
|
||||
CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY SELECT ${newQuantity} as available;
|
||||
CREATE OR REPLACE TEMPORARY TABLE tmp.ticketComponentPrice ENGINE = MEMORY SELECT 1 as grouping, 7.07 as price;`;
|
||||
params = null;
|
||||
}
|
||||
return models.Ticket.rawSql(sqlStatement, params, options);
|
||||
});
|
||||
params = null;
|
||||
}
|
||||
return models.Ticket.rawSql(sqlStatement, params, opts);
|
||||
});
|
||||
|
||||
await models.Sale.updateQuantity(ctx, saleId, newQuantity, options);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts);
|
||||
});
|
||||
|
||||
it('should increase quantity when the new price is lower than the previous one', async() => {
|
||||
const ctx = {
|
||||
req: {
|
||||
accessToken: {userId: 1},
|
||||
headers: {origin: 'localhost:5000'},
|
||||
__: () => {}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(1));
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true));
|
||||
|
||||
const tx = await models.Sale.beginTransaction({});
|
||||
const itemId = 2;
|
||||
const saleId = 17;
|
||||
const minQuantity = 30;
|
||||
const newQuantity = 31;
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
const item = await models.Item.findById(itemId, null, options);
|
||||
await item.updateAttribute('minQuantity', minQuantity, options);
|
||||
spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, options) => {
|
||||
if (sqlStatement.includes('catalog_calcFromItem')) {
|
||||
sqlStatement = `
|
||||
const item = await models.Item.findById(itemId, null, opts);
|
||||
await item.updateAttribute('minQuantity', minQuantity, opts);
|
||||
spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => {
|
||||
if (sqlStatement.includes('catalog_calcFromItem')) {
|
||||
sqlStatement = `
|
||||
CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY SELECT ${newQuantity} as available;
|
||||
CREATE OR REPLACE TEMPORARY TABLE tmp.ticketComponentPrice ENGINE = MEMORY SELECT 1 as grouping, 1 as price;`;
|
||||
params = null;
|
||||
}
|
||||
return models.Ticket.rawSql(sqlStatement, params, options);
|
||||
});
|
||||
params = null;
|
||||
}
|
||||
return models.Ticket.rawSql(sqlStatement, params, opts);
|
||||
});
|
||||
|
||||
await models.Sale.updateQuantity(ctx, saleId, newQuantity, options);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts);
|
||||
});
|
||||
|
||||
it('should throw error when increase quantity and the new price is higher than the previous one', async() => {
|
||||
const ctx = {
|
||||
req: {
|
||||
accessToken: {userId: 1},
|
||||
headers: {origin: 'localhost:5000'},
|
||||
__: () => {}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(1));
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true));
|
||||
|
||||
const tx = await models.Sale.beginTransaction({});
|
||||
const itemId = 2;
|
||||
const saleId = 17;
|
||||
const minQuantity = 30;
|
||||
const newQuantity = 31;
|
||||
|
||||
let error;
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
const item = await models.Item.findById(itemId, null, options);
|
||||
await item.updateAttribute('minQuantity', minQuantity, options);
|
||||
spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, options) => {
|
||||
const item = await models.Item.findById(itemId, null, opts);
|
||||
await item.updateAttribute('minQuantity', minQuantity, opts);
|
||||
spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => {
|
||||
if (sqlStatement.includes('catalog_calcFromItem')) {
|
||||
sqlStatement = `
|
||||
CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY SELECT ${newQuantity} as available;
|
||||
CREATE OR REPLACE TEMPORARY TABLE tmp.ticketComponentPrice ENGINE = MEMORY SELECT 1 as grouping, 100000 as price;`;
|
||||
params = null;
|
||||
}
|
||||
return models.Ticket.rawSql(sqlStatement, params, options);
|
||||
return models.Ticket.rawSql(sqlStatement, params, opts);
|
||||
});
|
||||
|
||||
await models.Sale.updateQuantity(ctx, saleId, newQuantity, options);
|
||||
|
||||
await tx.rollback();
|
||||
await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts);
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
error = e;
|
||||
expect(e).toEqual(new Error('The price of the item changed'));
|
||||
}
|
||||
|
||||
expect(error).toEqual(new Error('The price of the item changed'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('add a sale from a collection or previa ticket', () => {
|
||||
it('if is allocated to them and alert level higher than 0 as Production role', async() => {
|
||||
const ctx = getCtx(productionId);
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(productionId, true));
|
||||
|
||||
const beforeSalesCollection = await models.Sale.count({ticketFk: ticketCollectionProd}, opts);
|
||||
await models.Ticket.addSale(ctx, ticketCollectionProd, barcode, 20, opts);
|
||||
const afterSalesCollection = await models.Sale.count({ticketFk: ticketCollectionProd}, opts);
|
||||
|
||||
expect(afterSalesCollection).toEqual(beforeSalesCollection + 1);
|
||||
|
||||
const beforeSalesPrevia = await models.Sale.count({ticketFk: previaTicketProd}, opts);
|
||||
await models.Ticket.addSale(ctx, previaTicketProd, barcode, 20, opts);
|
||||
const afterSalesPrevia = await models.Sale.count({ticketFk: previaTicketProd}, opts);
|
||||
|
||||
expect(afterSalesPrevia).toEqual(beforeSalesPrevia + 1);
|
||||
});
|
||||
|
||||
it('should throw an error if is not allocated to them and alert level higher than 0 as Production role', async() => {
|
||||
const ctx = getCtx(productionId);
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(productionId, true));
|
||||
|
||||
try {
|
||||
await models.Ticket.addSale(ctx, ticketCollectionSalesPerson, barcode, 20, opts);
|
||||
} catch ({message}) {
|
||||
expect(message).toEqual(notEditableError);
|
||||
}
|
||||
|
||||
try {
|
||||
await models.Ticket.addSale(ctx, previaTicketSalesPerson, barcode, 20, opts);
|
||||
} catch ({message}) {
|
||||
expect(message).toEqual(notEditableError);
|
||||
}
|
||||
});
|
||||
|
||||
it('if is allocated to them and alert level higher than 0 as salesPerson role', async() => {
|
||||
const ctx = getCtx(salesPersonId);
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(salesPersonId, true));
|
||||
|
||||
const beforeSalesCollection = await models.Sale.count({ticketFk: ticketCollectionSalesPerson}, opts);
|
||||
await models.Ticket.addSale(ctx, ticketCollectionSalesPerson, barcode, 20, opts);
|
||||
const afterSalesCollection = await models.Sale.count({ticketFk: ticketCollectionSalesPerson}, opts);
|
||||
|
||||
expect(afterSalesCollection).toEqual(beforeSalesCollection + 1);
|
||||
|
||||
const beforeSalesPrevia = await models.Sale.count({ticketFk: previaTicketSalesPerson}, opts);
|
||||
await models.Ticket.addSale(ctx, previaTicketSalesPerson, barcode, 20, opts);
|
||||
const afterSalesPrevia = await models.Sale.count({ticketFk: previaTicketSalesPerson}, opts);
|
||||
|
||||
expect(afterSalesPrevia).toEqual(beforeSalesPrevia + 1);
|
||||
});
|
||||
|
||||
it('should throw an error if is not allocated to them and alert level higher than 0 as salesPerson role', async() => {
|
||||
const ctx = getCtx(salesPersonId);
|
||||
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(salesPersonId, true));
|
||||
|
||||
try {
|
||||
await models.Ticket.addSale(ctx, ticketCollectionProd, barcode, 20, opts);
|
||||
} catch ({message}) {
|
||||
expect(message).toEqual(notEditableError);
|
||||
}
|
||||
});
|
||||
|
||||
it('if is a reviewer', async() => {
|
||||
const ctx = getCtx(reviewerId);
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(reviewerId, true));
|
||||
|
||||
const beforeSalesCollection = await models.Sale.count({ticketFk: ticketCollectionSalesPerson}, opts);
|
||||
await models.Ticket.addSale(ctx, ticketCollectionSalesPerson, barcode, 20, opts);
|
||||
const afterSalesCollection = await models.Sale.count({ticketFk: ticketCollectionSalesPerson}, opts);
|
||||
|
||||
expect(afterSalesCollection).toEqual(beforeSalesCollection + 1);
|
||||
|
||||
const beforeSalesPrevia = await models.Sale.count({ticketFk: previaTicketSalesPerson}, opts);
|
||||
await models.Ticket.addSale(ctx, previaTicketSalesPerson, barcode, 20, opts);
|
||||
const afterSalesPrevia = await models.Sale.count({ticketFk: previaTicketSalesPerson}, opts);
|
||||
|
||||
expect(afterSalesPrevia).toEqual(beforeSalesPrevia + 1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -46,6 +46,5 @@ module.exports = function(Self) {
|
|||
require('../methods/ticket/invoiceTicketsAndPdf')(Self);
|
||||
require('../methods/ticket/docuwareDownload')(Self);
|
||||
require('../methods/ticket/myLastModified')(Self);
|
||||
require('../methods/ticket/addSaleByCode')(Self);
|
||||
require('../methods/ticket/clone')(Self);
|
||||
};
|
||||
|
|
|
@ -152,7 +152,7 @@
|
|||
</vn-item>
|
||||
<vn-item class="dropdown"
|
||||
vn-click-stop="refundMenu.show($event, 'left')"
|
||||
vn-acl="invoicing, claimManager, salesAssistant"
|
||||
vn-acl="invoicing, claimManager, salesAssistant, logistic"
|
||||
vn-acl-action="remove"
|
||||
vn-tooltip="Create a single ticket with all the content of the current ticket"
|
||||
translate>
|
||||
|
|
|
@ -476,7 +476,7 @@ class Controller extends Section {
|
|||
*/
|
||||
addSale(sale) {
|
||||
const data = {
|
||||
itemId: sale.itemFk,
|
||||
barcode: sale.itemFk,
|
||||
quantity: sale.quantity
|
||||
};
|
||||
const query = `tickets/${this.ticket.id}/addSale`;
|
||||
|
|
|
@ -659,7 +659,7 @@ describe('Ticket', () => {
|
|||
jest.spyOn(controller, 'resetChanges').mockReturnThis();
|
||||
|
||||
const newSale = {itemFk: 4, quantity: 10};
|
||||
const expectedParams = {itemId: 4, quantity: 10};
|
||||
const expectedParams = {barcode: 4, quantity: 10};
|
||||
const expectedResult = {
|
||||
id: 30,
|
||||
quantity: 10,
|
||||
|
|
|
@ -20,7 +20,7 @@ module.exports = Self => {
|
|||
const notifications = await models.NotificationQueue.find(
|
||||
{where: {created: {gte: new Date(Date.vnNow() - (backupPrinterNotificationDelay * 1000))},
|
||||
notificationFk: notificationName,
|
||||
status: 'sent'
|
||||
status: {neq: 'error'}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "salix-back",
|
||||
"version": "24.24.1",
|
||||
"version": "24.24.3",
|
||||
"author": "Verdnatura Levante SL",
|
||||
"description": "Salix backend",
|
||||
"license": "GPL-3.0",
|
||||
|
|
Loading…
Reference in New Issue