Skip to content

Commit b574c92

Browse files
committed
added tests and documentation
1 parent aa74894 commit b574c92

17 files changed

+933
-6
lines changed

appointment/email_sender/email_sender.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
from django.conf import settings
12
from django.core.mail import mail_admins, send_mail
23
from django.template import loader
3-
from django.conf import settings
44

55
from appointment.settings import APP_DEFAULT_FROM_EMAIL
66

@@ -24,6 +24,7 @@ def has_required_email_settings():
2424

2525
return True
2626

27+
2728
def send_email(recipient_list, subject: str, template_url: str = None, context: dict = None, from_email=None,
2829
message: str = None):
2930
if not has_required_email_settings():
@@ -52,6 +53,7 @@ def send_email(recipient_list, subject: str, template_url: str = None, context:
5253
except Exception as e:
5354
print(f"Error sending email: {e}")
5455

56+
5557
def notify_admin(subject: str, template_url: str = None, context: dict = None, message: str = None):
5658
if not has_required_email_settings():
5759
return
File renamed without changes.

appointment/migrations/0001_initial.py

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Generated by Django 4.2 on 2023-04-24 23:34
1+
# Generated by Django 4.2 on 2023-07-27 13:21
22

33
from django.conf import settings
44
import django.core.validators
@@ -82,19 +82,31 @@ class Migration(migrations.Migration):
8282
(
8383
"slot_duration",
8484
models.PositiveIntegerField(
85-
default=30, help_text="Duration of each slot in minutes"
85+
help_text="Minimum time for an appointment in minutes, recommended 30.",
86+
null=True,
8687
),
8788
),
8889
(
8990
"lead_time",
9091
models.TimeField(
91-
default="09:00", help_text="Time when slots start"
92+
help_text="Time when we start working.", null=True
9293
),
9394
),
9495
(
9596
"finish_time",
96-
models.TimeField(
97-
default="16:30", help_text="Time when we stop working"
97+
models.TimeField(help_text="Time when we stop working.", null=True),
98+
),
99+
(
100+
"appointment_buffer_time",
101+
models.FloatField(
102+
help_text="Time between now and the first available slot for the current day (doesn't affect tomorrow).",
103+
null=True,
104+
),
105+
),
106+
(
107+
"website_name",
108+
models.CharField(
109+
default="", help_text="Name of your website.", max_length=255
98110
),
99111
),
100112
],
@@ -115,6 +127,10 @@ class Migration(migrations.Migration):
115127
("description", models.TextField(blank=True, null=True)),
116128
("duration", models.DurationField()),
117129
("price", models.DecimalField(decimal_places=2, max_digits=6)),
130+
(
131+
"down_payment",
132+
models.DecimalField(decimal_places=2, default=0, max_digits=6),
133+
),
118134
("currency", models.CharField(default="USD", max_length=3)),
119135
(
120136
"image",
@@ -147,6 +163,30 @@ class Migration(migrations.Migration):
147163
),
148164
],
149165
),
166+
migrations.CreateModel(
167+
name="EmailVerificationCode",
168+
fields=[
169+
(
170+
"id",
171+
models.BigAutoField(
172+
auto_created=True,
173+
primary_key=True,
174+
serialize=False,
175+
verbose_name="ID",
176+
),
177+
),
178+
("code", models.CharField(max_length=6)),
179+
("created_at", models.DateTimeField(auto_now_add=True)),
180+
("updated_at", models.DateTimeField(auto_now=True)),
181+
(
182+
"user",
183+
models.ForeignKey(
184+
on_delete=django.db.models.deletion.CASCADE,
185+
to=settings.AUTH_USER_MODEL,
186+
),
187+
),
188+
],
189+
),
150190
migrations.CreateModel(
151191
name="AppointmentRequest",
152192
fields=[
@@ -162,6 +202,14 @@ class Migration(migrations.Migration):
162202
("date", models.DateField()),
163203
("start_time", models.TimeField()),
164204
("end_time", models.TimeField()),
205+
(
206+
"payment_type",
207+
models.CharField(
208+
choices=[("full", "Full payment"), ("down", "Down payment")],
209+
default="full",
210+
max_length=4,
211+
),
212+
),
165213
("id_request", models.CharField(blank=True, max_length=100, null=True)),
166214
("created_at", models.DateTimeField(auto_now_add=True)),
167215
("updated_at", models.DateTimeField(auto_now=True)),
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/* verification_code.css */
2+
body {
3+
background-color: #f4f4f4;
4+
}
5+
6+
.container {
7+
display: flex;
8+
justify-content: center;
9+
align-items: center;
10+
height: 100vh;
11+
}
12+
13+
.verification-container {
14+
background-color: white;
15+
padding: 20px;
16+
border-radius: 10px;
17+
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
18+
width: 100%;
19+
max-width: 400px;
20+
}
21+
22+
.verification-title {
23+
font-size: 24px;
24+
font-weight: bold;
25+
text-align: center;
26+
margin-bottom: 20px;
27+
}
28+
29+
.verification-instruction {
30+
font-size: 18px;
31+
text-align: center;
32+
margin-bottom: 20px;
33+
}
34+
35+
.verification-form {
36+
display: flex;
37+
flex-direction: column;
38+
align-items: center;
39+
}
40+
41+
.verification-label {
42+
font-size: 16px;
43+
font-weight: bold;
44+
margin-bottom: 10px;
45+
width: 100%;
46+
}
47+
48+
.verification-input {
49+
font-size: 14px;
50+
padding: 10px;
51+
border: 1px solid #ddd;
52+
border-radius: 5px;
53+
width: 100%;
54+
margin-bottom: 20px;
55+
}
56+
57+
.verification-submit {
58+
font-size: 16px;
59+
padding: 10px 20px;
60+
background-color: #007BFF;
61+
color: white;
62+
border: none;
63+
border-radius: 5px;
64+
cursor: pointer;
65+
transition: background-color 0.3s ease;
66+
}
67+
68+
.verification-submit:hover {
69+
background-color: #0056b3;
70+
}

appointment/tests/__init__.py

Whitespace-only changes.

appointment/tests/models/__init__.py

Whitespace-only changes.
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
from datetime import date, timedelta, time, datetime
2+
3+
from django.core.exceptions import ValidationError
4+
from django.test import TestCase
5+
6+
from appointment.models import Service, Appointment, AppointmentRequest
7+
from appointment.utils import Utility
8+
9+
10+
class AppointmentModelTestCase(TestCase):
11+
def setUp(self):
12+
self.user_model = Utility.get_user_model()
13+
self.user = self.user_model.objects.create_user(first_name="Tester",
14+
15+
username="test_user", password="Kfdqi3!?n")
16+
self.service = Service.objects.create(name="Test Service", duration=timedelta(hours=1), price=100)
17+
self.ar = AppointmentRequest.objects.create(date=date.today(), start_time=time(9, 0), end_time=time(10, 0),
18+
service=self.service)
19+
self.appointment = Appointment.objects.create(client=self.user, appointment_request=self.ar,
20+
phone="1234567890", address="Some City, Some State")
21+
22+
# Test appointment creation
23+
def test_appointment_creation(self):
24+
appointment = Appointment.objects.get(appointment_request=self.ar)
25+
self.assertIsNotNone(appointment)
26+
self.assertEqual(appointment.client, self.user)
27+
self.assertEqual(appointment.phone, "1234567890")
28+
self.assertEqual(appointment.address, "Some City, Some State")
29+
30+
# Test str representation
31+
def test_str_representation(self):
32+
expected_str = f"{self.user} - {self.ar.start_time.strftime('%Y-%m-%d %H:%M')} to " \
33+
f"{self.ar.end_time.strftime('%Y-%m-%d %H:%M')}"
34+
self.assertEqual(str(self.appointment), expected_str)
35+
36+
# Test start time
37+
def test_get_start_time(self):
38+
expected_start_time = datetime.combine(self.ar.get_date(),
39+
self.ar.get_start_time())
40+
self.assertEqual(self.appointment.get_start_time(), expected_start_time)
41+
42+
# Test end time
43+
def test_get_end_time(self):
44+
expected_end_time = datetime.combine(self.ar.get_date(),
45+
self.ar.get_end_time())
46+
self.assertEqual(self.appointment.get_end_time(), expected_end_time)
47+
48+
# Test service name retrieval
49+
def test_get_service_name(self):
50+
self.assertEqual(self.appointment.get_service_name(), "Test Service")
51+
52+
# Test service price retrieval
53+
def test_get_service_price(self):
54+
self.assertEqual(self.appointment.get_service_price(), 100)
55+
56+
# Test phone retrieval
57+
def test_get_phone(self):
58+
self.assertEqual(self.appointment.get_phone(), "1234567890")
59+
60+
# Test address retrieval
61+
def test_get_address(self):
62+
self.assertEqual(self.appointment.get_address(), "Some City, Some State")
63+
64+
# Test reminder retrieval
65+
def test_get_want_reminder(self):
66+
self.assertFalse(self.appointment.get_want_reminder())
67+
68+
# Test additional info retrieval
69+
def test_get_additional_info(self):
70+
self.assertIsNone(self.appointment.get_additional_info())
71+
72+
# Test paid status retrieval
73+
def test_is_paid(self):
74+
self.assertFalse(self.appointment.is_paid())
75+
76+
# Test appointment amount to pay
77+
def test_get_appointment_amount_to_pay(self):
78+
self.assertEqual(self.appointment.get_appointment_amount_to_pay(), 100)
79+
80+
# Test appointment currency retrieval
81+
def test_get_appointment_currency(self):
82+
self.assertEqual(self.appointment.get_appointment_currency(), "USD")
83+
84+
# Test appointment ID request retrieval
85+
def test_get_appointment_id_request(self):
86+
self.assertIsNotNone(self.appointment.get_appointment_id_request())
87+
88+
# Test created at retrieval
89+
def test_get_created_at(self):
90+
self.assertIsNotNone(self.appointment.get_created_at())
91+
92+
# Test updated at retrieval
93+
def test_get_updated_at(self):
94+
self.assertIsNotNone(self.appointment.get_updated_at())
95+
96+
# Test paid status setting
97+
def test_set_appointment_paid_status(self):
98+
self.appointment.set_appointment_paid_status(True)
99+
self.assertTrue(self.appointment.is_paid())
100+
self.appointment.set_appointment_paid_status(False)
101+
self.assertFalse(self.appointment.is_paid())
102+
103+
# Test invalid phone number
104+
def test_invalid_phone(self):
105+
self.appointment.phone = "1234" # Invalid phone number
106+
with self.assertRaises(ValidationError):
107+
self.appointment.full_clean()
108+
109+
# Test service down payment retrieval
110+
def test_get_service_down_payment(self):
111+
self.assertEqual(self.appointment.get_service_down_payment(), self.service.get_down_payment())
112+
113+
# Test service description retrieval
114+
def test_get_service_description(self):
115+
self.assertEqual(self.appointment.get_service_description(), self.service.get_description())
116+
117+
# Test appointment date retrieval
118+
def test_get_appointment_date(self):
119+
self.assertEqual(self.appointment.get_appointment_date(), self.ar.get_date())
120+
121+
# Test save function with down payment type
122+
def test_save_with_down_payment(self):
123+
self.ar.payment_type = 'down'
124+
self.ar.save()
125+
self.appointment.save()
126+
self.assertEqual(self.appointment.get_service_down_payment(), self.service.get_down_payment())

0 commit comments

Comments
 (0)