Merge pull request 'feat: refs #7704 Major changes' (!2717) from 7704-itemMinimalQuantity into dev
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
Reviewed-on: #2717 Reviewed-by: Javi Gallego <jgallego@verdnatura.es>
This commit is contained in:
commit
9b8e2e1279
|
@ -115,6 +115,9 @@ INSERT INTO `hedera`.`tpvConfig`(`id`, `currency`, `terminal`, `transactionType`
|
|||
VALUES
|
||||
(1, 978, 1, 0, 2000, 9, 0);
|
||||
|
||||
INSERT INTO hedera.orderConfig (`id`, `employeeFk`, `defaultAgencyFk`, `guestMethod`, `guestAgencyFk`, `reserveTime`, `defaultCompanyFk`)
|
||||
VALUES (1, 1, 2, 'PICKUP', 1, '00:20:00', 442);
|
||||
|
||||
INSERT INTO `account`.`user`(`id`,`name`,`nickname`, `password`,`role`,`active`,`email`,`lang`, `image`)
|
||||
VALUES
|
||||
(1101, 'brucewayne', 'Bruce Wayne', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 2, 1, 'BruceWayne@mydomain.com', 'es','1101'),
|
||||
|
@ -301,6 +304,17 @@ UPDATE `vn`.`agencyMode` SET `deliveryMethodFk` = 1 WHERE `id` = 8;
|
|||
UPDATE `vn`.`agencyMode` SET `deliveryMethodFk` = 4 WHERE `id` = 23;
|
||||
UPDATE `vn`.`agencyMode` SET `deliveryMethodFk` = 1 WHERE `id` = 10;
|
||||
|
||||
UPDATE `vn`.`agencyMode` SET `description` = 'inhouse pickup' WHERE `id` = 1;
|
||||
UPDATE `vn`.`agencyMode` SET `description` = 'Super-Man delivery' WHERE `id` = 2;
|
||||
UPDATE `vn`.`agencyMode` SET `description` = 'Teleportation device' WHERE `id` = 3;
|
||||
UPDATE `vn`.`agencyMode` SET `description` = 'Entanglement' WHERE `id` = 4;
|
||||
UPDATE `vn`.`agencyMode` SET `description` = 'Quantum break device' WHERE `id` = 5;
|
||||
UPDATE `vn`.`agencyMode` SET `description` = 'Walking' WHERE `id` = 6;
|
||||
UPDATE `vn`.`agencyMode` SET `description` = 'Gotham247' WHERE `id` = 7;
|
||||
UPDATE `vn`.`agencyMode` SET `description` = 'Gotham247Expensive' WHERE `id` = 8;
|
||||
UPDATE `vn`.`agencyMode` SET `description` = 'Other agency' WHERE `id` = 10;
|
||||
UPDATE `vn`.`agencyMode` SET `description` = 'Refund' WHERE `id` = 23;
|
||||
|
||||
UPDATE `vn`.`agencyMode` SET `web` = 1, `reportMail` = 'no-reply@gothamcity.com';
|
||||
|
||||
UPDATE `vn`.`agencyMode` SET `code` = 'refund' WHERE `id` = 23;
|
||||
|
@ -979,6 +993,14 @@ INSERT INTO `vn`.`priceFixed`(`id`, `itemFk`, `rate0`, `rate1`, `rate2`, `rate3`
|
|||
(2, 3, 10, 10, 10, 10, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH), 0, 1, util.VN_CURDATE()),
|
||||
(3, 13, 8.5, 10, 7.5, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH), 1, 2, util.VN_CURDATE());
|
||||
|
||||
INSERT INTO `vn`.`itemMinimumQuantity`(`itemFk`, `quantity`, `started`, `ended`, `warehouseFk`)
|
||||
VALUES
|
||||
(1, 5, util.VN_CURDATE() - INTERVAL 2 MONTH, util.VN_CURDATE() + INTERVAL 1 MONTH, 1),
|
||||
(2, 10, util.VN_CURDATE() - INTERVAL 2 DAY, NULL, 2),
|
||||
(3, 15, util.VN_CURDATE() + INTERVAL 3 DAY, util.VN_CURDATE() + INTERVAL 2 WEEK, 3),
|
||||
(2, 10, util.VN_CURDATE() + INTERVAL 2 MONTH, NULL, 5),
|
||||
(4, 8, util.VN_CURDATE() - INTERVAL 3 MONTH, NULL, NULL);
|
||||
|
||||
INSERT INTO `vn`.`expeditionBoxVol`(`boxFk`, `m3`, `ratio`)
|
||||
VALUES
|
||||
(71,0.141,1);
|
||||
|
|
|
@ -25,12 +25,7 @@ BEGIN
|
|||
JOIN vn.warehouse w ON w.id = p.warehouseFk
|
||||
ORDER BY warehouseFk, `grouping`;
|
||||
|
||||
DROP TEMPORARY TABLE
|
||||
tmp.ticketCalculateItem,
|
||||
tmp.ticketComponentPrice,
|
||||
tmp.ticketComponent,
|
||||
tmp.ticketLot,
|
||||
tmp.zoneGetShipped,
|
||||
tmp.item;
|
||||
CALL vn.ticketCalculatePurge();
|
||||
DROP TEMPORARY TABLE tmp.item;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
|
|
@ -56,11 +56,15 @@ BEGIN
|
|||
CALL util.throw ('ORDER_ROW_UNAVAILABLE');
|
||||
END IF;
|
||||
|
||||
SELECT IFNULL(minQuantity, 0) INTO vMinQuantity
|
||||
FROM vn.item
|
||||
WHERE id = vItem;
|
||||
SELECT quantity INTO vMinQuantity
|
||||
FROM vn.itemMinimumQuantity
|
||||
WHERE itemFk = vItem
|
||||
AND `started` <= vShipment
|
||||
AND (`ended` >= vShipment OR `ended` IS NULL)
|
||||
AND (warehouseFk = vWarehouse OR warehouseFk IS NULL)
|
||||
LIMIT 1;
|
||||
|
||||
IF vAmount < LEAST(vMinQuantity, vAvailable) THEN
|
||||
IF vAmount < LEAST(IFNULL(vMinQuantity, 0), vAvailable) THEN
|
||||
CALL util.throw ('quantityLessThanMin');
|
||||
END IF;
|
||||
|
||||
|
|
|
@ -45,8 +45,7 @@ BEGIN
|
|||
|
||||
CALL catalog_componentPrepare();
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.ticketCalculateItem;
|
||||
CREATE TEMPORARY TABLE tmp.ticketCalculateItem(
|
||||
CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem(
|
||||
itemFk INT(11) NOT NULL,
|
||||
available INT(11),
|
||||
producer VARCHAR(50),
|
||||
|
@ -60,11 +59,11 @@ BEGIN
|
|||
price DECIMAL(10,2),
|
||||
priceKg DECIMAL(10,2),
|
||||
`grouping` INT(10) UNSIGNED,
|
||||
minQuantity INT(10) UNSIGNED,
|
||||
PRIMARY KEY `itemFk` (`itemFk`)
|
||||
) ENGINE = MEMORY DEFAULT CHARSET=utf8;
|
||||
|
||||
OPEN cTravelTree;
|
||||
|
||||
l: LOOP
|
||||
SET vDone = FALSE;
|
||||
FETCH cTravelTree INTO vZoneFk, vWarehouseFk, vShipped;
|
||||
|
@ -136,7 +135,7 @@ BEGIN
|
|||
|
||||
CALL vn.catalog_componentCalculate(vZoneFk, vAddressFk, vShipped, vWarehouseFk);
|
||||
|
||||
INSERT INTO tmp.ticketCalculateItem (
|
||||
INSERT INTO tmp.ticketCalculateItem(
|
||||
itemFk,
|
||||
available,
|
||||
producer,
|
||||
|
@ -149,9 +148,9 @@ BEGIN
|
|||
origin,
|
||||
price,
|
||||
priceKg,
|
||||
`grouping`)
|
||||
SELECT
|
||||
tl.itemFk,
|
||||
`grouping`,
|
||||
minQuantity)
|
||||
SELECT tl.itemFk,
|
||||
SUM(tl.available) available,
|
||||
p.name producer,
|
||||
i.name item,
|
||||
|
@ -163,7 +162,8 @@ BEGIN
|
|||
o.code origin,
|
||||
bl.price,
|
||||
bl.priceKg,
|
||||
bl.`grouping`
|
||||
bl.`grouping`,
|
||||
mq.quantity
|
||||
FROM tmp.ticketLot tl
|
||||
JOIN item i ON tl.itemFk = i.id
|
||||
LEFT JOIN producer p ON p.id = i.producerFk AND p.isVisible
|
||||
|
@ -179,12 +179,19 @@ BEGIN
|
|||
) sub
|
||||
GROUP BY itemFk
|
||||
) bl ON bl.itemFk = tl.itemFk
|
||||
LEFT JOIN (
|
||||
SELECT itemFk, quantity, warehouseFk
|
||||
FROM itemMinimumQuantity
|
||||
WHERE `started` <= vShipped
|
||||
AND (`ended` >= vShipped OR `ended` IS NULL)
|
||||
GROUP BY itemFk, warehouseFk
|
||||
ORDER BY warehouseFk DESC
|
||||
) mq ON mq.itemFk = tl.itemFk
|
||||
AND (mq.warehouseFk = tl.warehouseFk OR mq.warehouseFk IS NULL)
|
||||
WHERE tl.zoneFk = vZoneFk AND tl.warehouseFk = vWarehouseFk
|
||||
GROUP BY tl.itemFk
|
||||
ON DUPLICATE KEY UPDATE available = available + VALUES(available);
|
||||
|
||||
END LOOP;
|
||||
|
||||
CLOSE cTravelTree;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
|
|
@ -63,7 +63,7 @@ BEGIN
|
|||
WHEN b.groupingMode = 'grouping' THEN b.grouping
|
||||
WHEN b.groupingMode = 'packing' THEN b.packing
|
||||
ELSE 1
|
||||
END AS minQuantity,
|
||||
END minQuantity,
|
||||
v.visible located,
|
||||
b.price2
|
||||
FROM vn.item i
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
DELIMITER $$
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`itemMinimumQuantity_afterDelete`
|
||||
AFTER DELETE ON `itemMinimumQuantity`
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
INSERT INTO itemLog
|
||||
SET `action` = 'delete',
|
||||
`changedModel` = 'ItemMinimumQuantity',
|
||||
`changedModelId` = OLD.id,
|
||||
`userFk` = account.myUser_getId();
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -0,0 +1,8 @@
|
|||
DELIMITER $$
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`itemMinimumQuantity_beforeInsert`
|
||||
BEFORE INSERT ON `itemMinimumQuantity`
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
SET NEW.editorFk = account.myUser_getId();
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -0,0 +1,8 @@
|
|||
DELIMITER $$
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`itemMinimumQuantity_beforeUpdate`
|
||||
BEFORE UPDATE ON `itemMinimumQuantity`
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
SET NEW.editorFk = account.myUser_getId();
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -1,5 +1,5 @@
|
|||
DELIMITER $$
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`itemShelving _afterDelete`
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`itemShelving_afterDelete`
|
||||
AFTER DELETE ON `itemShelving`
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
|
|
|
@ -54,8 +54,7 @@ AS SELECT `b`.`entryFk` AS `Id_Entrada`,
|
|||
`i`.`packingOut` AS `packingOut`,
|
||||
`b`.`itemOriginalFk` AS `itemOriginalFk`,
|
||||
`io`.`longName` AS `itemOriginalName`,
|
||||
`it`.`gramsMax` AS `gramsMax`,
|
||||
`i`.`minQuantity` AS `minQuantity`
|
||||
`it`.`gramsMax` AS `gramsMax`
|
||||
FROM (
|
||||
(
|
||||
(
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
ALTER TABLE vn.item CHANGE minQuantity minQuantity__ int(10) unsigned DEFAULT
|
||||
NULL NULL COMMENT '@deprecated 2024-07-11 refs #7704 Cantidad mínima para una línea de venta';
|
||||
|
||||
CREATE TABLE `vn`.`itemMinimumQuantity` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`itemFk` int(10) NOT NULL,
|
||||
`quantity` int(10) NOT NULL,
|
||||
`started` date NOT NULL,
|
||||
`ended` date DEFAULT NULL,
|
||||
`warehouseFk` smallint(5) unsigned DEFAULT NULL,
|
||||
`created` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`editorFk` int(10) unsigned DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `itemMinimumQuantity_UNIQUE` (`itemFk`, `started`, `ended`, `warehouseFk`),
|
||||
KEY `itemFk` (`itemFk`),
|
||||
KEY `started` (`started`),
|
||||
KEY `ended` (`ended`),
|
||||
KEY `warehouseFk` (`warehouseFk`),
|
||||
KEY `editorFk` (`editorFk`),
|
||||
CONSTRAINT `itemMinimumQuantity_ibfk_1` FOREIGN KEY (`itemFk`) REFERENCES `item` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT `itemMinimumQuantity_ibfk_2` FOREIGN KEY (`warehouseFk`) REFERENCES `warehouse` (`id`) ON UPDATE CASCADE,
|
||||
CONSTRAINT `itemMinimumQuantity_ibfk_3` FOREIGN KEY (`editorFk`) REFERENCES `account`.`user` (`id`),
|
||||
CONSTRAINT `itemMinimumQuantity_check_1` CHECK (`started` <= `ended`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
GRANT SELECT, UPDATE, DELETE, INSERT ON TABLE vn.itemMinimumQuantity TO buyer;
|
||||
GRANT EXECUTE ON PROCEDURE vn.ticketCalculatePurge TO guest;
|
||||
|
||||
ALTER TABLE vn.itemLog MODIFY COLUMN changedModel enum('Item','ItemBarcode','ItemBotanical','ItemNiche','ItemTag','ItemTaxCountry','ItemMinimumQuantity')
|
||||
CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci DEFAULT 'Item' NOT NULL;
|
|
@ -32,6 +32,9 @@
|
|||
"ItemLog": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"ItemMinimumQuantity": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"ItemPackingType": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
{
|
||||
"name": "ItemMinimumQuantity",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "itemMinimumQuantity"
|
||||
}
|
||||
},
|
||||
"mixins": {
|
||||
"Loggable": true
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "number",
|
||||
"id": true,
|
||||
"description": "Id"
|
||||
},
|
||||
"itemFk": {
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"quantity": {
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"started": {
|
||||
"type": "date",
|
||||
"required": true
|
||||
},
|
||||
"ended": {
|
||||
"type": "date"
|
||||
},
|
||||
"warehouseFk": {
|
||||
"type": "number"
|
||||
},
|
||||
"created": {
|
||||
"type": "date"
|
||||
},
|
||||
"editorFk": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"item": {
|
||||
"type": "belongsTo",
|
||||
"model": "Item",
|
||||
"foreignKey": "itemFk"
|
||||
},
|
||||
"warehouse": {
|
||||
"type": "belongsTo",
|
||||
"model": "Warehouse",
|
||||
"foreignKey": "warehouseFk"
|
||||
}
|
||||
},
|
||||
"acls": [
|
||||
{
|
||||
"accessType": "READ",
|
||||
"principalType": "ROLE",
|
||||
"principalId": "buyer",
|
||||
"permission": "ALLOW"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -152,10 +152,6 @@
|
|||
"columnName": "doPhoto"
|
||||
}
|
||||
},
|
||||
"minQuantity": {
|
||||
"type": "number",
|
||||
"description": "Min quantity"
|
||||
},
|
||||
"photoMotivation": {
|
||||
"type": "string"
|
||||
}
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
const {models} = require('vn-loopback/server/server');
|
||||
|
||||
describe('itemMinimumQuantity model', () => {
|
||||
const itemFk = 5;
|
||||
const warehouseFk = 60;
|
||||
|
||||
beforeAll(async() => {
|
||||
await models.ItemMinimumQuantity.destroyAll({where: {itemFk: itemFk}});
|
||||
});
|
||||
|
||||
describe('CRUD operations', () => {
|
||||
it('should create a new itemMinimumQuantity record', async() => {
|
||||
const newRecord = {
|
||||
itemFk: itemFk,
|
||||
quantity: 100,
|
||||
started: Date.vnNew(),
|
||||
ended: new Date(Date.vnNew().setFullYear(Date.vnNew().getFullYear() + 1)),
|
||||
warehouseFk: warehouseFk
|
||||
};
|
||||
|
||||
const createdRecord = await models.ItemMinimumQuantity.create(newRecord);
|
||||
|
||||
expect(createdRecord).toBeDefined();
|
||||
expect(createdRecord.quantity).toEqual(newRecord.quantity);
|
||||
});
|
||||
|
||||
it('should read an existing itemMinimumQuantity record', async() => {
|
||||
const newRecord = {
|
||||
itemFk: itemFk,
|
||||
quantity: 100,
|
||||
started: Date.vnNew(),
|
||||
ended: new Date(Date.vnNew().setFullYear(Date.vnNew().getFullYear() + 2)),
|
||||
warehouseFk: warehouseFk
|
||||
};
|
||||
|
||||
await models.ItemMinimumQuantity.create(newRecord);
|
||||
|
||||
const existingRecord = await models.ItemMinimumQuantity.findOne({where: {itemFk: itemFk}});
|
||||
|
||||
expect(existingRecord).toBeDefined();
|
||||
expect(existingRecord.itemFk).toEqual(itemFk);
|
||||
});
|
||||
|
||||
it('should update an existing itemMinimumQuantity record', async() => {
|
||||
const newRecord = {
|
||||
itemFk: itemFk,
|
||||
quantity: 100,
|
||||
started: Date.vnNew(),
|
||||
ended: new Date(Date.vnNew().setFullYear(Date.vnNew().getFullYear() + 3)),
|
||||
warehouseFk: warehouseFk
|
||||
};
|
||||
|
||||
await models.ItemMinimumQuantity.create(newRecord);
|
||||
|
||||
const newQuantity = 150;
|
||||
const existingRecord = await models.ItemMinimumQuantity.findOne({where: {itemFk: itemFk}});
|
||||
existingRecord.quantity = newQuantity;
|
||||
|
||||
await existingRecord.save();
|
||||
const updatedRecord = await models.ItemMinimumQuantity.findOne({where: {itemFk: itemFk}});
|
||||
|
||||
expect(updatedRecord.quantity).toEqual(newQuantity);
|
||||
});
|
||||
});
|
||||
|
||||
describe('validation and constraints', () => {
|
||||
it('should enforce unique constraint on itemFk, started, ended, and warehouseFk', async() => {
|
||||
const newRecord = {
|
||||
itemFk: itemFk,
|
||||
quantity: 100,
|
||||
started: Date.vnNew(),
|
||||
ended: Date.vnNew().setFullYear(Date.vnNew().getFullYear() + 5),
|
||||
warehouseFk: warehouseFk
|
||||
};
|
||||
|
||||
try {
|
||||
await models.ItemMinimumQuantity.create(newRecord);
|
||||
await models.ItemMinimumQuantity.create(newRecord);
|
||||
} catch (e) {
|
||||
expect(e).toBeDefined();
|
||||
expect(e.code).toContain('ER_DUP_ENTRY');
|
||||
}
|
||||
});
|
||||
|
||||
it('should allow null values for ended and warehouseFk', async() => {
|
||||
const newRecord = {
|
||||
itemFk: itemFk,
|
||||
quantity: 100,
|
||||
started: Date.vnNew(),
|
||||
ended: null,
|
||||
warehouseFk: null
|
||||
};
|
||||
|
||||
const createdRecord = await models.ItemMinimumQuantity.create(newRecord);
|
||||
|
||||
expect(createdRecord).toBeDefined();
|
||||
expect(createdRecord.ended).toBeNull();
|
||||
expect(createdRecord.warehouseFk).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -128,9 +128,6 @@
|
|||
<vn-label-value label="Non recycled plastic"
|
||||
value="{{$ctrl.summary.item.nonRecycledPlastic}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Minimum sales quantity"
|
||||
value="{{$ctrl.summary.item.minQuantity}}">
|
||||
</vn-label-value>
|
||||
</vn-one>
|
||||
<vn-one name="tags">
|
||||
<h4 ng-show="$ctrl.isBuyer || $ctrl.isReplenisher">
|
||||
|
|
|
@ -119,7 +119,7 @@ module.exports = Self => {
|
|||
w.firstName,
|
||||
tci.priceKg,
|
||||
ink.hex,
|
||||
i.minQuantity
|
||||
tci.minQuantity
|
||||
FROM tmp.ticketCalculateItem tci
|
||||
JOIN vn.item i ON i.id = tci.itemFk
|
||||
JOIN vn.itemType it ON it.id = i.typeFk
|
||||
|
@ -158,21 +158,19 @@ module.exports = Self => {
|
|||
|
||||
// Apply item prices
|
||||
const pricesIndex = stmts.push(
|
||||
`SELECT
|
||||
tcp.itemFk,
|
||||
`SELECT tcp.itemFk,
|
||||
tcp.grouping,
|
||||
tcp.price,
|
||||
tcp.rate,
|
||||
tcp.warehouseFk,
|
||||
tcp.priceKg,
|
||||
w.name AS warehouse
|
||||
w.name warehouse
|
||||
FROM tmp.ticketComponentPrice tcp
|
||||
JOIN vn.warehouse w ON w.id = tcp.warehouseFk`) - 1;
|
||||
|
||||
// Get tags from all items
|
||||
const itemTagsIndex = stmts.push(
|
||||
`SELECT
|
||||
t.id,
|
||||
`SELECT t.id,
|
||||
t.name,
|
||||
t.isFree,
|
||||
t.sourceTable,
|
||||
|
|
|
@ -37,18 +37,6 @@
|
|||
value="{{::item.value7}}">
|
||||
</vn-label-value>
|
||||
</div>
|
||||
<vn-horizontal
|
||||
class="text-right text-caption alert vn-mr-xs"
|
||||
ng-if="::item.minQuantity">
|
||||
<vn-one>
|
||||
<vn-icon
|
||||
icon="production_quantity_limits"
|
||||
translate-attr="{title: 'Minimal quantity'}"
|
||||
class="text-subtitle1">
|
||||
</vn-icon>
|
||||
</vn-one>
|
||||
{{::item.minQuantity}}
|
||||
</vn-horizontal>
|
||||
<div class="footer">
|
||||
<div class="price">
|
||||
<vn-one>
|
||||
|
|
|
@ -1,2 +1 @@
|
|||
Order created: Orden creada
|
||||
Minimal quantity: Cantidad mínima
|
||||
Order created: Orden creada
|
|
@ -65,7 +65,7 @@ module.exports = Self => {
|
|||
throw new UserError('You can only add negative amounts in refund tickets');
|
||||
|
||||
const item = await models.Item.findOne({
|
||||
fields: ['family', 'minQuantity'],
|
||||
fields: ['family'],
|
||||
where: {id: itemId},
|
||||
}, ctx.options);
|
||||
if (item.family == 'EMB') return;
|
||||
|
@ -88,7 +88,25 @@ module.exports = Self => {
|
|||
|
||||
if (await models.ACL.checkAccessAcl(ctx, 'Ticket', 'isRoleAdvanced', '*')) return;
|
||||
|
||||
if (newQuantity < item.minQuantity && newQuantity != available)
|
||||
const minQuantity = await models.ItemMinimumQuantity.findOne({
|
||||
fields: ['quantity'],
|
||||
where: {
|
||||
itemFk: itemId,
|
||||
started: {lte: ticket.shipped},
|
||||
or: [
|
||||
{ended: {gte: ticket.shipped}},
|
||||
{ended: null}
|
||||
],
|
||||
// eslint-disable-next-line no-dupe-keys
|
||||
or: [
|
||||
{warehouseFk: ticket.warehouseFk},
|
||||
{warehouseFk: null}
|
||||
]
|
||||
},
|
||||
limit: 1
|
||||
}, ctx.options);
|
||||
|
||||
if (newQuantity < minQuantity?.quantity && newQuantity != available)
|
||||
throw new UserError('The amount cannot be less than the minimum');
|
||||
|
||||
if (ctx.isNewInstance || isReduction) return;
|
||||
|
@ -114,4 +132,3 @@ module.exports = Self => {
|
|||
throw new UserError('The price of the item changed');
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -112,14 +112,10 @@ describe('sale model ', () => {
|
|||
it('should throw an error if the quantity is less than the minimum quantity of the item', async() => {
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true));
|
||||
|
||||
const itemId = 2;
|
||||
const saleId = 17;
|
||||
const minQuantity = 30;
|
||||
const newQuantity = minQuantity - 1;
|
||||
const newQuantity = 1;
|
||||
|
||||
try {
|
||||
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
|
||||
|
@ -138,13 +134,8 @@ describe('sale model ', () => {
|
|||
it('should change quantity if has minimum quantity and new quantity is equal than item available', async() => {
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true));
|
||||
|
||||
const itemId = 2;
|
||||
const saleId = 17;
|
||||
const minQuantity = 30;
|
||||
const newQuantity = minQuantity - 1;
|
||||
|
||||
const item = await models.Item.findById(itemId, null, opts);
|
||||
await item.updateAttribute('minQuantity', minQuantity, opts);
|
||||
const newQuantity = 8;
|
||||
|
||||
spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => {
|
||||
if (sqlStatement.includes('catalog_calcFromItem')) {
|
||||
|
@ -162,13 +153,9 @@ describe('sale model ', () => {
|
|||
it('should increase quantity if you have enough available and the new price is the same as the previous one', async() => {
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true));
|
||||
|
||||
const itemId = 2;
|
||||
const saleId = 17;
|
||||
const minQuantity = 30;
|
||||
const newQuantity = 31;
|
||||
|
||||
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 = `
|
||||
|
@ -185,13 +172,9 @@ describe('sale model ', () => {
|
|||
it('should increase quantity when the new price is lower than the previous one', async() => {
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true));
|
||||
|
||||
const itemId = 2;
|
||||
const saleId = 17;
|
||||
const minQuantity = 30;
|
||||
const newQuantity = 31;
|
||||
|
||||
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 = `
|
||||
|
@ -208,14 +191,10 @@ describe('sale model ', () => {
|
|||
it('should throw error when increase quantity and the new price is higher than the previous one', async() => {
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true));
|
||||
|
||||
const itemId = 2;
|
||||
const saleId = 17;
|
||||
const minQuantity = 30;
|
||||
const newQuantity = 31;
|
||||
|
||||
try {
|
||||
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 = `
|
||||
|
@ -231,6 +210,48 @@ describe('sale model ', () => {
|
|||
expect(e).toEqual(new Error('The price of the item changed'));
|
||||
}
|
||||
});
|
||||
|
||||
it('should throw an error if the quantity is lower than the minimum quantity of the item and is in range', async() => {
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true));
|
||||
|
||||
const saleId = 25;
|
||||
const newQuantity = 5;
|
||||
|
||||
try {
|
||||
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, opts);
|
||||
});
|
||||
|
||||
await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts);
|
||||
} catch (e) {
|
||||
expect(e).toEqual(new Error('The amount cannot be less than the minimum'));
|
||||
}
|
||||
});
|
||||
|
||||
it('should update the quantity if the quantity is lower than the minimum quantity of the item and is out of the range', async() => {
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true));
|
||||
|
||||
const saleId = 17;
|
||||
const newQuantity = 8;
|
||||
|
||||
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, opts);
|
||||
});
|
||||
|
||||
await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue