Widen order price columns so current gold rial quotes persist.

Gold gram prices now exceed the old DECIMAL/INT range and MySQL 1264 aborted buys; store money fields as DECIMAL(20,4) and hide the raw SQL error from the app.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-31 16:14:02 +03:30
co-authored by Cursor
parent 5537cd7086
commit 4c2200a0e0
4 changed files with 251 additions and 0 deletions
@@ -0,0 +1,78 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
/**
* مظنهٔ گرم طلا از سقف DECIMAL(10,2) / INT قدیمی رد شده (خطای 1264 روی orders.price).
*/
return new class extends Migration
{
/** @var list<string> */
private const ORDER_MONEY_COLUMNS = [
'price',
'price_original',
'total_price',
'total_price_original',
'total_price_liman',
'fee',
'total_fee',
'service_charge_price',
'payment_amount',
'payment_remind',
];
public function up(): void
{
if (Schema::hasTable('orders')) {
foreach (self::ORDER_MONEY_COLUMNS as $column) {
$this->widenMoneyColumn('orders', $column);
}
}
if (Schema::hasTable('prices')) {
$this->widenMoneyColumn('prices', 'price');
}
}
public function down(): void
{
// کوچک‌کردن ستون دادهٔ موجود را خراب می‌کند
}
private function widenMoneyColumn(string $table, string $column): void
{
$schema = DB::connection()->getDatabaseName();
$tableName = DB::getTablePrefix().$table;
$meta = DB::selectOne(
'SELECT DATA_TYPE, NUMERIC_PRECISION, NUMERIC_SCALE
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? AND COLUMN_NAME = ?',
[$schema, $tableName, $column]
);
if ($meta === null) {
return;
}
$type = strtolower((string) $meta->DATA_TYPE);
$precision = (int) ($meta->NUMERIC_PRECISION ?? 0);
$scale = (int) ($meta->NUMERIC_SCALE ?? 0);
$integerDigits = in_array($type, ['decimal', 'numeric'], true)
? max(0, $precision - $scale)
: $precision;
$alreadyWideDecimal = in_array($type, ['decimal', 'numeric'], true)
&& $integerDigits >= 16
&& $scale >= 4;
$alreadyBigint = $type === 'bigint';
if ($alreadyWideDecimal || $alreadyBigint) {
return;
}
DB::statement("ALTER TABLE `{$tableName}` MODIFY `{$column}` DECIMAL(20,4) NULL");
}
};
+136
View File
@@ -610,6 +610,142 @@ PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- ---------------------------------------------------------------------------
-- orders / prices: ظرفیت مظنهٔ ریالی (خطای 1264 Out of range column price)
-- DECIMAL(10,2) حداکثر ~۹۹ میلیون است؛ مظنهٔ گرم طلا از این سقف گذشته.
-- ---------------------------------------------------------------------------
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='price') > 0
AND (SELECT DATA_TYPE FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='price') <> 'bigint'
AND (SELECT IFNULL(NUMERIC_PRECISION, 0) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='price') < 20,
'ALTER TABLE `orders` MODIFY `price` DECIMAL(20,4) NULL',
'SELECT ''skip orders.price widen'' AS info'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='price_original') > 0
AND (SELECT DATA_TYPE FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='price_original') <> 'bigint'
AND (SELECT IFNULL(NUMERIC_PRECISION, 0) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='price_original') < 20,
'ALTER TABLE `orders` MODIFY `price_original` DECIMAL(20,4) NULL',
'SELECT ''skip orders.price_original widen'' AS info'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='total_price') > 0
AND (SELECT DATA_TYPE FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='total_price') <> 'bigint'
AND (SELECT IFNULL(NUMERIC_PRECISION, 0) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='total_price') < 20,
'ALTER TABLE `orders` MODIFY `total_price` DECIMAL(20,4) NULL',
'SELECT ''skip orders.total_price widen'' AS info'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='total_price_original') > 0
AND (SELECT DATA_TYPE FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='total_price_original') <> 'bigint'
AND (SELECT IFNULL(NUMERIC_PRECISION, 0) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='total_price_original') < 20,
'ALTER TABLE `orders` MODIFY `total_price_original` DECIMAL(20,4) NULL',
'SELECT ''skip orders.total_price_original widen'' AS info'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='fee') > 0
AND (SELECT DATA_TYPE FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='fee') <> 'bigint'
AND (SELECT IFNULL(NUMERIC_PRECISION, 0) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='fee') < 20,
'ALTER TABLE `orders` MODIFY `fee` DECIMAL(20,4) NULL',
'SELECT ''skip orders.fee widen'' AS info'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='total_fee') > 0
AND (SELECT DATA_TYPE FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='total_fee') <> 'bigint'
AND (SELECT IFNULL(NUMERIC_PRECISION, 0) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='total_fee') < 20,
'ALTER TABLE `orders` MODIFY `total_fee` DECIMAL(20,4) NULL',
'SELECT ''skip orders.total_fee widen'' AS info'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='service_charge_price') > 0
AND (SELECT DATA_TYPE FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='service_charge_price') <> 'bigint'
AND (SELECT IFNULL(NUMERIC_PRECISION, 0) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='service_charge_price') < 20,
'ALTER TABLE `orders` MODIFY `service_charge_price` DECIMAL(20,4) NULL',
'SELECT ''skip orders.service_charge_price widen'' AS info'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='payment_amount') > 0
AND (SELECT DATA_TYPE FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='payment_amount') <> 'bigint'
AND (SELECT IFNULL(NUMERIC_PRECISION, 0) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='payment_amount') < 20,
'ALTER TABLE `orders` MODIFY `payment_amount` DECIMAL(20,4) NULL',
'SELECT ''skip orders.payment_amount widen'' AS info'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='payment_remind') > 0
AND (SELECT DATA_TYPE FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='payment_remind') <> 'bigint'
AND (SELECT IFNULL(NUMERIC_PRECISION, 0) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='payment_remind') < 20,
'ALTER TABLE `orders` MODIFY `payment_remind` DECIMAL(20,4) NULL',
'SELECT ''skip orders.payment_remind widen'' AS info'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='total_price_liman') > 0
AND (SELECT DATA_TYPE FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='total_price_liman') <> 'bigint'
AND (SELECT IFNULL(NUMERIC_PRECISION, 0) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='orders' AND COLUMN_NAME='total_price_liman') < 20,
'ALTER TABLE `orders` MODIFY `total_price_liman` DECIMAL(20,4) NULL',
'SELECT ''skip orders.total_price_liman widen'' AS info'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='prices' AND COLUMN_NAME='price') > 0
AND (SELECT DATA_TYPE FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='prices' AND COLUMN_NAME='price') <> 'bigint'
AND (SELECT IFNULL(NUMERIC_PRECISION, 0) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='prices' AND COLUMN_NAME='price') < 20,
'ALTER TABLE `prices` MODIFY `price` DECIMAL(20,4) NULL',
'SELECT ''skip prices.price widen'' AS info'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-- ---------------------------------------------------------------------------
-- پایان — برای بورس‌مس (اختیاری، جدا اجرا کنید):
-- UPDATE `settings` SET `value` = 'کیلوگرم' WHERE `key` = 'unit';