Skip to content

Commit 23c8256

Browse files
committed
remove billing integration
1 parent dc6bb0b commit 23c8256

File tree

9 files changed

+176
-343
lines changed

9 files changed

+176
-343
lines changed

README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ django-saas is a generic subscription billing system built for django projects.
1111
## Installation
1212
- Clone the repo
1313

14-
```git clone git@github.com:devmedtz/django_saas.git```
14+
```git clone https://github.com/rebeccax06/martha-django-saas.git```
1515

1616
- Create virtual environment and activate it.
1717

1818
```
19-
virtualenv env
19+
python -m venv .venv
2020
21-
env/scripts/activate
21+
source .venv/bin/activate
2222
```
2323

2424
- Install the required packages
@@ -41,6 +41,9 @@ django-saas is a generic subscription billing system built for django projects.
4141

4242
```python manage.py runserver```
4343

44+
# Login
45+
- email: test@example.com
46+
- password: testpass123
4447

4548
### Contributions are warmly welcomed.
4649

accounts/managers.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,17 @@
22

33

44
class CustomUserManager(BaseUserManager):
5-
def create_user(self, email, name, password=None):
5+
def create_user(self, email, name, phone, password=None):
66

77
if not email:
8-
raise ValueError('Staff must have an email address')
8+
raise ValueError("Staff must have an email address")
9+
if not phone:
10+
raise ValueError("Staff must have a phone number")
911

1012
user = self.model(
1113
email=self.normalize_email(email),
1214
name=name,
15+
phone=phone,
1316
)
1417

1518
user.set_password(password)
@@ -22,6 +25,7 @@ def create_superuser(self, email, name, phone, password=None):
2225
email,
2326
password=password,
2427
name=name,
28+
phone=phone,
2529
)
2630
user.is_active = True
2731
user.is_superuser = True

config/settings.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,4 @@
175175
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
176176

177177

178-
# M-PESA PAYMENT CONFIGURATIONS
179-
if not DEBUG:
180-
PUBLIC_KEY = config("PUBLIC_KEY")
181-
API_KEY = config("API_KEY")
182-
else:
183-
PUBLIC_KEY = config("PUBLIC_KEY")
184-
API_KEY = config("API_KEY")
178+
# TODO: Billing provider integration pending (Stripe, Paddle, etc.)

membership/forms.py

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,25 @@
1-
import re
2-
31
from django import forms
42

53
from .models import Payment, Business
64

75

86
class PaymentForm(forms.ModelForm):
7+
"""
8+
Payment form - placeholder for future billing integration.
9+
"""
910

1011
class Meta:
1112
model = Payment
12-
fields = ['phone']
13-
14-
def clean_phone(self):
15-
phone = self.cleaned_data.get('phone')
16-
x = re.search("^2557[0-9]{8}$", phone)
13+
fields = ["phone"]
1714

18-
if not x:
19-
raise forms.ValidationError(
20-
"Phone number must in format 2557xxxxxxxx")
21-
return phone
15+
# TODO: Add validation for billing provider when integrated
2216

2317

2418
class BusinessForm(forms.ModelForm):
2519

2620
class Meta:
2721
model = Business
28-
fields = ['name', 'location', ]
22+
fields = [
23+
"name",
24+
"location",
25+
]
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Generated migration to add Basic plan
2+
3+
from django.db import migrations
4+
from django.apps.registry import apps
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
("membership", "0008_auto_20201107_1700"),
11+
]
12+
13+
def create_basic_plan(self, schema_editor):
14+
Plan = apps.get_model("membership", "Plan")
15+
Plan.objects.create(
16+
name="Basic",
17+
description="Basic plan with 5 staff and 5 branches",
18+
price=5.00,
19+
duration_days=30,
20+
max_staff=5,
21+
max_branch=5,
22+
)
23+
24+
operations = [
25+
migrations.RunPython(create_basic_plan, migrations.RunPython.noop),
26+
]
Lines changed: 43 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,49 @@
1-
{% extends 'base.html' %}
2-
{% load crispy_forms_tags %}
3-
{% load widget_tweaks %}
4-
5-
{% block content %}
1+
{% extends 'base.html' %} {% block content %}
62
<div class="container">
7-
<div class="row">
8-
<div class="col-md-4"></div>
9-
<div class="col-md-4">
10-
{% if messages %}
11-
<div class="messages">
12-
{% for message in messages %}
13-
<p class="alert alert-warning" >
14-
{{ message }}</p>
15-
{% endfor %}
16-
</div>
17-
{% endif %}
18-
<div class="card">
19-
<div class="card-body text-center">
20-
<form action="." method="POST" autocomplete="off">
21-
{% csrf_token %}
22-
23-
{% for hidden in form.hidden_fields %}
24-
{{ hidden }}
25-
{% endfor %}
26-
27-
{% for field in form.visible_fields %}
28-
<div class="form-group">
29-
<label class="mb-2" for="{{ field.id_for_label }}"><h5>{{ field.label }}</h5></label>
30-
{{form.phone|add_class:'form-control'|attr:'placeholder:Phone (eg. 255700000000)'}}
31-
{% for error in field.errors %}
32-
<small class="help-block text-danger">{{ error }}</small>
33-
{% endfor %}
34-
</div>
35-
{% endfor %}
36-
37-
<div class="mb-3 mt-3 form-group">
38-
<button class="btn btn-danger btn-block btn-lg" id="make-payment">Pay Tshs. {{plans.price|floatformat:2}}/=</button>
39-
<p class="mb-2 mt-2 text-secondary">Ref no: {{reference_no}}</p>
40-
</div>
41-
<div class="mb-2">
42-
<small>Please keep your phone in hand. Once you click "Pay" a request to comfirm your M-PESA PIN sent to your phone.</small>
43-
</div>
44-
</form>
45-
</div>
46-
</div>
3+
<div class="row">
4+
<div class="col-md-2"></div>
5+
<div class="col-md-8">
6+
{% if messages %}
7+
<div class="messages">
8+
{% for message in messages %}
9+
<p class="alert alert-warning">{{ message }}</p>
10+
{% endfor %}
11+
</div>
12+
{% endif %}
4713

14+
<div class="card shadow-sm mt-5">
15+
<div class="card-body text-center p-5">
16+
<div class="mb-4">
17+
<div style="font-size: 4rem">📋</div>
18+
</div>
19+
<h2 class="card-title mb-3">Billing Integration Pending</h2>
20+
<p class="text-muted mb-4">
21+
Your payment processing will appear here once billing is configured.
22+
</p>
23+
<p class="text-muted small">
24+
Integrate with your billing provider (Stripe, Paddle, etc.) to
25+
enable payments.
26+
</p>
27+
{% if plans %}
28+
<div class="mt-4 pt-4 border-top">
29+
<p class="text-muted mb-2">
30+
Selected Plan: <strong>{{ plans.name }}</strong>
31+
</p>
32+
<p class="text-muted mb-0">
33+
Price: <strong>${{ plans.price|floatformat:2 }}</strong> / month
34+
</p>
35+
</div>
36+
{% endif %}
37+
<div class="mt-4">
38+
<a href="{% url 'membership' %}" class="btn btn-primary"
39+
>Back to Pricing</a
40+
>
41+
</div>
4842
</div>
49-
<div class="col-md-4"></div>
43+
</div>
5044
</div>
45+
<div class="col-md-2"></div>
46+
</div>
5147
</div>
5248

53-
{% endblock %}
49+
{% endblock %}
Lines changed: 51 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,56 @@
1-
{% extends 'base.html' %}
2-
1+
{% extends 'base.html' %} {% block content %}
2+
<div class="pricing-header px-3 py-3 pt-md-5 pb-md-4 mx-auto text-center">
3+
<h3 class="display-5">Pricing</h3>
4+
</div>
35

