3 Коммиты 00e906869f ... 9c7582f43e

Автор SHA1 Сообщение Дата
  Benjamin Harris 9c7582f43e gitignore 2 недель назад
  Benjamin Harris 797dd687b7 Make sync() always return valid JSON with a readable error message 2 недель назад
  Benjamin Harris 3fa9e1a9c7 Fix OCMOD targeting wrong template file (product.twig vs product_form.twig) 2 недель назад
3 измененных файлов с 62 добавлено и 49 удалено
  1. 3 1
      .gitignore
  2. 14 17
      install.xml
  3. 45 31
      upload/admin/controller/extension/module/reverb.php

+ 3 - 1
.gitignore

@@ -3,4 +3,6 @@
 # Ignore all zip files
 *.zip
 
-OPENCART.md
+OPENCART.md
+
+_*

+ 14 - 17
install.xml

@@ -2,51 +2,48 @@
 <modification>
     <name>Reverb Integration</name>
     <code>reverb</code>
-    <version>1.0.3</version>
+    <version>1.0.4</version>
     <author>Reverb OpenCart</author>
     <link>https://reverb.com/au/page/integrations</link>
 
     <!--
         ========================================================================
-        FILE: admin/view/template/catalog/product.twig
-        Injects a Reverb tab into the product edit page.
-
-        Tab content is loaded via AJAX from extension/module/reverb/productTab
-        so no PHP controller patching is required. Saving is handled by the
-        OC event hooks registered in the module install() method.
+        FILE: admin/view/template/catalog/product_form.twig
+        (OC3 uses product_form.twig, NOT product.twig)
 
-        error="skip" on each operation means a single search miss will not
-        abort the other operation.
+        Injects a Reverb tab into the product edit page.
+        Tab content is loaded via AJAX from extension/module/reverb/productTab.
+        Saving is handled by OC event hooks registered in module install().
         ========================================================================
     -->
-    <file path="admin/view/template/catalog/product.twig">
+    <file path="admin/view/template/catalog/product_form.twig">
 
-        <!-- Tab nav item — inserted after the SEO tab -->
+        <!-- Tab nav item — inserted after the Design tab (last tab in OC3) -->
         <operation error="skip">
-            <search><![CDATA[<li><a href="#tab-seo" data-toggle="tab">{{ tab_seo }}</a></li>]]></search>
+            <search><![CDATA[<li><a href="#tab-design" data-toggle="tab">{{ tab_design }}</a></li>]]></search>
             <add position="after"><![CDATA[<li><a href="#tab-reverb" data-toggle="tab">Reverb</a></li>]]></add>
         </operation>
 
-        <!-- Tab pane placeholder + AJAX loader — inserted before the SEO pane -->
+        <!-- Tab pane + AJAX loader — inserted before the Design pane -->
         <operation error="skip">
-            <search><![CDATA[<div class="tab-pane" id="tab-seo">]]></search>
+            <search><![CDATA[<div class="tab-pane" id="tab-design">]]></search>
             <add position="before"><![CDATA[
 <div class="tab-pane" id="tab-reverb">
   <div id="reverb-tab-content" style="padding:20px;">
     <i class="fa fa-spinner fa-spin"></i> Loading&hellip;
   </div>
 </div>
-<script>
+<script type="text/javascript">
 (function () {
   $(document).ready(function () {
-    var p  = new URLSearchParams(window.location.search);
+    var p   = new URLSearchParams(window.location.search);
     var url = 'index.php?route=extension/module/reverb/productTab'
             + '&user_token=' + encodeURIComponent(p.get('user_token') || '')
             + '&product_id=' + encodeURIComponent(p.get('product_id') || 0);
     $.get(url).done(function (html) {
       $('#reverb-tab-content').html(html);
     }).fail(function () {
-      $('#reverb-tab-content').html('<p class="text-danger"><i class="fa fa-exclamation-circle"></i> Could not load Reverb tab. Check that the Reverb module is installed correctly.</p>');
+      $('#reverb-tab-content').html('<p class="text-danger"><i class="fa fa-exclamation-circle"></i> Could not load Reverb tab. Check that the Reverb module is installed and enabled.</p>');
     });
   });
 }());

+ 45 - 31
upload/admin/controller/extension/module/reverb.php

@@ -170,46 +170,60 @@ class ControllerExtensionModuleReverb extends Controller {
         $this->load->language('extension/module/reverb');
         $this->load->model('extension/module/reverb');
 
-        $json = ['success' => false];
+        // Set JSON header first so any uncaught error still returns parseable JSON.
+        $this->response->addHeader('Content-Type: application/json');
 
-        if (!$this->user->hasPermission('modify', 'extension/module/reverb')) {
-            $json['error'] = $this->language->get('error_permission');
-            $this->response->addHeader('Content-Type: application/json');
-            $this->response->setOutput(json_encode($json));
-            return;
-        }
+        try {
+            if (!$this->user->hasPermission('modify', 'extension/module/reverb')) {
+                $this->response->setOutput(json_encode(['success' => false, 'error' => $this->language->get('error_permission')]));
+                return;
+            }
 
-        $settings = $this->buildSettings();
+            $settings = $this->buildSettings();
 
-        if (empty($settings['api_token'])) {
-            $json['error'] = $this->language->get('error_api_token');
-            $this->response->addHeader('Content-Type: application/json');
-            $this->response->setOutput(json_encode($json));
-            return;
-        }
+            if (empty($settings['api_token'])) {
+                $this->response->setOutput(json_encode(['success' => false, 'error' => $this->language->get('error_api_token')]));
+                return;
+            }
 
-        $allowed_categories = $this->config->get('module_reverb_sync_categories') ?? [];
-        $products           = $this->model_extension_module_reverb->getSyncEnabledProducts((array)$allowed_categories);
+            $allowed_categories = $this->config->get('module_reverb_sync_categories');
+            if (empty($allowed_categories)) {
+                $this->response->setOutput(json_encode(['success' => false, 'error' => 'No sync categories configured. Select at least one category in the Settings tab.']));
+                return;
+            }
+
+            $products = $this->model_extension_module_reverb->getSyncEnabledProducts((array)$allowed_categories);
 
-        $pushed = 0;
-        $errors = 0;
+            $pushed = 0;
+            $errors = 0;
 
-        foreach ($products as $product) {
-            try {
-                $this->model_extension_module_reverb->syncProductToReverb($product, $product, $settings);
-                $this->model_extension_module_reverb->log($product['product_id'], 'push', 'success', 'Synced: ' . $product['name']);
-                $pushed++;
-            } catch (Exception $e) {
-                $this->model_extension_module_reverb->log($product['product_id'], 'push', 'error', $e->getMessage());
-                $errors++;
+            foreach ($products as $product) {
+                try {
+                    $this->model_extension_module_reverb->syncProductToReverb($product, $product, $settings);
+                    $pushed++;
+                    $this->safeLog($product['product_id'], 'push', 'success', 'Synced: ' . $product['name']);
+                } catch (Exception $e) {
+                    $errors++;
+                    $this->safeLog($product['product_id'], 'push', 'error', $e->getMessage());
+                }
             }
-        }
 
-        $json['success'] = true;
-        $json['message'] = sprintf($this->language->get('text_sync_complete'), $pushed, $errors);
+            $this->response->setOutput(json_encode([
+                'success' => true,
+                'message' => sprintf($this->language->get('text_sync_complete'), $pushed, $errors),
+            ]));
 
-        $this->response->addHeader('Content-Type: application/json');
-        $this->response->setOutput(json_encode($json));
+        } catch (Exception $e) {
+            $this->response->setOutput(json_encode(['success' => false, 'error' => $e->getMessage()]));
+        }
+    }
+
+    private function safeLog($product_id, $direction, $status, $message) {
+        try {
+            $this->model_extension_module_reverb->log($product_id, $direction, $status, $message);
+        } catch (Exception $e) {
+            // Log table missing or unavailable — ignore silently.
+        }
     }
 
     // -------------------------------------------------------------------------