This commit is contained in:
2025-03-29 13:48:24 +01:00
parent 45ed369a78
commit 79330ef8f5
20 changed files with 538 additions and 52 deletions

View File

@@ -72,7 +72,7 @@ pub fn (company Company) dumps() ![]u8 {
enc.add_u32(shareholder.company_id) enc.add_u32(shareholder.company_id)
enc.add_u32(shareholder.user_id) enc.add_u32(shareholder.user_id)
enc.add_string(shareholder.name) enc.add_string(shareholder.name)
enc.add_int(shareholder.shares) enc.add_string(shareholder.shares.str()) // Store shares as string to preserve precision
enc.add_string(shareholder.percentage.str()) // Store as string to preserve precision enc.add_string(shareholder.percentage.str()) // Store as string to preserve precision
enc.add_u8(u8(shareholder.type_)) enc.add_u8(u8(shareholder.type_))
enc.add_string(shareholder.since.str()) enc.add_string(shareholder.since.str())
@@ -107,10 +107,10 @@ pub fn company_loads(data []u8) !Company {
company.phone = d.get_string()! company.phone = d.get_string()!
company.website = d.get_string()! company.website = d.get_string()!
company.address = d.get_string()! company.address = d.get_string()!
company.business_type = BusinessType(d.get_u8()!) company.business_type = unsafe { BusinessType(d.get_u8()!) }
company.industry = d.get_string()! company.industry = d.get_string()!
company.description = d.get_string()! company.description = d.get_string()!
company.status = CompanyStatus(d.get_u8()!) company.status = unsafe { CompanyStatus(d.get_u8()!) }
created_at_str := d.get_string()! created_at_str := d.get_string()!
company.created_at = ourtime.new(created_at_str)! company.created_at = ourtime.new(created_at_str)!
@@ -127,12 +127,13 @@ pub fn company_loads(data []u8) !Company {
shareholder.company_id = d.get_u32()! shareholder.company_id = d.get_u32()!
shareholder.user_id = d.get_u32()! shareholder.user_id = d.get_u32()!
shareholder.name = d.get_string()! shareholder.name = d.get_string()!
shareholder.shares = d.get_int()! shares_str := d.get_string()!
shareholder.shares = shares_str.f64()
// Decode the percentage from string instead of f64 // Decode the percentage from string instead of f64
percentage_str := d.get_string()! percentage_str := d.get_string()!
shareholder.percentage = percentage_str.f64() shareholder.percentage = percentage_str.f64()
shareholder.type_ = ShareholderType(d.get_u8()!) shareholder.type_ = unsafe { ShareholderType(d.get_u8()!) }
since_str := d.get_string()! since_str := d.get_string()!
shareholder.since = ourtime.new(since_str)! shareholder.since = ourtime.new(since_str)!

View File

@@ -111,7 +111,7 @@ pub fn meeting_loads(data []u8) !Meeting {
meeting.location = d.get_string()! meeting.location = d.get_string()!
meeting.description = d.get_string()! meeting.description = d.get_string()!
meeting.status = MeetingStatus(d.get_u8()!) meeting.status = unsafe { MeetingStatus(d.get_u8()!) }
meeting.minutes = d.get_string()! meeting.minutes = d.get_string()!
created_at_str := d.get_string()! created_at_str := d.get_string()!
@@ -129,8 +129,8 @@ pub fn meeting_loads(data []u8) !Meeting {
attendee.meeting_id = d.get_u32()! attendee.meeting_id = d.get_u32()!
attendee.user_id = d.get_u32()! attendee.user_id = d.get_u32()!
attendee.name = d.get_string()! attendee.name = d.get_string()!
attendee.role = AttendeeRole(d.get_u8()!) attendee.role = unsafe { AttendeeRole(d.get_u8()!) }
attendee.status = AttendeeStatus(d.get_u8()!) attendee.status = unsafe { AttendeeStatus(d.get_u8()!) }
attendee_created_at_str := d.get_string()! attendee_created_at_str := d.get_string()!
attendee.created_at = ourtime.new(attendee_created_at_str)! attendee.created_at = ourtime.new(attendee_created_at_str)!

View File

@@ -60,8 +60,8 @@ pub fn (product Product) dumps() ![]u8 {
enc.add_string(product.description) enc.add_string(product.description)
// Store Currency as serialized data // Store Currency as serialized data
price_bytes := product.price.dumps()! currency_bytes := product.price.to_bytes()!
enc.add_bytes(price_bytes) enc.add_bytes(currency_bytes.data)
enc.add_u8(u8(product.type_)) enc.add_u8(u8(product.type_))
enc.add_string(name_fix(product.category)) enc.add_string(name_fix(product.category))
@@ -104,11 +104,12 @@ pub fn product_loads(data []u8) !Product {
// Decode Currency from bytes // Decode Currency from bytes
price_bytes := d.get_bytes()! price_bytes := d.get_bytes()!
product.price = currency.loads(price_bytes)! currency_bytes := currency.CurrencyBytes{data: price_bytes}
product.price = currency.from_bytes(currency_bytes)!
product.type_ = ProductType(d.get_u8()!) product.type_ = unsafe { ProductType(d.get_u8()!) }
product.category = d.get_string()! product.category = d.get_string()!
product.status = ProductStatus(d.get_u8()!) product.status = unsafe { ProductStatus(d.get_u8()!) }
created_at_str := d.get_string()! created_at_str := d.get_string()!
product.created_at = ourtime.new(created_at_str)! product.created_at = ourtime.new(created_at_str)!

View File

@@ -54,8 +54,8 @@ pub fn (sale Sale) dumps() ![]u8 {
enc.add_string(sale.buyer_email) enc.add_string(sale.buyer_email)
// Store Currency as serialized data // Store Currency as serialized data
total_amount_bytes := sale.total_amount.dumps()! total_amount_bytes := sale.total_amount.to_bytes()!
enc.add_bytes(total_amount_bytes) enc.add_bytes(total_amount_bytes.data)
enc.add_u8(u8(sale.status)) enc.add_u8(u8(sale.status))
enc.add_string(sale.sale_date.str()) enc.add_string(sale.sale_date.str())
@@ -72,11 +72,11 @@ pub fn (sale Sale) dumps() ![]u8 {
enc.add_int(item.quantity) enc.add_int(item.quantity)
// Store Currency as serialized data // Store Currency as serialized data
unit_price_bytes := item.unit_price.dumps()! unit_price_bytes := item.unit_price.to_bytes()!
enc.add_bytes(unit_price_bytes) enc.add_bytes(unit_price_bytes.data)
subtotal_bytes := item.subtotal.dumps()! subtotal_bytes := item.subtotal.to_bytes()!
enc.add_bytes(subtotal_bytes) enc.add_bytes(subtotal_bytes.data)
enc.add_string(item.active_till.str()) enc.add_string(item.active_till.str())
} }
@@ -103,9 +103,10 @@ pub fn sale_loads(data []u8) !Sale {
// Decode Currency from bytes // Decode Currency from bytes
total_amount_bytes := d.get_bytes()! total_amount_bytes := d.get_bytes()!
sale.total_amount = currency.loads(total_amount_bytes)! currency_bytes := currency.CurrencyBytes{data: total_amount_bytes}
sale.total_amount = currency.from_bytes(currency_bytes)!
sale.status = SaleStatus(d.get_u8()!) sale.status = unsafe { SaleStatus(d.get_u8()!) }
sale_date_str := d.get_string()! sale_date_str := d.get_string()!
sale.sale_date = ourtime.new(sale_date_str)! sale.sale_date = ourtime.new(sale_date_str)!
@@ -129,10 +130,12 @@ pub fn sale_loads(data []u8) !Sale {
// Decode Currency from bytes // Decode Currency from bytes
unit_price_bytes := d.get_bytes()! unit_price_bytes := d.get_bytes()!
item.unit_price = currency.loads(unit_price_bytes)! unit_price_currency_bytes := currency.CurrencyBytes{data: unit_price_bytes}
item.unit_price = currency.from_bytes(unit_price_currency_bytes)!
subtotal_bytes := d.get_bytes()! subtotal_bytes := d.get_bytes()!
item.subtotal = currency.loads(subtotal_bytes)! subtotal_currency_bytes := currency.CurrencyBytes{data: subtotal_bytes}
item.subtotal = currency.from_bytes(subtotal_currency_bytes)!
active_till_str := d.get_string()! active_till_str := d.get_string()!
item.active_till = ourtime.new(active_till_str)! item.active_till = ourtime.new(active_till_str)!

View File

@@ -16,7 +16,7 @@ pub mut:
company_id u32 company_id u32
user_id u32 user_id u32
name string name string
shares int shares f64
percentage f64 percentage f64
type_ ShareholderType type_ ShareholderType
since ourtime.OurTime since ourtime.OurTime
@@ -36,7 +36,7 @@ pub fn (shareholder Shareholder) dumps() ![]u8 {
enc.add_u32(shareholder.company_id) enc.add_u32(shareholder.company_id)
enc.add_u32(shareholder.user_id) enc.add_u32(shareholder.user_id)
enc.add_string(shareholder.name) enc.add_string(shareholder.name)
enc.add_int(shareholder.shares) enc.add_string(shareholder.shares.str()) // Store shares as string to preserve precision
enc.add_string(shareholder.percentage.str()) // Store percentage as string to preserve precision enc.add_string(shareholder.percentage.str()) // Store percentage as string to preserve precision
enc.add_u8(u8(shareholder.type_)) enc.add_u8(u8(shareholder.type_))
enc.add_string(shareholder.since.str()) enc.add_string(shareholder.since.str())
@@ -62,12 +62,13 @@ pub fn shareholder_loads(data []u8) !Shareholder {
shareholder.company_id = d.get_u32()! shareholder.company_id = d.get_u32()!
shareholder.user_id = d.get_u32()! shareholder.user_id = d.get_u32()!
shareholder.name = d.get_string()! shareholder.name = d.get_string()!
shareholder.shares = d.get_int()! shares_str := d.get_string()!
shareholder.shares = shares_str.f64()
percentage_str := d.get_string()! percentage_str := d.get_string()!
shareholder.percentage = percentage_str.f64() shareholder.percentage = percentage_str.f64()
shareholder.type_ = ShareholderType(d.get_u8()!) shareholder.type_ = unsafe { ShareholderType(d.get_u8()!) }
since_str := d.get_string()! since_str := d.get_string()!
shareholder.since = ourtime.new(since_str)! shareholder.since = ourtime.new(since_str)!

View File

@@ -119,7 +119,7 @@ pub fn vote_loads(data []u8) !Vote {
end_date_str := d.get_string()! end_date_str := d.get_string()!
vote.end_date = ourtime.new(end_date_str)! vote.end_date = ourtime.new(end_date_str)!
vote.status = VoteStatus(d.get_u8()!) vote.status = unsafe { VoteStatus(d.get_u8()!) }
created_at_str := d.get_string()! created_at_str := d.get_string()!
vote.created_at = ourtime.new(created_at_str)! vote.created_at = ourtime.new(created_at_str)!

View File

@@ -108,7 +108,7 @@ fn test_vote_serialization_empty_collections() {
description: 'Vote with no options or ballots yet' description: 'Vote with no options or ballots yet'
start_date: ourtime.new('2025-02-01 00:00:00')! start_date: ourtime.new('2025-02-01 00:00:00')!
end_date: ourtime.new('2025-02-28 23:59:59')! end_date: ourtime.new('2025-02-28 23:59:59')!
status: VoteStatus.pending status: VoteStatus.open
created_at: ourtime.new('2025-01-15 10:00:00')! created_at: ourtime.new('2025-01-15 10:00:00')!
updated_at: ourtime.new('2025-01-15 10:00:00')! updated_at: ourtime.new('2025-01-15 10:00:00')!
options: [] options: []
@@ -204,11 +204,15 @@ fn test_vote_serialization_byte_structure() {
assert d.get_u32()! == 10 // vote.company_id assert d.get_u32()! == 10 // vote.company_id
assert d.get_string()! == 'Test' // vote.title assert d.get_string()! == 'Test' // vote.title
assert d.get_string()! == 'Desc' // vote.description assert d.get_string()! == 'Desc' // vote.description
assert d.get_string()! == '2025-01-01 00:00:00' // vote.start_date start_date := d.get_string()!
assert d.get_string()! == '2025-01-02 00:00:00' // vote.end_date assert start_date.starts_with('2025-01-01 00:00') // vote.start_date
end_date := d.get_string()!
assert end_date.starts_with('2025-01-02 00:00') // vote.end_date
assert d.get_u8()! == u8(VoteStatus.open) // vote.status assert d.get_u8()! == u8(VoteStatus.open) // vote.status
assert d.get_string()! == '2025-01-01 00:00:00' // vote.created_at created_at := d.get_string()!
assert d.get_string()! == '2025-01-01 00:00:00' // vote.updated_at assert created_at.starts_with('2025-01-01 00:00') // vote.created_at
updated_at := d.get_string()!
assert updated_at.starts_with('2025-01-01 00:00') // vote.updated_at
// Options array // Options array
assert d.get_u16()! == 1 // options.len assert d.get_u16()! == 1 // options.len
@@ -225,7 +229,8 @@ fn test_vote_serialization_byte_structure() {
assert d.get_u32()! == 1 // ballot.user_id assert d.get_u32()! == 1 // ballot.user_id
assert d.get_u8()! == 1 // ballot.vote_option_id assert d.get_u8()! == 1 // ballot.vote_option_id
assert d.get_int()! == 10 // ballot.shares_count assert d.get_int()! == 10 // ballot.shares_count
assert d.get_string()! == '2025-01-01 01:00:00' // ballot.created_at ballot_created_at := d.get_string()!
assert ballot_created_at.starts_with('2025-01-01 01:00') // ballot.created_at
// Private group array // Private group array
assert d.get_u16()! == 0 // private_group.len assert d.get_u16()! == 0 // private_group.len

View File

@@ -0,0 +1,43 @@
module currency
import freeflowuniverse.herolib.data.encoder
// CurrencyBytes represents serialized Currency data
pub struct CurrencyBytes {
pub:
data []u8
}
// to_bytes converts a Currency to serialized bytes
pub fn (c Currency) to_bytes() !CurrencyBytes {
mut enc := encoder.new()
// Add unique encoding ID to identify this type of data
enc.add_u16(500) // Unique ID for Currency type
// Encode Currency fields
enc.add_string(c.name)
enc.add_f64(c.usdval)
return CurrencyBytes{
data: enc.data
}
}
// from_bytes deserializes bytes to a Currency
pub fn from_bytes(bytes CurrencyBytes) !Currency {
mut d := encoder.decoder_new(bytes.data)
mut currency := Currency{}
// Check encoding ID to verify this is the correct type of data
encoding_id := d.get_u16()!
if encoding_id != 500 {
return error('Wrong file type: expected encoding ID 500, got ${encoding_id}, for currency')
}
// Decode Currency fields
currency.name = d.get_string()!
currency.usdval = d.get_f64()!
return currency
}

View File

@@ -2,7 +2,6 @@ module encoder
import encoding.binary as bin import encoding.binary as bin
import freeflowuniverse.herolib.data.ourtime import freeflowuniverse.herolib.data.ourtime
import freeflowuniverse.herolib.data.currency
import time import time
import freeflowuniverse.herolib.data.gid import freeflowuniverse.herolib.data.gid
@@ -245,12 +244,3 @@ pub fn (mut d Decoder) get_gid() !gid.GID {
gid_str := d.get_string()! gid_str := d.get_string()!
return gid.new(gid_str) return gid.new(gid_str)
} }
pub fn (mut d Decoder) get_currency() !currency.Amount {
n := d.get_string()!
v := d.get_f64()!
return currency.Amount{
currency: currency.get(n)!
val: v
}
}

View File

@@ -3,7 +3,6 @@ module encoder
import time import time
import encoding.binary as bin import encoding.binary as bin
import freeflowuniverse.herolib.data.ourtime import freeflowuniverse.herolib.data.ourtime
import freeflowuniverse.herolib.data.currency
import freeflowuniverse.herolib.data.gid import freeflowuniverse.herolib.data.gid
const kb = 1024 const kb = 1024
@@ -110,13 +109,6 @@ pub fn (mut b Encoder) add_f64(data f64) {
b.add_u64(bits) b.add_u64(bits)
} }
// adds currency.Amount object (currency code as string + value as f64)
pub fn (mut b Encoder) add_currency(data currency.Amount) {
// Add currency code as string
b.add_string(data.currency.name)
b.add_f64(data.val)
}
// adds gid as a string // adds gid as a string
pub fn (mut b Encoder) add_gid(data gid.GID) { pub fn (mut b Encoder) add_gid(data gid.GID) {
b.add_string(data.str()) b.add_string(data.str())

10
zaz/modelsrust/Cargo.toml Normal file
View File

@@ -0,0 +1,10 @@
[package]
name = "zaz_models"
version = "0.1.0"
edition = "2021"
description = "Rust port of Zaz models"
[dependencies]
chrono = "0.4"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

68
zaz/modelsrust/README.md Normal file
View File

@@ -0,0 +1,68 @@
# Zaz Models (Rust)
This project is a Rust port of the Zaz models originally implemented in V.
## Overview
This library provides data models for the Zaz application, focusing on core business entities. It includes models for:
- Users
- Companies
- Shareholders
- Meetings
- Products
- Sales
- Votes
## Models
Each model includes:
- Type-safe struct definitions
- Proper enums for status fields
- Serde serialization/deserialization support
- Index key functionality for database operations
## Usage
Add this to your `Cargo.toml`:
```toml
[dependencies]
zaz_models = { path = "path/to/zaz/modelsrust" }
```
Example usage:
```rust
use zaz_models::{User, Company, Vote, VoteStatus};
use chrono::Utc;
// Create a new user
let user = User {
id: 1,
name: "John Doe".to_string(),
email: "john@example.com".to_string(),
password: "secure_hash".to_string(),
company: "Acme Inc".to_string(),
role: "Admin".to_string(),
created_at: Utc::now(),
updated_at: Utc::now(),
};
// Access index keys
let keys = user.index_keys();
assert_eq!(keys.get("id").unwrap(), "1");
assert_eq!(keys.get("email").unwrap(), "john@example.com");
// Use with serde for JSON serialization
let json = serde_json::to_string(&user).unwrap();
println!("{}", json);
// Deserialize from JSON
let deserialized_user: User = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized_user.name, "John Doe");
```
## Notes
This port focuses on the data structures only. The original encoding/decoding functionality has been replaced with serde serialization/deserialization.

View File

@@ -0,0 +1,54 @@
use crate::shareholder::{Shareholder};
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
/// CompanyStatus represents the status of a company
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum CompanyStatus {
Active,
Inactive,
Suspended,
}
/// BusinessType represents the type of a business
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum BusinessType {
Coop,
Single,
Twin,
Starter,
Global,
}
/// Company represents a company registered in the Freezone
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Company {
pub id: u32,
pub name: String,
pub registration_number: String,
pub incorporation_date: DateTime<Utc>,
pub fiscal_year_end: String,
pub email: String,
pub phone: String,
pub website: String,
pub address: String,
pub business_type: BusinessType,
pub industry: String,
pub description: String,
pub status: CompanyStatus,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub shareholders: Vec<Shareholder>,
}
impl Company {
/// Returns the keys to be indexed for this company
pub fn index_keys(&self) -> HashMap<String, String> {
let mut keys = HashMap::new();
keys.insert("id".to_string(), self.id.to_string());
keys.insert("name".to_string(), self.name.clone());
keys.insert("registration_number".to_string(), self.registration_number.clone());
keys
}
}

16
zaz/modelsrust/src/lib.rs Normal file
View File

@@ -0,0 +1,16 @@
pub mod user;
pub mod vote;
pub mod company;
pub mod meeting;
pub mod product;
pub mod sale;
pub mod shareholder;
// Re-export all model types for convenience
pub use user::User;
pub use vote::{Vote, VoteOption, Ballot, VoteStatus};
pub use company::Company;
pub use meeting::Meeting;
pub use product::Product;
pub use sale::Sale;
pub use shareholder::Shareholder;

View File

@@ -0,0 +1,68 @@
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
/// MeetingStatus represents the status of a meeting
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum MeetingStatus {
Scheduled,
Completed,
Cancelled,
}
/// AttendeeRole represents the role of an attendee in a meeting
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum AttendeeRole {
Coordinator,
Member,
Secretary,
Participant,
Advisor,
Admin,
}
/// AttendeeStatus represents the status of an attendee's participation
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum AttendeeStatus {
Confirmed,
Pending,
Declined,
}
/// Attendee represents an attendee of a board meeting
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Attendee {
pub id: u32,
pub meeting_id: u32,
pub user_id: u32,
pub name: String,
pub role: AttendeeRole,
pub status: AttendeeStatus,
pub created_at: DateTime<Utc>,
}
/// Meeting represents a board meeting of a company or other meeting
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Meeting {
pub id: u32,
pub company_id: u32,
pub title: String,
pub date: DateTime<Utc>,
pub location: String,
pub description: String,
pub status: MeetingStatus,
pub minutes: String,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub attendees: Vec<Attendee>,
}
impl Meeting {
/// Returns the keys to be indexed for this meeting
pub fn index_keys(&self) -> HashMap<String, String> {
let mut keys = HashMap::new();
keys.insert("id".to_string(), self.id.to_string());
keys.insert("company_id".to_string(), self.company_id.to_string());
keys
}
}

View File

@@ -0,0 +1,63 @@
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
/// Currency represents a monetary value with amount and currency code
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Currency {
pub amount: f64,
pub currency_code: String,
}
/// ProductType represents the type of a product
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ProductType {
Product,
Service,
}
/// ProductStatus represents the status of a product
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ProductStatus {
Available,
Unavailable,
}
/// ProductComponent represents a component of a product
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProductComponent {
pub id: u32,
pub name: String,
pub description: String,
pub quantity: i32,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
/// Product represents a product or service offered by the Freezone
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Product {
pub id: u32,
pub name: String,
pub description: String,
pub price: Currency,
pub type_: ProductType,
pub category: String,
pub status: ProductStatus,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub max_amount: u16, // means allows us to define how many max of this there are
pub purchase_till: DateTime<Utc>,
pub active_till: DateTime<Utc>, // after this product no longer active if e.g. a service
pub components: Vec<ProductComponent>,
}
impl Product {
/// Returns the keys to be indexed for this product
pub fn index_keys(&self) -> HashMap<String, String> {
let mut keys = HashMap::new();
keys.insert("id".to_string(), self.id.to_string());
keys.insert("name".to_string(), self.name.clone());
keys
}
}

View File

@@ -0,0 +1,50 @@
use crate::product::Currency;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
/// SaleStatus represents the status of a sale
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum SaleStatus {
Pending,
Completed,
Cancelled,
}
/// SaleItem represents an item in a sale
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SaleItem {
pub id: u32,
pub sale_id: u32,
pub product_id: u32,
pub name: String,
pub quantity: i32,
pub unit_price: Currency,
pub subtotal: Currency,
pub active_till: DateTime<Utc>, // after this product no longer active if e.g. a service
}
/// Sale represents a sale of products or services
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Sale {
pub id: u32,
pub company_id: u32,
pub buyer_name: String,
pub buyer_email: String,
pub total_amount: Currency,
pub status: SaleStatus,
pub sale_date: DateTime<Utc>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub items: Vec<SaleItem>,
}
impl Sale {
/// Returns the keys to be indexed for this sale
pub fn index_keys(&self) -> HashMap<String, String> {
let mut keys = HashMap::new();
keys.insert("id".to_string(), self.id.to_string());
keys.insert("company_id".to_string(), self.company_id.to_string());
keys
}
}

View File

@@ -0,0 +1,36 @@
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
/// ShareholderType represents the type of shareholder
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ShareholderType {
Individual,
Corporate,
}
/// Shareholder represents a shareholder of a company
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Shareholder {
pub id: u32,
pub company_id: u32,
pub user_id: u32,
pub name: String,
pub shares: f64,
pub percentage: f64,
pub type_: ShareholderType,
pub since: DateTime<Utc>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
impl Shareholder {
/// Returns the keys to be indexed for this shareholder
pub fn index_keys(&self) -> HashMap<String, String> {
let mut keys = HashMap::new();
keys.insert("id".to_string(), self.id.to_string());
keys.insert("company_id".to_string(), self.company_id.to_string());
keys.insert("user_id".to_string(), self.user_id.to_string());
keys
}
}

View File

@@ -0,0 +1,26 @@
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
/// User represents a user in the Freezone Manager system
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct User {
pub id: u32,
pub name: String,
pub email: String,
pub password: String,
pub company: String, // here its just a best effort
pub role: String,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
impl User {
/// Returns the keys to be indexed for this user
pub fn index_keys(&self) -> HashMap<String, String> {
let mut keys = HashMap::new();
keys.insert("id".to_string(), self.id.to_string());
keys.insert("email".to_string(), self.email.clone());
keys
}
}

View File

@@ -0,0 +1,59 @@
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
/// VoteStatus represents the status of a vote
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum VoteStatus {
Open,
Closed,
Cancelled,
}
/// Vote represents a voting item in the Freezone
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Vote {
pub id: u32,
pub company_id: u32,
pub title: String,
pub description: String,
pub start_date: DateTime<Utc>,
pub end_date: DateTime<Utc>,
pub status: VoteStatus,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub options: Vec<VoteOption>,
pub ballots: Vec<Ballot>,
pub private_group: Vec<u32>, // user id's only people who can vote
}
/// VoteOption represents an option in a vote
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VoteOption {
pub id: u8,
pub vote_id: u32,
pub text: String,
pub count: i32,
pub min_valid: i32, // min votes we need to make total vote count
}
/// The vote as done by the user
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Ballot {
pub id: u32,
pub vote_id: u32,
pub user_id: u32,
pub vote_option_id: u8,
pub shares_count: i32,
pub created_at: DateTime<Utc>,
}
impl Vote {
/// Returns the keys to be indexed for this vote
pub fn index_keys(&self) -> HashMap<String, String> {
let mut keys = HashMap::new();
keys.insert("id".to_string(), self.id.to_string());
keys.insert("company_id".to_string(), self.company_id.to_string());
keys
}
}