When wbc_category_filter is set, sync now pages through BC's /items endpoint filtered server-side by itemCategoryCode (or-chained eq - BC's classic OData rejects the `in` operator) and matches each returned item to a WooCommerce product locally via wc_get_product_id_by_sku(), instead of querying BC once per WooCommerce product only to discard most of them. Confirmed against live data that BC's `in` filter isn't supported here but chained `eq ... or ...` is. Also reorders find_bc_item_by_sku() to try GTIN/number before Item Reference (ReferenciasArticulo). Empirically, on this catalog Reference_No is always identical to Item_No, so the reference lookup never matched anything the GTIN/number checks didn't already find - it was costing an extra BC round trip on every single product for no benefit. Kept as a last-resort fallback both directions (SKU->item and item->SKU) in case that doesn't hold for some future item. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
315 lines
11 KiB
JavaScript
315 lines
11 KiB
JavaScript
/**
|
|
* WooCommerce Business Central - Admin JavaScript
|
|
*/
|
|
|
|
(function($) {
|
|
'use strict';
|
|
|
|
var WBC_Admin = {
|
|
/**
|
|
* Initialize
|
|
*/
|
|
init: function() {
|
|
this.bindEvents();
|
|
this.checkInitialSyncStatus();
|
|
},
|
|
|
|
/**
|
|
* If a background sync is already running (e.g. triggered by cron,
|
|
* or the admin reloaded the page mid-sync), resume polling for it.
|
|
*/
|
|
checkInitialSyncStatus: function() {
|
|
var $btn = $('#wbc-manual-sync');
|
|
var $status = $('#wbc-sync-status');
|
|
|
|
if (!$btn.length) {
|
|
return;
|
|
}
|
|
|
|
$.ajax({
|
|
url: wbc_admin.ajax_url,
|
|
type: 'POST',
|
|
data: {
|
|
action: 'wbc_sync_status',
|
|
nonce: wbc_admin.nonce
|
|
},
|
|
success: function(response) {
|
|
if (response.success && response.data.status === 'running') {
|
|
$btn.prop('disabled', true);
|
|
$status.removeClass('success error').addClass('loading');
|
|
WBC_Admin.pollSyncStatus($btn, $status);
|
|
}
|
|
}
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Bind event handlers
|
|
*/
|
|
bindEvents: function() {
|
|
// Test connection
|
|
$('#wbc-test-connection').on('click', this.testConnection);
|
|
|
|
// Manual sync
|
|
$('#wbc-manual-sync').on('click', this.manualSync);
|
|
|
|
// Clear logs
|
|
$('#wbc-clear-logs').on('click', this.clearLogs);
|
|
|
|
// Load companies
|
|
$('#wbc-load-companies').on('click', this.loadCompanies);
|
|
|
|
// Select company
|
|
$('#wbc-company-select').on('change', this.selectCompany);
|
|
|
|
// Toggle log data
|
|
$(document).on('click', '.wbc-toggle-data', this.toggleLogData);
|
|
},
|
|
|
|
/**
|
|
* Test connection to Business Central
|
|
*/
|
|
testConnection: function(e) {
|
|
e.preventDefault();
|
|
|
|
var $btn = $(this);
|
|
var $status = $('#wbc-connection-status');
|
|
|
|
$btn.prop('disabled', true);
|
|
$status.removeClass('success error').addClass('loading').text(wbc_admin.strings.testing);
|
|
|
|
$.ajax({
|
|
url: wbc_admin.ajax_url,
|
|
type: 'POST',
|
|
data: {
|
|
action: 'wbc_test_connection',
|
|
nonce: wbc_admin.nonce
|
|
},
|
|
success: function(response) {
|
|
$btn.prop('disabled', false);
|
|
$status.removeClass('loading');
|
|
|
|
if (response.success) {
|
|
$status.addClass('success').text(response.data.message);
|
|
} else {
|
|
$status.addClass('error').text(response.data.message || 'Connection failed');
|
|
}
|
|
},
|
|
error: function(xhr, status, error) {
|
|
$btn.prop('disabled', false);
|
|
$status.removeClass('loading').addClass('error').text('Request failed: ' + error);
|
|
}
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Run manual sync
|
|
*
|
|
* The sync itself runs in the background (Action Scheduler batches),
|
|
* so this just kicks it off and then polls for progress instead of
|
|
* waiting on one long-lived request.
|
|
*/
|
|
manualSync: function(e) {
|
|
e.preventDefault();
|
|
|
|
var $btn = $(this);
|
|
var $status = $('#wbc-sync-status');
|
|
|
|
$btn.prop('disabled', true);
|
|
$status.removeClass('success error').addClass('loading').text(wbc_admin.strings.syncing);
|
|
|
|
$.ajax({
|
|
url: wbc_admin.ajax_url,
|
|
type: 'POST',
|
|
data: {
|
|
action: 'wbc_manual_sync',
|
|
nonce: wbc_admin.nonce
|
|
},
|
|
success: function(response) {
|
|
if (response.success) {
|
|
WBC_Admin.pollSyncStatus($btn, $status);
|
|
} else {
|
|
$btn.prop('disabled', false);
|
|
$status.removeClass('loading').addClass('error').text((response.data && response.data.message) || 'Sync failed');
|
|
}
|
|
},
|
|
error: function(xhr, status, error) {
|
|
$btn.prop('disabled', false);
|
|
$status.removeClass('loading').addClass('error').text('Request failed: ' + error);
|
|
}
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Poll background sync progress until it completes
|
|
*/
|
|
pollSyncStatus: function($btn, $status) {
|
|
$.ajax({
|
|
url: wbc_admin.ajax_url,
|
|
type: 'POST',
|
|
data: {
|
|
action: 'wbc_sync_status',
|
|
nonce: wbc_admin.nonce
|
|
},
|
|
success: function(response) {
|
|
if (!response.success) {
|
|
$btn.prop('disabled', false);
|
|
$status.removeClass('loading').addClass('error').text((response.data && response.data.message) || 'Failed to get sync status');
|
|
return;
|
|
}
|
|
|
|
var run = response.data;
|
|
|
|
if (run.status === 'running') {
|
|
var progressText = (run.mode === 'category')
|
|
? (run.pages_done || 0) + ' page(s), ' + (run.total || 0) + ' item(s) checked'
|
|
: (run.batches_done || 0) + ' / ' + (run.total_batches || 0) + ' batches';
|
|
$status.text('Syncing... ' + progressText + ' (success: ' + (run.success || 0) + ', failed: ' + (run.failed || 0) + ', skipped: ' + (run.skipped || 0) + ')');
|
|
setTimeout(function() {
|
|
WBC_Admin.pollSyncStatus($btn, $status);
|
|
}, 3000);
|
|
} else if (run.status === 'completed') {
|
|
$btn.prop('disabled', false);
|
|
$status.removeClass('loading').addClass('success').text('Sync completed. Success: ' + (run.success || 0) + ', Failed: ' + (run.failed || 0) + ', Skipped: ' + (run.skipped || 0));
|
|
} else {
|
|
$btn.prop('disabled', false);
|
|
$status.removeClass('loading');
|
|
}
|
|
},
|
|
error: function(xhr, status, error) {
|
|
$btn.prop('disabled', false);
|
|
$status.removeClass('loading').addClass('error').text('Request failed: ' + error);
|
|
}
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Clear all logs
|
|
*/
|
|
clearLogs: function(e) {
|
|
e.preventDefault();
|
|
|
|
if (!confirm(wbc_admin.strings.confirm_clear)) {
|
|
return;
|
|
}
|
|
|
|
var $btn = $(this);
|
|
var originalText = $btn.text();
|
|
|
|
$btn.prop('disabled', true).text(wbc_admin.strings.clearing);
|
|
|
|
$.ajax({
|
|
url: wbc_admin.ajax_url,
|
|
type: 'POST',
|
|
data: {
|
|
action: 'wbc_clear_logs',
|
|
nonce: wbc_admin.nonce
|
|
},
|
|
success: function(response) {
|
|
if (response.success) {
|
|
// Reload the page to show empty logs
|
|
location.reload();
|
|
} else {
|
|
alert(response.data.message || 'Failed to clear logs');
|
|
$btn.prop('disabled', false).text(originalText);
|
|
}
|
|
},
|
|
error: function(xhr, status, error) {
|
|
alert('Request failed: ' + error);
|
|
$btn.prop('disabled', false).text(originalText);
|
|
}
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Load companies from Business Central
|
|
*/
|
|
loadCompanies: function(e) {
|
|
e.preventDefault();
|
|
|
|
var $btn = $(this);
|
|
var $select = $('#wbc-company-select');
|
|
var $list = $('#wbc-companies-list');
|
|
var originalText = $btn.text();
|
|
|
|
$btn.prop('disabled', true).text(wbc_admin.strings.loading);
|
|
|
|
$.ajax({
|
|
url: wbc_admin.ajax_url,
|
|
type: 'POST',
|
|
data: {
|
|
action: 'wbc_get_companies',
|
|
nonce: wbc_admin.nonce
|
|
},
|
|
success: function(response) {
|
|
$btn.prop('disabled', false).text(originalText);
|
|
|
|
if (response.success && response.data.companies) {
|
|
// Clear existing options except the first one
|
|
$select.find('option:not(:first)').remove();
|
|
|
|
// Add companies
|
|
$.each(response.data.companies, function(i, company) {
|
|
$select.append(
|
|
$('<option>', {
|
|
value: company.id,
|
|
text: company.displayName + ' (' + company.id.substring(0, 8) + '...)'
|
|
})
|
|
);
|
|
});
|
|
|
|
// Show the select
|
|
$list.slideDown();
|
|
|
|
// Pre-select current company if set
|
|
var currentCompany = $('#wbc_company_id').val();
|
|
if (currentCompany) {
|
|
$select.val(currentCompany);
|
|
}
|
|
} else {
|
|
alert(response.data.message || 'Failed to load companies. Make sure credentials are saved and correct.');
|
|
}
|
|
},
|
|
error: function(xhr, status, error) {
|
|
$btn.prop('disabled', false).text(originalText);
|
|
alert('Request failed: ' + error);
|
|
}
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Select company from dropdown
|
|
*/
|
|
selectCompany: function() {
|
|
var companyId = $(this).val();
|
|
if (companyId) {
|
|
$('#wbc_company_id').val(companyId);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Toggle log data visibility
|
|
*/
|
|
toggleLogData: function(e) {
|
|
e.preventDefault();
|
|
|
|
var $btn = $(this);
|
|
var $data = $btn.siblings('.wbc-log-data');
|
|
|
|
$data.slideToggle(200, function() {
|
|
if ($data.is(':visible')) {
|
|
$btn.text($btn.data('hide-text') || 'Hide data');
|
|
} else {
|
|
$btn.text($btn.data('show-text') || 'Show data');
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
// Initialize on document ready
|
|
$(document).ready(function() {
|
|
WBC_Admin.init();
|
|
});
|
|
|
|
})(jQuery);
|