db/herodb/src/models/biz
2025-04-20 09:21:32 +02:00
..
rhai biz rhai wrapper module wip 2025-04-20 01:52:12 +02:00
contract.rs ... 2025-04-20 09:21:32 +02:00
currency.rs ... 2025-04-20 09:21:32 +02:00
customer.rs ... 2025-04-20 09:21:32 +02:00
exchange_rate.rs ... 2025-04-20 09:21:32 +02:00
invoice.rs ... 2025-04-20 09:21:32 +02:00
lib.rs ... 2025-04-20 08:29:35 +02:00
mod.rs ... 2025-04-04 12:43:20 +02:00
product.rs ... 2025-04-20 09:21:32 +02:00
README.md ... 2025-04-19 13:53:41 +02:00
sale.rs ... 2025-04-20 09:21:32 +02:00
service.rs ... 2025-04-20 09:21:32 +02:00

Business Models

This directory contains the core business models used throughout the application for representing essential business objects like products, sales, and currency.

Overview

The business models are implemented as Rust structs and enums with serialization/deserialization support via Serde. These models implement the SledModel and Storable traits for persistence in the application's database layer.

Model Relationships

                                        ┌─────────────┐
                                        │  Customer   │
                                        └──────┬──────┘
                                               │
                                               ▼
┌─────────────┐     ┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│   Currency  │◄────┤   Product   │◄────┤  SaleItem   │◄────┤    Sale     │
└─────────────┘     └─────────────┘     └─────────────┘     └──────┬──────┘
                          ▲                                        │
                          │                                        │
                    ┌─────┴──────────┐                             │
                    │ProductComponent│                             │
                    └────────────────┘                             │
                                                                   │
┌─────────────┐     ┌─────────────┐     ┌─────────────┐            │
│   Currency  │◄────┤   Service   │◄────┤ ServiceItem │◄───────────┘
└─────────────┘     └─────────────┘     └─────────────┘
                                                                   │
                                                                   │
                                                                   ▼
                                        ┌─────────────┐     ┌─────────────┐
                                        │ InvoiceItem │◄────┤   Invoice   │
                                        └─────────────┘     └─────────────┘

Business Logic Relationships

  • Customer: The entity purchasing products or services
  • Product/Service: Defines what is being sold, including its base price
    • Can be marked as a template (is_template=true) to create copies for actual sales
  • Sale: Represents the transaction of selling products/services to customers, including tax calculations
    • Can be linked to a Service when the sale creates an ongoing service
  • Service: Represents an ongoing service provided to a customer
    • Created from a Product template when the product type is Service
  • Invoice: Represents the billing document for a sale, with payment tracking
    • Created from a Sale object to handle billing and payment tracking

Root Objects

  • Root objects are the ones stored directly in the DB
  • Root Objects are:
    • Customer
    • Currency
    • Product
    • Sale
    • Service
    • Invoice

Models

Currency (Root Object)

Represents a monetary value with an amount and currency code.

Properties:

  • amount: f64 - The monetary amount
  • currency_code: String - The currency code (e.g., "USD", "EUR")

Builder:

  • CurrencyBuilder - Provides a fluent interface for creating Currency instances

Customer (Root Object)

Represents a customer who can purchase products or services.

Properties:

  • id: u32 - Unique identifier
  • name: String - Customer name
  • description: String - Customer description
  • pubkey: String - Customer's public key
  • contact_ids: Vec - List of contact IDs
  • created_at: DateTime - Creation timestamp
  • updated_at: DateTime - Last update timestamp

Methods:

  • add_contact() - Adds a contact ID to the customer
  • remove_contact() - Removes a contact ID from the customer

Product

ProductType Enum

Categorizes products:

  • Product - Physical product
  • Service - Non-physical service

ProductStatus Enum

Tracks product availability:

  • Available - Product can be purchased
  • Unavailable - Product cannot be purchased

ProductComponent

Represents a component part of a product.

Properties:

  • id: u32 - Unique identifier
  • name: String - Component name
  • description: String - Component description
  • quantity: i32 - Number of this component
  • created_at: DateTime - Creation timestamp
  • updated_at: DateTime - Last update timestamp

Builder:

  • ProductComponentBuilder - Provides a fluent interface for creating ProductComponent instances

Product (Root Object)

Represents a product or service offered.

Properties:

  • id: i64 - Unique identifier
  • name: String - Product name
  • description: String - Product description
  • price: Currency - Product price
  • type_: ProductType - Product or Service
  • category: String - Product category
  • status: ProductStatus - Available or Unavailable
  • created_at: DateTime - Creation timestamp
  • updated_at: DateTime - Last update timestamp
  • max_amount: i64 - Maximum quantity available
  • purchase_till: DateTime - Deadline for purchasing
  • active_till: DateTime - When product/service expires
  • components: Vec - List of product components
  • is_template: bool - Whether this is a template product (to be added)

Methods:

  • add_component() - Adds a component to this product
  • set_purchase_period() - Updates purchase availability timeframe
  • set_active_period() - Updates active timeframe
  • is_purchasable() - Checks if product is available for purchase
  • is_active() - Checks if product is still active

Builder:

  • ProductBuilder - Provides a fluent interface for creating Product instances

Database Implementation:

  • Implements Storable trait for serialization
  • Implements SledModel trait with:
    • get_id() - Returns the ID as a string
    • db_prefix() - Returns "product" as the database prefix

Service (Root Object)

BillingFrequency Enum

Defines how often a service is billed:

  • Hourly - Billed by the hour
  • Daily - Billed daily
  • Weekly - Billed weekly
  • Monthly - Billed monthly
  • Yearly - Billed yearly

ServiceStatus Enum

Tracks the status of a service:

  • Active - Service is currently active
  • Paused - Service is temporarily paused
  • Cancelled - Service has been cancelled
  • Completed - Service has been completed

ServiceItem

Represents an item within a service.

Properties:

  • id: u32 - Unique identifier
  • service_id: u32 - Parent service ID
  • product_id: u32 - ID of the product this service is based on
  • name: String - Service name
  • description: String - Detailed description of the service item
  • comments: String - Additional notes or comments about the service item
  • quantity: i32 - Number of units
  • unit_price: Currency - Price per unit
  • subtotal: Currency - Total price before tax
  • tax_rate: f64 - Tax rate as a percentage
  • tax_amount: Currency - Calculated tax amount
  • is_taxable: bool - Whether this item is taxable
  • active_till: DateTime - When service expires

Service

Represents an ongoing service provided to a customer.

Properties:

  • id: u32 - Unique identifier
  • customer_id: u32 - ID of the customer receiving the service
  • total_amount: Currency - Total service amount including tax
  • status: ServiceStatus - Current service status
  • billing_frequency: BillingFrequency - How often the service is billed
  • service_date: DateTime - When service started
  • created_at: DateTime - Creation timestamp
  • updated_at: DateTime - Last update timestamp
  • items: Vec - List of items in the service
  • is_template: bool - Whether this is a template service (to be added)

Methods:

  • add_item() - Adds an item to the service and updates total
  • calculate_total() - Recalculates the total amount
  • update_status() - Updates the status of the service

Sale

SaleStatus Enum

Tracks the status of a sale:

  • Pending - Sale is in progress
  • Completed - Sale has been finalized
  • Cancelled - Sale has been cancelled

SaleItem

Represents an item within a sale.

Properties:

  • id: u32 - Unique identifier
  • sale_id: u32 - Parent sale ID
  • product_id: u32 - ID of the product sold
  • name: String - Product name at time of sale
  • description: String - Detailed description of the item
  • comments: String - Additional notes or comments about the item
  • quantity: i32 - Number of items purchased
  • unit_price: Currency - Price per unit
  • subtotal: Currency - Total price for this item before tax (calculated)
  • tax_rate: f64 - Tax rate as a percentage (e.g., 20.0 for 20%)
  • tax_amount: Currency - Calculated tax amount for this item
  • active_till: DateTime - When item/service expires

Methods:

  • total_with_tax() - Returns the total amount including tax

Builder:

  • SaleItemBuilder - Provides a fluent interface for creating SaleItem instances

