Prepared for VAT form filling
This commit is contained in:
parent
cc48775100
commit
22ff793727
|
|
@ -553,22 +553,42 @@ window.ETaxesCompany = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse profile data and extract field mappings
|
* Parse profile data and extract field mappings
|
||||||
* ПОЛНАЯ ВЕРСИЯ: Включает все поля включая VAT и новые поля
|
|
||||||
*/
|
*/
|
||||||
_parseProfileData: function(profile, frm) {
|
_parseProfileData: function(profile, frm) {
|
||||||
const updates = [];
|
const updates = [];
|
||||||
|
|
||||||
// Helper function to add update if value is different
|
// Helper function to add update if value is different
|
||||||
function addUpdate(fieldname, newValue, label, oldValue) {
|
function addUpdate(fieldname, newValue, label, oldValue) {
|
||||||
if (newValue && newValue !== oldValue && newValue.trim() !== '') {
|
// Специальная обработка для 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({
|
updates.push({
|
||||||
fieldname: fieldname,
|
fieldname: fieldname,
|
||||||
newValue: newValue.trim(),
|
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 || '',
|
oldValue: oldValue || '',
|
||||||
label: label
|
label: label
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Helper function to format date from YYYYMMDD to YYYY-MM-DD
|
// Helper function to format date from YYYYMMDD to YYYY-MM-DD
|
||||||
function formatDate(dateStr) {
|
function formatDate(dateStr) {
|
||||||
|
|
@ -579,6 +599,7 @@ window.ETaxesCompany = {
|
||||||
return `${year}-${month}-${day}`;
|
return `${year}-${month}-${day}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BASIC COMPANY INFORMATION
|
||||||
// Tax ID mapping (TIN)
|
// Tax ID mapping (TIN)
|
||||||
if (profile.tin) {
|
if (profile.tin) {
|
||||||
addUpdate('tax_id', profile.tin, __('Tax ID'), frm.doc.tax_id);
|
addUpdate('tax_id', profile.tin, __('Tax ID'), frm.doc.tax_id);
|
||||||
|
|
@ -589,10 +610,22 @@ window.ETaxesCompany = {
|
||||||
addUpdate('registration_details', profile.stateRegistrationDocumentNumber, __('Registration Details'), frm.doc.registration_details);
|
addUpdate('registration_details', profile.stateRegistrationDocumentNumber, __('Registration Details'), frm.doc.registration_details);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Phone mapping
|
// Phone mapping - prefer mobile over landline
|
||||||
const phoneNumber = ETaxesCompany._extractPhoneNumber(profile);
|
const mobilePhone = profile.mobilePhoneNumber || ETaxesCompany._extractPhoneNumber(profile, 'mobile');
|
||||||
if (phoneNumber) {
|
const landlinePhone = profile.landlinePhoneNumber || ETaxesCompany._extractPhoneNumber(profile, 'landline');
|
||||||
addUpdate('phone_no', phoneNumber, __('Phone'), frm.doc.phone_no);
|
|
||||||
|
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
|
// Email mapping
|
||||||
|
|
@ -606,19 +639,41 @@ window.ETaxesCompany = {
|
||||||
addUpdate('date_of_establishment', regDate, __('Date of Establishment'), frm.doc.date_of_establishment);
|
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)
|
// Domain mapping (if available)
|
||||||
if (profile.mainActivity) {
|
if (profile.mainActivity) {
|
||||||
addUpdate('domain', profile.mainActivity, __('Domain'), frm.doc.domain);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
// Main Activity mapping (custom field)
|
// Director PIN
|
||||||
|
if (profile.pin) {
|
||||||
|
addUpdate('director_pin', profile.pin, __('Director PIN'), frm.doc.director_pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
// BUSINESS ACTIVITIES
|
||||||
|
// Main Activity mapping
|
||||||
if (profile.mainActivity) {
|
if (profile.mainActivity) {
|
||||||
addUpdate('main_activity', profile.mainActivity, __('Main Activity'), frm.doc.main_activity);
|
addUpdate('main_activity', profile.mainActivity, __('Main Activity'), frm.doc.main_activity);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Taxation System mapping (custom field)
|
// 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) {
|
if (profile.taxRate) {
|
||||||
let taxationSystem = '';
|
let taxationSystem = '';
|
||||||
if (profile.taxRate === 'ƏDV' || profile.taxRate === 'VAT' || profile.taxRate === '18%') {
|
if (profile.taxRate === 'ƏDV' || profile.taxRate === 'VAT' || profile.taxRate === '18%') {
|
||||||
|
|
@ -626,16 +681,15 @@ window.ETaxesCompany = {
|
||||||
} else if (profile.taxRate === '0%' || profile.taxRate === 'ƏDV 0%') {
|
} else if (profile.taxRate === '0%' || profile.taxRate === 'ƏDV 0%') {
|
||||||
taxationSystem = '0% Value-added tax';
|
taxationSystem = '0% Value-added tax';
|
||||||
} else {
|
} else {
|
||||||
taxationSystem = profile.taxRate; // Если не распознали, используем как есть
|
taxationSystem = profile.taxRate;
|
||||||
}
|
}
|
||||||
addUpdate('taxation_system', taxationSystem, __('Taxation System'), frm.doc.taxation_system);
|
addUpdate('taxation_system', taxationSystem, __('Taxation System'), frm.doc.taxation_system);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Business Classification mapping (custom field)
|
// Business Classification mapping
|
||||||
if (profile.criteriaOfBusinessEntity) {
|
if (profile.criteriaOfBusinessEntity) {
|
||||||
let businessClassification = '';
|
let businessClassification = '';
|
||||||
|
|
||||||
// Преобразование значений E-Taxes в правильные названия
|
|
||||||
switch (profile.criteriaOfBusinessEntity.toLowerCase()) {
|
switch (profile.criteriaOfBusinessEntity.toLowerCase()) {
|
||||||
case 'micro':
|
case 'micro':
|
||||||
businessClassification = 'Micro Entrepreneur';
|
businessClassification = 'Micro Entrepreneur';
|
||||||
|
|
@ -652,15 +706,12 @@ window.ETaxesCompany = {
|
||||||
businessClassification = 'Big Entrepreneur';
|
businessClassification = 'Big Entrepreneur';
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// Если не распознали, используем исходное значение с добавлением " Entrepreneur"
|
|
||||||
businessClassification = profile.criteriaOfBusinessEntity + ' Entrepreneur';
|
businessClassification = profile.criteriaOfBusinessEntity + ' Entrepreneur';
|
||||||
}
|
}
|
||||||
|
|
||||||
addUpdate('business_classification', businessClassification, __('Business Classification'), frm.doc.business_classification);
|
addUpdate('business_classification', businessClassification, __('Business Classification'), frm.doc.business_classification);
|
||||||
}
|
}
|
||||||
|
|
||||||
// НОВЫЕ ПОЛЯ - добавляем пока коды, названия будут обновлены асинхронно
|
|
||||||
|
|
||||||
// State Registration Authority
|
// State Registration Authority
|
||||||
if (profile.stateRegistrationName) {
|
if (profile.stateRegistrationName) {
|
||||||
addUpdate('state_registration_authority', profile.stateRegistrationName, __('State Registration Authority'), frm.doc.state_registration_authority);
|
addUpdate('state_registration_authority', profile.stateRegistrationName, __('State Registration Authority'), frm.doc.state_registration_authority);
|
||||||
|
|
@ -671,9 +722,49 @@ window.ETaxesCompany = {
|
||||||
addUpdate('taxpayer_activity_group', profile.activityGroup, __('Taxpayer Activity Group'), frm.doc.taxpayer_activity_group);
|
addUpdate('taxpayer_activity_group', profile.activityGroup, __('Taxpayer Activity Group'), frm.doc.taxpayer_activity_group);
|
||||||
}
|
}
|
||||||
|
|
||||||
// VAT ПОЛЯ
|
// 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') {
|
if (profile.vatInfo && typeof profile.vatInfo === 'object') {
|
||||||
// VAT Registration Date (prOperationTableOperationDate)
|
// VAT Registration Date
|
||||||
if (profile.vatInfo.prOperationTableOperationDate) {
|
if (profile.vatInfo.prOperationTableOperationDate) {
|
||||||
const vatRegDate = formatDate(profile.vatInfo.prOperationTableOperationDate);
|
const vatRegDate = formatDate(profile.vatInfo.prOperationTableOperationDate);
|
||||||
if (vatRegDate) {
|
if (vatRegDate) {
|
||||||
|
|
@ -681,12 +772,12 @@ window.ETaxesCompany = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// VAT Certificate Number (recDocumentDocumentNumber)
|
// VAT Certificate Number
|
||||||
if (profile.vatInfo.recDocumentDocumentNumber) {
|
if (profile.vatInfo.recDocumentDocumentNumber) {
|
||||||
addUpdate('vat_certificate_number', profile.vatInfo.recDocumentDocumentNumber, __('VAT Certificate Number'), frm.doc.vat_certificate_number);
|
addUpdate('vat_certificate_number', profile.vatInfo.recDocumentDocumentNumber, __('VAT Certificate Number'), frm.doc.vat_certificate_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
// VAT Certificate Date (prVatOperationsRegDate)
|
// VAT Certificate Date
|
||||||
if (profile.vatInfo.prVatOperationsRegDate) {
|
if (profile.vatInfo.prVatOperationsRegDate) {
|
||||||
const vatCertDate = formatDate(profile.vatInfo.prVatOperationsRegDate);
|
const vatCertDate = formatDate(profile.vatInfo.prVatOperationsRegDate);
|
||||||
if (vatCertDate) {
|
if (vatCertDate) {
|
||||||
|
|
@ -695,15 +786,95 @@ window.ETaxesCompany = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ОРГАНИЗАЦИОННАЯ СТРУКТУРА
|
// ORGANIZATIONAL STRUCTURE
|
||||||
|
// Parent Organization
|
||||||
// Parent Organization (из headOrganizationName)
|
|
||||||
if (profile.headOrganizationName && Array.isArray(profile.headOrganizationName) && profile.headOrganizationName.length > 0) {
|
if (profile.headOrganizationName && Array.isArray(profile.headOrganizationName) && profile.headOrganizationName.length > 0) {
|
||||||
// Берем первую головную организацию или объединяем через запятую
|
|
||||||
const parentOrgText = profile.headOrganizationName.join(', ');
|
const parentOrgText = profile.headOrganizationName.join(', ');
|
||||||
addUpdate('parent_organization', parentOrgText, __('Parent Organization'), frm.doc.parent_organization);
|
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;
|
return updates;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -726,24 +897,28 @@ window.ETaxesCompany = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* ИСПРАВЛЕННАЯ ВЕРСИЯ: Обновляем Additional Activity Types из additionalActivityCodes
|
|
||||||
* с проверкой существования в Main type of activity
|
|
||||||
*/
|
|
||||||
_updateAdditionalActivities: function(profile, frm) {
|
_updateAdditionalActivities: function(profile, frm) {
|
||||||
if (profile.additionalActivityCodes && Array.isArray(profile.additionalActivityCodes) && profile.additionalActivityCodes.length > 0) {
|
if (profile.additionalActivityCodes && Array.isArray(profile.additionalActivityCodes) && profile.additionalActivityCodes.length > 0) {
|
||||||
// Очищаем существующие записи в табличной части Additional Activity Types
|
// ВАЖНО: Не очищаем таблицу сразу, а работаем с существующими данными
|
||||||
frm.clear_table('additional_activity_types');
|
const existingActivities = frm.doc.additional_activity_types || [];
|
||||||
|
const existingCodes = existingActivities.map(row => row.activity_type);
|
||||||
|
|
||||||
let addedCount = 0;
|
let addedCount = 0;
|
||||||
let skippedCount = 0;
|
let skippedCount = 0;
|
||||||
let processedCount = 0;
|
let duplicateCount = 0;
|
||||||
|
|
||||||
// Функция для проверки и добавления одного кода активности
|
// Функция для проверки и добавления одного кода активности
|
||||||
function processActivityCode(activityCode, callback) {
|
function processActivityCode(activityCode, callback) {
|
||||||
if (activityCode && activityCode.trim()) {
|
if (activityCode && activityCode.trim()) {
|
||||||
const trimmedCode = activityCode.trim();
|
const trimmedCode = activityCode.trim();
|
||||||
|
|
||||||
|
// Проверяем, не добавлен ли уже этот код
|
||||||
|
if (existingCodes.includes(trimmedCode)) {
|
||||||
|
duplicateCount++;
|
||||||
|
if (callback) callback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Проверяем существование записи Main type of activity перед добавлением
|
// Проверяем существование записи Main type of activity перед добавлением
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: 'frappe.client.get_value',
|
method: 'frappe.client.get_value',
|
||||||
|
|
@ -753,8 +928,6 @@ window.ETaxesCompany = {
|
||||||
filters: {name: trimmedCode}
|
filters: {name: trimmedCode}
|
||||||
},
|
},
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
processedCount++;
|
|
||||||
|
|
||||||
if (r.message && r.message.name) {
|
if (r.message && r.message.name) {
|
||||||
// Запись существует - добавляем
|
// Запись существует - добавляем
|
||||||
let row = frm.add_child('additional_activity_types');
|
let row = frm.add_child('additional_activity_types');
|
||||||
|
|
@ -765,17 +938,14 @@ window.ETaxesCompany = {
|
||||||
skippedCount++;
|
skippedCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Вызываем callback когда обработка завершена
|
|
||||||
if (callback) callback();
|
if (callback) callback();
|
||||||
},
|
},
|
||||||
error: function() {
|
error: function() {
|
||||||
processedCount++;
|
|
||||||
skippedCount++;
|
skippedCount++;
|
||||||
if (callback) callback();
|
if (callback) callback();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
processedCount++;
|
|
||||||
skippedCount++;
|
skippedCount++;
|
||||||
if (callback) callback();
|
if (callback) callback();
|
||||||
}
|
}
|
||||||
|
|
@ -784,7 +954,7 @@ window.ETaxesCompany = {
|
||||||
// Функция для последовательной обработки всех кодов
|
// Функция для последовательной обработки всех кодов
|
||||||
function processAllCodes(codes, index = 0) {
|
function processAllCodes(codes, index = 0) {
|
||||||
if (index >= codes.length) {
|
if (index >= codes.length) {
|
||||||
// Все коды обработаны - обновляем UI и показываем результат
|
// Все коды обработаны - обновляем UI
|
||||||
frm.refresh_field('additional_activity_types');
|
frm.refresh_field('additional_activity_types');
|
||||||
|
|
||||||
let message = '';
|
let message = '';
|
||||||
|
|
@ -793,10 +963,19 @@ window.ETaxesCompany = {
|
||||||
if (skippedCount > 0) {
|
if (skippedCount > 0) {
|
||||||
message += __(', skipped {0} (not found)', [skippedCount]);
|
message += __(', skipped {0} (not found)', [skippedCount]);
|
||||||
}
|
}
|
||||||
|
if (duplicateCount > 0) {
|
||||||
|
message += __(', {0} already existed', [duplicateCount]);
|
||||||
|
}
|
||||||
frappe.show_alert({
|
frappe.show_alert({
|
||||||
message: message,
|
message: message,
|
||||||
indicator: 'green'
|
indicator: 'green'
|
||||||
}, 4);
|
}, 4);
|
||||||
|
} else if (duplicateCount > 0) {
|
||||||
|
message = __('All {0} activities already exist', [duplicateCount]);
|
||||||
|
frappe.show_alert({
|
||||||
|
message: message,
|
||||||
|
indicator: 'blue'
|
||||||
|
}, 4);
|
||||||
} else {
|
} else {
|
||||||
message = __('No valid additional activities found');
|
message = __('No valid additional activities found');
|
||||||
if (skippedCount > 0) {
|
if (skippedCount > 0) {
|
||||||
|
|
@ -828,139 +1007,198 @@ window.ETaxesCompany = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* ОБНОВЛЕННАЯ ФУНКЦИЯ: Обновляем дочерние организации из affiliatesNames
|
|
||||||
*/
|
|
||||||
_updateAffiliateOrganizations: function(profile, frm) {
|
_updateAffiliateOrganizations: function(profile, frm) {
|
||||||
if (profile.affiliatesNames && Array.isArray(profile.affiliatesNames) && profile.affiliatesNames.length > 0) {
|
// Проверяем наличие дочерних организаций
|
||||||
// Очищаем существующие записи
|
const hasAffiliateNames = profile.affiliatesNames && Array.isArray(profile.affiliatesNames) && profile.affiliatesNames.length > 0;
|
||||||
|
const hasAffiliateTins = profile.affiliatesTins && Array.isArray(profile.affiliatesTins) && profile.affiliatesTins.length > 0;
|
||||||
|
|
||||||
|
if (hasAffiliateNames || hasAffiliateTins) {
|
||||||
|
// Очищаем существующие записи в табличной части
|
||||||
frm.clear_table('affiliate_organizations');
|
frm.clear_table('affiliate_organizations');
|
||||||
|
|
||||||
let addedCount = 0;
|
let addedCount = 0;
|
||||||
|
let skippedCount = 0;
|
||||||
|
|
||||||
// Добавляем каждую дочернюю организацию из affiliatesNames
|
// Определяем максимальную длину массивов
|
||||||
profile.affiliatesNames.forEach(function(orgName, index) {
|
const maxLength = Math.max(
|
||||||
if (orgName && orgName.trim()) {
|
hasAffiliateNames ? profile.affiliatesNames.length : 0,
|
||||||
|
hasAffiliateTins ? profile.affiliatesTins.length : 0
|
||||||
|
);
|
||||||
|
|
||||||
|
// Обрабатываем каждую организацию
|
||||||
|
for (let i = 0; i < maxLength; i++) {
|
||||||
|
// Получаем имя организации
|
||||||
|
let orgName = '';
|
||||||
|
if (hasAffiliateNames && profile.affiliatesNames[i]) {
|
||||||
|
orgName = profile.affiliatesNames[i].trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получаем TIN организации
|
||||||
|
let orgTin = '';
|
||||||
|
if (hasAffiliateTins && profile.affiliatesTins[i]) {
|
||||||
|
orgTin = profile.affiliatesTins[i].trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Добавляем строку только если есть хотя бы имя или TIN
|
||||||
|
if (orgName || orgTin) {
|
||||||
let row = frm.add_child('affiliate_organizations');
|
let row = frm.add_child('affiliate_organizations');
|
||||||
|
|
||||||
// Имя заполняем из массива affiliatesNames
|
// Заполняем имя организации
|
||||||
row.organization_name = orgName.trim();
|
if (orgName) {
|
||||||
|
row.organization_name = orgName;
|
||||||
|
} else {
|
||||||
|
// Если нет имени, но есть TIN, используем TIN как имя
|
||||||
|
row.organization_name = `Organization (TIN: ${orgTin})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Заполняем TIN если есть
|
||||||
|
if (orgTin) {
|
||||||
|
row.organization_tin = orgTin;
|
||||||
|
}
|
||||||
|
|
||||||
addedCount++;
|
addedCount++;
|
||||||
|
|
||||||
|
// Логируем для отладки
|
||||||
|
console.log(`Added affiliate organization: ${row.organization_name} (TIN: ${row.organization_tin || 'N/A'})`);
|
||||||
|
} else {
|
||||||
|
skippedCount++;
|
||||||
|
console.log(`Skipped empty affiliate organization at index ${i}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
// Обновляем отображение табличной части
|
// Обновляем отображение табличной части
|
||||||
frm.refresh_field('affiliate_organizations');
|
frm.refresh_field('affiliate_organizations');
|
||||||
|
|
||||||
|
// Показываем результат
|
||||||
if (addedCount > 0) {
|
if (addedCount > 0) {
|
||||||
|
let message = __('Added {0} affiliate organization(s)', [addedCount]);
|
||||||
|
if (skippedCount > 0) {
|
||||||
|
message += __(', skipped {0} empty record(s)', [skippedCount]);
|
||||||
|
}
|
||||||
|
|
||||||
frappe.show_alert({
|
frappe.show_alert({
|
||||||
message: __('Added {0} affiliate organizations', [addedCount]),
|
message: message,
|
||||||
indicator: 'green'
|
indicator: 'green'
|
||||||
|
}, 4);
|
||||||
|
|
||||||
|
// Дополнительное логирование
|
||||||
|
console.log(`Affiliate organizations update completed: ${addedCount} added, ${skippedCount} skipped`);
|
||||||
|
} else {
|
||||||
|
frappe.show_alert({
|
||||||
|
message: __('No valid affiliate organizations found to add'),
|
||||||
|
indicator: 'orange'
|
||||||
}, 3);
|
}, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Очищаем таблицу если нет дочерних организаций
|
// Нет дочерних организаций - очищаем таблицу
|
||||||
|
if (frm.doc.affiliate_organizations && frm.doc.affiliate_organizations.length > 0) {
|
||||||
frm.clear_table('affiliate_organizations');
|
frm.clear_table('affiliate_organizations');
|
||||||
frm.refresh_field('affiliate_organizations');
|
frm.refresh_field('affiliate_organizations');
|
||||||
|
|
||||||
|
frappe.show_alert({
|
||||||
|
message: __('Cleared affiliate organizations (none found in E-Taxes)'),
|
||||||
|
indicator: 'blue'
|
||||||
|
}, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('No affiliate organizations found in profile data');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Дополнительная проверка консистентности данных
|
||||||
|
if (hasAffiliateNames && hasAffiliateTins) {
|
||||||
|
if (profile.affiliatesNames.length !== profile.affiliatesTins.length) {
|
||||||
|
console.warn(`Warning: Mismatch in affiliate data - ${profile.affiliatesNames.length} names vs ${profile.affiliatesTins.length} TINs`);
|
||||||
|
|
||||||
|
// Можно показать предупреждение пользователю
|
||||||
|
frappe.show_alert({
|
||||||
|
message: __('Warning: Number of affiliate names and TINs do not match'),
|
||||||
|
indicator: 'yellow'
|
||||||
|
}, 5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Update company fields from profile data with automatic parsing
|
|
||||||
* ОБНОВЛЕННАЯ ВЕРСИЯ: с новыми полями и справочниками
|
|
||||||
*/
|
|
||||||
updateCompanyFromProfile: function(profileData, frm) {
|
updateCompanyFromProfile: function(profileData, frm) {
|
||||||
try {
|
try {
|
||||||
const profile = profileData.profile || profileData;
|
const profile = profileData.profile || profileData;
|
||||||
const updates = ETaxesCompany._parseProfileData(profile, frm);
|
const updates = ETaxesCompany._parseProfileData(profile, frm);
|
||||||
|
|
||||||
if (updates.length > 0) {
|
|
||||||
// Show confirmation with list of changes
|
|
||||||
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>';
|
|
||||||
|
|
||||||
// Добавляем информацию о дополнительных данных
|
|
||||||
let additionalInfo = '';
|
|
||||||
if (profile.additionalActivityCodes && profile.additionalActivityCodes.length > 0) {
|
|
||||||
additionalInfo += `<br><strong>${__('Additional activities to be added')}:</strong> ${profile.additionalActivityCodes.length} ${__('activities')}`;
|
|
||||||
}
|
|
||||||
if (profile.affiliatesNames && profile.affiliatesNames.length > 0) {
|
|
||||||
additionalInfo += `<br><strong>${__('Affiliate organizations to be added')}:</strong> ${profile.affiliatesNames.length} ${__('organizations')}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
frappe.confirm(
|
|
||||||
__('The following company fields will be updated with data from E-Taxes:') +
|
|
||||||
'<br><br>' + changesList + additionalInfo +
|
|
||||||
'<br>' + __('Continue?'),
|
|
||||||
function() {
|
|
||||||
// Apply all updates
|
|
||||||
updates.forEach(update => {
|
|
||||||
frm.set_value(update.fieldname, update.newValue);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Обновляем дополнительные активности
|
|
||||||
ETaxesCompany._updateAdditionalActivities(profile, frm);
|
|
||||||
|
|
||||||
// Обновляем дочерние организации
|
|
||||||
ETaxesCompany._updateAffiliateOrganizations(profile, frm);
|
|
||||||
|
|
||||||
// НОВОЕ: Обновляем поля из справочников
|
|
||||||
ETaxesCompany._updateDictionaryFields(profile, frm);
|
|
||||||
|
|
||||||
frappe.show_alert({
|
|
||||||
message: __('Company data updated from E-Taxes profile ({0} fields)', [updates.length]),
|
|
||||||
indicator: 'green'
|
|
||||||
}, 5);
|
|
||||||
|
|
||||||
// Сохраняем изменения
|
|
||||||
frm.save();
|
|
||||||
},
|
|
||||||
function() {
|
|
||||||
frappe.show_alert({
|
|
||||||
message: __('Update cancelled'),
|
|
||||||
indicator: 'blue'
|
|
||||||
}, 3);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// Проверяем есть ли дополнительные данные для обновления
|
// Проверяем есть ли дополнительные данные для обновления
|
||||||
const hasAdditionalActivities = profile.additionalActivityCodes && profile.additionalActivityCodes.length > 0;
|
const hasAdditionalActivities = profile.additionalActivityCodes && profile.additionalActivityCodes.length > 0;
|
||||||
const hasAffiliates = profile.affiliatesNames && profile.affiliatesNames.length > 0;
|
const hasAffiliates = profile.affiliatesNames && profile.affiliatesNames.length > 0;
|
||||||
const hasDictionaryFields = profile.taxAuthorityCode || profile.propertyType;
|
const hasDictionaryFields = profile.taxAuthorityCode || profile.propertyType;
|
||||||
|
|
||||||
if (hasAdditionalActivities || hasAffiliates || hasDictionaryFields) {
|
// Если есть обновления полей или дополнительные данные
|
||||||
let updateInfo = __('The following data will be updated:');
|
if (updates.length > 0 || hasAdditionalActivities || hasAffiliates || hasDictionaryFields) {
|
||||||
if (hasAdditionalActivities) {
|
// Формируем сообщение для подтверждения
|
||||||
updateInfo += `<br><strong>${__('Additional activities')}:</strong> ${profile.additionalActivityCodes.length} ${__('activities')}`;
|
let confirmMessage = '';
|
||||||
}
|
|
||||||
if (hasAffiliates) {
|
if (updates.length > 0) {
|
||||||
updateInfo += `<br><strong>${__('Affiliate organizations')}:</strong> ${profile.affiliatesNames.length} ${__('organizations')}`;
|
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;">';
|
||||||
if (hasDictionaryFields) {
|
updates.forEach(update => {
|
||||||
updateInfo += `<br><strong>${__('Dictionary fields')}:</strong> Tax Authority, Property Type`;
|
changesList += `<li><strong>${update.label}:</strong> ${update.oldValue || __('(empty)')} → ${update.newValue}</li>`;
|
||||||
|
});
|
||||||
|
changesList += '</ul>';
|
||||||
|
confirmMessage += changesList;
|
||||||
}
|
}
|
||||||
|
|
||||||
frappe.confirm(
|
// Добавляем информацию о дополнительных данных
|
||||||
updateInfo + '<br><br>' + __('Continue?'),
|
let additionalInfo = '';
|
||||||
function() {
|
|
||||||
if (hasAdditionalActivities) {
|
if (hasAdditionalActivities) {
|
||||||
ETaxesCompany._updateAdditionalActivities(profile, frm);
|
additionalInfo += `<br><strong>${__('Additional activities to be added')}:</strong> ${profile.additionalActivityCodes.length} ${__('activities')}`;
|
||||||
}
|
}
|
||||||
if (hasAffiliates) {
|
if (hasAffiliates) {
|
||||||
ETaxesCompany._updateAffiliateOrganizations(profile, frm);
|
additionalInfo += `<br><strong>${__('Affiliate organizations to be added')}:</strong> ${profile.affiliatesNames.length} ${__('organizations')}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!confirmMessage && additionalInfo) {
|
||||||
|
confirmMessage = __('The following data will be updated:');
|
||||||
|
}
|
||||||
|
|
||||||
|
confirmMessage += additionalInfo;
|
||||||
|
confirmMessage += '<br>' + __('Continue?');
|
||||||
|
|
||||||
|
frappe.confirm(
|
||||||
|
confirmMessage,
|
||||||
|
function() {
|
||||||
|
// ВАЖНО: Отключаем автосохранение перед массовыми изменениями
|
||||||
|
frm.disable_save();
|
||||||
|
|
||||||
|
// Apply all field updates
|
||||||
|
updates.forEach(update => {
|
||||||
|
frm.set_value(update.fieldname, update.newValue);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Обновляем поля из справочников
|
||||||
if (hasDictionaryFields) {
|
if (hasDictionaryFields) {
|
||||||
ETaxesCompany._updateDictionaryFields(profile, frm);
|
ETaxesCompany._updateDictionaryFields(profile, frm);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Автосохранение после добавления данных
|
// Задержка перед обновлением табличных частей
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
frm.save();
|
// Обновляем дополнительные активности
|
||||||
|
if (hasAdditionalActivities) {
|
||||||
|
ETaxesCompany._updateAdditionalActivities(profile, frm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обновляем дочерние организации
|
||||||
|
if (hasAffiliates) {
|
||||||
|
ETaxesCompany._updateAffiliateOrganizations(profile, frm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Включаем сохранение обратно и сохраняем
|
||||||
|
setTimeout(function() {
|
||||||
|
frm.enable_save();
|
||||||
|
frm.save('Update', function() {
|
||||||
|
frappe.show_alert({
|
||||||
|
message: __('Company data updated from E-Taxes profile'),
|
||||||
|
indicator: 'green'
|
||||||
|
}, 5);
|
||||||
|
});
|
||||||
}, 500);
|
}, 500);
|
||||||
|
}, 300);
|
||||||
},
|
},
|
||||||
function() {
|
function() {
|
||||||
frappe.show_alert({
|
frappe.show_alert({
|
||||||
|
|
@ -975,7 +1213,6 @@ window.ETaxesCompany = {
|
||||||
indicator: 'blue'
|
indicator: 'blue'
|
||||||
}, 3);
|
}, 3);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Error parsing profile data:', e);
|
console.error('Error parsing profile data:', e);
|
||||||
|
|
@ -989,7 +1226,15 @@ window.ETaxesCompany = {
|
||||||
/**
|
/**
|
||||||
* Extract best phone number from profile
|
* Extract best phone number from profile
|
||||||
*/
|
*/
|
||||||
_extractPhoneNumber: function(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
|
// Priority: mobile > landline > contacts mobile > contacts home
|
||||||
if (profile.mobilePhoneNumber) {
|
if (profile.mobilePhoneNumber) {
|
||||||
return profile.mobilePhoneNumber;
|
return profile.mobilePhoneNumber;
|
||||||
|
|
@ -1068,35 +1313,63 @@ window.ETaxesCompany = {
|
||||||
const regDate = moment(profile.taxpayerRegistrationDate).format('DD.MM.YYYY');
|
const regDate = moment(profile.taxpayerRegistrationDate).format('DD.MM.YYYY');
|
||||||
html += `<tr><td><strong>${__('Registration Date')}</strong></td><td class="text-content">${regDate}</td></tr>`;
|
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) {
|
if (profile.taxpayerStatus) {
|
||||||
html += `<tr><td><strong>${__('Status')}</strong></td><td class="text-content">${profile.taxpayerStatus}</td></tr>`;
|
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>';
|
html += '</table></div>';
|
||||||
|
|
||||||
// Contact Information
|
// Contact Information
|
||||||
const phoneNumber = ETaxesCompany._extractPhoneNumber(profile);
|
|
||||||
const address = profile.legalAddress || profile.actualAddress;
|
|
||||||
|
|
||||||
if (phoneNumber || profile.email || address) {
|
|
||||||
html += '<div class="section"><h5>' + __('Contact Information') + '</h5>';
|
html += '<div class="section"><h5>' + __('Contact Information') + '</h5>';
|
||||||
html += '<table class="table table-bordered table-sm profile-table">';
|
html += '<table class="table table-bordered table-sm profile-table">';
|
||||||
|
|
||||||
if (phoneNumber) {
|
if (profile.mobilePhoneNumber) {
|
||||||
html += `<tr><td><strong>${__('Phone')}</strong></td><td class="text-content">${phoneNumber}</td></tr>`;
|
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) {
|
if (profile.email) {
|
||||||
html += `<tr><td><strong>${__('Email')}</strong></td><td class="text-content">${profile.email}</td></tr>`;
|
html += `<tr><td><strong>${__('Email')}</strong></td><td class="text-content">${profile.email}</td></tr>`;
|
||||||
}
|
}
|
||||||
if (address) {
|
if (profile.legalAddress) {
|
||||||
html += `<tr><td><strong>${__('Address')}</strong></td><td class="text-content">${address}</td></tr>`;
|
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>';
|
html += '</table></div>';
|
||||||
}
|
|
||||||
|
|
||||||
// Business Information
|
// Business Information
|
||||||
if (profile.mainActivity || profile.additionalActivityCodes || profile.legalFormCode || profile.criteriaOfBusinessEntity) {
|
|
||||||
html += '<div class="section"><h5>' + __('Business Information') + '</h5>';
|
html += '<div class="section"><h5>' + __('Business Information') + '</h5>';
|
||||||
html += '<table class="table table-bordered table-sm profile-table">';
|
html += '<table class="table table-bordered table-sm profile-table">';
|
||||||
|
|
||||||
|
|
@ -1106,18 +1379,22 @@ window.ETaxesCompany = {
|
||||||
if (profile.additionalActivityCodes && profile.additionalActivityCodes.length > 0) {
|
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>`;
|
html += `<tr><td><strong>${__('Additional Activity Codes')}</strong></td><td class="text-content">${profile.additionalActivityCodes.join(', ')}</td></tr>`;
|
||||||
}
|
}
|
||||||
if (profile.legalFormCode) {
|
|
||||||
html += `<tr><td><strong>${__('Legal Form Code')}</strong></td><td class="text-content">${profile.legalFormCode}</td></tr>`;
|
|
||||||
}
|
|
||||||
if (profile.criteriaOfBusinessEntity) {
|
if (profile.criteriaOfBusinessEntity) {
|
||||||
html += `<tr><td><strong>${__('Business Entity Criteria')}</strong></td><td class="text-content">${profile.criteriaOfBusinessEntity}</td></tr>`;
|
html += `<tr><td><strong>${__('Business Entity Criteria')}</strong></td><td class="text-content">${profile.criteriaOfBusinessEntity}</td></tr>`;
|
||||||
}
|
}
|
||||||
|
if (profile.activityGroup) {
|
||||||
html += '</table></div>';
|
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
|
// Tax Information
|
||||||
if (profile.taxRate || profile.vatInfo || profile.specialTaxRegime !== undefined || profile.taxAuthorityCode || profile.propertyType) {
|
|
||||||
html += '<div class="section"><h5>' + __('Tax Information') + '</h5>';
|
html += '<div class="section"><h5>' + __('Tax Information') + '</h5>';
|
||||||
html += '<table class="table table-bordered table-sm profile-table">';
|
html += '<table class="table table-bordered table-sm profile-table">';
|
||||||
|
|
||||||
|
|
@ -1133,29 +1410,47 @@ window.ETaxesCompany = {
|
||||||
if (profile.propertyType) {
|
if (profile.propertyType) {
|
||||||
html += `<tr><td><strong>${__('Property Type')}</strong></td><td class="text-content">${profile.propertyType}</td></tr>`;
|
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) {
|
if (profile.vatInfo) {
|
||||||
const formattedVat = ETaxesCompany._formatVatInfo(profile.vatInfo);
|
const formattedVat = ETaxesCompany._formatVatInfo(profile.vatInfo);
|
||||||
html += `<tr><td><strong>${__('VAT Info')}</strong></td><td class="text-content">${formattedVat}</td></tr>`;
|
html += `<tr><td><strong>${__('VAT Info')}</strong></td><td class="text-content">${formattedVat}</td></tr>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
html += '</table></div>';
|
html += '</table></div>';
|
||||||
}
|
|
||||||
|
|
||||||
// Organizational Structure
|
// Organizational Structure
|
||||||
if (profile.affiliatesNames) {
|
|
||||||
html += '<div class="section"><h5>' + __('Organizational Structure') + '</h5>';
|
html += '<div class="section"><h5>' + __('Organizational Structure') + '</h5>';
|
||||||
html += '<table class="table table-bordered table-sm profile-table">';
|
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) {
|
if (profile.affiliatesNames && profile.affiliatesNames.length > 0) {
|
||||||
const affiliatesText = profile.affiliatesNames.join(', ');
|
const affiliatesText = profile.affiliatesNames.join(', ');
|
||||||
html += `<tr><td><strong>${__('Affiliate Organizations')}</strong></td><td class="text-content">${affiliatesText}</td></tr>`;
|
html += `<tr><td><strong>${__('Affiliate Organizations')}</strong></td><td class="text-content">${affiliatesText}</td></tr>`;
|
||||||
}
|
}
|
||||||
|
if (profile.affiliatesTins && profile.affiliatesTins.length > 0) {
|
||||||
html += '</table></div>';
|
const affiliatesTinsText = profile.affiliatesTins.join(', ');
|
||||||
|
html += `<tr><td><strong>${__('Affiliate Organizations TINs')}</strong></td><td class="text-content">${affiliatesTinsText}</td></tr>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Director Information
|
html += '</table></div>';
|
||||||
if (profile.companyDirectorName || profile.chief) {
|
|
||||||
|
// Management Information
|
||||||
html += '<div class="section"><h5>' + __('Management Information') + '</h5>';
|
html += '<div class="section"><h5>' + __('Management Information') + '</h5>';
|
||||||
html += '<table class="table table-bordered table-sm profile-table">';
|
html += '<table class="table table-bordered table-sm profile-table">';
|
||||||
|
|
||||||
|
|
@ -1171,11 +1466,72 @@ window.ETaxesCompany = {
|
||||||
html += `<tr><td><strong>${__('Chief PIN')}</strong></td><td class="text-content">${profile.chief.pin}</td></tr>`;
|
html += `<tr><td><strong>${__('Chief PIN')}</strong></td><td class="text-content">${profile.chief.pin}</td></tr>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (profile.employeeData && profile.employeeData.employeeCount) {
|
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 += `<tr><td><strong>${__('Employee Count')}</strong></td><td class="text-content">${profile.employeeData.employeeCount}</td></tr>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
html += '</table></div>';
|
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) {
|
} catch (e) {
|
||||||
|
|
@ -1184,7 +1540,7 @@ window.ETaxesCompany = {
|
||||||
|
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
|
|
||||||
// CSS с нормальным переносом строк
|
// CSS остается тем же
|
||||||
html = `
|
html = `
|
||||||
<style>
|
<style>
|
||||||
.etaxes-profile-info {
|
.etaxes-profile-info {
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,21 @@
|
||||||
{
|
{
|
||||||
"actions": [],
|
"actions": [],
|
||||||
"creation": "2025-06-05 14:25:30.955525",
|
"creation": "2025-06-16 21:29:11.777085",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
"field_order": [
|
"field_order": [
|
||||||
"section_break_t7i9"
|
"section_break_twaq"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"fieldname": "section_break_t7i9",
|
"fieldname": "section_break_twaq",
|
||||||
"fieldtype": "Section Break"
|
"fieldtype": "Section Break"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"in_create": 1,
|
"in_create": 1,
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2025-06-05 14:34:53.228349",
|
"modified": "2025-06-16 21:29:44.750246",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Taxes Az",
|
"module": "Taxes Az",
|
||||||
"name": "Business Classification",
|
"name": "Business Classification",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"allow_rename": 1,
|
||||||
|
"creation": "2025-06-16 17:05:37.052445",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"activity_type"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "activity_type",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Activity Type",
|
||||||
|
"options": "Main type of activity",
|
||||||
|
"reqd": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
|
"istable": 1,
|
||||||
|
"links": [],
|
||||||
|
"modified": "2025-06-16 17:05:37.052445",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Taxes Az",
|
||||||
|
"name": "Company Additional Activity",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"permissions": [],
|
||||||
|
"sort_field": "creation",
|
||||||
|
"sort_order": "DESC",
|
||||||
|
"states": []
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Copyright (c) 2025, Jey Soft and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
# import frappe
|
||||||
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
|
||||||
|
class CompanyAdditionalActivity(Document):
|
||||||
|
pass
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"allow_rename": 1,
|
||||||
|
"creation": "2025-06-16 17:05:37.121462",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"organization_name",
|
||||||
|
"organization_tin"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"columns": 8,
|
||||||
|
"fieldname": "organization_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Organization Name",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"columns": 4,
|
||||||
|
"fieldname": "organization_tin",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Organization TIN"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
|
"istable": 1,
|
||||||
|
"links": [],
|
||||||
|
"modified": "2025-06-18 12:00:00.000000",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Taxes Az",
|
||||||
|
"name": "Company Affiliate Organization",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"permissions": [],
|
||||||
|
"sort_field": "creation",
|
||||||
|
"sort_order": "DESC",
|
||||||
|
"states": []
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Copyright (c) 2025, Jey Soft and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
# import frappe
|
||||||
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
|
||||||
|
class CompanyAffiliateOrganization(Document):
|
||||||
|
pass
|
||||||
|
|
@ -0,0 +1,90 @@
|
||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"allow_rename": 1,
|
||||||
|
"creation": "2025-06-16 17:05:37.233923",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"object_name",
|
||||||
|
"object_code",
|
||||||
|
"object_address",
|
||||||
|
"main_area",
|
||||||
|
"additional_area",
|
||||||
|
"activity_classification",
|
||||||
|
"main_activity_code",
|
||||||
|
"total_employees",
|
||||||
|
"temporary_employees"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "object_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Object Name",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "object_code",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Object Code",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "object_address",
|
||||||
|
"fieldtype": "Text",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Object Address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "main_area",
|
||||||
|
"fieldtype": "Float",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Main Area (sq.m)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "additional_area",
|
||||||
|
"fieldtype": "Float",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Additional Area (sq.m)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "activity_classification",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Activity Classification",
|
||||||
|
"options": "P\u0259rak\u0259nd\u0259 ticar\u0259t\nTopdan ticar\u0259t\n\u0130ctimai ia\u015f\u0259\nEmaledici s\u0259naye\nTikinti\nXidm\u0259t\nDig\u0259r"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "main_activity_code",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Main Activity Code"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "total_employees",
|
||||||
|
"fieldtype": "Int",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Total Employees"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "temporary_employees",
|
||||||
|
"fieldtype": "Int",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Temporary Employees"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
|
"istable": 1,
|
||||||
|
"links": [],
|
||||||
|
"modified": "2025-06-16 17:05:37.233923",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Taxes Az",
|
||||||
|
"name": "Company Business Object",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"permissions": [],
|
||||||
|
"sort_field": "creation",
|
||||||
|
"sort_order": "DESC",
|
||||||
|
"states": []
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Copyright (c) 2025, Jey Soft and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
# import frappe
|
||||||
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
|
||||||
|
class CompanyBusinessObject(Document):
|
||||||
|
pass
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"allow_rename": 1,
|
||||||
|
"creation": "2025-06-16 17:05:37.403337",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"certificate_type",
|
||||||
|
"entity_name",
|
||||||
|
"entity_voen",
|
||||||
|
"certificate_series",
|
||||||
|
"certificate_number",
|
||||||
|
"service_value"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "certificate_type",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Certificate Type",
|
||||||
|
"options": "Issued\nReceived",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "entity_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Entity Name",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "entity_voen",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Entity V\u00d6EN",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "certificate_series",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Certificate Series",
|
||||||
|
"length": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "certificate_number",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Certificate Number"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Only for received certificates",
|
||||||
|
"fieldname": "service_value",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Service Value"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
|
"istable": 1,
|
||||||
|
"links": [],
|
||||||
|
"modified": "2025-06-16 17:05:37.403337",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Taxes Az",
|
||||||
|
"name": "Company Certificate Data",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"permissions": [],
|
||||||
|
"sort_field": "creation",
|
||||||
|
"sort_order": "DESC",
|
||||||
|
"states": []
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Copyright (c) 2025, Jey Soft and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
# import frappe
|
||||||
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
|
||||||
|
class CompanyCertificateData(Document):
|
||||||
|
pass
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"allow_rename": 1,
|
||||||
|
"creation": "2025-06-16 17:05:37.524930",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"non_resident_name",
|
||||||
|
"country_of_residence",
|
||||||
|
"service_description",
|
||||||
|
"service_period",
|
||||||
|
"foreign_voen",
|
||||||
|
"payment_document_number",
|
||||||
|
"payment_date",
|
||||||
|
"amount_without_vat",
|
||||||
|
"vat_amount"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "non_resident_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Non-Resident Name",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "country_of_residence",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Country of Residence",
|
||||||
|
"options": "T\u00fcrkiy\u0259\nRusiya\nG\u00fcrc\u00fcstan\nAlmaniya\n\u0130ngilt\u0259r\u0259\nAB\u015e\nDig\u0259r",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "service_description",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Service Description",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "service_period",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Service Period"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "foreign_voen",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Foreign V\u00d6EN"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "payment_document_number",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Payment Document Number"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "payment_date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Payment Date"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "amount_without_vat",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Amount Without VAT",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "vat_amount",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "VAT Amount",
|
||||||
|
"read_only": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
|
"istable": 1,
|
||||||
|
"links": [],
|
||||||
|
"modified": "2025-06-16 17:05:37.524930",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Taxes Az",
|
||||||
|
"name": "Company Non Resident Service",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"permissions": [],
|
||||||
|
"sort_field": "creation",
|
||||||
|
"sort_order": "DESC",
|
||||||
|
"states": []
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Copyright (c) 2025, Jey Soft and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
# import frappe
|
||||||
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
|
||||||
|
class CompanyNonResidentService(Document):
|
||||||
|
pass
|
||||||
|
|
@ -1,33 +1,424 @@
|
||||||
// Код для экспорта XML
|
|
||||||
frappe.ui.form.on('Declaration of value added tax', {
|
frappe.ui.form.on('Declaration of value added tax', {
|
||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
frm.add_custom_button(__('Export XML'), function() {
|
// Добавляем кнопку автозаполнения
|
||||||
frappe.call({
|
if (!frm.is_new() && frm.doc.docstatus === 0) {
|
||||||
method: 'taxes_az.taxes_az.doctype.xml_mapping_tool.xml_mapping_tool.generate_xml',
|
frm.add_custom_button(__('Avtomatik Doldur'), function() {
|
||||||
args: {
|
fill_declaration_automatically(frm);
|
||||||
mapping_tool: 'Declaration of value added tax', // Замените на имя вашего документа XML Mapping Tool
|
}, __('Əməliyyatlar'));
|
||||||
doctype: 'Declaration of value added tax', // Замените на имя DocType
|
|
||||||
docname: frm.docname
|
|
||||||
},
|
|
||||||
callback: function(r) {
|
|
||||||
if (r.message) {
|
|
||||||
// Создаем временный элемент для скачивания
|
|
||||||
var element = document.createElement('a');
|
|
||||||
element.setAttribute('href', 'data:text/xml;charset=utf-8,' + encodeURIComponent(r.message));
|
|
||||||
element.setAttribute('download', frm.docname + '.xml');
|
|
||||||
element.style.display = 'none';
|
|
||||||
document.body.appendChild(element);
|
|
||||||
element.click();
|
|
||||||
document.body.removeChild(element);
|
|
||||||
|
|
||||||
frappe.show_alert({
|
// Стилизуем кнопку
|
||||||
message: __('XML file generated and downloaded'),
|
frm.page.set_primary_action(__('Avtomatik Doldur'), function() {
|
||||||
indicator: 'green'
|
fill_declaration_automatically(frm);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Добавляем кнопку проверки
|
||||||
|
if (!frm.is_new()) {
|
||||||
|
frm.add_custom_button(__('Yoxla'), function() {
|
||||||
|
validate_declaration(frm);
|
||||||
|
}, __('Əməliyyatlar'));
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}, __('Actions'));
|
// Скрываем/показываем вкладки в зависимости от данных
|
||||||
|
toggle_tabs_visibility(frm);
|
||||||
|
},
|
||||||
|
|
||||||
|
onload: function(frm) {
|
||||||
|
// Устанавливаем значения по умолчанию
|
||||||
|
if (frm.is_new()) {
|
||||||
|
set_default_values(frm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Настраиваем фильтры для полей
|
||||||
|
setup_field_filters(frm);
|
||||||
|
},
|
||||||
|
|
||||||
|
rüb: function(frm) {
|
||||||
|
// При изменении квартала обновляем период
|
||||||
|
update_period_display(frm);
|
||||||
|
},
|
||||||
|
|
||||||
|
il: function(frm) {
|
||||||
|
// При изменении года обновляем период
|
||||||
|
update_period_display(frm);
|
||||||
|
},
|
||||||
|
|
||||||
|
bəyan_ediləcək_məlumatım_yoxdur: function(frm) {
|
||||||
|
// Если отмечено "нет данных для декларирования"
|
||||||
|
if (frm.doc.bəyan_ediləcək_məlumatım_yoxdur) {
|
||||||
|
frappe.confirm(
|
||||||
|
'Bütün məlumatlar silinəcək. Davam etmək istəyirsiniz?',
|
||||||
|
function() {
|
||||||
|
clear_all_tables(frm);
|
||||||
|
},
|
||||||
|
function() {
|
||||||
|
frm.set_value('bəyan_ediləcək_məlumatım_yoxdur', 0);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Функция автоматического заполнения
|
||||||
|
function fill_declaration_automatically(frm) {
|
||||||
|
// Проверяем обязательные поля
|
||||||
|
if (!frm.doc.rüb || !frm.doc.il) {
|
||||||
|
frappe.msgprint({
|
||||||
|
title: __('Xəta'),
|
||||||
|
indicator: 'red',
|
||||||
|
message: __('Zəhmət olmasa rüb və il seçin')
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получаем компанию
|
||||||
|
let company = frm.doc.company || frappe.defaults.get_user_default("Company");
|
||||||
|
|
||||||
|
if (!company) {
|
||||||
|
frappe.msgprint({
|
||||||
|
title: __('Xəta'),
|
||||||
|
indicator: 'red',
|
||||||
|
message: __('Şirkət seçilməyib')
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Показываем индикатор загрузки
|
||||||
|
frappe.show_progress('Doldurulur', 30, 100, 'Məlumatlar yüklənir...');
|
||||||
|
|
||||||
|
// Вызываем серверную функцию
|
||||||
|
frappe.call({
|
||||||
|
method: 'taxes_az.declaration_of_value_added_tax.fill_declaration_of_value_added_tax',
|
||||||
|
args: {
|
||||||
|
declaration_name: frm.doc.name,
|
||||||
|
company: company,
|
||||||
|
quarter: frm.doc.rüb,
|
||||||
|
year: frm.doc.il
|
||||||
|
},
|
||||||
|
callback: function(r) {
|
||||||
|
frappe.hide_progress();
|
||||||
|
|
||||||
|
if (r.message && r.message.status === 'success') {
|
||||||
|
frm.reload_doc();
|
||||||
|
|
||||||
|
// Показываем результат
|
||||||
|
let msg = `
|
||||||
|
<div>
|
||||||
|
<p><strong>Bəyannamə uğurla dolduruldu!</strong></p>
|
||||||
|
<p>Dövriyyə: ${format_currency(r.message.total_turnover)} AZN</p>
|
||||||
|
<p>Hesablanmış ƏDV: ${format_currency(r.message.total_vat)} AZN</p>
|
||||||
|
<p>Əvəzləşdirilən ƏDV: ${format_currency(r.message.offset_vat)} AZN</p>
|
||||||
|
<hr>
|
||||||
|
<p><strong>${r.message.total_vat_payable >= 0 ? 'Büdcəyə ödənilməli' : 'Büdcədən qaytarılmalı'}:
|
||||||
|
${format_currency(Math.abs(r.message.total_vat_payable))} AZN</strong></p>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
frappe.msgprint({
|
||||||
|
title: __('Nəticə'),
|
||||||
|
indicator: 'green',
|
||||||
|
message: msg
|
||||||
|
});
|
||||||
|
|
||||||
|
// Обновляем видимость вкладок
|
||||||
|
toggle_tabs_visibility(frm);
|
||||||
|
} else {
|
||||||
|
frappe.msgprint({
|
||||||
|
title: __('Xəta'),
|
||||||
|
indicator: 'red',
|
||||||
|
message: r.message.message || 'Xəta baş verdi'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(err) {
|
||||||
|
frappe.hide_progress();
|
||||||
|
frappe.msgprint({
|
||||||
|
title: __('Xəta'),
|
||||||
|
indicator: 'red',
|
||||||
|
message: __('Server xətası: ') + err.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Функция проверки декларации
|
||||||
|
function validate_declaration(frm) {
|
||||||
|
let errors = [];
|
||||||
|
let warnings = [];
|
||||||
|
|
||||||
|
// Проверка основных данных
|
||||||
|
if (!frm.doc.vöen) {
|
||||||
|
errors.push('VÖEN doldurulmayıb');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверка таблиц
|
||||||
|
if (!frm.doc.table_qzfk || frm.doc.table_qzfk.length === 0) {
|
||||||
|
errors.push('Hesabat dövriyyəsi cədvəli boşdur');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверка расчетов
|
||||||
|
let total_vat = 0;
|
||||||
|
let offset_vat = 0;
|
||||||
|
|
||||||
|
// Считаем начисленный НДС
|
||||||
|
(frm.doc.table_qzfk || []).forEach(row => {
|
||||||
|
if (row.göstəricilər && row.göstəricilər.startsWith('301')) {
|
||||||
|
total_vat += (row.ədvməbləği || 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Считаем зачетный НДС
|
||||||
|
(frm.doc.table_zvvh || []).forEach(row => {
|
||||||
|
if (row.göstəricilər && row.göstəricilər !== '317. Əməliyyatlar üzrə CƏMİ') {
|
||||||
|
offset_vat += (row.əlavədəyərvergisininməbləği || 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Проверка итоговой строки
|
||||||
|
let has_payable = false;
|
||||||
|
let has_refund = false;
|
||||||
|
|
||||||
|
(frm.doc.table_kyya || []).forEach(row => {
|
||||||
|
if (row.göstəricilər === '326. Büdcəyə ödənilməlidir') {
|
||||||
|
has_payable = true;
|
||||||
|
if (row.ədvməbləği !== (total_vat - offset_vat)) {
|
||||||
|
errors.push('Büdcəyə ödənilməli məbləğ düzgün hesablanmayıb');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (row.göstəricilər === '327. Büdcədən qaytarılır') {
|
||||||
|
has_refund = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (has_payable && has_refund) {
|
||||||
|
errors.push('Həm ödəniş, həm də qaytarma eyni vaxtda ola bilməz');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверка приложений
|
||||||
|
if (frm.doc.table_gpfh && frm.doc.table_gpfh.length > 0) {
|
||||||
|
frm.doc.table_gpfh.forEach((row, idx) => {
|
||||||
|
if (!row.obyektinadı || !row.obyektinünvanı) {
|
||||||
|
warnings.push(`Əlavə 9: Sətir ${idx + 1} - obyekt məlumatları natamamdır`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Показываем результаты
|
||||||
|
show_validation_results(errors, warnings);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Установка значений по умолчанию
|
||||||
|
function set_default_values(frm) {
|
||||||
|
// Текущий квартал
|
||||||
|
let current_month = frappe.datetime.now_date().getMonth() + 1;
|
||||||
|
let current_quarter = Math.ceil(current_month / 3);
|
||||||
|
let quarter_map = {1: '1. Rüb', 2: '2. Rüb', 3: '3. Rüb', 4: '4. Rüb'};
|
||||||
|
|
||||||
|
frm.set_value('rüb', quarter_map[current_quarter]);
|
||||||
|
frm.set_value('il', frappe.datetime.now_date().getFullYear());
|
||||||
|
frm.set_value('vergidövrü', 'Rüblük');
|
||||||
|
frm.set_value('bəyannaməninnövü', 'Cari');
|
||||||
|
|
||||||
|
// Данные компании
|
||||||
|
let company = frappe.defaults.get_user_default("Company");
|
||||||
|
if (company) {
|
||||||
|
frappe.db.get_doc('Company', company).then(doc => {
|
||||||
|
frm.set_value('vöen', doc.tax_id);
|
||||||
|
frm.set_value('ödəyicitipi', doc.taxpayer_type || 'Hüquqi');
|
||||||
|
frm.set_value('vergininödəyicisininqrupu', doc.taxpayer_group);
|
||||||
|
frm.set_value('vergiödəyisininqrupu', doc.tax_payment_group);
|
||||||
|
frm.set_value('vergiorqanı', doc.tax_authority);
|
||||||
|
frm.set_value('valyutanınnövü', 'Azərbaycan manatı');
|
||||||
|
|
||||||
|
// НДС регистрация
|
||||||
|
if (doc.vat_registration_date) {
|
||||||
|
frm.set_value('ədvqeydiyyatınınqüvəyyəminmətarixi',
|
||||||
|
frappe.datetime.str_to_user(doc.vat_registration_date).replace(/-/g, ''));
|
||||||
|
}
|
||||||
|
if (doc.vat_certificate_number) {
|
||||||
|
frm.set_value('ədvbildirişininnsi', doc.vat_certificate_number);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Настройка фильтров
|
||||||
|
function setup_field_filters(frm) {
|
||||||
|
// Фильтр для выбора месяца в зависимости от квартала
|
||||||
|
frm.set_query('ay', function() {
|
||||||
|
let quarter_months = {
|
||||||
|
'1. Rüb': ['Yanvar', 'Fevral', 'Mart'],
|
||||||
|
'2. Rüb': ['Aprel', 'May', 'İyun'],
|
||||||
|
'3. Rüb': ['İyul', 'Avqust', 'Sentyabr'],
|
||||||
|
'4. Rüb': ['Oktyabr', 'Noyabr', 'Dekabr']
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
filters: [
|
||||||
|
['name', 'in', quarter_months[frm.doc.rüb] || []]
|
||||||
|
]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Скрытие/показ вкладок
|
||||||
|
function toggle_tabs_visibility(frm) {
|
||||||
|
// Скрываем все вкладки приложений по умолчанию
|
||||||
|
let all_appendices = [
|
||||||
|
'əlavə_1_tab', 'əlavə_2_tab', 'əlavə_3_tab', 'əlavə_4_tab',
|
||||||
|
'əlavə_5_tab', 'əlavə_6_tab', 'əlavə_7_tab', 'əlavə_8_tab',
|
||||||
|
'əlavə_9_tab', 'əlavə_10_tab'
|
||||||
|
];
|
||||||
|
|
||||||
|
all_appendices.forEach(tab => {
|
||||||
|
frm.toggle_display(tab, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Показываем только заполненные
|
||||||
|
// Приложение 3 - всегда для услуг
|
||||||
|
if (frm.doc.table_kdll && frm.doc.table_kdll.length > 0) {
|
||||||
|
frm.toggle_display('əlavə_3_tab', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Приложение 7 - услуги нерезидентов
|
||||||
|
if (frm.doc.table_vonn && frm.doc.table_vonn.length > 0) {
|
||||||
|
frm.toggle_display('əlavə_7_tab', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Приложение 9 - объекты
|
||||||
|
if (frm.doc.table_gpfh && frm.doc.table_gpfh.length > 0) {
|
||||||
|
frm.toggle_display('əlavə_9_tab', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обновление отображения периода
|
||||||
|
function update_period_display(frm) {
|
||||||
|
if (frm.doc.rüb && frm.doc.il) {
|
||||||
|
let period_text = `${frm.doc.il}-ci il, ${frm.doc.rüb}`;
|
||||||
|
frm.set_intro(period_text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Очистка всех таблиц
|
||||||
|
function clear_all_tables(frm) {
|
||||||
|
let tables = [
|
||||||
|
'table_qzfk', 'table_ufli', 'table_zvvh', 'table_wtjt',
|
||||||
|
'table_kyya', 'table_ftqr', 'table_rsid', 'table_vliw',
|
||||||
|
'table_fdbw', 'table_anob', 'table_kdll', 'table_pycw',
|
||||||
|
'table_hnwx', 'table_bchc', 'table_vonn', 'table_gpfh',
|
||||||
|
'table_bgay', 'table_hnbv', 'table_kmis', 'table_twws'
|
||||||
|
];
|
||||||
|
|
||||||
|
tables.forEach(table => {
|
||||||
|
frm.clear_table(table);
|
||||||
|
});
|
||||||
|
|
||||||
|
frm.refresh_fields();
|
||||||
|
frappe.show_alert({
|
||||||
|
message: __('Bütün cədvəllər təmizləndi'),
|
||||||
|
indicator: 'blue'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Показ результатов валидации
|
||||||
|
function show_validation_results(errors, warnings) {
|
||||||
|
let html = '<div>';
|
||||||
|
|
||||||
|
if (errors.length > 0) {
|
||||||
|
html += '<h4 style="color: red;">Xətalar:</h4><ul>';
|
||||||
|
errors.forEach(err => {
|
||||||
|
html += `<li>${err}</li>`;
|
||||||
|
});
|
||||||
|
html += '</ul>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (warnings.length > 0) {
|
||||||
|
html += '<h4 style="color: orange;">Xəbərdarlıqlar:</h4><ul>';
|
||||||
|
warnings.forEach(warn => {
|
||||||
|
html += `<li>${warn}</li>`;
|
||||||
|
});
|
||||||
|
html += '</ul>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errors.length === 0 && warnings.length === 0) {
|
||||||
|
html += '<p style="color: green;">Heç bir xəta tapılmadı!</p>';
|
||||||
|
}
|
||||||
|
|
||||||
|
html += '</div>';
|
||||||
|
|
||||||
|
frappe.msgprint({
|
||||||
|
title: __('Yoxlama nəticəsi'),
|
||||||
|
indicator: errors.length > 0 ? 'red' : (warnings.length > 0 ? 'orange' : 'green'),
|
||||||
|
message: html
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Форматирование валюты
|
||||||
|
function format_currency(amount) {
|
||||||
|
return frappe.format(amount, {fieldtype: 'Currency', currency: 'AZN'});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Дополнительные обработчики для таблиц
|
||||||
|
frappe.ui.form.on('Declaration of value added tax Hesabat Dovriyye uzre', {
|
||||||
|
ədvməbləği: function(frm, cdt, cdn) {
|
||||||
|
calculate_totals(frm);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
frappe.ui.form.on('Declaration of value added tax Evezlesdirilen', {
|
||||||
|
əlavədəyərvergisininməbləği: function(frm, cdt, cdn) {
|
||||||
|
calculate_totals(frm);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Пересчет итогов
|
||||||
|
function calculate_totals(frm) {
|
||||||
|
let total_vat = 0;
|
||||||
|
let offset_vat = 0;
|
||||||
|
|
||||||
|
// Считаем начисленный НДС
|
||||||
|
(frm.doc.table_qzfk || []).forEach(row => {
|
||||||
|
if (row.göstəricilər && row.göstəricilər.startsWith('301')) {
|
||||||
|
total_vat += (row.ədvməbləği || 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Считаем зачетный НДС
|
||||||
|
(frm.doc.table_zvvh || []).forEach(row => {
|
||||||
|
if (row.göstəricilər && row.göstəricilər !== '317. Əməliyyatlar üzrə CƏMİ') {
|
||||||
|
offset_vat += (row.əlavədəyərvergisininməbləği || 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Обновляем итоговую таблицу
|
||||||
|
let net_vat = total_vat - offset_vat;
|
||||||
|
|
||||||
|
// Очищаем таблицу расчетов
|
||||||
|
frm.clear_table('table_kyya');
|
||||||
|
|
||||||
|
if (net_vat > 0) {
|
||||||
|
frm.add_child('table_kyya', {
|
||||||
|
göstəricilər: '326. Büdcəyə ödənilməlidir',
|
||||||
|
ədvməbləği: net_vat
|
||||||
|
});
|
||||||
|
} else if (net_vat < 0) {
|
||||||
|
frm.add_child('table_kyya', {
|
||||||
|
göstəricilər: '327. Büdcədən qaytarılır',
|
||||||
|
ədvməbləği: Math.abs(net_vat)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
frm.refresh_field('table_kyya');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Горячие клавиши
|
||||||
|
frappe.ui.keys.add_shortcut({
|
||||||
|
shortcut: 'ctrl+shift+f',
|
||||||
|
action: () => {
|
||||||
|
let frm = cur_frm;
|
||||||
|
if (frm && frm.doc.doctype === 'Declaration of value added tax') {
|
||||||
|
fill_declaration_automatically(frm);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
description: __('Avtomatik doldur')
|
||||||
|
});
|
||||||
|
|
@ -1,9 +1,381 @@
|
||||||
# Copyright (c) 2025, Jey Soft and contributors
|
# Copyright (c) 2025, Your Company and contributors
|
||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
# import frappe
|
import frappe
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
from frappe import _
|
||||||
|
from frappe.utils import flt, getdate, add_months, cint
|
||||||
|
from datetime import datetime, date
|
||||||
|
import calendar
|
||||||
|
|
||||||
class Declarationofvalueaddedtax(Document):
|
class Declarationofvalueaddedtax(Document):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
from frappe import _
|
||||||
|
from datetime import datetime, date
|
||||||
|
from dateutil.relativedelta import relativedelta
|
||||||
|
import json
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def fill_vat_declaration(declaration_name, company, quarter, year):
|
||||||
|
"""
|
||||||
|
Автоматическое заполнение НДС декларации для компании разработки ПО
|
||||||
|
"""
|
||||||
|
# Получаем документ декларации
|
||||||
|
doc = frappe.get_doc("Declaration of value added tax", declaration_name)
|
||||||
|
|
||||||
|
# Определяем период (начало и конец квартала)
|
||||||
|
quarter_start, quarter_end = get_quarter_dates(quarter, year)
|
||||||
|
|
||||||
|
# Основные данные компании
|
||||||
|
company_doc = frappe.get_doc("Company", company)
|
||||||
|
|
||||||
|
# 1. ЗАПОЛНЯЕМ ОСНОВНУЮ ЧАСТЬ ДЕКЛАРАЦИИ
|
||||||
|
|
||||||
|
# Получаем доходы от разработки ПО (Sales Invoice)
|
||||||
|
software_income = get_software_development_income(company, quarter_start, quarter_end)
|
||||||
|
|
||||||
|
# Получаем входящий НДС (Purchase Invoice)
|
||||||
|
input_vat = get_input_vat(company, quarter_start, quarter_end)
|
||||||
|
|
||||||
|
# Заполняем основную таблицу "Hesabat dövründəki dövriyyə üzrə"
|
||||||
|
fill_main_turnover_table(doc, software_income, input_vat)
|
||||||
|
|
||||||
|
# 2. ЗАПОЛНЯЕМ ПРИЛОЖЕНИЕ 3 (Əlavə 3)
|
||||||
|
fill_appendix_3(doc, software_income, quarter_start, quarter_end)
|
||||||
|
|
||||||
|
# 3. ЗАПОЛНЯЕМ ПРИЛОЖЕНИЕ 7 (если есть услуги от нерезидентов)
|
||||||
|
non_resident_services = get_non_resident_services(company, quarter_start, quarter_end)
|
||||||
|
if non_resident_services:
|
||||||
|
fill_appendix_7(doc, non_resident_services)
|
||||||
|
|
||||||
|
# 4. ЗАПОЛНЯЕМ ПРИЛОЖЕНИЕ 9 (офисы)
|
||||||
|
fill_appendix_9(doc, company_doc)
|
||||||
|
|
||||||
|
# Сохраняем документ
|
||||||
|
doc.save()
|
||||||
|
frappe.db.commit()
|
||||||
|
|
||||||
|
return {
|
||||||
|
"status": "success",
|
||||||
|
"message": f"НДС декларация заполнена за {quarter} квартал {year} года",
|
||||||
|
"total_vat_payable": calculate_vat_payable(doc)
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_quarter_dates(quarter, year):
|
||||||
|
"""Получаем даты начала и конца квартала"""
|
||||||
|
quarter_map = {
|
||||||
|
"1. Rüb": (1, 3),
|
||||||
|
"2. Rüb": (4, 6),
|
||||||
|
"3. Rüb": (7, 9),
|
||||||
|
"4. Rüb": (10, 12)
|
||||||
|
}
|
||||||
|
|
||||||
|
start_month, end_month = quarter_map[quarter]
|
||||||
|
quarter_start = date(year, start_month, 1)
|
||||||
|
quarter_end = date(year, end_month, 1) + relativedelta(months=1) - relativedelta(days=1)
|
||||||
|
|
||||||
|
return quarter_start, quarter_end
|
||||||
|
|
||||||
|
def get_software_development_income(company, start_date, end_date):
|
||||||
|
"""Получаем доходы от разработки ПО"""
|
||||||
|
# Выбираем все Sales Invoice за период
|
||||||
|
invoices = frappe.db.sql("""
|
||||||
|
SELECT
|
||||||
|
si.name,
|
||||||
|
si.customer,
|
||||||
|
si.total,
|
||||||
|
si.total_taxes_and_charges,
|
||||||
|
si.grand_total,
|
||||||
|
si.posting_date,
|
||||||
|
si.is_pos,
|
||||||
|
si.mode_of_payment
|
||||||
|
FROM `tabSales Invoice` si
|
||||||
|
WHERE si.company = %s
|
||||||
|
AND si.posting_date BETWEEN %s AND %s
|
||||||
|
AND si.docstatus = 1
|
||||||
|
AND si.is_return = 0
|
||||||
|
""", (company, start_date, end_date), as_dict=True)
|
||||||
|
|
||||||
|
# Группируем по типам операций
|
||||||
|
result = {
|
||||||
|
"total_without_vat": 0,
|
||||||
|
"total_vat": 0,
|
||||||
|
"cash_sales": 0,
|
||||||
|
"cashless_sales": 0,
|
||||||
|
"pos_sales": 0,
|
||||||
|
"invoices": invoices
|
||||||
|
}
|
||||||
|
|
||||||
|
for inv in invoices:
|
||||||
|
# Сумма без НДС
|
||||||
|
base_amount = inv.total or 0
|
||||||
|
vat_amount = inv.total_taxes_and_charges or 0
|
||||||
|
|
||||||
|
result["total_without_vat"] += base_amount
|
||||||
|
result["total_vat"] += vat_amount
|
||||||
|
|
||||||
|
# Определяем тип оплаты
|
||||||
|
if inv.is_pos:
|
||||||
|
result["pos_sales"] += base_amount
|
||||||
|
elif inv.mode_of_payment and "cash" in inv.mode_of_payment.lower():
|
||||||
|
result["cash_sales"] += base_amount
|
||||||
|
else:
|
||||||
|
result["cashless_sales"] += base_amount
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def get_input_vat(company, start_date, end_date):
|
||||||
|
"""Получаем входящий НДС"""
|
||||||
|
purchases = frappe.db.sql("""
|
||||||
|
SELECT
|
||||||
|
pi.name,
|
||||||
|
pi.supplier,
|
||||||
|
pi.total,
|
||||||
|
pi.total_taxes_and_charges,
|
||||||
|
pi.grand_total,
|
||||||
|
pi.posting_date,
|
||||||
|
s.supplier_type,
|
||||||
|
s.country
|
||||||
|
FROM `tabPurchase Invoice` pi
|
||||||
|
LEFT JOIN `tabSupplier` s ON pi.supplier = s.name
|
||||||
|
WHERE pi.company = %s
|
||||||
|
AND pi.posting_date BETWEEN %s AND %s
|
||||||
|
AND pi.docstatus = 1
|
||||||
|
AND pi.is_return = 0
|
||||||
|
""", (company, start_date, end_date), as_dict=True)
|
||||||
|
|
||||||
|
result = {
|
||||||
|
"total_without_vat": 0,
|
||||||
|
"total_vat": 0,
|
||||||
|
"resident_purchases": 0,
|
||||||
|
"resident_vat": 0,
|
||||||
|
"non_resident_purchases": 0,
|
||||||
|
"non_resident_vat": 0,
|
||||||
|
"purchases": purchases
|
||||||
|
}
|
||||||
|
|
||||||
|
for pur in purchases:
|
||||||
|
base_amount = pur.total or 0
|
||||||
|
vat_amount = pur.total_taxes_and_charges or 0
|
||||||
|
|
||||||
|
result["total_without_vat"] += base_amount
|
||||||
|
result["total_vat"] += vat_amount
|
||||||
|
|
||||||
|
# Определяем резидент или нет
|
||||||
|
if pur.country and pur.country != "Azerbaijan":
|
||||||
|
result["non_resident_purchases"] += base_amount
|
||||||
|
result["non_resident_vat"] += vat_amount
|
||||||
|
else:
|
||||||
|
result["resident_purchases"] += base_amount
|
||||||
|
result["resident_vat"] += vat_amount
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def fill_main_turnover_table(doc, income_data, input_vat_data):
|
||||||
|
"""Заполняем основную таблицу по обороту"""
|
||||||
|
# Очищаем существующие строки
|
||||||
|
doc.table_qzfk = []
|
||||||
|
|
||||||
|
# 301 - ƏDV-nə 18 faiz dərəcə ilə cəlb olunan əməliyyatlar
|
||||||
|
doc.append("table_qzfk", {
|
||||||
|
"göstəricilər": "301. ƏDV-nə 18 faiz dərəcə ilə cəlb olunan əməliyyatlar",
|
||||||
|
"təqdimedilmişmalişvəxidmətlərindəyəriədvnəzərəalınmadan": 0,
|
||||||
|
"daxilolmuşməbləğədvnəzərəalınmadan": 0,
|
||||||
|
"ədvməbləği": 0
|
||||||
|
})
|
||||||
|
|
||||||
|
# 301.1 - Malların təqdim edilməsi, işlərin görülməsi, xidmətlərin göstərilməsi
|
||||||
|
doc.append("table_qzfk", {
|
||||||
|
"göstəricilər": "301.1 Malların təqdim edilməsi, işlərin görülməsi, xidmətlərin göstərilməsi üzrə əməliyyatlar",
|
||||||
|
"təqdimedilmişmalişvəxidmətlərindəyəriədvnəzərəalınmadan": income_data["total_without_vat"],
|
||||||
|
"daxilolmuşməbləğədvnəzərəalınmadan": income_data["total_without_vat"], # Для услуг обычно равны
|
||||||
|
"ədvməbləği": income_data["total_vat"]
|
||||||
|
})
|
||||||
|
|
||||||
|
# 305 - Əməliyyatlar üzrə CƏMİ
|
||||||
|
total_turnover = income_data["total_without_vat"]
|
||||||
|
total_received = income_data["total_without_vat"]
|
||||||
|
total_vat = income_data["total_vat"]
|
||||||
|
|
||||||
|
doc.append("table_qzfk", {
|
||||||
|
"göstəricilər": "305. Əməliyyatlar üzrə CƏMİ",
|
||||||
|
"təqdimedilmişmalişvəxidmətlərindəyəriədvnəzərəalınmadan": total_turnover,
|
||||||
|
"daxilolmuşməbləğədvnəzərəalınmadan": total_received,
|
||||||
|
"ədvməbləği": total_vat
|
||||||
|
})
|
||||||
|
|
||||||
|
# Заполняем таблицу Əvəzləşdirilən (зачеты)
|
||||||
|
doc.table_zvvh = []
|
||||||
|
|
||||||
|
# 308 - Электронные счета-фактуры
|
||||||
|
if input_vat_data["resident_vat"] > 0:
|
||||||
|
doc.append("table_zvvh", {
|
||||||
|
"göstəricilər": "308. VM 175.1-ci maddəsinə əsasən alınmış elektron qaimə-fakturalar (elektron vergi hesab-fakturalar) üzrə nağdsız qaydada ödənilmiş məbləğ",
|
||||||
|
"ödənilmişməbləğədvnəzərəalınmadan": input_vat_data["resident_purchases"],
|
||||||
|
"əlavədəyərvergisininməbləği": input_vat_data["resident_vat"]
|
||||||
|
})
|
||||||
|
|
||||||
|
# 312 - Платежи нерезидентам (если есть)
|
||||||
|
if input_vat_data["non_resident_vat"] > 0:
|
||||||
|
doc.append("table_zvvh", {
|
||||||
|
"göstəricilər": "312. Vergi Məcəlləsinin 169.4-cü maddəsinə əsasən qeyri-rezidentə ödənilmiş məbləğ",
|
||||||
|
"ödənilmişməbləğədvnəzərəalınmadan": input_vat_data["non_resident_purchases"],
|
||||||
|
"əlavədəyərvergisininməbləği": input_vat_data["non_resident_vat"]
|
||||||
|
})
|
||||||
|
|
||||||
|
# 317 - Итого по зачетам
|
||||||
|
doc.append("table_zvvh", {
|
||||||
|
"göstəricilər": "317. Əməliyyatlar üzrə CƏMİ",
|
||||||
|
"ödənilmişməbləğədvnəzərəalınmadan": input_vat_data["total_without_vat"],
|
||||||
|
"əlavədəyərvergisininməbləği": input_vat_data["total_vat"]
|
||||||
|
})
|
||||||
|
|
||||||
|
# Заполняем Hesablaşmalar (расчеты с бюджетом)
|
||||||
|
doc.table_kyya = []
|
||||||
|
|
||||||
|
vat_payable = total_vat - input_vat_data["total_vat"]
|
||||||
|
|
||||||
|
if vat_payable > 0:
|
||||||
|
# 326 - К уплате в бюджет
|
||||||
|
doc.append("table_kyya", {
|
||||||
|
"göstəricilər": "326. Büdcəyə ödənilməlidir",
|
||||||
|
"ədvməbləği": vat_payable
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
# 327 - К возврату из бюджета
|
||||||
|
doc.append("table_kyya", {
|
||||||
|
"göstəricilər": "327. Büdcədən qaytarılır",
|
||||||
|
"ədvməbləği": abs(vat_payable)
|
||||||
|
})
|
||||||
|
|
||||||
|
def fill_appendix_3(doc, income_data, start_date, end_date):
|
||||||
|
"""Заполняем Приложение 3 - детализация операций"""
|
||||||
|
# Таблица 1 - ƏDV tutulan dövriyyə
|
||||||
|
doc.table_kdll = []
|
||||||
|
|
||||||
|
# 301.1.2.6 - Прочие услуги (разработка ПО)
|
||||||
|
doc.append("table_kdll", {
|
||||||
|
"göstəricilər": "301.1.2.6 Sair işlərin görülməsi və xidmətlərin göstərilməsi üzrə əməliyyatlar",
|
||||||
|
"təqdimedilmişmalişvəxidmətlərindəyəriədvnəzərəalınmadan": income_data["total_without_vat"],
|
||||||
|
"daxilolmuşməbləğədvnəzərəalınmadan": income_data["total_without_vat"]
|
||||||
|
})
|
||||||
|
|
||||||
|
def fill_appendix_7(doc, non_resident_services):
|
||||||
|
"""Заполняем Приложение 7 - услуги нерезидентов"""
|
||||||
|
doc.table_vonn = []
|
||||||
|
|
||||||
|
for service in non_resident_services:
|
||||||
|
doc.append("table_vonn", {
|
||||||
|
"qeyrirezidentinadı": service["supplier_name"],
|
||||||
|
"rezidentolduğuölkəninadı": service["country"],
|
||||||
|
"görülmüşişinxidmətinadı": service["service_description"],
|
||||||
|
"görülmüşişindövrü": service["service_period"],
|
||||||
|
"rezidentolduğuölkədəkivöeni": service["foreign_tax_id"],
|
||||||
|
"büdcəyəödənişitəsdiqtəsdiqedənsənədinnsi": service["payment_doc_no"],
|
||||||
|
"sənədintarixi": service["payment_date"],
|
||||||
|
"ödənilmişümumiədvsizməbləği": service["amount_without_vat"],
|
||||||
|
"ödənilmişümumiədvməbləği": service["vat_amount"]
|
||||||
|
})
|
||||||
|
|
||||||
|
def fill_appendix_9(doc, company_doc):
|
||||||
|
"""Заполняем Приложение 9 - данные об офисах"""
|
||||||
|
doc.table_gpfh = []
|
||||||
|
|
||||||
|
# Получаем офисы из business_objects компании
|
||||||
|
if company_doc.business_objects:
|
||||||
|
for idx, obj in enumerate(company_doc.business_objects):
|
||||||
|
doc.append("table_gpfh", {
|
||||||
|
"sətrinkodu": idx + 1,
|
||||||
|
"obyektinadı": obj.object_name,
|
||||||
|
"obyektinkodu": obj.object_code,
|
||||||
|
"obyektinünvanı": obj.address,
|
||||||
|
"obyektinəsassahəsikvm": obj.main_area,
|
||||||
|
"obyektinəlavəsahəsikvm": obj.additional_area,
|
||||||
|
"obyektinfəaliyyətsahəsiüzrətəsnifatı": "İXTİSASLI, ELMİ VƏ TEXNİKİ FƏALİYYƏT",
|
||||||
|
"obyektinəsasfəaliyyətnövününkoduvəadı": "J62010 - Kompüter proqramlaşdırma fəaliyyəti",
|
||||||
|
"obyektüzrəişçilərincəmisayı": obj.total_employees,
|
||||||
|
"ocümlədənobyektüzrəmüvəqqətiişçilərinsayı": obj.temporary_employees,
|
||||||
|
"obyektüzrətəqdimedilmişmallarınişlərinxidmətlərindəyərimanatla": obj.turnover,
|
||||||
|
"obyekttəqdimedilmişmallaraəldəedilmişhasilatməbləği": obj.revenue
|
||||||
|
})
|
||||||
|
|
||||||
|
def get_non_resident_services(company, start_date, end_date):
|
||||||
|
"""Получаем услуги от нерезидентов"""
|
||||||
|
# Здесь нужно определить логику получения услуг от нерезидентов
|
||||||
|
# Например, из Purchase Invoice где поставщик - нерезидент
|
||||||
|
|
||||||
|
services = frappe.db.sql("""
|
||||||
|
SELECT
|
||||||
|
pi.name,
|
||||||
|
pi.supplier,
|
||||||
|
s.supplier_name,
|
||||||
|
s.country,
|
||||||
|
pi.total as amount_without_vat,
|
||||||
|
pi.total_taxes_and_charges as vat_amount,
|
||||||
|
pi.posting_date,
|
||||||
|
pi.bill_no
|
||||||
|
FROM `tabPurchase Invoice` pi
|
||||||
|
JOIN `tabSupplier` s ON pi.supplier = s.name
|
||||||
|
WHERE pi.company = %s
|
||||||
|
AND pi.posting_date BETWEEN %s AND %s
|
||||||
|
AND pi.docstatus = 1
|
||||||
|
AND s.country != 'Azerbaijan'
|
||||||
|
AND s.country IS NOT NULL
|
||||||
|
""", (company, start_date, end_date), as_dict=True)
|
||||||
|
|
||||||
|
result = []
|
||||||
|
for service in services:
|
||||||
|
result.append({
|
||||||
|
"supplier_name": service.supplier_name,
|
||||||
|
"country": service.country,
|
||||||
|
"service_description": "IT услуги", # Можно брать из описания в PI
|
||||||
|
"service_period": service.posting_date.strftime("%Y%m"),
|
||||||
|
"foreign_tax_id": "", # Нужно добавить поле в Supplier
|
||||||
|
"payment_doc_no": service.bill_no or service.name,
|
||||||
|
"payment_date": service.posting_date.strftime("%Y%m%d"),
|
||||||
|
"amount_without_vat": service.amount_without_vat,
|
||||||
|
"vat_amount": service.vat_amount or (service.amount_without_vat * 0.18)
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def calculate_vat_payable(doc):
|
||||||
|
"""Рассчитываем НДС к уплате"""
|
||||||
|
# Берем из таблицы Hesablaşmalar
|
||||||
|
for row in doc.table_kyya:
|
||||||
|
if row.göstəricilər == "326. Büdcəyə ödənilməlidir":
|
||||||
|
return row.ədvməbləği
|
||||||
|
elif row.göstəricilər == "327. Büdcədən qaytarılır":
|
||||||
|
return -row.ədvməbləği
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# Функция для вызова из UI
|
||||||
|
@frappe.whitelist()
|
||||||
|
def create_and_fill_vat_declaration(company, quarter, year):
|
||||||
|
"""Создать и заполнить НДС декларацию"""
|
||||||
|
# Создаем новый документ
|
||||||
|
doc = frappe.new_doc("Declaration of value added tax")
|
||||||
|
|
||||||
|
# Базовые поля
|
||||||
|
doc.vergidövrü = "Rüblük"
|
||||||
|
doc.rüb = quarter
|
||||||
|
doc.il = int(year)
|
||||||
|
|
||||||
|
# Данные компании
|
||||||
|
company_doc = frappe.get_doc("Company", company)
|
||||||
|
doc.vöen = company_doc.tax_id
|
||||||
|
doc.adı = company_doc.company_name
|
||||||
|
doc.vergiorqanı = company_doc.tax_authority or "Dövlət Vergi xidmətinin Bakı şəhəri Kiçik Sahibkarlıqla İş üzrə Baş idarəsi"
|
||||||
|
|
||||||
|
# Сохраняем документ
|
||||||
|
doc.insert()
|
||||||
|
|
||||||
|
# Заполняем данными
|
||||||
|
result = fill_vat_declaration(doc.name, company, quarter, year)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"declaration_name": doc.name,
|
||||||
|
"result": result
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue