fix(amas): priority queue + connecting tick + drop role column

- import_bulk_employees gains a `queue` arg so callers can route the job
  off the contended default queue. The bar that hangs on "Preparing
  import..." for ~a minute post-setup is queue wait: a single `bench
  worker` drains short→default→long, so the import sat behind the
  post-setup backlog. The wizard now enqueues on "short".
- Emit a "connecting" progress tick the instant the worker starts, so the
  bar leaves the "queued" seed and shows it's actually running (vs still
  waiting) before the first detail fetch.
- Org selection: drop the Role column ("Hüquqi şəxs" for every row) — the
  name + VÖEN are enough. The role value is still sent to the API.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ali 2026-06-15 16:00:11 +00:00
parent 15047ffbaa
commit a275f4144e
2 changed files with 21 additions and 5 deletions

View File

@ -2731,10 +2731,15 @@ def on_delete_employee(doc, method):
@frappe.whitelist() @frappe.whitelist()
def import_bulk_employees(asan_login_name, employees_data, company, create_designation=0): def import_bulk_employees(asan_login_name, employees_data, company, create_designation=0, queue="default"):
"""Enqueue bulk employee import as a background job with realtime progress via Socket.IO. """Enqueue bulk employee import as a background job with realtime progress via Socket.IO.
Refuses to enqueue if an import for the same Asan Login is already running. Refuses to enqueue if an import for the same Asan Login is already running.
``queue`` lets callers pick a less-contended RQ queue. The setup wizard passes
"short" so the import isn't stuck behind the pile of post-setup jobs on the
default queue (a single `bench worker` drains queues shortdefaultlong, so
"short" jumps the line and starts as soon as the worker frees).
""" """
if isinstance(employees_data, str): if isinstance(employees_data, str):
employees_data = json.loads(employees_data) employees_data = json.loads(employees_data)
@ -2774,7 +2779,7 @@ def import_bulk_employees(asan_login_name, employees_data, company, create_desig
company=company, company=company,
create_designation=create_designation, create_designation=create_designation,
user=user, user=user,
queue="default", queue=queue or "default",
timeout=1200, timeout=1200,
) )
@ -2948,6 +2953,16 @@ def _process_bulk_employees_import(asan_login_name, employees, company, create_d
updated_count = 0 updated_count = 0
errors = [] errors = []
# First tick the instant the worker picks up the job: flips the bar from the
# "queued" seed to "connecting" so the user can tell the job actually started
# (vs. still waiting in the queue) even before the first detail fetch lands.
_set_import_progress(asan_login_name, 0, total, "connecting", None, 1)
frappe.publish_realtime(
"amas_import_progress",
{"current": 0, "total": total, "phase": "connecting", "percent": 1},
user=user,
)
try: try:
# Refresh the plaintext CSRF token from /core.dashboard once before going # Refresh the plaintext CSRF token from /core.dashboard once before going
# parallel. The DB may have a stale (or previously-corrupted) token; the # parallel. The DB may have a stale (or previously-corrupted) token; the

View File

@ -730,6 +730,8 @@ function attach_amas_import_listeners(listview, asan_login_name, total_hint) {
const phaseLabel = function(phase) { const phaseLabel = function(phase) {
if (phase === 'save') return __('Saving employees'); if (phase === 'save') return __('Saving employees');
if (phase === 'fetch') return __('Fetching details'); if (phase === 'fetch') return __('Fetching details');
if (phase === 'connecting') return __('Connecting to ƏMAS...');
if (phase === 'queued') return __('Waiting to start...');
return __('Preparing import...'); return __('Preparing import...');
}; };
@ -754,7 +756,7 @@ function attach_amas_import_listeners(listview, asan_login_name, total_hint) {
const label = phaseLabel(phase); const label = phaseLabel(phase);
let detail; let detail;
if (phase === 'queued' || !(total > 0)) { if (phase === 'queued' || phase === 'connecting' || !(total > 0)) {
detail = label; detail = label;
} else if (employee_name) { } else if (employee_name) {
detail = label + ': ' + employee_name + ' (' + current + '/' + total + ')'; detail = label + ': ' + employee_name + ' (' + current + '/' + total + ')';
@ -1461,7 +1463,7 @@ function show_amas_accounts_dialog(asan_login_name, accounts, retry_callback) {
// Build accounts table // Build accounts table
let table_html = '<div style="max-height: 400px; overflow-y: auto;">'; let table_html = '<div style="max-height: 400px; overflow-y: auto;">';
table_html += '<table class="table table-bordered table-hover">'; table_html += '<table class="table table-bordered table-hover">';
table_html += '<thead><tr><th style="width: 50%;">Organization Name</th><th style="width: 25%;">VOEN</th><th style="width: 15%;">Role</th><th style="width: 10%;">Action</th></tr></thead>'; table_html += '<thead><tr><th style="width: 60%;">Organization Name</th><th style="width: 30%;">VOEN</th><th style="width: 10%;">Action</th></tr></thead>';
table_html += '<tbody>'; table_html += '<tbody>';
accounts.forEach(function(account, index) { accounts.forEach(function(account, index) {
@ -1473,7 +1475,6 @@ function show_amas_accounts_dialog(asan_login_name, accounts, retry_callback) {
table_html += `<tr> table_html += `<tr>
<td>${frappe.utils.escape_html(name)}</td> <td>${frappe.utils.escape_html(name)}</td>
<td>${frappe.utils.escape_html(voen)}</td> <td>${frappe.utils.escape_html(voen)}</td>
<td>${frappe.utils.escape_html(role)}</td>
<td> <td>
<button class="btn btn-xs btn-primary select-amas-account" <button class="btn btn-xs btn-primary select-amas-account"
data-oid="${frappe.utils.escape_html(oid)}" data-oid="${frappe.utils.escape_html(oid)}"