feat: Add initial production deployment support

- Add .env.example file for environment variable setup
- Add .gitignore to manage sensitive files and directories
- Add Dockerfile.prod for production-ready Docker image
- Add PRODUCTION_CHECKLIST.md for pre/post deployment steps
- Add PRODUCTION_DEPLOYMENT.md for deployment instructions
- Add STRIPE_SETUP.md for Stripe payment configuration
- Add config/default.toml for default configuration settings
- Add config/local.toml.example for local configuration template
This commit is contained in:
Mahmoud-Emad
2025-06-25 18:32:20 +03:00
parent 464e253739
commit d3a66d4fc8
46 changed files with 11786 additions and 1230 deletions

View File

@@ -0,0 +1,417 @@
{% extends "base.html" %}
{% block title %}{{ company.name }} - Document Management{% endblock %}
{% block head %}
{{ super() }}
<style>
.document-card {
transition: transform 0.2s;
}
.document-card:hover {
transform: translateY(-2px);
}
.file-icon {
font-size: 2rem;
margin-bottom: 0.5rem;
}
.upload-area {
border: 2px dashed #dee2e6;
border-radius: 0.375rem;
padding: 2rem;
text-align: center;
transition: border-color 0.2s;
}
.upload-area:hover {
border-color: #0d6efd;
}
.upload-area.dragover {
border-color: #0d6efd;
background-color: #f8f9fa;
}
</style>
{% endblock %}
{% block content %}
<div class="container-fluid py-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2><i class="bi bi-folder me-2"></i>{{ company.name }} - Documents</h2>
<div>
<a href="/company/view/{{ company.base_data.id }}" class="btn btn-outline-secondary me-2">
<i class="bi bi-arrow-left me-1"></i>Back to Company
</a>
<a href="/company" class="btn btn-outline-secondary">
<i class="bi bi-building me-1"></i>All Companies
</a>
</div>
</div>
<!-- Success/Error Messages -->
{% if success %}
<div class="alert alert-success alert-dismissible fade show" role="alert">
<i class="bi bi-check-circle me-2"></i>{{ success }}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
{% endif %}
{% if error %}
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<i class="bi bi-exclamation-triangle me-2"></i>{{ error }}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
{% endif %}
<!-- Document Statistics -->
<div class="row mb-4">
<div class="col-md-3">
<div class="card text-center">
<div class="card-body">
<i class="bi bi-files text-primary" style="font-size: 2rem;"></i>
<h4 class="mt-2">{{ stats.total_documents }}</h4>
<p class="text-muted mb-0">Total Documents</p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-center">
<div class="card-body">
<i class="bi bi-hdd text-info" style="font-size: 2rem;"></i>
<h4 class="mt-2">{{ stats.formatted_total_size }}</h4>
<p class="text-muted mb-0">Total Size</p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-center">
<div class="card-body">
<i class="bi bi-upload text-success" style="font-size: 2rem;"></i>
<h4 class="mt-2">{{ stats.recent_uploads }}</h4>
<p class="text-muted mb-0">Recent Uploads</p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-center">
<div class="card-body">
<i class="bi bi-folder-plus text-warning" style="font-size: 2rem;"></i>
<h4 class="mt-2">{{ stats.by_type | length }}</h4>
<p class="text-muted mb-0">Document Types</p>
</div>
</div>
</div>
</div>
<!-- Document Upload Section -->
<div class="card mb-4">
<div class="card-header bg-primary text-white">
<h5 class="mb-0"><i class="bi bi-cloud-upload me-2"></i>Upload Documents</h5>
</div>
<div class="card-body">
<form action="/company/documents/{{ company_id }}/upload" method="post" enctype="multipart/form-data"
id="uploadForm">
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label for="document_type" class="form-label">Document Type</label>
<select class="form-select" id="document_type" name="document_type" required>
<option value="">Select document type...</option>
{% for doc_type in document_types %}
<option value="{{ doc_type.0 }}">{{ doc_type.1 }}</option>
{% endfor %}
</select>
</div>
<div class="mb-3">
<label for="description" class="form-label">Description (Optional)</label>
<textarea class="form-control" id="description" name="description" rows="3"
placeholder="Enter document description..."></textarea>
</div>
<div class="mb-3 form-check">
<input type="checkbox" class="form-check-input" id="is_public" name="is_public">
<label class="form-check-label" for="is_public">
Make document publicly accessible
</label>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label for="documents" class="form-label">Select Files</label>
<div class="upload-area" id="uploadArea">
<i class="bi bi-cloud-upload file-icon text-muted"></i>
<p class="mb-2">Drag and drop files here or click to browse</p>
<input type="file" class="form-control" id="documents" name="documents" multiple
accept=".pdf,.doc,.docx,.jpg,.jpeg,.png,.txt" style="display: none;">
<button type="button" class="btn btn-outline-primary"
onclick="document.getElementById('documents').click()">
<i class="bi bi-folder2-open me-1"></i>Browse Files
</button>
<div id="fileList" class="mt-3"></div>
</div>
</div>
</div>
</div>
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-primary" id="uploadBtn">
<i class="bi bi-upload me-1"></i>Upload Documents
</button>
</div>
</form>
</div>
</div>
<!-- Documents List -->
<div class="card">
<div class="card-header bg-light">
<div class="d-flex justify-content-between align-items-center">
<h5 class="mb-0"><i class="bi bi-files me-2"></i>Documents ({{ documents | length }})</h5>
<div class="input-group" style="width: 300px;">
<input type="text" class="form-control" id="searchInput" placeholder="Search documents...">
<button class="btn btn-outline-secondary" type="button" id="searchBtn">
<i class="bi bi-search"></i>
</button>
</div>
</div>
</div>
<div class="card-body">
{% if documents and documents | length > 0 %}
<div class="row" id="documentsGrid">
{% for document in documents %}
<div class="col-md-4 mb-3 document-item" data-name="{{ document.name | lower }}"
data-type="{{ document.document_type_str | lower }}">
<div class="card document-card h-100">
<div class="card-body">
<div class="d-flex justify-content-between align-items-start mb-2">
<div class="file-icon">
{% if document.is_pdf %}
<i class="bi bi-file-earmark-pdf text-danger"></i>
{% elif document.is_image %}
<i class="bi bi-file-earmark-image text-success"></i>
{% elif document.mime_type == "application/msword" %}
<i class="bi bi-file-earmark-word text-primary"></i>
{% else %}
<i class="bi bi-file-earmark text-secondary"></i>
{% endif %}
</div>
<div class="dropdown">
<button class="btn btn-sm btn-outline-secondary dropdown-toggle" type="button"
data-bs-toggle="dropdown">
<i class="bi bi-three-dots"></i>
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#"
onclick="downloadDocument({{ document.id }})">
<i class="bi bi-download me-1"></i>Download
</a></li>
<li><a class="dropdown-item" href="#" onclick="editDocument({{ document.id }})">
<i class="bi bi-pencil me-1"></i>Edit
</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li><a class="dropdown-item text-danger" href="#"
onclick="deleteDocument({{ document.id }}, '{{ document.name }}')">
<i class="bi bi-trash me-1"></i>Delete
</a></li>
</ul>
</div>
</div>
<h6 class="card-title text-truncate" title="{{ document.name }}">{{ document.name }}</h6>
<p class="card-text">
<small class="text-muted">
<span class="badge bg-secondary mb-1">{{ document.document_type_str }}</span><br>
Size: {{ document.formatted_file_size }}<br>
Uploaded: {{ document.formatted_upload_date }}<br>
By: {{ document.uploaded_by }}
{% if document.is_public %}
<br><span class="badge bg-success">Public</span>
{% endif %}
</small>
</p>
{% if document.description %}
<p class="card-text"><small>{{ document.description }}</small></p>
{% endif %}
</div>
</div>
</div>
{% endfor %}
</div>
{% else %}
<div class="text-center py-5">
<i class="bi bi-folder-x text-muted" style="font-size: 4rem;"></i>
<h4 class="text-muted mt-3">No Documents Found</h4>
<p class="text-muted">Upload your first document using the form above.</p>
</div>
{% endif %}
</div>
</div>
</div>
<!-- Delete Confirmation Modal -->
<div class="modal fade" id="deleteModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Confirm Delete</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<p>Are you sure you want to delete the document "<span id="deleteDocumentName"></span>"?</p>
<p class="text-danger"><small>This action cannot be undone.</small></p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<a href="#" class="btn btn-danger" id="confirmDeleteBtn">Delete Document</a>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
{{ super() }}
<script>
document.addEventListener('DOMContentLoaded', function () {
const uploadArea = document.getElementById('uploadArea');
const fileInput = document.getElementById('documents');
const fileList = document.getElementById('fileList');
const uploadBtn = document.getElementById('uploadBtn');
const searchInput = document.getElementById('searchInput');
// File upload handling
fileInput.addEventListener('change', function () {
console.log('Files selected:', this.files.length);
updateFileList();
updateUploadButton();
});
// Drag and drop
uploadArea.addEventListener('dragover', function (e) {
e.preventDefault();
e.stopPropagation();
uploadArea.classList.add('dragover');
});
uploadArea.addEventListener('dragleave', function (e) {
e.preventDefault();
e.stopPropagation();
uploadArea.classList.remove('dragover');
});
uploadArea.addEventListener('drop', function (e) {
e.preventDefault();
e.stopPropagation();
uploadArea.classList.remove('dragover');
const files = e.dataTransfer.files;
console.log('Files dropped:', files.length);
// Create a new DataTransfer object and assign to input
const dt = new DataTransfer();
for (let i = 0; i < files.length; i++) {
dt.items.add(files[i]);
}
fileInput.files = dt.files;
updateFileList();
updateUploadButton();
});
// Click to upload area
uploadArea.addEventListener('click', function (e) {
if (e.target.tagName !== 'BUTTON' && e.target.tagName !== 'INPUT') {
fileInput.click();
}
});
// Search functionality
searchInput.addEventListener('input', function () {
const searchTerm = this.value.toLowerCase();
const documentItems = document.querySelectorAll('.document-item');
documentItems.forEach(function (item) {
const name = item.dataset.name;
const type = item.dataset.type;
const matches = name.includes(searchTerm) || type.includes(searchTerm);
item.style.display = matches ? 'block' : 'none';
});
});
function updateFileList() {
const files = Array.from(fileInput.files);
if (files.length === 0) {
fileList.innerHTML = '';
return;
}
const listHtml = files.map(file =>
`<div class="d-flex justify-content-between align-items-center p-2 border rounded mb-1">
<span class="text-truncate">${file.name}</span>
<small class="text-muted">${formatFileSize(file.size)}</small>
</div>`
).join('');
fileList.innerHTML = `<div class="mt-2"><strong>Selected files:</strong>${listHtml}</div>`;
}
function updateUploadButton() {
const hasFiles = fileInput.files.length > 0;
const hasDocumentType = document.getElementById('document_type').value !== '';
uploadBtn.disabled = !hasFiles || !hasDocumentType;
console.log('Update upload button - Files:', hasFiles, 'DocType:', hasDocumentType);
}
// Also update button when document type changes
document.getElementById('document_type').addEventListener('change', function () {
updateUploadButton();
});
// Add form submission debugging
document.getElementById('uploadForm').addEventListener('submit', function (e) {
console.log('Form submitted');
console.log('Files:', fileInput.files.length);
console.log('Document type:', document.getElementById('document_type').value);
if (fileInput.files.length === 0) {
e.preventDefault();
alert('Please select at least one file to upload.');
return false;
}
if (document.getElementById('document_type').value === '') {
e.preventDefault();
alert('Please select a document type.');
return false;
}
});
function formatFileSize(bytes) {
if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
}
});
function deleteDocument(documentId, documentName) {
document.getElementById('deleteDocumentName').textContent = documentName;
document.getElementById('confirmDeleteBtn').href = `/company/documents/{{ company_id }}/delete/${documentId}`;
new bootstrap.Modal(document.getElementById('deleteModal')).show();
}
function downloadDocument(documentId) {
// TODO: Implement download functionality
alert('Download functionality will be implemented soon');
}
function editDocument(documentId) {
// TODO: Implement edit functionality
alert('Edit functionality will be implemented soon');
}
</script>
{% endblock %}

