bug fixes
This commit is contained in:
parent
0fd5399b7f
commit
7969b96d87
|
|
@ -1650,6 +1650,294 @@ def create_single_employee_from_amas(asan_login_name, employee_data, company, cr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def create_single_employee_from_amas(asan_login_name, emp_data, company, create_designation=0):
|
||||||
|
"""
|
||||||
|
Create/update a SINGLE Employee record from ƏMAS data.
|
||||||
|
This is called from frontend in a loop for progress bar updates.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
asan_login_name: Asan Login name
|
||||||
|
emp_data: Single employee data dict from ƏMAS API
|
||||||
|
company: Company name
|
||||||
|
create_designation: 1/0 to create designation if not found
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
{
|
||||||
|
"success": True/False,
|
||||||
|
"action": "created"/"updated"/"error",
|
||||||
|
"employee_name": "...",
|
||||||
|
"full_name": "...",
|
||||||
|
"message": "..."
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if isinstance(emp_data, str):
|
||||||
|
emp_data = json.loads(emp_data)
|
||||||
|
|
||||||
|
create_designation = int(create_designation)
|
||||||
|
|
||||||
|
if not company:
|
||||||
|
return {"success": False, "message": "Company is required"}
|
||||||
|
|
||||||
|
doc = frappe.get_doc("Asan Login", asan_login_name)
|
||||||
|
organization_name = doc.amas_account_name
|
||||||
|
organization_voen = doc.amas_account_number
|
||||||
|
|
||||||
|
# Status mapping
|
||||||
|
status_map = {
|
||||||
|
"qüvvədədir": "Active",
|
||||||
|
"aktiv": "Active",
|
||||||
|
"active": "Active",
|
||||||
|
"ləğv edilib": "Left",
|
||||||
|
"xitam": "Left",
|
||||||
|
"terminated": "Left",
|
||||||
|
"dayandırılıb": "Suspended",
|
||||||
|
"suspended": "Suspended",
|
||||||
|
}
|
||||||
|
|
||||||
|
doc_oid = emp_data.get("doc_oid")
|
||||||
|
doc_no = emp_data.get("doc_no")
|
||||||
|
doc_type = emp_data.get("doc_type", "docType_47")
|
||||||
|
|
||||||
|
# Fetch detail data for complete employee information
|
||||||
|
detail_data = None
|
||||||
|
full_name = str(emp_data.get("full_name") or "").strip()
|
||||||
|
|
||||||
|
if doc_oid:
|
||||||
|
detail_result = get_employee_detail(asan_login_name, doc_oid, doc_no, doc_type)
|
||||||
|
if detail_result.get('success'):
|
||||||
|
detail_data = detail_result.get('data')
|
||||||
|
|
||||||
|
# Get FIN from detail or list data
|
||||||
|
fin = None
|
||||||
|
if detail_data and 'EmasContractsEnt' in detail_data and isinstance(detail_data.get('EmasContractsEnt'), list) and len(detail_data['EmasContractsEnt']) > 0:
|
||||||
|
fin = detail_data['EmasContractsEnt'][0].get('pin')
|
||||||
|
# Also update full_name from detail data if available
|
||||||
|
if 'iamasBean' in detail_data and detail_data.get('iamasBean'):
|
||||||
|
person = detail_data['iamasBean']
|
||||||
|
name = person.get('name', '')
|
||||||
|
surname = person.get('surname', '')
|
||||||
|
full_name = f"{name} {surname}".strip()
|
||||||
|
|
||||||
|
if not fin:
|
||||||
|
fin = emp_data.get("identification_number")
|
||||||
|
|
||||||
|
if not fin:
|
||||||
|
return {
|
||||||
|
"success": False,
|
||||||
|
"action": "error",
|
||||||
|
"full_name": full_name,
|
||||||
|
"message": f"{full_name}: No identification_number"
|
||||||
|
}
|
||||||
|
|
||||||
|
fin = str(fin).strip()
|
||||||
|
|
||||||
|
# 1. Save/update Amas Employees record
|
||||||
|
amas_existing = None
|
||||||
|
if doc_oid:
|
||||||
|
amas_existing = frappe.db.exists("Amas Employees", {"doc_oid": str(doc_oid)})
|
||||||
|
if not amas_existing:
|
||||||
|
amas_existing = frappe.db.exists(
|
||||||
|
"Amas Employees",
|
||||||
|
{"identification_number": fin, "organization_voen": organization_voen}
|
||||||
|
)
|
||||||
|
|
||||||
|
if amas_existing:
|
||||||
|
amas_doc = frappe.get_doc("Amas Employees", amas_existing)
|
||||||
|
update_employee_from_data(amas_doc, emp_data)
|
||||||
|
if detail_data:
|
||||||
|
update_employee_from_detail_data(amas_doc, detail_data)
|
||||||
|
if not amas_doc.identification_number:
|
||||||
|
amas_doc.identification_number = fin
|
||||||
|
amas_doc.save(ignore_permissions=True)
|
||||||
|
else:
|
||||||
|
amas_doc = frappe.new_doc("Amas Employees")
|
||||||
|
amas_doc.asan_login = asan_login_name
|
||||||
|
amas_doc.organization_name = organization_name
|
||||||
|
amas_doc.organization_voen = organization_voen
|
||||||
|
amas_doc.identification_number = fin
|
||||||
|
update_employee_from_data(amas_doc, emp_data)
|
||||||
|
if detail_data:
|
||||||
|
update_employee_from_detail_data(amas_doc, detail_data)
|
||||||
|
if not amas_doc.identification_number:
|
||||||
|
amas_doc.identification_number = fin
|
||||||
|
amas_doc.insert(ignore_permissions=True)
|
||||||
|
|
||||||
|
# 2. Create/update Employee record
|
||||||
|
existing_employee = frappe.db.exists("Employee", {"passport_number": fin})
|
||||||
|
|
||||||
|
# Split full_name into first/last
|
||||||
|
name_parts = full_name.split() if full_name else []
|
||||||
|
first_name = name_parts[0] if name_parts else "?"
|
||||||
|
last_name = " ".join(name_parts[1:]) if len(name_parts) > 1 else ""
|
||||||
|
|
||||||
|
# Parse dates from detail data if available, otherwise from list data
|
||||||
|
dob = None
|
||||||
|
doj = None
|
||||||
|
contract_end = None
|
||||||
|
|
||||||
|
if detail_data:
|
||||||
|
if 'iamasBean' in detail_data and detail_data.get('iamasBean'):
|
||||||
|
dob = parse_amas_date(detail_data['iamasBean'].get('birthDate'))
|
||||||
|
if 'EmasContractDetailsEnt' in detail_data and isinstance(detail_data.get('EmasContractDetailsEnt'), list) and len(detail_data['EmasContractDetailsEnt']) > 0:
|
||||||
|
details = detail_data['EmasContractDetailsEnt'][0]
|
||||||
|
doj = parse_amas_date(details.get('beginDate'))
|
||||||
|
contract_end = parse_amas_date(details.get('endDate'))
|
||||||
|
else:
|
||||||
|
dob = parse_amas_date(emp_data.get("birthday"))
|
||||||
|
doj = parse_amas_date(emp_data.get("begin_date"))
|
||||||
|
contract_end = parse_amas_date(emp_data.get("end_date"))
|
||||||
|
|
||||||
|
# Map status
|
||||||
|
raw_status = ""
|
||||||
|
if detail_data and 'EmasContractsEnt' in detail_data and isinstance(detail_data.get('EmasContractsEnt'), list) and len(detail_data['EmasContractsEnt']) > 0:
|
||||||
|
raw_status = str(detail_data['EmasContractsEnt'][0].get('contractStatus') or "").strip().lower()
|
||||||
|
else:
|
||||||
|
raw_status = str(emp_data.get("contract_status") or "").strip().lower()
|
||||||
|
status = status_map.get(raw_status, "Active")
|
||||||
|
|
||||||
|
# Parse salary
|
||||||
|
salary = None
|
||||||
|
if detail_data and 'EmasContractDetailsEnt' in detail_data and isinstance(detail_data.get('EmasContractDetailsEnt'), list) and len(detail_data['EmasContractDetailsEnt']) > 0:
|
||||||
|
raw_salary = detail_data['EmasContractDetailsEnt'][0].get('monthlySalary')
|
||||||
|
else:
|
||||||
|
raw_salary = emp_data.get("monthly_salary")
|
||||||
|
|
||||||
|
if raw_salary:
|
||||||
|
try:
|
||||||
|
salary = float(str(raw_salary).replace(",", ".").replace(" ", ""))
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Resolve designation
|
||||||
|
position_text = None
|
||||||
|
if detail_data and 'staffData' in detail_data and detail_data.get('staffData'):
|
||||||
|
position_text = detail_data['staffData'].get('positionText')
|
||||||
|
else:
|
||||||
|
position_text = emp_data.get("work_position_text")
|
||||||
|
|
||||||
|
designation = resolve_designation(position_text, create_designation)
|
||||||
|
|
||||||
|
# Extract additional fields from amas_doc
|
||||||
|
middle_name = amas_doc.father_name if hasattr(amas_doc, 'father_name') else None
|
||||||
|
gender = map_gender(amas_doc.gender if hasattr(amas_doc, 'gender') else None)
|
||||||
|
cell_number = amas_doc.contact_phone if hasattr(amas_doc, 'contact_phone') else None
|
||||||
|
personal_email = amas_doc.contact_email if hasattr(amas_doc, 'contact_email') else None
|
||||||
|
marital_status_mapped = map_marital_status(amas_doc.marital_status if hasattr(amas_doc, 'marital_status') else None)
|
||||||
|
blood_group_mapped = map_blood_group(amas_doc.blood_type if hasattr(amas_doc, 'blood_type') else None)
|
||||||
|
date_of_issue = parse_amas_date(amas_doc.document_issue_date if hasattr(amas_doc, 'document_issue_date') else None)
|
||||||
|
valid_upto = parse_amas_date(amas_doc.document_expiry_date if hasattr(amas_doc, 'document_expiry_date') else None)
|
||||||
|
place_of_issue = amas_doc.document_issued_by if hasattr(amas_doc, 'document_issued_by') else None
|
||||||
|
current_address = build_full_address(
|
||||||
|
amas_doc.personal_address if hasattr(amas_doc, 'personal_address') else None,
|
||||||
|
amas_doc.personal_city if hasattr(amas_doc, 'personal_city') else None,
|
||||||
|
amas_doc.personal_district if hasattr(amas_doc, 'personal_district') else None
|
||||||
|
)
|
||||||
|
|
||||||
|
if existing_employee:
|
||||||
|
emp = frappe.get_doc("Employee", existing_employee)
|
||||||
|
emp.first_name = first_name
|
||||||
|
if middle_name:
|
||||||
|
emp.middle_name = middle_name
|
||||||
|
emp.last_name = last_name
|
||||||
|
emp.employee_name = full_name or first_name
|
||||||
|
emp.gender = gender
|
||||||
|
if dob:
|
||||||
|
emp.date_of_birth = dob
|
||||||
|
if doj:
|
||||||
|
emp.date_of_joining = doj
|
||||||
|
if contract_end:
|
||||||
|
emp.contract_end_date = contract_end
|
||||||
|
if salary is not None:
|
||||||
|
emp.ctc = salary
|
||||||
|
if designation:
|
||||||
|
emp.designation = designation
|
||||||
|
if cell_number:
|
||||||
|
emp.cell_number = cell_number
|
||||||
|
if personal_email:
|
||||||
|
emp.personal_email = personal_email
|
||||||
|
if marital_status_mapped:
|
||||||
|
emp.marital_status = marital_status_mapped
|
||||||
|
if blood_group_mapped:
|
||||||
|
emp.blood_group = blood_group_mapped
|
||||||
|
if date_of_issue:
|
||||||
|
emp.date_of_issue = date_of_issue
|
||||||
|
if valid_upto:
|
||||||
|
emp.valid_upto = valid_upto
|
||||||
|
if place_of_issue:
|
||||||
|
emp.place_of_issue = place_of_issue
|
||||||
|
if current_address:
|
||||||
|
emp.current_address = current_address
|
||||||
|
emp.save(ignore_permissions=True)
|
||||||
|
action = "updated"
|
||||||
|
else:
|
||||||
|
emp = frappe.new_doc("Employee")
|
||||||
|
emp.first_name = first_name
|
||||||
|
if middle_name:
|
||||||
|
emp.middle_name = middle_name
|
||||||
|
emp.last_name = last_name
|
||||||
|
emp.company = company
|
||||||
|
emp.passport_number = fin
|
||||||
|
emp.date_of_birth = dob or "2000-01-01"
|
||||||
|
emp.date_of_joining = doj or frappe.utils.today()
|
||||||
|
emp.gender = gender
|
||||||
|
emp.status = status
|
||||||
|
if contract_end:
|
||||||
|
emp.contract_end_date = contract_end
|
||||||
|
if salary is not None:
|
||||||
|
emp.ctc = salary
|
||||||
|
if designation:
|
||||||
|
emp.designation = designation
|
||||||
|
if cell_number:
|
||||||
|
emp.cell_number = cell_number
|
||||||
|
if personal_email:
|
||||||
|
emp.personal_email = personal_email
|
||||||
|
if marital_status_mapped:
|
||||||
|
emp.marital_status = marital_status_mapped
|
||||||
|
if blood_group_mapped:
|
||||||
|
emp.blood_group = blood_group_mapped
|
||||||
|
if date_of_issue:
|
||||||
|
emp.date_of_issue = date_of_issue
|
||||||
|
if valid_upto:
|
||||||
|
emp.valid_upto = valid_upto
|
||||||
|
if place_of_issue:
|
||||||
|
emp.place_of_issue = place_of_issue
|
||||||
|
if current_address:
|
||||||
|
emp.current_address = current_address
|
||||||
|
emp.insert(ignore_permissions=True)
|
||||||
|
action = "created"
|
||||||
|
|
||||||
|
# Link Amas Employees → Employee
|
||||||
|
amas_doc.employee = emp.name
|
||||||
|
amas_doc.save(ignore_permissions=True)
|
||||||
|
|
||||||
|
frappe.db.commit()
|
||||||
|
|
||||||
|
return {
|
||||||
|
"success": True,
|
||||||
|
"action": action,
|
||||||
|
"employee_name": emp.name,
|
||||||
|
"full_name": full_name,
|
||||||
|
"message": f"{action.capitalize()}: {full_name}"
|
||||||
|
}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
fin_val = emp_data.get("identification_number", "?") if isinstance(emp_data, dict) else "?"
|
||||||
|
name_val = emp_data.get("full_name", "?") if isinstance(emp_data, dict) else "?"
|
||||||
|
error_msg = f"{name_val} ({fin_val}): {str(e)}"
|
||||||
|
frappe.log_error(
|
||||||
|
f"{error_msg}\n{frappe.get_traceback()}",
|
||||||
|
"EMAS Single Employee Create Error"
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
"success": False,
|
||||||
|
"action": "error",
|
||||||
|
"full_name": name_val,
|
||||||
|
"message": error_msg
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def create_employees_from_amas(asan_login_name, employees, company, create_designation=0):
|
def create_employees_from_amas(asan_login_name, employees, company, create_designation=0):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -520,14 +520,6 @@ function show_employee_selection(listview, asan_login_name, organization_name, e
|
||||||
fieldtype: 'Section Break',
|
fieldtype: 'Section Break',
|
||||||
label: __('Settings')
|
label: __('Settings')
|
||||||
},
|
},
|
||||||
{
|
|
||||||
fieldname: 'company',
|
|
||||||
fieldtype: 'Link',
|
|
||||||
label: __('Company'),
|
|
||||||
options: 'Company',
|
|
||||||
reqd: 1,
|
|
||||||
default: default_company
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
fieldname: 'create_designation',
|
fieldname: 'create_designation',
|
||||||
fieldtype: 'Check',
|
fieldtype: 'Check',
|
||||||
|
|
@ -568,7 +560,7 @@ function show_employee_selection(listview, asan_login_name, organization_name, e
|
||||||
}
|
}
|
||||||
|
|
||||||
d.hide();
|
d.hide();
|
||||||
create_employees(listview, asan_login_name, selected_employees, values.company, values.create_designation);
|
create_employees(listview, asan_login_name, selected_employees, default_company, values.create_designation);
|
||||||
},
|
},
|
||||||
secondary_action_label: __('Cancel'),
|
secondary_action_label: __('Cancel'),
|
||||||
secondary_action: function() { d.hide(); }
|
secondary_action: function() { d.hide(); }
|
||||||
|
|
@ -594,56 +586,190 @@ function show_employee_selection(listview, asan_login_name, organization_name, e
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 5: Create employees via backend
|
// Step 5: Create employees via backend - ONE BY ONE like E-Taxes
|
||||||
function create_employees(listview, asan_login_name, selected_employees, company, create_designation) {
|
function create_employees(listview, asan_login_name, selected_employees, company, create_designation) {
|
||||||
// Show progress indicator
|
// Initialize counters
|
||||||
|
window.amas_employees_to_process = selected_employees.length;
|
||||||
|
window.amas_cancel_loading = false;
|
||||||
|
|
||||||
|
// Start processing
|
||||||
|
process_employees_one_by_one(
|
||||||
|
listview,
|
||||||
|
asan_login_name,
|
||||||
|
selected_employees,
|
||||||
|
company,
|
||||||
|
create_designation,
|
||||||
|
0, // created_count
|
||||||
|
0, // updated_count
|
||||||
|
0, // error_count
|
||||||
|
[], // errors
|
||||||
|
0 // current_index
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process employees one by one (like E-Taxes loadSelectedInvoices)
|
||||||
|
function process_employees_one_by_one(listview, asan_login_name, employees_queue, company, create_designation,
|
||||||
|
created_count, updated_count, error_count, errors, current_index) {
|
||||||
|
// Check if finished
|
||||||
|
if (employees_queue.length === 0) {
|
||||||
|
frappe.hide_progress();
|
||||||
|
$(document).off('progress-cancel.loading_amas_employees');
|
||||||
|
|
||||||
|
const total = created_count + updated_count + error_count;
|
||||||
|
show_import_summary(total, created_count, updated_count, error_count, errors);
|
||||||
|
|
||||||
|
window.amas_employees_to_process = null;
|
||||||
|
listview.refresh();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if cancelled
|
||||||
|
if (window.amas_cancel_loading) {
|
||||||
|
employees_queue = [];
|
||||||
|
frappe.hide_progress();
|
||||||
|
$(document).off('progress-cancel.loading_amas_employees');
|
||||||
|
|
||||||
|
const total = created_count + updated_count + error_count;
|
||||||
|
frappe.show_alert({
|
||||||
|
message: __('Import cancelled. Processed ') + total + __(' employees.'),
|
||||||
|
indicator: 'orange'
|
||||||
|
}, 5);
|
||||||
|
|
||||||
|
listview.refresh();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take first employee from queue
|
||||||
|
const emp_data = employees_queue.shift();
|
||||||
|
const is_last = employees_queue.length === 0;
|
||||||
|
const total_to_process = window.amas_employees_to_process || (created_count + updated_count + error_count + employees_queue.length + 1);
|
||||||
|
|
||||||
|
current_index++;
|
||||||
|
|
||||||
|
// Show progress
|
||||||
frappe.show_progress(
|
frappe.show_progress(
|
||||||
__('Loading from ƏMAS'),
|
__('Loading from ƏMAS'),
|
||||||
0,
|
current_index - 1,
|
||||||
selected_employees.length,
|
total_to_process,
|
||||||
__('Fetching employee details...')
|
__('Processing employee ') + current_index + __(' of ') + total_to_process,
|
||||||
|
null,
|
||||||
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Setup cancel handler
|
||||||
|
$(document).off('progress-cancel.loading_amas_employees');
|
||||||
|
$(document).on('progress-cancel.loading_amas_employees', function() {
|
||||||
|
window.amas_cancel_loading = true;
|
||||||
|
frappe.show_alert({
|
||||||
|
message: __('Cancelling import... Finishing current employee.'),
|
||||||
|
indicator: 'orange'
|
||||||
|
}, 3);
|
||||||
|
frappe.hide_progress();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get employee name for progress message
|
||||||
|
const emp_name = emp_data.full_name || emp_data.identification_number || 'Employee';
|
||||||
|
|
||||||
|
// Update progress with employee name
|
||||||
|
frappe.show_progress(
|
||||||
|
__('Loading from ƏMAS'),
|
||||||
|
current_index - 1,
|
||||||
|
total_to_process,
|
||||||
|
__('Processing: ') + emp_name
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create/update single employee
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: 'invoice_az.amas_api.create_employees_from_amas',
|
method: 'invoice_az.amas_api.create_single_employee_from_amas',
|
||||||
args: {
|
args: {
|
||||||
asan_login_name: asan_login_name,
|
asan_login_name: asan_login_name,
|
||||||
employees: selected_employees,
|
emp_data: emp_data,
|
||||||
company: company,
|
company: company,
|
||||||
create_designation: create_designation ? 1 : 0
|
create_designation: create_designation ? 1 : 0
|
||||||
},
|
},
|
||||||
freeze: true,
|
|
||||||
freeze_message: __('Creating employees from ƏMAS...'),
|
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
frappe.hide_progress();
|
if (r.message && r.message.success) {
|
||||||
if (!r.message || !r.message.success) {
|
// Success - increment counters
|
||||||
// Check for CSRF error - need to reconnect
|
if (r.message.action === 'created') {
|
||||||
if (r.message && r.message.csrf_error) {
|
created_count++;
|
||||||
show_amas_reconnect_dialog(asan_login_name, function() {
|
frappe.show_alert({
|
||||||
// Retry after successful reconnection
|
message: __('Created: ') + r.message.full_name,
|
||||||
create_employees(listview, asan_login_name, selected_employees, company, create_designation);
|
indicator: 'green'
|
||||||
});
|
}, 2);
|
||||||
return;
|
} else if (r.message.action === 'updated') {
|
||||||
|
updated_count++;
|
||||||
|
frappe.show_alert({
|
||||||
|
message: __('Updated: ') + r.message.full_name,
|
||||||
|
indicator: 'blue'
|
||||||
|
}, 2);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Error
|
||||||
|
error_count++;
|
||||||
|
const error_msg = r.message ? r.message.message : 'Unknown error';
|
||||||
|
errors.push(error_msg);
|
||||||
|
|
||||||
|
frappe.show_alert({
|
||||||
|
message: __('Error: ') + (r.message ? r.message.full_name : emp_name),
|
||||||
|
indicator: 'red'
|
||||||
|
}, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
frappe.msgprint({
|
// Continue with next employee after short delay (like E-Taxes)
|
||||||
title: __('Error'),
|
setTimeout(function() {
|
||||||
indicator: 'red',
|
process_employees_one_by_one(
|
||||||
message: r.message ? r.message.message : __('Failed to create employees')
|
listview,
|
||||||
|
asan_login_name,
|
||||||
|
employees_queue,
|
||||||
|
company,
|
||||||
|
create_designation,
|
||||||
|
created_count,
|
||||||
|
updated_count,
|
||||||
|
error_count,
|
||||||
|
errors,
|
||||||
|
current_index
|
||||||
|
);
|
||||||
|
}, 50); // 50ms delay like E-Taxes PROGRESS_UPDATE_DELAY
|
||||||
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
// Network error
|
||||||
|
error_count++;
|
||||||
|
const error_msg = emp_name + ': Network error - ' + (error || 'Unknown error');
|
||||||
|
errors.push(error_msg);
|
||||||
|
|
||||||
|
frappe.show_alert({
|
||||||
|
message: __('Network error: ') + emp_name,
|
||||||
|
indicator: 'red'
|
||||||
|
}, 3);
|
||||||
|
|
||||||
|
// Continue with next employee
|
||||||
|
setTimeout(function() {
|
||||||
|
process_employees_one_by_one(
|
||||||
|
listview,
|
||||||
|
asan_login_name,
|
||||||
|
employees_queue,
|
||||||
|
company,
|
||||||
|
create_designation,
|
||||||
|
created_count,
|
||||||
|
updated_count,
|
||||||
|
error_count,
|
||||||
|
errors,
|
||||||
|
current_index
|
||||||
|
);
|
||||||
|
}, 50);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = r.message;
|
// Show final summary (like E-Taxes)
|
||||||
const total = res.created_count + res.updated_count + res.error_count;
|
function show_import_summary(total, created_count, updated_count, error_count, errors) {
|
||||||
|
if (error_count === 0) {
|
||||||
if (res.error_count === 0) {
|
|
||||||
let msg = __('All ') + total + __(' employees were processed successfully.');
|
let msg = __('All ') + total + __(' employees were processed successfully.');
|
||||||
if (res.created_count > 0) {
|
if (created_count > 0) {
|
||||||
msg += '<br>' + __('Created: ') + '<strong>' + res.created_count + '</strong>';
|
msg += '<br>' + __('Created: ') + '<strong>' + created_count + '</strong>';
|
||||||
}
|
}
|
||||||
if (res.updated_count > 0) {
|
if (updated_count > 0) {
|
||||||
msg += '<br>' + __('Updated: ') + '<strong>' + res.updated_count + '</strong>';
|
msg += '<br>' + __('Updated: ') + '<strong>' + updated_count + '</strong>';
|
||||||
}
|
}
|
||||||
|
|
||||||
frappe.msgprint({
|
frappe.msgprint({
|
||||||
|
|
@ -653,34 +779,33 @@ function create_employees(listview, asan_login_name, selected_employees, company
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
let msg = '<div style="margin-bottom: 15px;">';
|
let msg = '<div style="margin-bottom: 15px;">';
|
||||||
if (res.created_count > 0) {
|
if (created_count > 0) {
|
||||||
msg += __('Successfully created: ') + '<strong>' + res.created_count + '</strong><br>';
|
msg += __('Successfully created: ') + '<strong>' + created_count + '</strong><br>';
|
||||||
}
|
}
|
||||||
if (res.updated_count > 0) {
|
if (updated_count > 0) {
|
||||||
msg += __('Updated: ') + '<strong>' + res.updated_count + '</strong><br>';
|
msg += __('Updated: ') + '<strong>' + updated_count + '</strong><br>';
|
||||||
}
|
}
|
||||||
msg += __('Failed: ') + '<strong>' + res.error_count + '</strong>';
|
msg += __('Failed: ') + '<strong>' + error_count + '</strong>';
|
||||||
msg += '</div>';
|
msg += '</div>';
|
||||||
|
|
||||||
if (res.errors && res.errors.length > 0) {
|
if (errors && errors.length > 0) {
|
||||||
msg += '<div style="max-height: 200px; overflow-y: auto;">';
|
msg += '<div style="max-height: 200px; overflow-y: auto;">';
|
||||||
msg += '<ul style="color: red; font-size: 12px; margin: 0; padding-left: 20px;">';
|
msg += '<ul style="color: red; font-size: 12px; margin: 0; padding-left: 20px;">';
|
||||||
res.errors.forEach(function(err) {
|
errors.slice(0, 10).forEach(function(err) {
|
||||||
msg += '<li>' + frappe.utils.escape_html(err) + '</li>';
|
msg += '<li>' + frappe.utils.escape_html(err) + '</li>';
|
||||||
});
|
});
|
||||||
|
if (errors.length > 10) {
|
||||||
|
msg += '<li><em>... and ' + (errors.length - 10) + ' more errors</em></li>';
|
||||||
|
}
|
||||||
msg += '</ul></div>';
|
msg += '</ul></div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
frappe.msgprint({
|
frappe.msgprint({
|
||||||
title: res.created_count > 0 ? __('Import Completed with Errors') : __('Import Failed'),
|
title: created_count > 0 ? __('Import Completed with Errors') : __('Import Failed'),
|
||||||
indicator: res.created_count > 0 ? 'orange' : 'red',
|
indicator: created_count > 0 ? 'orange' : 'red',
|
||||||
message: msg
|
message: msg
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
listview.refresh();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show reconnection dialog for ƏMAS when token expires (CSRF error)
|
// Show reconnection dialog for ƏMAS when token expires (CSRF error)
|
||||||
|
|
|
||||||
|
|
@ -71,21 +71,15 @@ scheduler_events = {
|
||||||
def after_install():
|
def after_install():
|
||||||
"""Run installation tasks"""
|
"""Run installation tasks"""
|
||||||
from invoice_az.auth import setup_token_renewal
|
from invoice_az.auth import setup_token_renewal
|
||||||
from invoice_az.install import after_install as install_custom_fields
|
|
||||||
|
|
||||||
setup_token_renewal()
|
setup_token_renewal()
|
||||||
install_custom_fields()
|
|
||||||
|
|
||||||
|
|
||||||
def after_migrate():
|
def after_migrate():
|
||||||
"""Run migration tasks"""
|
"""Run migration tasks"""
|
||||||
from invoice_az.auth import setup_token_renewal
|
from invoice_az.auth import setup_token_renewal
|
||||||
from invoice_az.install import create_journal_entry_custom_fields, create_supplier_custom_fields, create_employee_amas_fields
|
|
||||||
|
|
||||||
setup_token_renewal()
|
setup_token_renewal()
|
||||||
create_journal_entry_custom_fields()
|
|
||||||
create_supplier_custom_fields()
|
|
||||||
create_employee_amas_fields()
|
|
||||||
|
|
||||||
# Fixtures for master data
|
# Fixtures for master data
|
||||||
# ------------------------
|
# ------------------------
|
||||||
|
|
|
||||||
|
|
@ -1,177 +0,0 @@
|
||||||
"""Installation hooks for Invoice Az app"""
|
|
||||||
|
|
||||||
import frappe
|
|
||||||
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
|
|
||||||
|
|
||||||
|
|
||||||
def after_install():
|
|
||||||
"""Run after app installation"""
|
|
||||||
create_journal_entry_custom_fields()
|
|
||||||
create_supplier_custom_fields()
|
|
||||||
create_employee_amas_fields()
|
|
||||||
|
|
||||||
|
|
||||||
def create_journal_entry_custom_fields():
|
|
||||||
"""Custom fields for Journal Entry are now defined in jey_erp/custom_fields.py"""
|
|
||||||
# Just clear cache - fields are created by jey_erp
|
|
||||||
frappe.clear_cache(doctype='Journal Entry')
|
|
||||||
frappe.logger().info("Journal Entry cache cleared")
|
|
||||||
|
|
||||||
|
|
||||||
def create_supplier_custom_fields():
|
|
||||||
"""Create custom fields for Supplier doctype"""
|
|
||||||
|
|
||||||
custom_fields = {
|
|
||||||
'Supplier': [
|
|
||||||
{
|
|
||||||
'fieldname': 'patronimyc',
|
|
||||||
'label': 'Patronymic (Father\'s Name)',
|
|
||||||
'fieldtype': 'Data',
|
|
||||||
'insert_after': 'first_name_individual',
|
|
||||||
'depends_on': 'eval:doc.supplier_type=="Individual"'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
frappe.logger().info("Creating/updating custom fields for Supplier")
|
|
||||||
create_custom_fields(custom_fields, update=True)
|
|
||||||
|
|
||||||
# Clear cache for Supplier
|
|
||||||
frappe.clear_cache(doctype='Supplier')
|
|
||||||
frappe.logger().info("Custom fields created/updated successfully for Supplier")
|
|
||||||
|
|
||||||
|
|
||||||
def create_employee_amas_fields():
|
|
||||||
"""Create custom fields for Employee doctype to display AMAS data
|
|
||||||
|
|
||||||
This creates only the essential link field and HTML containers.
|
|
||||||
The AMAS data is displayed dynamically via JavaScript from the linked Amas Employees record.
|
|
||||||
This approach avoids MySQL's 65KB row size limit.
|
|
||||||
"""
|
|
||||||
|
|
||||||
custom_fields = {
|
|
||||||
'Employee': [
|
|
||||||
# AMAS Employee Link (essential field)
|
|
||||||
{
|
|
||||||
'fieldname': 'custom_amas_employee',
|
|
||||||
'fieldtype': 'Link',
|
|
||||||
'label': 'AMAS Employee Record',
|
|
||||||
'options': 'Amas Employees',
|
|
||||||
'read_only': 1,
|
|
||||||
'insert_after': 'profile_tab'
|
|
||||||
},
|
|
||||||
|
|
||||||
# Main AMAS Data Tab
|
|
||||||
{
|
|
||||||
'fieldname': 'amas_data_tab',
|
|
||||||
'fieldtype': 'Tab Break',
|
|
||||||
'label': 'AMAS Data',
|
|
||||||
'depends_on': 'eval:doc.custom_amas_employee'
|
|
||||||
},
|
|
||||||
|
|
||||||
# ===== SUB TAB 1: Contract =====
|
|
||||||
{
|
|
||||||
'fieldname': 'amas_contract_tab',
|
|
||||||
'fieldtype': 'Tab Break',
|
|
||||||
'label': 'Contract',
|
|
||||||
'js_parent_subtab': 'AMAS Data'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'fieldname': 'amas_contract_html',
|
|
||||||
'fieldtype': 'HTML',
|
|
||||||
'label': 'Contract Information',
|
|
||||||
'options': '<div id="amas_contract_data">Loading...</div>'
|
|
||||||
},
|
|
||||||
|
|
||||||
# ===== SUB TAB 2: Position & Activity =====
|
|
||||||
{
|
|
||||||
'fieldname': 'amas_position_tab',
|
|
||||||
'fieldtype': 'Tab Break',
|
|
||||||
'label': 'Position & Activity',
|
|
||||||
'js_parent_subtab': 'AMAS Data'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'fieldname': 'amas_position_html',
|
|
||||||
'fieldtype': 'HTML',
|
|
||||||
'label': 'Position Information',
|
|
||||||
'options': '<div id="amas_position_data">Loading...</div>'
|
|
||||||
},
|
|
||||||
|
|
||||||
# ===== SUB TAB 3: Salary & Compensation =====
|
|
||||||
{
|
|
||||||
'fieldname': 'amas_salary_tab',
|
|
||||||
'fieldtype': 'Tab Break',
|
|
||||||
'label': 'Salary & Compensation',
|
|
||||||
'js_parent_subtab': 'AMAS Data'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'fieldname': 'amas_salary_html',
|
|
||||||
'fieldtype': 'HTML',
|
|
||||||
'label': 'Salary Information',
|
|
||||||
'options': '<div id="amas_salary_data">Loading...</div>'
|
|
||||||
},
|
|
||||||
|
|
||||||
# ===== SUB TAB 4: Work Schedule & Vacation =====
|
|
||||||
{
|
|
||||||
'fieldname': 'amas_schedule_tab',
|
|
||||||
'fieldtype': 'Tab Break',
|
|
||||||
'label': 'Work Schedule & Vacation',
|
|
||||||
'js_parent_subtab': 'AMAS Data'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'fieldname': 'amas_schedule_html',
|
|
||||||
'fieldtype': 'HTML',
|
|
||||||
'label': 'Schedule Information',
|
|
||||||
'options': '<div id="amas_schedule_data">Loading...</div>'
|
|
||||||
},
|
|
||||||
|
|
||||||
# ===== SUB TAB 5: Personal & Education =====
|
|
||||||
{
|
|
||||||
'fieldname': 'amas_personal_tab',
|
|
||||||
'fieldtype': 'Tab Break',
|
|
||||||
'label': 'Personal & Education',
|
|
||||||
'js_parent_subtab': 'AMAS Data'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'fieldname': 'amas_personal_html',
|
|
||||||
'fieldtype': 'HTML',
|
|
||||||
'label': 'Personal Information',
|
|
||||||
'options': '<div id="amas_personal_data">Loading...</div>'
|
|
||||||
},
|
|
||||||
|
|
||||||
# ===== SUB TAB 6: Documents & Metadata =====
|
|
||||||
{
|
|
||||||
'fieldname': 'amas_documents_tab',
|
|
||||||
'fieldtype': 'Tab Break',
|
|
||||||
'label': 'Documents & Metadata',
|
|
||||||
'js_parent_subtab': 'AMAS Data'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'fieldname': 'amas_documents_html',
|
|
||||||
'fieldtype': 'HTML',
|
|
||||||
'label': 'Document Information',
|
|
||||||
'options': '<div id="amas_documents_data">Loading...</div>'
|
|
||||||
},
|
|
||||||
|
|
||||||
# ===== SUB TAB 7: AMAS Integration =====
|
|
||||||
{
|
|
||||||
'fieldname': 'amas_integration_tab',
|
|
||||||
'fieldtype': 'Tab Break',
|
|
||||||
'label': 'AMAS Integration',
|
|
||||||
'js_parent_subtab': 'AMAS Data'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'fieldname': 'amas_integration_html',
|
|
||||||
'fieldtype': 'HTML',
|
|
||||||
'label': 'Integration Information',
|
|
||||||
'options': '<div id="amas_integration_data">Loading...</div>'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
frappe.logger().info("Creating/updating custom AMAS fields for Employee")
|
|
||||||
create_custom_fields(custom_fields, update=True)
|
|
||||||
|
|
||||||
# Clear cache for Employee
|
|
||||||
frappe.clear_cache(doctype='Employee')
|
|
||||||
frappe.logger().info("Custom AMAS fields created/updated successfully for Employee")
|
|
||||||
|
|
@ -4,17 +4,6 @@
|
||||||
frappe.ui.form.on('Amas Employees', {
|
frappe.ui.form.on('Amas Employees', {
|
||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
// Form view - show employee details
|
// Form view - show employee details
|
||||||
if (!frm.is_new()) {
|
// Raw data is hidden and can be viewed if needed in customization
|
||||||
// Add button to view raw data if needed
|
|
||||||
if (frm.doc.raw_data) {
|
|
||||||
frm.add_custom_button(__('View Raw Data'), function() {
|
|
||||||
frappe.msgprint({
|
|
||||||
title: __('Raw Data from ƏMAS'),
|
|
||||||
message: `<pre style="max-height: 400px; overflow: auto;">${frm.doc.raw_data}</pre>`,
|
|
||||||
wide: true
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue