#2 sprint-4

Открыто
paras хочет смерджить 7 коммит(ов) из sprint-4 в main
  1. +9
    -0
      .gitignore
  2. +11
    -0
      Pipfile
  3. +20
    -0
      Pipfile.lock
  4. +0
    -0
      readme.md
  5. +12
    -0
      workx/Pipfile
  6. +134
    -0
      workx/Pipfile.lock
  7. +0
    -0
      workx/accounts/__init__.py
  8. +3
    -0
      workx/accounts/admin.py
  9. +6
    -0
      workx/accounts/apps.py
  10. +7
    -0
      workx/accounts/form.py
  11. +28
    -0
      workx/accounts/migrations/0001_initial.py
  12. +72
    -0
      workx/accounts/migrations/0002_client_expense_income_project_reimbursement_and_more.py
  13. +0
    -0
      workx/accounts/migrations/__init__.py
  14. +76
    -0
      workx/accounts/models.py
  15. +19
    -0
      workx/accounts/serializers.py
  16. +3
    -0
      workx/accounts/tests.py
  17. +17
    -0
      workx/accounts/views.py
  18. +0
    -0
      workx/client/__init__.py
  19. +9
    -0
      workx/client/admin.py
  20. +6
    -0
      workx/client/apps.py
  21. +44
    -0
      workx/client/models.py
  22. +3
    -0
      workx/client/tests.py
  23. +4
    -0
      workx/client/views.py
  24. +0
    -0
      workx/common/__init__.py
  25. +8
    -0
      workx/common/admin.py
  26. +6
    -0
      workx/common/apps.py
  27. +48
    -0
      workx/common/migrations/0001_initial.py
  28. +0
    -0
      workx/common/migrations/__init__.py
  29. +34
    -0
      workx/common/models.py
  30. +14
    -0
      workx/common/serializers.py
  31. +3
    -0
      workx/common/tests.py
  32. +3
    -0
      workx/common/views.py
  33. +0
    -0
      workx/company/__init__.py
  34. +5
    -0
      workx/company/admin.py
  35. +6
    -0
      workx/company/apps.py
  36. +7
    -0
      workx/company/form.py
  37. +47
    -0
      workx/company/migrations/0001_initial.py
  38. +0
    -0
      workx/company/migrations/__init__.py
  39. +36
    -0
      workx/company/models.py
  40. +7
    -0
      workx/company/serializers.py
  41. +3
    -0
      workx/company/tests.py
  42. +26
    -0
      workx/company/views.py
  43. +0
    -0
      workx/employee/__init__.py
  44. +7
    -0
      workx/employee/admin.py
  45. +6
    -0
      workx/employee/apps.py
  46. +11
    -0
      workx/employee/forms.py
  47. +42
    -0
      workx/employee/migrations/0001_initial.py
  48. +21
    -0
      workx/employee/migrations/0002_alter_employee_user.py
  49. +0
    -0
      workx/employee/migrations/__init__.py
  50. +26
    -0
      workx/employee/models.py
  51. +45
    -0
      workx/employee/permissions.py
  52. +29
    -0
      workx/employee/serializers.py
  53. +3
    -0
      workx/employee/tests.py
  54. +27
    -0
      workx/employee/views.py
  55. +0
    -0
      workx/google_auth/__init__.py
  56. +3
    -0
      workx/google_auth/admin.py
  57. +6
    -0
      workx/google_auth/apps.py
  58. +0
    -0
      workx/google_auth/migrations/__init__.py
  59. +3
    -0
      workx/google_auth/models.py
  60. +3
    -0
      workx/google_auth/tests.py
  61. +9
    -0
      workx/google_auth/urls.py
  62. +34
    -0
      workx/google_auth/views.py
  63. +22
    -0
      workx/manage.py
  64. +12
    -0
      workx/templates/home.html
  65. +12
    -0
      workx/templates/login.html
  66. +0
    -0
      workx/workx/__init__.py
  67. +16
    -0
      workx/workx/asgi.py
  68. +147
    -0
      workx/workx/settings.py
  69. +39
    -0
      workx/workx/urls.py
  70. +16
    -0
      workx/workx/wsgi.py

+ 9
- 0
.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

+ 11
- 0
Pipfile Просмотреть файл

@@ -0,0 +1,11 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]

[dev-packages]

[requires]
python_version = "3.11"

+ 20
- 0
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": {}
}


+ 12
- 0
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"

+ 134
- 0
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": {}
}

+ 0
- 0
workx/accounts/__init__.py Просмотреть файл


+ 3
- 0
workx/accounts/admin.py Просмотреть файл

@@ -0,0 +1,3 @@
from django.contrib import admin

# Register your models here.

+ 6
- 0
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'

+ 7
- 0
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 = () #
kj прокомментировал 2 лет назад
Рецензия

Useless line, please remomve it.

Useless line, please remomve it.

+ 28
- 0
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)),
],
),
]

+ 72
- 0
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'),
),
]

