ArcWOC/assets/js/hesabix-v2-admin.js
Babak Alizadeh 11e8f522d3 Release 4.10.0: safe disconnect and change-business cleanup
Add a dedicated disconnect flow that truncates mappings/queue, clears
business-scoped IDs (shipping/fee/warehouse/bank), bridge token, sync
meta, and best-effort Hesabix Woo bridge settings. Change-business and
setup-complete now require this cleanup so reconnecting to a new
business cannot reuse stale links. Also expose delete-data-on-uninstall
in settings.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 16:03:06 +00:00

596 lines
17 KiB
JavaScript
Executable file
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Admin JavaScript for Hesabix V2
*
* @since 2.0.0
* @package Hesabix_V2
*/
(function($) {
'use strict';
/**
* Main Hesabix V2 Admin object
*/
var HesabixV2Admin = {
summaryRequest: null,
/**
* Initialize
*/
init: function() {
this.bindEvents();
this.bindChangeBusinessWarning();
this.bindDisconnect();
this.initTooltips();
this.bootstrapConnectionPanels();
},
/**
* Bind events
*/
bindEvents: function() {
// Test connection
$(document).on('click', '.hesabix-v2-test-connection', this.testConnection);
$(document).on('click', '#hesabix-v2-bridge-generate-token', this.bridgeGenerateToken);
$(document).on('click', '#hesabix-v2-mp-refresh-license', this.refreshMarketplaceLicense);
$(document).on('click', '#hesabix-v2-mp-dismiss-banner', this.dismissMarketplaceBanner);
},
refreshMarketplaceLicense: function(e) {
e.preventDefault();
if (typeof hesabix_v2_ajax === 'undefined') {
return;
}
var st = hesabix_v2_ajax.strings || {};
var $btn = $(this);
if (!$btn.data('orig-label')) {
$btn.data('orig-label', $btn.text());
}
$btn.prop('disabled', true).text(st.mp_checking || '…');
$.post(hesabix_v2_ajax.ajax_url, {
action: 'hesabix_v2_marketplace_license_refresh',
nonce: hesabix_v2_ajax.nonce
})
.done(function(res) {
if (res && res.success && res.data && res.data.active) {
window.alert(st.mp_active || '');
window.location.reload();
return;
}
var msg = (res && res.data && res.data.status && res.data.status.error)
? res.data.status.error
: (st.mp_inactive || '');
window.alert(msg);
$btn.prop('disabled', false).text($btn.data('orig-label'));
})
.fail(function() {
window.alert(st.error || '');
$btn.prop('disabled', false).text($btn.data('orig-label'));
});
},
dismissMarketplaceBanner: function(e) {
e.preventDefault();
if (typeof hesabix_v2_ajax === 'undefined') {
return;
}
var st = hesabix_v2_ajax.strings || {};
$.post(hesabix_v2_ajax.ajax_url, {
action: 'hesabix_v2_marketplace_banner_dismiss',
nonce: hesabix_v2_ajax.nonce
})
.done(function(res) {
if (res && res.success) {
$('.hesabix-v2-mp-banner').slideUp(200, function() {
$(this).remove();
});
} else {
window.alert(st.error || '');
}
})
.fail(function() {
window.alert(st.error || '');
});
},
bootstrapConnectionPanels: function() {
var $settings = $('#hesabix-v2-settings-connection-live');
var $dash = $('#hesabix-v2-dashboard-connection-extra');
function fill($container) {
if (!$container || !$container.length) {
return;
}
var st = hesabix_v2_ajax.strings || {};
$container.attr('aria-busy', 'true');
HesabixV2Admin.requestConnectionSummary(function(response) {
$container.removeAttr('aria-busy');
if (response.success) {
$container.html(HesabixV2Admin.buildSnapshotMarkup(response));
} else {
$container.html(
'<p class="hesabix-v2-muted">' + HesabixV2Admin.escapeHtml(st.connection_detail_failed) + '</p>' +
'<p class="description">' + HesabixV2Admin.escapeHtml(response.message || '') + '</p>'
);
}
});
}
fill($settings);
fill($dash);
},
requestConnectionSummary: function(doneCb) {
if (typeof hesabix_v2_ajax === 'undefined') {
return;
}
if (this.summaryRequest && this.summaryRequest.abort) {
try {
this.summaryRequest.abort();
} catch (e) { /* noop */ }
}
this.summaryRequest = $.ajax({
url: hesabix_v2_ajax.ajax_url,
type: 'POST',
data: {
action: 'hesabix_v2_connection_summary',
nonce: hesabix_v2_ajax.nonce
},
success: function(response) {
if (typeof doneCb === 'function') {
doneCb(response || {});
}
},
error: function() {
if (typeof doneCb === 'function') {
var st = (hesabix_v2_ajax && hesabix_v2_ajax.strings) ? hesabix_v2_ajax.strings : {};
doneCb({
success: false,
message: st.connection_detail_failed || ''
});
}
}
});
},
escapeHtml: function(value) {
if (value == null || value === '') {
return '';
}
return $('<span/>').text(String(value)).html();
},
buildSnapshotMarkup: function(payload) {
var st = (hesabix_v2_ajax && hesabix_v2_ajax.strings) ? hesabix_v2_ajax.strings : {};
if (!payload || !payload.connection) {
return '<p class="hesabix-v2-muted">' + this.escapeHtml(st.connection_detail_failed) + '</p>';
}
var conn = payload.connection || {};
var rows = [];
function row(label, value) {
if (value == null || value === '') {
return '';
}
return '<tr><th scope="row">' + HesabixV2Admin.escapeHtml(label) +
'</th><td>' + HesabixV2Admin.escapeHtml(value) + '</td></tr>';
}
var bid = parseInt(conn.stored_business_id, 10);
if (!bid) {
return '<p class="hesabix-v2-muted">' +
HesabixV2Admin.escapeHtml(st.connection_detail_failed) + '</p>';
}
rows.push(row(st.lbl_business_id, String(bid)));
var b = conn.business;
if (b && b.name) {
rows.push(row(st.lbl_linked_business, b.name));
}
if (b && b.business_type) {
rows.push(row(st.lbl_type, b.business_type));
}
if (b && b.business_field) {
rows.push(row(st.lbl_field, b.business_field));
}
if (b && (b.role || typeof b.is_owner !== 'undefined')) {
var rolePart = '';
if (b.role) {
rolePart += String(b.role);
}
if (b.is_owner && st.lbl_owner_suffix) {
rolePart += (rolePart ? ' — ' : '') + String(st.lbl_owner_suffix);
}
if (rolePart.trim()) {
rows.push(row(st.lbl_your_role, rolePart.trim()));
}
}
if (conn.owner_display) {
rows.push(row(st.lbl_owner, conn.owner_display));
}
var fy = conn.fiscal_year;
if (fy && fy.title) {
var fyLineParts = [];
fyLineParts.push(String(fy.title));
if (fy.id) {
fyLineParts.push('#' + String(fy.id));
}
var fyLine = fyLineParts.join(' ');
if (fy.start_date || fy.end_date) {
var start = fy.start_date != null ? String(fy.start_date) : '';
var end = fy.end_date != null ? String(fy.end_date) : '';
fyLine += ' — ' + start + ' ‒ ' + end;
}
rows.push(row(st.lbl_fiscal_current, fyLine.trim()));
}
var user = payload.user || {};
var who = '';
var fn = (user.first_name || '').trim();
var ln = (user.last_name || '').trim();
if (fn || ln) {
who = (fn + ' ' + ln).trim();
}
if (!who && user.email) {
who = user.email;
} else if (!who && user.mobile) {
who = user.mobile;
}
if (who || user.id) {
var uline = who;
if (user.id) {
uline += (uline ? ' — ID ' : '') + String(user.id);
}
rows.push(row(st.lbl_api_key_owner, uline));
}
var notices = '';
if (conn.business_note) {
notices += '<p class="hesabix-v2-muted hesabix-v2-connection-note">' +
this.escapeHtml(conn.business_note) + '</p>';
}
if (conn.fiscal_year_note) {
notices += '<p class="hesabix-v2-muted hesabix-v2-connection-note">' +
this.escapeHtml(conn.fiscal_year_note) + '</p>';
}
var body = notices + '<table class="hesabix-v2-connection-detail-table widefat striped"><tbody>' +
rows.join('') + '</tbody></table>';
return body;
},
bindChangeBusinessWarning: function() {
$(document).on('click', '.hesabix-v2-change-connection-trigger', function(e) {
var dest = $(this).attr('href');
if (!dest) {
return;
}
e.preventDefault();
HesabixV2Admin.openConnectionActionDialog({
mode: 'change',
destUrl: dest
});
});
},
bindDisconnect: function() {
$(document).on('click', '.hesabix-v2-disconnect-trigger', function(e) {
e.preventDefault();
HesabixV2Admin.openConnectionActionDialog({
mode: 'disconnect'
});
});
},
/**
* @param {{mode:string, destUrl?:string}} opts
*/
openConnectionActionDialog: function(opts) {
var st = (hesabix_v2_ajax && hesabix_v2_ajax.strings) ? hesabix_v2_ajax.strings : {};
var mode = opts && opts.mode === 'change' ? 'change' : 'disconnect';
var title = mode === 'change' ? (st.warn_change_business_title || '') : (st.warn_disconnect_title || '');
var body = mode === 'change' ? (st.warn_change_business_body || '') : (st.warn_disconnect_body || '');
var okLabel = mode === 'change' ? (st.warn_change_business_ok || '') : (st.warn_disconnect_ok || '');
var cancelLabel = mode === 'change' ? (st.warn_change_business_cancel || '') : (st.warn_disconnect_cancel || '');
var html = ''
+ '<div class="hesabix-v2-warn-overlay" role="presentation">'
+ '<div class="hesabix-v2-warn-dialog" role="dialog" aria-labelledby="hesabix-v2-warn-title">'
+ '<div class="hesabix-v2-warn-dialog__header"><h3 id="hesabix-v2-warn-title">'
+ this.escapeHtml(title)
+ '</h3></div>'
+ '<div class="hesabix-v2-warn-dialog__body"><p>'
+ this.escapeHtml(body)
+ '</p>'
+ '<p class="hesabix-v2-warn-status hesabix-v2-muted" hidden></p>'
+ '</div>'
+ '<div class="hesabix-v2-warn-dialog__footer">'
+ '<button type="button" class="button button-primary hesabix-v2-warn-ok">' + this.escapeHtml(okLabel) + '</button> '
+ '<button type="button" class="button hesabix-v2-warn-cancel">' + this.escapeHtml(cancelLabel) + '</button>'
+ '</div></div></div>';
var $ovl = $(html);
$('body').append($ovl);
var busy = false;
function teardown() {
if (busy) {
return;
}
$ovl.remove();
$(document).off('keydown.hesabixv2warn');
}
function setBusy(on) {
busy = !!on;
$ovl.find('.hesabix-v2-warn-ok, .hesabix-v2-warn-cancel').prop('disabled', busy);
var $status = $ovl.find('.hesabix-v2-warn-status');
if (busy) {
$status.text(st.disconnecting || '…').prop('hidden', false);
} else {
$status.prop('hidden', true).text('');
}
}
function runDisconnect() {
if (typeof hesabix_v2_ajax === 'undefined') {
return;
}
setBusy(true);
$.post(hesabix_v2_ajax.ajax_url, {
action: 'hesabix_v2_disconnect',
nonce: hesabix_v2_ajax.nonce,
redirect_to_setup: mode === 'change' ? 1 : 0
})
.done(function(resp) {
if (resp && resp.success && resp.redirect) {
window.location.href = resp.redirect;
return;
}
setBusy(false);
var msg = (resp && resp.message) ? resp.message : (st.disconnect_failed || '');
$ovl.find('.hesabix-v2-warn-status').text(msg).prop('hidden', false);
})
.fail(function() {
setBusy(false);
$ovl.find('.hesabix-v2-warn-status').text(st.disconnect_failed || '').prop('hidden', false);
});
}
$ovl.on('click', function(ev) {
if (ev.target === $ovl[0]) {
teardown();
}
});
$ovl.find('.hesabix-v2-warn-cancel').on('click', function() {
teardown();
});
$ovl.find('.hesabix-v2-warn-ok').on('click', function() {
runDisconnect();
});
$(document).on('keydown.hesabixv2warn', function(ev) {
if (ev.keyCode === 27) {
ev.preventDefault();
teardown();
}
});
setTimeout(function() {
$ovl.find('.hesabix-v2-warn-cancel').trigger('focus');
}, 30);
},
openChangeBusinessDialog: function(destUrl) {
this.openConnectionActionDialog({
mode: 'change',
destUrl: destUrl
});
},
bridgeGenerateToken: function(e) {
if (e) {
e.preventDefault();
}
if (typeof hesabix_v2_ajax === 'undefined') {
return;
}
var $btn = $('#hesabix-v2-bridge-generate-token');
var $out = $('#hesabix-v2-bridge-token-inline');
$btn.prop('disabled', true);
$out.text('…');
$.ajax({
url: hesabix_v2_ajax.ajax_url,
type: 'POST',
data: {
action: 'hesabix_v2_bridge_generate_token',
nonce: hesabix_v2_ajax.nonce
},
success: function(response) {
var token = (response && response.data && response.data.token) ? response.data.token : '';
if (response && response.success && token) {
$out.html('<strong style="color:#1d2327;">' + HesabixV2Admin.escapeHtml(token) + '</strong>');
} else {
var m = (response && response.data && response.data.message) ? response.data.message : '';
if (!m && response && response.message) {
m = response.message;
}
$out.text(m || 'Error');
}
},
error: function() {
$out.text('Request failed');
},
complete: function() {
$btn.prop('disabled', false);
}
});
},
/**
* Test API connection
*/
testConnection: function(e) {
if (e) {
e.preventDefault();
}
var $btn = $(this);
var resultSel = ($btn.attr('data-hesabix-connection-result') || '#connection-result').trim();
var extraSel = ($btn.attr('data-hesabix-connection-extra') || '#hesabix-v2-dashboard-connection-extra').trim();
var $result = $(resultSel);
var extra = $(extraSel);
var originalText = $btn.data('hesabixOriginalLabel');
if (typeof originalText !== 'string' || originalText === '') {
originalText = $btn.text().trim();
$btn.data('hesabixOriginalLabel', originalText);
}
var st = (hesabix_v2_ajax && hesabix_v2_ajax.strings) ? hesabix_v2_ajax.strings : {};
var testingText = st.testing_connection || '';
$btn.prop('disabled', true).text(testingText || originalText || '…');
$result.html('');
if (extra.length && st.loading_connection_detail) {
extra.html('<p class="hesabix-v2-muted">' + HesabixV2Admin.escapeHtml(st.loading_connection_detail) + '</p>');
}
$.ajax({
url: hesabix_v2_ajax.ajax_url,
type: 'POST',
data: {
action: 'hesabix_v2_test_connection',
nonce: hesabix_v2_ajax.nonce
},
success: function(response) {
if (extra.length) {
if (response.success) {
extra.html(HesabixV2Admin.buildSnapshotMarkup(response));
} else if (response.connection) {
extra.empty();
}
}
var noticeCls = response.success ? 'notice-success' : 'notice-error';
var msg = HesabixV2Admin.escapeHtml(response.message || (st.error || ''));
$result.html('<div class="notice ' + noticeCls + '"><p>' + msg + '</p></div>');
},
error: function(xhr, status, error) {
if (extra.length) {
extra.empty();
}
$result.html('<div class="notice notice-error"><p>'
+ HesabixV2Admin.escapeHtml((st.error || '') + ': ' + (error || status))
+ '</p></div>');
},
complete: function() {
$btn.prop('disabled', false).text(originalText);
}
});
},
/**
* Initialize tooltips
*/
initTooltips: function() {
$('.hesabix-tooltip').hover(
function() {
$(this).attr('title', '');
},
function() {
}
);
},
showLoading: function($element) {
$element.html('<div class="hesabix-v2-loading">در حال بارگذاری</div>');
},
showSuccess: function($element, message) {
$element.html('<div class="notice notice-success"><p>' + message + '</p></div>');
},
showError: function($element, message) {
$element.html('<div class="notice notice-error"><p>' + message + '</p></div>');
},
toPersianNumber: function(num) {
var persianDigits = '۰۱۲۳۴۵۶۷۸۹';
return num.toString().replace(/\d/g, function(x) {
return persianDigits[parseInt(x)];
});
}
};
$(document).ready(function() {
HesabixV2Admin.init();
var $tabWrap = $('.hesabix-v2-settings-tabs');
if ($tabWrap.length) {
var $tabs = $tabWrap.find('.nav-tab');
var $panels = $('.hesabix-v2-tab-panel');
function activateTab(id) {
$tabs.removeClass('nav-tab-active').attr('aria-selected', 'false');
$tabs.filter('[data-tab="' + id + '"]').addClass('nav-tab-active').attr('aria-selected', 'true');
$panels.attr('hidden', true);
$panels.filter('[data-tab="' + id + '"]').removeAttr('hidden');
var $saveWrap = $('#hesabix-v2-settings-save-wrap');
if ($saveWrap.length) {
if (id === 'system') {
$saveWrap.attr('hidden', true);
} else {
$saveWrap.removeAttr('hidden');
}
}
if (window.history && window.history.replaceState) {
window.history.replaceState(null, '', '#hesabix-v2-tab-' + id);
}
}
$tabWrap.on('click', '.nav-tab', function(ev) {
ev.preventDefault();
var id = $(this).data('tab');
if (id) {
activateTab(id);
}
});
var m = /^#hesabix-v2-tab-(.+)$/.exec(window.location.hash || '');
if (m && m[1] && $panels.filter('[data-tab="' + m[1] + '"]').length) {
activateTab(m[1]);
}
}
var $finalizeRow = $('.hesabix-v2-proforma-finalize-settings');
if ($finalizeRow.length) {
function hesabixV2ToggleProformaFinalize() {
var proformaSelected = $('input[name="invoice_doc_mode"][value="proforma"]').is(':checked');
$finalizeRow.css('display', proformaSelected ? '' : 'none');
}
$(document).on('change', 'input[name="invoice_doc_mode"]', hesabixV2ToggleProformaFinalize);
hesabixV2ToggleProformaFinalize();
}
var $productSyncPreset = $('#hesabix_v2_product_sync_preset');
if ($productSyncPreset.length) {
function hesabixV2ToggleProductSyncFields() {
var preset = $productSyncPreset.val() || 'accounting';
var $advanced = $('.hesabix-v2-product-sync-advanced-only');
var $fieldRows = $('.hesabix-v2-product-sync-field-rows .hesabix-v2-product-sync-field-row');
$advanced.toggle(preset === 'advanced');
$fieldRows.toggle(preset !== 'import_only');
}
$productSyncPreset.on('change', hesabixV2ToggleProductSyncFields);
hesabixV2ToggleProductSyncFields();
}
});
window.HesabixV2Admin = HesabixV2Admin;
})(jQuery);