4-
{% block content %}
5-
<div class="pricing-header px-3 py-3 pt-md-5 pb-md-4 mx-auto text-center">
6-
<h3 class="display-5">Pricing</h3>
7-
</div>
8-
96
<div class="container">
10-
<div class="card-deck mb-3 text-center">
11-
{% for plan in object_list %}
12-
<div class="card mb-4 shadow-sm">
13-
<div class="card-header">
14-
<h4 class="my-0 font-weight-normal">{{plan.name}}</h4>
15-
</div>
16-
<div class="card-body">
17-
<h5 class="card-title pricing-card-title">Tshs. {{plan.price}} <small class="text-muted">/ mo</small></h5>
18-
<ul class="list-unstyled mt-3 mb-4">
19-
<li>3 users included</li>
20-
<li>3 Branch/store</li>
21-
<li>Free support</li>
22-
<li>Centre manager</li>
23-
</ul>
24-
{% if request.user.is_authenticated %}
25-
{% if plan.name == 'Free' %}
26-
{% if plan.name != current_plan %}
27-
<small class="text-warning">You can not subscribe to free plan</small>
28-
{% else %}
29-
<small class="text-success">This is your current plan</small>
30-
{% endif %}
31-
{% else %}
32-
<form action="" method="POST">
33-
{% csrf_token %}
34-
{% if plan.name != current_plan %}
35-
<button class="btn btn-lg btn-block btn-primary">Buy Now</button>
36-
{% else %}
37-
<small class="text-success">This is your current plan</small>
38-
{% endif %}
39-
<input type="hidden" name="plan_id" value="{{plan.id}}">
40-
</form>
41-
{% endif %}
42-
{% else %}
43-
{% if plan.name == 'Free' %}
44-
<a href="{% url 'accounts:signup' %}" class="btn btn-lg btn-block btn-outline-primary">Sign up for free</a>
45-
{% else %}
46-
<a href="{% url 'accounts:signup' %}" class="btn btn-lg btn-block btn-primary">Get Started</a>
47-
{% endif %}
48-
{% endif %}
49-
50-
</div>
51-
</div>
52-
{% endfor %}
7+
<div class="card-deck mb-3 text-center">
8+
{% for plan in object_list %}
9+
<div class="card mb-4 shadow-sm">
10+
<div class="card-header">
11+
<h4 class="my-0 font-weight-normal">{{plan.name}}</h4>
12+
</div>
13+
<div class="card-body">
14+
<h5 class="card-title pricing-card-title">
15+
${{plan.price|floatformat:2}} <small class="text-muted">/ mo</small>
16+
</h5>
17+
<ul class="list-unstyled mt-3 mb-4">
18+
<li>{{plan.max_staff}} staff included</li>
19+
<li>{{plan.max_branch}} branch/store</li>
20+
<li>{{plan.duration_days}} days duration</li>
21+
<li>Free support</li>
22+
</ul>
23+
{% if request.user.is_authenticated %} {% if plan.name == 'Free' %} {%
24+
if plan.name != current_plan %}
25+
<small class="text-warning">You can not subscribe to free plan</small>
26+
{% else %}
27+
<small class="text-success">This is your current plan</small>
28+
{% endif %} {% else %}
29+
<form action="" method="POST">
30+
{% csrf_token %} {% if plan.name != current_plan %}
31+
<button class="btn btn-lg btn-block btn-primary">Buy Now</button>
32+
{% else %}
33+
<small class="text-success">This is your current plan</small>
34+
{% endif %}
35+
<input type="hidden" name="plan_id" value="{{plan.id}}" />
36+
</form>
37+
{% endif %} {% else %} {% if plan.name == 'Free' %}
38+
<a
39+
href="{% url 'accounts:signup' %}"
40+
class="btn btn-lg btn-block btn-outline-primary"
41+
>Sign up for free</a
42+
>
43+
{% else %}
44+
<a
45+
href="{% url 'accounts:signup' %}"
46+
class="btn btn-lg btn-block btn-primary"
47+
>Get Started</a
48+
>
49+
{% endif %} {% endif %}
50+
</div>
5351
</div>
52+
{% endfor %}
53+
</div>
5454
</div>
5555

56-
{% endblock %}
56+
{% endblock %}

0 commit comments

Comments
 (0)