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.
@@ -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
+ ![Django](https://img.shields.io/badge/Django-4.x-green?style=for-the-badge&logo=django)
40
+ ![Python](https://img.shields.io/badge/Python-3.10+-blue?style=for-the-badge&logo=python)
41
+ ![PostgreSQL](https://img.shields.io/badge/PostgreSQL-316192?style=for-the-badge&logo=postgresql)
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,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (78.1.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,3 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Tom Stout
@@ -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
+ ]
@@ -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