fix bug
This commit is contained in:
@@ -6,6 +6,7 @@ use App\DB\Te\TableEngine;
|
|||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\Price;
|
use App\Models\Price;
|
||||||
use App\Models\PriceCandle;
|
use App\Models\PriceCandle;
|
||||||
|
use App\Services\ZaarboxPriceService;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
class PriceController extends Controller
|
class PriceController extends Controller
|
||||||
@@ -46,6 +47,18 @@ class PriceController extends Controller
|
|||||||
->export($prise);
|
->export($prise);
|
||||||
return response()->json($prise);
|
return response()->json($prise);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function chartPrices(ZaarboxPriceService $zaarboxPriceService)
|
||||||
|
{
|
||||||
|
return response()->json([
|
||||||
|
'code' => 0,
|
||||||
|
'message' => 'عملیات با موفقیت انجام شد.',
|
||||||
|
'data' => [
|
||||||
|
'prices' => $zaarboxPriceService->getAllPrices(),
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public function table(Request $request){
|
public function table(Request $request){
|
||||||
$records = Price::with(['user']);
|
$records = Price::with(['user']);
|
||||||
TableEngine::create($records, $request->all())
|
TableEngine::create($records, $request->all())
|
||||||
|
|||||||
@@ -349,6 +349,33 @@ class ProductController extends SuperController
|
|||||||
unset($data['price_offset_percent']);
|
unset($data['price_offset_percent']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!Product::hasOrderLimitColumns()) {
|
||||||
|
unset($data['order_limit_enabled'], $data['min_order_cash'], $data['max_order_cash']);
|
||||||
|
} elseif (empty($data['order_limit_enabled'])) {
|
||||||
|
$data['order_limit_enabled'] = false;
|
||||||
|
$data['min_order_cash'] = null;
|
||||||
|
$data['max_order_cash'] = null;
|
||||||
|
} else {
|
||||||
|
$min = $data['min_order_cash'] ?? null;
|
||||||
|
$max = $data['max_order_cash'] ?? null;
|
||||||
|
$hasMin = $min !== null && $min !== '';
|
||||||
|
$hasMax = $max !== null && $max !== '';
|
||||||
|
|
||||||
|
if (!$hasMin && !$hasMax) {
|
||||||
|
throw new UnprocessableEntityHttpException(
|
||||||
|
'با فعال بودن محدودیت مبلغ سفارش، حداقل یکی از حداقل یا حداکثر مبلغ باید وارد شود'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($hasMin && $hasMax && (float) $min > (float) $max) {
|
||||||
|
throw new UnprocessableEntityHttpException('حداقل مبلغ نمیتواند بیشتر از حداکثر باشد');
|
||||||
|
}
|
||||||
|
|
||||||
|
$data['order_limit_enabled'] = true;
|
||||||
|
$data['min_order_cash'] = $hasMin ? (int) $min : null;
|
||||||
|
$data['max_order_cash'] = $hasMax ? (int) $max : null;
|
||||||
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -219,6 +219,8 @@ class SingleOrderController extends Controller
|
|||||||
$data['total_price'] = $data['amount'] * $data['price'];
|
$data['total_price'] = $data['amount'] * $data['price'];
|
||||||
$data['payment_amount'] = $data['total_price'];
|
$data['payment_amount'] = $data['total_price'];
|
||||||
|
|
||||||
|
$this->enforceProductOrderLimits($data, (float) $data['total_price']);
|
||||||
|
|
||||||
if (!empty($data['first_buy']) && ($minFirstBuy = Setting::where('is_active', 1)->where('key', 'min_first_buy')->value('value'))) {
|
if (!empty($data['first_buy']) && ($minFirstBuy = Setting::where('is_active', 1)->where('key', 'min_first_buy')->value('value'))) {
|
||||||
if ($data['total_price'] < (int) $minFirstBuy) {
|
if ($data['total_price'] < (int) $minFirstBuy) {
|
||||||
throw new UnprocessableEntityHttpException('حداقل سفارش اول ' . number_format((int) $minFirstBuy) . ' ریال میباشد.');
|
throw new UnprocessableEntityHttpException('حداقل سفارش اول ' . number_format((int) $minFirstBuy) . ' ریال میباشد.');
|
||||||
@@ -256,6 +258,8 @@ class SingleOrderController extends Controller
|
|||||||
$data['total_price'] = $data['total_amount'] * $data['price'];
|
$data['total_price'] = $data['total_amount'] * $data['price'];
|
||||||
$data['payment_amount'] = $data['total_price'];
|
$data['payment_amount'] = $data['total_price'];
|
||||||
|
|
||||||
|
$this->enforceProductOrderLimits($data, (float) $data['total_price']);
|
||||||
|
|
||||||
if (!empty($data['first_buy']) && ($minFirstBuy = Setting::where('is_active', 1)->where('key', 'min_first_buy')->value('value'))) {
|
if (!empty($data['first_buy']) && ($minFirstBuy = Setting::where('is_active', 1)->where('key', 'min_first_buy')->value('value'))) {
|
||||||
if ($data['total_price'] < (int) $minFirstBuy) {
|
if ($data['total_price'] < (int) $minFirstBuy) {
|
||||||
throw new UnprocessableEntityHttpException('حداقل سفارش اول ' . number_format((int) $minFirstBuy) . ' ریال میباشد.');
|
throw new UnprocessableEntityHttpException('حداقل سفارش اول ' . number_format((int) $minFirstBuy) . ' ریال میباشد.');
|
||||||
@@ -306,6 +310,7 @@ class SingleOrderController extends Controller
|
|||||||
$data['total_amount'] = $data['amount'] + ($data['product']['percent_fee_buy'] * $data['amount']);
|
$data['total_amount'] = $data['amount'] + ($data['product']['percent_fee_buy'] * $data['amount']);
|
||||||
$data['total_price'] = $data['total_amount'] * $data['price'];
|
$data['total_price'] = $data['total_amount'] * $data['price'];
|
||||||
$data['payment_amount'] = $data['total_price'];
|
$data['payment_amount'] = $data['total_price'];
|
||||||
|
$this->enforceProductOrderLimits($data, (float) $data['total_price']);
|
||||||
$data['service_charge'] = isset($data['fee_free']) && $data['fee_free'] === true ? 0 : ($data['product']['percent_fee_buy'] * $data['amount']);
|
$data['service_charge'] = isset($data['fee_free']) && $data['fee_free'] === true ? 0 : ($data['product']['percent_fee_buy'] * $data['amount']);
|
||||||
$data['total_fee'] = 0;
|
$data['total_fee'] = 0;
|
||||||
$data['service_charge_price'] = $data['service_charge'] * $data['price_original'];
|
$data['service_charge_price'] = $data['service_charge'] * $data['price_original'];
|
||||||
@@ -345,6 +350,8 @@ class SingleOrderController extends Controller
|
|||||||
{
|
{
|
||||||
$response = [];
|
$response = [];
|
||||||
$data['price'] -= $data['difference'];
|
$data['price'] -= $data['difference'];
|
||||||
|
$grossTotal = $data['amount'] * $data['price'];
|
||||||
|
$this->enforceProductOrderLimits($data, (float) $grossTotal);
|
||||||
$data['service_charge'] = isset($data['fee_free']) && $data['fee_free'] === true ? 0 : $data['service_charge_percentage'] * $data['amount'];
|
$data['service_charge'] = isset($data['fee_free']) && $data['fee_free'] === true ? 0 : $data['service_charge_percentage'] * $data['amount'];
|
||||||
$data['service_charge_price'] = $data['service_charge'] * $data['price_original'];
|
$data['service_charge_price'] = $data['service_charge'] * $data['price_original'];
|
||||||
$data['total_price'] = $data['amount'] * $data['price'] - $data['service_charge_price'];
|
$data['total_price'] = $data['amount'] * $data['price'] - $data['service_charge_price'];
|
||||||
@@ -376,6 +383,8 @@ class SingleOrderController extends Controller
|
|||||||
$data['total_amount'] = $data['amount'] - ($data['product']['percent_fee_sell'] * $data['amount']);
|
$data['total_amount'] = $data['amount'] - ($data['product']['percent_fee_sell'] * $data['amount']);
|
||||||
$data['total_price'] = $data['total_amount'] * $data['price'];
|
$data['total_price'] = $data['total_amount'] * $data['price'];
|
||||||
$data['payment_amount'] = $data['total_price'];
|
$data['payment_amount'] = $data['total_price'];
|
||||||
|
$grossTotal = (float) ($data['amount'] * $data['price']);
|
||||||
|
$this->enforceProductOrderLimits($data, $grossTotal);
|
||||||
$data['service_charge'] = isset($data['fee_free']) && $data['fee_free'] === true ? 0 : ($data['product']['percent_fee_sell'] * $data['amount']);
|
$data['service_charge'] = isset($data['fee_free']) && $data['fee_free'] === true ? 0 : ($data['product']['percent_fee_sell'] * $data['amount']);
|
||||||
$data['service_charge_price'] = $data['service_charge'] * $data['price_original'];
|
$data['service_charge_price'] = $data['service_charge'] * $data['price_original'];
|
||||||
$wallet_interface_product = new WalletInterface(auth('customer')->id(), auth('customer')->user()->type, null, $data["product_id"]);
|
$wallet_interface_product = new WalletInterface(auth('customer')->id(), auth('customer')->user()->type, null, $data["product_id"]);
|
||||||
@@ -417,6 +426,8 @@ class SingleOrderController extends Controller
|
|||||||
$data['total_amount'] = $data['amount'] - ($data['product']['percent_fee_sell'] * $data['amount']);
|
$data['total_amount'] = $data['amount'] - ($data['product']['percent_fee_sell'] * $data['amount']);
|
||||||
$data['total_price'] = $data['total_amount'] * $data['price'];
|
$data['total_price'] = $data['total_amount'] * $data['price'];
|
||||||
$data['payment_amount'] = $data['total_price'];
|
$data['payment_amount'] = $data['total_price'];
|
||||||
|
$grossTotal = (float) ($data['amount'] * $data['price']);
|
||||||
|
$this->enforceProductOrderLimits($data, $grossTotal);
|
||||||
$data['service_charge'] = isset($data['fee_free']) && $data['fee_free'] === true ? 0 : ($data['product']['percent_fee_sell'] * $data['amount']);
|
$data['service_charge'] = isset($data['fee_free']) && $data['fee_free'] === true ? 0 : ($data['product']['percent_fee_sell'] * $data['amount']);
|
||||||
$data['total_fee'] = 0;
|
$data['total_fee'] = 0;
|
||||||
$data['service_charge_price'] = $data['service_charge'] * $data['price_original'];
|
$data['service_charge_price'] = $data['service_charge'] * $data['price_original'];
|
||||||
@@ -843,4 +854,28 @@ class SingleOrderController extends Controller
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function enforceProductOrderLimits(array &$data, float $totalPriceRial): void
|
||||||
|
{
|
||||||
|
$product = $data['product'] ?? null;
|
||||||
|
|
||||||
|
if (!$product instanceof Product) {
|
||||||
|
$productId = (int) ($data['abshode_id'] ?? $data['product_id'] ?? 0);
|
||||||
|
if ($productId) {
|
||||||
|
$product = Product::find($productId);
|
||||||
|
if ($product) {
|
||||||
|
$data['product'] = $product;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elseif (is_array($product)) {
|
||||||
|
$product = Product::find($product['id'] ?? $data['product_id'] ?? 0);
|
||||||
|
if ($product) {
|
||||||
|
$data['product'] = $product;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($product instanceof Product) {
|
||||||
|
$product->validateOrderCashLimit($totalPriceRial);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ class Product extends Model
|
|||||||
|
|
||||||
private static ?bool $priceOffsetColumnExists = null;
|
private static ?bool $priceOffsetColumnExists = null;
|
||||||
private static ?bool $priceColumnExists = null;
|
private static ?bool $priceColumnExists = null;
|
||||||
|
private static ?bool $orderLimitColumnsExist = null;
|
||||||
|
|
||||||
protected static function booted(): void
|
protected static function booted(): void
|
||||||
{
|
{
|
||||||
@@ -24,6 +25,13 @@ class Product extends Model
|
|||||||
if (!static::hasPriceOffsetColumn()) {
|
if (!static::hasPriceOffsetColumn()) {
|
||||||
unset($product->attributes['price_offset_percent']);
|
unset($product->attributes['price_offset_percent']);
|
||||||
}
|
}
|
||||||
|
if (!static::hasOrderLimitColumns()) {
|
||||||
|
unset(
|
||||||
|
$product->attributes['order_limit_enabled'],
|
||||||
|
$product->attributes['min_order_cash'],
|
||||||
|
$product->attributes['max_order_cash']
|
||||||
|
);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,6 +69,55 @@ class Product extends Model
|
|||||||
return static::$priceColumnExists;
|
return static::$priceColumnExists;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function hasOrderLimitColumns(): bool
|
||||||
|
{
|
||||||
|
if (static::$orderLimitColumnsExist !== null) {
|
||||||
|
return static::$orderLimitColumnsExist;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
static::$orderLimitColumnsExist = Schema::hasColumn(
|
||||||
|
(new static)->getTable(),
|
||||||
|
'order_limit_enabled'
|
||||||
|
);
|
||||||
|
} catch (\Throwable) {
|
||||||
|
static::$orderLimitColumnsExist = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return static::$orderLimitColumnsExist;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function orderLimitsEnabled(): bool
|
||||||
|
{
|
||||||
|
if (!static::hasOrderLimitColumns() || !($this->order_limit_enabled ?? false)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->min_order_cash !== null || $this->max_order_cash !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validateOrderCashLimit(float $totalPriceRial): void
|
||||||
|
{
|
||||||
|
if (!$this->orderLimitsEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$min = $this->min_order_cash;
|
||||||
|
$max = $this->max_order_cash;
|
||||||
|
|
||||||
|
if ($min !== null && $totalPriceRial < (float) $min) {
|
||||||
|
throw new \Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException(
|
||||||
|
'حداقل مبلغ این محصول ' . number_format((float) $min) . ' ریال میباشد'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($max !== null && $totalPriceRial > (float) $max) {
|
||||||
|
throw new \Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException(
|
||||||
|
'حداکثر مبلغ این محصول ' . number_format((float) $max) . ' ریال میباشد'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function getPriceOffsetPercentAttribute($value): float
|
public function getPriceOffsetPercentAttribute($value): float
|
||||||
{
|
{
|
||||||
if (!static::hasPriceOffsetColumn()) {
|
if (!static::hasPriceOffsetColumn()) {
|
||||||
@@ -91,6 +148,9 @@ class Product extends Model
|
|||||||
'cash_fee_buy', // Add cash_fee_buy to fillable
|
'cash_fee_buy', // Add cash_fee_buy to fillable
|
||||||
'cash_fee_sell', // Add cash_fee_sell to fillable
|
'cash_fee_sell', // Add cash_fee_sell to fillable
|
||||||
'percent_fee_buy', // Add percent_fee_buy to fillable
|
'percent_fee_buy', // Add percent_fee_buy to fillable
|
||||||
|
'order_limit_enabled',
|
||||||
|
'min_order_cash',
|
||||||
|
'max_order_cash',
|
||||||
'metal_id', //the material of metal (#gold or #silver)
|
'metal_id', //the material of metal (#gold or #silver)
|
||||||
'price_offset_percent', // admin only: +/- % vs automatic reference (baked into price on sync)
|
'price_offset_percent', // admin only: +/- % vs automatic reference (baked into price on sync)
|
||||||
'price_profit',
|
'price_profit',
|
||||||
@@ -109,6 +169,9 @@ class Product extends Model
|
|||||||
'price' => 'int', // Cast to float.
|
'price' => 'int', // Cast to float.
|
||||||
'percent_fee_sell' => 'float', // Cast to float.
|
'percent_fee_sell' => 'float', // Cast to float.
|
||||||
'percent_fee_buy' => 'float', // Cast to float.
|
'percent_fee_buy' => 'float', // Cast to float.
|
||||||
|
'order_limit_enabled' => 'boolean',
|
||||||
|
'min_order_cash' => 'int',
|
||||||
|
'max_order_cash' => 'int',
|
||||||
'cash_fee_buy' => 'int', // Cast to int or decimal if needed
|
'cash_fee_buy' => 'int', // Cast to int or decimal if needed
|
||||||
'cash_fee_sell' => 'int', // Cast to int or decimal if needed
|
'cash_fee_sell' => 'int', // Cast to int or decimal if needed
|
||||||
'price_offset_percent' => 'float',
|
'price_offset_percent' => 'float',
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
if (!Schema::hasTable('products')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Schema::table('products', function (Blueprint $table) {
|
||||||
|
if (!Schema::hasColumn('products', 'order_limit_enabled')) {
|
||||||
|
$table->boolean('order_limit_enabled')->default(false)->after('percent_fee_buy');
|
||||||
|
}
|
||||||
|
if (!Schema::hasColumn('products', 'min_order_cash')) {
|
||||||
|
$table->unsignedBigInteger('min_order_cash')->nullable()->after('order_limit_enabled');
|
||||||
|
}
|
||||||
|
if (!Schema::hasColumn('products', 'max_order_cash')) {
|
||||||
|
$table->unsignedBigInteger('max_order_cash')->nullable()->after('min_order_cash');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
if (!Schema::hasTable('products')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Schema::table('products', function (Blueprint $table) {
|
||||||
|
$columns = ['order_limit_enabled', 'min_order_cash', 'max_order_cash'];
|
||||||
|
foreach ($columns as $column) {
|
||||||
|
if (Schema::hasColumn('products', $column)) {
|
||||||
|
$table->dropColumn($column);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
-- محدودیت مبلغ سفارش روی محصول
|
||||||
|
-- امن برای اجرای مجدد: اگر ستون وجود داشته باشد خطا نمیدهد
|
||||||
|
-- USE دیتابیس_خودتان;
|
||||||
|
|
||||||
|
SET @db = DATABASE();
|
||||||
|
|
||||||
|
SET @sql = IF(
|
||||||
|
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'products' AND COLUMN_NAME = 'order_limit_enabled') = 0,
|
||||||
|
'ALTER TABLE `products` ADD COLUMN `order_limit_enabled` TINYINT(1) NOT NULL DEFAULT 0 AFTER `percent_fee_buy`',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
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 = 'products' AND COLUMN_NAME = 'min_order_cash') = 0,
|
||||||
|
'ALTER TABLE `products` ADD COLUMN `min_order_cash` BIGINT UNSIGNED NULL DEFAULT NULL AFTER `order_limit_enabled`',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
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 = 'products' AND COLUMN_NAME = 'max_order_cash') = 0,
|
||||||
|
'ALTER TABLE `products` ADD COLUMN `max_order_cash` BIGINT UNSIGNED NULL DEFAULT NULL AFTER `min_order_cash`',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE stmt FROM @sql;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
|
-- مقادیر محصولات (مثلاً گلد علی) را فقط از پنل ادمین تنظیم کنید؛ این اسکریپت فقط ستونها را اضافه میکند.
|
||||||
@@ -110,6 +110,7 @@ Route::middleware('auth:user')->group(function (){
|
|||||||
Route::post('price', [PriceController::class, 'store']);
|
Route::post('price', [PriceController::class, 'store']);
|
||||||
Route::post('price/table', [PriceController::class, 'table']);
|
Route::post('price/table', [PriceController::class, 'table']);
|
||||||
Route::post('prices', [PriceController::class, 'priceData']);
|
Route::post('prices', [PriceController::class, 'priceData']);
|
||||||
|
Route::post('prices/chart', [PriceController::class, 'chartPrices']);
|
||||||
|
|
||||||
|
|
||||||
Route::post('finance', [FinanceController::class, 'fall']);
|
Route::post('finance', [FinanceController::class, 'fall']);
|
||||||
|
|||||||
Reference in New Issue
Block a user