From 9b3f6d73695e1dd1b4ab02840fe5e2beb3e28041 Mon Sep 17 00:00:00 2001 From: Ali <010109ali@gmail.com> Date: Thu, 18 Sep 2025 19:49:03 +0400 Subject: [PATCH] added new gambling report --- .../report/gaming_revenue_report/__init__.py | 0 .../gaming_revenue_report.js | 319 ++++++++++++++++++ .../gaming_revenue_report.json | 33 ++ .../gaming_revenue_report.py | 197 +++++++++++ 4 files changed, 549 insertions(+) create mode 100644 taxes_az/taxes_az/report/gaming_revenue_report/__init__.py create mode 100644 taxes_az/taxes_az/report/gaming_revenue_report/gaming_revenue_report.js create mode 100644 taxes_az/taxes_az/report/gaming_revenue_report/gaming_revenue_report.json create mode 100644 taxes_az/taxes_az/report/gaming_revenue_report/gaming_revenue_report.py diff --git a/taxes_az/taxes_az/report/gaming_revenue_report/__init__.py b/taxes_az/taxes_az/report/gaming_revenue_report/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/taxes_az/taxes_az/report/gaming_revenue_report/gaming_revenue_report.js b/taxes_az/taxes_az/report/gaming_revenue_report/gaming_revenue_report.js new file mode 100644 index 0000000..3c5427b --- /dev/null +++ b/taxes_az/taxes_az/report/gaming_revenue_report/gaming_revenue_report.js @@ -0,0 +1,319 @@ +// Copyright (c) 2024, Your Company and contributors +// For license information, please see license.txt + +frappe.query_reports["Gaming Revenue Report"] = { + "filters": [ + { + "fieldname": "company", + "label": __("Company"), + "fieldtype": "Link", + "options": "Company", + "default": frappe.defaults.get_user_default("Company"), + "reqd": 1, + }, + { + "fieldname": "from_date", + "label": __("From Date"), + "fieldtype": "Date", + "default": frappe.datetime.add_months(frappe.datetime.get_today(), -1), + "reqd": 1, + }, + { + "fieldname": "to_date", + "label": __("To Date"), + "fieldtype": "Date", + "default": frappe.datetime.get_today(), + "reqd": 1, + } + ], + + "formatter": function (value, row, column, data, default_formatter) { + value = default_formatter(value, row, column, data); + + // Подсветка колонок с суммами + if (column.fieldname && (column.fieldname.includes("sports_") || column.fieldname.includes("lottery_"))) { + if (value && parseFloat(value) > 0) { + let color = "#28a745"; // зеленый по умолчанию + let icon = ""; + + if (column.fieldname.includes("sports_organizer")) { + color = "#0d6efd"; // синий для спортивных игр организатор + icon = "🏆"; + } else if (column.fieldname.includes("sports_seller")) { + color = "#17a2b8"; // голубой для спортивных игр продавец + icon = "⚽"; + } else if (column.fieldname.includes("lottery_organizer")) { + color = "#dc3545"; // красный для лотереи организатор + icon = "🎰"; + } else if (column.fieldname.includes("lottery_seller")) { + color = "#fd7e14"; // оранжевый для лотереи продавец + icon = "🎲"; + } + + value = `${icon} ${value}`; + } else if (value == 0 || !value) { + value = `0.00`; + } + } + + // Подсветка Sales Invoice колонки + if (column.fieldname == "sales_invoice" && value) { + value = `📄 ${value}`; + } + + // Подсветка Date колонки + if (column.fieldname == "posting_date" && value) { + value = `📅 ${value}`; + } + + return value; + }, + + "onload": function(report) { + // Добавляем кастомные кнопки + report.page.add_inner_button(__("Export Gaming Summary"), function() { + export_gaming_summary(report); + }); + + report.page.add_inner_button(__("Show Game Types"), function() { + show_game_types_info(); + }); + + // Добавляем информационное сообщение + report.page.add_inner_button(__("About Gaming Activities"), function() { + show_gaming_activities_info(); + }); + }, + + "after_datatable_render": function(datatable_obj) { + // Добавляем итоговую статистику + setTimeout(() => { + add_gaming_statistics(datatable_obj); + }, 500); + } +}; + +// Функция показа информации о игровых активностях +function show_gaming_activities_info() { + let info_html = '
'; + info_html += '

🎮 Oyun Fəaliyyətləri

