implement contracts
This commit is contained in:
		
							
								
								
									
										344
									
								
								actix_mvc_app/src/controllers/contract.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										344
									
								
								actix_mvc_app/src/controllers/contract.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,344 @@
 | 
			
		||||
use actix_web::{web, HttpResponse, Responder, Result};
 | 
			
		||||
use tera::{Context, Tera};
 | 
			
		||||
use chrono::{Utc, Duration};
 | 
			
		||||
use uuid::Uuid;
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
use crate::models::contract::{Contract, ContractStatus, ContractType, ContractStatistics, ContractSigner, ContractRevision, SignerStatus, ContractFilter};
 | 
			
		||||
use crate::controllers::auth::Claims;
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Deserialize)]
 | 
			
		||||
pub struct ContractForm {
 | 
			
		||||
    pub title: String,
 | 
			
		||||
    pub description: String,
 | 
			
		||||
    pub contract_type: String,
 | 
			
		||||
    pub content: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Deserialize)]
 | 
			
		||||
pub struct SignerForm {
 | 
			
		||||
    pub name: String,
 | 
			
		||||
    pub email: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct ContractController;
 | 
			
		||||
 | 
			
		||||
impl ContractController {
 | 
			
		||||
    // Display the contracts dashboard
 | 
			
		||||
    pub async fn index(tmpl: web::Data<Tera>) -> Result<HttpResponse> {
 | 
			
		||||
        let mut context = Context::new();
 | 
			
		||||
        
 | 
			
		||||
        let contracts = Self::get_mock_contracts();
 | 
			
		||||
        let stats = ContractStatistics::new(&contracts);
 | 
			
		||||
        
 | 
			
		||||
        // Add active_page for navigation highlighting
 | 
			
		||||
        context.insert("active_page", &"contracts");
 | 
			
		||||
        
 | 
			
		||||
        // Add stats
 | 
			
		||||
        context.insert("stats", &serde_json::to_value(stats).unwrap());
 | 
			
		||||
        
 | 
			
		||||
        // Add recent contracts
 | 
			
		||||
        let recent_contracts: Vec<serde_json::Map<String, serde_json::Value>> = contracts
 | 
			
		||||
            .iter()
 | 
			
		||||
            .take(5)
 | 
			
		||||
            .map(|c| Self::contract_to_json(c))
 | 
			
		||||
            .collect();
 | 
			
		||||
        
 | 
			
		||||
        context.insert("recent_contracts", &recent_contracts);
 | 
			
		||||
        
 | 
			
		||||
        // Add pending signature contracts
 | 
			
		||||
        let pending_signature_contracts: Vec<serde_json::Map<String, serde_json::Value>> = contracts
 | 
			
		||||
            .iter()
 | 
			
		||||
            .filter(|c| c.status == ContractStatus::PendingSignatures)
 | 
			
		||||
            .map(|c| Self::contract_to_json(c))
 | 
			
		||||
            .collect();
 | 
			
		||||
        
 | 
			
		||||
        context.insert("pending_signature_contracts", &pending_signature_contracts);
 | 
			
		||||
        
 | 
			
		||||
        // Add draft contracts
 | 
			
		||||
        let draft_contracts: Vec<serde_json::Map<String, serde_json::Value>> = contracts
 | 
			
		||||
            .iter()
 | 
			
		||||
            .filter(|c| c.status == ContractStatus::Draft)
 | 
			
		||||
            .map(|c| Self::contract_to_json(c))
 | 
			
		||||
            .collect();
 | 
			
		||||
        
 | 
			
		||||
        context.insert("draft_contracts", &draft_contracts);
 | 
			
		||||
        
 | 
			
		||||
        Ok(HttpResponse::Ok().content_type("text/html").body(
 | 
			
		||||
            tmpl.render("contracts/index.html", &context).unwrap()
 | 
			
		||||
        ))
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Display the list of all contracts
 | 
			
		||||
    pub async fn list(tmpl: web::Data<Tera>) -> Result<HttpResponse> {
 | 
			
		||||
        let mut context = Context::new();
 | 
			
		||||
        
 | 
			
		||||
        let contracts = Self::get_mock_contracts();
 | 
			
		||||
        let contracts_data: Vec<serde_json::Map<String, serde_json::Value>> = contracts
 | 
			
		||||
            .iter()
 | 
			
		||||
            .map(|c| Self::contract_to_json(c))
 | 
			
		||||
            .collect();
 | 
			
		||||
        
 | 
			
		||||
        // Add active_page for navigation highlighting
 | 
			
		||||
        context.insert("active_page", &"contracts");
 | 
			
		||||
        
 | 
			
		||||
        context.insert("contracts", &contracts_data);
 | 
			
		||||
        context.insert("filter", &"all");
 | 
			
		||||
        
 | 
			
		||||
        Ok(HttpResponse::Ok().content_type("text/html").body(
 | 
			
		||||
            tmpl.render("contracts/contracts.html", &context).unwrap()
 | 
			
		||||
        ))
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Display the list of user's contracts
 | 
			
		||||
    pub async fn my_contracts(tmpl: web::Data<Tera>) -> Result<HttpResponse> {
 | 
			
		||||
        let mut context = Context::new();
 | 
			
		||||
        
 | 
			
		||||
        let contracts = Self::get_mock_contracts();
 | 
			
		||||
        let contracts_data: Vec<serde_json::Map<String, serde_json::Value>> = contracts
 | 
			
		||||
            .iter()
 | 
			
		||||
            .map(|c| Self::contract_to_json(c))
 | 
			
		||||
            .collect();
 | 
			
		||||
        
 | 
			
		||||
        // Add active_page for navigation highlighting
 | 
			
		||||
        context.insert("active_page", &"contracts");
 | 
			
		||||
        
 | 
			
		||||
        context.insert("contracts", &contracts_data);
 | 
			
		||||
        
 | 
			
		||||
        Ok(HttpResponse::Ok().content_type("text/html").body(
 | 
			
		||||
            tmpl.render("contracts/my_contracts.html", &context).unwrap()
 | 
			
		||||
        ))
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Display a specific contract
 | 
			
		||||
    pub async fn detail(tmpl: web::Data<Tera>, path: web::Path<String>) -> Result<HttpResponse> {
 | 
			
		||||
        let contract_id = path.into_inner();
 | 
			
		||||
        let mut context = Context::new();
 | 
			
		||||
        
 | 
			
		||||
        // Add active_page for navigation highlighting
 | 
			
		||||
        context.insert("active_page", &"contracts");
 | 
			
		||||
        
 | 
			
		||||
        // Find the contract by ID
 | 
			
		||||
        let contracts = Self::get_mock_contracts();
 | 
			
		||||
        let contract = contracts.iter().find(|c| c.id == contract_id);
 | 
			
		||||
        
 | 
			
		||||
        match contract {
 | 
			
		||||
            Some(contract) => {
 | 
			
		||||
                // Convert contract to JSON
 | 
			
		||||
                let contract_json = Self::contract_to_json(contract);
 | 
			
		||||
                
 | 
			
		||||
                context.insert("contract", &contract_json);
 | 
			
		||||
                context.insert("user_has_signed", &false); // Mock data
 | 
			
		||||
                
 | 
			
		||||
                Ok(HttpResponse::Ok().content_type("text/html").body(
 | 
			
		||||
                    tmpl.render("contracts/contract_detail.html", &context).unwrap()
 | 
			
		||||
                ))
 | 
			
		||||
            },
 | 
			
		||||
            None => {
 | 
			
		||||
                Ok(HttpResponse::NotFound().finish())
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Display the create contract form
 | 
			
		||||
    pub async fn create_form(tmpl: web::Data<Tera>) -> Result<HttpResponse> {
 | 
			
		||||
        let mut context = Context::new();
 | 
			
		||||
        
 | 
			
		||||
        // Add active_page for navigation highlighting
 | 
			
		||||
        context.insert("active_page", &"contracts");
 | 
			
		||||
        
 | 
			
		||||
        // Add contract types for dropdown
 | 
			
		||||
        let contract_types = vec![
 | 
			
		||||
            ("Service", "Service Agreement"),
 | 
			
		||||
            ("Employment", "Employment Contract"),
 | 
			
		||||
            ("NDA", "Non-Disclosure Agreement"),
 | 
			
		||||
            ("SLA", "Service Level Agreement"),
 | 
			
		||||
            ("Other", "Other")
 | 
			
		||||
        ];
 | 
			
		||||
        
 | 
			
		||||
        context.insert("contract_types", &contract_types);
 | 
			
		||||
        
 | 
			
		||||
        Ok(HttpResponse::Ok().content_type("text/html").body(
 | 
			
		||||
            tmpl.render("contracts/create_contract.html", &context).unwrap()
 | 
			
		||||
        ))
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Process the create contract form
 | 
			
		||||
    pub async fn create(
 | 
			
		||||
        tmpl: web::Data<Tera>,
 | 
			
		||||
        form: web::Form<ContractForm>,
 | 
			
		||||
    ) -> Result<HttpResponse> {
 | 
			
		||||
        // In a real application, we would save the contract to the database
 | 
			
		||||
        // For now, we'll just redirect to the contracts list
 | 
			
		||||
        
 | 
			
		||||
        Ok(HttpResponse::Found().header("Location", "/contracts").finish())
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Helper method to convert Contract to a JSON object for templates
 | 
			
		||||
    fn contract_to_json(contract: &Contract) -> serde_json::Map<String, serde_json::Value> {
 | 
			
		||||
        let mut map = serde_json::Map::new();
 | 
			
		||||
        
 | 
			
		||||
        map.insert("id".to_string(), serde_json::Value::String(contract.id.clone()));
 | 
			
		||||
        map.insert("title".to_string(), serde_json::Value::String(contract.title.clone()));
 | 
			
		||||
        map.insert("description".to_string(), serde_json::Value::String(contract.description.clone()));
 | 
			
		||||
        map.insert("status".to_string(), serde_json::Value::String(format!("{:?}", contract.status)));
 | 
			
		||||
        map.insert("contract_type".to_string(), serde_json::Value::String(format!("{:?}", contract.contract_type)));
 | 
			
		||||
        map.insert("created_at".to_string(), serde_json::Value::String(contract.created_at.format("%Y-%m-%d").to_string()));
 | 
			
		||||
        map.insert("updated_at".to_string(), serde_json::Value::String(contract.updated_at.format("%Y-%m-%d").to_string()));
 | 
			
		||||
        map.insert("created_by".to_string(), serde_json::Value::String("John Doe".to_string())); // Mock data
 | 
			
		||||
        
 | 
			
		||||
        // Add signers
 | 
			
		||||
        let signers: Vec<serde_json::Value> = contract.signers.iter()
 | 
			
		||||
            .map(|s| {
 | 
			
		||||
                let mut signer_map = serde_json::Map::new();
 | 
			
		||||
                signer_map.insert("id".to_string(), serde_json::Value::String(s.id.clone()));
 | 
			
		||||
                signer_map.insert("name".to_string(), serde_json::Value::String(s.name.clone()));
 | 
			
		||||
                signer_map.insert("email".to_string(), serde_json::Value::String(s.email.clone()));
 | 
			
		||||
                signer_map.insert("status".to_string(), serde_json::Value::String(format!("{:?}", s.status)));
 | 
			
		||||
                
 | 
			
		||||
                if let Some(signed_at) = s.signed_at {
 | 
			
		||||
                    signer_map.insert("signed_at".to_string(), serde_json::Value::String(signed_at.format("%Y-%m-%d").to_string()));
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                serde_json::Value::Object(signer_map)
 | 
			
		||||
            })
 | 
			
		||||
            .collect();
 | 
			
		||||
        
 | 
			
		||||
        map.insert("signers".to_string(), serde_json::Value::Array(signers));
 | 
			
		||||
        
 | 
			
		||||
        // Add signed_signers count for templates
 | 
			
		||||
        let signed_signers = contract.signers.iter().filter(|s| s.status == SignerStatus::Signed).count();
 | 
			
		||||
        map.insert("signed_signers".to_string(), serde_json::Value::Number(serde_json::Number::from(signed_signers)));
 | 
			
		||||
        
 | 
			
		||||
        // Add pending_signers count for templates
 | 
			
		||||
        let pending_signers = contract.signers.iter().filter(|s| s.status == SignerStatus::Pending).count();
 | 
			
		||||
        map.insert("pending_signers".to_string(), serde_json::Value::Number(serde_json::Number::from(pending_signers)));
 | 
			
		||||
        
 | 
			
		||||
        // Add revisions
 | 
			
		||||
        let revisions: Vec<serde_json::Value> = contract.revisions.iter()
 | 
			
		||||
            .map(|r| {
 | 
			
		||||
                let mut revision_map = serde_json::Map::new();
 | 
			
		||||
                revision_map.insert("version".to_string(), serde_json::Value::Number(serde_json::Number::from(r.version)));
 | 
			
		||||
                revision_map.insert("content".to_string(), serde_json::Value::String(r.content.clone()));
 | 
			
		||||
                revision_map.insert("created_at".to_string(), serde_json::Value::String(r.created_at.format("%Y-%m-%d").to_string()));
 | 
			
		||||
                revision_map.insert("created_by".to_string(), serde_json::Value::String(r.created_by.clone()));
 | 
			
		||||
                
 | 
			
		||||
                if let Some(comments) = &r.comments {
 | 
			
		||||
                    revision_map.insert("comments".to_string(), serde_json::Value::String(comments.clone()));
 | 
			
		||||
                    // Add notes field using comments since ContractRevision doesn't have a notes field
 | 
			
		||||
                    revision_map.insert("notes".to_string(), serde_json::Value::String(comments.clone()));
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                serde_json::Value::Object(revision_map)
 | 
			
		||||
            })
 | 
			
		||||
            .collect();
 | 
			
		||||
        
 | 
			
		||||
        map.insert("revisions".to_string(), serde_json::Value::Array(revisions));
 | 
			
		||||
        
 | 
			
		||||
        // Add effective and expiration dates if present
 | 
			
		||||
        if let Some(effective_date) = &contract.effective_date {
 | 
			
		||||
            map.insert("effective_date".to_string(), serde_json::Value::String(effective_date.format("%Y-%m-%d").to_string()));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if let Some(expiration_date) = &contract.expiration_date {
 | 
			
		||||
            map.insert("expiration_date".to_string(), serde_json::Value::String(expiration_date.format("%Y-%m-%d").to_string()));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        map
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Generate mock contracts for testing
 | 
			
		||||
    fn get_mock_contracts() -> Vec<Contract> {
 | 
			
		||||
        let now = Utc::now();
 | 
			
		||||
        
 | 
			
		||||
        let mut contracts = Vec::new();
 | 
			
		||||
        
 | 
			
		||||
        // Contract 1 - Draft
 | 
			
		||||
        let mut contract1 = Contract::new(
 | 
			
		||||
            "Employment Agreement - Marketing Manager".to_string(),
 | 
			
		||||
            "Standard employment contract for the Marketing Manager position".to_string(),
 | 
			
		||||
            ContractType::Employment,
 | 
			
		||||
            "John Doe".to_string(),
 | 
			
		||||
            Some("Acme Corp".to_string())
 | 
			
		||||
        );
 | 
			
		||||
        
 | 
			
		||||
        contract1.effective_date = Some(now + Duration::days(30));
 | 
			
		||||
        contract1.expiration_date = Some(now + Duration::days(395)); // ~1 year
 | 
			
		||||
        
 | 
			
		||||
        contract1.add_revision(
 | 
			
		||||
            "<p>This is a draft employment contract for the Marketing Manager position.</p>".to_string(),
 | 
			
		||||
            "John Doe".to_string(),
 | 
			
		||||
            Some("Initial draft".to_string())
 | 
			
		||||
        );
 | 
			
		||||
        
 | 
			
		||||
        // Contract 2 - Pending Signatures
 | 
			
		||||
        let mut contract2 = Contract::new(
 | 
			
		||||
            "Non-Disclosure Agreement - Vendor XYZ".to_string(),
 | 
			
		||||
            "NDA for our partnership with Vendor XYZ".to_string(),
 | 
			
		||||
            ContractType::NDA,
 | 
			
		||||
            "John Doe".to_string(),
 | 
			
		||||
            Some("Acme Corp".to_string())
 | 
			
		||||
        );
 | 
			
		||||
        
 | 
			
		||||
        contract2.effective_date = Some(now);
 | 
			
		||||
        contract2.expiration_date = Some(now + Duration::days(730)); // 2 years
 | 
			
		||||
        
 | 
			
		||||
        contract2.add_revision(
 | 
			
		||||
            "<p>This is the first version of the NDA with Vendor XYZ.</p>".to_string(),
 | 
			
		||||
            "John Doe".to_string(),
 | 
			
		||||
            Some("Initial draft".to_string())
 | 
			
		||||
        );
 | 
			
		||||
        
 | 
			
		||||
        contract2.add_revision(
 | 
			
		||||
            "<p>This is the revised version of the NDA with Vendor XYZ.</p>".to_string(),
 | 
			
		||||
            "John Doe".to_string(),
 | 
			
		||||
            Some("Added confidentiality period".to_string())
 | 
			
		||||
        );
 | 
			
		||||
        
 | 
			
		||||
        contract2.add_signer("Jane Smith".to_string(), "jane@example.com".to_string());
 | 
			
		||||
        contract2.add_signer("Bob Johnson".to_string(), "bob@vendorxyz.com".to_string());
 | 
			
		||||
        
 | 
			
		||||
        // Mark Jane as signed
 | 
			
		||||
        if let Some(signer) = contract2.signers.iter_mut().next() {
 | 
			
		||||
            signer.sign(None);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        // Send for signatures
 | 
			
		||||
        let _ = contract2.send_for_signatures();
 | 
			
		||||
        
 | 
			
		||||
        // Contract 3 - Signed
 | 
			
		||||
        let mut contract3 = Contract::new(
 | 
			
		||||
            "Service Agreement - Website Maintenance".to_string(),
 | 
			
		||||
            "Agreement for ongoing website maintenance services".to_string(),
 | 
			
		||||
            ContractType::Service,
 | 
			
		||||
            "John Doe".to_string(),
 | 
			
		||||
            Some("Acme Corp".to_string())
 | 
			
		||||
        );
 | 
			
		||||
        
 | 
			
		||||
        contract3.effective_date = Some(now - Duration::days(7));
 | 
			
		||||
        contract3.expiration_date = Some(now + Duration::days(358)); // ~1 year from effective date
 | 
			
		||||
        
 | 
			
		||||
        contract3.add_revision(
 | 
			
		||||
            "<p>This is a service agreement for website maintenance.</p>".to_string(),
 | 
			
		||||
            "John Doe".to_string(),
 | 
			
		||||
            Some("Initial version".to_string())
 | 
			
		||||
        );
 | 
			
		||||
        
 | 
			
		||||
        contract3.add_signer("Jane Smith".to_string(), "jane@example.com".to_string());
 | 
			
		||||
        contract3.add_signer("Alice Brown".to_string(), "alice@webmaintenance.com".to_string());
 | 
			
		||||
        
 | 
			
		||||
        // Mark both signers as signed
 | 
			
		||||
        for signer in contract3.signers.iter_mut() {
 | 
			
		||||
            signer.sign(None);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        // Mark as signed
 | 
			
		||||
        contract3.status = ContractStatus::Signed;
 | 
			
		||||
        
 | 
			
		||||
        contracts.push(contract1);
 | 
			
		||||
        contracts.push(contract2);
 | 
			
		||||
        contracts.push(contract3);
 | 
			
		||||
        
 | 
			
		||||
        contracts
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -5,6 +5,7 @@ pub mod ticket;
 | 
			
		||||
pub mod calendar;
 | 
			
		||||
pub mod governance;
 | 
			
		||||
pub mod flow;
 | 
			
		||||
pub mod contract;
 | 
			
		||||
 | 
			
		||||
// Re-export controllers for easier imports
 | 
			
		||||
pub use home::HomeController;
 | 
			
		||||
@@ -12,4 +13,5 @@ pub use auth::AuthController;
 | 
			
		||||
pub use ticket::TicketController;
 | 
			
		||||
pub use calendar::CalendarController;
 | 
			
		||||
pub use governance::GovernanceController;
 | 
			
		||||
pub use flow::FlowController;
 | 
			
		||||
pub use flow::FlowController;
 | 
			
		||||
pub use contract::ContractController;
 | 
			
		||||
							
								
								
									
										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};
 | 
			
		||||
@@ -6,6 +6,7 @@ use crate::controllers::ticket::TicketController;
 | 
			
		||||
use crate::controllers::calendar::CalendarController;
 | 
			
		||||
use crate::controllers::governance::GovernanceController;
 | 
			
		||||
use crate::controllers::flow::FlowController;
 | 
			
		||||
use crate::controllers::contract::ContractController;
 | 
			
		||||
use crate::middleware::JwtAuth;
 | 
			
		||||
use crate::SESSION_KEY;
 | 
			
		||||
 | 
			
		||||
@@ -77,6 +78,17 @@ pub fn configure_routes(cfg: &mut web::ServiceConfig) {
 | 
			
		||||
                    .route("/create", web::post().to(FlowController::create_flow))
 | 
			
		||||
                    .route("/my-flows", web::get().to(FlowController::my_flows))
 | 
			
		||||
            )
 | 
			
		||||
            
 | 
			
		||||
            // Contract routes
 | 
			
		||||
            .service(
 | 
			
		||||
                web::scope("/contracts")
 | 
			
		||||
                    .route("", web::get().to(ContractController::index))
 | 
			
		||||
                    .route("/list", web::get().to(ContractController::list))
 | 
			
		||||
                    .route("/my", web::get().to(ContractController::my_contracts))
 | 
			
		||||
                    .route("/{id}", web::get().to(ContractController::detail))
 | 
			
		||||
                    .route("/create", web::get().to(ContractController::create_form))
 | 
			
		||||
                    .route("/create", web::post().to(ContractController::create))
 | 
			
		||||
            )
 | 
			
		||||
    );
 | 
			
		||||
    
 | 
			
		||||
    // Keep the /protected scope for any future routes that should be under that path
 | 
			
		||||
 
 | 
			
		||||
@@ -64,6 +64,11 @@
 | 
			
		||||
                        <i class="bi bi-diagram-3 me-2"></i> Flows
 | 
			
		||||
                    </a>
 | 
			
		||||
                </li>
 | 
			
		||||
                <li class="nav-item">
 | 
			
		||||
                    <a class="nav-link d-flex align-items-center ps-3 py-2 {% if active_page == 'contracts' %}active fw-bold border-start border-4 border-primary bg-light{% endif %}" href="/contracts">
 | 
			
		||||
                        <i class="bi bi-file-earmark-text me-2"></i> Contracts
 | 
			
		||||
                    </a>
 | 
			
		||||
                </li>
 | 
			
		||||
                <li class="nav-item">
 | 
			
		||||
                    <a class="nav-link d-flex align-items-center ps-3 py-2 {% if active_page == 'editor' %}active fw-bold border-start border-4 border-primary bg-light{% endif %}" href="/editor">
 | 
			
		||||
                        <i class="bi bi-markdown me-2"></i> Markdown Editor
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										340
									
								
								actix_mvc_app/src/views/contracts/contract_detail.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										340
									
								
								actix_mvc_app/src/views/contracts/contract_detail.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,340 @@
 | 
			
		||||
{% extends "base.html" %}
 | 
			
		||||
 | 
			
		||||
{% block title %}Contract Details{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
<div class="container">
 | 
			
		||||
    <div class="row mb-4">
 | 
			
		||||
        <div class="col-12">
 | 
			
		||||
            <nav aria-label="breadcrumb">
 | 
			
		||||
                <ol class="breadcrumb">
 | 
			
		||||
                    <li class="breadcrumb-item"><a href="/contracts">Contracts Dashboard</a></li>
 | 
			
		||||
                    <li class="breadcrumb-item"><a href="/contracts/list">All Contracts</a></li>
 | 
			
		||||
                    <li class="breadcrumb-item active" aria-current="page">Contract Details</li>
 | 
			
		||||
                </ol>
 | 
			
		||||
            </nav>
 | 
			
		||||
            <div class="d-flex justify-content-between align-items-center">
 | 
			
		||||
                <h1 class="display-5 mb-0">{{ contract.title }}</h1>
 | 
			
		||||
                <div class="btn-group">
 | 
			
		||||
                    <a href="/contracts/list" class="btn btn-outline-secondary">
 | 
			
		||||
                        <i class="bi bi-arrow-left me-1"></i> Back to List
 | 
			
		||||
                    </a>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- Contract Overview -->
 | 
			
		||||
    <div class="row mb-4">
 | 
			
		||||
        <div class="col-md-8">
 | 
			
		||||
            <div class="card h-100">
 | 
			
		||||
                <div class="card-header">
 | 
			
		||||
                    <h5 class="mb-0">Contract Overview</h5>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="card-body">
 | 
			
		||||
                    <div class="row mb-3">
 | 
			
		||||
                        <div class="col-md-3 fw-bold">Status:</div>
 | 
			
		||||
                        <div class="col-md-9">
 | 
			
		||||
                            <span class="badge {% if contract.status == 'Signed' %}bg-success{% elif contract.status == 'PendingSignatures' %}bg-warning text-dark{% elif contract.status == 'Draft' %}bg-secondary{% elif contract.status == 'Expired' %}bg-danger{% else %}bg-dark{% endif %}">
 | 
			
		||||
                                {{ contract.status }}
 | 
			
		||||
                            </span>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="row mb-3">
 | 
			
		||||
                        <div class="col-md-3 fw-bold">Type:</div>
 | 
			
		||||
                        <div class="col-md-9">{{ contract.contract_type }}</div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="row mb-3">
 | 
			
		||||
                        <div class="col-md-3 fw-bold">Created By:</div>
 | 
			
		||||
                        <div class="col-md-9">{{ contract.created_by }}</div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="row mb-3">
 | 
			
		||||
                        <div class="col-md-3 fw-bold">Created:</div>
 | 
			
		||||
                        <div class="col-md-9">{{ contract.created_at }}</div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="row mb-3">
 | 
			
		||||
                        <div class="col-md-3 fw-bold">Last Updated:</div>
 | 
			
		||||
                        <div class="col-md-9">{{ contract.updated_at }}</div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    {% if contract.effective_date %}
 | 
			
		||||
                    <div class="row mb-3">
 | 
			
		||||
                        <div class="col-md-3 fw-bold">Effective Date:</div>
 | 
			
		||||
                        <div class="col-md-9">{{ contract.effective_date }}</div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    {% endif %}
 | 
			
		||||
                    {% if contract.expiration_date %}
 | 
			
		||||
                    <div class="row mb-3">
 | 
			
		||||
                        <div class="col-md-3 fw-bold">Expiration Date:</div>
 | 
			
		||||
                        <div class="col-md-9">{{ contract.expiration_date }}</div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    {% endif %}
 | 
			
		||||
                    <div class="row mb-3">
 | 
			
		||||
                        <div class="col-md-3 fw-bold">Version:</div>
 | 
			
		||||
                        <div class="col-md-9">{{ contract.current_version }}</div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="row">
 | 
			
		||||
                        <div class="col-md-3 fw-bold">Description:</div>
 | 
			
		||||
                        <div class="col-md-9">{{ contract.description }}</div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="col-md-4">
 | 
			
		||||
            <div class="card h-100">
 | 
			
		||||
                <div class="card-header">
 | 
			
		||||
                    <h5 class="mb-0">Actions</h5>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="card-body">
 | 
			
		||||
                    <div class="d-grid gap-2">
 | 
			
		||||
                        {% if contract.status == 'Draft' %}
 | 
			
		||||
                            <a href="/contracts/{{ contract.id }}/edit" class="btn btn-primary">
 | 
			
		||||
                                <i class="bi bi-pencil me-1"></i> Edit Contract
 | 
			
		||||
                            </a>
 | 
			
		||||
                            <a href="/contracts/{{ contract.id }}/send" class="btn btn-success">
 | 
			
		||||
                                <i class="bi bi-send me-1"></i> Send for Signatures
 | 
			
		||||
                            </a>
 | 
			
		||||
                            <button class="btn btn-danger">
 | 
			
		||||
                                <i class="bi bi-trash me-1"></i> Delete Contract
 | 
			
		||||
                            </button>
 | 
			
		||||
                        {% elif contract.status == 'PendingSignatures' %}
 | 
			
		||||
                            <button class="btn btn-success">
 | 
			
		||||
                                <i class="bi bi-pen me-1"></i> Sign Contract
 | 
			
		||||
                            </button>
 | 
			
		||||
                            <button class="btn btn-warning">
 | 
			
		||||
                                <i class="bi bi-x-circle me-1"></i> Reject Contract
 | 
			
		||||
                            </button>
 | 
			
		||||
                            <button class="btn btn-secondary">
 | 
			
		||||
                                <i class="bi bi-send me-1"></i> Resend Invitations
 | 
			
		||||
                            </button>
 | 
			
		||||
                        {% elif contract.status == 'Signed' %}
 | 
			
		||||
                            <button class="btn btn-primary">
 | 
			
		||||
                                <i class="bi bi-download me-1"></i> Download Contract
 | 
			
		||||
                            </button>
 | 
			
		||||
                            <button class="btn btn-outline-secondary">
 | 
			
		||||
                                <i class="bi bi-files me-1"></i> Clone Contract
 | 
			
		||||
                            </button>
 | 
			
		||||
                        {% endif %}
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- Contract Content -->
 | 
			
		||||
    <div class="row mb-4">
 | 
			
		||||
        <div class="col-12">
 | 
			
		||||
            <div class="card">
 | 
			
		||||
                <div class="card-header d-flex justify-content-between align-items-center">
 | 
			
		||||
                    <h5 class="mb-0">Contract Content</h5>
 | 
			
		||||
                    {% if contract.revisions|length > 1 %}
 | 
			
		||||
                    <div class="dropdown">
 | 
			
		||||
                        <button class="btn btn-sm btn-outline-secondary dropdown-toggle" type="button" id="versionDropdown" data-bs-toggle="dropdown" aria-expanded="false">
 | 
			
		||||
                            Version {{ contract.current_version }}
 | 
			
		||||
                        </button>
 | 
			
		||||
                        <ul class="dropdown-menu" aria-labelledby="versionDropdown">
 | 
			
		||||
                            {% for revision in contract.revisions %}
 | 
			
		||||
                            <li><a class="dropdown-item" href="/contracts/{{ contract.id }}?version={{ revision.version }}">Version {{ revision.version }}</a></li>
 | 
			
		||||
                            {% endfor %}
 | 
			
		||||
                        </ul>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    {% endif %}
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="card-body">
 | 
			
		||||
                    {% if contract.revisions|length > 0 %}
 | 
			
		||||
                        {% set latest_revision = contract.latest_revision %}
 | 
			
		||||
                        <div class="contract-content border p-3 bg-light">
 | 
			
		||||
                            {{ latest_revision.content|safe }}
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="mt-3 text-muted small">
 | 
			
		||||
                            <p>Last updated by {{ latest_revision.created_by }} on {{ latest_revision.created_at }}</p>
 | 
			
		||||
                            {% if latest_revision.comments %}
 | 
			
		||||
                            <p><strong>Comments:</strong> {{ latest_revision.comments }}</p>
 | 
			
		||||
                            {% endif %}
 | 
			
		||||
                        </div>
 | 
			
		||||
                    {% else %}
 | 
			
		||||
                        <div class="text-center py-3 text-muted">
 | 
			
		||||
                            <p>No content has been added to this contract yet.</p>
 | 
			
		||||
                            {% if contract.status == 'Draft' %}
 | 
			
		||||
                            <a href="/contracts/{{ contract.id }}/edit" class="btn btn-sm btn-primary">
 | 
			
		||||
                                <i class="bi bi-pencil me-1"></i> Add Content
 | 
			
		||||
                            </a>
 | 
			
		||||
                            {% endif %}
 | 
			
		||||
                        </div>
 | 
			
		||||
                    {% endif %}
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- Signers -->
 | 
			
		||||
    <div class="row mb-4">
 | 
			
		||||
        <div class="col-12">
 | 
			
		||||
            <div class="card">
 | 
			
		||||
                <div class="card-header d-flex justify-content-between align-items-center">
 | 
			
		||||
                    <h5 class="mb-0">Signers</h5>
 | 
			
		||||
                    {% if contract.status == 'Draft' %}
 | 
			
		||||
                    <button class="btn btn-sm btn-primary">
 | 
			
		||||
                        <i class="bi bi-plus me-1"></i> Add Signer
 | 
			
		||||
                    </button>
 | 
			
		||||
                    {% endif %}
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="card-body">
 | 
			
		||||
                    {% if contract.signers|length > 0 %}
 | 
			
		||||
                    <div class="table-responsive">
 | 
			
		||||
                        <table class="table">
 | 
			
		||||
                            <thead>
 | 
			
		||||
                                <tr>
 | 
			
		||||
                                    <th>Name</th>
 | 
			
		||||
                                    <th>Email</th>
 | 
			
		||||
                                    <th>Status</th>
 | 
			
		||||
                                    <th>Signed Date</th>
 | 
			
		||||
                                    <th>Comments</th>
 | 
			
		||||
                                    {% if contract.status == 'Draft' %}
 | 
			
		||||
                                    <th>Actions</th>
 | 
			
		||||
                                    {% endif %}
 | 
			
		||||
                                </tr>
 | 
			
		||||
                            </thead>
 | 
			
		||||
                            <tbody>
 | 
			
		||||
                                {% for signer in contract.signers %}
 | 
			
		||||
                                <tr>
 | 
			
		||||
                                    <td>{{ signer.name }}</td>
 | 
			
		||||
                                    <td>{{ signer.email }}</td>
 | 
			
		||||
                                    <td>
 | 
			
		||||
                                        <span class="badge {% if signer.status == 'Signed' %}bg-success{% elif signer.status == 'Rejected' %}bg-danger{% else %}bg-warning text-dark{% endif %}">
 | 
			
		||||
                                            {{ signer.status }}
 | 
			
		||||
                                        </span>
 | 
			
		||||
                                    </td>
 | 
			
		||||
                                    <td>
 | 
			
		||||
                                        {% if signer.signed_at %}
 | 
			
		||||
                                            {{ signer.signed_at }}
 | 
			
		||||
                                        {% else %}
 | 
			
		||||
                                            -
 | 
			
		||||
                                        {% endif %}
 | 
			
		||||
                                    </td>
 | 
			
		||||
                                    <td>
 | 
			
		||||
                                        {% if signer.comments %}
 | 
			
		||||
                                            {{ signer.comments }}
 | 
			
		||||
                                        {% else %}
 | 
			
		||||
                                            -
 | 
			
		||||
                                        {% endif %}
 | 
			
		||||
                                    </td>
 | 
			
		||||
                                    {% if contract.status == 'Draft' %}
 | 
			
		||||
                                    <td>
 | 
			
		||||
                                        <button class="btn btn-sm btn-outline-danger">
 | 
			
		||||
                                            <i class="bi bi-trash"></i>
 | 
			
		||||
                                        </button>
 | 
			
		||||
                                    </td>
 | 
			
		||||
                                    {% endif %}
 | 
			
		||||
                                </tr>
 | 
			
		||||
                                {% endfor %}
 | 
			
		||||
                            </tbody>
 | 
			
		||||
                        </table>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    {% else %}
 | 
			
		||||
                    <div class="text-center py-3 text-muted">
 | 
			
		||||
                        <p>No signers have been added to this contract yet.</p>
 | 
			
		||||
                        {% if contract.status == 'Draft' %}
 | 
			
		||||
                        <button class="btn btn-sm btn-primary">
 | 
			
		||||
                            <i class="bi bi-plus me-1"></i> Add Signer
 | 
			
		||||
                        </button>
 | 
			
		||||
                        {% endif %}
 | 
			
		||||
                    </div>
 | 
			
		||||
                    {% endif %}
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- Contract Revisions -->
 | 
			
		||||
    <div class="card mt-4">
 | 
			
		||||
        <div class="card-header">
 | 
			
		||||
            <h5 class="mb-0">Contract Revisions</h5>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="card-body">
 | 
			
		||||
            {% if contract.revisions|length > 0 %}
 | 
			
		||||
            <div class="table-responsive">
 | 
			
		||||
                <table class="table table-striped">
 | 
			
		||||
                    <thead>
 | 
			
		||||
                        <tr>
 | 
			
		||||
                            <th>Version</th>
 | 
			
		||||
                            <th>Date</th>
 | 
			
		||||
                            <th>Notes</th>
 | 
			
		||||
                            <th>Actions</th>
 | 
			
		||||
                        </tr>
 | 
			
		||||
                    </thead>
 | 
			
		||||
                    <tbody>
 | 
			
		||||
                        {% for revision in contract.revisions %}
 | 
			
		||||
                        <tr>
 | 
			
		||||
                            <td>{{ revision.version }}</td>
 | 
			
		||||
                            <td>{{ revision.created_at }}</td>
 | 
			
		||||
                            <td>{{ revision.notes }}</td>
 | 
			
		||||
                            <td>
 | 
			
		||||
                                <a href="/contracts/{{ contract.id }}/revisions/{{ revision.version }}" class="btn btn-sm btn-primary">
 | 
			
		||||
                                    <i class="bi bi-eye"></i> View
 | 
			
		||||
                                </a>
 | 
			
		||||
                            </td>
 | 
			
		||||
                        </tr>
 | 
			
		||||
                        {% endfor %}
 | 
			
		||||
                    </tbody>
 | 
			
		||||
                </table>
 | 
			
		||||
            </div>
 | 
			
		||||
            {% else %}
 | 
			
		||||
            <p class="text-muted">No revisions available.</p>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- Revision History -->
 | 
			
		||||
    <div class="row">
 | 
			
		||||
        <div class="col-12">
 | 
			
		||||
            <div class="card">
 | 
			
		||||
                <div class="card-header">
 | 
			
		||||
                    <h5 class="mb-0">Revision History</h5>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="card-body">
 | 
			
		||||
                    {% if contract.revisions|length > 0 %}
 | 
			
		||||
                    <div class="table-responsive">
 | 
			
		||||
                        <table class="table">
 | 
			
		||||
                            <thead>
 | 
			
		||||
                                <tr>
 | 
			
		||||
                                    <th>Version</th>
 | 
			
		||||
                                    <th>Created By</th>
 | 
			
		||||
                                    <th>Created Date</th>
 | 
			
		||||
                                    <th>Comments</th>
 | 
			
		||||
                                    <th>Actions</th>
 | 
			
		||||
                                </tr>
 | 
			
		||||
                            </thead>
 | 
			
		||||
                            <tbody>
 | 
			
		||||
                                {% for revision in contract.revisions|reverse %}
 | 
			
		||||
                                <tr>
 | 
			
		||||
                                    <td>{{ revision.version }}</td>
 | 
			
		||||
                                    <td>{{ revision.created_by }}</td>
 | 
			
		||||
                                    <td>{{ revision.created_at }}</td>
 | 
			
		||||
                                    <td>
 | 
			
		||||
                                        {% if revision.comments %}
 | 
			
		||||
                                            {{ revision.comments }}
 | 
			
		||||
                                        {% else %}
 | 
			
		||||
                                            -
 | 
			
		||||
                                        {% endif %}
 | 
			
		||||
                                    </td>
 | 
			
		||||
                                    <td>
 | 
			
		||||
                                        <a href="/contracts/{{ contract.id }}?version={{ revision.version }}" class="btn btn-sm btn-outline-secondary">
 | 
			
		||||
                                            <i class="bi bi-eye"></i>
 | 
			
		||||
                                        </a>
 | 
			
		||||
                                    </td>
 | 
			
		||||
                                </tr>
 | 
			
		||||
                                {% endfor %}
 | 
			
		||||
                            </tbody>
 | 
			
		||||
                        </table>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    {% else %}
 | 
			
		||||
                    <div class="text-center py-3 text-muted">
 | 
			
		||||
                        <p>No revisions have been made to this contract yet.</p>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    {% endif %}
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
							
								
								
									
										140
									
								
								actix_mvc_app/src/views/contracts/contracts.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								actix_mvc_app/src/views/contracts/contracts.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,140 @@
 | 
			
		||||
{% extends "base.html" %}
 | 
			
		||||
 | 
			
		||||
{% block title %}All Contracts{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
<div class="container">
 | 
			
		||||
    <div class="row mb-4">
 | 
			
		||||
        <div class="col-12">
 | 
			
		||||
            <nav aria-label="breadcrumb">
 | 
			
		||||
                <ol class="breadcrumb">
 | 
			
		||||
                    <li class="breadcrumb-item"><a href="/contracts">Contracts Dashboard</a></li>
 | 
			
		||||
                    <li class="breadcrumb-item active" aria-current="page">All Contracts</li>
 | 
			
		||||
                </ol>
 | 
			
		||||
            </nav>
 | 
			
		||||
            <div class="d-flex justify-content-between align-items-center">
 | 
			
		||||
                <h1 class="display-5 mb-0">All Contracts</h1>
 | 
			
		||||
                <div class="btn-group">
 | 
			
		||||
                    <a href="/contracts/create" class="btn btn-primary">
 | 
			
		||||
                        <i class="bi bi-plus-circle me-1"></i> Create New Contract
 | 
			
		||||
                    </a>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- Filters -->
 | 
			
		||||
    <div class="row mb-4">
 | 
			
		||||
        <div class="col-12">
 | 
			
		||||
            <div class="card">
 | 
			
		||||
                <div class="card-header">
 | 
			
		||||
                    <h5 class="mb-0">Filters</h5>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="card-body">
 | 
			
		||||
                    <form action="/contracts/list" method="get" class="row g-3">
 | 
			
		||||
                        <div class="col-md-3">
 | 
			
		||||
                            <label for="status" class="form-label">Status</label>
 | 
			
		||||
                            <select class="form-select" id="status" name="status">
 | 
			
		||||
                                <option value="">All Statuses</option>
 | 
			
		||||
                                <option value="Draft">Draft</option>
 | 
			
		||||
                                <option value="PendingSignatures">Pending Signatures</option>
 | 
			
		||||
                                <option value="Signed">Signed</option>
 | 
			
		||||
                                <option value="Expired">Expired</option>
 | 
			
		||||
                                <option value="Cancelled">Cancelled</option>
 | 
			
		||||
                            </select>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="col-md-3">
 | 
			
		||||
                            <label for="type" class="form-label">Contract Type</label>
 | 
			
		||||
                            <select class="form-select" id="type" name="type">
 | 
			
		||||
                                <option value="">All Types</option>
 | 
			
		||||
                                <option value="Service">Service Agreement</option>
 | 
			
		||||
                                <option value="Employment">Employment Contract</option>
 | 
			
		||||
                                <option value="NDA">Non-Disclosure Agreement</option>
 | 
			
		||||
                                <option value="SLA">Service Level Agreement</option>
 | 
			
		||||
                                <option value="Other">Other</option>
 | 
			
		||||
                            </select>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="col-md-3">
 | 
			
		||||
                            <label for="search" class="form-label">Search</label>
 | 
			
		||||
                            <input type="text" class="form-control" id="search" name="search" placeholder="Search by title or description">
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="col-md-3 d-flex align-items-end">
 | 
			
		||||
                            <button type="submit" class="btn btn-primary w-100">Apply Filters</button>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </form>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- Contract List -->
 | 
			
		||||
    <div class="row">
 | 
			
		||||
        <div class="col-12">
 | 
			
		||||
            <div class="card">
 | 
			
		||||
                <div class="card-header">
 | 
			
		||||
                    <h5 class="mb-0">Contracts</h5>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="card-body">
 | 
			
		||||
                    {% if contracts and contracts | length > 0 %}
 | 
			
		||||
                    <div class="table-responsive">
 | 
			
		||||
                        <table class="table table-hover">
 | 
			
		||||
                            <thead>
 | 
			
		||||
                                <tr>
 | 
			
		||||
                                    <th>Contract Title</th>
 | 
			
		||||
                                    <th>Type</th>
 | 
			
		||||
                                    <th>Status</th>
 | 
			
		||||
                                    <th>Created By</th>
 | 
			
		||||
                                    <th>Signers</th>
 | 
			
		||||
                                    <th>Created</th>
 | 
			
		||||
                                    <th>Updated</th>
 | 
			
		||||
                                    <th>Actions</th>
 | 
			
		||||
                                </tr>
 | 
			
		||||
                            </thead>
 | 
			
		||||
                            <tbody>
 | 
			
		||||
                                {% for contract in contracts %}
 | 
			
		||||
                                <tr>
 | 
			
		||||
                                    <td>
 | 
			
		||||
                                        <a href="/contracts/{{ contract.id }}">{{ contract.title }}</a>
 | 
			
		||||
                                    </td>
 | 
			
		||||
                                    <td>{{ contract.contract_type }}</td>
 | 
			
		||||
                                    <td>
 | 
			
		||||
                                        <span class="badge {% if contract.status == 'Signed' %}bg-success{% elif contract.status == 'PendingSignatures' %}bg-warning text-dark{% elif contract.status == 'Draft' %}bg-secondary{% elif contract.status == 'Expired' %}bg-danger{% else %}bg-dark{% endif %}">
 | 
			
		||||
                                            {{ contract.status }}
 | 
			
		||||
                                        </span>
 | 
			
		||||
                                    </td>
 | 
			
		||||
                                    <td>{{ contract.created_by }}</td>
 | 
			
		||||
                                    <td>{{ contract.signed_signers }}/{{ contract.signers|length }}</td>
 | 
			
		||||
                                    <td>{{ contract.created_at | date(format="%Y-%m-%d") }}</td>
 | 
			
		||||
                                    <td>{{ contract.updated_at | date(format="%Y-%m-%d") }}</td>
 | 
			
		||||
                                    <td>
 | 
			
		||||
                                        <div class="btn-group">
 | 
			
		||||
                                            <a href="/contracts/{{ contract.id }}" class="btn btn-sm btn-primary">
 | 
			
		||||
                                                <i class="bi bi-eye"></i>
 | 
			
		||||
                                            </a>
 | 
			
		||||
                                            {% if contract.status == 'Draft' %}
 | 
			
		||||
                                            <a href="/contracts/{{ contract.id }}/edit" class="btn btn-sm btn-outline-secondary">
 | 
			
		||||
                                                <i class="bi bi-pencil"></i>
 | 
			
		||||
                                            </a>
 | 
			
		||||
                                            {% endif %}
 | 
			
		||||
                                        </div>
 | 
			
		||||
                                    </td>
 | 
			
		||||
                                </tr>
 | 
			
		||||
                                {% endfor %}
 | 
			
		||||
                            </tbody>
 | 
			
		||||
                        </table>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    {% else %}
 | 
			
		||||
                    <div class="text-center py-5">
 | 
			
		||||
                        <i class="bi bi-file-earmark-text fs-1 text-muted"></i>
 | 
			
		||||
                        <p class="mt-3 text-muted">No contracts found</p>
 | 
			
		||||
                        <a href="/contracts/create" class="btn btn-primary mt-2">
 | 
			
		||||
                            <i class="bi bi-plus-circle me-1"></i> Create New Contract
 | 
			
		||||
                        </a>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    {% endif %}
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
							
								
								
									
										166
									
								
								actix_mvc_app/src/views/contracts/create_contract.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								actix_mvc_app/src/views/contracts/create_contract.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,166 @@
 | 
			
		||||
{% extends "base.html" %}
 | 
			
		||||
 | 
			
		||||
{% block title %}Create New Contract{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
<div class="container">
 | 
			
		||||
    <div class="row mb-4">
 | 
			
		||||
        <div class="col-12">
 | 
			
		||||
            <nav aria-label="breadcrumb">
 | 
			
		||||
                <ol class="breadcrumb">
 | 
			
		||||
                    <li class="breadcrumb-item"><a href="/contracts">Contracts Dashboard</a></li>
 | 
			
		||||
                    <li class="breadcrumb-item active" aria-current="page">Create New Contract</li>
 | 
			
		||||
                </ol>
 | 
			
		||||
            </nav>
 | 
			
		||||
            <h1 class="display-5 mb-3">Create New Contract</h1>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="row">
 | 
			
		||||
        <div class="col-lg-8">
 | 
			
		||||
            <div class="card">
 | 
			
		||||
                <div class="card-header">
 | 
			
		||||
                    <h5 class="mb-0">Contract Details</h5>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="card-body">
 | 
			
		||||
                    <form action="/contracts/create" method="post">
 | 
			
		||||
                        <div class="mb-3">
 | 
			
		||||
                            <label for="title" class="form-label">Contract Title <span class="text-danger">*</span></label>
 | 
			
		||||
                            <input type="text" class="form-control" id="title" name="title" required>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        
 | 
			
		||||
                        <div class="mb-3">
 | 
			
		||||
                            <label for="contract_type" class="form-label">Contract Type <span class="text-danger">*</span></label>
 | 
			
		||||
                            <select class="form-select" id="contract_type" name="contract_type" required>
 | 
			
		||||
                                <option value="" selected disabled>Select a contract type</option>
 | 
			
		||||
                                {% for type in contract_types %}
 | 
			
		||||
                                <option value="{{ type }}">{{ type }}</option>
 | 
			
		||||
                                {% endfor %}
 | 
			
		||||
                            </select>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        
 | 
			
		||||
                        <div class="mb-3">
 | 
			
		||||
                            <label for="description" class="form-label">Description <span class="text-danger">*</span></label>
 | 
			
		||||
                            <textarea class="form-control" id="description" name="description" rows="3" required></textarea>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        
 | 
			
		||||
                        <div class="mb-3">
 | 
			
		||||
                            <label for="content" class="form-label">Contract Content</label>
 | 
			
		||||
                            <textarea class="form-control" id="content" name="content" rows="10"></textarea>
 | 
			
		||||
                            <div class="form-text">You can leave this blank and add content later.</div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        
 | 
			
		||||
                        <div class="mb-3">
 | 
			
		||||
                            <label for="effective_date" class="form-label">Effective Date</label>
 | 
			
		||||
                            <input type="date" class="form-control" id="effective_date" name="effective_date">
 | 
			
		||||
                        </div>
 | 
			
		||||
                        
 | 
			
		||||
                        <div class="mb-3">
 | 
			
		||||
                            <label for="expiration_date" class="form-label">Expiration Date</label>
 | 
			
		||||
                            <input type="date" class="form-control" id="expiration_date" name="expiration_date">
 | 
			
		||||
                        </div>
 | 
			
		||||
                        
 | 
			
		||||
                        <div class="d-grid gap-2 d-md-flex justify-content-md-end">
 | 
			
		||||
                            <a href="/contracts" class="btn btn-outline-secondary me-md-2">Cancel</a>
 | 
			
		||||
                            <button type="submit" class="btn btn-primary">Create Contract</button>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </form>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        
 | 
			
		||||
        <div class="col-lg-4">
 | 
			
		||||
            <div class="card mb-4">
 | 
			
		||||
                <div class="card-header">
 | 
			
		||||
                    <h5 class="mb-0">Tips</h5>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="card-body">
 | 
			
		||||
                    <p>Creating a new contract is just the first step. After creating the contract, you'll be able to:</p>
 | 
			
		||||
                    <ul>
 | 
			
		||||
                        <li>Add signers who need to approve the contract</li>
 | 
			
		||||
                        <li>Edit the contract content</li>
 | 
			
		||||
                        <li>Send the contract for signatures</li>
 | 
			
		||||
                        <li>Track the signing progress</li>
 | 
			
		||||
                    </ul>
 | 
			
		||||
                    <p>The contract will be in <strong>Draft</strong> status until you send it for signatures.</p>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            
 | 
			
		||||
            <div class="card">
 | 
			
		||||
                <div class="card-header">
 | 
			
		||||
                    <h5 class="mb-0">Contract Templates</h5>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="card-body">
 | 
			
		||||
                    <p>You can use one of our pre-defined templates to get started quickly:</p>
 | 
			
		||||
                    <div class="list-group">
 | 
			
		||||
                        <button type="button" class="list-group-item list-group-item-action" onclick="loadTemplate('nda')">
 | 
			
		||||
                            Non-Disclosure Agreement
 | 
			
		||||
                        </button>
 | 
			
		||||
                        <button type="button" class="list-group-item list-group-item-action" onclick="loadTemplate('service')">
 | 
			
		||||
                            Service Agreement
 | 
			
		||||
                        </button>
 | 
			
		||||
                        <button type="button" class="list-group-item list-group-item-action" onclick="loadTemplate('employment')">
 | 
			
		||||
                            Employment Contract
 | 
			
		||||
                        </button>
 | 
			
		||||
                        <button type="button" class="list-group-item list-group-item-action" onclick="loadTemplate('sla')">
 | 
			
		||||
                            Service Level Agreement
 | 
			
		||||
                        </button>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block scripts %}
 | 
			
		||||
<script>
 | 
			
		||||
    function loadTemplate(type) {
 | 
			
		||||
        // In a real application, this would load template content from the server
 | 
			
		||||
        let title = '';
 | 
			
		||||
        let description = '';
 | 
			
		||||
        let content = '';
 | 
			
		||||
        let contractType = '';
 | 
			
		||||
        
 | 
			
		||||
        switch(type) {
 | 
			
		||||
            case 'nda':
 | 
			
		||||
                title = 'Non-Disclosure Agreement';
 | 
			
		||||
                description = 'Standard NDA for protecting confidential information';
 | 
			
		||||
                contractType = 'Non-Disclosure Agreement';
 | 
			
		||||
                content = 'This Non-Disclosure Agreement (the "Agreement") is entered into as of [DATE] by and between [PARTY A] and [PARTY B].\n\n1. Definition of Confidential Information\n2. Obligations of Receiving Party\n3. Term\n...';
 | 
			
		||||
                break;
 | 
			
		||||
            case 'service':
 | 
			
		||||
                title = 'Service Agreement';
 | 
			
		||||
                description = 'Agreement for providing professional services';
 | 
			
		||||
                contractType = 'Service Agreement';
 | 
			
		||||
                content = 'This Service Agreement (the "Agreement") is made and entered into as of [DATE] by and between [SERVICE PROVIDER] and [CLIENT].\n\n1. Services to be Provided\n2. Compensation\n3. Term and Termination\n...';
 | 
			
		||||
                break;
 | 
			
		||||
            case 'employment':
 | 
			
		||||
                title = 'Employment Contract';
 | 
			
		||||
                description = 'Standard employment agreement';
 | 
			
		||||
                contractType = 'Employment Contract';
 | 
			
		||||
                content = 'This Employment Agreement (the "Agreement") is made and entered into as of [DATE] by and between [EMPLOYER] and [EMPLOYEE].\n\n1. Position and Duties\n2. Compensation and Benefits\n3. Term and Termination\n...';
 | 
			
		||||
                break;
 | 
			
		||||
            case 'sla':
 | 
			
		||||
                title = 'Service Level Agreement';
 | 
			
		||||
                description = 'Agreement defining service levels and metrics';
 | 
			
		||||
                contractType = 'Service Level Agreement';
 | 
			
		||||
                content = 'This Service Level Agreement (the "SLA") is made and entered into as of [DATE] by and between [SERVICE PROVIDER] and [CLIENT].\n\n1. Service Levels\n2. Performance Metrics\n3. Remedies for Failure\n...';
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        document.getElementById('title').value = title;
 | 
			
		||||
        document.getElementById('description').value = description;
 | 
			
		||||
        document.getElementById('content').value = content;
 | 
			
		||||
        
 | 
			
		||||
        // Set the select option
 | 
			
		||||
        const selectElement = document.getElementById('contract_type');
 | 
			
		||||
        for(let i = 0; i < selectElement.options.length; i++) {
 | 
			
		||||
            if(selectElement.options[i].text === contractType) {
 | 
			
		||||
                selectElement.selectedIndex = i;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
</script>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
							
								
								
									
										187
									
								
								actix_mvc_app/src/views/contracts/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								actix_mvc_app/src/views/contracts/index.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,187 @@
 | 
			
		||||
{% extends "base.html" %}
 | 
			
		||||
 | 
			
		||||
{% block title %}Contracts Dashboard{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
<div class="container">
 | 
			
		||||
    <div class="row mb-4">
 | 
			
		||||
        <div class="col-12">
 | 
			
		||||
            <h1 class="display-5 mb-3">Contracts Dashboard</h1>
 | 
			
		||||
            <p class="lead">Manage legal agreements and contracts across your organization.</p>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- Statistics Cards -->
 | 
			
		||||
    <div class="row mb-4">
 | 
			
		||||
        <div class="col-md-2 mb-3">
 | 
			
		||||
            <div class="card text-white bg-primary h-100">
 | 
			
		||||
                <div class="card-body">
 | 
			
		||||
                    <h5 class="card-title">Total</h5>
 | 
			
		||||
                    <p class="display-4">{{ stats.total_contracts }}</p>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="col-md-2 mb-3">
 | 
			
		||||
            <div class="card text-white bg-secondary h-100">
 | 
			
		||||
                <div class="card-body">
 | 
			
		||||
                    <h5 class="card-title">Draft</h5>
 | 
			
		||||
                    <p class="display-4">{{ stats.draft_contracts }}</p>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="col-md-2 mb-3">
 | 
			
		||||
            <div class="card text-white bg-warning h-100">
 | 
			
		||||
                <div class="card-body">
 | 
			
		||||
                    <h5 class="card-title">Pending</h5>
 | 
			
		||||
                    <p class="display-4">{{ stats.pending_signature_contracts }}</p>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="col-md-2 mb-3">
 | 
			
		||||
            <div class="card text-white bg-success h-100">
 | 
			
		||||
                <div class="card-body">
 | 
			
		||||
                    <h5 class="card-title">Signed</h5>
 | 
			
		||||
                    <p class="display-4">{{ stats.signed_contracts }}</p>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="col-md-2 mb-3">
 | 
			
		||||
            <div class="card text-white bg-danger h-100">
 | 
			
		||||
                <div class="card-body">
 | 
			
		||||
                    <h5 class="card-title">Expired</h5>
 | 
			
		||||
                    <p class="display-4">{{ stats.expired_contracts }}</p>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="col-md-2 mb-3">
 | 
			
		||||
            <div class="card text-white bg-dark h-100">
 | 
			
		||||
                <div class="card-body">
 | 
			
		||||
                    <h5 class="card-title">Cancelled</h5>
 | 
			
		||||
                    <p class="display-4">{{ stats.cancelled_contracts }}</p>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- Quick Actions -->
 | 
			
		||||
    <div class="row mb-4">
 | 
			
		||||
        <div class="col-12">
 | 
			
		||||
            <div class="card">
 | 
			
		||||
                <div class="card-header">
 | 
			
		||||
                    <h5 class="mb-0">Quick Actions</h5>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="card-body">
 | 
			
		||||
                    <div class="d-flex flex-wrap gap-2">
 | 
			
		||||
                        <a href="/contracts/create" class="btn btn-primary">
 | 
			
		||||
                            <i class="bi bi-plus-circle me-1"></i> Create New Contract
 | 
			
		||||
                        </a>
 | 
			
		||||
                        <a href="/contracts/list" class="btn btn-outline-secondary">
 | 
			
		||||
                            <i class="bi bi-list me-1"></i> View All Contracts
 | 
			
		||||
                        </a>
 | 
			
		||||
                        <a href="/contracts/my-contracts" class="btn btn-outline-secondary">
 | 
			
		||||
                            <i class="bi bi-person me-1"></i> My Contracts
 | 
			
		||||
                        </a>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- Pending Signature Contracts -->
 | 
			
		||||
    {% if pending_signature_contracts and pending_signature_contracts | length > 0 %}
 | 
			
		||||
    <div class="row mb-4">
 | 
			
		||||
        <div class="col-12">
 | 
			
		||||
            <div class="card border-warning">
 | 
			
		||||
                <div class="card-header bg-warning text-dark">
 | 
			
		||||
                    <h5 class="mb-0">Pending Signature ({{ pending_signature_contracts|length }})</h5>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="card-body">
 | 
			
		||||
                    <div class="table-responsive">
 | 
			
		||||
                        <table class="table table-hover">
 | 
			
		||||
                            <thead>
 | 
			
		||||
                                <tr>
 | 
			
		||||
                                    <th>Contract Title</th>
 | 
			
		||||
                                    <th>Type</th>
 | 
			
		||||
                                    <th>Created By</th>
 | 
			
		||||
                                    <th>Pending Signers</th>
 | 
			
		||||
                                    <th>Created</th>
 | 
			
		||||
                                    <th>Actions</th>
 | 
			
		||||
                                </tr>
 | 
			
		||||
                            </thead>
 | 
			
		||||
                            <tbody>
 | 
			
		||||
                                {% for contract in pending_signature_contracts %}
 | 
			
		||||
                                <tr>
 | 
			
		||||
                                    <td>
 | 
			
		||||
                                        <a href="/contracts/{{ contract.id }}">{{ contract.title }}</a>
 | 
			
		||||
                                    </td>
 | 
			
		||||
                                    <td>{{ contract.contract_type }}</td>
 | 
			
		||||
                                    <td>{{ contract.created_by }}</td>
 | 
			
		||||
                                    <td>{{ contract.pending_signers }} of {{ contract.signers|length }}</td>
 | 
			
		||||
                                    <td>{{ contract.created_at | date(format="%Y-%m-%d") }}</td>
 | 
			
		||||
                                    <td>
 | 
			
		||||
                                        <a href="/contracts/{{ contract.id }}" class="btn btn-sm btn-primary">
 | 
			
		||||
                                            <i class="bi bi-eye"></i>
 | 
			
		||||
                                        </a>
 | 
			
		||||
                                    </td>
 | 
			
		||||
                                </tr>
 | 
			
		||||
                                {% endfor %}
 | 
			
		||||
                            </tbody>
 | 
			
		||||
                        </table>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
 | 
			
		||||
    <!-- Draft Contracts -->
 | 
			
		||||
    {% if draft_contracts and draft_contracts | length > 0 %}
 | 
			
		||||
    <div class="row mb-4">
 | 
			
		||||
        <div class="col-12">
 | 
			
		||||
            <div class="card">
 | 
			
		||||
                <div class="card-header">
 | 
			
		||||
                    <h5 class="mb-0">Draft Contracts</h5>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="card-body">
 | 
			
		||||
                    <div class="table-responsive">
 | 
			
		||||
                        <table class="table table-hover">
 | 
			
		||||
                            <thead>
 | 
			
		||||
                                <tr>
 | 
			
		||||
                                    <th>Contract Title</th>
 | 
			
		||||
                                    <th>Type</th>
 | 
			
		||||
                                    <th>Created By</th>
 | 
			
		||||
                                    <th>Created</th>
 | 
			
		||||
                                    <th>Actions</th>
 | 
			
		||||
                                </tr>
 | 
			
		||||
                            </thead>
 | 
			
		||||
                            <tbody>
 | 
			
		||||
                                {% for contract in draft_contracts %}
 | 
			
		||||
                                <tr>
 | 
			
		||||
                                    <td>
 | 
			
		||||
                                        <a href="/contracts/{{ contract.id }}">{{ contract.title }}</a>
 | 
			
		||||
                                    </td>
 | 
			
		||||
                                    <td>{{ contract.contract_type }}</td>
 | 
			
		||||
                                    <td>{{ contract.created_by }}</td>
 | 
			
		||||
                                    <td>{{ contract.created_at | date(format="%Y-%m-%d") }}</td>
 | 
			
		||||
                                    <td>
 | 
			
		||||
                                        <div class="btn-group">
 | 
			
		||||
                                            <a href="/contracts/{{ contract.id }}" class="btn btn-sm btn-primary">
 | 
			
		||||
                                                <i class="bi bi-eye"></i>
 | 
			
		||||
                                            </a>
 | 
			
		||||
                                            <a href="/contracts/{{ contract.id }}/edit" class="btn btn-sm btn-outline-secondary">
 | 
			
		||||
                                                <i class="bi bi-pencil"></i>
 | 
			
		||||
                                            </a>
 | 
			
		||||
                                        </div>
 | 
			
		||||
                                    </td>
 | 
			
		||||
                                </tr>
 | 
			
		||||
                                {% endfor %}
 | 
			
		||||
                            </tbody>
 | 
			
		||||
                        </table>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
</div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
							
								
								
									
										134
									
								
								actix_mvc_app/src/views/contracts/my_contracts.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								actix_mvc_app/src/views/contracts/my_contracts.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,134 @@
 | 
			
		||||
{% extends "base.html" %}
 | 
			
		||||
 | 
			
		||||
{% block title %}My Contracts{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
<div class="container">
 | 
			
		||||
    <div class="row mb-4">
 | 
			
		||||
        <div class="col-12">
 | 
			
		||||
            <nav aria-label="breadcrumb">
 | 
			
		||||
                <ol class="breadcrumb">
 | 
			
		||||
                    <li class="breadcrumb-item"><a href="/contracts">Contracts Dashboard</a></li>
 | 
			
		||||
                    <li class="breadcrumb-item active" aria-current="page">My Contracts</li>
 | 
			
		||||
                </ol>
 | 
			
		||||
            </nav>
 | 
			
		||||
            <div class="d-flex justify-content-between align-items-center">
 | 
			
		||||
                <h1 class="display-5 mb-0">My Contracts</h1>
 | 
			
		||||
                <div class="btn-group">
 | 
			
		||||
                    <a href="/contracts/create" class="btn btn-primary">
 | 
			
		||||
                        <i class="bi bi-plus-circle me-1"></i> Create New Contract
 | 
			
		||||
                    </a>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- Filters -->
 | 
			
		||||
    <div class="row mb-4">
 | 
			
		||||
        <div class="col-12">
 | 
			
		||||
            <div class="card">
 | 
			
		||||
                <div class="card-header">
 | 
			
		||||
                    <h5 class="mb-0">Filters</h5>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="card-body">
 | 
			
		||||
                    <form action="/contracts/my-contracts" method="get" class="row g-3">
 | 
			
		||||
                        <div class="col-md-4">
 | 
			
		||||
                            <label for="status" class="form-label">Status</label>
 | 
			
		||||
                            <select class="form-select" id="status" name="status">
 | 
			
		||||
                                <option value="">All Statuses</option>
 | 
			
		||||
                                <option value="Draft">Draft</option>
 | 
			
		||||
                                <option value="PendingSignatures">Pending Signatures</option>
 | 
			
		||||
                                <option value="Signed">Signed</option>
 | 
			
		||||
                                <option value="Expired">Expired</option>
 | 
			
		||||
                                <option value="Cancelled">Cancelled</option>
 | 
			
		||||
                            </select>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="col-md-4">
 | 
			
		||||
                            <label for="type" class="form-label">Contract Type</label>
 | 
			
		||||
                            <select class="form-select" id="type" name="type">
 | 
			
		||||
                                <option value="">All Types</option>
 | 
			
		||||
                                <option value="Service">Service Agreement</option>
 | 
			
		||||
                                <option value="Employment">Employment Contract</option>
 | 
			
		||||
                                <option value="NDA">Non-Disclosure Agreement</option>
 | 
			
		||||
                                <option value="SLA">Service Level Agreement</option>
 | 
			
		||||
                                <option value="Other">Other</option>
 | 
			
		||||
                            </select>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="col-md-4 d-flex align-items-end">
 | 
			
		||||
                            <button type="submit" class="btn btn-primary w-100">Apply Filters</button>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </form>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- Contract List -->
 | 
			
		||||
    <div class="row">
 | 
			
		||||
        <div class="col-12">
 | 
			
		||||
            <div class="card">
 | 
			
		||||
                <div class="card-header">
 | 
			
		||||
                    <h5 class="mb-0">My Contracts</h5>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="card-body">
 | 
			
		||||
                    {% if contracts and contracts | length > 0 %}
 | 
			
		||||
                    <div class="table-responsive">
 | 
			
		||||
                        <table class="table table-hover">
 | 
			
		||||
                            <thead>
 | 
			
		||||
                                <tr>
 | 
			
		||||
                                    <th>Contract Title</th>
 | 
			
		||||
                                    <th>Type</th>
 | 
			
		||||
                                    <th>Status</th>
 | 
			
		||||
                                    <th>Signers</th>
 | 
			
		||||
                                    <th>Created</th>
 | 
			
		||||
                                    <th>Updated</th>
 | 
			
		||||
                                    <th>Actions</th>
 | 
			
		||||
                                </tr>
 | 
			
		||||
                            </thead>
 | 
			
		||||
                            <tbody>
 | 
			
		||||
                                {% for contract in contracts %}
 | 
			
		||||
                                <tr>
 | 
			
		||||
                                    <td>
 | 
			
		||||
                                        <a href="/contracts/{{ contract.id }}">{{ contract.title }}</a>
 | 
			
		||||
                                    </td>
 | 
			
		||||
                                    <td>{{ contract.contract_type }}</td>
 | 
			
		||||
                                    <td>
 | 
			
		||||
                                        <span class="badge {% if contract.status == 'Signed' %}bg-success{% elif contract.status == 'PendingSignatures' %}bg-warning text-dark{% elif contract.status == 'Draft' %}bg-secondary{% elif contract.status == 'Expired' %}bg-danger{% else %}bg-dark{% endif %}">
 | 
			
		||||
                                            {{ contract.status }}
 | 
			
		||||
                                        </span>
 | 
			
		||||
                                    </td>
 | 
			
		||||
                                    <td>{{ contract.signed_signers }}/{{ contract.signers|length }}</td>
 | 
			
		||||
                                    <td>{{ contract.created_at | date(format="%Y-%m-%d") }}</td>
 | 
			
		||||
                                    <td>{{ contract.updated_at | date(format="%Y-%m-%d") }}</td>
 | 
			
		||||
                                    <td>
 | 
			
		||||
                                        <div class="btn-group">
 | 
			
		||||
                                            <a href="/contracts/{{ contract.id }}" class="btn btn-sm btn-primary">
 | 
			
		||||
                                                <i class="bi bi-eye"></i>
 | 
			
		||||
                                            </a>
 | 
			
		||||
                                            {% if contract.status == 'Draft' %}
 | 
			
		||||
                                            <a href="/contracts/{{ contract.id }}/edit" class="btn btn-sm btn-outline-secondary">
 | 
			
		||||
                                                <i class="bi bi-pencil"></i>
 | 
			
		||||
                                            </a>
 | 
			
		||||
                                            {% endif %}
 | 
			
		||||
                                        </div>
 | 
			
		||||
                                    </td>
 | 
			
		||||
                                </tr>
 | 
			
		||||
                                {% endfor %}
 | 
			
		||||
                            </tbody>
 | 
			
		||||
                        </table>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    {% else %}
 | 
			
		||||
                    <div class="text-center py-5">
 | 
			
		||||
                        <i class="bi bi-file-earmark-text fs-1 text-muted"></i>
 | 
			
		||||
                        <p class="mt-3 text-muted">You don't have any contracts yet</p>
 | 
			
		||||
                        <a href="/contracts/create" class="btn btn-primary mt-2">
 | 
			
		||||
                            <i class="bi bi-plus-circle me-1"></i> Create Your First Contract
 | 
			
		||||
                        </a>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    {% endif %}
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
		Reference in New Issue
	
	Block a user