#2 sprint-4

otevřený
paras chce sloučit 7 revizí z větve sprint-4 do 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 Zobrazit soubor

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

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

@@ -0,0 +1,20 @@
{
"_meta": {
"hash": {
"sha256": "ed6d5d614626ae28e274e453164affb26694755170ccab3aa5866f093d51d3e4"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.11"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {},
"develop": {}
}

+ 0
- 0
readme.md Zobrazit soubor


+ 12
- 0
workx/Pipfile Zobrazit soubor

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

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


+ 3
- 0
workx/accounts/admin.py Zobrazit soubor

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

# Register your models here.

+ 6
- 0
workx/accounts/apps.py Zobrazit soubor

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

@@ -0,0 +1,7 @@
from django import forms
from .models import Account

class AccountForm(forms.ModelForm):
class Meta:
model = Account
exclude = () #
kj okomentoval před 2 roky
Posouzení

Useless line, please remomve it.

Useless line, please remomve it.

+ 28
- 0
workx/accounts/migrations/0001_initial.py Zobrazit soubor

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

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


+ 76
- 0
workx/accounts/models.py Zobrazit soubor

@@ -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 okomentoval před 2 roky
Posouzení

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 okomentoval před 2 roky
Posouzení

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 okomentoval před 2 roky
Posouzení

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 okomentoval před 2 roky
Posouzení

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 Zobrazit soubor

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

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

# Create your tests here.

+ 17
- 0
workx/accounts/views.py Zobrazit soubor

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


+ 9
- 0
workx/client/admin.py Zobrazit soubor

@@ -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 okomentoval před 2 roky
Posouzení

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 Zobrazit soubor

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

@@ -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 okomentoval před 2 roky
Posouzení

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 Zobrazit soubor

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

# Create your tests here.

+ 4
- 0
workx/client/views.py Zobrazit soubor

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

# Create your views here.


+ 0
- 0
workx/common/__init__.py Zobrazit soubor


+ 8
- 0
workx/common/admin.py Zobrazit soubor

@@ -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 okomentoval před 2 roky
Posouzení

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 Zobrazit soubor

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

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


+ 34
- 0
workx/common/models.py Zobrazit soubor

@@ -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 okomentoval před 2 roky
Posouzení

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 Zobrazit soubor

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

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

# Create your tests here.
kj okomentoval před 2 roky
Posouzení

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 Zobrazit soubor

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

# Create your views here.

+ 0
- 0
workx/company/__init__.py Zobrazit soubor


+ 5
- 0
workx/company/admin.py Zobrazit soubor

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

from company.models import Company

admin.site.register(Company)

+ 6
- 0
workx/company/apps.py Zobrazit soubor

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

@@ -0,0 +1,7 @@
from django import forms
from .models import Company

class CompanyForm(forms.ModelForm):
class Meta:
model = Company
exclude = () #
kj okomentoval před 2 roky
Posouzení

Useless line

Useless line

+ 47
- 0
workx/company/migrations/0001_initial.py Zobrazit soubor

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


+ 36
- 0
workx/company/models.py Zobrazit soubor

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

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

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

# Create your tests here.

+ 26
- 0
workx/company/views.py Zobrazit soubor

@@ -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 okomentoval před 2 roky
Posouzení

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 Zobrazit soubor


+ 7
- 0
workx/employee/admin.py Zobrazit soubor

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

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

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

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

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


+ 26
- 0
workx/employee/models.py Zobrazit soubor

@@ -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 okomentoval před 2 roky
Posouzení

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 okomentoval před 2 roky
Posouzení

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 Zobrazit soubor

@@ -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 okomentoval před 2 roky
Posouzení

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 Zobrazit soubor

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

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

# Create your tests here.

+ 27
- 0
workx/employee/views.py Zobrazit soubor

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


+ 3
- 0
workx/google_auth/admin.py Zobrazit soubor

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

# Register your models here.

+ 6
- 0
workx/google_auth/apps.py Zobrazit soubor

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


+ 3
- 0
workx/google_auth/models.py Zobrazit soubor

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

# Create your models here.

+ 3
- 0
workx/google_auth/tests.py Zobrazit soubor

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

# Create your tests here.

+ 9
- 0
workx/google_auth/urls.py Zobrazit soubor

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

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

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

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

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


+ 16
- 0
workx/workx/asgi.py Zobrazit soubor

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

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

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

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