reverb.twig 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. {{ header }}{{ column_left }}
  2. <div id="content">
  3. <div class="page-header">
  4. <div class="container-fluid">
  5. <div class="pull-right">
  6. <button type="submit" form="form-reverb" class="btn btn-primary">
  7. <i class="fa fa-floppy-o"></i> {{ button_save }}
  8. </button>
  9. <a href="{{ cancel }}" class="btn btn-default">
  10. <i class="fa fa-reply"></i> {{ button_cancel }}
  11. </a>
  12. </div>
  13. <h1>{{ heading_title }}</h1>
  14. <ul class="breadcrumb">
  15. {% for breadcrumb in breadcrumbs %}
  16. <li><a href="{{ breadcrumb.href }}">{{ breadcrumb.text }}</a></li>
  17. {% endfor %}
  18. </ul>
  19. </div>
  20. </div>
  21. <div class="container-fluid">
  22. {% if error_warning %}
  23. <div class="alert alert-danger alert-dismissible">
  24. <i class="fa fa-exclamation-circle"></i> {{ error_warning }}
  25. <button type="button" class="close" data-dismiss="alert">&times;</button>
  26. </div>
  27. {% endif %}
  28. {% if success %}
  29. <div class="alert alert-success alert-dismissible">
  30. <i class="fa fa-check-circle"></i> {{ success }}
  31. <button type="button" class="close" data-dismiss="alert">&times;</button>
  32. </div>
  33. {% endif %}
  34. <div class="panel panel-default">
  35. <div class="panel-heading">
  36. <h3 class="panel-title"><i class="fa fa-cog"></i> {{ heading_title }}</h3>
  37. </div>
  38. <div class="panel-body">
  39. <ul class="nav nav-tabs">
  40. <li class="active"><a href="#tab-settings" data-toggle="tab">{{ tab_settings }}</a></li>
  41. <li><a href="#tab-categories" data-toggle="tab">{{ tab_categories }}</a></li>
  42. <li><a href="#tab-log" data-toggle="tab">{{ tab_log }}</a></li>
  43. </ul>
  44. <form action="{{ action }}" method="post" enctype="multipart/form-data" id="form-reverb" class="form-horizontal">
  45. <!-- ================================================================ -->
  46. <!-- TAB: Settings -->
  47. <!-- ================================================================ -->
  48. <div class="tab-content">
  49. <div class="tab-pane active" id="tab-settings">
  50. <h4>{{ text_api_settings }}</h4>
  51. <div class="form-group required">
  52. <label class="col-sm-2 control-label">{{ entry_api_token }}</label>
  53. <div class="col-sm-10">
  54. <input type="text" name="module_reverb_api_token"
  55. value="{{ module_reverb_api_token }}"
  56. class="form-control" placeholder="e.g. abc123..." />
  57. <span class="help-block">{{ help_api_token }}</span>
  58. </div>
  59. </div>
  60. <div class="form-group">
  61. <label class="col-sm-2 control-label">{{ entry_status }}</label>
  62. <div class="col-sm-10">
  63. <select name="module_reverb_status" class="form-control">
  64. <option value="1" {% if module_reverb_status %}selected{% endif %}>{{ text_enabled }}</option>
  65. <option value="0" {% if not module_reverb_status %}selected{% endif %}>{{ text_disabled }}</option>
  66. </select>
  67. </div>
  68. </div>
  69. <div class="form-group">
  70. <label class="col-sm-2 control-label">{{ entry_sync_direction }}</label>
  71. <div class="col-sm-10">
  72. <select name="module_reverb_sync_direction" class="form-control">
  73. <option value="push" {% if module_reverb_sync_direction == 'push' %}selected{% endif %}>{{ text_sync_push }}</option>
  74. <option value="both" {% if module_reverb_sync_direction == 'both' %}selected{% endif %}>{{ text_sync_both }}</option>
  75. </select>
  76. </div>
  77. </div>
  78. <h4>{{ text_shipping_settings }}</h4>
  79. <div class="form-group">
  80. <label class="col-sm-2 control-label">{{ entry_shipping_domestic }}</label>
  81. <div class="col-sm-4">
  82. <div class="input-group">
  83. <span class="input-group-addon">$</span>
  84. <input type="text" name="module_reverb_shipping_domestic"
  85. value="{{ module_reverb_shipping_domestic }}"
  86. class="form-control" />
  87. </div>
  88. <span class="help-block">{{ help_shipping_domestic }}</span>
  89. </div>
  90. </div>
  91. <div class="form-group">
  92. <label class="col-sm-2 control-label">{{ entry_shipping_international }}</label>
  93. <div class="col-sm-4">
  94. <div class="input-group">
  95. <span class="input-group-addon">$</span>
  96. <input type="text" name="module_reverb_shipping_international"
  97. value="{{ module_reverb_shipping_international }}"
  98. class="form-control" />
  99. </div>
  100. <span class="help-block">{{ help_shipping_international }}</span>
  101. </div>
  102. </div>
  103. <h4>{{ text_sync_settings }}</h4>
  104. <div class="form-group">
  105. <label class="col-sm-2 control-label">Categories</label>
  106. <div class="col-sm-10">
  107. <select name="module_reverb_sync_categories[]" multiple class="form-control" size="10">
  108. {% for category in categories %}
  109. <option value="{{ category.category_id }}"
  110. {% if category.category_id in module_reverb_sync_categories %}selected{% endif %}>
  111. {{ category.name|raw }}
  112. </option>
  113. {% endfor %}
  114. </select>
  115. <span class="help-block">{{ help_sync_categories }}</span>
  116. </div>
  117. </div>
  118. <h4>{{ text_manual_sync }}</h4>
  119. <div class="form-group">
  120. <div class="col-sm-offset-2 col-sm-10">
  121. <button type="button" id="btn-sync-now" class="btn btn-warning">
  122. <i class="fa fa-refresh"></i> {{ button_sync_now }}
  123. </button>
  124. <span id="sync-result" class="help-block" style="display:none;"></span>
  125. </div>
  126. </div>
  127. <h4>{{ text_order_import }}</h4>
  128. <div class="form-group">
  129. <label class="col-sm-2 control-label">{{ entry_order_stores }}</label>
  130. <div class="col-sm-10">
  131. <div class="well well-sm" style="height:150px;overflow:auto;">
  132. {% for store in stores %}
  133. <div class="checkbox">
  134. <label>
  135. <input type="checkbox" name="module_reverb_order_stores[]" value="{{ store.store_id }}"
  136. {% if store.store_id in module_reverb_order_stores %}checked{% endif %}>
  137. {% if store.store_id == 0 %}<b>(Default)</b>{% else %}{{ store.name }}{% endif %}
  138. </label>
  139. </div>
  140. {% endfor %}
  141. </div>
  142. <a href="#" onclick="$(this).closest('.form-group').find(':checkbox').prop('checked',true);return false;">{{ text_select_all }}</a>
  143. /
  144. <a href="#" onclick="$(this).closest('.form-group').find(':checkbox').prop('checked',false);return false;">{{ text_unselect_all }}</a>
  145. <span class="help-block">{{ help_order_stores }}</span>
  146. </div>
  147. </div>
  148. <div class="form-group">
  149. <label class="col-sm-2 control-label">{{ entry_default_qty }}</label>
  150. <div class="col-sm-2">
  151. <input type="number" name="module_reverb_default_qty" min="1"
  152. value="{{ module_reverb_default_qty }}" class="form-control" />
  153. <span class="help-block">{{ help_default_qty }}</span>
  154. </div>
  155. </div>
  156. <div class="form-group">
  157. <div class="col-sm-offset-2 col-sm-10">
  158. <button type="button" id="btn-import-orders" class="btn btn-info">
  159. <i class="fa fa-download"></i> {{ button_import_orders }}
  160. </button>
  161. <span id="import-result" class="help-block" style="display:none;"></span>
  162. </div>
  163. </div>
  164. </div><!-- #tab-settings -->
  165. <!-- ================================================================ -->
  166. <!-- TAB: Category Mapping -->
  167. <!-- ================================================================ -->
  168. <div class="tab-pane" id="tab-categories">
  169. <p class="help-block">{{ text_category_mapping_help }}</p>
  170. {% if module_reverb_sync_categories is empty %}
  171. <div class="alert alert-info">{{ text_no_categories }}</div>
  172. {% else %}
  173. <table class="table table-bordered table-hover">
  174. <thead>
  175. <tr>
  176. <th>{{ column_oc_category }}</th>
  177. <th>{{ column_reverb_category }}</th>
  178. </tr>
  179. </thead>
  180. <tbody>
  181. {% for category in categories %}
  182. {% if category.category_id in module_reverb_sync_categories %}
  183. <tr>
  184. <td>{{ category.name|raw }}</td>
  185. <td>
  186. <select name="module_reverb_category_mappings[{{ category.category_id }}]"
  187. class="form-control">
  188. <option value="">-- Select Reverb Category --</option>
  189. {% for group_name, group_cats in reverb_categories_grouped %}
  190. <optgroup label="{{ group_name }}">
  191. {% for rc in group_cats %}
  192. <option value="{{ rc.uuid }}"
  193. {% if module_reverb_category_mappings[category.category_id] is defined
  194. and module_reverb_category_mappings[category.category_id] == rc.uuid %}
  195. selected
  196. {% endif %}>
  197. {{ rc.full_name|default(rc.name) }}
  198. </option>
  199. {% endfor %}
  200. </optgroup>
  201. {% endfor %}
  202. </select>
  203. </td>
  204. </tr>
  205. {% endif %}
  206. {% endfor %}
  207. </tbody>
  208. </table>
  209. {% endif %}
  210. </div><!-- #tab-categories -->
  211. <!-- ================================================================ -->
  212. <!-- TAB: Sync Log -->
  213. <!-- ================================================================ -->
  214. <div class="tab-pane" id="tab-log">
  215. <div style="margin-bottom:10px;">
  216. <button type="button" id="btn-clear-log" class="btn btn-danger btn-sm">
  217. <i class="fa fa-trash-o"></i> {{ button_clear_log }}
  218. </button>
  219. <span id="clear-log-result" style="margin-left:10px;"></span>
  220. </div>
  221. {% if sync_log is empty %}
  222. <p>{{ text_no_log }}</p>
  223. {% else %}
  224. <table class="table table-bordered table-hover table-striped">
  225. <thead>
  226. <tr>
  227. <th>{{ column_date }}</th>
  228. <th>{{ column_product }}</th>
  229. <th>{{ column_direction }}</th>
  230. <th>{{ column_status }}</th>
  231. <th>{{ column_message }}</th>
  232. </tr>
  233. </thead>
  234. <tbody>
  235. {% for entry in sync_log %}
  236. <tr class="{{ entry.status == 'error' ? 'danger' : '' }}">
  237. <td>{{ entry.created_at }}</td>
  238. <td>{{ entry.product_name ?? entry.product_id }}</td>
  239. <td>{{ entry.direction == 'push' ? text_push : text_pull }}</td>
  240. <td>
  241. <span class="label label-{{ entry.status == 'success' ? 'success' : 'danger' }}">
  242. {{ entry.status == 'success' ? text_log_success : text_error }}
  243. </span>
  244. </td>
  245. <td>{{ entry.message }}</td>
  246. </tr>
  247. {% endfor %}
  248. </tbody>
  249. </table>
  250. {% endif %}
  251. </div><!-- #tab-log -->
  252. </div><!-- .tab-content -->
  253. </form>
  254. </div><!-- .panel-body -->
  255. </div><!-- .panel -->
  256. </div><!-- .container-fluid -->
  257. </div><!-- #content -->
  258. <script>
  259. $(function() {
  260. $('#btn-sync-now').on('click', function() {
  261. var $btn = $(this);
  262. var $result = $('#sync-result');
  263. $btn.prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i> Syncing...');
  264. $result.hide();
  265. var _p = new URLSearchParams(window.location.search);
  266. var _syncUrl = 'index.php?route=extension/module/reverb/sync&user_token=' + encodeURIComponent(_p.get('user_token') || '');
  267. $.ajax({
  268. url: _syncUrl,
  269. type: 'GET',
  270. dataType: 'json',
  271. success: function(data) {
  272. if (data.success) {
  273. $result.removeClass('text-danger').addClass('text-success').text(data.message).show();
  274. } else {
  275. $result.removeClass('text-success').addClass('text-danger').text(data.error).show();
  276. }
  277. },
  278. error: function() {
  279. $result.removeClass('text-success').addClass('text-danger').text('Sync request failed.').show();
  280. },
  281. complete: function() {
  282. $btn.prop('disabled', false).html('<i class="fa fa-refresh"></i> {{ button_sync_now }}');
  283. }
  284. });
  285. });
  286. $('#btn-import-orders').on('click', function() {
  287. var $btn = $(this);
  288. var $result = $('#import-result');
  289. $btn.prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i> Importing...');
  290. $result.hide();
  291. var _p = new URLSearchParams(window.location.search);
  292. var _importUrl = 'index.php?route=extension/module/reverb/importOrders&user_token=' + encodeURIComponent(_p.get('user_token') || '');
  293. $.ajax({
  294. url: _importUrl,
  295. type: 'GET',
  296. dataType: 'json',
  297. success: function(data) {
  298. if (data.success) {
  299. $result.removeClass('text-danger').addClass('text-success').text(data.message).show();
  300. } else {
  301. $result.removeClass('text-success').addClass('text-danger').text(data.error).show();
  302. }
  303. },
  304. error: function() {
  305. $result.removeClass('text-success').addClass('text-danger').text('Import request failed.').show();
  306. },
  307. complete: function() {
  308. $btn.prop('disabled', false).html('<i class="fa fa-download"></i> {{ button_import_orders }}');
  309. }
  310. });
  311. });
  312. $('#btn-clear-log').on('click', function() {
  313. if (!confirm('Clear the entire sync log?')) { return; }
  314. var $btn = $(this);
  315. var $result = $('#clear-log-result');
  316. $btn.prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i>');
  317. var _p = new URLSearchParams(window.location.search);
  318. var _clearUrl = 'index.php?route=extension/module/reverb/clearLog&user_token=' + encodeURIComponent(_p.get('user_token') || '');
  319. $.ajax({
  320. url: _clearUrl,
  321. type: 'GET',
  322. dataType: 'json',
  323. success: function(data) {
  324. if (data.success) {
  325. $result.removeClass('text-danger').addClass('text-success').text(data.message);
  326. setTimeout(function() { window.location.reload(); }, 800);
  327. } else {
  328. $result.removeClass('text-success').addClass('text-danger').text(data.error);
  329. }
  330. },
  331. error: function() {
  332. $result.removeClass('text-success').addClass('text-danger').text('Request failed.');
  333. },
  334. complete: function() {
  335. $btn.prop('disabled', false).html('<i class="fa fa-trash-o"></i> {{ button_clear_log }}');
  336. }
  337. });
  338. });
  339. });
  340. </script>
  341. {{ footer }}