This commit is contained in:
Marwan Alwali 2025-12-11 10:43:43 +03:00
parent a4665842c9
commit 38d22db6f4
12 changed files with 9751 additions and 6 deletions

BIN
AGDAR_CENTRE_QUOTATION.docx Normal file

Binary file not shown.

422
AGDAR_CENTRE_QUOTATION.html Normal file
View File

@ -0,0 +1,422 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Quotation - Agdar Centre</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
color: #333;
background: #f5f5f5;
padding: 20px;
}
.container {
max-width: 900px;
margin: 0 auto;
background: white;
padding: 40px;
box-shadow: 0 0 20px rgba(0,0,0,0.1);
}
.header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 40px;
padding-bottom: 20px;
border-bottom: 3px solid #007bff;
}
.company-info {
flex: 1;
}
.company-name {
font-size: 28px;
font-weight: bold;
color: #007bff;
margin-bottom: 10px;
}
.company-details {
font-size: 14px;
color: #666;
line-height: 1.8;
}
.quotation-info {
text-align: right;
}
.quotation-title {
font-size: 32px;
font-weight: bold;
color: #333;
margin-bottom: 10px;
}
.quotation-number {
font-size: 16px;
color: #666;
margin-bottom: 5px;
}
.quotation-date {
font-size: 14px;
color: #666;
}
.client-section {
margin-bottom: 30px;
padding: 20px;
background: #f8f9fa;
border-left: 4px solid #007bff;
}
.section-title {
font-size: 16px;
font-weight: bold;
color: #007bff;
margin-bottom: 10px;
}
.client-name {
font-size: 18px;
font-weight: bold;
margin-bottom: 5px;
}
.items-table {
width: 100%;
border-collapse: collapse;
margin-bottom: 30px;
}
.items-table thead {
background: #007bff;
color: white;
}
.items-table th {
padding: 12px;
text-align: left;
font-weight: 600;
}
.items-table td {
padding: 12px;
border-bottom: 1px solid #dee2e6;
}
.items-table tbody tr:hover {
background: #f8f9fa;
}
.text-right {
text-align: right;
}
.text-center {
text-align: center;
}
.totals-section {
margin-left: auto;
width: 400px;
margin-bottom: 30px;
}
.total-row {
display: flex;
justify-content: space-between;
padding: 10px 0;
border-bottom: 1px solid #dee2e6;
}
.total-row.subtotal {
font-size: 16px;
}
.total-row.vat {
font-size: 16px;
color: #666;
}
.total-row.grand-total {
font-size: 20px;
font-weight: bold;
border-top: 2px solid #007bff;
border-bottom: 3px double #007bff;
padding: 15px 0;
color: #007bff;
}
.payment-terms {
margin-bottom: 30px;
padding: 20px;
background: #fff3cd;
border-left: 4px solid #ffc107;
}
.payment-schedule {
margin-top: 15px;
}
.payment-item {
display: flex;
justify-content: space-between;
padding: 8px 0;
border-bottom: 1px solid #dee2e6;
}
.payment-item:last-child {
border-bottom: none;
}
.payment-label {
font-weight: 600;
}
.payment-amount {
font-weight: bold;
color: #007bff;
}
.terms-conditions {
margin-bottom: 30px;
padding: 20px;
background: #f8f9fa;
border-radius: 5px;
}
.terms-conditions ul {
margin-left: 20px;
margin-top: 10px;
}
.terms-conditions li {
margin-bottom: 8px;
color: #666;
}
.validity {
padding: 15px;
background: #d1ecf1;
border-left: 4px solid #17a2b8;
margin-bottom: 30px;
font-weight: 600;
color: #0c5460;
}
.footer {
margin-top: 40px;
padding-top: 20px;
border-top: 2px solid #dee2e6;
text-align: center;
}
.signature-section {
display: flex;
justify-content: space-between;
margin-top: 60px;
margin-bottom: 30px;
}
.signature-box {
width: 45%;
text-align: center;
}
.signature-line {
border-top: 2px solid #333;
margin-top: 60px;
padding-top: 10px;
font-weight: 600;
}
.contact-info {
font-size: 14px;
color: #666;
line-height: 1.8;
}
@media print {
body {
background: white;
padding: 0;
}
.container {
box-shadow: none;
padding: 20px;
}
}
</style>
</head>
<body>
<div class="container">
<!-- Header -->
<div class="header">
<div class="company-info">
<div class="company-name">AGDAR CENTRE</div>
<div class="company-details">
Multidisciplinary Healthcare Services<br>
Kingdom of Saudi Arabia<br>
VAT No: 300000000000003
</div>
</div>
<div class="quotation-info">
<div class="quotation-title">QUOTATION</div>
<div class="quotation-number">Quote #: QT-2025-001</div>
<div class="quotation-date">Date: November 30, 2025</div>
</div>
</div>
<!-- Client Information -->
<div class="client-section">
<div class="section-title">QUOTATION FOR:</div>
<div class="client-name">Agdar Centre - Solution Implementation</div>
</div>
<!-- Validity Notice -->
<div class="validity">
⏰ This quotation is valid for 30 days from the date of issue
</div>
<!-- Items Table -->
<table class="items-table">
<thead>
<tr>
<th style="width: 10%">#</th>
<th style="width: 50%">Description</th>
<th style="width: 15%" class="text-center">Quantity</th>
<th style="width: 25%" class="text-right">Amount (SAR)</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>
<strong>Healthcare Management Solution</strong><br>
<span style="color: #666; font-size: 14px;">
Complete implementation of multidisciplinary healthcare management system including:
<ul style="margin-top: 8px; margin-left: 20px; font-size: 13px;">
<li>Patient Management System</li>
<li>Appointment Scheduling & Management</li>
<li>Clinical Documentation (ABA, OT, SLP, Psychology, Medical, Nursing)</li>
<li>Financial & Billing System with ZATCA E-Invoice Integration</li>
<li>Package Management & Scheduling</li>
<li>Multi-Disciplinary Team (MDT) Collaboration</li>
<li>Notifications & Communication System</li>
<li>Reporting & Analytics</li>
<li>User Management & Access Control</li>
</ul>
</span>
</td>
<td class="text-center">1</td>
<td class="text-right">50,000.00</td>
</tr>
</tbody>
</table>
<!-- Totals -->
<div class="totals-section">
<div class="total-row subtotal">
<span>Subtotal:</span>
<span>50,000.00 SAR</span>
</div>
<div class="total-row vat">
<span>VAT (15%):</span>
<span>7,500.00 SAR</span>
</div>
<div class="total-row grand-total">
<span>TOTAL AMOUNT:</span>
<span>57,500.00 SAR</span>
</div>
</div>
<!-- Payment Terms -->
<div class="payment-terms">
<div class="section-title">💳 PAYMENT TERMS</div>
<div class="payment-schedule">
<div class="payment-item">
<span class="payment-label">Down Payment (30%):</span>
<span class="payment-amount">17,250.00 SAR</span>
</div>
<div class="payment-item">
<span class="payment-label">Month 1 Payment:</span>
<span class="payment-amount">13,416.67 SAR</span>
</div>
<div class="payment-item">
<span class="payment-label">Month 2 Payment:</span>
<span class="payment-amount">13,416.67 SAR</span>
</div>
<div class="payment-item">
<span class="payment-label">Month 3 Payment (Final):</span>
<span class="payment-amount">13,416.66 SAR</span>
</div>
</div>
<div style="margin-top: 15px; padding-top: 15px; border-top: 1px solid #dee2e6; font-size: 14px; color: #666;">
<strong>Payment Schedule:</strong><br>
• 30% down payment due upon acceptance of quotation<br>
• Remaining 70% (40,250.00 SAR) to be paid in 3 equal monthly installments<br>
• Each installment approximately 13,416.67 SAR
</div>
</div>
<!-- Terms & Conditions -->
<div class="terms-conditions">
<div class="section-title">📋 TERMS & CONDITIONS</div>
<ul>
<li>This quotation is valid for 30 days from the date of issue</li>
<li>Prices are in Saudi Riyals (SAR) and include 15% VAT</li>
<li>Down payment of 30% is required to commence work</li>
<li>Monthly installments are due on the same date each month</li>
<li>Late payment may incur additional charges as per agreement</li>
<li>All payments should be made via bank transfer or approved payment methods</li>
<li>Implementation timeline will be confirmed upon contract signing</li>
<li>Training and support included as per service agreement</li>
<li>Warranty and maintenance terms as per separate agreement</li>
</ul>
</div>
<!-- Signature Section -->
<div class="signature-section">
<div class="signature-box">
<div class="signature-line">
Prepared By<br>
Agdar Centre
</div>
</div>
<div class="signature-box">
<div class="signature-line">
Accepted By<br>
Client Signature & Date
</div>
</div>
</div>
<!-- Footer -->
<div class="footer">
<div class="contact-info">
<strong>AGDAR CENTRE</strong><br>
Kingdom of Saudi Arabia<br>
Email: info@agdarcentre.com | Phone: +966 XX XXX XXXX<br>
VAT Registration Number: 300000000000003
</div>
<div style="margin-top: 20px; font-size: 12px; color: #999;">
Thank you for your business!
</div>
</div>
</div>
</body>
</html>

View File

@ -573,13 +573,28 @@ def handle_appointment_no_show(appointment: Appointment):
- Update patient statistics
- Consider automatic rescheduling policy
"""
from datetime import datetime, time
from core.tasks import send_email_task
# Convert scheduled_time to time object if it's a string
if isinstance(appointment.scheduled_time, str):
time_obj = datetime.strptime(appointment.scheduled_time, '%H:%M').time()
else:
time_obj = appointment.scheduled_time
# Get scheduled datetime
scheduled_datetime = datetime.combine(
appointment.scheduled_date,
time_obj
)
# Notify provider
if appointment.provider:
create_notification_task.delay(
user_id=str(appointment.provider.id),
user_id=str(appointment.provider.user.id),
title="Patient No-Show",
message=f"Patient {appointment.patient.full_name_en} did not show up for "
f"appointment on {appointment.start_at.strftime('%B %d, %Y at %I:%M %p')}",
f"appointment on {scheduled_datetime.strftime('%B %d, %Y at %I:%M %p')}",
notification_type='WARNING',
related_object_type='appointment',
related_object_id=str(appointment.id),
@ -587,13 +602,11 @@ def handle_appointment_no_show(appointment: Appointment):
# Send notification to patient
if appointment.patient.email:
from core.tasks import send_email_task
send_email_task.delay(
subject="Missed Appointment",
message=f"Dear {appointment.patient.full_name_en},\n\n"
f"We noticed you missed your appointment on "
f"{appointment.start_at.strftime('%B %d, %Y at %I:%M %p')}.\n\n"
f"{scheduled_datetime.strftime('%B %d, %Y at %I:%M %p')}.\n\n"
f"Please contact us to reschedule.\n\n"
f"Best regards,\nTenhal Healthcare Team",
recipient_list=[appointment.patient.email],

293
create_quotation_docx.py Normal file
View File

@ -0,0 +1,293 @@
#!/usr/bin/env python3
"""
Script to generate Agdar Centre Quotation in Word format
"""
from docx import Document
from docx.shared import Inches, Pt, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.oxml.ns import qn
from docx.oxml import OxmlElement
def add_horizontal_line(paragraph):
"""Add a horizontal line to a paragraph"""
p = paragraph._p
pPr = p.get_or_add_pPr()
pBdr = OxmlElement('w:pBdr')
bottom = OxmlElement('w:bottom')
bottom.set(qn('w:val'), 'single')
bottom.set(qn('w:sz'), '12')
bottom.set(qn('w:space'), '1')
bottom.set(qn('w:color'), '0070C0')
pBdr.append(bottom)
pPr.append(pBdr)
def create_quotation():
"""Create the quotation document"""
doc = Document()
# Set document margins
sections = doc.sections
for section in sections:
section.top_margin = Inches(0.75)
section.bottom_margin = Inches(0.75)
section.left_margin = Inches(1)
section.right_margin = Inches(1)
# Header Section
header_table = doc.add_table(rows=1, cols=2)
header_table.autofit = False
header_table.allow_autofit = False
# Left column - Company Info
left_cell = header_table.rows[0].cells[0]
company_name = left_cell.paragraphs[0]
company_name.text = "AGDAR CENTRE"
company_name.runs[0].font.size = Pt(24)
company_name.runs[0].font.bold = True
company_name.runs[0].font.color.rgb = RGBColor(0, 112, 192)
company_details = left_cell.add_paragraph("Multidisciplinary Healthcare Services")
company_details.runs[0].font.size = Pt(10)
company_details.runs[0].font.color.rgb = RGBColor(102, 102, 102)
company_details2 = left_cell.add_paragraph("Kingdom of Saudi Arabia")
company_details2.runs[0].font.size = Pt(10)
company_details2.runs[0].font.color.rgb = RGBColor(102, 102, 102)
company_details3 = left_cell.add_paragraph("VAT No: 300000000000003")
company_details3.runs[0].font.size = Pt(10)
company_details3.runs[0].font.color.rgb = RGBColor(102, 102, 102)
# Right column - Quotation Info
right_cell = header_table.rows[0].cells[1]
quote_title = right_cell.paragraphs[0]
quote_title.text = "QUOTATION"
quote_title.alignment = WD_ALIGN_PARAGRAPH.RIGHT
quote_title.runs[0].font.size = Pt(28)
quote_title.runs[0].font.bold = True
quote_number = right_cell.add_paragraph("Quote #: QT-2025-001")
quote_number.alignment = WD_ALIGN_PARAGRAPH.RIGHT
quote_number.runs[0].font.size = Pt(11)
quote_number.runs[0].font.color.rgb = RGBColor(102, 102, 102)
quote_date = right_cell.add_paragraph("Date: November 30, 2025")
quote_date.alignment = WD_ALIGN_PARAGRAPH.RIGHT
quote_date.runs[0].font.size = Pt(10)
quote_date.runs[0].font.color.rgb = RGBColor(102, 102, 102)
# Add horizontal line
line_para = doc.add_paragraph()
add_horizontal_line(line_para)
doc.add_paragraph() # Spacing
# Client Section
client_heading = doc.add_paragraph("QUOTATION FOR:")
client_heading.runs[0].font.size = Pt(12)
client_heading.runs[0].font.bold = True
client_heading.runs[0].font.color.rgb = RGBColor(0, 112, 192)
client_name = doc.add_paragraph("Agdar Centre - Solution Implementation")
client_name.runs[0].font.size = Pt(14)
client_name.runs[0].font.bold = True
doc.add_paragraph() # Spacing
# Validity Notice
validity = doc.add_paragraph("⏰ This quotation is valid for 30 days from the date of issue")
validity.runs[0].font.size = Pt(11)
validity.runs[0].font.bold = True
validity.runs[0].font.color.rgb = RGBColor(12, 84, 96)
doc.add_paragraph() # Spacing
# Items Table
items_table = doc.add_table(rows=1, cols=4)
items_table.style = 'Light Grid Accent 1'
# Header row
header_cells = items_table.rows[0].cells
header_cells[0].text = "#"
header_cells[1].text = "Description"
header_cells[2].text = "Quantity"
header_cells[3].text = "Amount (SAR)"
# Format header
for cell in header_cells:
cell.paragraphs[0].runs[0].font.bold = True
cell.paragraphs[0].runs[0].font.color.rgb = RGBColor(255, 255, 255)
shading_elm = OxmlElement('w:shd')
shading_elm.set(qn('w:fill'), '0070C0')
cell._element.get_or_add_tcPr().append(shading_elm)
header_cells[2].paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
header_cells[3].paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.RIGHT
# Data row
row_cells = items_table.add_row().cells
row_cells[0].text = "1"
# Description with bullet points
desc_para = row_cells[1].paragraphs[0]
desc_para.add_run("Healthcare Management Solution\n").bold = True
desc_para.add_run("\nComplete implementation of multidisciplinary healthcare management system including:\n").font.size = Pt(10)
features = [
"Patient Management System",
"Appointment Scheduling & Management",
"Clinical Documentation (ABA, OT, SLP, Psychology, Medical, Nursing)",
"Financial & Billing System with ZATCA E-Invoice Integration",
"Package Management & Scheduling",
"Multi-Disciplinary Team (MDT) Collaboration",
"Notifications & Communication System",
"Reporting & Analytics",
"User Management & Access Control"
]
for feature in features:
feature_para = row_cells[1].add_paragraph(f"{feature}", style='List Bullet')
feature_para.runs[0].font.size = Pt(9)
row_cells[2].text = "1"
row_cells[2].paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
row_cells[3].text = "50,000.00"
row_cells[3].paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.RIGHT
doc.add_paragraph() # Spacing
# Totals Section
totals_table = doc.add_table(rows=3, cols=2)
totals_table.alignment = WD_ALIGN_PARAGRAPH.RIGHT
# Subtotal
totals_table.rows[0].cells[0].text = "Subtotal:"
totals_table.rows[0].cells[1].text = "50,000.00 SAR"
totals_table.rows[0].cells[1].paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.RIGHT
# VAT
totals_table.rows[1].cells[0].text = "VAT (15%):"
totals_table.rows[1].cells[1].text = "7,500.00 SAR"
totals_table.rows[1].cells[1].paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.RIGHT
# Total
totals_table.rows[2].cells[0].text = "TOTAL AMOUNT:"
totals_table.rows[2].cells[0].paragraphs[0].runs[0].font.bold = True
totals_table.rows[2].cells[0].paragraphs[0].runs[0].font.size = Pt(14)
totals_table.rows[2].cells[0].paragraphs[0].runs[0].font.color.rgb = RGBColor(0, 112, 192)
totals_table.rows[2].cells[1].text = "57,500.00 SAR"
totals_table.rows[2].cells[1].paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.RIGHT
totals_table.rows[2].cells[1].paragraphs[0].runs[0].font.bold = True
totals_table.rows[2].cells[1].paragraphs[0].runs[0].font.size = Pt(14)
totals_table.rows[2].cells[1].paragraphs[0].runs[0].font.color.rgb = RGBColor(0, 112, 192)
doc.add_paragraph() # Spacing
# Payment Terms Section
payment_heading = doc.add_paragraph("💳 PAYMENT TERMS")
payment_heading.runs[0].font.size = Pt(12)
payment_heading.runs[0].font.bold = True
payment_heading.runs[0].font.color.rgb = RGBColor(0, 112, 192)
# Payment Schedule Table
payment_table = doc.add_table(rows=5, cols=2)
payment_table.style = 'Light List Accent 1'
payments = [
("Down Payment (30%):", "17,250.00 SAR"),
("Month 1 Payment:", "13,416.67 SAR"),
("Month 2 Payment:", "13,416.67 SAR"),
("Month 3 Payment (Final):", "13,416.66 SAR")
]
for i, (label, amount) in enumerate(payments):
payment_table.rows[i].cells[0].text = label
payment_table.rows[i].cells[0].paragraphs[0].runs[0].font.bold = True
payment_table.rows[i].cells[1].text = amount
payment_table.rows[i].cells[1].paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.RIGHT
payment_table.rows[i].cells[1].paragraphs[0].runs[0].font.bold = True
payment_table.rows[i].cells[1].paragraphs[0].runs[0].font.color.rgb = RGBColor(0, 112, 192)
doc.add_paragraph()
# Payment Schedule Details
schedule_para = doc.add_paragraph()
schedule_para.add_run("Payment Schedule:\n").bold = True
schedule_para.add_run("• 30% down payment due upon acceptance of quotation\n")
schedule_para.add_run("• Remaining 70% (40,250.00 SAR) to be paid in 3 equal monthly installments\n")
schedule_para.add_run("• Each installment approximately 13,416.67 SAR")
for run in schedule_para.runs[1:]:
run.font.size = Pt(10)
doc.add_paragraph() # Spacing
# Terms & Conditions
terms_heading = doc.add_paragraph("📋 TERMS & CONDITIONS")
terms_heading.runs[0].font.size = Pt(12)
terms_heading.runs[0].font.bold = True
terms_heading.runs[0].font.color.rgb = RGBColor(0, 112, 192)
terms = [
"This quotation is valid for 30 days from the date of issue",
"Prices are in Saudi Riyals (SAR) and include 15% VAT",
"Down payment of 30% is required to commence work",
"Monthly installments are due on the same date each month",
"Late payment may incur additional charges as per agreement",
"All payments should be made via bank transfer or approved payment methods",
"Implementation timeline will be confirmed upon contract signing",
"Training and support included as per service agreement",
"Warranty and maintenance terms as per separate agreement"
]
for term in terms:
term_para = doc.add_paragraph(term, style='List Bullet')
term_para.runs[0].font.size = Pt(10)
doc.add_paragraph() # Spacing
doc.add_paragraph() # Spacing
# Signature Section
sig_table = doc.add_table(rows=3, cols=2)
# Prepared By
sig_table.rows[0].cells[0].text = ""
sig_table.rows[1].cells[0].text = "_" * 30
sig_table.rows[2].cells[0].text = "Prepared By\nAgdar Centre"
sig_table.rows[2].cells[0].paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
sig_table.rows[2].cells[0].paragraphs[0].runs[0].font.bold = True
# Accepted By
sig_table.rows[0].cells[1].text = ""
sig_table.rows[1].cells[1].text = "_" * 30
sig_table.rows[1].cells[1].paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
sig_table.rows[2].cells[1].text = "Accepted By\nClient Signature & Date"
sig_table.rows[2].cells[1].paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
sig_table.rows[2].cells[1].paragraphs[0].runs[0].font.bold = True
doc.add_paragraph() # Spacing
# Footer
footer_line = doc.add_paragraph()
add_horizontal_line(footer_line)
footer = doc.add_paragraph()
footer.alignment = WD_ALIGN_PARAGRAPH.CENTER
footer.add_run("AGDAR CENTRE\n").bold = True
footer.add_run("Kingdom of Saudi Arabia\n")
footer.add_run("Email: info@agdarcentre.com | Phone: +966 XX XXX XXXX\n")
footer.add_run("VAT Registration Number: 300000000000003\n\n")
footer.add_run("Thank you for your business!").italic = True
for run in footer.runs:
run.font.size = Pt(9)
run.font.color.rgb = RGBColor(102, 102, 102)
# Save document
doc.save('AGDAR_CENTRE_QUOTATION.docx')
print("✅ Quotation document created successfully: AGDAR_CENTRE_QUOTATION.docx")
if __name__ == "__main__":
create_quotation()

Binary file not shown.

BIN
dump.rdb

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -203,12 +203,17 @@ class MDTContributionCreateView(LoginRequiredMixin, CreateView):
kwargs['mdt_note'] = self.mdt_note
return kwargs
def get_success_url(self):
"""Return URL to redirect to after successful form submission."""
return reverse_lazy('mdt:mdt_note_detail', kwargs={'pk': self.mdt_note.pk})
def form_valid(self, form):
"""Set contributor and mdt_note before saving."""
form.instance.mdt_note = self.mdt_note
form.instance.contributor = self.request.user
response = super().form_valid(form)
# Save the form
self.object = form.save()
# Handle mentions
mention_users = form.cleaned_data.get('mention_users', [])

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB