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