Compare commits
No commits in common. 'master' and 'main' have entirely different histories.
@ -1,41 +0,0 @@
|
|||||||
DB_USER="postgres"
|
|
||||||
DB_PASSWORD="admin"
|
|
||||||
DB_HOST="localhost"
|
|
||||||
DB_PORT=5432
|
|
||||||
DB_NAME="depot"
|
|
||||||
TEST_DB_NAME="depot_test"
|
|
||||||
|
|
||||||
SECRET_KEY='7b112605-9074-4195-98e9-7add8d57942d'
|
|
||||||
CONFIG_ENV='config.DevelopmentConfig'
|
|
||||||
|
|
||||||
JWT_EXPIRATION_DELTA=2
|
|
||||||
EPAY_SECURITY_KEY='VX6FIDVFI5MSP39UYMDWI47DX37T7H8ZT8AAC4UYS1IGCT9YFMJWJ98AH4YHJ3VY'
|
|
||||||
EPAY_CLIENT_ID='D056898459'
|
|
||||||
INVOICE_EXPIRE_PERIOD=3
|
|
||||||
|
|
||||||
OWNCLOUD_URL='https://cloud.kikimor.com'
|
|
||||||
OWNCLOUD_USER='kikimor'
|
|
||||||
OWNCLOUD_PASSWORD='ShuShunka1!'
|
|
||||||
OWNCLOUD_DAMAGES_FOLDER='damages/'
|
|
||||||
|
|
||||||
EMAIL_HOST="smtp.gmail.com"
|
|
||||||
EMAIL_PORT=587
|
|
||||||
EMAIL_HOST_USER="kikimor.eood@gmail.com"
|
|
||||||
EMAIL_HOST_PASSWORD="mjra fwsq iyaq yzai"
|
|
||||||
EMAIL_USE_TLS=True
|
|
||||||
|
|
||||||
ADMIN_USER_EMAIL="kikimor@gmail.com"
|
|
||||||
ADMIN_USER_NAME="kikimor"
|
|
||||||
ADMIN_USER_PASSWORD="shushunka1"
|
|
||||||
|
|
||||||
POSTGRES_USER=$DB_USER
|
|
||||||
POSTGRES_PASSWORD=$DB_PASSWORD
|
|
||||||
POSTGRES_DB=$DB_NAME
|
|
||||||
|
|
||||||
MINIO_ENDPOINT="localhost:9000"
|
|
||||||
MINIO_ACCESS_KEY="kikimor"
|
|
||||||
MINIO_SECRET_KEY="shushunka1"
|
|
||||||
MINIO_BUCKET_NAME="damages"
|
|
||||||
AWS_S3_CUSTOM_DOMAIN='localhost:9000' # For browser acce
|
|
||||||
AWS_S3_URL_PROTOCOL='http'
|
|
||||||
MINIO_SERVER_URL="http://localhost:9000"
|
|
||||||
@ -0,0 +1,162 @@
|
|||||||
|
# ---> Python
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
*.py,cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
cover/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
.pybuilder/
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
# For a library or package, you might want to ignore these files since the code is
|
||||||
|
# intended to run in multiple environments; otherwise, check them in:
|
||||||
|
# .python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
#Pipfile.lock
|
||||||
|
|
||||||
|
# poetry
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||||
|
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||||
|
# commonly ignored for libraries.
|
||||||
|
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||||
|
#poetry.lock
|
||||||
|
|
||||||
|
# pdm
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||||
|
#pdm.lock
|
||||||
|
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||||
|
# in version control.
|
||||||
|
# https://pdm.fming.dev/#use-with-ide
|
||||||
|
.pdm.toml
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||||
|
__pypackages__/
|
||||||
|
|
||||||
|
# Celery stuff
|
||||||
|
celerybeat-schedule
|
||||||
|
celerybeat.pid
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
||||||
|
# pytype static type analyzer
|
||||||
|
.pytype/
|
||||||
|
|
||||||
|
# Cython debug symbols
|
||||||
|
cython_debug/
|
||||||
|
|
||||||
|
# PyCharm
|
||||||
|
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||||
|
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||||
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
|
#.idea/
|
||||||
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module type="PYTHON_MODULE" version="4">
|
|
||||||
<component name="FacetManager">
|
|
||||||
<facet type="django" name="Django">
|
|
||||||
<configuration>
|
|
||||||
<option name="rootFolder" value="$MODULE_DIR$" />
|
|
||||||
<option name="settingsModule" value="DepoT/settings.py" />
|
|
||||||
<option name="manageScript" value="$MODULE_DIR$/manage.py" />
|
|
||||||
<option name="environment" value="<map/>" />
|
|
||||||
<option name="doNotUseTestRunner" value="false" />
|
|
||||||
<option name="trackFilePattern" value="migrations" />
|
|
||||||
</configuration>
|
|
||||||
</facet>
|
|
||||||
</component>
|
|
||||||
<component name="NewModuleRootManager">
|
|
||||||
<content url="file://$MODULE_DIR$">
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
|
||||||
</content>
|
|
||||||
<orderEntry type="jdk" jdkName="Python 3.13 (DepoT)" jdkType="Python SDK" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
</component>
|
|
||||||
<component name="TemplatesService">
|
|
||||||
<option name="TEMPLATE_CONFIGURATION" value="Django" />
|
|
||||||
<option name="TEMPLATE_FOLDERS">
|
|
||||||
<list>
|
|
||||||
<option value="$MODULE_DIR$/../DepoT\templates" />
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</module>
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
<component name="InspectionProjectProfileManager">
|
|
||||||
<profile version="1.0">
|
|
||||||
<option name="myName" value="Project Default" />
|
|
||||||
<inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
|
||||||
<option name="ignoredIdentifiers">
|
|
||||||
<list>
|
|
||||||
<option value="object.*" />
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
</inspection_tool>
|
|
||||||
</profile>
|
|
||||||
</component>
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
<component name="InspectionProjectProfileManager">
|
|
||||||
<settings>
|
|
||||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
|
||||||
<version value="1.0" />
|
|
||||||
</settings>
|
|
||||||
</component>
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="Black">
|
|
||||||
<option name="sdkName" value="Python 3.13 (DepoT)" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectModuleManager">
|
|
||||||
<modules>
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/DepoT.iml" filepath="$PROJECT_DIR$/.idea/DepoT.iml" />
|
|
||||||
</modules>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@ -1,314 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="AutoImportSettings">
|
|
||||||
<option name="autoReloadType" value="SELECTIVE" />
|
|
||||||
</component>
|
|
||||||
<component name="ChangeListManager">
|
|
||||||
<list default="true" id="7410a44d-51b9-408b-85ad-4fa46776b372" name="Changes" comment="commit unversioned files ;)">
|
|
||||||
<change afterPath="$PROJECT_DIR$/accounts/migrations/0001_initial.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/accounts/migrations/0002_clientpermission_codename_clientpermission_name.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/accounts/migrations/0003_remove_depotuser_is_company_admin_and_more.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/accounts/migrations/0004_employeepermission_depotuser_employee_permissions.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/accounts/migrations/0005_alter_depotuser_managers_alter_depotuser_user_type.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/accounts/migrations/0006_alter_clientpermission_options.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/accounts/migrations/0007_auto_20250725_1920.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/booking/migrations/0001_initial.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/booking/migrations/0002_rename_bookingmodel_booking.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/booking/migrations/0003_booking_container_expedited_count.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/booking/migrations/0004_booking_status.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/booking/migrations/0005_alter_booking_vehicles_left.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/booking/views/common.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/common/migrations/0001_initial.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/common/migrations/0002_alter_companymodel_short_name_and_more.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/common/migrations/0003_auto_20250725_1920.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/common/migrations/0005_companymodel_active_containerkindmodel_active_and_more.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/containers/migrations/0001_initial.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/containers/migrations/0002_rename_receive_vehicles_container_receive_vehicle.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/containers/migrations/0003_alter_container_booking.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/containers/migrations/0004_rename_line_id_container_line.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/containers/migrations/0005_alter_container_expedited_by_and_more.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/containers/migrations/0006_containerphotos.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/containers/migrations/0007_container_preinfo.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/damages_api/__init__.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/payments/migrations/0001_initial.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/payments/migrations/0002_additionalfees_containertariffperiod.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/payments/migrations/0003_auto_20250725_1920.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/payments/migrations/__init__.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/preinfo/migrations/0001_initial.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/preinfo/migrations/0002_alter_preinfomodel_deleted_by_and_more.py" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/preinfo/migrations/0003_rename_preinfomodel_preinfo.py" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
|
||||||
</list>
|
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
|
||||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
|
||||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
|
||||||
</component>
|
|
||||||
<component name="ChangesViewManager" show_ignored="true" />
|
|
||||||
<component name="DjangoConsoleOptions" custom-start-script="import sys; print('Python %s on %s' % (sys.version, sys.platform)) import django; print('Django %s' % django.get_version()) sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS]) if 'setup' in dir(django): django.setup() import django_manage_shell; django_manage_shell.run(PROJECT_ROOT)">
|
|
||||||
<option name="myCustomStartScript" value="import sys; print('Python %s on %s' % (sys.version, sys.platform)) import django; print('Django %s' % django.get_version()) sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS]) if 'setup' in dir(django): django.setup() import django_manage_shell; django_manage_shell.run(PROJECT_ROOT)" />
|
|
||||||
</component>
|
|
||||||
<component name="FileTemplateManagerImpl">
|
|
||||||
<option name="RECENT_TEMPLATES">
|
|
||||||
<list>
|
|
||||||
<option value="CSS File" />
|
|
||||||
<option value="JavaScript File" />
|
|
||||||
<option value="HTML File" />
|
|
||||||
<option value="Python Script" />
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
<component name="Git.Settings">
|
|
||||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
|
||||||
</component>
|
|
||||||
<component name="ProjectColorInfo">{
|
|
||||||
"associatedIndex": 6
|
|
||||||
}</component>
|
|
||||||
<component name="ProjectId" id="2yxmkOyUBM7hzsgEZWENDFkS6jw" />
|
|
||||||
<component name="ProjectViewState">
|
|
||||||
<option name="hideEmptyMiddlePackages" value="true" />
|
|
||||||
<option name="showLibraryContents" value="true" />
|
|
||||||
</component>
|
|
||||||
<component name="PropertiesComponent">{
|
|
||||||
"keyToString": {
|
|
||||||
"DefaultHtmlFileTemplate": "HTML File",
|
|
||||||
"Django Server.DepoT.executor": "Debug",
|
|
||||||
"RunOnceActivity.OpenDjangoStructureViewOnStart": "true",
|
|
||||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
|
||||||
"RunOnceActivity.git.unshallow": "true",
|
|
||||||
"RunOnceActivity.pycharm.django.structure.promotion.once.per.project": "true",
|
|
||||||
"django.template.preview.state": "SHOW_EDITOR_AND_PREVIEW",
|
|
||||||
"git-widget-placeholder": "master",
|
|
||||||
"ignore.virus.scanning.warn.message": "true",
|
|
||||||
"last_opened_file_path": "C:/dev_projects/python/Django/DepoT",
|
|
||||||
"list.type.of.created.stylesheet": "CSS",
|
|
||||||
"node.js.detected.package.eslint": "true",
|
|
||||||
"node.js.detected.package.tslint": "true",
|
|
||||||
"node.js.selected.package.eslint": "(autodetect)",
|
|
||||||
"node.js.selected.package.tslint": "(autodetect)",
|
|
||||||
"nodejs_package_manager_path": "npm",
|
|
||||||
"vue.rearranger.settings.migration": "true"
|
|
||||||
},
|
|
||||||
"keyToStringList": {
|
|
||||||
"DatabaseDriversLRU": [
|
|
||||||
"postgresql"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}</component>
|
|
||||||
<component name="RecentsManager">
|
|
||||||
<key name="CopyFile.RECENT_KEYS">
|
|
||||||
<recent name="C:\dev_projects\python\Django\DepoT" />
|
|
||||||
<recent name="C:\dev_projects\python\Django\DepoT\templates\employee" />
|
|
||||||
<recent name="C:\dev_projects\python\Django\DepoT\templates\client" />
|
|
||||||
<recent name="C:\dev_projects\python\Django\DepoT\templates" />
|
|
||||||
<recent name="C:\dev_projects\python\Django\DepoT\templates\registration" />
|
|
||||||
</key>
|
|
||||||
<key name="MoveFile.RECENT_KEYS">
|
|
||||||
<recent name="C:\dev_projects\python\Django\DepoT" />
|
|
||||||
<recent name="C:\dev_projects\python\Django\DepoT\templates\employee" />
|
|
||||||
<recent name="C:\dev_projects\python\Django\DepoT\templates\client" />
|
|
||||||
<recent name="C:\dev_projects\python\Django\DepoT\common\views" />
|
|
||||||
<recent name="C:\dev_projects\python\Django\DepoT\booking\views" />
|
|
||||||
</key>
|
|
||||||
</component>
|
|
||||||
<component name="RunManager">
|
|
||||||
<configuration name="DepoT" type="Python.DjangoServer" factoryName="Django server">
|
|
||||||
<module name="DepoT" />
|
|
||||||
<option name="ENV_FILES" value="" />
|
|
||||||
<option name="INTERPRETER_OPTIONS" value="" />
|
|
||||||
<option name="PARENT_ENVS" value="true" />
|
|
||||||
<envs>
|
|
||||||
<env name="PYTHONUNBUFFERED" value="1" />
|
|
||||||
<env name="DJANGO_SETTINGS_MODULE" value="DepoT.settings" />
|
|
||||||
</envs>
|
|
||||||
<option name="SDK_HOME" value="" />
|
|
||||||
<option name="WORKING_DIRECTORY" value="" />
|
|
||||||
<option name="IS_MODULE_SDK" value="false" />
|
|
||||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
|
||||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
|
||||||
<option name="launchJavascriptDebuger" value="false" />
|
|
||||||
<option name="port" value="8000" />
|
|
||||||
<option name="host" value="" />
|
|
||||||
<option name="additionalOptions" value="" />
|
|
||||||
<option name="browserUrl" value="" />
|
|
||||||
<option name="runTestServer" value="false" />
|
|
||||||
<option name="runNoReload" value="false" />
|
|
||||||
<option name="useCustomRunCommand" value="false" />
|
|
||||||
<option name="customRunCommand" value="" />
|
|
||||||
<method v="2" />
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
||||||
<component name="SharedIndexes">
|
|
||||||
<attachedChunks>
|
|
||||||
<set>
|
|
||||||
<option value="bundled-js-predefined-d6986cc7102b-09060db00ec0-JavaScript-PY-251.26927.74" />
|
|
||||||
<option value="bundled-python-sdk-657d8234b839-64d779b69b7a-com.jetbrains.pycharm.pro.sharedIndexes.bundled-PY-251.26927.74" />
|
|
||||||
</set>
|
|
||||||
</attachedChunks>
|
|
||||||
</component>
|
|
||||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
|
||||||
<component name="TaskManager">
|
|
||||||
<task active="true" id="Default" summary="Default task">
|
|
||||||
<changelist id="7410a44d-51b9-408b-85ad-4fa46776b372" name="Changes" comment="" />
|
|
||||||
<created>1750784740296</created>
|
|
||||||
<option name="number" value="Default" />
|
|
||||||
<option name="presentableId" value="Default" />
|
|
||||||
<updated>1750784740296</updated>
|
|
||||||
<workItem from="1750784741367" duration="240087000" />
|
|
||||||
<workItem from="1752078951079" duration="106000" />
|
|
||||||
<workItem from="1752079161329" duration="189445000" />
|
|
||||||
<workItem from="1753174764499" duration="271000" />
|
|
||||||
<workItem from="1753175068058" duration="4635000" />
|
|
||||||
<workItem from="1753179863298" duration="8357000" />
|
|
||||||
<workItem from="1753197869497" duration="98156000" />
|
|
||||||
<workItem from="1753637487803" duration="47474000" />
|
|
||||||
</task>
|
|
||||||
<task id="LOCAL-00001" summary="Add IntelliJ IDEA project configuration files This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA.">
|
|
||||||
<option name="closed" value="true" />
|
|
||||||
<created>1750855057151</created>
|
|
||||||
<option name="number" value="00001" />
|
|
||||||
<option name="presentableId" value="LOCAL-00001" />
|
|
||||||
<option name="project" value="LOCAL" />
|
|
||||||
<updated>1750855057151</updated>
|
|
||||||
</task>
|
|
||||||
<task id="LOCAL-00002" summary="Add IntelliJ IDEA project configuration files This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA.">
|
|
||||||
<option name="closed" value="true" />
|
|
||||||
<created>1750855273832</created>
|
|
||||||
<option name="number" value="00002" />
|
|
||||||
<option name="presentableId" value="LOCAL-00002" />
|
|
||||||
<option name="project" value="LOCAL" />
|
|
||||||
<updated>1750855273832</updated>
|
|
||||||
</task>
|
|
||||||
<task id="LOCAL-00003" summary="Add IntelliJ IDEA project configuration files This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA.">
|
|
||||||
<option name="closed" value="true" />
|
|
||||||
<created>1750942491703</created>
|
|
||||||
<option name="number" value="00003" />
|
|
||||||
<option name="presentableId" value="LOCAL-00003" />
|
|
||||||
<option name="project" value="LOCAL" />
|
|
||||||
<updated>1750942491703</updated>
|
|
||||||
</task>
|
|
||||||
<task id="LOCAL-00004" summary="Add IntelliJ IDEA project configuration files This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA.">
|
|
||||||
<option name="closed" value="true" />
|
|
||||||
<created>1750942543055</created>
|
|
||||||
<option name="number" value="00004" />
|
|
||||||
<option name="presentableId" value="LOCAL-00004" />
|
|
||||||
<option name="project" value="LOCAL" />
|
|
||||||
<updated>1750942543055</updated>
|
|
||||||
</task>
|
|
||||||
<task id="LOCAL-00005" summary="Add IntelliJ IDEA project configuration files This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA.">
|
|
||||||
<option name="closed" value="true" />
|
|
||||||
<created>1750942560128</created>
|
|
||||||
<option name="number" value="00005" />
|
|
||||||
<option name="presentableId" value="LOCAL-00005" />
|
|
||||||
<option name="project" value="LOCAL" />
|
|
||||||
<updated>1750942560128</updated>
|
|
||||||
</task>
|
|
||||||
<task id="LOCAL-00006" summary="Add IntelliJ IDEA project configuration files This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA.">
|
|
||||||
<option name="closed" value="true" />
|
|
||||||
<created>1751295996186</created>
|
|
||||||
<option name="number" value="00006" />
|
|
||||||
<option name="presentableId" value="LOCAL-00006" />
|
|
||||||
<option name="project" value="LOCAL" />
|
|
||||||
<updated>1751295996186</updated>
|
|
||||||
</task>
|
|
||||||
<task id="LOCAL-00007" summary="Add IntelliJ IDEA project configuration files This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA.">
|
|
||||||
<option name="closed" value="true" />
|
|
||||||
<created>1751359397230</created>
|
|
||||||
<option name="number" value="00007" />
|
|
||||||
<option name="presentableId" value="LOCAL-00007" />
|
|
||||||
<option name="project" value="LOCAL" />
|
|
||||||
<updated>1751359397230</updated>
|
|
||||||
</task>
|
|
||||||
<task id="LOCAL-00008" summary="Add IntelliJ IDEA project configuration files This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA.">
|
|
||||||
<option name="closed" value="true" />
|
|
||||||
<created>1751443902965</created>
|
|
||||||
<option name="number" value="00008" />
|
|
||||||
<option name="presentableId" value="LOCAL-00008" />
|
|
||||||
<option name="project" value="LOCAL" />
|
|
||||||
<updated>1751443902965</updated>
|
|
||||||
</task>
|
|
||||||
<task id="LOCAL-00009" summary="Add IntelliJ IDEA project configuration files This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA.">
|
|
||||||
<option name="closed" value="true" />
|
|
||||||
<created>1751557411675</created>
|
|
||||||
<option name="number" value="00009" />
|
|
||||||
<option name="presentableId" value="LOCAL-00009" />
|
|
||||||
<option name="project" value="LOCAL" />
|
|
||||||
<updated>1751557411675</updated>
|
|
||||||
</task>
|
|
||||||
<task id="LOCAL-00010" summary="commit unversioned files ;)">
|
|
||||||
<option name="closed" value="true" />
|
|
||||||
<created>1751618076902</created>
|
|
||||||
<option name="number" value="00010" />
|
|
||||||
<option name="presentableId" value="LOCAL-00010" />
|
|
||||||
<option name="project" value="LOCAL" />
|
|
||||||
<updated>1751618076902</updated>
|
|
||||||
</task>
|
|
||||||
<task id="LOCAL-00011" summary="commit unversioned files ;)">
|
|
||||||
<option name="closed" value="true" />
|
|
||||||
<created>1751877829547</created>
|
|
||||||
<option name="number" value="00011" />
|
|
||||||
<option name="presentableId" value="LOCAL-00011" />
|
|
||||||
<option name="project" value="LOCAL" />
|
|
||||||
<updated>1751877829547</updated>
|
|
||||||
</task>
|
|
||||||
<option name="localTasksCounter" value="12" />
|
|
||||||
<servers />
|
|
||||||
</component>
|
|
||||||
<component name="TypeScriptGeneratedFilesManager">
|
|
||||||
<option name="version" value="3" />
|
|
||||||
</component>
|
|
||||||
<component name="Vcs.Log.Tabs.Properties">
|
|
||||||
<option name="TAB_STATES">
|
|
||||||
<map>
|
|
||||||
<entry key="MAIN">
|
|
||||||
<value>
|
|
||||||
<State />
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
<component name="VcsManagerConfiguration">
|
|
||||||
<MESSAGE value="Add IntelliJ IDEA project configuration files This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA." />
|
|
||||||
<MESSAGE value="commit unversioned files ;)" />
|
|
||||||
<option name="LAST_COMMIT_MESSAGE" value="commit unversioned files ;)" />
|
|
||||||
</component>
|
|
||||||
<component name="XDebuggerManager">
|
|
||||||
<breakpoint-manager>
|
|
||||||
<breakpoints>
|
|
||||||
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
|
||||||
<url>file://$PROJECT_DIR$/DepoT/mixins/crudListViewMixin.py</url>
|
|
||||||
<line>7</line>
|
|
||||||
<option name="timeStamp" value="55" />
|
|
||||||
</line-breakpoint>
|
|
||||||
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
|
||||||
<url>file://$PROJECT_DIR$/common/views/client_views.py</url>
|
|
||||||
<line>118</line>
|
|
||||||
<option name="timeStamp" value="61" />
|
|
||||||
</line-breakpoint>
|
|
||||||
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
|
||||||
<url>file://$PROJECT_DIR$/payments/views.py</url>
|
|
||||||
<line>41</line>
|
|
||||||
<option name="timeStamp" value="98" />
|
|
||||||
</line-breakpoint>
|
|
||||||
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
|
||||||
<url>file://$PROJECT_DIR$/payments/views.py</url>
|
|
||||||
<line>56</line>
|
|
||||||
<option name="timeStamp" value="99" />
|
|
||||||
</line-breakpoint>
|
|
||||||
<line-breakpoint enabled="true" type="javascript">
|
|
||||||
<url>file://$PROJECT_DIR$/static/js/container_validation.js</url>
|
|
||||||
<line>4</line>
|
|
||||||
<option name="timeStamp" value="95" />
|
|
||||||
</line-breakpoint>
|
|
||||||
</breakpoints>
|
|
||||||
<default-breakpoints>
|
|
||||||
<breakpoint type="python-exception">
|
|
||||||
<properties notifyOnTerminate="true" exception="BaseException">
|
|
||||||
<option name="notifyOnTerminate" value="true" />
|
|
||||||
</properties>
|
|
||||||
</breakpoint>
|
|
||||||
</default-breakpoints>
|
|
||||||
</breakpoint-manager>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
"""
|
|
||||||
ASGI config for DepoT 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/5.2/howto/deployment/asgi/
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
from django.core.asgi import get_asgi_application
|
|
||||||
|
|
||||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "DepoT.settings")
|
|
||||||
|
|
||||||
application = get_asgi_application()
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
from common.models import LinesModel
|
|
||||||
|
|
||||||
|
|
||||||
class LineFilterFormMixin:
|
|
||||||
def get_form(self, form_class=None):
|
|
||||||
form = super().get_form(form_class)
|
|
||||||
user = self.request.user
|
|
||||||
if user.line:
|
|
||||||
form.fields['line'].queryset = form.fields['line'].queryset.filter(pk=user.line.pk)
|
|
||||||
form.fields['line'].initial = user.line
|
|
||||||
form.fields['line'].widget.attrs['readonly'] = True
|
|
||||||
else:
|
|
||||||
form.fields['line'].queryset = LinesModel.objects.filter(company=user.company)
|
|
||||||
form.fields['line'].widget.attrs['readonly'] = False
|
|
||||||
return form
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
from django.http import JsonResponse
|
|
||||||
from django.shortcuts import get_object_or_404
|
|
||||||
|
|
||||||
|
|
||||||
class CRUDListViewMixin:
|
|
||||||
...
|
|
||||||
# def post(self, request, *args, **kwargs):
|
|
||||||
# if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
|
|
||||||
# object_id = request.POST.get('object_id')
|
|
||||||
# obj = get_object_or_404(self.model, id=object_id)
|
|
||||||
# return JsonResponse(self.get_object_data(obj))
|
|
||||||
# else:
|
|
||||||
# return self.handle_form_submission(request, *args, **kwargs)
|
|
||||||
|
|
||||||
# def get_object_data(self, obj):
|
|
||||||
# """Override this method in child views to specify which data to return"""
|
|
||||||
# raise NotImplementedError
|
|
||||||
#
|
|
||||||
# def handle_form_submission(self, request, *args, **kwargs):
|
|
||||||
# """Override this method in child views to handle form submission"""
|
|
||||||
# raise NotImplementedError
|
|
||||||
@ -1,188 +0,0 @@
|
|||||||
"""
|
|
||||||
Django settings for DepoT project.
|
|
||||||
|
|
||||||
Generated by 'django-admin startproject' using Django 5.2.3.
|
|
||||||
|
|
||||||
For more information on this file, see
|
|
||||||
https://docs.djangoproject.com/en/5.2/topics/settings/
|
|
||||||
|
|
||||||
For the full list of settings and their values, see
|
|
||||||
https://docs.djangoproject.com/en/5.2/ref/settings/
|
|
||||||
"""
|
|
||||||
|
|
||||||
from pathlib import Path
|
|
||||||
import os
|
|
||||||
import environ
|
|
||||||
|
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
|
||||||
|
|
||||||
env = environ.Env()
|
|
||||||
environ.Env.read_env(os.path.join(BASE_DIR, '.env'))
|
|
||||||
|
|
||||||
SECRET_KEY = "django-insecure-g%187p84o9^rr)3#9@r3n^o2v1i%@6=+puxm7hlodg+kbsk%n#"
|
|
||||||
|
|
||||||
DEBUG = True
|
|
||||||
|
|
||||||
ALLOWED_HOSTS = ['192.168.24.43', '127.0.0.1', 'localhost', ]
|
|
||||||
|
|
||||||
|
|
||||||
PROJECT_APPS = [
|
|
||||||
'accounts',
|
|
||||||
"booking",
|
|
||||||
"common",
|
|
||||||
"containers",
|
|
||||||
'preinfo',
|
|
||||||
'payments',
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
INSTALLED_APPS = [
|
|
||||||
"django.contrib.admin",
|
|
||||||
"django.contrib.auth",
|
|
||||||
"django.contrib.contenttypes",
|
|
||||||
"django.contrib.sessions",
|
|
||||||
"django.contrib.messages",
|
|
||||||
"django.contrib.staticfiles",
|
|
||||||
"rest_framework",
|
|
||||||
"damages_api",
|
|
||||||
] + PROJECT_APPS
|
|
||||||
|
|
||||||
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 = "DepoT.urls"
|
|
||||||
|
|
||||||
TEMPLATES = [
|
|
||||||
{
|
|
||||||
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
|
||||||
"DIRS": [BASE_DIR / 'templates']
|
|
||||||
,
|
|
||||||
"APP_DIRS": True,
|
|
||||||
"OPTIONS": {
|
|
||||||
"context_processors": [
|
|
||||||
"django.template.context_processors.request",
|
|
||||||
"django.contrib.auth.context_processors.auth",
|
|
||||||
"django.contrib.messages.context_processors.messages",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
WSGI_APPLICATION = "DepoT.wsgi.application"
|
|
||||||
|
|
||||||
|
|
||||||
# Database
|
|
||||||
# https://docs.djangoproject.com/en/5.2/ref/settings/#databases
|
|
||||||
|
|
||||||
# DATABASES = {
|
|
||||||
# "default": {
|
|
||||||
# "ENGINE": "django.db.backends.sqlite3",
|
|
||||||
# "NAME": BASE_DIR / "db.sqlite3",
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
|
|
||||||
DATABASES = {
|
|
||||||
"default": {
|
|
||||||
"ENGINE": "django.db.backends.postgresql",
|
|
||||||
"NAME": env("DB_NAME"),
|
|
||||||
"USER": env("DB_USER"),
|
|
||||||
"PASSWORD": env("DB_PASSWORD"),
|
|
||||||
"HOST": env("DB_HOST"),
|
|
||||||
"PORT": env("DB_PORT"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
# Password validation
|
|
||||||
# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators
|
|
||||||
|
|
||||||
AUTH_USER_MODEL = 'accounts.DepotUser'
|
|
||||||
|
|
||||||
LOGIN_URL = '/user/login/'
|
|
||||||
|
|
||||||
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",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
AUTHENTICATION_BACKENDS = [
|
|
||||||
'django.contrib.auth.backends.ModelBackend',
|
|
||||||
]
|
|
||||||
|
|
||||||
# Internationalization
|
|
||||||
# https://docs.djangoproject.com/en/5.2/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/5.2/howto/static-files/
|
|
||||||
|
|
||||||
STATIC_URL = "static/"
|
|
||||||
|
|
||||||
STATICFILES_DIRS = [
|
|
||||||
BASE_DIR / 'static'
|
|
||||||
]
|
|
||||||
|
|
||||||
TEMP_FILE_FOLDER = "/tmp/damages_photos"
|
|
||||||
# Default primary key field type
|
|
||||||
# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field
|
|
||||||
|
|
||||||
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
|
||||||
|
|
||||||
|
|
||||||
OWNCLOUD_URL = env('OWNCLOUD_URL')
|
|
||||||
OWNCLOUD_USER = env('OWNCLOUD_USER')
|
|
||||||
OWNCLOUD_PASSWORD = env('OWNCLOUD_PASSWORD')
|
|
||||||
OWNCLOUD_DAMAGES_FOLDER = env('OWNCLOUD_DAMAGES_FOLDER')
|
|
||||||
|
|
||||||
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
|
||||||
EMAIL_HOST = env("EMAIL_HOST", cast=str, default=None)
|
|
||||||
EMAIL_PORT = env("EMAIL_PORT", cast=str, default='587') # Recommended
|
|
||||||
EMAIL_HOST_USER = env("EMAIL_HOST_USER", cast=str, default=None)
|
|
||||||
EMAIL_HOST_PASSWORD = env("EMAIL_HOST_PASSWORD", cast=str, default=None)
|
|
||||||
EMAIL_USE_TLS = env("EMAIL_USE_TLS", cast=bool, default=True) # Use EMAIL_PORT 587 for TLS
|
|
||||||
EMAIL_USE_SSL = env("EMAIL_USE_SSL", cast=bool, default=False) # EUse MAIL_PORT 465 for SSL
|
|
||||||
|
|
||||||
ADMIN_USER_NAME=env("ADMIN_USER_NAME")
|
|
||||||
ADMIN_USER_PASSWORD=env("ADMIN_USER_PASSWORD")
|
|
||||||
ADMIN_USER_EMAIL=env("ADMIN_USER_EMAIL")
|
|
||||||
|
|
||||||
MANAGERS=[]
|
|
||||||
ADMINS=[]
|
|
||||||
if all([ADMIN_USER_NAME, ADMIN_USER_EMAIL]):
|
|
||||||
ADMINS +=[
|
|
||||||
(f'{ADMIN_USER_NAME}', f'{ADMIN_USER_EMAIL}')
|
|
||||||
]
|
|
||||||
MANAGERS=ADMINS
|
|
||||||
|
|
||||||
|
|
||||||
MINIO_ENDPOINT = env('MINIO_ENDPOINT')
|
|
||||||
AWS_S3_CUSTOM_DOMAIN = env('AWS_S3_CUSTOM_DOMAIN')
|
|
||||||
MINIO_SERVER_URL = env('MINIO_SERVER_URL')
|
|
||||||
AWS_S3_URL_PROTOCOL = env('AWS_S3_URL_PROTOCOL')
|
|
||||||
MINIO_ACCESS_KEY = env('MINIO_ACCESS_KEY')
|
|
||||||
MINIO_SECRET_KEY = env('MINIO_SECRET_KEY')
|
|
||||||
MINIO_BUCKET_NAME = env('MINIO_BUCKET_NAME')
|
|
||||||
MINIO_SECURE = False # Set to True if using HTTPS
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
"""
|
|
||||||
URL configuration for DepoT project.
|
|
||||||
|
|
||||||
The `urlpatterns` list routes URLs to views. For more information please see:
|
|
||||||
https://docs.djangoproject.com/en/5.2/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.contrib import admin
|
|
||||||
from django.urls import path, include
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path("admin/", admin.site.urls),
|
|
||||||
path('', include('common.urls')),
|
|
||||||
path('user/', include('accounts.urls')),
|
|
||||||
path('preinfo/', include('preinfo.urls')),
|
|
||||||
path('container/', include('containers.urls')),
|
|
||||||
path('booking/', include('booking.urls')),
|
|
||||||
path('payment/', include('payments.urls')),
|
|
||||||
path('api/damages/', include('damages_api.urls')),
|
|
||||||
path('api/common/', include('common_api.urls')),
|
|
||||||
]
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
"""
|
|
||||||
WSGI config for DepoT 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/5.2/howto/deployment/wsgi/
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
from django.core.wsgi import get_wsgi_application
|
|
||||||
|
|
||||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "DepoT.settings")
|
|
||||||
|
|
||||||
application = get_wsgi_application()
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
from django.contrib import admin
|
|
||||||
from django.contrib.auth.admin import UserAdmin
|
|
||||||
from .models import DepotUser
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(DepotUser)
|
|
||||||
class DepotUserAdmin(UserAdmin):
|
|
||||||
# Add your custom fields to the fieldsets
|
|
||||||
fieldsets = UserAdmin.fieldsets + (
|
|
||||||
('Additional Info', {'fields': (
|
|
||||||
'phone_number',
|
|
||||||
'company',
|
|
||||||
'line',
|
|
||||||
'company_permissions',
|
|
||||||
'user_type',
|
|
||||||
)}),
|
|
||||||
)
|
|
||||||
|
|
||||||
# Add fields to display in list view
|
|
||||||
list_display = ('username', 'email', 'user_type', 'company', 'line', 'is_active', 'is_staff', 'is_superuser')
|
|
||||||
search_fields = ('username', 'email')
|
|
||||||
list_filter = ('user_type', 'is_active', 'is_staff', 'is_superuser')
|
|
||||||
|
|
||||||
# Add fields to the add form
|
|
||||||
add_fieldsets = UserAdmin.add_fieldsets + (
|
|
||||||
('Additional Info', {'fields': (
|
|
||||||
'email',
|
|
||||||
'phone_number',
|
|
||||||
'company',
|
|
||||||
'line',
|
|
||||||
'company_permissions',
|
|
||||||
'user_type',
|
|
||||||
)}),
|
|
||||||
)
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class UsersConfig(AppConfig):
|
|
||||||
default_auto_field = "django.db.models.BigAutoField"
|
|
||||||
name = "accounts"
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
from django.contrib.auth.backends import ModelBackend
|
|
||||||
|
|
||||||
|
|
||||||
class CompanyUserBackend(ModelBackend):
|
|
||||||
def get_user_permissions(self, user_obj, obj=None):
|
|
||||||
if not user_obj.is_active or user_obj.is_anonymous:
|
|
||||||
return set()
|
|
||||||
|
|
||||||
if user_obj.is_superuser:
|
|
||||||
return super().get_user_permissions(user_obj, obj)
|
|
||||||
|
|
||||||
perms = super().get_user_permissions(user_obj, obj)
|
|
||||||
if user_obj.company and user_obj.company.is_client:
|
|
||||||
# Filter permissions based on client company context
|
|
||||||
perms = {p for p in perms if p.startswith('accounts.client_')}
|
|
||||||
return perms
|
|
||||||
@ -1,96 +0,0 @@
|
|||||||
from django.contrib.auth import get_user_model
|
|
||||||
from django.contrib.auth.forms import AuthenticationForm
|
|
||||||
from django.contrib.auth.views import PasswordChangeView
|
|
||||||
from django.core.exceptions import ValidationError
|
|
||||||
from django.forms import CharField
|
|
||||||
from django.forms.models import ModelForm
|
|
||||||
from django.forms.widgets import PasswordInput
|
|
||||||
|
|
||||||
|
|
||||||
class LoginForm(AuthenticationForm):
|
|
||||||
field_order = ['username', 'password']
|
|
||||||
class Meta:
|
|
||||||
model = get_user_model()
|
|
||||||
|
|
||||||
|
|
||||||
class RegisterForm(ModelForm):
|
|
||||||
password1 = CharField(label='Password', widget=PasswordInput)
|
|
||||||
password2 = CharField(label='Confirm Password', widget=PasswordInput)
|
|
||||||
|
|
||||||
field_order = ['username', 'email', 'password1', 'password2', 'phone_number', 'company', 'line', 'user_type', 'company_permissions', 'employee_permissions', 'is_active']
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = get_user_model()
|
|
||||||
fields = ['username', 'email', 'password1', 'password2', 'phone_number', 'company', 'line', 'user_type', 'company_permissions', 'employee_permissions', 'is_active']
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
self.fields['password1'].widget.attrs.update({'autocomplete': 'new-password'})
|
|
||||||
self.fields['password2'].widget.attrs.update({'autocomplete': 'new-password'})
|
|
||||||
self.fields['user_type'].widget.attrs['readonly'] = True
|
|
||||||
self.fields['company_permissions'].widget.attrs['disabled'] = True
|
|
||||||
self.fields['employee_permissions'].widget.attrs['disabled'] = True
|
|
||||||
|
|
||||||
if self.data.get('user_type') in ( 'EM', 'BS'):
|
|
||||||
self.fields['company_permissions'].required = False
|
|
||||||
if self.data.get('user_type') in ('CL', 'CA', 'BS'):
|
|
||||||
self.fields['company_permissions'].required = False
|
|
||||||
|
|
||||||
def clean(self):
|
|
||||||
cleaned_data = super().clean()
|
|
||||||
password1 = cleaned_data.get('password1')
|
|
||||||
password2 = cleaned_data.get('password2')
|
|
||||||
|
|
||||||
if password1 and password2 and password1 != password2:
|
|
||||||
raise ValidationError("Passwords don't match")
|
|
||||||
return cleaned_data
|
|
||||||
|
|
||||||
def save(self, commit=True):
|
|
||||||
user = super().save(commit=False)
|
|
||||||
user.set_password(self.cleaned_data['password1'])
|
|
||||||
if commit:
|
|
||||||
user.save()
|
|
||||||
return user
|
|
||||||
|
|
||||||
class UserEditForm(ModelForm):
|
|
||||||
password1 = CharField(required=False, label='Password', widget=PasswordInput)
|
|
||||||
password2 = CharField(required=False, label='Confirm Password', widget=PasswordInput)
|
|
||||||
|
|
||||||
field_order = ['username', 'email', 'password1', 'password2', 'phone_number', 'company', 'line', 'user_type', 'company_permissions', 'employee_permissions', 'is_active']
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = get_user_model()
|
|
||||||
fields = ['username', 'email', 'password1', 'password2', 'phone_number', 'company', 'line', 'user_type', 'company_permissions', 'employee_permissions', 'is_active']
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
self.fields['user_type'].widget.attrs['readonly'] = True
|
|
||||||
self.fields['company_permissions'].widget.attrs['disabled'] = True
|
|
||||||
self.fields['employee_permissions'].widget.attrs['disabled'] = True
|
|
||||||
|
|
||||||
if self.data.get('user_type') in ( 'EM', 'BS'):
|
|
||||||
self.fields['company_permissions'].required = False
|
|
||||||
if self.data.get('user_type') in ('CL', 'CA', 'BS'):
|
|
||||||
self.fields['company_permissions'].required = False
|
|
||||||
|
|
||||||
def clean(self):
|
|
||||||
cleaned_data = super().clean()
|
|
||||||
password1 = cleaned_data.get('password1')
|
|
||||||
password2 = cleaned_data.get('password2')
|
|
||||||
|
|
||||||
if password1 and password2 and password1 != password2:
|
|
||||||
raise ValidationError("Passwords don't match")
|
|
||||||
return cleaned_data
|
|
||||||
|
|
||||||
def save(self, commit=True):
|
|
||||||
user = super().save(commit=False)
|
|
||||||
user.set_password(self.cleaned_data['password1'])
|
|
||||||
if commit:
|
|
||||||
user.save()
|
|
||||||
return user
|
|
||||||
|
|
||||||
|
|
||||||
class UserChangePasswordForm(PasswordChangeView):
|
|
||||||
old_password = CharField(widget=PasswordInput())
|
|
||||||
new_password = CharField(widget=PasswordInput())
|
|
||||||
confirm_password = CharField(widget=PasswordInput())
|
|
||||||
@ -1,182 +0,0 @@
|
|||||||
# Generated by Django 5.2.3 on 2025-06-27 11:42
|
|
||||||
|
|
||||||
import django.contrib.auth.models
|
|
||||||
import django.contrib.auth.validators
|
|
||||||
import django.db.models.deletion
|
|
||||||
import django.utils.timezone
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("auth", "0012_alter_user_first_name_max_length"),
|
|
||||||
("common", "0001_initial"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name="ClientPermission",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"id",
|
|
||||||
models.BigAutoField(
|
|
||||||
auto_created=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
verbose_name="ID",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
"permissions": (
|
|
||||||
("can_book_container", "Can book container"),
|
|
||||||
("can_view_bookings", "Can view bookings"),
|
|
||||||
("can_manage_company_users", "Can manage company users"),
|
|
||||||
),
|
|
||||||
"managed": True,
|
|
||||||
"default_permissions": (),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name="DepotUser",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"id",
|
|
||||||
models.BigAutoField(
|
|
||||||
auto_created=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
verbose_name="ID",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("password", models.CharField(max_length=128, verbose_name="password")),
|
|
||||||
(
|
|
||||||
"last_login",
|
|
||||||
models.DateTimeField(
|
|
||||||
blank=True, null=True, verbose_name="last login"
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"is_superuser",
|
|
||||||
models.BooleanField(
|
|
||||||
default=False,
|
|
||||||
help_text="Designates that this user has all permissions without explicitly assigning them.",
|
|
||||||
verbose_name="superuser status",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"username",
|
|
||||||
models.CharField(
|
|
||||||
error_messages={
|
|
||||||
"unique": "A user with that username already exists."
|
|
||||||
},
|
|
||||||
help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.",
|
|
||||||
max_length=150,
|
|
||||||
unique=True,
|
|
||||||
validators=[
|
|
||||||
django.contrib.auth.validators.UnicodeUsernameValidator()
|
|
||||||
],
|
|
||||||
verbose_name="username",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"first_name",
|
|
||||||
models.CharField(
|
|
||||||
blank=True, max_length=150, verbose_name="first name"
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"last_name",
|
|
||||||
models.CharField(
|
|
||||||
blank=True, max_length=150, verbose_name="last name"
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"is_staff",
|
|
||||||
models.BooleanField(
|
|
||||||
default=False,
|
|
||||||
help_text="Designates whether the user can log into this admin site.",
|
|
||||||
verbose_name="staff status",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"is_active",
|
|
||||||
models.BooleanField(
|
|
||||||
default=True,
|
|
||||||
help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",
|
|
||||||
verbose_name="active",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"date_joined",
|
|
||||||
models.DateTimeField(
|
|
||||||
default=django.utils.timezone.now, verbose_name="date joined"
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"phone_number",
|
|
||||||
models.CharField(blank=True, max_length=15, null=True),
|
|
||||||
),
|
|
||||||
("email", models.EmailField(max_length=254, unique=True)),
|
|
||||||
("new_field1", models.BooleanField(default=False)),
|
|
||||||
("is_company_admin", models.BooleanField(default=False)),
|
|
||||||
(
|
|
||||||
"company",
|
|
||||||
models.ForeignKey(
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="user_lines",
|
|
||||||
to="common.companymodel",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"groups",
|
|
||||||
models.ManyToManyField(
|
|
||||||
blank=True,
|
|
||||||
help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.",
|
|
||||||
related_name="user_set",
|
|
||||||
related_query_name="user",
|
|
||||||
to="auth.group",
|
|
||||||
verbose_name="groups",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"line",
|
|
||||||
models.ForeignKey(
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="user_lines",
|
|
||||||
to="common.linesmodel",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"user_permissions",
|
|
||||||
models.ManyToManyField(
|
|
||||||
blank=True,
|
|
||||||
help_text="Specific permissions for this user.",
|
|
||||||
related_name="user_set",
|
|
||||||
related_query_name="user",
|
|
||||||
to="auth.permission",
|
|
||||||
verbose_name="user permissions",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"company_permissions",
|
|
||||||
models.ManyToManyField(to="accounts.clientpermission"),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
"verbose_name": "user",
|
|
||||||
"verbose_name_plural": "users",
|
|
||||||
"abstract": False,
|
|
||||||
},
|
|
||||||
managers=[
|
|
||||||
("objects", django.contrib.auth.models.UserManager()),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
# Generated by Django 5.2.3 on 2025-07-02 08:02
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("accounts", "0001_initial"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name="clientpermission",
|
|
||||||
name="codename",
|
|
||||||
field=models.CharField(default="", max_length=100),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name="clientpermission",
|
|
||||||
name="name",
|
|
||||||
field=models.CharField(default="", max_length=255),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
# Generated by Django 5.2.3 on 2025-07-02 12:04
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("accounts", "0002_clientpermission_codename_clientpermission_name"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name="depotuser",
|
|
||||||
name="is_company_admin",
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name="depotuser",
|
|
||||||
name="new_field1",
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name="depotuser",
|
|
||||||
name="user_type",
|
|
||||||
field=models.CharField(
|
|
||||||
choices=[
|
|
||||||
("BS", "Barrier Staff"),
|
|
||||||
("CA", "Company Admin"),
|
|
||||||
("EM", "Employee"),
|
|
||||||
("CL", "Client"),
|
|
||||||
],
|
|
||||||
default="CL",
|
|
||||||
max_length=2,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,43 +0,0 @@
|
|||||||
# Generated by Django 5.2.3 on 2025-07-03 08:11
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("accounts", "0003_remove_depotuser_is_company_admin_and_more"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name="EmployeePermission",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"id",
|
|
||||||
models.BigAutoField(
|
|
||||||
auto_created=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
verbose_name="ID",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("codename", models.CharField(default="", max_length=100)),
|
|
||||||
("name", models.CharField(default="", max_length=255)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
"permissions": (
|
|
||||||
("can_manage_containers", "Can manage containers"),
|
|
||||||
("can_view_reports", "Can view reports"),
|
|
||||||
("can_handle_operations", "Can handle operations"),
|
|
||||||
),
|
|
||||||
"managed": True,
|
|
||||||
"default_permissions": (),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name="depotuser",
|
|
||||||
name="employee_permissions",
|
|
||||||
field=models.ManyToManyField(blank=True, to="accounts.employeepermission"),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
# Generated by Django 5.2.3 on 2025-07-03 14:17
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("accounts", "0004_employeepermission_depotuser_employee_permissions"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterModelManagers(
|
|
||||||
name="depotuser",
|
|
||||||
managers=[],
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="depotuser",
|
|
||||||
name="user_type",
|
|
||||||
field=models.CharField(
|
|
||||||
choices=[
|
|
||||||
("BS", "Barrier Staff"),
|
|
||||||
("CA", "Company Admin"),
|
|
||||||
("EM", "Employee"),
|
|
||||||
("CL", "Client"),
|
|
||||||
("AD", "Admin"),
|
|
||||||
],
|
|
||||||
default="CL",
|
|
||||||
max_length=2,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
# Generated by Django 5.2.3 on 2025-07-09 12:51
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("accounts", "0005_alter_depotuser_managers_alter_depotuser_user_type"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterModelOptions(
|
|
||||||
name="clientpermission",
|
|
||||||
options={
|
|
||||||
"default_permissions": (),
|
|
||||||
"managed": True,
|
|
||||||
"permissions": (
|
|
||||||
("can_view_booking", "Can view booking"),
|
|
||||||
("can_manage_booking", "Can book container"),
|
|
||||||
("can_view_preinfo", "Can view preinfo"),
|
|
||||||
("can_manage_preinfo", "Can manage preinfo"),
|
|
||||||
("can_view_payment", "Can view payment"),
|
|
||||||
("can_manage_payment", "Can manage payment"),
|
|
||||||
("can_manage_company_users", "Can manage company users"),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
# Generated by Django 5.2.3 on 2025-07-25 16:20
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("accounts", "0006_alter_clientpermission_options"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = []
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
def create_permissions(apps, schema_editor):
|
|
||||||
EmployeePermission = apps.get_model('accounts', 'EmployeePermission')
|
|
||||||
ClientPermission = apps.get_model('accounts', 'ClientPermission')
|
|
||||||
|
|
||||||
employee_permissions = [
|
|
||||||
(1, 'can_manage_containers', 'Can manage containers'),
|
|
||||||
(2, 'can_view_reports', 'Can view reports'),
|
|
||||||
(3, 'can_handle_operations', 'Can handle operations'),
|
|
||||||
]
|
|
||||||
for _id, codename, name in employee_permissions:
|
|
||||||
EmployeePermission.objects.create(id=_id, codename=codename, name=name)
|
|
||||||
|
|
||||||
client_permissions = [
|
|
||||||
(1, 'can_view_booking', 'Can view booking'),
|
|
||||||
(2, 'can_manage_booking', 'Can book container'),
|
|
||||||
(3, 'can_view_preinfo', 'Can view preinfo'),
|
|
||||||
(4, 'can_manage_preinfo', 'Can manage preinfo'),
|
|
||||||
(5, 'can_view_payment', 'Can view payment'),
|
|
||||||
(6, 'can_manage_payment', 'Can manage payment'),
|
|
||||||
(7, 'can_manage_company_users', 'Can manage company users'),
|
|
||||||
]
|
|
||||||
for _id, codename, name in client_permissions:
|
|
||||||
ClientPermission.objects.create(id=_id, codename=codename, name=name)
|
|
||||||
|
|
||||||
|
|
||||||
def reverse_permissions(apps, schema_editor):
|
|
||||||
EmployeePermission = apps.get_model('accounts', 'EmployeePermission')
|
|
||||||
ClientPermission = apps.get_model('accounts', 'ClientPermission')
|
|
||||||
|
|
||||||
EmployeePermission.objects.all().delete()
|
|
||||||
ClientPermission.objects.all().delete()
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
dependencies = [
|
|
||||||
('accounts', '0007_auto_20250725_1920'), # Adjust this to your last migration
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RunPython(create_permissions, reverse_permissions),
|
|
||||||
]
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
from django.db import migrations
|
|
||||||
from django.conf import settings
|
|
||||||
from django.contrib.auth.hashers import make_password
|
|
||||||
|
|
||||||
def create_superuser(apps, schema_editor):
|
|
||||||
User = apps.get_model('accounts', 'DepotUser')
|
|
||||||
if not User.objects.filter(email=settings.ADMIN_USER_EMAIL).exists():
|
|
||||||
user = User.objects.create(
|
|
||||||
email=settings.ADMIN_USER_EMAIL,
|
|
||||||
username=settings.ADMIN_USER_NAME,
|
|
||||||
is_staff=True,
|
|
||||||
is_superuser=True,
|
|
||||||
is_active=True,
|
|
||||||
user_type='AD',
|
|
||||||
password=make_password(settings.ADMIN_USER_PASSWORD)
|
|
||||||
)
|
|
||||||
|
|
||||||
def reverse_superuser(apps, schema_editor):
|
|
||||||
User = apps.get_model('accounts', 'DepotUser')
|
|
||||||
User.objects.filter(email=settings.ADMIN_USER_EMAIL).delete()
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
dependencies = [
|
|
||||||
('accounts', '0008_populate_permissions'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RunPython(create_superuser, reverse_superuser),
|
|
||||||
]
|
|
||||||
@ -1,115 +0,0 @@
|
|||||||
from django.contrib.auth.base_user import BaseUserManager
|
|
||||||
from django.contrib.auth.models import AbstractUser
|
|
||||||
from django.db import models
|
|
||||||
|
|
||||||
class ClientPermission(models.Model):
|
|
||||||
codename = models.CharField(max_length=100, default='')
|
|
||||||
name = models.CharField(max_length=255, default='')
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
managed = True
|
|
||||||
default_permissions = ()
|
|
||||||
permissions = (
|
|
||||||
('can_view_booking', 'Can view booking'),
|
|
||||||
('can_manage_booking', 'Can book container'),
|
|
||||||
|
|
||||||
('can_view_preinfo', 'Can view preinfo'),
|
|
||||||
('can_manage_preinfo', 'Can manage preinfo'),
|
|
||||||
|
|
||||||
('can_view_payment', 'Can view payment'),
|
|
||||||
('can_manage_payment', 'Can manage payment'),
|
|
||||||
|
|
||||||
('can_manage_company_users', 'Can manage company users'),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
class EmployeePermission(models.Model):
|
|
||||||
codename = models.CharField(max_length=100, default='')
|
|
||||||
name = models.CharField(max_length=255, default='')
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
managed = True
|
|
||||||
default_permissions = ()
|
|
||||||
permissions = (
|
|
||||||
('can_manage_containers', 'Can manage containers'),
|
|
||||||
('can_view_reports', 'Can view reports'),
|
|
||||||
('can_handle_operations', 'Can handle operations'),
|
|
||||||
)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
|
|
||||||
class CustomUserManager(BaseUserManager):
|
|
||||||
def create_user(self, email, password=None, **extra_fields):
|
|
||||||
if not email:
|
|
||||||
raise ValueError('Users must have an email address')
|
|
||||||
email = self.normalize_email(email)
|
|
||||||
user = self.model(email=email, **extra_fields)
|
|
||||||
user.set_password(password)
|
|
||||||
user.save(using=self._db)
|
|
||||||
return user
|
|
||||||
|
|
||||||
def create_superuser(self, email, password=None, **extra_fields):
|
|
||||||
extra_fields.setdefault('is_staff', True)
|
|
||||||
extra_fields.setdefault('is_superuser', True)
|
|
||||||
extra_fields.setdefault('is_active', True)
|
|
||||||
extra_fields.setdefault('user_type', 'AD') # Set user_type to admin
|
|
||||||
|
|
||||||
if extra_fields.get('is_staff') is not True:
|
|
||||||
raise ValueError('Superuser must have is_staff=True.')
|
|
||||||
if extra_fields.get('is_superuser') is not True:
|
|
||||||
raise ValueError('Superuser must have is_superuser=True.')
|
|
||||||
|
|
||||||
return self.create_user(email, password, **extra_fields)
|
|
||||||
|
|
||||||
|
|
||||||
class DepotUser(AbstractUser):
|
|
||||||
|
|
||||||
class UserType(models.TextChoices):
|
|
||||||
BARRIER_STAFF = 'BS', 'Barrier Staff'
|
|
||||||
COMPANY_ADMIN = 'CA', 'Company Admin'
|
|
||||||
EMPLOYEE = 'EM', 'Employee'
|
|
||||||
CLIENT = 'CL', 'Client',
|
|
||||||
ADMIN = 'AD', 'Admin'
|
|
||||||
|
|
||||||
objects = CustomUserManager()
|
|
||||||
|
|
||||||
user_type = models.CharField(
|
|
||||||
max_length=2,
|
|
||||||
choices=UserType.choices,
|
|
||||||
default=UserType.CLIENT
|
|
||||||
)
|
|
||||||
|
|
||||||
phone_number = models.CharField(max_length=15, blank=True, null=True)
|
|
||||||
email = models.EmailField(unique=True, blank=False, null=False)
|
|
||||||
company = models.ForeignKey(
|
|
||||||
'common.CompanyModel',
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='user_lines',
|
|
||||||
blank=True,
|
|
||||||
null=True
|
|
||||||
)
|
|
||||||
line = models.ForeignKey(
|
|
||||||
'common.LinesModel',
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='user_lines',
|
|
||||||
blank=True,
|
|
||||||
null=True
|
|
||||||
)
|
|
||||||
|
|
||||||
company_permissions = models.ManyToManyField('ClientPermission')
|
|
||||||
employee_permissions = models.ManyToManyField('EmployeePermission', blank=True)
|
|
||||||
|
|
||||||
def has_company_perm(self, perm_codename):
|
|
||||||
if self.is_superuser:
|
|
||||||
return True
|
|
||||||
return self.company_permissions.filter(codename=perm_codename).exists()
|
|
||||||
|
|
||||||
def has_employee_perm(self, perm_codename):
|
|
||||||
if self.is_superuser:
|
|
||||||
return True
|
|
||||||
return self.employee_permissions.filter(codename=perm_codename).exists()
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
# Create your tests here.
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
from django.urls import path, include
|
|
||||||
from django.contrib.auth import views as auth_views
|
|
||||||
from accounts import views
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path('', include([
|
|
||||||
path('', views.UserListView.as_view(), name='user_list'),
|
|
||||||
path('register/', views.RegisterView.as_view(), name='user_register'),
|
|
||||||
path('login/', views.DepotLoginView.as_view(), name='login'),
|
|
||||||
path('relogin/', auth_views.logout_then_login, name='relogin'),
|
|
||||||
path('change-password/', views.UserChangePasswordView.as_view(), name='change_password'),
|
|
||||||
path('<int:pk>/update/', views.UserUpdateView.as_view(), name='user_update'),
|
|
||||||
path('<int:pk>/active/', views.UserActiveView.as_view(), name='user_active'),
|
|
||||||
])),
|
|
||||||
]
|
|
||||||
@ -1,198 +0,0 @@
|
|||||||
from django.contrib.auth import get_user_model
|
|
||||||
from django.contrib.auth.views import LoginView
|
|
||||||
from django.http import HttpResponseForbidden, JsonResponse
|
|
||||||
from django.shortcuts import render
|
|
||||||
from django.urls import reverse_lazy
|
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
from django.views import View
|
|
||||||
from django.views.generic import TemplateView, FormView, ListView, UpdateView
|
|
||||||
from rest_framework.generics import get_object_or_404
|
|
||||||
|
|
||||||
from accounts.forms import LoginForm, RegisterForm, UserChangePasswordForm
|
|
||||||
from accounts.models import DepotUser
|
|
||||||
|
|
||||||
from django.contrib.auth.decorators import login_required, user_passes_test
|
|
||||||
from django.contrib.auth.mixins import AccessMixin, LoginRequiredMixin
|
|
||||||
|
|
||||||
|
|
||||||
# Create your views here.
|
|
||||||
|
|
||||||
|
|
||||||
class DepotLoginView(LoginView):
|
|
||||||
template_name = 'registration/login.html'
|
|
||||||
# success_url = reverse_lazy('dashboard')
|
|
||||||
form_class = LoginForm
|
|
||||||
next_page = reverse_lazy('dashboard')
|
|
||||||
|
|
||||||
|
|
||||||
def is_company_admin(user):
|
|
||||||
return user.is_authenticated and user.is_company_admin
|
|
||||||
|
|
||||||
@method_decorator(login_required, name='dispatch')
|
|
||||||
class RegisterView(AccessMixin, FormView):
|
|
||||||
template_name = 'registration/register.html'
|
|
||||||
form_class = RegisterForm
|
|
||||||
# model = get_user_model()
|
|
||||||
success_url = reverse_lazy('dashboard')
|
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
user: DepotUser = request.user
|
|
||||||
|
|
||||||
if not (user.is_superuser or user.user_type == DepotUser.UserType.COMPANY_ADMIN):
|
|
||||||
return self.handle_no_permission()
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
def form_valid(self, form):
|
|
||||||
# Create user from form data
|
|
||||||
user = form.save(commit=False)
|
|
||||||
user_type = form.cleaned_data['user_type']
|
|
||||||
user.save()
|
|
||||||
|
|
||||||
# Clear irrelevant permissions based on user type
|
|
||||||
if user_type == DepotUser.UserType.CLIENT:
|
|
||||||
user.employee_permissions.clear()
|
|
||||||
user.company_permissions.set(form.cleaned_data['company_permissions'])
|
|
||||||
elif user_type == DepotUser.UserType.EMPLOYEE:
|
|
||||||
user.company_permissions.clear()
|
|
||||||
user.employee_permissions.set(form.cleaned_data['employee_permissions'])
|
|
||||||
|
|
||||||
return super().form_valid(form)
|
|
||||||
|
|
||||||
def get_form(self, form_class = None):
|
|
||||||
form = super().get_form(form_class)
|
|
||||||
user: DepotUser = self.request.user
|
|
||||||
|
|
||||||
if user.is_superuser:
|
|
||||||
# Superuser can manage all permissions and user types
|
|
||||||
form.fields['user_type'].widget.attrs['disabled'] = False
|
|
||||||
form.fields['company_permissions'].widget.attrs['disabled'] = False
|
|
||||||
form.fields['employee_permissions'].widget.attrs['disabled'] = False
|
|
||||||
|
|
||||||
# Show relevant permissions based on selected user type
|
|
||||||
if form.initial.get('user_type') == DepotUser.UserType.CLIENT:
|
|
||||||
form.fields['employee_permissions'].widget.attrs['disabled'] = True
|
|
||||||
elif form.initial.get('user_type') == DepotUser.UserType.EMPLOYEE:
|
|
||||||
form.fields['company_permissions'].widget.attrs['disabled'] = True
|
|
||||||
|
|
||||||
elif user.user_type == DepotUser.UserType.COMPANY_ADMIN:
|
|
||||||
form.fields['company'].queryset = form.fields['company'].queryset.filter(pk=user.company.pk)
|
|
||||||
form.fields['company'].initial = user.company
|
|
||||||
form.fields['company'].widget.readonly = True # form.fields['line'].widget.attrs['disabled'] = True
|
|
||||||
form.fields['line'].queryset = form.fields['line'].queryset.filter(company=user.company.pk)
|
|
||||||
|
|
||||||
form.fields['user_type'].choices = [
|
|
||||||
(DepotUser.UserType.CLIENT, 'Client')
|
|
||||||
]
|
|
||||||
form.fields['user_type'].initial = DepotUser.UserType.CLIENT
|
|
||||||
|
|
||||||
form.fields['company_permissions'].widget.attrs['disabled'] = False
|
|
||||||
form.fields['employee_permissions'].widget.attrs['disabled'] = True
|
|
||||||
|
|
||||||
return form
|
|
||||||
|
|
||||||
class UserListView(ListView):
|
|
||||||
template_name = 'registration/user-list.html'
|
|
||||||
model = get_user_model()
|
|
||||||
context_object_name = 'objects'
|
|
||||||
paginate_by = 30 # Number of containers per page
|
|
||||||
# base_template = 'employee-base.html'
|
|
||||||
|
|
||||||
# def get_context_data(self, **kwargs):
|
|
||||||
# context = super().get_context_data(**kwargs)
|
|
||||||
# context['base_template'] = self.base_template
|
|
||||||
# return context
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
queryset = super().get_queryset()
|
|
||||||
user = self.request.user
|
|
||||||
|
|
||||||
data_filter = self.request.GET.get('filter')
|
|
||||||
|
|
||||||
if data_filter != 'all':
|
|
||||||
queryset = queryset.filter(is_active=True)
|
|
||||||
|
|
||||||
# Filter users based on permissions
|
|
||||||
if user.is_superuser:
|
|
||||||
return queryset.all()
|
|
||||||
elif user.user_type == DepotUser.UserType.COMPANY_ADMIN:
|
|
||||||
return queryset.filter(company=user.company)
|
|
||||||
else:
|
|
||||||
return queryset.none()
|
|
||||||
|
|
||||||
class UserUpdateView(UpdateView):
|
|
||||||
template_name = 'registration/register.html'
|
|
||||||
form_class = RegisterForm
|
|
||||||
model = get_user_model()
|
|
||||||
success_url = reverse_lazy('user_list')
|
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
user: DepotUser = request.user
|
|
||||||
|
|
||||||
if not (user.is_superuser or user.user_type == DepotUser.UserType.COMPANY_ADMIN):
|
|
||||||
return self.handle_no_permission()
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
def form_valid(self, form):
|
|
||||||
user = form.save(commit=False)
|
|
||||||
user_type = form.cleaned_data['user_type']
|
|
||||||
user.save()
|
|
||||||
# Clear irrelevant permissions based on user type
|
|
||||||
if user_type == DepotUser.UserType.CLIENT:
|
|
||||||
user.employee_permissions.clear()
|
|
||||||
user.company_permissions.set(form.cleaned_data['company_permissions'])
|
|
||||||
elif user_type == DepotUser.UserType.EMPLOYEE:
|
|
||||||
user.company_permissions.clear()
|
|
||||||
user.employee_permissions.set(form.cleaned_data['employee_permissions'])
|
|
||||||
return super().form_valid(form)
|
|
||||||
|
|
||||||
def get_form(self, form_class = None):
|
|
||||||
form = super().get_form(form_class)
|
|
||||||
user: DepotUser = self.request.user
|
|
||||||
|
|
||||||
if user.is_superuser:
|
|
||||||
# Superuser can manage all permissions and user types
|
|
||||||
form.fields['user_type'].widget.attrs['disabled'] = False
|
|
||||||
form.fields['company_permissions'].widget.attrs['disabled'] = False
|
|
||||||
form.fields['employee_permissions'].widget.attrs['disabled'] = False
|
|
||||||
|
|
||||||
# Show relevant permissions based on selected user type
|
|
||||||
if form.initial.get('user_type') == DepotUser.UserType.CLIENT:
|
|
||||||
form.fields['employee_permissions'].widget.attrs['disabled'] = True
|
|
||||||
elif form.initial.get('user_type') == DepotUser.UserType.EMPLOYEE:
|
|
||||||
form.fields['company_permissions'].widget.attrs['disabled'] = True
|
|
||||||
|
|
||||||
elif user.user_type == DepotUser.UserType.COMPANY_ADMIN:
|
|
||||||
form.fields['company'].queryset = form.fields['company'].queryset.filter(pk=user.company.pk)
|
|
||||||
form.fields['company'].initial = user.company
|
|
||||||
form.fields['company'].widget.readonly = True
|
|
||||||
form.fields['line'].queryset = form.fields['line'].queryset.filter(company=user.company.pk)
|
|
||||||
form.fields['user_type'].choices = [
|
|
||||||
(DepotUser.UserType.CLIENT, 'Client')
|
|
||||||
]
|
|
||||||
form.fields['user_type'].initial = DepotUser.UserType.CLIENT
|
|
||||||
form.fields['company_permissions'].widget.attrs['disabled'] = False
|
|
||||||
form.fields['employee_permissions'].widget.attrs['disabled'] = True
|
|
||||||
|
|
||||||
return form
|
|
||||||
|
|
||||||
class UserActiveView(LoginRequiredMixin, View):
|
|
||||||
success_url = reverse_lazy('user_list')
|
|
||||||
|
|
||||||
def post(self, request, pk, *args, **kwargs):
|
|
||||||
user = request.user
|
|
||||||
if not (user.is_superuser or getattr(user, 'user_type', None) == DepotUser.UserType.COMPANY_ADMIN):
|
|
||||||
return HttpResponseForbidden("You do not have permission to perform this action.")
|
|
||||||
|
|
||||||
target_user = get_object_or_404(get_user_model(), pk=pk)
|
|
||||||
if target_user == user:
|
|
||||||
return HttpResponseForbidden("You cannot change your own active status.")
|
|
||||||
|
|
||||||
target_user.is_active = not target_user.is_active
|
|
||||||
target_user.save()
|
|
||||||
return JsonResponse({'success': True, 'is_active': target_user.is_active})
|
|
||||||
|
|
||||||
|
|
||||||
class UserChangePasswordView(LoginRequiredMixin, View):
|
|
||||||
template_name = 'registration/change_password.html'
|
|
||||||
form_class = UserChangePasswordForm
|
|
||||||
success_url = reverse_lazy('home')
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
from django.contrib import admin
|
|
||||||
|
|
||||||
# Register your models here.
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class BookingConfig(AppConfig):
|
|
||||||
default_auto_field = "django.db.models.BigAutoField"
|
|
||||||
name = "booking"
|
|
||||||
@ -1,36 +0,0 @@
|
|||||||
from django import forms
|
|
||||||
|
|
||||||
from booking.models import Booking
|
|
||||||
|
|
||||||
|
|
||||||
class BookingBaseForm(forms.ModelForm):
|
|
||||||
"""
|
|
||||||
Base form for booking-related forms.
|
|
||||||
This can be extended by other booking forms.
|
|
||||||
"""
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
fields = '__all__'
|
|
||||||
model = Booking
|
|
||||||
|
|
||||||
class BookingCreateForm(BookingBaseForm):
|
|
||||||
|
|
||||||
class Meta(BookingBaseForm.Meta):
|
|
||||||
fields = ['number', 'vehicles', 'container_type', 'container_count', 'carrier', 'line', 'container_number']
|
|
||||||
widgets = {
|
|
||||||
'container_number': forms.TextInput(attrs={
|
|
||||||
'oninput': 'validateContainerNumber(this)',
|
|
||||||
'class': 'form-control'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
class BookingUpdateForm(BookingBaseForm):
|
|
||||||
|
|
||||||
class Meta(BookingBaseForm.Meta):
|
|
||||||
fields = ['number', 'vehicles', 'container_type', 'container_count', 'carrier', 'line', 'container_number']
|
|
||||||
widgets = {
|
|
||||||
'container_number': forms.TextInput(attrs={
|
|
||||||
'oninput': 'validateContainerNumber(this)',
|
|
||||||
'class': 'form-control'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@ -1,61 +0,0 @@
|
|||||||
# Generated by Django 5.2.3 on 2025-06-27 10:20
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("common", "0001_initial"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name="BookingModel",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"id",
|
|
||||||
models.BigAutoField(
|
|
||||||
auto_created=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
verbose_name="ID",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("number", models.CharField(max_length=50, unique=True)),
|
|
||||||
("vehicles", models.CharField(blank=True, null=True)),
|
|
||||||
("container_count", models.IntegerField()),
|
|
||||||
("carrier", models.CharField(blank=True, max_length=100, null=True)),
|
|
||||||
("visible", models.BooleanField(default=True)),
|
|
||||||
("is_new", models.BooleanField(default=True)),
|
|
||||||
(
|
|
||||||
"container_number",
|
|
||||||
models.CharField(blank=True, max_length=11, null=True),
|
|
||||||
),
|
|
||||||
("vehicles_left", models.IntegerField(blank=True, null=True)),
|
|
||||||
("created_on", models.DateTimeField(auto_now_add=True)),
|
|
||||||
("created_by", models.IntegerField()),
|
|
||||||
("updated_on", models.DateTimeField(auto_now=True)),
|
|
||||||
("updated_by", models.IntegerField()),
|
|
||||||
(
|
|
||||||
"container_type",
|
|
||||||
models.ForeignKey(
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="booking_container_types",
|
|
||||||
to="common.containertypemodel",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"line",
|
|
||||||
models.ForeignKey(
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="booking_lines",
|
|
||||||
to="common.linesmodel",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
# Generated by Django 5.2.3 on 2025-06-30 15:11
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("booking", "0001_initial"),
|
|
||||||
("common", "0002_alter_companymodel_short_name_and_more"),
|
|
||||||
("containers", "0005_alter_container_expedited_by_and_more"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RenameModel(
|
|
||||||
old_name="BookingModel",
|
|
||||||
new_name="Booking",
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 5.2.3 on 2025-07-01 08:41
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("booking", "0002_rename_bookingmodel_booking"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name="booking",
|
|
||||||
name="container_expedited_count",
|
|
||||||
field=models.IntegerField(default=0),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
# Generated by Django 5.2.3 on 2025-07-01 09:08
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("booking", "0003_booking_container_expedited_count"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name="booking",
|
|
||||||
name="status",
|
|
||||||
field=models.CharField(
|
|
||||||
choices=[
|
|
||||||
("active", "Active"),
|
|
||||||
("finished", "Finished"),
|
|
||||||
("canceled", "Canceled"),
|
|
||||||
],
|
|
||||||
default="active",
|
|
||||||
max_length=10,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 5.2.3 on 2025-07-01 09:31
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("booking", "0004_booking_status"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="booking",
|
|
||||||
name="vehicles_left",
|
|
||||||
field=models.CharField(blank=True, null=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
from django.db import models
|
|
||||||
from common.models import ContainerTypeModel, LinesModel, OperationModel
|
|
||||||
|
|
||||||
# Create your models here.
|
|
||||||
class Booking(models.Model):
|
|
||||||
|
|
||||||
STATUS_CHOICES = [
|
|
||||||
('active', 'Active'),
|
|
||||||
('finished', 'Finished'),
|
|
||||||
('canceled', 'Canceled'),
|
|
||||||
]
|
|
||||||
|
|
||||||
number = models.CharField(max_length=50, unique=True)
|
|
||||||
vehicles = models.CharField(blank=True, null=True)
|
|
||||||
container_type = models.ForeignKey(
|
|
||||||
ContainerTypeModel,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='booking_container_types',
|
|
||||||
)
|
|
||||||
container_count = models.IntegerField()
|
|
||||||
container_expedited_count = models.IntegerField(default=0)
|
|
||||||
carrier = models.CharField(max_length=100, blank=True, null=True)
|
|
||||||
line = models.ForeignKey(
|
|
||||||
LinesModel,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='booking_lines',
|
|
||||||
)
|
|
||||||
visible = models.BooleanField(default=True)
|
|
||||||
is_new = models.BooleanField(default=True)
|
|
||||||
container_number = models.CharField(max_length=11, blank=True, null=True)
|
|
||||||
vehicles_left = models.CharField(blank=True, null=True)
|
|
||||||
created_on = models.DateTimeField(auto_now_add=True)
|
|
||||||
created_by = models.IntegerField()
|
|
||||||
updated_on = models.DateTimeField(auto_now=True)
|
|
||||||
updated_by = models.IntegerField()
|
|
||||||
status = models.CharField(
|
|
||||||
max_length=10,
|
|
||||||
choices=STATUS_CHOICES,
|
|
||||||
default='active'
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def containers_left(self):
|
|
||||||
return self.container_count - (self.container_expedited_count or 0)
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
from django import template
|
|
||||||
|
|
||||||
register = template.Library()
|
|
||||||
|
|
||||||
@register.filter
|
|
||||||
def distinct_vehicles(vehicles):
|
|
||||||
vehicles_set = set(vehicles.split(','))
|
|
||||||
vehicles_str = ', '.join(sorted(vehicles_set))
|
|
||||||
return vehicles_str
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
# Create your tests here.
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
from django.urls import path, include
|
|
||||||
|
|
||||||
from booking.views.client_views import CreateBookingView, ClientBookingView, ClientBookingUpdateView
|
|
||||||
from booking.views.employee_views import BookingListView
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path('client/', include([
|
|
||||||
path('', ClientBookingView.as_view(), name='client_booking'),
|
|
||||||
path('create/', CreateBookingView.as_view(), name='client_booking_create'),
|
|
||||||
path('<int:pk>/update/', ClientBookingUpdateView.as_view(), name='client_booking_update'),
|
|
||||||
path('<int:pk>/active/', ClientBookingUpdateView.as_view(), name='client_booking_active'),
|
|
||||||
])),
|
|
||||||
path('employee/', BookingListView.as_view(), name='employee_bookings'),
|
|
||||||
]
|
|
||||||
@ -1,62 +0,0 @@
|
|||||||
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
|
|
||||||
from django.urls import reverse_lazy
|
|
||||||
from django.views.generic import CreateView, ListView
|
|
||||||
|
|
||||||
from DepoT.mixins.LineFiltweFormMixin import LineFilterFormMixin
|
|
||||||
from booking.forms import BookingCreateForm, BookingUpdateForm
|
|
||||||
from booking.models import Booking
|
|
||||||
from common.utils.utils import filter_queryset_by_user
|
|
||||||
|
|
||||||
|
|
||||||
class ClientBookingView(LoginRequiredMixin, UserPassesTestMixin, ListView):
|
|
||||||
model = Booking
|
|
||||||
template_name = 'client/booking-list.html'
|
|
||||||
paginate_by = 4
|
|
||||||
context_object_name = 'objects'
|
|
||||||
# base_template = 'client-base.html'
|
|
||||||
|
|
||||||
def test_func(self):
|
|
||||||
return self.request.user.has_company_perm('can_view_booking') or self.request.user.user_type == 'CA'
|
|
||||||
|
|
||||||
# def get_context_data(self, **kwargs):
|
|
||||||
# context = super().get_context_data(**kwargs)
|
|
||||||
# context['base_template'] = self.base_template
|
|
||||||
# return context
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
queryset = super().get_queryset()
|
|
||||||
user = self.request.user
|
|
||||||
result = filter_queryset_by_user(queryset, user)
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
class CreateBookingView(LoginRequiredMixin, UserPassesTestMixin, LineFilterFormMixin, CreateView):
|
|
||||||
template_name = 'client/booking-create.html'
|
|
||||||
model = Booking
|
|
||||||
form_class = BookingCreateForm
|
|
||||||
success_url = reverse_lazy('client_booking')
|
|
||||||
|
|
||||||
def form_valid(self, form):
|
|
||||||
# todo more validation
|
|
||||||
form.instance.created_by = self.request.user.id
|
|
||||||
form.instance.updated_by = self.request.user.id
|
|
||||||
form.instance.vehicles_left = form.cleaned_data.get('vehicles')
|
|
||||||
return super().form_valid(form)
|
|
||||||
|
|
||||||
def test_func(self):
|
|
||||||
return True # self.request.user.has_company_perm('can_edit_preinfo') or self.request.user.user_type == 'CA'
|
|
||||||
|
|
||||||
|
|
||||||
class ClientBookingUpdateView(LoginRequiredMixin, UserPassesTestMixin, LineFilterFormMixin, CreateView):
|
|
||||||
template_name = 'client/booking-edit.html'
|
|
||||||
model = Booking
|
|
||||||
form_class = BookingUpdateForm
|
|
||||||
success_url = reverse_lazy('client_booking')
|
|
||||||
|
|
||||||
def form_valid(self, form):
|
|
||||||
# todo more validation
|
|
||||||
form.instance.updated_by = self.request.user.id
|
|
||||||
return super().form_valid(form)
|
|
||||||
|
|
||||||
def test_func(self):
|
|
||||||
return True # self.request.user.has_company_perm('can_edit_preinfo') or self.request.user.user_type == 'CA'
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
from django.views.generic import ListView
|
|
||||||
|
|
||||||
from booking.models import Booking
|
|
||||||
|
|
||||||
|
|
||||||
class BookingListView(ListView):
|
|
||||||
template_name = 'employee/booking-list.html'
|
|
||||||
model = Booking
|
|
||||||
context_object_name = 'objects'
|
|
||||||
paginate_by = 30 # Number of containers per page
|
|
||||||
# base_template = 'employee-base.html'
|
|
||||||
|
|
||||||
# def get_context_data(self, **kwargs):
|
|
||||||
# context = super().get_context_data(**kwargs)
|
|
||||||
# context['base_template'] = self.base_template
|
|
||||||
# return context
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
queryset = super().get_queryset()
|
|
||||||
|
|
||||||
data_filter = self.request.GET.get('filter')
|
|
||||||
if data_filter != 'all':
|
|
||||||
queryset = queryset.filter(status='active')
|
|
||||||
|
|
||||||
queryset = queryset.order_by('-created_on')
|
|
||||||
|
|
||||||
return queryset
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
from django.contrib import admin
|
|
||||||
|
|
||||||
# Register your models here.
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class CommonConfig(AppConfig):
|
|
||||||
default_auto_field = "django.db.models.BigAutoField"
|
|
||||||
name = "common"
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
from django.forms import ModelForm
|
|
||||||
|
|
||||||
from common.models import CompanyModel
|
|
||||||
|
|
||||||
|
|
||||||
class CompanyBaseForm(ModelForm):
|
|
||||||
class Meta:
|
|
||||||
model = CompanyModel
|
|
||||||
fields = '__all__'
|
|
||||||
|
|
||||||
|
|
||||||
class CompanyCreateForm(CompanyBaseForm):
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
class CompanyUpdateForm(CompanyBaseForm):
|
|
||||||
...
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
from django.forms import ModelForm
|
|
||||||
|
|
||||||
from common.models import LinesModel
|
|
||||||
|
|
||||||
|
|
||||||
class LineBaseForm(ModelForm):
|
|
||||||
class Meta:
|
|
||||||
model = LinesModel
|
|
||||||
fields = '__all__'
|
|
||||||
|
|
||||||
|
|
||||||
class LineCreateForm(LineBaseForm):
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
class LineUpdateForm(LineBaseForm):
|
|
||||||
...
|
|
||||||
@ -1,132 +0,0 @@
|
|||||||
# Generated by Django 5.2.3 on 2025-06-27 10:20
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
dependencies = []
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name="CompanyModel",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"id",
|
|
||||||
models.BigAutoField(
|
|
||||||
auto_created=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
verbose_name="ID",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("name", models.CharField(max_length=100, unique=True)),
|
|
||||||
("short_name", models.CharField(max_length=5, unique=True)),
|
|
||||||
("description", models.TextField(blank=True, null=True)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
"ordering": ["name"],
|
|
||||||
"abstract": False,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name="ContainerKindModel",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"id",
|
|
||||||
models.BigAutoField(
|
|
||||||
auto_created=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
verbose_name="ID",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("name", models.CharField(max_length=100, unique=True)),
|
|
||||||
("short_name", models.CharField(max_length=5, unique=True)),
|
|
||||||
("description", models.TextField(blank=True, null=True)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
"ordering": ["name"],
|
|
||||||
"abstract": False,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name="OperationModel",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"id",
|
|
||||||
models.BigAutoField(
|
|
||||||
auto_created=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
verbose_name="ID",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("name", models.CharField(max_length=100, unique=True)),
|
|
||||||
("short_name", models.CharField(max_length=5, unique=True)),
|
|
||||||
("description", models.TextField(blank=True, null=True)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
"ordering": ["name"],
|
|
||||||
"abstract": False,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name="ContainerTypeModel",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"id",
|
|
||||||
models.BigAutoField(
|
|
||||||
auto_created=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
verbose_name="ID",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("name", models.CharField(max_length=6, unique=True)),
|
|
||||||
("length", models.IntegerField()),
|
|
||||||
("height", models.BooleanField()),
|
|
||||||
("deleted", models.BooleanField(default=False)),
|
|
||||||
(
|
|
||||||
"container_type",
|
|
||||||
models.ForeignKey(
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="container_type_container_kinds",
|
|
||||||
to="common.containerkindmodel",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name="LinesModel",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"id",
|
|
||||||
models.BigAutoField(
|
|
||||||
auto_created=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
verbose_name="ID",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("name", models.CharField(max_length=100, unique=True)),
|
|
||||||
("short_name", models.CharField(max_length=5, unique=True)),
|
|
||||||
("description", models.TextField(blank=True, null=True)),
|
|
||||||
(
|
|
||||||
"company",
|
|
||||||
models.ForeignKey(
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="line_company",
|
|
||||||
to="common.companymodel",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
"ordering": ["name"],
|
|
||||||
"abstract": False,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
# Generated by Django 5.2.3 on 2025-06-27 15:12
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("common", "0001_initial"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="companymodel",
|
|
||||||
name="short_name",
|
|
||||||
field=models.CharField(blank=True, max_length=5, null=True),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="containerkindmodel",
|
|
||||||
name="short_name",
|
|
||||||
field=models.CharField(blank=True, max_length=5, null=True),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="linesmodel",
|
|
||||||
name="short_name",
|
|
||||||
field=models.CharField(blank=True, max_length=5, null=True),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="operationmodel",
|
|
||||||
name="short_name",
|
|
||||||
field=models.CharField(blank=True, max_length=5, null=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
# Generated by Django 5.2.3 on 2025-07-25 16:20
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("common", "0002_alter_companymodel_short_name_and_more"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = []
|
|
||||||
@ -1,91 +0,0 @@
|
|||||||
from django.db import migrations
|
|
||||||
|
|
||||||
def create_initial_data(apps, schema_editor):
|
|
||||||
ContainerKindModel = apps.get_model('common', 'ContainerKindModel')
|
|
||||||
ContainerTypeModel = apps.get_model('common', 'ContainerTypeModel')
|
|
||||||
CompanyModel = apps.get_model('common', 'CompanyModel')
|
|
||||||
LinesModel = apps.get_model('common', 'LinesModel')
|
|
||||||
|
|
||||||
# Container Kinds
|
|
||||||
container_kinds = [
|
|
||||||
(1, 'Standart', '', ''),
|
|
||||||
(2, 'Reefer', '', ''),
|
|
||||||
(3, 'Opentop', '', ''),
|
|
||||||
(4, 'FlatRack', '', ''),
|
|
||||||
(5, 'Tank', '', ''),
|
|
||||||
(6, 'Platform', '', ''),
|
|
||||||
]
|
|
||||||
for _id, name, *rest in container_kinds:
|
|
||||||
ContainerKindModel.objects.create(id=_id, name=name)
|
|
||||||
|
|
||||||
# Container Types
|
|
||||||
container_types = [
|
|
||||||
(1, '20GP', 20, False, 1, False),
|
|
||||||
(2, '40GP', 40, False, 1, False),
|
|
||||||
(3, '40HC', 40, True, 1, False),
|
|
||||||
(4, '20RF', 20, False, 2, False),
|
|
||||||
(5, '40RF', 40, False, 2, False),
|
|
||||||
(6, '20OT', 20, False, 3, False),
|
|
||||||
(7, '40OT', 40, False, 3, False),
|
|
||||||
(8, '20FR', 20, False, 4, False),
|
|
||||||
(9, '20FRPL', 20, False, 6, False),
|
|
||||||
(10, '45HC', 45, True, 1, False),
|
|
||||||
(11, '40FRPL', 40, False, 6, False),
|
|
||||||
(12, '40HR', 40, True, 2, False),
|
|
||||||
|
|
||||||
]
|
|
||||||
for _id, name, length, height, container_type_id, deleted in container_types:
|
|
||||||
ContainerTypeModel.objects.create(
|
|
||||||
id=_id,
|
|
||||||
name=name,
|
|
||||||
length=length,
|
|
||||||
height=height,
|
|
||||||
container_type_id=container_type_id,
|
|
||||||
deleted=deleted
|
|
||||||
)
|
|
||||||
|
|
||||||
# Companies and Lines
|
|
||||||
companies = [
|
|
||||||
(1, 'GMS', 'GMS', 'Global Maritime Servises'),
|
|
||||||
(2, 'TO', 'TO', 'Терминален оператор'),
|
|
||||||
]
|
|
||||||
for _id, name, short_name, description in companies:
|
|
||||||
CompanyModel.objects.create(
|
|
||||||
id=_id,
|
|
||||||
name=name,
|
|
||||||
short_name=short_name,
|
|
||||||
description=description
|
|
||||||
)
|
|
||||||
lines = [
|
|
||||||
(1, 'GMS', 'GMS', 'GMS line', 1),
|
|
||||||
(2, 'HPG', 'HPG', 'Hapag Lloyds line', 1),
|
|
||||||
(3, 'TO', 'TO', 'Терминален оператор line', 2),
|
|
||||||
]
|
|
||||||
for _id, name, short_name, description, company_id in lines:
|
|
||||||
LinesModel.objects.create(
|
|
||||||
id=_id,
|
|
||||||
name=name,
|
|
||||||
short_name=short_name,
|
|
||||||
description=description,
|
|
||||||
company_id=company_id
|
|
||||||
)
|
|
||||||
|
|
||||||
def reverse_initial_data(apps, schema_editor):
|
|
||||||
ContainerKindModel = apps.get_model('common', 'ContainerKindModel')
|
|
||||||
ContainerTypeModel = apps.get_model('common', 'ContainerTypeModel')
|
|
||||||
CompanyModel = apps.get_model('common', 'CompanyModel')
|
|
||||||
LinesModel = apps.get_model('common', 'LinesModel')
|
|
||||||
|
|
||||||
ContainerKindModel.objects.all().delete()
|
|
||||||
ContainerTypeModel.objects.all().delete()
|
|
||||||
CompanyModel.objects.all().delete()
|
|
||||||
LinesModel.objects.all().delete()
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
dependencies = [
|
|
||||||
('common', '0003_auto_20250725_1920'), # Adjust this to your last migration
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RunPython(create_initial_data, reverse_initial_data),
|
|
||||||
]
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
# Generated by Django 5.2.3 on 2025-07-30 14:16
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("common", "0004_populate_initial_data"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name="companymodel",
|
|
||||||
name="active",
|
|
||||||
field=models.BooleanField(default=True),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name="containerkindmodel",
|
|
||||||
name="active",
|
|
||||||
field=models.BooleanField(default=True),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name="linesmodel",
|
|
||||||
name="active",
|
|
||||||
field=models.BooleanField(default=True),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name="operationmodel",
|
|
||||||
name="active",
|
|
||||||
field=models.BooleanField(default=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,46 +0,0 @@
|
|||||||
from django.db import models
|
|
||||||
|
|
||||||
# Create your models here.
|
|
||||||
class NomenclatureBaseModel(models.Model):
|
|
||||||
name = models.CharField(max_length=100, unique=True)
|
|
||||||
short_name = models.CharField(max_length=5, null=True, blank=True)
|
|
||||||
description = models.TextField(blank=True, null=True)
|
|
||||||
active = models.BooleanField(default=True)
|
|
||||||
class Meta:
|
|
||||||
abstract = True
|
|
||||||
ordering = ['name']
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
|
|
||||||
class CompanyModel(NomenclatureBaseModel):
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
class LinesModel(NomenclatureBaseModel):
|
|
||||||
company = models.ForeignKey(
|
|
||||||
'common.CompanyModel',
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='line_company'
|
|
||||||
)
|
|
||||||
|
|
||||||
class OperationModel(NomenclatureBaseModel):
|
|
||||||
...
|
|
||||||
|
|
||||||
class ContainerKindModel(NomenclatureBaseModel):
|
|
||||||
...
|
|
||||||
|
|
||||||
class ContainerTypeModel(models.Model):
|
|
||||||
name = models.CharField(max_length=6, unique=True)
|
|
||||||
length = models.IntegerField()
|
|
||||||
height = models.BooleanField()
|
|
||||||
container_type = models.ForeignKey(
|
|
||||||
'common.ContainerKindModel',
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='container_type_container_kinds'
|
|
||||||
)
|
|
||||||
deleted = models.BooleanField(default=False)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
from django import template
|
|
||||||
from django.template.defaultfilters import date
|
|
||||||
|
|
||||||
from common.utils.utils import check_container_number_validity
|
|
||||||
|
|
||||||
register = template.Library()
|
|
||||||
|
|
||||||
@register.filter
|
|
||||||
def bg_date(value):
|
|
||||||
if value:
|
|
||||||
return date(value, "y.m.d h:m")
|
|
||||||
return ""
|
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag
|
|
||||||
def container_validity_class(container_number):
|
|
||||||
if not check_container_number_validity(container_number):
|
|
||||||
return 'invalid-container'
|
|
||||||
return ''
|
|
||||||
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
# Create your tests here.
|
|
||||||
@ -1,39 +0,0 @@
|
|||||||
from django.urls import path, include
|
|
||||||
from common.views.barrier_views import BarrierDashboardView
|
|
||||||
from common.views.employee_views import EmployeeDashboardView, EmployeeCompanyListView, EmployeeCompanyCreateView, \
|
|
||||||
EmployeeCompanyUpdateView, EmployeeLineListView, EmployeeLineCreateView, EmployeeLineUpdateView
|
|
||||||
from common.views.client_views import ClientDashboardView, ClientCompanyListView, ClientCompanyCreateView, \
|
|
||||||
ClientCompanyUpdateView, ClientLineListView, ClientLineCreateView, ClientLineUpdateView
|
|
||||||
from common.views.shared_views import IndexView, DashboardRedirectView
|
|
||||||
urlpatterns = [
|
|
||||||
path('', IndexView.as_view(), name='index'),
|
|
||||||
path('dashboard/', include([
|
|
||||||
path('', DashboardRedirectView.as_view(), name='dashboard'),
|
|
||||||
path('client/', ClientDashboardView.as_view(), name='client_dashboard'),
|
|
||||||
path('barrier/', BarrierDashboardView.as_view(), name='barrier_dashboard'),
|
|
||||||
path('employee/', EmployeeDashboardView.as_view(), name='employee_dashboard'),
|
|
||||||
])),
|
|
||||||
path('client/company/', include([
|
|
||||||
path('', ClientCompanyListView.as_view(), name='client_company'),
|
|
||||||
path('create/', ClientCompanyCreateView.as_view(), name='client_company_create'),
|
|
||||||
path('<int:pk>/edit/', ClientCompanyUpdateView.as_view(), name='client_company_edit'),
|
|
||||||
])),
|
|
||||||
path('client/line/', include([
|
|
||||||
path('', ClientLineListView.as_view(), name='client_line'),
|
|
||||||
path('create/', ClientLineCreateView.as_view(), name='client_line_create'),
|
|
||||||
path('<int:pk>/edit/', ClientLineUpdateView.as_view(), name='client_line_update'),
|
|
||||||
path('<int:pk>/active/', ClientLineUpdateView.as_view(), name='client_line_active'),
|
|
||||||
])),
|
|
||||||
path('employee/company/', include([
|
|
||||||
path('', EmployeeCompanyListView.as_view(), name='employee_company'),
|
|
||||||
path('create/', EmployeeCompanyCreateView.as_view(), name='employee_company_create'),
|
|
||||||
path('<int:pk>/edit/', EmployeeCompanyUpdateView.as_view(), name='employee_company_update'),
|
|
||||||
path('<int:pk>/active/', EmployeeCompanyUpdateView.as_view(), name='employee_company_active'),
|
|
||||||
])),
|
|
||||||
path('employee/line/', include([
|
|
||||||
path('', EmployeeLineListView.as_view(), name='employee_line'),
|
|
||||||
path('create/', EmployeeLineCreateView.as_view(), name='employee_line_create'),
|
|
||||||
path('<int:pk>/edit/', EmployeeLineUpdateView.as_view(), name='employee_line_update'),
|
|
||||||
path('<int:pk>/active/', EmployeeLineUpdateView.as_view(), name='employee_line_active'),
|
|
||||||
])),
|
|
||||||
]
|
|
||||||
@ -1,73 +0,0 @@
|
|||||||
from minio import Minio
|
|
||||||
from django.conf import settings
|
|
||||||
from datetime import datetime, timedelta
|
|
||||||
from rest_framework.response import Response
|
|
||||||
from rest_framework import status
|
|
||||||
import boto3
|
|
||||||
from botocore.client import Config
|
|
||||||
|
|
||||||
client = Minio(
|
|
||||||
settings.MINIO_ENDPOINT,
|
|
||||||
access_key=settings.MINIO_ACCESS_KEY,
|
|
||||||
secret_key=settings.MINIO_SECRET_KEY,
|
|
||||||
secure=settings.MINIO_SECURE
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def upload_damage_photo(photo_file, depot_id, content_type):
|
|
||||||
try:
|
|
||||||
s3_client = boto3.client('s3',
|
|
||||||
endpoint_url=f'http://{settings.MINIO_ENDPOINT}',
|
|
||||||
aws_access_key_id=settings.MINIO_ACCESS_KEY,
|
|
||||||
aws_secret_access_key=settings.MINIO_SECRET_KEY,
|
|
||||||
config=Config(signature_version='s3v4'),
|
|
||||||
region_name='us-east-1'
|
|
||||||
)
|
|
||||||
|
|
||||||
# Use the full filename as the key, which includes the depot_id folder
|
|
||||||
s3_client.upload_fileobj(
|
|
||||||
photo_file,
|
|
||||||
settings.MINIO_BUCKET_NAME,
|
|
||||||
photo_file.name,
|
|
||||||
ExtraArgs={'ContentType': content_type}
|
|
||||||
)
|
|
||||||
|
|
||||||
# Generate a presigned URL for the uploaded object
|
|
||||||
url = s3_client.generate_presigned_url('get_object',
|
|
||||||
Params={
|
|
||||||
'Bucket': settings.MINIO_BUCKET_NAME,
|
|
||||||
'Key': photo_file.name
|
|
||||||
},
|
|
||||||
ExpiresIn=3600
|
|
||||||
)
|
|
||||||
|
|
||||||
return url
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error uploading to MinIO: {str(e)}")
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
def get_damages(depot_id):
|
|
||||||
try:
|
|
||||||
objects = client.list_objects(
|
|
||||||
settings.MINIO_BUCKET_NAME,
|
|
||||||
prefix=f"{depot_id}/"
|
|
||||||
)
|
|
||||||
|
|
||||||
damages = []
|
|
||||||
for obj in objects:
|
|
||||||
url = client.presigned_get_object(
|
|
||||||
settings.MINIO_BUCKET_NAME,
|
|
||||||
obj.object_name,
|
|
||||||
expires=timedelta(days=7)
|
|
||||||
)
|
|
||||||
damages.append({
|
|
||||||
"url": url,
|
|
||||||
"filename": obj.object_name.split('/')[-1]
|
|
||||||
})
|
|
||||||
|
|
||||||
return Response(damages, status=status.HTTP_200_OK)
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error listing objects from MinIO: {str(e)}")
|
|
||||||
return Response([], status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
|
||||||
@ -1,77 +0,0 @@
|
|||||||
import os
|
|
||||||
import uuid
|
|
||||||
from datetime import datetime
|
|
||||||
from django.conf import settings
|
|
||||||
from django.http import HttpResponse
|
|
||||||
from rest_framework import status
|
|
||||||
from rest_framework.response import Response
|
|
||||||
import owncloud
|
|
||||||
from owncloud import (HTTPResponseError)
|
|
||||||
|
|
||||||
import xml.etree.ElementTree as ET
|
|
||||||
import requests
|
|
||||||
|
|
||||||
|
|
||||||
class Owncloud:
|
|
||||||
@staticmethod
|
|
||||||
def upload_damage_photo(filename, depot_id):
|
|
||||||
_, ext = os.path.splitext(filename)
|
|
||||||
oc = owncloud.Client(settings.OWNCLOUD_URL)
|
|
||||||
oc.login(settings.OWNCLOUD_USER, settings.OWNCLOUD_PASSWORD)
|
|
||||||
path = f"{settings.OWNCLOUD_DAMAGES_FOLDER}{str(depot_id)}"
|
|
||||||
try:
|
|
||||||
oc.file_info(path)
|
|
||||||
except HTTPResponseError:
|
|
||||||
_ = oc.mkdir(path)
|
|
||||||
owncloud_filename = f"{datetime.today().strftime('%Y%m%d')}_{uuid.uuid4()}{ext}"
|
|
||||||
owncloud_fullpath = path + "/" + owncloud_filename
|
|
||||||
oc.put_file(owncloud_fullpath, filename)
|
|
||||||
file_info = oc.share_file_with_link(owncloud_fullpath)
|
|
||||||
return file_info.get_link()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_damages(depot_id):
|
|
||||||
oc = owncloud.Client(settings.OWNCLOUD_URL)
|
|
||||||
oc.login(settings.OWNCLOUD_USER, settings.OWNCLOUD_PASSWORD)
|
|
||||||
files = oc.list(f"{settings.OWNCLOUD_DAMAGES_FOLDER}{str(depot_id)}")
|
|
||||||
damages = []
|
|
||||||
for file_info in files:
|
|
||||||
if file_info.is_dir():
|
|
||||||
continue
|
|
||||||
link_info = oc.share_file_with_link(file_info.path)
|
|
||||||
damages.append(link_info.get_link())
|
|
||||||
return Response(damages, status=status.HTTP_200_OK)
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_damages_webdav(depot_id):
|
|
||||||
oc = owncloud.Client(settings.OWNCLOUD_URL)
|
|
||||||
oc.login(settings.OWNCLOUD_USER, settings.OWNCLOUD_PASSWORD)
|
|
||||||
path = f"{settings.OWNCLOUD_DAMAGES_FOLDER}{str(depot_id)}"
|
|
||||||
files = oc.list(path)
|
|
||||||
damages = []
|
|
||||||
|
|
||||||
for file_info in files:
|
|
||||||
if file_info.is_dir():
|
|
||||||
continue
|
|
||||||
|
|
||||||
original_filename = os.path.basename(file_info.path)
|
|
||||||
link_info = oc.share_file_with_link(file_info.path)
|
|
||||||
share_url = link_info.get_link()
|
|
||||||
token = share_url.rstrip('/').split('/')[-1]
|
|
||||||
|
|
||||||
damages.append({
|
|
||||||
"token": token,
|
|
||||||
"filename": original_filename
|
|
||||||
})
|
|
||||||
|
|
||||||
return Response(damages, status=status.HTTP_200_OK)
|
|
||||||
|
|
||||||
|
|
||||||
def proxy_owncloud_image(request, token, filename):
|
|
||||||
url = f"{settings.OWNCLOUD_URL}/public.php/webdav/{filename}"
|
|
||||||
r = requests.get(url, auth=(token, ''), stream=True)
|
|
||||||
if r.status_code == 200:
|
|
||||||
content_type = r.headers.get('Content-Type', 'image/jpeg')
|
|
||||||
return HttpResponse(r.content, content_type=content_type)
|
|
||||||
return HttpResponse("Not found", status=404)
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
import datetime
|
|
||||||
|
|
||||||
from models.enums import ContainerLength, ContainerType
|
|
||||||
|
|
||||||
PAYMENT_SCHEMA = {
|
|
||||||
"standart": [[0, 5, 25], [5, 20, 40], [40, 1000000, 75]],
|
|
||||||
"reefer": [[0, 7, 35], [7, 30, 60], [30, 1000000, 115]],
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def calc_storage_amount(depot, container):
|
|
||||||
result = (depot.expedited_on - depot.received_on + datetime.timedelta(days=1)).days
|
|
||||||
if container.container_type == ContainerType.ct_reefer:
|
|
||||||
data = PAYMENT_SCHEMA["reefer"]
|
|
||||||
result -= 1
|
|
||||||
else:
|
|
||||||
data = PAYMENT_SCHEMA["standart"]
|
|
||||||
|
|
||||||
for i in data:
|
|
||||||
start, end, price = i
|
|
||||||
if start <= result < end:
|
|
||||||
price_per_day = price
|
|
||||||
break
|
|
||||||
if container.container_length in (
|
|
||||||
ContainerLength.cl_40_ft,
|
|
||||||
ContainerLength.cl_45_ft,
|
|
||||||
):
|
|
||||||
result *= 2
|
|
||||||
result = result * price_per_day
|
|
||||||
return result
|
|
||||||
@ -1,89 +0,0 @@
|
|||||||
import re
|
|
||||||
|
|
||||||
from django.template.loader import render_to_string
|
|
||||||
from django.utils.html import strip_tags
|
|
||||||
|
|
||||||
from containers.models import Container
|
|
||||||
from preinfo.models import Preinfo
|
|
||||||
from django.conf import settings
|
|
||||||
from django.core.mail import send_mail, EmailMessage
|
|
||||||
|
|
||||||
|
|
||||||
def filter_queryset_by_user(queryset, user):
|
|
||||||
"""
|
|
||||||
Filters the queryset based on the user's line or company.
|
|
||||||
If the user has a line, it filters by that line.
|
|
||||||
If the user has a company, it filters by all lines associated with that company.
|
|
||||||
"""
|
|
||||||
print(f'user: {user}, user company: {user.company}, user line: {user.line}, user type: {user.user_type}')
|
|
||||||
if user.line:
|
|
||||||
filtered = queryset.filter(line=user.line)
|
|
||||||
print(f"Filtering by line: {user.line.id}, count: {filtered.count()}")
|
|
||||||
return filtered
|
|
||||||
elif user.company:
|
|
||||||
company_lines = user.company.line_company.all()
|
|
||||||
filtered = queryset.filter(line__in=company_lines)
|
|
||||||
print(f"Filtering by company: {user.company.id}, count: {filtered.count()}")
|
|
||||||
return filtered
|
|
||||||
return queryset
|
|
||||||
|
|
||||||
|
|
||||||
def get_preinfo_by_number(number):
|
|
||||||
"""
|
|
||||||
Retrieves a PreinfoModel instance by its container number.
|
|
||||||
Returns None if no matching PreinfoModel is found.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
return Preinfo.objects.get(container_number=number, received=False)
|
|
||||||
except Preinfo.DoesNotExist:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def get_container_by_number(number):
|
|
||||||
"""
|
|
||||||
Retrieves a Container instance by its number.
|
|
||||||
Returns None if no matching Container is found.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
return Container.objects.get(number=number, expedited=False)
|
|
||||||
except Container.DoesNotExist:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
CALC_STRING = "0123456789A.BCDEFGHIJK.LMNOPQRSTU.VWXYZ"
|
|
||||||
|
|
||||||
def check_container_number_validity(container_number):
|
|
||||||
if not re.search(r"[A-Z]{4}[0-9]{7}", container_number):
|
|
||||||
return False
|
|
||||||
subtotal = 0
|
|
||||||
delta = 1
|
|
||||||
for i in range(0, 10):
|
|
||||||
subtotal = subtotal + CALC_STRING.find(container_number[i]) * delta
|
|
||||||
delta = delta * 2
|
|
||||||
subtotal = (subtotal % 11) % 10
|
|
||||||
if not subtotal == CALC_STRING.find(container_number[10]):
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
ADMIN_USER_EMAIL= settings.ADMIN_USER_EMAIL
|
|
||||||
EMAIL_HOST_USER = settings.EMAIL_HOST_USER
|
|
||||||
|
|
||||||
def send_test_email(user_email, urls):
|
|
||||||
subject='Welcome to Our Platform'
|
|
||||||
html_message = render_to_string('email.html', {
|
|
||||||
'site_name': 'Our Platform',
|
|
||||||
'user_email': user_email,
|
|
||||||
'link1': urls['pay_epay'],
|
|
||||||
'link2': urls['pay_credit_card'],
|
|
||||||
})
|
|
||||||
plain_message = strip_tags(html_message)
|
|
||||||
|
|
||||||
email = EmailMessage(
|
|
||||||
subject=subject,
|
|
||||||
body=html_message,
|
|
||||||
from_email=EMAIL_HOST_USER,
|
|
||||||
to=[user_email],
|
|
||||||
)
|
|
||||||
email.content_subtype = 'html' # This tells Django to send HTML email
|
|
||||||
email.send()
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
from django.shortcuts import render
|
|
||||||
from django.views.generic import TemplateView
|
|
||||||
|
|
||||||
from containers.models import Container
|
|
||||||
|
|
||||||
|
|
||||||
class BarrierDashboardView(TemplateView):
|
|
||||||
template_name = 'barrier/barrier-dashboard.html'
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
context = super().get_context_data(**kwargs)
|
|
||||||
recent_containers = Container.objects.select_related('line', 'booking').order_by('-expedited_on', '-received_on')[:10]
|
|
||||||
context['recent_containers'] = recent_containers
|
|
||||||
return context
|
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
|
||||||
return render(request, self.template_name, self.get_context_data())
|
|
||||||
@ -1,140 +0,0 @@
|
|||||||
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
|
|
||||||
from django.shortcuts import render
|
|
||||||
from django.urls import reverse_lazy
|
|
||||||
from django.views.generic import TemplateView, ListView, CreateView, UpdateView
|
|
||||||
|
|
||||||
from DepoT.mixins.LineFiltweFormMixin import LineFilterFormMixin
|
|
||||||
from common.forms.company import CompanyCreateForm, CompanyUpdateForm
|
|
||||||
from common.forms.line import LineCreateForm, LineUpdateForm
|
|
||||||
from common.models import CompanyModel, LinesModel
|
|
||||||
from common.utils.utils import filter_queryset_by_user
|
|
||||||
|
|
||||||
|
|
||||||
class ClientDashboardView(TemplateView):
|
|
||||||
template_name = 'client-dashboard-content.html'
|
|
||||||
extra_context = {
|
|
||||||
'title': 'Client Dashboard',
|
|
||||||
'description': 'This is the client dashboard page.',
|
|
||||||
}
|
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
|
||||||
return render(request, self.template_name, self.extra_context)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ClientCompanyListView(LoginRequiredMixin, UserPassesTestMixin, ListView):
|
|
||||||
model = CompanyModel
|
|
||||||
template_name = 'common/../../templates/employee/company-list.html'
|
|
||||||
context_object_name = 'objects'
|
|
||||||
paginate_by = 3
|
|
||||||
# base_template = 'client-base.html'
|
|
||||||
|
|
||||||
def test_func(self):
|
|
||||||
return True # self.request.user.has_employee_perm('can_view_preinfo') or self.request.user.user_type == 'CA'
|
|
||||||
|
|
||||||
# def get_context_data(self, **kwargs):
|
|
||||||
# context = super().get_context_data(**kwargs)
|
|
||||||
# context['base_template'] = self.base_template
|
|
||||||
# return context
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
queryset = super().get_queryset()
|
|
||||||
user = self.request.user
|
|
||||||
result = filter_queryset_by_user(queryset, user)
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ClientCompanyCreateView(LoginRequiredMixin, UserPassesTestMixin, CreateView):
|
|
||||||
model = CompanyModel
|
|
||||||
template_name = 'common/../../templates/employee/company-create.html'
|
|
||||||
form_class = CompanyCreateForm
|
|
||||||
success_url = reverse_lazy('client-company')
|
|
||||||
|
|
||||||
def test_func(self):
|
|
||||||
return True # self.request.user.has_company_perm('can_create_preinfo') or self.request.user.user_type == 'CA'
|
|
||||||
|
|
||||||
# def form_valid(self, form):
|
|
||||||
# form.instance.created_by = self.request.user
|
|
||||||
# form.instance.updated_by = self.request.user
|
|
||||||
# return super().form_valid(form)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ClientCompanyUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
|
|
||||||
model = CompanyModel
|
|
||||||
template_name = 'common/../../templates/employee/company-update.html'
|
|
||||||
form_class = CompanyUpdateForm
|
|
||||||
success_url = reverse_lazy('client-company')
|
|
||||||
|
|
||||||
def test_func(self):
|
|
||||||
return True # self.request.user.ha.s_company_perm('can_edit_preinfo') or self.request.user.user_type == 'CA'
|
|
||||||
|
|
||||||
# def form_valid(self, form):
|
|
||||||
# form.instance.updated_by = self.request.user
|
|
||||||
# return super().form_valid(form)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ClientLineListView(LoginRequiredMixin, UserPassesTestMixin, ListView):
|
|
||||||
model = LinesModel
|
|
||||||
template_name = 'client/line-list.html'
|
|
||||||
context_object_name = 'objects'
|
|
||||||
paginate_by = 3
|
|
||||||
# base_template = 'client-base.html'
|
|
||||||
|
|
||||||
def test_func(self):
|
|
||||||
return True # self.request.user.has_employee_perm('can_view_preinfo') or self.request.user.user_type == 'CA'
|
|
||||||
|
|
||||||
# def get_context_data(self, **kwargs):
|
|
||||||
# context = super().get_context_data(**kwargs)
|
|
||||||
# context['base_template'] = self.base_template
|
|
||||||
# return context
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
queryset = super().get_queryset()
|
|
||||||
user = self.request.user
|
|
||||||
result = queryset.filter(company=user.company)
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
class ClientLineCreateView(LoginRequiredMixin, UserPassesTestMixin, CreateView):
|
|
||||||
model = LinesModel
|
|
||||||
template_name = 'client/line-create.html'
|
|
||||||
form_class = LineCreateForm
|
|
||||||
|
|
||||||
success_url = reverse_lazy('client-line')
|
|
||||||
|
|
||||||
def test_func(self):
|
|
||||||
return True # self.request.user.has_company_perm('can_create_preinfo') or self.request.user.user_type == 'CA'
|
|
||||||
|
|
||||||
def get_form(self, form_class=None):
|
|
||||||
form = super().get_form(form_class)
|
|
||||||
form.fields['company'].queryset = CompanyModel.objects.filter(id=self.request.user.company.id)
|
|
||||||
form.fields['company'].initial = self.request.user.company.id
|
|
||||||
return form
|
|
||||||
|
|
||||||
def form_valid(self, form):
|
|
||||||
# todo more validation
|
|
||||||
form.instance.company = self.request.user.company
|
|
||||||
return super().form_valid(form)
|
|
||||||
|
|
||||||
class ClientLineUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
|
|
||||||
model = LinesModel
|
|
||||||
template_name = 'client/line-update.html'
|
|
||||||
form_class = LineUpdateForm
|
|
||||||
success_url = reverse_lazy('client-company')
|
|
||||||
|
|
||||||
def test_func(self):
|
|
||||||
return True # self.request.user.ha.s_company_perm('can_edit_preinfo') or self.request.user.user_type == 'CA'
|
|
||||||
|
|
||||||
def get_form(self, form_class=None):
|
|
||||||
form = super().get_form(form_class)
|
|
||||||
form.fields['company'].queryset = CompanyModel.objects.filter(id=self.request.user.company.id)
|
|
||||||
form.fields['company'].initial = self.request.user.company.id
|
|
||||||
return form
|
|
||||||
|
|
||||||
def form_valid(self, form):
|
|
||||||
# todo more validation
|
|
||||||
form.instance.company = self.request.user.company
|
|
||||||
return super().form_valid(form)
|
|
||||||
@ -1,140 +0,0 @@
|
|||||||
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
|
|
||||||
from django.urls import reverse_lazy
|
|
||||||
from django.views.generic import TemplateView, ListView, CreateView, UpdateView
|
|
||||||
|
|
||||||
from booking.models import Booking
|
|
||||||
from common.forms.company import CompanyCreateForm, CompanyUpdateForm
|
|
||||||
from common.forms.line import LineCreateForm, LineUpdateForm
|
|
||||||
from common.models import CompanyModel, LinesModel
|
|
||||||
from containers.models import Container
|
|
||||||
from preinfo.models import Preinfo
|
|
||||||
|
|
||||||
|
|
||||||
class EmployeeDashboardView(TemplateView):
|
|
||||||
template_name = 'employee-dashboard-content.html'
|
|
||||||
extra_context = {
|
|
||||||
'title': 'Employee Dashboard',
|
|
||||||
'description': 'This is the depot employee dashboard page.',
|
|
||||||
}
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
context = super().get_context_data(**kwargs)
|
|
||||||
containers = Container.objects.filter(expedited=False).count()
|
|
||||||
preinfos = Preinfo.objects.filter(received=False).count()
|
|
||||||
bookings = Booking.objects.filter(status='active').count()
|
|
||||||
context['containers'] = containers
|
|
||||||
context['preinfos'] = preinfos
|
|
||||||
context['bookings'] = bookings
|
|
||||||
return context
|
|
||||||
|
|
||||||
|
|
||||||
class EmployeeCompanyListView(LoginRequiredMixin, UserPassesTestMixin, ListView):
|
|
||||||
model = CompanyModel
|
|
||||||
template_name = 'common/../../templates/employee/company-list.html'
|
|
||||||
context_object_name = 'objects'
|
|
||||||
paginate_by = 3
|
|
||||||
# base_template = 'employee-base.html'
|
|
||||||
|
|
||||||
def test_func(self):
|
|
||||||
return True # self.request.user.has_employee_perm('can_view_preinfo') or self.request.user.user_type == 'CA'
|
|
||||||
|
|
||||||
# def get_context_data(self, **kwargs):
|
|
||||||
# context = super().get_context_data(**kwargs)
|
|
||||||
# context['base_template'] = self.base_template
|
|
||||||
# return context
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
queryset = super().get_queryset()
|
|
||||||
|
|
||||||
data_filter = self.request.GET.get('filter')
|
|
||||||
if data_filter != 'all':
|
|
||||||
queryset = queryset.filter(active=True)
|
|
||||||
|
|
||||||
queryset = queryset.order_by('name')
|
|
||||||
|
|
||||||
return queryset
|
|
||||||
|
|
||||||
class EmployeeCompanyCreateView(LoginRequiredMixin, UserPassesTestMixin, CreateView):
|
|
||||||
model = CompanyModel
|
|
||||||
template_name = 'common/../../templates/employee/company-create.html'
|
|
||||||
form_class = CompanyCreateForm
|
|
||||||
success_url = reverse_lazy('employee_company')
|
|
||||||
|
|
||||||
def test_func(self):
|
|
||||||
return True # self.request.user.has_company_perm('can_create_preinfo') or self.request.user.user_type == 'CA'
|
|
||||||
|
|
||||||
# def form_valid(self, form):
|
|
||||||
# form.instance.created_by = self.request.user
|
|
||||||
# form.instance.updated_by = self.request.user
|
|
||||||
# return super().form_valid(form)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class EmployeeCompanyUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
|
|
||||||
model = CompanyModel
|
|
||||||
template_name = 'common/../../templates/employee/company-update.html'
|
|
||||||
form_class = CompanyUpdateForm
|
|
||||||
success_url = reverse_lazy('employee_company')
|
|
||||||
|
|
||||||
def test_func(self):
|
|
||||||
return True # self.request.user.ha.s_company_perm('can_edit_preinfo') or self.request.user.user_type == 'CA'
|
|
||||||
|
|
||||||
# def form_valid(self, form):
|
|
||||||
# form.instance.updated_by = self.request.user
|
|
||||||
# return super().form_valid(form)
|
|
||||||
|
|
||||||
|
|
||||||
class EmployeeLineListView(LoginRequiredMixin, UserPassesTestMixin, ListView):
|
|
||||||
model = LinesModel
|
|
||||||
template_name = 'employee/line-list.html'
|
|
||||||
context_object_name = 'objects'
|
|
||||||
paginate_by = 3
|
|
||||||
# base_template = 'employee-base.html'
|
|
||||||
|
|
||||||
def test_func(self):
|
|
||||||
return True # self.request.user.has_employee_perm('can_view_preinfo') or self.request.user.user_type == 'CA'
|
|
||||||
|
|
||||||
# def get_context_data(self, **kwargs):
|
|
||||||
# context = super().get_context_data(**kwargs)
|
|
||||||
# context['base_template'] = self.base_template
|
|
||||||
# return context
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
queryset = super().get_queryset()
|
|
||||||
|
|
||||||
data_filter = self.request.GET.get('filter')
|
|
||||||
if data_filter != 'all':
|
|
||||||
queryset = queryset.filter(active=True)
|
|
||||||
|
|
||||||
queryset = queryset.order_by('name')
|
|
||||||
|
|
||||||
return queryset
|
|
||||||
|
|
||||||
class EmployeeLineCreateView(LoginRequiredMixin, UserPassesTestMixin, CreateView):
|
|
||||||
model = LinesModel
|
|
||||||
template_name = 'employee/company-create.html'
|
|
||||||
form_class = LineCreateForm
|
|
||||||
success_url = reverse_lazy('employee_line')
|
|
||||||
|
|
||||||
def test_func(self):
|
|
||||||
return True # self.request.user.has_company_perm('can_create_preinfo') or self.request.user.user_type == 'CA'
|
|
||||||
|
|
||||||
# def form_valid(self, form):
|
|
||||||
# form.instance.created_by = self.request.user
|
|
||||||
# form.instance.updated_by = self.request.user
|
|
||||||
# return super().form_valid(form)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class EmployeeLineUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
|
|
||||||
model = LinesModel
|
|
||||||
template_name = 'employee/company-update.html'
|
|
||||||
form_class = LineUpdateForm
|
|
||||||
success_url = reverse_lazy('employee_line')
|
|
||||||
|
|
||||||
def test_func(self):
|
|
||||||
return True # self.request.user.ha.s_company_perm('can_edit_preinfo') or self.request.user.user_type == 'CA'
|
|
||||||
|
|
||||||
# def form_valid(self, form):
|
|
||||||
# form.instance.updated_by = self.request.user
|
|
||||||
# return super().form_valid(form)
|
|
||||||
@ -1,54 +0,0 @@
|
|||||||
from django.urls import reverse_lazy
|
|
||||||
from django.views.generic import TemplateView, RedirectView
|
|
||||||
from django.shortcuts import render
|
|
||||||
|
|
||||||
from accounts.models import DepotUser
|
|
||||||
from booking.models import Booking
|
|
||||||
from containers.models import Container
|
|
||||||
from preinfo.models import Preinfo
|
|
||||||
|
|
||||||
|
|
||||||
# Create your views here.
|
|
||||||
class IndexView(TemplateView):
|
|
||||||
template_name = 'landing-page.html'
|
|
||||||
extra_context = {
|
|
||||||
'title': 'Home',
|
|
||||||
'description': 'This is the home page of the container application.',
|
|
||||||
}
|
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
|
||||||
return render(request, self.template_name, self.extra_context)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class DashboardRedirectView(RedirectView):
|
|
||||||
is_permanent = False
|
|
||||||
|
|
||||||
def get_redirect_url(self, *args, **kwargs):
|
|
||||||
# if self.request.user.is_authenticated:
|
|
||||||
if self.request.user.user_type == DepotUser.UserType.COMPANY_ADMIN:
|
|
||||||
return reverse_lazy('client_dashboard')
|
|
||||||
elif self.request.user.user_type == DepotUser.UserType.CLIENT:
|
|
||||||
return reverse_lazy('client_dashboard')
|
|
||||||
elif self.request.user.user_type == DepotUser.UserType.BARRIER_STAFF:
|
|
||||||
return reverse_lazy('barrier_dashboard')
|
|
||||||
elif self.request.user.user_type == DepotUser.UserType.EMPLOYEE:
|
|
||||||
return reverse_lazy('employee_dashboard')
|
|
||||||
elif self.request.user.user_type == DepotUser.UserType.ADMIN:
|
|
||||||
return reverse_lazy('employee_dashboard')
|
|
||||||
return reverse_lazy('index')
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# class ClientPreinfoView(TemplateView):
|
|
||||||
# template_name = 'client-preinfo-content.html'
|
|
||||||
#
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# def get(self, request, *args, **kwargs):
|
|
||||||
# return render(request, self.template_name, self.extra_context)
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
from django.urls import path
|
|
||||||
from .views import validate_container
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
# ... your other urls
|
|
||||||
path('validate-container/<str:number>/', validate_container, name='validate_container'),
|
|
||||||
]
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
from django.http import JsonResponse
|
|
||||||
from common.utils.utils import check_container_number_validity
|
|
||||||
|
|
||||||
def validate_container(request, number):
|
|
||||||
is_valid = check_container_number_validity(number)
|
|
||||||
return JsonResponse({'valid': is_valid})
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
from django.contrib import admin
|
|
||||||
|
|
||||||
# Register your models here.
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class ContainersConfig(AppConfig):
|
|
||||||
default_auto_field = "django.db.models.BigAutoField"
|
|
||||||
name = "containers"
|
|
||||||
@ -1,65 +0,0 @@
|
|||||||
from django.forms import ModelForm, TextInput, CharField, Form
|
|
||||||
|
|
||||||
from containers.models import Container
|
|
||||||
|
|
||||||
|
|
||||||
class ContainerBaseForm(ModelForm):
|
|
||||||
class Meta:
|
|
||||||
model = Container
|
|
||||||
fields = '__all__'
|
|
||||||
widgets = {
|
|
||||||
'number': TextInput(attrs={
|
|
||||||
'oninput': 'validateContainerNumber(this)',
|
|
||||||
'class': 'form-control'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
class ContainerReceiveForm(ContainerBaseForm):
|
|
||||||
"""
|
|
||||||
Form for creating a new Container instance.
|
|
||||||
Inherits from ContainerBaseForm.
|
|
||||||
"""
|
|
||||||
class Meta(ContainerBaseForm.Meta):
|
|
||||||
fields = ['number', 'receive_vehicle', 'damages', 'heavy_damaged', 'position',]
|
|
||||||
|
|
||||||
def __init__(self, *args, preinfo=None, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
# Add form-control class to all fields
|
|
||||||
for field in self.fields.values():
|
|
||||||
field.widget.attrs.update({'class': 'form-control'})
|
|
||||||
|
|
||||||
# Checkbox specific styling
|
|
||||||
self.fields['heavy_damaged'].widget.attrs.update({'class': 'form-check-input'})
|
|
||||||
|
|
||||||
# If preinfo is provided, set initial values and make fields readonly
|
|
||||||
if preinfo:
|
|
||||||
...
|
|
||||||
# self.fields['preinfo'].initial = preinfo.container_number
|
|
||||||
# self.fields['number'].initial = preinfo.number
|
|
||||||
# self.fields['container_number'].widget.attrs['readonly'] = True
|
|
||||||
# self.fields['number'].widget.attrs['readonly'] = True
|
|
||||||
# self.fields['booking'].disabled = True
|
|
||||||
# self.fields['number'].disabled = True
|
|
||||||
|
|
||||||
|
|
||||||
class ContainerExpeditionForm(ContainerBaseForm):
|
|
||||||
class Meta(ContainerBaseForm.Meta):
|
|
||||||
fields = ['number', 'expedition_vehicle', 'position', 'line', 'container_type', 'damages', 'heavy_damaged']
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
readonly_fields = ['number', 'position', 'line', 'container_type', 'damages', 'heavy_damaged']
|
|
||||||
for field in readonly_fields:
|
|
||||||
self.fields[field].widget.attrs['readonly'] = True
|
|
||||||
# self.fields[field].disabled = True
|
|
||||||
|
|
||||||
|
|
||||||
class ContainerSearchForm(Form):
|
|
||||||
container_number = CharField(
|
|
||||||
max_length=11,
|
|
||||||
required=True,
|
|
||||||
widget=TextInput(attrs={
|
|
||||||
'class': 'form-control',
|
|
||||||
'placeholder': 'Enter container number'
|
|
||||||
})
|
|
||||||
)
|
|
||||||
@ -1,112 +0,0 @@
|
|||||||
# Generated by Django 5.2.3 on 2025-06-27 10:20
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("booking", "0001_initial"),
|
|
||||||
("common", "0001_initial"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name="Container",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"id",
|
|
||||||
models.BigAutoField(
|
|
||||||
auto_created=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
verbose_name="ID",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("number", models.CharField(max_length=11)),
|
|
||||||
("received_on", models.DateTimeField(auto_now_add=True)),
|
|
||||||
("received_by", models.IntegerField()),
|
|
||||||
(
|
|
||||||
"receive_vehicles",
|
|
||||||
models.CharField(blank=True, max_length=100, null=True),
|
|
||||||
),
|
|
||||||
("damages", models.TextField(blank=True, null=True)),
|
|
||||||
("heavy_damaged", models.BooleanField(default=False)),
|
|
||||||
("position", models.CharField(blank=True, max_length=100, null=True)),
|
|
||||||
("swept", models.BooleanField(default=False)),
|
|
||||||
("swept_on", models.DateTimeField(blank=True, null=True)),
|
|
||||||
("swept_by", models.IntegerField(blank=True, null=True)),
|
|
||||||
("washed", models.BooleanField(default=False)),
|
|
||||||
("washed_on", models.DateTimeField(blank=True, null=True)),
|
|
||||||
("washed_by", models.IntegerField(blank=True, null=True)),
|
|
||||||
("expedited", models.BooleanField(default=False)),
|
|
||||||
("expedited_on", models.DateTimeField(blank=True, null=True)),
|
|
||||||
("expedited_by", models.IntegerField(blank=True, null=True)),
|
|
||||||
(
|
|
||||||
"expedition_vehicle",
|
|
||||||
models.CharField(blank=True, max_length=100, null=True),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"booking",
|
|
||||||
models.ForeignKey(
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="container_bookings",
|
|
||||||
to="booking.bookingmodel",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"container_type",
|
|
||||||
models.ForeignKey(
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="container_container_types",
|
|
||||||
to="common.containertypemodel",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"line_id",
|
|
||||||
models.ForeignKey(
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="container_lines",
|
|
||||||
to="common.linesmodel",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name="ContainerHistory",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"container_ptr",
|
|
||||||
models.OneToOneField(
|
|
||||||
auto_created=True,
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
parent_link=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
to="containers.container",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("operation_date", models.DateTimeField(auto_now_add=True)),
|
|
||||||
(
|
|
||||||
"container",
|
|
||||||
models.ForeignKey(
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="history_containers",
|
|
||||||
to="containers.container",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"operation",
|
|
||||||
models.ForeignKey(
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="history_operations",
|
|
||||||
to="common.operationmodel",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
bases=("containers.container",),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 5.2.3 on 2025-06-28 06:15
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("containers", "0001_initial"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RenameField(
|
|
||||||
model_name="container",
|
|
||||||
old_name="receive_vehicles",
|
|
||||||
new_name="receive_vehicle",
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
# Generated by Django 5.2.3 on 2025-06-28 08:36
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("booking", "0001_initial"),
|
|
||||||
("containers", "0002_rename_receive_vehicles_container_receive_vehicle"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="container",
|
|
||||||
name="booking",
|
|
||||||
field=models.ForeignKey(
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="container_bookings",
|
|
||||||
to="booking.bookingmodel",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 5.2.3 on 2025-06-28 12:23
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("containers", "0003_alter_container_booking"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RenameField(
|
|
||||||
model_name="container",
|
|
||||||
old_name="line_id",
|
|
||||||
new_name="line",
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,58 +0,0 @@
|
|||||||
# Generated by Django 5.2.3 on 2025-06-28 12:30
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("containers", "0004_rename_line_id_container_line"),
|
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="container",
|
|
||||||
name="expedited_by",
|
|
||||||
field=models.ForeignKey(
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="container_expedited_by",
|
|
||||||
to=settings.AUTH_USER_MODEL,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="container",
|
|
||||||
name="received_by",
|
|
||||||
field=models.ForeignKey(
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="container_received_by",
|
|
||||||
to=settings.AUTH_USER_MODEL,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="container",
|
|
||||||
name="swept_by",
|
|
||||||
field=models.ForeignKey(
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="container_swept_by",
|
|
||||||
to=settings.AUTH_USER_MODEL,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="container",
|
|
||||||
name="washed_by",
|
|
||||||
field=models.ForeignKey(
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="container_washed_by",
|
|
||||||
to=settings.AUTH_USER_MODEL,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
# Generated by Django 5.2.3 on 2025-07-11 17:43
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("containers", "0005_alter_container_expedited_by_and_more"),
|
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name="ContainerPhotos",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"id",
|
|
||||||
models.BigAutoField(
|
|
||||||
auto_created=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
verbose_name="ID",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("photo", models.TextField(blank=True, null=True)),
|
|
||||||
("uploaded_on", models.DateTimeField(auto_now_add=True)),
|
|
||||||
(
|
|
||||||
"container",
|
|
||||||
models.ForeignKey(
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="photos",
|
|
||||||
to="containers.container",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"uploaded_by",
|
|
||||||
models.ForeignKey(
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="container_photos_uploaded_by",
|
|
||||||
to=settings.AUTH_USER_MODEL,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
# Generated by Django 5.2.3 on 2025-07-18 07:05
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("containers", "0006_containerphotos"),
|
|
||||||
("preinfo", "0003_rename_preinfomodel_preinfo"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name="container",
|
|
||||||
name="preinfo",
|
|
||||||
field=models.ForeignKey(
|
|
||||||
default=1,
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="container_preinfo",
|
|
||||||
to="preinfo.preinfo",
|
|
||||||
),
|
|
||||||
preserve_default=False,
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,97 +0,0 @@
|
|||||||
|
|
||||||
from django.db import models
|
|
||||||
from common.models import LinesModel, ContainerTypeModel
|
|
||||||
# from payments.models import ContainerTariffPeriod, AdditionalFees
|
|
||||||
|
|
||||||
# Create your models here.
|
|
||||||
class Container(models.Model):
|
|
||||||
number = models.CharField(max_length=11)
|
|
||||||
line = models.ForeignKey(
|
|
||||||
LinesModel,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='container_lines',
|
|
||||||
)
|
|
||||||
container_type = models.ForeignKey(
|
|
||||||
ContainerTypeModel,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='container_container_types',
|
|
||||||
)
|
|
||||||
received_on = models.DateTimeField(auto_now_add=True)
|
|
||||||
received_by = models.ForeignKey(
|
|
||||||
'accounts.DepotUser',
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='container_received_by',
|
|
||||||
)
|
|
||||||
receive_vehicle = models.CharField(max_length=100, blank=True, null=True)
|
|
||||||
damages = models.TextField(blank=True, null=True)
|
|
||||||
heavy_damaged = models.BooleanField(default=False)
|
|
||||||
position = models.CharField(max_length=100, blank=True, null=True)
|
|
||||||
swept = models.BooleanField(default=False)
|
|
||||||
swept_on = models.DateTimeField(blank=True, null=True)
|
|
||||||
swept_by = models.ForeignKey(
|
|
||||||
'accounts.DepotUser',
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='container_swept_by',
|
|
||||||
blank=True,
|
|
||||||
null=True
|
|
||||||
)
|
|
||||||
washed = models.BooleanField(default=False)
|
|
||||||
washed_on = models.DateTimeField(blank=True, null=True)
|
|
||||||
washed_by = models.ForeignKey(
|
|
||||||
'accounts.DepotUser',
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='container_washed_by',
|
|
||||||
blank=True,
|
|
||||||
null=True
|
|
||||||
)
|
|
||||||
preinfo = models.ForeignKey(
|
|
||||||
'preinfo.Preinfo',
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='container_preinfo',
|
|
||||||
)
|
|
||||||
booking = models.ForeignKey(
|
|
||||||
'booking.Booking',
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='container_bookings',
|
|
||||||
blank = True,
|
|
||||||
null = True
|
|
||||||
)
|
|
||||||
expedited = models.BooleanField(default=False)
|
|
||||||
expedited_on = models.DateTimeField(blank=True, null=True)
|
|
||||||
expedited_by = models.ForeignKey(
|
|
||||||
'accounts.DepotUser',
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='container_expedited_by',
|
|
||||||
blank=True,
|
|
||||||
null=True
|
|
||||||
)
|
|
||||||
expedition_vehicle = models.CharField(max_length=100, blank=True, null=True)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ContainerHistory(Container):
|
|
||||||
operation = models.ForeignKey(
|
|
||||||
'common.OperationModel',
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='history_operations',
|
|
||||||
)
|
|
||||||
operation_date = models.DateTimeField(auto_now_add=True)
|
|
||||||
container = models.ForeignKey(
|
|
||||||
Container,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='history_containers'
|
|
||||||
)
|
|
||||||
class ContainerPhotos(models.Model):
|
|
||||||
container = models.ForeignKey(
|
|
||||||
Container,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='photos',
|
|
||||||
)
|
|
||||||
photo = models.TextField(blank=True, null=True)
|
|
||||||
uploaded_on = models.DateTimeField(auto_now_add=True)
|
|
||||||
uploaded_by = models.ForeignKey(
|
|
||||||
'accounts.DepotUser',
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='container_photos_uploaded_by',
|
|
||||||
)
|
|
||||||
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
from booking.models import Booking
|
|
||||||
from containers.models import Container
|
|
||||||
|
|
||||||
def get_container_for_booking(booking):
|
|
||||||
filters = {
|
|
||||||
'expedited': False,
|
|
||||||
}
|
|
||||||
# booking = Booking.objects.get(number=booking_number)
|
|
||||||
if not booking:
|
|
||||||
return None
|
|
||||||
if booking.container_number:
|
|
||||||
filters['container_number'] = booking.container_number
|
|
||||||
else:
|
|
||||||
filters['container_type'] = booking.container_type
|
|
||||||
filters['line'] = booking.line
|
|
||||||
|
|
||||||
return Container.objects.filter(**filters).order_by('received_on').first()
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
# Create your tests here.
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
from django.urls import include, path
|
|
||||||
|
|
||||||
from containers.views.common import ContainerDetails
|
|
||||||
from containers.views.employee_views import ContainersListView, ReportContainersUnpaidListView
|
|
||||||
from containers.views.barrier_views import ContainerReceiveView, ContainerExpedition, ContainerSearchView, \
|
|
||||||
ContainerPhotosView
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path('container-search/', ContainerSearchView.as_view(), name='container_search'),
|
|
||||||
path('container-details/', ContainerDetails.as_view(), name='container_details'),
|
|
||||||
path('container-search/', ContainerSearchView.as_view(), name='barrier_photos'),
|
|
||||||
# path('search/', ContainerSearchView.as_view(), name='container_search'),
|
|
||||||
path('employee/', ContainersListView.as_view(), name='employee_containers'),
|
|
||||||
path('not-paid', ReportContainersUnpaidListView.as_view(), name='not_paid'),
|
|
||||||
path('barrier/receive/', ContainerReceiveView.as_view(), name='container_receive'),
|
|
||||||
path('barrier/expedition/', ContainerExpedition.as_view(), name='container_expedition'),
|
|
||||||
path('barrier/<int:pk>/', include([
|
|
||||||
path('photos/', ContainerPhotosView.as_view(), name='container_photos'),
|
|
||||||
])),
|
|
||||||
]
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue