django-finance-12bucks 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- django_finance_12bucks-0.1.0.dist-info/METADATA +135 -0
- django_finance_12bucks-0.1.0.dist-info/RECORD +12 -0
- django_finance_12bucks-0.1.0.dist-info/WHEEL +5 -0
- django_finance_12bucks-0.1.0.dist-info/licenses/LICENSE +3 -0
- django_finance_12bucks-0.1.0.dist-info/top_level.txt +1 -0
- migrations/0001_initial.py +132 -0
- migrations/0002_miles.py +35 -0
- migrations/0003_mileagerate.py +24 -0
- migrations/0004_alter_transaction_receipt.py +18 -0
- migrations/0005_remove_invoiceitem_invoice_numb_invoiceitem_invoice_and_more.py +33 -0
- migrations/0006_alter_invoice_options_alter_invoiceitem_invoice_and_more.py +33 -0
- migrations/__init__.py +0 -0
@@ -0,0 +1,135 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: django-finance-12bucks
|
3
|
+
Version: 0.1.0
|
4
|
+
Summary: A Django finance app to track income, expenses, mileage, and generate reports.
|
5
|
+
Home-page: https://github.com/yourusername/12bucks
|
6
|
+
Author: Tom Stout
|
7
|
+
Author-email: tom@airborne-images.net
|
8
|
+
License: MIT
|
9
|
+
Classifier: Framework :: Django
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
12
|
+
Classifier: Operating System :: OS Independent
|
13
|
+
Description-Content-Type: text/markdown
|
14
|
+
License-File: LICENSE
|
15
|
+
Requires-Dist: Django>=4.0
|
16
|
+
Requires-Dist: psycopg2-binary
|
17
|
+
Requires-Dist: pillow
|
18
|
+
Requires-Dist: django-crispy-forms
|
19
|
+
Requires-Dist: django-bootstrap-v5
|
20
|
+
Requires-Dist: django-environ
|
21
|
+
Requires-Dist: weasyprint
|
22
|
+
Dynamic: author
|
23
|
+
Dynamic: author-email
|
24
|
+
Dynamic: classifier
|
25
|
+
Dynamic: description
|
26
|
+
Dynamic: description-content-type
|
27
|
+
Dynamic: home-page
|
28
|
+
Dynamic: license
|
29
|
+
Dynamic: license-file
|
30
|
+
Dynamic: requires-dist
|
31
|
+
Dynamic: summary
|
32
|
+
|
33
|
+
# ๐ธ 12Bucks โ Django Finance & Accounting App
|
34
|
+
|
35
|
+
**12Bucks** is a Django-based financial management application built for freelancers, small business owners, and creators. It allows users to track income, expenses, mileage, clients, and invoices โ all in one responsive, modern dashboard.
|
36
|
+
|
37
|
+
> Developed by [Tom Stout](https://airborne-images.net) for Airborne Images and 12bytes.
|
38
|
+
|
39
|
+

|
40
|
+

|
41
|
+

|
42
|
+
|
43
|
+
---
|
44
|
+
|
45
|
+
## ๐ Features
|
46
|
+
|
47
|
+
- ๐ **Income & Expense Tracking** by category and subcategory
|
48
|
+
- ๐งพ **Client Management** with invoice generation and email delivery
|
49
|
+
- ๐ **Mileage Tracking** with deductible/reimbursable tagging
|
50
|
+
- ๐ฅ **Receipt Uploads** with image preview
|
51
|
+
- ๐
**Year-over-Year Keyword-Based Financial Summary**
|
52
|
+
- ๐ **Financial Statements** and category summaries
|
53
|
+
- ๐ง **Email Integration** for sending invoices
|
54
|
+
- ๐ฑ **Mobile-Friendly** Bootstrap 5 UI
|
55
|
+
- ๐ฆ **PDF Export** of invoices and reports (via WeasyPrint)
|
56
|
+
|
57
|
+
---
|
58
|
+
|
59
|
+
## ๐ Project Structure
|
60
|
+
|
61
|
+
```
|
62
|
+
finance/
|
63
|
+
โโโ templates/
|
64
|
+
โ โโโ finance/
|
65
|
+
โ โโโ components/
|
66
|
+
โโโ static/
|
67
|
+
โโโ forms.py
|
68
|
+
โโโ models.py
|
69
|
+
โโโ views.py
|
70
|
+
โโโ urls.py
|
71
|
+
...
|
72
|
+
```
|
73
|
+
|
74
|
+
---
|
75
|
+
|
76
|
+
## ๐ ๏ธ Installation
|
77
|
+
|
78
|
+
### ๐ฆ Via pip (after PyPI release):
|
79
|
+
```bash
|
80
|
+
pip install django-finance-12bucks
|
81
|
+
```
|
82
|
+
|
83
|
+
### ๐งช Manual Setup:
|
84
|
+
```bash
|
85
|
+
git clone https://github.com/yourusername/12bucks.git
|
86
|
+
cd 12bucks
|
87
|
+
python -m venv venv
|
88
|
+
source venv/bin/activate
|
89
|
+
pip install -r requirements.txt
|
90
|
+
python manage.py migrate
|
91
|
+
python manage.py runserver
|
92
|
+
```
|
93
|
+
|
94
|
+
---
|
95
|
+
|
96
|
+
## ๐งฉ Configuration
|
97
|
+
|
98
|
+
Set the following in your `.env`:
|
99
|
+
|
100
|
+
```env
|
101
|
+
DEBUG=True
|
102
|
+
SECRET_KEY=your_secret_key
|
103
|
+
DATABASE_URL=postgres://user:pass@localhost:5432/yourdb
|
104
|
+
EMAIL_HOST=smtp.office365.com
|
105
|
+
EMAIL_PORT=587
|
106
|
+
EMAIL_USE_TLS=True
|
107
|
+
EMAIL_HOST_USER=your@email.com
|
108
|
+
EMAIL_HOST_PASSWORD=yourpassword
|
109
|
+
```
|
110
|
+
|
111
|
+
---
|
112
|
+
|
113
|
+
## ๐ท Screenshots
|
114
|
+
|
115
|
+
Coming soon...
|
116
|
+
|
117
|
+
---
|
118
|
+
|
119
|
+
## ๐ค Contributing
|
120
|
+
|
121
|
+
Pull requests are welcome! For major changes, open an issue first to discuss what youโd like to add.
|
122
|
+
|
123
|
+
---
|
124
|
+
|
125
|
+
## ๐ License
|
126
|
+
|
127
|
+
This project is licensed under the [MIT License](LICENSE).
|
128
|
+
|
129
|
+
---
|
130
|
+
|
131
|
+
## ๐ฌ Contact
|
132
|
+
|
133
|
+
**Tom Stout**
|
134
|
+
โ๏ธ [tom@airborne-images.net](mailto:tom@airborne-images.net)
|
135
|
+
๐ [airborne-images.net](https://www.airborne-images.net)
|
@@ -0,0 +1,12 @@
|
|
1
|
+
django_finance_12bucks-0.1.0.dist-info/licenses/LICENSE,sha256=rgGlrvlCgOZwvZjr3SCMrgmrvb7OmqV1BgQe8Y0lb1U,41
|
2
|
+
migrations/0001_initial.py,sha256=ODk5QC_nYmH0z0XIy9D2AoUBQxEL1KAd_D4N25Q_few,6619
|
3
|
+
migrations/0002_miles.py,sha256=4sFVqznnQSc-tJlZyJze9Po4uoFOHB7ua0plopKhG28,1695
|
4
|
+
migrations/0003_mileagerate.py,sha256=9dSF8zZajgIOgNiyGnOTS8m1U-89DGZxmCCnHtNW_e4,683
|
5
|
+
migrations/0004_alter_transaction_receipt.py,sha256=hLxXcKyqh_DlXXRdhX8Mpb50HcfZDG6PloDRogV2UR0,417
|
6
|
+
migrations/0005_remove_invoiceitem_invoice_numb_invoiceitem_invoice_and_more.py,sha256=1LfmJBQfbxixNLWxd3dzbNAFmtx8PM_TWrQRfoAYilM,1013
|
7
|
+
migrations/0006_alter_invoice_options_alter_invoiceitem_invoice_and_more.py,sha256=d-dha9_Unx6wMrnphFbINfj5HDk5R4HQQ73g4yrhGm4,1017
|
8
|
+
migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
|
+
django_finance_12bucks-0.1.0.dist-info/METADATA,sha256=t7VrVEPTcgzslXq35YKjkc7XfamJuVY5moaIjLsRZI8,3421
|
10
|
+
django_finance_12bucks-0.1.0.dist-info/WHEEL,sha256=lTU6B6eIfYoiQJTZNc-fyaR6BpL6ehTzU3xGYxn2n8k,91
|
11
|
+
django_finance_12bucks-0.1.0.dist-info/top_level.txt,sha256=7Vfp3vCAN7rl4-1zzPa-_BHJXDWnajxHlyMCiJbvhvM,11
|
12
|
+
django_finance_12bucks-0.1.0.dist-info/RECORD,,
|
@@ -0,0 +1 @@
|
|
1
|
+
migrations
|
@@ -0,0 +1,132 @@
|
|
1
|
+
# Generated by Django 4.2.20 on 2025-04-02 17:41
|
2
|
+
|
3
|
+
from django.db import migrations, models
|
4
|
+
import django.db.models.deletion
|
5
|
+
|
6
|
+
|
7
|
+
class Migration(migrations.Migration):
|
8
|
+
|
9
|
+
initial = True
|
10
|
+
|
11
|
+
dependencies = [
|
12
|
+
]
|
13
|
+
|
14
|
+
operations = [
|
15
|
+
migrations.CreateModel(
|
16
|
+
name='Category',
|
17
|
+
fields=[
|
18
|
+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
19
|
+
('category', models.CharField(blank=True, max_length=500, null=True)),
|
20
|
+
],
|
21
|
+
options={
|
22
|
+
'verbose_name_plural': 'Categories',
|
23
|
+
},
|
24
|
+
),
|
25
|
+
migrations.CreateModel(
|
26
|
+
name='Client',
|
27
|
+
fields=[
|
28
|
+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
29
|
+
('business', models.CharField(blank=True, max_length=500, null=True)),
|
30
|
+
('first', models.CharField(blank=True, max_length=500, null=True)),
|
31
|
+
('last', models.CharField(blank=True, max_length=500, null=True)),
|
32
|
+
('street', models.CharField(blank=True, max_length=500, null=True)),
|
33
|
+
('address2', models.CharField(blank=True, max_length=500, null=True)),
|
34
|
+
('email', models.EmailField(max_length=254)),
|
35
|
+
('phone', models.CharField(blank=True, max_length=500, null=True)),
|
36
|
+
],
|
37
|
+
),
|
38
|
+
migrations.CreateModel(
|
39
|
+
name='Keyword',
|
40
|
+
fields=[
|
41
|
+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
42
|
+
('name', models.CharField(max_length=500)),
|
43
|
+
],
|
44
|
+
),
|
45
|
+
migrations.CreateModel(
|
46
|
+
name='Service',
|
47
|
+
fields=[
|
48
|
+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
49
|
+
('service', models.CharField(blank=True, max_length=500, null=True)),
|
50
|
+
],
|
51
|
+
),
|
52
|
+
migrations.CreateModel(
|
53
|
+
name='SubCategory',
|
54
|
+
fields=[
|
55
|
+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
56
|
+
('sub_cat', models.CharField(blank=True, max_length=500, null=True)),
|
57
|
+
],
|
58
|
+
options={
|
59
|
+
'verbose_name_plural': 'Sub Categories',
|
60
|
+
},
|
61
|
+
),
|
62
|
+
migrations.CreateModel(
|
63
|
+
name='Team',
|
64
|
+
fields=[
|
65
|
+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
66
|
+
('name', models.CharField(blank=True, max_length=50, null=True)),
|
67
|
+
],
|
68
|
+
),
|
69
|
+
migrations.CreateModel(
|
70
|
+
name='Type',
|
71
|
+
fields=[
|
72
|
+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
73
|
+
('trans_type', models.CharField(blank=True, max_length=50, null=True)),
|
74
|
+
],
|
75
|
+
options={
|
76
|
+
'verbose_name_plural': 'Types',
|
77
|
+
},
|
78
|
+
),
|
79
|
+
migrations.CreateModel(
|
80
|
+
name='Transaction',
|
81
|
+
fields=[
|
82
|
+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
83
|
+
('date', models.DateField()),
|
84
|
+
('date_created', models.DateField(auto_now_add=True)),
|
85
|
+
('amount', models.DecimalField(decimal_places=2, max_digits=20)),
|
86
|
+
('invoice_numb', models.CharField(blank=True, max_length=500, null=True)),
|
87
|
+
('paid', models.CharField(blank=True, default='No', max_length=500, null=True)),
|
88
|
+
('transaction', models.CharField(blank=True, max_length=500, null=True)),
|
89
|
+
('receipt', models.CharField(blank=True, max_length=500, null=True)),
|
90
|
+
('tax', models.CharField(blank=True, default='Yes', max_length=500, null=True)),
|
91
|
+
('category', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='finance.category')),
|
92
|
+
('keyword', models.ForeignKey(default=1, on_delete=django.db.models.deletion.PROTECT, to='finance.keyword')),
|
93
|
+
('sub_cat', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='finance.subcategory')),
|
94
|
+
('team', models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='finance.team')),
|
95
|
+
('trans_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='finance.type')),
|
96
|
+
],
|
97
|
+
options={
|
98
|
+
'verbose_name_plural': 'Transactions',
|
99
|
+
'ordering': ['date'],
|
100
|
+
},
|
101
|
+
),
|
102
|
+
migrations.CreateModel(
|
103
|
+
name='InvoiceItem',
|
104
|
+
fields=[
|
105
|
+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
106
|
+
('invoice_numb', models.CharField(blank=True, max_length=500, null=True)),
|
107
|
+
('qty', models.IntegerField(blank=True, default='1', null=True)),
|
108
|
+
('price', models.DecimalField(decimal_places=2, default='100.00', max_digits=20)),
|
109
|
+
('item', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='finance.service')),
|
110
|
+
],
|
111
|
+
),
|
112
|
+
migrations.CreateModel(
|
113
|
+
name='Invoice',
|
114
|
+
fields=[
|
115
|
+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
116
|
+
('invoice_numb', models.CharField(max_length=10, unique=True)),
|
117
|
+
('event', models.CharField(blank=True, max_length=500, null=True)),
|
118
|
+
('location', models.CharField(blank=True, max_length=500, null=True)),
|
119
|
+
('amount', models.DecimalField(decimal_places=2, default=0.0, max_digits=100)),
|
120
|
+
('date', models.DateField()),
|
121
|
+
('due', models.DateField()),
|
122
|
+
('paid', models.CharField(blank=True, default='No', max_length=100, null=True)),
|
123
|
+
('client', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='finance.client')),
|
124
|
+
('keyword', models.ForeignKey(default=1, on_delete=django.db.models.deletion.PROTECT, to='finance.keyword')),
|
125
|
+
('service', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='finance.service')),
|
126
|
+
],
|
127
|
+
options={
|
128
|
+
'verbose_name_plural': 'Invoices',
|
129
|
+
'ordering': ['invoice_numb'],
|
130
|
+
},
|
131
|
+
),
|
132
|
+
]
|
migrations/0002_miles.py
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# Generated by Django 4.2.20 on 2025-04-09 03:51
|
2
|
+
|
3
|
+
import django.core.validators
|
4
|
+
from django.db import migrations, models
|
5
|
+
import django.db.models.deletion
|
6
|
+
|
7
|
+
|
8
|
+
class Migration(migrations.Migration):
|
9
|
+
|
10
|
+
dependencies = [
|
11
|
+
('finance', '0001_initial'),
|
12
|
+
]
|
13
|
+
|
14
|
+
operations = [
|
15
|
+
migrations.CreateModel(
|
16
|
+
name='Miles',
|
17
|
+
fields=[
|
18
|
+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
19
|
+
('date', models.DateField()),
|
20
|
+
('begin', models.DecimalField(decimal_places=1, max_digits=10, null=True, validators=[django.core.validators.MinValueValidator(0)])),
|
21
|
+
('end', models.DecimalField(decimal_places=1, max_digits=10, null=True, validators=[django.core.validators.MinValueValidator(0)])),
|
22
|
+
('total', models.DecimalField(decimal_places=1, editable=False, max_digits=10, null=True)),
|
23
|
+
('invoice', models.CharField(blank=True, max_length=255, null=True)),
|
24
|
+
('tax', models.CharField(default='Yes', max_length=10, null=True)),
|
25
|
+
('job', models.CharField(blank=True, max_length=255, null=True)),
|
26
|
+
('vehicle', models.CharField(default='Lead Foot', max_length=255, null=True)),
|
27
|
+
('mileage_type', models.CharField(choices=[('Taxable', 'Taxable'), ('Reimbursed', 'Reimbursed')], default='Taxable', max_length=20)),
|
28
|
+
('client', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='finance.client')),
|
29
|
+
],
|
30
|
+
options={
|
31
|
+
'verbose_name_plural': 'Miles',
|
32
|
+
'ordering': ['-date'],
|
33
|
+
},
|
34
|
+
),
|
35
|
+
]
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Generated by Django 4.2.20 on 2025-04-09 04:38
|
2
|
+
|
3
|
+
from django.db import migrations, models
|
4
|
+
|
5
|
+
|
6
|
+
class Migration(migrations.Migration):
|
7
|
+
|
8
|
+
dependencies = [
|
9
|
+
('finance', '0002_miles'),
|
10
|
+
]
|
11
|
+
|
12
|
+
operations = [
|
13
|
+
migrations.CreateModel(
|
14
|
+
name='MileageRate',
|
15
|
+
fields=[
|
16
|
+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
17
|
+
('rate', models.DecimalField(decimal_places=2, default=0.7, max_digits=5)),
|
18
|
+
],
|
19
|
+
options={
|
20
|
+
'verbose_name': 'Mileage Rate',
|
21
|
+
'verbose_name_plural': 'Mileage Rates',
|
22
|
+
},
|
23
|
+
),
|
24
|
+
]
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Generated by Django 4.2.20 on 2025-04-12 03:40
|
2
|
+
|
3
|
+
from django.db import migrations, models
|
4
|
+
|
5
|
+
|
6
|
+
class Migration(migrations.Migration):
|
7
|
+
|
8
|
+
dependencies = [
|
9
|
+
('finance', '0003_mileagerate'),
|
10
|
+
]
|
11
|
+
|
12
|
+
operations = [
|
13
|
+
migrations.AlterField(
|
14
|
+
model_name='transaction',
|
15
|
+
name='receipt',
|
16
|
+
field=models.FileField(blank=True, null=True, upload_to='receipts/'),
|
17
|
+
),
|
18
|
+
]
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# Generated by Django 4.2.20 on 2025-04-20 00:35
|
2
|
+
|
3
|
+
from django.db import migrations, models
|
4
|
+
import django.db.models.deletion
|
5
|
+
|
6
|
+
|
7
|
+
class Migration(migrations.Migration):
|
8
|
+
|
9
|
+
dependencies = [
|
10
|
+
('finance', '0004_alter_transaction_receipt'),
|
11
|
+
]
|
12
|
+
|
13
|
+
operations = [
|
14
|
+
migrations.RemoveField(
|
15
|
+
model_name='invoiceitem',
|
16
|
+
name='invoice_numb',
|
17
|
+
),
|
18
|
+
migrations.AddField(
|
19
|
+
model_name='invoiceitem',
|
20
|
+
name='invoice',
|
21
|
+
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='items', to='finance.invoice'),
|
22
|
+
),
|
23
|
+
migrations.AlterField(
|
24
|
+
model_name='invoiceitem',
|
25
|
+
name='price',
|
26
|
+
field=models.DecimalField(decimal_places=2, default=100.0, max_digits=20),
|
27
|
+
),
|
28
|
+
migrations.AlterField(
|
29
|
+
model_name='invoiceitem',
|
30
|
+
name='qty',
|
31
|
+
field=models.IntegerField(blank=True, default=1, null=True),
|
32
|
+
),
|
33
|
+
]
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# Generated by Django 4.2.20 on 2025-04-20 03:04
|
2
|
+
|
3
|
+
from django.db import migrations, models
|
4
|
+
import django.db.models.deletion
|
5
|
+
|
6
|
+
|
7
|
+
class Migration(migrations.Migration):
|
8
|
+
|
9
|
+
dependencies = [
|
10
|
+
('finance', '0005_remove_invoiceitem_invoice_numb_invoiceitem_invoice_and_more'),
|
11
|
+
]
|
12
|
+
|
13
|
+
operations = [
|
14
|
+
migrations.AlterModelOptions(
|
15
|
+
name='invoice',
|
16
|
+
options={'ordering': ['invoice_numb']},
|
17
|
+
),
|
18
|
+
migrations.AlterField(
|
19
|
+
model_name='invoiceitem',
|
20
|
+
name='invoice',
|
21
|
+
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='finance.invoice'),
|
22
|
+
),
|
23
|
+
migrations.AlterField(
|
24
|
+
model_name='invoiceitem',
|
25
|
+
name='price',
|
26
|
+
field=models.DecimalField(decimal_places=2, default=0.0, max_digits=20),
|
27
|
+
),
|
28
|
+
migrations.AlterField(
|
29
|
+
model_name='invoiceitem',
|
30
|
+
name='qty',
|
31
|
+
field=models.IntegerField(default=1),
|
32
|
+
),
|
33
|
+
]
|
migrations/__init__.py
ADDED
File without changes
|