View File

@@ -0,0 +1,249 @@
{% extends "base.html" %}
{% block title %}Edit {{ company.name }} - Company Management{% endblock %}
{% block content %}
<div class="container-fluid py-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2><i class="bi bi-pencil-square me-2"></i>Edit Company</h2>
<div>
<a href="/company/view/{{ company.base_data.id }}" class="btn btn-outline-secondary me-2">
<i class="bi bi-arrow-left me-1"></i>Back to Company
</a>
<a href="/company" class="btn btn-outline-secondary">
<i class="bi bi-building me-1"></i>All Companies
</a>
</div>
</div>
<!-- Success/Error Messages -->
{% if success %}
<div class="alert alert-success alert-dismissible fade show" role="alert">
<i class="bi bi-check-circle me-2"></i>{{ success }}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
{% endif %}
{% if error %}
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<i class="bi bi-exclamation-triangle me-2"></i>{{ error }}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
{% endif %}
<!-- Edit Form -->
<div class="card">
<div class="card-header bg-light">
<h5 class="mb-0"><i class="bi bi-building me-2"></i>Company Information</h5>
</div>
<div class="card-body">
<form action="/company/edit/{{ company.base_data.id }}" method="post" id="editCompanyForm">
<div class="row">
<!-- Basic Information -->
<div class="col-md-6">
<h6 class="text-muted mb-3">Basic Information</h6>
<div class="mb-3">
<label for="company_name" class="form-label">Company Name <span
class="text-danger">*</span></label>
<input type="text" class="form-control" id="company_name" name="company_name"
value="{{ company.name }}" required>
</div>
<div class="mb-3">
<label for="company_type" class="form-label">Company Type <span
class="text-danger">*</span></label>
<select class="form-select" id="company_type" name="company_type" required>
<option value="Startup FZC" {% if company.business_type=="Starter" %}selected{% endif
%}>Startup FZC</option>
<option value="Growth FZC" {% if company.business_type=="Global" %}selected{% endif %}>
Growth FZC</option>
<option value="Cooperative FZC" {% if company.business_type=="Coop" %}selected{% endif
%}>Cooperative FZC</option>
<option value="Single FZC" {% if company.business_type=="Single" %}selected{% endif %}>
Single FZC</option>
<option value="Twin FZC" {% if company.business_type=="Twin" %}selected{% endif %}>Twin
FZC</option>
</select>
</div>
<div class="mb-3">
<label for="status" class="form-label">Status</label>
<select class="form-select" id="status" name="status">
<option value="Active" {% if company.status=="Active" %}selected{% endif %}>Active
</option>
<option value="Inactive" {% if company.status=="Inactive" %}selected{% endif %}>Inactive
</option>
<option value="Suspended" {% if company.status=="Suspended" %}selected{% endif %}>
Suspended</option>
</select>
</div>
<div class="mb-3">
<label for="industry" class="form-label">Industry</label>
<input type="text" class="form-control" id="industry" name="industry"
value="{{ company.industry | default(value='') }}">
</div>
<div class="mb-3">
<label for="fiscal_year_end" class="form-label">Fiscal Year End</label>
<input type="text" class="form-control" id="fiscal_year_end" name="fiscal_year_end"
value="{{ company.fiscal_year_end | default(value='') }}"
placeholder="MM-DD (e.g., 12-31)" pattern="^(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$"
title="Enter date in MM-DD format (e.g., 12-31)">
<div class="form-text">Enter the last day of your company's fiscal year (MM-DD format)</div>
</div>
</div>
<!-- Contact Information -->
<div class="col-md-6">
<h6 class="text-muted mb-3">Contact Information</h6>
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<input type="email" class="form-control" id="email" name="email"
value="{{ company.email | default(value='') }}">
</div>
<div class="mb-3">
<label for="phone" class="form-label">Phone</label>
<input type="tel" class="form-control" id="phone" name="phone"
value="{{ company.phone | default(value='') }}">
</div>
<div class="mb-3">
<label for="website" class="form-label">Website</label>
<input type="url" class="form-control" id="website" name="website"
value="{{ company.website | default(value='') }}" placeholder="https://example.com">
</div>
<div class="mb-3">
<label for="address" class="form-label">Address</label>
<textarea class="form-control" id="address" name="address"
rows="3">{{ company.address | default(value='') }}</textarea>
</div>
</div>
</div>
<!-- Description -->
<div class="row">
<div class="col-12">
<h6 class="text-muted mb-3">Additional Information</h6>
<div class="mb-3">
<label for="description" class="form-label">Company Description</label>
<textarea class="form-control" id="description" name="description" rows="4"
placeholder="Describe the company's purpose and activities">{{ company.description | default(value='') }}</textarea>
</div>
</div>
</div>
<!-- Read-only Information -->
<div class="row">
<div class="col-12">
<h6 class="text-muted mb-3">Registration Information (Read-only)</h6>
<div class="row">
<div class="col-md-4">
<div class="mb-3">
<label class="form-label">Registration Number</label>
<input type="text" class="form-control" value="{{ company.registration_number }}"
readonly>
</div>
</div>
<div class="col-md-4">
<div class="mb-3">
<label class="form-label">Incorporation Date</label>
<input type="text" class="form-control" value="{{ incorporation_date_formatted }}"
readonly>
</div>
</div>
<div class="col-md-4">
<div class="mb-3">
<label class="form-label">Company ID</label>
<input type="text" class="form-control" value="{{ company.base_data.id }}" readonly>
</div>
</div>
</div>
</div>
</div>
<!-- Form Actions -->
<div class="d-flex justify-content-between">
<div>
<a href="/company/view/{{ company.base_data.id }}" class="btn btn-outline-secondary">
<i class="bi bi-x-circle me-1"></i>Cancel
</a>
</div>
<div>
<button type="submit" class="btn btn-primary">
<i class="bi bi-check-circle me-1"></i>Update Company
</button>
</div>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
{{ super() }}
<script>
document.addEventListener('DOMContentLoaded', function () {
// Form validation
const form = document.getElementById('editCompanyForm');
const companyName = document.getElementById('company_name');
form.addEventListener('submit', function (e) {
if (companyName.value.trim() === '') {
e.preventDefault();
showValidationAlert('Company name is required', companyName);
}
});
// Function to show validation alert with consistent styling
function showValidationAlert(message, focusElement) {
// Remove existing alerts
const existingAlerts = document.querySelectorAll('.validation-alert');
existingAlerts.forEach(alert => alert.remove());
// Create new alert
const alertDiv = document.createElement('div');
alertDiv.className = 'alert alert-warning alert-dismissible fade show validation-alert mt-3';
alertDiv.innerHTML = `
<div class="d-flex align-items-center">
<i class="bi bi-exclamation-triangle me-2"></i>
<span>${message}</span>
</div>
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
`;
// Insert alert at the top of the form
const form = document.getElementById('editCompanyForm');
form.insertBefore(alertDiv, form.firstChild);
// Focus on the problematic field
if (focusElement) {
focusElement.focus();
focusElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
// Auto-dismiss after 5 seconds
setTimeout(() => {
if (alertDiv.parentNode) {
alertDiv.remove();
}
}, 5000);
}
// Auto-format website URL
const websiteInput = document.getElementById('website');
websiteInput.addEventListener('blur', function () {
let value = this.value.trim();
if (value && !value.startsWith('http://') && !value.startsWith('https://')) {
this.value = 'https://' + value;
}
});
});
</script>
{% endblock %}

View File

@@ -15,55 +15,71 @@
</tr>
</thead>
<tbody>
<!-- Example rows -->
{% if companies and companies|length > 0 %}
{% for company in companies %}
<tr>
<td>Zanzibar Digital Solutions</td>
<td>Startup FZC</td>
<td><span class="badge bg-success">Active</span></td>
<td>2025-04-01</td>
<td>{{ company.name }}</td>
<td>
{% if company.business_type == "Starter" %}Startup FZC
{% elif company.business_type == "Global" %}Growth FZC
{% elif company.business_type == "Coop" %}Cooperative FZC
{% elif company.business_type == "Single" %}Single FZC
{% elif company.business_type == "Twin" %}Twin FZC
{% else %}{{ company.business_type }}
{% endif %}
</td>
<td>
{% if company.status == "Active" %}
<span class="badge bg-success">Active</span>
{% elif company.status == "Inactive" %}
<span class="badge bg-secondary">Inactive</span>
{% elif company.status == "Suspended" %}
<span class="badge bg-warning text-dark">Suspended</span>
{% else %}
<span class="badge bg-secondary">{{ company.status }}</span>
{% endif %}
</td>
<td>{{ company.incorporation_date | date(format="%Y-%m-%d") }}</td>
<td>
<div class="btn-group">
<a href="/company/view/company1" class="btn btn-sm btn-outline-primary"><i class="bi bi-eye"></i> View</a>
<a href="/company/switch/company1" class="btn btn-sm btn-primary"><i class="bi bi-box-arrow-in-right"></i> Switch to Entity</a>
<a href="/company/view/{{ company.base_data.id }}" class="btn btn-sm btn-outline-primary">
<i class="bi bi-eye"></i> View
</a>
<a href="/company/switch/{{ company.base_data.id }}" class="btn btn-sm btn-primary">
<i class="bi bi-box-arrow-in-right"></i> Switch to Entity
</a>
</div>
</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td>Blockchain Innovations Ltd</td>
<td>Growth FZC</td>
<td><span class="badge bg-success">Active</span></td>
<td>2025-03-15</td>
<td>
<div class="btn-group">
<a href="/company/view/company2" class="btn btn-sm btn-outline-primary"><i class="bi bi-eye"></i> View</a>
<a href="/company/switch/company2" class="btn btn-sm btn-primary"><i class="bi bi-box-arrow-in-right"></i> Switch to Entity</a>
<td colspan="5" class="text-center py-4">
<div class="text-muted">
<i class="bi bi-building display-4 mb-3"></i>
<h5>No Companies Found</h5>
<p>You haven't registered any companies yet. Get started by registering your first company.
</p>
<button class="btn btn-primary" onclick="document.querySelector('#register-tab').click()">
<i class="bi bi-plus-circle me-1"></i> Register Your First Company
</button>
</div>
</td>
</tr>
<tr>
<td>Sustainable Energy Cooperative</td>
<td>Cooperative FZC</td>
<td><span class="badge bg-warning text-dark">Pending</span></td>
<td>2025-05-01</td>
<td>
<div class="btn-group">
<a href="/company/view/company3" class="btn btn-sm btn-outline-primary"><i class="bi bi-eye"></i> View</a>
<a href="/company/switch/company3" class="btn btn-sm btn-primary"><i class="bi bi-box-arrow-in-right"></i> Switch to Entity</a>
</div>
</td>
</tr>
<!-- More rows dynamically rendered here -->
{% endif %}
</tbody>
</table>
</div>
</div>
<!-- Company Details Modal -->
<div class="modal fade" id="companyDetailsModal" tabindex="-1" aria-labelledby="companyDetailsModalLabel" aria-hidden="true">
<div class="modal fade" id="companyDetailsModal" tabindex="-1" aria-labelledby="companyDetailsModalLabel"
aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header bg-light">
<h5 class="modal-title" id="companyDetailsModalLabel"><i class="bi bi-building me-2"></i>Company Details</h5>
<h5 class="modal-title" id="companyDetailsModalLabel"><i class="bi bi-building me-2"></i>Company Details
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
@@ -121,7 +137,7 @@
</div>
</div>
</div>
<div class="row mb-4">
<div class="col-md-6">
<div class="card h-100">
@@ -186,8 +202,9 @@
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" onclick="switchToEntityFromModal()"><i class="bi bi-box-arrow-in-right me-1"></i>Switch to Entity</button>
<button type="button" class="btn btn-primary" onclick="switchToEntityFromModal()"><i
class="bi bi-box-arrow-in-right me-1"></i>Switch to Entity</button>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,78 @@
{% extends "base.html" %}
{% block title %}Payment Error - Company Registration{% endblock %}
{% block content %}
<div class="container mt-4">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card border-danger">
<div class="card-header bg-danger text-white text-center">
<h3 class="mb-0">
<i class="bi bi-exclamation-triangle-fill me-2"></i>
Payment Error
</h3>
</div>
<div class="card-body text-center">
<div class="mb-4">
<i class="bi bi-x-circle text-danger" style="font-size: 4rem;"></i>
</div>
<h4 class="text-danger mb-3">Payment Processing Failed</h4>
<p class="lead mb-4">
We encountered an issue processing your payment. Your company registration could not be completed.
</p>
{% if error %}
<div class="alert alert-danger">
<h6><i class="bi bi-exclamation-circle me-2"></i>Error Details</h6>
<p class="mb-0">{{ error }}</p>
</div>
{% endif %}
<div class="alert alert-info">
<h6><i class="bi bi-info-circle me-2"></i>What You Can Do</h6>
<ul class="list-unstyled mb-0 text-start">
<li><i class="bi bi-arrow-right me-2"></i>Check your payment method details</li>
<li><i class="bi bi-arrow-right me-2"></i>Ensure you have sufficient funds</li>
<li><i class="bi bi-arrow-right me-2"></i>Try a different payment method</li>
<li><i class="bi bi-arrow-right me-2"></i>Contact your bank if the issue persists</li>
<li><i class="bi bi-arrow-right me-2"></i>Contact our support team for assistance</li>
</ul>
</div>
<div class="d-grid gap-2 d-md-flex justify-content-md-center">
<a href="/company?tab=register" class="btn btn-primary btn-lg">
<i class="bi bi-arrow-clockwise me-2"></i>Try Again
</a>
<a href="/contact" class="btn btn-outline-primary btn-lg">
<i class="bi bi-envelope me-2"></i>Contact Support
</a>
</div>
</div>
<div class="card-footer text-muted text-center">
<small>
<i class="bi bi-shield-check me-1"></i>
No charges were made to your account
</small>
</div>
</div>
</div>
</div>
</div>
<style>
.card {
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
}
.alert-info {
border-left: 4px solid #0dcaf0;
}
.alert-danger {
border-left: 4px solid #dc3545;
}
</style>
{% endblock %}

View File

@@ -0,0 +1,89 @@
{% extends "base.html" %}
{% block title %}Payment Successful - Company Registration{% endblock %}
{% block content %}
<div class="container mt-4">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card border-success">
<div class="card-header bg-success text-white text-center">
<h3 class="mb-0">
<i class="bi bi-check-circle-fill me-2"></i>
Payment Successful!
</h3>
</div>
<div class="card-body text-center">
<div class="mb-4">
<i class="bi bi-check-circle text-success" style="font-size: 4rem;"></i>
</div>
<h4 class="text-success mb-3">Company Registration Complete</h4>
<p class="lead mb-4">
Congratulations! Your payment has been processed successfully and your company has been registered.
</p>
<div class="row mb-4">
<div class="col-md-6">
<div class="card bg-light">
<div class="card-body">
<h6 class="card-title">Company ID</h6>
<p class="card-text h5 text-primary">{{ company_id }}</p>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card bg-light">
<div class="card-body">
<h6 class="card-title">Payment ID</h6>
<p class="card-text h6 text-muted">{{ payment_intent_id }}</p>
</div>
</div>
</div>
</div>
<div class="alert alert-info">
<h6><i class="bi bi-info-circle me-2"></i>What's Next?</h6>
<ul class="list-unstyled mb-0 text-start">
<li><i class="bi bi-check me-2"></i>You will receive a confirmation email shortly</li>
<li><i class="bi bi-check me-2"></i>Your company documents will be prepared within 24 hours</li>
<li><i class="bi bi-check me-2"></i>You can now access your company dashboard</li>
<li><i class="bi bi-check me-2"></i>Your subscription billing will begin next month</li>
</ul>
</div>
<div class="d-grid gap-2 d-md-flex justify-content-md-center">
<a href="/company" class="btn btn-primary btn-lg">
<i class="bi bi-building me-2"></i>Go to Company Dashboard
</a>
<a href="/company/view/{{ company_id }}" class="btn btn-outline-primary btn-lg">
<i class="bi bi-eye me-2"></i>View Company Details
</a>
</div>
</div>
<div class="card-footer text-muted text-center">
<small>
<i class="bi bi-shield-check me-1"></i>
Your payment was processed securely by Stripe
</small>
</div>
</div>
</div>
</div>
</div>
<style>
.card {
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
}
.bg-light {
background-color: #f8f9fa !important;
}
.alert-info {
border-left: 4px solid #0dcaf0;
}
</style>
{% endblock %}

File diff suppressed because it is too large Load Diff

View File

@@ -1,31 +1,80 @@
{% extends "base.html" %}
{% block title %}{{ company_name }} - Company Details{% endblock %}
{% block title %}{{ company.name }} - Company Details{% endblock %}
{% block head %}
{{ super() }}
<style>
.badge-signed {
background-color: #198754;
color: white;
}
.badge-pending {
background-color: #ffc107;
color: #212529;
}
</style>
{{ super() }}
<style>
.badge-signed {
background-color: #198754;
color: white;
}
.badge-pending {
background-color: #ffc107;
color: #212529;
}
</style>
{% endblock %}
{% block content %}
<div class="container-fluid py-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2><i class="bi bi-building me-2"></i>{{ company_name }}</h2>
<h2><i class="bi bi-building me-2"></i>{{ company.name }}</h2>
<div>
<a href="/company" class="btn btn-outline-secondary me-2"><i class="bi bi-arrow-left me-1"></i>Back to Companies</a>
<a href="/company/switch/{{ company_id }}" class="btn btn-primary"><i class="bi bi-box-arrow-in-right me-1"></i>Switch to Entity</a>
<a href="/company" class="btn btn-outline-secondary me-2"><i class="bi bi-arrow-left me-1"></i>Back to
Companies</a>
<a href="/company/switch/{{ company.base_data.id }}" class="btn btn-primary"><i
class="bi bi-box-arrow-in-right me-1"></i>Switch to Entity</a>
</div>
</div>
<!-- Profile Completion Status -->
{% if not company.email or company.email == "" or not company.phone or company.phone == "" or not company.address or
company.address == "" %}
<div class="alert alert-info alert-dismissible fade show" role="alert">
<div class="d-flex align-items-center">
<div class="me-3">
<i class="bi bi-info-circle fs-4"></i>
</div>
<div class="flex-grow-1">
<h6 class="alert-heading mb-1">Complete Your Company Profile</h6>
<p class="mb-2">Your company profile is missing some essential information. Add the missing details to
improve your company's visibility and professionalism.</p>
<div class="d-flex gap-2">
<a href="/company/edit/{{ company.base_data.id }}" class="btn btn-sm btn-outline-info">
<i class="bi bi-pencil me-1"></i>Complete Profile
</a>
<small class="text-muted align-self-center">
Missing:
{% if not company.email or company.email == "" %}Email{% endif %}
{% if not company.phone or company.phone == "" %}{% if not company.email or company.email == ""
%}, {% endif %}Phone{% endif %}
{% if not company.address or company.address == "" %}{% if not company.email or company.email ==
"" or not company.phone or company.phone == "" %}, {% endif %}Address{% endif %}
</small>
</div>
</div>
</div>
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
{% endif %}
<!-- Success/Error Messages -->
{% if success %}
<div class="alert alert-success alert-dismissible fade show" role="alert">
<i class="bi bi-check-circle me-2"></i>{{ success }}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
{% endif %}
{% if error %}
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<i class="bi bi-exclamation-triangle me-2"></i>{{ error }}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
{% endif %}
<div class="row mb-4">
<div class="col-md-6">
<div class="card h-100">
@@ -36,29 +85,49 @@
<table class="table table-borderless">
<tr>
<th style="width: 30%">Company Name:</th>
<td>{{ company_name }}</td>
<td>{{ company.name }}</td>
</tr>
<tr>
<th>Type:</th>
<td>{{ company_type }}</td>
</tr>
<tr>
<th>Registration Date:</th>
<td>{{ registration_date }}</td>
</tr>
<tr>
<th>Status:</th>
<td>
{% if status == "Active" %}
<span class="badge bg-success">{{ status }}</span>
{% else %}
<span class="badge bg-warning text-dark">{{ status }}</span>
{% if company.business_type == "Starter" %}Startup FZC
{% elif company.business_type == "Global" %}Growth FZC
{% elif company.business_type == "Coop" %}Cooperative FZC
{% elif company.business_type == "Single" %}Single FZC
{% elif company.business_type == "Twin" %}Twin FZC
{% else %}{{ company.business_type }}
{% endif %}
</td>
</tr>
<tr>
<th>Purpose:</th>
<td>{{ purpose }}</td>
<th>Registration Number:</th>
<td>{{ company.registration_number }}</td>
</tr>
<tr>
<th>Registration Date:</th>
<td>{{ incorporation_date_formatted }}</td>
</tr>
<tr>
<th>Status:</th>
<td>
{% if company.status == "Active" %}
<span class="badge bg-success">{{ company.status }}</span>
{% elif company.status == "Inactive" %}
<span class="badge bg-secondary">{{ company.status }}</span>
{% elif company.status == "Suspended" %}
<span class="badge bg-warning text-dark">{{ company.status }}</span>
{% else %}
<span class="badge bg-secondary">{{ company.status }}</span>
{% endif %}
</td>
</tr>
<tr>
<th>Industry:</th>
<td>{{ company.industry | default(value="Not specified") }}</td>
</tr>
<tr>
<th>Description:</th>
<td>{{ company.description | default(value="No description provided") }}</td>
</tr>
</table>
</div>
@@ -67,28 +136,86 @@
<div class="col-md-6">
<div class="card h-100">
<div class="card-header bg-light">
<h5 class="mb-0"><i class="bi bi-credit-card me-2"></i>Billing Information</h5>
<h5 class="mb-0"><i class="bi bi-info-circle me-2"></i>Additional Information</h5>
</div>
<div class="card-body">
<table class="table table-borderless">
<tr>
<th style="width: 30%">Plan:</th>
<td>{{ plan }}</td>
<th style="width: 30%">Email:</th>
<td>
{% if company.email and company.email != "" %}
{{ company.email }}
{% else %}
<span class="text-muted">Not provided</span>
<a href="/company/edit/{{ company.base_data.id }}"
class="btn btn-sm btn-outline-secondary ms-2">
<i class="bi bi-plus-circle me-1"></i>Add
</a>
{% endif %}
</td>
</tr>
<tr>
<th>Next Billing:</th>
<td>{{ next_billing }}</td>
<th>Phone:</th>
<td>
{% if company.phone and company.phone != "" %}
{{ company.phone }}
{% else %}
<span class="text-muted">Not provided</span>
<a href="/company/edit/{{ company.base_data.id }}"
class="btn btn-sm btn-outline-secondary ms-2">
<i class="bi bi-plus-circle me-1"></i>Add
</a>
{% endif %}
</td>
</tr>
<tr>
<th>Payment Method:</th>
<td>{{ payment_method }}</td>
<th>Website:</th>
<td>
{% if company.website and company.website != "" %}
<a href="{{ company.website }}" target="_blank">{{ company.website }}</a>
{% else %}
<span class="text-muted">Not provided</span>
<a href="/company/edit/{{ company.base_data.id }}"
class="btn btn-sm btn-outline-secondary ms-2">
<i class="bi bi-plus-circle me-1"></i>Add
</a>
{% endif %}
</td>
</tr>
<tr>
<th>Address:</th>
<td>
{% if company.address and company.address != "" %}
{{ company.address }}
{% else %}
<span class="text-muted">Not provided</span>
<a href="/company/edit/{{ company.base_data.id }}"
class="btn btn-sm btn-outline-secondary ms-2">
<i class="bi bi-plus-circle me-1"></i>Add
</a>
{% endif %}
</td>
</tr>
<tr>
<th>Fiscal Year End:</th>
<td>
{% if company.fiscal_year_end and company.fiscal_year_end != "" %}
{{ company.fiscal_year_end }}
{% else %}
<span class="text-muted">Not specified</span>
<a href="/company/edit/{{ company.base_data.id }}"
class="btn btn-sm btn-outline-secondary ms-2">
<i class="bi bi-plus-circle me-1"></i>Add
</a>
{% endif %}
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
<div class="row mb-4">
<div class="col-md-6">
<div class="card h-100">
@@ -104,12 +231,21 @@
</tr>
</thead>
<tbody>
{% if shareholders and shareholders|length > 0 %}
{% for shareholder in shareholders %}
<tr>
<td>{{ shareholder.0 }}</td>
<td>{{ shareholder.1 }}</td>
<td>{{ shareholder.name }}</td>
<td>{{ shareholder.percentage }}%</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td colspan="2" class="text-center text-muted py-3">
<i class="bi bi-people me-1"></i>
No shareholders registered yet
</td>
</tr>
{% endif %}
</tbody>
</table>
</div>
@@ -118,49 +254,91 @@
<div class="col-md-6">
<div class="card h-100">
<div class="card-header bg-light">
<h5 class="mb-0"><i class="bi bi-file-earmark-text me-2"></i>Contracts</h5>
<h5 class="mb-0"><i class="bi bi-credit-card me-2"></i>Billing & Payment</h5>
</div>
<div class="card-body">
<table class="table table-striped">
<thead>
<tr>
<th>Contract</th>
<th>Status</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{% for contract in contracts %}
<tr>
<td>{{ contract.0 }}</td>
<td>
{% if contract.1 == "Signed" %}
<span class="badge bg-success">{{ contract.1 }}</span>
{% else %}
<span class="badge bg-warning text-dark">{{ contract.1 }}</span>
{% endif %}
</td>
<td>
<a href="/contracts/view/{{ contract.0 | lower | replace(from=' ', to='-') }}" class="btn btn-sm btn-outline-primary">View</a>
</td>
</tr>
{% endfor %}
</tbody>
{% if payment_info %}
<table class="table table-borderless">
<tr>
<th style="width: 40%">Payment Status:</th>
<td>
{% if payment_info.status == "Succeeded" %}
<span class="badge bg-success">
<i class="bi bi-check-circle me-1"></i>Paid
</span>
{% elif payment_info.status == "Pending" %}
<span class="badge bg-warning">
<i class="bi bi-clock me-1"></i>Pending
</span>
{% elif payment_info.status == "Failed" %}
<span class="badge bg-danger">
<i class="bi bi-x-circle me-1"></i>Failed
</span>
{% else %}
<span class="badge bg-secondary">{{ payment_info.status }}</span>
{% endif %}
</td>
</tr>
<tr>
<th>Payment Plan:</th>
<td>{{ payment_plan_display }}</td>
</tr>
<tr>
<th>Setup Fee:</th>
<td>${{ payment_info.setup_fee }}</td>
</tr>
<tr>
<th>Monthly Fee:</th>
<td>${{ payment_info.monthly_fee }}</td>
</tr>
<tr>
<th>Total Paid:</th>
<td><strong>${{ payment_info.total_amount }}</strong></td>
</tr>
<tr>
<th>Payment Date:</th>
<td>{{ payment_created_formatted }}</td>
</tr>
{% if payment_completed_formatted %}
<tr>
<th>Completed:</th>
<td>{{ payment_completed_formatted }}</td>
</tr>
{% endif %}
{% if payment_info.payment_intent_id %}
<tr>
<th>Payment ID:</th>
<td>
<code class="small">{{ payment_info.payment_intent_id }}</code>
</td>
</tr>
{% endif %}
</table>
{% else %}
<div class="text-center text-muted py-3">
<i class="bi bi-credit-card me-1"></i>
No payment information available
<br>
<small class="text-muted">This company may have been created before payment integration</small>
</div>
{% endif %}
</div>
</div>
</div>
</div>
<div class="card mb-4">
<div class="card-header bg-light">
<h5 class="mb-0"><i class="bi bi-gear me-2"></i>Actions</h5>
</div>
<div class="card-body">
<div class="d-flex gap-2">
<a href="/company/edit/{{ company_id }}" class="btn btn-outline-primary"><i class="bi bi-pencil me-1"></i>Edit Company</a>
<a href="/company/documents/{{ company_id }}" class="btn btn-outline-secondary"><i class="bi bi-file-earmark me-1"></i>Manage Documents</a>
<a href="/company/switch/{{ company_id }}" class="btn btn-primary"><i class="bi bi-box-arrow-in-right me-1"></i>Switch to Entity</a>
<a href="/company/edit/{{ company.base_data.id }}" class="btn btn-outline-primary"><i
class="bi bi-pencil me-1"></i>Edit Company</a>
<a href="/company/documents/{{ company.base_data.id }}" class="btn btn-outline-secondary"><i
class="bi bi-file-earmark me-1"></i>Manage Documents</a>
<a href="/company/switch/{{ company.base_data.id }}" class="btn btn-primary"><i
class="bi bi-box-arrow-in-right me-1"></i>Switch to Entity</a>
</div>
</div>
</div>
@@ -168,10 +346,10 @@
{% endblock %}
{% block scripts %}
{{ super() }}
<script>
document.addEventListener('DOMContentLoaded', function() {
console.log('Company view page loaded');
});
</script>
{% endblock %}
{{ super() }}
<script>
document.addEventListener('DOMContentLoaded', function () {
console.log('Company view page loaded');
});
</script>
{% endblock %}