feat: refs #7704 Major changes #2717
|
@ -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;
|
||||
|
@ -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
|
||||
guillermo marked this conversation as resolved
|
||||
ORDER BY warehouseFk DESC
|
||||
guillermo marked this conversation as resolved
jgallego
commented
2 coses:
2 coses:
- per a que ordenes?
- fes una prova posant per a un mateix rango un registre amb warehouse i uno sense, i ha d'agafar el que sí te perque es mes específic.
guillermo
commented
Ordene perque vuic primer els que tinguen warehouseFk i els últims els nulls, quan ho he desarrollat he pensat ja en aixo. Ordene perque vuic primer els que tinguen warehouseFk i els últims els nulls, quan ho he desarrollat he pensat ja en aixo.
|
||||
) 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 ;
|
|
@ -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": {
|
||||
guillermo marked this conversation as resolved
jgallego
commented
si volem logejar ho podem posar ací i crear ja la taula editorFk en la nova taula per exemple si volem logejar ho podem posar ací i crear ja la taula editorFk en la nova taula per exemple
guillermo
commented
Fique la nova columna i els triggers que fiquen el editor, igualment, en el cas de que se vuiguera logejar caldria putjar versió de Salix igualment. Fique la nova columna i els triggers que fiquen el editor, igualment, en el cas de que se vuiguera logejar caldria putjar versió de Salix igualment.
|
||||
"mysql": {
|
||||
guillermo marked this conversation as resolved
jgallego
commented
si ací poses si ací poses
"mixins": {
"Loggable": true
},
amb lo que has fet de l'editor queda molt poc per a que ja logeje no?
exemple ClaimEnd
guillermo
commented
Se decide que la tabla también haga log en itemLog Se decide que la tabla también haga log en itemLog
|
||||
"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
|
|
@ -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() => {
|
||||
guillermo marked this conversation as resolved
jgallego
commented
crea uno que crea uno que
"should throw an error if the quantity is greater than the minimum quantity of the item but is out of range"
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
vShipped