The Very Good Building & Development Company (VGB)
Role: Software Engineer (Java)
Timeline: 6 weeks (MVP)
Team: Solo project (course project)
Stack: Java • JDBC • MySQL • JUnit • CSV → DB migration • OOP
Focus: Pricing & tax rules engine, invoice generation, data integrity
VGB managed invoices with spreadsheets and paper, leading to slow billing cycles and error-prone tax calculations. I built a robust Invoice Management System (IMS) that encodes business rules for equipment sales, leases, rentals, material sales, and subcontractor contracts. The system automates invoice creation, applies the correct tax logic per item type, and exports detailed and summary reports—always rounded to the nearest cent.
BigDecimal
with HALF_UP rounding to $0.01.Subtotal = retail_price
Tax = 5.25% use tax of subtotal
Total = subtotal + tax
Monthly base = retail_price / 60
(5 years)
Monthly with markup = 1.5 × base
Subtotal = months × monthly_with_markup
Lease-tax tier: small = untaxed, mid = $500 flat, large = $1,500 flat (thresholds configurable)
Hourly rate = 0.1% of retail = 0.001 × retail_price
Subtotal = hours × hourly_rate
Tax = 4.38% sales tax of subtotal
Subtotal = unit_price × quantity
(quantity must be an integer > 0)
Tax = 7.15% sales tax of subtotal
Subtotal = contract_amount
Tax = exempt
All money values rounded to nearest cent after each line-item computation.
Encapsulation: LineItem (abstract) → subclasses compute subtotal(), tax(), total().
Precision: BigDecimal with setScale(2, RoundingMode.HALF_UP); no floating-point drift.
Validation: integer quantities for materials, non-negative hours/months, non-negative prices.
Configuration: tax rates & lease tiers externalized for future changes.
Testing: JUnit tests cover each rule + edge cases (zero quantities, tier boundaries).
Automated invoice creation with deterministic rounding and rule enforcement.
Speed: CLI generates detailed + summary reports in seconds for multi-item invoices.
Quality: Unit tests prevent regressions when tax rates or tiers change.
Lesson: Keeping calculations inside each subclass made the code safer and easier to extend.