| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466 |
- {{ header }}{{ column_left }}
- <div id="content">
- <div class="page-header">
- <div class="container-fluid">
- <div class="pull-right">
- <button type="submit" form="form-reverb" class="btn btn-primary">
- <i class="fa fa-floppy-o"></i> {{ button_save }}
- </button>
- <a href="{{ cancel }}" class="btn btn-default">
- <i class="fa fa-reply"></i> {{ button_cancel }}
- </a>
- </div>
- <h1>{{ heading_title }}</h1>
- <ul class="breadcrumb">
- {% for breadcrumb in breadcrumbs %}
- <li><a href="{{ breadcrumb.href }}">{{ breadcrumb.text }}</a></li>
- {% endfor %}
- </ul>
- </div>
- </div>
- <div class="container-fluid">
- {% if error_warning %}
- <div class="alert alert-danger alert-dismissible">
- <i class="fa fa-exclamation-circle"></i> {{ error_warning }}
- <button type="button" class="close" data-dismiss="alert">×</button>
- </div>
- {% endif %}
- {% if success %}
- <div class="alert alert-success alert-dismissible">
- <i class="fa fa-check-circle"></i> {{ success }}
- <button type="button" class="close" data-dismiss="alert">×</button>
- </div>
- {% endif %}
- <div class="panel panel-default">
- <div class="panel-heading">
- <h3 class="panel-title"><i class="fa fa-cog"></i> {{ heading_title }}</h3>
- </div>
- <div class="panel-body">
- <ul class="nav nav-tabs">
- <li class="active"><a href="#tab-settings" data-toggle="tab">{{ tab_settings }}</a></li>
- <li><a href="#tab-categories" data-toggle="tab">{{ tab_categories }}</a></li>
- <li><a href="#tab-reverb-cats" data-toggle="tab">{{ tab_reverb_cats }}</a></li>
- <li><a href="#tab-log" data-toggle="tab">{{ tab_log }}</a></li>
- </ul>
- <form action="{{ action }}" method="post" enctype="multipart/form-data" id="form-reverb" class="form-horizontal">
- <!-- ================================================================ -->
- <!-- TAB: Settings -->
- <!-- ================================================================ -->
- <div class="tab-content">
- <div class="tab-pane active" id="tab-settings">
- <h4>{{ text_api_settings }}</h4>
- <div class="form-group required">
- <label class="col-sm-2 control-label">{{ entry_api_token }}</label>
- <div class="col-sm-10">
- <input type="text" name="module_reverb_api_token"
- value="{{ module_reverb_api_token }}"
- class="form-control" placeholder="e.g. abc123..." />
- <span class="help-block">{{ help_api_token }}</span>
- </div>
- </div>
- <div class="form-group">
- <label class="col-sm-2 control-label">{{ entry_status }}</label>
- <div class="col-sm-10">
- <select name="module_reverb_status" class="form-control">
- <option value="1" {% if module_reverb_status %}selected{% endif %}>{{ text_enabled }}</option>
- <option value="0" {% if not module_reverb_status %}selected{% endif %}>{{ text_disabled }}</option>
- </select>
- </div>
- </div>
- <div class="form-group">
- <label class="col-sm-2 control-label">{{ entry_sync_direction }}</label>
- <div class="col-sm-10">
- <select name="module_reverb_sync_direction" class="form-control">
- <option value="push" {% if module_reverb_sync_direction == 'push' %}selected{% endif %}>{{ text_sync_push }}</option>
- <option value="both" {% if module_reverb_sync_direction == 'both' %}selected{% endif %}>{{ text_sync_both }}</option>
- </select>
- </div>
- </div>
- <h4>{{ text_shipping_settings }}</h4>
- <div class="form-group">
- <label class="col-sm-2 control-label">{{ entry_shipping_domestic }}</label>
- <div class="col-sm-4">
- <div class="input-group">
- <span class="input-group-addon">$</span>
- <input type="text" name="module_reverb_shipping_domestic"
- value="{{ module_reverb_shipping_domestic }}"
- class="form-control" />
- </div>
- <span class="help-block">{{ help_shipping_domestic }}</span>
- </div>
- </div>
- <div class="form-group">
- <label class="col-sm-2 control-label">{{ entry_shipping_international }}</label>
- <div class="col-sm-4">
- <div class="input-group">
- <span class="input-group-addon">$</span>
- <input type="text" name="module_reverb_shipping_international"
- value="{{ module_reverb_shipping_international }}"
- class="form-control" />
- </div>
- <span class="help-block">{{ help_shipping_international }}</span>
- </div>
- </div>
- <h4>{{ text_sync_settings }}</h4>
- <div class="form-group">
- <label class="col-sm-2 control-label">Categories</label>
- <div class="col-sm-10">
- <select name="module_reverb_sync_categories[]" multiple class="form-control" size="10">
- {% for category in categories %}
- <option value="{{ category.category_id }}"
- {% if category.category_id in module_reverb_sync_categories %}selected{% endif %}>
- {{ category.name|raw }}
- </option>
- {% endfor %}
- </select>
- <span class="help-block">{{ help_sync_categories }}</span>
- </div>
- </div>
- <h4>{{ text_manual_sync }}</h4>
- <div class="form-group">
- <div class="col-sm-offset-2 col-sm-10">
- <button type="button" id="btn-sync-now" class="btn btn-warning">
- <i class="fa fa-refresh"></i> {{ button_sync_now }}
- </button>
- <span id="sync-result" class="help-block" style="display:none;"></span>
- </div>
- </div>
- <h4>{{ text_order_import }}</h4>
- <div class="form-group">
- <label class="col-sm-2 control-label">{{ entry_order_stores }}</label>
- <div class="col-sm-10">
- <div class="well well-sm" style="height:150px;overflow:auto;">
- {% for store in stores %}
- <div class="checkbox">
- <label>
- <input type="checkbox" name="module_reverb_order_stores[]" value="{{ store.store_id }}"
- {% if store.store_id in module_reverb_order_stores %}checked{% endif %}>
- {% if store.store_id == 0 %}<b>(Default)</b>{% else %}{{ store.name }}{% endif %}
- </label>
- </div>
- {% endfor %}
- </div>
- <a href="#" onclick="$(this).closest('.form-group').find(':checkbox').prop('checked',true);return false;">{{ text_select_all }}</a>
- /
- <a href="#" onclick="$(this).closest('.form-group').find(':checkbox').prop('checked',false);return false;">{{ text_unselect_all }}</a>
- <span class="help-block">{{ help_order_stores }}</span>
- </div>
- </div>
- <div class="form-group">
- <label class="col-sm-2 control-label">{{ entry_default_qty }}</label>
- <div class="col-sm-2">
- <input type="number" name="module_reverb_default_qty" min="1"
- value="{{ module_reverb_default_qty }}" class="form-control" />
- <span class="help-block">{{ help_default_qty }}</span>
- </div>
- </div>
- <div class="form-group">
- <div class="col-sm-offset-2 col-sm-10">
- <button type="button" id="btn-import-orders" class="btn btn-info">
- <i class="fa fa-download"></i> {{ button_import_orders }}
- </button>
- <span id="import-result" class="help-block" style="display:none;"></span>
- </div>
- </div>
- </div><!-- #tab-settings -->
- <!-- ================================================================ -->
- <!-- TAB: Category Mapping -->
- <!-- ================================================================ -->
- <div class="tab-pane" id="tab-categories">
- <p class="help-block">{{ text_category_mapping_help }}</p>
- {% if module_reverb_sync_categories is empty %}
- <div class="alert alert-info">{{ text_no_categories }}</div>
- {% else %}
- <table class="table table-bordered table-hover">
- <thead>
- <tr>
- <th>{{ column_oc_category }}</th>
- <th>{{ column_reverb_category }}</th>
- </tr>
- </thead>
- <tbody>
- {% for category in categories %}
- {% if category.category_id in module_reverb_sync_categories %}
- <tr>
- <td>{{ category.name|raw }}</td>
- <td>
- <select name="module_reverb_category_mappings[{{ category.category_id }}]"
- class="form-control">
- <option value="">-- Select Reverb Category --</option>
- {% for group_name, group_cats in reverb_categories_grouped %}
- <optgroup label="{{ group_name }}">
- {% for rc in group_cats %}
- <option value="{{ rc.uuid }}"
- {% if module_reverb_category_mappings[category.category_id] is defined
- and module_reverb_category_mappings[category.category_id] == rc.uuid %}
- selected
- {% endif %}>
- {{ rc.full_name|default(rc.name) }}
- </option>
- {% endfor %}
- </optgroup>
- {% endfor %}
- </select>
- </td>
- </tr>
- {% endif %}
- {% endfor %}
- </tbody>
- </table>
- {% endif %}
- </div><!-- #tab-categories -->
- <!-- ================================================================ -->
- <!-- TAB: Reverb Categories -->
- <!-- ================================================================ -->
- <div class="tab-pane" id="tab-reverb-cats">
- <p class="help-block">{{ text_reverb_cats_help }}</p>
- <div style="margin-bottom:12px;">
- <button type="button" id="btn-refresh-cats" class="btn btn-primary btn-sm">
- <i class="fa fa-refresh"></i> {{ button_refresh_cats }}
- </button>
- <span id="refresh-cats-result" style="margin-left:10px;"></span>
- </div>
- <div style="margin-bottom:10px;">
- <input type="text" id="cat-filter" class="form-control"
- placeholder="{{ text_filter_cats }}" style="max-width:400px;" />
- </div>
- <div style="max-height:500px;overflow-y:auto;">
- <table class="table table-bordered table-hover table-condensed" id="reverb-cats-table">
- <thead>
- <tr>
- <th>{{ column_cat_name }}</th>
- <th style="width:310px;">{{ column_cat_uuid }}</th>
- </tr>
- </thead>
- <tbody>
- {% for cat in reverb_categories_flat %}
- <tr>
- <td>{{ cat.full_name|default(cat.name) }}</td>
- <td><code>{{ cat.uuid }}</code></td>
- </tr>
- {% else %}
- <tr><td colspan="2" class="text-muted text-center">No categories loaded yet. Click Refresh to fetch from Reverb.</td></tr>
- {% endfor %}
- </tbody>
- </table>
- </div>
- </div><!-- #tab-reverb-cats -->
- <!-- ================================================================ -->
- <!-- TAB: Sync Log -->
- <!-- ================================================================ -->
- <div class="tab-pane" id="tab-log">
- <div style="margin-bottom:10px;">
- <button type="button" id="btn-clear-log" class="btn btn-danger btn-sm">
- <i class="fa fa-trash-o"></i> {{ button_clear_log }}
- </button>
- <span id="clear-log-result" style="margin-left:10px;"></span>
- </div>
- {% if sync_log is empty %}
- <p>{{ text_no_log }}</p>
- {% else %}
- <table class="table table-bordered table-hover table-striped">
- <thead>
- <tr>
- <th>{{ column_date }}</th>
- <th>{{ column_product }}</th>
- <th>{{ column_direction }}</th>
- <th>{{ column_status }}</th>
- <th>{{ column_message }}</th>
- </tr>
- </thead>
- <tbody>
- {% for entry in sync_log %}
- <tr class="{{ entry.status == 'error' ? 'danger' : '' }}">
- <td>{{ entry.created_at }}</td>
- <td>{{ entry.product_name ?? entry.product_id }}</td>
- <td>{{ entry.direction == 'push' ? text_push : text_pull }}</td>
- <td>
- <span class="label label-{{ entry.status == 'success' ? 'success' : 'danger' }}">
- {{ entry.status == 'success' ? text_log_success : text_error }}
- </span>
- </td>
- <td>{{ entry.message }}</td>
- </tr>
- {% endfor %}
- </tbody>
- </table>
- {% endif %}
- </div><!-- #tab-log -->
- </div><!-- .tab-content -->
- </form>
- </div><!-- .panel-body -->
- </div><!-- .panel -->
- </div><!-- .container-fluid -->
- </div><!-- #content -->
- <script>
- $(function() {
- $('#btn-sync-now').on('click', function() {
- var $btn = $(this);
- var $result = $('#sync-result');
- $btn.prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i> Syncing...');
- $result.hide();
- var _p = new URLSearchParams(window.location.search);
- var _syncUrl = 'index.php?route=extension/module/reverb/sync&user_token=' + encodeURIComponent(_p.get('user_token') || '');
- $.ajax({
- url: _syncUrl,
- type: 'GET',
- dataType: 'json',
- success: function(data) {
- if (data.success) {
- $result.removeClass('text-danger').addClass('text-success').text(data.message).show();
- } else {
- $result.removeClass('text-success').addClass('text-danger').text(data.error).show();
- }
- },
- error: function() {
- $result.removeClass('text-success').addClass('text-danger').text('Sync request failed.').show();
- },
- complete: function() {
- $btn.prop('disabled', false).html('<i class="fa fa-refresh"></i> {{ button_sync_now }}');
- }
- });
- });
- $('#btn-import-orders').on('click', function() {
- var $btn = $(this);
- var $result = $('#import-result');
- $btn.prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i> Importing...');
- $result.hide();
- var _p = new URLSearchParams(window.location.search);
- var _importUrl = 'index.php?route=extension/module/reverb/importOrders&user_token=' + encodeURIComponent(_p.get('user_token') || '');
- $.ajax({
- url: _importUrl,
- type: 'GET',
- dataType: 'json',
- success: function(data) {
- if (data.success) {
- $result.removeClass('text-danger').addClass('text-success').text(data.message).show();
- } else {
- $result.removeClass('text-success').addClass('text-danger').text(data.error).show();
- }
- },
- error: function() {
- $result.removeClass('text-success').addClass('text-danger').text('Import request failed.').show();
- },
- complete: function() {
- $btn.prop('disabled', false).html('<i class="fa fa-download"></i> {{ button_import_orders }}');
- }
- });
- });
- // Reverb Categories tab — refresh button
- $('#btn-refresh-cats').on('click', function() {
- var $btn = $(this);
- var $result = $('#refresh-cats-result');
- var $tbody = $('#reverb-cats-table tbody');
- $btn.prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i> Refreshing…');
- $result.text('');
- var _p = new URLSearchParams(window.location.search);
- var _url = 'index.php?route=extension/module/reverb/refreshCategories&user_token=' + encodeURIComponent(_p.get('user_token') || '');
- $.ajax({
- url: _url, type: 'GET', dataType: 'json',
- success: function(data) {
- if (data.success) {
- $result.removeClass('text-danger').addClass('text-success').text(data.message);
- var rows = '';
- $.each(data.categories, function(i, cat) {
- rows += '<tr><td>' + $('<span>').text(cat.full_name || cat.name).html() + '</td>'
- + '<td><code>' + $('<span>').text(cat.uuid).html() + '</code></td></tr>';
- });
- $tbody.html(rows || '<tr><td colspan="2" class="text-muted text-center">No categories returned.</td></tr>');
- $('#cat-filter').trigger('input');
- } else {
- $result.removeClass('text-success').addClass('text-danger').text(data.error || 'Refresh failed.');
- }
- },
- error: function() {
- $result.removeClass('text-success').addClass('text-danger').text('Request failed.');
- },
- complete: function() {
- $btn.prop('disabled', false).html('<i class="fa fa-refresh"></i> {{ button_refresh_cats }}');
- }
- });
- });
- // Reverb Categories tab — live filter
- $('#cat-filter').on('input', function() {
- var q = $(this).val().toLowerCase();
- $('#reverb-cats-table tbody tr').each(function() {
- $(this).toggle(!q || $(this).text().toLowerCase().indexOf(q) !== -1);
- });
- });
- $('#btn-clear-log').on('click', function() {
- if (!confirm('Clear the entire sync log?')) { return; }
- var $btn = $(this);
- var $result = $('#clear-log-result');
- $btn.prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i>');
- var _p = new URLSearchParams(window.location.search);
- var _clearUrl = 'index.php?route=extension/module/reverb/clearLog&user_token=' + encodeURIComponent(_p.get('user_token') || '');
- $.ajax({
- url: _clearUrl,
- type: 'GET',
- dataType: 'json',
- success: function(data) {
- if (data.success) {
- $result.removeClass('text-danger').addClass('text-success').text(data.message);
- setTimeout(function() { window.location.reload(); }, 800);
- } else {
- $result.removeClass('text-success').addClass('text-danger').text(data.error);
- }
- },
- error: function() {
- $result.removeClass('text-success').addClass('text-danger').text('Request failed.');
- },
- complete: function() {
- $btn.prop('disabled', false).html('<i class="fa fa-trash-o"></i> {{ button_clear_log }}');
- }
- });
- });
- });
- </script>
- {{ footer }}
|