label('In Shopify veröffentlichen') ->icon('heroicon-o-arrow-up-tray') ->color('warning') ->requiresConfirmation() ->modalHeading('Produkt in Shopify anlegen') ->modalDescription('Erstellt das Produkt mit allen Varianten in Shopify und verknüpft die IDs.') ->visible(fn () => ! $this->record->shopify_product_id) ->action(fn () => $this->createProductInShopify()), Actions\Action::make('rezept-versionen') ->label('Rezept-Versionen') ->icon('heroicon-o-clock') ->color('gray') ->url(fn () => ProductResource::getUrl('recipe-history', ['record' => $this->record])), Actions\DeleteAction::make(), ]; } protected function afterSave(): void { $this->syncSizes(); $this->syncRecipe(); } protected function syncSizes(): void { $product = $this->record; $incoming = collect($this->data['sizes'] ?? []); $keepIds = []; foreach ($incoming as $size) { if (empty($size['packing_id'])) { continue; } $gtin = preg_replace('/\D/', '', (string) ($size['gtin'] ?? '')); $ps = ProductSize::updateOrCreate( [ 'product_id' => $product->id, 'packing_id' => (int) $size['packing_id'], ], [ 'price' => $size['price'], 'sku' => $size['sku'] ?: null, 'gtin' => $gtin !== '' ? $gtin : null, 'description' => $size['description'] ?? null, ] ); $keepIds[] = $ps->id; } // Only delete local-only sizes (no shopify_variant_id) that were removed ProductSize::where('product_id', $product->id) ->whereNotIn('id', $keepIds) ->whereNull('shopify_variant_id') ->delete(); } protected function syncRecipe(): void { $product = $this->record; $spices = $this->data['recipe_spices'] ?? []; if (empty($spices)) { return; } $newPivot = collect($spices)->mapWithKeys(fn ($s) => [ (int) $s['spice_id'] => (float) $s['amount_in_percent'], ])->toArray(); $current = $product->recipe; if ($current) { $current->load('spices'); $existingPivot = $current->spices->mapWithKeys(fn ($s) => [ $s->id => (float) $s->pivot->amount_in_percent, ])->toArray(); if ($existingPivot == $newPivot) { return; } } $nextVersion = Recipe::where('product_id', $product->id)->max('version') + 1; $recipe = Recipe::create([ 'name' => $product->title, 'product_id' => $product->id, 'version' => $nextVersion, ]); $recipe->spices()->sync( collect($newPivot)->mapWithKeys(fn ($pct, $id) => [ $id => ['amount_in_percent' => $pct], ])->toArray() ); $product->update(['recipes_id' => $recipe->id]); } public function createProductInShopify(): void { $product = $this->record; if ($product->shopify_product_id) { Notification::make()->title('Bereits in Shopify verknüpft')->warning()->send(); return; } $sizes = ProductSize::with('packing')->where('product_id', $product->id)->get(); try { $result = app(ShopifyService::class)->createProduct($product, $sizes); $product->update(['shopify_product_id' => $result['shopify_product_id']]); foreach ($result['variants'] as $packingId => $variantId) { ProductSize::where('product_id', $product->id) ->where('packing_id', $packingId) ->update(['shopify_variant_id' => $variantId]); } Notification::make()->title('Produkt in Shopify erstellt')->success()->send(); $this->redirect(ProductResource::getUrl('edit', ['record' => $product])); } catch (\Throwable $e) { Notification::make()->title('Shopify-Fehler')->body($e->getMessage())->danger()->send(); } } public function publishVariantToShopify(int $sizeId): void { $size = ProductSize::with('packing')->find($sizeId); $product = $this->record; if (! $size || $size->shopify_variant_id || ! $product->shopify_product_id) { Notification::make() ->title('Nicht möglich') ->body($product->shopify_product_id ? 'Variante bereits in Shopify verknüpft.' : 'Produkt hat keine Shopify-ID — zuerst shopify:import ausführen.') ->warning() ->send(); return; } try { $variantId = app(ShopifyService::class)->createVariant($product->shopify_product_id, $size); $size->update(['shopify_variant_id' => $variantId]); Notification::make()->title('Variante in Shopify veröffentlicht')->success()->send(); $this->redirect(ProductResource::getUrl('edit', ['record' => $product])); } catch (\Throwable $e) { Notification::make()->title('Shopify-Fehler')->body($e->getMessage())->danger()->send(); } } public function syncVariantWithShopify(int $sizeId): void { $size = ProductSize::find($sizeId); if (! $size || ! $size->shopify_variant_id) { Notification::make()->title('Keine Shopify-Verknüpfung')->warning()->send(); return; } try { app(ShopifyService::class)->updateVariant($size); Notification::make()->title('Shopify synchronisiert')->success()->send(); } catch (\Throwable $e) { Notification::make()->title('Shopify-Fehler')->body($e->getMessage())->danger()->send(); } } }