Jakob e9cf2e031f Implement multi-batch invoice generation
- Add read_csv_file_by_batch() to group transactions by batch_number
- Modify generate command to create separate directories per batch
- Each batch directory contains index.html and customer_XXX.html files
- Add 3 unit tests for batch grouping logic
- Fixes issue #1: CSV with multiple batches now generates separate invoices

Closes: #1
2026-04-02 12:34:14 +02:00
2026-04-02 12:01:04 +02:00
2026-03-23 09:58:46 +01:00

rusty-petroleum

A petroleum transaction invoice generator with MariaDB backend.

Overview

This project processes petroleum/fuel station transaction data from CSV files and generates customer invoices. It stores transaction data in MariaDB for both invoicing and sales reporting.

Features

  • CSV Import: Import transaction data from fuel station CSV files into MariaDB
  • Invoice Generation: Generate HTML invoices from CSV data (file-to-file mode)
  • Multi-Environment: Separate databases for development, testing, and production
  • Sales Reporting: Query transactions by customer, product, date range
  • Test-Driven Development: Comprehensive test suite with 45 tests

Project Structure

rusty-petroleum/
├── Cargo.toml              # Rust dependencies
├── Cargo.lock              # Locked dependency versions
├── config.example.toml     # Config template
├── migrations/            # SQL schema files
│   └── 002_schema.sql    # Current schema
├── input/                  # CSV input files
├── output/                 # Generated invoices
├── src/
│   ├── lib.rs            # Library crate (for testing)
│   ├── main.rs           # CLI entry point
│   ├── config.rs         # Configuration loading
│   ├── db/               # Database layer
│   │   ├── mod.rs
│   │   ├── connection.rs
│   │   ├── models.rs
│   │   └── repository.rs
│   ├── commands/         # CLI commands
│   │   ├── mod.rs
│   │   ├── db.rs         # db setup/reset
│   │   └── import.rs     # CSV import
│   └── invoice_generator.rs
├── templates/             # HTML invoice templates
│   ├── index.html
│   └── customer.html
└── tests/                # Integration tests
    ├── common/           # Test utilities
    │   ├── mod.rs
    │   ├── fixtures.rs
    │   └── test_db.rs
    ├── config_test.rs   # Config module tests
    ├── import_test.rs    # CSV parsing tests
    ├── models_test.rs    # Model tests
    └── repository_test.rs # Database tests

Database Schema

customers

Column Type Description
id INT UNSIGNED Primary key
customer_number VARCHAR Unique customer identifier
card_report_group TINYINT UNSIGNED Customer classification (1=fleet, 3/4=retail)
created_at TIMESTAMP Record creation time
updated_at TIMESTAMP Last update time

cards

Column Type Description
id INT UNSIGNED Primary key
card_number VARCHAR Unique card identifier
customer_id INT UNSIGNED FK to customers
created_at TIMESTAMP Record creation time
updated_at TIMESTAMP Last update time

transactions

Column Type Description
id BIGINT UNSIGNED Primary key
transaction_date DATETIME Transaction timestamp
batch_number VARCHAR Batch identifier
amount DECIMAL(10,2) Transaction amount
volume DECIMAL(10,3) Volume in liters
price DECIMAL(8,4) Price per liter
quality_code INT Product code
quality_name VARCHAR Product name (95 Oktan, Diesel)
card_number VARCHAR Card used (including anonymized)
station VARCHAR Station ID
terminal VARCHAR Terminal ID
pump VARCHAR Pump number
receipt VARCHAR Receipt number
control_number VARCHAR Control/verification number
customer_id INT UNSIGNED FK to customers (NULL for anonymized)
created_at TIMESTAMP Record creation time

Configuration

Copy the example config and edit with your database credentials:

cp config.example.toml config.dev.toml  # or config.test.toml or config.prod.toml

Edit config.dev.toml:

[database]
host = "localhost"
port = 3306
user = "your_user"
password = "your_password"
name = "rusty_petroleum_dev"

Environment Config Loading

Config files are loaded in order:

  1. config.toml (local override, gitignored)
  2. config.<env>.toml (environment-specific, gitignored)
  3. config.example.toml (fallback, tracked)

Database Names by Environment

  • rusty_petroleum_dev - Development
  • rusty_petroleum_test - Testing
  • rusty_petroleum_prod - Production

Commands

# Database management
cargo run -- db setup --env <dev|test|prod>   # Create database and schema
cargo run -- db reset --env <dev|test|prod>   # Drop and recreate database

# Import data
cargo run -- import <csv-file> --env <dev|test|prod>   # Import to database (default: prod)

# Generate invoices (file-to-file, no database)
cargo run -- generate <csv-file> <output-dir>

Usage Examples

# Setup development database
cargo run -- db setup --env dev

# Import transactions to dev database
cargo run -- import input/409.csv --env dev

# Reset development database
cargo run -- db reset --env dev

# Generate HTML invoices from CSV
cargo run -- generate input/409.csv output/

Testing

The project has a comprehensive test suite with 45 tests covering config, CSV parsing, models, and database operations.

# Run all tests (lib + integration)
cargo test

# Run only lib/unit tests (fast, no database needed)
cargo test --lib

# Run only integration tests (requires test database)
cargo test --tests

# Run a specific test file
cargo test --test config_test
cargo test --test import_test
cargo test --test repository_test

# Run a specific test
cargo test customer_insert_returns_id

# Run tests in release mode
cargo test --release

Test Database Setup

Repository tests require a test database. Run setup before testing:

cargo run -- db setup --env test

Production Build

Build an optimized binary for production:

# Build release binary
cargo build --release

# Run the binary
./target/release/invoice-generator db setup --env prod
./target/release/invoice-generator import data.csv --env prod

Current Status

Implemented

  • Database schema for transactions, customers, cards
  • CSV import to MariaDB
  • Multi-environment support (dev/test/prod)
  • Configuration via TOML files
  • Invoice generation (HTML output)
  • Database setup/reset commands
  • Unit tests (45 tests)

TODO

  • Sales reporting queries (dashboard/API)
  • Customer invoice retrieval from database
  • Batch import across multiple CSV files
  • CI/CD pipeline

Technology Stack

  • Language: Rust (Edition 2021)
  • Database: MariaDB
  • ORM: sqlx (async MySQL)
  • Templating: Askama (HTML templates)
  • Config: TOML
  • Testing: tokio-test, tempfile

Getting Started

  1. Install Rust (if not already installed)

    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
    
  2. Create database user and grant permissions in MariaDB

    CREATE USER 'your_user'@'%' IDENTIFIED BY 'your_password';
    GRANT ALL PRIVILEGES ON rusty_petroleum_dev.* TO 'your_user'@'%';
    CREATE DATABASE rusty_petroleum_dev;
    
  3. Setup configuration

    cp config.example.toml config.dev.toml
    # Edit config.dev.toml with your credentials
    
  4. Setup database and import data

    cargo run -- db setup --env dev
    cargo run -- import input/409.csv --env dev
    
  5. Run tests

    cargo test --lib        # Unit tests (fast)
    cargo test --tests      # Integration tests (requires DB)
    

License

See LICENSE file.

Description
No description provided
Readme Unlicense 149 KiB
Languages
Rust 91.6%
HTML 8.4%