Sale (Root Object)

Represents a complete sale transaction.

Properties:

  • id: u32 - Unique identifier
  • company_id: u32 - ID of the company making the sale
  • customer_id: u32 - ID of the customer making the purchase (to be added)
  • buyer_name: String - Name of the buyer
  • buyer_email: String - Email of the buyer
  • subtotal_amount: Currency - Total sale amount before tax
  • tax_amount: Currency - Total tax amount for the sale
  • total_amount: Currency - Total sale amount including tax
  • status: SaleStatus - Current sale status
  • service_id: Option - ID of the service created from this sale (to be added)
  • sale_date: DateTime - When sale occurred
  • created_at: DateTime - Creation timestamp
  • updated_at: DateTime - Last update timestamp
  • items: Vec - List of items in the sale

Methods:

  • add_item() - Adds an item to the sale and updates totals
  • update_status() - Updates the status of the sale
  • recalculate_totals() - Recalculates all totals based on items
  • create_service() - Creates a service from this sale (to be added)

Builder:

  • SaleBuilder - Provides a fluent interface for creating Sale instances

Database Implementation:

  • Implements Storable trait for serialization
  • Implements SledModel trait with:
    • get_id() - Returns the ID as a string
    • db_prefix() - Returns "sale" as the database prefix

Usage Examples

Creating a Currency

let price = CurrencyBuilder::new()
    .amount(29.99)
    .currency_code("USD")
    .build()
    .expect("Failed to build currency");

Creating a Product

// Create a currency using the builder
let price = CurrencyBuilder::new()
    .amount(29.99)
    .currency_code("USD")
    .build()
    .expect("Failed to build currency");

// Create a component using the builder
let component = ProductComponentBuilder::new()
    .id(1)
    .name("Basic Support")
    .description("24/7 email support")
    .quantity(1)
    .build()
    .expect("Failed to build product component");

// Create a product using the builder
let product = ProductBuilder::new()
    .id(1)
    .name("Premium Service")
    .description("Our premium service offering")
    .price(price)
    .type_(ProductType::Service)
    .category("Services")
    .status(ProductStatus::Available)
    .max_amount(100)
    .validity_days(30)
    .add_component(component)
    .build()
    .expect("Failed to build product");

Creating a Sale

let now = Utc::now();

// Create a currency using the builder
let unit_price = CurrencyBuilder::new()
    .amount(29.99)
    .currency_code("USD")
    .build()
    .expect("Failed to build currency");

// Create a sale item using the builder
let item = SaleItemBuilder::new()
    .id(1)
    .sale_id(1)
    .product_id(1)
    .name("Premium Service")
    .quantity(1)
    .unit_price(unit_price)
    .tax_rate(20.0) // 20% tax rate
    .active_till(now + Duration::days(30))
    .build()
    .expect("Failed to build sale item");

// Create a sale using the builder
let mut sale = SaleBuilder::new()
    .id(1)
    .company_id(101)
    .buyer_name("John Doe")
    .buyer_email("john.doe@example.com")
    .currency_code("USD")
    .status(SaleStatus::Pending)
    .add_item(item)
    .build()
    .expect("Failed to build sale");

// Update the sale status
sale.update_status(SaleStatus::Completed);

// The sale now contains:
// - subtotal_amount: The sum of all items before tax
// - tax_amount: The sum of all tax amounts
// - total_amount: The total including tax

Relationship Between Sale and Invoice

The Sale model represents what is sold to a customer (products or services), including tax calculations. The Invoice model represents the billing document for that sale.

An InvoiceItem can be linked to a Sale via the sale_id field, establishing a connection between what was sold and how it's billed.

// Create an invoice item linked to a sale
let invoice_item = InvoiceItemBuilder::new()
    .id(1)
    .invoice_id(1)
    .description("Premium Service")
    .amount(sale.total_amount.clone()) // Use the total amount from the sale
    .sale_id(sale.id) // Link to the sale
    .build()
    .expect("Failed to build invoice item");

Database Operations

The library provides model-specific convenience methods for common database operations:

