diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c895b2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +# Ignore virtual environment +venv/ + +# Ignore compiled Python bytecode +workx/**/__pycache__/ +# Ignore macOS .DS_Store files +workx/.DS_Store + +.DS_Store diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..0757494 --- /dev/null +++ b/Pipfile @@ -0,0 +1,11 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] + +[dev-packages] + +[requires] +python_version = "3.11" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..54a7078 --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,20 @@ +{ + "_meta": { + "hash": { + "sha256": "ed6d5d614626ae28e274e453164affb26694755170ccab3aa5866f093d51d3e4" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.11" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": {}, + "develop": {} +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..e69de29 diff --git a/workx/Pipfile b/workx/Pipfile new file mode 100644 index 0000000..f59e539 --- /dev/null +++ b/workx/Pipfile @@ -0,0 +1,12 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +requests = "*" + +[dev-packages] + +[requires] +python_version = "3.11" diff --git a/workx/Pipfile.lock b/workx/Pipfile.lock new file mode 100644 index 0000000..2757098 --- /dev/null +++ b/workx/Pipfile.lock @@ -0,0 +1,134 @@ +{ + "_meta": { + "hash": { + "sha256": "ff88c6939e3090788e917cfdecf1af872168b83c8803457853061495493b5a71" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.11" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "certifi": { + "hashes": [ + "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7", + "sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716" + ], + "markers": "python_version >= '3.6'", + "version": "==2023.5.7" + }, + "charset-normalizer": { + "hashes": [ + "sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6", + "sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1", + "sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e", + "sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373", + "sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62", + "sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230", + "sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be", + "sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c", + "sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0", + "sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448", + "sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f", + "sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649", + "sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d", + "sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0", + "sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706", + "sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a", + "sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59", + "sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23", + "sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5", + "sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb", + "sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e", + "sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e", + "sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c", + "sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28", + "sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d", + "sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41", + "sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974", + "sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce", + "sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f", + "sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1", + "sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d", + "sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8", + "sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017", + "sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31", + "sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7", + "sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8", + "sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e", + "sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14", + "sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd", + "sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d", + "sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795", + "sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b", + "sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b", + "sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b", + "sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203", + "sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f", + "sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19", + "sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1", + "sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a", + "sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac", + "sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9", + "sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0", + "sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137", + "sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f", + "sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6", + "sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5", + "sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909", + "sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f", + "sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0", + "sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324", + "sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755", + "sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb", + "sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854", + "sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c", + "sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60", + "sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84", + "sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0", + "sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b", + "sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1", + "sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531", + "sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1", + "sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11", + "sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326", + "sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df", + "sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab" + ], + "markers": "python_full_version >= '3.7.0'", + "version": "==3.1.0" + }, + "idna": { + "hashes": [ + "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4", + "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2" + ], + "markers": "python_version >= '3.5'", + "version": "==3.4" + }, + "requests": { + "hashes": [ + "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", + "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" + ], + "index": "pypi", + "version": "==2.31.0" + }, + "urllib3": { + "hashes": [ + "sha256:48e7fafa40319d358848e1bc6809b208340fafe2096f1725d05d67443d0483d1", + "sha256:bee28b5e56addb8226c96f7f13ac28cb4c301dd5ea8a6ca179c0b9835e032825" + ], + "markers": "python_version >= '3.7'", + "version": "==2.0.3" + } + }, + "develop": {} +} diff --git a/workx/accounts/__init__.py b/workx/accounts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/workx/accounts/admin.py b/workx/accounts/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/workx/accounts/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/workx/accounts/apps.py b/workx/accounts/apps.py new file mode 100644 index 0000000..3e3c765 --- /dev/null +++ b/workx/accounts/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class AccountsConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'accounts' diff --git a/workx/accounts/form.py b/workx/accounts/form.py new file mode 100644 index 0000000..cc8dc5e --- /dev/null +++ b/workx/accounts/form.py @@ -0,0 +1,7 @@ +from django import forms +from .models import Account + +class AccountForm(forms.ModelForm): + class Meta: + model = Account + exclude = () # \ No newline at end of file diff --git a/workx/accounts/migrations/0001_initial.py b/workx/accounts/migrations/0001_initial.py new file mode 100644 index 0000000..d341f2a --- /dev/null +++ b/workx/accounts/migrations/0001_initial.py @@ -0,0 +1,28 @@ +# Generated by Django 4.1.9 on 2023-07-17 23:26 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Account', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100)), + ('address', models.CharField(max_length=200)), + ('phone_number', models.CharField(max_length=20)), + ('email', models.EmailField(max_length=254)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('total_revenue', models.DecimalField(decimal_places=2, default=0, max_digits=10)), + ('total_expenses', models.DecimalField(decimal_places=2, default=0, max_digits=10)), + ('total_investments', models.DecimalField(decimal_places=2, default=0, max_digits=10)), + ], + ), + ] diff --git a/workx/accounts/migrations/0002_client_expense_income_project_reimbursement_and_more.py b/workx/accounts/migrations/0002_client_expense_income_project_reimbursement_and_more.py new file mode 100644 index 0000000..edf0fd0 --- /dev/null +++ b/workx/accounts/migrations/0002_client_expense_income_project_reimbursement_and_more.py @@ -0,0 +1,72 @@ +# Generated by Django 4.1.9 on 2023-07-18 11:13 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('common', '0001_initial'), + ('employee', '0002_alter_employee_user'), + ('accounts', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Client', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100)), + ], + ), + migrations.CreateModel( + name='Expense', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('category', models.CharField(choices=[('Food', 'Food'), ('Fuel', 'Fuel'), ('Traveling', 'Traveling'), ('Gifts', 'Gifts')], max_length=100)), + ('title', models.CharField(max_length=100)), + ('bill_number', models.CharField(max_length=100)), + ('date', models.DateField()), + ('reimbursement', models.BooleanField()), + ('bank_account', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='common.bankdetails')), + ('employee', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='employee.employee')), + ], + ), + migrations.CreateModel( + name='Income', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('type', models.CharField(choices=[('Invoice', 'Invoice'), ('Dividend', 'Dividend')], max_length=10)), + ('title', models.CharField(max_length=100)), + ('invoice_number', models.CharField(max_length=100)), + ('date', models.DateField()), + ('client', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='accounts.client')), + ], + ), + migrations.CreateModel( + name='Project', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100)), + ], + ), + migrations.CreateModel( + name='Reimbursement', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=100)), + ('rate', models.DecimalField(decimal_places=2, max_digits=10)), + ('quantity', models.PositiveIntegerField()), + ('status', models.CharField(max_length=10)), + ], + ), + migrations.DeleteModel( + name='Account', + ), + migrations.AddField( + model_name='income', + name='project', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='accounts.project'), + ), + ] diff --git a/workx/accounts/migrations/__init__.py b/workx/accounts/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/workx/accounts/models.py b/workx/accounts/models.py new file mode 100644 index 0000000..083b2ae --- /dev/null +++ b/workx/accounts/models.py @@ -0,0 +1,76 @@ +from django.db import models + +# Create your models here. +from employee.models import Employee +from common.models import BankDetails + +class Client(models.Model): + name = models.CharField(max_length=100) + # Other fields for client information + + def __str__(self): + return self.name + + +class Project(models.Model): + name = models.CharField(max_length=100) + # Other fields for project information + + def __str__(self): + return self.name + + +class Income(models.Model): + TYPE_CHOICES = [ + ('Invoice', 'Invoice'), + ('Dividend', 'Dividend'), + ] + + type = models.CharField(max_length=10, choices=TYPE_CHOICES) + title = models.CharField(max_length=100) + invoice_number = models.CharField(max_length=100) + date = models.DateField() + client = models.ForeignKey(Client, on_delete=models.CASCADE) + project = models.ForeignKey(Project, on_delete=models.CASCADE) + # Other fields specific to income + + def __str__(self): + return self.title + + +class Expense(models.Model): + CATEGORY_CHOICES = [ + ('Food', 'Food'), + ('Fuel', 'Fuel'), + ('Traveling', 'Traveling'), + ('Gifts', 'Gifts'), + # Other expense categories + ] + + category = models.CharField(max_length=100, choices=CATEGORY_CHOICES) + title = models.CharField(max_length=100) + bill_number = models.CharField(max_length=100) + date = models.DateField() + employee = models.ForeignKey(Employee, on_delete=models.CASCADE) + bank_account = models.ForeignKey(BankDetails, on_delete=models.CASCADE) + reimbursement = models.BooleanField() + # Other fields specific to expenses + + def __str__(self): + return self.title + + +class Reimbursement(models.Model): + STATUS_CHOICES=[ + ('Paid','Paid'), + ('Due', 'Due'), + ('Overdue', 'Overdue'), + ] + title = models.CharField(max_length=100) + rate = models.DecimalField(max_digits=10, decimal_places=2) + quantity = models.PositiveIntegerField() + status = models.CharField(max_length=10, choices=STATUS_CHOICES) # Paid, Due, Overdue + # Other fields specific to reimbursements + + def __str__(self): + return self.title diff --git a/workx/accounts/serializers.py b/workx/accounts/serializers.py new file mode 100644 index 0000000..973f8a8 --- /dev/null +++ b/workx/accounts/serializers.py @@ -0,0 +1,19 @@ +from rest_framework import serializers +from .models import Income, Expense, Reimbursement + +class IncomeSerializer(serializers.ModelSerializer): + class Meta: + model = Income + fields = '__all__' + + +class ExpenseSerializer(serializers.ModelSerializer): + class Meta: + model = Expense + fields = '__all__' + + +class ReimbursementSerializer(serializers.ModelSerializer): + class Meta: + model = Reimbursement + fields = '__all__' diff --git a/workx/accounts/tests.py b/workx/accounts/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/workx/accounts/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/workx/accounts/views.py b/workx/accounts/views.py new file mode 100644 index 0000000..c504766 --- /dev/null +++ b/workx/accounts/views.py @@ -0,0 +1,17 @@ +from rest_framework import viewsets +from .models import Income, Expense, Reimbursement +from .serializers import IncomeSerializer, ExpenseSerializer, ReimbursementSerializer + +class IncomeViewSet(viewsets.ModelViewSet): + queryset = Income.objects.all() + serializer_class = IncomeSerializer + + +class ExpenseViewSet(viewsets.ModelViewSet): + queryset = Expense.objects.all() + serializer_class = ExpenseSerializer + + +class ReimbursementViewSet(viewsets.ModelViewSet): + queryset = Reimbursement.objects.all() + serializer_class = ReimbursementSerializer diff --git a/workx/client/__init__.py b/workx/client/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/workx/client/admin.py b/workx/client/admin.py new file mode 100644 index 0000000..66e44a5 --- /dev/null +++ b/workx/client/admin.py @@ -0,0 +1,9 @@ +from django.contrib import admin + +# Register your models here. +from client.models import Client, Contract, Requirement, Project + +admin.site.register(Client) +admin.site.register(Contract) +admin.site.register(Requirement) +admin.site.register(Project) \ No newline at end of file diff --git a/workx/client/apps.py b/workx/client/apps.py new file mode 100644 index 0000000..20d81d8 --- /dev/null +++ b/workx/client/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class ClientConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'client' diff --git a/workx/client/models.py b/workx/client/models.py new file mode 100644 index 0000000..fc38f7c --- /dev/null +++ b/workx/client/models.py @@ -0,0 +1,44 @@ +from django.db import models +from common.models import Address, NatureOfBusiness +from employee.models import Employee + +# Create your models here. +class Client(models.Model): + name = models.CharField(max_length=255) + email = models.EmailField(unique=True) + phone_number = models.CharField(max_length=15) + address = models.OneToOneField(Address, on_delete=models.SET_NULL, null=True) + gstin = models.CharField(max_length=15, blank=True, null=True) + cin = models.CharField(max_length=20, blank=True, null=True) + nature_of_business = models.ForeignKey(NatureOfBusiness, on_delete=models.SET_NULL, null=True) + + def __str__(self): + return self.name + +class Project(models.Model): + client = models.ForeignKey(Client, on_delete=models.CASCADE) + name = models.CharField(max_length=255) + description = models.TextField() + initiation_date = models.DateField() + + def __str__(self): + return self.name + +class Requirement(models.Model): + name = models.CharField(max_length=255) + description = models.TextField() + + def __str__(self): + return self.name + +class Contract(models.Model): + project = models.ForeignKey(Project, on_delete=models.CASCADE) + name = models.CharField(max_length=255) + description = models.TextField() + start_date = models.DateField() + end_date = models.DateField() + requirements = models.ManyToManyField(Requirement, blank=True) + employees = models.ManyToManyField(Employee, blank=True) + + def __str__(self): + return self.name diff --git a/workx/client/tests.py b/workx/client/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/workx/client/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/workx/client/views.py b/workx/client/views.py new file mode 100644 index 0000000..27cdb63 --- /dev/null +++ b/workx/client/views.py @@ -0,0 +1,4 @@ +from django.shortcuts import render + +# Create your views here. + diff --git a/workx/common/__init__.py b/workx/common/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/workx/common/admin.py b/workx/common/admin.py new file mode 100644 index 0000000..2f497d6 --- /dev/null +++ b/workx/common/admin.py @@ -0,0 +1,8 @@ +from django.contrib import admin + +# Register your models here. +from common.models import Address, BankDetails, NatureOfBusiness + +admin.site.register(Address) +admin.site.register(BankDetails) +admin.site.register(NatureOfBusiness) \ No newline at end of file diff --git a/workx/common/apps.py b/workx/common/apps.py new file mode 100644 index 0000000..01cca2f --- /dev/null +++ b/workx/common/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class CommonConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'common' diff --git a/workx/common/migrations/0001_initial.py b/workx/common/migrations/0001_initial.py new file mode 100644 index 0000000..fb012b1 --- /dev/null +++ b/workx/common/migrations/0001_initial.py @@ -0,0 +1,48 @@ +# Generated by Django 4.1.9 on 2023-07-17 22:36 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Address', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('address_line_1', models.CharField(max_length=200)), + ('address_line_2', models.CharField(blank=True, max_length=200)), + ('city', models.CharField(max_length=50)), + ('state', models.CharField(max_length=50)), + ('zip_code', models.CharField(max_length=10)), + ('country', models.CharField(max_length=50)), + ], + options={ + 'db_table': 'address', + }, + ), + migrations.CreateModel( + name='BankDetails', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('beneficiary_name', models.CharField(max_length=50)), + ('bank_name', models.CharField(max_length=50)), + ('account_number', models.CharField(max_length=20)), + ('ifsc_code', models.CharField(max_length=20)), + ('branch_name', models.CharField(max_length=50)), + ('upi_id', models.CharField(blank=True, max_length=50)), + ], + ), + migrations.CreateModel( + name='NatureOfBusiness', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=50)), + ], + ), + ] diff --git a/workx/common/migrations/__init__.py b/workx/common/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/workx/common/models.py b/workx/common/models.py new file mode 100644 index 0000000..adbca07 --- /dev/null +++ b/workx/common/models.py @@ -0,0 +1,34 @@ +from django.db import models + +# Create your models here. + +class Address(models.Model): + address_line_1 = models.CharField(max_length=200) + address_line_2 = models.CharField(max_length=200, blank=True) + city = models.CharField(max_length=50) + state = models.CharField(max_length=50) + zip_code = models.CharField(max_length=10) + country = models.CharField(max_length=50) + + def __str__(self): + return f"{self.address_line_1}, {self.address_line_2}, {self.city}, {self.state}, {self.zip_code}, {self.country}" + + class Meta: + db_table = 'address' + +class BankDetails(models.Model): + beneficiary_name = models.CharField(max_length=50) + bank_name = models.CharField(max_length=50) + account_number = models.CharField(max_length=20) + ifsc_code = models.CharField(max_length=20) + branch_name = models.CharField(max_length=50) + upi_id = models.CharField(max_length=50, blank=True) + + def __str__(self): + return self.account_number + +class NatureOfBusiness(models.Model): + name = models.CharField(max_length=50) + + def __str__(self): + return self.name \ No newline at end of file diff --git a/workx/common/serializers.py b/workx/common/serializers.py new file mode 100644 index 0000000..c5ab261 --- /dev/null +++ b/workx/common/serializers.py @@ -0,0 +1,14 @@ +from rest_framework import serializers +from .models import Address, BankDetails + + +class AddressSerializer(serializers.ModelSerializer): + class Meta: + model = Address + fields = '__all__' + + +class BankDetailsSerializer(serializers.ModelSerializer): + class Meta: + model = BankDetails + fields = '__all__' \ No newline at end of file diff --git a/workx/common/tests.py b/workx/common/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/workx/common/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/workx/common/views.py b/workx/common/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/workx/common/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/workx/company/__init__.py b/workx/company/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/workx/company/admin.py b/workx/company/admin.py new file mode 100644 index 0000000..138956e --- /dev/null +++ b/workx/company/admin.py @@ -0,0 +1,5 @@ +from django.contrib import admin + +from company.models import Company + +admin.site.register(Company) \ No newline at end of file diff --git a/workx/company/apps.py b/workx/company/apps.py new file mode 100644 index 0000000..b8ac738 --- /dev/null +++ b/workx/company/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class CompanyConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'company' diff --git a/workx/company/form.py b/workx/company/form.py new file mode 100644 index 0000000..4dd200c --- /dev/null +++ b/workx/company/form.py @@ -0,0 +1,7 @@ +from django import forms +from .models import Company + +class CompanyForm(forms.ModelForm): + class Meta: + model = Company + exclude = () # \ No newline at end of file diff --git a/workx/company/migrations/0001_initial.py b/workx/company/migrations/0001_initial.py new file mode 100644 index 0000000..793e574 --- /dev/null +++ b/workx/company/migrations/0001_initial.py @@ -0,0 +1,47 @@ +# Generated by Django 4.1.9 on 2023-07-19 21:26 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('common', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Company', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('legal_name', models.CharField(max_length=256)), + ('trade_name', models.CharField(max_length=256)), + ('cin', models.CharField(max_length=64)), + ('cin_proof', models.FileField(null=True, upload_to='company_proofs/')), + ('gstin', models.CharField(max_length=16)), + ('gstin_proof', models.FileField(null=True, upload_to='company_proofs/')), + ('date_of_incorporation', models.DateField()), + ('date_of_incorporation_proof', models.FileField(null=True, upload_to='company_proofs/')), + ('pan', models.CharField(max_length=16)), + ('pan_proof', models.FileField(null=True, upload_to='company_proofs/')), + ('iec', models.CharField(max_length=16)), + ('iec_proof', models.FileField(null=True, upload_to='company_proofs/')), + ('msme_code', models.CharField(max_length=64)), + ('msme_proof', models.FileField(null=True, upload_to='company_proofs/')), + ('provident_fund_code_number', models.CharField(max_length=32)), + ('provident_fund_code_number_proof', models.FileField(null=True, upload_to='company_proofs/')), + ('se_registration_number', models.CharField(max_length=32)), + ('se_registration_number_proof', models.FileField(null=True, upload_to='company_proofs/')), + ('phone_number', models.CharField(max_length=13)), + ('support_email', models.EmailField(max_length=254, null=True, unique=True)), + ('address', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='common.address')), + ('nature_of_business', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='common.natureofbusiness')), + ], + options={ + 'db_table': 'company', + }, + ), + ] diff --git a/workx/company/migrations/__init__.py b/workx/company/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/workx/company/models.py b/workx/company/models.py new file mode 100644 index 0000000..394fde2 --- /dev/null +++ b/workx/company/models.py @@ -0,0 +1,36 @@ +from django.db import models +from common.models import Address, NatureOfBusiness + +class Company(models.Model): + legal_name = models.CharField(max_length=256) + trade_name = models.CharField(max_length=256) + address = models.ForeignKey(Address, on_delete=models.SET_NULL, null=True) + cin = models.CharField(max_length=64) + cin_proof = models.FileField(null= True, upload_to='company_proofs/') + gstin = models.CharField(max_length=16) + gstin_proof = models.FileField(null= True,upload_to='company_proofs/') + date_of_incorporation = models.DateField() + date_of_incorporation_proof = models.FileField(null= True,upload_to='company_proofs/') + pan = models.CharField(max_length=16) + pan_proof = models.FileField(null= True,upload_to='company_proofs/') + iec = models.CharField(max_length=16) + iec_proof = models.FileField(null= True,upload_to='company_proofs/') + msme_code = models.CharField(max_length=64) + msme_proof = models.FileField(null= True,upload_to='company_proofs/') + provident_fund_code_number = models.CharField(max_length=32) + provident_fund_code_number_proof = models.FileField(null= True,upload_to='company_proofs/') + se_registration_number = models.CharField(max_length=32) + se_registration_number_proof = models.FileField(null= True,upload_to='company_proofs/') + nature_of_business = models.ForeignKey(NatureOfBusiness, on_delete=models.SET_NULL, null=True) + phone_number = models.CharField(max_length=13) #Need to look into this + support_email = models.EmailField(null=True, unique=True) + + class Meta: + db_table = 'company' + + def __str__(self): + return self.legal_name + + + + diff --git a/workx/company/serializers.py b/workx/company/serializers.py new file mode 100644 index 0000000..45443c7 --- /dev/null +++ b/workx/company/serializers.py @@ -0,0 +1,7 @@ +from rest_framework import serializers +from .models import Company + +class CompanySerializer(serializers.ModelSerializer): + class Meta: + model = Company + fields = '__all__' # Include all fields in the serializer \ No newline at end of file diff --git a/workx/company/tests.py b/workx/company/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/workx/company/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/workx/company/views.py b/workx/company/views.py new file mode 100644 index 0000000..a3b60fc --- /dev/null +++ b/workx/company/views.py @@ -0,0 +1,26 @@ +from django.shortcuts import render +from rest_framework import viewsets, permissions +from .models import Company +from .form import CompanyForm +from .serializers import CompanySerializer +# Create your views here. +class CompanyViewSet(viewsets.ModelViewSet): + queryset = Company.objects.all() + serializer_class = CompanySerializer + permission_classes = [permissions.IsAuthenticated] + + def perform_create(self, serializer): + form_data = self.request.data.get('form') + form = CompanyForm(form_data) + if form.is_valid(): + employee = serializer.save() + form.instance = employee + form.save() + + def perform_update(self, serializer): + form_data = self.request.data.get('form') + form = CompanyForm(form_data, instance=serializer.instance) + if form.is_valid(): + employee = serializer.save() + form.instance = employee + form.save() \ No newline at end of file diff --git a/workx/employee/__init__.py b/workx/employee/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/workx/employee/admin.py b/workx/employee/admin.py new file mode 100644 index 0000000..efcb459 --- /dev/null +++ b/workx/employee/admin.py @@ -0,0 +1,7 @@ +from django.contrib import admin + +# Register your models here. +from employee.models import Employee + + +admin.site.register(Employee) \ No newline at end of file diff --git a/workx/employee/apps.py b/workx/employee/apps.py new file mode 100644 index 0000000..b5ef142 --- /dev/null +++ b/workx/employee/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class EmployeeConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'employee' diff --git a/workx/employee/forms.py b/workx/employee/forms.py new file mode 100644 index 0000000..4910d87 --- /dev/null +++ b/workx/employee/forms.py @@ -0,0 +1,11 @@ +from django import forms +from .models import Employee + + +class EmployeeForm(forms.ModelForm): + class Meta: + model = Employee + fields = '__all__' + widgets = { + 'department': forms.CheckboxSelectMultiple(), + } \ No newline at end of file diff --git a/workx/employee/migrations/0001_initial.py b/workx/employee/migrations/0001_initial.py new file mode 100644 index 0000000..d1b2f1d --- /dev/null +++ b/workx/employee/migrations/0001_initial.py @@ -0,0 +1,42 @@ +# Generated by Django 4.1.9 on 2023-07-17 22:35 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('common', '__first__'), + ] + + operations = [ + migrations.CreateModel( + name='Role', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=50, unique=True)), + ], + ), + migrations.CreateModel( + name='Employee', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('first_name', models.CharField(max_length=30)), + ('last_name', models.CharField(max_length=30)), + ('personal_email', models.EmailField(max_length=254, unique=True)), + ('official_email', models.EmailField(max_length=254, unique=True)), + ('phone_number', models.CharField(max_length=13)), + ('job_title', models.CharField(max_length=100)), + ('ctc', models.DecimalField(decimal_places=2, max_digits=10)), + ('address', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='common.address')), + ('bank_details', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='common.bankdetails')), + ('role', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='employee.role')), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/workx/employee/migrations/0002_alter_employee_user.py b/workx/employee/migrations/0002_alter_employee_user.py new file mode 100644 index 0000000..2ed2946 --- /dev/null +++ b/workx/employee/migrations/0002_alter_employee_user.py @@ -0,0 +1,21 @@ +# Generated by Django 4.1.9 on 2023-07-17 22:46 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('employee', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='employee', + name='user', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='employee', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/workx/employee/migrations/__init__.py b/workx/employee/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/workx/employee/models.py b/workx/employee/models.py new file mode 100644 index 0000000..1d4b1de --- /dev/null +++ b/workx/employee/models.py @@ -0,0 +1,26 @@ +from django.db import models +from common.models import BankDetails, Address +from django.contrib.auth.models import User + +class Employee(models.Model): + user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='employee') + # Rest of the fields... + role = models.ForeignKey('Role', on_delete=models.SET_NULL, null=True) + first_name = models.CharField(max_length=30) + last_name = models.CharField(max_length=30) + personal_email = models.EmailField(unique=True) + official_email = models.EmailField(unique=True) + phone_number = models.CharField(max_length=13) + address = models.ForeignKey(Address, on_delete=models.SET_NULL, null=True) + job_title = models.CharField(max_length=100) + ctc = models.DecimalField(max_digits=10, decimal_places=2) + bank_details = models.OneToOneField(BankDetails, on_delete=models.CASCADE) + + def __str__(self): + return f"{self.first_name} {self.last_name}" + +class Role(models.Model): + name = models.CharField(max_length=50, unique=True) + + def __str__(self): + return self.name diff --git a/workx/employee/permissions.py b/workx/employee/permissions.py new file mode 100644 index 0000000..450e850 --- /dev/null +++ b/workx/employee/permissions.py @@ -0,0 +1,45 @@ +from rest_framework import permissions + +def has_permission(self, request, view): + if request.user.is_authenticated: + try: + employee = request.user.employee + return employee is not None and employee.role is not None + except Employee.DoesNotExist: + return False + return False +from .models import Employee + +class EmployeeAPIPermission(permissions.BasePermission): + def has_permission(self, request, view): + if request.method in permissions.SAFE_METHODS: + return True # Allow GET requests for all users + + user = request.user + if user.is_authenticated and user.role: + role_name = user.role.name + if role_name == 'Admin': + return True # Allow CRUD operations for Admin role + elif role_name == 'Employee' and request.method in ['GET', 'PUT']: + return True # Allow GET and PUT requests for Employee role + + return False + +from rest_framework import permissions + + +class GoogleAuthenticatedPermission(permissions.BasePermission): + def has_permission(self, request, view): + # Check if the user is authenticated + if not request.user.is_authenticated: + return False + + # Check if the user is authenticated with a Google account + if 'email' not in request.session: + return False + + # Perform additional checks if needed + # For example, verify the email in request.session with the email from id_token_data + + return True + diff --git a/workx/employee/serializers.py b/workx/employee/serializers.py new file mode 100644 index 0000000..4df4888 --- /dev/null +++ b/workx/employee/serializers.py @@ -0,0 +1,29 @@ +from rest_framework import serializers +from common.serializers import BankDetailsSerializer, AddressSerializer +from .models import Employee,Role +from common.models import BankDetails, Address + + +class EmployeeSerializer(serializers.ModelSerializer): + bank_details = BankDetailsSerializer() + address = AddressSerializer() + + class Meta: + model = Employee + fields = '__all__' + + def create(self, validated_data): + bank_details_data = validated_data.pop('bank_details') + address_data = validated_data.pop('address') + + bank_details = BankDetails.objects.create(**bank_details_data) + address = Address.objects.create(**address_data) + + employee = Employee.objects.create(bank_details=bank_details, address=address, **validated_data) + return employee + + +class RoleSerializer(serializers.ModelSerializer): + class Meta: + model = Role + fields = '__all__' \ No newline at end of file diff --git a/workx/employee/tests.py b/workx/employee/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/workx/employee/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/workx/employee/views.py b/workx/employee/views.py new file mode 100644 index 0000000..5a3bc0e --- /dev/null +++ b/workx/employee/views.py @@ -0,0 +1,27 @@ +from rest_framework import viewsets,permissions +from .models import Employee +from .serializers import EmployeeSerializer +from .forms import EmployeeForm +from rest_framework import generics, permissions +from .models import Role +from .serializers import RoleSerializer +from .permissions import EmployeeAPIPermission,GoogleAuthenticatedPermission + +class RoleListCreateAPIView(generics.ListCreateAPIView): + queryset = Role.objects.all() + serializer_class = RoleSerializer + permission_classes = [permissions.IsAuthenticated, permissions.IsAdminUser] + + +class EmployeeListCreateAPIView(generics.ListCreateAPIView): + queryset = Employee.objects.all() + serializer_class = EmployeeSerializer + permission_classes = [permissions.IsAuthenticated| EmployeeAPIPermission] + +class EmployeeRetrieveUpdateAPIView(generics.RetrieveUpdateAPIView): + queryset = Employee.objects.all() + serializer_class = EmployeeSerializer + permission_classes = [permissions.IsAuthenticated | EmployeeAPIPermission] + + + diff --git a/workx/google_auth/__init__.py b/workx/google_auth/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/workx/google_auth/admin.py b/workx/google_auth/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/workx/google_auth/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/workx/google_auth/apps.py b/workx/google_auth/apps.py new file mode 100644 index 0000000..3eb01b8 --- /dev/null +++ b/workx/google_auth/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class GoogleAuthConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'google_auth' diff --git a/workx/google_auth/migrations/__init__.py b/workx/google_auth/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/workx/google_auth/models.py b/workx/google_auth/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/workx/google_auth/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/workx/google_auth/tests.py b/workx/google_auth/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/workx/google_auth/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/workx/google_auth/urls.py b/workx/google_auth/urls.py new file mode 100644 index 0000000..da0e58d --- /dev/null +++ b/workx/google_auth/urls.py @@ -0,0 +1,9 @@ +from django.urls import path +from . import views + +app_name = 'google_auth' + +urlpatterns = [ + path('login/', views.login, name='login'), + path('callback/', views.callback, name='callback'), +] \ No newline at end of file diff --git a/workx/google_auth/views.py b/workx/google_auth/views.py new file mode 100644 index 0000000..27981da --- /dev/null +++ b/workx/google_auth/views.py @@ -0,0 +1,34 @@ + + +from django.shortcuts import redirect +from google.oauth2 import id_token +from django.conf import settings +from django.urls import reverse_lazy +import requests +from google.auth.transport import requests as google_requests + +def login(request): + # Redirect the user to the Google authentication URL + redirect_uri = request.build_absolute_uri(reverse_lazy('google_auth:callback')) + authorization_url = f'https://accounts.google.com/o/oauth2/auth?response_type=code&client_id={settings.GOOGLE_OAUTH2_CLIENT_ID}&redirect_uri={redirect_uri}&scope=openid%20email%20profile' + return redirect(authorization_url) + +def callback(request): + authorization_code = request.GET.get('code') + token_url = 'https://oauth2.googleapis.com/token' + redirect_uri = request.build_absolute_uri(reverse_lazy('google_auth:callback')) + token_request_data = { + 'code': authorization_code, + 'client_id': settings.GOOGLE_OAUTH2_CLIENT_ID, + 'client_secret': settings.GOOGLE_OAUTH2_CLIENT_SECRET, + 'redirect_uri': redirect_uri, + 'grant_type': 'authorization_code' + } + token_response = requests.post(token_url, data=token_request_data) + token_response_data = token_response.json() + id_token_data = id_token.verify_oauth2_token( + token_response_data['id_token'], + google_requests.Request(), + settings.GOOGLE_OAUTH2_CLIENT_ID + ) + return redirect('http://127.0.0.1:8000') diff --git a/workx/manage.py b/workx/manage.py new file mode 100755 index 0000000..492930f --- /dev/null +++ b/workx/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'workx.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/workx/templates/home.html b/workx/templates/home.html new file mode 100644 index 0000000..755ac57 --- /dev/null +++ b/workx/templates/home.html @@ -0,0 +1,12 @@ + + +
+