Erster Upload

This commit is contained in:
Malek Tellissi
2026-09-11 01:17:47 +02:00
commit 400172cdde
171 changed files with 18844 additions and 0 deletions
+122
View File
@@ -0,0 +1,122 @@
<?php
namespace App\Console\Commands;
use App\Models\Packing;
use App\Models\Product;
use App\Models\ProductInventory;
use App\Models\ProductSize;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
class ImportShopify extends Command
{
protected $signature = 'import:shopify {file : Pfad zur Shopify Inventory-CSV}';
protected $description = 'Importiert Produkte aus einem Shopify Inventory-Export';
public function handle(): int
{
$file = $this->argument('file');
if (! file_exists($file)) {
$this->error("Datei nicht gefunden: $file");
return self::FAILURE;
}
$rows = $this->parseCsv($file);
if (empty($rows)) {
$this->error('CSV ist leer oder konnte nicht gelesen werden.');
return self::FAILURE;
}
$byHandle = collect($rows)->groupBy('Handle');
$this->info("Gefunden: {$byHandle->count()} Produkte, " . count($rows) . ' Varianten');
$stats = ['products' => 0, 'sizes' => 0, 'inventory' => 0, 'skipped' => 0];
DB::transaction(function () use ($byHandle, &$stats) {
foreach ($byHandle as $variants) {
$first = $variants->first();
$product = Product::firstOrCreate(
['title' => $first['Title']],
['recipes_id' => null],
);
if ($product->wasRecentlyCreated) {
$stats['products']++;
}
foreach ($variants as $row) {
$packingRaw = $row['Option1 Value'];
// Format: "Standbodenbeutel 50 g" oder "Metalldose 40 g"
if (! preg_match('/^(.+?)\s+(\d+(?:[.,]\d+)?)\s*g$/i', $packingRaw, $m)) {
$this->warn(" ⚠ Verpackungsformat nicht erkannt: '$packingRaw' übersprungen");
$stats['skipped']++;
continue;
}
$packing = Packing::firstOrCreate([
'name' => trim($m[1]),
'size' => (float) str_replace(',', '.', $m[2]),
]);
$sku = $row['SKU'] ?: null;
$size = ProductSize::firstOrCreate(
['product_id' => $product->id, 'packing_id' => $packing->id],
['sku' => $sku, 'price' => 0],
);
if ($size->wasRecentlyCreated) {
$stats['sizes']++;
}
$onHand = (int) $row['On hand (current)'];
for ($i = 0; $i < $onHand; $i++) {
ProductInventory::create([
'product_id' => $product->id,
'size_id' => $size->id,
]);
$stats['inventory']++;
}
}
}
});
$this->info("{$stats['products']} Produkte erstellt");
$this->info("{$stats['sizes']} Varianten erstellt");
$this->info("{$stats['inventory']} Lagereinträge erstellt");
if ($stats['skipped'] > 0) {
$this->warn("{$stats['skipped']} Zeilen übersprungen (Verpackungsformat unbekannt)");
}
return self::SUCCESS;
}
private function parseCsv(string $file): array
{
$rows = [];
$headers = null;
$handle = fopen($file, 'r');
if ($handle === false) {
return [];
}
while (($data = fgetcsv($handle, 0, ',')) !== false) {
if ($headers === null) {
$headers = array_map('trim', $data);
continue;
}
if (count($data) === count($headers)) {
$rows[] = array_combine($headers, $data);
}
}
fclose($handle);
return $rows;
}
}