// Insert a product
db.insert_product(&product).expect("Failed to insert product");

// Retrieve a product by ID
let retrieved_product = db.get_product(1).expect("Failed to retrieve product");

// List all products
let all_products = db.list_products().expect("Failed to list products");

// Delete a product
db.delete_product(1).expect("Failed to delete product");

These methods are available for all root objects:

  • insert_product, get_product, delete_product, list_products for Product
  • insert_currency, get_currency, delete_currency, list_currencies for Currency
  • insert_sale, get_sale, delete_sale, list_sales for Sale
  • insert_service, get_service, delete_service, list_services for Service
  • insert_invoice, get_invoice, delete_invoice, list_invoices for Invoice
  • insert_customer, get_customer, delete_customer, list_customers for Customer

Invoice (Root Object)

InvoiceStatus Enum

Tracks the status of an invoice:

  • Draft - Invoice is in draft state
  • Sent - Invoice has been sent to the customer
  • Paid - Invoice has been paid
  • Overdue - Invoice is past due date
  • Cancelled - Invoice has been cancelled

PaymentStatus Enum

Tracks the payment status of an invoice:

  • Unpaid - Invoice has not been paid
  • PartiallyPaid - Invoice has been partially paid
  • Paid - Invoice has been fully paid

Payment

Represents a payment made against an invoice.

Properties:

  • amount: Currency - Payment amount
  • date: DateTime - Payment date
  • method: String - Payment method
  • comment: String - Payment comment

InvoiceItem

Represents an item in an invoice.

Properties:

  • id: u32 - Unique identifier
  • invoice_id: u32 - Parent invoice ID
  • description: String - Item description
  • amount: Currency - Item amount
  • service_id: Option - ID of the service this item is for
  • sale_id: Option - ID of the sale this item is for

Methods:

  • link_to_service() - Links the invoice item to a service
  • link_to_sale() - Links the invoice item to a sale

Invoice

Represents an invoice sent to a customer.

Properties:

  • id: u32 - Unique identifier
  • customer_id: u32 - ID of the customer being invoiced
  • total_amount: Currency - Total invoice amount
  • balance_due: Currency - Amount still due
  • status: InvoiceStatus - Current invoice status
  • payment_status: PaymentStatus - Current payment status
  • issue_date: DateTime - When invoice was issued
  • due_date: DateTime - When payment is due
  • created_at: DateTime - Creation timestamp
  • updated_at: DateTime - Last update timestamp
  • items: Vec - List of items in the invoice
  • payments: Vec - List of payments made

Methods:

  • add_item() - Adds an item to the invoice
  • calculate_total() - Calculates the total amount
  • add_payment() - Adds a payment to the invoice
  • calculate_balance() - Calculates the balance due
  • update_payment_status() - Updates the payment status
  • update_status() - Updates the status of the invoice
  • is_overdue() - Checks if the invoice is overdue
  • check_if_overdue() - Marks the invoice as overdue if past due date

Relationships Between Models

Product/Service Templates and Instances

Products and Services can be marked as templates (is_template=true). When a customer purchases a product or service, a copy is created from the template with the specific details of what was sold.

Sale to Service Relationship

When a product of type Service is sold, a Service instance can be created from the Sale:

// Create a service from a sale
let service = sale.create_service(
    service_id,
    ServiceStatus::Active,
    BillingFrequency::Monthly
);

Sale to Invoice Relationship

An Invoice is created from a Sale to handle billing and payment tracking:

// Create an invoice from a sale
let invoice = Invoice::from_sale(
    invoice_id,
    sale,
    due_date
);

Customer-Centric View

The models allow tracking all customer interactions:

  • What products/services they've purchased (via Sale records)
  • What ongoing services they have (via Service records)
  • What they've been invoiced for (via Invoice records)
  • What they've paid (via Payment records in Invoices)
// Get all sales for a customer
let customer_sales = db.list_sales_by_customer(customer_id);

// Get all services for a customer
let customer_services = db.list_services_by_customer(customer_id);

// Get all invoices for a customer
let customer_invoices = db.list_invoices_by_customer(customer_id);