'; + + info_html += '
'; + info_html += '
'; + info_html += '
🏆 İdman Oyunları:
'; + info_html += '
    '; + info_html += '
  • 92000 - Həvəsləndirici oyunlar
  • '; + info_html += '
  • 9200003 - Oyun avtomatları
  • '; + info_html += '
  • 9200004 - Virtual oyunlar
  • '; + info_html += '
  • 9200002 - Totalizator
  • '; + info_html += '
  • 9200005 - İdman mərc oyunları
  • '; + info_html += '
'; + info_html += '
'; + + info_html += '
'; + info_html += '
🎰 Lotereya Oyunları:
'; + info_html += '
    '; + info_html += '
  • 9200001 Lotereya oyunları
  • '; + info_html += '
'; + info_html += '
'; + info_html += '
👥 Rollər:
'; + info_html += '
    '; + info_html += '
  • Təşkilatçı: Oyunu təşkil edən
  • '; + info_html += '
  • Satıcı: Oyunu satan
  • '; + info_html += '
'; + info_html += '
'; + info_html += '
'; + + info_html += '
'; + + frappe.msgprint({ + title: __("Gaming Activities Information"), + message: info_html, + wide: true + }); +} + +// Функция показа типов игр +function show_game_types_info() { + let info_html = '
'; + info_html += '

🎯 Hesabatda İstifadə Olunan Oyun Tipləri:

'; + info_html += '
'; + + info_html += '
'; + info_html += '
'; + info_html += '
🏆 İdman Oyunları
'; + info_html += '

Təşkilatçı və Satıcı rollarında gəlir

'; + info_html += '
'; + info_html += '
'; + + info_html += '
'; + info_html += '
'; + info_html += '
🎰 Lotereya Oyunları
'; + info_html += '

Təşkilatçı və Satıcı rollarında gəlir

'; + info_html += '
'; + info_html += '
'; + + info_html += '
'; + info_html += '
'; + + frappe.msgprint({ + title: __("Game Types Information"), + message: info_html, + wide: true + }); +} + +// Функция экспорта сводки по игорному бизнесу +function export_gaming_summary(report) { + let data = report.data; + let summary = calculate_gaming_totals(data); + + // Создаем CSV с итогами + let csv_content = "Category,Role,Revenue,Documents Count\n"; + + csv_content += `"İdman Oyunları","Təşkilatçı",${summary.sports_organizer_total},${summary.sports_organizer_count}\n`; + csv_content += `"İdman Oyunları","Satıcı",${summary.sports_seller_total},${summary.sports_seller_count}\n`; + csv_content += `"Lotereya Oyunları","Təşkilatçı",${summary.lottery_organizer_total},${summary.lottery_organizer_count}\n`; + csv_content += `"Lotereya Oyunları","Satıcı",${summary.lottery_seller_total},${summary.lottery_seller_count}\n`; + + // Добавляем общие итоги + csv_content += `\n"CƏMİ","",${summary.grand_total},${summary.total_documents}\n`; + + // Скачиваем файл + let blob = new Blob([csv_content], { type: 'text/csv;charset=utf-8' }); + let url = window.URL.createObjectURL(blob); + let a = document.createElement('a'); + a.href = url; + a.download = 'gaming_revenue_summary_' + frappe.datetime.get_today() + '.csv'; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + window.URL.revokeObjectURL(url); + + frappe.show_alert({message: __("Gaming summary exported successfully"), indicator: "green"}); +} + +// Функция расчета итогов по игорному бизнесу +function calculate_gaming_totals(data) { + let summary = { + sports_organizer_total: 0, + sports_organizer_count: 0, + sports_seller_total: 0, + sports_seller_count: 0, + lottery_organizer_total: 0, + lottery_organizer_count: 0, + lottery_seller_total: 0, + lottery_seller_count: 0, + grand_total: 0, + total_documents: data.length + }; + + data.forEach(row => { + // Спортивные игры + if (row.sports_organizer && row.sports_organizer > 0) { + summary.sports_organizer_total += row.sports_organizer; + summary.sports_organizer_count++; + summary.grand_total += row.sports_organizer; + } + if (row.sports_seller && row.sports_seller > 0) { + summary.sports_seller_total += row.sports_seller; + summary.sports_seller_count++; + summary.grand_total += row.sports_seller; + } + + // Лотерейные игры + if (row.lottery_organizer && row.lottery_organizer > 0) { + summary.lottery_organizer_total += row.lottery_organizer; + summary.lottery_organizer_count++; + summary.grand_total += row.lottery_organizer; + } + if (row.lottery_seller && row.lottery_seller > 0) { + summary.lottery_seller_total += row.lottery_seller; + summary.lottery_seller_count++; + summary.grand_total += row.lottery_seller; + } + }); + + return summary; +} + +// Функция добавления статистики под таблицу +function add_gaming_statistics(datatable_obj) { + if (datatable_obj && datatable_obj.data) { + let summary = calculate_gaming_totals(datatable_obj.data); + + let stats_html = '
'; + stats_html += '

🎮 Oyun Gəlirləri Statistikası:

'; + + // Статистика по спортивным играм + stats_html += '
'; + stats_html += '
'; + stats_html += '
🏆 İdman Oyunları
'; + + stats_html += '
'; + stats_html += '
'; + stats_html += '
'; + stats_html += 'Təşkilatçı
'; + stats_html += `${summary.sports_organizer_total.toFixed(2)}
`; + stats_html += `${summary.sports_organizer_count} sənəd`; + stats_html += '
'; + stats_html += '
'; + + stats_html += '
'; + stats_html += '
'; + stats_html += 'Satıcı
'; + stats_html += `${summary.sports_seller_total.toFixed(2)}
`; + stats_html += `${summary.sports_seller_count} sənəd`; + stats_html += '
'; + stats_html += '
'; + stats_html += '
'; + + stats_html += '
'; + + // Статистика по лотерейным играм + stats_html += '
'; + stats_html += '
🎰 Lotereya Oyunları
'; + + stats_html += '
'; + stats_html += '
'; + stats_html += '
'; + stats_html += 'Təşkilatçı
'; + stats_html += `${summary.lottery_organizer_total.toFixed(2)}
`; + stats_html += `${summary.lottery_organizer_count} sənəd`; + stats_html += '
'; + stats_html += '
'; + + stats_html += '
'; + stats_html += '
'; + stats_html += 'Satıcı
'; + stats_html += `${summary.lottery_seller_total.toFixed(2)}
`; + stats_html += `${summary.lottery_seller_count} sənəd`; + stats_html += '
'; + stats_html += '
'; + stats_html += '
'; + + stats_html += '
'; + stats_html += '
'; + + // Общие итоги + let sports_total = summary.sports_organizer_total + summary.sports_seller_total; + let lottery_total = summary.lottery_organizer_total + summary.lottery_seller_total; + + stats_html += '
'; + stats_html += '
'; + stats_html += `
🏆 İdman Cəmi
${sports_total.toFixed(2)}
`; + stats_html += `
🎰 Lotereya Cəmi
${lottery_total.toFixed(2)}
`; + stats_html += `
💰 Ümumi Gəlir
${summary.grand_total.toFixed(2)}
`; + stats_html += `
📄 Cəmi Sənədlər
${summary.total_documents}
`; + stats_html += '
'; + stats_html += '
'; + + stats_html += '
'; + + // Удаляем предыдущую статистику если есть + $('.gaming-statistics').remove(); + + // Добавляем новую статистику + $(stats_html).insertAfter('.datatable'); + } +} \ No newline at end of file diff --git a/taxes_az/taxes_az/report/gaming_revenue_report/gaming_revenue_report.json b/taxes_az/taxes_az/report/gaming_revenue_report/gaming_revenue_report.json new file mode 100644 index 0000000..899b32a --- /dev/null +++ b/taxes_az/taxes_az/report/gaming_revenue_report/gaming_revenue_report.json @@ -0,0 +1,33 @@ +{ + "add_total_row": 0, + "columns": [], + "creation": "2025-09-18 19:33:16.290750", + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [], + "idx": 0, + "is_standard": "Yes", + "letterhead": null, + "modified": "2025-09-18 19:33:16.290750", + "modified_by": "Administrator", + "module": "Taxes Az", + "name": "Gaming Revenue Report", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Sales Invoice", + "report_name": "Gaming Revenue Report", + "report_type": "Script Report", + "roles": [ + { + "role": "Accounts User" + }, + { + "role": "Accounts Manager" + }, + { + "role": "Employee Self Service" + } + ], + "timeout": 0 +} \ No newline at end of file diff --git a/taxes_az/taxes_az/report/gaming_revenue_report/gaming_revenue_report.py b/taxes_az/taxes_az/report/gaming_revenue_report/gaming_revenue_report.py new file mode 100644 index 0000000..de50060 --- /dev/null +++ b/taxes_az/taxes_az/report/gaming_revenue_report/gaming_revenue_report.py @@ -0,0 +1,197 @@ +# Copyright (c) 2024, Your Company and contributors +# For license information, please see license.txt + +import frappe +from frappe import _ +from frappe.utils import flt, formatdate + + +def execute(filters=None): + columns, data = get_columns(), get_data(filters) + return columns, data + + +def get_data(filters): + """Получаем данные по Sales Invoice для игорного бизнеса""" + + # Получаем Sales Invoice с учетом фильтров + sales_invoices = get_sales_invoices(filters) + + if not sales_invoices: + return [] + + # Получаем информацию о компаниях для определения типа игры + companies_activity = get_companies_main_activity() + + # Формируем итоговые данные + data = [] + + for invoice in sales_invoices: + row = frappe._dict() + + # Основные данные + row.sales_invoice = invoice['name'] + row.posting_date = invoice['posting_date'] + row.company = invoice['company'] + row.grand_total = flt(invoice['grand_total']) + + # Определяем тип игры по main_activity компании + company_activity = companies_activity.get(invoice['company'], '') + game_type = determine_game_type(company_activity) + + # Инициализируем все колонки нулями + row.sports_organizer = 0 + row.sports_seller = 0 + row.lottery_organizer = 0 + row.lottery_seller = 0 + + # Распределяем сумму в зависимости от типа игры и роли + if game_type == 'sports': + if invoice.get('organizer'): + row.sports_organizer = row.grand_total + elif invoice.get('seller'): + row.sports_seller = row.grand_total + elif game_type == 'lottery': + if invoice.get('organizer'): + row.lottery_organizer = row.grand_total + elif invoice.get('seller'): + row.lottery_seller = row.grand_total + + data.append(row) + + return data + + +def get_sales_invoices(filters): + """Получает Sales Invoice с учетом фильтров""" + + conditions = [] + values = [] + + # Фильтр по компании + if filters.get("company"): + conditions.append("si.company = %s") + values.append(filters.get("company")) + + # Фильтр по датам + if filters.get("from_date"): + conditions.append("si.posting_date >= %s") + values.append(filters.get("from_date")) + + if filters.get("to_date"): + conditions.append("si.posting_date <= %s") + values.append(filters.get("to_date")) + + # Только подтвержденные документы + conditions.append("si.docstatus = 1") + + # Только документы с отмеченными галочками organizer или seller + conditions.append("(si.organizer = 1 OR si.seller = 1)") + + where_clause = "" + if conditions: + where_clause = "WHERE " + " AND ".join(conditions) + + query = f""" + SELECT + si.name, + si.posting_date, + si.company, + si.grand_total, + si.organizer, + si.seller + FROM + `tabSales Invoice` si + {where_clause} + ORDER BY + si.posting_date DESC, si.name + """ + + return frappe.db.sql(query, values, as_dict=True) + + +def get_companies_main_activity(): + """Получает main_activity для всех компаний""" + + companies = frappe.db.sql(""" + SELECT name, main_activity + FROM `tabCompany` + WHERE main_activity IS NOT NULL + """, as_dict=True) + + return {company['name']: company['main_activity'] for company in companies} + + +def determine_game_type(main_activity): + """Определяет тип игры на основе main_activity""" + + if not main_activity: + return 'unknown' + + # Коды для спортивных игр + sports_codes = [ + '92000', + '9200003', + '9200004', + '9200002', + '9200005' + ] + + # Код для лотерейных игр + lottery_codes = [ + '9200001' + ] + + # Проверяем на соответствие кодам + for code in sports_codes: + if code in main_activity: + return 'sports' + + for code in lottery_codes: + if code in main_activity: + return 'lottery' + + return 'unknown' + + +def get_columns(): + """Создает колонки отчета""" + return [ + { + "label": "Sales Invoice", + "fieldname": "sales_invoice", + "fieldtype": "Link", + "options": "Sales Invoice", + "width": 150 + }, + { + "label": "Tarix", + "fieldname": "posting_date", + "fieldtype": "Date", + "width": 100 + }, + { + "label": "İdman oyunları - Təşkilatçı", + "fieldname": "sports_organizer", + "fieldtype": "Currency", + "width": 160 + }, + { + "label": "İdman oyunları - Satıcı", + "fieldname": "sports_seller", + "fieldtype": "Currency", + "width": 160 + }, + { + "label": "Lotereya oyunları - Təşkilatçı", + "fieldname": "lottery_organizer", + "fieldtype": "Currency", + "width": 170 + }, + { + "label": "Lotereya oyunları - Satıcı", + "fieldname": "lottery_seller", + "fieldtype": "Currency", + "width": 170 + } + ] \ No newline at end of file