added new report Fuel Products Purchase Report

This commit is contained in:
Ali 2025-08-15 19:33:50 +04:00
parent 10287dd7e2
commit 537289c230
4 changed files with 413 additions and 0 deletions

View File

@ -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 = `<span style="color: ${color}; font-weight: bold; background-color: ${color}15; padding: 2px 6px; border-radius: 3px;">${value}</span>`;
} else if (value == 0 || !value) {
value = `<span style="color: #ccc;">0</span>`;
}
}
// Подсветка Total Qty
if (column.fieldname == "total_qty" && value) {
let qty = parseFloat(value);
if (qty > 50) {
value = `<span style="color: #dc3545; font-weight: bold;">${value}</span>`;
} else if (qty > 20) {
value = `<span style="color: #ffc107; font-weight: bold;">${value}</span>`;
} else if (qty > 0) {
value = `<span style="color: #28a745; font-weight: bold;">${value}</span>`;
}
}
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 = '<div class="fuel-statistics" style="margin-top: 20px; padding: 20px; background: #f8f9fa; border-radius: 8px; border: 1px solid #dee2e6;">';
stats_html += '<h4 style="margin-bottom: 15px; color: #495057;">📈 Итоговая статистика по периоду:</h4>';
stats_html += '<div class="row">';
stats_html += '<div class="col-md-6">';
stats_html += '<h5>Общее количество по типам:</h5>';
stats_html += `<div style="margin-bottom: 8px;"><span style="color: #28a745;">●</span> Aİ-92: <strong>${totals.ai_92.toFixed(2)}</strong></div>`;
stats_html += `<div style="margin-bottom: 8px;"><span style="color: #007bff;">●</span> Aİ-95: <strong>${totals.ai_95.toFixed(2)}</strong></div>`;
stats_html += `<div style="margin-bottom: 8px;"><span style="color: #6c757d;">●</span> Aİ-80: <strong>${totals.ai_80.toFixed(2)}</strong></div>`;
stats_html += `<div style="margin-bottom: 8px;"><span style="color: #fd7e14;">●</span> Dizel: <strong>${totals.dizel.toFixed(2)}</strong></div>`;
stats_html += `<div style="margin-bottom: 8px;"><span style="color: #e83e8c;">●</span> Maye qaz: <strong>${totals.maye_qaz.toFixed(2)}</strong></div>`;
stats_html += '</div>';
stats_html += '<div class="col-md-6">';
stats_html += '<h5>Количество документов:</h5>';
stats_html += `<div style="margin-bottom: 8px;">Всего документов: <strong>${totals.total_docs}</strong></div>`;
stats_html += `<div style="margin-bottom: 8px;">С Aİ-92: <strong>${totals.docs_with_ai92}</strong></div>`;
stats_html += `<div style="margin-bottom: 8px;">С Aİ-95: <strong>${totals.docs_with_ai95}</strong></div>`;
stats_html += `<div style="margin-bottom: 8px;">С Aİ-80: <strong>${totals.docs_with_ai80}</strong></div>`;
stats_html += `<div style="margin-bottom: 8px;">С Dizel: <strong>${totals.docs_with_dizel}</strong></div>`;
stats_html += `<div style="margin-bottom: 8px;">С Maye qaz: <strong>${totals.docs_with_maye_qaz}</strong></div>`;
stats_html += '</div>';
stats_html += '</div>';
stats_html += `<div style="margin-top: 15px; padding-top: 15px; border-top: 1px solid #dee2e6;">`;
stats_html += `<strong>🔥 Общее количество топлива: ${totals.total.toFixed(2)}</strong>`;
stats_html += `</div>`;
stats_html += '</div>';
// Удаляем предыдущую статистику если есть
$('.fuel-statistics').remove();
// Добавляем новую статистику
$(stats_html).insertAfter('.datatable');
}
}

View File

@ -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
}

View File

@ -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
}
]