Merge pull request '#6321 - Negative tickets' (!1945) from 6321_negative_tickets into dev
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
Reviewed-on: #1945 Reviewed-by: Javi Gallego <jgallego@verdnatura.es>
This commit is contained in:
commit
5df24d0e70
|
@ -798,7 +798,8 @@ INSERT INTO `vn`.`ticket`(`id`, `priority`, `agencyModeFk`,`warehouseFk`,`routeF
|
|||
(34, 1, 1, 1, 3, util.VN_CURDATE(), util.VN_CURDATE(), 1103, 'BEJAR', 123, NULL, 0, 1, 16, 0, util.VN_CURDATE(), NULL, NULL, 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, 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, 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, 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, NULL, NULL),
|
||||
(1000000, NULL, 1, 1, NULL, util.VN_CURDATE(), util.VN_CURDATE(), 1, 'employee', 131, NULL, 0, 1, 1.00, 0.00, CURDATE(), NULL, NULL, '', NULL);
|
||||
|
||||
INSERT INTO `vn`.`ticketObservation`(`id`, `ticketFk`, `observationTypeFk`, `description`)
|
||||
VALUES
|
||||
|
@ -1002,7 +1003,8 @@ VALUES
|
|||
(14, 5, 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 'VT', 1, NULL, NULL, 0, NULL, 0),
|
||||
(15, 4, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 'EMB', 0, NULL, NULL, 0, NULL, 0),
|
||||
(16, 6, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 'EMB', 0, NULL, NULL, 0, NULL, 0),
|
||||
(71, 6, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL, 0);
|
||||
(71, 6, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL, 0),
|
||||
(88, 1, 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '', 'Stark Industries', 10.0, 'VT', 0, NULL, NULL, 1, NULL, 0);
|
||||
|
||||
|
||||
-- Update the taxClass after insert of the items
|
||||
|
@ -1125,7 +1127,8 @@ INSERT INTO `vn`.`sale`(`id`, `itemFk`, `ticketFk`, `concept`, `quantity`, `pric
|
|||
(39, 1, 32, 'Ranged weapon longbow 200cm', 2, 103.49, 0, 0, 0, util.VN_CURDATE(), 'hasComponentLack'),
|
||||
(40, 2, 34, 'Melee weapon combat fist 15cm', 10.00, 3.91, 0, 0, 0, util.VN_CURDATE(), 'hasComponentLack,hasItemLost'),
|
||||
(41, 2, 35, 'Melee weapon combat fist 15cm', 8.00, 3.01, 0, 0, 0, util.VN_CURDATE(), 'hasComponentLack,hasRounding,hasItemLost'),
|
||||
(42, 2, 36, 'Melee weapon combat fist 15cm', 6.00, 2.50, 0, 0, 0, util.VN_CURDATE(), 'hasComponentLack,hasRounding,hasItemLost');
|
||||
(42, 2, 36, 'Melee weapon combat fist 15cm', 6.00, 2.50, 0, 0, 0, util.VN_CURDATE(), 'hasComponentLack,hasRounding,hasItemLost'),
|
||||
(43, 88, 1000000, 'Chest medical box 2', 15.00, 10.00, 0, 0, 0, CURDATE(), '');
|
||||
|
||||
INSERT INTO `vn`.`saleComponent`(`saleFk`, `componentFk`, `value`)
|
||||
VALUES
|
||||
|
@ -1457,7 +1460,14 @@ INSERT INTO `vn`.`itemTag`(`id`,`itemFk`,`tagFk`,`value`,`priority`)
|
|||
(98, 14, 23, '1', 7),
|
||||
(99, 15, 92, 'Trolley', 2),
|
||||
(100, 16, 92, 'Pallet', 2),
|
||||
(101, 71, 92, 'Shipping cost', 2);
|
||||
(101, 71, 92, 'Shipping cost', 2),
|
||||
(102, 88, 56, 'Chest', 1),
|
||||
(103, 88, 58, 'ammo box', 2),
|
||||
(104, 88, 27, '100cm', 3),
|
||||
(105, 88, 36, 'Stark Industries', 4),
|
||||
(106, 88, 1, 'White', 5),
|
||||
(107, 88, 67, 'supply', 6),
|
||||
(108, 88, 23, '13', 7);
|
||||
|
||||
INSERT INTO `vn`.`itemTypeTag`(`id`, `itemTypeFk`, `tagFk`, `priority`)
|
||||
VALUES
|
||||
|
@ -1585,7 +1595,8 @@ INSERT INTO `bs`.`waste`(`buyerFk`, `year`, `week`, `itemFk`, `itemTypeFk`, `sal
|
|||
(15, 7, 4, 1.25, 0, 3, 1, 2.000, 2.000, 0.000, 10, 10, 'grouping', NULL, 0.00, 1.75, 1.67, 0, 1, 0, 4, util.VN_CURDATE()),
|
||||
(16, 99,1,50.0000, 5000, 4, 1, 1.500, 1.500, 0.000, 1, 1, 'packing', NULL, 0.00, 99.60, 99.40, 0, 1, 0, 1.00, '2024-07-30 08:13:51.000'),
|
||||
(17, 11, 1, 50, 5000, 4, 1, 1.500, 1.500, 0.000, 1, 1, 'packing', NULL, 0.00, 99.6, 99.4, 0, 1, 0, 1, util.VN_CURDATE() - INTERVAL 2 MONTH),
|
||||
(18, 12, 1, 50, 5000, 4, 1, 1.500, 1.500, 0.000, 1, 1, 'grouping', NULL, 0.00, 99.6, 99.4, 0, 1, 0, 1, util.VN_CURDATE() - INTERVAL 2 MONTH);
|
||||
(18, 12, 1, 50, 5000, 4, 1, 1.500, 1.500, 0.000, 1, 1, 'grouping', NULL, 0.00, 99.6, 99.4, 0, 1, 0, 1, util.VN_CURDATE() - INTERVAL 2 MONTH),
|
||||
(10000002, 12, 88, 50.0000, 5000, '4', 1, 1.500, 1.500, 0.000, 1, 1, 'grouping', NULL, 0.00, 99.60, 99.40, 0, 1, 0, 1.00, util.VN_CURDATE() - INTERVAL 2 MONTH);
|
||||
|
||||
INSERT INTO `hedera`.`order`(`id`, `date_send`, `customer_id`, `delivery_method_id`, `agency_id`, `address_id`, `company_id`, `note`, `source_app`, `confirmed`,`total`, `date_make`, `first_row_stamp`, `confirm_date`)
|
||||
VALUES
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
DELIMITER $$
|
||||
CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`item_getLack`(IN vForce BOOLEAN, IN vDays INT)
|
||||
CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`item_getLack`(
|
||||
vSelf INT,
|
||||
vForce BOOLEAN,
|
||||
vDays INT,
|
||||
vLongname VARCHAR(255),
|
||||
vProducerName VARCHAR(255),
|
||||
vColor VARCHAR(255),
|
||||
vSize INT,
|
||||
vOrigen INT,
|
||||
vLack INT,
|
||||
vWarehouseFk INT
|
||||
)
|
||||
BEGIN
|
||||
/**
|
||||
* Calcula una tabla con el máximo negativo visible para cada producto y almacen
|
||||
|
@ -47,6 +58,14 @@ BEGIN
|
|||
WHERE w.isForTicket
|
||||
AND ic.display
|
||||
AND it.code != 'GEN'
|
||||
AND (vSelf IS NULL OR i.id = vSelf)
|
||||
AND (vLongname IS NULL OR i.name = vLongname)
|
||||
AND (vProducerName IS NULL OR p.`name` LIKE CONCAT('%', vProducerName, '%'))
|
||||
AND (vColor IS NULL OR vColor = i.inkFk)
|
||||
AND (vSize IS NULL OR vSize = i.`size`)
|
||||
AND (vOrigen IS NULL OR vOrigen = w.id)
|
||||
AND (vLack IS NULL OR vLack = sub.amount)
|
||||
AND (vWarehouseFk IS NULL OR vWarehouseFk = w.id)
|
||||
GROUP BY i.id, w.id
|
||||
HAVING lack < 0;
|
||||
|
||||
|
|
|
@ -82,14 +82,19 @@ BEGIN
|
|||
AND it.priority = vPriority
|
||||
LEFT JOIN vn.tag t ON t.id = it.tagFk
|
||||
LEFT JOIN vn.buy b ON b.id = bu.buyFk
|
||||
LEFT JOIN vn.itemShelvingStock iss ON iss.itemFk = i.id
|
||||
AND iss.warehouseFk = vWarehouseFk
|
||||
LEFT JOIN vn.ink ink ON ink.id = i.tag5
|
||||
JOIN itemTags its
|
||||
WHERE a.available > 0
|
||||
AND (i.typeFk = its.typeFk OR NOT vShowType)
|
||||
AND i.id <> vSelf
|
||||
ORDER BY `counter` DESC,
|
||||
ORDER BY (a.available > 0) DESC,
|
||||
`counter` DESC,
|
||||
(t.name = its.name) DESC,
|
||||
(it.value = its.value) DESC,
|
||||
(i.tag5 = its.tag5) DESC,
|
||||
(ink.`showOrder`) DESC,
|
||||
match5 DESC,
|
||||
(i.tag6 = its.tag6) DESC,
|
||||
match6 DESC,
|
||||
|
|
|
@ -25,9 +25,11 @@ BEGIN
|
|||
DECLARE vNewSaleFk INT;
|
||||
DECLARE vFinalPrice DECIMAL(10,2);
|
||||
|
||||
|
||||
DECLARE vIsRequiredTx BOOL DEFAULT NOT @@in_transaction;
|
||||
DECLARE EXIT HANDLER FOR SQLEXCEPTION
|
||||
BEGIN
|
||||
ROLLBACK;
|
||||
CALL util.tx_rollback(vIsRequiredTx);
|
||||
RESIGNAL;
|
||||
END;
|
||||
|
||||
|
@ -129,6 +131,6 @@ BEGIN
|
|||
VALUES(vItemFk, vNewItemFk, 1)
|
||||
ON DUPLICATE KEY UPDATE counter = counter + 1;
|
||||
|
||||
COMMIT;
|
||||
CALL util.tx_commit(vIsRequiredTx);
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
INSERT IGNORE INTO salix.ACL (model,property,accessType,permission,principalType,principalId)
|
||||
VALUES
|
||||
('Ticket','itemLack','READ','ALLOW','ROLE','employee'),
|
||||
('Ticket','itemLackDetail','READ','ALLOW','ROLE','employee'),
|
||||
('Ticket','split','WRITE','ALLOW','ROLE','employee'),
|
||||
('Sale','replaceItem','WRITE','ALLOW','ROLE','employee');
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE vn.ticketConfig ADD lackAlertPrice int(11) DEFAULT 30 NOT NULL COMMENT 'Value to alert when item proposal exceed price';
|
||||
ALTER TABLE vn.ticketConfig ADD lackScopeDays int(11) DEFAULT 2 NOT NULL COMMENT 'Number of days to look back for ticket with negatives';
|
|
@ -234,6 +234,7 @@
|
|||
"It has been invoiced but the PDF of refund not be generated": "It has been invoiced but the PDF of refund not be generated",
|
||||
"Cannot add holidays on this day": "Cannot add holidays on this day",
|
||||
"Cannot send mail": "Cannot send mail",
|
||||
"This worker already exists": "This worker already exists",
|
||||
"CONSTRAINT `chkParkingCodeFormat` failed for `vn`.`parking`": "CONSTRAINT `chkParkingCodeFormat` failed for `vn`.`parking`",
|
||||
"This postcode already exists": "This postcode already exists",
|
||||
"Original invoice not found": "Original invoice not found",
|
||||
|
@ -254,5 +255,7 @@
|
|||
"Holidays to past days not available": "Holidays to past days not available",
|
||||
"Incorrect delivery order alert on route": "Incorrect delivery order alert on route: {{ route }} zone: {{ zone }}",
|
||||
"Ticket has been delivered out of order": "The ticket {{ticket}} of route {{{fullUrl}}} has been delivered out of order.",
|
||||
"clonedFromTicketWeekly": ", that is a cloned sale from ticket {{ ticketWeekly }}"
|
||||
"clonedFromTicketWeekly": ", that is a cloned sale from ticket {{ ticketWeekly }}",
|
||||
"negativeReplaced": "Replaced item [#{{oldItemId}}]({{{oldItemUrl}}}) {{oldItem}} with [#{{newItemId}}]({{{newItemUrl}}}) {{newItem}} from ticket [{{ticketId}}]({{{ticketUrl}}})",
|
||||
"The tag and priority can't be repeated": "The tag and priority can't be repeated"
|
||||
}
|
||||
|
|
|
@ -397,5 +397,6 @@
|
|||
"Incorrect delivery order alert on route": "Alerta de orden de entrega incorrecta en ruta: {{ route }} zona: {{ zone }}",
|
||||
"Ticket has been delivered out of order": "El ticket {{ticket}} {{{fullUrl}}} no ha sido entregado en su orden.",
|
||||
"Price cannot be blank": "El precio no puede estar en blanco",
|
||||
"clonedFromTicketWeekly": ", que es una linea clonada del ticket {{ticketWeekly}}"
|
||||
"clonedFromTicketWeekly": ", que es una linea clonada del ticket {{ticketWeekly}}",
|
||||
"negativeReplaced": "Sustituido el articulo [#{{oldItemId}}]({{{oldItemUrl}}}) {{oldItem}} por [#{{newItemId}}]({{{newItemUrl}}}) {{newItem}} del ticket [{{ticketId}}]({{{ticketUrl}}})"
|
||||
}
|
||||
|
|
|
@ -368,5 +368,6 @@
|
|||
"ticketLostExpedition": "Le ticket [{{ticketId}}]({{{ticketUrl}}}) a l'expédition perdue suivante : {{expeditionId}}",
|
||||
"The web user's email already exists": "L'email de l'internaute existe déjà",
|
||||
"Incorrect delivery order alert on route": "Alerte de bon de livraison incorrect sur l'itinéraire: {{ route }} zone : {{ zone }}",
|
||||
"Ticket has been delivered out of order": "Le ticket {{ticket}} de la route {{{fullUrl}}} a été livré hors service."
|
||||
"Ticket has been delivered out of order": "Le ticket {{ticket}} de la route {{{fullUrl}}} a été livré hors service.",
|
||||
"negativeReplaced": "Remplacé l'article [#{{oldItemId}}]({{{oldItemUrl}}}) {{oldItem}} par [#{{newItemId}}]({{{newItemUrl}}}) {{newItem}} du ticket [{{ticketId}}]({{{ticketUrl}}})"
|
||||
}
|
|
@ -367,5 +367,6 @@
|
|||
"ticketLostExpedition": "O ticket [{{ticketId}}]({{{ticketUrl}}}) tem a seguinte expedição perdida: {{expeditionId}}",
|
||||
"The web user's email already exists": "O e-mail do utilizador da web já existe.",
|
||||
"Incorrect delivery order alert on route": "Alerta de ordem de entrega incorreta na rota: {{ route }} zona: {{ zone }}",
|
||||
"Ticket has been delivered out of order": "O ticket {{ticket}} da rota {{{fullUrl}}} foi entregue fora de ordem."
|
||||
"Ticket has been delivered out of order": "O ticket {{ticket}} da rota {{{fullUrl}}} foi entregue fora de ordem.",
|
||||
"negativeReplaced": "Substituído o artigo [#{{oldItemId}}]({{{oldItemUrl}}}) {{oldItem}} por [#{{newItemId}}]({{{newItemUrl}}}) {{newItem}} do ticket [{{ticketId}}]({{{ticketUrl}}})"
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethod('getSimilar', {
|
||||
description: 'Returns list of items with similar item requested',
|
||||
accessType: 'READ',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'filter',
|
||||
type: 'Object',
|
||||
required: true,
|
||||
description: 'Filter defining where and paginated data',
|
||||
http: {source: 'query'}
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
type: ['Object'],
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/getSimilar`,
|
||||
verb: 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
Self.getSimilar = async(ctx, filter, options) => {
|
||||
const myOptions = {userId: ctx.req.accessToken.userId};
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
const {where} = filter;
|
||||
|
||||
const query = [
|
||||
filter.itemFk,
|
||||
where.warehouseFk,
|
||||
where.date,
|
||||
where.showType,
|
||||
where.scopeDays
|
||||
];
|
||||
const [results] = await Self.rawSql('CALL vn.item_getSimilar(?, ?, ?, ?, ?)', query, myOptions);
|
||||
|
||||
return results;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,49 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
|
||||
describe('Item get similar', () => {
|
||||
let options;
|
||||
let tx;
|
||||
const ctx = beforeAll.getCtx();
|
||||
beforeAll.mockLoopBackContext();
|
||||
beforeEach(async() => {
|
||||
tx = await models.Item.beginTransaction({});
|
||||
options = {transaction: tx};
|
||||
});
|
||||
|
||||
afterEach(async() => {
|
||||
if (tx)
|
||||
await tx.rollback();
|
||||
});
|
||||
|
||||
it('should return similar items', async() => {
|
||||
const filter = {
|
||||
itemFk: 88, sales: 43,
|
||||
where: {
|
||||
'scopeDays': '2',
|
||||
'showType': true,
|
||||
'alertLevelCode': 'FREE',
|
||||
'date': '2001-01-01T11:00:00.000Z',
|
||||
'warehouseFk': 1
|
||||
}
|
||||
};
|
||||
const result = await models.Item.getSimilar(ctx, filter, options);
|
||||
|
||||
expect(result.length).toEqual(2);
|
||||
});
|
||||
|
||||
it('should return empty array is if not exists', async() => {
|
||||
const filter = {
|
||||
itemFk: 88, sales: 43,
|
||||
where: {
|
||||
'scopeDays': '2',
|
||||
'showType': true,
|
||||
'alertLevelCode': 'FREE',
|
||||
'date': '2001-01-01T11:00:00.000Z',
|
||||
'warehouseFk': 60
|
||||
}
|
||||
};
|
||||
const result = await models.Item.getSimilar(ctx, filter, options);
|
||||
|
||||
expect(result.length).toEqual(0);
|
||||
});
|
||||
});
|
|
@ -5,6 +5,7 @@ module.exports = Self => {
|
|||
require('../methods/item/clone')(Self);
|
||||
require('../methods/item/updateTaxes')(Self);
|
||||
require('../methods/item/getBalance')(Self);
|
||||
require('../methods/item/getSimilar')(Self);
|
||||
require('../methods/item/lastEntriesFilter')(Self);
|
||||
require('../methods/item/getSummary')(Self);
|
||||
require('../methods/item/getCard')(Self);
|
||||
|
|
|
@ -31,7 +31,7 @@ describe('route getSuggestedTickets()', () => {
|
|||
const length = result.length;
|
||||
const anyResult = result[Math.floor(Math.random() * Math.floor(length))];
|
||||
|
||||
expect(result.length).toEqual(4);
|
||||
expect(result.length).toEqual(5);
|
||||
expect(anyResult.zoneFk).toEqual(1);
|
||||
expect(anyResult.agencyModeFk).toEqual(8);
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ describe('route unlink()', () => {
|
|||
let tickets = await models.Route.getSuggestedTickets(routeId, options);
|
||||
|
||||
expect(zoneAgencyModes.length).toEqual(4);
|
||||
expect(tickets.length).toEqual(3);
|
||||
expect(tickets.length).toEqual(4);
|
||||
|
||||
await models.Route.unlink(agencyModeId, zoneId, options);
|
||||
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('replaceItem', {
|
||||
description: 'Replace item from sale',
|
||||
accessType: 'WRITE',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'saleFk',
|
||||
type: 'number',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
arg: 'substitutionFk',
|
||||
type: 'number',
|
||||
required: true
|
||||
},
|
||||
{
|
||||
arg: 'quantity',
|
||||
type: 'number',
|
||||
required: true
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
type: 'object',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/replaceItem`,
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
Self.replaceItem = async(ctx, saleFk, substitutionFk, quantity, options) => {
|
||||
const myOptions = {userId: ctx.req.accessToken.userId};
|
||||
let tx;
|
||||
const $t = ctx.req.__;
|
||||
|
||||
const models = Self.app.models;
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
if (!myOptions.transaction) {
|
||||
tx = await Self.beginTransaction({});
|
||||
myOptions.transaction = tx;
|
||||
}
|
||||
|
||||
try {
|
||||
const replaceItemQuery = {
|
||||
sql: 'CALL sale_replaceItem(?,?,?)',
|
||||
query: [saleFk, substitutionFk, quantity]
|
||||
};
|
||||
const resultReplaceItem = await Self.rawSql(replaceItemQuery.sql, replaceItemQuery.query, myOptions);
|
||||
const sale = await models.Sale.findById(saleFk, {
|
||||
fields: ['id', 'ticketFk', 'itemFk', 'quantity', 'price'],
|
||||
include: [
|
||||
{
|
||||
relation: 'ticket',
|
||||
scope: {
|
||||
fields: ['id']
|
||||
},
|
||||
}, {
|
||||
relation: 'item',
|
||||
scope: {
|
||||
fields: ['id', 'name', 'longName']
|
||||
}
|
||||
}
|
||||
]
|
||||
}, myOptions);
|
||||
|
||||
const salesPersonQuery = {
|
||||
sql: 'SELECT vn.client_getSalesPersonByTicket(?)',
|
||||
query: [sale.ticketFk]
|
||||
};
|
||||
const salesPerson = await Self.rawSql(salesPersonQuery.sql, salesPersonQuery.query, myOptions);
|
||||
const url = await models.Url.getUrl();
|
||||
const substitution = await models.Item.findById(substitutionFk, {
|
||||
fields: ['id', 'name', 'longName']
|
||||
}, myOptions);
|
||||
|
||||
const message = $t('negativeReplaced', {
|
||||
oldItemId: sale.itemFk,
|
||||
oldItem: sale.item().longName,
|
||||
oldItemUrl: `${url}item/${sale.itemFk}/summary`,
|
||||
newItemId: substitution.id,
|
||||
newItem: substitution.longName,
|
||||
newItemUrl: `${url}item/${substitution.id}/summary`,
|
||||
ticketId: sale.ticketFk,
|
||||
ticketUrl: `${url}ticket/${sale.ticketFk}/sale`
|
||||
});
|
||||
await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message);
|
||||
|
||||
return resultReplaceItem;
|
||||
} catch (e) {
|
||||
if (tx) await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
};
|
|
@ -0,0 +1,61 @@
|
|||
const {models} = require('vn-loopback/server/server');
|
||||
|
||||
describe('Sale - replaceItem function', () => {
|
||||
let options;
|
||||
let tx;
|
||||
const ctx = beforeAll.getCtx();
|
||||
beforeAll.mockLoopBackContext();
|
||||
beforeEach(async() => {
|
||||
tx = await models.Sale.beginTransaction({});
|
||||
options = {transaction: tx};
|
||||
});
|
||||
|
||||
afterEach(async() => {
|
||||
if (tx)
|
||||
await tx.rollback();
|
||||
});
|
||||
|
||||
it('should replace full item in sale and send notification', async() => {
|
||||
const saleFk = 43;
|
||||
const substitutionFk = 3;
|
||||
const quantity = 15;
|
||||
const ticketFk = 1000000;
|
||||
|
||||
const salesBefore = await models.Sale.find({where: {ticketFk}}, options);
|
||||
const salesLength = salesBefore.length;
|
||||
|
||||
expect(1).toEqual(salesBefore.length);
|
||||
|
||||
await models.Sale.replaceItem(ctx, saleFk, substitutionFk, quantity, options);
|
||||
const salesAfter = await models.Sale.find({where: {ticketFk}}, options);
|
||||
|
||||
expect(salesLength).toBeLessThan(salesAfter.length);
|
||||
expect(salesAfter[0].id).toEqual(saleFk);
|
||||
expect(salesAfter[salesLength].itemFk).toEqual(substitutionFk);
|
||||
expect(salesAfter[salesLength].quantity).toEqual(quantity);
|
||||
expect(salesAfter[0].quantity).toEqual(0);
|
||||
expect(salesAfter[salesLength].concept).toMatch(/^\+/);
|
||||
});
|
||||
|
||||
it('should replace half item in sale and send notification', async() => {
|
||||
const saleFk = 43;
|
||||
const substitutionFk = 3;
|
||||
const quantity = 10;
|
||||
const ticketFk = 1000000;
|
||||
|
||||
const salesBefore = await models.Sale.find({where: {ticketFk}}, options);
|
||||
const salesLength = salesBefore.length;
|
||||
|
||||
expect(1).toEqual(salesBefore.length);
|
||||
|
||||
await models.Sale.replaceItem(ctx, saleFk, substitutionFk, quantity, options);
|
||||
const salesAfter = await models.Sale.find({where: {ticketFk}}, options);
|
||||
|
||||
expect(salesLength).toBeLessThan(salesAfter.length);
|
||||
expect(salesAfter[0].id).toEqual(saleFk);
|
||||
expect(salesAfter[salesLength].itemFk).toEqual(substitutionFk);
|
||||
expect(salesAfter[salesLength].quantity).toEqual(quantity);
|
||||
expect(salesAfter[0].quantity).toEqual(5);
|
||||
expect(salesAfter[salesLength].concept).toMatch(/^\+/);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,111 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethod('itemLack', {
|
||||
description: 'Get tickets as negative status',
|
||||
accessType: 'READ',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'ctx',
|
||||
type: 'object',
|
||||
http: {source: 'context'}
|
||||
},
|
||||
{
|
||||
arg: 'filter',
|
||||
type: 'object',
|
||||
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
|
||||
http: {source: 'query'}
|
||||
},
|
||||
{
|
||||
arg: 'id',
|
||||
type: 'number',
|
||||
description: 'The item id',
|
||||
},
|
||||
{
|
||||
arg: 'longname',
|
||||
type: 'string',
|
||||
description: 'Article name',
|
||||
},
|
||||
{
|
||||
arg: 'supplier',
|
||||
type: 'string',
|
||||
description: 'Supplier id',
|
||||
},
|
||||
{
|
||||
arg: 'colour',
|
||||
type: 'string',
|
||||
description: 'Colour\'s item',
|
||||
},
|
||||
{
|
||||
arg: 'size',
|
||||
type: 'string',
|
||||
description: 'Size\'s item',
|
||||
},
|
||||
{
|
||||
arg: 'origen',
|
||||
type: 'string',
|
||||
description: 'origen id',
|
||||
},
|
||||
{
|
||||
arg: 'warehouseFk',
|
||||
type: 'number',
|
||||
description: 'The warehouse id',
|
||||
},
|
||||
{
|
||||
arg: 'lack',
|
||||
type: 'number',
|
||||
description: 'The item id',
|
||||
},
|
||||
{
|
||||
arg: 'days',
|
||||
type: 'number',
|
||||
description: 'The range days',
|
||||
}
|
||||
],
|
||||
returns: [
|
||||
{
|
||||
arg: 'body',
|
||||
type: ['object'],
|
||||
root: true
|
||||
}
|
||||
],
|
||||
http: {
|
||||
path: `/itemLack`,
|
||||
verb: 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
Self.itemLack = async(ctx, filter, options) => {
|
||||
const myOptions = {};
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
const filterKeyOrder = [
|
||||
'id', 'force', 'days', 'longname', 'supplier',
|
||||
'colour', 'size', 'originFk',
|
||||
'lack', 'warehouseFk'
|
||||
];
|
||||
|
||||
delete ctx?.args?.ctx;
|
||||
|
||||
delete ctx?.args?.filter;
|
||||
|
||||
Object.assign(filter, ctx.args ?? {});
|
||||
|
||||
let procedureParams = [];
|
||||
procedureParams.push(...filterKeyOrder.map(clave => filter[clave] ?? null));
|
||||
|
||||
// Default values
|
||||
const forceIndex = filterKeyOrder.indexOf('force');
|
||||
if (!procedureParams[forceIndex])procedureParams[forceIndex] = true;
|
||||
const daysIndex = filterKeyOrder.indexOf('days');
|
||||
if (!procedureParams[daysIndex])procedureParams[daysIndex] = 2;
|
||||
const procedureArgs = Array(procedureParams.length).fill('?').join(', ');
|
||||
|
||||
let query = `CALL vn.item_getLack(${procedureArgs})`;
|
||||
|
||||
const result = await Self.rawSql(query, procedureParams, myOptions);
|
||||
|
||||
const itemsIndex = 0;
|
||||
return result[itemsIndex];
|
||||
};
|
||||
};
|
|
@ -0,0 +1,167 @@
|
|||
const {ParameterizedSQL} = require('loopback-connector');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethod('itemLackDetail', {
|
||||
description: 'Retrieve detail from ticket as negative',
|
||||
accessType: 'READ',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'itemFk',
|
||||
type: 'number',
|
||||
description: 'The item as negative status',
|
||||
},
|
||||
{
|
||||
arg: 'filter',
|
||||
type: 'object',
|
||||
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
|
||||
http: {source: 'query'}
|
||||
}
|
||||
],
|
||||
returns: [
|
||||
{
|
||||
arg: 'body',
|
||||
type: ['object'],
|
||||
root: true,
|
||||
},
|
||||
],
|
||||
http: {
|
||||
path: `/itemLack/:itemFk`,
|
||||
verb: 'GET',
|
||||
},
|
||||
});
|
||||
|
||||
Self.itemLackDetail = async(itemFk, filter, options) => {
|
||||
const conn = Self.dataSource.connector;
|
||||
|
||||
const myOptions = {};
|
||||
if (typeof options == 'object') Object.assign(myOptions, options);
|
||||
const vDated = (Date.vnNew());
|
||||
vDated.setHours(0, 0, 0, 0);
|
||||
const scopeDays = filter.where.scopeDays ?? 0;
|
||||
let alertLevels = filter.where.alertLevelCode;
|
||||
|
||||
if (!alertLevels)
|
||||
alertLevels = (await Self.app.models.AlertLevel.find({fields: ['code']})).map(({code}) => code);
|
||||
|
||||
const stmt = new ParameterizedSQL(`
|
||||
SELECT s.id,
|
||||
st.code,
|
||||
t.id,
|
||||
t.nickname,
|
||||
c.id customerId,
|
||||
t.shipped,
|
||||
s.quantity,
|
||||
ag.name,
|
||||
ag.id agencyFk,
|
||||
tls.alertLevel alertLevel,
|
||||
st.name stateName,
|
||||
s.id saleFk,
|
||||
s.itemFk,
|
||||
s.price price,
|
||||
al.code alertLevelCode,
|
||||
z.name zoneName,
|
||||
z.id zoneFk,
|
||||
z.hour theoreticalhour,
|
||||
cn.isRookie,
|
||||
sc.saleClonedFk turno,
|
||||
tr.saleFk peticionCompra,
|
||||
DATE_FORMAT(IF(HOUR(t.shipped), t.shipped, IF(zc.hour, zc.hour, z.hour)),'%H:%i') minTimed,
|
||||
FALSE isBasket,
|
||||
substitution.hasObservation,
|
||||
(d.code = 'spainTeamVip') hasToIgnore
|
||||
FROM sale s
|
||||
LEFT JOIN saleGroupDetail sgd ON sgd.saleFk = s.id
|
||||
JOIN ticket t ON t.id = s.ticketFk
|
||||
LEFT JOIN zone z ON z.id = t.zoneFk
|
||||
LEFT JOIN zoneClosure zc ON zc.zoneFk = t.zoneFk
|
||||
AND t.shipped BETWEEN zc.dated AND util.dayEnd(t.shipped)
|
||||
JOIN client c ON c.id=t.clientFk
|
||||
LEFT JOIN bs.clientNewBorn cn ON cn.clientFk=c.id
|
||||
JOIN agencyMode ag ON ag.id=t.agencyModeFk
|
||||
JOIN ticketState tls ON tls.ticketFk=t.id
|
||||
LEFT JOIN state st ON st.id=tls.state
|
||||
LEFT JOIN alertLevel al ON al.id = st.alertLevel
|
||||
LEFT JOIN saleCloned sc ON sc.saleClonedFk = s.id
|
||||
LEFT JOIN ticketRequest tr ON tr.saleFk = s.id
|
||||
LEFT JOIN workerDepartment wd ON wd.workerFk = c.salesPersonFk
|
||||
LEFT JOIN department d ON d.id = wd.departmentFk
|
||||
LEFT JOIN (
|
||||
SELECT co.clientFk, COUNT(*) hasObservation
|
||||
FROM clientObservation co
|
||||
JOIN observationType ot ON ot.id = co.observationTypeFk
|
||||
WHERE ot.code = 'substitution'
|
||||
GROUP BY co.clientFk
|
||||
) substitution ON substitution.clientFk = c.id
|
||||
WHERE t.warehouseFk = ?
|
||||
AND s.itemFk = ?
|
||||
AND s.quantity <> 0
|
||||
|
||||
AND t.shipped BETWEEN ? AND (? + INTERVAL ? DAY)
|
||||
|
||||
AND sgd.saleFk IS NULL
|
||||
AND (al.code IN (?) OR al.id IS NULL)
|
||||
UNION ALL
|
||||
SELECT r.id,
|
||||
NULL,
|
||||
r.orderFk,
|
||||
c.name customerName,
|
||||
c.id customerId,
|
||||
r.shipment,
|
||||
r.amount,
|
||||
ag.name,
|
||||
ag.id,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
r.itemFk,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
cn.isRookie,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
TRUE,
|
||||
substitution.hasObservation,
|
||||
d.code = 'spainTeamVip'
|
||||
FROM hedera.orderRow r
|
||||
JOIN hedera.order o ON o.id = r.orderFk
|
||||
JOIN client c ON c.id = o.customer_id
|
||||
JOIN agencyMode ag ON ag.id=o.agency_id
|
||||
LEFT JOIN bs.clientNewBorn cn ON cn.clientFk=c.id
|
||||
LEFT JOIN workerDepartment wd ON wd.workerFk = c.salesPersonFk
|
||||
LEFT JOIN department d ON d.id = wd.departmentFk
|
||||
LEFT JOIN (
|
||||
SELECT co.clientFk, COUNT(*) hasObservation
|
||||
FROM clientObservation co
|
||||
JOIN observationType ot ON ot.id = co.observationTypeFk
|
||||
WHERE ot.code = 'substitution'
|
||||
GROUP BY co.clientFk
|
||||
) substitution ON substitution.clientFk = c.id
|
||||
WHERE r.shipment BETWEEN ? AND ? + INTERVAL ? DAY
|
||||
AND r.created >= ?
|
||||
AND r.warehouseFk = ?
|
||||
AND NOT o.confirmed
|
||||
AND r.itemFk = ?
|
||||
AND r.amount
|
||||
ORDER BY hasToIgnore, isBasket
|
||||
`,
|
||||
[
|
||||
filter.where.warehouseFk,
|
||||
itemFk,
|
||||
vDated, vDated,
|
||||
scopeDays,
|
||||
alertLevels,
|
||||
scopeDays,
|
||||
vDated, vDated, vDated,
|
||||
filter.where.warehouseFk,
|
||||
itemFk
|
||||
]);
|
||||
|
||||
const sql = ParameterizedSQL.join([stmt], ';');
|
||||
const result = await conn.executeStmt(sql, myOptions);
|
||||
return result;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,80 @@
|
|||
const {models} = require('vn-loopback/server/server');
|
||||
|
||||
describe('Item Lack', () => {
|
||||
let options;
|
||||
let tx;
|
||||
const ctx = beforeAll.getCtx();
|
||||
beforeAll.mockLoopBackContext();
|
||||
|
||||
beforeEach(async() => {
|
||||
tx = await models.Ticket.beginTransaction({});
|
||||
options = {transaction: tx};
|
||||
});
|
||||
|
||||
afterEach(async() => {
|
||||
if (tx)
|
||||
await tx.rollback();
|
||||
});
|
||||
|
||||
it('should return data with NO filters', async() => {
|
||||
const filter = {};
|
||||
const result = await models.Ticket.itemLack(ctx, filter, options);
|
||||
|
||||
expect(result.length).toEqual(2);
|
||||
});
|
||||
|
||||
it('should return data with filter.id', async() => {
|
||||
const filter = {
|
||||
id: 5
|
||||
};
|
||||
const result = await models.Ticket.itemLack(ctx, filter, options);
|
||||
|
||||
expect(result.length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should return data with filter.longname', async() => {
|
||||
const filter = {
|
||||
longname: 'Ranged weapon pistol 9mm'
|
||||
};
|
||||
const result = await models.Ticket.itemLack(ctx, filter, options);
|
||||
|
||||
expect(result.length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should return data with filter.color', async() => {
|
||||
const filter = {
|
||||
colour: 'WHT'
|
||||
};
|
||||
const result = await models.Ticket.itemLack(ctx, filter, options);
|
||||
|
||||
expect(result.length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should return data with filter.origen', async() => {
|
||||
const filter = {
|
||||
originFk: 1
|
||||
};
|
||||
const result = await models.Ticket.itemLack(ctx, filter, options);
|
||||
|
||||
expect(result.length).toEqual(2);
|
||||
});
|
||||
|
||||
it('should return data with filter.size', async() => {
|
||||
const filter = {
|
||||
size: '15'
|
||||
};
|
||||
const result = await models.Ticket.itemLack(ctx, filter, options);
|
||||
|
||||
expect(result.length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should return data with filter.lack', async() => {
|
||||
const filter = {
|
||||
lack: '-15'
|
||||
};
|
||||
|
||||
const result = await models.Ticket.itemLack(ctx, filter, options);
|
||||
|
||||
expect(result.length).toEqual(1);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,55 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
|
||||
describe('Item Lack Detail', () => {
|
||||
it('should return false if id is null', async() => {
|
||||
const tx = await models.Ticket.beginTransaction({});
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
const itemFk = null;
|
||||
|
||||
const filter = {where: {warehouseFk: 60}};
|
||||
const result = await models.Ticket.itemLackDetail(itemFk, filter, options);
|
||||
|
||||
expect(result.length).toEqual(0);
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
it('should return data if id exists', async() => {
|
||||
const tx = await models.Ticket.beginTransaction({});
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
const itemFk = 1167;
|
||||
const filter = {where: {warehouseFk: 60}};
|
||||
const result = await models.Ticket.itemLackDetail(itemFk, filter, options);
|
||||
|
||||
expect(result.length).toEqual(0);
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
it('should return error is if not exists', async() => {
|
||||
const tx = await models.Ticket.beginTransaction({});
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
const itemFk = 0;
|
||||
const filter = {where: {warehouseFk: 60}};
|
||||
const result = await models.Ticket.itemLackDetail(itemFk, filter, options);
|
||||
|
||||
expect(result.length).toEqual(0);
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
});
|
|
@ -0,0 +1,47 @@
|
|||
const {models} = require('vn-loopback/server/server');
|
||||
|
||||
describe('Split', () => {
|
||||
let options;
|
||||
let tx;
|
||||
const ctx = beforeAll.getCtx();
|
||||
beforeAll.mockLoopBackContext();
|
||||
|
||||
beforeEach(async() => {
|
||||
tx = await models.Ticket.beginTransaction({});
|
||||
options = {transaction: tx};
|
||||
});
|
||||
|
||||
afterEach(async() => {
|
||||
if (tx)
|
||||
await tx.rollback();
|
||||
});
|
||||
|
||||
it('should split tickets with count 1', async() => {
|
||||
const data =
|
||||
{ticketFk: 7, sales: [1]};
|
||||
const result = await models.Ticket.split(ctx, data, options);
|
||||
|
||||
expect(data.ticketFk).toEqual(result.ticket);
|
||||
expect('noSplit').toEqual(result.status);
|
||||
});
|
||||
|
||||
it('should split tickets with count 2 and error', async() => {
|
||||
const data =
|
||||
{ticketFk: 11, sales: [7]}
|
||||
;
|
||||
const result = await models.Ticket.split(ctx, data, options);
|
||||
|
||||
expect(data.ticketFk).toEqual(result.ticket);
|
||||
expect('error').toEqual(result.status);
|
||||
expect('Can\'t transfer claimed sales').toEqual(result.message);
|
||||
});
|
||||
|
||||
it('should split tickets with count 2 and success', async() => {
|
||||
const data =
|
||||
{ticketFk: 14, sales: [33]};
|
||||
const result = await models.Ticket.split(ctx, data, options);
|
||||
|
||||
expect(data.ticketFk).toEqual(result.ticket);
|
||||
expect('split').toEqual(result.status);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,73 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('split', {
|
||||
description: 'Split ticket with custom date',
|
||||
accessType: 'WRITE',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'ticket',
|
||||
type: 'Object',
|
||||
required: true,
|
||||
http: {source: 'body'}
|
||||
},
|
||||
{
|
||||
arg: 'date',
|
||||
type: 'date',
|
||||
required: true,
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
type: ['Object'],
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/split`,
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
Self.split = async(ctx, ticket, options) => {
|
||||
const {ticketFk} = ticket;
|
||||
const models = Self.app.models;
|
||||
const myOptions = {};
|
||||
let tx;
|
||||
let result = [];
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
if (!myOptions.transaction) {
|
||||
tx = await Self.beginTransaction({});
|
||||
myOptions.transaction = tx;
|
||||
}
|
||||
try {
|
||||
const count = await models.Sale.count({
|
||||
ticketFk
|
||||
}, myOptions);
|
||||
if (count === 1)
|
||||
return {ticket: ticketFk, status: 'noSplit'};
|
||||
|
||||
const [, [{vNewTicket}]] = await Self.rawSql(`
|
||||
CALL vn.ticket_clone(?, @vNewTicket);
|
||||
SELECT @vNewTicket vNewTicket;`,
|
||||
[ticketFk], myOptions);
|
||||
|
||||
if (vNewTicket === 0) return result;
|
||||
const sales = await models.Sale.find({
|
||||
where: {id: {inq: ticket.sales}}
|
||||
}, myOptions);
|
||||
|
||||
const updateIsPicked = sales.map(({sid}) => Self.rawSql(`
|
||||
UPDATE vn.sale SET isPicked = (id = ?) WHERE ticketFk = ?`,
|
||||
[sid, ticketFk], myOptions));
|
||||
|
||||
await Promise.all(updateIsPicked);
|
||||
await Self.transferSales(ctx, ticketFk, vNewTicket, sales, myOptions);
|
||||
|
||||
await Self.rawSql(`CALL vn.ticket_setState(?, ?)`, [ticketFk, 'FIXING'], myOptions);
|
||||
if (tx) await tx.commit();
|
||||
return {ticket: ticketFk, newTicket: vNewTicket, status: 'split'};
|
||||
} catch (e) {
|
||||
if (tx) await tx.rollback();
|
||||
return {ticket: ticketFk, status: 'error', message: e.message};
|
||||
}
|
||||
};
|
||||
};
|
|
@ -43,8 +43,8 @@ module.exports = Self => {
|
|||
const {code} = await models.State.findById(params.stateFk, {fields: ['code']}, myOptions);
|
||||
params.code = code;
|
||||
} else {
|
||||
const {id} = await models.State.findOne({where: {code: params.code}}, myOptions);
|
||||
params.stateFk = id;
|
||||
const state = await models.State.findOne({where: {id: params.code}}, myOptions);
|
||||
params.stateFk = state.id;
|
||||
}
|
||||
|
||||
if (!params.userFk) {
|
||||
|
|
|
@ -13,6 +13,7 @@ module.exports = Self => {
|
|||
require('../methods/sale/usesMana')(Self);
|
||||
require('../methods/sale/clone')(Self);
|
||||
require('../methods/sale/getFromSectorCollection')(Self);
|
||||
require('../methods/sale/replaceItem')(Self);
|
||||
|
||||
Self.validatesPresenceOf('concept', {
|
||||
message: `Concept cannot be blank`
|
||||
|
|
|
@ -26,6 +26,12 @@
|
|||
},
|
||||
"defaultAttenderFk": {
|
||||
"type": "number"
|
||||
},
|
||||
"lackAlertPrice": {
|
||||
"type": "number"
|
||||
},
|
||||
"lackScopeDays": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
|
|
|
@ -46,5 +46,8 @@ module.exports = function(Self) {
|
|||
require('../methods/ticket/docuwareDownload')(Self);
|
||||
require('../methods/ticket/myLastModified')(Self);
|
||||
require('../methods/ticket/setWeight')(Self);
|
||||
require('../methods/ticket/itemLack')(Self);
|
||||
require('../methods/ticket/itemLackDetail')(Self);
|
||||
require('../methods/ticket/split')(Self);
|
||||
require('../methods/ticket/getTicketProblems')(Self);
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue