|
Проблема с хранимыми процедурами и параметрами
#38838752
Ссылка:
Ссылка на сообщение:
Ссылка с названием темы:
|
|
|
|
Доброго времени суток, форумчане!
Такая ситуация - есть ERP-программа для кафе и Mysql-база. В базе есть таблицы, в которых хранятся данные о продажах, позициях меню и расходных материалах, а также о том, сколько нужно какого расходного материала для каждой позиции меню.
Что мы хотим - чтобы по нажатию кнопки в программе закрывался чек, считалась статистика продаж и вычиталась расходка.
Для этого мы используем хранимую процедуру, в которой курсор пробегает по позициям заказа, вычисляет цену и прочие параметры и для каждой позиции вызывает хранимую процедуру, которая при помощи своего курсора вычисляет кол-во расходным материалов.
Хочется чтобы при вызове исключения в процессе работы хранимки откатывались все изменения, сделанные в процессе работы алгоритма.
Собственно проблема: для отлова исключительной ситуации во второй хранимке используется переменная-флаг и если она принимает значение TRUE первая хранимка должна все откатить, но при выполнении почему-то переменная TRUE не принимает.
Первая хранимка
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. 111. 112. 113. 114.
CREATE DEFINER = 'root'@'%'
PROCEDURE cafedb.Proc_Client_Sell(IN ParamLogin VARCHAR(255), IN ParamShop VARCHAR(255), IN ParamSumm FLOAT, IN ParamPlace INT)
COMMENT 'Процедура проведения продажи'
BEGIN
DECLARE VarCheckNo,
VarItemID,
VarMenuID,
VarItemAmount,
VarItemBonus,
VarOrderBonus,
VarSupplyAmount
int(11);
DECLARE VarItemPrice,
VarItemCost,
VarItemSumm,
VarOrderSumm,
VarOrderCost
float;
DECLARE done, VarErrorSupply INT DEFAULT FALSE;
DECLARE CheckCursor CURSOR FOR
SELECT MenuID, Amount, Summ, Price, Cost FROM sales_stat WHERE SaleID = VarCheckNo;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
CALL Proc_Log_Update('Error', ParamLogin, CONCAT('Ошибка при продаже на сумму ', ParamSumm, ' чек #', VarCheckNo), ParamShop);
SELECT
'Error!';
END;
DECLARE EXIT HANDLER FOR SQLSTATE '45000'
BEGIN
ROLLBACK;
CALL Proc_Log_Update('Error', ParamLogin, CONCAT('Ошибка при продаже на сумму ', ParamSumm, ' чек #', VarCheckNo), ParamShop);
SELECT
'Error!';
END;
SET @RecordNo = 0;
SET @VarErrorSupply = FALSE;
SET VarOrderCost = 0;
SET VarOrderBonus = 0;
START TRANSACTION;
/* берем номер открытого чека */
SELECT IndexNo
FROM sales
WHERE (Status = 'Открыт')
AND (sales.Place = ParamPlace)
AND (DAYOFMONTH(Time) = DAYOFMONTH(CURDATE()))
INTO VarCheckNo;
/* Обработка ВСЕХ финансовых параметров */
OPEN CheckCursor;
read_loop: LOOP
/* берем значения переменных */
FETCH CheckCursor INTO VarMenuID, VarItemAmount, VarItemSumm, VarItemPrice, VarItemCost;
/*Выход из курсора*/
IF done THEN
LEAVE read_loop;
END IF;
CALL Proc_server_Sell_Supply_Count(VarMenuID, VarItemAmount, ParamShop);
SELECT VarMenuID, VarItemAmount, VarItemSumm, VarItemPrice, VarItemCost, @VarErrorSupply;
/* если произошла ошибка - откатываемся */
IF @VarErrorSupply = TRUE THEN SIGNAL SQLSTATE '45000'; END IF;
SELECT Bonus FROM menu WHERE ItemNo = VarMenuID INTO VarItemBonus;
/* обновляем значения прибыли и кол-ва позиций */
UPDATE menu
SET menu.Amount = menu.Amount + VarItemAmount,
menu.Profit = menu.Profit + (VarItemPrice - VarItemCost) * VarItemAmount
WHERE ItemNo = VarMenuID;
/* вычисление значений бонусов и себестоимости заказа */
SET VarOrderCost = VarItemCost * VarItemAmount + VarOrderCost;
SET VarOrderBonus = VarItemBonus * VarItemAmount + VarOrderBonus;
END LOOP;
CLOSE CheckCursor;
UPDATE shops
SET Profit = shops.Profit + ParamSumm - VarOrderCost
WHERE ShopName = ParamShop; -- обновляем прибыль магазина
UPDATE sales -- записываем в таблицу продаж
SET Status = 'Открыт', -- заменить
User = ParamLogin,
Summ = ParamSumm,
Cost = VarOrderCost,
Profit = Summ - VarOrderCost,
-- Client = ClientPhone,
Shop = Shop,
Place = ParamPlace
WHERE IndexNo = VarCheckNo;
/* запись в лог */
CALL Proc_Log_Update('Sell', ParamLogin, CONCAT('Закрыт счет #',VarCheckNo, ' на сумму ', ParamSumm,' ', ParamPlace), ParamShop);
COMMIT;
END
Вторая, вызывается внутри первой
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90.
CREATE DEFINER = 'root'@'%'
PROCEDURE cafedb.Proc_Server_Sell_Supply_Count(IN ParamMenuID INTEGER, IN ParamItemAmount INTEGER, IN ParamShopName VARCHAR(255))
BEGIN
DECLARE done int DEFAULT FALSE;
DECLARE VarSupplyAmount,
VarSupplyID,
VarCount
int(11);
DECLARE Command,
VarSupplyName
text;
DECLARE SuppliesCursor CURSOR FOR
SELECT Supply, Amount, SupplyID
FROM table_item_supplies
WHERE ItemID = ParamMenuID;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
SET @VarErrorSupply = TRUE;
SELECT @VarErrorSupply;
END;
DECLARE EXIT HANDLER FOR SQLSTATE '45000'
BEGIN
ROLLBACK;
SET @VarErrorSupply = TRUE;
SELECT @VarErrorSupply;
END;
/* начало процедуры */
START TRANSACTION;
OPEN SuppliesCursor;
read_loop:
LOOP
/* берем значения переменных */
FETCH SuppliesCursor INTO VarSupplyName, VarSupplyAmount, VarSupplyID;
/*Выход из курсора*/
IF done THEN
LEAVE read_loop;
END IF;
/* Расчет расходки */
/* Изменение кол-ва расходников на торговых точках */
SET @Command = CONCAT('UPDATE supplies SET ', ParamShopName, ' = ', ParamShopName, ' - ', VarSupplyAmount * ParamItemAmount, ' WHERE IndexNo=', VarSupplyID);
PREPARE Up FROM @Command;
EXECUTE Up;
DEALLOCATE PREPARE Up;
/* Поиск записи расходки на дату */
SELECT COUNT(*)
FROM consumption
WHERE Time = CURDATE()
AND SupplyID = VarSupplyID
AND Shop = ParamShopName
INTO VarCount;
IF VarCount = 0
THEN
INSERT INTO consumption (Time, SupplyID, Supply, Amount, Shop) /* если записи о расходе нет - добавить ее */
VALUES (CURDATE(), VarSupplyID, VarSupplyName, VarSupplyAmount * ParamItemAmount, ParamShopName);
ELSE
UPDATE consumption /* если запись есть - обновлем */
SET Amount = consumption.Amount + VarSupplyAmount * ParamItemAmount
WHERE Time = CURDATE()
AND SupplyID = VarSupplyID
AND Shop = ParamShopName;
END IF;
-- пример вызова исключения
IF ParamItemAmount = 3 THEN SIGNAL SQLSTATE '45000'; END IF;
END LOOP;
CLOSE SuppliesCursor;
SELECT @VarErrorSupply;
COMMIT;
END
Извиняюсь за длиннопост, но как наглядней объяснить по-другому не знаю.
Подскажите что я забыл, из-за каких тонкостей алгоритм не работает и как это должно быть сделано.
|
|
|