grafik laporan penjualan

This commit is contained in:
Bluwww 2025-12-14 11:28:33 +07:00
parent a2c374242f
commit a645ee5d5b
4 changed files with 137 additions and 1 deletions

BIN
lap/tes3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

BIN
lap/tes4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

BIN
lap/tes5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

138
main.py
View File

@ -3316,7 +3316,14 @@ class App:
text="💾 Export Laporan", text="💾 Export Laporan",
command=self.export_report_to_file, command=self.export_report_to_file,
style="Accent.TButton" style="Accent.TButton"
).grid(row=3, column=0, pady=10) ).grid(row=3, column=0, pady=(10, 5))
ttk.Button(
filter_frame,
text="🖼️ Export Grafik (PNG)",
command=self.export_report_chart,
style="Accent.TButton"
).grid(row=4, column=0, pady=5)
# Summary frame # Summary frame
summary_frame = ttk.LabelFrame(parent, text="📈 Ringkasan", padding=10) summary_frame = ttk.LabelFrame(parent, text="📈 Ringkasan", padding=10)
@ -3851,6 +3858,135 @@ class App:
# Fallback: Tampilkan grafik ASCII sederhana # Fallback: Tampilkan grafik ASCII sederhana
self.show_text_chart() self.show_text_chart()
def export_report_chart(self):
"""Export grafik laporan ke file gambar (PNG) - REVISI FREKUENSI TRANSAKSI"""
try:
import matplotlib.pyplot as plt
from matplotlib.ticker import MaxNLocator # Untuk sumbu Y bilangan bulat
from datetime import datetime
except ImportError:
messagebox.showerror("Error", "Modul 'matplotlib' belum terinstall.\nSilakan install dengan: pip install matplotlib")
return
# 1. Cek Data
if not self.report_tree.get_children():
messagebox.showwarning("Data Kosong", "Generate laporan terlebih dahulu sebelum export grafik.")
return
# Ambil periode saat ini ('harian', 'mingguan', atau 'bulanan')
periode_pilihan = self.report_period_var.get()
# 2. Kumpulkan Data dari Treeview
metode_counts = {}
trend_data = {} # Bisa per jam atau per hari tergantung periode
for item_id in self.report_tree.get_children():
values = self.report_tree.item(item_id)['values']
# Format values: (tid, tanggal, meja, total_str, metode, status)
tanggal_str = values[1] # Format: DD/MM/YYYY HH:MM
metode = values[4]
# Hitung Pie Chart (Metode)
metode_counts[metode] = metode_counts.get(metode, 0) + 1
# Hitung Bar Chart (Trend Transaksi)
try:
dt_obj = datetime.strptime(tanggal_str, "%d/%m/%Y %H:%M")
if periode_pilihan == 'harian':
# Jika Harian: Group by JAM (misal "14:00")
key = dt_obj.strftime("%H:00")
else:
# Jika Mingguan/Bulanan: Group by TANGGAL (misal "2025-12-14")
key = dt_obj.strftime("%Y-%m-%d")
# Kita hitung JUMLAH TRANSAKSI (+1), bukan total uang
trend_data[key] = trend_data.get(key, 0) + 1
except ValueError:
pass
# 3. Buat Figure & Plotting
try:
# Setup layout: 1 Baris, 2 Kolom
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 7))
judul_periode = periode_pilihan.upper()
fig.suptitle(f'LAPORAN TRANSAKSI - {judul_periode}', fontsize=16, fontweight='bold')
# --- PLOT 1: PIE CHART (Metode Pembayaran) ---
if metode_counts:
labels = list(metode_counts.keys())
sizes = list(metode_counts.values())
# Warna-warni pastel agar cantik
colors = ['#ff9999','#66b3ff','#99ff99','#ffcc99', '#c2c2f0']
ax1.pie(sizes, labels=labels, autopct='%1.0f%%', colors=colors[:len(labels)], startangle=90, shadow=True)
ax1.set_title('Proporsi Metode Pembayaran')
else:
ax1.text(0.5, 0.5, "Tidak ada data", ha='center')
# --- PLOT 2: BAR CHART (Trend Frekuensi Transaksi) ---
if trend_data:
keys = sorted(trend_data.keys())
counts = [trend_data[k] for k in keys]
# Label X-Axis (Formatting agar rapi)
if periode_pilihan == 'harian':
# Label jam tetap apa adanya
x_labels = keys
x_title = "Jam Transaksi"
chart_title = "Jumlah Transaksi per Jam (Busy Hours)"
else:
# Format tanggal jadi lebih pendek (DD/MM)
x_labels = [datetime.strptime(k, "%Y-%m-%d").strftime("%d/%m") for k in keys]
x_title = "Tanggal"
chart_title = "Total Transaksi per Hari"
bars = ax2.bar(x_labels, counts, color='#4ECDC4', zorder=3, edgecolor='black', linewidth=0.7)
ax2.set_title(chart_title)
ax2.set_xlabel(x_title)
ax2.set_ylabel('Jumlah Transaksi (Struk)')
# Grid garis putus-putus di belakang
ax2.grid(axis='y', linestyle='--', alpha=0.5, zorder=0)
# Pastikan Sumbu Y hanya menampilkan Angka Bulat (Integer)
# Karena tidak mungkin ada 1.5 transaksi
ax2.yaxis.set_major_locator(MaxNLocator(integer=True))
# Tambah label angka di atas setiap batang
for bar in bars:
height = bar.get_height()
ax2.text(bar.get_x() + bar.get_width()/2., height,
f'{int(height)}',
ha='center', va='bottom', fontsize=10, fontweight='bold')
# Putar label x jika data banyak agar tidak tabrakan
if len(x_labels) > 5:
plt.setp(ax2.get_xticklabels(), rotation=45, ha="right")
else:
ax2.text(0.5, 0.5, "Tidak ada data transaksi", ha='center')
plt.tight_layout()
# 4. Dialog Simpan File
filename = filedialog.asksaveasfilename(
defaultextension=".png",
filetypes=[("PNG Image", "*.png"), ("JPEG Image", "*.jpg")],
title="Simpan Grafik Statistik"
)
if filename:
plt.savefig(filename, dpi=150, bbox_inches='tight')
messagebox.showinfo("Sukses", f"Grafik berhasil disimpan:\n{filename}")
plt.close(fig)
except Exception as e:
messagebox.showerror("Export Gagal", f"Terjadi kesalahan: {e}")
def reload_payment_orders(self): def reload_payment_orders(self):