from pypos.core.base_view import BaseView from PySide6.QtWidgets import ( QDialog, QVBoxLayout, QHBoxLayout, QPushButton, QTableWidget, QTableWidgetItem, QLabel, QMessageBox, QDateEdit, QComboBox ) from PySide6.QtCore import QDate # upgraded: inherit base class class LoadTransaksiView(BaseView, QDialog): def __init__(self, controller): super().__init__() self.controller = controller self.setWindowTitle("Load Transaksi Tersimpan") from pypos.core.utils.dialog_size_helper import set_fixed_dialog_size set_fixed_dialog_size(self, 1200, 700) self.layout = QVBoxLayout() # PATCH[FrontEndAgent|HistoryFilter]: Strip filter dengan preset rentang dan opsi custom. filter_layout = QHBoxLayout() filter_label = QLabel("Mode Tampilan:") self.preset_combo = QComboBox() self.preset_combo.addItem("Hari Ini", "today") self.preset_combo.addItem("Kemarin", "yesterday") self.preset_combo.addItem("7 Hari Terakhir", "last7") self.preset_combo.addItem("30 Hari Terakhir", "last30") self.preset_combo.addItem("Rentang Bebas", "custom") self.preset_combo.currentIndexChanged.connect(self.on_preset_changed) reset_today_btn = QPushButton("Reset ke Hari Ini") reset_today_btn.clicked.connect(self.reset_to_today) tanggal_label = QLabel("Rentang Tanggal:") self.start_date_edit = QDateEdit() self.start_date_edit.setCalendarPopup(True) self.start_date_edit.setDate(QDate.currentDate()) self.end_date_edit = QDateEdit() self.end_date_edit.setCalendarPopup(True) self.end_date_edit.setDate(QDate.currentDate()) self.btn_filter = QPushButton("Tampilkan") self.btn_filter.clicked.connect(self.kirim_filter_tanggal) filter_layout.addWidget(filter_label) filter_layout.addWidget(self.preset_combo) filter_layout.addWidget(reset_today_btn) filter_layout.addSpacing(20) filter_layout.addWidget(tanggal_label) filter_layout.addWidget(self.start_date_edit) filter_layout.addWidget(QLabel("s.d")) filter_layout.addWidget(self.end_date_edit) filter_layout.addWidget(self.btn_filter) filter_layout.addStretch() self.layout.addLayout(filter_layout) self.table = QTableWidget(0, 5) self.table.setHorizontalHeaderLabels(["ID", "Nomer", "Tanggal","Customer", "Total Harga"]) # PATCH[FrontEndAgent|KeyboardNav]: Tangkap navigasi mouse dan keyboard self.table.cellClicked.connect(self.controller.transaksi_diklik) self.table.currentCellChanged.connect(self.on_current_cell_changed) from PySide6.QtWidgets import QHeaderView header = self.table.horizontalHeader() header.setSectionResizeMode(QHeaderView.Stretch) self.table.setStyleSheet("QTableWidget::item:selected { background: #d0d0d0; color: black; }") self.layout.addWidget(self.table) # PATCH[FrontEndAgent|ToggleDetail]: Header preview dengan button toggle preview_header_layout = QHBoxLayout() self.preview_label = QLabel("📝 Preview Detail Transaksi:") self.btn_toggle_detail = QPushButton("📦 Detail Barang") self.btn_toggle_detail.setStyleSheet(""" QPushButton { background-color: #17a2b8; color: white; font-weight: bold; padding: 4px 12px; border-radius: 5px; font-size: 8pt; } QPushButton:hover { background-color: #138496; } """) self.btn_toggle_detail.clicked.connect(self.toggle_detail_view) self.btn_toggle_detail.setVisible(False) # Hidden until data loaded preview_header_layout.addWidget(self.preview_label) preview_header_layout.addWidget(self.btn_toggle_detail) preview_header_layout.addStretch() self.layout.addLayout(preview_header_layout) # PATCH[FrontEndAgent|DetailInfo]: Section info transaksi lengkap (compact) self.info_transaksi_label = QLabel("") # Store data for toggle self.current_header_data = None self.current_detail_rows = None self.is_showing_items = False self.info_transaksi_label.setStyleSheet(""" QLabel { background-color: #f8f9fa; border: 2px solid #28a745; border-radius: 6px; padding: 12px; font-size: 10pt; line-height: 1.4; min-height: 180px; } """) self.info_transaksi_label.setWordWrap(True) self.layout.addWidget(self.info_transaksi_label) self.button_layout = QHBoxLayout() self.btn_close = QPushButton("🚪 Close (ESC)") self.btn_close.setStyleSheet(""" QPushButton { background-color: #6c757d; color: white; font-weight: bold; padding: 10px 30px; border-radius: 8px; font-size: 10pt; } QPushButton:hover { background-color: #5a6268; } """) self.btn_close.clicked.connect(self.reject) self.btn_close.setShortcut("Esc") self.button_layout.addStretch() self.button_layout.addWidget(self.btn_close) self.layout.addLayout(self.button_layout) self.setLayout(self.layout) # PATCH[FrontEndAgent|InitState]: Inisialisasi diserahkan ke controller setelah view siap. def render_transaksi_list(self, rows): """Render daftar transaksi tersimpan/history ke tabel utama.""" self.table.setRowCount(0) for row_data in rows: row = self.table.rowCount() self.table.insertRow(row) for col, val in enumerate(row_data[:5]): self.table.setItem(row, col, QTableWidgetItem(str(val))) def render_detail_transaksi(self, detail_rows): """Render detail transaksi yang dipilih.""" self.detail_table.setRowCount(0) for item in detail_rows: row = self.detail_table.rowCount() self.detail_table.insertRow(row) for col, val in enumerate(item): self.detail_table.setItem(row, col, QTableWidgetItem(str(val))) def warn_pilih_transaksi(self): QMessageBox.warning(self, "Pilih Transaksi", "Pilih transaksi untuk diload.") def kirim_filter_tanggal(self): start = self.start_date_edit.date() end = self.end_date_edit.date() if start > end: QMessageBox.warning(self, "Validasi Tanggal", "Tanggal mulai tidak boleh melebihi tanggal akhir.") return start_str = start.toString("yyyy-MM-dd") end_str = end.toString("yyyy-MM-dd") # Pastikan mode ditandai sebagai custom tanpa memicu handler preset. custom_idx = self.preset_combo.findData("custom") if custom_idx != -1 and self.preset_combo.currentIndex() != custom_idx: self.preset_combo.blockSignals(True) self.preset_combo.setCurrentIndex(custom_idx) self.preset_combo.blockSignals(False) self.controller.filter_by_date_range(start_str, end_str) def tampilkan_history_rows(self, rows): """Render daftar transaksi ke tabel utama.""" self.table.setRowCount(0) for row_data in rows: row = self.table.rowCount() self.table.insertRow(row) for col, val in enumerate(row_data[:5]): self.table.setItem(row, col, QTableWidgetItem(str(val))) def on_preset_changed(self, index): mode = self.preset_combo.itemData(index) # Aktifkan rentang tanggal selalu; preset mengisi otomatis, custom memakai input. self.start_date_edit.setEnabled(True) self.end_date_edit.setEnabled(True) self.btn_filter.setEnabled(True) if mode != "custom": # Hindari pemanggilan sebelum controller siap (saat konstruksi). if hasattr(self.controller, "filter_by_preset"): self.controller.filter_by_preset(mode) def reset_to_today(self): idx = self.preset_combo.findData("today") if idx != -1: self.preset_combo.setCurrentIndex(idx) def set_date_inputs(self, start_iso, end_iso): """ Menerapkan tanggal ke input untuk menjaga sinkronisasi UI. """ try: start_qdate = QDate.fromString(start_iso, "yyyy-MM-dd") end_qdate = QDate.fromString(end_iso, "yyyy-MM-dd") if start_qdate.isValid(): self.start_date_edit.setDate(start_qdate) if end_qdate.isValid(): self.end_date_edit.setDate(end_qdate) except Exception: # Fail silently jika format tidak valid; UI akan tetap pada nilai sebelumnya. pass def tampilkan_detail_transaksi(self, header_data, detail_rows): """PATCH[FrontEndAgent|DetailInfo]: Tampilkan info transaksi lengkap dengan format informatif""" if not header_data: self.info_transaksi_label.setText("❌ Data transaksi tidak ditemukan") self.btn_toggle_detail.setVisible(False) return # Store data for toggle self.current_header_data = header_data self.current_detail_rows = detail_rows self.is_showing_items = False self.btn_toggle_detail.setVisible(True) self.btn_toggle_detail.setText("📦 Detail Barang") self.preview_label.setText("📝 Preview Detail Transaksi:") # Parse header data ( customer_id, customer_nama, diskon_persen, ppn_persen, transaksi_nilai, dtime, kasir_id, kasir_nama, metode_pembayaran, bank_id, bank_nama, settlement_id, jumlah_bayar, kembalian, approval_code, no_kartu ) = header_data # Format rupiah def fmt_rp(nilai): if nilai is None: return "Rp 0,00" return f"Rp {float(nilai):,.2f}".replace(",", "X").replace(".", ",").replace("X", ".") # PATCH[FrontEndAgent|PPNFix]: ppn_persen di DB sebenarnya nilai Rupiah, bukan persen # Karena data lama tidak konsisten, tampilkan nilai Rupiah saja ppn_display = "" diskon_display = "" if ppn_persen and ppn_persen > 0: ppn_display = f"{fmt_rp(ppn_persen)}" else: ppn_display = "Rp 0,00" if diskon_persen and diskon_persen > 0: diskon_display = f"{diskon_persen:.0f}%" else: diskon_display = "0%" # Build items list HTML items_html = "" for idx, item in enumerate(detail_rows, 1): try: harga = float(item[2]) jumlah = float(item[3]) diskon_item = float(item[4]) if item[4] else 0 subtotal = (harga * jumlah) - diskon_item satuan = item[5] if len(item) > 5 else "" items_html += f"""
|
👤 PEMBELI {customer_nama or 'tunai'} |
👨💼 KASIR {kasir_nama or 'System'} |
🕐 WAKTU {tanggal_str} {jam_str} |
{metode_icon} BAYAR {(metode_pembayaran or 'tunai').upper()} - {bank_nama or 'Tunai'}{kartu_info} |
SETTLEMENT {settlement_status} |
||||||||||||||
|
||||||||||||||||||
| 📦 {len(detail_rows)} item dalam transaksi ini. Klik button "Detail Barang" untuk melihat daftar lengkap. | ||||||||||||||||||