store 6
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\DB\Te\TableEngine;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\PriceSyncLog;
|
||||
use App\Services\ConfigService;
|
||||
use App\Services\ProductPriceSyncService;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class PriceSyncLogController extends Controller
|
||||
{
|
||||
public function table(Request $request)
|
||||
{
|
||||
$records = PriceSyncLog::query()->orderByDesc('id');
|
||||
|
||||
TableEngine::create($records, $request->all())
|
||||
->initSearch(['source', 'source_url'])
|
||||
->select(['*'])
|
||||
->export($records);
|
||||
|
||||
return response()->json($records);
|
||||
}
|
||||
|
||||
public function show($id)
|
||||
{
|
||||
$log = PriceSyncLog::with('items')->findOrFail($id);
|
||||
|
||||
return response()->json($log);
|
||||
}
|
||||
|
||||
public function runSync(ProductPriceSyncService $syncService, ConfigService $configService)
|
||||
{
|
||||
if (! $configService->isStore()) {
|
||||
return response()->json(['message' => 'فقط در حالت فروشگاه'], 422);
|
||||
}
|
||||
|
||||
$syncService->syncStorePrices(true);
|
||||
|
||||
$log = PriceSyncLog::with('items')->orderByDesc('id')->first();
|
||||
|
||||
return response()->json([
|
||||
'message' => $log ? 'قیمتها بهروزرسانی شد' : 'تغییری در قیمت محصولات نبود',
|
||||
'data' => $log,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class PriceSyncLog extends Model
|
||||
{
|
||||
protected $table = 'price_sync_logs';
|
||||
|
||||
public $timestamps = false;
|
||||
|
||||
protected $fillable = [
|
||||
'source',
|
||||
'source_url',
|
||||
'liquid_gold_price',
|
||||
'products_updated',
|
||||
'created_at',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'liquid_gold_price' => 'integer',
|
||||
'products_updated' => 'integer',
|
||||
'created_at' => 'datetime',
|
||||
];
|
||||
|
||||
public function items(): HasMany
|
||||
{
|
||||
return $this->hasMany(PriceSyncLogItem::class, 'log_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class PriceSyncLogItem extends Model
|
||||
{
|
||||
protected $table = 'price_sync_log_items';
|
||||
|
||||
public $timestamps = false;
|
||||
|
||||
protected $fillable = [
|
||||
'log_id',
|
||||
'product_id',
|
||||
'product_title',
|
||||
'reading_method',
|
||||
'source_name',
|
||||
'base_price',
|
||||
'base_profit',
|
||||
'offset_percent',
|
||||
'stored_price',
|
||||
'previous_price',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'product_id' => 'integer',
|
||||
'base_price' => 'integer',
|
||||
'base_profit' => 'integer',
|
||||
'offset_percent' => 'float',
|
||||
'stored_price' => 'integer',
|
||||
'previous_price' => 'integer',
|
||||
];
|
||||
|
||||
public function log(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(PriceSyncLog::class, 'log_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\PriceSyncLog;
|
||||
use App\Models\PriceSyncLogItem;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class PriceSyncLogService
|
||||
{
|
||||
public function isAvailable(): bool
|
||||
{
|
||||
return Schema::hasTable('price_sync_logs') && Schema::hasTable('price_sync_log_items');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, array<string, mixed>> $items
|
||||
*/
|
||||
public function record(string $source, ?string $sourceUrl, int $liquidGoldPrice, array $items): ?PriceSyncLog
|
||||
{
|
||||
if (! $this->isAvailable() || $items === []) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$changedItems = array_values(array_filter(
|
||||
$items,
|
||||
static fn (array $item) => (bool) ($item['changed'] ?? false)
|
||||
));
|
||||
|
||||
if ($changedItems === []) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$log = PriceSyncLog::create([
|
||||
'source' => $source,
|
||||
'source_url' => $sourceUrl,
|
||||
'liquid_gold_price' => $liquidGoldPrice,
|
||||
'products_updated' => count($changedItems),
|
||||
'created_at' => now(),
|
||||
]);
|
||||
|
||||
foreach ($changedItems as $item) {
|
||||
PriceSyncLogItem::create([
|
||||
'log_id' => $log->id,
|
||||
'product_id' => $item['product_id'] ?? null,
|
||||
'product_title' => $item['product_title'] ?? null,
|
||||
'reading_method' => $item['reading_method'] ?? null,
|
||||
'source_name' => $item['source_name'] ?? null,
|
||||
'base_price' => (int) ($item['base_price'] ?? 0),
|
||||
'base_profit' => (int) ($item['base_profit'] ?? 0),
|
||||
'offset_percent' => (float) ($item['offset_percent'] ?? 0),
|
||||
'stored_price' => (int) ($item['new_price'] ?? 0),
|
||||
'previous_price' => (int) ($item['old_price'] ?? 0),
|
||||
]);
|
||||
}
|
||||
|
||||
return $log->load('items');
|
||||
}
|
||||
}
|
||||
@@ -26,21 +26,23 @@ class ProductPriceService
|
||||
: 0.0;
|
||||
}
|
||||
|
||||
public static function syncFromReference(Product $product, int $basePrice, int $baseProfit = 0): void
|
||||
/** @return array<string, mixed>|null */
|
||||
public static function syncFromReference(Product $product, int $basePrice, int $baseProfit = 0, ?string $sourceName = null): ?array
|
||||
{
|
||||
if (!Product::hasStoredPriceColumns()) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
$offsetPercent = self::offsetPercent($product);
|
||||
$adjustedPrice = self::adjustedTotal($basePrice, $baseProfit, $offsetPercent);
|
||||
$oldPrice = (int) ($product->price ?? 0);
|
||||
|
||||
if (
|
||||
$adjustedPrice <= 0
|
||||
&& Product::hasUseLastPriceIfZeroColumn()
|
||||
&& ($product->use_last_price_if_zero ?? false)
|
||||
) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
$data = ['price' => $adjustedPrice];
|
||||
@@ -50,6 +52,19 @@ class ProductPriceService
|
||||
}
|
||||
|
||||
Product::where('id', $product->id)->update($data);
|
||||
|
||||
return [
|
||||
'product_id' => $product->id,
|
||||
'product_title' => $product->title,
|
||||
'reading_method' => $product->reading_method,
|
||||
'source_name' => $sourceName ?? $product->reading_method,
|
||||
'base_price' => $basePrice,
|
||||
'base_profit' => $baseProfit,
|
||||
'offset_percent' => $offsetPercent,
|
||||
'old_price' => $oldPrice,
|
||||
'new_price' => $adjustedPrice,
|
||||
'changed' => $oldPrice !== $adjustedPrice,
|
||||
];
|
||||
}
|
||||
|
||||
/** وقتی فقط درصد در ادمین عوض میشود (بدون sync جدید) */
|
||||
|
||||
@@ -29,8 +29,12 @@ class ProductPriceSyncService
|
||||
*/
|
||||
public function syncStorePrices(bool $forceRefresh = true): bool
|
||||
{
|
||||
$feed = $this->zaarboxPriceService->cachedPriceList($forceRefresh)
|
||||
?? $this->cachedLegacyPriceList($forceRefresh);
|
||||
$zaarboxFeed = $this->zaarboxPriceService->cachedPriceList($forceRefresh);
|
||||
$feed = $zaarboxFeed ?? $this->cachedLegacyPriceList($forceRefresh);
|
||||
$source = $zaarboxFeed !== null ? 'zaarbox' : 'legacy';
|
||||
$sourceUrl = $source === 'zaarbox'
|
||||
? $this->zaarboxPriceService->apiUrl()
|
||||
: 'http://212.23.201.173:8381/price_list';
|
||||
|
||||
if ($feed === null) {
|
||||
return false;
|
||||
@@ -43,6 +47,7 @@ class ProductPriceSyncService
|
||||
}
|
||||
|
||||
$synced = false;
|
||||
$logItems = [];
|
||||
|
||||
foreach ($products as $product) {
|
||||
$row = $this->zaarboxPriceService->findFeedRow($feed, (string) $product->reading_method);
|
||||
@@ -53,9 +58,13 @@ class ProductPriceSyncService
|
||||
$row = $this->zaarboxPriceService->normalizeFeedRow($row);
|
||||
$basePrice = (int) ($row['price'] ?? 0);
|
||||
$baseProfit = (int) ($row['profit'] ?? 0);
|
||||
$sourceName = trim((string) ($row['name'] ?? $product->reading_method));
|
||||
|
||||
ProductPriceService::syncFromReference($product, $basePrice, $baseProfit);
|
||||
$synced = true;
|
||||
$result = ProductPriceService::syncFromReference($product, $basePrice, $baseProfit, $sourceName);
|
||||
if ($result !== null) {
|
||||
$logItems[] = $result;
|
||||
$synced = true;
|
||||
}
|
||||
|
||||
if ((int) ($product->bubble ?? 0) === 1 && $liquidGoldPrice > 0 && $basePrice > 0) {
|
||||
$p = Product::find($product->id);
|
||||
@@ -66,6 +75,8 @@ class ProductPriceSyncService
|
||||
}
|
||||
}
|
||||
|
||||
app(PriceSyncLogService::class)->record($source, $sourceUrl, $liquidGoldPrice, $logItems);
|
||||
|
||||
return $synced;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
<?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('price_sync_logs')) {
|
||||
Schema::create('price_sync_logs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('source', 32);
|
||||
$table->string('source_url', 512)->nullable();
|
||||
$table->unsignedBigInteger('liquid_gold_price')->default(0);
|
||||
$table->unsignedSmallInteger('products_updated')->default(0);
|
||||
$table->timestamp('created_at')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
if (! Schema::hasTable('price_sync_log_items')) {
|
||||
Schema::create('price_sync_log_items', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('log_id');
|
||||
$table->unsignedBigInteger('product_id')->nullable();
|
||||
$table->string('product_title', 255)->nullable();
|
||||
$table->string('reading_method', 128)->nullable();
|
||||
$table->string('source_name', 255)->nullable();
|
||||
$table->unsignedBigInteger('base_price')->default(0);
|
||||
$table->unsignedBigInteger('base_profit')->default(0);
|
||||
$table->decimal('offset_percent', 8, 2)->default(0);
|
||||
$table->unsignedBigInteger('stored_price')->default(0);
|
||||
$table->unsignedBigInteger('previous_price')->default(0);
|
||||
$table->index('log_id');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('price_sync_log_items');
|
||||
Schema::dropIfExists('price_sync_logs');
|
||||
}
|
||||
};
|
||||
@@ -20,6 +20,7 @@ use App\Http\Controllers\Site\OfferCodesController;
|
||||
use App\Http\Controllers\Admin\SettingsController;
|
||||
use \App\Http\Controllers\Admin\GiftCardController;
|
||||
use App\Http\Controllers\Admin\CategoryController;
|
||||
use App\Http\Controllers\Admin\PriceSyncLogController;
|
||||
use App\Services\ConfigService;
|
||||
|
||||
|
||||
@@ -112,6 +113,12 @@ Route::middleware('auth:user')->group(function (){
|
||||
Route::post('price/table', [PriceController::class, 'table']);
|
||||
Route::post('prices', [PriceController::class, 'priceData']);
|
||||
Route::post('prices/chart', [PriceController::class, 'chartPrices']);
|
||||
|
||||
if (app(ConfigService::class)->isStore()) {
|
||||
Route::post('price-sync-logs/table', [PriceSyncLogController::class, 'table']);
|
||||
Route::get('price-sync-logs/{id}', [PriceSyncLogController::class, 'show']);
|
||||
Route::post('price-sync/run', [PriceSyncLogController::class, 'runSync']);
|
||||
}
|
||||
Route::get('zaarbox/products', [PriceController::class, 'zaarboxProducts']);
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user