+ 0
- 0
workx/accounts/migrations/__init__.py Просмотреть файл


+ 76
- 0
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
kj прокомментировал 2 лет назад
Рецензия

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 прокомментировал 2 лет назад
Рецензия

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.

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 прокомментировал 2 лет назад
Рецензия

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 прокомментировал 2 лет назад
Рецензия

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

+ 19
- 0
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__'

+ 3
- 0
workx/accounts/tests.py Просмотреть файл

@@ -0,0 +1,3 @@
from django.test import TestCase

# Create your tests here.

+ 17
- 0
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

+ 0
- 0
workx/client/__init__.py Просмотреть файл


+ 9
- 0
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)
kj прокомментировал 2 лет назад
Рецензия

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

+ 6
- 0
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'

+ 44
- 0
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()
kj прокомментировал 2 лет назад
Рецензия

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

+ 3
- 0
workx/client/tests.py Просмотреть файл

@@ -0,0 +1,3 @@
from django.test import TestCase

# Create your tests here.

+ 4
- 0
workx/client/views.py Просмотреть файл

@@ -0,0 +1,4 @@
from django.shortcuts import render

# Create your views here.


+ 0
- 0
workx/common/__init__.py Просмотреть файл


+ 8
- 0
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)
kj прокомментировал 2 лет назад
Рецензия

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

+ 6
- 0
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'

+ 48
- 0
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)),
],
),
]

+ 0
- 0
workx/common/migrations/__init__.py Просмотреть файл


+ 34
- 0
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)
kj прокомментировал 2 лет назад
Рецензия

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

+ 14
- 0
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__'

+ 3
- 0
workx/common/tests.py Просмотреть файл

@@ -0,0 +1,3 @@
from django.test import TestCase

# Create your tests here.
kj прокомментировал 2 лет назад
Рецензия

Remove the file if it’s not gonna be useful.

Remove the file if it's not gonna be useful.

+ 3
- 0
workx/common/views.py Просмотреть файл

@@ -0,0 +1,3 @@
from django.shortcuts import render

# Create your views here.

+ 0
- 0
workx/company/__init__.py Просмотреть файл


+ 5
- 0
workx/company/admin.py Просмотреть файл

@@ -0,0 +1,5 @@
from django.contrib import admin

from company.models import Company

admin.site.register(Company)

+ 6
- 0
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'

+ 7
- 0
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 = () #
kj прокомментировал 2 лет назад
Рецензия

Useless line

Useless line

+ 47
- 0
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',
},
),
]

+ 0
- 0
workx/company/migrations/__init__.py Просмотреть файл


+ 36
- 0
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




+ 7
- 0
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

+ 3
- 0
workx/company/tests.py Просмотреть файл

@@ -0,0 +1,3 @@
from django.test import TestCase

# Create your tests here.

+ 26
- 0
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]
kj прокомментировал 2 лет назад
Рецензия

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
workx/employee/__init__.py Просмотреть файл


+ 7
- 0
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)

+ 6
- 0
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'

+ 11
- 0
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(),
}

+ 42
- 0
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)),
],
),
]

+ 21
- 0
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),
),
]

+ 0
- 0
workx/employee/migrations/__init__.py Просмотреть файл


+ 26
- 0
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...
kj прокомментировал 2 лет назад
Рецензия

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 прокомментировал 2 лет назад
Рецензия

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

+ 45
- 0
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':
kj прокомментировал 2 лет назад
Рецензия

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

+ 29
- 0
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__'

+ 3
- 0
workx/employee/tests.py Просмотреть файл

@@ -0,0 +1,3 @@
from django.test import TestCase

# Create your tests here.

+ 27
- 0
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]




+ 0
- 0
workx/google_auth/__init__.py Просмотреть файл


+ 3
- 0
workx/google_auth/admin.py Просмотреть файл

@@ -0,0 +1,3 @@
from django.contrib import admin

# Register your models here.

+ 6
- 0
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'

+ 0
- 0
workx/google_auth/migrations/__init__.py Просмотреть файл


+ 3
- 0
workx/google_auth/models.py Просмотреть файл

@@ -0,0 +1,3 @@
from django.db import models

# Create your models here.

+ 3
- 0
workx/google_auth/tests.py Просмотреть файл

@@ -0,0 +1,3 @@
from django.test import TestCase

# Create your tests here.

+ 9
- 0
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'),
]

+ 34
- 0
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')

+ 22
- 0
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()

+ 12
- 0
workx/templates/home.html Просмотреть файл

@@ -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>

+ 12
- 0
workx/templates/login.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
workx/workx/__init__.py Просмотреть файл


+ 16
- 0
workx/workx/asgi.py Просмотреть файл

@@ -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()

+ 147
- 0
workx/workx/settings.py Просмотреть файл

@@ -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'

+ 39
- 0
workx/workx/urls.py Просмотреть файл

@@ -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')),
]


+ 16
- 0
workx/workx/wsgi.py Просмотреть файл

@@ -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()