taxes_az/taxes_az/client/company.js

1747 lines
78 KiB
JavaScript
Raw 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.

/**
* Company DocType Enhancement for E-Taxes Integration
* Adds functionality to fetch company profile data from E-Taxes
*/
frappe.ui.form.on('Company', {
refresh: function(frm) {
// Add E-Taxes profile button
frm.add_custom_button(__('Get E-Taxes Profile'), function() {
ETaxesCompany.checkAuthAndFetchProfile(frm);
}, __('E-Taxes'));
// Add Set Main Activity button
frm.add_custom_button(__('Set Main Activity'), function() {
ETaxesCompany.showMainActivitySelector(frm);
}, __('E-Taxes'));
// Make declaration default fields always editable
ETaxesCompany.enableDeclarationDefaultFields(frm);
// Check gambling activity on refresh
ETaxesCompany.checkGamblingActivity(frm);
},
main_activity: function(frm) {
if (frm.doc.main_activity) {
ETaxesCompany.validateMainActivity(frm);
ETaxesCompany.checkGamblingActivity(frm);
}
},
'mdssüzrə': function(frm) {
ETaxesCompany.saveDeclarationDefaults(frm);
},
'icbaritibbisığortaüzrə': function(frm) {
ETaxesCompany.saveDeclarationDefaults(frm);
},
'işsizlikdənsığortaüzrə': function(frm) {
ETaxesCompany.saveDeclarationDefaults(frm);
},
seller: function(frm) {
ETaxesCompany.handleGamblingFieldChange(frm, 'seller');
},
organizer: function(frm) {
ETaxesCompany.handleGamblingFieldChange(frm, 'organizer');
}
});
// ======= ETAXES COMPANY MODULE =======
window.ETaxesCompany = {
// Хранение ссылки на текущий загрузочный диалог
currentLoadingDialog: null,
// Кэш для справочников
_dictionaryCache: {
taxAuthorities: null,
propertyTypes: null
},
// Gambling activity codes
gamblingActivityCodes: ['92000', '9200003', '9200004', '9200001', '9200002', '9200005'],
/**
* Check and manage gambling activity fields
*/
checkGamblingActivity: function(frm) {
const mainActivity = frm.doc.main_activity;
const isGamblingActivity = ETaxesCompany.gamblingActivityCodes.includes(mainActivity);
if (isGamblingActivity) {
let needsUpdate = false;
if (!frm.doc.seller && !frm.doc.organizer) {
frm.doc.seller = 1;
frm.doc.organizer = 1;
needsUpdate = true;
}
frm.set_df_property('seller', 'read_only', 0);
frm.set_df_property('organizer', 'read_only', 0);
frm.set_df_property('seller', 'hidden', 0);
frm.set_df_property('organizer', 'hidden', 0);
frm.refresh_field('seller');
frm.refresh_field('organizer');
if (needsUpdate) {
frappe.show_alert(__('Gambling activity detected. Seller and Organizer flags enabled.'), 'blue');
}
} else {
frm.set_df_property('seller', 'read_only', 1);
frm.set_df_property('organizer', 'read_only', 1);
let needsUpdate = false;
if (frm.doc.seller || frm.doc.organizer) {
frm.doc.seller = 0;
frm.doc.organizer = 0;
needsUpdate = true;
}
frm.refresh_field('seller');
frm.refresh_field('organizer');
if (needsUpdate) {
frappe.show_alert(__('Non-gambling activity. Seller and Organizer flags disabled.'), 'blue');
}
}
},
/**
* Handle gambling field changes
*/
handleGamblingFieldChange: function(frm, fieldName) {
const mainActivity = frm.doc.main_activity;
const isGamblingActivity = ETaxesCompany.gamblingActivityCodes.includes(mainActivity);
if (!isGamblingActivity) {
frm.doc[fieldName] = 0;
frm.refresh_field(fieldName);
frappe.msgprint(__('Seller and Organizer flags can only be set for gambling activities.'));
return;
}
if (!frm.doc.seller && !frm.doc.organizer) {
frm.doc[fieldName] = 1;
frm.refresh_field(fieldName);
frappe.msgprint(__('At least one of Seller or Organizer must be checked for gambling activities.'));
return;
}
ETaxesCompany.performForcedSave(frm, {
[fieldName]: frm.doc[fieldName] ? 1 : 0
});
},
/**
* Perform forced save for gambling fields
*/
performForcedSave: function(frm, fieldUpdates, callback) {
frappe.call({
method: 'taxes_az.company_etaxes.force_update_gambling_fields',
args: {
company_name: frm.doc.name,
field_updates: fieldUpdates
},
callback: function(r) {
if (r.message && r.message.success) {
frm.doc.__unsaved = 0;
frm.doc.__islocal = 0;
if (callback) callback(true);
} else {
if (callback) callback(false);
}
},
error: function(r) {
if (callback) callback(false);
}
});
},
/**
* Validate main activity exists in system
*/
validateMainActivity: function(frm) {
const activityCode = frm.doc.main_activity;
if (!activityCode) return;
frappe.call({
method: 'frappe.client.get_value',
args: {
doctype: 'Main type of activity',
fieldname: ['name'],
filters: {name: activityCode}
},
callback: function(r) {
if (!r.message) {
frappe.show_alert(__('Activity code not found in system'), 'orange');
}
}
});
},
/**
* Show main activity selector dialog
*/
showMainActivitySelector: function(frm) {
const dialog = new frappe.ui.Dialog({
title: __('Select Main Activity'),
fields: [{
fieldname: 'main_activity',
fieldtype: 'Link',
label: __('Main Activity Code'),
options: 'Main type of activity',
reqd: 1
}],
primary_action_label: __('Update'),
primary_action: function(values) {
if (values.main_activity) {
ETaxesCompany.forceUpdateMainActivity(frm, values.main_activity);
dialog.hide();
}
}
});
if (frm.doc.main_activity) {
dialog.set_value('main_activity', frm.doc.main_activity);
}
dialog.show();
},
/**
* Force update main activity
*/
forceUpdateMainActivity: function(frm, activityCode) {
frappe.call({
method: 'taxes_az.company_etaxes.force_update_single_field',
args: {
company_name: frm.doc.name,
field_name: 'main_activity',
field_value: activityCode
},
callback: function(r) {
if (r.message && r.message.success) {
frm.set_value('main_activity', activityCode);
frm.reload_doc();
} else {
frappe.msgprint(__('Failed to update main activity'));
}
}
});
},
/**
* Make declaration default fields editable regardless of docstatus
*/
enableDeclarationDefaultFields: function(frm) {
['mdssüzrə', 'icbaritibbisığortaüzrə', 'işsizlikdənsığortaüzrə'].forEach(function(fieldname) {
frm.set_df_property(fieldname, 'read_only', 0);
});
frm.refresh_fields(['mdssüzrə', 'icbaritibbisığortaüzrə', 'işsizlikdənsığortaüzrə']);
},
/**
* Auto-save declaration default fields via direct DB update (bypasses submit state)
*/
saveDeclarationDefaults: function(frm) {
frappe.call({
method: 'taxes_az.company_etaxes.force_update_declaration_defaults',
args: {
company_name: frm.doc.name,
mdss: frm.doc['mdssüzrə'] || '',
icbari: frm.doc['icbaritibbisığortaüzrə'] || '',
issizlik: frm.doc['işsizlikdənsığortaüzrə'] || ''
},
callback: function(r) {
if (r.message && r.message.success) {
frm.doc.__unsaved = 0;
if (frm.doc.docstatus === 1) {
frm.page.set_indicator(__('Submitted'), 'blue');
} else {
frm.page.clear_indicator();
}
frappe.show_alert({ message: __('Saved'), indicator: 'green' }, 2);
} else {
frappe.show_alert({ message: __('Save failed'), indicator: 'red' }, 3);
}
}
});
},
/**
* Check authentication and fetch profile with inline re-authentication
*/
checkAuthAndFetchProfile: function(frm) {
// Check if ETaxes common module is available
if (typeof ETaxes !== 'undefined' && ETaxes.auth) {
// Use ETaxes common authentication system
ETaxes.auth.checkAndProcess(function() {
ETaxesCompany.fetchProfile(frm);
});
} else {
// Fallback to simple token validity check
frappe.call({
method: 'taxes_az.auth.check_token_validity',
callback: function(r) {
if (r.message && r.message.valid) {
ETaxesCompany.fetchProfile(frm);
} else {
ETaxesCompany.handleAuthenticationRequired(frm);
}
},
error: function() {
frappe.msgprint(__('Error checking authentication status'));
}
});
}
},
/**
* Handle authentication required with inline process
*/
handleAuthenticationRequired: function(frm) {
frappe.confirm(
__('E-Taxes authentication is required. Would you like to authenticate now?'),
function() {
ETaxesCompany.startInlineAuthentication(frm);
},
function() {
frappe.show_alert({
message: __('Authentication cancelled'),
indicator: 'red'
}, 3);
}
);
},
/**
* Start inline authentication process
*/
startInlineAuthentication: function(frm) {
// Show loading dialog
ETaxesCompany.currentLoadingDialog = new frappe.ui.Dialog({
title: __('E-Taxes Authentication'),
indicator: 'blue',
fields: [
{
fieldname: 'loading_html',
fieldtype: 'HTML',
options: ETaxesCompany._getAuthLoadingHTML(__('Starting Authentication'), __('Getting Asan Login settings...'))
}
],
primary_action_label: __('Cancel'),
primary_action: function() {
ETaxesCompany._hideLoadingDialog();
}
});
ETaxesCompany.currentLoadingDialog.show();
// Get default login settings
frappe.call({
method: 'taxes_az.auth.get_default_asan_login',
callback: function(r) {
if (r.message && r.message.found) {
const asanLoginName = r.message.name;
// Update loading message
ETaxesCompany._updateLoadingDialog(ETaxesCompany.currentLoadingDialog,
__('Sending authentication request...'),
__('This will send a request to your Asan Imza mobile app'));
// Start authentication
frappe.call({
method: 'taxes_az.auth.handle_authentication',
args: { 'asan_login_name': asanLoginName },
callback: function(authR) {
if (authR.message && authR.message.success) {
const bearerToken = authR.message.bearer_token;
// Show verification code if available
if (authR.message.verification_code) {
ETaxesCompany._showVerificationCode(ETaxesCompany.currentLoadingDialog, authR.message.verification_code);
}
ETaxesCompany._updateLoadingDialog(ETaxesCompany.currentLoadingDialog,
__('Waiting for confirmation on your phone'),
__('Please check your phone and confirm the authentication request'));
// Start polling
ETaxesCompany.pollAuthStatus(ETaxesCompany.currentLoadingDialog, asanLoginName, bearerToken, function(success) {
if (success) {
ETaxesCompany.completeAuthentication(ETaxesCompany.currentLoadingDialog, asanLoginName, function() {
ETaxesCompany._hideLoadingDialog();
ETaxesCompany.fetchProfile(frm);
});
} else {
ETaxesCompany._setDialogError(ETaxesCompany.currentLoadingDialog,
__('Authentication Failed'),
__('Could not authenticate with Asan Imza'));
}
});
} else {
ETaxesCompany._setDialogError(ETaxesCompany.currentLoadingDialog,
__('Authentication Error'),
authR.message ? authR.message.message : __('Authentication request failed'));
}
},
error: function() {
ETaxesCompany._setDialogError(ETaxesCompany.currentLoadingDialog,
__('Network Error'),
__('Failed to start authentication process'));
}
});
} else {
ETaxesCompany._setDialogError(ETaxesCompany.currentLoadingDialog,
__('No Asan Login Settings'),
__('Please configure Asan Login settings first'));
}
},
error: function() {
ETaxesCompany._setDialogError(ETaxesCompany.currentLoadingDialog,
__('Error'),
__('Failed to get authentication settings'));
}
});
},
/**
* Poll authentication status
*/
pollAuthStatus: function(dialog, asanLoginName, bearerToken, callback) {
let attempts = 0;
const maxAttempts = 20;
const pollInterval = 6000; // 6 seconds
function pollStep() {
if (attempts >= maxAttempts) {
ETaxesCompany._setDialogError(dialog,
__('Authentication Timeout'),
__('The authentication request has timed out. Please try again.'));
callback(false);
return;
}
attempts++;
ETaxesCompany._updateLoadingDialog(dialog,
__('Waiting for confirmation on your phone'),
__('Please check your phone and confirm the authentication request') +
' (' + attempts + '/' + maxAttempts + ')');
frappe.call({
method: 'taxes_az.auth.poll_auth_status',
args: {
'asan_login_name': asanLoginName,
'bearer_token': bearerToken
},
callback: function(r) {
if (r.message && r.message.success) {
if (r.message.authenticated) {
ETaxesCompany._setDialogSuccess(dialog,
__('Authentication Successful'),
__('You are now authenticated with Asan Imza'));
setTimeout(() => callback(true), 1000);
} else {
setTimeout(pollStep, pollInterval);
}
} else {
ETaxesCompany._setDialogError(dialog,
__('Authentication Error'),
r.message ? r.message.message : __('An unknown error occurred'));
callback(false);
}
},
error: function() {
setTimeout(pollStep, pollInterval);
}
});
}
pollStep();
},
/**
* Complete authentication process
*/
completeAuthentication: function(dialog, asanLoginName, callback) {
ETaxesCompany._updateLoadingDialog(dialog,
__('Completing Authentication'),
__('Getting certificates and selecting taxpayer...'));
frappe.call({
method: 'taxes_az.auth.get_auth_certificates',
args: { 'asan_login_name': asanLoginName },
callback: function(certR) {
if (certR.message && certR.message.success) {
// Try to use existing certificate or select first available
frappe.call({
method: 'frappe.client.get',
args: {
doctype: 'Asan Login',
name: asanLoginName
},
callback: function(r) {
if (r.message && r.message.selected_certificate_json) {
// Use existing certificate
const certData = JSON.parse(r.message.selected_certificate_json);
const certName = r.message.selected_certificate;
ETaxesCompany.selectCertificateAndTaxpayer(dialog, asanLoginName, certData, certName, callback);
} else if (certR.message.certificates && certR.message.certificates.length > 0) {
// Use first available certificate
const cert = certR.message.certificates[0];
let certName = '';
if (cert.taxpayerType === 'individual' && cert.individualInfo) {
certName = `${cert.individualInfo.name} (${cert.individualInfo.fin})`;
} else if (cert.legalInfo) {
certName = `${cert.legalInfo.name} (${cert.legalInfo.voen || cert.legalInfo.tin})`;
} else {
certName = 'Certificate 1';
}
ETaxesCompany.selectCertificateAndTaxpayer(dialog, asanLoginName, cert, certName, callback);
} else {
ETaxesCompany._setDialogError(dialog,
__('No Certificates'),
__('No certificates found for this account'));
}
}
});
} else {
ETaxesCompany._setDialogError(dialog,
__('Error'),
certR.message ? certR.message.message : __('Failed to get certificates'));
}
}
});
},
/**
* Select certificate and taxpayer
*/
selectCertificateAndTaxpayer: function(dialog, asanLoginName, certData, certName, callback) {
ETaxesCompany._updateLoadingDialog(dialog,
__('Selecting certificate'),
certName);
frappe.call({
method: 'taxes_az.auth.select_certificate',
args: {
'asan_login_name': asanLoginName,
'certificate_data': certData,
'certificate_name': certName
},
callback: function(r) {
if (r.message && r.message.success) {
ETaxesCompany._updateLoadingDialog(dialog,
__('Selecting taxpayer'),
__('Using certificate: ') + certName);
frappe.call({
method: 'taxes_az.auth.select_taxpayer',
args: { 'asan_login_name': asanLoginName },
callback: function(r) {
if (r.message && r.message.success) {
ETaxesCompany._setDialogSuccess(dialog,
__('Authentication Complete'),
__('You can now access E-Taxes services'));
setTimeout(callback, 1000);
} else {
ETaxesCompany._setDialogError(dialog,
__('Error'),
r.message ? r.message.message : __('Failed to select taxpayer'));
}
}
});
} else {
ETaxesCompany._setDialogError(dialog,
__('Error'),
r.message ? r.message.message : __('Failed to select certificate'));
}
}
});
},
/**
* Fetch company profile from E-Taxes
*/
fetchProfile: function(frm) {
frappe.call({
method: 'taxes_az.company_etaxes.get_company_profile',
callback: function(r) {
ETaxesCompany._handleProfileResponse(r, frm);
},
error: function(xhr, status, error) {
frappe.msgprint({
title: __('Network Error'),
message: __('Failed to connect to server: {0}', [error || 'Unknown error']),
indicator: 'red'
});
}
});
},
/**
* Общая функция для скрытия загрузочного диалога
*/
_hideLoadingDialog: function() {
if (ETaxesCompany.currentLoadingDialog) {
try {
ETaxesCompany.currentLoadingDialog.hide();
} catch (e) {
console.error('Error hiding loading dialog:', e);
}
ETaxesCompany.currentLoadingDialog = null;
}
},
/**
* Handle profile response
*/
_handleProfileResponse: function(r, frm) {
if (r.message && r.message.success) {
ETaxesCompany.showProfileDialog(r.message.data, frm);
} else if (r.message && r.message.error === 'unauthorized') {
frappe.confirm(
__('Your E-Taxes session has expired. Would you like to authenticate again?'),
function() {
ETaxesCompany.startInlineAuthentication(frm);
},
function() {
frappe.show_alert({
message: __('Authentication cancelled'),
indicator: 'red'
}, 3);
}
);
} else if (r.message && r.message.error === 'server_error') {
frappe.msgprint({
title: __('Server Error'),
message: __('E-Taxes service is temporarily unavailable. Please try again in a few minutes.'),
indicator: 'orange'
});
} else {
frappe.msgprint({
title: __('Error'),
message: r.message ? r.message.message : __('An error occurred while fetching profile data'),
indicator: 'red'
});
}
},
/**
* Show enhanced profile dialog with automatic parsing
*/
showProfileDialog: function(profileData, frm) {
const profile = profileData.profile || profileData;
const parsedInfo = ETaxesCompany._formatParsedProfileHTML(profile);
const dialog = new frappe.ui.Dialog({
title: __('E-Taxes Company Profile'),
size: 'large',
fields: [
{
fieldname: 'parsed_info',
fieldtype: 'HTML',
label: __('Company Information')
}
],
primary_action_label: __('Update Company Fields'),
primary_action: function() {
dialog.hide(); // Hide dialog before starting update
ETaxesCompany.updateCompanyFromProfile(profileData, frm);
}
});
// Set parsed information HTML
dialog.fields_dict.parsed_info.$wrapper.html(parsedInfo);
dialog.show();
},
/**
* Получить справочник налоговых органов
*/
_getTaxAuthorities: function() {
return new Promise((resolve, reject) => {
// Проверяем кэш
if (ETaxesCompany._dictionaryCache.taxAuthorities) {
resolve(ETaxesCompany._dictionaryCache.taxAuthorities);
return;
}
// Запрашиваем справочник через Python API
frappe.call({
method: 'taxes_az.company_etaxes.get_tax_authorities',
callback: function(r) {
if (r.message && r.message.success) {
// Извлекаем массив authorities из data
const authoritiesArray = r.message.data.authorities || r.message.data;
ETaxesCompany._dictionaryCache.taxAuthorities = authoritiesArray;
resolve(authoritiesArray);
} else {
reject(r.message ? r.message.message : 'Failed to load tax authorities');
}
},
error: function() {
reject('Failed to load tax authorities');
}
});
});
},
/**
* Получить справочник типов собственности
*/
_getPropertyTypes: function() {
return new Promise((resolve, reject) => {
// Проверяем кэш
if (ETaxesCompany._dictionaryCache.propertyTypes) {
let cachedData = ETaxesCompany._dictionaryCache.propertyTypes;
// Исправляем структуру кэша если данные вложены неправильно
if (Array.isArray(cachedData) && cachedData.length === 1 && Array.isArray(cachedData[0])) {
cachedData = cachedData[0];
ETaxesCompany._dictionaryCache.propertyTypes = cachedData;
}
resolve(cachedData);
return;
}
// Запрашиваем справочник через Python API
frappe.call({
method: 'taxes_az.company_etaxes.get_property_types',
callback: function(r) {
if (r.message && r.message.success) {
const propertyTypesData = r.message.data;
let propertyTypesArray = [];
if (Array.isArray(propertyTypesData)) {
propertyTypesArray = propertyTypesData;
} else if (typeof propertyTypesData === 'object' && propertyTypesData !== null) {
// Преобразуем объект в массив
propertyTypesArray = Object.values(propertyTypesData);
}
ETaxesCompany._dictionaryCache.propertyTypes = propertyTypesArray;
resolve(propertyTypesArray);
} else {
reject(r.message ? r.message.message : 'Failed to load property types');
}
},
error: function() {
reject('Failed to load property types');
}
});
});
},
/**
* Найти название налогового органа по коду
*/
_getTaxAuthorityName: function(code) {
return new Promise((resolve) => {
ETaxesCompany._getTaxAuthorities().then((authorities) => {
if (authorities && Array.isArray(authorities)) {
const authority = authorities.find(auth => auth.code === code);
if (authority && authority.name && authority.name.az) {
resolve(authority.name.az);
} else if (authority && authority.name && typeof authority.name === 'string') {
resolve(authority.name);
} else {
resolve(code);
}
} else {
resolve(code);
}
}).catch(() => {
resolve(code);
});
});
},
/**
* Найти название типа собственности по коду
*/
_getPropertyTypeName: function(code) {
return new Promise((resolve) => {
ETaxesCompany._getPropertyTypes().then((propertyTypes) => {
let dataToSearch = propertyTypes;
// Дополнительная проверка структуры данных
if (Array.isArray(propertyTypes) && propertyTypes.length === 1 && Array.isArray(propertyTypes[0])) {
dataToSearch = propertyTypes[0];
}
if (dataToSearch && Array.isArray(dataToSearch)) {
const propertyType = dataToSearch.find(prop => prop.code === code);
if (propertyType && propertyType.name && propertyType.name.az) {
resolve(propertyType.name.az);
} else if (propertyType && propertyType.name && typeof propertyType.name === 'string') {
resolve(propertyType.name);
} else {
resolve(code);
}
} else {
resolve(code);
}
}).catch(() => {
resolve(code);
});
});
},
/**
* Parse profile data and extract field mappings
*/
_parseProfileData: function(profile, frm) {
const updates = [];
// Helper function to add update if value is different
function addUpdate(fieldname, newValue, label, oldValue) {
// Специальная обработка для checkbox полей
if (typeof newValue === 'boolean' || fieldname.includes('is_') || fieldname.includes('has_') || fieldname.includes('special_tax_regime')) {
// Преобразуем оба значения к boolean для корректного сравнения
const newBool = Boolean(newValue);
const oldBool = Boolean(oldValue);
// Сравниваем как boolean
if (newBool !== oldBool) {
updates.push({
fieldname: fieldname,
newValue: newBool ? '1' : '0',
oldValue: oldBool ? '1' : '0',
label: label
});
}
} else {
// Для остальных полей - обычная логика
if (newValue !== null && newValue !== undefined && newValue !== oldValue) {
newValue = String(newValue).trim();
if (newValue !== '' && newValue !== String(oldValue || '').trim()) {
updates.push({
fieldname: fieldname,
newValue: newValue,
oldValue: oldValue || '',
label: label
});
}
}
}
}
// Helper function to format date from YYYYMMDD to YYYY-MM-DD
function formatDate(dateStr) {
if (!dateStr || dateStr.length !== 8) return null;
const year = dateStr.substring(0, 4);
const month = dateStr.substring(4, 6);
const day = dateStr.substring(6, 8);
return `${year}-${month}-${day}`;
}
// BASIC COMPANY INFORMATION
// Tax ID mapping (TIN)
if (profile.tin) {
addUpdate('tax_id', profile.tin, __('Tax ID'), frm.doc.tax_id);
}
// Registration Number mapping
if (profile.stateRegistrationDocumentNumber) {
addUpdate('registration_details', profile.stateRegistrationDocumentNumber, __('Registration Details'), frm.doc.registration_details);
}
// Phone mapping - prefer mobile over landline
const mobilePhone = profile.mobilePhoneNumber || ETaxesCompany._extractPhoneNumber(profile, 'mobile');
const landlinePhone = profile.landlinePhoneNumber || ETaxesCompany._extractPhoneNumber(profile, 'landline');
if (mobilePhone) {
addUpdate('phone_no', mobilePhone, __('Phone'), frm.doc.phone_no);
} else if (landlinePhone) {
addUpdate('phone_no', landlinePhone, __('Phone'), frm.doc.phone_no);
}
// Store both phones in dedicated fields
if (mobilePhone) {
addUpdate('mobile_phone', mobilePhone, __('Mobile Phone'), frm.doc.mobile_phone);
}
if (landlinePhone) {
addUpdate('landline_phone', landlinePhone, __('Landline Phone'), frm.doc.landline_phone);
}
// Email mapping
if (profile.email) {
addUpdate('email', profile.email, __('Email'), frm.doc.email);
}
// Registration Date mapping
if (profile.taxpayerRegistrationDate) {
const regDate = moment(profile.taxpayerRegistrationDate).format('YYYY-MM-DD');
addUpdate('date_of_establishment', regDate, __('Date of Establishment'), frm.doc.date_of_establishment);
}
// State Registration Document Issued Date
if (profile.stateRegistrationDocumentIssuedDate) {
const issuedDate = moment(profile.stateRegistrationDocumentIssuedDate).format('YYYY-MM-DD');
addUpdate('state_registration_document_issued_date', issuedDate, __('State Registration Document Issued Date'), frm.doc.state_registration_document_issued_date);
}
// Domain mapping (if available)
if (profile.mainActivity) {
addUpdate('domain', profile.mainActivity, __('Domain'), frm.doc.domain);
}
// MANAGEMENT INFORMATION
// Director Name from E-Taxes
if (profile.companyDirectorName) {
addUpdate('director_name_etaxes', profile.companyDirectorName, __('Director Name (E-Taxes)'), frm.doc.director_name_etaxes);
}
// Director PIN
if (profile.pin) {
addUpdate('director_pin', profile.pin, __('Director PIN'), frm.doc.director_pin);
}
// BUSINESS ACTIVITIES
// Main Activity mapping
if (profile.mainActivity) {
addUpdate('main_activity', profile.mainActivity, __('Main Activity'), frm.doc.main_activity);
}
// Legal Form Code
if (profile.legalFormCode) {
addUpdate('legal_form_code', profile.legalFormCode, __('Legal Form Code'), frm.doc.legal_form_code);
}
// TAX INFORMATION
// Taxation System mapping
if (profile.taxRate) {
let taxationSystem = '';
if (profile.taxRate === 'ƏDV' || profile.taxRate === 'VAT' || profile.taxRate === '18%') {
taxationSystem = '18% Value-added tax';
} else if (profile.taxRate === '0%' || profile.taxRate === 'ƏDV 0%') {
taxationSystem = '0% Value-added tax';
} else {
taxationSystem = profile.taxRate;
}
addUpdate('taxation_system', taxationSystem, __('Taxation System'), frm.doc.taxation_system);
}
// Business Classification mapping
if (profile.criteriaOfBusinessEntity) {
let businessClassification = '';
switch (profile.criteriaOfBusinessEntity.toLowerCase()) {
case 'micro':
businessClassification = 'Micro Entrepreneur';
break;
case 'small':
businessClassification = 'Small Entrepreneur';
break;
case 'middle':
case 'medium':
businessClassification = 'Medium Entrepreneur';
break;
case 'big':
case 'large':
businessClassification = 'Big Entrepreneur';
break;
default:
businessClassification = profile.criteriaOfBusinessEntity + ' Entrepreneur';
}
addUpdate('business_classification', businessClassification, __('Business Classification'), frm.doc.business_classification);
}
// State Registration Authority
if (profile.stateRegistrationName) {
addUpdate('state_registration_authority', profile.stateRegistrationName, __('State Registration Authority'), frm.doc.state_registration_authority);
}
// Taxpayer Activity Group
if (profile.activityGroup) {
addUpdate('taxpayer_activity_group', profile.activityGroup, __('Taxpayer Activity Group'), frm.doc.taxpayer_activity_group);
}
// Special Tax Regime
if (profile.specialTaxRegime !== undefined) {
addUpdate('special_tax_regime', profile.specialTaxRegime, __('Special Tax Regime'), frm.doc.special_tax_regime);
}
// TIN Type
if (profile.tinType) {
addUpdate('tin_type', profile.tinType, __('TIN Type'), frm.doc.tin_type);
}
// Is Risky
if (profile.isRisky !== undefined) {
addUpdate('is_risky_taxpayer', profile.isRisky, __('Is Risky Taxpayer'), frm.doc.is_risky_taxpayer);
}
// Sport Betting Operator
if (profile.sportBettingOperator !== undefined) {
addUpdate('is_sport_betting_operator', profile.sportBettingOperator, __('Sport Betting Operator'), frm.doc.is_sport_betting_operator);
}
// Has Active Production Object
if (profile.hasActiveProductionObject !== undefined) {
addUpdate('has_active_production_object', profile.hasActiveProductionObject, __('Has Active Production Object'), frm.doc.has_active_production_object);
}
// Tax System Type
if (profile.taxSystemType) {
addUpdate('tax_system_type', profile.taxSystemType, __('Tax System Type'), frm.doc.tax_system_type);
}
// Is Taxpayer in Cancellation Process
if (profile.isTaxPayerInCancellationProcess !== undefined) {
addUpdate('is_taxpayer_in_cancellation_process', profile.isTaxPayerInCancellationProcess, __('Is Taxpayer in Cancellation Process'), frm.doc.is_taxpayer_in_cancellation_process);
}
// Is Chief of Any Legal Entity
if (profile.isChiefOfAnyLegalEntity !== undefined) {
addUpdate('is_chief_of_any_legal_entity', profile.isChiefOfAnyLegalEntity, __('Is Chief of Any Legal Entity'), frm.doc.is_chief_of_any_legal_entity);
}
// VAT INFORMATION
if (profile.vatInfo && typeof profile.vatInfo === 'object') {
// VAT Registration Date
if (profile.vatInfo.prOperationTableOperationDate) {
const vatRegDate = formatDate(profile.vatInfo.prOperationTableOperationDate);
if (vatRegDate) {
addUpdate('vat_registration_date', vatRegDate, __('VAT Registration Date'), frm.doc.vat_registration_date);
}
}
// VAT Certificate Number
if (profile.vatInfo.recDocumentDocumentNumber) {
addUpdate('vat_certificate_number', profile.vatInfo.recDocumentDocumentNumber, __('VAT Certificate Number'), frm.doc.vat_certificate_number);
}
// VAT Certificate Date
if (profile.vatInfo.prVatOperationsRegDate) {
const vatCertDate = formatDate(profile.vatInfo.prVatOperationsRegDate);
if (vatCertDate) {
addUpdate('vat_certificate_date', vatCertDate, __('VAT Certificate Date'), frm.doc.vat_certificate_date);
}
}
}
// ORGANIZATIONAL STRUCTURE
// Parent Organization
if (profile.headOrganizationName && Array.isArray(profile.headOrganizationName) && profile.headOrganizationName.length > 0) {
const parentOrgText = profile.headOrganizationName.join(', ');
addUpdate('parent_organization', parentOrgText, __('Parent Organization'), frm.doc.parent_organization);
}
// Parent Organization TIN
if (profile.headOrganizationTin) {
addUpdate('parent_organization_tin', profile.headOrganizationTin, __('Parent Organization TIN'), frm.doc.parent_organization_tin);
}
// Employee Count
if (profile.employeeData && profile.employeeData.employeeCount !== undefined) {
addUpdate('employee_count', profile.employeeData.employeeCount, __('Employee Count'), frm.doc.employee_count);
}
// REGISTRATION DATES
// Suspension Dates
if (profile.suspensionStartDate) {
const suspStartDate = moment(profile.suspensionStartDate).format('YYYY-MM-DD');
addUpdate('suspension_start_date', suspStartDate, __('Suspension Start Date'), frm.doc.suspension_start_date);
}
if (profile.suspensionEndDate) {
const suspEndDate = moment(profile.suspensionEndDate).format('YYYY-MM-DD');
addUpdate('suspension_end_date', suspEndDate, __('Suspension End Date'), frm.doc.suspension_end_date);
}
// Liquidation Date
if (profile.liquidationDate) {
const liqDate = moment(profile.liquidationDate).format('YYYY-MM-DD');
addUpdate('liquidation_date', liqDate, __('Liquidation Date'), frm.doc.liquidation_date);
}
// ADDRESS INFORMATION
// Legal Address Full
if (profile.legalAddress) {
addUpdate('legal_address_full', profile.legalAddress, __('Legal Address (Full)'), frm.doc.legal_address_full);
}
// Actual Address Full
if (profile.actualAddress) {
addUpdate('actual_address_full', profile.actualAddress, __('Actual Address (Full)'), frm.doc.actual_address_full);
}
// Address for Mail
if (profile.addressForMail) {
addUpdate('address_for_mail', profile.addressForMail, __('Address for Mail'), frm.doc.address_for_mail);
}
// Legal Address Details
if (profile.legalAddressObject && typeof profile.legalAddressObject === 'object') {
if (profile.legalAddressObject.postcode) {
addUpdate('legal_address_postcode', profile.legalAddressObject.postcode, __('Legal Address Postcode'), frm.doc.legal_address_postcode);
}
if (profile.legalAddressObject.region) {
addUpdate('legal_address_region', profile.legalAddressObject.region, __('Legal Address Region'), frm.doc.legal_address_region);
}
if (profile.legalAddressObject.locality) {
addUpdate('legal_address_locality', profile.legalAddressObject.locality, __('Legal Address Locality'), frm.doc.legal_address_locality);
}
if (profile.legalAddressObject.street) {
addUpdate('legal_address_street', profile.legalAddressObject.street, __('Legal Address Street'), frm.doc.legal_address_street);
}
if (profile.legalAddressObject.houseNumber) {
addUpdate('legal_address_house', profile.legalAddressObject.houseNumber, __('Legal Address House Number'), frm.doc.legal_address_house);
}
if (profile.legalAddressObject.roomNumber) {
addUpdate('legal_address_room', profile.legalAddressObject.roomNumber, __('Legal Address Room Number'), frm.doc.legal_address_room);
}
}
// TAX SYSTEMS LIST
if (profile.taxSystems && Array.isArray(profile.taxSystems) && profile.taxSystems.length > 0) {
const taxSystemsList = profile.taxSystems.join(', ');
addUpdate('tax_systems_list', taxSystemsList, __('Tax Systems List'), frm.doc.tax_systems_list);
}
// EMPLOYER INFORMATION
if (profile.employer && typeof profile.employer === 'object') {
if (profile.employer.name) {
addUpdate('employer_name', profile.employer.name, __('Employer Name'), frm.doc.employer_name);
}
if (profile.employer.position) {
addUpdate('employer_position', profile.employer.position, __('Employer Position'), frm.doc.employer_position);
}
}
return updates;
},
updateCompanyFromProfile: function(profileData, frm) {
try {
const profile = profileData.profile || profileData;
const updates = ETaxesCompany._parseProfileData(profile, frm);
const hasAdditionalActivities = profile.additionalActivityCodes && Array.isArray(profile.additionalActivityCodes) && profile.additionalActivityCodes.length > 0;
const hasAffiliates = (profile.affiliatesNames && profile.affiliatesNames.length > 0) || (profile.affiliatesTins && profile.affiliatesTins.length > 0);
const hasDictionaryFields = profile.taxAuthorityCode || profile.propertyType;
if (updates.length > 0 || hasAdditionalActivities || hasAffiliates || hasDictionaryFields) {
let confirmMessage = '';
if (updates.length > 0) {
confirmMessage = __('The following company fields will be updated with data from E-Taxes:') + '<br><br>';
let changesList = '<ul style="text-align: left; margin: 10px 0;">';
updates.forEach(update => {
changesList += `<li><strong>${update.label}:</strong> ${update.oldValue || __('(empty)')}${update.newValue}</li>`;
});
changesList += '</ul>';
confirmMessage += changesList;
}
let additionalInfo = '';
if (hasAdditionalActivities) {
additionalInfo += `<br><strong>${__('Additional activities to be added')}:</strong> ${profile.additionalActivityCodes.length} ${__('activities')}`;
additionalInfo += '<br><small>' + profile.additionalActivityCodes.join(', ') + '</small>';
}
if (hasAffiliates) {
const affiliateCount = Math.max(
(profile.affiliatesNames || []).length,
(profile.affiliatesTins || []).length
);
additionalInfo += `<br><strong>${__('Affiliate organizations to be added')}:</strong> ${affiliateCount} ${__('organizations')}`;
}
if (!confirmMessage && additionalInfo) {
confirmMessage = __('The following data will be updated:');
}
confirmMessage += additionalInfo;
confirmMessage += '<br><br>' + __('Continue?');
frappe.confirm(
confirmMessage,
function() {
// Показываем индикатор загрузки
frappe.show_alert({
message: __('Updating company data...'),
indicator: 'blue'
});
// Собираем все обновления полей
let allUpdates = {};
updates.forEach(update => {
allUpdates[update.fieldname] = update.newValue;
});
// Обрабатываем справочники
let promises = [];
if (profile.taxAuthorityCode) {
promises.push(
ETaxesCompany._getTaxAuthorityName(profile.taxAuthorityCode).then((authorityName) => {
allUpdates['tax_authority'] = authorityName;
})
);
}
if (profile.propertyType) {
promises.push(
ETaxesCompany._getPropertyTypeName(profile.propertyType).then((propertyTypeName) => {
allUpdates['property_type'] = propertyTypeName;
})
);
}
Promise.all(promises).then(() => {
// Подготавливаем данные для отправки
const updateData = {
company_name: frm.doc.name,
field_updates: JSON.stringify(allUpdates),
additional_activities: JSON.stringify(hasAdditionalActivities ? profile.additionalActivityCodes : []),
affiliate_names: JSON.stringify(hasAffiliates ? (profile.affiliatesNames || []) : []),
affiliate_tins: JSON.stringify(hasAffiliates ? (profile.affiliatesTins || []) : [])
};
console.log('Sending update data:', updateData);
// Вызываем серверный метод для форсированного обновления
frappe.call({
method: 'taxes_az.company_etaxes.force_update_company',
args: updateData,
callback: function(r) {
console.log('Update response:', r);
if (r.message && r.message.success) {
// Перезагружаем форму
frm.reload_doc();
let successMessage = __('Company data successfully updated from E-Taxes profile');
if (r.message.additional_activities_added > 0) {
successMessage += '<br>' + __('Added {0} additional activities', [r.message.additional_activities_added]);
}
if (r.message.affiliates_added > 0) {
successMessage += '<br>' + __('Added {0} affiliate organizations', [r.message.affiliates_added]);
}
frappe.show_alert({
message: successMessage,
indicator: 'green'
}, 5);
} else {
frappe.msgprint({
title: __('Update Error'),
message: r.message ? r.message.message : __('Error updating company data'),
indicator: 'red'
});
}
},
error: function(r) {
console.error('Update error:', r);
frappe.msgprint({
title: __('Server Error'),
message: __('Server error during update. Please check the error logs.'),
indicator: 'red'
});
}
});
}).catch(error => {
console.error('Error processing dictionaries:', error);
frappe.msgprint({
title: __('Processing Error'),
message: __('Error processing dictionary data: {0}', [error]),
indicator: 'red'
});
});
},
function() {
frappe.show_alert({
message: __('Update cancelled'),
indicator: 'blue'
}, 3);
}
);
} else {
frappe.show_alert({
message: __('No new data to update'),
indicator: 'blue'
}, 3);
}
} catch (e) {
console.error('Error parsing profile data:', e);
frappe.show_alert({
message: __('Error parsing profile data: {0}', [e.message]),
indicator: 'red'
}, 5);
}
},
/**
* Extract best phone number from profile
*/
_extractPhoneNumber: function(profile, preferredType = null) {
// If preferredType is specified, try to get that type first
if (preferredType === 'mobile' && profile.mobilePhoneNumber) {
return profile.mobilePhoneNumber;
}
if (preferredType === 'landline' && profile.landlinePhoneNumber) {
return profile.landlinePhoneNumber;
}
// Priority: mobile > landline > contacts mobile > contacts home
if (profile.mobilePhoneNumber) {
return profile.mobilePhoneNumber;
}
if (profile.landlinePhoneNumber) {
return profile.landlinePhoneNumber;
}
// Check contacts array
if (profile.contacts && Array.isArray(profile.contacts)) {
// Look for mobile first
const mobileContact = profile.contacts.find(c => c.type === 'mobile' && c.contact);
if (mobileContact) {
return mobileContact.prefix ? `${mobileContact.prefix}${mobileContact.contact}` : mobileContact.contact;
}
// Then home phone
const phoneContact = profile.contacts.find(c => c.type === 'homePhone' && c.contact);
if (phoneContact) {
return phoneContact.prefix ? `${phoneContact.prefix}${phoneContact.contact}` : phoneContact.contact;
}
}
return null;
},
/**
* Format VAT Info object as readable text
*/
_formatVatInfo: function(vatInfo) {
if (!vatInfo || typeof vatInfo !== 'object') {
return vatInfo;
}
let formatted = '';
if (vatInfo.recDocumentDocumentNumber) {
formatted += __('Document No') + ': ' + vatInfo.recDocumentDocumentNumber;
}
if (vatInfo.prVatOperationsRegDate) {
if (formatted) formatted += '<br>';
formatted += __('Registration Date') + ': ' + vatInfo.prVatOperationsRegDate;
}
if (vatInfo.prOperationTableOperationDate) {
if (formatted) formatted += '<br>';
formatted += __('Operation Date') + ': ' + vatInfo.prOperationTableOperationDate;
}
return formatted || JSON.stringify(vatInfo);
},
/**
* Format parsed profile data as HTML
*/
_formatParsedProfileHTML: function(profile) {
let html = '<div class="etaxes-profile-info">';
try {
// Basic Company Information
html += '<div class="section"><h5>' + __('Company Information') + '</h5>';
html += '<table class="table table-bordered table-sm profile-table">';
if (profile.companyName) {
html += `<tr><td><strong>${__('Company Name')}</strong></td><td class="text-content">${profile.companyName}</td></tr>`;
}
if (profile.tin) {
html += `<tr><td><strong>${__('TIN')}</strong></td><td class="text-content">${profile.tin}</td></tr>`;
}
if (profile.pin) {
html += `<tr><td><strong>${__('PIN')}</strong></td><td class="text-content">${profile.pin}</td></tr>`;
}
if (profile.stateRegistrationDocumentNumber) {
html += `<tr><td><strong>${__('Registration Number')}</strong></td><td class="text-content">${profile.stateRegistrationDocumentNumber}</td></tr>`;
}
if (profile.taxpayerRegistrationDate) {
const regDate = moment(profile.taxpayerRegistrationDate).format('DD.MM.YYYY');
html += `<tr><td><strong>${__('Registration Date')}</strong></td><td class="text-content">${regDate}</td></tr>`;
}
if (profile.stateRegistrationDocumentIssuedDate) {
const issuedDate = moment(profile.stateRegistrationDocumentIssuedDate).format('DD.MM.YYYY');
html += `<tr><td><strong>${__('State Registration Document Issued Date')}</strong></td><td class="text-content">${issuedDate}</td></tr>`;
}
if (profile.taxpayerStatus) {
const statusText = profile.taxpayerStatus === 'A' ? __('Active') : profile.taxpayerStatus;
html += `<tr><td><strong>${__('Status')}</strong></td><td class="text-content">${statusText}</td></tr>`;
}
if (profile.legalFormCode) {
html += `<tr><td><strong>${__('Legal Form Code')}</strong></td><td class="text-content">${profile.legalFormCode}</td></tr>`;
}
if (profile.tinType) {
html += `<tr><td><strong>${__('TIN Type')}</strong></td><td class="text-content">${profile.tinType}</td></tr>`;
}
html += '</table></div>';
// Contact Information
html += '<div class="section"><h5>' + __('Contact Information') + '</h5>';
html += '<table class="table table-bordered table-sm profile-table">';
if (profile.mobilePhoneNumber) {
html += `<tr><td><strong>${__('Mobile Phone')}</strong></td><td class="text-content">${profile.mobilePhoneNumber}</td></tr>`;
}
if (profile.landlinePhoneNumber) {
html += `<tr><td><strong>${__('Landline Phone')}</strong></td><td class="text-content">${profile.landlinePhoneNumber}</td></tr>`;
}
if (profile.email) {
html += `<tr><td><strong>${__('Email')}</strong></td><td class="text-content">${profile.email}</td></tr>`;
}
if (profile.legalAddress) {
html += `<tr><td><strong>${__('Legal Address')}</strong></td><td class="text-content">${profile.legalAddress}</td></tr>`;
}
if (profile.actualAddress) {
html += `<tr><td><strong>${__('Actual Address')}</strong></td><td class="text-content">${profile.actualAddress}</td></tr>`;
}
if (profile.addressForMail) {
html += `<tr><td><strong>${__('Address for Mail')}</strong></td><td class="text-content">${profile.addressForMail}</td></tr>`;
}
// Legal Address Details
if (profile.legalAddressObject && typeof profile.legalAddressObject === 'object') {
const addr = profile.legalAddressObject;
if (addr.postcode || addr.region || addr.locality || addr.street || addr.houseNumber || addr.roomNumber) {
html += `<tr><td colspan="2"><strong>${__('Legal Address Details')}</strong></td></tr>`;
if (addr.postcode) html += `<tr><td>${__('Postcode')}</td><td class="text-content">${addr.postcode}</td></tr>`;
if (addr.region) html += `<tr><td>${__('Region')}</td><td class="text-content">${addr.region}</td></tr>`;
if (addr.locality) html += `<tr><td>${__('Locality')}</td><td class="text-content">${addr.locality}</td></tr>`;
if (addr.street) html += `<tr><td>${__('Street')}</td><td class="text-content">${addr.street}</td></tr>`;
if (addr.houseNumber) html += `<tr><td>${__('House Number')}</td><td class="text-content">${addr.houseNumber}</td></tr>`;
if (addr.roomNumber) html += `<tr><td>${__('Room Number')}</td><td class="text-content">${addr.roomNumber}</td></tr>`;
}
}
html += '</table></div>';
// Business Information
html += '<div class="section"><h5>' + __('Business Information') + '</h5>';
html += '<table class="table table-bordered table-sm profile-table">';
if (profile.mainActivity) {
html += `<tr><td><strong>${__('Main Activity Code')}</strong></td><td class="text-content">${profile.mainActivity}</td></tr>`;
}
if (profile.additionalActivityCodes && profile.additionalActivityCodes.length > 0) {
html += `<tr><td><strong>${__('Additional Activity Codes')}</strong></td><td class="text-content">${profile.additionalActivityCodes.join(', ')}</td></tr>`;
}
if (profile.criteriaOfBusinessEntity) {
html += `<tr><td><strong>${__('Business Entity Criteria')}</strong></td><td class="text-content">${profile.criteriaOfBusinessEntity}</td></tr>`;
}
if (profile.activityGroup) {
html += `<tr><td><strong>${__('Activity Group')}</strong></td><td class="text-content">${profile.activityGroup}</td></tr>`;
}
if (profile.sportBettingOperator !== undefined) {
html += `<tr><td><strong>${__('Sport Betting Operator')}</strong></td><td class="text-content">${profile.sportBettingOperator ? __('Yes') : __('No')}</td></tr>`;
}
if (profile.hasActiveProductionObject !== undefined) {
html += `<tr><td><strong>${__('Has Active Production Object')}</strong></td><td class="text-content">${profile.hasActiveProductionObject ? __('Yes') : __('No')}</td></tr>`;
}
html += '</table></div>';
// Tax Information
html += '<div class="section"><h5>' + __('Tax Information') + '</h5>';
html += '<table class="table table-bordered table-sm profile-table">';
if (profile.taxRate) {
html += `<tr><td><strong>${__('Tax Rate')}</strong></td><td class="text-content">${profile.taxRate}</td></tr>`;
}
if (profile.specialTaxRegime !== undefined) {
html += `<tr><td><strong>${__('Special Tax Regime')}</strong></td><td class="text-content">${profile.specialTaxRegime ? __('Yes') : __('No')}</td></tr>`;
}
if (profile.taxAuthorityCode) {
html += `<tr><td><strong>${__('Tax Authority Code')}</strong></td><td class="text-content">${profile.taxAuthorityCode}</td></tr>`;
}
if (profile.propertyType) {
html += `<tr><td><strong>${__('Property Type')}</strong></td><td class="text-content">${profile.propertyType}</td></tr>`;
}
if (profile.taxSystemType) {
html += `<tr><td><strong>${__('Tax System Type')}</strong></td><td class="text-content">${profile.taxSystemType}</td></tr>`;
}
if (profile.taxSystems && profile.taxSystems.length > 0) {
html += `<tr><td><strong>${__('Tax Systems')}</strong></td><td class="text-content">${profile.taxSystems.join(', ')}</td></tr>`;
}
if (profile.isRisky !== undefined) {
html += `<tr><td><strong>${__('Is Risky Taxpayer')}</strong></td><td class="text-content">${profile.isRisky ? __('Yes') : __('No')}</td></tr>`;
}
if (profile.isTaxPayerInCancellationProcess !== undefined) {
html += `<tr><td><strong>${__('In Cancellation Process')}</strong></td><td class="text-content">${profile.isTaxPayerInCancellationProcess ? __('Yes') : __('No')}</td></tr>`;
}
if (profile.vatInfo) {
const formattedVat = ETaxesCompany._formatVatInfo(profile.vatInfo);
html += `<tr><td><strong>${__('VAT Info')}</strong></td><td class="text-content">${formattedVat}</td></tr>`;
}
html += '</table></div>';
// Organizational Structure
html += '<div class="section"><h5>' + __('Organizational Structure') + '</h5>';
html += '<table class="table table-bordered table-sm profile-table">';
if (profile.headOrganizationName && profile.headOrganizationName.length > 0) {
html += `<tr><td><strong>${__('Parent Organization')}</strong></td><td class="text-content">${profile.headOrganizationName.join(', ')}</td></tr>`;
}
if (profile.headOrganizationTin) {
html += `<tr><td><strong>${__('Parent Organization TIN')}</strong></td><td class="text-content">${profile.headOrganizationTin}</td></tr>`;
}
if (profile.affiliatesNames && profile.affiliatesNames.length > 0) {
const affiliatesText = profile.affiliatesNames.join(', ');
html += `<tr><td><strong>${__('Affiliate Organizations')}</strong></td><td class="text-content">${affiliatesText}</td></tr>`;
}
if (profile.affiliatesTins && profile.affiliatesTins.length > 0) {
const affiliatesTinsText = profile.affiliatesTins.join(', ');
html += `<tr><td><strong>${__('Affiliate Organizations TINs')}</strong></td><td class="text-content">${affiliatesTinsText}</td></tr>`;
}
html += '</table></div>';
// Management Information
html += '<div class="section"><h5>' + __('Management Information') + '</h5>';
html += '<table class="table table-bordered table-sm profile-table">';
if (profile.companyDirectorName) {
html += `<tr><td><strong>${__('Director Name')}</strong></td><td class="text-content">${profile.companyDirectorName}</td></tr>`;
}
if (profile.chief) {
const chiefName = `${profile.chief.name || ''} ${profile.chief.surname || ''} ${profile.chief.middleName || ''}`.trim();
if (chiefName) {
html += `<tr><td><strong>${__('Chief')}</strong></td><td class="text-content">${chiefName}</td></tr>`;
}
if (profile.chief.pin) {
html += `<tr><td><strong>${__('Chief PIN')}</strong></td><td class="text-content">${profile.chief.pin}</td></tr>`;
}
}
if (profile.employer && profile.employer.name) {
html += `<tr><td><strong>${__('Employer')}</strong></td><td class="text-content">${profile.employer.name}</td></tr>`;
if (profile.employer.position) {
html += `<tr><td><strong>${__('Employer Position')}</strong></td><td class="text-content">${profile.employer.position}</td></tr>`;
}
}
if (profile.isChiefOfAnyLegalEntity !== undefined) {
html += `<tr><td><strong>${__('Is Chief of Any Legal Entity')}</strong></td><td class="text-content">${profile.isChiefOfAnyLegalEntity ? __('Yes') : __('No')}</td></tr>`;
}
if (profile.employeeData && profile.employeeData.employeeCount !== undefined) {
html += `<tr><td><strong>${__('Employee Count')}</strong></td><td class="text-content">${profile.employeeData.employeeCount}</td></tr>`;
}
html += '</table></div>';
// Important Dates
if (profile.suspensionStartDate || profile.suspensionEndDate || profile.liquidationDate) {
html += '<div class="section"><h5>' + __('Important Dates') + '</h5>';
html += '<table class="table table-bordered table-sm profile-table">';
if (profile.suspensionStartDate) {
const suspStartDate = moment(profile.suspensionStartDate).format('DD.MM.YYYY');
html += `<tr><td><strong>${__('Suspension Start Date')}</strong></td><td class="text-content">${suspStartDate}</td></tr>`;
}
if (profile.suspensionEndDate) {
const suspEndDate = moment(profile.suspensionEndDate).format('DD.MM.YYYY');
html += `<tr><td><strong>${__('Suspension End Date')}</strong></td><td class="text-content">${suspEndDate}</td></tr>`;
}
if (profile.liquidationDate) {
const liqDate = moment(profile.liquidationDate).format('DD.MM.YYYY');
html += `<tr><td><strong>${__('Liquidation Date')}</strong></td><td class="text-content">${liqDate}</td></tr>`;
}
html += '</table></div>';
}
// Certificates Information (if any)
if (profile.certificates && profile.certificates.length > 0) {
html += '<div class="section"><h5>' + __('Certificates') + '</h5>';
html += '<table class="table table-bordered table-sm profile-table">';
profile.certificates.forEach((cert, index) => {
html += `<tr><td colspan="2"><strong>${__('Certificate')} ${index + 1}</strong></td></tr>`;
if (cert.taxpayerType) {
html += `<tr><td>${__('Type')}</td><td class="text-content">${cert.taxpayerType}</td></tr>`;
}
if (cert.legalInfo) {
if (cert.legalInfo.tin) html += `<tr><td>${__('TIN')}</td><td class="text-content">${cert.legalInfo.tin}</td></tr>`;
if (cert.legalInfo.name) html += `<tr><td>${__('Name')}</td><td class="text-content">${cert.legalInfo.name}</td></tr>`;
}
if (cert.individualInfo) {
if (cert.individualInfo.fin) html += `<tr><td>${__('FIN')}</td><td class="text-content">${cert.individualInfo.fin}</td></tr>`;
if (cert.individualInfo.name) html += `<tr><td>${__('Name')}</td><td class="text-content">${cert.individualInfo.name}</td></tr>`;
}
if (cert.position) {
html += `<tr><td>${__('Position')}</td><td class="text-content">${cert.position}</td></tr>`;
}
if (cert.hasAccess !== undefined) {
html += `<tr><td>${__('Has Access')}</td><td class="text-content">${cert.hasAccess ? __('Yes') : __('No')}</td></tr>`;
}
if (cert.liquidated !== undefined) {
html += `<tr><td>${__('Liquidated')}</td><td class="text-content">${cert.liquidated ? __('Yes') : __('No')}</td></tr>`;
}
});
html += '</table></div>';
}
} catch (e) {
html += '<div class="alert alert-warning">' + __('Unable to parse profile data: {0}', [e.message]) + '</div>';
}
html += '</div>';
// CSS остается тем же
html = `
<style>
.etaxes-profile-info {
color: var(--text-color, #333);
background: var(--bg-color, #fff);
max-width: 100%;
overflow-x: auto;
}
.etaxes-profile-info .section {
margin-bottom: 20px;
}
.etaxes-profile-info h5 {
color: var(--primary-color, #5e64ff);
margin-bottom: 10px;
font-weight: 600;
}
.etaxes-profile-info .profile-table {
background: var(--bg-color, #fff);
border: 1px solid var(--border-color, #dee2e6);
color: var(--text-color, #333);
width: 100%;
table-layout: auto;
max-width: 100%;
}
.etaxes-profile-info .profile-table td {
padding: 8px 12px;
border: 1px solid var(--border-color, #dee2e6);
color: var(--text-color, #333);
word-wrap: break-word;
word-break: break-word;
vertical-align: top;
white-space: normal;
}
.etaxes-profile-info .profile-table td:first-child {
width: 180px;
background: var(--control-bg-color, #f8f9fa);
font-weight: 500;
color: var(--text-color, #333);
min-width: 150px;
}
.etaxes-profile-info .profile-table td.text-content {
background: var(--bg-color, #fff);
color: var(--text-color, #333);
white-space: normal;
word-wrap: break-word;
}
@media (prefers-color-scheme: dark) {
.etaxes-profile-info {
color: #e4e6ea;
background: #2b2d42;
}
.etaxes-profile-info .profile-table {
background: #2b2d42;
border-color: #495057;
color: #e4e6ea;
}
.etaxes-profile-info .profile-table td {
border-color: #495057;
color: #e4e6ea;
}
.etaxes-profile-info .profile-table td:first-child {
background: #3a3d5c;
color: #e4e6ea;
}
.etaxes-profile-info .profile-table td.text-content {
background: #2b2d42;
color: #e4e6ea;
}
}
</style>
` + html;
return html;
},
/**
* Helper functions for authentication dialogs
*/
_getAuthLoadingHTML: function(title, message) {
return `
<div class="text-center">
<div class="loading-animation" style="display: inline-block; width: 64px; height: 64px;">
<div style="width: 64px; height: 64px; border: 6px solid #4e73df; border-radius: 50%; border-color: #4e73df transparent #4e73df transparent; animation: lds-dual-ring 1.2s linear infinite;"></div>
</div>
<style>
@keyframes lds-dual-ring {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
<div class="mt-3" id="auth_status_message">
<h4 id="auth_loading_title">${title || __('Please wait...')}</h4>
<p id="auth_loading_message">${message || __('The operation may take some time')}</p>
</div>
<div id="auth_verification_code_container" style="display:none; margin-top: 15px;">
<div style="background: #f8f9fa; padding: 10px; display: inline-block; border-radius: 5px; font-size: 24px; font-weight: bold; letter-spacing: 2px; color: #333; border: 1px solid #ddd;">
<span id="auth_verification_code">----</span>
</div>
<p style="margin-top: 5px; font-size: 12px; color: #666;">Verification Code</p>
</div>
</div>
`;
},
_updateLoadingDialog: function(dialog, title, message) {
if (title) $('#auth_loading_title').text(title);
if (message) $('#auth_loading_message').text(message);
},
_showVerificationCode: function(dialog, code) {
if (code) {
$('#auth_verification_code').text(code);
$('#auth_verification_code_container').show();
}
},
_setDialogSuccess: function(dialog, title, message) {
dialog.$wrapper.find('.loading-animation').html(`
<div style="width: 64px; height: 64px; display: flex; align-items: center; justify-content: center;">
<i class="fa fa-check" style="font-size: 48px; color: #5cb85c;"></i>
</div>
`);
$('#auth_loading_title').text(title);
$('#auth_loading_message').text(message);
$('#auth_verification_code_container').hide();
},
_setDialogError: function(dialog, title, message) {
dialog.$wrapper.find('.loading-animation').html(`
<div style="width: 64px; height: 64px; display: flex; align-items: center; justify-content: center;">
<i class="fa fa-times" style="font-size: 48px; color: #d9534f;"></i>
</div>
`);
$('#auth_loading_title').text(title);
$('#auth_loading_message').text(message);
$('#auth_verification_code_container').hide();
dialog.set_primary_action(__('Close'), () => dialog.hide());
}
};