浏览代码

feat: add Country of Origin field to product Reverb tab

Adds origin_country_code (ISO 3166-1 alpha-2) to the per-product
Reverb tab with a Select2 searchable country dropdown.

- DB: origin_country_code VARCHAR(2) added to oc_reverb_product_map
  in both install() CREATE TABLE and migrate() addColumnIfMissing()
  so existing installs get the column automatically on next load
- saveProductMap(): persists the value; sanitised to 2-char uppercase
- saveProductReverb() event handler: reads reverb_origin_country_code
  from POST and passes it through to saveProductMap()
- ProductMapper::toReverb(): includes origin_country_code in the
  listing payload when set
- productTab(): loads oc_country list via model_localisation_country,
  resolves the store default from config_country_id, falls back to
  that default when the saved value is empty
- Template: Select2 country dropdown placed above the Handmade field;
  initialised alongside the existing category Select2

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Benjamin Harris 1 周之前
父节点
当前提交
afe97be0bd

+ 25 - 2
upload/admin/controller/extension/module/reverb.php

@@ -176,10 +176,11 @@ class ControllerExtensionModuleReverb extends Controller {
         $this->load->model('extension/module/reverb');
         $this->model_extension_module_reverb->saveProductMap($product_id, [
             'sync_enabled'         => (int)(bool)$this->request->post['reverb_sync_enabled'],
-            'condition_uuid'       => $this->request->post['reverb_condition_uuid'] ?? '',
-            'reverb_category_uuid' => $this->request->post['reverb_category_uuid'] ?? '',
+            'condition_uuid'       => $this->request->post['reverb_condition_uuid']       ?? '',
+            'reverb_category_uuid' => $this->request->post['reverb_category_uuid']        ?? '',
             'handmade'             => (int)(bool)($this->request->post['reverb_handmade'] ?? 0),
             'upc_does_not_apply'   => (int)(bool)($this->request->post['reverb_upc_does_not_apply'] ?? 1),
+            'origin_country_code'  => strtoupper(substr($this->request->post['reverb_origin_country_code'] ?? '', 0, 2)),
         ]);
     }
 
@@ -309,6 +310,26 @@ class ControllerExtensionModuleReverb extends Controller {
         $product_id = isset($this->request->get['product_id']) ? (int)$this->request->get['product_id'] : 0;
         $reverb_row = $this->model_extension_module_reverb->getProductMap($product_id);
 
+        // Countries list for the origin dropdown
+        $this->load->model('localisation/country');
+        $countries = $this->model_localisation_country->getCountries();
+
+        // Store default country ISO code
+        $store_country_id  = (int)$this->config->get('config_country_id');
+        $store_country_iso = '';
+        foreach ($countries as $c) {
+            if ((int)$c['country_id'] === $store_country_id) {
+                $store_country_iso = $c['iso_code_2'];
+                break;
+            }
+        }
+
+        // Saved per-product value, falling back to store default
+        $saved_country = $reverb_row ? $reverb_row['origin_country_code'] : '';
+        if ($saved_country === '') {
+            $saved_country = $store_country_iso;
+        }
+
         $data = [
             'product_id'                => $product_id,
             'reverb_sync_enabled'       => $reverb_row ? (int)$reverb_row['sync_enabled']      : 0,
@@ -317,6 +338,8 @@ class ControllerExtensionModuleReverb extends Controller {
             'reverb_listing_id'         => $reverb_row ? $reverb_row['reverb_listing_id']       : '',
             'reverb_handmade'           => $reverb_row ? (int)$reverb_row['handmade']           : 0,
             'reverb_upc_does_not_apply' => $reverb_row ? (int)$reverb_row['upc_does_not_apply'] : 1,
+            'origin_country_code'       => $saved_country,
+            'countries'                 => $countries,
             'reverb_conditions'         => $this->model_extension_module_reverb->getListingConditions(),
             'reverb_categories_grouped' => $this->model_extension_module_reverb->getReverbCategoriesGrouped(),
             'clear_listing_url'         => $this->url->link('extension/module/reverb/clearListingId', 'user_token=' . $this->session->data['user_token'], true),

+ 20 - 15
upload/admin/model/extension/module/reverb.php

@@ -8,14 +8,15 @@ class ModelExtensionModuleReverb extends Model {
     public function install() {
         $this->db->query("
             CREATE TABLE IF NOT EXISTS `" . DB_PREFIX . "reverb_product_map` (
-                `product_id`           INT(11) NOT NULL,
-                `reverb_listing_id`    VARCHAR(64) NOT NULL DEFAULT '',
-                `sync_enabled`         TINYINT(1) NOT NULL DEFAULT 0,
-                `condition_uuid`       VARCHAR(64) NOT NULL DEFAULT '',
-                `reverb_category_uuid` VARCHAR(64) NOT NULL DEFAULT '',
-                `handmade`             TINYINT(1) NOT NULL DEFAULT 0,
-                `upc_does_not_apply`   TINYINT(1) NOT NULL DEFAULT 1,
-                `last_synced_at`       DATETIME NULL DEFAULT NULL,
+                `product_id`            INT(11) NOT NULL,
+                `reverb_listing_id`     VARCHAR(64) NOT NULL DEFAULT '',
+                `sync_enabled`          TINYINT(1) NOT NULL DEFAULT 0,
+                `condition_uuid`        VARCHAR(64) NOT NULL DEFAULT '',
+                `reverb_category_uuid`  VARCHAR(64) NOT NULL DEFAULT '',
+                `handmade`              TINYINT(1) NOT NULL DEFAULT 0,
+                `upc_does_not_apply`    TINYINT(1) NOT NULL DEFAULT 1,
+                `origin_country_code`   VARCHAR(2) NOT NULL DEFAULT '',
+                `last_synced_at`        DATETIME NULL DEFAULT NULL,
                 PRIMARY KEY (`product_id`)
             ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
         ");
@@ -56,8 +57,9 @@ class ModelExtensionModuleReverb extends Model {
         static $done = false;
         if ($done) return;
         $done = true;
-        $this->addColumnIfMissing(DB_PREFIX . 'reverb_product_map', 'handmade',           'TINYINT(1) NOT NULL DEFAULT 0');
-        $this->addColumnIfMissing(DB_PREFIX . 'reverb_product_map', 'upc_does_not_apply', 'TINYINT(1) NOT NULL DEFAULT 1');
+        $this->addColumnIfMissing(DB_PREFIX . 'reverb_product_map', 'handmade',             'TINYINT(1) NOT NULL DEFAULT 0');
+        $this->addColumnIfMissing(DB_PREFIX . 'reverb_product_map', 'upc_does_not_apply',   'TINYINT(1) NOT NULL DEFAULT 1');
+        $this->addColumnIfMissing(DB_PREFIX . 'reverb_product_map', 'origin_country_code',  "VARCHAR(2) NOT NULL DEFAULT ''");
         // Create order map table for upgrades from earlier versions
         $this->db->query("
             CREATE TABLE IF NOT EXISTS `" . DB_PREFIX . "reverb_order_map` (
@@ -106,15 +108,17 @@ class ModelExtensionModuleReverb extends Model {
         $last_synced_at       = isset($data['last_synced_at'])       ? "'" . $this->db->escape($data['last_synced_at']) . "'"    : 'NULL';
         $handmade             = isset($data['handmade'])             ? (int)(bool)$data['handmade']                             : 0;
         $upc_does_not_apply   = isset($data['upc_does_not_apply'])   ? (int)(bool)$data['upc_does_not_apply']                   : 1;
+        $origin_country_code  = isset($data['origin_country_code'])  ? strtoupper(substr($this->db->escape($data['origin_country_code']), 0, 2)) : '';
 
         if ($existing) {
             $this->db->query("
                 UPDATE `" . DB_PREFIX . "reverb_product_map`
                 SET `sync_enabled`         = $sync_enabled,
-                    `condition_uuid`       = '$condition_uuid',
-                    `reverb_category_uuid` = '$reverb_category_uuid',
-                    `handmade`             = $handmade,
-                    `upc_does_not_apply`   = $upc_does_not_apply"
+                    `condition_uuid`        = '$condition_uuid',
+                    `reverb_category_uuid`  = '$reverb_category_uuid',
+                    `handmade`              = $handmade,
+                    `upc_does_not_apply`    = $upc_does_not_apply,
+                    `origin_country_code`   = '$origin_country_code'"
                 . (!empty($reverb_listing_id) ? ", `reverb_listing_id` = '$reverb_listing_id'" : '')
                 . (isset($data['last_synced_at']) ? ", `last_synced_at` = $last_synced_at" : '')
                 . " WHERE `product_id` = '" . (int)$product_id . "'"
@@ -123,7 +127,7 @@ class ModelExtensionModuleReverb extends Model {
             $this->db->query("
                 INSERT INTO `" . DB_PREFIX . "reverb_product_map`
                 (`product_id`, `sync_enabled`, `condition_uuid`, `reverb_category_uuid`,
-                 `reverb_listing_id`, `handmade`, `upc_does_not_apply`, `last_synced_at`)
+                 `reverb_listing_id`, `handmade`, `upc_does_not_apply`, `origin_country_code`, `last_synced_at`)
                 VALUES (
                     '" . (int)$product_id . "',
                     $sync_enabled,
@@ -132,6 +136,7 @@ class ModelExtensionModuleReverb extends Model {
                     '$reverb_listing_id',
                     $handmade,
                     $upc_does_not_apply,
+                    '$origin_country_code',
                     $last_synced_at
                 )
             ");

+ 22 - 1
upload/admin/view/template/extension/module/reverb_product.twig

@@ -55,6 +55,22 @@
       </div>
     </div>
 
+    <div class="form-group">
+      <label class="col-sm-2 control-label">Country of Origin</label>
+      <div class="col-sm-4">
+        <select name="reverb_origin_country_code" id="reverb-country-select" class="form-control">
+          <option value=""></option>
+          {% for country in countries %}
+          <option value="{{ country.iso_code_2 }}"
+            {% if origin_country_code == country.iso_code_2 %}selected="selected"{% endif %}>
+            {{ country.name }}
+          </option>
+          {% endfor %}
+        </select>
+        <p class="help-block">Country where this item was made. Defaults to your store country.</p>
+      </div>
+    </div>
+
     <div class="form-group">
       <label class="col-sm-2 control-label">Is this handmade?</label>
       <div class="col-sm-10">
@@ -108,7 +124,7 @@
     </div>
 
     <script type="text/javascript">
-    // Searchable category dropdown — OC3 admin bundles Select2
+    // Searchable dropdowns — OC3 admin bundles Select2
     (function () {
       if (typeof $.fn.select2 !== 'undefined') {
         $('#reverb-category-select').select2({
@@ -116,6 +132,11 @@
           allowClear: true,
           width: '100%'
         });
+        $('#reverb-country-select').select2({
+          placeholder: '-- Select country --',
+          allowClear: true,
+          width: '100%'
+        });
       }
     }());
 

+ 4 - 0
upload/system/library/reverb/ProductMapper.php

@@ -46,6 +46,10 @@ class ProductMapper {
             $payload['categories'] = [['uuid' => $reverb_data['reverb_category_uuid']]];
         }
 
+        if (!empty($reverb_data['origin_country_code'])) {
+            $payload['origin_country_code'] = strtoupper($reverb_data['origin_country_code']);
+        }
+
         // Shipping rates
         $rates = [];
         if (!empty($settings['shipping_domestic'])) {