From bfff05a61bb2c6ef0a094727d0b8f9e0e73feff6 Mon Sep 17 00:00:00 2001 From: Jacek Pyziak Date: Fri, 27 Feb 2026 19:27:39 +0100 Subject: [PATCH] fix: include languages.pl content when saving categories to shopPRO shopPRO's products/update clears ALL language fields (name, description, short_description, etc.) for any language not included in the payload. Sending only {"categories":[...]} wiped them out. saveProductCategoriesJson() now: 1. Looks up the local orderPRO product via findMappedProductId() 2. Loads per-integration translation (with global fallback) 3. Includes languages.pl in the payload alongside categories Also adds ProductRepository to MarketplaceController constructor. Co-Authored-By: Claude Sonnet 4.6 --- routes/web.php | 3 +- .../Marketplace/MarketplaceController.php | 40 ++++++++++++++++++- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/routes/web.php b/routes/web.php index a244135..c6c4185 100644 --- a/routes/web.php +++ b/routes/web.php @@ -92,7 +92,8 @@ return static function (Application $app): void { $auth, $marketplaceRepository, $integrationRepository, - $shopProClient + $shopProClient, + $productRepository ); $authMiddleware = new AuthMiddleware($auth); diff --git a/src/Modules/Marketplace/MarketplaceController.php b/src/Modules/Marketplace/MarketplaceController.php index 8e492c4..8b907cf 100644 --- a/src/Modules/Marketplace/MarketplaceController.php +++ b/src/Modules/Marketplace/MarketplaceController.php @@ -10,6 +10,7 @@ use App\Core\Security\Csrf; use App\Core\Support\Flash; use App\Core\View\Template; use App\Modules\Auth\AuthService; +use App\Modules\Products\ProductRepository; use App\Modules\Settings\IntegrationRepository; use App\Modules\Settings\ShopProClient; @@ -21,7 +22,8 @@ final class MarketplaceController private readonly AuthService $auth, private readonly MarketplaceRepository $marketplace, private readonly IntegrationRepository $integrationRepository, - private readonly ShopProClient $shopProClient + private readonly ShopProClient $shopProClient, + private readonly ProductRepository $productRepository ) { } @@ -177,12 +179,46 @@ final class MarketplaceController ? array_values(array_filter(array_map('intval', $body['category_ids']), static fn(int $id): bool => $id > 0)) : []; + $payload = ['categories' => $categoryIds]; + + // Include language content so shopPRO doesn't clear name/description when saving categories. + // Use per-integration translation if set, otherwise fall back to global product translation. + $localProductId = $this->integrationRepository->findMappedProductId( + 'shoppro', + (string) $externalProductId, + $integrationId + ); + if ($localProductId !== null && $localProductId > 0) { + $integrationTranslation = null; + foreach ($this->productRepository->findIntegrationTranslations($localProductId) as $row) { + if ((int) ($row['integration_id'] ?? 0) === $integrationId) { + $integrationTranslation = $row; + break; + } + } + $global = $this->productRepository->findById($localProductId, 'pl'); + if ($global !== null) { + $name = (string) ($integrationTranslation['name'] ?? $global['name'] ?? ''); + $payload['languages'] = [ + 'pl' => [ + 'name' => $name !== '' ? $name : ('orderPRO #' . $localProductId), + 'short_description' => $integrationTranslation['short_description'] ?? $global['short_description'] ?? null, + 'description' => $integrationTranslation['description'] ?? $global['description'] ?? null, + 'meta_title' => $global['meta_title'] ?? null, + 'meta_description' => $global['meta_description'] ?? null, + 'meta_keywords' => $global['meta_keywords'] ?? null, + 'seo_link' => $global['seo_link'] ?? null, + ], + ]; + } + } + $result = $this->shopProClient->updateProduct( (string) ($creds['base_url'] ?? ''), (string) ($creds['api_key'] ?? ''), (int) ($creds['timeout_seconds'] ?? 10), $externalProductId, - ['categories' => $categoryIds] + $payload ); if (!($result['ok'] ?? false)) {