Seems like thie model is not complete. Was this intentional?
Please revert back.
sprint-4
into main
@@ -0,0 +1,9 @@ | |||
# Ignore virtual environment | |||
venv/ | |||
# Ignore compiled Python bytecode | |||
workx/**/__pycache__/ | |||
# Ignore macOS .DS_Store files | |||
workx/.DS_Store | |||
.DS_Store |
@@ -0,0 +1,11 @@ | |||
[[source]] | |||
url = "https://pypi.org/simple" | |||
verify_ssl = true | |||
name = "pypi" | |||
[packages] | |||
[dev-packages] | |||
[requires] | |||
python_version = "3.11" |
@@ -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": {} | |||
} |
@@ -0,0 +1,12 @@ | |||
[[source]] | |||
url = "https://pypi.org/simple" | |||
verify_ssl = true | |||
name = "pypi" | |||
[packages] | |||
requests = "*" | |||
[dev-packages] | |||
[requires] | |||
python_version = "3.11" |
@@ -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": {} | |||
} |
@@ -0,0 +1,3 @@ | |||
from django.contrib import admin | |||
# Register your models here. |
@@ -0,0 +1,6 @@ | |||
from django.apps import AppConfig | |||
class AccountsConfig(AppConfig): | |||
default_auto_field = 'django.db.models.BigAutoField' | |||
name = 'accounts' |
@@ -0,0 +1,7 @@ | |||
from django import forms | |||
from .models import Account | |||
class AccountForm(forms.ModelForm): | |||
class Meta: | |||
model = Account | |||
exclude = () # | |||
|
@@ -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)), | |||
], | |||
), | |||
] |
@@ -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'), | |||
), | |||
] |
@@ -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 | |||
kj commented 2 years ago
Review
Seems like thie model is not complete. Was this intentional? Please revert back. Seems like thie model is not complete. Was this intentional?
Please revert back.
|
|||
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 | |||
kj commented 2 years ago
Review
Business Take: Also, I don’t see THE CURRENCY and VALUE of the INCOME. Business Take:
Does the invoice include CGST, IGST breakup? Is it calculated implicitly?
Please add the field if missing.
Also, I don't see THE CURRENCY and VALUE of the 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) | |||
kj commented 2 years ago
Review
Missing VALUE/AMO0UNT of Expense field. Missing VALUE/AMO0UNT of Expense field.
|
|||
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() | |||
kj commented 2 years ago
Review
What is the boolean used for? Also, was the reimbursment paid or not? No flag for that? If Expense / Reimbursement / Income invoice record generated has to be deleted it shouldn’t undergo delete operation. Please add ISARCHIVED Boolean field What is the boolean used for?
Also, was the reimbursment paid or not? No flag for that?
If Expense / Reimbursement / Income invoice record generated has to be deleted it shouldn't undergo delete operation.
Please add ISARCHIVED Boolean field
|
|||
# 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 |
@@ -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__' |
@@ -0,0 +1,3 @@ | |||
from django.test import TestCase | |||
# Create your tests here. |
@@ -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 |
@@ -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) | |||
kj commented 2 years ago
Review
All Admin side Registration can be done in one Shot using Array format. Shorten this code All Admin side Registration can be done in one Shot using Array format.
Shorten this code
|
@@ -0,0 +1,6 @@ | |||
from django.apps import AppConfig | |||
class ClientConfig(AppConfig): | |||
default_auto_field = 'django.db.models.BigAutoField' | |||
name = 'client' |
@@ -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() | |||
kj commented 2 years ago
Review
Add attachment / file field since there are high chances of uploading the document as requirement rather than typing it inside the description field. Add attachment / file field since there are high chances of uploading the document as requirement rather than typing it inside the description field.
|
|||
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 |
@@ -0,0 +1,3 @@ | |||
from django.test import TestCase | |||
# Create your tests here. |
@@ -0,0 +1,4 @@ | |||
from django.shortcuts import render | |||
# Create your views here. | |||
@@ -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) | |||
kj commented 2 years ago
Review
As mentioned earlier, make this a One Liner statement by registering in Array format As mentioned earlier, make this a One Liner statement by registering in Array format
|
@@ -0,0 +1,6 @@ | |||
from django.apps import AppConfig | |||
class CommonConfig(AppConfig): | |||
default_auto_field = 'django.db.models.BigAutoField' | |||
name = 'common' |
@@ -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)), | |||
], | |||
), | |||
] |
@@ -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) | |||
kj commented 2 years ago
Review
Add Lat,Lng since we can also get the location name by the coordinates. They can be made optional. Add Lat,Lng since we can also get the location name by the coordinates. They can be made optional.
|
|||
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 |
@@ -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__' |
@@ -0,0 +1,3 @@ | |||
from django.test import TestCase | |||
# Create your tests here. | |||
kj commented 2 years ago
Review
Remove the file if it’s not gonna be useful. Remove the file if it's not gonna be useful.
|
@@ -0,0 +1,3 @@ | |||
from django.shortcuts import render | |||
# Create your views here. |
@@ -0,0 +1,5 @@ | |||
from django.contrib import admin | |||
from company.models import Company | |||
admin.site.register(Company) |
@@ -0,0 +1,6 @@ | |||
from django.apps import AppConfig | |||
class CompanyConfig(AppConfig): | |||
default_auto_field = 'django.db.models.BigAutoField' | |||
name = 'company' |
@@ -0,0 +1,7 @@ | |||
from django import forms | |||
from .models import Company | |||
class CompanyForm(forms.ModelForm): | |||
class Meta: | |||
model = Company | |||
exclude = () # | |||
kj commented 2 years ago
Review
Useless line Useless line
|
@@ -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', | |||
}, | |||
), | |||
] |
@@ -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 | |||
@@ -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 |
@@ -0,0 +1,3 @@ | |||
from django.test import TestCase | |||
# Create your tests here. |
@@ -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] | |||
kj commented 2 years ago
Review
Is authenticated is not a good enough security especially to manipulate Employee data. Please do the needful. Is authenticated is not a good enough security especially to manipulate Employee data. Please do the needful.
|
|||
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() |
@@ -0,0 +1,7 @@ | |||
from django.contrib import admin | |||
# Register your models here. | |||
from employee.models import Employee | |||
admin.site.register(Employee) |
@@ -0,0 +1,6 @@ | |||
from django.apps import AppConfig | |||
class EmployeeConfig(AppConfig): | |||
default_auto_field = 'django.db.models.BigAutoField' | |||
name = 'employee' |
@@ -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(), | |||
} |
@@ -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)), | |||
], | |||
), | |||
] |
@@ -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), | |||
), | |||
] |
@@ -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... | |||
kj commented 2 years ago
Review
Employee ID has a pattern and should be generated on the fly or during the creation of the data. Please add the field. Employee ID has a pattern and should be generated on the fly or during the creation of the data. Please add the field.
|
|||
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) | |||
kj commented 2 years ago
Review
Can we add another field called Reporting Manager? Please check with Shashank. Can we add another field called Reporting Manager? Please check with Shashank.
|
|||
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 |
@@ -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': | |||
kj commented 2 years ago
Review
Checking against the word “Admin” for permission is not the right way. Please use Choices or Enum and make the Roles to be common in such a way that there is no ambiguity in checking the User Role. Checking against the word "Admin" for permission is not the right way.
Please use Choices or Enum and make the Roles to be common in such a way that there is no ambiguity in checking the User Role.
|
|||
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 | |||
@@ -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__' |
@@ -0,0 +1,3 @@ | |||
from django.test import TestCase | |||
# Create your tests here. |
@@ -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] | |||
@@ -0,0 +1,3 @@ | |||
from django.contrib import admin | |||
# Register your models here. |
@@ -0,0 +1,6 @@ | |||
from django.apps import AppConfig | |||
class GoogleAuthConfig(AppConfig): | |||
default_auto_field = 'django.db.models.BigAutoField' | |||
name = 'google_auth' |
@@ -0,0 +1,3 @@ | |||
from django.db import models | |||
# Create your models here. |
@@ -0,0 +1,3 @@ | |||
from django.test import TestCase | |||
# Create your tests here. |
@@ -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'), | |||
] |
@@ -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') |
@@ -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() |
@@ -0,0 +1,12 @@ | |||
<!DOCTYPE html> | |||
<html> | |||
<head> | |||
<title>Home</title> | |||
<script> | |||
window.location.href = "http://127.0.0.1:8000/api/"; // Replace "https://example.com" with your desired redirect URL | |||
</script> | |||
</head> | |||
<body> | |||
<h1>Redirecting...</h1> | |||
</body> | |||
</html> |
@@ -0,0 +1,12 @@ | |||
<-- templates/login.html --> | |||
{% load socialaccount %} | |||
{% block content %} | |||
... | |||
<button class="btn btn-outline-info"> | |||
<a href="{% provider_login_url 'google'%}?next=/"> | |||
<i class="fab fa-google"></i> | |||
Login with Google | |||
</a> | |||
</button> | |||
... | |||
{% endblock content %} |
@@ -0,0 +1,16 @@ | |||
""" | |||
ASGI config for workx project. | |||
It exposes the ASGI callable as a module-level variable named ``application``. | |||
For more information on this file, see | |||
https://docs.djangoproject.com/en/4.1/howto/deployment/asgi/ | |||
""" | |||
import os | |||
from django.core.asgi import get_asgi_application | |||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'workx.settings') | |||
application = get_asgi_application() |
@@ -0,0 +1,147 @@ | |||
""" | |||
Django settings for workx project. | |||
Generated by 'django-admin startproject' using Django 4.1.5. | |||
For more information on this file, see | |||
https://docs.djangoproject.com/en/4.1/topics/settings/ | |||
For the full list of settings and their values, see | |||
https://docs.djangoproject.com/en/4.1/ref/settings/ | |||
""" | |||
from pathlib import Path | |||
# Build paths inside the project like this: BASE_DIR / 'subdir'. | |||
BASE_DIR = Path(__file__).resolve().parent.parent | |||
# Quick-start development settings - unsuitable for production | |||
# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/ | |||
# SECURITY WARNING: keep the secret key used in production secret! | |||
SECRET_KEY = 'django-insecure-)c#cqk!av3fuey9jjywjs_b2z5l%r*!09h0-@+wxxzq-c4o_fi' | |||
# SECURITY WARNING: don't run with debug turned on in production! | |||
DEBUG = True | |||
ALLOWED_HOSTS = ['*'] | |||
GOOGLE_OAUTH2_CLIENT_ID = "611194092059-kk4bhv18i19cvngmi3335gtvk4nmp25d.apps.googleusercontent.com" | |||
GOOGLE_OAUTH2_CLIENT_SECRET ="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" | |||
# Application definition | |||
INSTALLED_APPS = [ | |||
'django.contrib.admin', | |||
'django.contrib.auth', | |||
'django.contrib.contenttypes', | |||
'django.contrib.sessions', | |||
'django.contrib.staticfiles', | |||
'company', | |||
'common', | |||
'accounts', | |||
'employee', | |||
'client', | |||
'rest_framework', | |||
"django.contrib.messages", | |||
"google_auth", | |||
] | |||
MIDDLEWARE = [ | |||
'django.middleware.security.SecurityMiddleware', | |||
'django.contrib.sessions.middleware.SessionMiddleware', | |||
'django.middleware.common.CommonMiddleware', | |||
'django.middleware.csrf.CsrfViewMiddleware', | |||
'django.contrib.auth.middleware.AuthenticationMiddleware', | |||
'django.contrib.messages.middleware.MessageMiddleware', | |||
'django.middleware.clickjacking.XFrameOptionsMiddleware', | |||
] | |||
ROOT_URLCONF = 'workx.urls' | |||
TEMPLATES = [ | |||
{ | |||
'BACKEND': 'django.template.backends.django.DjangoTemplates', | |||
'DIRS': [], | |||
'APP_DIRS': True, | |||
'OPTIONS': { | |||
'context_processors': [ | |||
'django.template.context_processors.debug', | |||
'django.template.context_processors.request', | |||
'django.contrib.auth.context_processors.auth', | |||
'django.contrib.messages.context_processors.messages', | |||
], | |||
}, | |||
}, | |||
] | |||
WSGI_APPLICATION = 'workx.wsgi.application' | |||
# AUTH_PASSWORD_VALIDATORS = [ | |||
# { | |||
# "NAME": "django.contrib.auth.password_validation." | |||
# "UserAttributeSimilarityValidator", | |||
# }, | |||
# { | |||
# "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", | |||
# }, | |||
# { | |||
# "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", | |||
# }, | |||
# { | |||
# "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", | |||
# }, | |||
# ] | |||
# Database | |||
# https://docs.djangoproject.com/en/4.1/ref/settings/#databases | |||
DATABASES = { | |||
'default': { | |||
'ENGINE': 'django.db.backends.postgresql_psycopg2', | |||
'NAME': 'workxx', | |||
'USER': 'postgres', | |||
'PASSWORD': '123456', | |||
'HOST': 'localhost', | |||
'PORT': '5432', | |||
} | |||
} | |||
# Password validation | |||
# https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators | |||
# GOOGLE_SSO_SCOPES = [ # default values | |||
# "openid", | |||
# "https://www.googleapis.com/auth/userinfo.email", | |||
# "https://www.googleapis.com/auth/userinfo.profile", | |||
# ] | |||
# Internationalization | |||
# https://docs.djangoproject.com/en/4.1/topics/i18n/ | |||
LANGUAGE_CODE = 'en-us' | |||
TIME_ZONE = 'UTC' | |||
USE_I18N = True | |||
USE_TZ = True | |||
# Static files (CSS, JavaScript, Images) | |||
# https://docs.djangoproject.com/en/4.1/howto/static-files/ | |||
STATIC_URL = 'static/' | |||
# Default primary key field type | |||
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field | |||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' |
@@ -0,0 +1,39 @@ | |||
"""workx URL Configuration | |||
The `urlpatterns` list routes URLs to views. For more information please see: | |||
https://docs.djangoproject.com/en/4.1/topics/http/urls/ | |||
Examples: | |||
Function views | |||
1. Add an import: from my_app import views | |||
2. Add a URL to urlpatterns: path('', views.home, name='home') | |||
Class-based views | |||
1. Add an import: from other_app.views import Home | |||
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') | |||
Including another URLconf | |||
1. Import the include() function: from django.urls import include, path | |||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) | |||
""" | |||
from django.contrib import admin | |||
from django.urls import path,include | |||
from accounts.views import IncomeViewSet,ExpenseViewSet,ReimbursementViewSet | |||
from employee.views import EmployeeListCreateAPIView,EmployeeRetrieveUpdateAPIView,RoleListCreateAPIView | |||
from company.views import CompanyViewSet | |||
from rest_framework import routers | |||
from google_auth.views import login, callback | |||
router = routers.DefaultRouter() | |||
router.register(r'company', CompanyViewSet) | |||
router.register(r'accounts/income', IncomeViewSet) | |||
router.register(r'accounts/reimbursement', ReimbursementViewSet) | |||
router.register(r'accounts/expense', ExpenseViewSet) | |||
urlpatterns = [ | |||
path('admin/', admin.site.urls), | |||
path('', include(router.urls)), | |||
path('employees/', EmployeeListCreateAPIView.as_view(), name='employee-list-create'), | |||
path('employees/<int:pk>/', EmployeeRetrieveUpdateAPIView.as_view(), name='employee-retrieve-update'), | |||
path('roles/', RoleListCreateAPIView.as_view(), name='role-list-create'), | |||
path('google-auth/', include('google_auth.urls')), | |||
] | |||
@@ -0,0 +1,16 @@ | |||
""" | |||
WSGI config for workx project. | |||
It exposes the WSGI callable as a module-level variable named ``application``. | |||
For more information on this file, see | |||
https://docs.djangoproject.com/en/4.1/howto/deployment/wsgi/ | |||
""" | |||
import os | |||
from django.core.wsgi import get_wsgi_application | |||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'workx.settings') | |||
application = get_wsgi_application() |
Useless line, please remomve it.