taxes_az/taxes_az/company_etaxes.py

870 lines
36 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

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

# ======= PYTHON API FUNCTIONS =======
import frappe
import requests
import json
from frappe.utils import nowdate, now, cint, now_datetime, get_datetime
# Список кодов игорной деятельности
GAMBLING_ACTIVITY_CODES = [
'92000',
'9200003',
'9200004',
'9200001',
'9200002',
'9200005'
]
@frappe.whitelist()
def force_update_gambling_fields(company_name, field_updates=None):
"""Форсированное обновление полей игорной деятельности"""
import json
try:
# Парсим JSON если нужно
if isinstance(field_updates, str):
field_updates = json.loads(field_updates) if field_updates else {}
# Проверяем существование компании
if not frappe.db.exists("Company", company_name):
return {"success": False, "message": f"Company {company_name} not found"}
# Получаем текущие данные компании
company = frappe.get_doc("Company", company_name)
# Проверяем что это игорная деятельность
if company.main_activity not in GAMBLING_ACTIVITY_CODES:
return {"success": False, "message": "This operation is only allowed for gambling activities"}
# Получаем текущие значения
current_seller = company.seller or 0
current_organizer = company.organizer or 0
# Применяем новые значения
new_seller = field_updates.get('seller', current_seller)
new_organizer = field_updates.get('organizer', current_organizer)
# Валидация: хотя бы одна галочка должна быть активна
if not new_seller and not new_organizer:
return {
"success": False,
"message": "At least one of Seller or Organizer must be checked for gambling activities"
}
# Белый список разрешенных полей для игорной деятельности
allowed_gambling_fields = ['seller', 'organizer']
# Фильтруем только разрешенные поля
filtered_updates = {
field: value for field, value in field_updates.items()
if field in allowed_gambling_fields
}
if not filtered_updates:
return {"success": False, "message": "No valid gambling fields to update"}
# Выполняем обновление через SQL
set_clauses = []
values = []
for field, value in filtered_updates.items():
set_clauses.append(f"`{field}` = %s")
values.append(cint(value))
if set_clauses:
sql = f"""
UPDATE `tabCompany`
SET {', '.join(set_clauses)}, `modified` = NOW(), `modified_by` = %s
WHERE `name` = %s
"""
values.append(frappe.session.user)
values.append(company_name)
frappe.db.sql(sql, tuple(values))
frappe.db.commit()
# Очищаем кэш
frappe.clear_cache(doctype="Company")
# Логируем изменение
frappe.logger().info(f"Gambling fields updated for company {company_name}: {filtered_updates}")
return {
"success": True,
"message": f"Gambling fields updated successfully",
"updated_fields": filtered_updates
}
except Exception as e:
frappe.log_error(f"Error in force_update_gambling_fields: {str(e)}", "Gambling Fields Update Error")
return {
"success": False,
"message": f"Error updating gambling fields: {str(e)}"
}
@frappe.whitelist()
def validate_gambling_activity(company_name, main_activity=None):
"""Валидация игорной деятельности и автоматическая настройка полей"""
try:
if not frappe.db.exists("Company", company_name):
return {"success": False, "message": f"Company {company_name} not found"}
company = frappe.get_doc("Company", company_name)
# Используем переданный main_activity или текущий
activity_code = main_activity or company.main_activity
if not activity_code:
return {"success": True, "is_gambling": False, "message": "No main activity set"}
is_gambling = activity_code in GAMBLING_ACTIVITY_CODES
updates_needed = {}
if is_gambling:
# Для игорной деятельности
if not company.seller and not company.organizer:
# Автоматически включаем обе галочки
updates_needed['seller'] = 1
updates_needed['organizer'] = 1
else:
# Для негавой деятельности - выключаем галочки
if company.seller or company.organizer:
updates_needed['seller'] = 0
updates_needed['organizer'] = 0
# Применяем изменения если нужно
if updates_needed:
set_clauses = []
values = []
for field, value in updates_needed.items():
set_clauses.append(f"`{field}` = %s")
values.append(cint(value))
sql = f"""
UPDATE `tabCompany`
SET {', '.join(set_clauses)}, `modified` = NOW(), `modified_by` = %s
WHERE `name` = %s
"""
values.append(frappe.session.user)
values.append(company_name)
frappe.db.sql(sql, tuple(values))
frappe.db.commit()
frappe.clear_cache(doctype="Company")
return {
"success": True,
"is_gambling": is_gambling,
"updates_applied": updates_needed,
"message": f"Activity validation completed for {activity_code}"
}
except Exception as e:
frappe.log_error(f"Error in validate_gambling_activity: {str(e)}", "Gambling Activity Validation Error")
return {
"success": False,
"message": f"Error validating gambling activity: {str(e)}"
}
@frappe.whitelist()
def get_company_profile(asan_login_name=None):
"""Получает профиль компании из E-Taxes"""
record_etaxes_activity()
try:
if not asan_login_name:
default_settings = get_default_asan_login()
if not default_settings.get("found", False):
return {"success": False, "message": "No Asan Login settings found."}
asan_login_name = default_settings.get("name")
asan_login = frappe.get_doc("Asan Login", asan_login_name)
if not asan_login.main_token:
return {"success": False, "message": "Main token not found. Please authenticate first."}
if asan_login.auth_status != "Fully Authenticated":
return {"success": False, "message": "Not fully authenticated. Please complete authentication process."}
url = "https://new.e-taxes.gov.az/api/po/profile/public/v2/profile"
headers = {
"Accept": "application/json, text/plain, */*",
"Accept-Language": "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7",
"Cache-Control": "no-cache",
"Pragma": "no-cache",
"x-authorization": f"Bearer {asan_login.main_token}"
}
response = requests.get(url, headers=headers, timeout=15)
if response.status_code == 500:
return {
"error": "server_error",
"message": "E-Taxes service temporarily unavailable. Please try again in a few minutes.",
"status_code": 500
}
if response.status_code == 401:
frappe.db.set_value("Asan Login", asan_login_name, "auth_status", "Not Authenticated")
frappe.db.commit()
return {
"error": "unauthorized",
"message": "Authentication required. Please login again.",
"status_code": 401
}
response.raise_for_status()
profile_data = response.json()
frappe.logger().info(f"Company profile retrieved successfully for {asan_login_name}")
return {
"success": True,
"data": profile_data,
"message": "Company profile retrieved successfully"
}
except requests.exceptions.HTTPError as e:
if e.response.status_code == 401:
return {
"error": "unauthorized",
"message": "Authentication required. Please login again.",
"status_code": 401
}
elif e.response.status_code == 500:
return {
"error": "server_error",
"message": "E-Taxes service temporarily unavailable. Please try again in a few minutes.",
"status_code": 500
}
frappe.log_error(f"HTTP error in get_company_profile: {str(e)}", "Company Profile API Error")
return {
"error": "http_error",
"message": "An error occurred while fetching company profile"
}
except requests.exceptions.RequestException as e:
frappe.log_error(f"Request error in get_company_profile: {str(e)}", "Company Profile API Error")
return {
"error": "network_error",
"message": "Network error occurred. Please check your connection and try again."
}
except Exception as e:
frappe.log_error(f"Unexpected error in get_company_profile: {str(e)}\n{frappe.get_traceback()}", "Company Profile Error")
return {
"error": "unknown_error",
"message": "An unknown error occurred, please try again in a few minutes."
}
@frappe.whitelist()
def get_tax_authorities(asan_login_name=None):
"""Получает справочник налоговых органов из E-Taxes"""
record_etaxes_activity()
try:
if not asan_login_name:
default_settings = get_default_asan_login()
if not default_settings.get("found", False):
return {"success": False, "message": "No Asan Login settings found."}
asan_login_name = default_settings.get("name")
asan_login = frappe.get_doc("Asan Login", asan_login_name)
if not asan_login.main_token:
return {"success": False, "message": "Main token not found. Please authenticate first."}
if asan_login.auth_status != "Fully Authenticated":
return {"success": False, "message": "Not fully authenticated. Please complete authentication process."}
url = "https://new.e-taxes.gov.az/api/po/dictionary/public/v1/taxAuthorities"
headers = {
"Accept": "application/json, text/plain, */*",
"Accept-Language": "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7",
"Cache-Control": "no-cache",
"Pragma": "no-cache",
"x-authorization": f"Bearer {asan_login.main_token}"
}
response = requests.get(url, headers=headers, timeout=15)
if response.status_code == 500:
return {
"error": "server_error",
"message": "E-Taxes service temporarily unavailable. Please try again in a few minutes.",
"status_code": 500
}
if response.status_code == 401:
frappe.db.set_value("Asan Login", asan_login_name, "auth_status", "Not Authenticated")
frappe.db.commit()
return {
"error": "unauthorized",
"message": "Authentication required. Please login again.",
"status_code": 401
}
response.raise_for_status()
tax_authorities_data = response.json()
frappe.logger().info(f"Tax authorities dictionary retrieved successfully for {asan_login_name}")
return {
"success": True,
"data": tax_authorities_data,
"message": "Tax authorities dictionary retrieved successfully"
}
except requests.exceptions.HTTPError as e:
if e.response.status_code == 401:
return {
"error": "unauthorized",
"message": "Authentication required. Please login again.",
"status_code": 401
}
elif e.response.status_code == 500:
return {
"error": "server_error",
"message": "E-Taxes service temporarily unavailable. Please try again in a few minutes.",
"status_code": 500
}
frappe.log_error(f"HTTP error in get_tax_authorities: {str(e)}", "Tax Authorities API Error")
return {
"error": "http_error",
"message": "An error occurred while fetching tax authorities dictionary"
}
except requests.exceptions.RequestException as e:
frappe.log_error(f"Request error in get_tax_authorities: {str(e)}", "Tax Authorities API Error")
return {
"error": "network_error",
"message": "Network error occurred. Please check your connection and try again."
}
except Exception as e:
frappe.log_error(f"Unexpected error in get_tax_authorities: {str(e)}\n{frappe.get_traceback()}", "Tax Authorities Error")
return {
"error": "unknown_error",
"message": "An unknown error occurred, please try again in a few minutes."
}
@frappe.whitelist()
def get_property_types(asan_login_name=None):
"""Получает справочник типов собственности из E-Taxes"""
record_etaxes_activity()
try:
if not asan_login_name:
default_settings = get_default_asan_login()
if not default_settings.get("found", False):
return {"success": False, "message": "No Asan Login settings found."}
asan_login_name = default_settings.get("name")
asan_login = frappe.get_doc("Asan Login", asan_login_name)
if not asan_login.main_token:
return {"success": False, "message": "Main token not found. Please authenticate first."}
if asan_login.auth_status != "Fully Authenticated":
return {"success": False, "message": "Not fully authenticated. Please complete authentication process."}
url = "https://new.e-taxes.gov.az/api/po/profile/public/v1/dictionary/propertyTypes"
headers = {
"Accept": "application/json, text/plain, */*",
"Accept-Language": "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7",
"Cache-Control": "no-cache",
"Pragma": "no-cache",
"x-authorization": f"Bearer {asan_login.main_token}"
}
response = requests.get(url, headers=headers, timeout=15)
if response.status_code == 500:
return {
"error": "server_error",
"message": "E-Taxes service temporarily unavailable. Please try again in a few minutes.",
"status_code": 500
}
if response.status_code == 401:
frappe.db.set_value("Asan Login", asan_login_name, "auth_status", "Not Authenticated")
frappe.db.commit()
return {
"error": "unauthorized",
"message": "Authentication required. Please login again.",
"status_code": 401
}
response.raise_for_status()
property_types_data = response.json()
frappe.logger().info(f"Property types dictionary retrieved successfully for {asan_login_name}")
return {
"success": True,
"data": property_types_data,
"message": "Property types dictionary retrieved successfully"
}
except requests.exceptions.HTTPError as e:
if e.response.status_code == 401:
return {
"error": "unauthorized",
"message": "Authentication required. Please login again.",
"status_code": 401
}
elif e.response.status_code == 500:
return {
"error": "server_error",
"message": "E-Taxes service temporarily unavailable. Please try again in a few minutes.",
"status_code": 500
}
frappe.log_error(f"HTTP error in get_property_types: {str(e)}", "Property Types API Error")
return {
"error": "http_error",
"message": "An error occurred while fetching property types dictionary"
}
except requests.exceptions.RequestException as e:
frappe.log_error(f"Request error in get_property_types: {str(e)}", "Property Types API Error")
return {
"error": "network_error",
"message": "Network error occurred. Please check your connection and try again."
}
except Exception as e:
frappe.log_error(f"Unexpected error in get_property_types: {str(e)}\n{frappe.get_traceback()}", "Property Types Error")
return {
"error": "unknown_error",
"message": "An unknown error occurred, please try again in a few minutes."
}
@frappe.whitelist()
def get_tax_authority_name_by_code(code, asan_login_name=None):
"""Получает название налогового органа по коду"""
try:
tax_authorities_result = get_tax_authorities(asan_login_name)
if not tax_authorities_result.get("success"):
return {
"success": False,
"message": tax_authorities_result.get("message", "Failed to get tax authorities dictionary")
}
tax_authorities = tax_authorities_result.get("data", [])
if tax_authorities and isinstance(tax_authorities, list):
for authority in tax_authorities:
if authority.get("code") == code:
name = authority.get("name", {})
if isinstance(name, dict) and name.get("az"):
return {
"success": True,
"name": name.get("az"),
"code": code
}
elif isinstance(name, str):
return {
"success": True,
"name": name,
"code": code
}
return {
"success": True,
"name": code,
"code": code,
"message": "Tax authority name not found, returning code"
}
except Exception as e:
frappe.log_error(f"Error in get_tax_authority_name_by_code: {str(e)}", "Tax Authority Name Error")
return {
"success": False,
"message": "An error occurred while getting tax authority name"
}
@frappe.whitelist()
def get_property_type_name_by_code(code, asan_login_name=None):
"""Получает название типа собственности по коду"""
try:
property_types_result = get_property_types(asan_login_name)
if not property_types_result.get("success"):
return {
"success": False,
"message": property_types_result.get("message", "Failed to get property types dictionary")
}
property_types = property_types_result.get("data", {})
if property_types and isinstance(property_types, dict):
for property_type in property_types.values():
if isinstance(property_type, dict) and property_type.get("code") == code:
name = property_type.get("name", {})
if isinstance(name, dict) and name.get("az"):
return {
"success": True,
"name": name.get("az"),
"code": code
}
elif isinstance(name, str):
return {
"success": True,
"name": name,
"code": code
}
return {
"success": True,
"name": code,
"code": code,
"message": "Property type name not found, returning code"
}
except Exception as e:
frappe.log_error(f"Error in get_property_type_name_by_code: {str(e)}", "Property Type Name Error")
return {
"success": False,
"message": "An error occurred while getting property type name"
}
@frappe.whitelist()
def force_update_declaration_defaults(company_name, mdss, icbari, issizlik):
"""Обновление полей умолчаний деклараций на компании, минуя проверку submit-статуса"""
try:
if not frappe.db.exists("Company", company_name):
return {"success": False, "message": f"Company {company_name} not found"}
frappe.db.sql("""
UPDATE `tabCompany`
SET `mdssüzrə` = %s,
`icbaritibbisığortaüzrə` = %s,
`işsizlikdənsığortaüzrə` = %s,
`modified` = NOW(),
`modified_by` = %s
WHERE `name` = %s
""", (mdss or '', icbari or '', issizlik or '', frappe.session.user, company_name))
frappe.db.commit()
return {"success": True}
except Exception as e:
frappe.log_error(f"Error in force_update_declaration_defaults: {str(e)}", "Declaration Defaults Error")
return {"success": False, "message": str(e)}
@frappe.whitelist()
def force_update_single_field(company_name, field_name, field_value):
"""Форсированное обновление одного поля компании"""
try:
if not company_name or not field_name:
return {"success": False, "message": "Company name and field name are required"}
if not frappe.db.exists("Company", company_name):
return {"success": False, "message": f"Company {company_name} not found"}
allowed_fields = [
'main_activity', 'tax_id', 'phone_no', 'email',
'director_name_etaxes', 'business_classification',
'tax_authority', 'property_type', 'vat_certificate_number'
]
if field_name not in allowed_fields:
return {"success": False, "message": f"Field {field_name} is not allowed for force update"}
if field_name == 'main_activity' and field_value:
if not frappe.db.exists("Main type of activity", field_value):
return {"success": False, "message": f"Main type of activity {field_value} does not exist"}
frappe.db.sql("""
UPDATE `tabCompany`
SET `{field}` = %s, `modified` = NOW(), `modified_by` = %s
WHERE `name` = %s
""".format(field=field_name), (field_value, frappe.session.user, company_name))
frappe.db.commit()
frappe.clear_cache(doctype="Company")
# Если обновляли main_activity, проверяем игорную деятельность
if field_name == 'main_activity':
validate_gambling_activity(company_name, field_value)
return {
"success": True,
"message": f"Field {field_name} updated successfully"
}
except Exception as e:
frappe.log_error(f"Error in force_update_single_field: {str(e)}", "Force Update Error")
return {
"success": False,
"message": f"Error updating field: {str(e)}"
}
@frappe.whitelist()
def force_update_company(company_name, field_updates=None, additional_activities=None, affiliate_names=None, affiliate_tins=None):
"""Форсированное обновление полей компании через прямые SQL-запросы"""
import json
try:
# Парсим JSON если нужно
if isinstance(field_updates, str):
field_updates = json.loads(field_updates) if field_updates else {}
if isinstance(additional_activities, str):
additional_activities = json.loads(additional_activities) if additional_activities else []
if isinstance(affiliate_names, str):
affiliate_names = json.loads(affiliate_names) if affiliate_names else []
if isinstance(affiliate_tins, str):
affiliate_tins = json.loads(affiliate_tins) if affiliate_tins else []
# Проверяем существование компании
if not frappe.db.exists("Company", company_name):
return {"success": False, "message": f"Company {company_name} not found"}
# Обновляем основные поля через SQL
if field_updates:
set_clauses = []
values = []
for field, value in field_updates.items():
set_clauses.append(f"`{field}` = %s")
values.append(value)
if set_clauses:
sql = f"""
UPDATE `tabCompany`
SET {', '.join(set_clauses)}, `modified` = NOW(), `modified_by` = %s
WHERE `name` = %s
"""
values.append(frappe.session.user)
values.append(company_name)
frappe.db.sql(sql, tuple(values))
# Обработка additional activities
activities_added = 0
if additional_activities and len(additional_activities) > 0:
# ИСПРАВЛЕНО: Правильное имя таблицы
table_name = "Company Additional Activity" # БЕЗ "Types" в конце!
if not frappe.db.table_exists(table_name):
frappe.log_error(f"Table '{table_name}' does not exist", "Table Check Error")
return {"success": False, "message": f"Table '{table_name}' does not exist"}
# Удаляем старые записи
frappe.db.sql(f"""DELETE FROM `tab{table_name}` WHERE parent = %s""", company_name)
# Добавляем новые additional activities
for idx, activity_code in enumerate(additional_activities):
if activity_code and activity_code.strip():
# Проверяем существование activity в справочнике
activity_exists = frappe.db.exists("Main type of activity", activity_code.strip())
if activity_exists:
# Генерируем уникальное имя
record_name = frappe.generate_hash(length=10)
frappe.db.sql(f"""
INSERT INTO `tab{table_name}`
(name, parent, parenttype, parentfield, idx, activity_type, docstatus, creation, modified, modified_by, owner)
VALUES (%s, %s, %s, %s, %s, %s, %s, NOW(), NOW(), %s, %s)
""", (
record_name,
company_name,
'Company',
'additional_activity_types', # fieldname остается тем же
idx + 1,
activity_code.strip(),
0,
frappe.session.user,
frappe.session.user
))
activities_added += 1
frappe.logger().info(f"Added additional activity: {activity_code} for company {company_name}")
else:
frappe.logger().warning(f"Activity code {activity_code} not found in Main type of activity")
# Проверяем, что записи действительно добавились
count = frappe.db.sql(f"""
SELECT COUNT(*) FROM `tab{table_name}`
WHERE parent = %s
""", company_name)[0][0]
frappe.logger().info(f"Total additional activities in DB after update: {count}")
# Обработка affiliate organizations
affiliates_added = 0
if (affiliate_names or affiliate_tins):
# ИСПРАВЛЕНО: Правильное имя таблицы
table_name = "Company Affiliate Organization" # В единственном числе!
if frappe.db.table_exists(table_name):
# Удаляем старые записи
frappe.db.sql(f"""DELETE FROM `tab{table_name}` WHERE parent = %s""", company_name)
# Добавляем новые affiliate organizations
max_length = max(len(affiliate_names or []), len(affiliate_tins or []))
for idx in range(max_length):
org_name = affiliate_names[idx] if affiliate_names and idx < len(affiliate_names) else ""
org_tin = affiliate_tins[idx] if affiliate_tins and idx < len(affiliate_tins) else ""
if org_name or org_tin:
if not org_name and org_tin:
org_name = f"Organization (TIN: {org_tin})"
record_name = frappe.generate_hash(length=10)
frappe.db.sql(f"""
INSERT INTO `tab{table_name}`
(name, parent, parenttype, parentfield, idx, organization_name, organization_tin, docstatus, creation, modified, modified_by, owner)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, NOW(), NOW(), %s, %s)
""", (
record_name,
company_name,
'Company',
'affiliate_organizations', # fieldname остается тем же
idx + 1,
org_name,
org_tin or None,
0,
frappe.session.user,
frappe.session.user
))
affiliates_added += 1
frappe.logger().info(f"Added affiliate organization: {org_name} (TIN: {org_tin}) for company {company_name}")
else:
frappe.logger().error(f"Table '{table_name}' does not exist")
# Коммитим изменения
frappe.db.commit()
# Очищаем весь кэш для компании
frappe.clear_cache(doctype="Company")
frappe.clear_document_cache("Company", company_name)
# Если обновляли main_activity, проверяем игорную деятельность
if field_updates and 'main_activity' in field_updates:
validate_gambling_activity(company_name, field_updates['main_activity'])
# Возвращаем детальную информацию об обновлении
return {
"success": True,
"message": "Company updated successfully",
"updated_fields": len(field_updates) if field_updates else 0,
"additional_activities_added": activities_added,
"affiliates_added": affiliates_added
}
except Exception as e:
frappe.log_error(f"Error in force_update_company: {str(e)}\n{frappe.get_traceback()}", "Company Update Error")
frappe.db.rollback()
return {
"success": False,
"message": f"Error updating company: {str(e)}"
}
# Helper functions
def record_etaxes_activity():
"""Placeholder for activity recording"""
pass
def get_default_asan_login():
"""Получает настройки по умолчанию для Asan Login"""
try:
default_login = frappe.get_list(
"Asan Login",
filters={"is_default": 1},
fields=["name"]
)
if default_login:
asan_login = frappe.get_doc("Asan Login", default_login[0].name)
return {
"found": True,
"name": asan_login.name,
"phone": asan_login.phone,
"user_id": asan_login.user_id,
"auth_status": asan_login.auth_status,
"bearer_token": asan_login.bearer_token,
"main_token": asan_login.main_token,
"selected_certificate": asan_login.selected_certificate
}
else:
return {"found": False, "message": "No Asan Login settings found."}
except Exception as e:
return {"found": False, "error": str(e)}
@frappe.whitelist()
def check_company_structure(company_name):
"""Диагностическая функция для проверки структуры Company"""
try:
company = frappe.get_doc("Company", company_name)
# Проверяем наличие полей
has_additional_activities = hasattr(company, 'additional_activity_types')
has_affiliate_orgs = hasattr(company, 'affiliate_organizations')
# ИСПРАВЛЕНО: Правильные имена таблиц
table1_exists = frappe.db.table_exists("Company Additional Activity")
table2_exists = frappe.db.table_exists("Company Affiliate Organization")
# Получаем текущее количество записей
activities_count = 0
affiliates_count = 0
if table1_exists:
activities_count = frappe.db.sql("""
SELECT COUNT(*) FROM `tabCompany Additional Activity`
WHERE parent = %s
""", company_name)[0][0]
if table2_exists:
affiliates_count = frappe.db.sql("""
SELECT COUNT(*) FROM `tabCompany Affiliate Organization`
WHERE parent = %s
""", company_name)[0][0]
# Получаем метаданные о child tables
meta = frappe.get_meta("Company")
child_tables = []
for field in meta.fields:
if field.fieldtype == "Table":
child_tables.append({
"fieldname": field.fieldname,
"options": field.options,
"label": field.label
})
return {
"success": True,
"has_additional_activities_field": has_additional_activities,
"has_affiliate_orgs_field": has_affiliate_orgs,
"table1_exists": table1_exists,
"table2_exists": table2_exists,
"activities_count_in_db": activities_count,
"affiliates_count_in_db": affiliates_count,
"child_tables": child_tables
}
except Exception as e:
return {
"success": False,
"error": str(e)
}