From 537289c23086746ef877bce7416b27774122c63a Mon Sep 17 00:00:00 2001
From: Ali <010109ali@gmail.com>
Date: Fri, 15 Aug 2025 19:33:50 +0400
Subject: [PATCH] added new report Fuel Products Purchase Report
---
.../fuel_products_purchase_report/__init__.py | 0
.../fuel_products_purchase_report.js | 190 ++++++++++++++++++
.../fuel_products_purchase_report.json | 36 ++++
.../fuel_products_purchase_report.py | 187 +++++++++++++++++
4 files changed, 413 insertions(+)
create mode 100644 taxes_az/taxes_az/report/fuel_products_purchase_report/__init__.py
create mode 100644 taxes_az/taxes_az/report/fuel_products_purchase_report/fuel_products_purchase_report.js
create mode 100644 taxes_az/taxes_az/report/fuel_products_purchase_report/fuel_products_purchase_report.json
create mode 100644 taxes_az/taxes_az/report/fuel_products_purchase_report/fuel_products_purchase_report.py
diff --git a/taxes_az/taxes_az/report/fuel_products_purchase_report/__init__.py b/taxes_az/taxes_az/report/fuel_products_purchase_report/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/taxes_az/taxes_az/report/fuel_products_purchase_report/fuel_products_purchase_report.js b/taxes_az/taxes_az/report/fuel_products_purchase_report/fuel_products_purchase_report.js
new file mode 100644
index 0000000..6e34156
--- /dev/null
+++ b/taxes_az/taxes_az/report/fuel_products_purchase_report/fuel_products_purchase_report.js
@@ -0,0 +1,190 @@
+// Copyright (c) 2024, Your Company and contributors
+// For license information, please see license.txt
+
+frappe.query_reports["Fuel Products Purchase Report"] = {
+ "filters": [
+ {
+ "fieldname": "from_date",
+ "label": __("From Date"),
+ "fieldtype": "Date",
+ "default": frappe.datetime.add_months(frappe.datetime.get_today(), -1),
+ "reqd": 1,
+ "width": "100px"
+ },
+ {
+ "fieldname": "to_date",
+ "label": __("To Date"),
+ "fieldtype": "Date",
+ "default": frappe.datetime.get_today(),
+ "reqd": 1,
+ "width": "100px"
+ }
+ ],
+
+ "formatter": function (value, row, column, data, default_formatter) {
+ value = default_formatter(value, row, column, data);
+
+ // Подсветка колонок с топливом
+ if (["ai_92", "ai_95", "ai_80", "dizel", "maye_qaz"].includes(column.fieldname)) {
+ if (value && parseFloat(value) > 0) {
+ // Разные цвета для разных типов топлива
+ let color = "#28a745"; // зеленый по умолчанию
+
+ switch(column.fieldname) {
+ case "ai_92":
+ color = "#28a745"; // зеленый
+ break;
+ case "ai_95":
+ color = "#007bff"; // синий
+ break;
+ case "ai_80":
+ color = "#6c757d"; // серый
+ break;
+ case "dizel":
+ color = "#fd7e14"; // оранжевый
+ break;
+ case "maye_qaz":
+ color = "#e83e8c"; // розовый
+ break;
+ }
+
+ value = `${value}`;
+ } else if (value == 0 || !value) {
+ value = `0`;
+ }
+ }
+
+ // Подсветка Total Qty
+ if (column.fieldname == "total_qty" && value) {
+ let qty = parseFloat(value);
+ if (qty > 50) {
+ value = `${value}`;
+ } else if (qty > 20) {
+ value = `${value}`;
+ } else if (qty > 0) {
+ value = `${value}`;
+ }
+ }
+
+ return value;
+ },
+
+ "onload": function(report) {
+ // Добавляем кастомные кнопки
+ report.page.add_inner_button(__("Export Summary"), function() {
+ export_fuel_summary(report);
+ });
+
+
+ },
+
+ "after_datatable_render": function(datatable_obj) {
+ // Добавляем итоговую статистику
+ setTimeout(() => {
+ add_fuel_statistics(datatable_obj);
+ }, 500);
+ }
+};
+
+// Функция экспорта сводки
+function export_fuel_summary(report) {
+ let data = report.data;
+ let summary = calculate_totals(data);
+
+ // Создаем CSV с итогами
+ let csv_content = "Metric,Aİ-92,Aİ-95,Aİ-80,Dizel yanacağı,Maye qaz,Total\n";
+ csv_content += `Total Quantity,${summary.ai_92},${summary.ai_95},${summary.ai_80},${summary.dizel},${summary.maye_qaz},${summary.total}\n`;
+ csv_content += `Documents Count,${summary.docs_with_ai92},${summary.docs_with_ai95},${summary.docs_with_ai80},${summary.docs_with_dizel},${summary.docs_with_maye_qaz},${summary.total_docs}\n`;
+
+ // Скачиваем файл
+ let blob = new Blob([csv_content], { type: 'text/csv' });
+ let url = window.URL.createObjectURL(blob);
+ let a = document.createElement('a');
+ a.href = url;
+ a.download = 'fuel_summary_' + frappe.datetime.get_today() + '.csv';
+ document.body.appendChild(a);
+ a.click();
+ document.body.removeChild(a);
+ window.URL.revokeObjectURL(url);
+
+ frappe.show_alert({message: __("Summary exported successfully"), indicator: "green"});
+}
+
+// Функция расчета итогов
+function calculate_totals(data) {
+ let totals = {
+ ai_92: 0,
+ ai_95: 0,
+ ai_80: 0,
+ dizel: 0,
+ maye_qaz: 0,
+ total: 0,
+ docs_with_ai92: 0,
+ docs_with_ai95: 0,
+ docs_with_ai80: 0,
+ docs_with_dizel: 0,
+ docs_with_maye_qaz: 0,
+ total_docs: data.length
+ };
+
+ data.forEach(row => {
+ totals.ai_92 += row.ai_92 || 0;
+ totals.ai_95 += row.ai_95 || 0;
+ totals.ai_80 += row.ai_80 || 0;
+ totals.dizel += row.dizel || 0;
+ totals.maye_qaz += row.maye_qaz || 0;
+ totals.total += row.total_qty || 0;
+
+ // Считаем документы с каждым типом топлива
+ if (row.ai_92 > 0) totals.docs_with_ai92++;
+ if (row.ai_95 > 0) totals.docs_with_ai95++;
+ if (row.ai_80 > 0) totals.docs_with_ai80++;
+ if (row.dizel > 0) totals.docs_with_dizel++;
+ if (row.maye_qaz > 0) totals.docs_with_maye_qaz++;
+ });
+
+ return totals;
+}
+
+// Функция добавления статистики под таблицу
+function add_fuel_statistics(datatable_obj) {
+ if (datatable_obj && datatable_obj.data) {
+ let totals = calculate_totals(datatable_obj.data);
+
+ let stats_html = '
';
+ stats_html += '
📈 Итоговая статистика по периоду:
';
+
+ stats_html += '
';
+ stats_html += '
';
+ stats_html += '
Общее количество по типам:
';
+ stats_html += `
● Aİ-92: ${totals.ai_92.toFixed(2)}
`;
+ stats_html += `
● Aİ-95: ${totals.ai_95.toFixed(2)}
`;
+ stats_html += `
● Aİ-80: ${totals.ai_80.toFixed(2)}
`;
+ stats_html += `
● Dizel: ${totals.dizel.toFixed(2)}
`;
+ stats_html += `
● Maye qaz: ${totals.maye_qaz.toFixed(2)}
`;
+ stats_html += '
';
+
+ stats_html += '
';
+ stats_html += '
Количество документов:
';
+ stats_html += `
Всего документов: ${totals.total_docs}
`;
+ stats_html += `
С Aİ-92: ${totals.docs_with_ai92}
`;
+ stats_html += `
С Aİ-95: ${totals.docs_with_ai95}
`;
+ stats_html += `
С Aİ-80: ${totals.docs_with_ai80}
`;
+ stats_html += `
С Dizel: ${totals.docs_with_dizel}
`;
+ stats_html += `
С Maye qaz: ${totals.docs_with_maye_qaz}
`;
+ stats_html += '
';
+ stats_html += '
';
+
+ stats_html += `
`;
+ stats_html += `🔥 Общее количество топлива: ${totals.total.toFixed(2)}`;
+ stats_html += `
`;
+
+ stats_html += '
';
+
+ // Удаляем предыдущую статистику если есть
+ $('.fuel-statistics').remove();
+
+ // Добавляем новую статистику
+ $(stats_html).insertAfter('.datatable');
+ }
+}
\ No newline at end of file
diff --git a/taxes_az/taxes_az/report/fuel_products_purchase_report/fuel_products_purchase_report.json b/taxes_az/taxes_az/report/fuel_products_purchase_report/fuel_products_purchase_report.json
new file mode 100644
index 0000000..7c18ff4
--- /dev/null
+++ b/taxes_az/taxes_az/report/fuel_products_purchase_report/fuel_products_purchase_report.json
@@ -0,0 +1,36 @@
+{
+ "add_total_row": 0,
+ "columns": [],
+ "creation": "2025-08-15 17:22:57.350629",
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "filters": [],
+ "idx": 0,
+ "is_standard": "Yes",
+ "letterhead": null,
+ "modified": "2025-08-15 17:22:57.350629",
+ "modified_by": "Administrator",
+ "module": "Taxes Az",
+ "name": "Fuel Products Purchase Report",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "Purchase Invoice",
+ "report_name": "Fuel Products Purchase Report",
+ "report_type": "Script Report",
+ "roles": [
+ {
+ "role": "Accounts User"
+ },
+ {
+ "role": "Purchase User"
+ },
+ {
+ "role": "Accounts Manager"
+ },
+ {
+ "role": "Auditor"
+ }
+ ],
+ "timeout": 0
+}
\ No newline at end of file
diff --git a/taxes_az/taxes_az/report/fuel_products_purchase_report/fuel_products_purchase_report.py b/taxes_az/taxes_az/report/fuel_products_purchase_report/fuel_products_purchase_report.py
new file mode 100644
index 0000000..2745617
--- /dev/null
+++ b/taxes_az/taxes_az/report/fuel_products_purchase_report/fuel_products_purchase_report.py
@@ -0,0 +1,187 @@
+# Copyright (c) 2024, Your Company and contributors
+# For license information, please see license.txt
+
+import frappe
+from frappe import _
+
+
+def execute(filters=None):
+ columns = get_columns()
+ data = get_data(filters)
+
+ return columns, data
+
+
+def get_columns():
+ return [
+ {
+ "label": _("Purchase Invoice"),
+ "fieldname": "invoice",
+ "fieldtype": "Link",
+ "options": "Purchase Invoice",
+ "width": 150
+ },
+ {
+ "label": _("Date"),
+ "fieldname": "posting_date",
+ "fieldtype": "Date",
+ "width": 100
+ },
+ {
+ "label": _("Supplier"),
+ "fieldname": "supplier",
+ "fieldtype": "Link",
+ "options": "Supplier",
+ "width": 150
+ },
+ {
+ "label": _("Aİ-92"),
+ "fieldname": "ai_92",
+ "fieldtype": "Float",
+ "width": 80
+ },
+ {
+ "label": _("Aİ-95"),
+ "fieldname": "ai_95",
+ "fieldtype": "Float",
+ "width": 80
+ },
+ {
+ "label": _("Aİ-80"),
+ "fieldname": "ai_80",
+ "fieldtype": "Float",
+ "width": 80
+ },
+ {
+ "label": _("Dizel yanacağı"),
+ "fieldname": "dizel",
+ "fieldtype": "Float",
+ "width": 100
+ },
+ {
+ "label": _("Maye qaz"),
+ "fieldname": "maye_qaz",
+ "fieldtype": "Float",
+ "width": 80
+ },
+ {
+ "label": _("Total Qty"),
+ "fieldname": "total_qty",
+ "fieldtype": "Float",
+ "width": 100
+ }
+ ]
+
+
+def get_data(filters):
+ # Хардкод фильтр на топливные продукты
+ fuel_items = [
+ "Avtomobil benzini (Aİ-92)",
+ "Avtomobil benzini (Aİ-95)",
+ "Avtomobil benzini (Aİ-80)",
+ "Dizel yanacağı",
+ "Maye qaz"
+ ]
+
+ conditions = []
+ values = []
+
+ # Фильтр по датам
+ if filters.get("from_date"):
+ conditions.append("pi.posting_date >= %s")
+ values.append(filters.get("from_date"))
+
+ if filters.get("to_date"):
+ conditions.append("pi.posting_date <= %s")
+ values.append(filters.get("to_date"))
+
+ # Хардкод фильтр по товарам
+ item_condition = "pii.item_name IN ({})".format(", ".join(["%s"] * len(fuel_items)))
+ conditions.append(item_condition)
+ values.extend(fuel_items)
+
+ # Только подтвержденные инвойсы
+ conditions.append("pi.docstatus = 1")
+
+ where_clause = ""
+ if conditions:
+ where_clause = "WHERE " + " AND ".join(conditions)
+
+ # Получаем все данные
+ query = """
+ SELECT
+ pi.name as invoice,
+ pi.posting_date,
+ pi.supplier,
+ pii.item_name,
+ pii.qty
+ FROM
+ `tabPurchase Invoice Item` pii
+ INNER JOIN
+ `tabPurchase Invoice` pi ON pii.parent = pi.name
+ {where_clause}
+ ORDER BY
+ pi.posting_date DESC, pi.name
+ """.format(where_clause=where_clause)
+
+ raw_data = frappe.db.sql(query, values, as_dict=True)
+
+ # Группируем данные по документам
+ invoice_data = {}
+
+ for row in raw_data:
+ invoice = row['invoice']
+
+ if invoice not in invoice_data:
+ invoice_data[invoice] = {
+ 'invoice': invoice,
+ 'posting_date': row['posting_date'],
+ 'supplier': row['supplier'],
+ 'ai_92': 0,
+ 'ai_95': 0,
+ 'ai_80': 0,
+ 'dizel': 0,
+ 'maye_qaz': 0,
+ 'total_qty': 0
+ }
+
+ # Распределяем количество по колонкам
+ item_name = row['item_name']
+ qty = row['qty'] or 0
+
+ if 'Aİ-92' in item_name:
+ invoice_data[invoice]['ai_92'] += qty
+ elif 'Aİ-95' in item_name:
+ invoice_data[invoice]['ai_95'] += qty
+ elif 'Aİ-80' in item_name:
+ invoice_data[invoice]['ai_80'] += qty
+ elif 'Dizel' in item_name:
+ invoice_data[invoice]['dizel'] += qty
+ elif 'Maye qaz' in item_name:
+ invoice_data[invoice]['maye_qaz'] += qty
+
+ invoice_data[invoice]['total_qty'] += qty
+
+ # Конвертируем в список
+ data = list(invoice_data.values())
+
+ return data
+
+
+def get_filters():
+ return [
+ {
+ "fieldname": "from_date",
+ "label": _("From Date"),
+ "fieldtype": "Date",
+ "default": frappe.utils.add_months(frappe.utils.today(), -1),
+ "reqd": 1
+ },
+ {
+ "fieldname": "to_date",
+ "label": _("To Date"),
+ "fieldtype": "Date",
+ "default": frappe.utils.today(),
+ "reqd": 1
+ }
+ ]
\ No newline at end of file