Reporting (Crystal Reports)¶
Reporting is a first-class, large part of the system: 101 .rpt report layouts ship in
the Inventory project alone. All reports are rendered with Crystal Reports for .NET.
How reporting is wired¶
Each report is three co-located artifacts plus a shared print dialog:
flowchart LR
subgraph Family["A report family folder (e.g. Laporan/LPP/)"]
RPT["Xxx.rpt<br/>(Crystal layout)"]
CLS["Xxx.vb<br/>(auto-generated ReportClass)"]
VW["frmLapXxx.vb<br/>(viewer/launcher form)"]
end
DATA["Data feed<br/>(SQL builder OR temp table)"] --> RPT
VW -->|"ReportSource = new Xxx()"| CRV["CrystalReportViewer"]
VW -->|"push ParameterFields"| RPT
CRV --> PRINT["frmCetakForm.vb<br/>(shared print dialog → PrintToPrinter)"]
style Family fill:#ede7f6,stroke:#673ab7
| Artifact | Role |
|---|---|
Xxx.rpt |
The Crystal layout file. |
Xxx.vb |
Auto-generated class — Inherits ReportClass, exposes ResourceName, layout sections, and Parameter_* fields (e.g. Parameter_UserId, Parameter_KodeCabang, Parameter_Kategori). A CachedXxx companion implements ICachedReport. |
frmLapXxx.vb |
Per-family viewer form; news up the report class, binds it to a CrystalReportViewer, and pushes parameters. |
frmCetakForm.vb |
Shared print dialog — resolves paper size and calls PrintToPrinter(...) (F8 = print, Esc = close). |
FrmWait.vb |
Shared wait spinner during generation. |
Uses CrystalDecisions.CrystalReports.Engine / .Shared / .ReportSource.
Two ways data reaches a report¶
flowchart TD
subgraph A["① SQL-builder classes"]
SB["FrameWork.SmartSoft.Laporan/*.vb<br/>build SQL by StringBuilder"]
end
subgraph B["② Temp-table staging"]
TB["Class/ProsesLaporanPenjualan.vb<br/>DELETE + repopulate tbTemp_LapPenjualan"]
end
SB --> RPT[".rpt reads the result set"]
TB --> RPT
style A fill:#e3f2fd,stroke:#1976d2
style B fill:#fff3e0,stroke:#f57c00
- SQL-builder classes — in
FrameWork.SmartSoft.Laporan/, report SQL is concatenated withStringBuilderand exposed via write-only properties (KodeCabang,TglAwal/TglAkhir,Div/Dept/Kat,GroupByCabang):LaporanPurchaseOrder— PO reports (DetailPOperNoBukti,RekapPOperNoBukti,RekapPOperDivDeptKat,RekapPOperTanggal).PenjualanMarginProfit—LaporanMarginMinus(sales below cost, honouringTipeHPP= last cost vs average cost).
- Temp-table staging —
Class/ProsesLaporanPenjualan.vbis the canonical builder:DetailPenjualanPerBarang()clears and repopulatestbTemp_LapPenjualan(keyedUSERID+LAPID) fromtbTr_Penjualan_H/_Djoined to master tables, driving a progress bar; the.rptthen reads that temp table.
Typed datasets back the reports: DataSet1.xsd (shared), plus DataSetTransaksi.xsd,
DataSetTemporary.xsd, and Form/Transaksi/Kasir/dsDetail.xsd.
Report data sources¶
Reports are read-only over the transaction tables — there are no report-specific tables except temp staging. This diagram maps the main report families to the tables they read (so a wrong number leads you straight to the upstream table):
flowchart LR
subgraph Src["Source tables"]
PJ[("tbTr_Penjualan_H/_D")]
PO[("tbTr_PurchaseOrder_H/_D")]
BO[("tbTr_BackOffice_H/_D")]
ST[("tbMaster_Stock")]
OP[("tbTr_StockOpname_H/_D")]
BR[("tbMaster_Barang")]
end
subgraph Rep["Report families"]
R1["LPP / Margin<br/>(sales analysis)"]
R2["Pembelian / PO"]
R3["Bukti<br/>(transaction proofs)"]
R4["Stock / KartuStock"]
R5["StockOpname"]
R6["Barang"]
end
PJ --> R1
BR --> R1
PO --> R2
BO --> R3
ST --> R4
OP --> R5
BR --> R6
R1 -.stages via.-> TMP[("tbTemp_LapPenjualan")]
style Src fill:#e0f2f1,stroke:#00897b
style TMP fill:#fff3e0,stroke:#fb8c00
Report families¶
Report families are organised by folder under INVENTORY/Form/Laporan/ — the folder name
is the family.
| Family | Representative reports |
|---|---|
| Barang (item master) | Barang, BarangExpired, BarangPerSupplier, BarangPhoto |
| Stock | KartuStock (stock card), StockBarang, StockOut |
| StockOpname (physical count) | LHSO / ReLHSO / CheckerLHSO, LKSO, CHKSO, NBH |
| Pembelian (purchase) | BuktiPembelian, BuktiTerimaPembelian |
| PermintaanBarang / PO | BuktiPurchaseOrder(+Image/TanpaHarga), BuktiUsulanOrder, ListPurchaseOrder |
| SalesOrder | BuktiPB, FormDO, FormInvoice, FormPengambilanBarang, FormSuratJalan |
| SuratJalan (delivery note) | SuratJalan, FormSJS, FormInvoiceMutasi, FormPindahGudang |
| LPP (product/sales-purchase analysis) | AnalisaProduk, LPPByDivisi/KodeBarang/Supplier |
| HargaJual (price change) | PerubahanHargaJual, InstruksiCetakBarcode/PriceTag |
| Hutang (payables) | TandaTerimaTukarFaktur |
| PemusnahanBarang (disposal) | BeritaAcaraPemusnahan, ListPemusnahanBarang |
| PinjamanBarang / TitipBarang | DetailPinjamanBarang; FormTitipBarang, FormAmbilBarang |
| Voucher | BuktiPenerimaanVoucher |
| Bukti (transaction proofs — largest) | BuktiBarangHilang, BuktiMPP, BuktiMutasiGudang, BuktiPemakaianSendiri, BuktiRePacking, BuktiReturBarang, RekapResetKasir, TandaTerimaService, … |
| MarginMinusPerBarang (emailed) |
Additional .rpt live outside this tree, e.g. Form/Utility/PriceTag/ and
Form/Utility/Complain/Laporan/.
Reports read, they don't post
Reports are read-only views over the same tables the transactions write. A "report is
wrong" bug is almost always upstream — a posting or a stock recompute — not the .rpt.
Reproduce the underlying query first (the SQL-builder class or the temp-table populate)
before touching the layout.