merge branches and cleanup db
This commit is contained in:
355
_archive/herodb_old/src/models/gov/README.md
Normal file
355
_archive/herodb_old/src/models/gov/README.md
Normal file
@@ -0,0 +1,355 @@
|
||||
# Corporate Governance Module
|
||||
|
||||
This directory contains the core data structures used for corporate governance functionality. These models serve as the foundation for managing companies, shareholders, meetings, voting, resolutions, committees, and more in any organizational context.
|
||||
|
||||
## Overview
|
||||
|
||||
The governance models implement the Serde traits (Serialize/Deserialize) and database traits (Storable, SledModel), which allows them to be stored and retrieved using the generic SledDB implementation. Each model provides:
|
||||
|
||||
- A struct definition with appropriate fields
|
||||
- Serde serialization through derive macros
|
||||
- Methods for database integration through the SledModel trait
|
||||
- Utility methods for common operations
|
||||
|
||||
## Core Models
|
||||
|
||||
### Company (`company.rs`)
|
||||
|
||||
The Company model represents a company entity with its basic information:
|
||||
|
||||
- **Company**: Main struct with fields for company information
|
||||
- Basic details: name, registration number, incorporation date
|
||||
- Contact information: email, phone, website, address
|
||||
- Business information: business type, industry, description
|
||||
- Status tracking: current status, timestamps
|
||||
- **CompanyStatus**: Enum for possible company statuses (Active, Inactive, Suspended)
|
||||
- **BusinessType**: String-based type with validation for business types (Corporation, Partnership, LLC, etc.)
|
||||
|
||||
Key methods:
|
||||
- `add_shareholder()`: Add a shareholder to the company
|
||||
- `link_to_circle()`: Link the company to a Circle for access control
|
||||
- `link_to_customer()`: Link the company to a Customer in the biz module
|
||||
- `get_resolutions()`: Get all resolutions for this company
|
||||
|
||||
### Shareholder (`shareholder.rs`)
|
||||
|
||||
The Shareholder model represents a shareholder of a company:
|
||||
|
||||
- **Shareholder**: Main struct with fields for shareholder information
|
||||
- Identifiers: id, company_id, user_id
|
||||
- Ownership details: shares, percentage
|
||||
- Type and timestamps: shareholder type, since date, created/updated timestamps
|
||||
- **ShareholderType**: Enum for possible shareholder types (Individual, Corporate)
|
||||
|
||||
Key methods:
|
||||
- `update_shares()`: Update the shares owned by this shareholder
|
||||
|
||||
### Meeting (`meeting.rs`)
|
||||
|
||||
The Meeting model represents a board meeting of a company:
|
||||
|
||||
- **Meeting**: Main struct with fields for meeting information
|
||||
- Basic details: id, company_id, title, date, location, description
|
||||
- Status and content: meeting status, minutes
|
||||
- Timestamps and attendees: created/updated timestamps, list of attendees
|
||||
- **Attendee**: Represents an attendee of a meeting
|
||||
- Details: id, meeting_id, user_id, name, role, status, created timestamp
|
||||
- **MeetingStatus**: Enum for possible meeting statuses (Scheduled, Completed, Cancelled)
|
||||
- **AttendeeRole**: Enum for possible attendee roles (Coordinator, Member, Secretary, etc.)
|
||||
- **AttendeeStatus**: Enum for possible attendee statuses (Confirmed, Pending, Declined)
|
||||
|
||||
Key methods:
|
||||
- `add_attendee()`: Add an attendee to the meeting
|
||||
- `update_status()`: Update the status of the meeting
|
||||
- `update_minutes()`: Update the meeting minutes
|
||||
- `find_attendee_by_user_id()`: Find an attendee by user ID
|
||||
- `confirmed_attendees()`: Get all confirmed attendees
|
||||
- `link_to_event()`: Link the meeting to a Calendar Event
|
||||
- `get_resolutions()`: Get all resolutions discussed in this meeting
|
||||
|
||||
### User (`user.rs`)
|
||||
|
||||
The User model represents a user in the governance system:
|
||||
|
||||
- **User**: Main struct with fields for user information
|
||||
- Basic details: id, name, email, password
|
||||
- Role information: company, role
|
||||
- Timestamps: created/updated timestamps
|
||||
|
||||
### Vote (`vote.rs`)
|
||||
|
||||
The Vote model represents a voting item for corporate decision-making:
|
||||
|
||||
- **Vote**: Main struct with fields for vote information
|
||||
- Basic details: id, company_id, title, description
|
||||
- Timing: start_date, end_date
|
||||
- Status and timestamps: vote status, created/updated timestamps
|
||||
- Options and results: list of vote options, list of ballots, private group
|
||||
- **VoteOption**: Represents an option in a vote
|
||||
- Details: id, vote_id, text, count, min_valid
|
||||
- **Ballot**: Represents a ballot cast by a user
|
||||
- Details: id, vote_id, user_id, vote_option_id, shares_count, created timestamp
|
||||
- **VoteStatus**: Enum for possible vote statuses (Open, Closed, Cancelled)
|
||||
|
||||
Key methods:
|
||||
- `add_option()`: Add a voting option to this vote
|
||||
- `add_ballot()`: Add a ballot to this vote
|
||||
- `get_resolution()`: Get the resolution associated with this vote
|
||||
|
||||
### Resolution (`resolution.rs`)
|
||||
|
||||
The Resolution model represents a board resolution:
|
||||
|
||||
- **Resolution**: Main struct with fields for resolution information
|
||||
- Identifiers: id, company_id, meeting_id, vote_id
|
||||
- Content: title, description, text
|
||||
- Status and tracking: resolution status, proposed_by, proposed_at, approved_at, rejected_at
|
||||
- Timestamps and approvals: created/updated timestamps, list of approvals
|
||||
- **Approval**: Represents an approval of a resolution by a board member
|
||||
- Details: id, resolution_id, user_id, name, approved, comments, created timestamp
|
||||
- **ResolutionStatus**: Enum for possible resolution statuses (Draft, Proposed, Approved, Rejected, Withdrawn)
|
||||
|
||||
Key methods:
|
||||
- `propose()`: Propose the resolution
|
||||
- `approve()`: Approve the resolution
|
||||
- `reject()`: Reject the resolution
|
||||
- `withdraw()`: Withdraw the resolution
|
||||
- `add_approval()`: Add an approval to the resolution
|
||||
- `find_approval_by_user_id()`: Find an approval by user ID
|
||||
- `get_approvals()`: Get all approvals
|
||||
- `approval_count()`: Get approval count
|
||||
- `rejection_count()`: Get rejection count
|
||||
- `link_to_meeting()`: Link this resolution to a meeting
|
||||
- `link_to_vote()`: Link this resolution to a vote
|
||||
- `get_meeting()`: Get the meeting associated with this resolution
|
||||
- `get_vote()`: Get the vote associated with this resolution
|
||||
|
||||
### Committee (`committee.rs`)
|
||||
|
||||
The Committee model represents a board committee:
|
||||
|
||||
- **Committee**: Main struct with fields for committee information
|
||||
- Basic details: id, company_id, name, description, purpose
|
||||
- Integration: circle_id
|
||||
- Timestamps and members: created/updated timestamps, list of members
|
||||
- **CommitteeMember**: Represents a member of a committee
|
||||
- Details: id, committee_id, user_id, name, role, since, created timestamp
|
||||
- **CommitteeRole**: Enum for possible committee roles (Chair, ViceChair, Secretary, Member, Advisor, Observer)
|
||||
|
||||
Key methods:
|
||||
- `add_member()`: Add a member to the committee
|
||||
- `find_member_by_user_id()`: Find a member by user ID
|
||||
- `remove_member()`: Remove a member from the committee
|
||||
- `link_to_circle()`: Link this committee to a Circle for access control
|
||||
- `get_member_users()`: Get all users who are members of this committee
|
||||
|
||||
## Model Relationships
|
||||
|
||||
The following diagram illustrates the relationships between the governance models:
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
Company --> |has many| Shareholder
|
||||
Company --> |has many| Meeting
|
||||
Company --> |has many| Resolution
|
||||
Company --> |has many| Vote
|
||||
Company --> |has many| Committee
|
||||
|
||||
Meeting --> |has many| Attendee
|
||||
Attendee --> |is a| User
|
||||
|
||||
Resolution --> |can be linked to| Meeting
|
||||
Resolution --> |can be linked to| Vote
|
||||
Resolution --> |has many| Approval
|
||||
|
||||
Vote --> |has many| VoteOption
|
||||
Vote --> |has many| Ballot
|
||||
Ballot --> |cast by| User
|
||||
|
||||
Committee --> |has many| CommitteeMember
|
||||
CommitteeMember --> |is a| User
|
||||
```
|
||||
|
||||
## Key Relationships
|
||||
|
||||
- **Company-Shareholder**: A company has multiple shareholders who own shares in the company
|
||||
- **Company-Meeting**: A company holds multiple meetings for governance purposes
|
||||
- **Company-Resolution**: A company creates resolutions that need to be approved
|
||||
- **Company-Vote**: A company conducts votes on various matters
|
||||
- **Company-Committee**: A company can have multiple committees for specialized governance functions
|
||||
- **Meeting-Resolution**: Resolutions can be discussed and approved in meetings
|
||||
- **Resolution-Vote**: Resolutions can be subject to formal voting
|
||||
- **User-Governance**: Users participate in governance as shareholders, meeting attendees, committee members, and by casting votes
|
||||
|
||||
## Integration with Other Modules
|
||||
|
||||
The governance module integrates with other modules in the system:
|
||||
|
||||
### Integration with Biz Module
|
||||
|
||||
- **Company-Customer**: Companies can be linked to customers in the biz module
|
||||
- **Company-Contract**: Companies can be linked to contracts in the biz module
|
||||
- **Shareholder-Customer**: Shareholders can be linked to customers in the biz module
|
||||
- **Meeting-Invoice**: Meetings can be linked to invoices for expense tracking
|
||||
|
||||
### Integration with MCC Module
|
||||
|
||||
- **Meeting-Calendar/Event**: Meetings can be linked to calendar events in the mcc module
|
||||
- **User-Contact**: Users can be linked to contacts in the mcc module
|
||||
- **Vote-Message**: Votes can be linked to messages for notifications
|
||||
|
||||
### Integration with Circle Module
|
||||
|
||||
- **Company-Circle**: Companies can be linked to circles for group-based access control
|
||||
- **User-Member**: Users can be linked to members for role-based permissions
|
||||
|
||||
## Detailed Data Model
|
||||
|
||||
A more detailed class diagram showing the fields and methods of each model:
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Company {
|
||||
+u32 id
|
||||
+String name
|
||||
+String registration_number
|
||||
+DateTime incorporation_date
|
||||
+String fiscal_year_end
|
||||
+String email
|
||||
+String phone
|
||||
+String website
|
||||
+String address
|
||||
+BusinessType business_type
|
||||
+String industry
|
||||
+String description
|
||||
+CompanyStatus status
|
||||
+DateTime created_at
|
||||
+DateTime updated_at
|
||||
+add_shareholder()
|
||||
+link_to_circle()
|
||||
+link_to_customer()
|
||||
+get_resolutions()
|
||||
}
|
||||
|
||||
class Shareholder {
|
||||
+u32 id
|
||||
+u32 company_id
|
||||
+u32 user_id
|
||||
+String name
|
||||
+f64 shares
|
||||
+f64 percentage
|
||||
+ShareholderType type_
|
||||
+DateTime since
|
||||
+DateTime created_at
|
||||
+DateTime updated_at
|
||||
+update_shares()
|
||||
}
|
||||
|
||||
class Meeting {
|
||||
+u32 id
|
||||
+u32 company_id
|
||||
+String title
|
||||
+DateTime date
|
||||
+String location
|
||||
+String description
|
||||
+MeetingStatus status
|
||||
+String minutes
|
||||
+DateTime created_at
|
||||
+DateTime updated_at
|
||||
+Vec~Attendee~ attendees
|
||||
+add_attendee()
|
||||
+update_status()
|
||||
+update_minutes()
|
||||
+find_attendee_by_user_id()
|
||||
+confirmed_attendees()
|
||||
+link_to_event()
|
||||
+get_resolutions()
|
||||
}
|
||||
|
||||
class User {
|
||||
+u32 id
|
||||
+String name
|
||||
+String email
|
||||
+String password
|
||||
+String company
|
||||
+String role
|
||||
+DateTime created_at
|
||||
+DateTime updated_at
|
||||
}
|
||||
|
||||
class Vote {
|
||||
+u32 id
|
||||
+u32 company_id
|
||||
+String title
|
||||
+String description
|
||||
+DateTime start_date
|
||||
+DateTime end_date
|
||||
+VoteStatus status
|
||||
+DateTime created_at
|
||||
+DateTime updated_at
|
||||
+Vec~VoteOption~ options
|
||||
+Vec~Ballot~ ballots
|
||||
+Vec~u32~ private_group
|
||||
+add_option()
|
||||
+add_ballot()
|
||||
+get_resolution()
|
||||
}
|
||||
|
||||
class Resolution {
|
||||
+u32 id
|
||||
+u32 company_id
|
||||
+Option~u32~ meeting_id
|
||||
+Option~u32~ vote_id
|
||||
+String title
|
||||
+String description
|
||||
+String text
|
||||
+ResolutionStatus status
|
||||
+u32 proposed_by
|
||||
+DateTime proposed_at
|
||||
+Option~DateTime~ approved_at
|
||||
+Option~DateTime~ rejected_at
|
||||
+DateTime created_at
|
||||
+DateTime updated_at
|
||||
+Vec~Approval~ approvals
|
||||
+propose()
|
||||
+approve()
|
||||
+reject()
|
||||
+add_approval()
|
||||
+link_to_meeting()
|
||||
+link_to_vote()
|
||||
}
|
||||
|
||||
class Committee {
|
||||
+u32 id
|
||||
+u32 company_id
|
||||
+String name
|
||||
+String description
|
||||
+String purpose
|
||||
+Option~u32~ circle_id
|
||||
+DateTime created_at
|
||||
+DateTime updated_at
|
||||
+Vec~CommitteeMember~ members
|
||||
+add_member()
|
||||
+find_member_by_user_id()
|
||||
+remove_member()
|
||||
+link_to_circle()
|
||||
+get_member_users()
|
||||
}
|
||||
|
||||
Company "1" -- "many" Shareholder: has
|
||||
Company "1" -- "many" Meeting: holds
|
||||
Company "1" -- "many" Vote: conducts
|
||||
Company "1" -- "many" Resolution: issues
|
||||
Company "1" -- "many" Committee: establishes
|
||||
Meeting "1" -- "many" Attendee: has
|
||||
Meeting "1" -- "many" Resolution: discusses
|
||||
Vote "1" -- "many" VoteOption: has
|
||||
Vote "1" -- "many" Ballot: collects
|
||||
Vote "1" -- "1" Resolution: decides
|
||||
Resolution "1" -- "many" Approval: receives
|
||||
Committee "1" -- "many" CommitteeMember: has
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
These models are used by the governance module to manage corporate governance. They are typically accessed through the database handlers that implement the generic SledDB interface.
|
149
_archive/herodb_old/src/models/gov/committee.rs
Normal file
149
_archive/herodb_old/src/models/gov/committee.rs
Normal file
@@ -0,0 +1,149 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use crate::db::{Model, Storable, DB, DbError, DbResult};
|
||||
use crate::models::gov::User;
|
||||
|
||||
/// CommitteeRole represents the role of a member in a committee
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum CommitteeRole {
|
||||
Chair,
|
||||
ViceChair,
|
||||
Secretary,
|
||||
Member,
|
||||
Advisor,
|
||||
Observer,
|
||||
}
|
||||
|
||||
/// CommitteeMember represents a member of a committee
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct CommitteeMember {
|
||||
pub id: u32,
|
||||
pub committee_id: u32,
|
||||
pub user_id: u32,
|
||||
pub name: String,
|
||||
pub role: CommitteeRole,
|
||||
pub since: DateTime<Utc>,
|
||||
pub created_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
/// Committee represents a board committee
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct Committee {
|
||||
pub id: u32,
|
||||
pub company_id: u32,
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
pub purpose: String,
|
||||
pub circle_id: Option<u32>, // Link to Circle for access control
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
pub members: Vec<CommitteeMember>,
|
||||
}
|
||||
|
||||
impl Committee {
|
||||
/// Create a new committee with default values
|
||||
pub fn new(
|
||||
id: u32,
|
||||
company_id: u32,
|
||||
name: String,
|
||||
description: String,
|
||||
purpose: String,
|
||||
) -> Self {
|
||||
let now = Utc::now();
|
||||
Self {
|
||||
id,
|
||||
company_id,
|
||||
name,
|
||||
description,
|
||||
purpose,
|
||||
circle_id: None,
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
members: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a member to the committee
|
||||
pub fn add_member(&mut self, user_id: u32, name: String, role: CommitteeRole) -> &CommitteeMember {
|
||||
let id = if self.members.is_empty() {
|
||||
1
|
||||
} else {
|
||||
self.members.iter().map(|m| m.id).max().unwrap_or(0) + 1
|
||||
};
|
||||
|
||||
let now = Utc::now();
|
||||
let member = CommitteeMember {
|
||||
id,
|
||||
committee_id: self.id,
|
||||
user_id,
|
||||
name,
|
||||
role,
|
||||
since: now,
|
||||
created_at: now,
|
||||
};
|
||||
|
||||
self.members.push(member);
|
||||
self.updated_at = now;
|
||||
self.members.last().unwrap()
|
||||
}
|
||||
|
||||
/// Find a member by user ID
|
||||
pub fn find_member_by_user_id(&self, user_id: u32) -> Option<&CommitteeMember> {
|
||||
self.members.iter().find(|m| m.user_id == user_id)
|
||||
}
|
||||
|
||||
/// Find a member by user ID (mutable version)
|
||||
pub fn find_member_by_user_id_mut(&mut self, user_id: u32) -> Option<&mut CommitteeMember> {
|
||||
self.members.iter_mut().find(|m| m.user_id == user_id)
|
||||
}
|
||||
|
||||
/// Remove a member from the committee
|
||||
pub fn remove_member(&mut self, member_id: u32) -> bool {
|
||||
let len = self.members.len();
|
||||
self.members.retain(|m| m.id != member_id);
|
||||
let removed = self.members.len() < len;
|
||||
|
||||
if removed {
|
||||
self.updated_at = Utc::now();
|
||||
}
|
||||
|
||||
removed
|
||||
}
|
||||
|
||||
/// Link this committee to a Circle for access control
|
||||
pub fn link_to_circle(&mut self, circle_id: u32) {
|
||||
self.circle_id = Some(circle_id);
|
||||
self.updated_at = Utc::now();
|
||||
}
|
||||
|
||||
/// Get all users who are members of this committee
|
||||
pub fn get_member_users(&self, db: &DB) -> DbResult<Vec<User>> {
|
||||
let mut users = Vec::new();
|
||||
|
||||
for member in &self.members {
|
||||
if let Ok(user) = db.get::<User>(member.user_id) {
|
||||
users.push(user);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(users)
|
||||
}
|
||||
}
|
||||
|
||||
// Implement Storable trait
|
||||
impl Storable for Committee {
|
||||
}
|
||||
|
||||
impl Storable for CommitteeMember {
|
||||
}
|
||||
|
||||
// Implement Model trait
|
||||
impl Model for Committee {
|
||||
fn get_id(&self) -> u32 {
|
||||
self.id
|
||||
}
|
||||
|
||||
fn db_prefix() -> &'static str {
|
||||
"committee"
|
||||
}
|
||||
}
|
185
_archive/herodb_old/src/models/gov/company.rs
Normal file
185
_archive/herodb_old/src/models/gov/company.rs
Normal file
@@ -0,0 +1,185 @@
|
||||
use crate::db::{Model, Storable, DbResult};
|
||||
use crate::db::db::DB;
|
||||
use super::shareholder::Shareholder; // Use super:: for sibling module
|
||||
use super::Resolution;
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Debug;
|
||||
|
||||
/// 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, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct BusinessType(pub String);
|
||||
|
||||
impl BusinessType {
|
||||
pub const CORPORATION: &'static str = "Corporation";
|
||||
pub const PARTNERSHIP: &'static str = "Partnership";
|
||||
pub const LLC: &'static str = "LLC";
|
||||
pub const COOP: &'static str = "Coop";
|
||||
pub const SINGLE: &'static str = "Single";
|
||||
pub const TWIN: &'static str = "Twin";
|
||||
pub const STARTER: &'static str = "Starter";
|
||||
pub const GLOBAL: &'static str = "Global";
|
||||
|
||||
/// Create a new BusinessType, validating that the type is one of the predefined types
|
||||
pub fn new(type_str: String) -> Result<Self, String> {
|
||||
if Self::is_valid(&type_str) {
|
||||
Ok(BusinessType(type_str))
|
||||
} else {
|
||||
Err(format!("Invalid business type: {}. Valid types are: {}",
|
||||
type_str, Self::valid_types().join(", ")))
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new BusinessType without validation (use with caution)
|
||||
pub fn new_unchecked(type_str: String) -> Self {
|
||||
BusinessType(type_str)
|
||||
}
|
||||
|
||||
/// Get the string value of the business type
|
||||
pub fn as_str(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
|
||||
/// Check if a string is a valid business type
|
||||
pub fn is_valid(type_str: &str) -> bool {
|
||||
Self::valid_types().contains(&type_str.to_string())
|
||||
}
|
||||
|
||||
/// Get a list of all valid business types
|
||||
pub fn valid_types() -> Vec<String> {
|
||||
vec![
|
||||
Self::CORPORATION.to_string(),
|
||||
Self::PARTNERSHIP.to_string(),
|
||||
Self::LLC.to_string(),
|
||||
Self::COOP.to_string(),
|
||||
Self::SINGLE.to_string(),
|
||||
Self::TWIN.to_string(),
|
||||
Self::STARTER.to_string(),
|
||||
Self::GLOBAL.to_string(),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
/// Company represents a company entity
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] // Added PartialEq
|
||||
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>,
|
||||
// Removed shareholders property
|
||||
}
|
||||
|
||||
impl Storable for Company{}
|
||||
|
||||
// Model requires get_id and db_prefix
|
||||
impl Model for Company {
|
||||
fn get_id(&self) -> u32 {
|
||||
self.id
|
||||
}
|
||||
|
||||
fn db_prefix() -> &'static str {
|
||||
"company" // Prefix for company records in the database
|
||||
}
|
||||
}
|
||||
|
||||
impl Company {
|
||||
/// Create a new company with default timestamps
|
||||
pub fn new(
|
||||
id: u32,
|
||||
name: String,
|
||||
registration_number: String,
|
||||
incorporation_date: DateTime<Utc>,
|
||||
fiscal_year_end: String,
|
||||
email: String,
|
||||
phone: String,
|
||||
website: String,
|
||||
address: String,
|
||||
business_type: BusinessType,
|
||||
industry: String,
|
||||
description: String,
|
||||
status: CompanyStatus,
|
||||
) -> Self {
|
||||
let now = Utc::now();
|
||||
Self {
|
||||
id,
|
||||
name,
|
||||
registration_number,
|
||||
incorporation_date,
|
||||
fiscal_year_end,
|
||||
email,
|
||||
phone,
|
||||
website,
|
||||
address,
|
||||
business_type,
|
||||
industry,
|
||||
description,
|
||||
status,
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a shareholder to the company, saving it to the database
|
||||
pub fn add_shareholder(
|
||||
&mut self,
|
||||
db: &mut DB, // Pass in the DB instance
|
||||
mut shareholder: Shareholder,
|
||||
) -> DbResult<()> {
|
||||
shareholder.company_id = self.id; // Set the company_id
|
||||
db.set(&shareholder)?; // Insert the shareholder into the DB
|
||||
self.updated_at = Utc::now();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Link this company to a Circle for access control
|
||||
pub fn link_to_circle(&mut self, _circle_id: u32) {
|
||||
// Implementation would involve updating a mapping in a separate database
|
||||
// For now, we'll just update the timestamp to indicate the change
|
||||
self.updated_at = Utc::now();
|
||||
}
|
||||
|
||||
/// Link this company to a Customer in the biz module
|
||||
pub fn link_to_customer(&mut self, _customer_id: u32) {
|
||||
// Implementation would involve updating a mapping in a separate database
|
||||
// For now, we'll just update the timestamp to indicate the change
|
||||
self.updated_at = Utc::now();
|
||||
}
|
||||
|
||||
/// Get all resolutions for this company
|
||||
pub fn get_resolutions(&self, db: &DB) -> DbResult<Vec<Resolution>> {
|
||||
let all_resolutions = db.list::<Resolution>()?;
|
||||
let company_resolutions = all_resolutions
|
||||
.into_iter()
|
||||
.filter(|resolution| resolution.company_id == self.id)
|
||||
.collect();
|
||||
|
||||
Ok(company_resolutions)
|
||||
}
|
||||
|
||||
// Future methods:
|
||||
// /// Get all committees for this company
|
||||
// pub fn get_committees(&self, db: &DB) -> DbResult<Vec<Committee>> { ... }
|
||||
//
|
||||
// /// Get all compliance requirements for this company
|
||||
// pub fn get_compliance_requirements(&self, db: &DB) -> DbResult<Vec<ComplianceRequirement>> { ... }
|
||||
}
|
188
_archive/herodb_old/src/models/gov/meeting.rs
Normal file
188
_archive/herodb_old/src/models/gov/meeting.rs
Normal file
@@ -0,0 +1,188 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use crate::db::{Model, Storable, DB, DbError, DbResult}; // Import traits from db module
|
||||
// use std::collections::HashMap; // Removed unused import
|
||||
|
||||
// use super::db::Model; // Removed old Model trait import
|
||||
|
||||
/// 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>,
|
||||
}
|
||||
|
||||
impl Attendee {
|
||||
/// Create a new attendee with default values
|
||||
pub fn new(
|
||||
id: u32,
|
||||
meeting_id: u32,
|
||||
user_id: u32,
|
||||
name: String,
|
||||
role: AttendeeRole,
|
||||
) -> Self {
|
||||
Self {
|
||||
id,
|
||||
meeting_id,
|
||||
user_id,
|
||||
name,
|
||||
role,
|
||||
status: AttendeeStatus::Pending,
|
||||
created_at: Utc::now(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Update the status of an attendee
|
||||
pub fn update_status(&mut self, status: AttendeeStatus) {
|
||||
self.status = status;
|
||||
}
|
||||
}
|
||||
|
||||
/// 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>,
|
||||
}
|
||||
|
||||
// Removed old Model trait implementation
|
||||
|
||||
impl Meeting {
|
||||
/// Create a new meeting with default values
|
||||
pub fn new(
|
||||
id: u32,
|
||||
company_id: u32,
|
||||
title: String,
|
||||
date: DateTime<Utc>,
|
||||
location: String,
|
||||
description: String,
|
||||
) -> Self {
|
||||
let now = Utc::now();
|
||||
Self {
|
||||
id,
|
||||
company_id,
|
||||
title,
|
||||
date,
|
||||
location,
|
||||
description,
|
||||
status: MeetingStatus::Scheduled,
|
||||
minutes: String::new(),
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
attendees: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Add an attendee to the meeting
|
||||
pub fn add_attendee(&mut self, attendee: Attendee) {
|
||||
// Make sure the attendee's meeting_id matches this meeting
|
||||
assert_eq!(self.id, attendee.meeting_id, "Attendee meeting_id must match meeting id");
|
||||
|
||||
// Check if the attendee already exists
|
||||
if !self.attendees.iter().any(|a| a.id == attendee.id) {
|
||||
self.attendees.push(attendee);
|
||||
self.updated_at = Utc::now();
|
||||
}
|
||||
}
|
||||
|
||||
/// Update the status of the meeting
|
||||
pub fn update_status(&mut self, status: MeetingStatus) {
|
||||
self.status = status;
|
||||
self.updated_at = Utc::now();
|
||||
}
|
||||
|
||||
/// Update the meeting minutes
|
||||
pub fn update_minutes(&mut self, minutes: String) {
|
||||
self.minutes = minutes;
|
||||
self.updated_at = Utc::now();
|
||||
}
|
||||
|
||||
/// Find an attendee by user ID
|
||||
pub fn find_attendee_by_user_id(&self, user_id: u32) -> Option<&Attendee> {
|
||||
self.attendees.iter().find(|a| a.user_id == user_id)
|
||||
}
|
||||
|
||||
/// Find an attendee by user ID (mutable version)
|
||||
pub fn find_attendee_by_user_id_mut(&mut self, user_id: u32) -> Option<&mut Attendee> {
|
||||
self.attendees.iter_mut().find(|a| a.user_id == user_id)
|
||||
}
|
||||
|
||||
/// Get all confirmed attendees
|
||||
pub fn confirmed_attendees(&self) -> Vec<&Attendee> {
|
||||
self.attendees
|
||||
.iter()
|
||||
.filter(|a| a.status == AttendeeStatus::Confirmed)
|
||||
.collect()
|
||||
}
|
||||
/// Link this meeting to a Calendar Event in the mcc module
|
||||
pub fn link_to_event(&mut self, _event_id: u32) -> DbResult<()> {
|
||||
// Implementation would involve updating a mapping in a separate database
|
||||
// For now, we'll just update the timestamp to indicate the change
|
||||
self.updated_at = Utc::now();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get all resolutions discussed in this meeting
|
||||
pub fn get_resolutions(&self, db: &DB) -> DbResult<Vec<super::Resolution>> {
|
||||
let all_resolutions = db.list::<super::Resolution>()?;
|
||||
let meeting_resolutions = all_resolutions
|
||||
.into_iter()
|
||||
.filter(|resolution| resolution.meeting_id == Some(self.id))
|
||||
.collect();
|
||||
|
||||
Ok(meeting_resolutions)
|
||||
}
|
||||
}
|
||||
|
||||
impl Storable for Meeting{}
|
||||
// Implement Model trait
|
||||
impl Model for Meeting {
|
||||
fn get_id(&self) -> u32 {
|
||||
self.id
|
||||
}
|
||||
|
||||
fn db_prefix() -> &'static str {
|
||||
"meeting"
|
||||
}
|
||||
}
|
20
_archive/herodb_old/src/models/gov/mod.rs
Normal file
20
_archive/herodb_old/src/models/gov/mod.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
pub mod company;
|
||||
pub mod shareholder;
|
||||
pub mod meeting;
|
||||
pub mod user;
|
||||
pub mod vote;
|
||||
pub mod resolution;
|
||||
// All modules:
|
||||
pub mod committee;
|
||||
|
||||
// Re-export all model types for convenience
|
||||
pub use company::{Company, CompanyStatus, BusinessType};
|
||||
pub use shareholder::{Shareholder, ShareholderType};
|
||||
pub use meeting::{Meeting, Attendee, MeetingStatus, AttendeeRole, AttendeeStatus};
|
||||
pub use user::User;
|
||||
pub use vote::{Vote, VoteOption, Ballot, VoteStatus};
|
||||
pub use resolution::{Resolution, ResolutionStatus, Approval};
|
||||
pub use committee::{Committee, CommitteeMember, CommitteeRole};
|
||||
|
||||
// Re-export database components from db module
|
||||
pub use crate::db::{DB, DBBuilder, Model, Storable, DbError, DbResult};
|
195
_archive/herodb_old/src/models/gov/resolution.rs
Normal file
195
_archive/herodb_old/src/models/gov/resolution.rs
Normal file
@@ -0,0 +1,195 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use crate::db::{Model, Storable, DB, DbError, DbResult};
|
||||
use crate::models::gov::{Meeting, Vote};
|
||||
|
||||
/// ResolutionStatus represents the status of a resolution
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum ResolutionStatus {
|
||||
Draft,
|
||||
Proposed,
|
||||
Approved,
|
||||
Rejected,
|
||||
Withdrawn,
|
||||
}
|
||||
|
||||
/// Resolution represents a board resolution
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct Resolution {
|
||||
pub id: u32,
|
||||
pub company_id: u32,
|
||||
pub meeting_id: Option<u32>,
|
||||
pub vote_id: Option<u32>,
|
||||
pub title: String,
|
||||
pub description: String,
|
||||
pub text: String,
|
||||
pub status: ResolutionStatus,
|
||||
pub proposed_by: u32, // User ID
|
||||
pub proposed_at: DateTime<Utc>,
|
||||
pub approved_at: Option<DateTime<Utc>>,
|
||||
pub rejected_at: Option<DateTime<Utc>>,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
pub approvals: Vec<Approval>,
|
||||
}
|
||||
|
||||
/// Approval represents an approval of a resolution by a board member
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct Approval {
|
||||
pub id: u32,
|
||||
pub resolution_id: u32,
|
||||
pub user_id: u32,
|
||||
pub name: String,
|
||||
pub approved: bool,
|
||||
pub comments: String,
|
||||
pub created_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
impl Resolution {
|
||||
/// Create a new resolution with default values
|
||||
pub fn new(
|
||||
id: u32,
|
||||
company_id: u32,
|
||||
title: String,
|
||||
description: String,
|
||||
text: String,
|
||||
proposed_by: u32,
|
||||
) -> Self {
|
||||
let now = Utc::now();
|
||||
Self {
|
||||
id,
|
||||
company_id,
|
||||
meeting_id: None,
|
||||
vote_id: None,
|
||||
title,
|
||||
description,
|
||||
text,
|
||||
status: ResolutionStatus::Draft,
|
||||
proposed_by,
|
||||
proposed_at: now,
|
||||
approved_at: None,
|
||||
rejected_at: None,
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
approvals: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Propose the resolution
|
||||
pub fn propose(&mut self) {
|
||||
self.status = ResolutionStatus::Proposed;
|
||||
self.proposed_at = Utc::now();
|
||||
self.updated_at = Utc::now();
|
||||
}
|
||||
|
||||
/// Approve the resolution
|
||||
pub fn approve(&mut self) {
|
||||
self.status = ResolutionStatus::Approved;
|
||||
self.approved_at = Some(Utc::now());
|
||||
self.updated_at = Utc::now();
|
||||
}
|
||||
|
||||
/// Reject the resolution
|
||||
pub fn reject(&mut self) {
|
||||
self.status = ResolutionStatus::Rejected;
|
||||
self.rejected_at = Some(Utc::now());
|
||||
self.updated_at = Utc::now();
|
||||
}
|
||||
|
||||
/// Withdraw the resolution
|
||||
pub fn withdraw(&mut self) {
|
||||
self.status = ResolutionStatus::Withdrawn;
|
||||
self.updated_at = Utc::now();
|
||||
}
|
||||
|
||||
/// Add an approval to the resolution
|
||||
pub fn add_approval(&mut self, user_id: u32, name: String, approved: bool, comments: String) -> &Approval {
|
||||
let id = if self.approvals.is_empty() {
|
||||
1
|
||||
} else {
|
||||
self.approvals.iter().map(|a| a.id).max().unwrap_or(0) + 1
|
||||
};
|
||||
|
||||
let approval = Approval {
|
||||
id,
|
||||
resolution_id: self.id,
|
||||
user_id,
|
||||
name,
|
||||
approved,
|
||||
comments,
|
||||
created_at: Utc::now(),
|
||||
};
|
||||
|
||||
self.approvals.push(approval);
|
||||
self.updated_at = Utc::now();
|
||||
self.approvals.last().unwrap()
|
||||
}
|
||||
|
||||
/// Find an approval by user ID
|
||||
pub fn find_approval_by_user_id(&self, user_id: u32) -> Option<&Approval> {
|
||||
self.approvals.iter().find(|a| a.user_id == user_id)
|
||||
}
|
||||
|
||||
/// Get all approvals
|
||||
pub fn get_approvals(&self) -> &[Approval] {
|
||||
&self.approvals
|
||||
}
|
||||
|
||||
/// Get approval count
|
||||
pub fn approval_count(&self) -> usize {
|
||||
self.approvals.iter().filter(|a| a.approved).count()
|
||||
}
|
||||
|
||||
/// Get rejection count
|
||||
pub fn rejection_count(&self) -> usize {
|
||||
self.approvals.iter().filter(|a| !a.approved).count()
|
||||
}
|
||||
|
||||
/// Link this resolution to a meeting
|
||||
pub fn link_to_meeting(&mut self, meeting_id: u32) {
|
||||
self.meeting_id = Some(meeting_id);
|
||||
self.updated_at = Utc::now();
|
||||
}
|
||||
|
||||
/// Link this resolution to a vote
|
||||
pub fn link_to_vote(&mut self, vote_id: u32) {
|
||||
self.vote_id = Some(vote_id);
|
||||
self.updated_at = Utc::now();
|
||||
}
|
||||
|
||||
/// Get the meeting associated with this resolution
|
||||
pub fn get_meeting(&self, db: &DB) -> DbResult<Option<Meeting>> {
|
||||
match self.meeting_id {
|
||||
Some(meeting_id) => {
|
||||
let meeting = db.get::<Meeting>(meeting_id)?;
|
||||
Ok(Some(meeting))
|
||||
}
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the vote associated with this resolution
|
||||
pub fn get_vote(&self, db: &DB) -> DbResult<Option<Vote>> {
|
||||
match self.vote_id {
|
||||
Some(vote_id) => {
|
||||
let vote = db.get::<Vote>(vote_id)?;
|
||||
Ok(Some(vote))
|
||||
}
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Storable for Resolution{}
|
||||
|
||||
// Implement Model trait
|
||||
impl Model for Resolution {
|
||||
fn get_id(&self) -> u32 {
|
||||
self.id
|
||||
}
|
||||
|
||||
fn db_prefix() -> &'static str {
|
||||
"resolution"
|
||||
}
|
||||
}
|
77
_archive/herodb_old/src/models/gov/shareholder.rs
Normal file
77
_archive/herodb_old/src/models/gov/shareholder.rs
Normal file
@@ -0,0 +1,77 @@
|
||||
use crate::db::{Model, Storable}; // Import db traits
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
// use std::collections::HashMap; // Removed unused import
|
||||
|
||||
// use super::db::Model; // Removed old Model trait import
|
||||
|
||||
/// 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, PartialEq)] // Added PartialEq
|
||||
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>,
|
||||
}
|
||||
|
||||
// Removed old Model trait implementation
|
||||
|
||||
impl Shareholder {
|
||||
/// Create a new shareholder with default timestamps
|
||||
pub fn new(
|
||||
id: u32,
|
||||
company_id: u32,
|
||||
user_id: u32,
|
||||
name: String,
|
||||
shares: f64,
|
||||
percentage: f64,
|
||||
type_: ShareholderType,
|
||||
) -> Self {
|
||||
let now = Utc::now();
|
||||
Self {
|
||||
id,
|
||||
company_id,
|
||||
user_id,
|
||||
name,
|
||||
shares,
|
||||
percentage,
|
||||
type_,
|
||||
since: now,
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
}
|
||||
}
|
||||
|
||||
/// Update the shares owned by this shareholder
|
||||
pub fn update_shares(&mut self, shares: f64, percentage: f64) {
|
||||
self.shares = shares;
|
||||
self.percentage = percentage;
|
||||
self.updated_at = Utc::now();
|
||||
}
|
||||
}
|
||||
|
||||
impl Storable for Shareholder{}
|
||||
|
||||
// Implement Model trait
|
||||
impl Model for Shareholder {
|
||||
fn get_id(&self) -> u32 {
|
||||
self.id
|
||||
}
|
||||
|
||||
fn db_prefix() -> &'static str {
|
||||
"shareholder"
|
||||
}
|
||||
}
|
56
_archive/herodb_old/src/models/gov/user.rs
Normal file
56
_archive/herodb_old/src/models/gov/user.rs
Normal file
@@ -0,0 +1,56 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use crate::db::{Model, Storable}; // Import db traits
|
||||
// use std::collections::HashMap; // Removed unused import
|
||||
|
||||
/// User represents a user in the governance 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>,
|
||||
}
|
||||
|
||||
// Removed old Model trait implementation
|
||||
|
||||
impl User {
|
||||
/// Create a new user with default timestamps
|
||||
pub fn new(
|
||||
id: u32,
|
||||
name: String,
|
||||
email: String,
|
||||
password: String,
|
||||
company: String,
|
||||
role: String,
|
||||
) -> Self {
|
||||
let now = Utc::now();
|
||||
Self {
|
||||
id,
|
||||
name,
|
||||
email,
|
||||
password,
|
||||
company,
|
||||
role,
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Storable for User{}
|
||||
|
||||
// Implement Model trait
|
||||
impl Model for User {
|
||||
fn get_id(&self) -> u32 {
|
||||
self.id
|
||||
}
|
||||
|
||||
fn db_prefix() -> &'static str {
|
||||
"user"
|
||||
}
|
||||
}
|
150
_archive/herodb_old/src/models/gov/vote.rs
Normal file
150
_archive/herodb_old/src/models/gov/vote.rs
Normal file
@@ -0,0 +1,150 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use crate::db::{Model, Storable, DB, DbError, DbResult}; // Import traits from db module
|
||||
// use std::collections::HashMap; // Removed unused import
|
||||
|
||||
// use super::db::Model; // Removed old Model trait import
|
||||
|
||||
/// 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 for corporate decision-making
|
||||
#[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 Storable for Vote{}
|
||||
|
||||
impl Vote {
|
||||
/// Create a new vote with default timestamps
|
||||
pub fn new(
|
||||
id: u32,
|
||||
company_id: u32,
|
||||
title: String,
|
||||
description: String,
|
||||
start_date: DateTime<Utc>,
|
||||
end_date: DateTime<Utc>,
|
||||
status: VoteStatus,
|
||||
) -> Self {
|
||||
let now = Utc::now();
|
||||
Self {
|
||||
id,
|
||||
company_id,
|
||||
title,
|
||||
description,
|
||||
start_date,
|
||||
end_date,
|
||||
status,
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
options: Vec::new(),
|
||||
ballots: Vec::new(),
|
||||
private_group: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a voting option to this vote
|
||||
pub fn add_option(&mut self, text: String, min_valid: i32) -> &VoteOption {
|
||||
let id = if self.options.is_empty() {
|
||||
1
|
||||
} else {
|
||||
self.options.iter().map(|o| o.id).max().unwrap_or(0) + 1
|
||||
};
|
||||
|
||||
let option = VoteOption {
|
||||
id,
|
||||
vote_id: self.id,
|
||||
text,
|
||||
count: 0,
|
||||
min_valid,
|
||||
};
|
||||
|
||||
self.options.push(option);
|
||||
self.options.last().unwrap()
|
||||
}
|
||||
|
||||
/// Add a ballot to this vote
|
||||
pub fn add_ballot(&mut self, user_id: u32, vote_option_id: u8, shares_count: i32) -> &Ballot {
|
||||
let id = if self.ballots.is_empty() {
|
||||
1
|
||||
} else {
|
||||
self.ballots.iter().map(|b| b.id).max().unwrap_or(0) + 1
|
||||
};
|
||||
|
||||
let ballot = Ballot {
|
||||
id,
|
||||
vote_id: self.id,
|
||||
user_id,
|
||||
vote_option_id,
|
||||
shares_count,
|
||||
created_at: Utc::now(),
|
||||
};
|
||||
|
||||
// Update the vote count for the selected option
|
||||
if let Some(option) = self.options.iter_mut().find(|o| o.id == vote_option_id) {
|
||||
option.count += shares_count;
|
||||
}
|
||||
|
||||
self.ballots.push(ballot);
|
||||
self.ballots.last().unwrap()
|
||||
}
|
||||
|
||||
/// Get the resolution associated with this vote
|
||||
pub fn get_resolution(&self, db: &DB) -> DbResult<Option<super::Resolution>> {
|
||||
let all_resolutions = db.list::<super::Resolution>()?;
|
||||
let vote_resolution = all_resolutions
|
||||
.into_iter()
|
||||
.find(|resolution| resolution.vote_id == Some(self.id));
|
||||
|
||||
Ok(vote_resolution)
|
||||
}
|
||||
}
|
||||
|
||||
// Implement Model trait
|
||||
impl Model for Vote {
|
||||
fn get_id(&self) -> u32 {
|
||||
self.id
|
||||
}
|
||||
|
||||
fn db_prefix() -> &'static str {
|
||||
"vote"
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user