OpenConsignment is a JavaFX desktop application for managing consignment sale data — buyers, suppliers, transports, bills, collections, and payments — with SQLite storage and PDF ledger reports.
- Master data — maintain buyers, suppliers, and transports.
- Bill entry — record consignment bills, including LR (lorry receipt) details, with an editable history view.
- Collections & payments — record buyer collections and supplier payments against pending bills, with dedicated history views.
- Ledger reports — generate buyer, supplier, and transport ledgers as PDFs (via JasperReports), including agewise-outstanding variants.
- Local-first storage — data is kept in a local SQLite database
(
database.db), with helper scripts to configure backups to a private Git repository (see Backups).
- Java 17, JavaFX 17
- Dagger 2 for dependency injection (see
src/main/java/openconsignment/di) - SQLite (via
sqlite-jdbc) for storage - JasperReports for PDF report generation
- SLF4J with Log4j 2 for asynchronous rolling-file logging
- Gradle (Kotlin DSL) with the Shadow plugin for a single runnable JAR
- JUnit 5, Mockito, and TestFX for testing; Spotless (
palantir-java-format) for formatting; JaCoCo for coverage
- JDK 17, with
javaavailable on yourPATH. - A graphical desktop environment to run the application, and a PDF viewer to open generated reports.
The repository includes the Gradle wrapper; a separate Gradle installation is not required. Gradle resolves JavaFX dependencies when running from source.
./gradlew runRun commands from the repository root. On Windows, use gradlew.bat in
place of ./gradlew.
./gradlew shadowJarThis produces build/libs/OpenConsignment.jar and copies the launch scripts,
backup configuration script, and backup templates into build/libs/.
The launch scripts require a separate JavaFX 17 SDK matching your operating
system and CPU architecture.
On macOS/Linux, the launcher defaults to ~/javafx-sdk-17.0.19/lib:
bash build/libs/start.shTo use a different SDK location, set JAVAFX_MODULE_PATH to its lib directory:
JAVAFX_MODULE_PATH="/path/to/javafx-sdk-17/lib" bash build/libs/start.shOn Windows, edit build/libs/start.bat to match your local Java and JavaFX
installations, then run it from build/libs/:
cd build\libs
start.batThe batch script currently sets Java to C:\Program Files\Java\jdk-17
and the JavaFX module path to %USERPROFILE%\javafx-sdk-17.0.18\lib.
Keep the JAR and launch script together when moving the application.
- The application creates and initializes
database.dbin its working directory usingsrc/main/resources/sql/init.sql. - Repository queries live in domain-specific folders under
src/main/resources/sql(for example,bill/get.sql). Paths are registered in theSqlQueryenum and loaded withSqlLoader.load(SqlQuery.BILL_GET), using UTF-8 decoding and caching. When adding a query, add its SQL file and enum entry; tests verify that every entry has a non-empty resource. - Running
./gradlew runuses the repository root; the packaged launch commands above usebuild/libs/. Each location has its own database. - Reports are written to
report.pdfin the working directory, replacing the previous report, and opened with the system's default PDF viewer.
At startup, the application reads UTF-8 application.yaml beside the JAR, regardless
of the current working directory. If this file does not exist, the application copies
src/main/resources/application.yaml from inside the JAR to that location and loads
the new file. Existing configuration files are never overwritten.
Edit the generated file to set your organization name:
organizationName: "YOUR ORGANIZATION"This name appears on the welcome screen and in buyer, supplier, and transport ledger reports. The bundled YAML is used only as the template for first-run creation; properties are not merged or filled in from it when an external file already exists. YAML is bound directly to configuration POJOs using SnakeYAML. Quote the name to preserve its exact text; scalar values such as numbers are converted to strings. Surrounding whitespace is trimmed. A blank or null name, malformed YAML, or an unreadable configuration file is reported as a startup error. An empty file or missing required property also fails validation. The application needs write access to the JAR directory when creating the file for the first time.
For Gradle/IDE runs, the file is created and read in the working directory (the
repository root for ./gradlew run). The example file is included in build/libs/
when building. Restart the application after editing the file. Updating the JAR
does not replace an existing configuration file.
The application writes INFO and higher messages to stderr and to
logs/openconsignment.log in its working directory. Application logging uses
SLF4J directly with Log4j 2 as its backend, including exception stack traces.
Use SLF4J's LoggerFactory and parameterized messages in application code.
The file is rolled at startup, daily, or when it reaches 10 MB. Archives are compressed; during rollover, archives older than 30 days or beyond 100 MB total are deleted. The active file is separate from that archive limit. File writes use a bounded asynchronous queue; if it fills, callers wait rather than dropping messages. The queue is drained on normal JVM shutdown. An abrupt termination may lose queued messages. Log4j reports file setup problems to stderr, where console logging remains available.
The working directory is the repository root when using ./gradlew run and
build/libs when using the supplied launch scripts. To use a different
directory or file size, pass JVM properties, for example:
java -Dopenconsignment.logDir=/path/to/logs -Dopenconsignment.logSize="20 MB" ...Configure these options in the launch script when running the packaged JAR. Use a separate log directory for each simultaneous application instance; the rolling files are not coordinated across processes. Log files can contain exception details, so restrict access and review them before sharing.
./gradlew test- Unit tests (
src/test/java/openconsignment/service,.../repository) cover the service layer (mocked repositories, mocked staticUtils.generatePdfcalls) and the repository layer (real in-memory SQLite, schema-initialized fromsrc/main/resources/sql/init.sql). - Functional tests (
src/test/java/functional) use TestFX to smoke-test the JavaFX UI and check bill-entry layout.
Tests run headlessly by default. To debug with visible JavaFX windows:
./gradlew test -PheadlessTests=falseTo run a specific group of tests:
./gradlew test --tests 'openconsignment.service.*'
./gradlew test --tests 'openconsignment.repository.*'
./gradlew test --tests 'functional.*'Every test run also produces a JaCoCo coverage report at
build/reports/jacoco/test/html/index.html. The test results are available at
build/reports/tests/test/index.html.
Formatting is enforced by Spotless and checked on every build
(spotlessJavaCheck). To auto-format:
just format
# or: ./gradlew spotlessApplysrc/main/java/openconsignment/
├── di/ Dagger modules and components (wires the object graph,
│ including JavaFX's controller factory)
├── controller/ JavaFX FXML controllers, grouped by feature area
├── service/ Business logic, one per domain (bill, buyer, supplier, ...)
├── repository/ JDBC/SQL access, one per domain
├── entity/ Persistence-shaped data classes
├── model/ Read-model/report row classes (ledgers, etc.)
└── common/ Shared utilities (PDF generation, constants, ...)
src/main/resources/
├── fxml/ JavaFX view definitions
├── jrxml/ JasperReports report templates
├── css/ Shared and feature-specific stylesheets
├── icons/ Application and toolbar icons
└── sql/ Database schema (init.sql)
src/test/java/
├── openconsignment/ Service, repository, and dependency-injection tests
└── functional/ JavaFX UI tests
scripts/ Launchers and financial-year backup helpers
gradle/libs.versions.toml Dependency and plugin versions
scripts/configure-backup.py generates year-scoped upload/download
scripts (from scripts/templates) for backing up database.db to a
private, per-financial-year Git repository. It requires Python 3, Git, and
SSH access to the backup repository. The repository must already exist;
the script clones it rather than creating it.
The repository owner is currently hard-coded as drcbabu81 in
configure-backup.py, with repository names such as
Satyam-Database-2026-27. Update the owner for your deployment.
After building the JAR, run the configuration script from build/libs/
so it can find templates/ and create the helpers beside database.db:
cd build/libs
python3 configure-backup.pyEnter a financial year such as 2026-27 when prompted. On Windows, use
python configure-backup.py from the same directory. The script generates
upload.sh/download.sh on macOS/Linux or upload.bat/download.bat on
Windows. Run the generated helpers from that directory.
Review the templates before use: the shell upload template currently uses
a Windows-style separator in its database copy destination, which needs
adjusting for macOS/Linux. The download helper replaces the local
database.db with the repository copy. Backup scheduling is managed separately.
GitHub Actions builds and tests every push/PR (.github/workflows/build.yml).
Pushing a v* tag builds and publishes a shadow JAR to a GitHub Release
(.github/workflows/release.yml).
