diff --git a/app/Console/Commands/UpdateProductStatus.php b/app/Console/Commands/UpdateProductStatus.php index 0d9098c..f3b6921 100644 --- a/app/Console/Commands/UpdateProductStatus.php +++ b/app/Console/Commands/UpdateProductStatus.php @@ -4,7 +4,8 @@ namespace App\Console\Commands; use Illuminate\Console\Command; use App\Models\Product; use Illuminate\Support\Facades\Http; -use App\Http\Controllers\Site\ReportController ; +use App\Http\Controllers\Site\ReportController; +use App\Services\ProductPriceService; // مدل محصول خود را ایمپورت کنید @@ -47,10 +48,11 @@ class UpdateProductStatus extends Command $show = ($current_time >= $product->auto_open_at && $current_time <= $product->auto_close_at); if ($product->reading_method == $RPrice['name']) { - $p = Product::where('id', $product->id)->update([ - 'price' => $RPrice['price'], - 'price_profit' => $RPrice['profit'], - ]); + ProductPriceService::syncFromReference( + $product, + (int) $RPrice['price'], + (int) ($RPrice['profit'] ?? 0) + ); if($product->bubble== 1){ $ReportController = new ReportController(); @@ -63,11 +65,9 @@ class UpdateProductStatus extends Command } } - if($product->reading_method == 'مس' && $CP){ - $p = Product::where('id', $product->id)->update([ - 'price' => $CP, - 'show' => $show, - ]); + if ($product->reading_method == 'مس' && $CP) { + ProductPriceService::syncFromReference($product, (int) $CP, 0); + Product::where('id', $product->id)->update(['show' => $show]); } } } diff --git a/app/Http/Controllers/Admin/ProductController.php b/app/Http/Controllers/Admin/ProductController.php index d2aea58..5a285b7 100644 --- a/app/Http/Controllers/Admin/ProductController.php +++ b/app/Http/Controllers/Admin/ProductController.php @@ -15,6 +15,7 @@ use Illuminate\Support\Facades\Http; use \App\Http\Controllers\Customer\FundController; use App\Http\Controllers\Site\ReportController; use App\Services\ConfigService; +use App\Services\ProductPriceService; class ProductController extends SuperController @@ -73,7 +74,7 @@ class ProductController extends SuperController public function store(Request $request) { - $data = $request->all(); + $data = $this->filterProductData($request->all()); $product = Product::create($data); return $this->resultCreate($product->id); @@ -83,9 +84,12 @@ class ProductController extends SuperController { // return 1; - $data = $request->all(); + $data = $this->filterProductData($request->all()); if (isset($data["price"])){ $data["reading_method"] = null; + if (Product::hasPriceOffsetColumn()) { + $data['price_offset_percent'] = 0; + } } if (isset($data["auto_close_at"]) and isset($data["auto_close_at"])){ if ($data["auto_close_at"] == $data["auto_open_at"]){ @@ -103,8 +107,23 @@ class ProductController extends SuperController // $data['auto_open_at'] = Carbon::parse($data['auto_open_at'])->format('Y-m-d H:i:s'); // $data['auto_close_at'] = Carbon::parse($data['auto_close_at'])->format('Y-m-d H:i:s'); -// Product::find($id)->update($data); - Product::find($id)->update($data); + $product = Product::findOrFail($id); + $oldOffsetPercent = (float) ($product->price_offset_percent ?? 0); + + if ( + Product::hasPriceOffsetColumn() + && $product->reading_method + && array_key_exists('price_offset_percent', $data) + ) { + ProductPriceService::reapplyOffsetPercent( + $product, + (float) $data['price_offset_percent'], + $oldOffsetPercent + ); + unset($data['price'], $data['price_profit']); + } + + $product->update($data); return response()->json(true); } @@ -121,8 +140,13 @@ class ProductController extends SuperController { // $this->getPrice(); // $this->auto_close_open(); - $product = Product::with(['file'])->where('active', 1)->get(); - return response()->json($product); + $products = Product::with(['file'])->where('active', 1)->get(); + + if (Product::hasPriceOffsetColumn() && str_contains(request()->path(), '/customer/')) { + $products->each->makeHidden(['price_offset_percent']); + } + + return response()->json($products); } public function getPrice() @@ -159,11 +183,16 @@ class ProductController extends SuperController if ($RPrice['name'] == 'گلد دات ای از آبشده - رسمی - نقد فردا') { $RPrice['price'] = $RPrice['price'] / 4.3318; } - $p = Product::where('id', $product->id)->update([ - 'price' => $RPrice['price'], - 'price_profit' => $RPrice['profit'], - ]); - $productPrice = (float) $RPrice['price'] + (float) ($RPrice['profit'] ?? 0); + ProductPriceService::syncFromReference( + $product, + (int) $RPrice['price'], + (int) ($RPrice['profit'] ?? 0) + ); + $productPrice = (float) ProductPriceService::adjustedTotal( + (int) $RPrice['price'], + (int) ($RPrice['profit'] ?? 0), + ProductPriceService::offsetPercent($product) + ); if ( $hasExtremeKeys && $mainProductId @@ -183,10 +212,12 @@ class ProductController extends SuperController } } if (isset($copper) && isset($dollar)) { - $cp = ($copper / 1000000) * $dollar; - $p = Product::where('metal_id', 3)->update([ - 'price' => $cp, - 'price_profit' => 0, + $cp = (int) round(($copper / 1000000) * $dollar); + $copperProducts = Product::where('metal_id', 3)->get(); + foreach ($copperProducts as $copperProduct) { + ProductPriceService::syncFromReference($copperProduct, $cp, 0); + } + Product::where('metal_id', 3)->update([ 'updated_at' => \Carbon\Carbon::now()->format('Y-m-d H:i:s'), ]); if ( @@ -194,7 +225,11 @@ class ProductController extends SuperController && $mainProductId && Product::where('id', $mainProductId)->where('metal_id', 3)->exists() ) { - $config->trackDailyPriceExtreme((float) $cp); + $mainCopper = Product::find($mainProductId); + $extremePrice = $mainCopper + ? (float) ($mainCopper->price + ($mainCopper->price_profit ?? 0)) + : (float) $cp; + $config->trackDailyPriceExtreme($extremePrice); } } @@ -291,4 +326,13 @@ class ProductController extends SuperController } + + private function filterProductData(array $data): array + { + if (!Product::hasPriceOffsetColumn()) { + unset($data['price_offset_percent']); + } + + return $data; + } } diff --git a/app/Models/Product.php b/app/Models/Product.php index 82ec4cc..257304c 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -9,12 +9,49 @@ use Rooyesh\Wallet\models\Transaction; use Rooyesh\Wallet\models\Wallet; use Carbon\Carbon; use Illuminate\Support\Facades\DB; - - +use Illuminate\Support\Facades\Schema; class Product extends Model { use HasFactory,Selector,SoftDeletes; + + private static ?bool $priceOffsetColumnExists = null; + + protected static function booted(): void + { + static::saving(function (Product $product) { + if (!static::hasPriceOffsetColumn()) { + unset($product->attributes['price_offset_percent']); + } + }); + } + + public static function hasPriceOffsetColumn(): bool + { + if (static::$priceOffsetColumnExists !== null) { + return static::$priceOffsetColumnExists; + } + + try { + static::$priceOffsetColumnExists = Schema::hasColumn( + (new static)->getTable(), + 'price_offset_percent' + ); + } catch (\Throwable) { + static::$priceOffsetColumnExists = false; + } + + return static::$priceOffsetColumnExists; + } + + public function getPriceOffsetPercentAttribute($value): float + { + if (!static::hasPriceOffsetColumn()) { + return 0.0; + } + + return (float) ($value ?? 0); + } protected $fillable = [ 'title', // The title of the record. 'price', // The amount of the record. @@ -38,6 +75,9 @@ class Product extends Model 'cash_fee_sell', // Add cash_fee_sell to fillable 'percent_fee_buy', // Add percent_fee_buy to fillable 'metal_id', //the material of metal (#gold or #silver) + 'price_offset_percent', // admin only: +/- % vs automatic reference (baked into price on sync) + 'price_profit', + 'bubble', ]; protected $casts = [ @@ -54,6 +94,8 @@ class Product extends Model 'percent_fee_buy' => 'float', // Cast to float. 'cash_fee_buy' => 'int', // Cast to int or decimal if needed 'cash_fee_sell' => 'int', // Cast to int or decimal if needed + 'price_offset_percent' => 'float', + 'price_profit' => 'int', ]; static $METAL_ID = [ diff --git a/app/Services/ProductPriceService.php b/app/Services/ProductPriceService.php new file mode 100644 index 0000000..79cba0d --- /dev/null +++ b/app/Services/ProductPriceService.php @@ -0,0 +1,57 @@ +price_offset_percent ?? 0) + : 0.0; + } + + public static function syncFromReference(Product $product, int $basePrice, int $baseProfit = 0): void + { + $offsetPercent = self::offsetPercent($product); + + Product::where('id', $product->id)->update([ + 'price' => self::adjustedTotal($basePrice, $baseProfit, $offsetPercent), + 'price_profit' => 0, + ]); + } + + /** وقتی فقط درصد در ادمین عوض می‌شود (بدون sync جدید) */ + public static function reapplyOffsetPercent(Product $product, float $newOffsetPercent, ?float $oldOffsetPercent = null): void + { + if (!Product::hasPriceOffsetColumn()) { + return; + } + + $oldOffset = $oldOffsetPercent ?? self::offsetPercent($product); + $currentTotal = (int) ($product->price + ($product->price_profit ?? 0)); + $reference = $oldOffset != 0.0 + ? (int) round($currentTotal / (1 + $oldOffset / 100)) + : $currentTotal; + + Product::where('id', $product->id)->update([ + 'price' => (int) round($reference * (1 + ($newOffsetPercent / 100))), + 'price_profit' => 0, + ]); + } +} diff --git a/database/migrations/2026_06_02_000001_add_price_offset_percent_to_products_table.php b/database/migrations/2026_06_02_000001_add_price_offset_percent_to_products_table.php new file mode 100644 index 0000000..e142195 --- /dev/null +++ b/database/migrations/2026_06_02_000001_add_price_offset_percent_to_products_table.php @@ -0,0 +1,34 @@ +decimal('price_offset_percent', 8, 2)->default(0)->after('price_profit'); + } + }); + } + + public function down(): void + { + if (!Schema::hasTable('products')) { + return; + } + + if (Schema::hasColumn('products', 'price_offset_percent')) { + Schema::table('products', function (Blueprint $table) { + $table->dropColumn('price_offset_percent'); + }); + } + } +}; diff --git a/routes/web.php b/routes/web.php index 613a3f3..699c0de 100644 --- a/routes/web.php +++ b/routes/web.php @@ -2,6 +2,7 @@ use App\Models\Customer; use App\Models\Product; +use App\Services\ProductPriceService; use Carbon\Carbon; use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Http; @@ -33,19 +34,20 @@ Route::get('/refPricer', function () { if ($RPrice['name'] == 'گلد دات ای از آبشده - رسمی - نقد فردا') { $RPrice['price'] = $RPrice['price'] / 4.3318; } - $p = Product::where('id', $product->id)->update([ - 'price' => $RPrice['price'], - 'price_profit' => $RPrice['profit'], - ]); + ProductPriceService::syncFromReference( + $product, + (int) $RPrice['price'], + (int) ($RPrice['profit'] ?? 0) + ); // } } } if (isset($copper) && isset($dollar)) { $cp = ($copper / 1000000) * $dollar; - $p = Product::where('id', 33)->update([ - 'price' => $cp, - 'price_profit' => 0, - ]); + $copperProduct = Product::find(33); + if ($copperProduct) { + ProductPriceService::syncFromReference($copperProduct, (int) round($cp), 0); + } } return response()->json(true);