# edited by glg
import os
import sqlite3
import tempfile
import unittest

from pypos.modules.sinkronisasi.services.transaction_export_service import TransactionExportService


class SettlementExportPayloadLegacyTests(unittest.TestCase):
    def test_build_settlement_payment_payload_uses_netto_not_tender(self):
        service = TransactionExportService()
        rows = [
            {
                "id": 1,
                "transaksi_bulat": 35000,
                "transaksi_nilai": 35000,
                "transaksi_dibayar": 50000,
                "transaksi_dibayar_return": 15000,
                "pembayaran_non_tunai": 0,
                "bank_rekening_id": 108,
                "bank_nama": "Tunai",
                "diskon_nilai": 0,
                "tambahan_nilai": 0,
                "diskon_log": "diskon_customer=0;cashback=0;point=0",
            },
            {
                "id": 2,
                "transaksi_bulat": 23400,
                "transaksi_nilai": 20000,
                "transaksi_dibayar": 23400,
                "transaksi_dibayar_return": 0,
                "pembayaran_non_tunai": 23400,
                "bank_rekening_id": 109,
                "bank_nama": "Debit",
                "diskon_nilai": 3400,
                "tambahan_nilai": 3400,
                "diskon_log": "diskon_customer=0;cashback=0;point=0",
            },
        ]
        out = service._build_settlement_payment_payload(
            transaksi_rows=rows,
            total_disetor=35000,
            total_return_penjualan=0,
        )

        self.assertEqual(out["108"]["nilai_diterima"], 35000)
        self.assertEqual(out["109"]["nilai_diterima"], 20000)

    def test_build_settlement_payment_payload_allocates_return_per_payment_method(self):
        # edited by glg
        service = TransactionExportService()
        rows = [
            {
                "id": 1,
                "transaksi_bulat": 100000,
                "transaksi_nilai": 90000,
                "transaksi_dibayar": 100000,
                "transaksi_dibayar_return": 10000,
                "pembayaran_non_tunai": 0,
                "bank_rekening_id": 108,
                "bank_nama": "Tunai",
                "diskon_nilai": 10000,
                "tambahan_nilai": 0,
                "diskon_log": "diskon_customer=0;cashback=0;point=0",
            },
            {
                "id": 2,
                "transaksi_bulat": 100000,
                "transaksi_nilai": 80000,
                "transaksi_dibayar": 100000,
                "transaksi_dibayar_return": 20000,
                "pembayaran_non_tunai": 100000,
                "bank_rekening_id": 109,
                "bank_nama": "Debit",
                "diskon_nilai": 20000,
                "tambahan_nilai": 0,
                "diskon_log": "diskon_customer=0;cashback=0;point=0",
            },
        ]
        out = service._build_settlement_payment_payload(
            transaksi_rows=rows,
            total_disetor=90000,
            total_return_penjualan=30000,
            return_rows=[
                {"id": 901, "transaksi_id": 1, "refund_amount": 12000, "refund_method": "cash"},
                {"id": 902, "transaksi_id": 2, "refund_amount": 18000, "refund_method": "cash"},
            ],
        )

        self.assertEqual(out["108"]["return_nilai"], 12000)
        self.assertEqual(out["109"]["return_nilai"], 18000)

    def test_build_legacy_settlement_payload_shape_and_payment_breakdown(self):
        service = TransactionExportService()

        service._get_export_device_context = lambda machine_id_hint="": {
            "machine_id": "4CE9341348",
            "cabang_id": 101,
            "cabang_nama": "BPJ",
            "cpu_info": "intel Q9500",
            "com_info": "WHQL0921345",
        }
        service._fetch_transaksi_rows_for_ids = lambda transaksi_ids: [
            {
                "id": 183,
                "dtime": "2025-06-19 10:10:00",
                "oleh_id": 183,
                "cabang_id": 101,
                "cabang_nama": "BPJ",
                "transaksi_bulat": 400000,
                "transaksi_nilai": 250000,
                "transaksi_dibayar": 259500,
                "transaksi_dibayar_return": 9500,
                "pembayaran_non_tunai": 0,
                "bank_rekening_id": 108,
                "bank_nama": "Tunai",
                "diskon_nilai": 10000,
                "tambahan_nilai": 10000,
                "diskon_log": "diskon_customer=0;cashback=0;point=0",
            },
            {
                "id": 185,
                "dtime": "2025-06-19 13:38:09",
                "oleh_id": 183,
                "cabang_id": 101,
                "cabang_nama": "BPJ",
                "transaksi_bulat": 348500,
                "transaksi_nilai": 411070,
                "transaksi_dibayar": 297570,
                "transaksi_dibayar_return": 0,
                "pembayaran_non_tunai": 297570,
                "bank_rekening_id": 110,
                "bank_nama": "credit card",
                "diskon_nilai": 67430,
                "tambahan_nilai": 0,
                "diskon_log": "diskon_customer=29430;cashback=0;point=0",
            },
        ]
        service._fetch_transaksi_data_by_transaksi_ids = lambda transaksi_ids, limit=0: [
            {
                "id": 1,
                "transaksi_id": 183,
                "produk_id": 10,
                "produk_jenis": "item",
                "produk_ord_hrg": 100000,
                "produk_ord_jml": 1,
                "produk_ord_diskon_nominal": 10000,
            },
            {
                "id": 2,
                "transaksi_id": 185,
                "produk_id": 20,
                "produk_jenis": "item",
                "produk_ord_hrg": 190000,
                "produk_ord_jml": 2,
                "produk_ord_diskon_khusus": 38000,
            },
        ]
        service._fetch_return_summary_for_transaksi_ids = (
            lambda transaksi_ids, fallback_total=0: {"ids": [191], "total": 114000}
        )
        service._pick_matching_transaksi_settlement_row = lambda settlement_row, transaksi_ids: {
            "oleh_id": 183,
            "approval_id": 182,
            "cabang_id": 101,
            "cabang_nama": "BPJ",
        }

        payload = service._build_legacy_settlement_history_payload(
            settlement_rows=[
                {
                    "id": 1,
                    "tanggal": "2025-06-21 16:57:11",
                    "admin": "admin_bpj",
                    "kasir": "kasir glg",
                    "cabang_id": 101,
                    "machine_id": "4CE9341348",
                    "total_harus": 661070,
                    "total_disetor": 250000,
                    "total_refund_cash": 114000,
                    "data_transaksi_id": "[183,185]",
                }
            ],
            batch_end="2025-06-21 16:57:11",
        )

        self.assertEqual(payload["user_id"], 183)
        self.assertEqual(payload["cabang_id"], 101)
        self.assertEqual(payload["device_id"], "4CE9341348")
        self.assertIn("tokoID", payload)
        self.assertIn("toko_id", payload)
        self.assertIn("2025-06-19", payload["data"])

        section = payload["data"]["2025-06-19"]
        self.assertEqual(section["date_settlement"], "2025-06-21 16:57:11")
        self.assertEqual(section["total_penjualan_bruto"], 748500)
        self.assertEqual(section["total_tagihan"], 661070)
        self.assertEqual(section["total_diskon_produk"], 48000)
        self.assertEqual(section["total_diskon_member"], 29430)
        self.assertEqual(section["total_additional_diskon"], 10000)
        self.assertEqual(section["total_return_penjualan"], 114000)
        self.assertEqual(section["id_penjualan"], [183, 185])
        self.assertEqual(section["id_return"], [191])
        self.assertEqual(section["settlement_oto_id"], 182)
        self.assertEqual(section["settlement_oto_nama"], "admin_bpj")
        self.assertEqual(section["harga"], 748500)
        self.assertEqual(section["harga_nett2"], 661070)
        self.assertEqual(section["grand_total"], 661070)
        self.assertEqual(section["tagihan"], 661070)
        self.assertEqual(section["diskon_produk"], 48000)
        self.assertEqual(section["diskon_tambahan_nilai"], 10000)
        self.assertEqual(section["add_disc"], 10000)
        self.assertEqual(section["kas_nilai"], 547570)
        self.assertEqual(section["selisih_plus"], 0)
        self.assertIn("tokoID", section)
        self.assertIn("toko_id", section)

        payment = section["payment"]
        self.assertIn("108", payment)
        self.assertIn("110", payment)
        self.assertEqual(payment["108"]["metode_pembayaran"], "cash")
        self.assertEqual(payment["108"]["nilai_diterima"], 250000)
        self.assertEqual(payment["108"]["nilai_settlement"], 250000)
        self.assertEqual(payment["108"]["selisih_settlement"], 0)
        self.assertEqual(payment["108"]["return_nilai"], 114000)
        self.assertEqual(payment["108"]["harga"], 250000)
        self.assertEqual(payment["108"]["harga_nett2"], 250000)
        self.assertEqual(payment["108"]["grand_total"], 250000)
        self.assertEqual(payment["108"]["tagihan"], 250000)
        self.assertEqual(payment["108"]["diskon_produk"], 0)
        self.assertEqual(payment["108"]["diskon_tambahan_nilai"], 0)
        self.assertEqual(payment["108"]["add_disc"], 0)
        self.assertEqual(payment["108"]["selisih_plus"], 0)
        self.assertEqual(payment["108"]["kas_nilai"], 250000)
        self.assertEqual(payment["110"]["metode_pembayaran"], "credit card")
        self.assertEqual(payment["110"]["nilai_diterima"], 297570)
        self.assertEqual(payment["110"]["nilai_settlement"], 297570)
        self.assertEqual(payment["110"]["harga"], 297570)
        self.assertEqual(payment["110"]["harga_nett2"], 297570)
        self.assertEqual(payment["110"]["grand_total"], 297570)
        self.assertEqual(payment["110"]["tagihan"], 297570)
        self.assertEqual(payment["110"]["diskon_produk"], 0)
        self.assertEqual(payment["110"]["diskon_tambahan_nilai"], 0)
        self.assertEqual(payment["110"]["add_disc"], 0)
        self.assertEqual(payment["110"]["selisih_plus"], 0)
        self.assertEqual(payment["110"]["kas_nilai"], 297570)

    def test_build_export_payload_uses_legacy_settlement_builder(self):
        service = TransactionExportService()
        service._resolve_payload_profile = lambda _cfg: "legacy_bundle"
        service._get_export_device_context = lambda machine_id_hint="": {"machine_id": "MACHINE-1"}
        service._build_legacy_settlement_history_payload = lambda rows, batch_end: {
            "user_id": 1,
            "dtime": batch_end,
            "cabang_id": 101,
            "device_id": "MACHINE-1",
            "data": {"2025-06-19": {"id_penjualan": [1]}},
        }

        payload = service._build_export_payload(
            table_name="settlement_history",
            last_id=10,
            new_last_id=11,
            batch_end="2025-06-21 16:57:11",
            rows=[{"id": 11, "data_transaksi_id": "[1]"}],
        )

        self.assertEqual(payload["user_id"], 1)
        self.assertIn("data", payload)
        self.assertNotIn("table", payload)

    def test_build_legacy_settlement_payload_fallbacks_approval_and_cabang_name(self):
        # edited by glg
        service = TransactionExportService()
        service._get_export_device_context = lambda machine_id_hint="": {
            "machine_id": "4CE9341348",
            "cabang_id": 101,
            "cabang_nama": "",
            "cpu_info": "intel Q9500",
            "com_info": "WHQL0921345",
            "toko_id": 1001,
        }
        service._fetch_transaksi_rows_for_ids = lambda transaksi_ids: [
            {
                "id": 183,
                "dtime": "2025-06-19 10:10:00",
                "oleh_id": 183,
                "cabang_id": 101,
                "cabang_nama": "",
                "transaksi_bulat": 35000,
                "transaksi_nilai": 35000,
                "transaksi_dibayar": 35000,
                "transaksi_dibayar_return": 0,
                "pembayaran_non_tunai": 0,
                "bank_rekening_id": 108,
                "bank_nama": "Tunai",
                "diskon_nilai": 0,
                "tambahan_nilai": 0,
                "diskon_log": "diskon_customer=0;cashback=0;point=0",
            }
        ]
        service._fetch_return_summary_for_transaksi_ids = (
            lambda transaksi_ids, fallback_total=0: {"ids": [], "total": 0}
        )
        service._pick_matching_transaksi_settlement_row = lambda settlement_row, transaksi_ids: {
            "oleh_id": 183,
            "approval_id": 0,
            "approval_nama": "",
            "cabang_id": 101,
            "cabang_nama": "",
        }
        service._lookup_employee_id_by_login = lambda login_name: 182 if str(login_name) == "admin_bpj" else 0
        service._lookup_cabang_nama_by_id = lambda cabang_id: "BPJ" if int(cabang_id or 0) == 101 else ""

        payload = service._build_legacy_settlement_history_payload(
            settlement_rows=[
                {
                    "id": 1,
                    "tanggal": "2025-06-21 16:57:11",
                    "admin": "admin_bpj",
                    "kasir": "kasir glg",
                    "cabang_id": 101,
                    "machine_id": "4CE9341348",
                    "total_harus": 35000,
                    "total_disetor": 35000,
                    "total_refund_cash": 0,
                    "data_transaksi_id": "[183]",
                }
            ],
            batch_end="2025-06-21 16:57:11",
        )

        section = payload["data"]["2025-06-19"]
        self.assertEqual(int(section["settlement_oto_id"]), 182)
        self.assertEqual(str(section["settlement_oto_nama"]), "admin_bpj")
        self.assertEqual(str(section["cabang_nama"]), "BPJ")

    def test_build_legacy_settlement_payload_merges_return_transaksi_into_id_penjualan(self):
        # edited by glg
        service = TransactionExportService()
        service._get_export_device_context = lambda machine_id_hint="": {
            "machine_id": "4CE9341348",
            "cabang_id": 101,
            "cabang_nama": "BPJ",
            "cpu_info": "intel Q9500",
            "com_info": "WHQL0921345",
            "toko_id": 1001,
        }
        service._fetch_transaksi_rows_for_ids = lambda transaksi_ids: [
            {
                "id": 183,
                "dtime": "2025-06-19 10:10:00",
                "oleh_id": 183,
                "cabang_id": 101,
                "cabang_nama": "BPJ",
                "transaksi_bulat": 35000,
                "transaksi_nilai": 35000,
                "transaksi_dibayar": 35000,
                "transaksi_dibayar_return": 0,
                "pembayaran_non_tunai": 0,
                "bank_rekening_id": 108,
                "bank_nama": "Tunai",
                "diskon_nilai": 0,
                "tambahan_nilai": 0,
                "diskon_log": "diskon_customer=0;cashback=0;point=0",
            }
        ]
        service._fetch_transaksi_data_by_transaksi_ids = lambda transaksi_ids, limit=0: []
        service._pick_matching_transaksi_settlement_row = lambda settlement_row, transaksi_ids: {
            "oleh_id": 183,
            "approval_id": 182,
            "approval_nama": "admin_bpj",
            "cabang_id": 101,
            "cabang_nama": "BPJ",
        }
        service._fetch_return_summary_for_transaksi_ids = (
            lambda transaksi_ids, fallback_total=0: {
                "ids": [191],
                "total": 5000,
                "rows": [
                    {
                        "id": 191,
                        "transaksi_id": 999,
                        "refund_amount": 5000,
                        "total_return": 5000,
                        "refund_method": "cash",
                    }
                ],
            }
        )

        payload = service._build_legacy_settlement_history_payload(
            settlement_rows=[
                {
                    "id": 1,
                    "tanggal": "2025-06-21 16:57:11",
                    "admin": "admin_bpj",
                    "kasir": "kasir glg",
                    "cabang_id": 101,
                    "machine_id": "4CE9341348",
                    "total_harus": 35000,
                    "total_disetor": 35000,
                    "total_refund_cash": 5000,
                    "data_transaksi_id": "[183]",
                }
            ],
            batch_end="2025-06-21 16:57:11",
        )

        section = payload["data"]["2025-06-19"]
        self.assertEqual(section["id_penjualan"], [183, 999])
        self.assertEqual(section["id_return"], [191])
        self.assertEqual(int(section["jml_transaksi"]), 3)
        self.assertEqual(int(section["payment"]["108"]["return_nilai"]), 5000)

    def test_build_direct_settlement_payload_memilih_row_berdasarkan_transaksi_ids(self):
        # edited by glg
        # Gunakan DB temp nyata agar jalur query/pick row tervalidasi end-to-end.
        fd, db_path = tempfile.mkstemp(suffix=".db")
        os.close(fd)
        try:
            conn = sqlite3.connect(db_path)
            cur = conn.cursor()
            cur.execute(
                """
                CREATE TABLE settlement_history (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    tanggal TEXT,
                    admin TEXT,
                    data_transaksi_id TEXT
                )
                """
            )
            cur.execute(
                """
                CREATE TABLE transaksi_settlement (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    counter TEXT,
                    data_transaksi_id TEXT
                )
                """
            )
            cur.execute(
                "INSERT INTO settlement_history (tanggal, admin, data_transaksi_id) VALUES (?, ?, ?)",
                ("2026-03-10 10:00:00", "admin1", "[1,2,3]"),
            )
            cur.execute(
                "INSERT INTO settlement_history (tanggal, admin, data_transaksi_id) VALUES (?, ?, ?)",
                ("2026-03-11 10:00:00", "admin2", "[10,11]"),
            )
            cur.execute(
                "INSERT INTO transaksi_settlement (counter, data_transaksi_id) VALUES (?, ?)",
                ("ST-20260311-001", "[10,11]"),
            )
            conn.commit()
            conn.close()

            service = TransactionExportService(db_path=db_path)

            captured = {}

            def _fake_builder(rows, batch_end):
                captured["rows"] = rows
                captured["batch_end"] = batch_end
                return {"row_id": int(rows[0]["id"]), "batch_end": str(batch_end)}

            service._build_legacy_settlement_history_payload = _fake_builder
            payload = service.build_direct_settlement_payload(transaksi_ids=[10, 11])

            self.assertEqual(payload["row_id"], 2)
            self.assertEqual(str(payload["batch_end"]), "2026-03-11 10:00:00")
            self.assertEqual(int(captured["rows"][0]["id"]), 2)
        finally:
            try:
                os.remove(db_path)
            except Exception:
                pass

    def test_build_direct_settlement_payload_fallback_dari_counter(self):
        fd, db_path = tempfile.mkstemp(suffix=".db")
        os.close(fd)
        try:
            conn = sqlite3.connect(db_path)
            cur = conn.cursor()
            cur.execute(
                """
                CREATE TABLE settlement_history (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    tanggal TEXT,
                    admin TEXT,
                    data_transaksi_id TEXT
                )
                """
            )
            cur.execute(
                """
                CREATE TABLE transaksi_settlement (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    counter TEXT,
                    data_transaksi_id TEXT
                )
                """
            )
            cur.execute(
                "INSERT INTO settlement_history (tanggal, admin, data_transaksi_id) VALUES (?, ?, ?)",
                ("2026-03-11 12:00:00", "admin3", "[31,32]"),
            )
            cur.execute(
                "INSERT INTO transaksi_settlement (counter, data_transaksi_id) VALUES (?, ?)",
                ("ST-20260311-009", "[31,32]"),
            )
            conn.commit()
            conn.close()

            service = TransactionExportService(db_path=db_path)
            service._build_legacy_settlement_history_payload = (
                lambda rows, batch_end: {"row_id": int(rows[0]["id"]), "batch_end": str(batch_end)}
            )
            payload = service.build_direct_settlement_payload(
                transaksi_ids=[],
                settlement_counter="ST-20260311-009",
            )

            self.assertEqual(payload["row_id"], 1)
            self.assertEqual(payload["batch_end"], "2026-03-11 12:00:00")
        finally:
            try:
                os.remove(db_path)
            except Exception:
                pass

    def test_build_direct_settlement_payload_mixed_return_partial_and_cancel_full(self):
        # edited by glg
        # Integrasi: gabungan partial return + pembatalan full nota
        # harus terpetakan ke id_penjualan, id_return, jml_transaksi, dan return_nilai per metode.
        fd, db_path = tempfile.mkstemp(suffix=".db")
        os.close(fd)
        try:
            conn = sqlite3.connect(db_path)
            cur = conn.cursor()
            cur.execute(
                """
                CREATE TABLE settlement_history (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    tanggal TEXT,
                    admin TEXT,
                    kasir TEXT,
                    cabang_id INTEGER,
                    machine_id TEXT,
                    total_harus REAL,
                    total_disetor REAL,
                    total_non_tunai REAL,
                    total_refund_cash REAL,
                    data_transaksi_id TEXT
                )
                """
            )
            cur.execute(
                """
                CREATE TABLE transaksi_settlement (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    counter TEXT,
                    oleh_id INTEGER,
                    oleh_dtime TEXT,
                    approval_id INTEGER,
                    approval_nama TEXT,
                    data_transaksi_id TEXT,
                    cabang_id INTEGER,
                    oleh_nama TEXT,
                    cabang_nama TEXT
                )
                """
            )
            cur.execute(
                """
                CREATE TABLE transaksi (
                    id INTEGER PRIMARY KEY,
                    dtime TEXT,
                    oleh_id INTEGER,
                    oleh_nama TEXT,
                    cabang_id INTEGER,
                    cabang_nama TEXT,
                    transaksi_bulat REAL,
                    transaksi_nilai REAL,
                    transaksi_dibayar REAL,
                    transaksi_dibayar_return REAL,
                    pembayaran_non_tunai REAL,
                    bank_rekening_id INTEGER,
                    bank_nama TEXT,
                    pembayaran TEXT,
                    pembayaran_sys TEXT,
                    diskon_nilai REAL,
                    tambahan_nilai REAL,
                    diskon_log TEXT,
                    point_transaksi REAL
                )
                """
            )
            cur.execute(
                """
                CREATE TABLE return_transaksi_penjualan (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    transaksi_id TEXT NOT NULL,
                    tanggal_return TEXT NOT NULL,
                    total_return REAL NOT NULL,
                    kode_voucher TEXT NOT NULL,
                    nilai_voucher REAL NOT NULL,
                    customer_id TEXT,
                    keterangan TEXT,
                    jenis_return TEXT,
                    refund_method TEXT,
                    refund_amount REAL
                )
                """
            )
            cur.execute(
                """
                CREATE TABLE pembatalan_transaksi_history (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    transaksi_id TEXT NOT NULL,
                    nomer TEXT,
                    transaksi_dtime TEXT,
                    customers_nama TEXT,
                    kasir_nama TEXT,
                    transaksi_nilai REAL,
                    admin_verifikasi TEXT NOT NULL,
                    dibatalkan_oleh_id TEXT,
                    dibatalkan_oleh_nama TEXT,
                    cancel_dtime TEXT NOT NULL
                )
                """
            )
            # transaksi aktif di settlement (82, 84)
            cur.execute(
                """
                INSERT INTO transaksi
                (id, dtime, oleh_id, oleh_nama, cabang_id, cabang_nama, transaksi_bulat, transaksi_nilai,
                 transaksi_dibayar, transaksi_dibayar_return, pembayaran_non_tunai, bank_rekening_id, bank_nama,
                 pembayaran, pembayaran_sys, diskon_nilai, tambahan_nilai, diskon_log, point_transaksi)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
                """,
                (
                    82,
                    "2026-04-02 11:40:00",
                    777,
                    "kasir glg",
                    101,
                    "BPJ",
                    100000,
                    100000,
                    100000,
                    0,
                    0,
                    108,
                    "Tunai",
                    "cash",
                    "",
                    0,
                    0,
                    "diskon_customer=0;cashback=0;point=0",
                    0,
                ),
            )
            cur.execute(
                """
                INSERT INTO transaksi
                (id, dtime, oleh_id, oleh_nama, cabang_id, cabang_nama, transaksi_bulat, transaksi_nilai,
                 transaksi_dibayar, transaksi_dibayar_return, pembayaran_non_tunai, bank_rekening_id, bank_nama,
                 pembayaran, pembayaran_sys, diskon_nilai, tambahan_nilai, diskon_log, point_transaksi)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
                """,
                (
                    83,
                    "2026-04-02 11:44:00",
                    777,
                    "kasir glg",
                    101,
                    "BPJ",
                    80000,
                    80000,
                    80000,
                    0,
                    80000,
                    110,
                    "credit card",
                    "credit card",
                    "credit card",
                    0,
                    0,
                    "diskon_customer=0;cashback=0;point=0",
                    0,
                ),
            )
            cur.execute(
                """
                INSERT INTO transaksi
                (id, dtime, oleh_id, oleh_nama, cabang_id, cabang_nama, transaksi_bulat, transaksi_nilai,
                 transaksi_dibayar, transaksi_dibayar_return, pembayaran_non_tunai, bank_rekening_id, bank_nama,
                 pembayaran, pembayaran_sys, diskon_nilai, tambahan_nilai, diskon_log, point_transaksi)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
                """,
                (
                    84,
                    "2026-04-02 11:46:00",
                    777,
                    "kasir glg",
                    101,
                    "BPJ",
                    50000,
                    50000,
                    50000,
                    0,
                    0,
                    108,
                    "Tunai",
                    "cash",
                    "",
                    0,
                    0,
                    "diskon_customer=0;cashback=0;point=0",
                    0,
                ),
            )
            # partial return transaksi 82
            cur.execute(
                """
                INSERT INTO return_transaksi_penjualan
                (id, transaksi_id, tanggal_return, total_return, kode_voucher, nilai_voucher, customer_id, keterangan, jenis_return, refund_method, refund_amount)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
                """,
                (
                    191,
                    "82",
                    "2026-04-02 11:48:00",
                    20000,
                    "RTR202604021148",
                    20000,
                    "0",
                    "partial return",
                    "partial",
                    "cash",
                    20000,
                ),
            )
            # pembatalan full nota transaksi 83
            cur.execute(
                """
                INSERT INTO pembatalan_transaksi_history
                (id, transaksi_id, nomer, transaksi_dtime, customers_nama, kasir_nama, transaksi_nilai, admin_verifikasi, dibatalkan_oleh_id, dibatalkan_oleh_nama, cancel_dtime)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
                """,
                (
                    7,
                    "83",
                    "INV-83",
                    "2026-04-02 11:44:00",
                    "cust",
                    "kasir glg",
                    80000,
                    "admin_bpj",
                    "999",
                    "admin_bpj",
                    "2026-04-02 11:49:00",
                ),
            )

            # row settlement sebelumnya untuk batas window
            cur.execute(
                """
                INSERT INTO settlement_history
                (id, tanggal, admin, kasir, cabang_id, machine_id, total_harus, total_disetor, total_non_tunai, total_refund_cash, data_transaksi_id)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
                """,
                (
                    1,
                    "2026-04-02 09:00:00",
                    "admin_bpj",
                    "kasir glg",
                    101,
                    "MACHINE-1",
                    0,
                    0,
                    0,
                    0,
                    "[]",
                ),
            )
            # batch settlement target: transaksi 82 dan 84, transaksi 83 hilang karena dibatalkan
            cur.execute(
                """
                INSERT INTO settlement_history
                (id, tanggal, admin, kasir, cabang_id, machine_id, total_harus, total_disetor, total_non_tunai, total_refund_cash, data_transaksi_id)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
                """,
                (
                    2,
                    "2026-04-02 11:50:00",
                    "admin_bpj",
                    "kasir glg",
                    101,
                    "MACHINE-1",
                    150000,
                    150000,
                    0,
                    0,
                    "[82,84]",
                ),
            )
            cur.execute(
                """
                INSERT INTO transaksi_settlement
                (id, counter, oleh_id, oleh_dtime, approval_id, approval_nama, data_transaksi_id, cabang_id, oleh_nama, cabang_nama)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
                """,
                (
                    1,
                    "ST-20260402-001",
                    777,
                    "2026-04-02 11:50:00",
                    182,
                    "admin_bpj",
                    "[82,84]",
                    101,
                    "kasir glg",
                    "BPJ",
                ),
            )
            conn.commit()
            conn.close()

            service = TransactionExportService(db_path=db_path)
            service._get_export_device_context = lambda machine_id_hint="": {
                "machine_id": "MACHINE-1",
                "cabang_id": 101,
                "cabang_nama": "BPJ",
                "cpu_info": "intel Q9500",
                "com_info": "WHQL0921345",
                "toko_id": 1001,
            }
            payload = service.build_direct_settlement_payload(settlement_counter="ST-20260402-001")

            self.assertIn("2026-04-02", payload.get("data", {}))
            section = payload["data"]["2026-04-02"]
            self.assertEqual(section["id_penjualan"], [82, 84, 83])
            self.assertEqual(section["id_return"], [191, 83])
            # edited by glg
            # Event-based tracking: nota asli + event return/pembatalan dihitung terpisah.
            self.assertEqual(int(section["jml_transaksi"]), 5)
            self.assertEqual(int(section["total_return_penjualan"]), 100000)
            self.assertIn("108", section["payment"])
            self.assertIn("110", section["payment"])
            self.assertEqual(int(section["payment"]["108"]["return_nilai"]), 20000)
            self.assertEqual(int(section["payment"]["110"]["return_nilai"]), 80000)
        finally:
            try:
                os.remove(db_path)
            except Exception:
                pass


if __name__ == "__main__":
    unittest.main()
