implement contracts
This commit is contained in:
291
actix_mvc_app/src/models/contract.rs
Normal file
291
actix_mvc_app/src/models/contract.rs
Normal file
@@ -0,0 +1,291 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
/// Contract status enum
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum ContractStatus {
|
||||
Draft,
|
||||
PendingSignatures,
|
||||
Signed,
|
||||
Expired,
|
||||
Cancelled
|
||||
}
|
||||
|
||||
impl ContractStatus {
|
||||
pub fn as_str(&self) -> &str {
|
||||
match self {
|
||||
ContractStatus::Draft => "Draft",
|
||||
ContractStatus::PendingSignatures => "Pending Signatures",
|
||||
ContractStatus::Signed => "Signed",
|
||||
ContractStatus::Expired => "Expired",
|
||||
ContractStatus::Cancelled => "Cancelled",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Contract type enum
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum ContractType {
|
||||
Service,
|
||||
Employment,
|
||||
NDA,
|
||||
SLA,
|
||||
Other
|
||||
}
|
||||
|
||||
impl ContractType {
|
||||
pub fn as_str(&self) -> &str {
|
||||
match self {
|
||||
ContractType::Service => "Service Agreement",
|
||||
ContractType::Employment => "Employment Contract",
|
||||
ContractType::NDA => "Non-Disclosure Agreement",
|
||||
ContractType::SLA => "Service Level Agreement",
|
||||
ContractType::Other => "Other",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Contract signer status
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum SignerStatus {
|
||||
Pending,
|
||||
Signed,
|
||||
Rejected
|
||||
}
|
||||
|
||||
impl SignerStatus {
|
||||
pub fn as_str(&self) -> &str {
|
||||
match self {
|
||||
SignerStatus::Pending => "Pending",
|
||||
SignerStatus::Signed => "Signed",
|
||||
SignerStatus::Rejected => "Rejected",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Contract signer
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ContractSigner {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub email: String,
|
||||
pub status: SignerStatus,
|
||||
pub signed_at: Option<DateTime<Utc>>,
|
||||
pub comments: Option<String>,
|
||||
}
|
||||
|
||||
impl ContractSigner {
|
||||
/// Creates a new contract signer
|
||||
pub fn new(name: String, email: String) -> Self {
|
||||
Self {
|
||||
id: Uuid::new_v4().to_string(),
|
||||
name,
|
||||
email,
|
||||
status: SignerStatus::Pending,
|
||||
signed_at: None,
|
||||
comments: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Signs the contract
|
||||
pub fn sign(&mut self, comments: Option<String>) {
|
||||
self.status = SignerStatus::Signed;
|
||||
self.signed_at = Some(Utc::now());
|
||||
self.comments = comments;
|
||||
}
|
||||
|
||||
/// Rejects the contract
|
||||
pub fn reject(&mut self, comments: Option<String>) {
|
||||
self.status = SignerStatus::Rejected;
|
||||
self.signed_at = Some(Utc::now());
|
||||
self.comments = comments;
|
||||
}
|
||||
}
|
||||
|
||||
/// Contract revision
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ContractRevision {
|
||||
pub version: u32,
|
||||
pub content: String,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub created_by: String,
|
||||
pub comments: Option<String>,
|
||||
}
|
||||
|
||||
impl ContractRevision {
|
||||
/// Creates a new contract revision
|
||||
pub fn new(version: u32, content: String, created_by: String, comments: Option<String>) -> Self {
|
||||
Self {
|
||||
version,
|
||||
content,
|
||||
created_at: Utc::now(),
|
||||
created_by,
|
||||
comments,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Contract model
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Contract {
|
||||
pub id: String,
|
||||
pub title: String,
|
||||
pub description: String,
|
||||
pub contract_type: ContractType,
|
||||
pub status: ContractStatus,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
pub created_by: String,
|
||||
pub effective_date: Option<DateTime<Utc>>,
|
||||
pub expiration_date: Option<DateTime<Utc>>,
|
||||
pub signers: Vec<ContractSigner>,
|
||||
pub revisions: Vec<ContractRevision>,
|
||||
pub current_version: u32,
|
||||
pub organization_id: Option<String>,
|
||||
}
|
||||
|
||||
impl Contract {
|
||||
/// Creates a new contract
|
||||
pub fn new(title: String, description: String, contract_type: ContractType, created_by: String, organization_id: Option<String>) -> Self {
|
||||
Self {
|
||||
id: Uuid::new_v4().to_string(),
|
||||
title,
|
||||
description,
|
||||
contract_type,
|
||||
status: ContractStatus::Draft,
|
||||
created_at: Utc::now(),
|
||||
updated_at: Utc::now(),
|
||||
created_by,
|
||||
effective_date: None,
|
||||
expiration_date: None,
|
||||
signers: Vec::new(),
|
||||
revisions: Vec::new(),
|
||||
current_version: 0,
|
||||
organization_id,
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds a signer to the contract
|
||||
pub fn add_signer(&mut self, name: String, email: String) {
|
||||
let signer = ContractSigner::new(name, email);
|
||||
self.signers.push(signer);
|
||||
self.updated_at = Utc::now();
|
||||
}
|
||||
|
||||
/// Adds a revision to the contract
|
||||
pub fn add_revision(&mut self, content: String, created_by: String, comments: Option<String>) {
|
||||
let new_version = self.current_version + 1;
|
||||
let revision = ContractRevision::new(new_version, content, created_by, comments);
|
||||
self.revisions.push(revision);
|
||||
self.current_version = new_version;
|
||||
self.updated_at = Utc::now();
|
||||
}
|
||||
|
||||
/// Sends the contract for signatures
|
||||
pub fn send_for_signatures(&mut self) -> Result<(), String> {
|
||||
if self.revisions.is_empty() {
|
||||
return Err("Cannot send contract without content".to_string());
|
||||
}
|
||||
|
||||
if self.signers.is_empty() {
|
||||
return Err("Cannot send contract without signers".to_string());
|
||||
}
|
||||
|
||||
self.status = ContractStatus::PendingSignatures;
|
||||
self.updated_at = Utc::now();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Checks if all signers have signed
|
||||
pub fn is_fully_signed(&self) -> bool {
|
||||
if self.signers.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.signers.iter().all(|signer| signer.status == SignerStatus::Signed)
|
||||
}
|
||||
|
||||
/// Marks the contract as signed if all signers have signed
|
||||
pub fn finalize_if_signed(&mut self) -> bool {
|
||||
if self.is_fully_signed() {
|
||||
self.status = ContractStatus::Signed;
|
||||
self.updated_at = Utc::now();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Cancels the contract
|
||||
pub fn cancel(&mut self) {
|
||||
self.status = ContractStatus::Cancelled;
|
||||
self.updated_at = Utc::now();
|
||||
}
|
||||
|
||||
/// Gets the latest revision
|
||||
pub fn latest_revision(&self) -> Option<&ContractRevision> {
|
||||
self.revisions.last()
|
||||
}
|
||||
|
||||
/// Gets a specific revision
|
||||
pub fn get_revision(&self, version: u32) -> Option<&ContractRevision> {
|
||||
self.revisions.iter().find(|r| r.version == version)
|
||||
}
|
||||
|
||||
/// Gets the number of pending signers
|
||||
pub fn pending_signers_count(&self) -> usize {
|
||||
self.signers.iter().filter(|s| s.status == SignerStatus::Pending).count()
|
||||
}
|
||||
|
||||
/// Gets the number of signed signers
|
||||
pub fn signed_signers_count(&self) -> usize {
|
||||
self.signers.iter().filter(|s| s.status == SignerStatus::Signed).count()
|
||||
}
|
||||
|
||||
/// Gets the number of rejected signers
|
||||
pub fn rejected_signers_count(&self) -> usize {
|
||||
self.signers.iter().filter(|s| s.status == SignerStatus::Rejected).count()
|
||||
}
|
||||
}
|
||||
|
||||
/// Contract filter for listing contracts
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ContractFilter {
|
||||
pub status: Option<ContractStatus>,
|
||||
pub contract_type: Option<ContractType>,
|
||||
pub created_by: Option<String>,
|
||||
pub organization_id: Option<String>,
|
||||
}
|
||||
|
||||
/// Contract statistics
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ContractStatistics {
|
||||
pub total_contracts: usize,
|
||||
pub draft_contracts: usize,
|
||||
pub pending_signature_contracts: usize,
|
||||
pub signed_contracts: usize,
|
||||
pub expired_contracts: usize,
|
||||
pub cancelled_contracts: usize,
|
||||
}
|
||||
|
||||
impl ContractStatistics {
|
||||
/// Creates new contract statistics from a list of contracts
|
||||
pub fn new(contracts: &[Contract]) -> Self {
|
||||
let total_contracts = contracts.len();
|
||||
let draft_contracts = contracts.iter().filter(|c| c.status == ContractStatus::Draft).count();
|
||||
let pending_signature_contracts = contracts.iter().filter(|c| c.status == ContractStatus::PendingSignatures).count();
|
||||
let signed_contracts = contracts.iter().filter(|c| c.status == ContractStatus::Signed).count();
|
||||
let expired_contracts = contracts.iter().filter(|c| c.status == ContractStatus::Expired).count();
|
||||
let cancelled_contracts = contracts.iter().filter(|c| c.status == ContractStatus::Cancelled).count();
|
||||
|
||||
Self {
|
||||
total_contracts,
|
||||
draft_contracts,
|
||||
pending_signature_contracts,
|
||||
signed_contracts,
|
||||
expired_contracts,
|
||||
cancelled_contracts,
|
||||
}
|
||||
}
|
||||
}
|
@@ -4,10 +4,12 @@ pub mod ticket;
|
||||
pub mod calendar;
|
||||
pub mod governance;
|
||||
pub mod flow;
|
||||
pub mod contract;
|
||||
|
||||
// Re-export models for easier imports
|
||||
pub use user::User;
|
||||
pub use ticket::{Ticket, TicketComment, TicketStatus, TicketPriority};
|
||||
pub use calendar::{CalendarEvent, CalendarViewMode};
|
||||
pub use governance::{Proposal, ProposalStatus, Vote, VoteType, VotingResults, ProposalFilter};
|
||||
pub use flow::{Flow, FlowStep, FlowLog, FlowStatus, FlowType, StepStatus, FlowFilter, FlowStatistics};
|
||||
pub use flow::{Flow, FlowStep, FlowLog, FlowStatus, FlowType, StepStatus, FlowFilter, FlowStatistics};
|
||||
pub use contract::{Contract, ContractSigner, ContractRevision, ContractStatus, ContractType, SignerStatus, ContractFilter, ContractStatistics};
|
Reference in New Issue
Block a user